1/*
2 * Wireless interface translation utility functions
3 *
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: wlif_utils.c 418993 2013-08-19 07:41:41Z $
19 */
20
21#include <typedefs.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29
30#include <bcmparams.h>
31#include <bcmnvram.h>
32#include <bcmutils.h>
33#include <netconf.h>
34#include <nvparse.h>
35#include <shutils.h>
36#include <wlutils.h>
37#include <wlif_utils.h>
38
39#ifndef MAX_NVPARSE
40#define MAX_NVPARSE 255
41#endif
42
43int
44get_wlname_by_mac(unsigned char *mac, char *wlname)
45{
46	char eabuf[18];
47	char tmptr[] = "wlXXXXX_hwaddr";
48	char *wl_hw;
49	int i, j;
50
51	ether_etoa(mac, eabuf);
52	/* find out the wl name from mac */
53	for (i = 0; i < MAX_NVPARSE; i++) {
54		sprintf(wlname, "wl%d", i);
55		sprintf(tmptr, "wl%d_hwaddr", i);
56		wl_hw = nvram_get(tmptr);
57		if (wl_hw) {
58			if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
59				return 0;
60		}
61
62		for (j = 1; j < WL_MAXBSSCFG; j++) {
63			sprintf(wlname, "wl%d.%d", i, j);
64			sprintf(tmptr, "wl%d.%d_hwaddr", i, j);
65			wl_hw = nvram_get(tmptr);
66			if (wl_hw) {
67				if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
68					return 0;
69			}
70		}
71	}
72
73	return -1;
74}
75
76bool
77wl_wlif_is_psta(char *ifname)
78{
79	int32 psta = FALSE;
80
81	if (wl_probe(ifname) < 0)
82		return FALSE;
83
84	wl_iovar_getint(ifname, "psta_if", &psta);
85
86	return psta ? TRUE : FALSE;
87}
88
89bool
90wl_wlif_is_dwds(char *ifname)
91{
92	int32 wds_type = FALSE;
93
94	if (wl_probe(ifname) < 0)
95		return FALSE;
96
97	wl_iovar_getint(ifname, "wds_type", &wds_type);
98
99	return (wds_type == WL_WDSIFTYPE_DWDS);
100}
101
102/*
103 * Get LAN or WAN ifname by wl mac
104 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode)
105 */
106char *
107get_ifname_by_wlmac(unsigned char *mac, char *name)
108{
109	char nv_name[16], os_name[16];
110	static char if_name[16];
111	char tmptr[] = "lanXX_ifnames";
112	char *ifnames, *ifname;
113	int i;
114
115	/*
116	  * In case of URE mode, wl0.1 and wl0 have same mac,
117	  * we need extra identity (name).
118	  */
119	if (name && !strncmp(name, "wl", 2))
120		snprintf(nv_name, sizeof(nv_name), "%s", name);
121	else if (get_wlname_by_mac(mac, nv_name))
122		return 0;
123
124	if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0)
125		return 0;
126
127	if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0)
128		return 0;
129	/* find for dpsta */
130	if (wl_wlif_is_psta(os_name))
131		return name;
132
133	ifnames = nvram_get("dpsta_ifnames");
134	if (ifnames && (find_in_list(ifnames, nv_name) || find_in_list(ifnames, os_name))) {
135		/* find dpsta in which bridge */
136		for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
137			sprintf(tmptr, "br%d_ifnames", i);
138			sprintf(if_name, "br%d", i);
139			ifnames = nvram_get(tmptr);
140			ifname = if_name;
141
142			if (ifnames) {
143				/* the name in ifnames may nvifname or osifname */
144				if (find_in_list(ifnames, nv_name) ||
145				    find_in_list(ifnames, os_name))
146					return ifname;
147			}
148		}
149	}
150
151	/* find for lan */
152	for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
153		if (i == 0) {
154			ifnames = nvram_get("lan_ifnames");
155			ifname = nvram_get("lan_ifname");
156			if (ifname) {
157				/* the name in ifnames may nvifname or osifname */
158				if (find_in_list(ifnames, nv_name) ||
159				    find_in_list(ifnames, os_name))
160					return ifname;
161			}
162		}
163		else {
164			sprintf(if_name, "lan%d_ifnames", i);
165			sprintf(tmptr, "lan%d_ifname", i);
166			ifnames = nvram_get(if_name);
167			ifname = nvram_get(tmptr);
168			if (ifname) {
169				/* the name in ifnames may nvifname or osifname */
170				if (find_in_list(ifnames, nv_name) ||
171				    find_in_list(ifnames, os_name))
172					return ifname;
173			}
174		}
175	}
176
177	/* find for wan  */
178	ifnames = nvram_get("wan_ifnames");
179	ifname = nvram_get("wan0_ifname");
180	/* the name in ifnames may nvifname or osifname */
181	if (find_in_list(ifnames, nv_name) ||
182	    find_in_list(ifnames, os_name))
183		return ifname;
184
185	return 0;
186}
187
188#define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \
189				   WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK))
190#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
191#define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \
192				      WPA2_AUTH_UNSPECIFIED))
193
194/* Get wireless security setting by interface name */
195int
196get_wsec(wsec_info_t *info, unsigned char *mac, char *osifname)
197{
198	int i, unit, wds = 0, wds_wsec = 0;
199	char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8];
200	char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16],
201	        remote[ETHER_ADDR_LEN];
202	char akm[16], *akms, *akmnext, *value, *infra;
203
204	if (info == NULL || mac == NULL)
205		return WLIFU_ERR_INVALID_PARAMETER;
206
207	if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) {
208		if (get_wlname_by_mac(mac, nv_name))
209			return WLIFU_ERR_INVALID_PARAMETER;
210		else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)))
211			return WLIFU_ERR_INVALID_PARAMETER;
212	}
213	else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)))
214			return WLIFU_ERR_INVALID_PARAMETER;
215
216	/* check if i/f exists and retrieve the i/f index */
217	if (wl_probe(os_name) ||
218		wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
219		return WLIFU_ERR_NOT_WL_INTERFACE;
220
221	/* get wl_prefix.
222	 *
223	 * Due to DWDS and WDS may be enabled at the same time,
224	 * checking whether this is WDS interface in order to
225	 * get per WDS interface security settings from NVRAM.
226	 */
227	if (strstr(os_name, "wds") && (wl_wlif_is_dwds(os_name) == FALSE)) {
228		/* the wireless interface must be configured to run NAS */
229		snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
230		wds = 1;
231	}
232	else if (wl_wlif_is_psta(os_name))
233		snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
234	else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix)))
235		return WLIFU_ERR_INVALID_PARAMETER;
236
237	strcat(wl_prefix, "_");
238	memset(info, 0, sizeof(wsec_info_t));
239
240	/* get wds setting */
241	if (wds) {
242		/* remote address */
243		if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN))
244			return WLIFU_ERR_WL_REMOTE_HWADDR;
245		memcpy(info->remote, remote, ETHER_ADDR_LEN);
246
247		/* get per wds settings */
248		for (i = 0; i < MAX_NVPARSE; i ++) {
249			char macaddr[18];
250			uint8 ea[ETHER_ADDR_LEN];
251
252			if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid,
253			                 wds_psk) &&
254			    ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) ||
255			     ((mac[0] == '*') && (mac[1] == '\0')))) {
256			     /* found wds settings */
257			     wds_wsec = 1;
258			     break;
259			}
260		}
261	}
262
263	/* interface unit */
264	info->unit = unit;
265	/* interface os name */
266	strcpy(info->osifname, os_name);
267	/* interface address */
268	memcpy(info->ea, mac, ETHER_ADDR_LEN);
269	/* ssid */
270	if (wds && wds_wsec)
271		strncpy(info->ssid, wds_ssid, MAX_SSID_LEN);
272	else {
273		value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb));
274		strncpy(info->ssid, value, MAX_SSID_LEN);
275	}
276	/* auth */
277	if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1"))
278		info->auth = 1;
279	/* nas auth mode */
280	value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb));
281	info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0;
282	if (wds && wds_wsec)
283		akms = wds_akms;
284	else
285		akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb));
286	foreach(akm, akms, akmnext) {
287		if (!strcmp(akm, "wpa"))
288			info->akm |= WPA_AUTH_UNSPECIFIED;
289		if (!strcmp(akm, "psk"))
290			info->akm |= WPA_AUTH_PSK;
291		if (!strcmp(akm, "wpa2"))
292			info->akm |= WPA2_AUTH_UNSPECIFIED;
293		if (!strcmp(akm, "psk2"))
294			info->akm |= WPA2_AUTH_PSK;
295	}
296	/* wsec encryption */
297	value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb));
298	info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0;
299	if (wds && wds_wsec)
300		value = wds_crypto;
301	else
302		value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb));
303	if (CHECK_NAS(info->akm)) {
304		if (!strcmp(value, "tkip"))
305			info->wsec |= TKIP_ENABLED;
306		else if (!strcmp(value, "aes"))
307			info->wsec |= AES_ENABLED;
308		else if (!strcmp(value, "tkip+aes"))
309			info->wsec |= TKIP_ENABLED|AES_ENABLED;
310	}
311	/* nas role setting, may overwrite later in wds case */
312	value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
313	infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb));
314	if (!strcmp(value, "ap")) {
315		info->flags |= WLIFU_WSEC_AUTH;
316	}
317	else if (!strcmp(value, "sta") || !strcmp(value, "wet") ||
318	         !strcmp(value, "psr") || !strcmp(value, "psta")) {
319		if (!strcmp(infra, "0")) {
320			/* IBSS, so we must act as Authenticator and Supplicant */
321			info->flags |= WLIFU_WSEC_AUTH;
322			info->flags |= WLIFU_WSEC_SUPPL;
323			/* Adhoc Mode */
324			info->ibss = TRUE;
325		}
326		else {
327			info->flags |= WLIFU_WSEC_SUPPL;
328		}
329	}
330	else if (!strcmp(value, "wds")) {
331		;
332	}
333	else {
334		/* Unsupported network mode */
335		return WLIFU_ERR_NOT_SUPPORT_MODE;
336	}
337	/* overwrite flags */
338	if (wds) {
339		char buf[32];
340		unsigned char *ptr, lrole;
341
342		/* did not find WDS link configuration, use wireless' */
343		if (!wds_wsec)
344			strcpy(wds_role, "auto");
345
346		/* get right role */
347		if (!strcmp(wds_role, "sup"))
348			lrole = WL_WDS_WPA_ROLE_SUP;
349		else if (!strcmp(wds_role, "auth"))
350			lrole = WL_WDS_WPA_ROLE_AUTH;
351		else /* if (!strcmp(wds_role, "auto")) */
352			lrole = WL_WDS_WPA_ROLE_AUTO;
353
354		strcpy(buf, "wds_wpa_role");
355		ptr = (unsigned char *)buf + strlen(buf) + 1;
356		bcopy(info->remote, ptr, ETHER_ADDR_LEN);
357		ptr[ETHER_ADDR_LEN] = lrole;
358		if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf)))
359			return WLIFU_ERR_WL_WPA_ROLE;
360		else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf)))
361			return WLIFU_ERR_WL_WPA_ROLE;
362		lrole = *buf;
363
364		/* overwrite these flags */
365		info->flags = WLIFU_WSEC_WDS;
366		if (lrole == WL_WDS_WPA_ROLE_SUP) {
367			info->flags |= WLIFU_WSEC_SUPPL;
368		}
369		else if (lrole == WL_WDS_WPA_ROLE_AUTH) {
370			info->flags |= WLIFU_WSEC_AUTH;
371		}
372		else {
373			/* unable to determine WPA role */
374			return WLIFU_ERR_WL_WPA_ROLE;
375		}
376	}
377	/* user-supplied psk passphrase */
378	if (CHECK_PSK(info->akm)) {
379		if (wds && wds_wsec) {
380			strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN);
381			info->psk[MAX_USER_KEY_LEN] = 0;
382		}
383		else {
384			value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb));
385			strncpy((char *)info->psk, value, MAX_USER_KEY_LEN);
386			info->psk[MAX_USER_KEY_LEN] = 0;
387		}
388	}
389	/* user-supplied radius server secret */
390	if (CHECK_RADIUS(info->akm))
391		info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb));
392	/* AP specific settings */
393	value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
394	if (!strcmp(value, "ap")) {
395		/* gtk rekey interval */
396		if (CHECK_NAS(info->akm)) {
397			value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb));
398			info->gtk_rekey_secs = (int)strtoul(value, NULL, 0);
399		}
400		/* wep key */
401		if (info->wsec & WEP_ENABLED) {
402			/* key index */
403			value = nvram_safe_get(strcat_r(wl_prefix, "key", comb));
404			info->wep_index = (int)strtoul(value, NULL, 0);
405			/* key */
406			sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb)));
407			info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb));
408		}
409		/* radius server host/port */
410		if (CHECK_RADIUS(info->akm)) {
411			/* update radius server address */
412			info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr",
413			                                            comb));
414			value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb));
415			info->radius_port = htons((int)strtoul(value, NULL, 0));
416			/* 802.1x session timeout/pmk cache duration */
417			value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb));
418			info->ssn_to = (int)strtoul(value, NULL, 0);
419		}
420	}
421	/* preauth */
422	value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb));
423	info->preauth = (int)strtoul(value, NULL, 0);
424
425	/* verbose */
426	value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb));
427	info->debug = (int)strtoul(value, NULL, 0);
428
429
430
431	return WLIFU_WSEC_SUCCESS;
432}
433