1/*
2 * Wireless interface translation utility functions
3 *
4 * Copyright (C) 2015, 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 559751 2015-05-28 12:44:43Z $
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	if (wl_iovar_getint(ifname, "psta_if", &psta) < 0)
85		return FALSE;
86
87	return psta ? TRUE : FALSE;
88}
89
90bool
91wl_wlif_is_dwds(char *ifname)
92{
93	int32 wds_type = FALSE;
94
95	if (wl_probe(ifname) < 0)
96		return FALSE;
97
98	return (!wl_iovar_getint(ifname, "wds_type", &wds_type) && wds_type == WL_WDSIFTYPE_DWDS);
99}
100
101bool
102wl_wlif_is_psr_ap(char *ifname)
103{
104	int32 psta = FALSE;
105	int32 psta_mode = 0;
106
107	if (wl_probe(ifname) < 0)
108		return FALSE;
109
110	wl_iovar_getint(ifname, "psta", &psta_mode);
111	if (psta_mode == 2) {
112		wl_iovar_getint(ifname, "psta_if", &psta);
113		if (!psta) {
114			return strncmp(ifname, "wl", 2) ? FALSE : TRUE;
115		}
116	} else
117		return FALSE;
118}
119
120/*
121 * Get LAN or WAN ifname by wl mac
122 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode)
123 */
124char *
125get_ifname_by_wlmac(unsigned char *mac, char *name)
126{
127	char nv_name[16], os_name[16], if_name[16];
128	char tmptr[] = "lanXX_ifnames";
129	char *ifnames, *ifname;
130	int i;
131
132	/*
133	  * In case of URE mode, wl0.1 and wl0 have same mac,
134	  * we need extra identity (name).
135	  */
136	if (name && !strncmp(name, "wl", 2))
137		snprintf(nv_name, sizeof(nv_name), "%s", name);
138	else if (get_wlname_by_mac(mac, nv_name))
139		return 0;
140
141	if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0)
142		return 0;
143
144	if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0)
145		return 0;
146
147	/* find for dpsta */
148	if (wl_wlif_is_psta(os_name))
149		return name;
150
151	ifnames = nvram_get("dpsta_ifnames");
152	if (ifnames && (find_in_list(ifnames, nv_name) || find_in_list(ifnames, os_name))) {
153		/* find dpsta in which bridge */
154		for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
155			sprintf(tmptr, "br%d_ifnames", i);
156			sprintf(if_name, "br%d", i);
157			ifnames = nvram_get(tmptr);
158			ifname = if_name;
159
160			if (ifnames) {
161				/* the name in ifnames may nvifname or osifname */
162				if (find_in_list(ifnames, nv_name) ||
163					find_in_list(ifnames, os_name))
164					return ifname;
165			}
166		}
167	}
168
169	/* find for lan */
170	for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
171		if (i == 0) {
172			ifnames = nvram_get("lan_ifnames");
173			ifname = nvram_get("lan_ifname");
174			if (ifname) {
175				/* the name in ifnames may nvifname or osifname */
176				if (find_in_list(ifnames, nv_name) ||
177				    find_in_list(ifnames, os_name))
178					return ifname;
179			}
180		}
181		else {
182			sprintf(if_name, "lan%d_ifnames", i);
183			sprintf(tmptr, "lan%d_ifname", i);
184			ifnames = nvram_get(if_name);
185			ifname = nvram_get(tmptr);
186			if (ifname) {
187				/* the name in ifnames may nvifname or osifname */
188				if (find_in_list(ifnames, nv_name) ||
189				    find_in_list(ifnames, os_name))
190					return ifname;
191			}
192		}
193	}
194
195	/* find for wan  */
196	ifnames = nvram_get("wan_ifnames");
197	ifname = nvram_get("wan0_ifname");
198	/* the name in ifnames may nvifname or osifname */
199	if (find_in_list(ifnames, nv_name) ||
200	    find_in_list(ifnames, os_name))
201		return ifname;
202
203	return 0;
204}
205
206#define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \
207				   WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK))
208#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
209#define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \
210				      WPA2_AUTH_UNSPECIFIED))
211
212/* Get wireless security setting by interface name */
213int
214get_wsec(wsec_info_t *info, unsigned char *mac, char *osifname)
215{
216	int i, unit, wds = 0, wds_wsec = 0;
217	char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8];
218	char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16],
219	        remote[ETHER_ADDR_LEN];
220	char akm[16], *akms, *akmnext, *value, *infra;
221
222	if (info == NULL || mac == NULL)
223		return WLIFU_ERR_INVALID_PARAMETER;
224
225	if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) {
226		if (get_wlname_by_mac(mac, nv_name))
227			return WLIFU_ERR_INVALID_PARAMETER;
228		else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)))
229			return WLIFU_ERR_INVALID_PARAMETER;
230	}
231	else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)))
232			return WLIFU_ERR_INVALID_PARAMETER;
233
234	/* check if i/f exists and retrieve the i/f index */
235	if (wl_probe(os_name) ||
236		wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
237		return WLIFU_ERR_NOT_WL_INTERFACE;
238
239	/* get wl_prefix.
240	 *
241	 * Due to DWDS and WDS may be enabled at the same time,
242	 * checking whether this is WDS interface in order to
243	 * get per WDS interface security settings from NVRAM.
244	 */
245	if (strstr(os_name, "wds") && (wl_wlif_is_dwds(os_name) == FALSE)) {
246		/* the wireless interface must be configured to run NAS */
247		snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
248		wds = 1;
249	}
250	else if (wl_wlif_is_psta(os_name))
251		snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
252	else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix)))
253		return WLIFU_ERR_INVALID_PARAMETER;
254
255	strcat(wl_prefix, "_");
256	memset(info, 0, sizeof(wsec_info_t));
257
258	/* get wds setting */
259	if (wds) {
260		/* remote address */
261		if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN))
262			return WLIFU_ERR_WL_REMOTE_HWADDR;
263		memcpy(info->remote, remote, ETHER_ADDR_LEN);
264
265		/* get per wds settings */
266		for (i = 0; i < MAX_NVPARSE; i ++) {
267			char macaddr[18];
268			uint8 ea[ETHER_ADDR_LEN];
269
270			if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid,
271			                 wds_psk) &&
272			    ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) ||
273			     ((mac[0] == '*') && (mac[1] == '\0')))) {
274			     /* found wds settings */
275			     wds_wsec = 1;
276			     break;
277			}
278		}
279	}
280
281	/* interface unit */
282	info->unit = unit;
283	/* interface os name */
284	strcpy(info->osifname, os_name);
285	/* interface address */
286	memcpy(info->ea, mac, ETHER_ADDR_LEN);
287	/* ssid */
288	if (wds && wds_wsec)
289		strncpy(info->ssid, wds_ssid, MAX_SSID_LEN);
290	else {
291		value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb));
292		strncpy(info->ssid, value, MAX_SSID_LEN);
293	}
294	/* auth */
295	if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1"))
296		info->auth = 1;
297	/* nas auth mode */
298	value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb));
299	info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0;
300	if (wds && wds_wsec)
301		akms = wds_akms;
302	else
303		akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb));
304	foreach(akm, akms, akmnext) {
305		if (!strcmp(akm, "wpa"))
306			info->akm |= WPA_AUTH_UNSPECIFIED;
307		if (!strcmp(akm, "psk"))
308			info->akm |= WPA_AUTH_PSK;
309		if (!strcmp(akm, "wpa2"))
310			info->akm |= WPA2_AUTH_UNSPECIFIED;
311		if (!strcmp(akm, "psk2"))
312			info->akm |= WPA2_AUTH_PSK;
313	}
314	/* wsec encryption */
315	value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb));
316	info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0;
317	if (wds && wds_wsec)
318		value = wds_crypto;
319	else
320		value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb));
321	if (CHECK_NAS(info->akm)) {
322		if (!strcmp(value, "tkip"))
323			info->wsec |= TKIP_ENABLED;
324		else if (!strcmp(value, "aes"))
325			info->wsec |= AES_ENABLED;
326		else if (!strcmp(value, "tkip+aes"))
327			info->wsec |= TKIP_ENABLED|AES_ENABLED;
328	}
329	/* nas role setting, may overwrite later in wds case */
330	value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
331	infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb));
332	if (!strcmp(value, "ap")) {
333		info->flags |= WLIFU_WSEC_AUTH;
334	}
335	else if (!strcmp(value, "sta") || !strcmp(value, "wet") ||
336	         !strcmp(value, "psr") || !strcmp(value, "psta")) {
337		if (!strcmp(infra, "0")) {
338			/* IBSS, so we must act as Authenticator and Supplicant */
339			info->flags |= WLIFU_WSEC_AUTH;
340			info->flags |= WLIFU_WSEC_SUPPL;
341			/* Adhoc Mode */
342			info->ibss = TRUE;
343		}
344		else {
345			info->flags |= WLIFU_WSEC_SUPPL;
346		}
347	}
348	else if (!strcmp(value, "wds")) {
349		;
350	}
351	else {
352		/* Unsupported network mode */
353		return WLIFU_ERR_NOT_SUPPORT_MODE;
354	}
355	/* overwrite flags */
356	if (wds) {
357		char buf[32];
358		unsigned char *ptr, lrole;
359
360		/* did not find WDS link configuration, use wireless' */
361		if (!wds_wsec)
362			strcpy(wds_role, "auto");
363
364		/* get right role */
365		if (!strcmp(wds_role, "sup"))
366			lrole = WL_WDS_WPA_ROLE_SUP;
367		else if (!strcmp(wds_role, "auth"))
368			lrole = WL_WDS_WPA_ROLE_AUTH;
369		else /* if (!strcmp(wds_role, "auto")) */
370			lrole = WL_WDS_WPA_ROLE_AUTO;
371
372		strcpy(buf, "wds_wpa_role");
373		ptr = (unsigned char *)buf + strlen(buf) + 1;
374		bcopy(info->remote, ptr, ETHER_ADDR_LEN);
375		ptr[ETHER_ADDR_LEN] = lrole;
376		if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf)))
377			return WLIFU_ERR_WL_WPA_ROLE;
378		else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf)))
379			return WLIFU_ERR_WL_WPA_ROLE;
380		lrole = *buf;
381
382		/* overwrite these flags */
383		info->flags = WLIFU_WSEC_WDS;
384		if (lrole == WL_WDS_WPA_ROLE_SUP) {
385			info->flags |= WLIFU_WSEC_SUPPL;
386		}
387		else if (lrole == WL_WDS_WPA_ROLE_AUTH) {
388			info->flags |= WLIFU_WSEC_AUTH;
389		}
390		else {
391			/* unable to determine WPA role */
392			return WLIFU_ERR_WL_WPA_ROLE;
393		}
394	}
395	/* user-supplied psk passphrase */
396	if (CHECK_PSK(info->akm)) {
397		if (wds && wds_wsec) {
398			strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN);
399			info->psk[MAX_USER_KEY_LEN] = 0;
400		}
401		else {
402			value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb));
403			strncpy((char *)info->psk, value, MAX_USER_KEY_LEN);
404			info->psk[MAX_USER_KEY_LEN] = 0;
405		}
406	}
407	/* user-supplied radius server secret */
408	if (CHECK_RADIUS(info->akm))
409		info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb));
410	/* AP specific settings */
411	value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
412	if (!strcmp(value, "ap")) {
413		/* gtk rekey interval */
414		if (CHECK_NAS(info->akm)) {
415			value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb));
416			info->gtk_rekey_secs = (int)strtoul(value, NULL, 0);
417		}
418		/* wep key */
419		if (info->wsec & WEP_ENABLED) {
420			/* key index */
421			value = nvram_safe_get(strcat_r(wl_prefix, "key", comb));
422			info->wep_index = (int)strtoul(value, NULL, 0);
423			/* key */
424			sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb)));
425			info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb));
426		}
427		/* radius server host/port */
428		if (CHECK_RADIUS(info->akm)) {
429			/* update radius server address */
430			info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr",
431			                                            comb));
432			value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb));
433			info->radius_port = htons((int)strtoul(value, NULL, 0));
434			/* 802.1x session timeout/pmk cache duration */
435			value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb));
436			info->ssn_to = (int)strtoul(value, NULL, 0);
437		}
438	}
439	/* preauth */
440	value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb));
441	info->preauth = (int)strtoul(value, NULL, 0);
442
443	/* verbose */
444	value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb));
445	info->debug = (int)strtoul(value, NULL, 0);
446
447
448
449	return WLIFU_WSEC_SUCCESS;
450}
451