• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 
3 #include <linux/module.h>
4 #include <linux/netdevice.h>
5 #include <net/netlink.h>
6 #include <typedefs.h>
7 #include <linuxver.h>
8 #include <osl.h>
9 
10 #include <bcmutils.h>
11 #include <bcmendian.h>
12 #include <ethernet.h>
13 
14 #include <wl_android.h>
15 #include <linux/if_arp.h>
16 #include <linux/uaccess.h>
17 #include <linux/wireless.h>
18 #if defined(WL_WIRELESS_EXT)
19 #include <wl_iw.h>
20 #endif /* WL_WIRELESS_EXT */
21 #include <wldev_common.h>
22 #include <wlioctl.h>
23 #include <bcmutils.h>
24 #include <linux_osl.h>
25 #include <dhd_dbg.h>
26 #include <dngl_stats.h>
27 #include <dhd.h>
28 #include <dhd_config.h>
29 #ifdef WL_CFG80211
30 #include <wl_cfg80211.h>
31 #endif /* WL_CFG80211 */
32 #ifdef WL_ESCAN
33 #include <wl_escan.h>
34 #endif /* WL_ESCAN */
35 
36 #define AEXT_ERROR(name, arg1, args...) \
37 	do { \
38 		if (android_msg_level & ANDROID_ERROR_LEVEL) { \
39 			printk(KERN_ERR DHD_LOG_PREFIX "[%s] AEXT-ERROR) %s : " arg1, name, __func__, ## args); \
40 		} \
41 	} while (0)
42 #define AEXT_TRACE(name, arg1, args...) \
43 	do { \
44 		if (android_msg_level & ANDROID_TRACE_LEVEL) { \
45 			printk(KERN_INFO DHD_LOG_PREFIX "[%s] AEXT-TRACE) %s : " arg1, name, __func__, ## args); \
46 		} \
47 	} while (0)
48 #define AEXT_INFO(name, arg1, args...) \
49 	do { \
50 		if (android_msg_level & ANDROID_INFO_LEVEL) { \
51 			printk(KERN_INFO DHD_LOG_PREFIX "[%s] AEXT-INFO) %s : " arg1, name, __func__, ## args); \
52 		} \
53 	} while (0)
54 #define AEXT_DBG(name, arg1, args...) \
55 	do { \
56 		if (android_msg_level & ANDROID_DBG_LEVEL) { \
57 			printk(KERN_INFO DHD_LOG_PREFIX "[%s] AEXT-DBG) %s : " arg1, name, __func__, ## args); \
58 		} \
59 	} while (0)
60 
61 #ifndef WL_CFG80211
62 #define htod32(i) i
63 #define htod16(i) i
64 #define dtoh32(i) i
65 #define dtoh16(i) i
66 #define htodchanspec(i) i
67 #define dtohchanspec(i) i
68 #define IEEE80211_BAND_2GHZ 0
69 #define IEEE80211_BAND_5GHZ 1
70 #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 		20
71 #define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 	320
72 #define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 	400
73 #endif /* WL_CFG80211 */
74 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
75 
76 #ifndef IW_CUSTOM_MAX
77 #define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */
78 #endif /* IW_CUSTOM_MAX */
79 
80 #define CMD_CHANNEL				"CHANNEL"
81 #define CMD_CHANNELS			"CHANNELS"
82 #define CMD_ROAM_TRIGGER		"ROAM_TRIGGER"
83 #define CMD_PM					"PM"
84 #define CMD_MONITOR				"MONITOR"
85 #define CMD_SET_SUSPEND_BCN_LI_DTIM		"SET_SUSPEND_BCN_LI_DTIM"
86 #define CMD_WLMSGLEVEL			"WLMSGLEVEL"
87 
88 #ifdef WLEASYMESH
89 #define CMD_EASYMESH "EASYMESH"
90 #endif /* WLEASYMESH */
91 
92 #ifdef WL_EXT_IAPSTA
93 #include <net/rtnetlink.h>
94 #define CMD_IAPSTA_INIT			"IAPSTA_INIT"
95 #define CMD_IAPSTA_CONFIG		"IAPSTA_CONFIG"
96 #define CMD_IAPSTA_ENABLE		"IAPSTA_ENABLE"
97 #define CMD_IAPSTA_DISABLE		"IAPSTA_DISABLE"
98 #define CMD_ISAM_INIT			"ISAM_INIT"
99 #define CMD_ISAM_CONFIG			"ISAM_CONFIG"
100 #define CMD_ISAM_ENABLE			"ISAM_ENABLE"
101 #define CMD_ISAM_DISABLE		"ISAM_DISABLE"
102 #define CMD_ISAM_STATUS			"ISAM_STATUS"
103 #define CMD_ISAM_PEER_PATH		"ISAM_PEER_PATH"
104 #define CMD_ISAM_PARAM			"ISAM_PARAM"
105 #ifdef PROP_TXSTATUS
106 #include <dhd_wlfc.h>
107 #ifdef PROP_TXSTATUS_VSDB
108 extern int disable_proptx;
109 #endif /* PROP_TXSTATUS_VSDB */
110 #endif /* PROP_TXSTATUS */
111 #endif /* WL_EXT_IAPSTA */
112 #define CMD_AUTOCHANNEL		"AUTOCHANNEL"
113 #define CMD_WL		"WL"
114 
115 #ifdef WL_EXT_IAPSTA
116 typedef enum APSTAMODE {
117 	IUNKNOWN_MODE = 0,
118 	ISTAONLY_MODE = 1,
119 	IAPONLY_MODE = 2,
120 	ISTAAP_MODE = 3,
121 	ISTAGO_MODE = 4,
122 	ISTASTA_MODE = 5,
123 	IDUALAP_MODE = 6,
124 	ISTAAPAP_MODE = 7,
125 	IMESHONLY_MODE = 8,
126 	ISTAMESH_MODE = 9,
127 	IMESHAP_MODE = 10,
128 	ISTAAPMESH_MODE = 11,
129 	IMESHAPAP_MODE = 12
130 } apstamode_t;
131 
132 typedef enum IFMODE {
133 	ISTA_MODE = 1,
134 	IAP_MODE,
135 	IGO_MODE,
136 	IGC_MODE,
137 	IMESH_MODE
138 } ifmode_t;
139 
140 typedef enum BGNMODE {
141 	IEEE80211B = 1,
142 	IEEE80211G,
143 	IEEE80211BG,
144 	IEEE80211BGN,
145 	IEEE80211BGNAC
146 } bgnmode_t;
147 
148 typedef enum AUTHMODE {
149 	AUTH_OPEN,
150 	AUTH_SHARED,
151 	AUTH_WPAPSK,
152 	AUTH_WPA2PSK,
153 	AUTH_WPAWPA2PSK,
154 	AUTH_SAE
155 } authmode_t;
156 
157 typedef enum ENCMODE {
158 	ENC_NONE,
159 	ENC_WEP,
160 	ENC_TKIP,
161 	ENC_AES,
162 	ENC_TKIPAES
163 } encmode_t;
164 
165 enum wl_if_list {
166 	IF_PIF,
167 	IF_VIF,
168 	IF_VIF2,
169 	MAX_IF_NUM
170 };
171 
172 typedef enum WL_PRIO {
173 	PRIO_AP,
174 	PRIO_MESH,
175 	PRIO_STA
176 } wl_prio_t;
177 
178 typedef struct wl_if_info {
179 	struct net_device *dev;
180 	ifmode_t ifmode;
181 	unsigned long status;
182 	char prefix;
183 	wl_prio_t prio;
184 	int ifidx;
185 	uint8 bssidx;
186 	char ifname[IFNAMSIZ+1];
187 	char ssid[DOT11_MAX_SSID_LEN];
188 	struct ether_addr bssid;
189 	bgnmode_t bgnmode;
190 	int hidden;
191 	int maxassoc;
192 	uint16 channel;
193 	authmode_t amode;
194 	encmode_t emode;
195 	char key[100];
196 #if defined(WLMESH) && defined(WL_ESCAN)
197 	struct wl_escan_info *escan;
198 	timer_list_compat_t delay_scan;
199 #endif /* WLMESH && WL_ESCAN */
200 	struct delayed_work pm_enable_work;
201 	struct mutex pm_sync;
202 #ifdef PROPTX_MAXCOUNT
203 	int transit_maxcount;
204 #endif /* PROPTX_MAXCOUNT */
205 	uint eapol_status;
206 	uint16 prev_channel;
207 	uint16 post_channel;
208 } wl_if_info_t;
209 
210 #define CSA_FW_BIT		(1<<0)
211 #define CSA_DRV_BIT		(1<<1)
212 
213 typedef struct wl_apsta_params {
214 	struct wl_if_info if_info[MAX_IF_NUM];
215 	struct dhd_pub *dhd;
216 	int ioctl_ver;
217 	bool init;
218 	int rsdb;
219 	bool vsdb;
220 	uint csa;
221 	uint acs;
222 	bool radar;
223 	apstamode_t apstamode;
224 	wait_queue_head_t netif_change_event;
225 	struct mutex usr_sync;
226 #if defined(WLMESH) && defined(WL_ESCAN)
227 	int macs;
228 	struct wl_mesh_params mesh_info;
229 #endif /* WLMESH && WL_ESCAN */
230 	struct mutex in4way_sync;
231 	uint sta_handshaking;
232 	int sta_btc_mode;
233 	struct osl_timespec sta_disc_ts;
234 	bool ap_recon_sta;
235 	wait_queue_head_t ap_recon_sta_event;
236 	struct ether_addr ap_disc_sta_bssid;
237 	struct osl_timespec ap_disc_sta_ts;
238 } wl_apsta_params_t;
239 
240 #define MAX_AP_LINK_WAIT_TIME   3000
241 #define MAX_STA_LINK_WAIT_TIME   15000
242 enum wifi_isam_status {
243 	ISAM_STATUS_IF_ADDING = 0,
244 	ISAM_STATUS_IF_READY,
245 	ISAM_STATUS_STA_CONNECTING,
246 	ISAM_STATUS_STA_CONNECTED,
247 	ISAM_STATUS_AP_CREATING,
248 	ISAM_STATUS_AP_CREATED
249 };
250 
251 #define wl_get_isam_status(cur_if, stat) \
252 	(test_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
253 #define wl_set_isam_status(cur_if, stat) \
254 	(set_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
255 #define wl_clr_isam_status(cur_if, stat) \
256 	(clear_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
257 #define wl_chg_isam_status(cur_if, stat) \
258 	(change_bit(ISAM_STATUS_ ## stat, &(cur_if)->status))
259 
260 static int wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up);
261 static int wl_ext_disable_iface(struct net_device *dev, char *ifname);
262 #if defined(WLMESH) && defined(WL_ESCAN)
263 static int wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *cur_if);
264 #endif /* WLMESH && WL_ESCAN */
265 void wl_ext_add_remove_pm_enable_work(struct net_device *dev, bool add);
266 #endif /* WL_EXT_IAPSTA */
267 
268 #ifdef IDHCP
269 typedef struct dhcpc_parameter {
270 	uint32 ip_addr;
271 	uint32 ip_serv;
272 	uint32 lease_time;
273 } dhcpc_para_t;
274 #endif /* IDHCP */
275 
276 #ifdef WL_EXT_WOWL
277 #define WL_WOWL_TCPFIN	(1 << 26)
278 typedef struct wl_wowl_pattern2 {
279 	char cmd[4];
280 	wl_wowl_pattern_t wowl_pattern;
281 } wl_wowl_pattern2_t;
282 #endif /* WL_EXT_WOWL */
283 
284 #ifdef WL_EXT_TCPKA
285 typedef struct tcpka_conn {
286 	uint32 sess_id;
287 	struct ether_addr dst_mac;	/* Destinition Mac */
288 	struct ipv4_addr  src_ip;	/* Sorce IP */
289 	struct ipv4_addr  dst_ip;	/* Destinition IP */
290 	uint16 ipid;	/* Ip Identification */
291 	uint16 srcport;	/* Source Port Address */
292 	uint16 dstport;	/* Destination Port Address */
293 	uint32 seq;		/* TCP Sequence Number */
294 	uint32 ack;		/* TCP Ack Number */
295 	uint16 tcpwin;	/* TCP window */
296 	uint32 tsval;	/* Timestamp Value */
297 	uint32 tsecr;	/* Timestamp Echo Reply */
298 	uint32 len;		/* last packet payload len */
299 	uint32 ka_payload_len;	/* keep alive payload length */
300 	uint8  ka_payload[1];	/* keep alive payload */
301 } tcpka_conn_t;
302 
303 typedef struct tcpka_conn_sess {
304 	uint32 sess_id;	/* session id */
305 	uint32 flag;	/* enable/disable flag */
306 	wl_mtcpkeep_alive_timers_pkt_t  tcpka_timers;
307 } tcpka_conn_sess_t;
308 
309 typedef struct tcpka_conn_info {
310 	uint32 ipid;
311 	uint32 seq;
312 	uint32 ack;
313 } tcpka_conn_sess_info_t;
314 #endif /* WL_EXT_TCPKA */
315 
316 static int wl_ext_wl_iovar(struct net_device *dev, char *command, int total_len);
317 
318 static int
wl_ext_ioctl(struct net_device * dev,u32 cmd,void * arg,u32 len,u32 set)319 wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
320 {
321 	int ret;
322 
323 	ret = wldev_ioctl(dev, cmd, arg, len, set);
324 	if (ret)
325 		AEXT_ERROR(dev->name, "cmd=%d, ret=%d\n", cmd, ret);
326 	return ret;
327 }
328 
329 static int
wl_ext_iovar_getint(struct net_device * dev,s8 * iovar,s32 * val)330 wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val)
331 {
332 	int ret;
333 
334 	ret = wldev_iovar_getint(dev, iovar, val);
335 	if (ret)
336 		AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar, ret);
337 
338 	return ret;
339 }
340 
341 static int
wl_ext_iovar_setint(struct net_device * dev,s8 * iovar,s32 val)342 wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val)
343 {
344 	int ret;
345 
346 	ret = wldev_iovar_setint(dev, iovar, val);
347 	if (ret)
348 		AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar, ret);
349 
350 	return ret;
351 }
352 
353 static int
wl_ext_iovar_getbuf(struct net_device * dev,s8 * iovar_name,void * param,s32 paramlen,void * buf,s32 buflen,struct mutex * buf_sync)354 wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name,
355 	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
356 {
357 	int ret;
358 
359 	ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
360 	if (ret != 0)
361 		AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar_name, ret);
362 
363 	return ret;
364 }
365 
366 static int
wl_ext_iovar_setbuf(struct net_device * dev,s8 * iovar_name,void * param,s32 paramlen,void * buf,s32 buflen,struct mutex * buf_sync)367 wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
368 	void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
369 {
370 	int ret;
371 
372 	ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
373 	if (ret != 0)
374 		AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar_name, ret);
375 
376 	return ret;
377 }
378 
379 static int
wl_ext_iovar_setbuf_bsscfg(struct net_device * dev,s8 * iovar_name,void * param,s32 paramlen,void * buf,s32 buflen,s32 bsscfg_idx,struct mutex * buf_sync)380 wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
381 	void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx,
382 	struct mutex* buf_sync)
383 {
384 	int ret;
385 
386 	ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen,
387 		buf, buflen, bsscfg_idx, buf_sync);
388 	if (ret < 0)
389 		AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar_name, ret);
390 
391 	return ret;
392 }
393 
394 static chanspec_t
wl_ext_chspec_to_legacy(chanspec_t chspec)395 wl_ext_chspec_to_legacy(chanspec_t chspec)
396 {
397 	chanspec_t lchspec;
398 
399 	if (wf_chspec_malformed(chspec)) {
400 		AEXT_ERROR("wlan", "input chanspec (0x%04X) malformed\n", chspec);
401 		return INVCHANSPEC;
402 	}
403 
404 	/* get the channel number */
405 	lchspec = CHSPEC_CHANNEL(chspec);
406 
407 	/* convert the band */
408 	if (CHSPEC_IS2G(chspec)) {
409 		lchspec |= WL_LCHANSPEC_BAND_2G;
410 	} else {
411 		lchspec |= WL_LCHANSPEC_BAND_5G;
412 	}
413 
414 	/* convert the bw and sideband */
415 	if (CHSPEC_IS20(chspec)) {
416 		lchspec |= WL_LCHANSPEC_BW_20;
417 		lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
418 	} else if (CHSPEC_IS40(chspec)) {
419 		lchspec |= WL_LCHANSPEC_BW_40;
420 		if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
421 			lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
422 		} else {
423 			lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
424 		}
425 	} else {
426 		/* cannot express the bandwidth */
427 		char chanbuf[CHANSPEC_STR_LEN];
428 		AEXT_ERROR("wlan", "unable to convert chanspec %s (0x%04X) "
429 			"to pre-11ac format\n",
430 			wf_chspec_ntoa(chspec, chanbuf), chspec);
431 		return INVCHANSPEC;
432 	}
433 
434 	return lchspec;
435 }
436 
437 static chanspec_t
wl_ext_chspec_host_to_driver(int ioctl_ver,chanspec_t chanspec)438 wl_ext_chspec_host_to_driver(int ioctl_ver, chanspec_t chanspec)
439 {
440 	if (ioctl_ver == 1) {
441 		chanspec = wl_ext_chspec_to_legacy(chanspec);
442 		if (chanspec == INVCHANSPEC) {
443 			return chanspec;
444 		}
445 	}
446 	chanspec = htodchanspec(chanspec);
447 
448 	return chanspec;
449 }
450 
451 static void
wl_ext_ch_to_chanspec(int ioctl_ver,int ch,struct wl_join_params * join_params,size_t * join_params_size)452 wl_ext_ch_to_chanspec(int ioctl_ver, int ch,
453 	struct wl_join_params *join_params, size_t *join_params_size)
454 {
455 	chanspec_t chanspec = 0;
456 
457 	if (ch != 0) {
458 		join_params->params.chanspec_num = 1;
459 		join_params->params.chanspec_list[0] = ch;
460 
461 		if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
462 			chanspec |= WL_CHANSPEC_BAND_2G;
463 		else
464 			chanspec |= WL_CHANSPEC_BAND_5G;
465 
466 		chanspec |= WL_CHANSPEC_BW_20;
467 		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
468 
469 		*join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
470 			join_params->params.chanspec_num * sizeof(chanspec_t);
471 
472 		join_params->params.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
473 		join_params->params.chanspec_list[0] |= chanspec;
474 		join_params->params.chanspec_list[0] =
475 			wl_ext_chspec_host_to_driver(ioctl_ver,
476 				join_params->params.chanspec_list[0]);
477 
478 		join_params->params.chanspec_num =
479 			htod32(join_params->params.chanspec_num);
480 	}
481 }
482 
483 #if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN)
484 static chanspec_t
wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)485 wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
486 {
487 	chanspec_t chspec;
488 
489 	/* get the channel number */
490 	chspec = LCHSPEC_CHANNEL(legacy_chspec);
491 
492 	/* convert the band */
493 	if (LCHSPEC_IS2G(legacy_chspec)) {
494 		chspec |= WL_CHANSPEC_BAND_2G;
495 	} else {
496 		chspec |= WL_CHANSPEC_BAND_5G;
497 	}
498 
499 	/* convert the bw and sideband */
500 	if (LCHSPEC_IS20(legacy_chspec)) {
501 		chspec |= WL_CHANSPEC_BW_20;
502 	} else {
503 		chspec |= WL_CHANSPEC_BW_40;
504 		if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
505 			chspec |= WL_CHANSPEC_CTL_SB_L;
506 		} else {
507 			chspec |= WL_CHANSPEC_CTL_SB_U;
508 		}
509 	}
510 
511 	if (wf_chspec_malformed(chspec)) {
512 		AEXT_ERROR("wlan", "output chanspec (0x%04X) malformed\n", chspec);
513 		return INVCHANSPEC;
514 	}
515 
516 	return chspec;
517 }
518 
519 static chanspec_t
wl_ext_chspec_driver_to_host(int ioctl_ver,chanspec_t chanspec)520 wl_ext_chspec_driver_to_host(int ioctl_ver, chanspec_t chanspec)
521 {
522 	chanspec = dtohchanspec(chanspec);
523 	if (ioctl_ver == 1) {
524 		chanspec = wl_ext_chspec_from_legacy(chanspec);
525 	}
526 
527 	return chanspec;
528 }
529 #endif /* WL_EXT_IAPSTA || WL_CFG80211 || WL_ESCAN */
530 
531 bool
wl_ext_check_scan(struct net_device * dev,dhd_pub_t * dhdp)532 wl_ext_check_scan(struct net_device *dev, dhd_pub_t *dhdp)
533 {
534 #ifdef WL_CFG80211
535 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
536 #endif /* WL_CFG80211 */
537 #ifdef WL_ESCAN
538 	struct wl_escan_info *escan = dhdp->escan;
539 #endif /* WL_ESCAN */
540 
541 #ifdef WL_CFG80211
542 	if (wl_get_drv_status_all(cfg, SCANNING)) {
543 		AEXT_ERROR(dev->name, "cfg80211 scanning...\n");
544 		return TRUE;
545 	}
546 #endif /* WL_CFG80211 */
547 
548 #ifdef WL_ESCAN
549 	if (escan->escan_state == ESCAN_STATE_SCANING) {
550 		AEXT_ERROR(dev->name, "escan scanning...\n");
551 		return TRUE;
552 	}
553 #endif /* WL_ESCAN */
554 
555 	return FALSE;
556 }
557 
558 #if defined(WL_CFG80211) || defined(WL_ESCAN)
559 void
wl_ext_user_sync(struct dhd_pub * dhd,int ifidx,bool lock)560 wl_ext_user_sync(struct dhd_pub *dhd, int ifidx, bool lock)
561 {
562 	struct net_device *dev = dhd_idx2net(dhd, ifidx);
563 #ifdef WL_CFG80211
564 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
565 #endif /* WL_CFG80211 */
566 #ifdef WL_ESCAN
567 	struct wl_escan_info *escan = dhd->escan;
568 #endif /* WL_ESCAN */
569 
570 	AEXT_INFO(dev->name, "lock=%d\n", lock);
571 
572 	if (lock) {
573 #if defined(WL_CFG80211)
574 		mutex_lock(&cfg->usr_sync);
575 #endif
576 #if defined(WL_ESCAN)
577 		mutex_lock(&escan->usr_sync);
578 #endif
579 	} else {
580 #if defined(WL_CFG80211)
581 		mutex_unlock(&cfg->usr_sync);
582 #endif
583 #if defined(WL_ESCAN)
584 		mutex_unlock(&escan->usr_sync);
585 #endif
586 	}
587 }
588 
589 bool
wl_ext_event_complete(struct dhd_pub * dhd,int ifidx)590 wl_ext_event_complete(struct dhd_pub *dhd, int ifidx)
591 {
592 	struct net_device *dev = dhd_idx2net(dhd, ifidx);
593 #ifdef WL_CFG80211
594 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
595 #endif /* WL_CFG80211 */
596 #ifdef WL_ESCAN
597 	struct wl_escan_info *escan = dhd->escan;
598 #endif /* WL_ESCAN */
599 #ifdef WL_EXT_IAPSTA
600 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
601 	struct wl_if_info *cur_if = NULL;
602 #endif /* WL_EXT_IAPSTA */
603 	bool complete = TRUE;
604 
605 #ifdef WL_CFG80211
606 	if (wl_get_drv_status_all(cfg, SCANNING)) {
607 		AEXT_INFO(dev->name, "SCANNING\n");
608 		complete = FALSE;
609 	}
610 	if (wl_get_drv_status_all(cfg, CONNECTING)) {
611 		AEXT_INFO(dev->name, "CONNECTING\n");
612 		complete = FALSE;
613 	}
614 	if (wl_get_drv_status_all(cfg, DISCONNECTING)) {
615 		AEXT_INFO(dev->name, "DISCONNECTING\n");
616 		complete = FALSE;
617 	}
618 #endif /* WL_CFG80211 */
619 #ifdef WL_ESCAN
620 	if (escan->escan_state == ESCAN_STATE_SCANING) {
621 		AEXT_INFO(dev->name, "ESCAN_STATE_SCANING\n");
622 		complete = FALSE;
623 	}
624 #endif /* WL_ESCAN */
625 #ifdef WL_EXT_IAPSTA
626 	if (ifidx < MAX_IF_NUM) {
627 		cur_if = &apsta_params->if_info[ifidx];
628 	}
629 	if (cur_if && cur_if->ifmode == ISTA_MODE &&
630 			cur_if->eapol_status >= EAPOL_STATUS_4WAY_START &&
631 			cur_if->eapol_status < EAPOL_STATUS_4WAY_DONE) {
632 		AEXT_INFO(dev->name, "4-WAY handshaking\n");
633 		complete = FALSE;
634 	}
635 #endif /* WL_EXT_IAPSTA */
636 
637 	return complete;
638 }
639 #endif /* WL_CFG80211 && WL_ESCAN */
640 
641 static int
wl_ext_get_ioctl_ver(struct net_device * dev,int * ioctl_ver)642 wl_ext_get_ioctl_ver(struct net_device *dev, int *ioctl_ver)
643 {
644 	int ret = 0;
645 	s32 val = 0;
646 
647 	val = 1;
648 	ret = wl_ext_ioctl(dev, WLC_GET_VERSION, &val, sizeof(val), 0);
649 	if (ret) {
650 		return ret;
651 	}
652 	val = dtoh32(val);
653 	if (val != WLC_IOCTL_VERSION && val != 1) {
654 		AEXT_ERROR(dev->name, "Version mismatch, please upgrade. Got %d, expected %d or 1\n",
655 			val, WLC_IOCTL_VERSION);
656 		return BCME_VERSION;
657 	}
658 	*ioctl_ver = val;
659 
660 	return ret;
661 }
662 
663 void
wl_ext_bss_iovar_war(struct net_device * ndev,s32 * val)664 wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val)
665 {
666 	dhd_pub_t *dhd = dhd_get_pub(ndev);
667 	uint chip;
668 	bool need_war = false;
669 
670 	chip = dhd_conf_get_chip(dhd);
671 
672 	if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
673 		chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
674 		chip == BCM4371_CHIP_ID ||
675 		chip == BCM43430_CHIP_ID ||
676 		chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
677 		chip == BCM4359_CHIP_ID ||
678 		chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
679 		chip == BCM43569_CHIP_ID) {
680 		need_war = true;
681 	}
682 
683 	if (need_war) {
684 		/* Few firmware branches have issues in bss iovar handling and
685 		 * that can't be changed since they are in production.
686 		 */
687 		if (*val == WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE) {
688 			*val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
689 		} else if (*val == WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE) {
690 			*val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
691 		} else {
692 			/* Ignore for other bss enums */
693 			return;
694 		}
695 		AEXT_TRACE(ndev->name, "wl bss %d\n", *val);
696 	}
697 }
698 
699 static int
wl_ext_set_chanspec(struct net_device * dev,int ioctl_ver,uint16 channel,chanspec_t * ret_chspec)700 wl_ext_set_chanspec(struct net_device *dev, int ioctl_ver,
701 	uint16 channel, chanspec_t *ret_chspec)
702 {
703 	s32 _chan = channel;
704 	chanspec_t chspec = 0;
705 	chanspec_t fw_chspec = 0;
706 	u32 bw = WL_CHANSPEC_BW_20;
707 	s32 err = BCME_OK;
708 	s32 bw_cap = 0;
709 	s8 iovar_buf[WLC_IOCTL_SMLEN];
710 	struct {
711 		u32 band;
712 		u32 bw_cap;
713 	} param = {0, 0};
714 	uint band;
715 
716 	if (_chan <= CH_MAX_2G_CHANNEL)
717 		band = IEEE80211_BAND_2GHZ;
718 	else
719 		band = IEEE80211_BAND_5GHZ;
720 
721 	if (band == IEEE80211_BAND_5GHZ) {
722 		param.band = WLC_BAND_5G;
723 		err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
724 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
725 		if (err) {
726 			if (err != BCME_UNSUPPORTED) {
727 				AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err);
728 				return err;
729 			} else {
730 				err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
731 				if (bw_cap != WLC_N_BW_20ALL)
732 					bw = WL_CHANSPEC_BW_40;
733 			}
734 		} else {
735 			if (WL_BW_CAP_80MHZ(iovar_buf[0]))
736 				bw = WL_CHANSPEC_BW_80;
737 			else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
738 				bw = WL_CHANSPEC_BW_40;
739 			else
740 				bw = WL_CHANSPEC_BW_20;
741 
742 		}
743 	}
744 	else if (band == IEEE80211_BAND_2GHZ)
745 		bw = WL_CHANSPEC_BW_20;
746 
747 set_channel:
748 	chspec = wf_channel2chspec(_chan, bw);
749 	if (wf_chspec_valid(chspec)) {
750 		fw_chspec = wl_ext_chspec_host_to_driver(ioctl_ver, chspec);
751 		if (fw_chspec != INVCHANSPEC) {
752 			if ((err = wl_ext_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) {
753 				if (bw == WL_CHANSPEC_BW_80)
754 					goto change_bw;
755 				err = wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
756 				WL_MSG(dev->name, "channel %d\n", _chan);
757 			} else if (err) {
758 				AEXT_ERROR(dev->name, "failed to set chanspec error %d\n", err);
759 			} else
760 				WL_MSG(dev->name, "channel %d, 0x%x\n", channel, chspec);
761 		} else {
762 			AEXT_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n");
763 			err = BCME_ERROR;
764 		}
765 	} else {
766 change_bw:
767 		if (bw == WL_CHANSPEC_BW_80)
768 			bw = WL_CHANSPEC_BW_40;
769 		else if (bw == WL_CHANSPEC_BW_40)
770 			bw = WL_CHANSPEC_BW_20;
771 		else
772 			bw = 0;
773 		if (bw)
774 			goto set_channel;
775 		AEXT_ERROR(dev->name, "Invalid chanspec 0x%x\n", chspec);
776 		err = BCME_ERROR;
777 	}
778 	*ret_chspec = fw_chspec;
779 
780 	return err;
781 }
782 
783 static int
wl_ext_channel(struct net_device * dev,char * command,int total_len)784 wl_ext_channel(struct net_device *dev, char* command, int total_len)
785 {
786 	int ret;
787 	int channel=0;
788 	channel_info_t ci;
789 	int bytes_written = 0;
790 	chanspec_t fw_chspec;
791 	int ioctl_ver = 0;
792 
793 	AEXT_TRACE(dev->name, "cmd %s", command);
794 
795 	sscanf(command, "%*s %d", &channel);
796 
797 	if (channel > 0) {
798 		wl_ext_get_ioctl_ver(dev, &ioctl_ver);
799 		ret = wl_ext_set_chanspec(dev, ioctl_ver, channel, &fw_chspec);
800 	} else {
801 		if (!(ret = wl_ext_ioctl(dev, WLC_GET_CHANNEL, &ci,
802 				sizeof(channel_info_t), FALSE))) {
803 			AEXT_TRACE(dev->name, "hw_channel %d\n", ci.hw_channel);
804 			AEXT_TRACE(dev->name, "target_channel %d\n", ci.target_channel);
805 			AEXT_TRACE(dev->name, "scan_channel %d\n", ci.scan_channel);
806 			bytes_written = snprintf(command, sizeof(channel_info_t)+2,
807 				"channel %d", ci.hw_channel);
808 			AEXT_TRACE(dev->name, "command result is %s\n", command);
809 			ret = bytes_written;
810 		}
811 	}
812 
813 	return ret;
814 }
815 
816 static int
wl_ext_channels(struct net_device * dev,char * command,int total_len)817 wl_ext_channels(struct net_device *dev, char* command, int total_len)
818 {
819 	int ret, i;
820 	int bytes_written = -1;
821 	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
822 	wl_uint32_list_t *list;
823 
824 	AEXT_TRACE(dev->name, "cmd %s", command);
825 
826 	memset(valid_chan_list, 0, sizeof(valid_chan_list));
827 	list = (wl_uint32_list_t *)(void *) valid_chan_list;
828 	list->count = htod32(WL_NUMCHANNELS);
829 	ret = wl_ext_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
830 		sizeof(valid_chan_list), 0);
831 	if (ret<0) {
832 		AEXT_ERROR(dev->name, "get channels failed with %d\n", ret);
833 	} else {
834 		bytes_written = snprintf(command, total_len, "channels");
835 		for (i = 0; i < dtoh32(list->count); i++) {
836 			bytes_written += snprintf(command+bytes_written, total_len, " %d",
837 				dtoh32(list->element[i]));
838 		}
839 		AEXT_TRACE(dev->name, "command result is %s\n", command);
840 		ret = bytes_written;
841 	}
842 
843 	return ret;
844 }
845 
846 static int
wl_ext_roam_trigger(struct net_device * dev,char * command,int total_len)847 wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len)
848 {
849 	int ret = 0;
850 	int roam_trigger[2] = {0, 0};
851 	int trigger[2]= {0, 0};
852 	int bytes_written=-1;
853 
854 	sscanf(command, "%*s %10d", &roam_trigger[0]);
855 
856 	if (roam_trigger[0]) {
857 		roam_trigger[1] = WLC_BAND_ALL;
858 		ret = wl_ext_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
859 			sizeof(roam_trigger), 1);
860 	} else {
861 		roam_trigger[1] = WLC_BAND_2G;
862 		ret = wl_ext_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
863 			sizeof(roam_trigger), 0);
864 		if (!ret)
865 			trigger[0] = roam_trigger[0];
866 
867 		roam_trigger[1] = WLC_BAND_5G;
868 		ret = wl_ext_ioctl(dev, WLC_GET_ROAM_TRIGGER, &roam_trigger,
869 			sizeof(roam_trigger), 0);
870 		if (!ret)
871 			trigger[1] = roam_trigger[0];
872 
873 		AEXT_TRACE(dev->name, "roam_trigger %d %d\n", trigger[0], trigger[1]);
874 		bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
875 		ret = bytes_written;
876 	}
877 
878 	return ret;
879 }
880 
881 static int
wl_ext_pm(struct net_device * dev,char * command,int total_len)882 wl_ext_pm(struct net_device *dev, char *command, int total_len)
883 {
884 	int pm=-1, ret = -1;
885 	char *pm_local;
886 	int bytes_written=-1;
887 
888 	AEXT_TRACE(dev->name, "cmd %s", command);
889 
890 	sscanf(command, "%*s %d", &pm);
891 
892 	if (pm >= 0) {
893 		ret = wl_ext_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), 1);
894 	} else {
895 		ret = wl_ext_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), 0);
896 		if (!ret) {
897 			AEXT_TRACE(dev->name, "PM = %d", pm);
898 			if (pm == PM_OFF)
899 				pm_local = "PM_OFF";
900 			else if(pm == PM_MAX)
901 				pm_local = "PM_MAX";
902 			else if(pm == PM_FAST)
903 				pm_local = "PM_FAST";
904 			else {
905 				pm = 0;
906 				pm_local = "Invalid";
907 			}
908 			bytes_written = snprintf(command, total_len, "PM %s", pm_local);
909 			AEXT_TRACE(dev->name, "command result is %s\n", command);
910 			ret = bytes_written;
911 		}
912 	}
913 
914 	return ret;
915 }
916 
917 static int
wl_ext_monitor(struct net_device * dev,char * command,int total_len)918 wl_ext_monitor(struct net_device *dev, char *command, int total_len)
919 {
920 	int val = -1, ret = -1;
921 	int bytes_written=-1;
922 
923 	sscanf(command, "%*s %d", &val);
924 
925 	if (val >=0) {
926 		ret = wl_ext_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(val), 1);
927 	} else {
928 		ret = wl_ext_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), 0);
929 		if (!ret) {
930 			AEXT_TRACE(dev->name, "monitor = %d\n", val);
931 			bytes_written = snprintf(command, total_len, "monitor %d", val);
932 			AEXT_TRACE(dev->name, "command result is %s\n", command);
933 			ret = bytes_written;
934 		}
935 	}
936 
937 	return ret;
938 }
939 
940 s32
wl_ext_connect(struct net_device * dev,struct wl_conn_info * conn_info)941 wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info)
942 {
943 	struct dhd_pub *dhd = dhd_get_pub(dev);
944 	wl_extjoin_params_t *ext_join_params = NULL;
945 	struct wl_join_params join_params;
946 	size_t join_params_size;
947 	s32 err = 0;
948 	u32 chan_cnt = 0;
949 	s8 *iovar_buf = NULL;
950 	int ioctl_ver = 0;
951 	char sec[32];
952 
953 	wl_ext_get_ioctl_ver(dev, &ioctl_ver);
954 
955 	if (dhd->conf->chip == BCM43362_CHIP_ID)
956 		goto set_ssid;
957 
958 	if (conn_info->channel) {
959 		chan_cnt = 1;
960 	}
961 
962 	iovar_buf = kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
963 	if (iovar_buf == NULL) {
964 		err = -ENOMEM;
965 		goto exit;
966 	}
967 
968 	/*
969 	 *	Join with specific BSSID and cached SSID
970 	 *	If SSID is zero join based on BSSID only
971 	 */
972 	join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
973 		chan_cnt * sizeof(chanspec_t);
974 	ext_join_params =  (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
975 	if (ext_join_params == NULL) {
976 		err = -ENOMEM;
977 		goto exit;
978 	}
979 	ext_join_params->ssid.SSID_len = min((uint32)sizeof(ext_join_params->ssid.SSID),
980 		conn_info->ssid.SSID_len);
981 	memcpy(&ext_join_params->ssid.SSID, conn_info->ssid.SSID, ext_join_params->ssid.SSID_len);
982 	ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
983 	/* increate dwell time to receive probe response or detect Beacon
984 	* from target AP at a noisy air only during connect command
985 	*/
986 	ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
987 	ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
988 	/* Set up join scan parameters */
989 	ext_join_params->scan.scan_type = -1;
990 	ext_join_params->scan.nprobes = chan_cnt ?
991 		(ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
992 	ext_join_params->scan.home_time = -1;
993 
994 	if (memcmp(&ether_null, &conn_info->bssid, ETHER_ADDR_LEN))
995 		memcpy(&ext_join_params->assoc.bssid, &conn_info->bssid, ETH_ALEN);
996 	else
997 		memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
998 	ext_join_params->assoc.chanspec_num = chan_cnt;
999 	if (chan_cnt) {
1000 		u16 band, bw, ctl_sb;
1001 		chanspec_t chspec;
1002 		band = (conn_info->channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
1003 			: WL_CHANSPEC_BAND_5G;
1004 		bw = WL_CHANSPEC_BW_20;
1005 		ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
1006 		chspec = (conn_info->channel | band | bw | ctl_sb);
1007 		ext_join_params->assoc.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
1008 		ext_join_params->assoc.chanspec_list[0] |= chspec;
1009 		ext_join_params->assoc.chanspec_list[0] =
1010 			wl_ext_chspec_host_to_driver(ioctl_ver,
1011 				ext_join_params->assoc.chanspec_list[0]);
1012 	}
1013 	ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
1014 
1015 	wl_ext_get_sec(dev, 0, sec, sizeof(sec));
1016 	WL_MSG(dev->name,
1017 		"Connecting with %pM channel (%d) ssid \"%s\", len (%d), sec=%s\n\n",
1018 		&ext_join_params->assoc.bssid, conn_info->channel,
1019 		ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec);
1020 	err = wl_ext_iovar_setbuf_bsscfg(dev, "join", ext_join_params,
1021 		join_params_size, iovar_buf, WLC_IOCTL_MAXLEN, conn_info->bssidx, NULL);
1022 
1023 	if (err) {
1024 		if (err == BCME_UNSUPPORTED) {
1025 			AEXT_TRACE(dev->name, "join iovar is not supported\n");
1026 			goto set_ssid;
1027 		} else {
1028 			AEXT_ERROR(dev->name, "error (%d)\n", err);
1029 			goto exit;
1030 		}
1031 	} else
1032 		goto exit;
1033 
1034 set_ssid:
1035 	memset(&join_params, 0, sizeof(join_params));
1036 	join_params_size = sizeof(join_params.ssid);
1037 
1038 	join_params.ssid.SSID_len = min((uint32)sizeof(join_params.ssid.SSID),
1039 		conn_info->ssid.SSID_len);
1040 	memcpy(&join_params.ssid.SSID, conn_info->ssid.SSID, join_params.ssid.SSID_len);
1041 	join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
1042 	if (memcmp(&ether_null, &conn_info->bssid, ETHER_ADDR_LEN))
1043 		memcpy(&join_params.params.bssid, &conn_info->bssid, ETH_ALEN);
1044 	else
1045 		memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
1046 
1047 	wl_ext_ch_to_chanspec(ioctl_ver, conn_info->channel, &join_params, &join_params_size);
1048 	AEXT_TRACE(dev->name, "join_param_size %zu\n", join_params_size);
1049 
1050 	if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
1051 		AEXT_INFO(dev->name, "ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
1052 			join_params.ssid.SSID_len);
1053 	}
1054 	wl_ext_get_sec(dev, 0, sec, sizeof(sec));
1055 	WL_MSG(dev->name,
1056 		"Connecting with %pM channel (%d) ssid \"%s\", len (%d), sec=%s\n\n",
1057 		&join_params.params.bssid, conn_info->channel,
1058 		join_params.ssid.SSID, join_params.ssid.SSID_len, sec);
1059 	err = wl_ext_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, 1);
1060 
1061 exit:
1062 #ifdef WL_EXT_IAPSTA
1063 	if (!err)
1064 		wl_ext_add_remove_pm_enable_work(dev, TRUE);
1065 #endif /* WL_EXT_IAPSTA */
1066 	if (iovar_buf)
1067 		kfree(iovar_buf);
1068 	if (ext_join_params)
1069 		kfree(ext_join_params);
1070 	return err;
1071 
1072 }
1073 
1074 void
wl_ext_get_sec(struct net_device * dev,int ifmode,char * sec,int total_len)1075 wl_ext_get_sec(struct net_device *dev, int ifmode, char *sec, int total_len)
1076 {
1077 	int auth=0, wpa_auth=0, wsec=0, mfp=0, wsec_tmp;
1078 	int bytes_written=0;
1079 
1080 	memset(sec, 0, total_len);
1081 	wl_ext_iovar_getint(dev, "auth", &auth);
1082 	wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
1083 	wl_ext_iovar_getint(dev, "wsec", &wsec);
1084 	wldev_iovar_getint(dev, "mfp", &mfp);
1085 
1086 #ifdef WL_EXT_IAPSTA
1087 	if (ifmode == IMESH_MODE) {
1088 		if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA_AUTH_DISABLED) {
1089 			bytes_written += snprintf(sec+bytes_written, total_len, "open");
1090 		} else if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA2_AUTH_PSK) {
1091 			bytes_written += snprintf(sec+bytes_written, total_len, "sae");
1092 		} else {
1093 			bytes_written += snprintf(sec+bytes_written, total_len, "%d/0x%x",
1094 				auth, wpa_auth);
1095 		}
1096 	} else
1097 #endif /* WL_EXT_IAPSTA */
1098 	{
1099 		if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA_AUTH_DISABLED) {
1100 			bytes_written += snprintf(sec+bytes_written, total_len, "open");
1101 		} else if (auth == WL_AUTH_SHARED_KEY && wpa_auth == WPA_AUTH_DISABLED) {
1102 			bytes_written += snprintf(sec+bytes_written, total_len, "shared");
1103 		} else if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA_AUTH_PSK) {
1104 			bytes_written += snprintf(sec+bytes_written, total_len, "wpapsk");
1105 		} else if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA2_AUTH_PSK) {
1106 			bytes_written += snprintf(sec+bytes_written, total_len, "wpa2psk");
1107 		} else if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA2_AUTH_UNSPECIFIED) {
1108 			bytes_written += snprintf(sec+bytes_written, total_len, "wpa2eap");
1109 		} else if (auth == WL_AUTH_OPEN_SYSTEM &&
1110 				wpa_auth == (WPA2_AUTH_FT|WPA2_AUTH_PSK)) {
1111 			bytes_written += snprintf(sec+bytes_written, total_len, "wpa2psk-ft");
1112 		} else if (auth == WL_AUTH_OPEN_SYSTEM &&
1113 				wpa_auth == (WPA2_AUTH_FT|WPA2_AUTH_UNSPECIFIED)) {
1114 			bytes_written += snprintf(sec+bytes_written, total_len, "wpa2eap-ft");
1115 		} else if ((auth == WL_AUTH_OPEN_SYSTEM || auth == WL_AUTH_SAE_KEY) &&
1116 				wpa_auth == WPA3_AUTH_SAE_PSK) {
1117 			bytes_written += snprintf(sec+bytes_written, total_len, "wpa3");
1118 		} else if ((auth == WL_AUTH_OPEN_SYSTEM || auth == WL_AUTH_SAE_KEY) &&
1119 				wpa_auth == 0x20) {
1120 			bytes_written += snprintf(sec+bytes_written, total_len, "wpa3");
1121 		} else {
1122 			bytes_written += snprintf(sec+bytes_written, total_len, "%d/0x%x",
1123 				auth, wpa_auth);
1124 		}
1125 	}
1126 
1127 	if (mfp == WL_MFP_NONE) {
1128 		bytes_written += snprintf(sec+bytes_written, total_len, "/mfpn");
1129 	} else if (mfp == WL_MFP_CAPABLE) {
1130 		bytes_written += snprintf(sec+bytes_written, total_len, "/mfpc");
1131 	} else if (mfp == WL_MFP_REQUIRED) {
1132 		bytes_written += snprintf(sec+bytes_written, total_len, "/mfpr");
1133 	} else {
1134 		bytes_written += snprintf(sec+bytes_written, total_len, "/%d", mfp);
1135 	}
1136 
1137 #ifdef WL_EXT_IAPSTA
1138 	if (ifmode == IMESH_MODE) {
1139 		if (wsec == WSEC_NONE) {
1140 			bytes_written += snprintf(sec+bytes_written, total_len, "/none");
1141 		} else {
1142 			bytes_written += snprintf(sec+bytes_written, total_len, "/aes");
1143 		}
1144 	} else
1145 #endif /* WL_EXT_IAPSTA */
1146 	{
1147 		wsec_tmp = wsec & 0xf;
1148 		if (wsec_tmp == WSEC_NONE) {
1149 			bytes_written += snprintf(sec+bytes_written, total_len, "/none");
1150 		} else if (wsec_tmp == WEP_ENABLED) {
1151 			bytes_written += snprintf(sec+bytes_written, total_len, "/wep");
1152 		} else if (wsec_tmp == (TKIP_ENABLED|AES_ENABLED) ||
1153 				wsec_tmp == (WSEC_SWFLAG|TKIP_ENABLED|AES_ENABLED)) {
1154 			bytes_written += snprintf(sec+bytes_written, total_len, "/tkipaes");
1155 		} else if (wsec_tmp == TKIP_ENABLED || wsec_tmp == (WSEC_SWFLAG|TKIP_ENABLED)) {
1156 			bytes_written += snprintf(sec+bytes_written, total_len, "/tkip");
1157 		} else if (wsec_tmp == AES_ENABLED || wsec_tmp == (WSEC_SWFLAG|AES_ENABLED)) {
1158 			bytes_written += snprintf(sec+bytes_written, total_len, "/aes");
1159 		} else {
1160 			bytes_written += snprintf(sec+bytes_written, total_len, "/0x%x", wsec);
1161 		}
1162 	}
1163 
1164 }
1165 
1166 static bool
wl_ext_dfs_chan(uint16 chan)1167 wl_ext_dfs_chan(uint16 chan)
1168 {
1169 	if (chan >= 52 && chan <= 144)
1170 		return TRUE;
1171 	return FALSE;
1172 }
1173 
1174 static uint16
wl_ext_get_default_chan(struct net_device * dev,uint16 * chan_2g,uint16 * chan_5g,bool nodfs)1175 wl_ext_get_default_chan(struct net_device *dev,
1176 	uint16 *chan_2g, uint16 *chan_5g, bool nodfs)
1177 {
1178 	struct dhd_pub *dhd = dhd_get_pub(dev);
1179 	uint16 chan_tmp = 0, chan = 0;
1180 	wl_uint32_list_t *list;
1181 	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
1182 	s32 ret = BCME_OK;
1183 	int i;
1184 
1185 	*chan_2g = 0;
1186 	*chan_5g = 0;
1187 	memset(valid_chan_list, 0, sizeof(valid_chan_list));
1188 	list = (wl_uint32_list_t *)(void *) valid_chan_list;
1189 	list->count = htod32(WL_NUMCHANNELS);
1190 	ret = wl_ext_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
1191 		sizeof(valid_chan_list), 0);
1192 	if (ret == 0) {
1193 		for (i=0; i<dtoh32(list->count); i++) {
1194 			chan_tmp = dtoh32(list->element[i]);
1195 			if (!dhd_conf_match_channel(dhd, chan_tmp))
1196 				continue;
1197 			if (chan_tmp <= 13 && !*chan_2g) {
1198 				*chan_2g = chan_tmp;
1199 			} else if (chan_tmp >= 36 && chan_tmp <= 161 && !*chan_5g) {
1200 				if (wl_ext_dfs_chan(chan_tmp) && nodfs)
1201 					continue;
1202 				else
1203 					*chan_5g = chan_tmp;
1204 			}
1205 		}
1206 	}
1207 
1208 	return chan;
1209 }
1210 
1211 static int
wl_ext_wlmsglevel(struct net_device * dev,char * command,int total_len)1212 wl_ext_wlmsglevel(struct net_device *dev, char *command, int total_len)
1213 {
1214 	int val = -1, ret = 0;
1215 	int bytes_written = 0;
1216 
1217 	sscanf(command, "%*s %x", &val);
1218 
1219 	if (val >=0) {
1220 		if (val & DHD_ANDROID_VAL) {
1221 			android_msg_level = (uint)(val & 0xFFFF);
1222 			printf("android_msg_level=0x%x\n", android_msg_level);
1223 		}
1224 #if defined(WL_WIRELESS_EXT)
1225 		else if (val & DHD_IW_VAL) {
1226 			iw_msg_level = (uint)(val & 0xFFFF);
1227 			printf("iw_msg_level=0x%x\n", iw_msg_level);
1228 		}
1229 #endif
1230 #ifdef WL_CFG80211
1231 		else if (val & DHD_CFG_VAL) {
1232 			wl_cfg80211_enable_trace((u32)(val & 0xFFFF));
1233 		}
1234 #endif
1235 		else if (val & DHD_CONFIG_VAL) {
1236 			config_msg_level = (uint)(val & 0xFFFF);
1237 			printf("config_msg_level=0x%x\n", config_msg_level);
1238 		}
1239 		else if (val & DHD_DUMP_VAL) {
1240 			dump_msg_level = (uint)(val & 0xFFFF);
1241 			printf("dump_msg_level=0x%x\n", dump_msg_level);
1242 		}
1243 	}
1244 	else {
1245 		bytes_written += snprintf(command+bytes_written, total_len,
1246 			"android_msg_level=0x%x", android_msg_level);
1247 #if defined(WL_WIRELESS_EXT)
1248 		bytes_written += snprintf(command+bytes_written, total_len,
1249 			"\niw_msg_level=0x%x", iw_msg_level);
1250 #endif
1251 #ifdef WL_CFG80211
1252 		bytes_written += snprintf(command+bytes_written, total_len,
1253 			"\nwl_dbg_level=0x%x", wl_dbg_level);
1254 #endif
1255 		bytes_written += snprintf(command+bytes_written, total_len,
1256 			"\nconfig_msg_level=0x%x", config_msg_level);
1257 		bytes_written += snprintf(command+bytes_written, total_len,
1258 			"\ndump_msg_level=0x%x", dump_msg_level);
1259 		AEXT_INFO(dev->name, "%s\n", command);
1260 		ret = bytes_written;
1261 	}
1262 
1263 	return ret;
1264 }
1265 
1266 #ifdef WLEASYMESH
1267 //Set map 4 and dwds 1 on wlan0 interface
1268 #define EASYMESH_SLAVE		"slave"
1269 #define EASYMESH_MASTER		"master"
1270 static int
wl_ext_easymesh(struct net_device * dev,char * command,int total_len)1271 wl_ext_easymesh(struct net_device *dev, char* command, int total_len)
1272 {
1273 	int err = 0, wlc_down = 1, wlc_up = 1;
1274 	int orig_map = 0, orig_dwds = 0;
1275 	int map = 4; //default for slave mode
1276 	int dwds = 1; //default for slave mode
1277 
1278 	wl_ext_iovar_getint(dev, "map", &orig_map);
1279 	wl_ext_iovar_getint(dev, "dwds", &orig_dwds);
1280 
1281 	if (strncmp(command, EASYMESH_SLAVE, strlen(EASYMESH_SLAVE)) == 0) {
1282 		WL_MSG(dev->name, "try to set map %d, dwds %d\n", map, dwds);
1283 		if ((0x80 == orig_map) && (dwds == orig_dwds)) {
1284 			WL_MSG(dev->name, "Same map and dwds, ignoring, error = %d\n", err);
1285 			return 0;
1286 		}
1287 		err = wl_ext_ioctl(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down), 1);
1288 		if (err) {
1289 			goto exit;
1290 		}
1291 		wl_ext_iovar_setint(dev, "map", map);
1292 		wl_ext_iovar_setint(dev, "dwds", dwds);
1293 		err = wl_ext_ioctl(dev, WLC_UP, &wlc_up, sizeof(wlc_up), 1);
1294 		if (err) {
1295 			goto exit;
1296 		}
1297 	}
1298 	else if (strncmp(command, EASYMESH_MASTER, strlen(EASYMESH_MASTER)) == 0) {
1299 		map = dwds = 0;
1300 		WL_MSG(dev->name, "try to set map %d, dwds %d\n", map, dwds);
1301 		if ((0 == orig_map) && (dwds == orig_dwds)) {
1302 			WL_MSG(dev->name, "Same map and dwds, ignoring, error = %d\n", err);
1303 			return 0;
1304 		}
1305 		err = wl_ext_ioctl(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down), 1);
1306 		if (err) {
1307 			goto exit;
1308 		}
1309 		wl_ext_iovar_setint(dev, "map", map);
1310 		wl_ext_iovar_setint(dev, "dwds", dwds);
1311 		err = wl_ext_ioctl(dev, WLC_UP, &wlc_up, sizeof(wlc_up), 1);
1312 		if (err) {
1313 			goto exit;
1314 		}
1315 	}
1316 
1317 exit:
1318 	return err;
1319 }
1320 #endif /* WLEASYMESH */
1321 
1322 #if defined(SENDPROB) || (defined(WLMESH) && defined(WL_ESCAN))
1323 static int
wl_ext_add_del_ie(struct net_device * dev,uint pktflag,char * ie_data,const char * add_del_cmd)1324 wl_ext_add_del_ie(struct net_device *dev, uint pktflag, char *ie_data, const char* add_del_cmd)
1325 {
1326 	vndr_ie_setbuf_t *vndr_ie = NULL;
1327 	char iovar_buf[WLC_IOCTL_SMLEN]="\0";
1328 	int ie_data_len = 0, tot_len = 0, iecount;
1329 	int err = -1;
1330 
1331 	if (!strlen(ie_data)) {
1332 		AEXT_ERROR(dev->name, "wrong ie %s\n", ie_data);
1333 		goto exit;
1334 	}
1335 
1336 	tot_len = (int)(sizeof(vndr_ie_setbuf_t) + ((strlen(ie_data)-2)/2));
1337 	vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, GFP_KERNEL);
1338 	if (!vndr_ie) {
1339 		AEXT_ERROR(dev->name, "IE memory alloc failed\n");
1340 		err = -ENOMEM;
1341 		goto exit;
1342 	}
1343 
1344 	/* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1345 	strncpy(vndr_ie->cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1);
1346 	vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1347 
1348 	/* Set the IE count - the buffer contains only 1 IE */
1349 	iecount = htod32(1);
1350 	memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
1351 
1352 	/* Set packet flag to indicate that BEACON's will contain this IE */
1353 	pktflag = htod32(pktflag);
1354 	memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
1355 		sizeof(u32));
1356 
1357 	/* Set the IE ID */
1358 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar)DOT11_MNG_VS_ID;
1359 
1360 	/* Set the IE LEN */
1361 	vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (strlen(ie_data)-2)/2;
1362 
1363 	/* Set the IE OUI and DATA */
1364 	ie_data_len = wl_pattern_atoh(ie_data,
1365 		(char *)vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui);
1366 	if (ie_data_len <= 0) {
1367 		AEXT_ERROR(dev->name, "wrong ie_data_len %d\n", (int)strlen(ie_data)-2);
1368 		goto exit;
1369 	}
1370 
1371 	err = wl_ext_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, iovar_buf,
1372 		sizeof(iovar_buf), NULL);
1373 
1374 exit:
1375 	if (vndr_ie) {
1376 		kfree(vndr_ie);
1377 	}
1378 	return err;
1379 }
1380 #endif /* SENDPROB || (WLMESH && WL_ESCAN) */
1381 
1382 #ifdef WL_EXT_IAPSTA
1383 static struct wl_if_info *
wl_get_cur_if(struct net_device * dev)1384 wl_get_cur_if(struct net_device *dev)
1385 {
1386 	dhd_pub_t *dhd = dhd_get_pub(dev);
1387 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
1388 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
1389 	int i;
1390 
1391 	for (i=0; i<MAX_IF_NUM; i++) {
1392 		tmp_if = &apsta_params->if_info[i];
1393 		if (tmp_if->dev && tmp_if->dev == dev) {
1394 			cur_if = tmp_if;
1395 			break;
1396 		}
1397 	}
1398 
1399 	return cur_if;
1400 }
1401 
1402 #define WL_PM_ENABLE_TIMEOUT 10000
1403 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
1404 	4 && __GNUC_MINOR__ >= 6))
1405 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
1406 _Pragma("GCC diagnostic push") \
1407 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
1408 entry = container_of((ptr), type, member); \
1409 _Pragma("GCC diagnostic pop")
1410 #else
1411 #define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
1412 entry = container_of((ptr), type, member);
1413 #endif /* STRICT_GCC_WARNINGS */
1414 
1415 static void
wl_ext_pm_work_handler(struct work_struct * work)1416 wl_ext_pm_work_handler(struct work_struct *work)
1417 {
1418 	struct wl_if_info *cur_if;
1419 	s32 pm = PM_FAST;
1420 	dhd_pub_t *dhd;
1421 
1422 	BCM_SET_CONTAINER_OF(cur_if, work, struct wl_if_info, pm_enable_work.work);
1423 
1424 	AEXT_TRACE("wlan", "%s: Enter\n", __FUNCTION__);
1425 
1426 	if (cur_if->dev == NULL)
1427 		return;
1428 
1429 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
1430 	4 && __GNUC_MINOR__ >= 6))
1431 _Pragma("GCC diagnostic push")
1432 _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
1433 #endif
1434 
1435 	dhd = dhd_get_pub(cur_if->dev);
1436 
1437 	if (!dhd || !dhd->up) {
1438 		AEXT_TRACE(cur_if->ifname, "dhd is null or not up\n");
1439 		return;
1440 	}
1441 	if (dhd_conf_get_pm(dhd) >= 0)
1442 		pm = dhd_conf_get_pm(dhd);
1443 	wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
1444 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
1445 	4 && __GNUC_MINOR__ >= 6))
1446 _Pragma("GCC diagnostic pop")
1447 #endif
1448 	DHD_PM_WAKE_UNLOCK(dhd);
1449 
1450 }
1451 
1452 void
wl_ext_add_remove_pm_enable_work(struct net_device * dev,bool add)1453 wl_ext_add_remove_pm_enable_work(struct net_device *dev, bool add)
1454 {
1455 	dhd_pub_t *dhd = dhd_get_pub(dev);
1456 	struct wl_if_info *cur_if = NULL;
1457 	u16 wq_duration = 0;
1458 	s32 pm = PM_OFF;
1459 
1460 	cur_if = wl_get_cur_if(dev);
1461 	if (!cur_if)
1462 		return;
1463 
1464 	mutex_lock(&cur_if->pm_sync);
1465 	/*
1466 	 * Make cancel and schedule work part mutually exclusive
1467 	 * so that while cancelling, we are sure that there is no
1468 	 * work getting scheduled.
1469 	 */
1470 
1471 	if (delayed_work_pending(&cur_if->pm_enable_work)) {
1472 		cancel_delayed_work_sync(&cur_if->pm_enable_work);
1473 		DHD_PM_WAKE_UNLOCK(dhd);
1474 	}
1475 
1476 	if (add) {
1477 		wq_duration = (WL_PM_ENABLE_TIMEOUT);
1478 	}
1479 
1480 	/* It should schedule work item only if driver is up */
1481 	if (dhd->up) {
1482 		if (dhd_conf_get_pm(dhd) >= 0)
1483 			pm = dhd_conf_get_pm(dhd);
1484 		wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
1485 		if (wq_duration) {
1486 			if (schedule_delayed_work(&cur_if->pm_enable_work,
1487 					msecs_to_jiffies((const unsigned int)wq_duration))) {
1488 				DHD_PM_WAKE_LOCK_TIMEOUT(dhd, wq_duration);
1489 			} else {
1490 				AEXT_ERROR(cur_if->ifname, "Can't schedule pm work handler\n");
1491 			}
1492 		}
1493 	}
1494 	mutex_unlock(&cur_if->pm_sync);
1495 
1496 }
1497 
1498 static int
wl_ext_parse_wep(char * key,struct wl_wsec_key * wsec_key)1499 wl_ext_parse_wep(char *key, struct wl_wsec_key *wsec_key)
1500 {
1501 	char hex[] = "XX";
1502 	unsigned char *data = wsec_key->data;
1503 	char *keystr = key;
1504 
1505 	switch (strlen(keystr)) {
1506 	case 5:
1507 	case 13:
1508 	case 16:
1509 		wsec_key->len = strlen(keystr);
1510 		memcpy(data, keystr, wsec_key->len + 1);
1511 		break;
1512 	case 12:
1513 	case 28:
1514 	case 34:
1515 	case 66:
1516 		/* strip leading 0x */
1517 		if (!strnicmp(keystr, "0x", 2))
1518 			keystr += 2;
1519 		else
1520 			return -1;
1521 		/* fall through */
1522 	case 10:
1523 	case 26:
1524 	case 32:
1525 	case 64:
1526 		wsec_key->len = strlen(keystr) / 2;
1527 		while (*keystr) {
1528 			strncpy(hex, keystr, 2);
1529 			*data++ = (char) strtoul(hex, NULL, 16);
1530 			keystr += 2;
1531 		}
1532 		break;
1533 	default:
1534 		return -1;
1535 	}
1536 
1537 	switch (wsec_key->len) {
1538 	case 5:
1539 		wsec_key->algo = CRYPTO_ALGO_WEP1;
1540 		break;
1541 	case 13:
1542 		wsec_key->algo = CRYPTO_ALGO_WEP128;
1543 		break;
1544 	case 16:
1545 		/* default to AES-CCM */
1546 		wsec_key->algo = CRYPTO_ALGO_AES_CCM;
1547 		break;
1548 	case 32:
1549 		wsec_key->algo = CRYPTO_ALGO_TKIP;
1550 		break;
1551 	default:
1552 		return -1;
1553 	}
1554 
1555 	/* Set as primary wsec_key by default */
1556 	wsec_key->flags |= WL_PRIMARY_KEY;
1557 
1558 	return 0;
1559 }
1560 
1561 static int
wl_ext_set_bgnmode(struct wl_if_info * cur_if)1562 wl_ext_set_bgnmode(struct wl_if_info *cur_if)
1563 {
1564 	struct net_device *dev = cur_if->dev;
1565 	bgnmode_t bgnmode = cur_if->bgnmode;
1566 	int val;
1567 
1568 	if (bgnmode == 0)
1569 		return 0;
1570 
1571 	wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
1572 	if (bgnmode == IEEE80211B) {
1573 		wl_ext_iovar_setint(dev, "nmode", 0);
1574 		val = 0;
1575 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
1576 		AEXT_TRACE(dev->name, "Network mode: B only\n");
1577 	} else if (bgnmode == IEEE80211G) {
1578 		wl_ext_iovar_setint(dev, "nmode", 0);
1579 		val = 2;
1580 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
1581 		AEXT_TRACE(dev->name, "Network mode: G only\n");
1582 	} else if (bgnmode == IEEE80211BG) {
1583 		wl_ext_iovar_setint(dev, "nmode", 0);
1584 		val = 1;
1585 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
1586 		AEXT_TRACE(dev->name, "Network mode: B/G mixed\n");
1587 	} else if (bgnmode == IEEE80211BGN) {
1588 		wl_ext_iovar_setint(dev, "nmode", 0);
1589 		wl_ext_iovar_setint(dev, "nmode", 1);
1590 		wl_ext_iovar_setint(dev, "vhtmode", 0);
1591 		val = 1;
1592 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
1593 		AEXT_TRACE(dev->name, "Network mode: B/G/N mixed\n");
1594 	} else if (bgnmode == IEEE80211BGNAC) {
1595 		wl_ext_iovar_setint(dev, "nmode", 0);
1596 		wl_ext_iovar_setint(dev, "nmode", 1);
1597 		wl_ext_iovar_setint(dev, "vhtmode", 1);
1598 		val = 1;
1599 		wl_ext_ioctl(dev, WLC_SET_GMODE, &val, sizeof(val), 1);
1600 		AEXT_TRACE(dev->name, "Network mode: B/G/N/AC mixed\n");
1601 	}
1602 	wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
1603 
1604 	return 0;
1605 }
1606 
1607 static int
wl_ext_set_amode(struct wl_if_info * cur_if)1608 wl_ext_set_amode(struct wl_if_info *cur_if)
1609 {
1610 	struct net_device *dev = cur_if->dev;
1611 	authmode_t amode = cur_if->amode;
1612 	int auth=0, wpa_auth=0;
1613 
1614 #ifdef WLMESH
1615 	if (cur_if->ifmode == IMESH_MODE) {
1616 		if (amode == AUTH_SAE) {
1617 			auth = WL_AUTH_OPEN_SYSTEM;
1618 			wpa_auth = WPA2_AUTH_PSK;
1619 			AEXT_INFO(dev->name, "SAE\n");
1620 		} else {
1621 			auth = WL_AUTH_OPEN_SYSTEM;
1622 			wpa_auth = WPA_AUTH_DISABLED;
1623 			AEXT_INFO(dev->name, "Open System\n");
1624 		}
1625 	} else
1626 #endif /* WLMESH */
1627 	if (amode == AUTH_OPEN) {
1628 		auth = WL_AUTH_OPEN_SYSTEM;
1629 		wpa_auth = WPA_AUTH_DISABLED;
1630 		AEXT_INFO(dev->name, "Open System\n");
1631 	} else if (amode == AUTH_SHARED) {
1632 		auth = WL_AUTH_SHARED_KEY;
1633 		wpa_auth = WPA_AUTH_DISABLED;
1634 		AEXT_INFO(dev->name, "Shared Key\n");
1635 	} else if (amode == AUTH_WPAPSK) {
1636 		auth = WL_AUTH_OPEN_SYSTEM;
1637 		wpa_auth = WPA_AUTH_PSK;
1638 		AEXT_INFO(dev->name, "WPA-PSK\n");
1639 	} else if (amode == AUTH_WPA2PSK) {
1640 		auth = WL_AUTH_OPEN_SYSTEM;
1641 		wpa_auth = WPA2_AUTH_PSK;
1642 		AEXT_INFO(dev->name, "WPA2-PSK\n");
1643 	} else if (amode == AUTH_WPAWPA2PSK) {
1644 		auth = WL_AUTH_OPEN_SYSTEM;
1645 		wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK;
1646 		AEXT_INFO(dev->name, "WPA/WPA2-PSK\n");
1647 	}
1648 #ifdef WLMESH
1649 	if (cur_if->ifmode == IMESH_MODE) {
1650 		s32 val = WL_BSSTYPE_MESH;
1651 		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
1652 	} else
1653 #endif /* WLMESH */
1654 	if (cur_if->ifmode == ISTA_MODE) {
1655 		s32 val = WL_BSSTYPE_INFRA;
1656 		wl_ext_ioctl(dev, WLC_SET_INFRA, &val, sizeof(val), 1);
1657 	}
1658 	wl_ext_iovar_setint(dev, "auth", auth);
1659 
1660 	wl_ext_iovar_setint(dev, "wpa_auth", wpa_auth);
1661 
1662 	return 0;
1663 }
1664 
1665 static int
wl_ext_set_emode(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)1666 wl_ext_set_emode(struct wl_apsta_params *apsta_params,
1667 	struct wl_if_info *cur_if)
1668 {
1669 	struct net_device *dev = cur_if->dev;
1670 	int wsec=0;
1671 	struct wl_wsec_key wsec_key;
1672 	wsec_pmk_t psk;
1673 	authmode_t amode = cur_if->amode;
1674 	encmode_t emode = cur_if->emode;
1675 	char *key = cur_if->key;
1676 	struct dhd_pub *dhd = apsta_params->dhd;
1677 
1678 	memset(&wsec_key, 0, sizeof(wsec_key));
1679 	memset(&psk, 0, sizeof(psk));
1680 
1681 #ifdef WLMESH
1682 	if (cur_if->ifmode == IMESH_MODE) {
1683 		if (amode == AUTH_SAE) {
1684 			wsec = AES_ENABLED;
1685 		} else {
1686 			wsec = WSEC_NONE;
1687 		}
1688 	} else
1689 #endif /* WLMESH */
1690 	if (emode == ENC_NONE) {
1691 		wsec = WSEC_NONE;
1692 		AEXT_INFO(dev->name, "No securiy\n");
1693 	} else if (emode == ENC_WEP) {
1694 		wsec = WEP_ENABLED;
1695 		wl_ext_parse_wep(key, &wsec_key);
1696 		AEXT_INFO(dev->name, "WEP key \"%s\"\n", wsec_key.data);
1697 	} else if (emode == ENC_TKIP) {
1698 		wsec = TKIP_ENABLED;
1699 		psk.key_len = strlen(key);
1700 		psk.flags = WSEC_PASSPHRASE;
1701 		memcpy(psk.key, key, strlen(key));
1702 		AEXT_INFO(dev->name, "TKIP key \"%s\"\n", psk.key);
1703 	} else if (emode == ENC_AES || amode == AUTH_SAE) {
1704 		wsec = AES_ENABLED;
1705 		psk.key_len = strlen(key);
1706 		psk.flags = WSEC_PASSPHRASE;
1707 		memcpy(psk.key, key, strlen(key));
1708 		AEXT_INFO(dev->name, "AES key \"%s\"\n", psk.key);
1709 	} else if (emode == ENC_TKIPAES) {
1710 		wsec = TKIP_ENABLED | AES_ENABLED;
1711 		psk.key_len = strlen(key);
1712 		psk.flags = WSEC_PASSPHRASE;
1713 		memcpy(psk.key, key, strlen(key));
1714 		AEXT_INFO(dev->name, "TKIP/AES key \"%s\"\n", psk.key);
1715 	}
1716 	if (dhd->conf->chip == BCM43430_CHIP_ID && cur_if->ifidx > 0 && wsec >= 2 &&
1717 			apsta_params->apstamode == ISTAAP_MODE) {
1718 		wsec |= WSEC_SWFLAG; // terence 20180628: fix me, this is a workaround
1719 	}
1720 
1721 	wl_ext_iovar_setint(dev, "wsec", wsec);
1722 
1723 #ifdef WLMESH
1724 	if (cur_if->ifmode == IMESH_MODE) {
1725 		if (amode == AUTH_SAE) {
1726 			s8 iovar_buf[WLC_IOCTL_SMLEN];
1727 			AEXT_INFO(dev->name, "AES key \"%s\"\n", key);
1728 			wl_ext_iovar_setint(dev, "mesh_auth_proto", 1);
1729 			wl_ext_iovar_setint(dev, "mfp", WL_MFP_REQUIRED);
1730 			wl_ext_iovar_setbuf(dev, "sae_password", key, strlen(key),
1731 				iovar_buf, WLC_IOCTL_SMLEN, NULL);
1732 		} else {
1733 			AEXT_INFO(dev->name, "No securiy\n");
1734 			wl_ext_iovar_setint(dev, "mesh_auth_proto", 0);
1735 			wl_ext_iovar_setint(dev, "mfp", WL_MFP_NONE);
1736 		}
1737 	} else
1738 #endif /* WLMESH */
1739 	if (emode == ENC_WEP) {
1740 		wl_ext_ioctl(dev, WLC_SET_KEY, &wsec_key, sizeof(wsec_key), 1);
1741 	} else if (emode == ENC_TKIP || emode == ENC_AES || emode == ENC_TKIPAES) {
1742 		if (cur_if->ifmode == ISTA_MODE)
1743 			wl_ext_iovar_setint(dev, "sup_wpa", 1);
1744 		wl_ext_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk), 1);
1745 	}
1746 
1747 	return 0;
1748 }
1749 
1750 static u32
wl_ext_get_chanspec(struct wl_apsta_params * apsta_params,struct net_device * dev)1751 wl_ext_get_chanspec(struct wl_apsta_params *apsta_params,
1752 	struct net_device *dev)
1753 {
1754 	int ret = 0;
1755 	struct ether_addr bssid;
1756 	u32 chanspec = 0;
1757 
1758 	ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
1759 	if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
1760 		if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
1761 			chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
1762 			return chanspec;
1763 		}
1764 	}
1765 
1766 	return 0;
1767 }
1768 
1769 static uint16
wl_ext_get_chan(struct wl_apsta_params * apsta_params,struct net_device * dev)1770 wl_ext_get_chan(struct wl_apsta_params *apsta_params, struct net_device *dev)
1771 {
1772 	int ret = 0;
1773 	uint16 chan = 0, ctl_chan;
1774 	struct ether_addr bssid;
1775 	u32 chanspec = 0;
1776 
1777 	ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
1778 	if (ret != BCME_NOTASSOCIATED && memcmp(&ether_null, &bssid, ETHER_ADDR_LEN)) {
1779 		if (wl_ext_iovar_getint(dev, "chanspec", (s32 *)&chanspec) == BCME_OK) {
1780 			chanspec = wl_ext_chspec_driver_to_host(apsta_params->ioctl_ver, chanspec);
1781 			ctl_chan = wf_chspec_ctlchan(chanspec);
1782 			chan = (u16)(ctl_chan & 0x00FF);
1783 			return chan;
1784 		}
1785 	}
1786 
1787 	return 0;
1788 }
1789 
1790 static chanspec_t
wl_ext_chan_to_chanspec(struct wl_apsta_params * apsta_params,struct net_device * dev,uint16 channel)1791 wl_ext_chan_to_chanspec(struct wl_apsta_params *apsta_params,
1792 	struct net_device *dev, uint16 channel)
1793 {
1794 	s32 _chan = channel;
1795 	chanspec_t chspec = 0;
1796 	chanspec_t fw_chspec = 0;
1797 	u32 bw = WL_CHANSPEC_BW_20;
1798 	s32 err = BCME_OK;
1799 	s32 bw_cap = 0;
1800 	s8 iovar_buf[WLC_IOCTL_SMLEN];
1801 	struct {
1802 		u32 band;
1803 		u32 bw_cap;
1804 	} param = {0, 0};
1805 	uint band;
1806 
1807 	if (_chan <= CH_MAX_2G_CHANNEL)
1808 		band = IEEE80211_BAND_2GHZ;
1809 	else
1810 		band = IEEE80211_BAND_5GHZ;
1811 
1812 	if (band == IEEE80211_BAND_5GHZ) {
1813 		param.band = WLC_BAND_5G;
1814 		err = wl_ext_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
1815 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
1816 		if (err) {
1817 			if (err != BCME_UNSUPPORTED) {
1818 				AEXT_ERROR(dev->name, "bw_cap failed, %d\n", err);
1819 				return err;
1820 			} else {
1821 				err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
1822 				if (bw_cap != WLC_N_BW_20ALL)
1823 					bw = WL_CHANSPEC_BW_40;
1824 			}
1825 		} else {
1826 			if (WL_BW_CAP_80MHZ(iovar_buf[0]))
1827 				bw = WL_CHANSPEC_BW_80;
1828 			else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
1829 				bw = WL_CHANSPEC_BW_40;
1830 			else
1831 				bw = WL_CHANSPEC_BW_20;
1832 		}
1833 	}
1834 	else if (band == IEEE80211_BAND_2GHZ)
1835 		bw = WL_CHANSPEC_BW_20;
1836 
1837 set_channel:
1838 	chspec = wf_channel2chspec(_chan, bw);
1839 	if (wf_chspec_valid(chspec)) {
1840 		fw_chspec = wl_ext_chspec_host_to_driver(apsta_params->ioctl_ver, chspec);
1841 		if (fw_chspec == INVCHANSPEC) {
1842 			AEXT_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n");
1843 			fw_chspec = 0;
1844 		}
1845 	} else {
1846 		if (bw == WL_CHANSPEC_BW_80)
1847 			bw = WL_CHANSPEC_BW_40;
1848 		else if (bw == WL_CHANSPEC_BW_40)
1849 			bw = WL_CHANSPEC_BW_20;
1850 		else
1851 			bw = 0;
1852 		if (bw)
1853 			goto set_channel;
1854 		AEXT_ERROR(dev->name, "Invalid chanspec 0x%x\n", chspec);
1855 		err = BCME_ERROR;
1856 	}
1857 
1858 	return fw_chspec;
1859 }
1860 
1861 static bool
wl_ext_radar_detect(struct net_device * dev)1862 wl_ext_radar_detect(struct net_device *dev)
1863 {
1864 	int ret = BCME_OK;
1865 	bool radar = FALSE;
1866 	s32 val = 0;
1867 
1868 	if ((ret = wldev_ioctl(dev, WLC_GET_RADAR, &val, sizeof(int), false) == 0)) {
1869 		radar = TRUE;
1870 	}
1871 
1872 	return radar;
1873 }
1874 
1875 #if defined(WL_CFG80211) || (defined(WLMESH) && defined(WL_ESCAN))
1876 static struct wl_if_info *
wl_ext_if_enabled(struct wl_apsta_params * apsta_params,ifmode_t ifmode)1877 wl_ext_if_enabled(struct wl_apsta_params *apsta_params, ifmode_t ifmode)
1878 {
1879 	struct wl_if_info *tmp_if, *target_if = NULL;
1880 	int i;
1881 
1882 	for (i=0; i<MAX_IF_NUM; i++) {
1883 		tmp_if = &apsta_params->if_info[i];
1884 		if (tmp_if && tmp_if->ifmode == ifmode &&
1885 				wl_get_isam_status(tmp_if, IF_READY)) {
1886 			if (wl_ext_get_chan(apsta_params, tmp_if->dev)) {
1887 				target_if = tmp_if;
1888 				break;
1889 			}
1890 		}
1891 	}
1892 
1893 	return target_if;
1894 }
1895 #endif
1896 
1897 #ifndef WL_STATIC_IF
1898 s32
wl_ext_add_del_bss(struct net_device * ndev,s32 bsscfg_idx,int iftype,s32 del,u8 * addr)1899 wl_ext_add_del_bss(struct net_device *ndev, s32 bsscfg_idx,
1900 	int iftype, s32 del, u8 *addr)
1901 {
1902 	s32 ret = BCME_OK;
1903 	s32 val = 0;
1904 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
1905 	struct {
1906 		s32 cfg;
1907 		s32 val;
1908 		struct ether_addr ea;
1909 	} bss_setbuf;
1910 
1911 	AEXT_TRACE(ndev->name, "wl_iftype:%d del:%d \n", iftype, del);
1912 
1913 	bzero(&bss_setbuf, sizeof(bss_setbuf));
1914 
1915 	/* AP=2, STA=3, up=1, down=0, val=-1 */
1916 	if (del) {
1917 		val = WLC_AP_IOV_OP_DELETE;
1918 	} else if (iftype == WL_INTERFACE_TYPE_AP) {
1919 		/* Add/role change to AP Interface */
1920 		AEXT_TRACE(ndev->name, "Adding AP Interface\n");
1921 		val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
1922 	} else if (iftype == WL_INTERFACE_TYPE_STA) {
1923 		/* Add/role change to STA Interface */
1924 		AEXT_TRACE(ndev->name, "Adding STA Interface\n");
1925 		val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
1926 	} else {
1927 		AEXT_ERROR(ndev->name, "add_del_bss NOT supported for IFACE type:0x%x", iftype);
1928 		return -EINVAL;
1929 	}
1930 
1931 	if (!del) {
1932 		wl_ext_bss_iovar_war(ndev, &val);
1933 	}
1934 
1935 	bss_setbuf.cfg = htod32(bsscfg_idx);
1936 	bss_setbuf.val = htod32(val);
1937 
1938 	if (addr) {
1939 		memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
1940 	}
1941 
1942 	AEXT_INFO(ndev->name, "wl bss %d bssidx:%d\n", val, bsscfg_idx);
1943 	ret = wl_ext_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
1944 		ioctl_buf, WLC_IOCTL_SMLEN, NULL);
1945 	if (ret != 0)
1946 		AEXT_ERROR(ndev->name, "'bss %d' failed with %d\n", val, ret);
1947 
1948 	return ret;
1949 }
1950 
1951 static int
wl_ext_interface_ops(struct net_device * dev,struct wl_apsta_params * apsta_params,int iftype,u8 * addr)1952 wl_ext_interface_ops(struct net_device *dev,
1953 	struct wl_apsta_params *apsta_params, int iftype, u8 *addr)
1954 {
1955 	s32 ret;
1956 	struct wl_interface_create_v2 iface;
1957 	wl_interface_create_v3_t iface_v3;
1958 	struct wl_interface_info_v1 *info;
1959 	wl_interface_info_v2_t *info_v2;
1960 	uint32 ifflags = 0;
1961 	bool use_iface_info_v2 = false;
1962 	u8 ioctl_buf[WLC_IOCTL_SMLEN];
1963 	wl_wlc_version_t wlc_ver;
1964 
1965 	/* Interface create */
1966 	bzero(&iface, sizeof(iface));
1967 
1968 	if (addr) {
1969 		ifflags |= WL_INTERFACE_MAC_USE;
1970 	}
1971 
1972 	ret = wldev_iovar_getbuf(dev, "wlc_ver", NULL, 0,
1973 		&wlc_ver, sizeof(wl_wlc_version_t), NULL);
1974 	if ((ret == BCME_OK) && (wlc_ver.wlc_ver_major >= 5)) {
1975 		ret = wldev_iovar_getbuf(dev, "interface_create",
1976 			&iface, sizeof(struct wl_interface_create_v2),
1977 			ioctl_buf, sizeof(ioctl_buf), NULL);
1978 		if ((ret == BCME_OK) && (*((uint32 *)ioctl_buf) == WL_INTERFACE_CREATE_VER_3)) {
1979 			use_iface_info_v2 = true;
1980 			bzero(&iface_v3, sizeof(wl_interface_create_v3_t));
1981 			iface_v3.ver = WL_INTERFACE_CREATE_VER_3;
1982 			iface_v3.iftype = iftype;
1983 			iface_v3.flags = ifflags;
1984 			if (addr) {
1985 				memcpy(&iface_v3.mac_addr.octet, addr, ETH_ALEN);
1986 			}
1987 			ret = wl_ext_iovar_getbuf(dev, "interface_create",
1988 				&iface_v3, sizeof(wl_interface_create_v3_t),
1989 				ioctl_buf, sizeof(ioctl_buf), NULL);
1990 			if (unlikely(ret)) {
1991 				AEXT_ERROR(dev->name, "Interface v3 create failed!! ret %d\n", ret);
1992 				return ret;
1993 			}
1994 		}
1995 	}
1996 
1997 	/* success case */
1998 	if (use_iface_info_v2 == true) {
1999 		info_v2 = (wl_interface_info_v2_t *)ioctl_buf;
2000 		ret = info_v2->bsscfgidx;
2001 	} else {
2002 		/* Use v1 struct */
2003 		iface.ver = WL_INTERFACE_CREATE_VER_2;
2004 		iface.iftype = iftype;
2005 		iface.flags = iftype | ifflags;
2006 		if (addr) {
2007 			memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
2008 		}
2009 		ret = wldev_iovar_getbuf(dev, "interface_create",
2010 			&iface, sizeof(struct wl_interface_create_v2),
2011 			ioctl_buf, sizeof(ioctl_buf), NULL);
2012 		if (ret == BCME_OK) {
2013 			info = (struct wl_interface_info_v1 *)ioctl_buf;
2014 			ret = info->bsscfgidx;
2015 		}
2016 	}
2017 
2018 	AEXT_INFO(dev->name, "wl interface create success!! bssidx:%d \n", ret);
2019 	return ret;
2020 }
2021 
2022 static void
wl_ext_wait_netif_change(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)2023 wl_ext_wait_netif_change(struct wl_apsta_params *apsta_params,
2024 	struct wl_if_info *cur_if)
2025 {
2026 	rtnl_unlock();
2027 	wait_event_interruptible_timeout(apsta_params->netif_change_event,
2028 		wl_get_isam_status(cur_if, IF_READY),
2029 		msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
2030 	rtnl_lock();
2031 }
2032 
2033 static void
wl_ext_interface_create(struct net_device * dev,struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,int iftype,u8 * addr)2034 wl_ext_interface_create(struct net_device *dev, struct wl_apsta_params *apsta_params,
2035 	struct wl_if_info *cur_if, int iftype, u8 *addr)
2036 {
2037 	s32 ret;
2038 
2039 	wl_set_isam_status(cur_if, IF_ADDING);
2040 	ret = wl_ext_interface_ops(dev, apsta_params, iftype, addr);
2041 	if (ret == BCME_UNSUPPORTED) {
2042 		wl_ext_add_del_bss(dev, 1, iftype, 0, addr);
2043 	}
2044 	wl_ext_wait_netif_change(apsta_params, cur_if);
2045 }
2046 
2047 static void
wl_ext_iapsta_intf_add(struct net_device * dev,struct wl_apsta_params * apsta_params)2048 wl_ext_iapsta_intf_add(struct net_device *dev, struct wl_apsta_params *apsta_params)
2049 {
2050 	struct dhd_pub *dhd;
2051 	apstamode_t apstamode = apsta_params->apstamode;
2052 	struct wl_if_info *cur_if;
2053 	s8 iovar_buf[WLC_IOCTL_SMLEN];
2054 	wl_p2p_if_t ifreq;
2055 	struct ether_addr mac_addr;
2056 
2057 	dhd = dhd_get_pub(dev);
2058 	bzero(&mac_addr, sizeof(mac_addr));
2059 
2060 	if (apstamode == ISTAAP_MODE) {
2061 		cur_if = &apsta_params->if_info[IF_VIF];
2062 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
2063 	}
2064 	else if (apstamode == ISTAGO_MODE) {
2065 		bzero(&ifreq, sizeof(wl_p2p_if_t));
2066 		ifreq.type = htod32(WL_P2P_IF_GO);
2067 		cur_if = &apsta_params->if_info[IF_VIF];
2068 		wl_set_isam_status(cur_if, IF_ADDING);
2069 		wl_ext_iovar_setbuf(dev, "p2p_ifadd", &ifreq, sizeof(ifreq),
2070 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
2071 		wl_ext_wait_netif_change(apsta_params, cur_if);
2072 	}
2073 	else if (apstamode == ISTASTA_MODE) {
2074 		cur_if = &apsta_params->if_info[IF_VIF];
2075 		memcpy(&mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
2076 		mac_addr.octet[0] |= 0x02;
2077 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_STA,
2078 			(u8*)&mac_addr);
2079 	}
2080 	else if (apstamode == IDUALAP_MODE) {
2081 		cur_if = &apsta_params->if_info[IF_VIF];
2082 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
2083 	}
2084 	else if (apstamode == ISTAAPAP_MODE) {
2085 		u8 rand_bytes[2] = {0, };
2086 		get_random_bytes(&rand_bytes, sizeof(rand_bytes));
2087 		cur_if = &apsta_params->if_info[IF_VIF];
2088 		memcpy(&mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
2089 		mac_addr.octet[0] |= 0x02;
2090 		mac_addr.octet[5] += 0x01;
2091 		memcpy(&mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
2092 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP,
2093 			(u8*)&mac_addr);
2094 		cur_if = &apsta_params->if_info[IF_VIF2];
2095 		memcpy(&mac_addr, dev->dev_addr, ETHER_ADDR_LEN);
2096 		mac_addr.octet[0] |= 0x02;
2097 		mac_addr.octet[5] += 0x02;
2098 		memcpy(&mac_addr.octet[3], rand_bytes, sizeof(rand_bytes));
2099 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP,
2100 			(u8*)&mac_addr);
2101 	}
2102 #ifdef WLMESH
2103 	else if (apstamode == ISTAMESH_MODE) {
2104 		cur_if = &apsta_params->if_info[IF_VIF];
2105 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_STA, NULL);
2106 	}
2107 	else if (apstamode == IMESHAP_MODE) {
2108 		cur_if = &apsta_params->if_info[IF_VIF];
2109 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
2110 	}
2111 	else if (apstamode == ISTAAPMESH_MODE) {
2112 		cur_if = &apsta_params->if_info[IF_VIF];
2113 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
2114 		cur_if = &apsta_params->if_info[IF_VIF2];
2115 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_STA, NULL);
2116 	}
2117 	else if (apstamode == IMESHAPAP_MODE) {
2118 		cur_if = &apsta_params->if_info[IF_VIF];
2119 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
2120 		cur_if = &apsta_params->if_info[IF_VIF2];
2121 		wl_ext_interface_create(dev, apsta_params, cur_if, WL_INTERFACE_TYPE_AP, NULL);
2122 	}
2123 #endif /* WLMESH */
2124 
2125 }
2126 #endif /* WL_STATIC_IF */
2127 
2128 static void
wl_ext_iapsta_preinit(struct net_device * dev,struct wl_apsta_params * apsta_params)2129 wl_ext_iapsta_preinit(struct net_device *dev, struct wl_apsta_params *apsta_params)
2130 {
2131 	struct dhd_pub *dhd;
2132 	apstamode_t apstamode = apsta_params->apstamode;
2133 	struct wl_if_info *cur_if;
2134 	s8 iovar_buf[WLC_IOCTL_SMLEN];
2135 	s32 val = 0;
2136 	int i;
2137 
2138 	dhd = dhd_get_pub(dev);
2139 
2140 	for (i=0; i<MAX_IF_NUM; i++) {
2141 		cur_if = &apsta_params->if_info[i];
2142 		if (i >= 1 && !strlen(cur_if->ifname))
2143 			snprintf(cur_if->ifname, IFNAMSIZ, "wlan%d", i);
2144 		if (cur_if->ifmode == ISTA_MODE) {
2145 			cur_if->channel = 0;
2146 			cur_if->maxassoc = -1;
2147 			cur_if->prio = PRIO_STA;
2148 			cur_if->prefix = 'S';
2149 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
2150 		} else if (cur_if->ifmode == IAP_MODE) {
2151 			cur_if->channel = 1;
2152 			cur_if->maxassoc = -1;
2153 			cur_if->prio = PRIO_AP;
2154 			cur_if->prefix = 'A';
2155 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
2156 #ifdef WLMESH
2157 		} else if (cur_if->ifmode == IMESH_MODE) {
2158 			cur_if->channel = 1;
2159 			cur_if->maxassoc = -1;
2160 			cur_if->prio = PRIO_MESH;
2161 			cur_if->prefix = 'M';
2162 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
2163 #ifdef WL_ESCAN
2164 			if (i == 0 && apsta_params->macs)
2165 				wl_mesh_escan_attach(dhd, cur_if);
2166 #endif /* WL_ESCAN */
2167 #endif /* WLMESH */
2168 		}
2169 	}
2170 
2171 	if (FW_SUPPORTED(dhd, rsdb)) {
2172 		if (apstamode == IDUALAP_MODE)
2173 			apsta_params->rsdb = -1;
2174 		else if (apstamode == ISTAAPAP_MODE)
2175 			apsta_params->rsdb = 0;
2176 		if (apstamode == ISTAAPAP_MODE || apstamode == IDUALAP_MODE ||
2177 				apstamode == IMESHONLY_MODE || apstamode == ISTAMESH_MODE ||
2178 				apstamode == IMESHAP_MODE || apstamode == ISTAAPMESH_MODE ||
2179 				apstamode == IMESHAPAP_MODE) {
2180 			wl_config_t rsdb_mode_cfg = {0, 0};
2181 			rsdb_mode_cfg.config = apsta_params->rsdb;
2182 			AEXT_INFO(dev->name, "set rsdb_mode %d\n", rsdb_mode_cfg.config);
2183 			wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2184 			wl_ext_iovar_setbuf(dev, "rsdb_mode", &rsdb_mode_cfg,
2185 				sizeof(rsdb_mode_cfg), iovar_buf, sizeof(iovar_buf), NULL);
2186 			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2187 		}
2188 	} else {
2189 		apsta_params->rsdb = 0;
2190 	}
2191 
2192 	if (apstamode == ISTAONLY_MODE) {
2193 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2194 		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
2195 		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
2196 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2197 	} else if (apstamode == IAPONLY_MODE) {
2198 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2199 #ifdef ARP_OFFLOAD_SUPPORT
2200 		/* IF SoftAP is enabled, disable arpoe */
2201 		dhd_arp_offload_set(dhd, 0);
2202 		dhd_arp_offload_enable(dhd, FALSE);
2203 #endif /* ARP_OFFLOAD_SUPPORT */
2204 		wl_ext_iovar_setint(dev, "mpc", 0);
2205 		wl_ext_iovar_setint(dev, "apsta", 0);
2206 		val = 1;
2207 		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
2208 #ifdef PROP_TXSTATUS_VSDB
2209 #if defined(BCMSDIO)
2210 		if (!(FW_SUPPORTED(dhd, rsdb)) && !disable_proptx) {
2211 			bool enabled;
2212 			dhd_wlfc_get_enable(dhd, &enabled);
2213 			if (!enabled) {
2214 				dhd_wlfc_init(dhd);
2215 				wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2216 			}
2217 		}
2218 #endif /* BCMSDIO */
2219 #endif /* PROP_TXSTATUS_VSDB */
2220 	}
2221 	else if (apstamode == ISTAAP_MODE) {
2222 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2223 		wl_ext_iovar_setint(dev, "mpc", 0);
2224 		wl_ext_iovar_setint(dev, "apsta", 1);
2225 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2226 	}
2227 	else if (apstamode == ISTAGO_MODE) {
2228 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2229 		wl_ext_iovar_setint(dev, "apsta", 1);
2230 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2231 	}
2232 	else if (apstamode == ISTASTA_MODE) {
2233 	}
2234 	else if (apstamode == IDUALAP_MODE) {
2235 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2236 		/* IF SoftAP is enabled, disable arpoe or wlan1 will ping fail */
2237 #ifdef ARP_OFFLOAD_SUPPORT
2238 		/* IF SoftAP is enabled, disable arpoe */
2239 		dhd_arp_offload_set(dhd, 0);
2240 		dhd_arp_offload_enable(dhd, FALSE);
2241 #endif /* ARP_OFFLOAD_SUPPORT */
2242 		wl_ext_iovar_setint(dev, "mpc", 0);
2243 		wl_ext_iovar_setint(dev, "mbcn", 1);
2244 		wl_ext_iovar_setint(dev, "apsta", 0);
2245 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2246 		val = 1;
2247 		wl_ext_ioctl(dev, WLC_SET_AP, &val, sizeof(val), 1);
2248 	}
2249 	else if (apstamode == ISTAAPAP_MODE) {
2250 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2251 		wl_ext_iovar_setint(dev, "mpc", 0);
2252 		wl_ext_iovar_setint(dev, "mbss", 1);
2253 		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
2254 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2255 		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
2256 	}
2257 #ifdef WLMESH
2258 	else if (apstamode == IMESHONLY_MODE || apstamode == ISTAMESH_MODE ||
2259 			apstamode == IMESHAP_MODE || apstamode == ISTAAPMESH_MODE ||
2260 			apstamode == IMESHAPAP_MODE) {
2261 		int pm = 0;
2262 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
2263 		wl_ext_iovar_setint(dev, "mpc", 0);
2264 		if (apstamode == IMESHONLY_MODE)
2265 			wl_ext_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), 1);
2266 		else
2267 			wl_ext_iovar_setint(dev, "mbcn", 1);
2268 		wl_ext_iovar_setint(dev, "apsta", 1); // keep 1 as we set in dhd_preinit_ioctls
2269 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
2270 		// don't set WLC_SET_AP to 0, some parameters will be reset, such as bcn_timeout and roam_off
2271 	}
2272 #endif /* WLMESH */
2273 
2274 	wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
2275 	apsta_params->init = TRUE;
2276 
2277 	WL_MSG(dev->name, "apstamode=%d\n", apstamode);
2278 }
2279 
2280 static int
wl_ext_isam_param(struct net_device * dev,char * command,int total_len)2281 wl_ext_isam_param(struct net_device *dev, char *command, int total_len)
2282 {
2283 	struct dhd_pub *dhd = dhd_get_pub(dev);
2284 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2285 	int ret = -1;
2286 	char *pick_tmp, *data, *param;
2287 	int bytes_written=-1;
2288 
2289 	AEXT_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
2290 
2291 	pick_tmp = command;
2292 	param = bcmstrtok(&pick_tmp, " ", 0); // pick isam_param
2293 	param = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
2294 	while (param != NULL) {
2295 		data = bcmstrtok(&pick_tmp, " ", 0); // pick data
2296 		if (!strcmp(param, "acs")) {
2297 			if (data) {
2298 				apsta_params->acs = simple_strtol(data, NULL, 0);
2299 				ret = 0;
2300 			} else {
2301 				bytes_written = snprintf(command, total_len, "%d", apsta_params->acs);
2302 				ret = bytes_written;
2303 				goto exit;
2304 			}
2305 		}
2306 		param = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
2307 	}
2308 
2309 exit:
2310 	return ret;
2311 }
2312 
2313 static int
wl_ext_isam_init(struct net_device * dev,char * command,int total_len)2314 wl_ext_isam_init(struct net_device *dev, char *command, int total_len)
2315 {
2316 	struct dhd_pub *dhd = dhd_get_pub(dev);
2317 	char *pch, *pick_tmp, *pick_tmp2, *param;
2318 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2319 	int i;
2320 
2321 	if (apsta_params->init) {
2322 		AEXT_ERROR(dev->name, "don't init twice\n");
2323 		return -1;
2324 	}
2325 	AEXT_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
2326 
2327 	pick_tmp = command;
2328 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_init
2329 	param = bcmstrtok(&pick_tmp, " ", 0);
2330 	while (param != NULL) {
2331 		pick_tmp2 = bcmstrtok(&pick_tmp, " ", 0);
2332 		if (!pick_tmp2) {
2333 			AEXT_ERROR(dev->name, "wrong param %s\n", param);
2334 			return -1;
2335 		}
2336 		if (!strcmp(param, "mode")) {
2337 			pch = NULL;
2338 			if (!strcmp(pick_tmp2, "sta")) {
2339 				apsta_params->apstamode = ISTAONLY_MODE;
2340 			} else if (!strcmp(pick_tmp2, "ap")) {
2341 				apsta_params->apstamode = IAPONLY_MODE;
2342 			} else if (!strcmp(pick_tmp2, "sta-ap")) {
2343 				apsta_params->apstamode = ISTAAP_MODE;
2344 			} else if (!strcmp(pick_tmp2, "sta-sta")) {
2345 				apsta_params->apstamode = ISTASTA_MODE;
2346 				apsta_params->vsdb = TRUE;
2347 			} else if (!strcmp(pick_tmp2, "ap-ap")) {
2348 				apsta_params->apstamode = IDUALAP_MODE;
2349 			} else if (!strcmp(pick_tmp2, "sta-ap-ap")) {
2350 				apsta_params->apstamode = ISTAAPAP_MODE;
2351 			} else if (!strcmp(pick_tmp2, "apsta")) {
2352 				apsta_params->apstamode = ISTAAP_MODE;
2353 				apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
2354 				apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
2355 			} else if (!strcmp(pick_tmp2, "dualap")) {
2356 				apsta_params->apstamode = IDUALAP_MODE;
2357 				apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
2358 				apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
2359 			} else if (!strcmp(pick_tmp2, "sta-go") ||
2360 					!strcmp(pick_tmp2, "gosta")) {
2361 				if (!FW_SUPPORTED(dhd, p2p)) {
2362 					return -1;
2363 				}
2364 				apsta_params->apstamode = ISTAGO_MODE;
2365 				apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
2366 				apsta_params->if_info[IF_VIF].ifmode = IAP_MODE;
2367 #ifdef WLMESH
2368 			} else if (!strcmp(pick_tmp2, "mesh")) {
2369 				apsta_params->apstamode = IMESHONLY_MODE;
2370 			} else if (!strcmp(pick_tmp2, "sta-mesh")) {
2371 				apsta_params->apstamode = ISTAMESH_MODE;
2372 			} else if (!strcmp(pick_tmp2, "sta-ap-mesh")) {
2373 				apsta_params->apstamode = ISTAAPMESH_MODE;
2374 			} else if (!strcmp(pick_tmp2, "mesh-ap")) {
2375 				apsta_params->apstamode = IMESHAP_MODE;
2376 			} else if (!strcmp(pick_tmp2, "mesh-ap-ap")) {
2377 				apsta_params->apstamode = IMESHAPAP_MODE;
2378 #endif /* WLMESH */
2379 			} else {
2380 				AEXT_ERROR(dev->name, "mode [sta|ap|sta-ap|ap-ap]\n");
2381 				return -1;
2382 			}
2383 			pch = bcmstrtok(&pick_tmp2, " -", 0);
2384 			for (i=0; i<MAX_IF_NUM && pch; i++) {
2385 				if (!strcmp(pch, "sta"))
2386 					apsta_params->if_info[i].ifmode = ISTA_MODE;
2387 				else if (!strcmp(pch, "ap"))
2388 					apsta_params->if_info[i].ifmode = IAP_MODE;
2389 #ifdef WLMESH
2390 				else if (!strcmp(pch, "mesh")) {
2391 					if (dhd->conf->fw_type != FW_TYPE_MESH) {
2392 						AEXT_ERROR(dev->name, "wrong fw type\n");
2393 						return -1;
2394 					}
2395 					apsta_params->if_info[i].ifmode = IMESH_MODE;
2396 				}
2397 #endif /* WLMESH */
2398 				pch = bcmstrtok(&pick_tmp2, " -", 0);
2399 			}
2400 		}
2401 		else if (!strcmp(param, "rsdb")) {
2402 			apsta_params->rsdb = (int)simple_strtol(pick_tmp2, NULL, 0);
2403 		} else if (!strcmp(param, "vsdb")) {
2404 			if (!strcmp(pick_tmp2, "y")) {
2405 				apsta_params->vsdb = TRUE;
2406 			} else if (!strcmp(pick_tmp2, "n")) {
2407 				apsta_params->vsdb = FALSE;
2408 			} else {
2409 				AEXT_ERROR(dev->name, "vsdb [y|n]\n");
2410 				return -1;
2411 			}
2412 		} else if (!strcmp(param, "csa")) {
2413 			apsta_params->csa = (int)simple_strtol(pick_tmp2, NULL, 0);
2414 		} else if (!strcmp(param, "acs")) {
2415 			apsta_params->acs = (int)simple_strtol(pick_tmp2, NULL, 0);
2416 #if defined(WLMESH) && defined(WL_ESCAN)
2417 		} else if (!strcmp(param, "macs")) {
2418 			apsta_params->macs = (int)simple_strtol(pick_tmp2, NULL, 0);
2419 #endif /* WLMESH && WL_ESCAN */
2420 		} else if (!strcmp(param, "ifname")) {
2421 			pch = NULL;
2422 			pch = bcmstrtok(&pick_tmp2, " -", 0);
2423 			for (i=0; i<MAX_IF_NUM && pch; i++) {
2424 				strcpy(apsta_params->if_info[i].ifname, pch);
2425 				pch = bcmstrtok(&pick_tmp2, " -", 0);
2426 			}
2427 		} else if (!strcmp(param, "vifname")) {
2428 			strcpy(apsta_params->if_info[IF_VIF].ifname, pick_tmp2);
2429 		}
2430 		param = bcmstrtok(&pick_tmp, " ", 0);
2431 	}
2432 
2433 	if (apsta_params->apstamode == 0) {
2434 		AEXT_ERROR(dev->name, "mode [sta|ap|sta-ap|ap-ap]\n");
2435 		return -1;
2436 	}
2437 
2438 	wl_ext_iapsta_preinit(dev, apsta_params);
2439 #ifndef WL_STATIC_IF
2440 	wl_ext_iapsta_intf_add(dev, apsta_params);
2441 #endif /* WL_STATIC_IF */
2442 
2443 	return 0;
2444 }
2445 
2446 static int
wl_ext_parse_config(struct wl_if_info * cur_if,char * command,char ** pick_next)2447 wl_ext_parse_config(struct wl_if_info *cur_if, char *command, char **pick_next)
2448 {
2449 	char *pch, *pick_tmp;
2450 	char name[20], data[100];
2451 	int i, j, len;
2452 	char *ifname_head = NULL;
2453 
2454 	typedef struct config_map_t {
2455 		char name[20];
2456 		char *head;
2457 		char *tail;
2458 	} config_map_t;
2459 
2460 	config_map_t config_map [] = {
2461 		{" ifname ",	NULL, NULL},
2462 		{" ssid ",		NULL, NULL},
2463 		{" bssid ", 	NULL, NULL},
2464 		{" bgnmode ",	NULL, NULL},
2465 		{" hidden ",	NULL, NULL},
2466 		{" maxassoc ",	NULL, NULL},
2467 		{" chan ",		NULL, NULL},
2468 		{" amode ", 	NULL, NULL},
2469 		{" emode ", 	NULL, NULL},
2470 		{" key ",		NULL, NULL},
2471 	};
2472 	config_map_t *row, *row_prev;
2473 
2474 	pick_tmp = command;
2475 
2476 	// reset head and tail
2477 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
2478 		row = &config_map[i];
2479 		row->head = NULL;
2480 		row->tail = pick_tmp + strlen(pick_tmp);
2481 	}
2482 
2483 	// pick head
2484 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
2485 		row = &config_map[i];
2486 		pch = strstr(pick_tmp, row->name);
2487 		if (pch) {
2488 			row->head = pch;
2489 		}
2490 	}
2491 
2492 	// sort by head
2493 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
2494 		row_prev = &config_map[i];
2495 		for (j = i+1; j < sizeof(config_map)/sizeof(config_map[0]); j++) {
2496 			row = &config_map[j];
2497 			if (row->head < row_prev->head) {
2498 				strcpy(name, row_prev->name);
2499 				strcpy(row_prev->name, row->name);
2500 				strcpy(row->name, name);
2501 				pch = row_prev->head;
2502 				row_prev->head = row->head;
2503 				row->head = pch;
2504 			}
2505 		}
2506 	}
2507 
2508 	// pick tail
2509 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]) - 1; i++) {
2510 		row_prev = &config_map[i];
2511 		row = &config_map[i+1];
2512 		if (row_prev->head) {
2513 			row_prev->tail = row->head;
2514 		}
2515 	}
2516 
2517 	// remove name from head
2518 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
2519 		row = &config_map[i];
2520 		if (row->head) {
2521 			if (!strcmp(row->name, " ifname ")) {
2522 				ifname_head = row->head + 1;
2523 				break;
2524 			}
2525 			row->head += strlen(row->name);
2526 		}
2527 	}
2528 
2529 	for (i = 0; i < sizeof(config_map)/sizeof(config_map[0]); i++) {
2530 		row = &config_map[i];
2531 		if (row->head) {
2532 			memset(data, 0, sizeof(data));
2533 			if (row->tail && row->tail > row->head) {
2534 				strncpy(data, row->head, row->tail-row->head);
2535 			} else {
2536 				strcpy(data, row->head);
2537 			}
2538 			pick_tmp = data;
2539 
2540 			if (!strcmp(row->name, " ifname ")) {
2541 				break;
2542 			} else if (!strcmp(row->name, " ssid ")) {
2543 				len = strlen(pick_tmp);
2544 				memset(cur_if->ssid, 0, sizeof(cur_if->ssid));
2545 				if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
2546 					strncpy(cur_if->ssid, &pick_tmp[1], len-2);
2547 				else
2548 					strcpy(cur_if->ssid, pick_tmp);
2549 			} else if (!strcmp(row->name, " bssid ")) {
2550 				pch = bcmstrtok(&pick_tmp, ": ", 0);
2551 				for (j=0; j<6 && pch; j++) {
2552 					((u8 *)&cur_if->bssid)[j] = (int)simple_strtol(pch, NULL, 16);
2553 					pch = bcmstrtok(&pick_tmp, ": ", 0);
2554 				}
2555 			} else if (!strcmp(row->name, " bgnmode ")) {
2556 				if (!strcmp(pick_tmp, "b"))
2557 					cur_if->bgnmode = IEEE80211B;
2558 				else if (!strcmp(pick_tmp, "g"))
2559 					cur_if->bgnmode = IEEE80211G;
2560 				else if (!strcmp(pick_tmp, "bg"))
2561 					cur_if->bgnmode = IEEE80211BG;
2562 				else if (!strcmp(pick_tmp, "bgn"))
2563 					cur_if->bgnmode = IEEE80211BGN;
2564 				else if (!strcmp(pick_tmp, "bgnac"))
2565 					cur_if->bgnmode = IEEE80211BGNAC;
2566 				else {
2567 					AEXT_ERROR(cur_if->dev->name, "bgnmode [b|g|bg|bgn|bgnac]\n");
2568 					return -1;
2569 				}
2570 			} else if (!strcmp(row->name, " hidden ")) {
2571 				if (!strcmp(pick_tmp, "n"))
2572 					cur_if->hidden = 0;
2573 				else if (!strcmp(pick_tmp, "y"))
2574 					cur_if->hidden = 1;
2575 				else {
2576 					AEXT_ERROR(cur_if->dev->name, "hidden [y|n]\n");
2577 					return -1;
2578 				}
2579 			} else if (!strcmp(row->name, " maxassoc ")) {
2580 				cur_if->maxassoc = (int)simple_strtol(pick_tmp, NULL, 10);
2581 			} else if (!strcmp(row->name, " chan ")) {
2582 				cur_if->channel = (int)simple_strtol(pick_tmp, NULL, 10);
2583 			} else if (!strcmp(row->name, " amode ")) {
2584 				if (!strcmp(pick_tmp, "open"))
2585 					cur_if->amode = AUTH_OPEN;
2586 				else if (!strcmp(pick_tmp, "shared"))
2587 					cur_if->amode = AUTH_SHARED;
2588 				else if (!strcmp(pick_tmp, "wpapsk"))
2589 					cur_if->amode = AUTH_WPAPSK;
2590 				else if (!strcmp(pick_tmp, "wpa2psk"))
2591 					cur_if->amode = AUTH_WPA2PSK;
2592 				else if (!strcmp(pick_tmp, "wpawpa2psk"))
2593 					cur_if->amode = AUTH_WPAWPA2PSK;
2594 				else if (!strcmp(pick_tmp, "sae"))
2595 					cur_if->amode = AUTH_SAE;
2596 				else {
2597 					AEXT_ERROR(cur_if->dev->name, "amode [open|shared|wpapsk|wpa2psk|wpawpa2psk]\n");
2598 					return -1;
2599 				}
2600 			} else if (!strcmp(row->name, " emode ")) {
2601 				if (!strcmp(pick_tmp, "none"))
2602 					cur_if->emode = ENC_NONE;
2603 				else if (!strcmp(pick_tmp, "wep"))
2604 					cur_if->emode = ENC_WEP;
2605 				else if (!strcmp(pick_tmp, "tkip"))
2606 					cur_if->emode = ENC_TKIP;
2607 				else if (!strcmp(pick_tmp, "aes"))
2608 					cur_if->emode = ENC_AES;
2609 				else if (!strcmp(pick_tmp, "tkipaes"))
2610 					cur_if->emode = ENC_TKIPAES;
2611 				else {
2612 					AEXT_ERROR(cur_if->dev->name, "emode [none|wep|tkip|aes|tkipaes]\n");
2613 					return -1;
2614 				}
2615 			} else if (!strcmp(row->name, " key ")) {
2616 				len = strlen(pick_tmp);
2617 				memset(cur_if->key, 0, sizeof(cur_if->key));
2618 				if (pick_tmp[0] == '"' && pick_tmp[len-1] == '"')
2619 					strncpy(cur_if->key, &pick_tmp[1], len-2);
2620 				else
2621 					strcpy(cur_if->key, pick_tmp);
2622 			}
2623 		}
2624 	}
2625 
2626 	*pick_next = ifname_head;
2627 	return 0;
2628 }
2629 
2630 static int
wl_ext_iapsta_config(struct net_device * dev,char * command,int total_len)2631 wl_ext_iapsta_config(struct net_device *dev, char *command, int total_len)
2632 {
2633 	struct dhd_pub *dhd = dhd_get_pub(dev);
2634 	int ret=0, i;
2635 	char *pch, *pch2, *pick_tmp, *pick_next=NULL, *param;
2636 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
2637 	char ifname[IFNAMSIZ+1];
2638 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
2639 
2640 	if (!apsta_params->init) {
2641 		AEXT_ERROR(dev->name, "please init first\n");
2642 		return -1;
2643 	}
2644 
2645 	AEXT_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
2646 
2647 	pick_tmp = command;
2648 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_config
2649 
2650 	mutex_lock(&apsta_params->usr_sync);
2651 
2652 	while (pick_tmp != NULL) {
2653 		memset(ifname, 0, IFNAMSIZ+1);
2654 		if (!strncmp(pick_tmp, "ifname ", strlen("ifname "))) {
2655 			pch = pick_tmp + strlen("ifname ");
2656 			pch2 = strchr(pch, ' ');
2657 			if (pch && pch2) {
2658 				strncpy(ifname, pch, pch2-pch);
2659 			} else {
2660 				AEXT_ERROR(dev->name, "ifname [wlanX]\n");
2661 				ret = -1;
2662 				break;
2663 			}
2664 			for (i=0; i<MAX_IF_NUM; i++) {
2665 				tmp_if = &apsta_params->if_info[i];
2666 				if (tmp_if->dev && !strcmp(tmp_if->dev->name, ifname)) {
2667 					cur_if = tmp_if;
2668 					break;
2669 				}
2670 			}
2671 			if (!cur_if) {
2672 				AEXT_ERROR(dev->name, "wrong ifname=%s in apstamode=%d\n",
2673 					ifname, apsta_params->apstamode);
2674 				ret = -1;
2675 				break;
2676 			}
2677 			ret = wl_ext_parse_config(cur_if, pick_tmp, &pick_next);
2678 			if (ret)
2679 				break;
2680 			pick_tmp = pick_next;
2681 		} else {
2682 			AEXT_ERROR(dev->name, "first arg must be ifname\n");
2683 			ret = -1;
2684 			break;
2685 		}
2686 
2687 	}
2688 
2689 	mutex_unlock(&apsta_params->usr_sync);
2690 
2691 	return ret;
2692 }
2693 
2694 static int
wl_ext_assoclist(struct net_device * dev,char * data,char * command,int total_len)2695 wl_ext_assoclist(struct net_device *dev, char *data, char *command,
2696 	int total_len)
2697 {
2698 	int ret = 0, i, maxassoc = 0, bytes_written = 0;
2699 	char mac_buf[MAX_NUM_OF_ASSOCLIST *
2700 		sizeof(struct ether_addr) + sizeof(uint)] = {0};
2701 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
2702 
2703 	assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
2704 	ret = wl_ext_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), 0);
2705 	if (ret)
2706 		return -1;
2707 	maxassoc = dtoh32(assoc_maclist->count);
2708 	bytes_written += snprintf(command+bytes_written, total_len,
2709 		"%2s: %12s",
2710 		"no", "------addr------");
2711 	for (i=0; i<maxassoc; i++) {
2712 		bytes_written += snprintf(command+bytes_written, total_len,
2713 			"\n%2d: %pM", i, &assoc_maclist->ea[i]);
2714 	}
2715 
2716 	return bytes_written;
2717 }
2718 
2719 #ifdef WLMESH
2720 static int
wl_mesh_print_peer_info(mesh_peer_info_ext_t * mpi_ext,uint32 peer_results_count,char * command,int total_len)2721 wl_mesh_print_peer_info(mesh_peer_info_ext_t *mpi_ext,
2722 	uint32 peer_results_count, char *command, int total_len)
2723 {
2724 	char *peering_map[] = MESH_PEERING_STATE_STRINGS;
2725 	uint32 count = 0;
2726 	int bytes_written = 0;
2727 
2728 	bytes_written += snprintf(command+bytes_written, total_len,
2729 		"%2s: %12s : %6s : %-6s : %6s :"
2730 		" %5s : %4s : %4s : %11s : %4s",
2731 		"no", "------addr------ ", "l.aid", "state", "p.aid",
2732 		"mppid", "llid", "plid", "entry_state", "rssi");
2733 	for (count=0; count < peer_results_count; count++) {
2734 		if (mpi_ext->entry_state != MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT) {
2735 			bytes_written += snprintf(command+bytes_written, total_len,
2736 				"\n%2d: %pM : 0x%4x : %6s : 0x%4x :"
2737 				" %5d : %4d : %4d : %11s : %4d",
2738 				count, &mpi_ext->ea, mpi_ext->local_aid,
2739 				peering_map[mpi_ext->peer_info.state],
2740 				mpi_ext->peer_info.peer_aid,
2741 				mpi_ext->peer_info.mesh_peer_prot_id,
2742 				mpi_ext->peer_info.local_link_id,
2743 				mpi_ext->peer_info.peer_link_id,
2744 				(mpi_ext->entry_state == MESH_SELF_PEER_ENTRY_STATE_ACTIVE) ?
2745 				"ACTIVE" :
2746 				"EXTERNAL",
2747 				mpi_ext->rssi);
2748 		} else {
2749 			bytes_written += snprintf(command+bytes_written, total_len,
2750 				"\n%2d: %pM : %6s : %5s : %6s :"
2751 				" %5s : %4s : %4s : %11s : %4s",
2752 				count, &mpi_ext->ea, "  NA  ", "  NA  ", "  NA  ",
2753 				"  NA ", " NA ", " NA ", "  TIMEDOUT ", " NA ");
2754 		}
2755 		mpi_ext++;
2756 	}
2757 
2758 	return bytes_written;
2759 }
2760 
2761 static int
wl_mesh_get_peer_results(struct net_device * dev,char * buf,int len)2762 wl_mesh_get_peer_results(struct net_device *dev, char *buf, int len)
2763 {
2764 	int indata, inlen;
2765 	mesh_peer_info_dump_t *peer_results;
2766 	int ret;
2767 
2768 	memset(buf, 0, len);
2769 	peer_results = (mesh_peer_info_dump_t *)buf;
2770 	indata = htod32(len);
2771 	inlen = 4;
2772 	ret = wl_ext_iovar_getbuf(dev, "mesh_peer_status", &indata, inlen, buf, len, NULL);
2773 	if (!ret) {
2774 		peer_results = (mesh_peer_info_dump_t *)buf;
2775 		ret = peer_results->count;
2776 	}
2777 
2778 	return ret;
2779 }
2780 
2781 static int
wl_ext_mesh_peer_status(struct net_device * dev,char * data,char * command,int total_len)2782 wl_ext_mesh_peer_status(struct net_device *dev, char *data, char *command,
2783 	int total_len)
2784 {
2785 	struct wl_if_info *cur_if;
2786 	mesh_peer_info_dump_t *peer_results;
2787 	mesh_peer_info_ext_t *mpi_ext;
2788 	char *peer_buf = NULL;
2789 	int peer_len = WLC_IOCTL_MAXLEN;
2790 	int dump_written = 0, ret;
2791 
2792 	if (!data) {
2793 		peer_buf = kmalloc(peer_len, GFP_KERNEL);
2794 		if (peer_buf == NULL) {
2795 			AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
2796 				peer_len);
2797 			return -1;
2798 		}
2799 		cur_if = wl_get_cur_if(dev);
2800 		if (cur_if && cur_if->ifmode == IMESH_MODE) {
2801 			memset(peer_buf, 0, peer_len);
2802 			ret = wl_mesh_get_peer_results(dev, peer_buf, peer_len);
2803 			if (ret >= 0) {
2804 				peer_results = (mesh_peer_info_dump_t *)peer_buf;
2805 				mpi_ext = (mesh_peer_info_ext_t *)peer_results->mpi_ext;
2806 				dump_written += wl_mesh_print_peer_info(mpi_ext,
2807 					peer_results->count, command+dump_written,
2808 					total_len-dump_written);
2809 			}
2810 		} else if (cur_if) {
2811 			AEXT_ERROR(dev->name, "[%s][%c] is not mesh interface\n",
2812 				cur_if->ifname, cur_if->prefix);
2813 		}
2814 	}
2815 
2816 	if (peer_buf)
2817 		kfree(peer_buf);
2818 	return dump_written;
2819 }
2820 
2821 #ifdef WL_ESCAN
2822 #define WL_MESH_DELAY_SCAN_MS	3000
2823 static void
wl_mesh_timer(unsigned long data)2824 wl_mesh_timer(unsigned long data)
2825 {
2826 	wl_event_msg_t msg;
2827 	struct wl_if_info *mesh_if = (struct wl_if_info *)data;
2828 	struct dhd_pub *dhd;
2829 
2830 	if (!mesh_if) {
2831 		AEXT_ERROR("wlan", "mesh_if is not ready\n");
2832 		return;
2833 	}
2834 
2835 	if (!mesh_if->dev) {
2836 		AEXT_ERROR("wlan", "ifidx %d is not ready\n", mesh_if->ifidx);
2837 		return;
2838 	}
2839 	dhd = dhd_get_pub(mesh_if->dev);
2840 
2841 	bzero(&msg, sizeof(wl_event_msg_t));
2842 	AEXT_TRACE(mesh_if->dev->name, "timer expired\n");
2843 
2844 	msg.ifidx = mesh_if->ifidx;
2845 	msg.event_type = hton32(WLC_E_RESERVED);
2846 	msg.reason = 0xFFFFFFFF;
2847 	wl_ext_event_send(dhd->event_params, &msg, NULL);
2848 }
2849 
2850 static void
wl_mesh_set_timer(struct wl_if_info * mesh_if,uint timeout)2851 wl_mesh_set_timer(struct wl_if_info *mesh_if, uint timeout)
2852 {
2853 	AEXT_TRACE(mesh_if->dev->name, "timeout=%d\n", timeout);
2854 
2855 	if (timer_pending(&mesh_if->delay_scan))
2856 		del_timer_sync(&mesh_if->delay_scan);
2857 
2858 	if (timeout) {
2859 		if (timer_pending(&mesh_if->delay_scan))
2860 			del_timer_sync(&mesh_if->delay_scan);
2861 		mod_timer(&mesh_if->delay_scan, jiffies + msecs_to_jiffies(timeout));
2862 	}
2863 }
2864 
2865 static int
wl_mesh_clear_vndr_ie(struct net_device * dev,uchar * oui)2866 wl_mesh_clear_vndr_ie(struct net_device *dev, uchar *oui)
2867 {
2868 	char *vndr_ie_buf = NULL;
2869 	vndr_ie_setbuf_t *vndr_ie = NULL;
2870 	ie_getbuf_t vndr_ie_tmp;
2871 	char *iovar_buf = NULL;
2872 	int err = -1, i;
2873 	vndr_ie_buf_t *vndr_ie_dump = NULL;
2874 	uchar *iebuf;
2875 	vndr_ie_info_t *ie_info;
2876 	vndr_ie_t *ie;
2877 
2878 	vndr_ie_buf = kzalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
2879 	if (!vndr_ie_buf) {
2880 		AEXT_ERROR(dev->name, "IE memory alloc failed\n");
2881 		err = -ENOMEM;
2882 		goto exit;
2883 	}
2884 
2885 	iovar_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
2886 	if (!iovar_buf) {
2887 		AEXT_ERROR(dev->name, "iovar_buf alloc failed\n");
2888 		err = -ENOMEM;
2889 		goto exit;
2890 	}
2891 
2892 	memset(iovar_buf, 0, WLC_IOCTL_MEDLEN);
2893 	vndr_ie_tmp.pktflag = (uint32) -1;
2894 	vndr_ie_tmp.id = (uint8) DOT11_MNG_PROPR_ID;
2895 	err = wl_ext_iovar_getbuf(dev, "vndr_ie", &vndr_ie_tmp, sizeof(vndr_ie_tmp),
2896 		iovar_buf, WLC_IOCTL_MEDLEN, NULL);
2897 	if (err)
2898 		goto exit;
2899 
2900 	vndr_ie_dump = (vndr_ie_buf_t *)iovar_buf;
2901 	if (!vndr_ie_dump->iecount)
2902 		goto exit;
2903 
2904 	iebuf = (uchar *)&vndr_ie_dump->vndr_ie_list[0];
2905 	for (i=0; i<vndr_ie_dump->iecount; i++) {
2906 		ie_info = (vndr_ie_info_t *) iebuf;
2907 		ie = &ie_info->vndr_ie_data;
2908 		if (memcmp(ie->oui, oui, 3))
2909 			memset(ie->oui, 0, 3);
2910 		iebuf += sizeof(uint32) + ie->len + VNDR_IE_HDR_LEN;
2911 	}
2912 
2913 	vndr_ie = (vndr_ie_setbuf_t *) vndr_ie_buf;
2914 	strncpy(vndr_ie->cmd, "del", VNDR_IE_CMD_LEN - 1);
2915 	vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
2916 	memcpy(&vndr_ie->vndr_ie_buffer, vndr_ie_dump, WLC_IOCTL_SMLEN-VNDR_IE_CMD_LEN-1);
2917 
2918 	memset(iovar_buf, 0, WLC_IOCTL_MEDLEN);
2919 	err = wl_ext_iovar_setbuf(dev, "vndr_ie", vndr_ie, WLC_IOCTL_SMLEN, iovar_buf,
2920 		WLC_IOCTL_MEDLEN, NULL);
2921 
2922 exit:
2923 	if (vndr_ie) {
2924 		kfree(vndr_ie);
2925 	}
2926 	if (iovar_buf) {
2927 		kfree(iovar_buf);
2928 	}
2929 	return err;
2930 }
2931 
2932 static int
wl_mesh_clear_mesh_info(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if,bool scan)2933 wl_mesh_clear_mesh_info(struct wl_apsta_params *apsta_params,
2934 	struct wl_if_info *mesh_if, bool scan)
2935 {
2936 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
2937 	uchar mesh_oui[]={0x00, 0x22, 0xf4};
2938 	int ret;
2939 
2940 	AEXT_TRACE(mesh_if->dev->name, "Enter\n");
2941 
2942 	ret = wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui);
2943 	memset(mesh_info, 0, sizeof(struct wl_mesh_params));
2944 	if (scan) {
2945 		mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
2946 		wl_mesh_set_timer(mesh_if, 100);
2947 	}
2948 
2949 	return ret;
2950 }
2951 
2952 static int
wl_mesh_update_vndr_ie(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if)2953 wl_mesh_update_vndr_ie(struct wl_apsta_params *apsta_params,
2954 	struct wl_if_info *mesh_if)
2955 {
2956 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
2957 	char *vndr_ie;
2958 	uchar mesh_oui[]={0x00, 0x22, 0xf4};
2959 	int bytes_written = 0;
2960 	int ret = 0, i, vndr_ie_len;
2961 	uint8 *peer_bssid;
2962 
2963 	wl_mesh_clear_vndr_ie(mesh_if->dev, mesh_oui);
2964 
2965 	vndr_ie_len = WLC_IOCTL_MEDLEN;
2966 	vndr_ie = kmalloc(vndr_ie_len, GFP_KERNEL);
2967 	if (vndr_ie == NULL) {
2968 		AEXT_ERROR(mesh_if->dev->name, "Failed to allocate buffer of %d bytes\n",
2969 			WLC_IOCTL_MEDLEN);
2970 		ret = -1;
2971 		goto exit;
2972 	}
2973 
2974 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
2975 		"0x%02x%02x%02x", mesh_oui[0], mesh_oui[1], mesh_oui[2]);
2976 
2977 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
2978 		"%02x%02x%02x%02x%02x%02x%02x%02x", MESH_INFO_MASTER_BSSID, ETHER_ADDR_LEN,
2979 		((u8 *)(&mesh_info->master_bssid))[0], ((u8 *)(&mesh_info->master_bssid))[1],
2980 		((u8 *)(&mesh_info->master_bssid))[2], ((u8 *)(&mesh_info->master_bssid))[3],
2981 		((u8 *)(&mesh_info->master_bssid))[4], ((u8 *)(&mesh_info->master_bssid))[5]);
2982 
2983 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
2984 		"%02x%02x%02x", MESH_INFO_MASTER_CHANNEL, 1, mesh_info->master_channel);
2985 
2986 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
2987 		"%02x%02x%02x", MESH_INFO_HOP_CNT, 1, mesh_info->hop_cnt);
2988 
2989 	bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
2990 		"%02x%02x", MESH_INFO_PEER_BSSID, mesh_info->hop_cnt*ETHER_ADDR_LEN);
2991 	for (i=0; i<mesh_info->hop_cnt && i<MAX_HOP_LIST; i++) {
2992 		peer_bssid = (uint8 *)&mesh_info->peer_bssid[i];
2993 		bytes_written += snprintf(vndr_ie+bytes_written, vndr_ie_len,
2994 			"%02x%02x%02x%02x%02x%02x",
2995  			peer_bssid[0], peer_bssid[1], peer_bssid[2],
2996 			peer_bssid[3], peer_bssid[4], peer_bssid[5]);
2997 	}
2998 
2999 	ret = wl_ext_add_del_ie(mesh_if->dev, VNDR_IE_BEACON_FLAG|VNDR_IE_PRBRSP_FLAG,
3000 		vndr_ie, "add");
3001 	if (!ret) {
3002 		AEXT_INFO(mesh_if->dev->name, "mbssid=%pM, mchannel=%d, hop=%d, pbssid=%pM\n",
3003 			&mesh_info->master_bssid, mesh_info->master_channel, mesh_info->hop_cnt,
3004 			mesh_info->peer_bssid);
3005 	}
3006 
3007 exit:
3008 	if (vndr_ie)
3009 		kfree(vndr_ie);
3010 	return ret;
3011 }
3012 
3013 static bool
wl_mesh_update_master_info(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if)3014 wl_mesh_update_master_info(struct wl_apsta_params *apsta_params,
3015 	struct wl_if_info *mesh_if)
3016 {
3017 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
3018 	struct wl_if_info *sta_if = NULL;
3019 	bool updated = FALSE;
3020 
3021 	sta_if = wl_ext_if_enabled(apsta_params, ISTA_MODE);
3022 	if (sta_if) {
3023 		wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &mesh_info->master_bssid,
3024 			ETHER_ADDR_LEN, 0);
3025 		mesh_info->master_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
3026 		mesh_info->hop_cnt = 0;
3027 		memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN);
3028 		if (!wl_mesh_update_vndr_ie(apsta_params, mesh_if))
3029 			updated = TRUE;
3030 	}
3031 
3032 	return updated;
3033 }
3034 
3035 static bool
wl_mesh_update_mesh_info(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if)3036 wl_mesh_update_mesh_info(struct wl_apsta_params *apsta_params,
3037 	struct wl_if_info *mesh_if)
3038 {
3039 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info, peer_mesh_info;
3040 	uint32 count = 0;
3041 	char *dump_buf = NULL;
3042 	mesh_peer_info_dump_t *peer_results;
3043 	mesh_peer_info_ext_t *mpi_ext;
3044 	struct ether_addr bssid;
3045 	bool updated = FALSE, bss_found = FALSE;
3046 	uint16 cur_chan;
3047 
3048 	dump_buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
3049 	if (dump_buf == NULL) {
3050 		AEXT_ERROR(mesh_if->dev->name, "Failed to allocate buffer of %d bytes\n",
3051 			WLC_IOCTL_MAXLEN);
3052 		return FALSE;
3053 	}
3054 	count = wl_mesh_get_peer_results(mesh_if->dev, dump_buf, WLC_IOCTL_MAXLEN);
3055 	if (count > 0) {
3056 		memset(&bssid, 0, ETHER_ADDR_LEN);
3057 		wldev_ioctl(mesh_if->dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, 0);
3058 		peer_results = (mesh_peer_info_dump_t *)dump_buf;
3059 		mpi_ext = (mesh_peer_info_ext_t *)peer_results->mpi_ext;
3060 		for (count = 0; count < peer_results->count; count++) {
3061 			if (mpi_ext->entry_state != MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT &&
3062 					mpi_ext->peer_info.state == MESH_PEERING_ESTAB) {
3063 				memset(&peer_mesh_info, 0, sizeof(struct wl_mesh_params));
3064 				bss_found = wl_escan_mesh_info(mesh_if->dev, mesh_if->escan,
3065 					&mpi_ext->ea, &peer_mesh_info);
3066 				if (bss_found && (mesh_info->master_channel == 0 ||
3067 						peer_mesh_info.hop_cnt <= mesh_info->hop_cnt) &&
3068 						memcmp(&peer_mesh_info.peer_bssid, &bssid, ETHER_ADDR_LEN)) {
3069 					memcpy(&mesh_info->master_bssid, &peer_mesh_info.master_bssid,
3070 						ETHER_ADDR_LEN);
3071 					mesh_info->master_channel = peer_mesh_info.master_channel;
3072 					mesh_info->hop_cnt = peer_mesh_info.hop_cnt+1;
3073 					memset(mesh_info->peer_bssid, 0, MAX_HOP_LIST*ETHER_ADDR_LEN);
3074 					memcpy(&mesh_info->peer_bssid, &mpi_ext->ea, ETHER_ADDR_LEN);
3075 					memcpy(&mesh_info->peer_bssid[1], peer_mesh_info.peer_bssid,
3076 						(MAX_HOP_LIST-1)*ETHER_ADDR_LEN);
3077 					updated = TRUE;
3078 				}
3079 			}
3080 			mpi_ext++;
3081 		}
3082 		if (updated) {
3083 			if (wl_mesh_update_vndr_ie(apsta_params, mesh_if)) {
3084 				AEXT_ERROR(mesh_if->dev->name, "update failed\n");
3085 				mesh_info->master_channel = 0;
3086 				updated = FALSE;
3087 				goto exit;
3088 			}
3089 		}
3090 	}
3091 
3092 	if (!mesh_info->master_channel) {
3093 		wlc_ssid_t cur_ssid;
3094 		char sec[32];
3095 		bool sae = FALSE;
3096 		memset(&peer_mesh_info, 0, sizeof(struct wl_mesh_params));
3097 		wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &cur_ssid, sizeof(cur_ssid), 0);
3098 		wl_ext_get_sec(mesh_if->dev, mesh_if->ifmode, sec, sizeof(sec));
3099 		if (strnicmp(sec, "sae/sae", strlen("sae/sae")) == 0)
3100 			sae = TRUE;
3101 		cur_chan = wl_ext_get_chan(apsta_params, mesh_if->dev);
3102 		bss_found = wl_escan_mesh_peer(mesh_if->dev, mesh_if->escan, &cur_ssid, cur_chan,
3103 			sae, &peer_mesh_info);
3104 
3105 		if (bss_found && peer_mesh_info.master_channel&&
3106 				(cur_chan != peer_mesh_info.master_channel)) {
3107 			WL_MSG(mesh_if->ifname, "moving channel %d -> %d\n",
3108 				cur_chan, peer_mesh_info.master_channel);
3109 			wl_ext_disable_iface(mesh_if->dev, mesh_if->ifname);
3110 			mesh_if->channel = peer_mesh_info.master_channel;
3111 			wl_ext_enable_iface(mesh_if->dev, mesh_if->ifname, 500);
3112 		}
3113 	}
3114 
3115 exit:
3116 	if (dump_buf)
3117 		kfree(dump_buf);
3118 	return updated;
3119 }
3120 
3121 static void
wl_mesh_event_handler(struct wl_apsta_params * apsta_params,struct wl_if_info * mesh_if,const wl_event_msg_t * e,void * data)3122 wl_mesh_event_handler(	struct wl_apsta_params *apsta_params,
3123 	struct wl_if_info *mesh_if, const wl_event_msg_t *e, void *data)
3124 {
3125 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
3126 	uint32 event_type = ntoh32(e->event_type);
3127 	uint32 status = ntoh32(e->status);
3128 	uint32 reason = ntoh32(e->reason);
3129 	wlc_ssid_t ssid;
3130 	int ret;
3131 
3132 	if (wl_get_isam_status(mesh_if, AP_CREATED) &&
3133 			((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
3134 			(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
3135 			reason == WLC_E_REASON_INITIAL_ASSOC))) {
3136 		if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
3137 			mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
3138 			wl_mesh_set_timer(mesh_if, WL_MESH_DELAY_SCAN_MS);
3139 		}
3140 	}
3141 	else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
3142 			(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
3143 			reason == WLC_E_REASON_DEAUTH)) {
3144 		wl_mesh_clear_mesh_info(apsta_params, mesh_if, FALSE);
3145 	}
3146 	else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
3147 			(event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
3148 			reason == DOT11_SC_SUCCESS) {
3149 		mesh_info->scan_channel = wl_ext_get_chan(apsta_params, mesh_if->dev);
3150 		wl_mesh_set_timer(mesh_if, 100);
3151 	}
3152 	else if (event_type == WLC_E_DISASSOC_IND || event_type == WLC_E_DEAUTH_IND ||
3153 			(event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
3154 		if (!memcmp(&mesh_info->peer_bssid, &e->addr, ETHER_ADDR_LEN))
3155 			wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
3156 	}
3157 	else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
3158 			event_type == WLC_E_RESERVED && reason == 0xFFFFFFFF) {
3159 		if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
3160 			wl_ext_ioctl(mesh_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
3161 			ret = wl_escan_set_scan(mesh_if->dev, apsta_params->dhd, &ssid,
3162 				mesh_info->scan_channel, FALSE);
3163 			if (ret)
3164 				wl_mesh_set_timer(mesh_if, WL_MESH_DELAY_SCAN_MS);
3165 		}
3166 	}
3167 	else if (wl_get_isam_status(mesh_if, AP_CREATED) &&
3168 			((event_type == WLC_E_ESCAN_RESULT && status == WLC_E_STATUS_SUCCESS) ||
3169 			(event_type == WLC_E_ESCAN_RESULT &&
3170 			(status == WLC_E_STATUS_ABORT || status == WLC_E_STATUS_NEWSCAN ||
3171 			status == WLC_E_STATUS_11HQUIET || status == WLC_E_STATUS_CS_ABORT ||
3172 			status == WLC_E_STATUS_NEWASSOC || status == WLC_E_STATUS_TIMEOUT)))) {
3173 		if (!wl_mesh_update_master_info(apsta_params, mesh_if)) {
3174 			if (!wl_mesh_update_mesh_info(apsta_params, mesh_if)) {
3175 				mesh_info->scan_channel = 0;
3176 				wl_mesh_set_timer(mesh_if, WL_MESH_DELAY_SCAN_MS);
3177 			}
3178 		}
3179 	}
3180 }
3181 
3182 static void
wl_mesh_escan_detach(dhd_pub_t * dhd,struct wl_if_info * mesh_if)3183 wl_mesh_escan_detach(dhd_pub_t *dhd, struct wl_if_info *mesh_if)
3184 {
3185 	AEXT_TRACE(mesh_if->dev->name, "Enter\n");
3186 
3187 	del_timer_sync(&mesh_if->delay_scan);
3188 
3189 	if (mesh_if->escan) {
3190 		mesh_if->escan = NULL;
3191 	}
3192 }
3193 
3194 static int
wl_mesh_escan_attach(dhd_pub_t * dhd,struct wl_if_info * mesh_if)3195 wl_mesh_escan_attach(dhd_pub_t *dhd, struct wl_if_info *mesh_if)
3196 {
3197 	AEXT_TRACE(mesh_if->dev->name, "Enter\n");
3198 
3199 	mesh_if->escan = dhd->escan;
3200 	init_timer_compat(&mesh_if->delay_scan, wl_mesh_timer, mesh_if);
3201 
3202 	return 0;
3203 }
3204 
3205 static uint
wl_mesh_update_peer_path(struct wl_if_info * mesh_if,char * command,int total_len)3206 wl_mesh_update_peer_path(struct wl_if_info *mesh_if, char *command,
3207 	int total_len)
3208 {
3209 	struct wl_mesh_params peer_mesh_info;
3210 	uint32 count = 0;
3211 	char *dump_buf = NULL;
3212 	mesh_peer_info_dump_t *peer_results;
3213 	mesh_peer_info_ext_t *mpi_ext;
3214 	int bytes_written = 0, j, k;
3215 	bool bss_found = FALSE;
3216 
3217 	dump_buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
3218 	if (dump_buf == NULL) {
3219 		AEXT_ERROR(mesh_if->dev->name, "Failed to allocate buffer of %d bytes\n",
3220 			WLC_IOCTL_MAXLEN);
3221 		return FALSE;
3222 	}
3223 	count = wl_mesh_get_peer_results(mesh_if->dev, dump_buf, WLC_IOCTL_MAXLEN);
3224 	if (count > 0) {
3225 		peer_results = (mesh_peer_info_dump_t *)dump_buf;
3226 		mpi_ext = (mesh_peer_info_ext_t *)peer_results->mpi_ext;
3227 		for (count = 0; count < peer_results->count; count++) {
3228 			if (mpi_ext->entry_state != MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT &&
3229 					mpi_ext->peer_info.state == MESH_PEERING_ESTAB) {
3230 				memset(&peer_mesh_info, 0, sizeof(struct wl_mesh_params));
3231 				bss_found = wl_escan_mesh_info(mesh_if->dev, mesh_if->escan,
3232 					&mpi_ext->ea, &peer_mesh_info);
3233 				if (bss_found) {
3234 					bytes_written += snprintf(command+bytes_written, total_len,
3235 						"\npeer=%pM, hop=%d",
3236 						&mpi_ext->ea, peer_mesh_info.hop_cnt);
3237 					for (j=1; j<peer_mesh_info.hop_cnt; j++) {
3238 						bytes_written += snprintf(command+bytes_written,
3239 							total_len, "\n");
3240 						for (k=0; k<j; k++) {
3241 							bytes_written += snprintf(command+bytes_written,
3242 								total_len, " ");
3243 						}
3244 						bytes_written += snprintf(command+bytes_written, total_len,
3245 							"%pM", &peer_mesh_info.peer_bssid[j]);
3246 					}
3247 				}
3248 			}
3249 			mpi_ext++;
3250 		}
3251 	}
3252 
3253 	if (dump_buf)
3254 		kfree(dump_buf);
3255 	return bytes_written;
3256 }
3257 
3258 static int
wl_ext_isam_peer_path(struct net_device * dev,char * command,int total_len)3259 wl_ext_isam_peer_path(struct net_device *dev, char *command, int total_len)
3260 {
3261 	struct dhd_pub *dhd = dhd_get_pub(dev);
3262 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3263 	struct wl_mesh_params *mesh_info = &apsta_params->mesh_info;
3264 	struct wl_if_info *tmp_if;
3265 	uint16 chan = 0;
3266 	char *dump_buf = NULL;
3267 	int dump_len = WLC_IOCTL_MEDLEN;
3268 	int dump_written = 0;
3269 	int i;
3270 
3271 	if (command || android_msg_level & ANDROID_INFO_LEVEL) {
3272 		if (command) {
3273 			dump_buf = command;
3274 			dump_len = total_len;
3275 		} else {
3276 			dump_buf = kmalloc(dump_len, GFP_KERNEL);
3277 			if (dump_buf == NULL) {
3278 				AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
3279 					dump_len);
3280 				return -1;
3281 			}
3282 		}
3283 		for (i=0; i<MAX_IF_NUM; i++) {
3284 			tmp_if = &apsta_params->if_info[i];
3285 			if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE && apsta_params->macs) {
3286 				chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
3287 				if (chan) {
3288 					dump_written += snprintf(dump_buf+dump_written, dump_len,
3289 						DHD_LOG_PREFIX "[%s-%c] mbssid=%pM, mchan=%d, hop=%d, pbssid=%pM",
3290 						tmp_if->ifname, tmp_if->prefix, &mesh_info->master_bssid,
3291 						mesh_info->master_channel, mesh_info->hop_cnt,
3292 						&mesh_info->peer_bssid);
3293 					dump_written += wl_mesh_update_peer_path(tmp_if,
3294 						dump_buf+dump_written, dump_len-dump_written);
3295 				}
3296 			}
3297 		}
3298 		AEXT_INFO(dev->name, "%s\n", dump_buf);
3299 	}
3300 
3301 	if (!command && dump_buf)
3302 		kfree(dump_buf);
3303 	return dump_written;
3304 }
3305 #endif /* WL_ESCAN */
3306 #endif /* WLMESH */
3307 
3308 static int
wl_ext_isam_status(struct net_device * dev,char * command,int total_len)3309 wl_ext_isam_status(struct net_device *dev, char *command, int total_len)
3310 {
3311 	struct dhd_pub *dhd = dhd_get_pub(dev);
3312 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3313 	int i;
3314 	struct wl_if_info *tmp_if;
3315 	uint16 chan = 0;
3316 	wlc_ssid_t ssid = { 0, {0} };
3317 	struct ether_addr bssid;
3318 	scb_val_t scb_val;
3319 	char sec[32];
3320 	u32 chanspec = 0;
3321 	char *dump_buf = NULL;
3322 	int dump_len = WLC_IOCTL_MEDLEN;
3323 	int dump_written = 0;
3324 
3325 	if (command || android_msg_level & ANDROID_INFO_LEVEL) {
3326 		if (command) {
3327 			dump_buf = command;
3328 			dump_len = total_len;
3329 		} else {
3330 			dump_buf = kmalloc(dump_len, GFP_KERNEL);
3331 			if (dump_buf == NULL) {
3332 				AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
3333 					dump_len);
3334 				return -1;
3335 			}
3336 		}
3337 		dump_written += snprintf(dump_buf+dump_written, dump_len,
3338 			"apstamode=%d", apsta_params->apstamode);
3339 		for (i=0; i<MAX_IF_NUM; i++) {
3340 			memset(&ssid, 0, sizeof(ssid));
3341 			memset(&bssid, 0, sizeof(bssid));
3342 			memset(&scb_val, 0, sizeof(scb_val));
3343 			tmp_if = &apsta_params->if_info[i];
3344 			if (tmp_if->dev) {
3345 				chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
3346 				if (chan) {
3347 					wl_ext_ioctl(tmp_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
3348 					wldev_ioctl(tmp_if->dev, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
3349 					wldev_ioctl(tmp_if->dev, WLC_GET_RSSI, &scb_val,
3350 						sizeof(scb_val_t), 0);
3351 					chanspec = wl_ext_get_chanspec(apsta_params, tmp_if->dev);
3352 					wl_ext_get_sec(tmp_if->dev, tmp_if->ifmode, sec, sizeof(sec));
3353 					dump_written += snprintf(dump_buf+dump_written, dump_len,
3354 						"\n" DHD_LOG_PREFIX "[%s-%c]: bssid=%pM, chan=%3d(0x%x %sMHz), "
3355 						"rssi=%3d, sec=%-15s, SSID=\"%s\"",
3356 						tmp_if->ifname, tmp_if->prefix, &bssid, chan, chanspec,
3357 						CHSPEC_IS20(chanspec)?"20":
3358 						CHSPEC_IS40(chanspec)?"40":
3359 						CHSPEC_IS80(chanspec)?"80":"160",
3360 						dtoh32(scb_val.val), sec, ssid.SSID);
3361 					if (tmp_if->ifmode == IAP_MODE) {
3362 						dump_written += snprintf(dump_buf+dump_written, dump_len, "\n");
3363 						dump_written += wl_ext_assoclist(tmp_if->dev, NULL,
3364 							dump_buf+dump_written, dump_len-dump_written);
3365 					}
3366 #ifdef WLMESH
3367 					else if (tmp_if->ifmode == IMESH_MODE) {
3368 						dump_written += snprintf(dump_buf+dump_written, dump_len, "\n");
3369 						dump_written += wl_ext_mesh_peer_status(tmp_if->dev, NULL,
3370 							dump_buf+dump_written, dump_len-dump_written);
3371 					}
3372 #endif /* WLMESH */
3373 				} else {
3374 					dump_written += snprintf(dump_buf+dump_written, dump_len,
3375 						"\n" DHD_LOG_PREFIX "[%s-%c]:", tmp_if->ifname, tmp_if->prefix);
3376 				}
3377 			}
3378 		}
3379 		AEXT_INFO(dev->name, "%s\n", dump_buf);
3380 	}
3381 
3382 	if (!command && dump_buf)
3383 		kfree(dump_buf);
3384 	return dump_written;
3385 }
3386 
3387 static bool
wl_ext_master_if(struct wl_if_info * cur_if)3388 wl_ext_master_if(struct wl_if_info *cur_if)
3389 {
3390 	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE)
3391 		return TRUE;
3392 	else
3393 		return FALSE;
3394 }
3395 
3396 static int
wl_ext_if_down(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3397 wl_ext_if_down(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
3398 {
3399 	s8 iovar_buf[WLC_IOCTL_SMLEN];
3400 	scb_val_t scbval;
3401 	struct {
3402 		s32 cfg;
3403 		s32 val;
3404 	} bss_setbuf;
3405 	apstamode_t apstamode = apsta_params->apstamode;
3406 
3407 	WL_MSG(cur_if->ifname, "[%c] Turning off...\n", cur_if->prefix);
3408 
3409 	if (cur_if->ifmode == ISTA_MODE) {
3410 		wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
3411 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
3412 		// deauthenticate all STA first
3413 		memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
3414 		wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
3415 	}
3416 
3417 	if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
3418 		wl_ext_ioctl(cur_if->dev, WLC_DOWN, NULL, 0, 1);
3419 	} else {
3420 		bss_setbuf.cfg = 0xffffffff;
3421 		bss_setbuf.val = htod32(0);
3422 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3423 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
3424 	}
3425 	wl_clr_isam_status(cur_if, AP_CREATED);
3426 
3427 	return 0;
3428 }
3429 
3430 static int
wl_ext_if_up(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,bool force_enable)3431 wl_ext_if_up(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if,
3432 	bool force_enable)
3433 {
3434 	s8 iovar_buf[WLC_IOCTL_SMLEN];
3435 	struct {
3436 		s32 cfg;
3437 		s32 val;
3438 	} bss_setbuf;
3439 	apstamode_t apstamode = apsta_params->apstamode;
3440 	chanspec_t fw_chspec;
3441 	u32 timeout;
3442 	wlc_ssid_t ssid = { 0, {0} };
3443 	uint16 chan = 0;
3444 
3445 	if (cur_if->ifmode != IAP_MODE) {
3446 		AEXT_ERROR(cur_if->ifname, "Wrong ifmode\n");
3447 		return 0;
3448 	}
3449 
3450 	if (wl_ext_dfs_chan(cur_if->channel) && !apsta_params->radar && !force_enable) {
3451 		WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n",
3452 			cur_if->prefix, cur_if->channel);
3453 		return 0;
3454 	} else if (!cur_if->channel) {
3455 		WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
3456 		return 0;
3457 	}
3458 
3459 	WL_MSG(cur_if->ifname, "[%c] Turning on...\n", cur_if->prefix);
3460 
3461 	wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver, cur_if->channel,
3462 		&fw_chspec);
3463 
3464 	wl_clr_isam_status(cur_if, AP_CREATED);
3465 	wl_set_isam_status(cur_if, AP_CREATING);
3466 	if (apstamode == IAPONLY_MODE) {
3467 		wl_ext_ioctl(cur_if->dev, WLC_UP, NULL, 0, 1);
3468 	} else {
3469 		bss_setbuf.cfg = 0xffffffff;
3470 		bss_setbuf.val = htod32(1);
3471 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
3472 			sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
3473 	}
3474 
3475 	timeout = wait_event_interruptible_timeout(apsta_params->netif_change_event,
3476 		wl_get_isam_status(cur_if, AP_CREATED),
3477 		msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
3478 	if (timeout <= 0 || !wl_get_isam_status(cur_if, AP_CREATED)) {
3479 		wl_ext_if_down(apsta_params, cur_if);
3480 		WL_MSG(cur_if->ifname, "[%c] failed to up with SSID: \"%s\"\n",
3481 			cur_if->prefix, cur_if->ssid);
3482 	} else {
3483 		wl_ext_ioctl(cur_if->dev, WLC_GET_SSID, &ssid, sizeof(ssid), 0);
3484 		chan = wl_ext_get_chan(apsta_params, cur_if->dev);
3485 		WL_MSG(cur_if->ifname, "[%c] enabled with SSID: \"%s\" on channel %d\n",
3486 			cur_if->prefix, ssid.SSID, chan);
3487 	}
3488 	wl_clr_isam_status(cur_if, AP_CREATING);
3489 
3490 	wl_ext_isam_status(cur_if->dev, NULL, 0);
3491 
3492 	return 0;
3493 }
3494 
3495 static int
wl_ext_disable_iface(struct net_device * dev,char * ifname)3496 wl_ext_disable_iface(struct net_device *dev, char *ifname)
3497 {
3498 	struct dhd_pub *dhd = dhd_get_pub(dev);
3499 	int i;
3500 	s8 iovar_buf[WLC_IOCTL_SMLEN];
3501 	wlc_ssid_t ssid = { 0, {0} };
3502 	scb_val_t scbval;
3503 	struct {
3504 		s32 cfg;
3505 		s32 val;
3506 	} bss_setbuf;
3507 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
3508 	apstamode_t apstamode = apsta_params->apstamode;
3509 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
3510 
3511 	for (i=0; i<MAX_IF_NUM; i++) {
3512 		tmp_if = &apsta_params->if_info[i];
3513 		if (tmp_if->dev && !strcmp(tmp_if->dev->name, ifname)) {
3514 			cur_if = tmp_if;
3515 			break;
3516 		}
3517 	}
3518 	if (!cur_if) {
3519 		AEXT_ERROR(dev->name, "wrong ifname=%s or dev not ready\n", ifname);
3520 		return -1;
3521 	}
3522 
3523 	mutex_lock(&apsta_params->usr_sync);
3524 	WL_MSG(ifname, "[%c] Disabling...\n", cur_if->prefix);
3525 
3526 	if (cur_if->ifmode == ISTA_MODE) {
3527 		wl_ext_ioctl(cur_if->dev, WLC_DISASSOC, NULL, 0, 1);
3528 		wl_ext_add_remove_pm_enable_work(dev, FALSE);
3529 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
3530 		// deauthenticate all STA first
3531 		memcpy(scbval.ea.octet, &ether_bcast, ETHER_ADDR_LEN);
3532 		wl_ext_ioctl(cur_if->dev, WLC_SCB_DEAUTHENTICATE, &scbval.ea, ETHER_ADDR_LEN, 1);
3533 	}
3534 
3535 	if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
3536 		wl_ext_ioctl(dev, WLC_DOWN, NULL, 0, 1);
3537 		wl_ext_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1); // reset ssid
3538 		wl_ext_iovar_setint(dev, "mpc", 1);
3539 	} else if ((apstamode==ISTAAP_MODE || apstamode==ISTAGO_MODE) &&
3540 			cur_if->ifmode == IAP_MODE) {
3541 		bss_setbuf.cfg = 0xffffffff;
3542 		bss_setbuf.val = htod32(0);
3543 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3544 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
3545 		wl_ext_iovar_setint(dev, "mpc", 1);
3546 #ifdef ARP_OFFLOAD_SUPPORT
3547 		/* IF SoftAP is disabled, enable arpoe back for STA mode. */
3548 		dhd_arp_offload_set(dhd, dhd_arp_mode);
3549 		dhd_arp_offload_enable(dhd, TRUE);
3550 #endif /* ARP_OFFLOAD_SUPPORT */
3551 #ifdef PROP_TXSTATUS_VSDB
3552 #if defined(BCMSDIO)
3553 		if (dhd->conf->disable_proptx!=0) {
3554 			bool enabled;
3555 			dhd_wlfc_get_enable(dhd, &enabled);
3556 			if (enabled) {
3557 				dhd_wlfc_deinit(dhd);
3558 			}
3559 		}
3560 #endif /* BCMSDIO */
3561 #endif /* PROP_TXSTATUS_VSDB */
3562 	}
3563 	else if (apstamode == IDUALAP_MODE || apstamode == ISTAAPAP_MODE) {
3564 		bss_setbuf.cfg = 0xffffffff;
3565 		bss_setbuf.val = htod32(0);
3566 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3567 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
3568 #ifdef WLMESH
3569 	} else if (apstamode == ISTAMESH_MODE || apstamode == IMESHAP_MODE ||
3570 			apstamode == ISTAAPMESH_MODE || apstamode == IMESHAPAP_MODE) {
3571 		bss_setbuf.cfg = 0xffffffff;
3572 		bss_setbuf.val = htod32(0);
3573 		wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf, sizeof(bss_setbuf),
3574 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
3575 		if (cur_if->ifmode == IMESH_MODE) {
3576 			int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
3577 			for (i=0; i<MAX_IF_NUM; i++) {
3578 				tmp_if = &apsta_params->if_info[i];
3579 				if (tmp_if->dev && tmp_if->ifmode == ISTA_MODE) {
3580 					wl_ext_ioctl(tmp_if->dev, WLC_SET_SCAN_CHANNEL_TIME,
3581 						&scan_assoc_time, sizeof(scan_assoc_time), 1);
3582 				}
3583 			}
3584 		}
3585 #endif /* WLMESH */
3586 	}
3587 
3588 	wl_clr_isam_status(cur_if, AP_CREATED);
3589 
3590 	WL_MSG(ifname, "[%c] Exit\n", cur_if->prefix);
3591 	mutex_unlock(&apsta_params->usr_sync);
3592 	return 0;
3593 }
3594 
3595 static int
wl_ext_iapsta_disable(struct net_device * dev,char * command,int total_len)3596 wl_ext_iapsta_disable(struct net_device *dev, char *command, int total_len)
3597 {
3598 	int ret = 0;
3599 	char *pch, *pick_tmp, *param;
3600 	char ifname[IFNAMSIZ+1];
3601 
3602 	AEXT_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
3603 
3604 	pick_tmp = command;
3605 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_disable
3606 	param = bcmstrtok(&pick_tmp, " ", 0);
3607 	while (param != NULL) {
3608 		if (!strcmp(param, "ifname")) {
3609 			pch = bcmstrtok(&pick_tmp, " ", 0);
3610 			if (pch) {
3611 				strcpy(ifname, pch);
3612 				ret = wl_ext_disable_iface(dev, ifname);
3613 				if (ret)
3614 					return ret;
3615 			}
3616 			else {
3617 				AEXT_ERROR(dev->name, "ifname [wlanX]\n");
3618 				return -1;
3619 			}
3620 		}
3621 		param = bcmstrtok(&pick_tmp, " ", 0);
3622 	}
3623 
3624 	return ret;
3625 }
3626 
3627 static bool
wl_ext_diff_band(uint16 chan1,uint16 chan2)3628 wl_ext_diff_band(uint16 chan1, uint16 chan2)
3629 {
3630 	if ((chan1 <= CH_MAX_2G_CHANNEL && chan2 > CH_MAX_2G_CHANNEL) ||
3631 		(chan1 > CH_MAX_2G_CHANNEL && chan2 <= CH_MAX_2G_CHANNEL)) {
3632 		return TRUE;
3633 	}
3634 	return FALSE;
3635 }
3636 
3637 static uint16
wl_ext_same_band(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,bool nodfs)3638 wl_ext_same_band(struct wl_apsta_params *apsta_params,
3639 	struct wl_if_info *cur_if, bool nodfs)
3640 {
3641 	struct wl_if_info *tmp_if;
3642 	uint16 tmp_chan, target_chan = 0;
3643 	wl_prio_t max_prio;
3644 	int i;
3645 
3646 	// find the max prio
3647 	max_prio = cur_if->prio;
3648 	for (i=0; i<MAX_IF_NUM; i++) {
3649 		tmp_if = &apsta_params->if_info[i];
3650 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
3651 				tmp_if->prio > max_prio) {
3652 			tmp_chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
3653 			if (wl_ext_dfs_chan(tmp_chan) && nodfs)
3654 				continue;
3655 			if (tmp_chan && !wl_ext_diff_band(cur_if->channel, tmp_chan)) {
3656 				target_chan = tmp_chan;
3657 				max_prio = tmp_if->prio;
3658 			}
3659 		}
3660 	}
3661 
3662 	return target_chan;
3663 }
3664 
3665 static uint16
wl_ext_get_vsdb_chan(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if,struct wl_if_info * target_if)3666 wl_ext_get_vsdb_chan(struct wl_apsta_params *apsta_params,
3667 	struct wl_if_info *cur_if, struct wl_if_info *target_if)
3668 {
3669 	uint16 target_chan = 0, cur_chan = cur_if->channel;
3670 
3671 	target_chan = wl_ext_get_chan(apsta_params, target_if->dev);
3672 	if (target_chan) {
3673 		AEXT_INFO(cur_if->ifname, "cur_chan=%d, target_chan=%d\n",
3674 			cur_chan, target_chan);
3675 		if (wl_ext_diff_band(cur_chan, target_chan)) {
3676 			if (!apsta_params->rsdb)
3677 				return target_chan;
3678 		} else {
3679 			if (cur_chan != target_chan)
3680 				return target_chan;
3681 		}
3682 	}
3683 
3684 	return 0;
3685 }
3686 
3687 static int
wl_ext_rsdb_core_conflict(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3688 wl_ext_rsdb_core_conflict(struct wl_apsta_params *apsta_params,
3689 	struct wl_if_info *cur_if)
3690 {
3691 	struct wl_if_info *tmp_if;
3692 	uint16 cur_chan, tmp_chan;
3693 	int i;
3694 
3695 	if (apsta_params->rsdb) {
3696 		cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
3697 		for (i=0; i<MAX_IF_NUM; i++) {
3698 			tmp_if = &apsta_params->if_info[i];
3699 			if (tmp_if != cur_if && wl_get_isam_status(tmp_if, IF_READY) &&
3700 					tmp_if->prio > cur_if->prio) {
3701 				tmp_chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
3702 				if (!tmp_chan)
3703 					continue;
3704 				if (wl_ext_diff_band(cur_chan, tmp_chan) &&
3705 						wl_ext_diff_band(cur_chan, cur_if->channel))
3706 					return TRUE;
3707 				else if (!wl_ext_diff_band(cur_chan, tmp_chan) &&
3708 						wl_ext_diff_band(cur_chan, cur_if->channel))
3709 					return TRUE;
3710 			}
3711 		}
3712 	}
3713 	return FALSE;
3714 }
3715 
3716 static int
wl_ext_trigger_csa(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3717 wl_ext_trigger_csa(struct wl_apsta_params *apsta_params, struct wl_if_info *cur_if)
3718 {
3719 	s8 iovar_buf[WLC_IOCTL_SMLEN];
3720 	bool core_conflict = FALSE;
3721 
3722 	if (wl_ext_master_if(cur_if) && (apsta_params->csa & CSA_DRV_BIT)) {
3723 		if (!cur_if->channel) {
3724 			WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
3725 		} else if (wl_ext_dfs_chan(cur_if->channel) && !apsta_params->radar) {
3726 			WL_MSG(cur_if->ifname, "[%c] skip DFS channel %d\n",
3727 				cur_if->prefix, cur_if->channel);
3728 			wl_ext_if_down(apsta_params, cur_if);
3729 		} else {
3730 			wl_chan_switch_t csa_arg;
3731 			memset(&csa_arg, 0, sizeof(csa_arg));
3732 			csa_arg.mode = 1;
3733 			csa_arg.count = 3;
3734 			csa_arg.chspec = wl_ext_chan_to_chanspec(apsta_params, cur_if->dev,
3735 				cur_if->channel);
3736 			core_conflict = wl_ext_rsdb_core_conflict(apsta_params, cur_if);
3737 			if (core_conflict) {
3738 				WL_MSG(cur_if->ifname, "[%c] Skip CSA due to rsdb core conflict\n",
3739 					cur_if->prefix);
3740 			} else if (csa_arg.chspec) {
3741 				WL_MSG(cur_if->ifname, "[%c] Trigger CSA to channel %d(0x%x)\n",
3742 					cur_if->prefix, cur_if->channel, csa_arg.chspec);
3743 				wl_set_isam_status(cur_if, AP_CREATING);
3744 				wl_ext_iovar_setbuf(cur_if->dev, "csa", &csa_arg, sizeof(csa_arg),
3745 					iovar_buf, sizeof(iovar_buf), NULL);
3746 				OSL_SLEEP(500);
3747 				wl_clr_isam_status(cur_if, AP_CREATING);
3748 				wl_ext_isam_status(cur_if->dev, NULL, 0);
3749 			} else {
3750 				AEXT_ERROR(cur_if->ifname, "fail to get chanspec\n");
3751 			}
3752 		}
3753 	}
3754 
3755 	return 0;
3756 }
3757 
3758 static void
wl_ext_move_cur_dfs_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3759 wl_ext_move_cur_dfs_channel(struct wl_apsta_params *apsta_params,
3760 	struct wl_if_info *cur_if)
3761 {
3762 	uint16 other_chan = 0, cur_chan = cur_if->channel;
3763 	uint16 chan_2g = 0, chan_5g = 0;
3764 	uint32 auto_band = WLC_BAND_2G;
3765 
3766 	if (wl_ext_master_if(cur_if) && wl_ext_dfs_chan(cur_if->channel) &&
3767 			!apsta_params->radar) {
3768 
3769 		wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
3770 		if (!chan_2g && !chan_5g) {
3771 			cur_if->channel = 0;
3772 			WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
3773 			return;
3774 		}
3775 
3776 		if (apsta_params->vsdb) {
3777 			if (chan_5g) {
3778 				cur_if->channel = chan_5g;
3779 				auto_band = WLC_BAND_5G;
3780 				other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3781 			} else {
3782 				cur_if->channel = chan_2g;
3783 				auto_band = WLC_BAND_2G;
3784 				other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3785 			}
3786 			if (!other_chan) {
3787 				other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
3788 					auto_band);
3789 			}
3790 			if (other_chan)
3791 				cur_if->channel = other_chan;
3792 		} else if (apsta_params->rsdb) {
3793 			if (chan_5g) {
3794 				cur_if->channel = chan_5g;
3795 				auto_band = WLC_BAND_5G;
3796 				other_chan = wl_ext_same_band(apsta_params, cur_if, FALSE);
3797 				if (wl_ext_dfs_chan(other_chan) && chan_2g) {
3798 					cur_if->channel = chan_2g;
3799 					auto_band = WLC_BAND_2G;
3800 					other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3801 				}
3802 			} else {
3803 				cur_if->channel = chan_2g;
3804 				auto_band = WLC_BAND_2G;
3805 				other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3806 			}
3807 			if (!other_chan) {
3808 				other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
3809 					auto_band);
3810 			}
3811 			if (other_chan)
3812 				cur_if->channel = other_chan;
3813 		} else {
3814 			cur_if->channel = chan_5g;
3815 			other_chan = wl_ext_same_band(apsta_params, cur_if, FALSE);
3816 			if (other_chan) {
3817 				cur_if->channel = other_chan;
3818 			} else {
3819 				auto_band = WLC_BAND_5G;
3820 				other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
3821 					auto_band);
3822 				if (other_chan)
3823 					cur_if->channel = other_chan;
3824 			}
3825 		}
3826 		WL_MSG(cur_if->ifname, "[%c] move channel %d => %d\n",
3827 			cur_if->prefix, cur_chan, cur_if->channel);
3828 	}
3829 }
3830 
3831 static void
wl_ext_move_other_dfs_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3832 wl_ext_move_other_dfs_channel(struct wl_apsta_params *apsta_params,
3833 	struct wl_if_info *cur_if)
3834 {
3835 	uint16 other_chan = 0, cur_chan = cur_if->channel;
3836 	uint16 chan_2g = 0, chan_5g = 0;
3837 	uint32 auto_band = WLC_BAND_2G;
3838 
3839 	if (wl_ext_master_if(cur_if) && wl_ext_dfs_chan(cur_if->channel) &&
3840 			!apsta_params->radar) {
3841 
3842 		wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
3843 		if (!chan_2g && !chan_5g) {
3844 			cur_if->channel = 0;
3845 			WL_MSG(cur_if->ifname, "[%c] no valid channel\n", cur_if->prefix);
3846 			return;
3847 		}
3848 
3849 		if (apsta_params->vsdb) {
3850 			if (chan_5g) {
3851 				cur_if->channel = chan_5g;
3852 				auto_band = WLC_BAND_5G;
3853 				other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3854 			} else {
3855 				cur_if->channel = chan_2g;
3856 				auto_band = WLC_BAND_2G;
3857 				other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3858 			}
3859 			if (!other_chan) {
3860 				other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
3861 					auto_band);
3862 			}
3863 			if (other_chan)
3864 				cur_if->channel = other_chan;
3865 		} else if (apsta_params->rsdb) {
3866 			if (chan_2g) {
3867 				cur_if->channel = chan_2g;
3868 				auto_band = WLC_BAND_2G;
3869 				other_chan = wl_ext_same_band(apsta_params, cur_if, TRUE);
3870 				if (!other_chan) {
3871 					other_chan = wl_ext_autochannel(cur_if->dev, ACS_FW_BIT|ACS_DRV_BIT,
3872 						auto_band);
3873 				}
3874 			} else {
3875 				cur_if->channel = 0;
3876 			}
3877 			if (other_chan)
3878 				cur_if->channel = other_chan;
3879 		} else {
3880 			cur_if->channel = 0;
3881 		}
3882 		WL_MSG(cur_if->ifname, "[%c] move channel %d => %d\n",
3883 			cur_if->prefix, cur_chan, cur_if->channel);
3884 	}
3885 }
3886 
3887 static uint16
wl_ext_move_cur_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3888 wl_ext_move_cur_channel(struct wl_apsta_params *apsta_params,
3889 	struct wl_if_info *cur_if)
3890 {
3891 	struct wl_if_info *tmp_if, *target_if = NULL;
3892 	uint16 tmp_chan, target_chan = 0;
3893 	wl_prio_t max_prio;
3894 	int i;
3895 
3896 	if (apsta_params->vsdb) {
3897 		target_chan = cur_if->channel;
3898 		goto exit;
3899 	}
3900 
3901 	// find the max prio
3902 	max_prio = cur_if->prio;
3903 	for (i=0; i<MAX_IF_NUM; i++) {
3904 		tmp_if = &apsta_params->if_info[i];
3905 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
3906 				tmp_if->prio > max_prio) {
3907 			tmp_chan = wl_ext_get_vsdb_chan(apsta_params, cur_if, tmp_if);
3908 			if (tmp_chan) {
3909 				target_if = tmp_if;
3910 				target_chan = tmp_chan;
3911 				max_prio = tmp_if->prio;
3912 			}
3913 		}
3914 	}
3915 
3916 	if (target_chan) {
3917 		tmp_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
3918 		if (apsta_params->rsdb && tmp_chan &&
3919 				wl_ext_diff_band(tmp_chan, target_chan)) {
3920 			WL_MSG(cur_if->ifname, "[%c] keep on current channel %d\n",
3921 				cur_if->prefix, tmp_chan);
3922 			cur_if->channel = 0;
3923 		} else {
3924 			WL_MSG(cur_if->ifname, "[%c] channel=%d => %s[%c] channel=%d\n",
3925 				cur_if->prefix, cur_if->channel,
3926 				target_if->ifname, target_if->prefix, target_chan);
3927 			cur_if->channel = target_chan;
3928 		}
3929 	}
3930 
3931 exit:
3932 	wl_ext_move_cur_dfs_channel(apsta_params, cur_if);
3933 
3934 	return cur_if->channel;
3935 }
3936 
3937 static void
wl_ext_move_other_channel(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3938 wl_ext_move_other_channel(struct wl_apsta_params *apsta_params,
3939 	struct wl_if_info *cur_if)
3940 {
3941 	struct wl_if_info *tmp_if, *target_if=NULL;
3942 	uint16 tmp_chan, target_chan = 0;
3943 	wl_prio_t max_prio = 0, cur_prio;
3944 	int i;
3945 
3946 	if (apsta_params->vsdb || !cur_if->channel) {
3947 		return;
3948 	}
3949 
3950 	// find the max prio, but lower than cur_if
3951 	cur_prio = cur_if->prio;
3952 	for (i=0; i<MAX_IF_NUM; i++) {
3953 		tmp_if = &apsta_params->if_info[i];
3954 		if (cur_if != tmp_if && wl_get_isam_status(tmp_if, IF_READY) &&
3955 				tmp_if->prio >= max_prio && tmp_if->prio <= cur_prio) {
3956 			tmp_chan = wl_ext_get_vsdb_chan(apsta_params, cur_if, tmp_if);
3957 			if (tmp_chan) {
3958 				target_if = tmp_if;
3959 				target_chan = tmp_chan;
3960 				max_prio = tmp_if->prio;
3961 			}
3962 		}
3963 	}
3964 
3965 	if (target_if) {
3966 		WL_MSG(target_if->ifname, "channel=%d => %s channel=%d\n",
3967 			target_chan, cur_if->ifname, cur_if->channel);
3968 		target_if->channel = cur_if->channel;
3969 		wl_ext_move_other_dfs_channel(apsta_params, target_if);
3970 		if (apsta_params->csa == 0) {
3971 			wl_ext_if_down(apsta_params, target_if);
3972 			wl_ext_move_other_channel(apsta_params, cur_if);
3973 			if (target_if->ifmode == ISTA_MODE || target_if->ifmode == IMESH_MODE) {
3974 				wl_ext_enable_iface(target_if->dev, target_if->ifname, 0);
3975 			} else if (target_if->ifmode == IAP_MODE) {
3976 				wl_ext_if_up(apsta_params, target_if, FALSE);
3977 			}
3978 		} else {
3979 			wl_ext_trigger_csa(apsta_params, target_if);
3980 		}
3981 	}
3982 
3983 }
3984 
3985 static bool
wl_ext_wait_other_enabling(struct wl_apsta_params * apsta_params,struct wl_if_info * cur_if)3986 wl_ext_wait_other_enabling(struct wl_apsta_params *apsta_params,
3987 	struct wl_if_info *cur_if)
3988 {
3989 	struct wl_if_info *tmp_if;
3990 	bool enabling = FALSE;
3991 	u32 timeout = 1;
3992 	int i;
3993 
3994 	for (i=0; i<MAX_IF_NUM; i++) {
3995 		tmp_if = &apsta_params->if_info[i];
3996 		if (tmp_if->dev && tmp_if->dev != cur_if->dev) {
3997 			if (tmp_if->ifmode == ISTA_MODE)
3998 				enabling = wl_get_isam_status(tmp_if, STA_CONNECTING);
3999 			else if (tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IMESH_MODE)
4000 				enabling = wl_get_isam_status(tmp_if, AP_CREATING);
4001 			if (enabling)
4002 				WL_MSG(cur_if->ifname, "waiting for %s[%c] enabling...\n",
4003 					tmp_if->ifname, tmp_if->prefix);
4004 			if (enabling && tmp_if->ifmode == ISTA_MODE) {
4005 				timeout = wait_event_interruptible_timeout(
4006 					apsta_params->netif_change_event,
4007 					!wl_get_isam_status(tmp_if, STA_CONNECTING),
4008 					msecs_to_jiffies(MAX_STA_LINK_WAIT_TIME));
4009 			} else if (enabling &&
4010 					(tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IMESH_MODE)) {
4011 				timeout = wait_event_interruptible_timeout(
4012 					apsta_params->netif_change_event,
4013 					!wl_get_isam_status(tmp_if, AP_CREATING),
4014 					msecs_to_jiffies(MAX_STA_LINK_WAIT_TIME));
4015 			}
4016 			if (tmp_if->ifmode == ISTA_MODE)
4017 				enabling = wl_get_isam_status(tmp_if, STA_CONNECTING);
4018 			else if (tmp_if->ifmode == IAP_MODE || tmp_if->ifmode == IMESH_MODE)
4019 				enabling = wl_get_isam_status(tmp_if, AP_CREATING);
4020 			if (timeout <= 0 || enabling) {
4021 				WL_MSG(cur_if->ifname, "%s[%c] is still enabling...\n",
4022 					tmp_if->ifname, tmp_if->prefix);
4023 			}
4024 		}
4025 	}
4026 
4027 	return enabling;
4028 }
4029 
4030 static int
wl_ext_enable_iface(struct net_device * dev,char * ifname,int wait_up)4031 wl_ext_enable_iface(struct net_device *dev, char *ifname, int wait_up)
4032 {
4033 	struct dhd_pub *dhd = dhd_get_pub(dev);
4034 	int i, ret = 0;
4035 	s8 iovar_buf[WLC_IOCTL_SMLEN];
4036 	wlc_ssid_t ssid = { 0, {0} };
4037 	chanspec_t fw_chspec;
4038 	struct {
4039 		s32 cfg;
4040 		s32 val;
4041 	} bss_setbuf;
4042 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4043 	apstamode_t apstamode = apsta_params->apstamode;
4044 	struct wl_if_info *cur_if = NULL, *tmp_if = NULL;
4045 	uint16 cur_chan;
4046 	struct wl_conn_info conn_info;
4047 	u32 timeout;
4048 
4049 	for (i=0; i<MAX_IF_NUM; i++) {
4050 		tmp_if = &apsta_params->if_info[i];
4051 		if (tmp_if->dev && !strcmp(tmp_if->dev->name, ifname)) {
4052 			cur_if = tmp_if;
4053 			break;
4054 		}
4055 	}
4056 	if (!cur_if) {
4057 		AEXT_ERROR(dev->name, "wrong ifname=%s or dev not ready\n", ifname);
4058 		return -1;
4059 	}
4060 
4061 	mutex_lock(&apsta_params->usr_sync);
4062 
4063 	if (cur_if->ifmode == ISTA_MODE) {
4064 		wl_set_isam_status(cur_if, STA_CONNECTING);
4065 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
4066 		wl_set_isam_status(cur_if, AP_CREATING);
4067 	}
4068 
4069 	wl_ext_isam_status(cur_if->dev, NULL, 0);
4070 	WL_MSG(ifname, "[%c] Enabling...\n", cur_if->prefix);
4071 
4072 	wl_ext_wait_other_enabling(apsta_params, cur_if);
4073 
4074 	if (wl_ext_master_if(cur_if) && apsta_params->acs) {
4075 		uint16 chan_2g, chan_5g;
4076 		uint auto_band;
4077 		auto_band = WL_GET_BAND(cur_if->channel);
4078 		wl_ext_get_default_chan(cur_if->dev, &chan_2g, &chan_5g, TRUE);
4079 		if ((chan_2g && auto_band == WLC_BAND_2G) ||
4080 				(chan_5g && auto_band == WLC_BAND_5G)) {
4081 			cur_if->channel = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
4082 				auto_band);
4083 		} else {
4084 			AEXT_ERROR(ifname, "invalid channel\n");
4085 			ret = -1;
4086 			goto exit;
4087 		}
4088 	}
4089 
4090 	wl_ext_move_cur_channel(apsta_params, cur_if);
4091 
4092 	if (wl_ext_master_if(cur_if) && !cur_if->channel) {
4093 		AEXT_ERROR(ifname, "skip channel 0\n");
4094 		ret = -1;
4095 		goto exit;
4096 	}
4097 
4098 	cur_chan = wl_ext_get_chan(apsta_params, cur_if->dev);
4099 	if (cur_chan) {
4100 		AEXT_INFO(cur_if->ifname, "Associated\n");
4101 		if (cur_chan != cur_if->channel) {
4102 			wl_ext_trigger_csa(apsta_params, cur_if);
4103 		}
4104 		goto exit;
4105 	}
4106 	if (cur_if->ifmode == ISTA_MODE) {
4107 		wl_clr_isam_status(cur_if, STA_CONNECTED);
4108 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
4109 		wl_clr_isam_status(cur_if, AP_CREATED);
4110 	}
4111 
4112 	wl_ext_move_other_channel(apsta_params, cur_if);
4113 
4114 	if (cur_if->ifidx > 0) {
4115 		wl_ext_iovar_setbuf(cur_if->dev, "cur_etheraddr", (u8 *)cur_if->dev->dev_addr,
4116 			ETHER_ADDR_LEN, iovar_buf, WLC_IOCTL_SMLEN, NULL);
4117 	}
4118 
4119 	// set ssid for AP
4120 	ssid.SSID_len = strlen(cur_if->ssid);
4121 	memcpy(ssid.SSID, cur_if->ssid, ssid.SSID_len);
4122 	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
4123 		wl_ext_iovar_setint(dev, "mpc", 0);
4124 		if (apstamode == IAPONLY_MODE || apstamode == IMESHONLY_MODE) {
4125 			wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
4126 		} else if (apstamode==ISTAAP_MODE || apstamode==ISTAGO_MODE) {
4127 			wl_ext_iovar_setbuf_bsscfg(cur_if->dev, "ssid", &ssid, sizeof(ssid),
4128 				iovar_buf, WLC_IOCTL_SMLEN, cur_if->bssidx, NULL);
4129 		}
4130 	}
4131 
4132 	if (wl_ext_master_if(cur_if)) {
4133 		wl_ext_set_bgnmode(cur_if);
4134 		if (!cur_if->channel) {
4135 			cur_if->channel = 1;
4136 		}
4137 		ret = wl_ext_set_chanspec(cur_if->dev, apsta_params->ioctl_ver,
4138 			cur_if->channel, &fw_chspec);
4139 		if (ret)
4140 			goto exit;
4141 	}
4142 
4143 	wl_ext_set_amode(cur_if);
4144 	wl_ext_set_emode(apsta_params, cur_if);
4145 
4146 	if (cur_if->ifmode == ISTA_MODE) {
4147 		conn_info.bssidx = cur_if->bssidx;
4148 		conn_info.channel = cur_if->channel;
4149 		memcpy(conn_info.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
4150 		conn_info.ssid.SSID_len = strlen(cur_if->ssid);
4151 		memcpy(&conn_info.bssid, &cur_if->bssid, ETHER_ADDR_LEN);
4152 	}
4153 	if (cur_if->ifmode == IAP_MODE) {
4154 		if (cur_if->maxassoc >= 0)
4155 			wl_ext_iovar_setint(dev, "maxassoc", cur_if->maxassoc);
4156 		// terence: fix me, hidden does not work in dualAP mode
4157 		if (cur_if->hidden > 0) {
4158 			wl_ext_ioctl(cur_if->dev, WLC_SET_CLOSED, &cur_if->hidden,
4159 				sizeof(cur_if->hidden), 1);
4160 			WL_MSG(ifname, "[%c] Broadcast SSID: %s\n",
4161 				cur_if->prefix, cur_if->hidden ? "OFF":"ON");
4162 		}
4163 	}
4164 
4165 	if (apstamode == ISTAONLY_MODE) {
4166 		wl_ext_connect(cur_if->dev, &conn_info);
4167 	} else if (apstamode == IAPONLY_MODE) {
4168 		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
4169 		wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
4170 	} else if (apstamode == ISTAAP_MODE || apstamode == ISTAGO_MODE) {
4171 		if (cur_if->ifmode == ISTA_MODE) {
4172 			wl_ext_connect(cur_if->dev, &conn_info);
4173 		} else {
4174 			if (FW_SUPPORTED(dhd, rsdb)) {
4175 				wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
4176 			} else {
4177 				bss_setbuf.cfg = htod32(cur_if->bssidx);
4178 				bss_setbuf.val = htod32(1);
4179 				wl_ext_iovar_setbuf(cur_if->dev, "bss", &bss_setbuf,
4180 					sizeof(bss_setbuf), iovar_buf, WLC_IOCTL_SMLEN, NULL);
4181 			}
4182 #ifdef ARP_OFFLOAD_SUPPORT
4183 			/* IF SoftAP is enabled, disable arpoe */
4184 			dhd_arp_offload_set(dhd, 0);
4185 			dhd_arp_offload_enable(dhd, FALSE);
4186 #endif /* ARP_OFFLOAD_SUPPORT */
4187 #ifdef PROP_TXSTATUS_VSDB
4188 #if defined(BCMSDIO)
4189 			if (!(FW_SUPPORTED(dhd, rsdb)) && !disable_proptx) {
4190 				bool enabled;
4191 				dhd_wlfc_get_enable(dhd, &enabled);
4192 				if (!enabled) {
4193 					dhd_wlfc_init(dhd);
4194 					wl_ext_ioctl(dev, WLC_UP, NULL, 0, 1);
4195 				}
4196 			}
4197 #endif /* BCMSDIO */
4198 #endif /* PROP_TXSTATUS_VSDB */
4199 		}
4200 	}
4201 	else if (apstamode == IDUALAP_MODE) {
4202 		wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
4203 	} else if (apstamode == ISTAAPAP_MODE) {
4204 		if (cur_if->ifmode == ISTA_MODE) {
4205 			wl_ext_connect(cur_if->dev, &conn_info);
4206 		} else if (cur_if->ifmode == IAP_MODE) {
4207 			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
4208 		} else {
4209 			AEXT_ERROR(cur_if->ifname, "wrong ifmode %d\n", cur_if->ifmode);
4210 		}
4211 #ifdef WLMESH
4212 	} else if (apstamode == IMESHONLY_MODE ||
4213 			apstamode == ISTAMESH_MODE || apstamode == IMESHAP_MODE ||
4214 			apstamode == ISTAAPMESH_MODE || apstamode == IMESHAPAP_MODE) {
4215 		if (cur_if->ifmode == ISTA_MODE) {
4216 			wl_ext_connect(cur_if->dev, &conn_info);
4217 		} else if (cur_if->ifmode == IAP_MODE) {
4218 			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &ssid, sizeof(ssid), 1);
4219 		} else if (cur_if->ifmode == IMESH_MODE) {
4220 			struct wl_join_params join_params;
4221 			// need to up before setting ssid
4222 			memset(&join_params, 0, sizeof(join_params));
4223 			join_params.ssid.SSID_len = strlen(cur_if->ssid);
4224 			memcpy((void *)join_params.ssid.SSID, cur_if->ssid, strlen(cur_if->ssid));
4225 			join_params.params.chanspec_list[0] = fw_chspec;
4226 			join_params.params.chanspec_num = 1;
4227 			wl_ext_ioctl(cur_if->dev, WLC_SET_SSID, &join_params, sizeof(join_params), 1);
4228 		} else {
4229 			AEXT_ERROR(cur_if->ifname, "wrong ifmode %d\n", cur_if->ifmode);
4230 		}
4231 #endif /* WLMESH */
4232 	}
4233 
4234 	if (wait_up) {
4235 		OSL_SLEEP(wait_up);
4236 	} else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
4237 		timeout = wait_event_interruptible_timeout(apsta_params->netif_change_event,
4238 			wl_get_isam_status(cur_if, AP_CREATED),
4239 			msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
4240 		if (timeout <= 0 || !wl_get_isam_status(cur_if, AP_CREATED)) {
4241 			mutex_unlock(&apsta_params->usr_sync);
4242 			wl_ext_disable_iface(dev, cur_if->ifname);
4243 			WL_MSG(ifname, "[%c] failed to enable with SSID: \"%s\"\n",
4244 				cur_if->prefix, cur_if->ssid);
4245 			ret = -1;
4246 		}
4247 	}
4248 
4249 	if (wl_get_isam_status(cur_if, AP_CREATED) &&
4250 			(cur_if->ifmode == IMESH_MODE || cur_if->ifmode == IAP_MODE) &&
4251 			(apstamode == ISTAAP_MODE || apstamode == ISTAAPAP_MODE ||
4252 			apstamode == ISTAMESH_MODE || apstamode == IMESHAP_MODE ||
4253 			apstamode == ISTAAPMESH_MODE || apstamode == IMESHAPAP_MODE)) {
4254 		int scan_assoc_time = 80;
4255 		for (i=0; i<MAX_IF_NUM; i++) {
4256 			tmp_if = &apsta_params->if_info[i];
4257 			if (tmp_if->dev && tmp_if->ifmode == ISTA_MODE) {
4258 				wl_ext_ioctl(tmp_if->dev, WLC_SET_SCAN_CHANNEL_TIME,
4259 					&scan_assoc_time, sizeof(scan_assoc_time), 1);
4260 			}
4261 		}
4262 	}
4263 
4264 	wl_ext_isam_status(cur_if->dev, NULL, 0);
4265 
4266 exit:
4267 	if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
4268 		wl_clr_isam_status(cur_if, AP_CREATING);
4269 	}
4270 	WL_MSG(ifname, "[%c] Exit ret=%d\n", cur_if->prefix, ret);
4271 	mutex_unlock(&apsta_params->usr_sync);
4272 	return ret;
4273 }
4274 
4275 static int
wl_ext_iapsta_enable(struct net_device * dev,char * command,int total_len)4276 wl_ext_iapsta_enable(struct net_device *dev, char *command, int total_len)
4277 {
4278 	int ret = 0;
4279 	char *pch, *pick_tmp, *param;
4280 	char ifname[IFNAMSIZ+1];
4281 
4282 	AEXT_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
4283 
4284 	pick_tmp = command;
4285 	param = bcmstrtok(&pick_tmp, " ", 0); // skip iapsta_enable
4286 	param = bcmstrtok(&pick_tmp, " ", 0);
4287 	while (param != NULL) {
4288 		if (!strcmp(param, "ifname")) {
4289 			pch = bcmstrtok(&pick_tmp, " ", 0);
4290 			if (pch) {
4291 				strcpy(ifname, pch);
4292 				ret = wl_ext_enable_iface(dev, ifname, 0);
4293 				if (ret)
4294 					return ret;
4295 			} else {
4296 				AEXT_ERROR(dev->name, "ifname [wlanX]\n");
4297 				return -1;
4298 			}
4299 		}
4300 		param = bcmstrtok(&pick_tmp, " ", 0);
4301 	}
4302 
4303 	return ret;
4304 }
4305 
4306 #ifdef PROPTX_MAXCOUNT
4307 int
wl_ext_get_wlfc_maxcount(struct dhd_pub * dhd,int ifidx)4308 wl_ext_get_wlfc_maxcount(struct dhd_pub *dhd, int ifidx)
4309 {
4310 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4311 	struct wl_if_info *tmp_if, *cur_if = NULL;
4312 	int i, maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
4313 
4314 	if (!apsta_params->rsdb)
4315 		return maxcount;
4316 
4317 	for (i=0; i<MAX_IF_NUM; i++) {
4318 		tmp_if = &apsta_params->if_info[i];
4319 		if (tmp_if->dev && tmp_if->ifidx == ifidx) {
4320 			cur_if = tmp_if;
4321 			maxcount = cur_if->transit_maxcount;
4322 		}
4323 	}
4324 
4325 	if (cur_if)
4326 		AEXT_INFO(cur_if->ifname, "update maxcount %d\n", maxcount);
4327 	else
4328 		AEXT_INFO("wlan", "update maxcount %d for ifidx %d\n", maxcount, ifidx);
4329 	return maxcount;
4330 }
4331 
4332 void
wl_ext_update_wlfc_maxcount(struct dhd_pub * dhd)4333 wl_ext_update_wlfc_maxcount(struct dhd_pub *dhd)
4334 {
4335 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4336 	struct wl_if_info *tmp_if;
4337 	bool band_5g = FALSE;
4338 	uint16 chan = 0;
4339 	int i, ret;
4340 
4341 	if (!apsta_params->rsdb)
4342 		return;
4343 
4344 	for (i=0; i<MAX_IF_NUM; i++) {
4345 		tmp_if = &apsta_params->if_info[i];
4346 		if (tmp_if->dev) {
4347 			chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
4348 			if (chan > CH_MAX_2G_CHANNEL) {
4349 				tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g;
4350 				ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx,
4351 					tmp_if->transit_maxcount);
4352 				if (ret == 0)
4353 					AEXT_INFO(tmp_if->ifname, "updated maxcount %d\n",
4354 						tmp_if->transit_maxcount);
4355 				band_5g = TRUE;
4356 			}
4357 		}
4358 	}
4359 
4360 	for (i=0; i<MAX_IF_NUM; i++) {
4361 		tmp_if = &apsta_params->if_info[i];
4362 		if (tmp_if->dev) {
4363 			chan = wl_ext_get_chan(apsta_params, tmp_if->dev);
4364 			if ((chan == 0) || (chan <= CH_MAX_2G_CHANNEL && chan >= CH_MIN_2G_CHANNEL)) {
4365 				if (chan == 0) {
4366 					tmp_if->transit_maxcount = WL_TXSTATUS_FREERUNCTR_MASK;
4367 				} else if (band_5g) {
4368 					tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_2g;
4369 				} else {
4370 					tmp_if->transit_maxcount = dhd->conf->proptx_maxcnt_5g;
4371 				}
4372 				ret = dhd_wlfc_update_maxcount(dhd, tmp_if->ifidx,
4373 					tmp_if->transit_maxcount);
4374 				if (ret == 0)
4375 					AEXT_INFO(tmp_if->ifname, "updated maxcount %d\n",
4376 						tmp_if->transit_maxcount);
4377 			}
4378 		}
4379 	}
4380 }
4381 #endif /* PROPTX_MAXCOUNT */
4382 
4383 static s32
wl_ext_iapsta_event(struct net_device * dev,void * params,const wl_event_msg_t * e,void * data)4384 wl_ext_iapsta_event(struct net_device *dev,
4385 	void *params, const wl_event_msg_t *e, void* data)
4386 {
4387 	struct wl_if_info *cur_if = NULL;
4388 #if defined(WLMESH) && defined(WL_ESCAN)
4389 	struct wl_if_info *tmp_if = NULL;
4390 	struct wl_if_info *mesh_if = NULL;
4391 	int i;
4392 #endif /* WLMESH && WL_ESCAN */
4393 	uint32 event_type = ntoh32(e->event_type);
4394 	uint32 status =  ntoh32(e->status);
4395 	uint32 reason =  ntoh32(e->reason);
4396 	uint16 flags =  ntoh16(e->flags);
4397 	struct wl_apsta_params *apsta_params = (struct wl_apsta_params *)params;
4398 
4399 	cur_if = wl_get_cur_if(dev);
4400 
4401 #if defined(WLMESH) && defined(WL_ESCAN)
4402 	for (i=0; i<MAX_IF_NUM; i++) {
4403 		tmp_if = &apsta_params->if_info[i];
4404 		if (tmp_if->dev && tmp_if->ifmode == IMESH_MODE) {
4405 			mesh_if = tmp_if;
4406 			break;
4407 		}
4408 	}
4409 #endif /* WLMESH && WL_ESCAN */
4410 	if (!cur_if || !cur_if->dev) {
4411 		AEXT_DBG(dev->name, "ifidx %d is not ready\n", e->ifidx);
4412 		return -1;
4413 	}
4414 
4415 	if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE) {
4416 		if (event_type == WLC_E_LINK) {
4417 			if (!(flags & WLC_EVENT_MSG_LINK)) {
4418 				WL_MSG(cur_if->ifname,
4419 					"[%c] Link down with %pM, %s(%d), reason %d\n",
4420 					cur_if->prefix, &e->addr, bcmevent_get_name(event_type),
4421 					event_type, reason);
4422 				wl_clr_isam_status(cur_if, STA_CONNECTED);
4423 #if defined(WLMESH) && defined(WL_ESCAN)
4424 				if (mesh_if && apsta_params->macs)
4425 					wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
4426 #endif /* WLMESH && WL_ESCAN */
4427 			} else {
4428 				WL_MSG(cur_if->ifname, "[%c] Link UP with %pM\n",
4429 					cur_if->prefix, &e->addr);
4430 				wl_set_isam_status(cur_if, STA_CONNECTED);
4431 #if defined(WLMESH) && defined(WL_ESCAN)
4432 				if (mesh_if && apsta_params->macs)
4433 					wl_mesh_update_master_info(apsta_params, mesh_if);
4434 #endif /* WLMESH && WL_ESCAN */
4435 			}
4436 			wl_clr_isam_status(cur_if, STA_CONNECTING);
4437 			wake_up_interruptible(&apsta_params->netif_change_event);
4438 #ifdef PROPTX_MAXCOUNT
4439 			wl_ext_update_wlfc_maxcount(apsta_params->dhd);
4440 #endif /* PROPTX_MAXCOUNT */
4441 		}
4442 		else if (event_type == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS) {
4443 			WL_MSG(cur_if->ifname,
4444 				"connect failed event=%d, reason=%d, status=%d\n",
4445 				event_type, reason, status);
4446 			wl_clr_isam_status(cur_if, STA_CONNECTING);
4447 			wake_up_interruptible(&apsta_params->netif_change_event);
4448 #if defined(WLMESH) && defined(WL_ESCAN)
4449 			if (mesh_if && apsta_params->macs)
4450 				wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
4451 #endif /* WLMESH && WL_ESCAN */
4452 #ifdef PROPTX_MAXCOUNT
4453 			wl_ext_update_wlfc_maxcount(apsta_params->dhd);
4454 #endif /* PROPTX_MAXCOUNT */
4455 		}
4456 		else if (event_type == WLC_E_DEAUTH || event_type == WLC_E_DEAUTH_IND ||
4457 				event_type == WLC_E_DISASSOC || event_type == WLC_E_DISASSOC_IND) {
4458 			WL_MSG(cur_if->ifname, "[%c] Link down with %pM, %s(%d), reason %d\n",
4459 				cur_if->prefix, &e->addr, bcmevent_get_name(event_type),
4460 				event_type, reason);
4461 #if defined(WLMESH) && defined(WL_ESCAN)
4462 			if (mesh_if && apsta_params->macs)
4463 				wl_mesh_clear_mesh_info(apsta_params, mesh_if, TRUE);
4464 #endif /* WLMESH && WL_ESCAN */
4465 		}
4466 	}
4467 	else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IMESH_MODE) {
4468 		if ((event_type == WLC_E_SET_SSID && status == WLC_E_STATUS_SUCCESS) ||
4469 				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
4470 				reason == WLC_E_REASON_INITIAL_ASSOC)) {
4471 			if (wl_get_isam_status(cur_if, AP_CREATING)) {
4472 				WL_MSG(cur_if->ifname, "[%c] Link up (etype=%d)\n",
4473 					cur_if->prefix, event_type);
4474 				wl_set_isam_status(cur_if, AP_CREATED);
4475 				wake_up_interruptible(&apsta_params->netif_change_event);
4476 			} else {
4477 				wl_set_isam_status(cur_if, AP_CREATED);
4478 				WL_MSG(cur_if->ifname, "[%c] Link up w/o creating? (etype=%d)\n",
4479 					cur_if->prefix, event_type);
4480 			}
4481 #ifdef PROPTX_MAXCOUNT
4482 			wl_ext_update_wlfc_maxcount(apsta_params->dhd);
4483 #endif /* PROPTX_MAXCOUNT */
4484 		}
4485 		else if ((event_type == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS) ||
4486 				(event_type == WLC_E_LINK && status == WLC_E_STATUS_SUCCESS &&
4487 				reason == WLC_E_REASON_DEAUTH)) {
4488 			wl_clr_isam_status(cur_if, AP_CREATED);
4489 			WL_MSG(cur_if->ifname, "[%c] Link down, reason=%d\n",
4490 				cur_if->prefix, reason);
4491 #ifdef PROPTX_MAXCOUNT
4492 			wl_ext_update_wlfc_maxcount(apsta_params->dhd);
4493 #endif /* PROPTX_MAXCOUNT */
4494 		}
4495 		else if ((event_type == WLC_E_ASSOC_IND || event_type == WLC_E_REASSOC_IND) &&
4496 				reason == DOT11_SC_SUCCESS) {
4497 			WL_MSG(cur_if->ifname, "[%c] connected device %pM\n",
4498 				cur_if->prefix, &e->addr);
4499 			wl_ext_isam_status(cur_if->dev, NULL, 0);
4500 		}
4501 		else if (event_type == WLC_E_DISASSOC_IND ||
4502 				event_type == WLC_E_DEAUTH_IND ||
4503 				(event_type == WLC_E_DEAUTH && reason != DOT11_RC_RESERVED)) {
4504 			WL_MSG_RLMT(cur_if->ifname, &e->addr, ETHER_ADDR_LEN,
4505 				"[%c] disconnected device %pM, %s(%d), reason=%d\n",
4506 				cur_if->prefix, &e->addr, bcmevent_get_name(event_type),
4507 				event_type, reason);
4508 			wl_ext_isam_status(cur_if->dev, NULL, 0);
4509 		}
4510 #if defined(WLMESH) && defined(WL_ESCAN)
4511 		if (cur_if->ifmode == IMESH_MODE && apsta_params->macs)
4512 			wl_mesh_event_handler(apsta_params, cur_if, e, data);
4513 #endif /* WLMESH && WL_ESCAN */
4514 	}
4515 
4516 	return 0;
4517 }
4518 
4519 #ifdef WL_CFG80211
4520 static struct wl_if_info *
wl_ext_get_dfs_master_if(struct wl_apsta_params * apsta_params)4521 wl_ext_get_dfs_master_if(struct wl_apsta_params *apsta_params)
4522 {
4523 	struct wl_if_info *cur_if = NULL;
4524 	uint16 chan = 0;
4525 	int i;
4526 
4527 	for (i=0; i<MAX_IF_NUM; i++) {
4528 		cur_if = &apsta_params->if_info[i];
4529 		if (!cur_if->dev || !wl_ext_master_if(cur_if))
4530 			continue;
4531 		chan = wl_ext_get_chan(apsta_params, cur_if->dev);
4532 		if (wl_ext_dfs_chan(chan)) {
4533 			return cur_if;
4534 		}
4535 	}
4536 	return NULL;
4537 }
4538 
4539 static void
wl_ext_save_master_channel(struct wl_apsta_params * apsta_params,uint16 post_channel)4540 wl_ext_save_master_channel(struct wl_apsta_params *apsta_params,
4541 	uint16 post_channel)
4542 {
4543 	struct wl_if_info *cur_if = NULL;
4544 	uint16 chan = 0;
4545 	int i;
4546 
4547 	if (apsta_params->vsdb)
4548 		return;
4549 
4550 	for (i=0; i<MAX_IF_NUM; i++) {
4551 		cur_if = &apsta_params->if_info[i];
4552 		if (!cur_if->dev || !wl_ext_master_if(cur_if))
4553 			continue;
4554 		chan = wl_ext_get_chan(apsta_params, cur_if->dev);
4555 		if (chan) {
4556 			cur_if->prev_channel = chan;
4557 			cur_if->post_channel = post_channel;
4558 		}
4559 	}
4560 }
4561 
4562 bool
wl_legacy_chip_check(struct net_device * net)4563 wl_legacy_chip_check(struct net_device *net)
4564 {
4565 	struct dhd_pub *dhd = dhd_get_pub(net);
4566 	uint chip;
4567 
4568 	chip = dhd_conf_get_chip(dhd);
4569 
4570 	if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
4571 		chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
4572 		chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
4573 		chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
4574 		chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
4575 		chip == BCM4371_CHIP_ID ||
4576 		chip == BCM43430_CHIP_ID ||
4577 		chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
4578 		chip == BCM4359_CHIP_ID ||
4579 		chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
4580 		chip == BCM43569_CHIP_ID) {
4581 		return true;
4582 	}
4583 
4584 	return false;
4585 }
4586 
4587 bool
wl_extsae_chip(struct dhd_pub * dhd)4588 wl_extsae_chip(struct dhd_pub *dhd)
4589 {
4590 	uint chip;
4591 
4592 	chip = dhd_conf_get_chip(dhd);
4593 
4594 	if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
4595 		chip == BCM4334_CHIP_ID || chip == BCM43340_CHIP_ID ||
4596 		chip == BCM43341_CHIP_ID || chip == BCM4324_CHIP_ID ||
4597 		chip == BCM4335_CHIP_ID || chip == BCM4339_CHIP_ID ||
4598 		chip == BCM4354_CHIP_ID ||
4599 		chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
4600 		chip == BCM43569_CHIP_ID) {
4601 		return false;
4602 	}
4603 
4604 	return true;
4605 }
4606 
4607 bool
wl_new_chip_check(struct net_device * net)4608 wl_new_chip_check(struct net_device *net)
4609 {
4610 	struct dhd_pub *dhd = dhd_get_pub(net);
4611 	uint chip;
4612 
4613 	chip = dhd_conf_get_chip(dhd);
4614 
4615 	if (chip == BCM4359_CHIP_ID || chip == BCM43012_CHIP_ID ||
4616 			chip == BCM43751_CHIP_ID || chip == BCM43752_CHIP_ID) {
4617 		return true;
4618 	}
4619 
4620 	return false;
4621 }
4622 
4623 u32
wl_ext_iapsta_update_channel(dhd_pub_t * dhd,struct net_device * dev,u32 channel)4624 wl_ext_iapsta_update_channel(dhd_pub_t *dhd, struct net_device *dev,
4625 	u32 channel)
4626 {
4627 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4628 	struct wl_if_info *cur_if = NULL;
4629 
4630 	cur_if = wl_get_cur_if(dev);
4631 	if (cur_if) {
4632 		wl_ext_isam_status(cur_if->dev, NULL, 0);
4633 		cur_if->channel = channel;
4634 		if (wl_ext_master_if(cur_if) && apsta_params->acs) {
4635 			uint auto_band = WL_GET_BAND(channel);
4636 			cur_if->channel = wl_ext_autochannel(cur_if->dev, apsta_params->acs,
4637 				auto_band);
4638 		}
4639 		channel = wl_ext_move_cur_channel(apsta_params, cur_if);
4640 		if (channel) {
4641 			if (cur_if->ifmode == ISTA_MODE && wl_ext_dfs_chan(channel))
4642 				wl_ext_save_master_channel(apsta_params, channel);
4643 			wl_ext_move_other_channel(apsta_params, cur_if);
4644 		}
4645 		if (cur_if->ifmode == ISTA_MODE)
4646 			wl_set_isam_status(cur_if, STA_CONNECTING);
4647 	}
4648 
4649 	return channel;
4650 }
4651 
4652 static int
wl_ext_iftype_to_ifmode(struct net_device * net,int wl_iftype,ifmode_t * ifmode)4653 wl_ext_iftype_to_ifmode(struct net_device *net, int wl_iftype, ifmode_t *ifmode)
4654 {
4655 	switch (wl_iftype) {
4656 		case WL_IF_TYPE_STA:
4657 			*ifmode = ISTA_MODE;
4658 			break;
4659 		case WL_IF_TYPE_AP:
4660 			*ifmode = IAP_MODE;
4661 			break;
4662 		case WL_IF_TYPE_P2P_GO:
4663 			*ifmode = IGO_MODE;
4664 			break;
4665 		case WL_IF_TYPE_P2P_GC:
4666 			*ifmode = IGC_MODE;
4667 			break;
4668 		default:
4669 			AEXT_ERROR(net->name, "Unknown interface wl_iftype:0x%x\n", wl_iftype);
4670 			return BCME_ERROR;
4671 	}
4672 	return BCME_OK;
4673 }
4674 
4675 void
wl_ext_iapsta_update_iftype(struct net_device * net,int ifidx,int wl_iftype)4676 wl_ext_iapsta_update_iftype(struct net_device *net, int ifidx, int wl_iftype)
4677 {
4678 	struct dhd_pub *dhd = dhd_get_pub(net);
4679 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4680 	struct wl_if_info *cur_if = NULL;
4681 
4682 	AEXT_TRACE(net->name, "ifidx=%d, wl_iftype=%d\n", ifidx, wl_iftype);
4683 
4684 	if (ifidx < MAX_IF_NUM) {
4685 		cur_if = &apsta_params->if_info[ifidx];
4686 	}
4687 
4688 	if (cur_if) {
4689 		if (wl_iftype == WL_IF_TYPE_STA) {
4690 			cur_if->ifmode = ISTA_MODE;
4691 			cur_if->prio = PRIO_STA;
4692 			cur_if->prefix = 'S';
4693 		} else if (wl_iftype == WL_IF_TYPE_AP && cur_if->ifmode != IMESH_MODE) {
4694 			cur_if->ifmode = IAP_MODE;
4695 			cur_if->prio = PRIO_AP;
4696 			cur_if->prefix = 'A';
4697 		} else if (wl_iftype == WL_IF_TYPE_P2P_GO) {
4698 			cur_if->ifmode = IGO_MODE;
4699 			cur_if->prio = PRIO_AP;
4700 			cur_if->prefix = 'P';
4701 			apsta_params->vsdb = TRUE;
4702 		} else if (wl_iftype == WL_IF_TYPE_P2P_GC) {
4703 			cur_if->ifmode = IGC_MODE;
4704 			cur_if->prio = PRIO_STA;
4705 			cur_if->prefix = 'P';
4706 			apsta_params->vsdb = TRUE;
4707 			wl_ext_iovar_setint(cur_if->dev, "assoc_retry_max", 3);
4708 		}
4709 	}
4710 }
4711 
4712 void
wl_ext_iapsta_ifadding(struct net_device * net,int ifidx)4713 wl_ext_iapsta_ifadding(struct net_device *net, int ifidx)
4714 {
4715 	struct dhd_pub *dhd = dhd_get_pub(net);
4716 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4717 	struct wl_if_info *cur_if = NULL;
4718 
4719 	AEXT_TRACE(net->name, "ifidx=%d\n", ifidx);
4720 	if (ifidx < MAX_IF_NUM) {
4721 		cur_if = &apsta_params->if_info[ifidx];
4722 		wl_set_isam_status(cur_if, IF_ADDING);
4723 	}
4724 }
4725 
4726 bool
wl_ext_iapsta_iftype_enabled(struct net_device * net,int wl_iftype)4727 wl_ext_iapsta_iftype_enabled(struct net_device *net, int wl_iftype)
4728 {
4729 	struct dhd_pub *dhd = dhd_get_pub(net);
4730 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4731 	struct wl_if_info *cur_if = NULL;
4732 	ifmode_t ifmode = 0;
4733 
4734 	wl_ext_iftype_to_ifmode(net, wl_iftype, &ifmode);
4735 	cur_if = wl_ext_if_enabled(apsta_params, ifmode);
4736 	if (cur_if)
4737 		return TRUE;
4738 
4739 	return FALSE;
4740 }
4741 
4742 bool
wl_ext_iapsta_other_if_enabled(struct net_device * net)4743 wl_ext_iapsta_other_if_enabled(struct net_device *net)
4744 {
4745 	struct dhd_pub *dhd = dhd_get_pub(net);
4746 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4747 	struct wl_if_info *tmp_if;
4748 	bool enabled = FALSE;
4749 	int i;
4750 
4751 	for (i=0; i<MAX_IF_NUM; i++) {
4752 		tmp_if = &apsta_params->if_info[i];
4753 		if (tmp_if && wl_get_isam_status(tmp_if, IF_READY)) {
4754 			if (wl_ext_get_chan(apsta_params, tmp_if->dev)) {
4755 				enabled = TRUE;
4756 				break;
4757 			}
4758 		}
4759 	}
4760 
4761 	return enabled;
4762 }
4763 
4764 void
wl_ext_iapsta_enable_master_if(struct net_device * dev,bool post)4765 wl_ext_iapsta_enable_master_if(struct net_device *dev, bool post)
4766 {
4767 	dhd_pub_t *dhd = dhd_get_pub(dev);
4768 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4769 	struct wl_if_info *cur_if = NULL;
4770 	int i;
4771 
4772 	for (i=0; i<MAX_IF_NUM; i++) {
4773 		cur_if = &apsta_params->if_info[i];
4774 		if (cur_if && cur_if->post_channel) {
4775 			if (post)
4776 				cur_if->channel = cur_if->post_channel;
4777 			else
4778 				cur_if->channel = cur_if->prev_channel;
4779 			wl_ext_if_up(apsta_params, cur_if, TRUE);
4780 			cur_if->prev_channel = 0;
4781 			cur_if->post_channel = 0;
4782 		}
4783 	}
4784 }
4785 
4786 void
wl_ext_iapsta_restart_master(struct net_device * dev)4787 wl_ext_iapsta_restart_master(struct net_device *dev)
4788 {
4789 	dhd_pub_t *dhd = dhd_get_pub(dev);
4790 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4791 	struct wl_if_info *ap_if = NULL;
4792 
4793 	if (apsta_params->radar)
4794 		return;
4795 
4796 	ap_if = wl_ext_get_dfs_master_if(apsta_params);
4797 	if (ap_if) {
4798 		uint16 chan_2g, chan_5g;
4799 		wl_ext_if_down(apsta_params, ap_if);
4800 		wl_ext_iapsta_restart_master(dev);
4801 		wl_ext_get_default_chan(ap_if->dev, &chan_2g, &chan_5g, TRUE);
4802 		if (chan_5g)
4803 			ap_if->channel = chan_5g;
4804 		else if (chan_2g)
4805 			ap_if->channel = chan_2g;
4806 		else
4807 			ap_if->channel = 0;
4808 		if (ap_if->channel) {
4809 			wl_ext_move_cur_channel(apsta_params, ap_if);
4810 			wl_ext_if_up(apsta_params, ap_if, FALSE);
4811 		}
4812 	}
4813 }
4814 
4815 bool
wl_ext_iapsta_mesh_creating(struct net_device * net)4816 wl_ext_iapsta_mesh_creating(struct net_device *net)
4817 {
4818 	struct dhd_pub *dhd = dhd_get_pub(net);
4819 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4820 	struct wl_if_info *cur_if;
4821 	int i;
4822 
4823 	if (apsta_params) {
4824 		for (i=0; i<MAX_IF_NUM; i++) {
4825 			cur_if = &apsta_params->if_info[i];
4826 			if (cur_if->ifmode==IMESH_MODE && wl_get_isam_status(cur_if, IF_ADDING))
4827 				return TRUE;
4828 		}
4829 	}
4830 	return FALSE;
4831 }
4832 #endif /* WL_CFG80211 */
4833 
4834 int
wl_ext_in4way_sync_sta(dhd_pub_t * dhd,struct wl_if_info * cur_if,uint action,enum wl_ext_status status,void * context)4835 wl_ext_in4way_sync_sta(dhd_pub_t *dhd, struct wl_if_info *cur_if,
4836 	uint action, enum wl_ext_status status, void *context)
4837 {
4838 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
4839 	struct net_device *dev = cur_if->dev;
4840 	struct osl_timespec cur_ts, *sta_disc_ts = &apsta_params->sta_disc_ts;
4841 	int ret = 0, err, cur_eapol_status;
4842 	int max_wait_time, max_wait_cnt;
4843 	int suppressed = 0, wpa_auth = 0;
4844 
4845 	action = action & dhd->conf->in4way;
4846 	cur_eapol_status = cur_if->eapol_status;
4847 	AEXT_TRACE(dev->name, "status=%d, action=0x%x, in4way=0x%x\n",
4848 		status, action, dhd->conf->in4way);
4849 
4850 	switch (status) {
4851 		case WL_EXT_STATUS_SCAN:
4852 			wldev_ioctl(dev, WLC_GET_SCANSUPPRESS, &suppressed, sizeof(int), false);
4853 			if (suppressed) {
4854 				AEXT_ERROR(dev->name, "scan suppressed\n");
4855 				ret = -EBUSY;
4856 				break;
4857 			}
4858 			if (action & STA_NO_SCAN_IN4WAY) {
4859 				if (apsta_params->sta_handshaking > 0 && apsta_params->sta_handshaking <= 3) {
4860 					AEXT_ERROR(dev->name, "return -EBUSY cnt %d\n",
4861 						apsta_params->sta_handshaking);
4862 					apsta_params->sta_handshaking++;
4863 					ret = -EBUSY;
4864 					break;
4865 				}
4866 			}
4867 			break;
4868  		case WL_EXT_STATUS_DISCONNECTING:
4869 			if (cur_eapol_status >= EAPOL_STATUS_4WAY_START &&
4870 					cur_eapol_status < EAPOL_STATUS_4WAY_DONE) {
4871 				AEXT_ERROR(dev->name, "WPA failed at %d\n", cur_eapol_status);
4872 				cur_if->eapol_status = EAPOL_STATUS_NONE;
4873 			} else if (cur_eapol_status >= EAPOL_STATUS_WSC_START &&
4874 					cur_eapol_status < EAPOL_STATUS_WSC_DONE) {
4875 				AEXT_ERROR(dev->name, "WPS failed at %d\n", cur_eapol_status);
4876 				cur_if->eapol_status = EAPOL_STATUS_NONE;
4877 			}
4878 			if (action & (STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY)) {
4879 				if (apsta_params->sta_handshaking) {
4880 					if ((action & STA_NO_BTC_IN4WAY) && apsta_params->sta_btc_mode) {
4881 						AEXT_INFO(dev->name, "status=%d, restore sta_btc_mode %d\n",
4882 							status, apsta_params->sta_btc_mode);
4883 						wldev_iovar_setint(dev, "sta_btc_mode", apsta_params->sta_btc_mode);
4884 					}
4885 					apsta_params->sta_handshaking = 0;
4886 				}
4887 			}
4888 			if (action & STA_WAIT_DISCONNECTED) {
4889 				uint32 diff_ms;
4890 				max_wait_time = 200;
4891 				max_wait_cnt = 20;
4892 				osl_do_gettimeofday(sta_disc_ts);
4893 				osl_do_gettimeofday(&cur_ts);
4894 				diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
4895 				while (diff_ms < max_wait_time && max_wait_cnt) {
4896 					AEXT_INFO(dev->name, "status=%d, max_wait_cnt=%d waiting...\n",
4897 						status, max_wait_cnt);
4898 					mutex_unlock(&apsta_params->in4way_sync);
4899 					OSL_SLEEP(50);
4900 					mutex_lock(&apsta_params->in4way_sync);
4901 					max_wait_cnt--;
4902 					osl_do_gettimeofday(&cur_ts);
4903 					diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
4904 				}
4905 				wake_up_interruptible(&dhd->conf->event_complete);
4906 			}
4907 			break;
4908 		case WL_EXT_STATUS_CONNECTING:
4909 			wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
4910 			if (wpa_auth >= 2)
4911 				cur_if->eapol_status = EAPOL_STATUS_4WAY_START;
4912 			else
4913 				cur_if->eapol_status = EAPOL_STATUS_NONE;
4914 			if (action & (STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY)) {
4915 				if (wpa_auth >= 2 && cur_if->bssidx == 0) {
4916 					apsta_params->sta_handshaking = 1;
4917 					if (action & STA_NO_BTC_IN4WAY) {
4918 						err = wldev_iovar_getint(dev, "sta_btc_mode", &apsta_params->sta_btc_mode);
4919 						if (!err && apsta_params->sta_btc_mode) {
4920 							AEXT_INFO(dev->name, "status=%d, disable current sta_btc_mode %d\n",
4921 								status, apsta_params->sta_btc_mode);
4922 							wldev_iovar_setint(dev, "sta_btc_mode", 0);
4923 						}
4924 					}
4925 				}
4926 			}
4927 			if (action & STA_WAIT_DISCONNECTED) {
4928 				uint32 diff_ms;
4929 				max_wait_time = 200;
4930 				max_wait_cnt = 10;
4931 				osl_do_gettimeofday(&cur_ts);
4932 				diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
4933 				while (diff_ms < max_wait_time && max_wait_cnt) {
4934 					AEXT_INFO(dev->name, "status=%d, max_wait_cnt=%d waiting...\n",
4935 						status, max_wait_cnt);
4936 					mutex_unlock(&apsta_params->in4way_sync);
4937 					OSL_SLEEP(50);
4938 					mutex_lock(&apsta_params->in4way_sync);
4939 					max_wait_cnt--;
4940 					osl_do_gettimeofday(&cur_ts);
4941 					diff_ms = osl_do_gettimediff(&cur_ts, sta_disc_ts)/1000;
4942 				}
4943 				wake_up_interruptible(&dhd->conf->event_complete);
4944 			}
4945 			break;
4946 		case WL_EXT_STATUS_CONNECTED:
4947 			if (cur_if->ifmode == ISTA_MODE) {
4948 				dhd_conf_set_wme(dhd, cur_if->ifidx, 0);
4949 				wake_up_interruptible(&dhd->conf->event_complete);
4950 			}
4951 			else if (cur_if->ifmode == IGC_MODE) {
4952 				dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_CLIENT, -1);
4953 			}
4954 			break;
4955 		case WL_EXT_STATUS_DISCONNECTED:
4956 			if (cur_eapol_status >= EAPOL_STATUS_4WAY_START &&
4957 					cur_eapol_status < EAPOL_STATUS_4WAY_DONE) {
4958 				AEXT_ERROR(dev->name, "WPA failed at %d\n", cur_eapol_status);
4959 				cur_if->eapol_status = EAPOL_STATUS_NONE;
4960 			} else if (cur_eapol_status >= EAPOL_STATUS_WSC_START &&
4961 					cur_eapol_status < EAPOL_STATUS_WSC_DONE) {
4962 				AEXT_ERROR(dev->name, "WPS failed at %d\n", cur_eapol_status);
4963 				cur_if->eapol_status = EAPOL_STATUS_NONE;
4964 			}
4965 			if (action & (STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY)) {
4966 				if (apsta_params->sta_handshaking) {
4967 					if ((action & STA_NO_BTC_IN4WAY) && apsta_params->sta_btc_mode) {
4968 						AEXT_INFO(dev->name, "status=%d, restore sta_btc_mode %d\n",
4969 							status, apsta_params->sta_btc_mode);
4970 						wldev_iovar_setint(dev, "sta_btc_mode", apsta_params->sta_btc_mode);
4971 					}
4972 					apsta_params->sta_handshaking = 0;
4973 				}
4974 			}
4975 			if (action & STA_WAIT_DISCONNECTED) {
4976 				osl_do_gettimeofday(sta_disc_ts);
4977 			}
4978 			wake_up_interruptible(&dhd->conf->event_complete);
4979 			break;
4980 		case WL_EXT_STATUS_ADD_KEY:
4981 			cur_if->eapol_status = EAPOL_STATUS_4WAY_DONE;
4982 			if (action & (STA_NO_SCAN_IN4WAY|STA_NO_BTC_IN4WAY)) {
4983 				if (apsta_params->sta_handshaking) {
4984 					if ((action & STA_NO_BTC_IN4WAY) && apsta_params->sta_btc_mode) {
4985 						AEXT_INFO(dev->name, "status=%d, restore sta_btc_mode %d\n",
4986 							status, apsta_params->sta_btc_mode);
4987 						wldev_iovar_setint(dev, "sta_btc_mode", apsta_params->sta_btc_mode);
4988 					}
4989 					apsta_params->sta_handshaking = 0;
4990 				}
4991 			}
4992 			wake_up_interruptible(&dhd->conf->event_complete);
4993 			break;
4994 		default:
4995 			AEXT_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status);
4996 	}
4997 
4998 	return ret;
4999 }
5000 
5001 int
wl_ext_in4way_sync_ap(dhd_pub_t * dhd,struct wl_if_info * cur_if,uint action,enum wl_ext_status status,void * context)5002 wl_ext_in4way_sync_ap(dhd_pub_t *dhd, struct wl_if_info *cur_if,
5003 	uint action, enum wl_ext_status status, void *context)
5004 {
5005 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5006 	struct net_device *dev = cur_if->dev;
5007 	struct osl_timespec cur_ts, *ap_disc_sta_ts = &apsta_params->ap_disc_sta_ts;
5008 	u8 *ap_disc_sta_bssid = (u8*)&apsta_params->ap_disc_sta_bssid;
5009 	uint32 diff_ms, timeout, max_wait_time = 300;
5010 	int ret = 0, suppressed = 0;
5011 	u8* mac_addr = context;
5012 	bool wait = FALSE;
5013 
5014 	action = action & dhd->conf->in4way;
5015 	AEXT_TRACE(dev->name, "status=%d, action=0x%x, in4way=0x%x\n",
5016 		status, action, dhd->conf->in4way);
5017 
5018 	switch (status) {
5019 		case WL_EXT_STATUS_SCAN:
5020 			wldev_ioctl(dev, WLC_GET_SCANSUPPRESS, &suppressed, sizeof(int), false);
5021 			if (suppressed) {
5022 				AEXT_ERROR(dev->name, "scan suppressed\n");
5023 				ret = -EBUSY;
5024 				break;
5025 			}
5026 			break;
5027 		case WL_EXT_STATUS_AP_ENABLED:
5028 			if (cur_if->ifmode == IAP_MODE)
5029 				dhd_conf_set_wme(dhd, cur_if->ifidx, 1);
5030 			else if (cur_if->ifmode == IGO_MODE)
5031 				dhd_conf_set_mchan_bw(dhd, WL_P2P_IF_GO, -1);
5032 			break;
5033 		case WL_EXT_STATUS_DELETE_STA:
5034 			if (action & AP_WAIT_STA_RECONNECT) {
5035 				osl_do_gettimeofday(&cur_ts);
5036 				diff_ms = osl_do_gettimediff(&cur_ts, ap_disc_sta_ts)/1000;
5037 				if (mac_addr && diff_ms < max_wait_time) {
5038 					if (cur_if->ifmode == IAP_MODE &&
5039 							!memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) {
5040 						wait = TRUE;
5041 					} else if (cur_if->ifmode == IGO_MODE &&
5042 							cur_if->eapol_status == EAPOL_STATUS_WSC_DONE &&
5043 							memcmp(&ether_bcast, mac_addr, ETHER_ADDR_LEN)) {
5044 						wait = TRUE;
5045 					}
5046 				}
5047 				if (wait) {
5048 					AEXT_INFO(dev->name, "status=%d, ap_recon_sta=%d, waiting %dms ...\n",
5049 						status, apsta_params->ap_recon_sta, max_wait_time);
5050 					mutex_unlock(&apsta_params->in4way_sync);
5051 					timeout = wait_event_interruptible_timeout(apsta_params->ap_recon_sta_event,
5052 						apsta_params->ap_recon_sta, msecs_to_jiffies(max_wait_time));
5053 					mutex_lock(&apsta_params->in4way_sync);
5054 					AEXT_INFO(dev->name, "status=%d, ap_recon_sta=%d, timeout=%d\n",
5055 						status, apsta_params->ap_recon_sta, timeout);
5056 					if (timeout > 0) {
5057 						AEXT_INFO(dev->name, "skip delete STA %pM\n", mac_addr);
5058 						ret = -1;
5059 						break;
5060 					}
5061 				} else {
5062 					AEXT_INFO(dev->name, "status=%d, ap_recon_sta=%d => 0\n",
5063 						status, apsta_params->ap_recon_sta);
5064 					apsta_params->ap_recon_sta = FALSE;
5065 					if (cur_if->ifmode == IGO_MODE)
5066 						cur_if->eapol_status = EAPOL_STATUS_NONE;
5067 				}
5068 			}
5069 			break;
5070 		case WL_EXT_STATUS_STA_DISCONNECTED:
5071 			if (action & AP_WAIT_STA_RECONNECT) {
5072 				AEXT_INFO(dev->name, "latest disc STA %pM ap_recon_sta=%d\n",
5073 					ap_disc_sta_bssid, apsta_params->ap_recon_sta);
5074 				osl_do_gettimeofday(ap_disc_sta_ts);
5075 				memcpy(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN);
5076 				apsta_params->ap_recon_sta = FALSE;
5077 			}
5078 			break;
5079 		case WL_EXT_STATUS_STA_CONNECTED:
5080 			if (action & AP_WAIT_STA_RECONNECT) {
5081 				osl_do_gettimeofday(&cur_ts);
5082 				diff_ms = osl_do_gettimediff(&cur_ts, ap_disc_sta_ts)/1000;
5083 				if (diff_ms < max_wait_time &&
5084 						!memcmp(ap_disc_sta_bssid, mac_addr, ETHER_ADDR_LEN)) {
5085 					AEXT_INFO(dev->name, "status=%d, ap_recon_sta=%d => 1\n",
5086 						status, apsta_params->ap_recon_sta);
5087 					apsta_params->ap_recon_sta = TRUE;
5088 					wake_up_interruptible(&apsta_params->ap_recon_sta_event);
5089 				} else {
5090 					apsta_params->ap_recon_sta = FALSE;
5091 				}
5092 			}
5093 			break;
5094 		default:
5095 			AEXT_INFO(dev->name, "Unknown action=0x%x, status=%d\n", action, status);
5096 	}
5097 
5098 	return ret;
5099 }
5100 
5101 #ifdef WL_CFG80211
5102 int
wl_ext_in4way_sync(struct net_device * dev,uint action,enum wl_ext_status status,void * context)5103 wl_ext_in4way_sync(struct net_device *dev, uint action,
5104 	enum wl_ext_status status, void *context)
5105 {
5106 	dhd_pub_t *dhd = dhd_get_pub(dev);
5107 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5108 	struct wl_if_info *cur_if = NULL;
5109 	int ret = 0;
5110 
5111 	mutex_lock(&apsta_params->in4way_sync);
5112 	cur_if = wl_get_cur_if(dev);
5113 	if (cur_if) {
5114 		if (cur_if->ifmode == ISTA_MODE || cur_if->ifmode == IGC_MODE)
5115 			ret = wl_ext_in4way_sync_sta(dhd, cur_if, action, status, context);
5116 		else if (cur_if->ifmode == IAP_MODE || cur_if->ifmode == IGO_MODE)
5117 			ret = wl_ext_in4way_sync_ap(dhd, cur_if, action, status, context);
5118 		else
5119 			AEXT_INFO(dev->name, "Unknown mode %d\n", cur_if->ifmode);
5120 	}
5121 	mutex_unlock(&apsta_params->in4way_sync);
5122 
5123 	return ret;
5124 }
5125 #endif /* WL_CFG80211 */
5126 
5127 #ifdef WL_WIRELESS_EXT
5128 int
wl_ext_in4way_sync_wext(struct net_device * dev,uint action,enum wl_ext_status status,void * context)5129 wl_ext_in4way_sync_wext(struct net_device *dev, uint action,
5130 	enum wl_ext_status status, void *context)
5131 {
5132 	int ret = 0;
5133 #ifndef WL_CFG80211
5134 	dhd_pub_t *dhd = dhd_get_pub(dev);
5135 	struct wl_apsta_params *apsta_params;
5136 	struct wl_if_info *cur_if = NULL;
5137 	int i;
5138 
5139 	if (!dhd)
5140 		return 0;
5141 
5142 	apsta_params = dhd->iapsta_params;
5143 
5144 	mutex_lock(&apsta_params->in4way_sync);
5145 	cur_if = wl_get_cur_if(dev);
5146 	if (cur_if && cur_if->ifmode == ISTA_MODE) {
5147 		if (status == WL_EXT_STATUS_DISCONNECTING) {
5148 			wl_ext_add_remove_pm_enable_work(dev, FALSE);
5149 		} else if (status == WL_EXT_STATUS_CONNECTING) {
5150 			wl_ext_add_remove_pm_enable_work(dev, TRUE);
5151 		}
5152 		ret = wl_ext_in4way_sync_sta(dhd, cur_if, 0, status, NULL);
5153 	}
5154 	mutex_unlock(&apsta_params->in4way_sync);
5155 #endif
5156 	return ret;
5157 }
5158 #endif /* WL_WIRELESS_EXT */
5159 
5160 void
wl_ext_update_eapol_status(dhd_pub_t * dhd,int ifidx,uint eapol_status)5161 wl_ext_update_eapol_status(dhd_pub_t *dhd, int ifidx, uint eapol_status)
5162 {
5163 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5164 	struct wl_if_info *cur_if = NULL;
5165 
5166 	if (ifidx < MAX_IF_NUM) {
5167 		cur_if = &apsta_params->if_info[ifidx];
5168 		cur_if->eapol_status = eapol_status;
5169 	}
5170 }
5171 
5172 int
wl_ext_iapsta_alive_preinit(struct net_device * dev)5173 wl_ext_iapsta_alive_preinit(struct net_device *dev)
5174 {
5175 	struct dhd_pub *dhd = dhd_get_pub(dev);
5176 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5177 
5178 	if (apsta_params->init == TRUE) {
5179 		AEXT_ERROR(dev->name, "don't init twice\n");
5180 		return -1;
5181 	}
5182 
5183 	AEXT_TRACE(dev->name, "Enter\n");
5184 
5185 	apsta_params->init = TRUE;
5186 
5187 	return 0;
5188 }
5189 
5190 int
wl_ext_iapsta_alive_postinit(struct net_device * dev)5191 wl_ext_iapsta_alive_postinit(struct net_device *dev)
5192 {
5193 	struct dhd_pub *dhd = dhd_get_pub(dev);
5194 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5195 	s32 apsta = 0, ap = 0;
5196 	struct wl_if_info *cur_if;
5197 	int i;
5198 
5199 	wl_ext_iovar_getint(dev, "apsta", &apsta);
5200 	wl_ext_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap), 0);
5201 	if (apsta == 1 || ap == 0) {
5202 		apsta_params->apstamode = ISTAONLY_MODE;
5203 		apsta_params->if_info[IF_PIF].ifmode = ISTA_MODE;
5204 		op_mode = DHD_FLAG_STA_MODE;
5205 	} else {
5206 		apsta_params->apstamode = IAPONLY_MODE;
5207 		apsta_params->if_info[IF_PIF].ifmode = IAP_MODE;
5208 		op_mode = DHD_FLAG_HOSTAP_MODE;
5209 	}
5210 	// fix me: how to check it's ISTAAP_MODE or IDUALAP_MODE?
5211 
5212 	wl_ext_get_ioctl_ver(dev, &apsta_params->ioctl_ver);
5213 	WL_MSG(dev->name, "apstamode=%d\n", apsta_params->apstamode);
5214 
5215 	for (i=0; i<MAX_IF_NUM; i++) {
5216 		cur_if = &apsta_params->if_info[i];
5217 		if (i == 1 && !strlen(cur_if->ifname))
5218 			strcpy(cur_if->ifname, "wlan1");
5219 		if (i == 2 && !strlen(cur_if->ifname))
5220 			strcpy(cur_if->ifname, "wlan2");
5221 		if (cur_if->ifmode == ISTA_MODE) {
5222 			cur_if->channel = 0;
5223 			cur_if->maxassoc = -1;
5224 			wl_set_isam_status(cur_if, IF_READY);
5225 			cur_if->prio = PRIO_STA;
5226 			cur_if->prefix = 'S';
5227 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_sta");
5228 		}
5229 		else if (cur_if->ifmode == IAP_MODE) {
5230 			cur_if->channel = 1;
5231 			cur_if->maxassoc = -1;
5232 			wl_set_isam_status(cur_if, IF_READY);
5233 			cur_if->prio = PRIO_AP;
5234 			cur_if->prefix = 'A';
5235 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_ap");
5236 		}
5237 #ifdef WLMESH
5238 		else if (cur_if->ifmode == IMESH_MODE) {
5239 			cur_if->channel = 1;
5240 			cur_if->maxassoc = -1;
5241 			wl_set_isam_status(cur_if, IF_READY);
5242 			cur_if->prio = PRIO_MESH;
5243 			cur_if->prefix = 'M';
5244 			snprintf(cur_if->ssid, DOT11_MAX_SSID_LEN, "ttt_mesh");
5245 		}
5246 #endif /* WLMESH */
5247 	}
5248 
5249 	return op_mode;
5250 }
5251 
5252 static int
wl_ext_iapsta_get_rsdb(struct net_device * net,struct dhd_pub * dhd)5253 wl_ext_iapsta_get_rsdb(struct net_device *net, struct dhd_pub *dhd)
5254 {
5255 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5256 	wl_config_t *rsdb_p;
5257 	int ret = 0, rsdb = 0;
5258 
5259 	if (dhd->conf->chip == BCM4359_CHIP_ID || dhd->conf->chip == BCM4375_CHIP_ID) {
5260 		ret = wldev_iovar_getbuf(net, "rsdb_mode", NULL, 0,
5261 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
5262 		if (!ret) {
5263 			if (dhd->conf->fw_type == FW_TYPE_MESH) {
5264 				rsdb = 1;
5265 			} else {
5266 				rsdb_p = (wl_config_t *) iovar_buf;
5267 				if (dhd->conf->chip == BCM4375_CHIP_ID)
5268 					rsdb = rsdb_p->status;
5269 				else
5270 					rsdb = rsdb_p->config;
5271 				AEXT_INFO(net->name, "config=%d, status=%d\n",
5272 					rsdb_p->config, rsdb_p->status);
5273 			}
5274 		}
5275 	}
5276 
5277 	AEXT_INFO(net->name, "rsdb_mode=%d\n", rsdb);
5278 
5279 	return rsdb;
5280 }
5281 
5282 static void
wl_ext_iapsta_postinit(struct net_device * net,struct wl_if_info * cur_if)5283 wl_ext_iapsta_postinit(struct net_device *net, struct wl_if_info *cur_if)
5284 {
5285 	struct dhd_pub *dhd = dhd_get_pub(net);
5286 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5287 	int pm;
5288 
5289 	AEXT_TRACE(cur_if->ifname, "ifidx=%d\n", cur_if->ifidx);
5290 	if (cur_if->ifidx == 0) {
5291 		apsta_params->rsdb = wl_ext_iapsta_get_rsdb(net, dhd);
5292 		apsta_params->vsdb = FALSE;
5293 		apsta_params->csa = 0;
5294 		apsta_params->acs = 0;
5295 		apsta_params->radar = wl_ext_radar_detect(net);
5296 		if (dhd->conf->fw_type == FW_TYPE_MESH) {
5297 			apsta_params->csa |= (CSA_FW_BIT | CSA_DRV_BIT);
5298 		}
5299 	} else {
5300 		if (cur_if->ifmode == ISTA_MODE) {
5301 			wl_ext_iovar_setint(cur_if->dev, "roam_off", dhd->conf->roam_off);
5302 			wl_ext_iovar_setint(cur_if->dev, "bcn_timeout", dhd->conf->bcn_timeout);
5303 			if (dhd->conf->pm >= 0)
5304 				pm = dhd->conf->pm;
5305 			else
5306 				pm = PM_FAST;
5307 			wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
5308 			wl_ext_iovar_setint(cur_if->dev, "assoc_retry_max", 20);
5309 		}
5310 #ifdef WLMESH
5311 		else if (cur_if->ifmode == IMESH_MODE) {
5312 			pm = 0;
5313 			wl_ext_ioctl(cur_if->dev, WLC_SET_PM, &pm, sizeof(pm), 1);
5314 		}
5315 #endif /* WLMESH */
5316 	}
5317 #ifdef PROPTX_MAXCOUNT
5318 	wl_ext_update_wlfc_maxcount(dhd);
5319 #endif /* PROPTX_MAXCOUNT */
5320 
5321 }
5322 
5323 int
wl_ext_iapsta_attach_name(struct net_device * net,int ifidx)5324 wl_ext_iapsta_attach_name(struct net_device *net, int ifidx)
5325 {
5326 	struct dhd_pub *dhd = dhd_get_pub(net);
5327 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5328 	struct wl_if_info *cur_if = NULL;
5329 
5330 	AEXT_TRACE(net->name, "ifidx=%d\n", ifidx);
5331 	if (ifidx < MAX_IF_NUM) {
5332 		cur_if = &apsta_params->if_info[ifidx];
5333 	}
5334 	if (ifidx == 0) {
5335 		strcpy(cur_if->ifname, net->name);
5336 		wl_ext_iapsta_postinit(net, cur_if);
5337 		wl_set_isam_status(cur_if, IF_READY);
5338 	} else if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) {
5339 		strcpy(cur_if->ifname, net->name);
5340 		wl_ext_iapsta_postinit(net, cur_if);
5341 		wl_clr_isam_status(cur_if, IF_ADDING);
5342 		wl_set_isam_status(cur_if, IF_READY);
5343 #ifndef WL_STATIC_IF
5344 		wake_up_interruptible(&apsta_params->netif_change_event);
5345 #endif /* WL_STATIC_IF */
5346 	}
5347 
5348 	return 0;
5349 }
5350 
5351 int
wl_ext_iapsta_update_net_device(struct net_device * net,int ifidx)5352 wl_ext_iapsta_update_net_device(struct net_device *net, int ifidx)
5353 {
5354 	struct dhd_pub *dhd = dhd_get_pub(net);
5355 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5356 	struct wl_if_info *cur_if = NULL, *primary_if;
5357 
5358 	AEXT_TRACE(net->name, "ifidx=%d\n", ifidx);
5359 	if (ifidx < MAX_IF_NUM) {
5360 		cur_if = &apsta_params->if_info[ifidx];
5361 	}
5362 	if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) {
5363 		primary_if = &apsta_params->if_info[IF_PIF];
5364 		if (strlen(cur_if->ifname)) {
5365 			memset(net->name, 0, sizeof(IFNAMSIZ));
5366 			strcpy(net->name, cur_if->ifname);
5367 			net->name[IFNAMSIZ-1] = '\0';
5368 		}
5369 #ifndef WL_STATIC_IF
5370 		if (apsta_params->apstamode != IUNKNOWN_MODE &&
5371 				apsta_params->apstamode != ISTAAPAP_MODE &&
5372 				apsta_params->apstamode != ISTASTA_MODE) {
5373 			memcpy(net->dev_addr, primary_if->dev->dev_addr, ETHER_ADDR_LEN);
5374 			net->dev_addr[0] |= 0x02;
5375 			if (ifidx >= 2) {
5376 				net->dev_addr[4] ^= 0x80;
5377 				net->dev_addr[4] += ifidx;
5378 				net->dev_addr[5] += (ifidx-1);
5379 			}
5380 		}
5381 #endif /* WL_STATIC_IF */
5382 	}
5383 
5384 	return 0;
5385 }
5386 
5387 int
wl_ext_iapsta_attach_netdev(struct net_device * net,int ifidx,uint8 bssidx)5388 wl_ext_iapsta_attach_netdev(struct net_device *net, int ifidx, uint8 bssidx)
5389 {
5390 	struct dhd_pub *dhd = dhd_get_pub(net);
5391 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5392 	struct wl_if_info *cur_if = NULL, *primary_if;
5393 
5394 	AEXT_TRACE(net->name, "ifidx=%d, bssidx=%d\n", ifidx, bssidx);
5395 	if (ifidx < MAX_IF_NUM) {
5396 		cur_if = &apsta_params->if_info[ifidx];
5397 	}
5398 	if (ifidx == 0) {
5399 		memset(apsta_params, 0, sizeof(struct wl_apsta_params));
5400 		apsta_params->dhd = dhd;
5401 		cur_if->dev = net;
5402 		cur_if->ifidx = ifidx;
5403 		cur_if->bssidx = bssidx;
5404 		cur_if->ifmode = ISTA_MODE;
5405 		cur_if->prio = PRIO_STA;
5406 		cur_if->prefix = 'S';
5407 		wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event,
5408 			apsta_params, PRIO_EVENT_IAPSTA);
5409 		strcpy(cur_if->ifname, net->name);
5410 		init_waitqueue_head(&apsta_params->netif_change_event);
5411 		init_waitqueue_head(&apsta_params->ap_recon_sta_event);
5412 		mutex_init(&apsta_params->usr_sync);
5413 		mutex_init(&apsta_params->in4way_sync);
5414 		mutex_init(&cur_if->pm_sync);
5415 		INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler);
5416 	} else if (cur_if && wl_get_isam_status(cur_if, IF_ADDING)) {
5417 		primary_if = &apsta_params->if_info[IF_PIF];
5418 		cur_if->dev = net;
5419 		cur_if->ifidx = ifidx;
5420 		cur_if->bssidx = bssidx;
5421 		wl_ext_event_register(net, dhd, WLC_E_LAST, wl_ext_iapsta_event,
5422 			apsta_params, PRIO_EVENT_IAPSTA);
5423 #if defined(WLMESH) && defined(WL_ESCAN)
5424 		if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
5425 			wl_mesh_escan_attach(dhd, cur_if);
5426 		}
5427 #endif /* WLMESH && WL_ESCAN */
5428 		mutex_init(&cur_if->pm_sync);
5429 		INIT_DELAYED_WORK(&cur_if->pm_enable_work, wl_ext_pm_work_handler);
5430 	}
5431 
5432 	return 0;
5433 }
5434 
5435 int
wl_ext_iapsta_dettach_netdev(struct net_device * net,int ifidx)5436 wl_ext_iapsta_dettach_netdev(struct net_device *net, int ifidx)
5437 {
5438 	struct dhd_pub *dhd = dhd_get_pub(net);
5439 	struct wl_apsta_params *apsta_params = dhd->iapsta_params;
5440 	struct wl_if_info *cur_if = NULL;
5441 
5442 	if (!apsta_params)
5443 		return 0;
5444 
5445 	AEXT_TRACE(net->name, "ifidx=%d\n", ifidx);
5446 	if (ifidx < MAX_IF_NUM) {
5447 		cur_if = &apsta_params->if_info[ifidx];
5448 	}
5449 
5450 	if (ifidx == 0) {
5451 		wl_ext_add_remove_pm_enable_work(net, FALSE);
5452 		wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event);
5453 #if defined(WLMESH) && defined(WL_ESCAN)
5454 		if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
5455 			wl_mesh_escan_detach(dhd, cur_if);
5456 		}
5457 #endif /* WLMESH && WL_ESCAN */
5458 		memset(apsta_params, 0, sizeof(struct wl_apsta_params));
5459 	} else if (cur_if && (wl_get_isam_status(cur_if, IF_READY) ||
5460 			wl_get_isam_status(cur_if, IF_ADDING))) {
5461 		wl_ext_add_remove_pm_enable_work(net, FALSE);
5462 		wl_ext_event_deregister(net, dhd, WLC_E_LAST, wl_ext_iapsta_event);
5463 #if defined(WLMESH) && defined(WL_ESCAN)
5464 		if (cur_if->ifmode == IMESH_MODE && apsta_params->macs) {
5465 			wl_mesh_escan_detach(dhd, cur_if);
5466 		}
5467 #endif /* WLMESH && WL_ESCAN */
5468 		memset(cur_if, 0, sizeof(struct wl_if_info));
5469 	}
5470 
5471 	return 0;
5472 }
5473 
5474 int
wl_ext_iapsta_attach(dhd_pub_t * pub)5475 wl_ext_iapsta_attach(dhd_pub_t *pub)
5476 {
5477 	struct wl_apsta_params *iapsta_params;
5478 
5479 	iapsta_params = kzalloc(sizeof(struct wl_apsta_params), GFP_KERNEL);
5480 	if (unlikely(!iapsta_params)) {
5481 		AEXT_ERROR("wlan", "Could not allocate apsta_params\n");
5482 		return -ENOMEM;
5483 	}
5484 	pub->iapsta_params = (void *)iapsta_params;
5485 
5486 	return 0;
5487 }
5488 
5489 void
wl_ext_iapsta_dettach(dhd_pub_t * pub)5490 wl_ext_iapsta_dettach(dhd_pub_t *pub)
5491 {
5492 	if (pub->iapsta_params) {
5493 		kfree(pub->iapsta_params);
5494 		pub->iapsta_params = NULL;
5495 	}
5496 }
5497 #endif /* WL_EXT_IAPSTA */
5498 
5499 #ifdef IDHCP
5500 /*
5501 terence 20190409:
5502 dhd_priv wl dhcpc_dump
5503 dhd_priv wl dhcpc_param <client ip> <server ip> <lease time>
5504 */
5505 static int
wl_ext_dhcpc_dump(struct net_device * dev,char * data,char * command,int total_len)5506 wl_ext_dhcpc_dump(struct net_device *dev, char *data, char *command,
5507 	int total_len)
5508 {
5509 	int ret = 0;
5510 	int bytes_written = 0;
5511 	uint32 ip_addr;
5512 	char buf[20]="";
5513 
5514 	if (!data) {
5515 		ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr);
5516 		if (!ret) {
5517 			bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
5518 			bytes_written += snprintf(command+bytes_written, total_len,
5519 				"ipaddr %s ", buf);
5520 		}
5521 
5522 		ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr);
5523 		if (!ret) {
5524 			bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
5525 			bytes_written += snprintf(command+bytes_written, total_len,
5526 				"mask %s ", buf);
5527 		}
5528 
5529 		ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr);
5530 		if (!ret) {
5531 			bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
5532 			bytes_written += snprintf(command+bytes_written, total_len,
5533 				"gw %s ", buf);
5534 		}
5535 
5536 		ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr);
5537 		if (!ret) {
5538 			bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
5539 			bytes_written += snprintf(command+bytes_written, total_len,
5540 				"dnsserv %s ", buf);
5541 		}
5542 
5543 		if (!bytes_written)
5544 			bytes_written = -1;
5545 
5546 		AEXT_TRACE(dev->name, "command result is %s\n", command);
5547 	}
5548 
5549 	return bytes_written;
5550 }
5551 
5552 int
wl_ext_dhcpc_param(struct net_device * dev,char * data,char * command,int total_len)5553 wl_ext_dhcpc_param(struct net_device *dev, char *data, char *command,
5554 	int total_len)
5555 {
5556 	int ret = -1, bytes_written = 0;
5557 	char ip_addr_str[20]="", ip_serv_str[20]="";
5558 	struct dhcpc_parameter dhcpc_param;
5559 	uint32 ip_addr, ip_serv, lease_time;
5560 	char iovar_buf[WLC_IOCTL_SMLEN]="\0";
5561 
5562 	if (data) {
5563 		AEXT_TRACE(dev->name, "cmd %s", command);
5564 		sscanf(data, "%s %s %d", ip_addr_str, ip_serv_str, &lease_time);
5565 		AEXT_TRACE(dev->name, "ip_addr = %s, ip_serv = %s, lease_time = %d",
5566 			ip_addr_str, ip_serv_str, lease_time);
5567 
5568 		memset(&dhcpc_param, 0, sizeof(struct dhcpc_parameter));
5569 		if (!bcm_atoipv4(ip_addr_str, (struct ipv4_addr *)&ip_addr)) {
5570 			AEXT_ERROR(dev->name, "wrong ip_addr_str %s\n", ip_addr_str);
5571 			ret = -1;
5572 			goto exit;
5573 		}
5574 		dhcpc_param.ip_addr = ip_addr;
5575 
5576 		if (!bcm_atoipv4(ip_addr_str, (struct ipv4_addr *)&ip_serv)) {
5577 			AEXT_ERROR(dev->name, "wrong ip_addr_str %s\n", ip_addr_str);
5578 			ret = -1;
5579 			goto exit;
5580 		}
5581 		dhcpc_param.ip_serv = ip_serv;
5582 		dhcpc_param.lease_time = lease_time;
5583 		ret = wl_ext_iovar_setbuf(dev, "dhcpc_param", &dhcpc_param,
5584 			sizeof(struct dhcpc_parameter), iovar_buf, sizeof(iovar_buf), NULL);
5585 	} else {
5586 		ret = wl_ext_iovar_getbuf(dev, "dhcpc_param", &dhcpc_param,
5587 			sizeof(struct dhcpc_parameter), iovar_buf, WLC_IOCTL_SMLEN, NULL);
5588 		if (!ret) {
5589 			bcm_ip_ntoa((struct ipv4_addr *)&dhcpc_param.ip_addr, ip_addr_str);
5590 			bytes_written += snprintf(command + bytes_written, total_len,
5591 				"ip_addr %s\n", ip_addr_str);
5592 			bcm_ip_ntoa((struct ipv4_addr *)&dhcpc_param.ip_serv, ip_serv_str);
5593 			bytes_written += snprintf(command + bytes_written, total_len,
5594 				"ip_serv %s\n", ip_serv_str);
5595 			bytes_written += snprintf(command + bytes_written, total_len,
5596 				"lease_time %d\n", dhcpc_param.lease_time);
5597 			AEXT_TRACE(dev->name, "command result is %s\n", command);
5598 			ret = bytes_written;
5599 		}
5600 	}
5601 
5602 	exit:
5603 		return ret;
5604 }
5605 #endif /* IDHCP */
5606 
5607 int
wl_ext_mkeep_alive(struct net_device * dev,char * data,char * command,int total_len)5608 wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command,
5609 	int total_len)
5610 {
5611 	struct dhd_pub *dhd = dhd_get_pub(dev);
5612 	wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
5613 	int ret = -1, i, ifidx, id, period=-1;
5614 	char *packet = NULL, *buf = NULL;
5615 	int bytes_written = 0;
5616 
5617 	if (data) {
5618 		buf = kmalloc(total_len, GFP_KERNEL);
5619 		if (buf == NULL) {
5620 			AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
5621 			goto exit;
5622 		}
5623 		packet = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
5624 		if (packet == NULL) {
5625 			AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
5626 			goto exit;
5627 		}
5628 		AEXT_TRACE(dev->name, "cmd %s", command);
5629 		sscanf(data, "%d %d %s", &id, &period, packet);
5630 		AEXT_TRACE(dev->name, "id=%d, period=%d, packet=%s", id, period, packet);
5631 		if (period >= 0) {
5632 			ifidx = dhd_net2idx(dhd->info, dev);
5633 			ret = dhd_conf_mkeep_alive(dhd, ifidx, id, period, packet, FALSE);
5634 		} else {
5635 			if (id < 0)
5636 				id = 0;
5637 			ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf,
5638 				total_len, NULL);
5639 			if (!ret) {
5640 				mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) buf;
5641 				bytes_written += snprintf(command+bytes_written, total_len,
5642 					"Id            :%d\n"
5643 					"Period (msec) :%d\n"
5644 					"Length        :%d\n"
5645 					"Packet        :0x",
5646 					mkeep_alive_pktp->keep_alive_id,
5647 					dtoh32(mkeep_alive_pktp->period_msec),
5648 					dtoh16(mkeep_alive_pktp->len_bytes));
5649 				for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
5650 					bytes_written += snprintf(command+bytes_written, total_len,
5651 						"%02x", mkeep_alive_pktp->data[i]);
5652 				}
5653 				AEXT_TRACE(dev->name, "command result is %s\n", command);
5654 				ret = bytes_written;
5655 			}
5656 		}
5657 	}
5658 
5659 exit:
5660 	if (buf)
5661 		kfree(buf);
5662 	if (packet)
5663 		kfree(packet);
5664 	return ret;
5665 }
5666 
5667 #ifdef WL_EXT_TCPKA
5668 static int
wl_ext_tcpka_conn_add(struct net_device * dev,char * data,char * command,int total_len)5669 wl_ext_tcpka_conn_add(struct net_device *dev, char *data, char *command,
5670 	int total_len)
5671 {
5672 	int ret = 0;
5673 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5674 	tcpka_conn_t *tcpka = NULL;
5675 	uint32 sess_id = 0, ipid = 0, srcport = 0, dstport = 0, seq = 0, ack = 0,
5676 		tcpwin = 0, tsval = 0, tsecr = 0, len = 0, ka_payload_len = 0;
5677 	char dst_mac[ETHER_ADDR_STR_LEN], src_ip[IPV4_ADDR_STR_LEN],
5678 		dst_ip[IPV4_ADDR_STR_LEN], ka_payload[32];
5679 
5680 	if (data) {
5681 		memset(dst_mac, 0, sizeof(dst_mac));
5682 		memset(src_ip, 0, sizeof(src_ip));
5683 		memset(dst_ip, 0, sizeof(dst_ip));
5684 		memset(ka_payload, 0, sizeof(ka_payload));
5685 		sscanf(data, "%d %s %s %s %d %d %d %u %u %d %u %u %u %32s",
5686 			&sess_id, dst_mac, src_ip, dst_ip, &ipid, &srcport, &dstport, &seq,
5687 			&ack, &tcpwin, &tsval, &tsecr, &len, ka_payload);
5688 
5689 		ka_payload_len = strlen(ka_payload) / 2;
5690 		tcpka = kmalloc(sizeof(struct tcpka_conn) + ka_payload_len, GFP_KERNEL);
5691 		if (tcpka == NULL) {
5692 			AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
5693 				sizeof(struct tcpka_conn) + ka_payload_len);
5694 			ret = -1;
5695 			goto exit;
5696 		}
5697 		memset(tcpka, 0, sizeof(struct tcpka_conn) + ka_payload_len);
5698 
5699 		tcpka->sess_id = sess_id;
5700 		if (!(ret = bcm_ether_atoe(dst_mac, &tcpka->dst_mac))) {
5701 			AEXT_ERROR(dev->name, "mac parsing err addr=%s\n", dst_mac);
5702 			ret = -1;
5703 			goto exit;
5704 		}
5705 		if (!bcm_atoipv4(src_ip, &tcpka->src_ip)) {
5706 			AEXT_ERROR(dev->name, "src_ip parsing err ip=%s\n", src_ip);
5707 			ret = -1;
5708 			goto exit;
5709 		}
5710 		if (!bcm_atoipv4(dst_ip, &tcpka->dst_ip)) {
5711 			AEXT_ERROR(dev->name, "dst_ip parsing err ip=%s\n", dst_ip);
5712 			ret = -1;
5713 			goto exit;
5714 		}
5715 		tcpka->ipid = ipid;
5716 		tcpka->srcport = srcport;
5717 		tcpka->dstport = dstport;
5718 		tcpka->seq = seq;
5719 		tcpka->ack = ack;
5720 		tcpka->tcpwin = tcpwin;
5721 		tcpka->tsval = tsval;
5722 		tcpka->tsecr = tsecr;
5723 		tcpka->len = len;
5724 		ka_payload_len = wl_pattern_atoh(ka_payload, (char *)tcpka->ka_payload);
5725 		if (ka_payload_len == -1) {
5726 			AEXT_ERROR(dev->name,"rejecting ka_payload=%s\n", ka_payload);
5727 			ret = -1;
5728 			goto exit;
5729 		}
5730 		tcpka->ka_payload_len = ka_payload_len;
5731 
5732 		AEXT_INFO(dev->name,
5733 			"tcpka_conn_add %d %pM %pM %pM %d %d %d %u %u %d %u %u %u %u \"%s\"\n",
5734 			tcpka->sess_id, &tcpka->dst_mac, &tcpka->src_ip, &tcpka->dst_ip,
5735 			tcpka->ipid, tcpka->srcport, tcpka->dstport, tcpka->seq,
5736 			tcpka->ack, tcpka->tcpwin, tcpka->tsval, tcpka->tsecr,
5737 			tcpka->len, tcpka->ka_payload_len, tcpka->ka_payload);
5738 
5739 		ret = wl_ext_iovar_setbuf(dev, "tcpka_conn_add", (char *)tcpka,
5740 			(sizeof(tcpka_conn_t) + tcpka->ka_payload_len - 1),
5741 			iovar_buf, sizeof(iovar_buf), NULL);
5742 	}
5743 
5744 exit:
5745 	if (tcpka)
5746 		kfree(tcpka);
5747 	return ret;
5748 }
5749 
5750 static int
wl_ext_tcpka_conn_enable(struct net_device * dev,char * data,char * command,int total_len)5751 wl_ext_tcpka_conn_enable(struct net_device *dev, char *data, char *command,
5752 	int total_len)
5753 {
5754 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5755 	tcpka_conn_sess_t tcpka_conn;
5756 	int ret = 0;
5757 	uint32 sess_id = 0, flag, interval = 0, retry_interval = 0, retry_count = 0;
5758 
5759 	if (data) {
5760 		sscanf(data, "%d %d %d %d %d",
5761 			&sess_id, &flag, &interval, &retry_interval, &retry_count);
5762 		tcpka_conn.sess_id = sess_id;
5763 		tcpka_conn.flag = flag;
5764 		if (tcpka_conn.flag) {
5765 			tcpka_conn.tcpka_timers.interval = interval;
5766 			tcpka_conn.tcpka_timers.retry_interval = retry_interval;
5767 			tcpka_conn.tcpka_timers.retry_count = retry_count;
5768 		} else {
5769 			tcpka_conn.tcpka_timers.interval = 0;
5770 			tcpka_conn.tcpka_timers.retry_interval = 0;
5771 			tcpka_conn.tcpka_timers.retry_count = 0;
5772 		}
5773 
5774 		AEXT_INFO(dev->name, "tcpka_conn_enable %d %d %d %d %d\n",
5775 			tcpka_conn.sess_id, tcpka_conn.flag,
5776 			tcpka_conn.tcpka_timers.interval,
5777 			tcpka_conn.tcpka_timers.retry_interval,
5778 			tcpka_conn.tcpka_timers.retry_count);
5779 
5780 		ret = wl_ext_iovar_setbuf(dev, "tcpka_conn_enable", (char *)&tcpka_conn,
5781 			sizeof(tcpka_conn_sess_t), iovar_buf, sizeof(iovar_buf), NULL);
5782 	}
5783 
5784 	return ret;
5785 }
5786 
5787 static int
wl_ext_tcpka_conn_info(struct net_device * dev,char * data,char * command,int total_len)5788 wl_ext_tcpka_conn_info(struct net_device *dev, char *data, char *command,
5789 	int total_len)
5790 {
5791 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5792 	tcpka_conn_sess_info_t *info = NULL;
5793 	uint32 sess_id = 0;
5794 	int ret = 0, bytes_written = 0;
5795 
5796 	if (data) {
5797 		sscanf(data, "%d", &sess_id);
5798 		AEXT_INFO(dev->name, "tcpka_conn_sess_info %d\n", sess_id);
5799 		ret = wl_ext_iovar_getbuf(dev, "tcpka_conn_sess_info", (char *)&sess_id,
5800 			sizeof(uint32), iovar_buf, sizeof(iovar_buf), NULL);
5801 		if (!ret) {
5802 			info = (tcpka_conn_sess_info_t *) iovar_buf;
5803 			bytes_written += snprintf(command+bytes_written, total_len,
5804 				"id   :%d\n"
5805 				"ipid :%d\n"
5806 				"seq  :%u\n"
5807 				"ack  :%u",
5808 				sess_id, info->ipid, info->seq, info->ack);
5809 			AEXT_INFO(dev->name, "%s\n", command);
5810 			ret = bytes_written;
5811 		}
5812 	}
5813 
5814 	return ret;
5815 }
5816 #endif /* WL_EXT_TCPKA */
5817 
5818 static int
wl_ext_rsdb_mode(struct net_device * dev,char * data,char * command,int total_len)5819 wl_ext_rsdb_mode(struct net_device *dev, char *data, char *command,
5820 	int total_len)
5821 {
5822 	s8 iovar_buf[WLC_IOCTL_SMLEN];
5823 	wl_config_t rsdb_mode_cfg = {1, 0}, *rsdb_p;
5824 	int ret = 0;
5825 
5826 	if (data) {
5827 		rsdb_mode_cfg.config = (int)simple_strtol(data, NULL, 0);
5828 		ret = wl_ext_iovar_setbuf(dev, "rsdb_mode", (char *)&rsdb_mode_cfg,
5829 			sizeof(rsdb_mode_cfg), iovar_buf, WLC_IOCTL_SMLEN, NULL);
5830 		AEXT_INFO(dev->name, "rsdb_mode %d\n", rsdb_mode_cfg.config);
5831 	} else {
5832 		ret = wl_ext_iovar_getbuf(dev, "rsdb_mode", NULL, 0,
5833 			iovar_buf, WLC_IOCTL_SMLEN, NULL);
5834 		if (!ret) {
5835 			rsdb_p = (wl_config_t *) iovar_buf;
5836 			ret = snprintf(command, total_len, "%d", rsdb_p->config);
5837 			AEXT_TRACE(dev->name, "command result is %s\n", command);
5838 		}
5839 	}
5840 
5841 	return ret;
5842 }
5843 
5844 static int
wl_ext_recal(struct net_device * dev,char * data,char * command,int total_len)5845 wl_ext_recal(struct net_device *dev, char *data, char *command,
5846 	int total_len)
5847 {
5848 	int ret = 0, i, nchan, nssid = 0;
5849 	int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
5850 	wl_scan_params_t *params = NULL;
5851 	int ioctl_ver;
5852 	char *p;
5853 
5854 	AEXT_TRACE(dev->name, "Enter\n");
5855 
5856 	if (data) {
5857 		params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
5858 		params = (wl_scan_params_t *) kzalloc(params_size, GFP_KERNEL);
5859 		if (params == NULL) {
5860 			ret = -ENOMEM;
5861 			goto exit;
5862 		}
5863 		memset(params, 0, params_size);
5864 
5865 		wl_ext_get_ioctl_ver(dev, &ioctl_ver);
5866 
5867 		memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
5868 		params->bss_type = DOT11_BSSTYPE_ANY;
5869 		params->scan_type = 0;
5870 		params->nprobes = -1;
5871 		params->active_time = -1;
5872 		params->passive_time = -1;
5873 		params->home_time = -1;
5874 		params->channel_num = 0;
5875 
5876 		params->scan_type |= WL_SCANFLAGS_PASSIVE;
5877 		nchan = 2;
5878 		params->channel_list[0] = wf_channel2chspec(1, WL_CHANSPEC_BW_20);
5879 		params->channel_list[1] = wf_channel2chspec(2, WL_CHANSPEC_BW_20);
5880 
5881 		params->nprobes = htod32(params->nprobes);
5882 		params->active_time = htod32(params->active_time);
5883 		params->passive_time = htod32(params->passive_time);
5884 		params->home_time = htod32(params->home_time);
5885 
5886 		for (i = 0; i < nchan; i++) {
5887 			wl_ext_chspec_host_to_driver(ioctl_ver, params->channel_list[i]);
5888 		}
5889 
5890 		p = (char*)params->channel_list + nchan * sizeof(uint16);
5891 
5892 		params->channel_num = htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
5893 		                             (nchan & WL_SCAN_PARAMS_COUNT_MASK));
5894 		params_size = p - (char*)params + nssid * sizeof(wlc_ssid_t);
5895 
5896 		AEXT_INFO(dev->name, "recal\n");
5897 		ret = wl_ext_ioctl(dev, WLC_SCAN, params, params_size, 1);
5898 	}
5899 
5900 exit:
5901 	if (params)
5902 		kfree(params);
5903 	return ret;
5904 }
5905 
5906 static s32
wl_ext_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)5907 wl_ext_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
5908 {
5909 	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5910 	s8 eventmask[WL_EVENTING_MASK_LEN];
5911 	s32 err = 0;
5912 
5913 	if (!ndev)
5914 		return -ENODEV;
5915 
5916 	/* Setup event_msgs */
5917 	err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
5918 	if (unlikely(err)) {
5919 		AEXT_ERROR(ndev->name, "Get event_msgs error (%d)\n", err);
5920 		goto eventmsg_out;
5921 	}
5922 	memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
5923 	if (add) {
5924 		setbit(eventmask, event);
5925 	} else {
5926 		clrbit(eventmask, event);
5927 	}
5928 	err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
5929 			sizeof(iovbuf), NULL);
5930 	if (unlikely(err)) {
5931 		AEXT_ERROR(ndev->name, "Set event_msgs error (%d)\n", err);
5932 		goto eventmsg_out;
5933 	}
5934 
5935 eventmsg_out:
5936 	return err;
5937 }
5938 
5939 static int
wl_ext_event_msg(struct net_device * dev,char * data,char * command,int total_len)5940 wl_ext_event_msg(struct net_device *dev, char *data,
5941 	char *command, int total_len)
5942 {
5943 	s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5944 	s8 eventmask[WL_EVENTING_MASK_LEN];
5945 	int i, bytes_written = 0, add = -1;
5946 	uint event;
5947 	char *vbuf;
5948 	bool skipzeros;
5949 
5950 	/* dhd_priv wl event_msg [offset] [1/0, 1 for add, 0 for remove] */
5951 	/* dhd_priv wl event_msg 40 1 */
5952 	if (data) {
5953 		AEXT_TRACE(dev->name, "data = %s\n", data);
5954 		sscanf(data, "%d %d", &event, &add);
5955 		/* Setup event_msgs */
5956 		bytes_written = wldev_iovar_getbuf(dev, "event_msgs", NULL, 0, iovbuf,
5957 			sizeof(iovbuf), NULL);
5958 		if (unlikely(bytes_written)) {
5959 			AEXT_ERROR(dev->name, "Get event_msgs error (%d)\n", bytes_written);
5960 			goto eventmsg_out;
5961 		}
5962 		memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
5963 		if (add == -1) {
5964 			if (isset(eventmask, event))
5965 				bytes_written += snprintf(command+bytes_written, total_len, "1");
5966 			else
5967 				bytes_written += snprintf(command+bytes_written, total_len, "0");
5968 			AEXT_INFO(dev->name, "%s\n", command);
5969 			goto eventmsg_out;
5970 		}
5971 		bytes_written = wl_ext_add_remove_eventmsg(dev, event, add);
5972 	}
5973 	else {
5974 		/* Setup event_msgs */
5975 		bytes_written = wldev_iovar_getbuf(dev, "event_msgs", NULL, 0, iovbuf,
5976 			sizeof(iovbuf), NULL);
5977 		if (bytes_written) {
5978 			AEXT_ERROR(dev->name, "Get event_msgs error (%d)\n", bytes_written);
5979 			goto eventmsg_out;
5980 		}
5981 		vbuf = (char *)iovbuf;
5982 		bytes_written += snprintf(command+bytes_written, total_len, "0x");
5983 		for (i = (sizeof(eventmask) - 1); i >= 0; i--) {
5984 			if (vbuf[i] || (i == 0))
5985 				skipzeros = FALSE;
5986 			if (skipzeros)
5987 				continue;
5988 			bytes_written += snprintf(command+bytes_written, total_len,
5989 				"%02x", vbuf[i] & 0xff);
5990 		}
5991 		AEXT_INFO(dev->name, "%s\n", command);
5992 	}
5993 
5994 eventmsg_out:
5995 	return bytes_written;
5996 }
5997 
5998 #ifdef PKT_FILTER_SUPPORT
5999 extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
6000 extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
6001 extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
6002 static int
wl_ext_pkt_filter_add(struct net_device * dev,char * data,char * command,int total_len)6003 wl_ext_pkt_filter_add(struct net_device *dev, char *data, char *command,
6004 	int total_len)
6005 {
6006 	struct dhd_pub *dhd = dhd_get_pub(dev);
6007 	int i, filter_id, new_id = 0, cnt;
6008 	conf_pkt_filter_add_t *filter_add = &dhd->conf->pkt_filter_add;
6009 	char **pktfilter = dhd->pktfilter;
6010 	int err = 0;
6011 
6012 	if (data) {
6013 		AEXT_TRACE(dev->name, "data = %s\n", data);
6014 
6015 		new_id = simple_strtol(data, NULL, 10);
6016 		if (new_id <= 0) {
6017 			AEXT_ERROR(dev->name, "wrong id %d\n", new_id);
6018 			return -1;
6019 		}
6020 
6021 		cnt = dhd->pktfilter_count;
6022 		for (i=0; i<cnt; i++) {
6023 			if (!pktfilter[i])
6024 				continue;
6025 			filter_id = simple_strtol(pktfilter[i], NULL, 10);
6026 			if (new_id == filter_id) {
6027 				AEXT_ERROR(dev->name, "filter id %d already in list\n", filter_id);
6028 				return -1;
6029 			}
6030 		}
6031 
6032 		cnt = filter_add->count;
6033 		if (cnt >= DHD_CONF_FILTER_MAX) {
6034 			AEXT_ERROR(dev->name, "not enough filter\n");
6035 			return -1;
6036 		}
6037 		for (i=0; i<cnt; i++) {
6038 			filter_id = simple_strtol(filter_add->filter[i], NULL, 10);
6039 			if (new_id == filter_id) {
6040 				AEXT_ERROR(dev->name, "filter id %d already in list\n", filter_id);
6041 				return -1;
6042 			}
6043 		}
6044 
6045 		strcpy(&filter_add->filter[cnt][0], data);
6046 		dhd->pktfilter[dhd->pktfilter_count] = filter_add->filter[cnt];
6047 		filter_add->count++;
6048 		dhd->pktfilter_count++;
6049 
6050 		dhd_pktfilter_offload_set(dhd, data);
6051 		AEXT_INFO(dev->name, "filter id %d added\n", new_id);
6052 	}
6053 
6054 	return err;
6055 }
6056 
6057 static int
wl_ext_pkt_filter_delete(struct net_device * dev,char * data,char * command,int total_len)6058 wl_ext_pkt_filter_delete(struct net_device *dev, char *data, char *command,
6059 	int total_len)
6060 {
6061 	struct dhd_pub *dhd = dhd_get_pub(dev);
6062 	int i, j, filter_id, cnt;
6063 	char **pktfilter = dhd->pktfilter;
6064 	conf_pkt_filter_add_t *filter_add = &dhd->conf->pkt_filter_add;
6065 	bool in_filter = FALSE;
6066 	int id, err = 0;
6067 
6068 	if (data) {
6069 		AEXT_TRACE(dev->name, "data = %s\n", data);
6070 		id = (int)simple_strtol(data, NULL, 0);
6071 
6072 		cnt = filter_add->count;
6073 		for (i=0; i<cnt; i++) {
6074 			filter_id = simple_strtol(filter_add->filter[i], NULL, 10);
6075 			if (id == filter_id) {
6076 				in_filter = TRUE;
6077 				memset(filter_add->filter[i], 0, PKT_FILTER_LEN);
6078 				for (j=i; j<(cnt-1); j++) {
6079 					strcpy(filter_add->filter[j], filter_add->filter[j+1]);
6080 					memset(filter_add->filter[j+1], 0, PKT_FILTER_LEN);
6081 				}
6082 				cnt--;
6083 				filter_add->count--;
6084 				dhd->pktfilter_count--;
6085 			}
6086 		}
6087 
6088 		cnt = dhd->pktfilter_count;
6089 		for (i=0; i<cnt; i++) {
6090 			if (!pktfilter[i])
6091 				continue;
6092 			filter_id = simple_strtol(pktfilter[i], NULL, 10);
6093 			if (id == filter_id) {
6094 				in_filter = TRUE;
6095 				memset(pktfilter[i], 0, strlen(pktfilter[i]));
6096 			}
6097 		}
6098 
6099 		if (in_filter) {
6100 			dhd_pktfilter_offload_delete(dhd, id);
6101 			AEXT_INFO(dev->name, "filter id %d deleted\n", id);
6102 		} else {
6103 			AEXT_ERROR(dev->name, "filter id %d not in list\n", id);
6104 			err = -1;
6105 		}
6106 	}
6107 
6108 	return err;
6109 }
6110 
6111 static int
wl_ext_pkt_filter_enable(struct net_device * dev,char * data,char * command,int total_len)6112 wl_ext_pkt_filter_enable(struct net_device *dev, char *data, char *command,
6113 	int total_len)
6114 {
6115 	struct dhd_pub *dhd = dhd_get_pub(dev);
6116 	int err = 0, id, enable;
6117 	int i, filter_id, cnt;
6118 	char **pktfilter = dhd->pktfilter;
6119 	bool in_filter = FALSE;
6120 
6121 	/* dhd_priv wl pkt_filter_enable [id] [1/0] */
6122 	/* dhd_priv wl pkt_filter_enable 141 1 */
6123 	if (data) {
6124 		sscanf(data, "%d %d", &id, &enable);
6125 
6126 		cnt = dhd->pktfilter_count;
6127 		for (i=0; i<cnt; i++) {
6128 			if (!pktfilter[i])
6129 				continue;
6130 			filter_id = simple_strtol(pktfilter[i], NULL, 10);
6131 			if (id == filter_id) {
6132 				in_filter = TRUE;
6133 				break;
6134 			}
6135 		}
6136 
6137 		if (in_filter) {
6138 			dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
6139 				enable, dhd_master_mode);
6140 			AEXT_INFO(dev->name, "filter id %d %s\n", id, enable?"enabled":"disabled");
6141 		} else {
6142 			AEXT_ERROR(dev->name, "filter id %d not in list\n", id);
6143 			err = -1;
6144 		}
6145 	}
6146 
6147 	return err;
6148 }
6149 #endif /* PKT_FILTER_SUPPORT */
6150 
6151 #ifdef SENDPROB
6152 static int
wl_ext_send_probreq(struct net_device * dev,char * data,char * command,int total_len)6153 wl_ext_send_probreq(struct net_device *dev, char *data, char *command,
6154 	int total_len)
6155 {
6156 	int err = 0;
6157 	char addr_str[16], addr[6];
6158 	char iovar_buf[WLC_IOCTL_SMLEN]="\0";
6159 	char ie_data[WLC_IOCTL_SMLEN] = "\0";
6160 	wl_probe_params_t params;
6161 
6162 	/* dhd_priv wl send_probreq [dest. addr] [OUI+VAL] */
6163 	/* dhd_priv wl send_probreq 0x00904c010203 0x00904c01020304050607 */
6164 	if (data) {
6165 		AEXT_TRACE(dev->name, "data = %s\n", data);
6166 		sscanf(data, "%s %s", addr_str, ie_data);
6167 		AEXT_TRACE(dev->name, "addr=%s, ie=%s\n", addr_str, ie_data);
6168 
6169 		if (strlen(addr_str) != 14) {
6170 			AEXT_ERROR(dev->name, "wrong addr %s\n", addr_str);
6171 			goto exit;
6172 		}
6173 		wl_pattern_atoh(addr_str, (char *) addr);
6174 		memset(&params, 0, sizeof(params));
6175 		memcpy(&params.bssid, addr, ETHER_ADDR_LEN);
6176 		memcpy(&params.mac, addr, ETHER_ADDR_LEN);
6177 
6178 		err = wl_ext_add_del_ie(dev, VNDR_IE_PRBREQ_FLAG, ie_data, "add");
6179 		if (err)
6180 			goto exit;
6181 		err = wl_ext_iovar_setbuf(dev, "sendprb", (char *)&params, sizeof(params),
6182 			iovar_buf, sizeof(iovar_buf), NULL);
6183 		OSL_SLEEP(100);
6184 		wl_ext_add_del_ie(dev, VNDR_IE_PRBREQ_FLAG, ie_data, "del");
6185 	}
6186 
6187 exit:
6188     return err;
6189 }
6190 
6191 static int
wl_ext_send_probresp(struct net_device * dev,char * data,char * command,int total_len)6192 wl_ext_send_probresp(struct net_device *dev, char *data, char *command,
6193 	int total_len)
6194 {
6195 	int err = 0;
6196 	char addr_str[16], addr[6];
6197 	char iovar_buf[WLC_IOCTL_SMLEN]="\0";
6198 	char ie_data[WLC_IOCTL_SMLEN] = "\0";
6199 
6200 	/* dhd_priv wl send_probresp [dest. addr] [OUI+VAL] */
6201 	/* dhd_priv wl send_probresp 0x00904c010203 0x00904c01020304050607 */
6202 	if (data) {
6203 		AEXT_TRACE(dev->name, "data = %s\n", data);
6204 		sscanf(data, "%s %s", addr_str, ie_data);
6205 		AEXT_TRACE(dev->name, "addr=%s, ie=%s\n", addr_str, ie_data);
6206 
6207 		if (strlen(addr_str) != 14) {
6208 			AEXT_ERROR(dev->name, "wrong addr %s\n", addr_str);
6209 			goto exit;
6210 		}
6211 		wl_pattern_atoh(addr_str, (char *) addr);
6212 
6213 		err = wl_ext_add_del_ie(dev, VNDR_IE_PRBRSP_FLAG, ie_data, "add");
6214 		if (err)
6215 			goto exit;
6216 		err = wl_ext_iovar_setbuf(dev, "send_probresp", addr, sizeof(addr),
6217 			iovar_buf, sizeof(iovar_buf), NULL);
6218 		OSL_SLEEP(100);
6219 		wl_ext_add_del_ie(dev, VNDR_IE_PRBRSP_FLAG, ie_data, "del");
6220 	}
6221 
6222 exit:
6223     return err;
6224 }
6225 
6226 static int
wl_ext_recv_probreq(struct net_device * dev,char * data,char * command,int total_len)6227 wl_ext_recv_probreq(struct net_device *dev, char *data, char *command,
6228 	int total_len)
6229 {
6230 	int err = 0, enable = 0;
6231 	char cmd[32];
6232 	struct dhd_pub *dhd = dhd_get_pub(dev);
6233 
6234 	/* enable:
6235 	    1. dhd_priv wl 86 0
6236 	    2. dhd_priv wl event_msg 44 1
6237 	    disable:
6238 	    1. dhd_priv wl 86 2;
6239 	    2. dhd_priv wl event_msg 44 0
6240 	*/
6241 	if (data) {
6242 		AEXT_TRACE(dev->name, "data = %s\n", data);
6243 		sscanf(data, "%d", &enable);
6244 		if (enable) {
6245 			strcpy(cmd, "wl 86 0");
6246 			err = wl_ext_wl_iovar(dev, cmd, total_len);
6247 			if (err)
6248 				goto exit;
6249 			strcpy(cmd, "wl event_msg 44 1");
6250 			err = wl_ext_wl_iovar(dev, cmd, total_len);
6251 			if (err)
6252 				goto exit;
6253 			dhd->recv_probereq = TRUE;
6254 		} else {
6255 			if (dhd->conf->pm) {
6256 				strcpy(cmd, "wl 86 2");
6257 				wl_ext_wl_iovar(dev, cmd, total_len);
6258 			}
6259 			strcpy(cmd, "wl event_msg 44 0");
6260 			wl_ext_wl_iovar(dev, cmd, total_len);
6261 			dhd->recv_probereq = FALSE;
6262 		}
6263 	}
6264 
6265 exit:
6266     return err;
6267 }
6268 
6269 static int
wl_ext_recv_probresp(struct net_device * dev,char * data,char * command,int total_len)6270 wl_ext_recv_probresp(struct net_device *dev, char *data, char *command,
6271 	int total_len)
6272 {
6273 	int err = 0, enable = 0;
6274 	char cmd[32];
6275 
6276 	/* enable:
6277 	    1. dhd_priv wl pkt_filter_add 150 0 0 0 0xFF 0x50
6278 	    2. dhd_priv wl pkt_filter_enable 150 1
6279 	    3. dhd_priv wl mpc 0
6280 	    4. dhd_priv wl 108 1
6281 	    disable:
6282 	    1. dhd_priv wl 108 0
6283 	    2. dhd_priv wl mpc 1
6284 	    3. dhd_priv wl pkt_filter_disable 150 0
6285 	    4. dhd_priv pkt_filter_delete 150
6286 	*/
6287 	if (data) {
6288 		AEXT_TRACE(dev->name, "data = %s\n", data);
6289 		sscanf(data, "%d", &enable);
6290 		if (enable) {
6291 			strcpy(cmd, "wl pkt_filter_add 150 0 0 0 0xFF 0x50");
6292 			err = wl_ext_wl_iovar(dev, cmd, total_len);
6293 			if (err)
6294 				goto exit;
6295 			strcpy(cmd, "wl pkt_filter_enable 150 1");
6296 			err = wl_ext_wl_iovar(dev, cmd, total_len);
6297 			if (err)
6298 				goto exit;
6299 			strcpy(cmd, "wl mpc 0");
6300 			err = wl_ext_wl_iovar(dev, cmd, total_len);
6301 			if (err)
6302 				goto exit;
6303 			strcpy(cmd, "wl 108 1");
6304 			err= wl_ext_wl_iovar(dev, cmd, total_len);
6305 		} else {
6306 			strcpy(cmd, "wl 108 0");
6307 			wl_ext_wl_iovar(dev, cmd, total_len);
6308 			strcpy(cmd, "wl mpc 1");
6309 			wl_ext_wl_iovar(dev, cmd, total_len);
6310 			strcpy(cmd, "wl pkt_filter_enable 150 0");
6311 			wl_ext_wl_iovar(dev, cmd, total_len);
6312 			strcpy(cmd, "wl pkt_filter_delete 150");
6313 			wl_ext_wl_iovar(dev, cmd, total_len);
6314 		}
6315 	}
6316 
6317 exit:
6318     return err;
6319 }
6320 #endif /* SENDPROB */
6321 
6322 static int
wl_ext_gtk_key_info(struct net_device * dev,char * data,char * command,int total_len)6323 wl_ext_gtk_key_info(struct net_device *dev, char *data, char *command, int total_len)
6324 {
6325 	int err = 0;
6326 	char iovar_buf[WLC_IOCTL_SMLEN]="\0";
6327 	gtk_keyinfo_t keyinfo;
6328 	bcol_gtk_para_t bcol_keyinfo;
6329 
6330 	/* wl gtk_key_info [kck kek replay_ctr] */
6331 	/* wl gtk_key_info 001122..FF001122..FF00000000000001 */
6332 	if (data) {
6333 		memset(&keyinfo, 0, sizeof(keyinfo));
6334 		memcpy(&keyinfo, data, RSN_KCK_LENGTH+RSN_KEK_LENGTH+RSN_REPLAY_LEN);
6335 		if (android_msg_level & ANDROID_INFO_LEVEL) {
6336 			prhex("kck", (uchar *)keyinfo.KCK, RSN_KCK_LENGTH);
6337 			prhex("kek", (uchar *)keyinfo.KEK, RSN_KEK_LENGTH);
6338 			prhex("replay_ctr", (uchar *)keyinfo.ReplayCounter, RSN_REPLAY_LEN);
6339 		}
6340 
6341 		memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
6342 		bcol_keyinfo.enable = 1;
6343 		bcol_keyinfo.ptk_len = 64;
6344 		memcpy(&bcol_keyinfo.ptk, data, RSN_KCK_LENGTH+RSN_KEK_LENGTH);
6345 		err = wl_ext_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
6346 			sizeof(bcol_keyinfo), iovar_buf, sizeof(iovar_buf), NULL);
6347 		if (!err) {
6348 			goto exit;
6349 		}
6350 
6351 		err = wl_ext_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
6352 			iovar_buf, sizeof(iovar_buf), NULL);
6353 		if (err) {
6354 			AEXT_ERROR(dev->name, "failed to set gtk_key_info\n");
6355 			goto exit;
6356 		}
6357 	}
6358 
6359 exit:
6360     return err;
6361 }
6362 
6363 #ifdef WL_EXT_WOWL
6364 static int
wl_ext_wowl_pattern(struct net_device * dev,char * data,char * command,int total_len)6365 wl_ext_wowl_pattern(struct net_device *dev, char *data, char *command,
6366 	int total_len)
6367 {
6368 	s8 iovar_buf[WLC_IOCTL_SMLEN];
6369 	uint buf_len = 0;
6370 	int	offset;
6371 	char mask[128]="\0", pattern[128]="\0", add[4]="\0",
6372 		mask_tmp[128], *pmask_tmp;
6373 	uint32 masksize, patternsize, pad_len = 0;
6374 	wl_wowl_pattern2_t *wowl_pattern2 = NULL;
6375 	wl_wowl_pattern_t *wowl_pattern = NULL;
6376 	char *mask_and_pattern;
6377 	wl_wowl_pattern_list_t *list;
6378 	uint8 *ptr;
6379 	int ret = 0, i, j, v;
6380 
6381 	if (data) {
6382 		sscanf(data, "%s %d %s %s", add, &offset, mask_tmp, pattern);
6383 		if (strcmp(add, "add") != 0 && strcmp(add, "clr") != 0) {
6384 			AEXT_ERROR(dev->name, "first arg should be add or clr\n");
6385 			goto exit;
6386 		}
6387 		if (!strcmp(add, "clr")) {
6388 			AEXT_INFO(dev->name, "wowl_pattern clr\n");
6389 			ret = wl_ext_iovar_setbuf(dev, "wowl_pattern", add,
6390 				sizeof(add), iovar_buf, sizeof(iovar_buf), NULL);
6391 			goto exit;
6392 		}
6393 		masksize = strlen(mask_tmp) -2;
6394 		AEXT_TRACE(dev->name, "0 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
6395 
6396 		// add pading
6397 		if (masksize % 16)
6398 			pad_len = (16 - masksize % 16);
6399 		for (i=0; i<pad_len; i++)
6400 			strcat(mask_tmp, "0");
6401 		masksize += pad_len;
6402 		AEXT_TRACE(dev->name, "1 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
6403 
6404 		// translate 0x00 to 0, others to 1
6405 		j = 0;
6406 		pmask_tmp = &mask_tmp[2];
6407 		for (i=0; i<masksize/2; i++) {
6408 			if(strncmp(&pmask_tmp[i*2], "00", 2))
6409 				pmask_tmp[j] = '1';
6410 			else
6411 				pmask_tmp[j] = '0';
6412 			j++;
6413 		}
6414 		pmask_tmp[j] = '\0';
6415 		masksize = masksize / 2;
6416 		AEXT_TRACE(dev->name, "2 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
6417 
6418 		// reorder per 8bits
6419 		pmask_tmp = &mask_tmp[2];
6420 		for (i=0; i<masksize/8; i++) {
6421 			char c;
6422 			for (j=0; j<4; j++) {
6423 				c = pmask_tmp[i*8+j];
6424 				pmask_tmp[i*8+j] = pmask_tmp[(i+1)*8-j-1];
6425 				pmask_tmp[(i+1)*8-j-1] = c;
6426 			}
6427 		}
6428 		AEXT_TRACE(dev->name, "3 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
6429 
6430 		// translate 8bits to 1byte
6431 		j = 0; v = 0;
6432 		pmask_tmp = &mask_tmp[2];
6433 		strcpy(mask, "0x");
6434 		for (i=0; i<masksize; i++) {
6435 			v = (v<<1) | (pmask_tmp[i]=='1');
6436 			if (((i+1)%4) == 0) {
6437 				if (v < 10)
6438 					mask[j+2] = v + '0';
6439 				else
6440 					mask[j+2] = (v-10) + 'a';
6441 				j++;
6442 				v = 0;
6443 			}
6444 		}
6445 		mask[j+2] = '\0';
6446 		masksize = j/2;
6447 		AEXT_TRACE(dev->name, "4 mask=%s, masksize=%d\n", mask, masksize);
6448 
6449 		patternsize = (strlen(pattern)-2)/2;
6450 		buf_len = sizeof(wl_wowl_pattern2_t) + patternsize + masksize;
6451 		wowl_pattern2 = kmalloc(buf_len, GFP_KERNEL);
6452 		if (wowl_pattern2 == NULL) {
6453 			AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", buf_len);
6454 			goto exit;
6455 		}
6456 		memset(wowl_pattern2, 0, sizeof(wl_wowl_pattern2_t));
6457 
6458 		strncpy(wowl_pattern2->cmd, add, sizeof(add));
6459 		wowl_pattern2->wowl_pattern.type = 0;
6460 		wowl_pattern2->wowl_pattern.offset = offset;
6461 		mask_and_pattern = (char*)wowl_pattern2 + sizeof(wl_wowl_pattern2_t);
6462 
6463 		wowl_pattern2->wowl_pattern.masksize = masksize;
6464 		ret = wl_pattern_atoh(mask, mask_and_pattern);
6465 		if (ret == -1) {
6466 			AEXT_ERROR(dev->name, "rejecting mask=%s\n", mask);
6467 			goto exit;
6468 		}
6469 
6470 		mask_and_pattern += wowl_pattern2->wowl_pattern.masksize;
6471 		wowl_pattern2->wowl_pattern.patternoffset = sizeof(wl_wowl_pattern_t) +
6472 			wowl_pattern2->wowl_pattern.masksize;
6473 
6474 		wowl_pattern2->wowl_pattern.patternsize = patternsize;
6475 		ret = wl_pattern_atoh(pattern, mask_and_pattern);
6476 		if (ret == -1) {
6477 			AEXT_ERROR(dev->name, "rejecting pattern=%s\n", pattern);
6478 			goto exit;
6479 		}
6480 
6481 		AEXT_INFO(dev->name, "%s %d %s %s\n", add, offset, mask, pattern);
6482 
6483 		ret = wl_ext_iovar_setbuf(dev, "wowl_pattern", (char *)wowl_pattern2,
6484 			buf_len, iovar_buf, sizeof(iovar_buf), NULL);
6485 	}
6486 	else {
6487 		ret = wl_ext_iovar_getbuf(dev, "wowl_pattern", NULL, 0,
6488 			iovar_buf, sizeof(iovar_buf), NULL);
6489 		if (!ret) {
6490 			list = (wl_wowl_pattern_list_t *)iovar_buf;
6491 			ret = snprintf(command, total_len, "#of patterns :%d\n", list->count);
6492 			ptr = (uint8 *)list->pattern;
6493 			for (i=0; i<list->count; i++) {
6494 				uint8 *pattern;
6495 				wowl_pattern = (wl_wowl_pattern_t *)ptr;
6496 				ret += snprintf(command+ret, total_len,
6497 					"Pattern %d:\n"
6498 					"ID         :0x%x\n"
6499 					"Offset     :%d\n"
6500 					"Masksize   :%d\n"
6501 					"Mask       :0x",
6502 					i+1, (uint32)wowl_pattern->id, wowl_pattern->offset,
6503 					wowl_pattern->masksize);
6504 				pattern = ((uint8 *)wowl_pattern + sizeof(wl_wowl_pattern_t));
6505 				for (j = 0; j < wowl_pattern->masksize; j++) {
6506 					ret += snprintf(command+ret, total_len, "%02x", pattern[j]);
6507 				}
6508 				ret += snprintf(command+ret, total_len, "\n");
6509 				ret += snprintf(command+ret, total_len,
6510 					"PatternSize:%d\n"
6511 					"Pattern    :0x",
6512 					wowl_pattern->patternsize);
6513 
6514 				pattern = ((uint8*)wowl_pattern + wowl_pattern->patternoffset);
6515 				for (j=0; j<wowl_pattern->patternsize; j++)
6516 					ret += snprintf(command+ret, total_len, "%02x", pattern[j]);
6517 				ret += snprintf(command+ret, total_len, "\n");
6518 				ptr += (wowl_pattern->masksize + wowl_pattern->patternsize +
6519 				        sizeof(wl_wowl_pattern_t));
6520 			}
6521 
6522 			AEXT_INFO(dev->name, "%s\n", command);
6523 		}
6524 	}
6525 
6526 exit:
6527 	if (wowl_pattern2)
6528 		kfree(wowl_pattern2);
6529 	return ret;
6530 }
6531 
6532 static int
wl_ext_wowl_wakeind(struct net_device * dev,char * data,char * command,int total_len)6533 wl_ext_wowl_wakeind(struct net_device *dev, char *data, char *command,
6534 	int total_len)
6535 {
6536 	s8 iovar_buf[WLC_IOCTL_SMLEN];
6537 	wl_wowl_wakeind_t *wake = NULL;
6538 	int ret = -1;
6539 	char clr[6]="\0";
6540 
6541 	if (data) {
6542 		sscanf(data, "%s", clr);
6543 		if (!strcmp(clr, "clear")) {
6544 			AEXT_INFO(dev->name, "wowl_wakeind clear\n");
6545 			ret = wl_ext_iovar_setbuf(dev, "wowl_wakeind", clr, sizeof(clr),
6546 				iovar_buf, sizeof(iovar_buf), NULL);
6547 		} else {
6548 			AEXT_ERROR(dev->name, "first arg should be clear\n");
6549 		}
6550 	} else {
6551 		ret = wl_ext_iovar_getbuf(dev, "wowl_wakeind", NULL, 0,
6552 			iovar_buf, sizeof(iovar_buf), NULL);
6553 		if (!ret) {
6554 			wake = (wl_wowl_wakeind_t *) iovar_buf;
6555 			ret = snprintf(command, total_len, "wakeind=0x%x", wake->ucode_wakeind);
6556 			if (wake->ucode_wakeind & WL_WOWL_MAGIC)
6557 				ret += snprintf(command+ret, total_len, " (MAGIC packet)");
6558 			if (wake->ucode_wakeind & WL_WOWL_NET)
6559 				ret += snprintf(command+ret, total_len, " (Netpattern)");
6560 			if (wake->ucode_wakeind & WL_WOWL_DIS)
6561 				ret += snprintf(command+ret, total_len, " (Disassoc/Deauth)");
6562 			if (wake->ucode_wakeind & WL_WOWL_BCN)
6563 				ret += snprintf(command+ret, total_len, " (Loss of beacon)");
6564 			if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_TIME)
6565 				ret += snprintf(command+ret, total_len, " (TCPKA timeout)");
6566 			if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_DATA)
6567 				ret += snprintf(command+ret, total_len, " (TCPKA data)");
6568 			if (wake->ucode_wakeind & WL_WOWL_TCPFIN)
6569 				ret += snprintf(command+ret, total_len, " (TCP FIN)");
6570 			AEXT_INFO(dev->name, "%s\n", command);
6571 		}
6572 	}
6573 
6574 	return ret;
6575 }
6576 #endif /* WL_EXT_WOWL */
6577 
6578 #ifdef WL_GPIO_NOTIFY
6579 typedef struct notify_payload {
6580 	int index;
6581 	int len;
6582 	char payload[128];
6583 } notify_payload_t;
6584 
6585 static int
wl_ext_gpio_notify(struct net_device * dev,char * data,char * command,int total_len)6586 wl_ext_gpio_notify(struct net_device *dev, char *data, char *command,
6587 	int total_len)
6588 {
6589 	s8 iovar_buf[WLC_IOCTL_SMLEN];
6590 	notify_payload_t notify, *pnotify = NULL;
6591 	int i, ret = 0, bytes_written = 0;
6592 	char frame_str[WLC_IOCTL_SMLEN+3];
6593 
6594 	if (data) {
6595 		memset(&notify, 0, sizeof(notify));
6596 		memset(frame_str, 0, sizeof(frame_str));
6597 		sscanf(data, "%d %s", &notify.index, frame_str);
6598 
6599 		if (notify.index < 0)
6600 			notify.index = 0;
6601 
6602 		if (strlen(frame_str)) {
6603 			notify.len = wl_pattern_atoh(frame_str, notify.payload);
6604 			if (notify.len == -1) {
6605 				AEXT_ERROR(dev->name, "rejecting pattern=%s\n", frame_str);
6606 				goto exit;
6607 			}
6608 			AEXT_INFO(dev->name, "index=%d, len=%d\n", notify.index, notify.len);
6609 			if (android_msg_level & ANDROID_INFO_LEVEL)
6610 				prhex("payload", (uchar *)notify.payload, notify.len);
6611 			ret = wl_ext_iovar_setbuf(dev, "bcol_gpio_noti", (char *)&notify,
6612 				sizeof(notify), iovar_buf, WLC_IOCTL_SMLEN, NULL);
6613 		} else {
6614 			AEXT_INFO(dev->name, "index=%d\n", notify.index);
6615 			ret = wl_ext_iovar_getbuf(dev, "bcol_gpio_noti", &notify.index,
6616 				sizeof(notify.index), iovar_buf, sizeof(iovar_buf), NULL);
6617 			if (!ret) {
6618 				pnotify = (notify_payload_t *)iovar_buf;
6619 				bytes_written += snprintf(command+bytes_written, total_len,
6620 					"Id            :%d\n"
6621 					"Packet        :0x",
6622 					pnotify->index);
6623 				for (i=0; i<pnotify->len; i++) {
6624 					bytes_written += snprintf(command+bytes_written, total_len,
6625 						"%02x", pnotify->payload[i]);
6626 				}
6627 				AEXT_TRACE(dev->name, "command result is\n%s\n", command);
6628 				ret = bytes_written;
6629 			}
6630 		}
6631 	}
6632 
6633 exit:
6634 	return ret;
6635 }
6636 #endif /* WL_GPIO_NOTIFY */
6637 
6638 #ifdef CSI_SUPPORT
6639 typedef struct csi_config {
6640 	/* Peer device mac address. */
6641 	struct ether_addr addr;
6642 	/* BW to be used in the measurements. This needs to be supported both by the */
6643 	/* device itself and the peer. */
6644 	uint32 bw;
6645 	/* Time interval between measurements (units: 1 ms). */
6646 	uint32 period;
6647 	/* CSI method */
6648 	uint32 method;
6649 } csi_config_t;
6650 
6651 typedef struct csi_list {
6652 	uint32 cnt;
6653 	csi_config_t configs[1];
6654 } csi_list_t;
6655 
6656 static int
wl_ether_atoe(const char * a,struct ether_addr * n)6657 wl_ether_atoe(const char *a, struct ether_addr *n)
6658 {
6659 	char *c = NULL;
6660 	int i = 0;
6661 
6662 	memset(n, 0, ETHER_ADDR_LEN);
6663 	for (;;) {
6664 		n->octet[i++] = (uint8)strtoul(a, &c, 16);
6665 		if (!*c++ || i == ETHER_ADDR_LEN)
6666 			break;
6667 		a = c;
6668 	}
6669 	return (i == ETHER_ADDR_LEN);
6670 }
6671 
6672 static int
wl_ext_csi(struct net_device * dev,char * data,char * command,int total_len)6673 wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len)
6674 {
6675 	csi_config_t csi, *csip;
6676 	csi_list_t *csi_list;
6677 	int ret = -1, period=-1, i;
6678 	char mac[32], *buf = NULL;
6679 	struct ether_addr ea;
6680 	int bytes_written = 0;
6681 
6682 	buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
6683 	if (buf == NULL) {
6684 		AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
6685 		goto exit;
6686 	}
6687 	memset(buf, 0, WLC_IOCTL_SMLEN);
6688 
6689 	if (data) {
6690 		sscanf(data, "%s %d", mac, &period);
6691 		ret = wl_ether_atoe(mac, &ea);
6692 		if (!ret) {
6693 			AEXT_ERROR(dev->name, "rejecting mac=%s, ret=%d\n", mac, ret);
6694 			goto exit;
6695 		}
6696 		AEXT_TRACE(dev->name, "mac=%pM, period=%d", &ea, period);
6697 		if (period > 0) {
6698 			memset(&csi, 0, sizeof(csi_config_t));
6699 			bcopy(&ea, &csi.addr, ETHER_ADDR_LEN);
6700 			csi.period = period;
6701 			ret = wl_ext_iovar_setbuf(dev, "csi", (char *)&csi, sizeof(csi),
6702 				buf, WLC_IOCTL_SMLEN, NULL);
6703 		} else if (period == 0) {
6704 			memset(&csi, 0, sizeof(csi_config_t));
6705 			bcopy(&ea, &csi.addr, ETHER_ADDR_LEN);
6706 			ret = wl_ext_iovar_setbuf(dev, "csi_del", (char *)&csi, sizeof(csi),
6707 				buf, WLC_IOCTL_SMLEN, NULL);
6708 		} else {
6709 			ret = wl_ext_iovar_getbuf(dev, "csi", &ea, ETHER_ADDR_LEN, buf,
6710 				WLC_IOCTL_SMLEN, NULL);
6711 			if (!ret) {
6712 				csip = (csi_config_t *) buf;
6713 					/* Dump all lists */
6714 				bytes_written += snprintf(command+bytes_written, total_len,
6715 					"Mac    :%pM\n"
6716 					"Period :%d\n"
6717 					"BW     :%d\n"
6718 					"Method :%d\n",
6719 					&csip->addr, csip->period, csip->bw, csip->method);
6720 				AEXT_TRACE(dev->name, "command result is %s\n", command);
6721 				ret = bytes_written;
6722 			}
6723 		}
6724 	}
6725 	else {
6726 		ret = wl_ext_iovar_getbuf(dev, "csi_list", NULL, 0, buf, WLC_IOCTL_SMLEN, NULL);
6727 		if (!ret) {
6728 			csi_list = (csi_list_t *)buf;
6729 			bytes_written += snprintf(command+bytes_written, total_len,
6730 				"Total number :%d\n", csi_list->cnt);
6731 			for (i=0; i<csi_list->cnt; i++) {
6732 				csip = &csi_list->configs[i];
6733 				bytes_written += snprintf(command+bytes_written, total_len,
6734 					"Idx    :%d\n"
6735 					"Mac    :%pM\n"
6736 					"Period :%d\n"
6737 					"BW     :%d\n"
6738 					"Method :%d\n\n",
6739 					i+1, &csip->addr, csip->period, csip->bw, csip->method);
6740 			}
6741 			AEXT_TRACE(dev->name, "command result is %s\n", command);
6742 			ret = bytes_written;
6743 		}
6744 	}
6745 
6746 exit:
6747 	if (buf)
6748 		kfree(buf);
6749 	return ret;
6750 }
6751 #endif /* CSI_SUPPORT */
6752 
6753 typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command,
6754 	int total_len);
6755 
6756 typedef struct wl_ext_iovar_tpl_t {
6757 	int get;
6758 	int set;
6759 	char *name;
6760 	wl_ext_tpl_parse_t *parse;
6761 } wl_ext_iovar_tpl_t;
6762 
6763 const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = {
6764 	{WLC_GET_VAR,	WLC_SET_VAR,	"event_msg",	wl_ext_event_msg},
6765 	{WLC_GET_VAR,	WLC_SET_VAR,	"gtk_key_info",	wl_ext_gtk_key_info},
6766 	{WLC_GET_VAR,	WLC_SET_VAR,	"recal",		wl_ext_recal},
6767 	{WLC_GET_VAR,	WLC_SET_VAR,	"rsdb_mode",	wl_ext_rsdb_mode},
6768 	{WLC_GET_VAR,	WLC_SET_VAR,	"mkeep_alive",	wl_ext_mkeep_alive},
6769 #ifdef PKT_FILTER_SUPPORT
6770 	{WLC_GET_VAR,	WLC_SET_VAR,	"pkt_filter_add",		wl_ext_pkt_filter_add},
6771 	{WLC_GET_VAR,	WLC_SET_VAR,	"pkt_filter_delete",	wl_ext_pkt_filter_delete},
6772 	{WLC_GET_VAR,	WLC_SET_VAR,	"pkt_filter_enable",	wl_ext_pkt_filter_enable},
6773 #endif /* PKT_FILTER_SUPPORT */
6774 #if defined(WL_EXT_IAPSTA) && defined(WLMESH)
6775 	{WLC_GET_VAR,	WLC_SET_VAR,	"mesh_peer_status",	wl_ext_mesh_peer_status},
6776 #endif /* WL_EXT_IAPSTA && WLMESH */
6777 #ifdef SENDPROB
6778 	{WLC_GET_VAR,	WLC_SET_VAR,	"send_probreq",		wl_ext_send_probreq},
6779 	{WLC_GET_VAR,	WLC_SET_VAR,	"send_probresp",	wl_ext_send_probresp},
6780 	{WLC_GET_VAR,	WLC_SET_VAR,	"recv_probreq",		wl_ext_recv_probreq},
6781 	{WLC_GET_VAR,	WLC_SET_VAR,	"recv_probresp",	wl_ext_recv_probresp},
6782 #endif /* SENDPROB */
6783 #ifdef WL_EXT_TCPKA
6784 	{WLC_GET_VAR,	WLC_SET_VAR,	"tcpka_conn_add",		wl_ext_tcpka_conn_add},
6785 	{WLC_GET_VAR,	WLC_SET_VAR,	"tcpka_conn_enable",	wl_ext_tcpka_conn_enable},
6786 	{WLC_GET_VAR,	WLC_SET_VAR,	"tcpka_conn_sess_info",	wl_ext_tcpka_conn_info},
6787 #endif /* WL_EXT_TCPKA */
6788 #ifdef WL_EXT_WOWL
6789 	{WLC_GET_VAR,	WLC_SET_VAR,	"wowl_pattern",		wl_ext_wowl_pattern},
6790 	{WLC_GET_VAR,	WLC_SET_VAR,	"wowl_wakeind",		wl_ext_wowl_wakeind},
6791 #endif /* WL_EXT_WOWL */
6792 #ifdef IDHCP
6793 	{WLC_GET_VAR,	WLC_SET_VAR,	"dhcpc_dump",		wl_ext_dhcpc_dump},
6794 	{WLC_GET_VAR,	WLC_SET_VAR,	"dhcpc_param",		wl_ext_dhcpc_param},
6795 #endif /* IDHCP */
6796 #ifdef WL_GPIO_NOTIFY
6797 	{WLC_GET_VAR,	WLC_SET_VAR,	"bcol_gpio_noti",	wl_ext_gpio_notify},
6798 #endif /* WL_GPIO_NOTIFY */
6799 #ifdef CSI_SUPPORT
6800 	{WLC_GET_VAR,	WLC_SET_VAR,	"csi",				wl_ext_csi},
6801 #endif /* CSI_SUPPORT */
6802 };
6803 
6804 /*
6805 Ex: dhd_priv wl [cmd] [val]
6806   dhd_priv wl 85
6807   dhd_priv wl 86 1
6808   dhd_priv wl mpc
6809   dhd_priv wl mpc 1
6810 */
6811 static int
wl_ext_wl_iovar(struct net_device * dev,char * command,int total_len)6812 wl_ext_wl_iovar(struct net_device *dev, char *command, int total_len)
6813 {
6814 	int cmd, val, ret = -1, i;
6815 	char name[32], *pch, *pick_tmp, *data;
6816 	int bytes_written=-1;
6817 	const wl_ext_iovar_tpl_t *tpl = wl_ext_iovar_tpl_list;
6818 	int tpl_count = ARRAY_SIZE(wl_ext_iovar_tpl_list);
6819 
6820 	AEXT_TRACE(dev->name, "cmd %s\n", command);
6821 	pick_tmp = command;
6822 
6823 	pch = bcmstrtok(&pick_tmp, " ", 0); // pick wl
6824 	if (!pch || strncmp(pch, "wl", 2))
6825 		goto exit;
6826 
6827 	pch = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
6828 	if (!pch)
6829 		goto exit;
6830 
6831 	memset(name, 0 , sizeof (name));
6832 	cmd = (int)simple_strtol(pch, NULL, 0);
6833 	if (cmd == 0) {
6834 		strcpy(name, pch);
6835 	}
6836 	data = bcmstrtok(&pick_tmp, "", 0); // pick data
6837 	if (data && cmd == 0) {
6838 		cmd = WLC_SET_VAR;
6839 	} else if (cmd == 0) {
6840 		cmd = WLC_GET_VAR;
6841 	}
6842 
6843 	/* look for a matching code in the table */
6844 	for (i = 0; i < tpl_count; i++, tpl++) {
6845 		if ((tpl->get == cmd || tpl->set == cmd) && !strcmp(tpl->name, name))
6846 			break;
6847 	}
6848 	if (i < tpl_count && tpl->parse) {
6849 		ret = tpl->parse(dev, data, command, total_len);
6850 	} else {
6851 		if (cmd == WLC_SET_VAR) {
6852 			val = (int)simple_strtol(data, NULL, 0);
6853 			AEXT_INFO(dev->name, "set %s %d\n", name, val);
6854 			ret = wl_ext_iovar_setint(dev, name, val);
6855 		} else if (cmd == WLC_GET_VAR) {
6856 			AEXT_INFO(dev->name, "get %s\n", name);
6857 			ret = wl_ext_iovar_getint(dev, name, &val);
6858 			if (!ret) {
6859 				bytes_written = snprintf(command, total_len, "%d", val);
6860 				AEXT_INFO(dev->name, "command result is %s\n", command);
6861 				ret = bytes_written;
6862 			}
6863 		} else if (data) {
6864 			val = (int)simple_strtol(data, NULL, 0);
6865 			AEXT_INFO(dev->name, "set %d %d\n", cmd, val);
6866 			ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
6867 		} else {
6868 			AEXT_INFO(dev->name, "get %d\n", cmd);
6869 			ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
6870 			if (!ret) {
6871 				bytes_written = snprintf(command, total_len, "%d", val);
6872 				AEXT_INFO(dev->name, "command result is %s\n", command);
6873 				ret = bytes_written;
6874 			}
6875 		}
6876 	}
6877 
6878 exit:
6879 	return ret;
6880 }
6881 
6882 int
wl_android_ext_priv_cmd(struct net_device * net,char * command,int total_len,int * bytes_written)6883 wl_android_ext_priv_cmd(struct net_device *net, char *command,
6884 	int total_len, int *bytes_written)
6885 {
6886 	int ret = 0;
6887 
6888 	if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) {
6889 		*bytes_written = wl_ext_channels(net, command, total_len);
6890 	}
6891 	else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) {
6892 		*bytes_written = wl_ext_channel(net, command, total_len);
6893 	}
6894 	else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) {
6895 		*bytes_written = wl_ext_roam_trigger(net, command, total_len);
6896 	}
6897 	else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) {
6898 		*bytes_written = wl_ext_pm(net, command, total_len);
6899 	}
6900 	else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
6901 		*bytes_written = wl_ext_monitor(net, command, total_len);
6902 	}
6903 	else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) {
6904 		int bcn_li_dtim;
6905 		bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10);
6906 		*bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim);
6907 	}
6908 #ifdef WL_EXT_IAPSTA
6909 	else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0 ||
6910 			strnicmp(command, CMD_ISAM_INIT, strlen(CMD_ISAM_INIT)) == 0) {
6911 		*bytes_written = wl_ext_isam_init(net, command, total_len);
6912 	}
6913 	else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0 ||
6914 			strnicmp(command, CMD_ISAM_CONFIG, strlen(CMD_ISAM_CONFIG)) == 0) {
6915 		*bytes_written = wl_ext_iapsta_config(net, command, total_len);
6916 	}
6917 	else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0 ||
6918 			strnicmp(command, CMD_ISAM_ENABLE, strlen(CMD_ISAM_ENABLE)) == 0) {
6919 		*bytes_written = wl_ext_iapsta_enable(net, command, total_len);
6920 	}
6921 	else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0 ||
6922 			strnicmp(command, CMD_ISAM_DISABLE, strlen(CMD_ISAM_DISABLE)) == 0) {
6923 		*bytes_written = wl_ext_iapsta_disable(net, command, total_len);
6924 	}
6925 	else if (strnicmp(command, CMD_ISAM_STATUS, strlen(CMD_ISAM_STATUS)) == 0) {
6926 		*bytes_written = wl_ext_isam_status(net, command, total_len);
6927 	}
6928 	else if (strnicmp(command, CMD_ISAM_PARAM, strlen(CMD_ISAM_PARAM)) == 0) {
6929 		*bytes_written = wl_ext_isam_param(net, command, total_len);
6930 	}
6931 #if defined(WLMESH) && defined(WL_ESCAN)
6932 	else if (strnicmp(command, CMD_ISAM_PEER_PATH, strlen(CMD_ISAM_PEER_PATH)) == 0) {
6933 		*bytes_written = wl_ext_isam_peer_path(net, command, total_len);
6934 	}
6935 #endif /* WLMESH && WL_ESCAN */
6936 #endif /* WL_EXT_IAPSTA */
6937 #ifdef WL_CFG80211
6938 	else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
6939 		*bytes_written = wl_cfg80211_autochannel(net, command, total_len);
6940 	}
6941 #endif /* WL_CFG80211 */
6942 #if defined(WL_WIRELESS_EXT) && defined(WL_ESCAN)
6943 	else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
6944 		*bytes_written = wl_iw_autochannel(net, command, total_len);
6945 	}
6946 #endif /* WL_WIRELESS_EXT && WL_ESCAN */
6947 	else if (strnicmp(command, CMD_WLMSGLEVEL, strlen(CMD_WLMSGLEVEL)) == 0) {
6948 		*bytes_written = wl_ext_wlmsglevel(net, command, total_len);
6949 	}
6950 #ifdef WLEASYMESH
6951     else if (strnicmp(command, CMD_EASYMESH, strlen(CMD_EASYMESH)) == 0) {
6952 		int skip = strlen(CMD_EASYMESH) + 1;
6953 		*bytes_written = wl_ext_easymesh(net, command+skip, total_len);
6954     }
6955 #endif /* WLEASYMESH */
6956 	else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
6957 		*bytes_written = wl_ext_wl_iovar(net, command, total_len);
6958 	}
6959 	else
6960 		ret = -1;
6961 
6962 	return ret;
6963 }
6964 
6965 #if defined(WL_CFG80211) || defined(WL_ESCAN)
6966 int
wl_ext_get_distance(struct net_device * net,u32 band)6967 wl_ext_get_distance(struct net_device *net, u32 band)
6968 {
6969 	u32 bw = WL_CHANSPEC_BW_20;
6970 	s32 bw_cap = 0, distance = 0;
6971 	struct {
6972 		u32 band;
6973 		u32 bw_cap;
6974 	} param = {0, 0};
6975 	char buf[WLC_IOCTL_SMLEN]="\0";
6976 	s32 err = BCME_OK;
6977 
6978 	param.band = band;
6979 	err = wl_ext_iovar_getbuf(net, "bw_cap", &param, sizeof(param), buf,
6980 		sizeof(buf), NULL);
6981 	if (err) {
6982 		if (err != BCME_UNSUPPORTED) {
6983 			AEXT_ERROR(net->name, "bw_cap failed, %d\n", err);
6984 			return err;
6985 		} else {
6986 			err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap);
6987 			if (bw_cap != WLC_N_BW_20ALL)
6988 				bw = WL_CHANSPEC_BW_40;
6989 		}
6990 	} else {
6991 		if (WL_BW_CAP_80MHZ(buf[0]))
6992 			bw = WL_CHANSPEC_BW_80;
6993 		else if (WL_BW_CAP_40MHZ(buf[0]))
6994 			bw = WL_CHANSPEC_BW_40;
6995 		else
6996 			bw = WL_CHANSPEC_BW_20;
6997 	}
6998 
6999 	if (bw == WL_CHANSPEC_BW_20)
7000 		distance = 2;
7001 	else if (bw == WL_CHANSPEC_BW_40)
7002 		distance = 4;
7003 	else if (bw == WL_CHANSPEC_BW_80)
7004 		distance = 8;
7005 	else
7006 		distance = 16;
7007 	AEXT_INFO(net->name, "bw=0x%x, distance=%d\n", bw, distance);
7008 
7009 	return distance;
7010 }
7011 
7012 int
wl_ext_get_best_channel(struct net_device * net,wl_bss_cache_ctrl_t * bss_cache_ctrl,int ioctl_ver,int * best_2g_ch,int * best_5g_ch)7013 wl_ext_get_best_channel(struct net_device *net,
7014 #if defined(BSSCACHE)
7015 	wl_bss_cache_ctrl_t *bss_cache_ctrl,
7016 #else
7017 	wl_scan_results_t *bss_list,
7018 #endif /* BSSCACHE */
7019 	int ioctl_ver, int *best_2g_ch, int *best_5g_ch
7020 )
7021 {
7022 	struct wl_bss_info *bi = NULL;	/* must be initialized */
7023 	s32 i, j;
7024 #if defined(BSSCACHE)
7025 	wl_bss_cache_t *node;
7026 #endif /* BSSCACHE */
7027 	int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0};
7028 	s32 cen_ch, distance, distance_2g, distance_5g, ch, min_ap=999;
7029 	u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
7030 	wl_uint32_list_t *list;
7031 	int ret;
7032 	chanspec_t chanspec;
7033 	struct dhd_pub *dhd = dhd_get_pub(net);
7034 
7035 	memset(b_band, -1, sizeof(b_band));
7036 	memset(a_band1, -1, sizeof(a_band1));
7037 	memset(a_band4, -1, sizeof(a_band4));
7038 
7039 	memset(valid_chan_list, 0, sizeof(valid_chan_list));
7040 	list = (wl_uint32_list_t *)(void *) valid_chan_list;
7041 	list->count = htod32(WL_NUMCHANNELS);
7042 	ret = wl_ext_ioctl(net, WLC_GET_VALID_CHANNELS, &valid_chan_list,
7043 		sizeof(valid_chan_list), 0);
7044 	if (ret<0) {
7045 		AEXT_ERROR(net->name, "get channels failed with %d\n", ret);
7046 		return 0;
7047 	} else {
7048 		for (i = 0; i < dtoh32(list->count); i++) {
7049 			ch = dtoh32(list->element[i]);
7050 			if (!dhd_conf_match_channel(dhd, ch))
7051 				continue;
7052 			if (ch < CH_MAX_2G_CHANNEL)
7053 				b_band[ch-1] = 0;
7054 			else if (ch <= 48)
7055 				a_band1[(ch-36)/4] = 0;
7056 			else if (ch >= 149 && ch <= 161)
7057 				a_band4[(ch-149)/4] = 0;
7058 		}
7059 	}
7060 
7061 	distance_2g = wl_ext_get_distance(net, WLC_BAND_2G);
7062 	distance_5g = wl_ext_get_distance(net, WLC_BAND_5G);
7063 
7064 #if defined(BSSCACHE)
7065 	node = bss_cache_ctrl->m_cache_head;
7066 	for (i=0; node && i<256; i++)
7067 #else
7068 	for (i=0; i < bss_list->count; i++)
7069 #endif /* BSSCACHE */
7070 	{
7071 #if defined(BSSCACHE)
7072 		bi = node->results.bss_info;
7073 #else
7074 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
7075 #endif /* BSSCACHE */
7076 		chanspec = wl_ext_chspec_driver_to_host(ioctl_ver, bi->chanspec);
7077 		cen_ch = CHSPEC_CHANNEL(bi->chanspec);
7078 		distance = 0;
7079 		if (CHSPEC_IS20(chanspec))
7080 			distance += 2;
7081 		else if (CHSPEC_IS40(chanspec))
7082 			distance += 4;
7083 		else if (CHSPEC_IS80(chanspec))
7084 			distance += 8;
7085 		else
7086 			distance += 16;
7087 
7088 		if (CHSPEC_IS2G(chanspec)) {
7089 			distance += distance_2g;
7090 			for (j=0; j<ARRAYSIZE(b_band); j++) {
7091 				if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance)
7092 					b_band[j] += 1;
7093 			}
7094 		} else {
7095 			distance += distance_5g;
7096 			if (cen_ch <= 48) {
7097 				for (j=0; j<ARRAYSIZE(a_band1); j++) {
7098 					if (a_band1[j] >= 0 && abs(cen_ch-(36+j*4)) <= distance)
7099 						a_band1[j] += 1;
7100 				}
7101 			} else if (cen_ch >= 149) {
7102 				for (j=0; j<ARRAYSIZE(a_band4); j++) {
7103 					if (a_band4[j] >= 0 && abs(cen_ch-(149+j*4)) <= distance)
7104 						a_band4[j] += 1;
7105 				}
7106 			}
7107 		}
7108 #if defined(BSSCACHE)
7109 		node = node->next;
7110 #endif /* BSSCACHE */
7111 	}
7112 
7113 	*best_2g_ch = 0;
7114 	min_ap = 999;
7115 	for (i=0; i<CH_MAX_2G_CHANNEL; i++) {
7116 		if(b_band[i] < min_ap && b_band[i] >= 0) {
7117 			min_ap = b_band[i];
7118 			*best_2g_ch = i+1;
7119 		}
7120 	}
7121 	*best_5g_ch = 0;
7122 	min_ap = 999;
7123 	for (i=0; i<ARRAYSIZE(a_band1); i++) {
7124 		if(a_band1[i] < min_ap && a_band1[i] >= 0) {
7125 			min_ap = a_band1[i];
7126 			*best_5g_ch = i*4 + 36;
7127 		}
7128 	}
7129 	for (i=0; i<ARRAYSIZE(a_band4); i++) {
7130 		if(a_band4[i] < min_ap && a_band4[i] >= 0) {
7131 			min_ap = a_band4[i];
7132 			*best_5g_ch = i*4 + 149;
7133 		}
7134 	}
7135 
7136 	if (android_msg_level & ANDROID_INFO_LEVEL) {
7137 		struct bcmstrbuf strbuf;
7138 		char *tmp_buf = NULL;
7139 		tmp_buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
7140 		if (tmp_buf == NULL) {
7141 			AEXT_ERROR(net->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
7142 			goto exit;
7143 		}
7144 		bcm_binit(&strbuf, tmp_buf, WLC_IOCTL_SMLEN);
7145 		for (j=0; j<ARRAYSIZE(b_band); j++)
7146 			bcm_bprintf(&strbuf, "%d/%d, ", b_band[j], 1+j);
7147 		bcm_bprintf(&strbuf, "\n");
7148 		for (j=0; j<ARRAYSIZE(a_band1); j++)
7149 			bcm_bprintf(&strbuf, "%d/%d, ", a_band1[j], 36+j*4);
7150 		bcm_bprintf(&strbuf, "\n");
7151 		for (j=0; j<ARRAYSIZE(a_band4); j++)
7152 			bcm_bprintf(&strbuf, "%d/%d, ", a_band4[j], 149+j*4);
7153 		bcm_bprintf(&strbuf, "\n");
7154 		bcm_bprintf(&strbuf, "best_2g_ch=%d, best_5g_ch=%d\n",
7155 			*best_2g_ch, *best_5g_ch);
7156 		AEXT_INFO(net->name, "\n%s", strbuf.origbuf);
7157 		if (tmp_buf) {
7158 			kfree(tmp_buf);
7159 		}
7160 	}
7161 
7162 exit:
7163 	return 0;
7164 }
7165 #endif /* WL_CFG80211 || WL_ESCAN */
7166 
7167 #ifdef WL_CFG80211
7168 #define APCS_MAX_RETRY		10
7169 static int
wl_ext_fw_apcs(struct net_device * dev,uint32 band)7170 wl_ext_fw_apcs(struct net_device *dev, uint32 band)
7171 {
7172 	int channel = 0, chosen = 0, retry = 0, ret = 0, spect = 0;
7173 	u8 *reqbuf = NULL;
7174 	uint32 buf_size;
7175 
7176 	ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
7177 	if (ret) {
7178 		AEXT_ERROR(dev->name, "ACS: error getting the spect, ret=%d\n", ret);
7179 		goto done;
7180 	}
7181 
7182 	if (spect > 0) {
7183 		ret = wl_cfg80211_set_spect(dev, 0);
7184 		if (ret < 0) {
7185 			AEXT_ERROR(dev->name, "ACS: error while setting spect, ret=%d\n", ret);
7186 			goto done;
7187 		}
7188 	}
7189 
7190 	reqbuf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
7191 	if (reqbuf == NULL) {
7192 		AEXT_ERROR(dev->name, "failed to allocate chanspec buffer\n");
7193 		goto done;
7194 	}
7195 	memset(reqbuf, 0, CHANSPEC_BUF_SIZE);
7196 
7197 	if (band == WLC_BAND_AUTO) {
7198 		AEXT_INFO(dev->name, "ACS full channel scan \n");
7199 		reqbuf[0] = htod32(0);
7200 	} else if (band == WLC_BAND_5G) {
7201 		AEXT_INFO(dev->name, "ACS 5G band scan \n");
7202 		if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
7203 			AEXT_ERROR(dev->name, "ACS 5g chanspec retreival failed! \n");
7204 			goto done;
7205 		}
7206 	} else if (band == WLC_BAND_2G) {
7207 		/*
7208 		 * If channel argument is not provided/ argument 20 is provided,
7209 		 * Restrict channel to 2GHz, 20MHz BW, No SB
7210 		 */
7211 		AEXT_INFO(dev->name, "ACS 2G band scan \n");
7212 		if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
7213 			AEXT_ERROR(dev->name, "ACS 2g chanspec retreival failed! \n");
7214 			goto done;
7215 		}
7216 	} else {
7217 		AEXT_ERROR(dev->name, "ACS: No band chosen\n");
7218 		goto done;
7219 	}
7220 
7221 	buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
7222 	ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
7223 		buf_size);
7224 	if (ret < 0) {
7225 		AEXT_ERROR(dev->name, "can't start auto channel scan, err = %d\n", ret);
7226 		channel = 0;
7227 		goto done;
7228 	}
7229 
7230 	/* Wait for auto channel selection, max 3000 ms */
7231 	if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G)) {
7232 		OSL_SLEEP(500);
7233 	} else {
7234 		/*
7235 		 * Full channel scan at the minimum takes 1.2secs
7236 		 * even with parallel scan. max wait time: 3500ms
7237 		 */
7238 		OSL_SLEEP(1000);
7239 	}
7240 
7241 	retry = APCS_MAX_RETRY;
7242 	while (retry--) {
7243 		ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
7244 			sizeof(chosen));
7245 		if (ret < 0) {
7246 			chosen = 0;
7247 		} else {
7248 			chosen = dtoh32(chosen);
7249 		}
7250 
7251 		if (chosen) {
7252 			int chosen_band;
7253 			int apcs_band;
7254 #ifdef D11AC_IOTYPES
7255 			if (wl_cfg80211_get_ioctl_version() == 1) {
7256 				channel = LCHSPEC_CHANNEL((chanspec_t)chosen);
7257 			} else {
7258 				channel = CHSPEC_CHANNEL((chanspec_t)chosen);
7259 			}
7260 #else
7261 			channel = CHSPEC_CHANNEL((chanspec_t)chosen);
7262 #endif /* D11AC_IOTYPES */
7263 			apcs_band = (band == WLC_BAND_AUTO) ? WLC_BAND_2G : band;
7264 			chosen_band = (channel <= CH_MAX_2G_CHANNEL) ? WLC_BAND_2G : WLC_BAND_5G;
7265 			if (apcs_band == chosen_band) {
7266 				WL_MSG(dev->name, "selected channel = %d\n", channel);
7267 				break;
7268 			}
7269 		}
7270 		AEXT_INFO(dev->name, "%d tried, ret = %d, chosen = 0x%x\n",
7271 			(APCS_MAX_RETRY - retry), ret, chosen);
7272 		OSL_SLEEP(250);
7273 	}
7274 
7275 done:
7276 	if (spect > 0) {
7277 		if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
7278 			AEXT_ERROR(dev->name, "ACS: error while setting spect\n");
7279 		}
7280 	}
7281 
7282 	if (reqbuf) {
7283 		kfree(reqbuf);
7284 	}
7285 
7286 	return channel;
7287 }
7288 #endif /* WL_CFG80211 */
7289 
7290 #ifdef WL_ESCAN
7291 int
wl_ext_drv_apcs(struct net_device * dev,uint32 band)7292 wl_ext_drv_apcs(struct net_device *dev, uint32 band)
7293 {
7294 	int ret = 0, channel = 0;
7295 	struct dhd_pub *dhd = dhd_get_pub(dev);
7296 	struct wl_escan_info *escan = NULL;
7297 	int retry = 0, retry_max, retry_interval = 250, up = 1;
7298 #ifdef WL_CFG80211
7299 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
7300 #endif /* WL_CFG80211 */
7301 
7302 	escan = dhd->escan;
7303 	if (dhd) {
7304 		retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval;
7305 		ret = wldev_ioctl_get(dev, WLC_GET_UP, &up, sizeof(s32));
7306 		if (ret < 0 || up == 0) {
7307 			ret = wldev_ioctl_set(dev, WLC_UP, &up, sizeof(s32));
7308 		}
7309 		retry = retry_max;
7310 		while (retry--) {
7311 			if (escan->escan_state == ESCAN_STATE_SCANING
7312 #ifdef WL_CFG80211
7313 				|| wl_get_drv_status_all(cfg, SCANNING)
7314 #endif
7315 			)
7316 			{
7317 				AEXT_INFO(dev->name, "Scanning %d tried, ret = %d\n",
7318 					(retry_max - retry), ret);
7319 			} else {
7320 				escan->autochannel = 1;
7321 				ret = wl_escan_set_scan(dev, dhd, NULL, 0, TRUE);
7322 				if (!ret)
7323 					break;
7324 			}
7325 			OSL_SLEEP(retry_interval);
7326 		}
7327 		if ((retry == 0) || (ret < 0))
7328 			goto done;
7329 		retry = retry_max;
7330 		while (retry--) {
7331 			if (escan->escan_state == ESCAN_STATE_IDLE) {
7332 				if (band == WLC_BAND_5G)
7333 					channel = escan->best_5g_ch;
7334 				else
7335 					channel = escan->best_2g_ch;
7336 				WL_MSG(dev->name, "selected channel = %d\n", channel);
7337 				goto done;
7338 			}
7339 			AEXT_INFO(dev->name, "escan_state=%d, %d tried, ret = %d\n",
7340 				escan->escan_state, (retry_max - retry), ret);
7341 			OSL_SLEEP(retry_interval);
7342 		}
7343 		if ((retry == 0) || (ret < 0))
7344 			goto done;
7345 	}
7346 
7347 done:
7348 	if (escan)
7349 		escan->autochannel = 0;
7350 
7351 	return channel;
7352 }
7353 #endif /* WL_ESCAN */
7354 
7355 int
wl_ext_autochannel(struct net_device * dev,uint acs,uint32 band)7356 wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band)
7357 {
7358 	int channel = 0;
7359 	uint16 chan_2g, chan_5g;
7360 
7361 	AEXT_INFO(dev->name, "acs=0x%x, band=%d \n", acs, band);
7362 
7363 #ifdef WL_CFG80211
7364 	if (acs & ACS_FW_BIT) {
7365 		int ret = 0;
7366 		ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &channel, sizeof(channel));
7367 		channel = 0;
7368 		if (ret != BCME_UNSUPPORTED)
7369 			channel = wl_ext_fw_apcs(dev, band);
7370 		if (channel)
7371 			return channel;
7372 	}
7373 #endif
7374 
7375 #ifdef WL_ESCAN
7376 	if (acs & ACS_DRV_BIT)
7377 		channel = wl_ext_drv_apcs(dev, band);
7378 #endif /* WL_ESCAN */
7379 
7380 	if (channel == 0) {
7381 		wl_ext_get_default_chan(dev, &chan_2g, &chan_5g, TRUE);
7382 		if (band == WLC_BAND_5G) {
7383 			channel = chan_5g;
7384 		} else {
7385 			channel = chan_2g;
7386 		}
7387 		AEXT_ERROR(dev->name, "ACS failed. Fall back to default channel (%d) \n", channel);
7388 	}
7389 
7390 	return channel;
7391 }
7392 
7393 #if defined(RSSIAVG)
7394 void
wl_free_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl)7395 wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
7396 {
7397 	wl_rssi_cache_t *node, *cur, **rssi_head;
7398 	int i=0;
7399 
7400 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7401 	node = *rssi_head;
7402 
7403 	for (;node;) {
7404 		AEXT_INFO("wlan", "Free %d with BSSID %pM\n", i, &node->BSSID);
7405 		cur = node;
7406 		node = cur->next;
7407 		kfree(cur);
7408 		i++;
7409 	}
7410 	*rssi_head = NULL;
7411 }
7412 
7413 void
wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl)7414 wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
7415 {
7416 	wl_rssi_cache_t *node, *prev, **rssi_head;
7417 	int i = -1, tmp = 0;
7418 	struct osl_timespec now;
7419 
7420 	osl_do_gettimeofday(&now);
7421 
7422 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7423 	node = *rssi_head;
7424 	prev = node;
7425 	for (;node;) {
7426 		i++;
7427 		if (now.tv_sec > node->tv.tv_sec) {
7428 			if (node == *rssi_head) {
7429 				tmp = 1;
7430 				*rssi_head = node->next;
7431 			} else {
7432 				tmp = 0;
7433 				prev->next = node->next;
7434 			}
7435 			AEXT_INFO("wlan", "Del %d with BSSID %pM\n", i, &node->BSSID);
7436 			kfree(node);
7437 			if (tmp == 1) {
7438 				node = *rssi_head;
7439 				prev = node;
7440 			} else {
7441 				node = prev->next;
7442 			}
7443 			continue;
7444 		}
7445 		prev = node;
7446 		node = node->next;
7447 	}
7448 }
7449 
7450 void
wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,u8 * bssid)7451 wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
7452 	u8 *bssid)
7453 {
7454 	wl_rssi_cache_t *node, *prev, **rssi_head;
7455 	int i = -1, tmp = 0;
7456 
7457 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7458 	node = *rssi_head;
7459 	prev = node;
7460 	for (;node;) {
7461 		i++;
7462 		if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) {
7463 			if (node == *rssi_head) {
7464 				tmp = 1;
7465 				*rssi_head = node->next;
7466 			} else {
7467 				tmp = 0;
7468 				prev->next = node->next;
7469 			}
7470 			AEXT_INFO("wlan", "Del %d with BSSID %pM\n", i, &node->BSSID);
7471 			kfree(node);
7472 			if (tmp == 1) {
7473 				node = *rssi_head;
7474 				prev = node;
7475 			} else {
7476 				node = prev->next;
7477 			}
7478 			continue;
7479 		}
7480 		prev = node;
7481 		node = node->next;
7482 	}
7483 }
7484 
7485 void
wl_reset_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl)7486 wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
7487 {
7488 	wl_rssi_cache_t *node, **rssi_head;
7489 
7490 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7491 
7492 	/* reset dirty */
7493 	node = *rssi_head;
7494 	for (;node;) {
7495 		node->dirty += 1;
7496 		node = node->next;
7497 	}
7498 }
7499 
7500 int
wl_update_connected_rssi_cache(struct net_device * net,wl_rssi_cache_ctrl_t * rssi_cache_ctrl,int * rssi_avg)7501 wl_update_connected_rssi_cache(struct net_device *net,
7502 	wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
7503 {
7504 	wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
7505 	int j, k=0;
7506 	int rssi, error=0;
7507 	struct ether_addr bssid;
7508 	struct osl_timespec now, timeout;
7509 	scb_val_t scbval;
7510 
7511 	if (!g_wifi_on)
7512 		return 0;
7513 
7514 	error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
7515 	if (error == BCME_NOTASSOCIATED) {
7516 		AEXT_INFO("wlan", "Not Associated! res:%d\n", error);
7517 		return 0;
7518 	}
7519 	if (error) {
7520 		AEXT_ERROR(net->name, "Could not get bssid (%d)\n", error);
7521 	}
7522 	error = wldev_get_rssi(net, &scbval);
7523 	if (error) {
7524 		AEXT_ERROR(net->name, "Could not get rssi (%d)\n", error);
7525 		return error;
7526 	}
7527 	rssi = scbval.val;
7528 
7529 	osl_do_gettimeofday(&now);
7530 	timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
7531 	if (timeout.tv_sec < now.tv_sec) {
7532 		/*
7533 		 * Integer overflow - assume long enough timeout to be assumed
7534 		 * to be infinite, i.e., the timeout would never happen.
7535 		 */
7536 		AEXT_TRACE(net->name,
7537 			"Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
7538 			RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec);
7539 	}
7540 
7541 	/* update RSSI */
7542 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7543 	node = *rssi_head;
7544 	prev = NULL;
7545 	for (;node;) {
7546 		if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
7547 			AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%d\n", k, &bssid, rssi);
7548 			for (j=0; j<RSSIAVG_LEN-1; j++)
7549 				node->RSSI[j] = node->RSSI[j+1];
7550 			node->RSSI[j] = rssi;
7551 			node->dirty = 0;
7552 			node->tv = timeout;
7553 			goto exit;
7554 		}
7555 		prev = node;
7556 		node = node->next;
7557 		k++;
7558 	}
7559 
7560 	leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
7561 	if (!leaf) {
7562 		AEXT_ERROR(net->name, "Memory alloc failure %d\n", (int)sizeof(wl_rssi_cache_t));
7563 		return 0;
7564 	}
7565 	AEXT_INFO(net->name, "Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
7566 		k, &bssid, rssi);
7567 
7568 	leaf->next = NULL;
7569 	leaf->dirty = 0;
7570 	leaf->tv = timeout;
7571 	memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN);
7572 	for (j=0; j<RSSIAVG_LEN; j++)
7573 		leaf->RSSI[j] = rssi;
7574 
7575 	if (!prev)
7576 		*rssi_head = leaf;
7577 	else
7578 		prev->next = leaf;
7579 
7580 exit:
7581 	*rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid);
7582 
7583 	return error;
7584 }
7585 
7586 void
wl_update_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,wl_scan_results_t * ss_list)7587 wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
7588 	wl_scan_results_t *ss_list)
7589 {
7590 	wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
7591 	wl_bss_info_t *bi = NULL;
7592 	int i, j, k;
7593 	struct osl_timespec now, timeout;
7594 
7595 	if (!ss_list->count)
7596 		return;
7597 
7598 	osl_do_gettimeofday(&now);
7599 	timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
7600 	if (timeout.tv_sec < now.tv_sec) {
7601 		/*
7602 		 * Integer overflow - assume long enough timeout to be assumed
7603 		 * to be infinite, i.e., the timeout would never happen.
7604 		 */
7605 		AEXT_TRACE("wlan",
7606 			"Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
7607 			RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec);
7608 	}
7609 
7610 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7611 
7612 	/* update RSSI */
7613 	for (i = 0; i < ss_list->count; i++) {
7614 		node = *rssi_head;
7615 		prev = NULL;
7616 		k = 0;
7617 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
7618 		for (;node;) {
7619 			if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
7620 				AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7621 					k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
7622 				for (j=0; j<RSSIAVG_LEN-1; j++)
7623 					node->RSSI[j] = node->RSSI[j+1];
7624 				node->RSSI[j] = dtoh16(bi->RSSI);
7625 				node->dirty = 0;
7626 				node->tv = timeout;
7627 				break;
7628 			}
7629 			prev = node;
7630 			node = node->next;
7631 			k++;
7632 		}
7633 
7634 		if (node)
7635 			continue;
7636 
7637 		leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
7638 		if (!leaf) {
7639 			AEXT_ERROR("wlan", "Memory alloc failure %d\n",
7640 				(int)sizeof(wl_rssi_cache_t));
7641 			return;
7642 		}
7643 		AEXT_INFO("wlan", "Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
7644 			k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
7645 
7646 		leaf->next = NULL;
7647 		leaf->dirty = 0;
7648 		leaf->tv = timeout;
7649 		memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN);
7650 		for (j=0; j<RSSIAVG_LEN; j++)
7651 			leaf->RSSI[j] = dtoh16(bi->RSSI);
7652 
7653 		if (!prev)
7654 			*rssi_head = leaf;
7655 		else
7656 			prev->next = leaf;
7657 	}
7658 }
7659 
7660 int16
wl_get_avg_rssi(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,void * addr)7661 wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr)
7662 {
7663 	wl_rssi_cache_t *node, **rssi_head;
7664 	int j, rssi_sum, rssi=RSSI_MINVAL;
7665 
7666 	rssi_head = &rssi_cache_ctrl->m_cache_head;
7667 
7668 	node = *rssi_head;
7669 	for (;node;) {
7670 		if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) {
7671 			rssi_sum = 0;
7672 			rssi = 0;
7673 			for (j=0; j<RSSIAVG_LEN; j++)
7674 				rssi_sum += node->RSSI[RSSIAVG_LEN-j-1];
7675 			rssi = rssi_sum / j;
7676 			break;
7677 		}
7678 		node = node->next;
7679 	}
7680 	rssi = MIN(rssi, RSSI_MAXVAL);
7681 	if (rssi == RSSI_MINVAL) {
7682 		AEXT_ERROR("wlan", "BSSID %pM does not in RSSI cache\n", addr);
7683 	}
7684 	return (int16)rssi;
7685 }
7686 #endif /* RSSIAVG */
7687 
7688 #if defined(RSSIOFFSET)
7689 int
wl_update_rssi_offset(struct net_device * net,int rssi)7690 wl_update_rssi_offset(struct net_device *net, int rssi)
7691 {
7692 #if defined(RSSIOFFSET_NEW)
7693 	int j;
7694 #endif /* RSSIOFFSET_NEW */
7695 
7696 	if (!g_wifi_on)
7697 		return rssi;
7698 
7699 #if defined(RSSIOFFSET_NEW)
7700 	for (j=0; j<RSSI_OFFSET; j++) {
7701 		if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
7702 			break;
7703 	}
7704 	rssi += j;
7705 #else
7706 	rssi += RSSI_OFFSET;
7707 #endif /* RSSIOFFSET_NEW */
7708 	return MIN(rssi, RSSI_MAXVAL);
7709 }
7710 #endif /* RSSIOFFSET */
7711 
7712 #if defined(BSSCACHE)
7713 void
wl_free_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl)7714 wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
7715 {
7716 	wl_bss_cache_t *node, *cur, **bss_head;
7717 	int i=0;
7718 
7719 	AEXT_TRACE("wlan", "called\n");
7720 
7721 	bss_head = &bss_cache_ctrl->m_cache_head;
7722 	node = *bss_head;
7723 
7724 	for (;node;) {
7725 		AEXT_TRACE("wlan", "Free %d with BSSID %pM\n",
7726 			i, &node->results.bss_info->BSSID);
7727 		cur = node;
7728 		node = cur->next;
7729 		kfree(cur);
7730 		i++;
7731 	}
7732 	*bss_head = NULL;
7733 }
7734 
7735 void
wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl)7736 wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
7737 {
7738 	wl_bss_cache_t *node, *prev, **bss_head;
7739 	int i = -1, tmp = 0;
7740 	struct osl_timespec now;
7741 
7742 	osl_do_gettimeofday(&now);
7743 
7744 	bss_head = &bss_cache_ctrl->m_cache_head;
7745 	node = *bss_head;
7746 	prev = node;
7747 	for (;node;) {
7748 		i++;
7749 		if (now.tv_sec > node->tv.tv_sec) {
7750 			if (node == *bss_head) {
7751 				tmp = 1;
7752 				*bss_head = node->next;
7753 			} else {
7754 				tmp = 0;
7755 				prev->next = node->next;
7756 			}
7757 			AEXT_TRACE("wlan", "Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7758 				i, &node->results.bss_info->BSSID,
7759 				dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID);
7760 			kfree(node);
7761 			if (tmp == 1) {
7762 				node = *bss_head;
7763 				prev = node;
7764 			} else {
7765 				node = prev->next;
7766 			}
7767 			continue;
7768 		}
7769 		prev = node;
7770 		node = node->next;
7771 	}
7772 }
7773 
7774 void
wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl,u8 * bssid)7775 wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
7776 	u8 *bssid)
7777 {
7778 	wl_bss_cache_t *node, *prev, **bss_head;
7779 	int i = -1, tmp = 0;
7780 
7781 	bss_head = &bss_cache_ctrl->m_cache_head;
7782 	node = *bss_head;
7783 	prev = node;
7784 	for (;node;) {
7785 		i++;
7786 		if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) {
7787 			if (node == *bss_head) {
7788 				tmp = 1;
7789 				*bss_head = node->next;
7790 			} else {
7791 				tmp = 0;
7792 				prev->next = node->next;
7793 			}
7794 			AEXT_TRACE("wlan", "Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7795 				i, &node->results.bss_info->BSSID,
7796 				dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID);
7797 			kfree(node);
7798 			if (tmp == 1) {
7799 				node = *bss_head;
7800 				prev = node;
7801 			} else {
7802 				node = prev->next;
7803 			}
7804 			continue;
7805 		}
7806 		prev = node;
7807 		node = node->next;
7808 	}
7809 }
7810 
7811 void
wl_reset_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl)7812 wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
7813 {
7814 	wl_bss_cache_t *node, **bss_head;
7815 
7816 	bss_head = &bss_cache_ctrl->m_cache_head;
7817 
7818 	/* reset dirty */
7819 	node = *bss_head;
7820 	for (;node;) {
7821 		node->dirty += 1;
7822 		node = node->next;
7823 	}
7824 }
7825 
dump_bss_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,wl_bss_cache_t * node)7826 void dump_bss_cache(
7827 #if defined(RSSIAVG)
7828 	wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
7829 #endif /* RSSIAVG */
7830 	wl_bss_cache_t *node)
7831 {
7832 	int k = 0;
7833 	int16 rssi;
7834 
7835 	for (;node;) {
7836 #if defined(RSSIAVG)
7837 		rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
7838 #else
7839 		rssi = dtoh16(node->results.bss_info->RSSI);
7840 #endif /* RSSIAVG */
7841 		AEXT_TRACE("wlan", "dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7842 			k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID);
7843 		k++;
7844 		node = node->next;
7845 	}
7846 }
7847 
7848 void
wl_update_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl,wl_rssi_cache_ctrl_t * rssi_cache_ctrl,wl_scan_results_t * ss_list)7849 wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
7850 #if defined(RSSIAVG)
7851 	wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
7852 #endif /* RSSIAVG */
7853 	wl_scan_results_t *ss_list)
7854 {
7855 	wl_bss_cache_t *node, *prev, *leaf, **bss_head;
7856 	wl_bss_info_t *bi = NULL;
7857 	int i, k=0;
7858 #if defined(SORT_BSS_BY_RSSI)
7859 	int16 rssi, rssi_node;
7860 #endif /* SORT_BSS_BY_RSSI */
7861 	struct osl_timespec now, timeout;
7862 
7863 	if (!ss_list->count)
7864 		return;
7865 
7866 	osl_do_gettimeofday(&now);
7867 	timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT;
7868 	if (timeout.tv_sec < now.tv_sec) {
7869 		/*
7870 		 * Integer overflow - assume long enough timeout to be assumed
7871 		 * to be infinite, i.e., the timeout would never happen.
7872 		 */
7873 		AEXT_TRACE("wlan",
7874 			"Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
7875 			BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec);
7876 	}
7877 
7878 	bss_head = &bss_cache_ctrl->m_cache_head;
7879 
7880 	for (i=0; i < ss_list->count; i++) {
7881 		node = *bss_head;
7882 		prev = NULL;
7883 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
7884 
7885 		for (;node;) {
7886 			if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
7887 				if (node == *bss_head)
7888 					*bss_head = node->next;
7889 				else {
7890 					prev->next = node->next;
7891 				}
7892 				break;
7893 			}
7894 			prev = node;
7895 			node = node->next;
7896 		}
7897 
7898 		leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL);
7899 		if (!leaf) {
7900 			AEXT_ERROR("wlan", "Memory alloc failure %d\n",
7901 				dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t));
7902 			return;
7903 		}
7904 		if (node) {
7905 			kfree(node);
7906 			node = NULL;
7907 			AEXT_TRACE("wlan",
7908 				"Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7909 				k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
7910 		} else
7911 			AEXT_TRACE("wlan",
7912 				"Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
7913 				k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
7914 
7915 		memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
7916 		leaf->next = NULL;
7917 		leaf->dirty = 0;
7918 		leaf->tv = timeout;
7919 		leaf->results.count = 1;
7920 		leaf->results.version = ss_list->version;
7921 		k++;
7922 
7923 		if (*bss_head == NULL)
7924 			*bss_head = leaf;
7925 		else {
7926 #if defined(SORT_BSS_BY_RSSI)
7927 			node = *bss_head;
7928 #if defined(RSSIAVG)
7929 			rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID);
7930 #else
7931 			rssi = dtoh16(leaf->results.bss_info->RSSI);
7932 #endif /* RSSIAVG */
7933 			for (;node;) {
7934 #if defined(RSSIAVG)
7935 				rssi_node = wl_get_avg_rssi(rssi_cache_ctrl,
7936 					&node->results.bss_info->BSSID);
7937 #else
7938 				rssi_node = dtoh16(node->results.bss_info->RSSI);
7939 #endif /* RSSIAVG */
7940 				if (rssi > rssi_node) {
7941 					leaf->next = node;
7942 					if (node == *bss_head)
7943 						*bss_head = leaf;
7944 					else
7945 						prev->next = leaf;
7946 					break;
7947 				}
7948 				prev = node;
7949 				node = node->next;
7950 			}
7951 			if (node == NULL)
7952 				prev->next = leaf;
7953 #else
7954 			leaf->next = *bss_head;
7955 			*bss_head = leaf;
7956 #endif /* SORT_BSS_BY_RSSI */
7957 		}
7958 	}
7959 	dump_bss_cache(
7960 #if defined(RSSIAVG)
7961 		rssi_cache_ctrl,
7962 #endif /* RSSIAVG */
7963 		*bss_head);
7964 }
7965 
7966 void
wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t * bss_cache_ctrl)7967 wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl)
7968 {
7969 	AEXT_TRACE("wlan", "Enter\n");
7970 	wl_free_bss_cache(bss_cache_ctrl);
7971 }
7972 #endif /* BSSCACHE */
7973 
7974 
7975