1/*
2 * Wireless interface translation utility functions
3 *
4 * Copyright (C) 2012, 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 415105 2013-07-28 03:40:28Z $
19 */
20
21#include <typedefs.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <stdarg.h>	// for va_list
26
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <arpa/inet.h>
30
31#include <bcmparams.h>
32#include <bcmnvram.h>
33#include <bcmutils.h>
34#include <netconf.h>
35#include <nvparse.h>
36#include <shutils.h>
37#include <wlutils.h>
38#include <wlif_utils.h>
39
40#include "shared.h"
41
42#ifndef MAX_NVPARSE
43#define MAX_NVPARSE 16
44#endif
45
46/* wireless interface name descriptors */
47typedef struct _wlif_name_desc {
48	char		*name;		/* wlif name */
49	bool		wds;		/* wds interface */
50	bool		subunit;		/* subunit existance */
51} wlif_name_desc_t;
52
53wlif_name_desc_t wlif_name_array[] = {
54/*	  name	wds		subunit */
55/* PARIMARY */
56#if defined(linux)
57	{ "eth",	0,		0}, /* primary */
58#else
59	{ "wl",	0,		0}, /* primary */
60#endif
61
62/* MBSS */
63	{ "wl",	0,		1}, /* mbss */
64
65/* WDS */
66	{ "wds",	1,		1} /* wds */
67};
68
69/*
70 * Translate virtual interface mac to spoof mac
71 * Rule:
72 *		00:aa:bb:cc:dd:ee                                              00:00:00:x:y:z
73 *		wl0 ------------ [wlx/wlx.y/wdsx.y]0.1 ------ x=1/2/3, y=0, z=1
74 *		     +----------- [wlx/wlx.y/wdsx.y]0.2 ------ x=1/2/3, y=0, z=2
75 *		wl1 ------------ [wlx/wlx.y/wdsx.y]1.1 ------ x=1/2/3, y=1, z=1
76 *		     +----------- [wlx/wlx.y/wdsx.y]1.2 ------ x=1/2/3, y=1, z=2
77 *
78 *		URE ON	: wds/mbss not support and wlx.y have same mac as wlx
79 *		URE OFF	: wlx.y have unique mac and wdsx.y have same mac as wlx
80 *
81 */
82int
83get_spoof_mac(const char *osifname, char *mac, int maclen)
84{
85	char nvifname[16];
86	int i, unit, subunit;
87	wlif_name_desc_t *wlif_name;
88
89	if (osifname == NULL ||
90		mac == NULL ||
91		maclen < ETHER_ADDR_LEN)
92		return -1;
93	if (osifname_to_nvifname(osifname, nvifname, sizeof(nvifname)) < 0)
94		return -1;
95
96	/* translate to spoof mac */
97	if (!get_ifname_unit(nvifname, &unit, &subunit)) {
98		memset(mac, 0, maclen);
99		for (i = 0; i < ARRAYSIZE(wlif_name_array); i++) {
100			wlif_name = &wlif_name_array[i];
101			if (!strncmp(osifname, wlif_name->name, strlen(wlif_name->name))) {
102				if (subunit >= 0 && wlif_name->subunit)
103					break;
104				else if (subunit < 0 && !wlif_name->subunit) {
105					subunit = 0; /* reset to zero */
106					break;
107				}
108			}
109		}
110
111		/* not found */
112		if (i == ARRAYSIZE(wlif_name_array))
113			return -1;
114
115		/* translate it */
116		mac[3] = i+1;
117		mac[4] = unit;
118		mac[5] = subunit;
119
120		return 0;
121	}
122
123	return -1;
124}
125
126int
127get_spoof_ifname(char *mac, char *osifname, int osifnamelen)
128{
129	int idx, unit, subunit;
130	char nvifname[16];
131	wlif_name_desc_t *wlif_name;
132
133	if (osifname == NULL ||
134		mac == NULL)
135		return -1;
136
137	if (mac[0] != 0 || mac[1] != 0 ||
138		mac[2] != 0)
139		return -1; /* is a real mac, fast check */
140
141	idx = mac[3];
142	idx --; /* map to wlif_name_array index */
143	unit = mac[4];
144	subunit = mac[5];
145	if (idx < 0 || idx >= ARRAYSIZE(wlif_name_array))
146		return -1;
147
148	/* get nvname format */
149	wlif_name = &wlif_name_array[idx];
150	if (wlif_name->subunit)
151		snprintf(nvifname, sizeof(nvifname), "%s%d.%d", (wlif_name->wds) ? "wds" : "wl",
152		              unit, subunit);
153	else
154		snprintf(nvifname, sizeof(nvifname), "wl%d", unit);
155
156	/* translate to osifname */
157	if (nvifname_to_osifname(nvifname, osifname, osifnamelen) < 0)
158		return -1;
159
160	return 0;
161}
162
163int
164get_real_mac(char *mac, int maclen)
165{
166	int idx, unit, subunit;
167	char *ptr, ifname[32];
168	wlif_name_desc_t *wlif_name;
169
170	if (mac == NULL ||
171	    maclen < ETHER_ADDR_LEN)
172		return -1;
173
174	if (mac[0] != 0 || mac[1] != 0 ||
175		mac[2] != 0)
176		return 0; /* is a real mac, fast path */
177
178	idx = mac[3];
179	idx --; /* map to wlif_name_array index */
180	unit = mac[4];
181	subunit = mac[5];
182	if (idx < 0 || idx >= ARRAYSIZE(wlif_name_array))
183		return -1;
184
185	/* get wlx.y mac addr */
186	wlif_name = &wlif_name_array[idx];
187	if (wlif_name->subunit && !wlif_name->wds)
188		snprintf(ifname, sizeof(ifname), "wl%d.%d_hwaddr", unit, subunit);
189	else
190		snprintf(ifname, sizeof(ifname), "wl%d_hwaddr", unit);
191
192	ptr = nvram_get(ifname);
193	if (ptr == NULL)
194		return -1;
195
196	ether_atoe(ptr, (unsigned char *) mac);
197	return 0;
198}
199
200unsigned char *
201get_wlmacstr_by_unit(char *unit)
202{
203	char tmptr[] = "wlXXXXX_hwaddr";
204	char *macaddr;
205
206	sprintf(tmptr, "wl%s_hwaddr", unit);
207
208	macaddr = nvram_get(tmptr);
209
210	if (!macaddr)
211		return NULL;
212
213	return (unsigned char *) macaddr;
214}
215
216int
217get_lan_mac(unsigned char *mac)
218{
219	char *lanmac_str = nvram_get("lan_hwaddr");
220
221	if (mac)
222		memset(mac, 0, 6);
223
224	if (!lanmac_str || mac == NULL)
225		return -1;
226
227	ether_atoe(lanmac_str, mac);
228
229	return 0;
230}
231
232int
233get_wlname_by_mac(unsigned char *mac, char *wlname)
234{
235	char eabuf[18];
236	char tmptr[] = "wlXXXXX_hwaddr";
237	char *wl_hw;
238	int i, j;
239
240	ether_etoa(mac, eabuf);
241	/* find out the wl name from mac */
242	for (i = 0; i < MAX_NVPARSE; i++) {
243		sprintf(wlname, "wl%d", i);
244		sprintf(tmptr, "wl%d_hwaddr", i);
245		wl_hw = nvram_get(tmptr);
246		if (wl_hw) {
247			if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
248				return 0;
249		}
250
251		for (j = 1; j < WL_MAXBSSCFG; j++) {
252			sprintf(wlname, "wl%d.%d", i, j);
253			sprintf(tmptr, "wl%d.%d_hwaddr", i, j);
254			wl_hw = nvram_get(tmptr);
255			if (wl_hw) {
256				if (!strncasecmp(wl_hw, eabuf, sizeof(eabuf)))
257					return 0;
258			}
259		}
260	}
261
262	return -1;
263}
264
265bool
266wl_wlif_is_psta(char *ifname)
267{
268	int32 psta = FALSE;
269
270	if (wl_probe(ifname) < 0)
271		return FALSE;
272
273	if (wl_iovar_getint(ifname, "psta_if", &psta) < 0)
274		return FALSE;
275
276	return psta ? TRUE : FALSE;
277}
278
279bool
280wl_wlif_is_dwds(char *ifname)
281{
282#ifdef RTCONFIG_BCMARM
283	int32 wds_type = FALSE;
284
285	if (wl_probe(ifname) < 0)
286		return FALSE;
287
288	return (!wl_iovar_getint(ifname, "wds_type", &wds_type) && wds_type == WL_WDSIFTYPE_DWDS);
289#else
290	return FALSE;
291#endif
292}
293
294/*
295 * Get LAN or WAN ifname by wl mac
296 * NOTE: We pass ifname in case of same mac in vifs (like URE TR mode)
297 */
298char *
299get_ifname_by_wlmac(unsigned char *mac, char *name)
300{
301	char nv_name[16], os_name[16], if_name[16];
302	char tmptr[] = "lanXX_ifnames";
303	char *ifnames, *ifname;
304	int i;
305
306	/*
307	  * In case of URE mode, wl0.1 and wl0 have same mac,
308	  * we need extra identity (name).
309	  */
310	if (name && !strncmp(name, "wl", 2))
311		snprintf(nv_name, sizeof(nv_name), "%s", name);
312	else if (get_wlname_by_mac(mac, nv_name))
313		return 0;
314
315	if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)) < 0)
316		return 0;
317
318	if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)) < 0)
319		return 0;
320
321	/* find for lan */
322	for (i = 0; i < WLIFU_MAX_NO_BRIDGE; i++) {
323		if (i == 0) {
324			ifnames = nvram_get("lan_ifnames");
325			ifname = nvram_get("lan_ifname");
326			if (ifname) {
327				/* the name in ifnames may nvifname or osifname */
328				if (find_in_list(ifnames, nv_name) ||
329				    find_in_list(ifnames, os_name))
330					return ifname;
331			}
332		}
333		else {
334			sprintf(if_name, "lan%d_ifnames", i);
335			sprintf(tmptr, "lan%d_ifname", i);
336			ifnames = nvram_get(if_name);
337			ifname = nvram_get(tmptr);
338			if (ifname) {
339				/* the name in ifnames may nvifname or osifname */
340				if (find_in_list(ifnames, nv_name) ||
341				    find_in_list(ifnames, os_name))
342					return ifname;
343			}
344		}
345	}
346
347	/* find for wan  */
348	ifnames = nvram_get("wan_ifnames");
349	ifname = nvram_get("wan0_ifname");
350	/* the name in ifnames may nvifname or osifname */
351	if (find_in_list(ifnames, nv_name) ||
352	    find_in_list(ifnames, os_name))
353		return ifname;
354
355	return 0;
356}
357
358#define CHECK_NAS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WPA_AUTH_PSK | \
359				   WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_PSK))
360#define CHECK_PSK(mode) ((mode) & (WPA_AUTH_PSK | WPA2_AUTH_PSK))
361#define CHECK_RADIUS(mode) ((mode) & (WPA_AUTH_UNSPECIFIED | WLIFU_AUTH_RADIUS | \
362				      WPA2_AUTH_UNSPECIFIED))
363
364/* Get wireless security setting by interface name */
365int
366get_wsec(wsec_info_t *info, unsigned char *mac, char *osifname)
367{
368	int i, unit, wds = 0, wds_wsec = 0;
369	char nv_name[16], os_name[16], wl_prefix[16], comb[32], key[8];
370	char wds_role[8], wds_ssid[48], wds_psk[80], wds_akms[16], wds_crypto[16],
371	        remote[ETHER_ADDR_LEN];
372	char akm[16], *akms, *akmnext, *value, *infra;
373
374	if (info == NULL || mac == NULL)
375		return WLIFU_ERR_INVALID_PARAMETER;
376
377	if (nvifname_to_osifname(osifname, os_name, sizeof(os_name))) {
378		if (get_wlname_by_mac(mac, nv_name))
379			return WLIFU_ERR_INVALID_PARAMETER;
380		else if (nvifname_to_osifname(nv_name, os_name, sizeof(os_name)))
381			return WLIFU_ERR_INVALID_PARAMETER;
382	}
383	else if (osifname_to_nvifname(os_name, nv_name, sizeof(nv_name)))
384			return WLIFU_ERR_INVALID_PARAMETER;
385
386	/* check if i/f exists and retrieve the i/f index */
387	if (wl_probe(os_name) ||
388		wl_ioctl(os_name, WLC_GET_INSTANCE, &unit, sizeof(unit)))
389		return WLIFU_ERR_NOT_WL_INTERFACE;
390
391        /* get wl_prefix.
392	 *
393	 * Due to DWDS and WDS may be enabled at the same time,
394	 * checking whether this is WDS interface in order to
395	 * get per WDS interface security settings from NVRAM.
396	 */
397	if (strstr(os_name, "wds") && (wl_wlif_is_dwds(os_name) == FALSE)) {
398		/* the wireless interface must be configured to run NAS */
399		snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
400		wds = 1;
401	}
402	else if (wl_wlif_is_psta(os_name))
403		snprintf(wl_prefix, sizeof(wl_prefix), "wl%d", unit);
404	else if (osifname_to_nvifname(os_name, wl_prefix, sizeof(wl_prefix)))
405		return WLIFU_ERR_INVALID_PARAMETER;
406
407	strcat(wl_prefix, "_");
408	memset(info, 0, sizeof(wsec_info_t));
409
410
411	/* get wds setting */
412	if (wds) {
413		/* remote address */
414		if (wl_ioctl(os_name, WLC_WDS_GET_REMOTE_HWADDR, remote, ETHER_ADDR_LEN))
415			return WLIFU_ERR_WL_REMOTE_HWADDR;
416		memcpy(info->remote, remote, ETHER_ADDR_LEN);
417
418		/* get per wds settings */
419		for (i = 0; i < MAX_NVPARSE; i ++) {
420			char macaddr[18];
421			uint8 ea[ETHER_ADDR_LEN];
422
423			if (get_wds_wsec(unit, i, macaddr, wds_role, wds_crypto, wds_akms, wds_ssid,
424			                 wds_psk) &&
425			    ((ether_atoe(macaddr, ea) && !bcmp(ea, remote, ETHER_ADDR_LEN)) ||
426			     ((mac[0] == '*') && (mac[1] == '\0')))) {
427			     /* found wds settings */
428			     wds_wsec = 1;
429			     break;
430			}
431		}
432	}
433
434	/* interface unit */
435	info->unit = unit;
436	/* interface os name */
437	strcpy(info->osifname, os_name);
438	/* interface address */
439	memcpy(info->ea, mac, ETHER_ADDR_LEN);
440	/* ssid */
441	if (wds && wds_wsec)
442		strncpy(info->ssid, wds_ssid, MAX_SSID_LEN);
443	else {
444		value = nvram_safe_get(strcat_r(wl_prefix, "ssid", comb));
445		strncpy(info->ssid, value, MAX_SSID_LEN);
446	}
447	/* auth */
448	if (nvram_match(strcat_r(wl_prefix, "auth", comb), "1"))
449		info->auth = 1;
450	/* nas auth mode */
451	value = nvram_safe_get(strcat_r(wl_prefix, "auth_mode", comb));
452	info->akm = !strcmp(value, "radius") ? WLIFU_AUTH_RADIUS : 0;
453	if (wds && wds_wsec)
454		akms = wds_akms;
455	else
456		akms = nvram_safe_get(strcat_r(wl_prefix, "akm", comb));
457	foreach(akm, akms, akmnext) {
458		if (!strcmp(akm, "wpa"))
459			info->akm |= WPA_AUTH_UNSPECIFIED;
460		if (!strcmp(akm, "psk"))
461			info->akm |= WPA_AUTH_PSK;
462		if (!strcmp(akm, "wpa2"))
463			info->akm |= WPA2_AUTH_UNSPECIFIED;
464		if (!strcmp(akm, "psk2"))
465			info->akm |= WPA2_AUTH_PSK;
466	}
467	/* wsec encryption */
468	value = nvram_safe_get(strcat_r(wl_prefix, "wep", comb));
469	info->wsec = !strcmp(value, "enabled") ? WEP_ENABLED : 0;
470	if (wds && wds_wsec)
471		value = wds_crypto;
472	else
473		value = nvram_safe_get(strcat_r(wl_prefix, "crypto", comb));
474	if (CHECK_NAS(info->akm)) {
475		if (!strcmp(value, "tkip"))
476			info->wsec |= TKIP_ENABLED;
477		else if (!strcmp(value, "aes"))
478			info->wsec |= AES_ENABLED;
479		else if (!strcmp(value, "tkip+aes"))
480			info->wsec |= TKIP_ENABLED|AES_ENABLED;
481	}
482	/* nas role setting, may overwrite later in wds case */
483	value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
484	infra = nvram_safe_get(strcat_r(wl_prefix, "infra", comb));
485	if (!strcmp(value, "ap")) {
486		info->flags |= WLIFU_WSEC_AUTH;
487	}
488	else if (!strcmp(value, "sta") || !strcmp(value, "wet") ||
489	         !strcmp(value, "psr") || !strcmp(value, "psta")) {
490		if (!strcmp(infra, "0")) {
491			/* IBSS, so we must act as Authenticator and Supplicant */
492			info->flags |= WLIFU_WSEC_AUTH;
493			info->flags |= WLIFU_WSEC_SUPPL;
494			/* Adhoc Mode */
495			info->ibss = TRUE;
496		}
497		else {
498			info->flags |= WLIFU_WSEC_SUPPL;
499		}
500	}
501	else if (!strcmp(value, "wds")) {
502		;
503	}
504	else {
505		/* Unsupported network mode */
506		return WLIFU_ERR_NOT_SUPPORT_MODE;
507	}
508	/* overwrite flags */
509	if (wds) {
510		char buf[32];
511		unsigned char *ptr, lrole;
512
513		/* did not find WDS link configuration, use wireless' */
514		if (!wds_wsec)
515			strcpy(wds_role, "auto");
516
517		/* get right role */
518		if (!strcmp(wds_role, "sup"))
519			lrole = WL_WDS_WPA_ROLE_SUP;
520		else if (!strcmp(wds_role, "auth"))
521			lrole = WL_WDS_WPA_ROLE_AUTH;
522		else /* if (!strcmp(wds_role, "auto")) */
523			lrole = WL_WDS_WPA_ROLE_AUTO;
524
525		strcpy(buf, "wds_wpa_role");
526		ptr = (unsigned char *)buf + strlen(buf) + 1;
527		bcopy(info->remote, ptr, ETHER_ADDR_LEN);
528		ptr[ETHER_ADDR_LEN] = lrole;
529		if (wl_ioctl(os_name, WLC_SET_VAR, buf, sizeof(buf)))
530			return WLIFU_ERR_WL_WPA_ROLE;
531		else if (wl_ioctl(os_name, WLC_GET_VAR, buf, sizeof(buf)))
532			return WLIFU_ERR_WL_WPA_ROLE;
533		lrole = *buf;
534
535		/* overwrite these flags */
536		info->flags = WLIFU_WSEC_WDS;
537		if (lrole == WL_WDS_WPA_ROLE_SUP) {
538			info->flags |= WLIFU_WSEC_SUPPL;
539		}
540		else if (lrole == WL_WDS_WPA_ROLE_AUTH) {
541			info->flags |= WLIFU_WSEC_AUTH;
542		}
543		else {
544			/* unable to determine WPA role */
545			return WLIFU_ERR_WL_WPA_ROLE;
546		}
547	}
548	/* user-supplied psk passphrase */
549	if (CHECK_PSK(info->akm)) {
550		if (wds && wds_wsec) {
551			strncpy((char *)info->psk, wds_psk, MAX_USER_KEY_LEN);
552			info->psk[MAX_USER_KEY_LEN] = 0;
553		}
554		else {
555			value = nvram_safe_get(strcat_r(wl_prefix, "wpa_psk", comb));
556			strncpy((char *)info->psk, value, MAX_USER_KEY_LEN);
557			info->psk[MAX_USER_KEY_LEN] = 0;
558		}
559	}
560	/* user-supplied radius server secret */
561	if (CHECK_RADIUS(info->akm))
562		info->secret = nvram_safe_get(strcat_r(wl_prefix, "radius_key", comb));
563	/* AP specific settings */
564	value = nvram_safe_get(strcat_r(wl_prefix, "mode", comb));
565	if (!strcmp(value, "ap")) {
566		/* gtk rekey interval */
567		if (CHECK_NAS(info->akm)) {
568			value = nvram_safe_get(strcat_r(wl_prefix, "wpa_gtk_rekey", comb));
569			info->gtk_rekey_secs = (int)strtoul(value, NULL, 0);
570		}
571		/* wep key */
572		if (info->wsec & WEP_ENABLED) {
573			/* key index */
574			value = nvram_safe_get(strcat_r(wl_prefix, "key", comb));
575			info->wep_index = (int)strtoul(value, NULL, 0);
576			/* key */
577			sprintf(key, "key%s", nvram_safe_get(strcat_r(wl_prefix, "key", comb)));
578			info->wep_key = nvram_safe_get(strcat_r(wl_prefix, key, comb));
579		}
580		/* radius server host/port */
581		if (CHECK_RADIUS(info->akm)) {
582			/* update radius server address */
583			info->radius_addr = nvram_safe_get(strcat_r(wl_prefix, "radius_ipaddr",
584			                                            comb));
585			value = nvram_safe_get(strcat_r(wl_prefix, "radius_port", comb));
586			info->radius_port = htons((int)strtoul(value, NULL, 0));
587			/* 802.1x session timeout/pmk cache duration */
588			value = nvram_safe_get(strcat_r(wl_prefix, "net_reauth", comb));
589			info->ssn_to = (int)strtoul(value, NULL, 0);
590		}
591	}
592	/* preauth */
593	value = nvram_safe_get(strcat_r(wl_prefix, "preauth", comb));
594	info->preauth = (int)strtoul(value, NULL, 0);
595
596	/* verbose */
597	value = nvram_safe_get(strcat_r(wl_prefix, "nas_dbg", comb));
598	info->debug = (int)strtoul(value, NULL, 0);
599
600	/* get mfp setting */
601	info->mfp = atoi(nvram_safe_get(strcat_r(wl_prefix, "mfp", comb)));
602
603	return WLIFU_WSEC_SUCCESS;
604}
605