1*4882a593Smuzhiyun
2*4882a593Smuzhiyun #include <linux/module.h>
3*4882a593Smuzhiyun #include <linux/netdevice.h>
4*4882a593Smuzhiyun #include <net/netlink.h>
5*4882a593Smuzhiyun #include <typedefs.h>
6*4882a593Smuzhiyun #include <linuxver.h>
7*4882a593Smuzhiyun #include <osl.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <bcmutils.h>
10*4882a593Smuzhiyun #include <bcmendian.h>
11*4882a593Smuzhiyun #include <ethernet.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <wl_android.h>
14*4882a593Smuzhiyun #include <linux/if_arp.h>
15*4882a593Smuzhiyun #include <asm/uaccess.h>
16*4882a593Smuzhiyun #include <linux/wireless.h>
17*4882a593Smuzhiyun #if defined(WL_WIRELESS_EXT)
18*4882a593Smuzhiyun #include <wl_iw.h>
19*4882a593Smuzhiyun #endif /* WL_WIRELESS_EXT */
20*4882a593Smuzhiyun #include <wldev_common.h>
21*4882a593Smuzhiyun #include <wlioctl.h>
22*4882a593Smuzhiyun #include <bcmutils.h>
23*4882a593Smuzhiyun #include <linux_osl.h>
24*4882a593Smuzhiyun #include <dhd_dbg.h>
25*4882a593Smuzhiyun #include <dngl_stats.h>
26*4882a593Smuzhiyun #include <dhd.h>
27*4882a593Smuzhiyun #include <dhd_config.h>
28*4882a593Smuzhiyun #ifdef WL_CFG80211
29*4882a593Smuzhiyun #include <wl_cfg80211.h>
30*4882a593Smuzhiyun #endif /* WL_CFG80211 */
31*4882a593Smuzhiyun #ifdef WL_ESCAN
32*4882a593Smuzhiyun #include <wl_escan.h>
33*4882a593Smuzhiyun #endif /* WL_ESCAN */
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun uint android_msg_level = ANDROID_ERROR_LEVEL | ANDROID_MSG_LEVEL;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define AEXT_ERROR(name, arg1, args...) \
38*4882a593Smuzhiyun do { \
39*4882a593Smuzhiyun if (android_msg_level & ANDROID_ERROR_LEVEL) { \
40*4882a593Smuzhiyun printf("[%s] AEXT-ERROR) %s : " arg1, name, __func__, ## args); \
41*4882a593Smuzhiyun } \
42*4882a593Smuzhiyun } while (0)
43*4882a593Smuzhiyun #define AEXT_TRACE(name, arg1, args...) \
44*4882a593Smuzhiyun do { \
45*4882a593Smuzhiyun if (android_msg_level & ANDROID_TRACE_LEVEL) { \
46*4882a593Smuzhiyun printf("[%s] AEXT-TRACE) %s : " arg1, name, __func__, ## args); \
47*4882a593Smuzhiyun } \
48*4882a593Smuzhiyun } while (0)
49*4882a593Smuzhiyun #define AEXT_INFO(name, arg1, args...) \
50*4882a593Smuzhiyun do { \
51*4882a593Smuzhiyun if (android_msg_level & ANDROID_INFO_LEVEL) { \
52*4882a593Smuzhiyun printf("[%s] AEXT-INFO) %s : " arg1, name, __func__, ## args); \
53*4882a593Smuzhiyun } \
54*4882a593Smuzhiyun } while (0)
55*4882a593Smuzhiyun #define AEXT_DBG(name, arg1, args...) \
56*4882a593Smuzhiyun do { \
57*4882a593Smuzhiyun if (android_msg_level & ANDROID_DBG_LEVEL) { \
58*4882a593Smuzhiyun printf("[%s] AEXT-DBG) %s : " arg1, name, __func__, ## args); \
59*4882a593Smuzhiyun } \
60*4882a593Smuzhiyun } while (0)
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun #ifndef WL_CFG80211
63*4882a593Smuzhiyun #define htod32(i) i
64*4882a593Smuzhiyun #define htod16(i) i
65*4882a593Smuzhiyun #define dtoh32(i) i
66*4882a593Smuzhiyun #define dtoh16(i) i
67*4882a593Smuzhiyun #define htodchanspec(i) i
68*4882a593Smuzhiyun #define dtohchanspec(i) i
69*4882a593Smuzhiyun #define IEEE80211_BAND_2GHZ 0
70*4882a593Smuzhiyun #define IEEE80211_BAND_5GHZ 1
71*4882a593Smuzhiyun #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
72*4882a593Smuzhiyun #define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
73*4882a593Smuzhiyun #define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
74*4882a593Smuzhiyun #endif /* WL_CFG80211 */
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #ifndef IW_CUSTOM_MAX
77*4882a593Smuzhiyun #define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */
78*4882a593Smuzhiyun #endif /* IW_CUSTOM_MAX */
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #define CMD_CHANNEL "CHANNEL"
81*4882a593Smuzhiyun #define CMD_CHANNELS "CHANNELS"
82*4882a593Smuzhiyun #define CMD_ROAM_TRIGGER "ROAM_TRIGGER"
83*4882a593Smuzhiyun #define CMD_PM "PM"
84*4882a593Smuzhiyun #define CMD_MONITOR "MONITOR"
85*4882a593Smuzhiyun #ifdef BTC_WAR
86*4882a593Smuzhiyun #define CMD_BTC_WAR "BTC_WAR"
87*4882a593Smuzhiyun #endif /* BTC_WAR */
88*4882a593Smuzhiyun #define CMD_SET_SUSPEND_BCN_LI_DTIM "SET_SUSPEND_BCN_LI_DTIM"
89*4882a593Smuzhiyun #define CMD_WLMSGLEVEL "WLMSGLEVEL"
90*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
91*4882a593Smuzhiyun #define CMD_IAPSTA_INIT "IAPSTA_INIT"
92*4882a593Smuzhiyun #define CMD_IAPSTA_CONFIG "IAPSTA_CONFIG"
93*4882a593Smuzhiyun #define CMD_IAPSTA_ENABLE "IAPSTA_ENABLE"
94*4882a593Smuzhiyun #define CMD_IAPSTA_DISABLE "IAPSTA_DISABLE"
95*4882a593Smuzhiyun #define CMD_ISAM_INIT "ISAM_INIT"
96*4882a593Smuzhiyun #define CMD_ISAM_CONFIG "ISAM_CONFIG"
97*4882a593Smuzhiyun #define CMD_ISAM_ENABLE "ISAM_ENABLE"
98*4882a593Smuzhiyun #define CMD_ISAM_DISABLE "ISAM_DISABLE"
99*4882a593Smuzhiyun #define CMD_ISAM_STATUS "ISAM_STATUS"
100*4882a593Smuzhiyun #define CMD_ISAM_PEER_PATH "ISAM_PEER_PATH"
101*4882a593Smuzhiyun #define CMD_ISAM_PARAM "ISAM_PARAM"
102*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
103*4882a593Smuzhiyun #define CMD_AUTOCHANNEL "AUTOCHANNEL"
104*4882a593Smuzhiyun #define CMD_WL "WL"
105*4882a593Smuzhiyun #define CMD_CONF "CONF"
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun #if defined(PKT_STATICS) && defined(BCMSDIO)
108*4882a593Smuzhiyun #define CMD_DUMP_PKT_STATICS "DUMP_PKT_STATICS"
109*4882a593Smuzhiyun #define CMD_CLEAR_PKT_STATICS "CLEAR_PKT_STATICS"
110*4882a593Smuzhiyun extern void dhd_bus_dump_txpktstatics(dhd_pub_t *dhdp);
111*4882a593Smuzhiyun extern void dhd_bus_clear_txpktstatics(dhd_pub_t *dhdp);
112*4882a593Smuzhiyun #endif /* PKT_STATICS && BCMSDIO */
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun #ifdef IDHCP
115*4882a593Smuzhiyun typedef struct dhcpc_parameter {
116*4882a593Smuzhiyun uint32 ip_addr;
117*4882a593Smuzhiyun uint32 ip_serv;
118*4882a593Smuzhiyun uint32 lease_time;
119*4882a593Smuzhiyun } dhcpc_para_t;
120*4882a593Smuzhiyun #endif /* IDHCP */
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun #ifdef WL_EXT_WOWL
123*4882a593Smuzhiyun #define WL_WOWL_TCPFIN (1 << 26)
124*4882a593Smuzhiyun typedef struct wl_wowl_pattern2 {
125*4882a593Smuzhiyun char cmd[4];
126*4882a593Smuzhiyun wl_wowl_pattern_t wowl_pattern;
127*4882a593Smuzhiyun } wl_wowl_pattern2_t;
128*4882a593Smuzhiyun #endif /* WL_EXT_WOWL */
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun #ifdef WL_EXT_TCPKA
131*4882a593Smuzhiyun typedef struct tcpka_conn {
132*4882a593Smuzhiyun uint32 sess_id;
133*4882a593Smuzhiyun struct ether_addr dst_mac; /* Destinition Mac */
134*4882a593Smuzhiyun struct ipv4_addr src_ip; /* Sorce IP */
135*4882a593Smuzhiyun struct ipv4_addr dst_ip; /* Destinition IP */
136*4882a593Smuzhiyun uint16 ipid; /* Ip Identification */
137*4882a593Smuzhiyun uint16 srcport; /* Source Port Address */
138*4882a593Smuzhiyun uint16 dstport; /* Destination Port Address */
139*4882a593Smuzhiyun uint32 seq; /* TCP Sequence Number */
140*4882a593Smuzhiyun uint32 ack; /* TCP Ack Number */
141*4882a593Smuzhiyun uint16 tcpwin; /* TCP window */
142*4882a593Smuzhiyun uint32 tsval; /* Timestamp Value */
143*4882a593Smuzhiyun uint32 tsecr; /* Timestamp Echo Reply */
144*4882a593Smuzhiyun uint32 len; /* last packet payload len */
145*4882a593Smuzhiyun uint32 ka_payload_len; /* keep alive payload length */
146*4882a593Smuzhiyun uint8 ka_payload[1]; /* keep alive payload */
147*4882a593Smuzhiyun } tcpka_conn_t;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun typedef struct tcpka_conn_sess {
150*4882a593Smuzhiyun uint32 sess_id; /* session id */
151*4882a593Smuzhiyun uint32 flag; /* enable/disable flag */
152*4882a593Smuzhiyun wl_mtcpkeep_alive_timers_pkt_t tcpka_timers;
153*4882a593Smuzhiyun } tcpka_conn_sess_t;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun typedef struct tcpka_conn_info {
156*4882a593Smuzhiyun uint32 ipid;
157*4882a593Smuzhiyun uint32 seq;
158*4882a593Smuzhiyun uint32 ack;
159*4882a593Smuzhiyun } tcpka_conn_sess_info_t;
160*4882a593Smuzhiyun #endif /* WL_EXT_TCPKA */
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun typedef struct auth_name_map_t {
163*4882a593Smuzhiyun uint auth;
164*4882a593Smuzhiyun uint wpa_auth;
165*4882a593Smuzhiyun char *auth_name;
166*4882a593Smuzhiyun } auth_name_map_t;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun const auth_name_map_t auth_name_map[] = {
169*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA_AUTH_DISABLED, "open"},
170*4882a593Smuzhiyun {WL_AUTH_SHARED_KEY, WPA_AUTH_DISABLED, "shared"},
171*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA_AUTH_PSK, "wpa/psk"},
172*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA2_AUTH_PSK, "wpa2/psk"},
173*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa2/psk/sha256"},
174*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA2_AUTH_FT|WPA2_AUTH_PSK, "wpa2/psk/ft"},
175*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA2_AUTH_UNSPECIFIED, "wpa2/eap"},
176*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA2_AUTH_FT|WPA2_AUTH_UNSPECIFIED, "wpa2/eap/ft"},
177*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_SAE_PSK, "wpa3/psk"},
178*4882a593Smuzhiyun {WL_AUTH_SAE_KEY, WPA3_AUTH_SAE_PSK, "wpa3sae/psk"},
179*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_SAE_PSK|WPA2_AUTH_PSK, "wpa3/psk"},
180*4882a593Smuzhiyun {WL_AUTH_SAE_KEY, WPA3_AUTH_SAE_PSK|WPA2_AUTH_PSK, "wpa3sae/psk"},
181*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, 0x20, "wpa3/psk"},
182*4882a593Smuzhiyun {WL_AUTH_SAE_KEY, 0x20, "wpa3sae/psk"},
183*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_SAE_PSK|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3/psk/sha256"},
184*4882a593Smuzhiyun {WL_AUTH_SAE_KEY, WPA3_AUTH_SAE_PSK|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3sae/psk/sha256"},
185*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, 0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3/psk/sha256"},
186*4882a593Smuzhiyun {WL_AUTH_SAE_KEY, 0x20|WPA2_AUTH_PSK_SHA256|WPA2_AUTH_PSK, "wpa3sae/psk/sha256"},
187*4882a593Smuzhiyun {WL_AUTH_OPEN_SYSTEM, WPA3_AUTH_OWE, "owe"},
188*4882a593Smuzhiyun };
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun typedef struct wsec_name_map_t {
191*4882a593Smuzhiyun uint wsec;
192*4882a593Smuzhiyun char *wsec_name;
193*4882a593Smuzhiyun } wsec_name_map_t;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun const wsec_name_map_t wsec_name_map[] = {
196*4882a593Smuzhiyun {WSEC_NONE, "none"},
197*4882a593Smuzhiyun {WEP_ENABLED, "wep"},
198*4882a593Smuzhiyun {TKIP_ENABLED, "tkip"},
199*4882a593Smuzhiyun {AES_ENABLED, "aes"},
200*4882a593Smuzhiyun {TKIP_ENABLED|AES_ENABLED, "tkip/aes"},
201*4882a593Smuzhiyun };
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun static int wl_ext_wl_iovar(struct net_device *dev, char *command, int total_len);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun int
wl_ext_ioctl(struct net_device * dev,u32 cmd,void * arg,u32 len,u32 set)206*4882a593Smuzhiyun wl_ext_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun int ret;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun ret = wldev_ioctl(dev, cmd, arg, len, set);
211*4882a593Smuzhiyun if (ret)
212*4882a593Smuzhiyun AEXT_ERROR(dev->name, "cmd=%d, ret=%d\n", cmd, ret);
213*4882a593Smuzhiyun return ret;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun int
wl_ext_iovar_getint(struct net_device * dev,s8 * iovar,s32 * val)217*4882a593Smuzhiyun wl_ext_iovar_getint(struct net_device *dev, s8 *iovar, s32 *val)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun int ret;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun ret = wldev_iovar_getint(dev, iovar, val);
222*4882a593Smuzhiyun if (ret)
223*4882a593Smuzhiyun AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar, ret);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun return ret;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun int
wl_ext_iovar_setint(struct net_device * dev,s8 * iovar,s32 val)229*4882a593Smuzhiyun wl_ext_iovar_setint(struct net_device *dev, s8 *iovar, s32 val)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun int ret;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun ret = wldev_iovar_setint(dev, iovar, val);
234*4882a593Smuzhiyun if (ret)
235*4882a593Smuzhiyun AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar, ret);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return ret;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun int
wl_ext_iovar_getbuf(struct net_device * dev,s8 * iovar_name,void * param,s32 paramlen,void * buf,s32 buflen,struct mutex * buf_sync)241*4882a593Smuzhiyun wl_ext_iovar_getbuf(struct net_device *dev, s8 *iovar_name,
242*4882a593Smuzhiyun void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun int ret;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun ret = wldev_iovar_getbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
247*4882a593Smuzhiyun if (ret != 0)
248*4882a593Smuzhiyun AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar_name, ret);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun return ret;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun int
wl_ext_iovar_setbuf(struct net_device * dev,s8 * iovar_name,void * param,s32 paramlen,void * buf,s32 buflen,struct mutex * buf_sync)254*4882a593Smuzhiyun wl_ext_iovar_setbuf(struct net_device *dev, s8 *iovar_name,
255*4882a593Smuzhiyun void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun int ret;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ret = wldev_iovar_setbuf(dev, iovar_name, param, paramlen, buf, buflen, buf_sync);
260*4882a593Smuzhiyun if (ret != 0)
261*4882a593Smuzhiyun AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar_name, ret);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun return ret;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun 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)267*4882a593Smuzhiyun wl_ext_iovar_setbuf_bsscfg(struct net_device *dev, s8 *iovar_name,
268*4882a593Smuzhiyun void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx,
269*4882a593Smuzhiyun struct mutex* buf_sync)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun int ret;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun ret = wldev_iovar_setbuf_bsscfg(dev, iovar_name, param, paramlen,
274*4882a593Smuzhiyun buf, buflen, bsscfg_idx, buf_sync);
275*4882a593Smuzhiyun if (ret < 0)
276*4882a593Smuzhiyun AEXT_ERROR(dev->name, "iovar=%s, ret=%d\n", iovar_name, ret);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return ret;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun static chanspec_t
wl_ext_chspec_to_legacy(chanspec_t chspec)282*4882a593Smuzhiyun wl_ext_chspec_to_legacy(chanspec_t chspec)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun chanspec_t lchspec;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (wf_chspec_malformed(chspec)) {
287*4882a593Smuzhiyun AEXT_ERROR("wlan", "input chanspec (0x%04X) malformed\n", chspec);
288*4882a593Smuzhiyun return INVCHANSPEC;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* get the channel number */
292*4882a593Smuzhiyun lchspec = CHSPEC_CHANNEL(chspec);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /* convert the band */
295*4882a593Smuzhiyun if (CHSPEC_IS2G(chspec)) {
296*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_BAND_2G;
297*4882a593Smuzhiyun } else {
298*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_BAND_5G;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* convert the bw and sideband */
302*4882a593Smuzhiyun if (CHSPEC_IS20(chspec)) {
303*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_BW_20;
304*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
305*4882a593Smuzhiyun } else if (CHSPEC_IS40(chspec)) {
306*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_BW_40;
307*4882a593Smuzhiyun if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
308*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
309*4882a593Smuzhiyun } else {
310*4882a593Smuzhiyun lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun } else {
313*4882a593Smuzhiyun /* cannot express the bandwidth */
314*4882a593Smuzhiyun char chanbuf[CHANSPEC_STR_LEN];
315*4882a593Smuzhiyun AEXT_ERROR("wlan", "unable to convert chanspec %s (0x%04X) "
316*4882a593Smuzhiyun "to pre-11ac format\n",
317*4882a593Smuzhiyun wf_chspec_ntoa(chspec, chanbuf), chspec);
318*4882a593Smuzhiyun return INVCHANSPEC;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun return lchspec;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun chanspec_t
wl_ext_chspec_host_to_driver(struct dhd_pub * dhd,chanspec_t chanspec)325*4882a593Smuzhiyun wl_ext_chspec_host_to_driver(struct dhd_pub *dhd, chanspec_t chanspec)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun if (dhd->conf->ioctl_ver == 1) {
328*4882a593Smuzhiyun chanspec = wl_ext_chspec_to_legacy(chanspec);
329*4882a593Smuzhiyun if (chanspec == INVCHANSPEC) {
330*4882a593Smuzhiyun return chanspec;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun chanspec = htodchanspec(chanspec);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun return chanspec;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun static void
wl_ext_ch_to_chanspec(struct dhd_pub * dhd,int ch,struct wl_join_params * join_params,size_t * join_params_size)339*4882a593Smuzhiyun wl_ext_ch_to_chanspec(struct dhd_pub *dhd, int ch,
340*4882a593Smuzhiyun struct wl_join_params *join_params, size_t *join_params_size)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun chanspec_t chanspec = 0;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (ch != 0) {
345*4882a593Smuzhiyun join_params->params.chanspec_num = 1;
346*4882a593Smuzhiyun join_params->params.chanspec_list[0] = ch;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
349*4882a593Smuzhiyun chanspec |= WL_CHANSPEC_BAND_2G;
350*4882a593Smuzhiyun else
351*4882a593Smuzhiyun chanspec |= WL_CHANSPEC_BAND_5G;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun chanspec |= WL_CHANSPEC_BW_20;
354*4882a593Smuzhiyun chanspec |= WL_CHANSPEC_CTL_SB_NONE;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
357*4882a593Smuzhiyun join_params->params.chanspec_num * sizeof(chanspec_t);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
360*4882a593Smuzhiyun join_params->params.chanspec_list[0] |= chanspec;
361*4882a593Smuzhiyun join_params->params.chanspec_list[0] =
362*4882a593Smuzhiyun wl_ext_chspec_host_to_driver(dhd,
363*4882a593Smuzhiyun join_params->params.chanspec_list[0]);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun join_params->params.chanspec_num =
366*4882a593Smuzhiyun htod32(join_params->params.chanspec_num);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun #if defined(WL_EXT_IAPSTA) || defined(WL_CFG80211) || defined(WL_ESCAN)
371*4882a593Smuzhiyun static chanspec_t
wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)372*4882a593Smuzhiyun wl_ext_chspec_from_legacy(chanspec_t legacy_chspec)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun chanspec_t chspec;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* get the channel number */
377*4882a593Smuzhiyun chspec = LCHSPEC_CHANNEL(legacy_chspec);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* convert the band */
380*4882a593Smuzhiyun if (LCHSPEC_IS2G(legacy_chspec)) {
381*4882a593Smuzhiyun chspec |= WL_CHANSPEC_BAND_2G;
382*4882a593Smuzhiyun } else {
383*4882a593Smuzhiyun chspec |= WL_CHANSPEC_BAND_5G;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* convert the bw and sideband */
387*4882a593Smuzhiyun if (LCHSPEC_IS20(legacy_chspec)) {
388*4882a593Smuzhiyun chspec |= WL_CHANSPEC_BW_20;
389*4882a593Smuzhiyun } else {
390*4882a593Smuzhiyun chspec |= WL_CHANSPEC_BW_40;
391*4882a593Smuzhiyun if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
392*4882a593Smuzhiyun chspec |= WL_CHANSPEC_CTL_SB_L;
393*4882a593Smuzhiyun } else {
394*4882a593Smuzhiyun chspec |= WL_CHANSPEC_CTL_SB_U;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (wf_chspec_malformed(chspec)) {
399*4882a593Smuzhiyun AEXT_ERROR("wlan", "output chanspec (0x%04X) malformed\n", chspec);
400*4882a593Smuzhiyun return INVCHANSPEC;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun return chspec;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun chanspec_t
wl_ext_chspec_driver_to_host(struct dhd_pub * dhd,chanspec_t chanspec)407*4882a593Smuzhiyun wl_ext_chspec_driver_to_host(struct dhd_pub *dhd, chanspec_t chanspec)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun chanspec = dtohchanspec(chanspec);
410*4882a593Smuzhiyun if (dhd->conf->ioctl_ver == 1) {
411*4882a593Smuzhiyun chanspec = wl_ext_chspec_from_legacy(chanspec);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return chanspec;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA || WL_CFG80211 || WL_ESCAN */
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun chanspec_band_t
wl_ext_wlcband_to_chanspec_band(int band)419*4882a593Smuzhiyun wl_ext_wlcband_to_chanspec_band(int band)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun chanspec_band_t chanspec_band = INVCHANSPEC;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun switch (band) {
424*4882a593Smuzhiyun #ifdef WL_6G_BAND
425*4882a593Smuzhiyun case WLC_BAND_6G:
426*4882a593Smuzhiyun chanspec_band = WL_CHANSPEC_BAND_6G;
427*4882a593Smuzhiyun break;
428*4882a593Smuzhiyun #endif /* WL_6G_BAND */
429*4882a593Smuzhiyun case WLC_BAND_5G:
430*4882a593Smuzhiyun chanspec_band = WL_CHANSPEC_BAND_5G;
431*4882a593Smuzhiyun break;
432*4882a593Smuzhiyun case WLC_BAND_2G:
433*4882a593Smuzhiyun chanspec_band = WL_CHANSPEC_BAND_2G;
434*4882a593Smuzhiyun break;
435*4882a593Smuzhiyun default:
436*4882a593Smuzhiyun AEXT_ERROR("wlan", "Invalid Frequency Band\n");
437*4882a593Smuzhiyun break;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun return chanspec_band;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun bool
wl_ext_check_scan(struct net_device * dev,dhd_pub_t * dhdp)443*4882a593Smuzhiyun wl_ext_check_scan(struct net_device *dev, dhd_pub_t *dhdp)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun #ifdef WL_CFG80211
446*4882a593Smuzhiyun struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
447*4882a593Smuzhiyun #endif /* WL_CFG80211 */
448*4882a593Smuzhiyun #ifdef WL_ESCAN
449*4882a593Smuzhiyun struct wl_escan_info *escan = dhdp->escan;
450*4882a593Smuzhiyun #endif /* WL_ESCAN */
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun #ifdef WL_CFG80211
453*4882a593Smuzhiyun if (wl_get_drv_status_all(cfg, SCANNING)) {
454*4882a593Smuzhiyun AEXT_ERROR(dev->name, "cfg80211 scanning...\n");
455*4882a593Smuzhiyun return TRUE;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun #endif /* WL_CFG80211 */
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun #ifdef WL_ESCAN
460*4882a593Smuzhiyun if (escan->escan_state == ESCAN_STATE_SCANING) {
461*4882a593Smuzhiyun AEXT_ERROR(dev->name, "escan scanning...\n");
462*4882a593Smuzhiyun return TRUE;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun #endif /* WL_ESCAN */
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun return FALSE;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun #if defined(WL_CFG80211) || defined(WL_ESCAN)
470*4882a593Smuzhiyun void
wl_ext_user_sync(struct dhd_pub * dhd,int ifidx,bool lock)471*4882a593Smuzhiyun wl_ext_user_sync(struct dhd_pub *dhd, int ifidx, bool lock)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun struct net_device *dev = dhd_idx2net(dhd, ifidx);
474*4882a593Smuzhiyun #ifdef WL_CFG80211
475*4882a593Smuzhiyun struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
476*4882a593Smuzhiyun #endif /* WL_CFG80211 */
477*4882a593Smuzhiyun #ifdef WL_ESCAN
478*4882a593Smuzhiyun struct wl_escan_info *escan = dhd->escan;
479*4882a593Smuzhiyun #endif /* WL_ESCAN */
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun AEXT_INFO(dev->name, "lock=%d\n", lock);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun if (lock) {
484*4882a593Smuzhiyun #if defined(WL_CFG80211)
485*4882a593Smuzhiyun mutex_lock(&cfg->usr_sync);
486*4882a593Smuzhiyun #endif
487*4882a593Smuzhiyun #if defined(WL_ESCAN)
488*4882a593Smuzhiyun mutex_lock(&escan->usr_sync);
489*4882a593Smuzhiyun #endif
490*4882a593Smuzhiyun } else {
491*4882a593Smuzhiyun #if defined(WL_CFG80211)
492*4882a593Smuzhiyun mutex_unlock(&cfg->usr_sync);
493*4882a593Smuzhiyun #endif
494*4882a593Smuzhiyun #if defined(WL_ESCAN)
495*4882a593Smuzhiyun mutex_unlock(&escan->usr_sync);
496*4882a593Smuzhiyun #endif
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun #endif /* WL_CFG80211 && WL_ESCAN */
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun static bool
wl_ext_event_complete(struct dhd_pub * dhd,int ifidx)502*4882a593Smuzhiyun wl_ext_event_complete(struct dhd_pub *dhd, int ifidx)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun struct net_device *dev = dhd_idx2net(dhd, ifidx);
505*4882a593Smuzhiyun #ifdef WL_CFG80211
506*4882a593Smuzhiyun struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
507*4882a593Smuzhiyun #endif /* WL_CFG80211 */
508*4882a593Smuzhiyun #ifdef WL_ESCAN
509*4882a593Smuzhiyun struct wl_escan_info *escan = dhd->escan;
510*4882a593Smuzhiyun #endif /* WL_ESCAN */
511*4882a593Smuzhiyun bool complete = TRUE;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun #ifdef WL_CFG80211
514*4882a593Smuzhiyun if (wl_get_drv_status_all(cfg, SCANNING)) {
515*4882a593Smuzhiyun AEXT_INFO(dev->name, "SCANNING\n");
516*4882a593Smuzhiyun complete = FALSE;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun if (wl_get_drv_status_all(cfg, CONNECTING)) {
519*4882a593Smuzhiyun AEXT_INFO(dev->name, "CFG80211 CONNECTING\n");
520*4882a593Smuzhiyun complete = FALSE;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun if (wl_get_drv_status_all(cfg, DISCONNECTING)) {
523*4882a593Smuzhiyun AEXT_INFO(dev->name, "DISCONNECTING\n");
524*4882a593Smuzhiyun complete = FALSE;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun #endif /* WL_CFG80211 */
527*4882a593Smuzhiyun #ifdef WL_ESCAN
528*4882a593Smuzhiyun if (escan->escan_state == ESCAN_STATE_SCANING) {
529*4882a593Smuzhiyun AEXT_INFO(dev->name, "ESCAN_STATE_SCANING\n");
530*4882a593Smuzhiyun complete = FALSE;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun #endif /* WL_ESCAN */
533*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
534*4882a593Smuzhiyun if (wl_ext_sta_connecting(dev)) {
535*4882a593Smuzhiyun AEXT_INFO(dev->name, "CONNECTING\n");
536*4882a593Smuzhiyun complete = FALSE;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun return complete;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun void
wl_ext_wait_event_complete(struct dhd_pub * dhd,int ifidx)544*4882a593Smuzhiyun wl_ext_wait_event_complete(struct dhd_pub *dhd, int ifidx)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun struct net_device *net;
547*4882a593Smuzhiyun s32 timeout = -1;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun timeout = wait_event_interruptible_timeout(dhd->conf->event_complete,
550*4882a593Smuzhiyun wl_ext_event_complete(dhd, ifidx), msecs_to_jiffies(10000));
551*4882a593Smuzhiyun if (timeout <= 0 || !wl_ext_event_complete(dhd, ifidx)) {
552*4882a593Smuzhiyun wl_ext_event_complete(dhd, ifidx);
553*4882a593Smuzhiyun net = dhd_idx2net(dhd, ifidx);
554*4882a593Smuzhiyun AEXT_ERROR(net->name, "timeout\n");
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun void
wl_ext_bss_iovar_war(struct net_device * ndev,s32 * val)559*4882a593Smuzhiyun wl_ext_bss_iovar_war(struct net_device *ndev, s32 *val)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun dhd_pub_t *dhd = dhd_get_pub(ndev);
562*4882a593Smuzhiyun uint chip;
563*4882a593Smuzhiyun bool need_war = false;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun chip = dhd_conf_get_chip(dhd);
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun if (chip == BCM43362_CHIP_ID || chip == BCM4330_CHIP_ID ||
568*4882a593Smuzhiyun chip == BCM4354_CHIP_ID || chip == BCM4356_CHIP_ID ||
569*4882a593Smuzhiyun chip == BCM4371_CHIP_ID ||
570*4882a593Smuzhiyun chip == BCM43430_CHIP_ID ||
571*4882a593Smuzhiyun chip == BCM4345_CHIP_ID || chip == BCM43454_CHIP_ID ||
572*4882a593Smuzhiyun chip == BCM4359_CHIP_ID ||
573*4882a593Smuzhiyun chip == BCM43143_CHIP_ID || chip == BCM43242_CHIP_ID ||
574*4882a593Smuzhiyun chip == BCM43569_CHIP_ID) {
575*4882a593Smuzhiyun need_war = true;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun if (need_war) {
579*4882a593Smuzhiyun /* Few firmware branches have issues in bss iovar handling and
580*4882a593Smuzhiyun * that can't be changed since they are in production.
581*4882a593Smuzhiyun */
582*4882a593Smuzhiyun if (*val == WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE) {
583*4882a593Smuzhiyun *val = WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE;
584*4882a593Smuzhiyun } else if (*val == WLC_AP_IOV_OP_MANUAL_STA_BSSCFG_CREATE) {
585*4882a593Smuzhiyun *val = WLC_AP_IOV_OP_MANUAL_AP_BSSCFG_CREATE;
586*4882a593Smuzhiyun } else {
587*4882a593Smuzhiyun /* Ignore for other bss enums */
588*4882a593Smuzhiyun return;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun AEXT_TRACE(ndev->name, "wl bss %d\n", *val);
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun int
wl_ext_set_chanspec(struct net_device * dev,struct wl_chan_info * chan_info,chanspec_t * ret_chspec)595*4882a593Smuzhiyun wl_ext_set_chanspec(struct net_device *dev, struct wl_chan_info *chan_info,
596*4882a593Smuzhiyun chanspec_t *ret_chspec)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
599*4882a593Smuzhiyun s32 _chan = chan_info->chan;
600*4882a593Smuzhiyun chanspec_t chspec = 0;
601*4882a593Smuzhiyun chanspec_t fw_chspec = 0;
602*4882a593Smuzhiyun u32 bw = WL_CHANSPEC_BW_20;
603*4882a593Smuzhiyun s32 err = BCME_OK;
604*4882a593Smuzhiyun s32 bw_cap = 0;
605*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
606*4882a593Smuzhiyun struct {
607*4882a593Smuzhiyun u32 band;
608*4882a593Smuzhiyun u32 bw_cap;
609*4882a593Smuzhiyun } param = {0, 0};
610*4882a593Smuzhiyun chanspec_band_t chanspec_band = 0;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun if ((chan_info->band != WLC_BAND_2G) && (chan_info->band != WLC_BAND_5G) &&
613*4882a593Smuzhiyun (chan_info->band != WLC_BAND_6G)) {
614*4882a593Smuzhiyun AEXT_ERROR(dev->name, "bad band %d\n", chan_info->band);
615*4882a593Smuzhiyun return BCME_BADBAND;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun param.band = chan_info->band;
619*4882a593Smuzhiyun err = wldev_iovar_getbuf(dev, "bw_cap", ¶m, sizeof(param),
620*4882a593Smuzhiyun iovar_buf, WLC_IOCTL_SMLEN, NULL);
621*4882a593Smuzhiyun if (err) {
622*4882a593Smuzhiyun if (err != BCME_UNSUPPORTED) {
623*4882a593Smuzhiyun AEXT_TRACE(dev->name, "bw_cap failed, %d\n", err);
624*4882a593Smuzhiyun return err;
625*4882a593Smuzhiyun } else {
626*4882a593Smuzhiyun err = wl_ext_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
627*4882a593Smuzhiyun if (bw_cap != WLC_N_BW_20ALL)
628*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_40;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun } else {
631*4882a593Smuzhiyun if (WL_BW_CAP_80MHZ(iovar_buf[0]))
632*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_80;
633*4882a593Smuzhiyun else if (WL_BW_CAP_40MHZ(iovar_buf[0]))
634*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_40;
635*4882a593Smuzhiyun else
636*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_20;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun set_channel:
640*4882a593Smuzhiyun chanspec_band = wl_ext_wlcband_to_chanspec_band(chan_info->band);
641*4882a593Smuzhiyun chspec = wf_create_chspec_from_primary(chan_info->chan, bw, chanspec_band);
642*4882a593Smuzhiyun if (wf_chspec_valid(chspec)) {
643*4882a593Smuzhiyun fw_chspec = wl_ext_chspec_host_to_driver(dhd, chspec);
644*4882a593Smuzhiyun if (fw_chspec != INVCHANSPEC) {
645*4882a593Smuzhiyun if ((err = wl_ext_iovar_setint(dev, "chanspec", fw_chspec)) == BCME_BADCHAN) {
646*4882a593Smuzhiyun if (bw == WL_CHANSPEC_BW_80)
647*4882a593Smuzhiyun goto change_bw;
648*4882a593Smuzhiyun err = wl_ext_ioctl(dev, WLC_SET_CHANNEL, &_chan, sizeof(_chan), 1);
649*4882a593Smuzhiyun WL_MSG(dev->name, "channel %s-%d\n", CHSPEC2BANDSTR(chspec), _chan);
650*4882a593Smuzhiyun } else if (err) {
651*4882a593Smuzhiyun AEXT_ERROR(dev->name, "failed to set chanspec error %d\n", err);
652*4882a593Smuzhiyun } else
653*4882a593Smuzhiyun WL_MSG(dev->name, "channel %s-%d(0x%x %sMHz)\n",
654*4882a593Smuzhiyun CHSPEC2BANDSTR(chspec), chan_info->chan, chspec,
655*4882a593Smuzhiyun CHSPEC_IS20(chspec)?"20":
656*4882a593Smuzhiyun CHSPEC_IS40(chspec)?"40":
657*4882a593Smuzhiyun CHSPEC_IS80(chspec)?"80":"160");
658*4882a593Smuzhiyun } else {
659*4882a593Smuzhiyun AEXT_ERROR(dev->name, "failed to convert host chanspec to fw chanspec\n");
660*4882a593Smuzhiyun err = BCME_ERROR;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun } else {
663*4882a593Smuzhiyun change_bw:
664*4882a593Smuzhiyun if (bw == WL_CHANSPEC_BW_80)
665*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_40;
666*4882a593Smuzhiyun else if (bw == WL_CHANSPEC_BW_40)
667*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_20;
668*4882a593Smuzhiyun else
669*4882a593Smuzhiyun bw = 0;
670*4882a593Smuzhiyun if (bw)
671*4882a593Smuzhiyun goto set_channel;
672*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Invalid chanspec 0x%x\n", chspec);
673*4882a593Smuzhiyun err = BCME_ERROR;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun *ret_chspec = fw_chspec;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun return err;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun static int
wl_ext_channel(struct net_device * dev,char * command,int total_len)681*4882a593Smuzhiyun wl_ext_channel(struct net_device *dev, char* command, int total_len)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun struct wl_chan_info chan_info;
684*4882a593Smuzhiyun int ret;
685*4882a593Smuzhiyun char band[16]="";
686*4882a593Smuzhiyun int channel = 0;
687*4882a593Smuzhiyun channel_info_t ci;
688*4882a593Smuzhiyun int bytes_written = 0;
689*4882a593Smuzhiyun chanspec_t fw_chspec;
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s", command);
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun sscanf(command, "%*s %d %s", &channel, band);
694*4882a593Smuzhiyun if (strnicmp(band, "band=auto", strlen("band=auto")) == 0) {
695*4882a593Smuzhiyun chan_info.band = WLC_BAND_AUTO;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun #ifdef WL_6G_BAND
698*4882a593Smuzhiyun else if (strnicmp(band, "band=6g", strlen("band=6g")) == 0) {
699*4882a593Smuzhiyun chan_info.band = WLC_BAND_6G;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun #endif /* WL_6G_BAND */
702*4882a593Smuzhiyun else if (strnicmp(band, "band=5g", strlen("band=5g")) == 0) {
703*4882a593Smuzhiyun chan_info.band = WLC_BAND_5G;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun else if (strnicmp(band, "band=2g", strlen("band=2g")) == 0) {
706*4882a593Smuzhiyun chan_info.band = WLC_BAND_2G;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun else if (channel <= CH_MAX_2G_CHANNEL)
709*4882a593Smuzhiyun chan_info.band = WLC_BAND_2G;
710*4882a593Smuzhiyun else
711*4882a593Smuzhiyun chan_info.band = WLC_BAND_5G;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun if (channel > 0) {
714*4882a593Smuzhiyun chan_info.chan = channel;
715*4882a593Smuzhiyun ret = wl_ext_set_chanspec(dev, &chan_info, &fw_chspec);
716*4882a593Smuzhiyun } else {
717*4882a593Smuzhiyun if (!(ret = wl_ext_ioctl(dev, WLC_GET_CHANNEL, &ci,
718*4882a593Smuzhiyun sizeof(channel_info_t), FALSE))) {
719*4882a593Smuzhiyun AEXT_TRACE(dev->name, "hw_channel %d\n", ci.hw_channel);
720*4882a593Smuzhiyun AEXT_TRACE(dev->name, "target_channel %d\n", ci.target_channel);
721*4882a593Smuzhiyun AEXT_TRACE(dev->name, "scan_channel %d\n", ci.scan_channel);
722*4882a593Smuzhiyun bytes_written = snprintf(command, sizeof(channel_info_t)+2,
723*4882a593Smuzhiyun "channel %d", ci.hw_channel);
724*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
725*4882a593Smuzhiyun ret = bytes_written;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun return ret;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun static int
wl_ext_channels(struct net_device * dev,char * command,int total_len)733*4882a593Smuzhiyun wl_ext_channels(struct net_device *dev, char* command, int total_len)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun int ret, i;
736*4882a593Smuzhiyun int bytes_written = -1;
737*4882a593Smuzhiyun u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
738*4882a593Smuzhiyun wl_uint32_list_t *list;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s", command);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun memset(valid_chan_list, 0, sizeof(valid_chan_list));
743*4882a593Smuzhiyun list = (wl_uint32_list_t *)(void *) valid_chan_list;
744*4882a593Smuzhiyun list->count = htod32(WL_NUMCHANNELS);
745*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
746*4882a593Smuzhiyun sizeof(valid_chan_list), 0);
747*4882a593Smuzhiyun if (ret<0) {
748*4882a593Smuzhiyun AEXT_ERROR(dev->name, "get channels failed with %d\n", ret);
749*4882a593Smuzhiyun } else {
750*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "channels");
751*4882a593Smuzhiyun for (i = 0; i < dtoh32(list->count); i++) {
752*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len, " %d",
753*4882a593Smuzhiyun dtoh32(list->element[i]));
754*4882a593Smuzhiyun }
755*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
756*4882a593Smuzhiyun ret = bytes_written;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun return ret;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun static int
wl_ext_roam_trigger(struct net_device * dev,char * command,int total_len)763*4882a593Smuzhiyun wl_ext_roam_trigger(struct net_device *dev, char* command, int total_len)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun int ret = 0;
766*4882a593Smuzhiyun int roam_trigger[2] = {0, 0};
767*4882a593Smuzhiyun int trigger[2]= {0, 0};
768*4882a593Smuzhiyun int bytes_written=-1;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun sscanf(command, "%*s %10d", &roam_trigger[0]);
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (roam_trigger[0]) {
773*4882a593Smuzhiyun roam_trigger[1] = WLC_BAND_ALL;
774*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
775*4882a593Smuzhiyun sizeof(roam_trigger), 1);
776*4882a593Smuzhiyun } else {
777*4882a593Smuzhiyun roam_trigger[1] = WLC_BAND_2G;
778*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger,
779*4882a593Smuzhiyun sizeof(roam_trigger), 0);
780*4882a593Smuzhiyun if (!ret)
781*4882a593Smuzhiyun trigger[0] = roam_trigger[0];
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun roam_trigger[1] = WLC_BAND_5G;
784*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_GET_ROAM_TRIGGER, &roam_trigger,
785*4882a593Smuzhiyun sizeof(roam_trigger), 0);
786*4882a593Smuzhiyun if (!ret)
787*4882a593Smuzhiyun trigger[1] = roam_trigger[0];
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun AEXT_TRACE(dev->name, "roam_trigger %d %d\n", trigger[0], trigger[1]);
790*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
791*4882a593Smuzhiyun ret = bytes_written;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun return ret;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun static int
wl_ext_pm(struct net_device * dev,char * command,int total_len)798*4882a593Smuzhiyun wl_ext_pm(struct net_device *dev, char *command, int total_len)
799*4882a593Smuzhiyun {
800*4882a593Smuzhiyun int pm=-1, ret = -1;
801*4882a593Smuzhiyun char *pm_local;
802*4882a593Smuzhiyun int bytes_written=-1;
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s", command);
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun sscanf(command, "%*s %d", &pm);
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun if (pm >= 0) {
809*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), 1);
810*4882a593Smuzhiyun } else {
811*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), 0);
812*4882a593Smuzhiyun if (!ret) {
813*4882a593Smuzhiyun AEXT_TRACE(dev->name, "PM = %d", pm);
814*4882a593Smuzhiyun if (pm == PM_OFF)
815*4882a593Smuzhiyun pm_local = "PM_OFF";
816*4882a593Smuzhiyun else if(pm == PM_MAX)
817*4882a593Smuzhiyun pm_local = "PM_MAX";
818*4882a593Smuzhiyun else if(pm == PM_FAST)
819*4882a593Smuzhiyun pm_local = "PM_FAST";
820*4882a593Smuzhiyun else {
821*4882a593Smuzhiyun pm = 0;
822*4882a593Smuzhiyun pm_local = "Invalid";
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "PM %s", pm_local);
825*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
826*4882a593Smuzhiyun ret = bytes_written;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun return ret;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun static int
wl_ext_monitor(struct net_device * dev,char * command,int total_len)834*4882a593Smuzhiyun wl_ext_monitor(struct net_device *dev, char *command, int total_len)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun int val = -1, ret = -1;
837*4882a593Smuzhiyun int bytes_written=-1;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun sscanf(command, "%*s %d", &val);
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun if (val >=0) {
842*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(val), 1);
843*4882a593Smuzhiyun } else {
844*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_GET_MONITOR, &val, sizeof(val), 0);
845*4882a593Smuzhiyun if (!ret) {
846*4882a593Smuzhiyun AEXT_TRACE(dev->name, "monitor = %d\n", val);
847*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "monitor %d", val);
848*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
849*4882a593Smuzhiyun ret = bytes_written;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun return ret;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun #ifdef BTC_WAR
857*4882a593Smuzhiyun extern int btc_war;
858*4882a593Smuzhiyun static int
wl_ext_btc_war(struct net_device * dev,char * command,int total_len)859*4882a593Smuzhiyun wl_ext_btc_war(struct net_device *dev, char *command, int total_len)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun int user_btc_war = 0;
862*4882a593Smuzhiyun bool enable = FALSE;
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun sscanf(command, "%*s %d", &user_btc_war);
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun AEXT_TRACE(dev->name, "btc_war=%d, user_btc_war=%d\n",
867*4882a593Smuzhiyun btc_war, user_btc_war);
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if (btc_war >= 0) {
870*4882a593Smuzhiyun btc_war = user_btc_war;
871*4882a593Smuzhiyun if (btc_war > 0)
872*4882a593Smuzhiyun enable = TRUE;
873*4882a593Smuzhiyun wl_ext_btc_config(dev, enable);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun return 0;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun #endif /* BTC_WAR */
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun s32
wl_ext_connect(struct net_device * dev,struct wl_conn_info * conn_info)881*4882a593Smuzhiyun wl_ext_connect(struct net_device *dev, struct wl_conn_info *conn_info)
882*4882a593Smuzhiyun {
883*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
884*4882a593Smuzhiyun wl_extjoin_params_t *ext_join_params = NULL;
885*4882a593Smuzhiyun struct wl_join_params join_params;
886*4882a593Smuzhiyun size_t join_params_size;
887*4882a593Smuzhiyun s32 err = 0;
888*4882a593Smuzhiyun u32 chan_cnt = 0;
889*4882a593Smuzhiyun s8 *iovar_buf = NULL;
890*4882a593Smuzhiyun char sec[64];
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun if (dhd->conf->chip == BCM43362_CHIP_ID)
893*4882a593Smuzhiyun goto set_ssid;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun if (conn_info->channel) {
896*4882a593Smuzhiyun chan_cnt = 1;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun iovar_buf = kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
900*4882a593Smuzhiyun if (iovar_buf == NULL) {
901*4882a593Smuzhiyun err = -ENOMEM;
902*4882a593Smuzhiyun goto exit;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun /*
906*4882a593Smuzhiyun * Join with specific BSSID and cached SSID
907*4882a593Smuzhiyun * If SSID is zero join based on BSSID only
908*4882a593Smuzhiyun */
909*4882a593Smuzhiyun join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
910*4882a593Smuzhiyun chan_cnt * sizeof(chanspec_t);
911*4882a593Smuzhiyun ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
912*4882a593Smuzhiyun if (ext_join_params == NULL) {
913*4882a593Smuzhiyun err = -ENOMEM;
914*4882a593Smuzhiyun goto exit;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun ext_join_params->ssid.SSID_len = min((uint32)sizeof(ext_join_params->ssid.SSID),
917*4882a593Smuzhiyun conn_info->ssid.SSID_len);
918*4882a593Smuzhiyun memcpy(&ext_join_params->ssid.SSID, conn_info->ssid.SSID, ext_join_params->ssid.SSID_len);
919*4882a593Smuzhiyun ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
920*4882a593Smuzhiyun /* increate dwell time to receive probe response or detect Beacon
921*4882a593Smuzhiyun * from target AP at a noisy air only during connect command
922*4882a593Smuzhiyun */
923*4882a593Smuzhiyun ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
924*4882a593Smuzhiyun ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
925*4882a593Smuzhiyun /* Set up join scan parameters */
926*4882a593Smuzhiyun ext_join_params->scan.scan_type = -1;
927*4882a593Smuzhiyun ext_join_params->scan.nprobes = chan_cnt ?
928*4882a593Smuzhiyun (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
929*4882a593Smuzhiyun ext_join_params->scan.home_time = -1;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun if (memcmp(ðer_null, &conn_info->bssid, ETHER_ADDR_LEN))
932*4882a593Smuzhiyun memcpy(&ext_join_params->assoc.bssid, &conn_info->bssid, ETH_ALEN);
933*4882a593Smuzhiyun else
934*4882a593Smuzhiyun memcpy(&ext_join_params->assoc.bssid, ðer_bcast, ETH_ALEN);
935*4882a593Smuzhiyun ext_join_params->assoc.chanspec_num = chan_cnt;
936*4882a593Smuzhiyun if (chan_cnt) {
937*4882a593Smuzhiyun u16 band, bw, ctl_sb;
938*4882a593Smuzhiyun chanspec_t chspec;
939*4882a593Smuzhiyun band = (conn_info->channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
940*4882a593Smuzhiyun : WL_CHANSPEC_BAND_5G;
941*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_20;
942*4882a593Smuzhiyun ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
943*4882a593Smuzhiyun chspec = (conn_info->channel | band | bw | ctl_sb);
944*4882a593Smuzhiyun ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
945*4882a593Smuzhiyun ext_join_params->assoc.chanspec_list[0] |= chspec;
946*4882a593Smuzhiyun ext_join_params->assoc.chanspec_list[0] =
947*4882a593Smuzhiyun wl_ext_chspec_host_to_driver(dhd,
948*4882a593Smuzhiyun ext_join_params->assoc.chanspec_list[0]);
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
953*4882a593Smuzhiyun WL_MSG(dev->name,
954*4882a593Smuzhiyun "Connecting with %pM channel (%d) ssid \"%s\", len (%d), sec=%s\n\n",
955*4882a593Smuzhiyun &ext_join_params->assoc.bssid, conn_info->channel,
956*4882a593Smuzhiyun ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, sec);
957*4882a593Smuzhiyun err = wl_ext_iovar_setbuf_bsscfg(dev, "join", ext_join_params,
958*4882a593Smuzhiyun join_params_size, iovar_buf, WLC_IOCTL_MAXLEN, conn_info->bssidx, NULL);
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun if (err) {
961*4882a593Smuzhiyun if (err == BCME_UNSUPPORTED) {
962*4882a593Smuzhiyun AEXT_TRACE(dev->name, "join iovar is not supported\n");
963*4882a593Smuzhiyun goto set_ssid;
964*4882a593Smuzhiyun } else {
965*4882a593Smuzhiyun AEXT_ERROR(dev->name, "error (%d)\n", err);
966*4882a593Smuzhiyun goto exit;
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun } else
969*4882a593Smuzhiyun goto exit;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun set_ssid:
972*4882a593Smuzhiyun memset(&join_params, 0, sizeof(join_params));
973*4882a593Smuzhiyun join_params_size = sizeof(join_params.ssid);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun join_params.ssid.SSID_len = min((uint32)sizeof(join_params.ssid.SSID),
976*4882a593Smuzhiyun conn_info->ssid.SSID_len);
977*4882a593Smuzhiyun memcpy(&join_params.ssid.SSID, conn_info->ssid.SSID, join_params.ssid.SSID_len);
978*4882a593Smuzhiyun join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
979*4882a593Smuzhiyun if (memcmp(ðer_null, &conn_info->bssid, ETHER_ADDR_LEN))
980*4882a593Smuzhiyun memcpy(&join_params.params.bssid, &conn_info->bssid, ETH_ALEN);
981*4882a593Smuzhiyun else
982*4882a593Smuzhiyun memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN);
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun wl_ext_ch_to_chanspec(dhd, conn_info->channel, &join_params, &join_params_size);
985*4882a593Smuzhiyun AEXT_TRACE(dev->name, "join_param_size %zu\n", join_params_size);
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
988*4882a593Smuzhiyun AEXT_INFO(dev->name, "ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
989*4882a593Smuzhiyun join_params.ssid.SSID_len);
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun wl_ext_get_sec(dev, 0, sec, sizeof(sec), TRUE);
992*4882a593Smuzhiyun WL_MSG(dev->name,
993*4882a593Smuzhiyun "Connecting with %pM channel (%d) ssid \"%s\", len (%d), sec=%s\n\n",
994*4882a593Smuzhiyun &join_params.params.bssid, conn_info->channel,
995*4882a593Smuzhiyun join_params.ssid.SSID, join_params.ssid.SSID_len, sec);
996*4882a593Smuzhiyun err = wl_ext_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, 1);
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun exit:
999*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
1000*4882a593Smuzhiyun if (!err)
1001*4882a593Smuzhiyun wl_ext_add_remove_pm_enable_work(dev, TRUE);
1002*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
1003*4882a593Smuzhiyun if (iovar_buf)
1004*4882a593Smuzhiyun kfree(iovar_buf);
1005*4882a593Smuzhiyun if (ext_join_params)
1006*4882a593Smuzhiyun kfree(ext_join_params);
1007*4882a593Smuzhiyun return err;
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun void
wl_ext_get_sec(struct net_device * dev,int ifmode,char * sec,int total_len,bool dump)1012*4882a593Smuzhiyun wl_ext_get_sec(struct net_device *dev, int ifmode, char *sec, int total_len, bool dump)
1013*4882a593Smuzhiyun {
1014*4882a593Smuzhiyun int auth=0, wpa_auth=0, wsec=0, mfp=0, i;
1015*4882a593Smuzhiyun int bytes_written=0;
1016*4882a593Smuzhiyun bool match = FALSE;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun memset(sec, 0, total_len);
1019*4882a593Smuzhiyun wl_ext_iovar_getint(dev, "auth", &auth);
1020*4882a593Smuzhiyun wl_ext_iovar_getint(dev, "wpa_auth", &wpa_auth);
1021*4882a593Smuzhiyun wl_ext_iovar_getint(dev, "wsec", &wsec);
1022*4882a593Smuzhiyun wldev_iovar_getint(dev, "mfp", &mfp);
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
1025*4882a593Smuzhiyun if (ifmode == IMESH_MODE) {
1026*4882a593Smuzhiyun if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA_AUTH_DISABLED) {
1027*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "open");
1028*4882a593Smuzhiyun } else if (auth == WL_AUTH_OPEN_SYSTEM && wpa_auth == WPA2_AUTH_PSK) {
1029*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "sae");
1030*4882a593Smuzhiyun } else {
1031*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "%d/0x%x",
1032*4882a593Smuzhiyun auth, wpa_auth);
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun } else
1035*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
1036*4882a593Smuzhiyun {
1037*4882a593Smuzhiyun match = FALSE;
1038*4882a593Smuzhiyun for (i=0; i<sizeof(auth_name_map)/sizeof(auth_name_map[0]); i++) {
1039*4882a593Smuzhiyun const auth_name_map_t* row = &auth_name_map[i];
1040*4882a593Smuzhiyun if (row->auth == auth && row->wpa_auth == wpa_auth) {
1041*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "%s",
1042*4882a593Smuzhiyun row->auth_name);
1043*4882a593Smuzhiyun match = TRUE;
1044*4882a593Smuzhiyun break;
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun if (!match) {
1048*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "%d/0x%x",
1049*4882a593Smuzhiyun auth, wpa_auth);
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun if (mfp == WL_MFP_NONE) {
1054*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/mfpn");
1055*4882a593Smuzhiyun } else if (mfp == WL_MFP_CAPABLE) {
1056*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/mfpc");
1057*4882a593Smuzhiyun } else if (mfp == WL_MFP_REQUIRED) {
1058*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/mfpr");
1059*4882a593Smuzhiyun } else {
1060*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/%d", mfp);
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
1064*4882a593Smuzhiyun if (ifmode == IMESH_MODE) {
1065*4882a593Smuzhiyun if (wsec == WSEC_NONE) {
1066*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/none");
1067*4882a593Smuzhiyun } else {
1068*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/aes");
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun } else
1071*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
1072*4882a593Smuzhiyun {
1073*4882a593Smuzhiyun match = FALSE;
1074*4882a593Smuzhiyun for (i=0; i<sizeof(wsec_name_map)/sizeof(wsec_name_map[0]); i++) {
1075*4882a593Smuzhiyun const wsec_name_map_t* row = &wsec_name_map[i];
1076*4882a593Smuzhiyun if (row->wsec == (wsec&0x7)) {
1077*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/%s",
1078*4882a593Smuzhiyun row->wsec_name);
1079*4882a593Smuzhiyun match = TRUE;
1080*4882a593Smuzhiyun break;
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun if (!match) {
1084*4882a593Smuzhiyun bytes_written += snprintf(sec+bytes_written, total_len, "/0x%x", wsec);
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun if (dump) {
1088*4882a593Smuzhiyun AEXT_INFO(dev->name, "auth/wpa_auth/mfp/wsec = %d/0x%x/%d/0x%x\n",
1089*4882a593Smuzhiyun auth, wpa_auth, mfp, wsec);
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun }
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun bool
wl_ext_dfs_chan(struct wl_chan_info * chan_info)1094*4882a593Smuzhiyun wl_ext_dfs_chan(struct wl_chan_info *chan_info)
1095*4882a593Smuzhiyun {
1096*4882a593Smuzhiyun if (chan_info->band == WLC_BAND_5G && chan_info->chan >= 52 && chan_info->chan <= 144)
1097*4882a593Smuzhiyun return TRUE;
1098*4882a593Smuzhiyun return FALSE;
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun bool
wl_ext_passive_chan(struct net_device * dev,struct wl_chan_info * chan_info)1102*4882a593Smuzhiyun wl_ext_passive_chan(struct net_device *dev, struct wl_chan_info *chan_info)
1103*4882a593Smuzhiyun {
1104*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1105*4882a593Smuzhiyun u32 chanspec;
1106*4882a593Smuzhiyun s32 ret = BCME_OK;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun chanspec = wf_create_chspec_from_primary(chan_info->chan,
1109*4882a593Smuzhiyun WL_CHANSPEC_BW_20, wl_ext_wlcband_to_chanspec_band(chan_info->band));
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun chanspec = wl_ext_chspec_host_to_driver(dhd, chanspec);
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun ret = wldev_iovar_getint(dev, "per_chan_info", &chanspec);
1114*4882a593Smuzhiyun if (!ret) {
1115*4882a593Smuzhiyun if (chanspec & WL_CHAN_PASSIVE)
1116*4882a593Smuzhiyun return TRUE;
1117*4882a593Smuzhiyun } else {
1118*4882a593Smuzhiyun if (chan_info->band == WLC_BAND_5G && chan_info->chan >= 52 && chan_info->chan <= 144)
1119*4882a593Smuzhiyun return TRUE;
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun return FALSE;
1123*4882a593Smuzhiyun }
1124*4882a593Smuzhiyun
1125*4882a593Smuzhiyun uint16
wl_ext_get_default_chan(struct net_device * dev,uint16 * chan_2g,uint16 * chan_5g,bool nodfs)1126*4882a593Smuzhiyun wl_ext_get_default_chan(struct net_device *dev,
1127*4882a593Smuzhiyun uint16 *chan_2g, uint16 *chan_5g, bool nodfs)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1130*4882a593Smuzhiyun struct wl_chan_info chan_info;
1131*4882a593Smuzhiyun uint16 chan_tmp = 0, chan = 0;
1132*4882a593Smuzhiyun wl_uint32_list_t *list;
1133*4882a593Smuzhiyun u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)];
1134*4882a593Smuzhiyun s32 ret = BCME_OK;
1135*4882a593Smuzhiyun int i;
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun *chan_2g = 0;
1138*4882a593Smuzhiyun *chan_5g = 0;
1139*4882a593Smuzhiyun memset(valid_chan_list, 0, sizeof(valid_chan_list));
1140*4882a593Smuzhiyun list = (wl_uint32_list_t *)(void *) valid_chan_list;
1141*4882a593Smuzhiyun list->count = htod32(WL_NUMCHANNELS);
1142*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_GET_VALID_CHANNELS, valid_chan_list,
1143*4882a593Smuzhiyun sizeof(valid_chan_list), 0);
1144*4882a593Smuzhiyun if (ret == 0) {
1145*4882a593Smuzhiyun for (i=0; i<dtoh32(list->count); i++) {
1146*4882a593Smuzhiyun chan_tmp = dtoh32(list->element[i]);
1147*4882a593Smuzhiyun if (!dhd_conf_match_channel(dhd, chan_tmp))
1148*4882a593Smuzhiyun continue;
1149*4882a593Smuzhiyun if (chan_tmp <= 13 && !*chan_2g) {
1150*4882a593Smuzhiyun *chan_2g = chan_tmp;
1151*4882a593Smuzhiyun } else if (chan_tmp >= 36 && chan_tmp <= 161 && !*chan_5g) {
1152*4882a593Smuzhiyun chan_info.band = WLC_BAND_5G;
1153*4882a593Smuzhiyun chan_info.chan = chan_tmp;
1154*4882a593Smuzhiyun if (wl_ext_dfs_chan(&chan_info) && nodfs)
1155*4882a593Smuzhiyun continue;
1156*4882a593Smuzhiyun else if (wl_ext_passive_chan(dev, &chan_info))
1157*4882a593Smuzhiyun continue;
1158*4882a593Smuzhiyun else
1159*4882a593Smuzhiyun *chan_5g = chan_tmp;
1160*4882a593Smuzhiyun }
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun return chan;
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun int
wl_ext_set_scan_time(struct net_device * dev,int scan_time,uint32 scan_get,uint32 scan_set)1168*4882a593Smuzhiyun wl_ext_set_scan_time(struct net_device *dev, int scan_time,
1169*4882a593Smuzhiyun uint32 scan_get, uint32 scan_set)
1170*4882a593Smuzhiyun {
1171*4882a593Smuzhiyun int ret, cur_scan_time;
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, scan_get, &cur_scan_time, sizeof(cur_scan_time), 0);
1174*4882a593Smuzhiyun if (ret)
1175*4882a593Smuzhiyun return 0;
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun if (scan_time != cur_scan_time)
1178*4882a593Smuzhiyun wl_ext_ioctl(dev, scan_set, &scan_time, sizeof(scan_time), 1);
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun return cur_scan_time;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun static int
wl_ext_wlmsglevel(struct net_device * dev,char * command,int total_len)1184*4882a593Smuzhiyun wl_ext_wlmsglevel(struct net_device *dev, char *command, int total_len)
1185*4882a593Smuzhiyun {
1186*4882a593Smuzhiyun int val = -1, ret = 0;
1187*4882a593Smuzhiyun int bytes_written = 0;
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun sscanf(command, "%*s %x", &val);
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun if (val >=0) {
1192*4882a593Smuzhiyun if (val & DHD_ANDROID_VAL) {
1193*4882a593Smuzhiyun android_msg_level = (uint)(val & 0xFFFF);
1194*4882a593Smuzhiyun WL_MSG(dev->name, "android_msg_level=0x%x\n", android_msg_level);
1195*4882a593Smuzhiyun }
1196*4882a593Smuzhiyun #if defined(WL_WIRELESS_EXT)
1197*4882a593Smuzhiyun else if (val & DHD_IW_VAL) {
1198*4882a593Smuzhiyun iw_msg_level = (uint)(val & 0xFFFF);
1199*4882a593Smuzhiyun WL_MSG(dev->name, "iw_msg_level=0x%x\n", iw_msg_level);
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun #endif
1202*4882a593Smuzhiyun #ifdef WL_CFG80211
1203*4882a593Smuzhiyun else if (val & DHD_CFG_VAL) {
1204*4882a593Smuzhiyun wl_cfg80211_enable_trace((u32)(val & 0xFFFF));
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun #endif
1207*4882a593Smuzhiyun else if (val & DHD_CONFIG_VAL) {
1208*4882a593Smuzhiyun config_msg_level = (uint)(val & 0xFFFF);
1209*4882a593Smuzhiyun WL_MSG(dev->name, "config_msg_level=0x%x\n", config_msg_level);
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun else if (val & DHD_DUMP_VAL) {
1212*4882a593Smuzhiyun dump_msg_level = (uint)(val & 0xFFFF);
1213*4882a593Smuzhiyun WL_MSG(dev->name, "dump_msg_level=0x%x\n", dump_msg_level);
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun }
1216*4882a593Smuzhiyun else {
1217*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1218*4882a593Smuzhiyun "android_msg_level=0x%x", android_msg_level);
1219*4882a593Smuzhiyun #if defined(WL_WIRELESS_EXT)
1220*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1221*4882a593Smuzhiyun "\niw_msg_level=0x%x", iw_msg_level);
1222*4882a593Smuzhiyun #endif
1223*4882a593Smuzhiyun #ifdef WL_CFG80211
1224*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1225*4882a593Smuzhiyun "\nwl_dbg_level=0x%x", wl_dbg_level);
1226*4882a593Smuzhiyun #endif
1227*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1228*4882a593Smuzhiyun "\nconfig_msg_level=0x%x", config_msg_level);
1229*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1230*4882a593Smuzhiyun "\ndump_msg_level=0x%x", dump_msg_level);
1231*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s\n", command);
1232*4882a593Smuzhiyun ret = bytes_written;
1233*4882a593Smuzhiyun }
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun return ret;
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun #ifdef WLEASYMESH
1239*4882a593Smuzhiyun #define CMD_EASYMESH "EASYMESH"
1240*4882a593Smuzhiyun //Set map 4 and dwds 1 on wlan0 interface
1241*4882a593Smuzhiyun #define EASYMESH_SLAVE "slave"
1242*4882a593Smuzhiyun #define EASYMESH_MASTER "master"
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun static int
wl_ext_easymesh(struct net_device * dev,char * command,int total_len)1245*4882a593Smuzhiyun wl_ext_easymesh(struct net_device *dev, char* command, int total_len)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun int ret = 0, wlc_down = 1, wlc_up = 1, map = 4, dwds = 1;
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command=%s, len=%d\n", command, total_len);
1250*4882a593Smuzhiyun if (strncmp(command, EASYMESH_SLAVE, strlen(EASYMESH_SLAVE)) == 0) {
1251*4882a593Smuzhiyun WL_MSG(dev->name, "try to set map %d, dwds %d\n", map, dwds);
1252*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down), 1);
1253*4882a593Smuzhiyun if (ret)
1254*4882a593Smuzhiyun goto exit;
1255*4882a593Smuzhiyun wl_ext_iovar_setint(dev, "map", map);
1256*4882a593Smuzhiyun wl_ext_iovar_setint(dev, "dwds", dwds);
1257*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_UP, &wlc_up, sizeof(wlc_up), 1);
1258*4882a593Smuzhiyun if (ret)
1259*4882a593Smuzhiyun goto exit;
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun else if (strncmp(command, EASYMESH_MASTER, strlen(EASYMESH_MASTER)) == 0) {
1262*4882a593Smuzhiyun map = dwds = 0;
1263*4882a593Smuzhiyun WL_MSG(dev->name, "try to set map %d, dwds %d\n", map, dwds);
1264*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_DOWN, &wlc_down, sizeof(wlc_down), 1);
1265*4882a593Smuzhiyun if (ret) {
1266*4882a593Smuzhiyun goto exit;
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun wl_ext_iovar_setint(dev, "map", map);
1269*4882a593Smuzhiyun wl_ext_iovar_setint(dev, "dwds", dwds);
1270*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_UP, &wlc_up, sizeof(wlc_up), 1);
1271*4882a593Smuzhiyun if (ret) {
1272*4882a593Smuzhiyun goto exit;
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun }
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun exit:
1277*4882a593Smuzhiyun return ret;
1278*4882a593Smuzhiyun }
1279*4882a593Smuzhiyun #endif /* WLEASYMESH */
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun int
wl_ext_add_del_ie(struct net_device * dev,uint pktflag,char * ie_data,const char * add_del_cmd)1282*4882a593Smuzhiyun wl_ext_add_del_ie(struct net_device *dev, uint pktflag, char *ie_data, const char* add_del_cmd)
1283*4882a593Smuzhiyun {
1284*4882a593Smuzhiyun vndr_ie_setbuf_t *vndr_ie = NULL;
1285*4882a593Smuzhiyun char iovar_buf[WLC_IOCTL_SMLEN]="\0";
1286*4882a593Smuzhiyun int ie_data_len = 0, tot_len = 0, iecount;
1287*4882a593Smuzhiyun int err = -1;
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun if (!strlen(ie_data)) {
1290*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong ie %s\n", ie_data);
1291*4882a593Smuzhiyun goto exit;
1292*4882a593Smuzhiyun }
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun tot_len = (int)(sizeof(vndr_ie_setbuf_t) + ((strlen(ie_data)-2)/2));
1295*4882a593Smuzhiyun vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, GFP_KERNEL);
1296*4882a593Smuzhiyun if (!vndr_ie) {
1297*4882a593Smuzhiyun AEXT_ERROR(dev->name, "IE memory alloc failed\n");
1298*4882a593Smuzhiyun err = -ENOMEM;
1299*4882a593Smuzhiyun goto exit;
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun
1302*4882a593Smuzhiyun /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1303*4882a593Smuzhiyun strncpy(vndr_ie->cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1);
1304*4882a593Smuzhiyun vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun /* Set the IE count - the buffer contains only 1 IE */
1307*4882a593Smuzhiyun iecount = htod32(1);
1308*4882a593Smuzhiyun memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun /* Set packet flag to indicate that BEACON's will contain this IE */
1311*4882a593Smuzhiyun pktflag = htod32(pktflag);
1312*4882a593Smuzhiyun memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
1313*4882a593Smuzhiyun sizeof(u32));
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun /* Set the IE ID */
1316*4882a593Smuzhiyun vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar)DOT11_MNG_VS_ID;
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun /* Set the IE LEN */
1319*4882a593Smuzhiyun vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (strlen(ie_data)-2)/2;
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun /* Set the IE OUI and DATA */
1322*4882a593Smuzhiyun ie_data_len = wl_pattern_atoh(ie_data,
1323*4882a593Smuzhiyun (char *)vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui);
1324*4882a593Smuzhiyun if (ie_data_len <= 0) {
1325*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong ie_data_len %d\n", (int)strlen(ie_data)-2);
1326*4882a593Smuzhiyun goto exit;
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun err = wl_ext_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, iovar_buf,
1330*4882a593Smuzhiyun sizeof(iovar_buf), NULL);
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun exit:
1333*4882a593Smuzhiyun if (vndr_ie) {
1334*4882a593Smuzhiyun kfree(vndr_ie);
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun return err;
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun #ifdef IDHCP
1340*4882a593Smuzhiyun /*
1341*4882a593Smuzhiyun terence 20190409:
1342*4882a593Smuzhiyun dhd_priv wl dhcpc_dump
1343*4882a593Smuzhiyun dhd_priv wl dhcpc_param <client ip> <server ip> <lease time>
1344*4882a593Smuzhiyun */
1345*4882a593Smuzhiyun static int
wl_ext_dhcpc_dump(struct net_device * dev,char * data,char * command,int total_len)1346*4882a593Smuzhiyun wl_ext_dhcpc_dump(struct net_device *dev, char *data, char *command,
1347*4882a593Smuzhiyun int total_len)
1348*4882a593Smuzhiyun {
1349*4882a593Smuzhiyun int ret = 0;
1350*4882a593Smuzhiyun int bytes_written = 0;
1351*4882a593Smuzhiyun uint32 ip_addr;
1352*4882a593Smuzhiyun char buf[20]="";
1353*4882a593Smuzhiyun
1354*4882a593Smuzhiyun if (!data) {
1355*4882a593Smuzhiyun ret = wl_ext_iovar_getint(dev, "dhcpc_ip_addr", &ip_addr);
1356*4882a593Smuzhiyun if (!ret) {
1357*4882a593Smuzhiyun bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
1358*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1359*4882a593Smuzhiyun "ipaddr %s ", buf);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun ret = wl_ext_iovar_getint(dev, "dhcpc_ip_mask", &ip_addr);
1363*4882a593Smuzhiyun if (!ret) {
1364*4882a593Smuzhiyun bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
1365*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1366*4882a593Smuzhiyun "mask %s ", buf);
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun
1369*4882a593Smuzhiyun ret = wl_ext_iovar_getint(dev, "dhcpc_ip_gateway", &ip_addr);
1370*4882a593Smuzhiyun if (!ret) {
1371*4882a593Smuzhiyun bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
1372*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1373*4882a593Smuzhiyun "gw %s ", buf);
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun
1376*4882a593Smuzhiyun ret = wl_ext_iovar_getint(dev, "dhcpc_ip_dnsserv", &ip_addr);
1377*4882a593Smuzhiyun if (!ret) {
1378*4882a593Smuzhiyun bcm_ip_ntoa((struct ipv4_addr *)&ip_addr, buf);
1379*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1380*4882a593Smuzhiyun "dnsserv %s ", buf);
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun if (!bytes_written)
1384*4882a593Smuzhiyun bytes_written = -1;
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
1387*4882a593Smuzhiyun }
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun return bytes_written;
1390*4882a593Smuzhiyun }
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun int
wl_ext_dhcpc_param(struct net_device * dev,char * data,char * command,int total_len)1393*4882a593Smuzhiyun wl_ext_dhcpc_param(struct net_device *dev, char *data, char *command,
1394*4882a593Smuzhiyun int total_len)
1395*4882a593Smuzhiyun {
1396*4882a593Smuzhiyun int ret = -1, bytes_written = 0;
1397*4882a593Smuzhiyun char ip_addr_str[20]="", ip_serv_str[20]="";
1398*4882a593Smuzhiyun struct dhcpc_parameter dhcpc_param;
1399*4882a593Smuzhiyun uint32 ip_addr, ip_serv, lease_time;
1400*4882a593Smuzhiyun char iovar_buf[WLC_IOCTL_SMLEN]="\0";
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun if (data) {
1403*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s", command);
1404*4882a593Smuzhiyun sscanf(data, "%s %s %d", ip_addr_str, ip_serv_str, &lease_time);
1405*4882a593Smuzhiyun AEXT_TRACE(dev->name, "ip_addr = %s, ip_serv = %s, lease_time = %d",
1406*4882a593Smuzhiyun ip_addr_str, ip_serv_str, lease_time);
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun memset(&dhcpc_param, 0, sizeof(struct dhcpc_parameter));
1409*4882a593Smuzhiyun if (!bcm_atoipv4(ip_addr_str, (struct ipv4_addr *)&ip_addr)) {
1410*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong ip_addr_str %s\n", ip_addr_str);
1411*4882a593Smuzhiyun ret = -1;
1412*4882a593Smuzhiyun goto exit;
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun dhcpc_param.ip_addr = ip_addr;
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun if (!bcm_atoipv4(ip_addr_str, (struct ipv4_addr *)&ip_serv)) {
1417*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong ip_addr_str %s\n", ip_addr_str);
1418*4882a593Smuzhiyun ret = -1;
1419*4882a593Smuzhiyun goto exit;
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun dhcpc_param.ip_serv = ip_serv;
1422*4882a593Smuzhiyun dhcpc_param.lease_time = lease_time;
1423*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "dhcpc_param", &dhcpc_param,
1424*4882a593Smuzhiyun sizeof(struct dhcpc_parameter), iovar_buf, sizeof(iovar_buf), NULL);
1425*4882a593Smuzhiyun } else {
1426*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "dhcpc_param", &dhcpc_param,
1427*4882a593Smuzhiyun sizeof(struct dhcpc_parameter), iovar_buf, WLC_IOCTL_SMLEN, NULL);
1428*4882a593Smuzhiyun if (!ret) {
1429*4882a593Smuzhiyun bcm_ip_ntoa((struct ipv4_addr *)&dhcpc_param.ip_addr, ip_addr_str);
1430*4882a593Smuzhiyun bytes_written += snprintf(command + bytes_written, total_len,
1431*4882a593Smuzhiyun "ip_addr %s\n", ip_addr_str);
1432*4882a593Smuzhiyun bcm_ip_ntoa((struct ipv4_addr *)&dhcpc_param.ip_serv, ip_serv_str);
1433*4882a593Smuzhiyun bytes_written += snprintf(command + bytes_written, total_len,
1434*4882a593Smuzhiyun "ip_serv %s\n", ip_serv_str);
1435*4882a593Smuzhiyun bytes_written += snprintf(command + bytes_written, total_len,
1436*4882a593Smuzhiyun "lease_time %d\n", dhcpc_param.lease_time);
1437*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
1438*4882a593Smuzhiyun ret = bytes_written;
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun exit:
1443*4882a593Smuzhiyun return ret;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun #endif /* IDHCP */
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun int
wl_ext_mkeep_alive(struct net_device * dev,char * data,char * command,int total_len)1448*4882a593Smuzhiyun wl_ext_mkeep_alive(struct net_device *dev, char *data, char *command,
1449*4882a593Smuzhiyun int total_len)
1450*4882a593Smuzhiyun {
1451*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1452*4882a593Smuzhiyun wl_mkeep_alive_pkt_v1_t *mkeep_alive_pktp;
1453*4882a593Smuzhiyun int ret = -1, i, ifidx, id, period=-1;
1454*4882a593Smuzhiyun char *packet = NULL, *buf = NULL;
1455*4882a593Smuzhiyun int bytes_written = 0;
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun if (data) {
1458*4882a593Smuzhiyun buf = kmalloc(total_len, GFP_KERNEL);
1459*4882a593Smuzhiyun if (buf == NULL) {
1460*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
1461*4882a593Smuzhiyun goto exit;
1462*4882a593Smuzhiyun }
1463*4882a593Smuzhiyun packet = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
1464*4882a593Smuzhiyun if (packet == NULL) {
1465*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
1466*4882a593Smuzhiyun goto exit;
1467*4882a593Smuzhiyun }
1468*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s", command);
1469*4882a593Smuzhiyun sscanf(data, "%d %d %s", &id, &period, packet);
1470*4882a593Smuzhiyun AEXT_TRACE(dev->name, "id=%d, period=%d, packet=%s", id, period, packet);
1471*4882a593Smuzhiyun if (period >= 0) {
1472*4882a593Smuzhiyun ifidx = dhd_net2idx(dhd->info, dev);
1473*4882a593Smuzhiyun ret = dhd_conf_mkeep_alive(dhd, ifidx, id, period, packet, FALSE);
1474*4882a593Smuzhiyun } else {
1475*4882a593Smuzhiyun if (id < 0)
1476*4882a593Smuzhiyun id = 0;
1477*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "mkeep_alive", &id, sizeof(id), buf,
1478*4882a593Smuzhiyun total_len, NULL);
1479*4882a593Smuzhiyun if (!ret) {
1480*4882a593Smuzhiyun mkeep_alive_pktp = (wl_mkeep_alive_pkt_v1_t *) buf;
1481*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1482*4882a593Smuzhiyun "Id :%d\n"
1483*4882a593Smuzhiyun "Period (msec) :%d\n"
1484*4882a593Smuzhiyun "Length :%d\n"
1485*4882a593Smuzhiyun "Packet :0x",
1486*4882a593Smuzhiyun mkeep_alive_pktp->keep_alive_id,
1487*4882a593Smuzhiyun dtoh32(mkeep_alive_pktp->period_msec),
1488*4882a593Smuzhiyun dtoh16(mkeep_alive_pktp->len_bytes));
1489*4882a593Smuzhiyun for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
1490*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1491*4882a593Smuzhiyun "%02x", mkeep_alive_pktp->data[i]);
1492*4882a593Smuzhiyun }
1493*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
1494*4882a593Smuzhiyun ret = bytes_written;
1495*4882a593Smuzhiyun }
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun
1499*4882a593Smuzhiyun exit:
1500*4882a593Smuzhiyun if (buf)
1501*4882a593Smuzhiyun kfree(buf);
1502*4882a593Smuzhiyun if (packet)
1503*4882a593Smuzhiyun kfree(packet);
1504*4882a593Smuzhiyun return ret;
1505*4882a593Smuzhiyun }
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun #ifdef WL_EXT_TCPKA
1508*4882a593Smuzhiyun static int
wl_ext_tcpka_conn_add(struct net_device * dev,char * data,char * command,int total_len)1509*4882a593Smuzhiyun wl_ext_tcpka_conn_add(struct net_device *dev, char *data, char *command,
1510*4882a593Smuzhiyun int total_len)
1511*4882a593Smuzhiyun {
1512*4882a593Smuzhiyun int ret = 0;
1513*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
1514*4882a593Smuzhiyun tcpka_conn_t *tcpka = NULL;
1515*4882a593Smuzhiyun uint32 sess_id = 0, ipid = 0, srcport = 0, dstport = 0, seq = 0, ack = 0,
1516*4882a593Smuzhiyun tcpwin = 0, tsval = 0, tsecr = 0, len = 0, ka_payload_len = 0;
1517*4882a593Smuzhiyun char dst_mac[ETHER_ADDR_STR_LEN], src_ip[IPV4_ADDR_STR_LEN],
1518*4882a593Smuzhiyun dst_ip[IPV4_ADDR_STR_LEN], ka_payload[32];
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun if (data) {
1521*4882a593Smuzhiyun memset(dst_mac, 0, sizeof(dst_mac));
1522*4882a593Smuzhiyun memset(src_ip, 0, sizeof(src_ip));
1523*4882a593Smuzhiyun memset(dst_ip, 0, sizeof(dst_ip));
1524*4882a593Smuzhiyun memset(ka_payload, 0, sizeof(ka_payload));
1525*4882a593Smuzhiyun sscanf(data, "%d %s %s %s %d %d %d %u %u %d %u %u %u %32s",
1526*4882a593Smuzhiyun &sess_id, dst_mac, src_ip, dst_ip, &ipid, &srcport, &dstport, &seq,
1527*4882a593Smuzhiyun &ack, &tcpwin, &tsval, &tsecr, &len, ka_payload);
1528*4882a593Smuzhiyun
1529*4882a593Smuzhiyun ka_payload_len = strlen(ka_payload) / 2;
1530*4882a593Smuzhiyun tcpka = kmalloc(sizeof(struct tcpka_conn) + ka_payload_len, GFP_KERNEL);
1531*4882a593Smuzhiyun if (tcpka == NULL) {
1532*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n",
1533*4882a593Smuzhiyun sizeof(struct tcpka_conn) + ka_payload_len);
1534*4882a593Smuzhiyun ret = -1;
1535*4882a593Smuzhiyun goto exit;
1536*4882a593Smuzhiyun }
1537*4882a593Smuzhiyun memset(tcpka, 0, sizeof(struct tcpka_conn) + ka_payload_len);
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun tcpka->sess_id = sess_id;
1540*4882a593Smuzhiyun if (!(ret = bcm_ether_atoe(dst_mac, &tcpka->dst_mac))) {
1541*4882a593Smuzhiyun AEXT_ERROR(dev->name, "mac parsing err addr=%s\n", dst_mac);
1542*4882a593Smuzhiyun ret = -1;
1543*4882a593Smuzhiyun goto exit;
1544*4882a593Smuzhiyun }
1545*4882a593Smuzhiyun if (!bcm_atoipv4(src_ip, &tcpka->src_ip)) {
1546*4882a593Smuzhiyun AEXT_ERROR(dev->name, "src_ip parsing err ip=%s\n", src_ip);
1547*4882a593Smuzhiyun ret = -1;
1548*4882a593Smuzhiyun goto exit;
1549*4882a593Smuzhiyun }
1550*4882a593Smuzhiyun if (!bcm_atoipv4(dst_ip, &tcpka->dst_ip)) {
1551*4882a593Smuzhiyun AEXT_ERROR(dev->name, "dst_ip parsing err ip=%s\n", dst_ip);
1552*4882a593Smuzhiyun ret = -1;
1553*4882a593Smuzhiyun goto exit;
1554*4882a593Smuzhiyun }
1555*4882a593Smuzhiyun tcpka->ipid = ipid;
1556*4882a593Smuzhiyun tcpka->srcport = srcport;
1557*4882a593Smuzhiyun tcpka->dstport = dstport;
1558*4882a593Smuzhiyun tcpka->seq = seq;
1559*4882a593Smuzhiyun tcpka->ack = ack;
1560*4882a593Smuzhiyun tcpka->tcpwin = tcpwin;
1561*4882a593Smuzhiyun tcpka->tsval = tsval;
1562*4882a593Smuzhiyun tcpka->tsecr = tsecr;
1563*4882a593Smuzhiyun tcpka->len = len;
1564*4882a593Smuzhiyun ka_payload_len = wl_pattern_atoh(ka_payload, (char *)tcpka->ka_payload);
1565*4882a593Smuzhiyun if (ka_payload_len == -1) {
1566*4882a593Smuzhiyun AEXT_ERROR(dev->name,"rejecting ka_payload=%s\n", ka_payload);
1567*4882a593Smuzhiyun ret = -1;
1568*4882a593Smuzhiyun goto exit;
1569*4882a593Smuzhiyun }
1570*4882a593Smuzhiyun tcpka->ka_payload_len = ka_payload_len;
1571*4882a593Smuzhiyun
1572*4882a593Smuzhiyun AEXT_INFO(dev->name,
1573*4882a593Smuzhiyun "tcpka_conn_add %d %pM %pM %pM %d %d %d %u %u %d %u %u %u %u \"%s\"\n",
1574*4882a593Smuzhiyun tcpka->sess_id, &tcpka->dst_mac, &tcpka->src_ip, &tcpka->dst_ip,
1575*4882a593Smuzhiyun tcpka->ipid, tcpka->srcport, tcpka->dstport, tcpka->seq,
1576*4882a593Smuzhiyun tcpka->ack, tcpka->tcpwin, tcpka->tsval, tcpka->tsecr,
1577*4882a593Smuzhiyun tcpka->len, tcpka->ka_payload_len, tcpka->ka_payload);
1578*4882a593Smuzhiyun
1579*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "tcpka_conn_add", (char *)tcpka,
1580*4882a593Smuzhiyun (sizeof(tcpka_conn_t) + tcpka->ka_payload_len - 1),
1581*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun exit:
1585*4882a593Smuzhiyun if (tcpka)
1586*4882a593Smuzhiyun kfree(tcpka);
1587*4882a593Smuzhiyun return ret;
1588*4882a593Smuzhiyun }
1589*4882a593Smuzhiyun
1590*4882a593Smuzhiyun static int
wl_ext_tcpka_conn_enable(struct net_device * dev,char * data,char * command,int total_len)1591*4882a593Smuzhiyun wl_ext_tcpka_conn_enable(struct net_device *dev, char *data, char *command,
1592*4882a593Smuzhiyun int total_len)
1593*4882a593Smuzhiyun {
1594*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
1595*4882a593Smuzhiyun tcpka_conn_sess_t tcpka_conn;
1596*4882a593Smuzhiyun int ret = 0;
1597*4882a593Smuzhiyun uint32 sess_id = 0, flag, interval = 0, retry_interval = 0, retry_count = 0;
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun if (data) {
1600*4882a593Smuzhiyun sscanf(data, "%d %d %d %d %d",
1601*4882a593Smuzhiyun &sess_id, &flag, &interval, &retry_interval, &retry_count);
1602*4882a593Smuzhiyun tcpka_conn.sess_id = sess_id;
1603*4882a593Smuzhiyun tcpka_conn.flag = flag;
1604*4882a593Smuzhiyun if (tcpka_conn.flag) {
1605*4882a593Smuzhiyun tcpka_conn.tcpka_timers.interval = interval;
1606*4882a593Smuzhiyun tcpka_conn.tcpka_timers.retry_interval = retry_interval;
1607*4882a593Smuzhiyun tcpka_conn.tcpka_timers.retry_count = retry_count;
1608*4882a593Smuzhiyun } else {
1609*4882a593Smuzhiyun tcpka_conn.tcpka_timers.interval = 0;
1610*4882a593Smuzhiyun tcpka_conn.tcpka_timers.retry_interval = 0;
1611*4882a593Smuzhiyun tcpka_conn.tcpka_timers.retry_count = 0;
1612*4882a593Smuzhiyun }
1613*4882a593Smuzhiyun
1614*4882a593Smuzhiyun AEXT_INFO(dev->name, "tcpka_conn_enable %d %d %d %d %d\n",
1615*4882a593Smuzhiyun tcpka_conn.sess_id, tcpka_conn.flag,
1616*4882a593Smuzhiyun tcpka_conn.tcpka_timers.interval,
1617*4882a593Smuzhiyun tcpka_conn.tcpka_timers.retry_interval,
1618*4882a593Smuzhiyun tcpka_conn.tcpka_timers.retry_count);
1619*4882a593Smuzhiyun
1620*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "tcpka_conn_enable", (char *)&tcpka_conn,
1621*4882a593Smuzhiyun sizeof(tcpka_conn_sess_t), iovar_buf, sizeof(iovar_buf), NULL);
1622*4882a593Smuzhiyun }
1623*4882a593Smuzhiyun
1624*4882a593Smuzhiyun return ret;
1625*4882a593Smuzhiyun }
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun static int
wl_ext_tcpka_conn_info(struct net_device * dev,char * data,char * command,int total_len)1628*4882a593Smuzhiyun wl_ext_tcpka_conn_info(struct net_device *dev, char *data, char *command,
1629*4882a593Smuzhiyun int total_len)
1630*4882a593Smuzhiyun {
1631*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
1632*4882a593Smuzhiyun tcpka_conn_sess_info_t *info = NULL;
1633*4882a593Smuzhiyun uint32 sess_id = 0;
1634*4882a593Smuzhiyun int ret = 0, bytes_written = 0;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun if (data) {
1637*4882a593Smuzhiyun sscanf(data, "%d", &sess_id);
1638*4882a593Smuzhiyun AEXT_INFO(dev->name, "tcpka_conn_sess_info %d\n", sess_id);
1639*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "tcpka_conn_sess_info", (char *)&sess_id,
1640*4882a593Smuzhiyun sizeof(uint32), iovar_buf, sizeof(iovar_buf), NULL);
1641*4882a593Smuzhiyun if (!ret) {
1642*4882a593Smuzhiyun info = (tcpka_conn_sess_info_t *) iovar_buf;
1643*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1644*4882a593Smuzhiyun "id :%d\n"
1645*4882a593Smuzhiyun "ipid :%d\n"
1646*4882a593Smuzhiyun "seq :%u\n"
1647*4882a593Smuzhiyun "ack :%u",
1648*4882a593Smuzhiyun sess_id, info->ipid, info->seq, info->ack);
1649*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s\n", command);
1650*4882a593Smuzhiyun ret = bytes_written;
1651*4882a593Smuzhiyun }
1652*4882a593Smuzhiyun }
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun return ret;
1655*4882a593Smuzhiyun }
1656*4882a593Smuzhiyun #endif /* WL_EXT_TCPKA */
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun static int
wl_ext_rsdb_mode(struct net_device * dev,char * data,char * command,int total_len)1659*4882a593Smuzhiyun wl_ext_rsdb_mode(struct net_device *dev, char *data, char *command,
1660*4882a593Smuzhiyun int total_len)
1661*4882a593Smuzhiyun {
1662*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
1663*4882a593Smuzhiyun wl_config_t rsdb_mode_cfg = {1, 0}, *rsdb_p;
1664*4882a593Smuzhiyun int ret = 0;
1665*4882a593Smuzhiyun
1666*4882a593Smuzhiyun if (data) {
1667*4882a593Smuzhiyun rsdb_mode_cfg.config = (int)simple_strtol(data, NULL, 0);
1668*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "rsdb_mode", (char *)&rsdb_mode_cfg,
1669*4882a593Smuzhiyun sizeof(rsdb_mode_cfg), iovar_buf, WLC_IOCTL_SMLEN, NULL);
1670*4882a593Smuzhiyun AEXT_INFO(dev->name, "rsdb_mode %d\n", rsdb_mode_cfg.config);
1671*4882a593Smuzhiyun } else {
1672*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "rsdb_mode", NULL, 0,
1673*4882a593Smuzhiyun iovar_buf, WLC_IOCTL_SMLEN, NULL);
1674*4882a593Smuzhiyun if (!ret) {
1675*4882a593Smuzhiyun rsdb_p = (wl_config_t *) iovar_buf;
1676*4882a593Smuzhiyun ret = snprintf(command, total_len, "%d", rsdb_p->config);
1677*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun }
1680*4882a593Smuzhiyun
1681*4882a593Smuzhiyun return ret;
1682*4882a593Smuzhiyun }
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun static int
wl_ext_recal(struct net_device * dev,char * data,char * command,int total_len)1685*4882a593Smuzhiyun wl_ext_recal(struct net_device *dev, char *data, char *command,
1686*4882a593Smuzhiyun int total_len)
1687*4882a593Smuzhiyun {
1688*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1689*4882a593Smuzhiyun int ret = 0, i, nchan, nssid = 0;
1690*4882a593Smuzhiyun int params_size = WL_SCAN_PARAMS_V1_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
1691*4882a593Smuzhiyun wl_scan_params_v1_t *params = NULL;
1692*4882a593Smuzhiyun char *p;
1693*4882a593Smuzhiyun
1694*4882a593Smuzhiyun AEXT_TRACE(dev->name, "Enter\n");
1695*4882a593Smuzhiyun
1696*4882a593Smuzhiyun if (data) {
1697*4882a593Smuzhiyun params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
1698*4882a593Smuzhiyun params = (wl_scan_params_v1_t *) kzalloc(params_size, GFP_KERNEL);
1699*4882a593Smuzhiyun if (params == NULL) {
1700*4882a593Smuzhiyun ret = -ENOMEM;
1701*4882a593Smuzhiyun goto exit;
1702*4882a593Smuzhiyun }
1703*4882a593Smuzhiyun memset(params, 0, params_size);
1704*4882a593Smuzhiyun
1705*4882a593Smuzhiyun memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN);
1706*4882a593Smuzhiyun params->bss_type = DOT11_BSSTYPE_ANY;
1707*4882a593Smuzhiyun params->scan_type = 0;
1708*4882a593Smuzhiyun params->nprobes = -1;
1709*4882a593Smuzhiyun params->active_time = -1;
1710*4882a593Smuzhiyun params->passive_time = -1;
1711*4882a593Smuzhiyun params->home_time = -1;
1712*4882a593Smuzhiyun params->channel_num = 0;
1713*4882a593Smuzhiyun
1714*4882a593Smuzhiyun params->scan_type |= WL_SCANFLAGS_PASSIVE;
1715*4882a593Smuzhiyun nchan = 2;
1716*4882a593Smuzhiyun params->channel_list[0] = wf_channel2chspec(1, WL_CHANSPEC_BW_20);
1717*4882a593Smuzhiyun params->channel_list[1] = wf_channel2chspec(2, WL_CHANSPEC_BW_20);
1718*4882a593Smuzhiyun
1719*4882a593Smuzhiyun params->nprobes = htod32(params->nprobes);
1720*4882a593Smuzhiyun params->active_time = htod32(params->active_time);
1721*4882a593Smuzhiyun params->passive_time = htod32(params->passive_time);
1722*4882a593Smuzhiyun params->home_time = htod32(params->home_time);
1723*4882a593Smuzhiyun
1724*4882a593Smuzhiyun for (i = 0; i < nchan; i++) {
1725*4882a593Smuzhiyun wl_ext_chspec_host_to_driver(dhd, params->channel_list[i]);
1726*4882a593Smuzhiyun }
1727*4882a593Smuzhiyun
1728*4882a593Smuzhiyun p = (char*)params->channel_list + nchan * sizeof(uint16);
1729*4882a593Smuzhiyun
1730*4882a593Smuzhiyun params->channel_num = htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
1731*4882a593Smuzhiyun (nchan & WL_SCAN_PARAMS_COUNT_MASK));
1732*4882a593Smuzhiyun params_size = p - (char*)params + nssid * sizeof(wlc_ssid_t);
1733*4882a593Smuzhiyun
1734*4882a593Smuzhiyun AEXT_INFO(dev->name, "recal\n");
1735*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, WLC_SCAN, params, params_size, 1);
1736*4882a593Smuzhiyun }
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun exit:
1739*4882a593Smuzhiyun if (params)
1740*4882a593Smuzhiyun kfree(params);
1741*4882a593Smuzhiyun return ret;
1742*4882a593Smuzhiyun }
1743*4882a593Smuzhiyun
1744*4882a593Smuzhiyun static s32
wl_ext_add_remove_eventmsg(struct net_device * ndev,u16 event,bool add)1745*4882a593Smuzhiyun wl_ext_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
1746*4882a593Smuzhiyun {
1747*4882a593Smuzhiyun s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
1748*4882a593Smuzhiyun s8 eventmask[WL_EVENTING_MASK_LEN];
1749*4882a593Smuzhiyun s32 err = 0;
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyun if (!ndev)
1752*4882a593Smuzhiyun return -ENODEV;
1753*4882a593Smuzhiyun
1754*4882a593Smuzhiyun /* Setup event_msgs */
1755*4882a593Smuzhiyun err = wldev_iovar_getbuf(ndev, "event_msgs", NULL, 0, iovbuf, sizeof(iovbuf), NULL);
1756*4882a593Smuzhiyun if (unlikely(err)) {
1757*4882a593Smuzhiyun AEXT_ERROR(ndev->name, "Get event_msgs error (%d)\n", err);
1758*4882a593Smuzhiyun goto eventmsg_out;
1759*4882a593Smuzhiyun }
1760*4882a593Smuzhiyun memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
1761*4882a593Smuzhiyun if (add) {
1762*4882a593Smuzhiyun setbit(eventmask, event);
1763*4882a593Smuzhiyun } else {
1764*4882a593Smuzhiyun clrbit(eventmask, event);
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun err = wldev_iovar_setbuf(ndev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
1767*4882a593Smuzhiyun sizeof(iovbuf), NULL);
1768*4882a593Smuzhiyun if (unlikely(err)) {
1769*4882a593Smuzhiyun AEXT_ERROR(ndev->name, "Set event_msgs error (%d)\n", err);
1770*4882a593Smuzhiyun goto eventmsg_out;
1771*4882a593Smuzhiyun }
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun eventmsg_out:
1774*4882a593Smuzhiyun return err;
1775*4882a593Smuzhiyun }
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun static int
wl_ext_event_msg(struct net_device * dev,char * data,char * command,int total_len)1778*4882a593Smuzhiyun wl_ext_event_msg(struct net_device *dev, char *data,
1779*4882a593Smuzhiyun char *command, int total_len)
1780*4882a593Smuzhiyun {
1781*4882a593Smuzhiyun s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
1782*4882a593Smuzhiyun s8 eventmask[WL_EVENTING_MASK_LEN];
1783*4882a593Smuzhiyun int i, bytes_written = 0, add = -1;
1784*4882a593Smuzhiyun uint event;
1785*4882a593Smuzhiyun char *vbuf;
1786*4882a593Smuzhiyun bool skipzeros;
1787*4882a593Smuzhiyun
1788*4882a593Smuzhiyun /* dhd_priv wl event_msg [offset] [1/0, 1 for add, 0 for remove] */
1789*4882a593Smuzhiyun /* dhd_priv wl event_msg 40 1 */
1790*4882a593Smuzhiyun if (data) {
1791*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
1792*4882a593Smuzhiyun sscanf(data, "%d %d", &event, &add);
1793*4882a593Smuzhiyun /* Setup event_msgs */
1794*4882a593Smuzhiyun bytes_written = wldev_iovar_getbuf(dev, "event_msgs", NULL, 0, iovbuf,
1795*4882a593Smuzhiyun sizeof(iovbuf), NULL);
1796*4882a593Smuzhiyun if (unlikely(bytes_written)) {
1797*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Get event_msgs error (%d)\n", bytes_written);
1798*4882a593Smuzhiyun goto eventmsg_out;
1799*4882a593Smuzhiyun }
1800*4882a593Smuzhiyun memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
1801*4882a593Smuzhiyun if (add == -1) {
1802*4882a593Smuzhiyun if (isset(eventmask, event))
1803*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len, "1");
1804*4882a593Smuzhiyun else
1805*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len, "0");
1806*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s\n", command);
1807*4882a593Smuzhiyun goto eventmsg_out;
1808*4882a593Smuzhiyun }
1809*4882a593Smuzhiyun bytes_written = wl_ext_add_remove_eventmsg(dev, event, add);
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun else {
1812*4882a593Smuzhiyun /* Setup event_msgs */
1813*4882a593Smuzhiyun bytes_written = wldev_iovar_getbuf(dev, "event_msgs", NULL, 0, iovbuf,
1814*4882a593Smuzhiyun sizeof(iovbuf), NULL);
1815*4882a593Smuzhiyun if (bytes_written) {
1816*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Get event_msgs error (%d)\n", bytes_written);
1817*4882a593Smuzhiyun goto eventmsg_out;
1818*4882a593Smuzhiyun }
1819*4882a593Smuzhiyun vbuf = (char *)iovbuf;
1820*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len, "0x");
1821*4882a593Smuzhiyun for (i = (sizeof(eventmask) - 1); i >= 0; i--) {
1822*4882a593Smuzhiyun if (vbuf[i] || (i == 0))
1823*4882a593Smuzhiyun skipzeros = FALSE;
1824*4882a593Smuzhiyun if (skipzeros)
1825*4882a593Smuzhiyun continue;
1826*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
1827*4882a593Smuzhiyun "%02x", vbuf[i] & 0xff);
1828*4882a593Smuzhiyun }
1829*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s\n", command);
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun
1832*4882a593Smuzhiyun eventmsg_out:
1833*4882a593Smuzhiyun return bytes_written;
1834*4882a593Smuzhiyun }
1835*4882a593Smuzhiyun
1836*4882a593Smuzhiyun #ifdef PKT_FILTER_SUPPORT
1837*4882a593Smuzhiyun extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
1838*4882a593Smuzhiyun extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
1839*4882a593Smuzhiyun extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
1840*4882a593Smuzhiyun static int
wl_ext_pkt_filter_add(struct net_device * dev,char * data,char * command,int total_len)1841*4882a593Smuzhiyun wl_ext_pkt_filter_add(struct net_device *dev, char *data, char *command,
1842*4882a593Smuzhiyun int total_len)
1843*4882a593Smuzhiyun {
1844*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1845*4882a593Smuzhiyun int i, filter_id, new_id = 0, cnt;
1846*4882a593Smuzhiyun conf_pkt_filter_add_t *filter_add = &dhd->conf->pkt_filter_add;
1847*4882a593Smuzhiyun char **pktfilter = dhd->pktfilter;
1848*4882a593Smuzhiyun int err = 0;
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun if (data) {
1851*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
1852*4882a593Smuzhiyun
1853*4882a593Smuzhiyun new_id = simple_strtol(data, NULL, 10);
1854*4882a593Smuzhiyun if (new_id <= 0) {
1855*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong id %d\n", new_id);
1856*4882a593Smuzhiyun return -1;
1857*4882a593Smuzhiyun }
1858*4882a593Smuzhiyun
1859*4882a593Smuzhiyun cnt = dhd->pktfilter_count;
1860*4882a593Smuzhiyun for (i=0; i<cnt; i++) {
1861*4882a593Smuzhiyun if (!pktfilter[i])
1862*4882a593Smuzhiyun continue;
1863*4882a593Smuzhiyun filter_id = simple_strtol(pktfilter[i], NULL, 10);
1864*4882a593Smuzhiyun if (new_id == filter_id) {
1865*4882a593Smuzhiyun AEXT_ERROR(dev->name, "filter id %d already in list\n", filter_id);
1866*4882a593Smuzhiyun return -1;
1867*4882a593Smuzhiyun }
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun
1870*4882a593Smuzhiyun cnt = filter_add->count;
1871*4882a593Smuzhiyun if (cnt >= DHD_CONF_FILTER_MAX) {
1872*4882a593Smuzhiyun AEXT_ERROR(dev->name, "not enough filter\n");
1873*4882a593Smuzhiyun return -1;
1874*4882a593Smuzhiyun }
1875*4882a593Smuzhiyun for (i=0; i<cnt; i++) {
1876*4882a593Smuzhiyun filter_id = simple_strtol(filter_add->filter[i], NULL, 10);
1877*4882a593Smuzhiyun if (new_id == filter_id) {
1878*4882a593Smuzhiyun AEXT_ERROR(dev->name, "filter id %d already in list\n", filter_id);
1879*4882a593Smuzhiyun return -1;
1880*4882a593Smuzhiyun }
1881*4882a593Smuzhiyun }
1882*4882a593Smuzhiyun
1883*4882a593Smuzhiyun strcpy(&filter_add->filter[cnt][0], data);
1884*4882a593Smuzhiyun dhd->pktfilter[dhd->pktfilter_count] = filter_add->filter[cnt];
1885*4882a593Smuzhiyun filter_add->count++;
1886*4882a593Smuzhiyun dhd->pktfilter_count++;
1887*4882a593Smuzhiyun
1888*4882a593Smuzhiyun dhd_pktfilter_offload_set(dhd, data);
1889*4882a593Smuzhiyun AEXT_INFO(dev->name, "filter id %d added\n", new_id);
1890*4882a593Smuzhiyun }
1891*4882a593Smuzhiyun
1892*4882a593Smuzhiyun return err;
1893*4882a593Smuzhiyun }
1894*4882a593Smuzhiyun
1895*4882a593Smuzhiyun static int
wl_ext_pkt_filter_delete(struct net_device * dev,char * data,char * command,int total_len)1896*4882a593Smuzhiyun wl_ext_pkt_filter_delete(struct net_device *dev, char *data, char *command,
1897*4882a593Smuzhiyun int total_len)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1900*4882a593Smuzhiyun int i, j, filter_id, cnt;
1901*4882a593Smuzhiyun char **pktfilter = dhd->pktfilter;
1902*4882a593Smuzhiyun conf_pkt_filter_add_t *filter_add = &dhd->conf->pkt_filter_add;
1903*4882a593Smuzhiyun bool in_filter = FALSE;
1904*4882a593Smuzhiyun int id, err = 0;
1905*4882a593Smuzhiyun
1906*4882a593Smuzhiyun if (data) {
1907*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
1908*4882a593Smuzhiyun id = (int)simple_strtol(data, NULL, 0);
1909*4882a593Smuzhiyun
1910*4882a593Smuzhiyun cnt = filter_add->count;
1911*4882a593Smuzhiyun for (i=0; i<cnt; i++) {
1912*4882a593Smuzhiyun filter_id = simple_strtol(filter_add->filter[i], NULL, 10);
1913*4882a593Smuzhiyun if (id == filter_id) {
1914*4882a593Smuzhiyun in_filter = TRUE;
1915*4882a593Smuzhiyun memset(filter_add->filter[i], 0, PKT_FILTER_LEN);
1916*4882a593Smuzhiyun for (j=i; j<(cnt-1); j++) {
1917*4882a593Smuzhiyun strcpy(filter_add->filter[j], filter_add->filter[j+1]);
1918*4882a593Smuzhiyun memset(filter_add->filter[j+1], 0, PKT_FILTER_LEN);
1919*4882a593Smuzhiyun }
1920*4882a593Smuzhiyun cnt--;
1921*4882a593Smuzhiyun filter_add->count--;
1922*4882a593Smuzhiyun dhd->pktfilter_count--;
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun cnt = dhd->pktfilter_count;
1927*4882a593Smuzhiyun for (i=0; i<cnt; i++) {
1928*4882a593Smuzhiyun if (!pktfilter[i])
1929*4882a593Smuzhiyun continue;
1930*4882a593Smuzhiyun filter_id = simple_strtol(pktfilter[i], NULL, 10);
1931*4882a593Smuzhiyun if (id == filter_id) {
1932*4882a593Smuzhiyun in_filter = TRUE;
1933*4882a593Smuzhiyun memset(pktfilter[i], 0, strlen(pktfilter[i]));
1934*4882a593Smuzhiyun }
1935*4882a593Smuzhiyun }
1936*4882a593Smuzhiyun
1937*4882a593Smuzhiyun if (in_filter) {
1938*4882a593Smuzhiyun dhd_pktfilter_offload_delete(dhd, id);
1939*4882a593Smuzhiyun AEXT_INFO(dev->name, "filter id %d deleted\n", id);
1940*4882a593Smuzhiyun } else {
1941*4882a593Smuzhiyun AEXT_ERROR(dev->name, "filter id %d not in list\n", id);
1942*4882a593Smuzhiyun err = -1;
1943*4882a593Smuzhiyun }
1944*4882a593Smuzhiyun }
1945*4882a593Smuzhiyun
1946*4882a593Smuzhiyun return err;
1947*4882a593Smuzhiyun }
1948*4882a593Smuzhiyun
1949*4882a593Smuzhiyun static int
wl_ext_pkt_filter_enable(struct net_device * dev,char * data,char * command,int total_len)1950*4882a593Smuzhiyun wl_ext_pkt_filter_enable(struct net_device *dev, char *data, char *command,
1951*4882a593Smuzhiyun int total_len)
1952*4882a593Smuzhiyun {
1953*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
1954*4882a593Smuzhiyun int err = 0, id, enable;
1955*4882a593Smuzhiyun int i, filter_id, cnt;
1956*4882a593Smuzhiyun char **pktfilter = dhd->pktfilter;
1957*4882a593Smuzhiyun bool in_filter = FALSE;
1958*4882a593Smuzhiyun
1959*4882a593Smuzhiyun /* dhd_priv wl pkt_filter_enable [id] [1/0] */
1960*4882a593Smuzhiyun /* dhd_priv wl pkt_filter_enable 141 1 */
1961*4882a593Smuzhiyun if (data) {
1962*4882a593Smuzhiyun sscanf(data, "%d %d", &id, &enable);
1963*4882a593Smuzhiyun
1964*4882a593Smuzhiyun cnt = dhd->pktfilter_count;
1965*4882a593Smuzhiyun for (i=0; i<cnt; i++) {
1966*4882a593Smuzhiyun if (!pktfilter[i])
1967*4882a593Smuzhiyun continue;
1968*4882a593Smuzhiyun filter_id = simple_strtol(pktfilter[i], NULL, 10);
1969*4882a593Smuzhiyun if (id == filter_id) {
1970*4882a593Smuzhiyun in_filter = TRUE;
1971*4882a593Smuzhiyun break;
1972*4882a593Smuzhiyun }
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun
1975*4882a593Smuzhiyun if (in_filter) {
1976*4882a593Smuzhiyun dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
1977*4882a593Smuzhiyun enable, dhd_master_mode);
1978*4882a593Smuzhiyun AEXT_INFO(dev->name, "filter id %d %s\n", id, enable?"enabled":"disabled");
1979*4882a593Smuzhiyun } else {
1980*4882a593Smuzhiyun AEXT_ERROR(dev->name, "filter id %d not in list\n", id);
1981*4882a593Smuzhiyun err = -1;
1982*4882a593Smuzhiyun }
1983*4882a593Smuzhiyun }
1984*4882a593Smuzhiyun
1985*4882a593Smuzhiyun return err;
1986*4882a593Smuzhiyun }
1987*4882a593Smuzhiyun #endif /* PKT_FILTER_SUPPORT */
1988*4882a593Smuzhiyun
1989*4882a593Smuzhiyun #ifdef SENDPROB
1990*4882a593Smuzhiyun static int
wl_ext_send_probreq(struct net_device * dev,char * data,char * command,int total_len)1991*4882a593Smuzhiyun wl_ext_send_probreq(struct net_device *dev, char *data, char *command,
1992*4882a593Smuzhiyun int total_len)
1993*4882a593Smuzhiyun {
1994*4882a593Smuzhiyun int err = 0;
1995*4882a593Smuzhiyun char addr_str[16], addr[6];
1996*4882a593Smuzhiyun char iovar_buf[WLC_IOCTL_SMLEN]="\0";
1997*4882a593Smuzhiyun char ie_data[WLC_IOCTL_SMLEN] = "\0";
1998*4882a593Smuzhiyun wl_probe_params_t params;
1999*4882a593Smuzhiyun
2000*4882a593Smuzhiyun /* dhd_priv wl send_probreq [dest. addr] [OUI+VAL] */
2001*4882a593Smuzhiyun /* dhd_priv wl send_probreq 0x00904c010203 0x00904c01020304050607 */
2002*4882a593Smuzhiyun if (data) {
2003*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
2004*4882a593Smuzhiyun sscanf(data, "%s %s", addr_str, ie_data);
2005*4882a593Smuzhiyun AEXT_TRACE(dev->name, "addr=%s, ie=%s\n", addr_str, ie_data);
2006*4882a593Smuzhiyun
2007*4882a593Smuzhiyun if (strlen(addr_str) != 14) {
2008*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong addr %s\n", addr_str);
2009*4882a593Smuzhiyun goto exit;
2010*4882a593Smuzhiyun }
2011*4882a593Smuzhiyun wl_pattern_atoh(addr_str, (char *) addr);
2012*4882a593Smuzhiyun memset(¶ms, 0, sizeof(params));
2013*4882a593Smuzhiyun memcpy(¶ms.bssid, addr, ETHER_ADDR_LEN);
2014*4882a593Smuzhiyun memcpy(¶ms.mac, addr, ETHER_ADDR_LEN);
2015*4882a593Smuzhiyun
2016*4882a593Smuzhiyun err = wl_ext_add_del_ie(dev, VNDR_IE_PRBREQ_FLAG, ie_data, "add");
2017*4882a593Smuzhiyun if (err)
2018*4882a593Smuzhiyun goto exit;
2019*4882a593Smuzhiyun err = wl_ext_iovar_setbuf(dev, "sendprb", (char *)¶ms, sizeof(params),
2020*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
2021*4882a593Smuzhiyun OSL_SLEEP(100);
2022*4882a593Smuzhiyun wl_ext_add_del_ie(dev, VNDR_IE_PRBREQ_FLAG, ie_data, "del");
2023*4882a593Smuzhiyun }
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun exit:
2026*4882a593Smuzhiyun return err;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun static int
wl_ext_send_probresp(struct net_device * dev,char * data,char * command,int total_len)2030*4882a593Smuzhiyun wl_ext_send_probresp(struct net_device *dev, char *data, char *command,
2031*4882a593Smuzhiyun int total_len)
2032*4882a593Smuzhiyun {
2033*4882a593Smuzhiyun int err = 0;
2034*4882a593Smuzhiyun char addr_str[16], addr[6];
2035*4882a593Smuzhiyun char iovar_buf[WLC_IOCTL_SMLEN]="\0";
2036*4882a593Smuzhiyun char ie_data[WLC_IOCTL_SMLEN] = "\0";
2037*4882a593Smuzhiyun
2038*4882a593Smuzhiyun /* dhd_priv wl send_probresp [dest. addr] [OUI+VAL] */
2039*4882a593Smuzhiyun /* dhd_priv wl send_probresp 0x00904c010203 0x00904c01020304050607 */
2040*4882a593Smuzhiyun if (data) {
2041*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
2042*4882a593Smuzhiyun sscanf(data, "%s %s", addr_str, ie_data);
2043*4882a593Smuzhiyun AEXT_TRACE(dev->name, "addr=%s, ie=%s\n", addr_str, ie_data);
2044*4882a593Smuzhiyun
2045*4882a593Smuzhiyun if (strlen(addr_str) != 14) {
2046*4882a593Smuzhiyun AEXT_ERROR(dev->name, "wrong addr %s\n", addr_str);
2047*4882a593Smuzhiyun goto exit;
2048*4882a593Smuzhiyun }
2049*4882a593Smuzhiyun wl_pattern_atoh(addr_str, (char *) addr);
2050*4882a593Smuzhiyun
2051*4882a593Smuzhiyun err = wl_ext_add_del_ie(dev, VNDR_IE_PRBRSP_FLAG, ie_data, "add");
2052*4882a593Smuzhiyun if (err)
2053*4882a593Smuzhiyun goto exit;
2054*4882a593Smuzhiyun err = wl_ext_iovar_setbuf(dev, "send_probresp", addr, sizeof(addr),
2055*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
2056*4882a593Smuzhiyun OSL_SLEEP(100);
2057*4882a593Smuzhiyun wl_ext_add_del_ie(dev, VNDR_IE_PRBRSP_FLAG, ie_data, "del");
2058*4882a593Smuzhiyun }
2059*4882a593Smuzhiyun
2060*4882a593Smuzhiyun exit:
2061*4882a593Smuzhiyun return err;
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun static int
wl_ext_recv_probreq(struct net_device * dev,char * data,char * command,int total_len)2065*4882a593Smuzhiyun wl_ext_recv_probreq(struct net_device *dev, char *data, char *command,
2066*4882a593Smuzhiyun int total_len)
2067*4882a593Smuzhiyun {
2068*4882a593Smuzhiyun int err = 0, enable = 0;
2069*4882a593Smuzhiyun char cmd[32];
2070*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
2071*4882a593Smuzhiyun
2072*4882a593Smuzhiyun /* enable:
2073*4882a593Smuzhiyun 1. dhd_priv wl 86 0
2074*4882a593Smuzhiyun 2. dhd_priv wl event_msg 44 1
2075*4882a593Smuzhiyun disable:
2076*4882a593Smuzhiyun 1. dhd_priv wl 86 2;
2077*4882a593Smuzhiyun 2. dhd_priv wl event_msg 44 0
2078*4882a593Smuzhiyun */
2079*4882a593Smuzhiyun if (data) {
2080*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
2081*4882a593Smuzhiyun sscanf(data, "%d", &enable);
2082*4882a593Smuzhiyun if (enable) {
2083*4882a593Smuzhiyun strcpy(cmd, "wl 86 0");
2084*4882a593Smuzhiyun err = wl_ext_wl_iovar(dev, cmd, total_len);
2085*4882a593Smuzhiyun if (err)
2086*4882a593Smuzhiyun goto exit;
2087*4882a593Smuzhiyun strcpy(cmd, "wl event_msg 44 1");
2088*4882a593Smuzhiyun err = wl_ext_wl_iovar(dev, cmd, total_len);
2089*4882a593Smuzhiyun if (err)
2090*4882a593Smuzhiyun goto exit;
2091*4882a593Smuzhiyun dhd->recv_probereq = TRUE;
2092*4882a593Smuzhiyun } else {
2093*4882a593Smuzhiyun if (dhd->conf->pm) {
2094*4882a593Smuzhiyun strcpy(cmd, "wl 86 2");
2095*4882a593Smuzhiyun wl_ext_wl_iovar(dev, cmd, total_len);
2096*4882a593Smuzhiyun }
2097*4882a593Smuzhiyun strcpy(cmd, "wl event_msg 44 0");
2098*4882a593Smuzhiyun wl_ext_wl_iovar(dev, cmd, total_len);
2099*4882a593Smuzhiyun dhd->recv_probereq = FALSE;
2100*4882a593Smuzhiyun }
2101*4882a593Smuzhiyun }
2102*4882a593Smuzhiyun
2103*4882a593Smuzhiyun exit:
2104*4882a593Smuzhiyun return err;
2105*4882a593Smuzhiyun }
2106*4882a593Smuzhiyun
2107*4882a593Smuzhiyun static int
wl_ext_recv_probresp(struct net_device * dev,char * data,char * command,int total_len)2108*4882a593Smuzhiyun wl_ext_recv_probresp(struct net_device *dev, char *data, char *command,
2109*4882a593Smuzhiyun int total_len)
2110*4882a593Smuzhiyun {
2111*4882a593Smuzhiyun int err = 0, enable = 0;
2112*4882a593Smuzhiyun char cmd[64];
2113*4882a593Smuzhiyun
2114*4882a593Smuzhiyun /* enable:
2115*4882a593Smuzhiyun 1. dhd_priv wl pkt_filter_add 150 0 0 0 0xFF 0x50
2116*4882a593Smuzhiyun 2. dhd_priv wl pkt_filter_enable 150 1
2117*4882a593Smuzhiyun 3. dhd_priv wl mpc 0
2118*4882a593Smuzhiyun 4. dhd_priv wl 108 1
2119*4882a593Smuzhiyun disable:
2120*4882a593Smuzhiyun 1. dhd_priv wl 108 0
2121*4882a593Smuzhiyun 2. dhd_priv wl mpc 1
2122*4882a593Smuzhiyun 3. dhd_priv wl pkt_filter_disable 150 0
2123*4882a593Smuzhiyun 4. dhd_priv pkt_filter_delete 150
2124*4882a593Smuzhiyun */
2125*4882a593Smuzhiyun if (data) {
2126*4882a593Smuzhiyun AEXT_TRACE(dev->name, "data = %s\n", data);
2127*4882a593Smuzhiyun sscanf(data, "%d", &enable);
2128*4882a593Smuzhiyun if (enable) {
2129*4882a593Smuzhiyun strcpy(cmd, "wl pkt_filter_add 150 0 0 0 0xFF 0x50");
2130*4882a593Smuzhiyun err = wl_ext_wl_iovar(dev, cmd, total_len);
2131*4882a593Smuzhiyun if (err)
2132*4882a593Smuzhiyun goto exit;
2133*4882a593Smuzhiyun strcpy(cmd, "wl pkt_filter_enable 150 1");
2134*4882a593Smuzhiyun err = wl_ext_wl_iovar(dev, cmd, total_len);
2135*4882a593Smuzhiyun if (err)
2136*4882a593Smuzhiyun goto exit;
2137*4882a593Smuzhiyun strcpy(cmd, "wl mpc 0");
2138*4882a593Smuzhiyun err = wl_ext_wl_iovar(dev, cmd, total_len);
2139*4882a593Smuzhiyun if (err)
2140*4882a593Smuzhiyun goto exit;
2141*4882a593Smuzhiyun strcpy(cmd, "wl 108 1");
2142*4882a593Smuzhiyun err= wl_ext_wl_iovar(dev, cmd, total_len);
2143*4882a593Smuzhiyun } else {
2144*4882a593Smuzhiyun strcpy(cmd, "wl 108 0");
2145*4882a593Smuzhiyun wl_ext_wl_iovar(dev, cmd, total_len);
2146*4882a593Smuzhiyun strcpy(cmd, "wl mpc 1");
2147*4882a593Smuzhiyun wl_ext_wl_iovar(dev, cmd, total_len);
2148*4882a593Smuzhiyun strcpy(cmd, "wl pkt_filter_enable 150 0");
2149*4882a593Smuzhiyun wl_ext_wl_iovar(dev, cmd, total_len);
2150*4882a593Smuzhiyun strcpy(cmd, "wl pkt_filter_delete 150");
2151*4882a593Smuzhiyun wl_ext_wl_iovar(dev, cmd, total_len);
2152*4882a593Smuzhiyun }
2153*4882a593Smuzhiyun }
2154*4882a593Smuzhiyun
2155*4882a593Smuzhiyun exit:
2156*4882a593Smuzhiyun return err;
2157*4882a593Smuzhiyun }
2158*4882a593Smuzhiyun #endif /* SENDPROB */
2159*4882a593Smuzhiyun
2160*4882a593Smuzhiyun #if defined(USE_IW)
2161*4882a593Smuzhiyun static int
wl_ext_gtk_key_info(struct net_device * dev,char * data,char * command,int total_len)2162*4882a593Smuzhiyun wl_ext_gtk_key_info(struct net_device *dev, char *data, char *command, int total_len)
2163*4882a593Smuzhiyun {
2164*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
2165*4882a593Smuzhiyun int err = 0;
2166*4882a593Smuzhiyun char iovar_buf[WLC_IOCTL_SMLEN]="\0";
2167*4882a593Smuzhiyun gtk_keyinfo_t keyinfo;
2168*4882a593Smuzhiyun bcol_gtk_para_t bcol_keyinfo;
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun /* wl gtk_key_info [kck kek replay_ctr] */
2171*4882a593Smuzhiyun /* wl gtk_key_info 001122..FF001122..FF00000000000001 */
2172*4882a593Smuzhiyun if (data) {
2173*4882a593Smuzhiyun if (!dhd->conf->rekey_offload) {
2174*4882a593Smuzhiyun AEXT_INFO(dev->name, "rekey_offload disabled\n");
2175*4882a593Smuzhiyun return BCME_UNSUPPORTED;
2176*4882a593Smuzhiyun }
2177*4882a593Smuzhiyun
2178*4882a593Smuzhiyun memset(&bcol_keyinfo, 0, sizeof(bcol_keyinfo));
2179*4882a593Smuzhiyun bcol_keyinfo.enable = 1;
2180*4882a593Smuzhiyun bcol_keyinfo.ptk_len = 64;
2181*4882a593Smuzhiyun memcpy(&bcol_keyinfo.ptk, data, RSN_KCK_LENGTH+RSN_KEK_LENGTH);
2182*4882a593Smuzhiyun err = wl_ext_iovar_setbuf(dev, "bcol_gtk_rekey_ptk", &bcol_keyinfo,
2183*4882a593Smuzhiyun sizeof(bcol_keyinfo), iovar_buf, sizeof(iovar_buf), NULL);
2184*4882a593Smuzhiyun if (!err) {
2185*4882a593Smuzhiyun goto exit;
2186*4882a593Smuzhiyun }
2187*4882a593Smuzhiyun
2188*4882a593Smuzhiyun memset(&keyinfo, 0, sizeof(keyinfo));
2189*4882a593Smuzhiyun memcpy(&keyinfo, data, RSN_KCK_LENGTH+RSN_KEK_LENGTH+RSN_REPLAY_LEN);
2190*4882a593Smuzhiyun err = wl_ext_iovar_setbuf(dev, "gtk_key_info", &keyinfo, sizeof(keyinfo),
2191*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
2192*4882a593Smuzhiyun if (err) {
2193*4882a593Smuzhiyun AEXT_ERROR(dev->name, "failed to set gtk_key_info\n");
2194*4882a593Smuzhiyun return err;
2195*4882a593Smuzhiyun }
2196*4882a593Smuzhiyun }
2197*4882a593Smuzhiyun
2198*4882a593Smuzhiyun exit:
2199*4882a593Smuzhiyun if (android_msg_level & ANDROID_INFO_LEVEL) {
2200*4882a593Smuzhiyun prhex("kck", (uchar *)keyinfo.KCK, RSN_KCK_LENGTH);
2201*4882a593Smuzhiyun prhex("kek", (uchar *)keyinfo.KEK, RSN_KEK_LENGTH);
2202*4882a593Smuzhiyun prhex("replay_ctr", (uchar *)keyinfo.ReplayCounter, RSN_REPLAY_LEN);
2203*4882a593Smuzhiyun }
2204*4882a593Smuzhiyun return err;
2205*4882a593Smuzhiyun }
2206*4882a593Smuzhiyun #endif /* USE_IW */
2207*4882a593Smuzhiyun
2208*4882a593Smuzhiyun #ifdef WL_EXT_WOWL
2209*4882a593Smuzhiyun static int
wl_ext_wowl_pattern(struct net_device * dev,char * data,char * command,int total_len)2210*4882a593Smuzhiyun wl_ext_wowl_pattern(struct net_device *dev, char *data, char *command,
2211*4882a593Smuzhiyun int total_len)
2212*4882a593Smuzhiyun {
2213*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
2214*4882a593Smuzhiyun uint buf_len = 0;
2215*4882a593Smuzhiyun int offset;
2216*4882a593Smuzhiyun char mask[128]="\0", pattern[128]="\0", add[4]="\0",
2217*4882a593Smuzhiyun mask_tmp[128], *pmask_tmp;
2218*4882a593Smuzhiyun uint32 masksize, patternsize, pad_len = 0;
2219*4882a593Smuzhiyun wl_wowl_pattern2_t *wowl_pattern2 = NULL;
2220*4882a593Smuzhiyun wl_wowl_pattern_t *wowl_pattern = NULL;
2221*4882a593Smuzhiyun char *mask_and_pattern;
2222*4882a593Smuzhiyun wl_wowl_pattern_list_t *list;
2223*4882a593Smuzhiyun uint8 *ptr;
2224*4882a593Smuzhiyun int ret = 0, i, j, v;
2225*4882a593Smuzhiyun
2226*4882a593Smuzhiyun if (data) {
2227*4882a593Smuzhiyun sscanf(data, "%s %d %s %s", add, &offset, mask_tmp, pattern);
2228*4882a593Smuzhiyun if (strcmp(add, "add") != 0 && strcmp(add, "clr") != 0) {
2229*4882a593Smuzhiyun AEXT_ERROR(dev->name, "first arg should be add or clr\n");
2230*4882a593Smuzhiyun goto exit;
2231*4882a593Smuzhiyun }
2232*4882a593Smuzhiyun if (!strcmp(add, "clr")) {
2233*4882a593Smuzhiyun AEXT_INFO(dev->name, "wowl_pattern clr\n");
2234*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "wowl_pattern", add,
2235*4882a593Smuzhiyun sizeof(add), iovar_buf, sizeof(iovar_buf), NULL);
2236*4882a593Smuzhiyun goto exit;
2237*4882a593Smuzhiyun }
2238*4882a593Smuzhiyun masksize = strlen(mask_tmp) -2;
2239*4882a593Smuzhiyun AEXT_TRACE(dev->name, "0 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2240*4882a593Smuzhiyun
2241*4882a593Smuzhiyun // add pading
2242*4882a593Smuzhiyun if (masksize % 16)
2243*4882a593Smuzhiyun pad_len = (16 - masksize % 16);
2244*4882a593Smuzhiyun for (i=0; i<pad_len; i++)
2245*4882a593Smuzhiyun strcat(mask_tmp, "0");
2246*4882a593Smuzhiyun masksize += pad_len;
2247*4882a593Smuzhiyun AEXT_TRACE(dev->name, "1 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun // translate 0x00 to 0, others to 1
2250*4882a593Smuzhiyun j = 0;
2251*4882a593Smuzhiyun pmask_tmp = &mask_tmp[2];
2252*4882a593Smuzhiyun for (i=0; i<masksize/2; i++) {
2253*4882a593Smuzhiyun if(strncmp(&pmask_tmp[i*2], "00", 2))
2254*4882a593Smuzhiyun pmask_tmp[j] = '1';
2255*4882a593Smuzhiyun else
2256*4882a593Smuzhiyun pmask_tmp[j] = '0';
2257*4882a593Smuzhiyun j++;
2258*4882a593Smuzhiyun }
2259*4882a593Smuzhiyun pmask_tmp[j] = '\0';
2260*4882a593Smuzhiyun masksize = masksize / 2;
2261*4882a593Smuzhiyun AEXT_TRACE(dev->name, "2 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2262*4882a593Smuzhiyun
2263*4882a593Smuzhiyun // reorder per 8bits
2264*4882a593Smuzhiyun pmask_tmp = &mask_tmp[2];
2265*4882a593Smuzhiyun for (i=0; i<masksize/8; i++) {
2266*4882a593Smuzhiyun char c;
2267*4882a593Smuzhiyun for (j=0; j<4; j++) {
2268*4882a593Smuzhiyun c = pmask_tmp[i*8+j];
2269*4882a593Smuzhiyun pmask_tmp[i*8+j] = pmask_tmp[(i+1)*8-j-1];
2270*4882a593Smuzhiyun pmask_tmp[(i+1)*8-j-1] = c;
2271*4882a593Smuzhiyun }
2272*4882a593Smuzhiyun }
2273*4882a593Smuzhiyun AEXT_TRACE(dev->name, "3 mask_tmp=%s, masksize=%d\n", mask_tmp, masksize);
2274*4882a593Smuzhiyun
2275*4882a593Smuzhiyun // translate 8bits to 1byte
2276*4882a593Smuzhiyun j = 0; v = 0;
2277*4882a593Smuzhiyun pmask_tmp = &mask_tmp[2];
2278*4882a593Smuzhiyun strcpy(mask, "0x");
2279*4882a593Smuzhiyun for (i=0; i<masksize; i++) {
2280*4882a593Smuzhiyun v = (v<<1) | (pmask_tmp[i]=='1');
2281*4882a593Smuzhiyun if (((i+1)%4) == 0) {
2282*4882a593Smuzhiyun if (v < 10)
2283*4882a593Smuzhiyun mask[j+2] = v + '0';
2284*4882a593Smuzhiyun else
2285*4882a593Smuzhiyun mask[j+2] = (v-10) + 'a';
2286*4882a593Smuzhiyun j++;
2287*4882a593Smuzhiyun v = 0;
2288*4882a593Smuzhiyun }
2289*4882a593Smuzhiyun }
2290*4882a593Smuzhiyun mask[j+2] = '\0';
2291*4882a593Smuzhiyun masksize = j/2;
2292*4882a593Smuzhiyun AEXT_TRACE(dev->name, "4 mask=%s, masksize=%d\n", mask, masksize);
2293*4882a593Smuzhiyun
2294*4882a593Smuzhiyun patternsize = (strlen(pattern)-2)/2;
2295*4882a593Smuzhiyun buf_len = sizeof(wl_wowl_pattern2_t) + patternsize + masksize;
2296*4882a593Smuzhiyun wowl_pattern2 = kmalloc(buf_len, GFP_KERNEL);
2297*4882a593Smuzhiyun if (wowl_pattern2 == NULL) {
2298*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", buf_len);
2299*4882a593Smuzhiyun goto exit;
2300*4882a593Smuzhiyun }
2301*4882a593Smuzhiyun memset(wowl_pattern2, 0, sizeof(wl_wowl_pattern2_t));
2302*4882a593Smuzhiyun
2303*4882a593Smuzhiyun strncpy(wowl_pattern2->cmd, add, sizeof(add));
2304*4882a593Smuzhiyun wowl_pattern2->wowl_pattern.type = 0;
2305*4882a593Smuzhiyun wowl_pattern2->wowl_pattern.offset = offset;
2306*4882a593Smuzhiyun mask_and_pattern = (char*)wowl_pattern2 + sizeof(wl_wowl_pattern2_t);
2307*4882a593Smuzhiyun
2308*4882a593Smuzhiyun wowl_pattern2->wowl_pattern.masksize = masksize;
2309*4882a593Smuzhiyun ret = wl_pattern_atoh(mask, mask_and_pattern);
2310*4882a593Smuzhiyun if (ret == -1) {
2311*4882a593Smuzhiyun AEXT_ERROR(dev->name, "rejecting mask=%s\n", mask);
2312*4882a593Smuzhiyun goto exit;
2313*4882a593Smuzhiyun }
2314*4882a593Smuzhiyun
2315*4882a593Smuzhiyun mask_and_pattern += wowl_pattern2->wowl_pattern.masksize;
2316*4882a593Smuzhiyun wowl_pattern2->wowl_pattern.patternoffset = sizeof(wl_wowl_pattern_t) +
2317*4882a593Smuzhiyun wowl_pattern2->wowl_pattern.masksize;
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun wowl_pattern2->wowl_pattern.patternsize = patternsize;
2320*4882a593Smuzhiyun ret = wl_pattern_atoh(pattern, mask_and_pattern);
2321*4882a593Smuzhiyun if (ret == -1) {
2322*4882a593Smuzhiyun AEXT_ERROR(dev->name, "rejecting pattern=%s\n", pattern);
2323*4882a593Smuzhiyun goto exit;
2324*4882a593Smuzhiyun }
2325*4882a593Smuzhiyun
2326*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s %d %s %s\n", add, offset, mask, pattern);
2327*4882a593Smuzhiyun
2328*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "wowl_pattern", (char *)wowl_pattern2,
2329*4882a593Smuzhiyun buf_len, iovar_buf, sizeof(iovar_buf), NULL);
2330*4882a593Smuzhiyun }
2331*4882a593Smuzhiyun else {
2332*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "wowl_pattern", NULL, 0,
2333*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
2334*4882a593Smuzhiyun if (!ret) {
2335*4882a593Smuzhiyun list = (wl_wowl_pattern_list_t *)iovar_buf;
2336*4882a593Smuzhiyun ret = snprintf(command, total_len, "#of patterns :%d\n", list->count);
2337*4882a593Smuzhiyun ptr = (uint8 *)list->pattern;
2338*4882a593Smuzhiyun for (i=0; i<list->count; i++) {
2339*4882a593Smuzhiyun uint8 *pattern;
2340*4882a593Smuzhiyun wowl_pattern = (wl_wowl_pattern_t *)ptr;
2341*4882a593Smuzhiyun ret += snprintf(command+ret, total_len,
2342*4882a593Smuzhiyun "Pattern %d:\n"
2343*4882a593Smuzhiyun "ID :0x%x\n"
2344*4882a593Smuzhiyun "Offset :%d\n"
2345*4882a593Smuzhiyun "Masksize :%d\n"
2346*4882a593Smuzhiyun "Mask :0x",
2347*4882a593Smuzhiyun i+1, (uint32)wowl_pattern->id, wowl_pattern->offset,
2348*4882a593Smuzhiyun wowl_pattern->masksize);
2349*4882a593Smuzhiyun pattern = ((uint8 *)wowl_pattern + sizeof(wl_wowl_pattern_t));
2350*4882a593Smuzhiyun for (j = 0; j < wowl_pattern->masksize; j++) {
2351*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, "%02x", pattern[j]);
2352*4882a593Smuzhiyun }
2353*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, "\n");
2354*4882a593Smuzhiyun ret += snprintf(command+ret, total_len,
2355*4882a593Smuzhiyun "PatternSize:%d\n"
2356*4882a593Smuzhiyun "Pattern :0x",
2357*4882a593Smuzhiyun wowl_pattern->patternsize);
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun pattern = ((uint8*)wowl_pattern + wowl_pattern->patternoffset);
2360*4882a593Smuzhiyun for (j=0; j<wowl_pattern->patternsize; j++)
2361*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, "%02x", pattern[j]);
2362*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, "\n");
2363*4882a593Smuzhiyun ptr += (wowl_pattern->masksize + wowl_pattern->patternsize +
2364*4882a593Smuzhiyun sizeof(wl_wowl_pattern_t));
2365*4882a593Smuzhiyun }
2366*4882a593Smuzhiyun
2367*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s\n", command);
2368*4882a593Smuzhiyun }
2369*4882a593Smuzhiyun }
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun exit:
2372*4882a593Smuzhiyun if (wowl_pattern2)
2373*4882a593Smuzhiyun kfree(wowl_pattern2);
2374*4882a593Smuzhiyun return ret;
2375*4882a593Smuzhiyun }
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun static int
wl_ext_wowl_wakeind(struct net_device * dev,char * data,char * command,int total_len)2378*4882a593Smuzhiyun wl_ext_wowl_wakeind(struct net_device *dev, char *data, char *command,
2379*4882a593Smuzhiyun int total_len)
2380*4882a593Smuzhiyun {
2381*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
2382*4882a593Smuzhiyun wl_wowl_wakeind_t *wake = NULL;
2383*4882a593Smuzhiyun int ret = -1;
2384*4882a593Smuzhiyun char clr[6]="\0";
2385*4882a593Smuzhiyun
2386*4882a593Smuzhiyun if (data) {
2387*4882a593Smuzhiyun sscanf(data, "%s", clr);
2388*4882a593Smuzhiyun if (!strcmp(clr, "clear")) {
2389*4882a593Smuzhiyun AEXT_INFO(dev->name, "wowl_wakeind clear\n");
2390*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "wowl_wakeind", clr, sizeof(clr),
2391*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
2392*4882a593Smuzhiyun } else {
2393*4882a593Smuzhiyun AEXT_ERROR(dev->name, "first arg should be clear\n");
2394*4882a593Smuzhiyun }
2395*4882a593Smuzhiyun } else {
2396*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "wowl_wakeind", NULL, 0,
2397*4882a593Smuzhiyun iovar_buf, sizeof(iovar_buf), NULL);
2398*4882a593Smuzhiyun if (!ret) {
2399*4882a593Smuzhiyun wake = (wl_wowl_wakeind_t *) iovar_buf;
2400*4882a593Smuzhiyun ret = snprintf(command, total_len, "wakeind=0x%x", wake->ucode_wakeind);
2401*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_MAGIC)
2402*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (MAGIC packet)");
2403*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_NET)
2404*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (Netpattern)");
2405*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_DIS)
2406*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (Disassoc/Deauth)");
2407*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_BCN)
2408*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (Loss of beacon)");
2409*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_TIME)
2410*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (TCPKA timeout)");
2411*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_TCPKEEP_DATA)
2412*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (TCPKA data)");
2413*4882a593Smuzhiyun if (wake->ucode_wakeind & WL_WOWL_TCPFIN)
2414*4882a593Smuzhiyun ret += snprintf(command+ret, total_len, " (TCP FIN)");
2415*4882a593Smuzhiyun AEXT_INFO(dev->name, "%s\n", command);
2416*4882a593Smuzhiyun }
2417*4882a593Smuzhiyun }
2418*4882a593Smuzhiyun
2419*4882a593Smuzhiyun return ret;
2420*4882a593Smuzhiyun }
2421*4882a593Smuzhiyun #endif /* WL_EXT_WOWL */
2422*4882a593Smuzhiyun
2423*4882a593Smuzhiyun #ifdef WL_GPIO_NOTIFY
2424*4882a593Smuzhiyun typedef struct notify_payload {
2425*4882a593Smuzhiyun int index;
2426*4882a593Smuzhiyun int len;
2427*4882a593Smuzhiyun char payload[128];
2428*4882a593Smuzhiyun } notify_payload_t;
2429*4882a593Smuzhiyun
2430*4882a593Smuzhiyun static int
wl_ext_gpio_notify(struct net_device * dev,char * data,char * command,int total_len)2431*4882a593Smuzhiyun wl_ext_gpio_notify(struct net_device *dev, char *data, char *command,
2432*4882a593Smuzhiyun int total_len)
2433*4882a593Smuzhiyun {
2434*4882a593Smuzhiyun s8 iovar_buf[WLC_IOCTL_SMLEN];
2435*4882a593Smuzhiyun notify_payload_t notify, *pnotify = NULL;
2436*4882a593Smuzhiyun int i, ret = 0, bytes_written = 0;
2437*4882a593Smuzhiyun char frame_str[WLC_IOCTL_SMLEN+3];
2438*4882a593Smuzhiyun
2439*4882a593Smuzhiyun if (data) {
2440*4882a593Smuzhiyun memset(¬ify, 0, sizeof(notify));
2441*4882a593Smuzhiyun memset(frame_str, 0, sizeof(frame_str));
2442*4882a593Smuzhiyun sscanf(data, "%d %s", ¬ify.index, frame_str);
2443*4882a593Smuzhiyun
2444*4882a593Smuzhiyun if (notify.index < 0)
2445*4882a593Smuzhiyun notify.index = 0;
2446*4882a593Smuzhiyun
2447*4882a593Smuzhiyun if (strlen(frame_str)) {
2448*4882a593Smuzhiyun notify.len = wl_pattern_atoh(frame_str, notify.payload);
2449*4882a593Smuzhiyun if (notify.len == -1) {
2450*4882a593Smuzhiyun AEXT_ERROR(dev->name, "rejecting pattern=%s\n", frame_str);
2451*4882a593Smuzhiyun goto exit;
2452*4882a593Smuzhiyun }
2453*4882a593Smuzhiyun AEXT_INFO(dev->name, "index=%d, len=%d\n", notify.index, notify.len);
2454*4882a593Smuzhiyun if (android_msg_level & ANDROID_INFO_LEVEL)
2455*4882a593Smuzhiyun prhex("payload", (uchar *)notify.payload, notify.len);
2456*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "bcol_gpio_noti", (char *)¬ify,
2457*4882a593Smuzhiyun sizeof(notify), iovar_buf, WLC_IOCTL_SMLEN, NULL);
2458*4882a593Smuzhiyun } else {
2459*4882a593Smuzhiyun AEXT_INFO(dev->name, "index=%d\n", notify.index);
2460*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "bcol_gpio_noti", ¬ify.index,
2461*4882a593Smuzhiyun sizeof(notify.index), iovar_buf, sizeof(iovar_buf), NULL);
2462*4882a593Smuzhiyun if (!ret) {
2463*4882a593Smuzhiyun pnotify = (notify_payload_t *)iovar_buf;
2464*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
2465*4882a593Smuzhiyun "Id :%d\n"
2466*4882a593Smuzhiyun "Packet :0x",
2467*4882a593Smuzhiyun pnotify->index);
2468*4882a593Smuzhiyun for (i=0; i<pnotify->len; i++) {
2469*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
2470*4882a593Smuzhiyun "%02x", pnotify->payload[i]);
2471*4882a593Smuzhiyun }
2472*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is\n%s\n", command);
2473*4882a593Smuzhiyun ret = bytes_written;
2474*4882a593Smuzhiyun }
2475*4882a593Smuzhiyun }
2476*4882a593Smuzhiyun }
2477*4882a593Smuzhiyun
2478*4882a593Smuzhiyun exit:
2479*4882a593Smuzhiyun return ret;
2480*4882a593Smuzhiyun }
2481*4882a593Smuzhiyun #endif /* WL_GPIO_NOTIFY */
2482*4882a593Smuzhiyun
2483*4882a593Smuzhiyun #ifdef CSI_SUPPORT
2484*4882a593Smuzhiyun typedef struct csi_config {
2485*4882a593Smuzhiyun /* Peer device mac address. */
2486*4882a593Smuzhiyun struct ether_addr addr;
2487*4882a593Smuzhiyun /* BW to be used in the measurements. This needs to be supported both by the */
2488*4882a593Smuzhiyun /* device itself and the peer. */
2489*4882a593Smuzhiyun uint32 bw;
2490*4882a593Smuzhiyun /* Time interval between measurements (units: 1 ms). */
2491*4882a593Smuzhiyun uint32 period;
2492*4882a593Smuzhiyun /* CSI method */
2493*4882a593Smuzhiyun uint32 method;
2494*4882a593Smuzhiyun } csi_config_t;
2495*4882a593Smuzhiyun
2496*4882a593Smuzhiyun typedef struct csi_list {
2497*4882a593Smuzhiyun uint32 cnt;
2498*4882a593Smuzhiyun csi_config_t configs[1];
2499*4882a593Smuzhiyun } csi_list_t;
2500*4882a593Smuzhiyun
2501*4882a593Smuzhiyun static int
wl_ext_csi(struct net_device * dev,char * data,char * command,int total_len)2502*4882a593Smuzhiyun wl_ext_csi(struct net_device *dev, char *data, char *command, int total_len)
2503*4882a593Smuzhiyun {
2504*4882a593Smuzhiyun csi_config_t csi, *csip;
2505*4882a593Smuzhiyun csi_list_t *csi_list;
2506*4882a593Smuzhiyun int ret = -1, period=-1, i;
2507*4882a593Smuzhiyun char mac[32], *buf = NULL;
2508*4882a593Smuzhiyun struct ether_addr ea;
2509*4882a593Smuzhiyun int bytes_written = 0;
2510*4882a593Smuzhiyun
2511*4882a593Smuzhiyun buf = kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
2512*4882a593Smuzhiyun if (buf == NULL) {
2513*4882a593Smuzhiyun AEXT_ERROR(dev->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
2514*4882a593Smuzhiyun goto exit;
2515*4882a593Smuzhiyun }
2516*4882a593Smuzhiyun memset(buf, 0, WLC_IOCTL_SMLEN);
2517*4882a593Smuzhiyun
2518*4882a593Smuzhiyun if (data) {
2519*4882a593Smuzhiyun sscanf(data, "%s %d", mac, &period);
2520*4882a593Smuzhiyun ret = bcm_ether_atoe(mac, &ea);
2521*4882a593Smuzhiyun if (!ret) {
2522*4882a593Smuzhiyun AEXT_ERROR(dev->name, "rejecting mac=%s, ret=%d\n", mac, ret);
2523*4882a593Smuzhiyun goto exit;
2524*4882a593Smuzhiyun }
2525*4882a593Smuzhiyun AEXT_TRACE(dev->name, "mac=%pM, period=%d", &ea, period);
2526*4882a593Smuzhiyun if (period > 0) {
2527*4882a593Smuzhiyun memset(&csi, 0, sizeof(csi_config_t));
2528*4882a593Smuzhiyun bcopy(&ea, &csi.addr, ETHER_ADDR_LEN);
2529*4882a593Smuzhiyun csi.period = period;
2530*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "csi", (char *)&csi, sizeof(csi),
2531*4882a593Smuzhiyun buf, WLC_IOCTL_SMLEN, NULL);
2532*4882a593Smuzhiyun } else if (period == 0) {
2533*4882a593Smuzhiyun memset(&csi, 0, sizeof(csi_config_t));
2534*4882a593Smuzhiyun bcopy(&ea, &csi.addr, ETHER_ADDR_LEN);
2535*4882a593Smuzhiyun ret = wl_ext_iovar_setbuf(dev, "csi_del", (char *)&csi, sizeof(csi),
2536*4882a593Smuzhiyun buf, WLC_IOCTL_SMLEN, NULL);
2537*4882a593Smuzhiyun } else {
2538*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "csi", &ea, ETHER_ADDR_LEN, buf,
2539*4882a593Smuzhiyun WLC_IOCTL_SMLEN, NULL);
2540*4882a593Smuzhiyun if (!ret) {
2541*4882a593Smuzhiyun csip = (csi_config_t *) buf;
2542*4882a593Smuzhiyun /* Dump all lists */
2543*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
2544*4882a593Smuzhiyun "Mac :%pM\n"
2545*4882a593Smuzhiyun "Period :%d\n"
2546*4882a593Smuzhiyun "BW :%d\n"
2547*4882a593Smuzhiyun "Method :%d\n",
2548*4882a593Smuzhiyun &csip->addr, csip->period, csip->bw, csip->method);
2549*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
2550*4882a593Smuzhiyun ret = bytes_written;
2551*4882a593Smuzhiyun }
2552*4882a593Smuzhiyun }
2553*4882a593Smuzhiyun }
2554*4882a593Smuzhiyun else {
2555*4882a593Smuzhiyun ret = wl_ext_iovar_getbuf(dev, "csi_list", NULL, 0, buf, WLC_IOCTL_SMLEN, NULL);
2556*4882a593Smuzhiyun if (!ret) {
2557*4882a593Smuzhiyun csi_list = (csi_list_t *)buf;
2558*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
2559*4882a593Smuzhiyun "Total number :%d\n", csi_list->cnt);
2560*4882a593Smuzhiyun for (i=0; i<csi_list->cnt; i++) {
2561*4882a593Smuzhiyun csip = &csi_list->configs[i];
2562*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
2563*4882a593Smuzhiyun "Idx :%d\n"
2564*4882a593Smuzhiyun "Mac :%pM\n"
2565*4882a593Smuzhiyun "Period :%d\n"
2566*4882a593Smuzhiyun "BW :%d\n"
2567*4882a593Smuzhiyun "Method :%d\n\n",
2568*4882a593Smuzhiyun i+1, &csip->addr, csip->period, csip->bw, csip->method);
2569*4882a593Smuzhiyun }
2570*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
2571*4882a593Smuzhiyun ret = bytes_written;
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun }
2574*4882a593Smuzhiyun
2575*4882a593Smuzhiyun exit:
2576*4882a593Smuzhiyun if (buf)
2577*4882a593Smuzhiyun kfree(buf);
2578*4882a593Smuzhiyun return ret;
2579*4882a593Smuzhiyun }
2580*4882a593Smuzhiyun #endif /* CSI_SUPPORT */
2581*4882a593Smuzhiyun
2582*4882a593Smuzhiyun static int
wl_ext_get_country(struct net_device * dev,char * data,char * command,int total_len)2583*4882a593Smuzhiyun wl_ext_get_country(struct net_device *dev, char *data, char *command,
2584*4882a593Smuzhiyun int total_len)
2585*4882a593Smuzhiyun {
2586*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
2587*4882a593Smuzhiyun wl_country_t cspec = {{0}, 0, {0}};
2588*4882a593Smuzhiyun int bytes_written = 0, ret = 0;
2589*4882a593Smuzhiyun
2590*4882a593Smuzhiyun if (data) {
2591*4882a593Smuzhiyun char *country_code = data;
2592*4882a593Smuzhiyun char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
2593*4882a593Smuzhiyun int revinfo = 0;
2594*4882a593Smuzhiyun if ((rev_info_delim) &&
2595*4882a593Smuzhiyun (strnicmp(rev_info_delim, "/", strlen("/")) == 0) && (rev_info_delim + 1)) {
2596*4882a593Smuzhiyun revinfo = bcm_atoi(rev_info_delim + 1);
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun #ifdef WL_CFG80211
2599*4882a593Smuzhiyun bytes_written = wl_cfg80211_set_country_code(dev, country_code,
2600*4882a593Smuzhiyun true, true, revinfo);
2601*4882a593Smuzhiyun #else
2602*4882a593Smuzhiyun bytes_written = wldev_set_country(dev, country_code, true, true, revinfo);
2603*4882a593Smuzhiyun #endif /* WL_CFG80211 */
2604*4882a593Smuzhiyun } else {
2605*4882a593Smuzhiyun ret = dhd_conf_get_country(dhd, &cspec);
2606*4882a593Smuzhiyun if (!ret) {
2607*4882a593Smuzhiyun bytes_written += snprintf(command+bytes_written, total_len,
2608*4882a593Smuzhiyun "%s/%d", cspec.ccode, cspec.rev);
2609*4882a593Smuzhiyun }
2610*4882a593Smuzhiyun if (!bytes_written)
2611*4882a593Smuzhiyun bytes_written = -1;
2612*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
2613*4882a593Smuzhiyun }
2614*4882a593Smuzhiyun
2615*4882a593Smuzhiyun return bytes_written;
2616*4882a593Smuzhiyun }
2617*4882a593Smuzhiyun
2618*4882a593Smuzhiyun static int
wl_ext_disable_5g_band(struct net_device * dev,char * data,char * command,int total_len)2619*4882a593Smuzhiyun wl_ext_disable_5g_band(struct net_device *dev, char *data, char *command,
2620*4882a593Smuzhiyun int total_len)
2621*4882a593Smuzhiyun {
2622*4882a593Smuzhiyun #ifdef WL_CFG80211
2623*4882a593Smuzhiyun struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
2624*4882a593Smuzhiyun #endif
2625*4882a593Smuzhiyun int ret = -1;
2626*4882a593Smuzhiyun int val;
2627*4882a593Smuzhiyun
2628*4882a593Smuzhiyun if (data) {
2629*4882a593Smuzhiyun val = (int)simple_strtol(data, NULL, 0);
2630*4882a593Smuzhiyun ret = wl_ext_iovar_setint(dev, "disable_5g_band", val);
2631*4882a593Smuzhiyun #ifdef WL_CFG80211
2632*4882a593Smuzhiyun if (!ret)
2633*4882a593Smuzhiyun wl_update_wiphybands(cfg, true);
2634*4882a593Smuzhiyun #endif
2635*4882a593Smuzhiyun } else {
2636*4882a593Smuzhiyun ret = wl_ext_iovar_getint(dev, "disable_5g_band", &val);
2637*4882a593Smuzhiyun if (!ret) {
2638*4882a593Smuzhiyun ret = snprintf(command, total_len, "%d", val);
2639*4882a593Smuzhiyun AEXT_TRACE(dev->name, "command result is %s\n", command);
2640*4882a593Smuzhiyun }
2641*4882a593Smuzhiyun }
2642*4882a593Smuzhiyun
2643*4882a593Smuzhiyun return ret;
2644*4882a593Smuzhiyun }
2645*4882a593Smuzhiyun
2646*4882a593Smuzhiyun typedef int (wl_ext_tpl_parse_t)(struct net_device *dev, char *data, char *command,
2647*4882a593Smuzhiyun int total_len);
2648*4882a593Smuzhiyun
2649*4882a593Smuzhiyun typedef struct wl_ext_iovar_tpl_t {
2650*4882a593Smuzhiyun int get;
2651*4882a593Smuzhiyun int set;
2652*4882a593Smuzhiyun char *name;
2653*4882a593Smuzhiyun wl_ext_tpl_parse_t *parse;
2654*4882a593Smuzhiyun } wl_ext_iovar_tpl_t;
2655*4882a593Smuzhiyun
2656*4882a593Smuzhiyun const wl_ext_iovar_tpl_t wl_ext_iovar_tpl_list[] = {
2657*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "event_msg", wl_ext_event_msg},
2658*4882a593Smuzhiyun #if defined(USE_IW)
2659*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "gtk_key_info", wl_ext_gtk_key_info},
2660*4882a593Smuzhiyun #endif /* USE_IW */
2661*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "recal", wl_ext_recal},
2662*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "rsdb_mode", wl_ext_rsdb_mode},
2663*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "mkeep_alive", wl_ext_mkeep_alive},
2664*4882a593Smuzhiyun #ifdef PKT_FILTER_SUPPORT
2665*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "pkt_filter_add", wl_ext_pkt_filter_add},
2666*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "pkt_filter_delete", wl_ext_pkt_filter_delete},
2667*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "pkt_filter_enable", wl_ext_pkt_filter_enable},
2668*4882a593Smuzhiyun #endif /* PKT_FILTER_SUPPORT */
2669*4882a593Smuzhiyun #if defined(WL_EXT_IAPSTA) && defined(WLMESH)
2670*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "mesh_peer_status", wl_ext_mesh_peer_status},
2671*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA && WLMESH */
2672*4882a593Smuzhiyun #ifdef SENDPROB
2673*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "send_probreq", wl_ext_send_probreq},
2674*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "send_probresp", wl_ext_send_probresp},
2675*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "recv_probreq", wl_ext_recv_probreq},
2676*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "recv_probresp", wl_ext_recv_probresp},
2677*4882a593Smuzhiyun #endif /* SENDPROB */
2678*4882a593Smuzhiyun #ifdef WL_EXT_TCPKA
2679*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "tcpka_conn_add", wl_ext_tcpka_conn_add},
2680*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "tcpka_conn_enable", wl_ext_tcpka_conn_enable},
2681*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "tcpka_conn_sess_info", wl_ext_tcpka_conn_info},
2682*4882a593Smuzhiyun #endif /* WL_EXT_TCPKA */
2683*4882a593Smuzhiyun #ifdef WL_EXT_WOWL
2684*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "wowl_pattern", wl_ext_wowl_pattern},
2685*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "wowl_wakeind", wl_ext_wowl_wakeind},
2686*4882a593Smuzhiyun #endif /* WL_EXT_WOWL */
2687*4882a593Smuzhiyun #ifdef IDHCP
2688*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "dhcpc_dump", wl_ext_dhcpc_dump},
2689*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "dhcpc_param", wl_ext_dhcpc_param},
2690*4882a593Smuzhiyun #endif /* IDHCP */
2691*4882a593Smuzhiyun #ifdef WL_GPIO_NOTIFY
2692*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "bcol_gpio_noti", wl_ext_gpio_notify},
2693*4882a593Smuzhiyun #endif /* WL_GPIO_NOTIFY */
2694*4882a593Smuzhiyun #ifdef CSI_SUPPORT
2695*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "csi", wl_ext_csi},
2696*4882a593Smuzhiyun #endif /* CSI_SUPPORT */
2697*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "country", wl_ext_get_country},
2698*4882a593Smuzhiyun {WLC_GET_VAR, WLC_SET_VAR, "disable_5g_band", wl_ext_disable_5g_band},
2699*4882a593Smuzhiyun };
2700*4882a593Smuzhiyun
2701*4882a593Smuzhiyun /*
2702*4882a593Smuzhiyun Ex: dhd_priv wl [cmd] [val]
2703*4882a593Smuzhiyun dhd_priv wl 85
2704*4882a593Smuzhiyun dhd_priv wl 86 1
2705*4882a593Smuzhiyun dhd_priv wl mpc
2706*4882a593Smuzhiyun dhd_priv wl mpc 1
2707*4882a593Smuzhiyun */
2708*4882a593Smuzhiyun static int
wl_ext_wl_iovar(struct net_device * dev,char * command,int total_len)2709*4882a593Smuzhiyun wl_ext_wl_iovar(struct net_device *dev, char *command, int total_len)
2710*4882a593Smuzhiyun {
2711*4882a593Smuzhiyun int cmd, val, ret = -1, i;
2712*4882a593Smuzhiyun char name[32], *pch, *pick_tmp, *data;
2713*4882a593Smuzhiyun int bytes_written=-1;
2714*4882a593Smuzhiyun const wl_ext_iovar_tpl_t *tpl = wl_ext_iovar_tpl_list;
2715*4882a593Smuzhiyun int tpl_count = ARRAY_SIZE(wl_ext_iovar_tpl_list);
2716*4882a593Smuzhiyun char *pEnd;
2717*4882a593Smuzhiyun
2718*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s\n", command);
2719*4882a593Smuzhiyun pick_tmp = command;
2720*4882a593Smuzhiyun
2721*4882a593Smuzhiyun pch = bcmstrtok(&pick_tmp, " ", 0); // pick wl
2722*4882a593Smuzhiyun if (!pch || strncmp(pch, "wl", 2))
2723*4882a593Smuzhiyun goto exit;
2724*4882a593Smuzhiyun
2725*4882a593Smuzhiyun pch = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
2726*4882a593Smuzhiyun if (!pch)
2727*4882a593Smuzhiyun goto exit;
2728*4882a593Smuzhiyun
2729*4882a593Smuzhiyun memset(name, 0 , sizeof (name));
2730*4882a593Smuzhiyun cmd = bcm_strtoul(pch, &pEnd, 0);
2731*4882a593Smuzhiyun if (cmd == 0 || strlen(pEnd)) {
2732*4882a593Smuzhiyun strcpy(name, pch);
2733*4882a593Smuzhiyun }
2734*4882a593Smuzhiyun data = bcmstrtok(&pick_tmp, "", 0); // pick data
2735*4882a593Smuzhiyun if (data && (cmd == 0|| strlen(pEnd))) {
2736*4882a593Smuzhiyun cmd = WLC_SET_VAR;
2737*4882a593Smuzhiyun } else if (cmd == 0|| strlen(pEnd)) {
2738*4882a593Smuzhiyun cmd = WLC_GET_VAR;
2739*4882a593Smuzhiyun }
2740*4882a593Smuzhiyun
2741*4882a593Smuzhiyun /* look for a matching code in the table */
2742*4882a593Smuzhiyun for (i = 0; i < tpl_count; i++, tpl++) {
2743*4882a593Smuzhiyun if ((tpl->get == cmd || tpl->set == cmd) && !strcmp(tpl->name, name))
2744*4882a593Smuzhiyun break;
2745*4882a593Smuzhiyun }
2746*4882a593Smuzhiyun if (i < tpl_count && tpl->parse) {
2747*4882a593Smuzhiyun ret = tpl->parse(dev, data, command, total_len);
2748*4882a593Smuzhiyun } else {
2749*4882a593Smuzhiyun if (cmd == WLC_SET_VAR) {
2750*4882a593Smuzhiyun val = (int)simple_strtol(data, NULL, 0);
2751*4882a593Smuzhiyun AEXT_INFO(dev->name, "set %s %d\n", name, val);
2752*4882a593Smuzhiyun ret = wl_ext_iovar_setint(dev, name, val);
2753*4882a593Smuzhiyun } else if (cmd == WLC_GET_VAR) {
2754*4882a593Smuzhiyun AEXT_INFO(dev->name, "get %s\n", name);
2755*4882a593Smuzhiyun ret = wl_ext_iovar_getint(dev, name, &val);
2756*4882a593Smuzhiyun if (!ret) {
2757*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "%d", val);
2758*4882a593Smuzhiyun AEXT_INFO(dev->name, "command result is %s\n", command);
2759*4882a593Smuzhiyun ret = bytes_written;
2760*4882a593Smuzhiyun }
2761*4882a593Smuzhiyun } else if (data) {
2762*4882a593Smuzhiyun val = (int)simple_strtol(data, NULL, 0);
2763*4882a593Smuzhiyun AEXT_INFO(dev->name, "set %d %d\n", cmd, val);
2764*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), TRUE);
2765*4882a593Smuzhiyun } else {
2766*4882a593Smuzhiyun AEXT_INFO(dev->name, "get %d\n", cmd);
2767*4882a593Smuzhiyun ret = wl_ext_ioctl(dev, cmd, &val, sizeof(val), FALSE);
2768*4882a593Smuzhiyun if (!ret) {
2769*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "%d", val);
2770*4882a593Smuzhiyun AEXT_INFO(dev->name, "command result is %s\n", command);
2771*4882a593Smuzhiyun ret = bytes_written;
2772*4882a593Smuzhiyun }
2773*4882a593Smuzhiyun }
2774*4882a593Smuzhiyun }
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun exit:
2777*4882a593Smuzhiyun return ret;
2778*4882a593Smuzhiyun }
2779*4882a593Smuzhiyun
2780*4882a593Smuzhiyun int
wl_ext_conf_iovar(struct net_device * dev,char * command,int total_len)2781*4882a593Smuzhiyun wl_ext_conf_iovar(struct net_device *dev, char *command, int total_len)
2782*4882a593Smuzhiyun {
2783*4882a593Smuzhiyun int ret = 0;
2784*4882a593Smuzhiyun char name[32], *pch, *pick_tmp, *data;
2785*4882a593Smuzhiyun int bytes_written=-1;
2786*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
2787*4882a593Smuzhiyun
2788*4882a593Smuzhiyun AEXT_TRACE(dev->name, "cmd %s\n", command);
2789*4882a593Smuzhiyun pick_tmp = command;
2790*4882a593Smuzhiyun
2791*4882a593Smuzhiyun pch = bcmstrtok(&pick_tmp, " ", 0); // pick conf
2792*4882a593Smuzhiyun if (!pch || strncmp(pch, "conf", 4))
2793*4882a593Smuzhiyun goto exit;
2794*4882a593Smuzhiyun
2795*4882a593Smuzhiyun pch = bcmstrtok(&pick_tmp, " ", 0); // pick cmd
2796*4882a593Smuzhiyun if (!pch)
2797*4882a593Smuzhiyun goto exit;
2798*4882a593Smuzhiyun
2799*4882a593Smuzhiyun strncpy(name, pch, sizeof(name));
2800*4882a593Smuzhiyun
2801*4882a593Smuzhiyun data = bcmstrtok(&pick_tmp, "", 0); // pick data
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun if (!strcmp(name, "pm")) {
2804*4882a593Smuzhiyun if (data) {
2805*4882a593Smuzhiyun dhd->conf->pm = simple_strtol(data, NULL, 0);
2806*4882a593Smuzhiyun ret = 0;
2807*4882a593Smuzhiyun } else {
2808*4882a593Smuzhiyun bytes_written = snprintf(command, total_len, "%d", dhd->conf->pm);
2809*4882a593Smuzhiyun ret = bytes_written;
2810*4882a593Smuzhiyun }
2811*4882a593Smuzhiyun } else {
2812*4882a593Smuzhiyun AEXT_ERROR(dev->name, "no config parameter found\n");
2813*4882a593Smuzhiyun }
2814*4882a593Smuzhiyun
2815*4882a593Smuzhiyun exit:
2816*4882a593Smuzhiyun return ret;
2817*4882a593Smuzhiyun }
2818*4882a593Smuzhiyun
2819*4882a593Smuzhiyun int
wl_android_ext_priv_cmd(struct net_device * net,char * command,int total_len,int * bytes_written)2820*4882a593Smuzhiyun wl_android_ext_priv_cmd(struct net_device *net, char *command,
2821*4882a593Smuzhiyun int total_len, int *bytes_written)
2822*4882a593Smuzhiyun {
2823*4882a593Smuzhiyun int ret = 0;
2824*4882a593Smuzhiyun
2825*4882a593Smuzhiyun if (strnicmp(command, CMD_CHANNELS, strlen(CMD_CHANNELS)) == 0) {
2826*4882a593Smuzhiyun *bytes_written = wl_ext_channels(net, command, total_len);
2827*4882a593Smuzhiyun }
2828*4882a593Smuzhiyun else if (strnicmp(command, CMD_CHANNEL, strlen(CMD_CHANNEL)) == 0) {
2829*4882a593Smuzhiyun *bytes_written = wl_ext_channel(net, command, total_len);
2830*4882a593Smuzhiyun }
2831*4882a593Smuzhiyun else if (strnicmp(command, CMD_ROAM_TRIGGER, strlen(CMD_ROAM_TRIGGER)) == 0) {
2832*4882a593Smuzhiyun *bytes_written = wl_ext_roam_trigger(net, command, total_len);
2833*4882a593Smuzhiyun }
2834*4882a593Smuzhiyun else if (strnicmp(command, CMD_PM, strlen(CMD_PM)) == 0) {
2835*4882a593Smuzhiyun *bytes_written = wl_ext_pm(net, command, total_len);
2836*4882a593Smuzhiyun }
2837*4882a593Smuzhiyun else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
2838*4882a593Smuzhiyun *bytes_written = wl_ext_monitor(net, command, total_len);
2839*4882a593Smuzhiyun }
2840*4882a593Smuzhiyun #ifdef BTC_WAR
2841*4882a593Smuzhiyun else if (strnicmp(command, CMD_BTC_WAR, strlen(CMD_BTC_WAR)) == 0) {
2842*4882a593Smuzhiyun *bytes_written = wl_ext_btc_war(net, command, total_len);
2843*4882a593Smuzhiyun }
2844*4882a593Smuzhiyun #endif /* BTC_WAR */
2845*4882a593Smuzhiyun else if (strnicmp(command, CMD_SET_SUSPEND_BCN_LI_DTIM, strlen(CMD_SET_SUSPEND_BCN_LI_DTIM)) == 0) {
2846*4882a593Smuzhiyun int bcn_li_dtim;
2847*4882a593Smuzhiyun bcn_li_dtim = (int)simple_strtol((command + strlen(CMD_SET_SUSPEND_BCN_LI_DTIM) + 1), NULL, 10);
2848*4882a593Smuzhiyun *bytes_written = net_os_set_suspend_bcn_li_dtim(net, bcn_li_dtim);
2849*4882a593Smuzhiyun }
2850*4882a593Smuzhiyun #ifdef WL_EXT_IAPSTA
2851*4882a593Smuzhiyun else if (strnicmp(command, CMD_IAPSTA_INIT, strlen(CMD_IAPSTA_INIT)) == 0 ||
2852*4882a593Smuzhiyun strnicmp(command, CMD_ISAM_INIT, strlen(CMD_ISAM_INIT)) == 0) {
2853*4882a593Smuzhiyun *bytes_written = wl_ext_isam_init(net, command, total_len);
2854*4882a593Smuzhiyun }
2855*4882a593Smuzhiyun else if (strnicmp(command, CMD_IAPSTA_CONFIG, strlen(CMD_IAPSTA_CONFIG)) == 0 ||
2856*4882a593Smuzhiyun strnicmp(command, CMD_ISAM_CONFIG, strlen(CMD_ISAM_CONFIG)) == 0) {
2857*4882a593Smuzhiyun *bytes_written = wl_ext_iapsta_config(net, command, total_len);
2858*4882a593Smuzhiyun }
2859*4882a593Smuzhiyun else if (strnicmp(command, CMD_IAPSTA_ENABLE, strlen(CMD_IAPSTA_ENABLE)) == 0 ||
2860*4882a593Smuzhiyun strnicmp(command, CMD_ISAM_ENABLE, strlen(CMD_ISAM_ENABLE)) == 0) {
2861*4882a593Smuzhiyun *bytes_written = wl_ext_iapsta_enable(net, command, total_len);
2862*4882a593Smuzhiyun }
2863*4882a593Smuzhiyun else if (strnicmp(command, CMD_IAPSTA_DISABLE, strlen(CMD_IAPSTA_DISABLE)) == 0 ||
2864*4882a593Smuzhiyun strnicmp(command, CMD_ISAM_DISABLE, strlen(CMD_ISAM_DISABLE)) == 0) {
2865*4882a593Smuzhiyun *bytes_written = wl_ext_iapsta_disable(net, command, total_len);
2866*4882a593Smuzhiyun }
2867*4882a593Smuzhiyun else if (strnicmp(command, CMD_ISAM_STATUS, strlen(CMD_ISAM_STATUS)) == 0) {
2868*4882a593Smuzhiyun *bytes_written = wl_ext_isam_status(net, command, total_len);
2869*4882a593Smuzhiyun }
2870*4882a593Smuzhiyun else if (strnicmp(command, CMD_ISAM_PARAM, strlen(CMD_ISAM_PARAM)) == 0) {
2871*4882a593Smuzhiyun *bytes_written = wl_ext_isam_param(net, command, total_len);
2872*4882a593Smuzhiyun }
2873*4882a593Smuzhiyun #if defined(WLMESH) && defined(WL_ESCAN)
2874*4882a593Smuzhiyun else if (strnicmp(command, CMD_ISAM_PEER_PATH, strlen(CMD_ISAM_PEER_PATH)) == 0) {
2875*4882a593Smuzhiyun *bytes_written = wl_ext_isam_peer_path(net, command, total_len);
2876*4882a593Smuzhiyun }
2877*4882a593Smuzhiyun #endif /* WLMESH && WL_ESCAN */
2878*4882a593Smuzhiyun #endif /* WL_EXT_IAPSTA */
2879*4882a593Smuzhiyun #ifdef WL_CFG80211
2880*4882a593Smuzhiyun else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
2881*4882a593Smuzhiyun *bytes_written = wl_cfg80211_autochannel(net, command, total_len);
2882*4882a593Smuzhiyun }
2883*4882a593Smuzhiyun #endif /* WL_CFG80211 */
2884*4882a593Smuzhiyun #if defined(WL_WIRELESS_EXT) && defined(WL_ESCAN)
2885*4882a593Smuzhiyun else if (strnicmp(command, CMD_AUTOCHANNEL, strlen(CMD_AUTOCHANNEL)) == 0) {
2886*4882a593Smuzhiyun *bytes_written = wl_iw_autochannel(net, command, total_len);
2887*4882a593Smuzhiyun }
2888*4882a593Smuzhiyun #endif /* WL_WIRELESS_EXT && WL_ESCAN */
2889*4882a593Smuzhiyun else if (strnicmp(command, CMD_WLMSGLEVEL, strlen(CMD_WLMSGLEVEL)) == 0) {
2890*4882a593Smuzhiyun *bytes_written = wl_ext_wlmsglevel(net, command, total_len);
2891*4882a593Smuzhiyun }
2892*4882a593Smuzhiyun #ifdef WLEASYMESH
2893*4882a593Smuzhiyun else if (strnicmp(command, CMD_EASYMESH, strlen(CMD_EASYMESH)) == 0) {
2894*4882a593Smuzhiyun int skip = strlen(CMD_EASYMESH) + 1;
2895*4882a593Smuzhiyun *bytes_written = wl_ext_easymesh(net, command+skip, total_len);
2896*4882a593Smuzhiyun }
2897*4882a593Smuzhiyun #endif /* WLEASYMESH */
2898*4882a593Smuzhiyun #if defined(PKT_STATICS) && defined(BCMSDIO)
2899*4882a593Smuzhiyun else if (strnicmp(command, CMD_DUMP_PKT_STATICS, strlen(CMD_DUMP_PKT_STATICS)) == 0) {
2900*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(net);
2901*4882a593Smuzhiyun dhd_bus_dump_txpktstatics(dhd);
2902*4882a593Smuzhiyun }
2903*4882a593Smuzhiyun else if (strnicmp(command, CMD_CLEAR_PKT_STATICS, strlen(CMD_CLEAR_PKT_STATICS)) == 0) {
2904*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(net);
2905*4882a593Smuzhiyun dhd_bus_clear_txpktstatics(dhd);
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun #endif /* PKT_STATICS && BCMSDIO */
2908*4882a593Smuzhiyun else if (strnicmp(command, CMD_WL, strlen(CMD_WL)) == 0) {
2909*4882a593Smuzhiyun *bytes_written = wl_ext_wl_iovar(net, command, total_len);
2910*4882a593Smuzhiyun }
2911*4882a593Smuzhiyun else if (strnicmp(command, CMD_CONF, strlen(CMD_CONF)) == 0) {
2912*4882a593Smuzhiyun *bytes_written = wl_ext_conf_iovar(net, command, total_len);
2913*4882a593Smuzhiyun }
2914*4882a593Smuzhiyun else
2915*4882a593Smuzhiyun ret = -1;
2916*4882a593Smuzhiyun
2917*4882a593Smuzhiyun return ret;
2918*4882a593Smuzhiyun }
2919*4882a593Smuzhiyun
2920*4882a593Smuzhiyun #define CH_MIN_5G_CHANNEL 34
2921*4882a593Smuzhiyun int
wl_construct_ctl_chanspec_list(struct net_device * dev,wl_uint32_list_t * chan_list)2922*4882a593Smuzhiyun wl_construct_ctl_chanspec_list(struct net_device *dev, wl_uint32_list_t *chan_list)
2923*4882a593Smuzhiyun {
2924*4882a593Smuzhiyun void *list;
2925*4882a593Smuzhiyun u32 i, channel;
2926*4882a593Smuzhiyun chanspec_t chspec = 0;
2927*4882a593Smuzhiyun s32 err = BCME_OK;
2928*4882a593Smuzhiyun bool legacy_chan_info = FALSE;
2929*4882a593Smuzhiyun u16 list_count;
2930*4882a593Smuzhiyun
2931*4882a593Smuzhiyun #define LOCAL_BUF_LEN 4096
2932*4882a593Smuzhiyun list = kmalloc(LOCAL_BUF_LEN, GFP_KERNEL);
2933*4882a593Smuzhiyun if (list == NULL) {
2934*4882a593Smuzhiyun WL_ERR(("failed to allocate local buf\n"));
2935*4882a593Smuzhiyun return -ENOMEM;
2936*4882a593Smuzhiyun }
2937*4882a593Smuzhiyun
2938*4882a593Smuzhiyun err = wldev_iovar_getbuf(dev, "chan_info_list", NULL,
2939*4882a593Smuzhiyun 0, list, LOCAL_BUF_LEN, NULL);
2940*4882a593Smuzhiyun if (err == BCME_UNSUPPORTED) {
2941*4882a593Smuzhiyun err = wl_ext_iovar_getbuf(dev, "chanspecs", NULL,
2942*4882a593Smuzhiyun 0, list, LOCAL_BUF_LEN, NULL);
2943*4882a593Smuzhiyun if (err != BCME_OK) {
2944*4882a593Smuzhiyun WL_ERR(("get chanspecs err(%d)\n", err));
2945*4882a593Smuzhiyun kfree(list);
2946*4882a593Smuzhiyun return err;
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun /* Update indicating legacy chan info usage */
2949*4882a593Smuzhiyun legacy_chan_info = TRUE;
2950*4882a593Smuzhiyun } else if (err != BCME_OK) {
2951*4882a593Smuzhiyun WL_ERR(("get chan_info_list err(%d)\n", err));
2952*4882a593Smuzhiyun kfree(list);
2953*4882a593Smuzhiyun return err;
2954*4882a593Smuzhiyun }
2955*4882a593Smuzhiyun
2956*4882a593Smuzhiyun list_count = legacy_chan_info ? ((wl_uint32_list_t *)list)->count :
2957*4882a593Smuzhiyun ((wl_chanspec_list_v1_t *)list)->count;
2958*4882a593Smuzhiyun for (i = 0; i < dtoh32(list_count); i++) {
2959*4882a593Smuzhiyun if (legacy_chan_info) {
2960*4882a593Smuzhiyun chspec = (chanspec_t)dtoh32(((wl_uint32_list_t *)list)->element[i]);
2961*4882a593Smuzhiyun } else {
2962*4882a593Smuzhiyun chspec = (chanspec_t)dtoh32
2963*4882a593Smuzhiyun (((wl_chanspec_list_v1_t *)list)->chspecs[i].chanspec);
2964*4882a593Smuzhiyun }
2965*4882a593Smuzhiyun chspec = wl_chspec_driver_to_host(chspec);
2966*4882a593Smuzhiyun channel = wf_chspec_ctlchan(chspec);
2967*4882a593Smuzhiyun
2968*4882a593Smuzhiyun if (!CHSPEC_IS20(chspec)) {
2969*4882a593Smuzhiyun continue;
2970*4882a593Smuzhiyun }
2971*4882a593Smuzhiyun if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
2972*4882a593Smuzhiyun (channel <= CH_MAX_2G_CHANNEL)) {
2973*4882a593Smuzhiyun chan_list->element[chan_list->count] = chspec;
2974*4882a593Smuzhiyun chan_list->count++;
2975*4882a593Smuzhiyun }
2976*4882a593Smuzhiyun #ifdef WL_6G_BAND
2977*4882a593Smuzhiyun else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
2978*4882a593Smuzhiyun (channel <= CH_MAX_6G_CHANNEL)) {
2979*4882a593Smuzhiyun if (channel == 2)
2980*4882a593Smuzhiyun continue;
2981*4882a593Smuzhiyun chan_list->element[chan_list->count] = chspec;
2982*4882a593Smuzhiyun chan_list->count++;
2983*4882a593Smuzhiyun }
2984*4882a593Smuzhiyun #endif /* WL_6G_BAND */
2985*4882a593Smuzhiyun else if (CHSPEC_IS5G(chspec) && (channel >= CH_MIN_5G_CHANNEL) &&
2986*4882a593Smuzhiyun (channel <= 165)) {
2987*4882a593Smuzhiyun chan_list->element[chan_list->count] = chspec;
2988*4882a593Smuzhiyun chan_list->count++;
2989*4882a593Smuzhiyun } else {
2990*4882a593Smuzhiyun continue;
2991*4882a593Smuzhiyun }
2992*4882a593Smuzhiyun }
2993*4882a593Smuzhiyun
2994*4882a593Smuzhiyun kfree(list);
2995*4882a593Smuzhiyun #undef LOCAL_BUF_LEN
2996*4882a593Smuzhiyun return err;
2997*4882a593Smuzhiyun }
2998*4882a593Smuzhiyun
2999*4882a593Smuzhiyun #if defined(WL_CFG80211) || defined(WL_ESCAN)
3000*4882a593Smuzhiyun int
wl_ext_get_distance(struct net_device * net,u32 band)3001*4882a593Smuzhiyun wl_ext_get_distance(struct net_device *net, u32 band)
3002*4882a593Smuzhiyun {
3003*4882a593Smuzhiyun u32 bw = WL_CHANSPEC_BW_20;
3004*4882a593Smuzhiyun s32 bw_cap = 0, distance = 0;
3005*4882a593Smuzhiyun struct {
3006*4882a593Smuzhiyun u32 band;
3007*4882a593Smuzhiyun u32 bw_cap;
3008*4882a593Smuzhiyun } param = {0, 0};
3009*4882a593Smuzhiyun char buf[WLC_IOCTL_SMLEN]="\0";
3010*4882a593Smuzhiyun s32 err = BCME_OK;
3011*4882a593Smuzhiyun
3012*4882a593Smuzhiyun param.band = band;
3013*4882a593Smuzhiyun err = wldev_iovar_getbuf(net, "bw_cap", ¶m, sizeof(param), buf,
3014*4882a593Smuzhiyun sizeof(buf), NULL);
3015*4882a593Smuzhiyun if (err) {
3016*4882a593Smuzhiyun if (err != BCME_UNSUPPORTED) {
3017*4882a593Smuzhiyun AEXT_TRACE(net->name, "bw_cap failed, %d\n", err);
3018*4882a593Smuzhiyun return err;
3019*4882a593Smuzhiyun } else {
3020*4882a593Smuzhiyun err = wl_ext_iovar_getint(net, "mimo_bw_cap", &bw_cap);
3021*4882a593Smuzhiyun if (bw_cap != WLC_N_BW_20ALL)
3022*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_40;
3023*4882a593Smuzhiyun }
3024*4882a593Smuzhiyun } else {
3025*4882a593Smuzhiyun if (WL_BW_CAP_80MHZ(buf[0]))
3026*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_80;
3027*4882a593Smuzhiyun else if (WL_BW_CAP_40MHZ(buf[0]))
3028*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_40;
3029*4882a593Smuzhiyun else
3030*4882a593Smuzhiyun bw = WL_CHANSPEC_BW_20;
3031*4882a593Smuzhiyun }
3032*4882a593Smuzhiyun
3033*4882a593Smuzhiyun if (bw == WL_CHANSPEC_BW_20)
3034*4882a593Smuzhiyun distance = 2;
3035*4882a593Smuzhiyun else if (bw == WL_CHANSPEC_BW_40)
3036*4882a593Smuzhiyun distance = 4;
3037*4882a593Smuzhiyun else if (bw == WL_CHANSPEC_BW_80)
3038*4882a593Smuzhiyun distance = 8;
3039*4882a593Smuzhiyun else
3040*4882a593Smuzhiyun distance = 16;
3041*4882a593Smuzhiyun AEXT_INFO(net->name, "bw=0x%x, distance=%d\n", bw, distance);
3042*4882a593Smuzhiyun
3043*4882a593Smuzhiyun return distance;
3044*4882a593Smuzhiyun }
3045*4882a593Smuzhiyun
3046*4882a593Smuzhiyun int
wl_ext_get_best_channel(struct net_device * net,wl_bss_cache_ctrl_t * bss_cache_ctrl,int * best_2g_ch,int * best_5g_ch,int * best_6g_ch)3047*4882a593Smuzhiyun wl_ext_get_best_channel(struct net_device *net,
3048*4882a593Smuzhiyun #if defined(BSSCACHE)
3049*4882a593Smuzhiyun wl_bss_cache_ctrl_t *bss_cache_ctrl,
3050*4882a593Smuzhiyun #else
3051*4882a593Smuzhiyun wl_scan_results_v109_t *bss_list,
3052*4882a593Smuzhiyun #endif /* BSSCACHE */
3053*4882a593Smuzhiyun int *best_2g_ch, int *best_5g_ch, int *best_6g_ch)
3054*4882a593Smuzhiyun {
3055*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(net);
3056*4882a593Smuzhiyun struct wl_bss_info *bi = NULL; /* must be initialized */
3057*4882a593Smuzhiyun struct wl_chan_info chan_info;
3058*4882a593Smuzhiyun s32 i, j;
3059*4882a593Smuzhiyun #if defined(BSSCACHE)
3060*4882a593Smuzhiyun wl_bss_cache_t *node;
3061*4882a593Smuzhiyun #endif /* BSSCACHE */
3062*4882a593Smuzhiyun int b_band[CH_MAX_2G_CHANNEL]={0}, a_band1[4]={0}, a_band4[5]={0};
3063*4882a593Smuzhiyun #ifdef WL_6G_BAND
3064*4882a593Smuzhiyun int six_g_band5[24]={0}, six_g_band6[5]={0}, six_g_band7[18]={0}, six_g_band8[13]={0};
3065*4882a593Smuzhiyun s32 distance_6g;
3066*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3067*4882a593Smuzhiyun s32 cen_ch, distance, distance_2g, distance_5g, chanspec, min_ap=999;
3068*4882a593Smuzhiyun wl_uint32_list_t *list = NULL;
3069*4882a593Smuzhiyun int ret;
3070*4882a593Smuzhiyun chanspec_t chspec;
3071*4882a593Smuzhiyun u32 channel;
3072*4882a593Smuzhiyun
3073*4882a593Smuzhiyun memset(b_band, -1, sizeof(b_band));
3074*4882a593Smuzhiyun memset(a_band1, -1, sizeof(a_band1));
3075*4882a593Smuzhiyun memset(a_band4, -1, sizeof(a_band4));
3076*4882a593Smuzhiyun #ifdef WL_6G_BAND
3077*4882a593Smuzhiyun memset(six_g_band5, -1, sizeof(six_g_band5));
3078*4882a593Smuzhiyun memset(six_g_band6, -1, sizeof(six_g_band6));
3079*4882a593Smuzhiyun memset(six_g_band7, -1, sizeof(six_g_band7));
3080*4882a593Smuzhiyun memset(six_g_band8, -1, sizeof(six_g_band8));
3081*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3082*4882a593Smuzhiyun
3083*4882a593Smuzhiyun list = kzalloc(sizeof(u32)*(MAX_CTRL_CHANSPECS + 1), GFP_KERNEL);
3084*4882a593Smuzhiyun if (list == NULL) {
3085*4882a593Smuzhiyun AEXT_ERROR(net->name, "kzalloc failed\n");
3086*4882a593Smuzhiyun ret = -ENOMEM;
3087*4882a593Smuzhiyun goto exit;
3088*4882a593Smuzhiyun }
3089*4882a593Smuzhiyun
3090*4882a593Smuzhiyun ret = wl_construct_ctl_chanspec_list(net, list);
3091*4882a593Smuzhiyun if (ret < 0) {
3092*4882a593Smuzhiyun AEXT_ERROR(net->name, "get channels failed with %d\n", ret);
3093*4882a593Smuzhiyun goto exit;
3094*4882a593Smuzhiyun } else {
3095*4882a593Smuzhiyun for (i = 0; i < list->count; i++) {
3096*4882a593Smuzhiyun chspec = list->element[i];
3097*4882a593Smuzhiyun channel = wf_chspec_ctlchan(chspec);
3098*4882a593Smuzhiyun chan_info.band = CHSPEC2WLC_BAND(chspec);
3099*4882a593Smuzhiyun chan_info.chan = channel;
3100*4882a593Smuzhiyun if (wl_ext_passive_chan(net, &chan_info)) {
3101*4882a593Smuzhiyun continue;
3102*4882a593Smuzhiyun }
3103*4882a593Smuzhiyun if (CHSPEC_IS2G(chspec) && (channel >= CH_MIN_2G_CHANNEL) &&
3104*4882a593Smuzhiyun (channel <= CH_MAX_2G_CHANNEL)) {
3105*4882a593Smuzhiyun b_band[channel-1] = 0;
3106*4882a593Smuzhiyun }
3107*4882a593Smuzhiyun #ifdef WL_6G_BAND
3108*4882a593Smuzhiyun else if (CHSPEC_IS6G(chspec) && (channel >= CH_MIN_6G_CHANNEL) &&
3109*4882a593Smuzhiyun (channel <= CH_MAX_6G_CHANNEL)) {
3110*4882a593Smuzhiyun if (channel <= 93)
3111*4882a593Smuzhiyun six_g_band5[(channel-1)/4] = 0;
3112*4882a593Smuzhiyun else if (channel >= 97 && channel <= 109)
3113*4882a593Smuzhiyun six_g_band6[(channel-97)/4] = 0;
3114*4882a593Smuzhiyun else if (channel >= 117 && channel <= 181)
3115*4882a593Smuzhiyun six_g_band7[(channel-117)/4] = 0;
3116*4882a593Smuzhiyun else if (channel >= 189 && channel <= 221)
3117*4882a593Smuzhiyun six_g_band8[(channel-189)/4] = 0;
3118*4882a593Smuzhiyun }
3119*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3120*4882a593Smuzhiyun else if (CHSPEC_IS5G(chspec) && channel >= CH_MIN_5G_CHANNEL) {
3121*4882a593Smuzhiyun if (channel <= 48)
3122*4882a593Smuzhiyun a_band1[(channel-36)/4] = 0;
3123*4882a593Smuzhiyun else if (channel >= 149 && channel <= 161)
3124*4882a593Smuzhiyun a_band4[(channel-149)/4] = 0;
3125*4882a593Smuzhiyun }
3126*4882a593Smuzhiyun }
3127*4882a593Smuzhiyun }
3128*4882a593Smuzhiyun
3129*4882a593Smuzhiyun distance_2g = wl_ext_get_distance(net, WLC_BAND_2G);
3130*4882a593Smuzhiyun distance_5g = wl_ext_get_distance(net, WLC_BAND_5G);
3131*4882a593Smuzhiyun #ifdef WL_6G_BAND
3132*4882a593Smuzhiyun distance_6g = wl_ext_get_distance(net, WLC_BAND_6G);
3133*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3134*4882a593Smuzhiyun
3135*4882a593Smuzhiyun #if defined(BSSCACHE)
3136*4882a593Smuzhiyun node = bss_cache_ctrl->m_cache_head;
3137*4882a593Smuzhiyun for (i=0; node && i<256; i++)
3138*4882a593Smuzhiyun #else
3139*4882a593Smuzhiyun for (i=0; i < bss_list->count; i++)
3140*4882a593Smuzhiyun #endif /* BSSCACHE */
3141*4882a593Smuzhiyun {
3142*4882a593Smuzhiyun #if defined(BSSCACHE)
3143*4882a593Smuzhiyun bi = node->results.bss_info;
3144*4882a593Smuzhiyun #else
3145*4882a593Smuzhiyun bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : bss_list->bss_info;
3146*4882a593Smuzhiyun #endif /* BSSCACHE */
3147*4882a593Smuzhiyun chanspec = wl_ext_chspec_driver_to_host(dhd, bi->chanspec);
3148*4882a593Smuzhiyun cen_ch = CHSPEC_CHANNEL(bi->chanspec);
3149*4882a593Smuzhiyun distance = 0;
3150*4882a593Smuzhiyun if (CHSPEC_IS20(chanspec))
3151*4882a593Smuzhiyun distance += 2;
3152*4882a593Smuzhiyun else if (CHSPEC_IS40(chanspec))
3153*4882a593Smuzhiyun distance += 4;
3154*4882a593Smuzhiyun else if (CHSPEC_IS80(chanspec))
3155*4882a593Smuzhiyun distance += 8;
3156*4882a593Smuzhiyun else
3157*4882a593Smuzhiyun distance += 16;
3158*4882a593Smuzhiyun
3159*4882a593Smuzhiyun if (CHSPEC_IS2G(chanspec)) {
3160*4882a593Smuzhiyun distance += distance_2g;
3161*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(b_band); j++) {
3162*4882a593Smuzhiyun if (b_band[j] >= 0 && abs(cen_ch-(1+j)) <= distance)
3163*4882a593Smuzhiyun b_band[j] += 1;
3164*4882a593Smuzhiyun }
3165*4882a593Smuzhiyun }
3166*4882a593Smuzhiyun #ifdef WL_6G_BAND
3167*4882a593Smuzhiyun else if (CHSPEC_IS6G(chanspec)) {
3168*4882a593Smuzhiyun distance += distance_6g;
3169*4882a593Smuzhiyun if (cen_ch <= 93) {
3170*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band5); j++) {
3171*4882a593Smuzhiyun if (six_g_band5[j] >= 0 && abs(cen_ch-(93+j*4)) <= distance)
3172*4882a593Smuzhiyun six_g_band5[j] += 1;
3173*4882a593Smuzhiyun }
3174*4882a593Smuzhiyun }
3175*4882a593Smuzhiyun else if (channel >= 97 && channel <= 109) {
3176*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band6); j++) {
3177*4882a593Smuzhiyun if (six_g_band6[j] >= 0 && abs(cen_ch-(97+j*4)) <= distance)
3178*4882a593Smuzhiyun six_g_band6[j] += 1;
3179*4882a593Smuzhiyun }
3180*4882a593Smuzhiyun }
3181*4882a593Smuzhiyun else if (channel >= 117 && channel <= 181) {
3182*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band7); j++) {
3183*4882a593Smuzhiyun if (six_g_band7[j] >= 0 && abs(cen_ch-(117+j*4)) <= distance)
3184*4882a593Smuzhiyun six_g_band7[j] += 1;
3185*4882a593Smuzhiyun }
3186*4882a593Smuzhiyun }
3187*4882a593Smuzhiyun else if (channel >= 189 && channel <= 221) {
3188*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band8); j++) {
3189*4882a593Smuzhiyun if (six_g_band8[j] >= 0 && abs(cen_ch-(189+j*4)) <= distance)
3190*4882a593Smuzhiyun six_g_band8[j] += 1;
3191*4882a593Smuzhiyun }
3192*4882a593Smuzhiyun }
3193*4882a593Smuzhiyun }
3194*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3195*4882a593Smuzhiyun else {
3196*4882a593Smuzhiyun distance += distance_5g;
3197*4882a593Smuzhiyun if (cen_ch <= 48) {
3198*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(a_band1); j++) {
3199*4882a593Smuzhiyun if (a_band1[j] >= 0 && abs(cen_ch-(36+j*4)) <= distance)
3200*4882a593Smuzhiyun a_band1[j] += 1;
3201*4882a593Smuzhiyun }
3202*4882a593Smuzhiyun }
3203*4882a593Smuzhiyun else if (cen_ch >= 149) {
3204*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(a_band4); j++) {
3205*4882a593Smuzhiyun if (a_band4[j] >= 0 && abs(cen_ch-(149+j*4)) <= distance)
3206*4882a593Smuzhiyun a_band4[j] += 1;
3207*4882a593Smuzhiyun }
3208*4882a593Smuzhiyun }
3209*4882a593Smuzhiyun }
3210*4882a593Smuzhiyun #if defined(BSSCACHE)
3211*4882a593Smuzhiyun node = node->next;
3212*4882a593Smuzhiyun #endif /* BSSCACHE */
3213*4882a593Smuzhiyun }
3214*4882a593Smuzhiyun
3215*4882a593Smuzhiyun *best_2g_ch = 0;
3216*4882a593Smuzhiyun min_ap = 999;
3217*4882a593Smuzhiyun for (i=0; i<CH_MAX_2G_CHANNEL; i++) {
3218*4882a593Smuzhiyun if(b_band[i] < min_ap && b_band[i] >= 0) {
3219*4882a593Smuzhiyun min_ap = b_band[i];
3220*4882a593Smuzhiyun *best_2g_ch = i+1;
3221*4882a593Smuzhiyun }
3222*4882a593Smuzhiyun }
3223*4882a593Smuzhiyun *best_5g_ch = 0;
3224*4882a593Smuzhiyun min_ap = 999;
3225*4882a593Smuzhiyun for (i=0; i<ARRAYSIZE(a_band1); i++) {
3226*4882a593Smuzhiyun if(a_band1[i] < min_ap && a_band1[i] >= 0) {
3227*4882a593Smuzhiyun min_ap = a_band1[i];
3228*4882a593Smuzhiyun *best_5g_ch = i*4 + 36;
3229*4882a593Smuzhiyun }
3230*4882a593Smuzhiyun }
3231*4882a593Smuzhiyun for (i=0; i<ARRAYSIZE(a_band4); i++) {
3232*4882a593Smuzhiyun if(a_band4[i] < min_ap && a_band4[i] >= 0) {
3233*4882a593Smuzhiyun min_ap = a_band4[i];
3234*4882a593Smuzhiyun *best_5g_ch = i*4 + 149;
3235*4882a593Smuzhiyun }
3236*4882a593Smuzhiyun }
3237*4882a593Smuzhiyun #ifdef WL_6G_BAND
3238*4882a593Smuzhiyun *best_6g_ch = 0;
3239*4882a593Smuzhiyun min_ap = 999;
3240*4882a593Smuzhiyun for (i=0; i<ARRAYSIZE(six_g_band5); i++) {
3241*4882a593Smuzhiyun if(six_g_band5[i] < min_ap && six_g_band5[i] >= 0) {
3242*4882a593Smuzhiyun min_ap = six_g_band5[i];
3243*4882a593Smuzhiyun *best_6g_ch = i*4 + 1;
3244*4882a593Smuzhiyun }
3245*4882a593Smuzhiyun }
3246*4882a593Smuzhiyun for (i=0; i<ARRAYSIZE(six_g_band6); i++) {
3247*4882a593Smuzhiyun if(six_g_band6[i] < min_ap && six_g_band6[i] >= 0) {
3248*4882a593Smuzhiyun min_ap = six_g_band6[i];
3249*4882a593Smuzhiyun *best_6g_ch = i*4 + 97;
3250*4882a593Smuzhiyun }
3251*4882a593Smuzhiyun }
3252*4882a593Smuzhiyun for (i=0; i<ARRAYSIZE(six_g_band7); i++) {
3253*4882a593Smuzhiyun if(six_g_band7[i] < min_ap && six_g_band7[i] >= 0) {
3254*4882a593Smuzhiyun min_ap = six_g_band7[i];
3255*4882a593Smuzhiyun *best_6g_ch = i*4 + 117;
3256*4882a593Smuzhiyun }
3257*4882a593Smuzhiyun }
3258*4882a593Smuzhiyun for (i=0; i<ARRAYSIZE(six_g_band8); i++) {
3259*4882a593Smuzhiyun if(six_g_band8[i] < min_ap && six_g_band8[i] >= 0) {
3260*4882a593Smuzhiyun min_ap = six_g_band8[i];
3261*4882a593Smuzhiyun *best_6g_ch = i*4 + 189;
3262*4882a593Smuzhiyun }
3263*4882a593Smuzhiyun }
3264*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3265*4882a593Smuzhiyun
3266*4882a593Smuzhiyun if (android_msg_level & ANDROID_INFO_LEVEL) {
3267*4882a593Smuzhiyun struct bcmstrbuf strbuf;
3268*4882a593Smuzhiyun char *tmp_buf = NULL;
3269*4882a593Smuzhiyun tmp_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
3270*4882a593Smuzhiyun if (tmp_buf == NULL) {
3271*4882a593Smuzhiyun AEXT_ERROR(net->name, "Failed to allocate buffer of %d bytes\n", WLC_IOCTL_SMLEN);
3272*4882a593Smuzhiyun goto exit;
3273*4882a593Smuzhiyun }
3274*4882a593Smuzhiyun bcm_binit(&strbuf, tmp_buf, WLC_IOCTL_MEDLEN);
3275*4882a593Smuzhiyun bcm_bprintf(&strbuf, "2g: ");
3276*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(b_band); j++)
3277*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", b_band[j], 1+j);
3278*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3279*4882a593Smuzhiyun bcm_bprintf(&strbuf, "5g band 1: ");
3280*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(a_band1); j++)
3281*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", a_band1[j], 36+j*4);
3282*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3283*4882a593Smuzhiyun bcm_bprintf(&strbuf, "5g band 4: ");
3284*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(a_band4); j++)
3285*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", a_band4[j], 149+j*4);
3286*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3287*4882a593Smuzhiyun #ifdef WL_6G_BAND
3288*4882a593Smuzhiyun bcm_bprintf(&strbuf, "6g band 5: ");
3289*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band5); j++)
3290*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", six_g_band5[j], 1+j*4);
3291*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3292*4882a593Smuzhiyun bcm_bprintf(&strbuf, "6g band 6: ");
3293*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band6); j++)
3294*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", six_g_band6[j], 97+j*4);
3295*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3296*4882a593Smuzhiyun bcm_bprintf(&strbuf, "6g band 7: ");
3297*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band7); j++)
3298*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", six_g_band7[j], 117+j*4);
3299*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3300*4882a593Smuzhiyun bcm_bprintf(&strbuf, "6g band 8: ");
3301*4882a593Smuzhiyun for (j=0; j<ARRAYSIZE(six_g_band8); j++)
3302*4882a593Smuzhiyun bcm_bprintf(&strbuf, "%d/%d, ", six_g_band8[j], 189+j*4);
3303*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3304*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3305*4882a593Smuzhiyun bcm_bprintf(&strbuf, "best_2g_ch=%d, best_5g_ch=%d",
3306*4882a593Smuzhiyun *best_2g_ch, *best_5g_ch);
3307*4882a593Smuzhiyun #ifdef WL_6G_BAND
3308*4882a593Smuzhiyun bcm_bprintf(&strbuf, ", best_6g_ch=%d", *best_6g_ch);
3309*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3310*4882a593Smuzhiyun bcm_bprintf(&strbuf, "\n");
3311*4882a593Smuzhiyun AEXT_INFO(net->name, "\n%s", strbuf.origbuf);
3312*4882a593Smuzhiyun if (tmp_buf) {
3313*4882a593Smuzhiyun kfree(tmp_buf);
3314*4882a593Smuzhiyun }
3315*4882a593Smuzhiyun }
3316*4882a593Smuzhiyun
3317*4882a593Smuzhiyun exit:
3318*4882a593Smuzhiyun if (list)
3319*4882a593Smuzhiyun kfree(list);
3320*4882a593Smuzhiyun return ret;
3321*4882a593Smuzhiyun }
3322*4882a593Smuzhiyun #endif /* WL_CFG80211 || WL_ESCAN */
3323*4882a593Smuzhiyun
3324*4882a593Smuzhiyun #ifdef WL_CFG80211
3325*4882a593Smuzhiyun #define APCS_MAX_RETRY 10
3326*4882a593Smuzhiyun static int
wl_ext_fw_apcs(struct net_device * dev,uint32 band)3327*4882a593Smuzhiyun wl_ext_fw_apcs(struct net_device *dev, uint32 band)
3328*4882a593Smuzhiyun {
3329*4882a593Smuzhiyun int channel = 0, chosen = 0, retry = 0, ret = 0, spect = 0;
3330*4882a593Smuzhiyun u8 *reqbuf = NULL;
3331*4882a593Smuzhiyun uint32 buf_size;
3332*4882a593Smuzhiyun chanspec_band_t acs_band = WLC_BAND_INVALID;
3333*4882a593Smuzhiyun
3334*4882a593Smuzhiyun ret = wldev_ioctl_get(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect));
3335*4882a593Smuzhiyun if (ret) {
3336*4882a593Smuzhiyun AEXT_ERROR(dev->name, "ACS: error getting the spect, ret=%d\n", ret);
3337*4882a593Smuzhiyun goto done;
3338*4882a593Smuzhiyun }
3339*4882a593Smuzhiyun
3340*4882a593Smuzhiyun if (spect > 0) {
3341*4882a593Smuzhiyun ret = wl_android_set_spect(dev, 0);
3342*4882a593Smuzhiyun if (ret < 0) {
3343*4882a593Smuzhiyun AEXT_ERROR(dev->name, "ACS: error while setting spect, ret=%d\n", ret);
3344*4882a593Smuzhiyun goto done;
3345*4882a593Smuzhiyun }
3346*4882a593Smuzhiyun }
3347*4882a593Smuzhiyun
3348*4882a593Smuzhiyun reqbuf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
3349*4882a593Smuzhiyun if (reqbuf == NULL) {
3350*4882a593Smuzhiyun AEXT_ERROR(dev->name, "failed to allocate chanspec buffer\n");
3351*4882a593Smuzhiyun goto done;
3352*4882a593Smuzhiyun }
3353*4882a593Smuzhiyun memset(reqbuf, 0, CHANSPEC_BUF_SIZE);
3354*4882a593Smuzhiyun
3355*4882a593Smuzhiyun acs_band = wl_ext_wlcband_to_chanspec_band(band);
3356*4882a593Smuzhiyun if (acs_band == INVCHANSPEC) {
3357*4882a593Smuzhiyun acs_band = WL_CHANSPEC_BAND_2G;
3358*4882a593Smuzhiyun }
3359*4882a593Smuzhiyun
3360*4882a593Smuzhiyun if ((ret = wl_android_get_band_chanspecs(dev, reqbuf, CHANSPEC_BUF_SIZE,
3361*4882a593Smuzhiyun acs_band, true)) < 0) {
3362*4882a593Smuzhiyun WL_ERR(("ACS chanspec retrieval failed!\n"));
3363*4882a593Smuzhiyun goto done;
3364*4882a593Smuzhiyun }
3365*4882a593Smuzhiyun
3366*4882a593Smuzhiyun AEXT_INFO(dev->name, "ACS chanspec band 0x%x\n", acs_band);
3367*4882a593Smuzhiyun
3368*4882a593Smuzhiyun buf_size = CHANSPEC_BUF_SIZE;
3369*4882a593Smuzhiyun ret = wldev_ioctl_set(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
3370*4882a593Smuzhiyun buf_size);
3371*4882a593Smuzhiyun if (ret < 0) {
3372*4882a593Smuzhiyun AEXT_ERROR(dev->name, "can't start auto channel scan, err = %d\n", ret);
3373*4882a593Smuzhiyun channel = 0;
3374*4882a593Smuzhiyun goto done;
3375*4882a593Smuzhiyun }
3376*4882a593Smuzhiyun
3377*4882a593Smuzhiyun /* Wait for auto channel selection, max 3000 ms */
3378*4882a593Smuzhiyun if ((band == WLC_BAND_2G) || (band == WLC_BAND_5G) || (band == WLC_BAND_6G)) {
3379*4882a593Smuzhiyun OSL_SLEEP(500);
3380*4882a593Smuzhiyun } else {
3381*4882a593Smuzhiyun /*
3382*4882a593Smuzhiyun * Full channel scan at the minimum takes 1.2secs
3383*4882a593Smuzhiyun * even with parallel scan. max wait time: 3500ms
3384*4882a593Smuzhiyun */
3385*4882a593Smuzhiyun OSL_SLEEP(1000);
3386*4882a593Smuzhiyun }
3387*4882a593Smuzhiyun
3388*4882a593Smuzhiyun retry = APCS_MAX_RETRY;
3389*4882a593Smuzhiyun while (retry--) {
3390*4882a593Smuzhiyun ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &chosen,
3391*4882a593Smuzhiyun sizeof(chosen));
3392*4882a593Smuzhiyun if (ret < 0) {
3393*4882a593Smuzhiyun chosen = 0;
3394*4882a593Smuzhiyun } else {
3395*4882a593Smuzhiyun chosen = dtoh32(chosen);
3396*4882a593Smuzhiyun }
3397*4882a593Smuzhiyun
3398*4882a593Smuzhiyun if (wf_chspec_valid((chanspec_t)chosen)) {
3399*4882a593Smuzhiyun channel = wf_chspec_ctlchan((chanspec_t)chosen);
3400*4882a593Smuzhiyun acs_band = CHSPEC_BAND((chanspec_t)chosen);
3401*4882a593Smuzhiyun WL_MSG(dev->name, "selected channel = %d(band %d)\n",
3402*4882a593Smuzhiyun channel, CHSPEC2WLC_BAND((chanspec_t)chosen));
3403*4882a593Smuzhiyun break;
3404*4882a593Smuzhiyun }
3405*4882a593Smuzhiyun AEXT_INFO(dev->name, "%d tried, ret = %d, chosen = 0x%x\n",
3406*4882a593Smuzhiyun (APCS_MAX_RETRY - retry), ret, chosen);
3407*4882a593Smuzhiyun OSL_SLEEP(250);
3408*4882a593Smuzhiyun }
3409*4882a593Smuzhiyun
3410*4882a593Smuzhiyun done:
3411*4882a593Smuzhiyun if (spect > 0) {
3412*4882a593Smuzhiyun if ((ret = wl_android_set_spect(dev, spect) < 0)) {
3413*4882a593Smuzhiyun AEXT_ERROR(dev->name, "ACS: error while setting spect\n");
3414*4882a593Smuzhiyun }
3415*4882a593Smuzhiyun }
3416*4882a593Smuzhiyun
3417*4882a593Smuzhiyun if (reqbuf) {
3418*4882a593Smuzhiyun kfree(reqbuf);
3419*4882a593Smuzhiyun }
3420*4882a593Smuzhiyun
3421*4882a593Smuzhiyun return chosen;
3422*4882a593Smuzhiyun }
3423*4882a593Smuzhiyun #endif /* WL_CFG80211 */
3424*4882a593Smuzhiyun
3425*4882a593Smuzhiyun #ifdef WL_ESCAN
3426*4882a593Smuzhiyun int
wl_ext_drv_scan(struct net_device * dev,uint32 band,bool fast_scan)3427*4882a593Smuzhiyun wl_ext_drv_scan(struct net_device *dev, uint32 band, bool fast_scan)
3428*4882a593Smuzhiyun {
3429*4882a593Smuzhiyun int ret = -1, i, cnt = 0;
3430*4882a593Smuzhiyun int retry = 0, retry_max, retry_interval = 250, up = 1;
3431*4882a593Smuzhiyun wl_scan_info_t *scan_info = NULL;
3432*4882a593Smuzhiyun
3433*4882a593Smuzhiyun scan_info = kmalloc(sizeof(wl_scan_info_t), GFP_KERNEL);
3434*4882a593Smuzhiyun if (scan_info == NULL) {
3435*4882a593Smuzhiyun AEXT_ERROR(dev->name, "kzalloc failed\n");
3436*4882a593Smuzhiyun ret = -ENOMEM;
3437*4882a593Smuzhiyun goto exit;
3438*4882a593Smuzhiyun }
3439*4882a593Smuzhiyun
3440*4882a593Smuzhiyun retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval;
3441*4882a593Smuzhiyun ret = wldev_ioctl_get(dev, WLC_GET_UP, &up, sizeof(s32));
3442*4882a593Smuzhiyun if (ret < 0 || up == 0) {
3443*4882a593Smuzhiyun ret = wldev_ioctl_set(dev, WLC_UP, &up, sizeof(s32));
3444*4882a593Smuzhiyun }
3445*4882a593Smuzhiyun memset(scan_info, 0, sizeof(wl_scan_info_t));
3446*4882a593Smuzhiyun if (band == WLC_BAND_2G || band == WLC_BAND_AUTO) {
3447*4882a593Smuzhiyun for (i=0; i<13; i++) {
3448*4882a593Smuzhiyun scan_info->channels.channel[i+cnt] = wf_create_chspec_from_primary(i+1,
3449*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G);
3450*4882a593Smuzhiyun }
3451*4882a593Smuzhiyun cnt += 13;
3452*4882a593Smuzhiyun }
3453*4882a593Smuzhiyun if (band == WLC_BAND_5G || band == WLC_BAND_AUTO) {
3454*4882a593Smuzhiyun for (i=0; i<4; i++) {
3455*4882a593Smuzhiyun scan_info->channels.channel[i+cnt] = wf_create_chspec_from_primary(36+i*4,
3456*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G);
3457*4882a593Smuzhiyun }
3458*4882a593Smuzhiyun cnt += 4;
3459*4882a593Smuzhiyun for (i=0; i<4; i++) {
3460*4882a593Smuzhiyun scan_info->channels.channel[i+cnt] = wf_create_chspec_from_primary(149+i*4,
3461*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G);
3462*4882a593Smuzhiyun }
3463*4882a593Smuzhiyun cnt += 4;
3464*4882a593Smuzhiyun }
3465*4882a593Smuzhiyun #ifdef WL_6G_BAND
3466*4882a593Smuzhiyun if (band == WLC_BAND_6G || band == WLC_BAND_AUTO) {
3467*4882a593Smuzhiyun for (i=0; i<59; i++) {
3468*4882a593Smuzhiyun scan_info->channels.channel[i+cnt] = wf_create_chspec_from_primary(1+i*4,
3469*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G);
3470*4882a593Smuzhiyun }
3471*4882a593Smuzhiyun cnt += 59;
3472*4882a593Smuzhiyun }
3473*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3474*4882a593Smuzhiyun if (band == WLC_BAND_2G)
3475*4882a593Smuzhiyun fast_scan = FALSE;
3476*4882a593Smuzhiyun scan_info->channels.count = cnt;
3477*4882a593Smuzhiyun if (fast_scan)
3478*4882a593Smuzhiyun scan_info->scan_time = 40;
3479*4882a593Smuzhiyun scan_info->bcast_ssid = TRUE;
3480*4882a593Smuzhiyun retry = retry_max;
3481*4882a593Smuzhiyun while (retry--) {
3482*4882a593Smuzhiyun ret = wl_escan_set_scan(dev, scan_info);
3483*4882a593Smuzhiyun if (!ret)
3484*4882a593Smuzhiyun break;
3485*4882a593Smuzhiyun OSL_SLEEP(retry_interval);
3486*4882a593Smuzhiyun }
3487*4882a593Smuzhiyun if (retry == 0) {
3488*4882a593Smuzhiyun AEXT_ERROR(dev->name, "scan retry failed %d\n", retry_max);
3489*4882a593Smuzhiyun ret = -1;
3490*4882a593Smuzhiyun }
3491*4882a593Smuzhiyun
3492*4882a593Smuzhiyun exit:
3493*4882a593Smuzhiyun if (scan_info)
3494*4882a593Smuzhiyun kfree(scan_info);
3495*4882a593Smuzhiyun return ret;
3496*4882a593Smuzhiyun }
3497*4882a593Smuzhiyun
3498*4882a593Smuzhiyun static int
wl_ext_drv_apcs(struct net_device * dev,uint32 band)3499*4882a593Smuzhiyun wl_ext_drv_apcs(struct net_device *dev, uint32 band)
3500*4882a593Smuzhiyun {
3501*4882a593Smuzhiyun int ret = 0, chanspec = 0;
3502*4882a593Smuzhiyun struct dhd_pub *dhd = dhd_get_pub(dev);
3503*4882a593Smuzhiyun struct wl_escan_info *escan = NULL;
3504*4882a593Smuzhiyun int retry = 0, retry_max, retry_interval = 250;
3505*4882a593Smuzhiyun
3506*4882a593Smuzhiyun escan = dhd->escan;
3507*4882a593Smuzhiyun WL_MSG(dev->name, "ACS_SCAN\n");
3508*4882a593Smuzhiyun escan->autochannel = 1;
3509*4882a593Smuzhiyun ret = wl_ext_drv_scan(dev, band, TRUE);
3510*4882a593Smuzhiyun if (ret < 0)
3511*4882a593Smuzhiyun goto done;
3512*4882a593Smuzhiyun retry_max = WL_ESCAN_TIMER_INTERVAL_MS/retry_interval;
3513*4882a593Smuzhiyun retry = retry_max;
3514*4882a593Smuzhiyun while (retry--) {
3515*4882a593Smuzhiyun if (escan->escan_state == ESCAN_STATE_IDLE) {
3516*4882a593Smuzhiyun if (band == WLC_BAND_5G) {
3517*4882a593Smuzhiyun chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(escan->best_5g_ch),
3518*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G);
3519*4882a593Smuzhiyun }
3520*4882a593Smuzhiyun #ifdef WL_6G_BAND
3521*4882a593Smuzhiyun else if (band == WLC_BAND_6G) {
3522*4882a593Smuzhiyun chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(escan->best_6g_ch),
3523*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_6G);
3524*4882a593Smuzhiyun }
3525*4882a593Smuzhiyun #endif /* WL_6G_BAND */
3526*4882a593Smuzhiyun else {
3527*4882a593Smuzhiyun chanspec = wf_create_chspec_from_primary(wf_chspec_primary20_chan(escan->best_2g_ch),
3528*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G);
3529*4882a593Smuzhiyun }
3530*4882a593Smuzhiyun WL_MSG(dev->name, "selected channel = %d(0x%x)\n",
3531*4882a593Smuzhiyun wf_chspec_ctlchan(chanspec), chanspec);
3532*4882a593Smuzhiyun goto done;
3533*4882a593Smuzhiyun }
3534*4882a593Smuzhiyun AEXT_INFO(dev->name, "escan_state=%d, %d tried, ret = %d\n",
3535*4882a593Smuzhiyun escan->escan_state, (retry_max - retry), ret);
3536*4882a593Smuzhiyun OSL_SLEEP(retry_interval);
3537*4882a593Smuzhiyun }
3538*4882a593Smuzhiyun
3539*4882a593Smuzhiyun done:
3540*4882a593Smuzhiyun escan->autochannel = 0;
3541*4882a593Smuzhiyun
3542*4882a593Smuzhiyun return chanspec;
3543*4882a593Smuzhiyun }
3544*4882a593Smuzhiyun #endif /* WL_ESCAN */
3545*4882a593Smuzhiyun
3546*4882a593Smuzhiyun int
wl_ext_autochannel(struct net_device * dev,uint acs,uint32 band)3547*4882a593Smuzhiyun wl_ext_autochannel(struct net_device *dev, uint acs, uint32 band)
3548*4882a593Smuzhiyun {
3549*4882a593Smuzhiyun int chosen = 0;
3550*4882a593Smuzhiyun uint16 chan_2g, chan_5g, channel;
3551*4882a593Smuzhiyun
3552*4882a593Smuzhiyun AEXT_INFO(dev->name, "acs=0x%x, band=%s\n", acs, WLCBAND2STR(band));
3553*4882a593Smuzhiyun
3554*4882a593Smuzhiyun #ifdef WL_CFG80211
3555*4882a593Smuzhiyun if (acs & ACS_FW_BIT) {
3556*4882a593Smuzhiyun int ret = 0;
3557*4882a593Smuzhiyun ret = wldev_ioctl_get(dev, WLC_GET_CHANNEL_SEL, &channel, sizeof(channel));
3558*4882a593Smuzhiyun chosen = 0;
3559*4882a593Smuzhiyun if (ret != BCME_UNSUPPORTED)
3560*4882a593Smuzhiyun chosen = wl_ext_fw_apcs(dev, band);
3561*4882a593Smuzhiyun if (chosen)
3562*4882a593Smuzhiyun return chosen;
3563*4882a593Smuzhiyun }
3564*4882a593Smuzhiyun #endif
3565*4882a593Smuzhiyun
3566*4882a593Smuzhiyun #ifdef WL_ESCAN
3567*4882a593Smuzhiyun if (acs & ACS_DRV_BIT)
3568*4882a593Smuzhiyun chosen = wl_ext_drv_apcs(dev, band);
3569*4882a593Smuzhiyun #endif /* WL_ESCAN */
3570*4882a593Smuzhiyun
3571*4882a593Smuzhiyun if (chosen == 0) {
3572*4882a593Smuzhiyun wl_ext_get_default_chan(dev, &chan_2g, &chan_5g, TRUE);
3573*4882a593Smuzhiyun if (band == WLC_BAND_5G) {
3574*4882a593Smuzhiyun chosen = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chan_5g),
3575*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_5G);
3576*4882a593Smuzhiyun channel = chan_5g;
3577*4882a593Smuzhiyun } else {
3578*4882a593Smuzhiyun chosen = wf_create_chspec_from_primary(wf_chspec_primary20_chan(chan_2g),
3579*4882a593Smuzhiyun WL_CHANSPEC_BW_20, WL_CHANSPEC_BAND_2G);
3580*4882a593Smuzhiyun channel = chan_2g;
3581*4882a593Smuzhiyun }
3582*4882a593Smuzhiyun AEXT_ERROR(dev->name, "ACS failed. Fall back to default channel (%s-%d) \n",
3583*4882a593Smuzhiyun CHSPEC2BANDSTR(chosen), channel);
3584*4882a593Smuzhiyun }
3585*4882a593Smuzhiyun
3586*4882a593Smuzhiyun return chosen;
3587*4882a593Smuzhiyun }
3588*4882a593Smuzhiyun
3589*4882a593Smuzhiyun #if defined(RSSIAVG)
3590*4882a593Smuzhiyun void
wl_free_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl)3591*4882a593Smuzhiyun wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3592*4882a593Smuzhiyun {
3593*4882a593Smuzhiyun wl_rssi_cache_t *node, *cur, **rssi_head;
3594*4882a593Smuzhiyun int i=0;
3595*4882a593Smuzhiyun
3596*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3597*4882a593Smuzhiyun node = *rssi_head;
3598*4882a593Smuzhiyun
3599*4882a593Smuzhiyun for (;node;) {
3600*4882a593Smuzhiyun AEXT_INFO("wlan", "Free %d with BSSID %pM\n", i, &node->BSSID);
3601*4882a593Smuzhiyun cur = node;
3602*4882a593Smuzhiyun node = cur->next;
3603*4882a593Smuzhiyun kfree(cur);
3604*4882a593Smuzhiyun i++;
3605*4882a593Smuzhiyun }
3606*4882a593Smuzhiyun *rssi_head = NULL;
3607*4882a593Smuzhiyun }
3608*4882a593Smuzhiyun
3609*4882a593Smuzhiyun void
wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl)3610*4882a593Smuzhiyun wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3611*4882a593Smuzhiyun {
3612*4882a593Smuzhiyun wl_rssi_cache_t *node, *prev, **rssi_head;
3613*4882a593Smuzhiyun int i = -1, tmp = 0;
3614*4882a593Smuzhiyun struct osl_timespec now;
3615*4882a593Smuzhiyun
3616*4882a593Smuzhiyun osl_do_gettimeofday(&now);
3617*4882a593Smuzhiyun
3618*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3619*4882a593Smuzhiyun node = *rssi_head;
3620*4882a593Smuzhiyun prev = node;
3621*4882a593Smuzhiyun for (;node;) {
3622*4882a593Smuzhiyun i++;
3623*4882a593Smuzhiyun if (now.tv_sec > node->tv.tv_sec) {
3624*4882a593Smuzhiyun if (node == *rssi_head) {
3625*4882a593Smuzhiyun tmp = 1;
3626*4882a593Smuzhiyun *rssi_head = node->next;
3627*4882a593Smuzhiyun } else {
3628*4882a593Smuzhiyun tmp = 0;
3629*4882a593Smuzhiyun prev->next = node->next;
3630*4882a593Smuzhiyun }
3631*4882a593Smuzhiyun AEXT_INFO("wlan", "Del %d with BSSID %pM\n", i, &node->BSSID);
3632*4882a593Smuzhiyun kfree(node);
3633*4882a593Smuzhiyun if (tmp == 1) {
3634*4882a593Smuzhiyun node = *rssi_head;
3635*4882a593Smuzhiyun prev = node;
3636*4882a593Smuzhiyun } else {
3637*4882a593Smuzhiyun node = prev->next;
3638*4882a593Smuzhiyun }
3639*4882a593Smuzhiyun continue;
3640*4882a593Smuzhiyun }
3641*4882a593Smuzhiyun prev = node;
3642*4882a593Smuzhiyun node = node->next;
3643*4882a593Smuzhiyun }
3644*4882a593Smuzhiyun }
3645*4882a593Smuzhiyun
3646*4882a593Smuzhiyun void
wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,u8 * bssid)3647*4882a593Smuzhiyun wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
3648*4882a593Smuzhiyun u8 *bssid)
3649*4882a593Smuzhiyun {
3650*4882a593Smuzhiyun wl_rssi_cache_t *node, *prev, **rssi_head;
3651*4882a593Smuzhiyun int i = -1, tmp = 0;
3652*4882a593Smuzhiyun
3653*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3654*4882a593Smuzhiyun node = *rssi_head;
3655*4882a593Smuzhiyun prev = node;
3656*4882a593Smuzhiyun for (;node;) {
3657*4882a593Smuzhiyun i++;
3658*4882a593Smuzhiyun if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) {
3659*4882a593Smuzhiyun if (node == *rssi_head) {
3660*4882a593Smuzhiyun tmp = 1;
3661*4882a593Smuzhiyun *rssi_head = node->next;
3662*4882a593Smuzhiyun } else {
3663*4882a593Smuzhiyun tmp = 0;
3664*4882a593Smuzhiyun prev->next = node->next;
3665*4882a593Smuzhiyun }
3666*4882a593Smuzhiyun AEXT_INFO("wlan", "Del %d with BSSID %pM\n", i, &node->BSSID);
3667*4882a593Smuzhiyun kfree(node);
3668*4882a593Smuzhiyun if (tmp == 1) {
3669*4882a593Smuzhiyun node = *rssi_head;
3670*4882a593Smuzhiyun prev = node;
3671*4882a593Smuzhiyun } else {
3672*4882a593Smuzhiyun node = prev->next;
3673*4882a593Smuzhiyun }
3674*4882a593Smuzhiyun continue;
3675*4882a593Smuzhiyun }
3676*4882a593Smuzhiyun prev = node;
3677*4882a593Smuzhiyun node = node->next;
3678*4882a593Smuzhiyun }
3679*4882a593Smuzhiyun }
3680*4882a593Smuzhiyun
3681*4882a593Smuzhiyun void
wl_reset_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl)3682*4882a593Smuzhiyun wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3683*4882a593Smuzhiyun {
3684*4882a593Smuzhiyun wl_rssi_cache_t *node, **rssi_head;
3685*4882a593Smuzhiyun
3686*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3687*4882a593Smuzhiyun
3688*4882a593Smuzhiyun /* reset dirty */
3689*4882a593Smuzhiyun node = *rssi_head;
3690*4882a593Smuzhiyun for (;node;) {
3691*4882a593Smuzhiyun node->dirty += 1;
3692*4882a593Smuzhiyun node = node->next;
3693*4882a593Smuzhiyun }
3694*4882a593Smuzhiyun }
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun int
wl_update_connected_rssi_cache(struct net_device * net,wl_rssi_cache_ctrl_t * rssi_cache_ctrl,int * rssi_avg)3697*4882a593Smuzhiyun wl_update_connected_rssi_cache(struct net_device *net,
3698*4882a593Smuzhiyun wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
3699*4882a593Smuzhiyun {
3700*4882a593Smuzhiyun wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
3701*4882a593Smuzhiyun int j, k=0;
3702*4882a593Smuzhiyun int rssi, error=0;
3703*4882a593Smuzhiyun struct ether_addr bssid;
3704*4882a593Smuzhiyun struct osl_timespec now, timeout;
3705*4882a593Smuzhiyun scb_val_t scbval;
3706*4882a593Smuzhiyun
3707*4882a593Smuzhiyun if (!g_wifi_on)
3708*4882a593Smuzhiyun return 0;
3709*4882a593Smuzhiyun
3710*4882a593Smuzhiyun error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), 0);
3711*4882a593Smuzhiyun if (error == BCME_NOTASSOCIATED) {
3712*4882a593Smuzhiyun AEXT_INFO("wlan", "Not Associated! res:%d\n", error);
3713*4882a593Smuzhiyun return 0;
3714*4882a593Smuzhiyun }
3715*4882a593Smuzhiyun if (error) {
3716*4882a593Smuzhiyun AEXT_ERROR(net->name, "Could not get bssid (%d)\n", error);
3717*4882a593Smuzhiyun }
3718*4882a593Smuzhiyun error = wldev_get_rssi(net, &scbval);
3719*4882a593Smuzhiyun if (error) {
3720*4882a593Smuzhiyun AEXT_ERROR(net->name, "Could not get rssi (%d)\n", error);
3721*4882a593Smuzhiyun return error;
3722*4882a593Smuzhiyun }
3723*4882a593Smuzhiyun rssi = dtoh32(scbval.val);
3724*4882a593Smuzhiyun
3725*4882a593Smuzhiyun osl_do_gettimeofday(&now);
3726*4882a593Smuzhiyun timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
3727*4882a593Smuzhiyun if (timeout.tv_sec < now.tv_sec) {
3728*4882a593Smuzhiyun /*
3729*4882a593Smuzhiyun * Integer overflow - assume long enough timeout to be assumed
3730*4882a593Smuzhiyun * to be infinite, i.e., the timeout would never happen.
3731*4882a593Smuzhiyun */
3732*4882a593Smuzhiyun AEXT_TRACE(net->name,
3733*4882a593Smuzhiyun "Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
3734*4882a593Smuzhiyun RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec);
3735*4882a593Smuzhiyun }
3736*4882a593Smuzhiyun
3737*4882a593Smuzhiyun /* update RSSI */
3738*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3739*4882a593Smuzhiyun node = *rssi_head;
3740*4882a593Smuzhiyun prev = NULL;
3741*4882a593Smuzhiyun for (;node;) {
3742*4882a593Smuzhiyun if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
3743*4882a593Smuzhiyun AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%d\n", k, &bssid, rssi);
3744*4882a593Smuzhiyun for (j=0; j<RSSIAVG_LEN-1; j++)
3745*4882a593Smuzhiyun node->RSSI[j] = node->RSSI[j+1];
3746*4882a593Smuzhiyun node->RSSI[j] = rssi;
3747*4882a593Smuzhiyun node->dirty = 0;
3748*4882a593Smuzhiyun node->tv = timeout;
3749*4882a593Smuzhiyun goto exit;
3750*4882a593Smuzhiyun }
3751*4882a593Smuzhiyun prev = node;
3752*4882a593Smuzhiyun node = node->next;
3753*4882a593Smuzhiyun k++;
3754*4882a593Smuzhiyun }
3755*4882a593Smuzhiyun
3756*4882a593Smuzhiyun leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
3757*4882a593Smuzhiyun if (!leaf) {
3758*4882a593Smuzhiyun AEXT_ERROR(net->name, "Memory alloc failure %d\n", (int)sizeof(wl_rssi_cache_t));
3759*4882a593Smuzhiyun return 0;
3760*4882a593Smuzhiyun }
3761*4882a593Smuzhiyun AEXT_INFO(net->name, "Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
3762*4882a593Smuzhiyun k, &bssid, rssi);
3763*4882a593Smuzhiyun
3764*4882a593Smuzhiyun leaf->next = NULL;
3765*4882a593Smuzhiyun leaf->dirty = 0;
3766*4882a593Smuzhiyun leaf->tv = timeout;
3767*4882a593Smuzhiyun memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN);
3768*4882a593Smuzhiyun for (j=0; j<RSSIAVG_LEN; j++)
3769*4882a593Smuzhiyun leaf->RSSI[j] = rssi;
3770*4882a593Smuzhiyun
3771*4882a593Smuzhiyun if (!prev)
3772*4882a593Smuzhiyun *rssi_head = leaf;
3773*4882a593Smuzhiyun else
3774*4882a593Smuzhiyun prev->next = leaf;
3775*4882a593Smuzhiyun
3776*4882a593Smuzhiyun exit:
3777*4882a593Smuzhiyun *rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid);
3778*4882a593Smuzhiyun
3779*4882a593Smuzhiyun return error;
3780*4882a593Smuzhiyun }
3781*4882a593Smuzhiyun
3782*4882a593Smuzhiyun void
wl_update_rssi_cache(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,wl_scan_results_v109_t * ss_list)3783*4882a593Smuzhiyun wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
3784*4882a593Smuzhiyun wl_scan_results_v109_t *ss_list)
3785*4882a593Smuzhiyun {
3786*4882a593Smuzhiyun wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
3787*4882a593Smuzhiyun wl_bss_info_v109_t *bi = NULL;
3788*4882a593Smuzhiyun int i, j, k;
3789*4882a593Smuzhiyun struct osl_timespec now, timeout;
3790*4882a593Smuzhiyun
3791*4882a593Smuzhiyun if (!ss_list->count)
3792*4882a593Smuzhiyun return;
3793*4882a593Smuzhiyun
3794*4882a593Smuzhiyun osl_do_gettimeofday(&now);
3795*4882a593Smuzhiyun timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
3796*4882a593Smuzhiyun if (timeout.tv_sec < now.tv_sec) {
3797*4882a593Smuzhiyun /*
3798*4882a593Smuzhiyun * Integer overflow - assume long enough timeout to be assumed
3799*4882a593Smuzhiyun * to be infinite, i.e., the timeout would never happen.
3800*4882a593Smuzhiyun */
3801*4882a593Smuzhiyun AEXT_TRACE("wlan",
3802*4882a593Smuzhiyun "Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
3803*4882a593Smuzhiyun RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec);
3804*4882a593Smuzhiyun }
3805*4882a593Smuzhiyun
3806*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3807*4882a593Smuzhiyun
3808*4882a593Smuzhiyun /* update RSSI */
3809*4882a593Smuzhiyun for (i = 0; i < ss_list->count; i++) {
3810*4882a593Smuzhiyun node = *rssi_head;
3811*4882a593Smuzhiyun prev = NULL;
3812*4882a593Smuzhiyun k = 0;
3813*4882a593Smuzhiyun bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3814*4882a593Smuzhiyun for (;node;) {
3815*4882a593Smuzhiyun if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3816*4882a593Smuzhiyun AEXT_INFO("wlan", "Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3817*4882a593Smuzhiyun k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
3818*4882a593Smuzhiyun for (j=0; j<RSSIAVG_LEN-1; j++)
3819*4882a593Smuzhiyun node->RSSI[j] = node->RSSI[j+1];
3820*4882a593Smuzhiyun node->RSSI[j] = dtoh16(bi->RSSI);
3821*4882a593Smuzhiyun node->dirty = 0;
3822*4882a593Smuzhiyun node->tv = timeout;
3823*4882a593Smuzhiyun break;
3824*4882a593Smuzhiyun }
3825*4882a593Smuzhiyun prev = node;
3826*4882a593Smuzhiyun node = node->next;
3827*4882a593Smuzhiyun k++;
3828*4882a593Smuzhiyun }
3829*4882a593Smuzhiyun
3830*4882a593Smuzhiyun if (node)
3831*4882a593Smuzhiyun continue;
3832*4882a593Smuzhiyun
3833*4882a593Smuzhiyun leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
3834*4882a593Smuzhiyun if (!leaf) {
3835*4882a593Smuzhiyun AEXT_ERROR("wlan", "Memory alloc failure %d\n",
3836*4882a593Smuzhiyun (int)sizeof(wl_rssi_cache_t));
3837*4882a593Smuzhiyun return;
3838*4882a593Smuzhiyun }
3839*4882a593Smuzhiyun AEXT_INFO("wlan", "Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
3840*4882a593Smuzhiyun k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
3841*4882a593Smuzhiyun
3842*4882a593Smuzhiyun leaf->next = NULL;
3843*4882a593Smuzhiyun leaf->dirty = 0;
3844*4882a593Smuzhiyun leaf->tv = timeout;
3845*4882a593Smuzhiyun memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN);
3846*4882a593Smuzhiyun for (j=0; j<RSSIAVG_LEN; j++)
3847*4882a593Smuzhiyun leaf->RSSI[j] = dtoh16(bi->RSSI);
3848*4882a593Smuzhiyun
3849*4882a593Smuzhiyun if (!prev)
3850*4882a593Smuzhiyun *rssi_head = leaf;
3851*4882a593Smuzhiyun else
3852*4882a593Smuzhiyun prev->next = leaf;
3853*4882a593Smuzhiyun }
3854*4882a593Smuzhiyun }
3855*4882a593Smuzhiyun
3856*4882a593Smuzhiyun int16
wl_get_avg_rssi(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,void * addr)3857*4882a593Smuzhiyun wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr)
3858*4882a593Smuzhiyun {
3859*4882a593Smuzhiyun wl_rssi_cache_t *node, **rssi_head;
3860*4882a593Smuzhiyun int j, rssi_sum, rssi=RSSI_MINVAL;
3861*4882a593Smuzhiyun
3862*4882a593Smuzhiyun rssi_head = &rssi_cache_ctrl->m_cache_head;
3863*4882a593Smuzhiyun
3864*4882a593Smuzhiyun node = *rssi_head;
3865*4882a593Smuzhiyun for (;node;) {
3866*4882a593Smuzhiyun if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) {
3867*4882a593Smuzhiyun rssi_sum = 0;
3868*4882a593Smuzhiyun rssi = 0;
3869*4882a593Smuzhiyun for (j=0; j<RSSIAVG_LEN; j++)
3870*4882a593Smuzhiyun rssi_sum += node->RSSI[RSSIAVG_LEN-j-1];
3871*4882a593Smuzhiyun rssi = rssi_sum / j;
3872*4882a593Smuzhiyun break;
3873*4882a593Smuzhiyun }
3874*4882a593Smuzhiyun node = node->next;
3875*4882a593Smuzhiyun }
3876*4882a593Smuzhiyun rssi = MIN(rssi, RSSI_MAXVAL);
3877*4882a593Smuzhiyun if (rssi == RSSI_MINVAL) {
3878*4882a593Smuzhiyun AEXT_ERROR("wlan", "BSSID %pM does not in RSSI cache\n", addr);
3879*4882a593Smuzhiyun }
3880*4882a593Smuzhiyun return (int16)rssi;
3881*4882a593Smuzhiyun }
3882*4882a593Smuzhiyun #endif /* RSSIAVG */
3883*4882a593Smuzhiyun
3884*4882a593Smuzhiyun #if defined(RSSIOFFSET)
3885*4882a593Smuzhiyun int
wl_update_rssi_offset(struct net_device * net,int rssi)3886*4882a593Smuzhiyun wl_update_rssi_offset(struct net_device *net, int rssi)
3887*4882a593Smuzhiyun {
3888*4882a593Smuzhiyun #if defined(RSSIOFFSET_NEW)
3889*4882a593Smuzhiyun int j;
3890*4882a593Smuzhiyun #endif /* RSSIOFFSET_NEW */
3891*4882a593Smuzhiyun
3892*4882a593Smuzhiyun if (!g_wifi_on)
3893*4882a593Smuzhiyun return rssi;
3894*4882a593Smuzhiyun
3895*4882a593Smuzhiyun #if defined(RSSIOFFSET_NEW)
3896*4882a593Smuzhiyun for (j=0; j<RSSI_OFFSET; j++) {
3897*4882a593Smuzhiyun if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
3898*4882a593Smuzhiyun break;
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun rssi += j;
3901*4882a593Smuzhiyun #else
3902*4882a593Smuzhiyun rssi += RSSI_OFFSET;
3903*4882a593Smuzhiyun #endif /* RSSIOFFSET_NEW */
3904*4882a593Smuzhiyun return MIN(rssi, RSSI_MAXVAL);
3905*4882a593Smuzhiyun }
3906*4882a593Smuzhiyun #endif /* RSSIOFFSET */
3907*4882a593Smuzhiyun
3908*4882a593Smuzhiyun #if defined(BSSCACHE)
3909*4882a593Smuzhiyun void
wl_free_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl)3910*4882a593Smuzhiyun wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3911*4882a593Smuzhiyun {
3912*4882a593Smuzhiyun wl_bss_cache_t *node, *cur, **bss_head;
3913*4882a593Smuzhiyun int i=0;
3914*4882a593Smuzhiyun
3915*4882a593Smuzhiyun AEXT_TRACE("wlan", "called\n");
3916*4882a593Smuzhiyun
3917*4882a593Smuzhiyun bss_head = &bss_cache_ctrl->m_cache_head;
3918*4882a593Smuzhiyun node = *bss_head;
3919*4882a593Smuzhiyun
3920*4882a593Smuzhiyun for (;node;) {
3921*4882a593Smuzhiyun AEXT_TRACE("wlan", "Free %d with BSSID %pM\n",
3922*4882a593Smuzhiyun i, &node->results.bss_info->BSSID);
3923*4882a593Smuzhiyun cur = node;
3924*4882a593Smuzhiyun node = cur->next;
3925*4882a593Smuzhiyun kfree(cur);
3926*4882a593Smuzhiyun i++;
3927*4882a593Smuzhiyun }
3928*4882a593Smuzhiyun *bss_head = NULL;
3929*4882a593Smuzhiyun }
3930*4882a593Smuzhiyun
3931*4882a593Smuzhiyun void
wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl)3932*4882a593Smuzhiyun wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3933*4882a593Smuzhiyun {
3934*4882a593Smuzhiyun wl_bss_cache_t *node, *prev, **bss_head;
3935*4882a593Smuzhiyun int i = -1, tmp = 0;
3936*4882a593Smuzhiyun struct osl_timespec now;
3937*4882a593Smuzhiyun
3938*4882a593Smuzhiyun osl_do_gettimeofday(&now);
3939*4882a593Smuzhiyun
3940*4882a593Smuzhiyun bss_head = &bss_cache_ctrl->m_cache_head;
3941*4882a593Smuzhiyun node = *bss_head;
3942*4882a593Smuzhiyun prev = node;
3943*4882a593Smuzhiyun for (;node;) {
3944*4882a593Smuzhiyun i++;
3945*4882a593Smuzhiyun if (now.tv_sec > node->tv.tv_sec || node->dirty > BSSCACHE_DIRTY) {
3946*4882a593Smuzhiyun if (node == *bss_head) {
3947*4882a593Smuzhiyun tmp = 1;
3948*4882a593Smuzhiyun *bss_head = node->next;
3949*4882a593Smuzhiyun } else {
3950*4882a593Smuzhiyun tmp = 0;
3951*4882a593Smuzhiyun prev->next = node->next;
3952*4882a593Smuzhiyun }
3953*4882a593Smuzhiyun AEXT_TRACE("wlan", "Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3954*4882a593Smuzhiyun i, &node->results.bss_info->BSSID,
3955*4882a593Smuzhiyun dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID);
3956*4882a593Smuzhiyun kfree(node);
3957*4882a593Smuzhiyun if (tmp == 1) {
3958*4882a593Smuzhiyun node = *bss_head;
3959*4882a593Smuzhiyun prev = node;
3960*4882a593Smuzhiyun } else {
3961*4882a593Smuzhiyun node = prev->next;
3962*4882a593Smuzhiyun }
3963*4882a593Smuzhiyun continue;
3964*4882a593Smuzhiyun }
3965*4882a593Smuzhiyun prev = node;
3966*4882a593Smuzhiyun node = node->next;
3967*4882a593Smuzhiyun }
3968*4882a593Smuzhiyun }
3969*4882a593Smuzhiyun
3970*4882a593Smuzhiyun void
wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl,u8 * bssid)3971*4882a593Smuzhiyun wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
3972*4882a593Smuzhiyun u8 *bssid)
3973*4882a593Smuzhiyun {
3974*4882a593Smuzhiyun wl_bss_cache_t *node, *prev, **bss_head;
3975*4882a593Smuzhiyun int i = -1, tmp = 0;
3976*4882a593Smuzhiyun
3977*4882a593Smuzhiyun bss_head = &bss_cache_ctrl->m_cache_head;
3978*4882a593Smuzhiyun node = *bss_head;
3979*4882a593Smuzhiyun prev = node;
3980*4882a593Smuzhiyun for (;node;) {
3981*4882a593Smuzhiyun i++;
3982*4882a593Smuzhiyun if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) {
3983*4882a593Smuzhiyun if (node == *bss_head) {
3984*4882a593Smuzhiyun tmp = 1;
3985*4882a593Smuzhiyun *bss_head = node->next;
3986*4882a593Smuzhiyun } else {
3987*4882a593Smuzhiyun tmp = 0;
3988*4882a593Smuzhiyun prev->next = node->next;
3989*4882a593Smuzhiyun }
3990*4882a593Smuzhiyun AEXT_TRACE("wlan", "Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
3991*4882a593Smuzhiyun i, &node->results.bss_info->BSSID,
3992*4882a593Smuzhiyun dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID);
3993*4882a593Smuzhiyun kfree(node);
3994*4882a593Smuzhiyun if (tmp == 1) {
3995*4882a593Smuzhiyun node = *bss_head;
3996*4882a593Smuzhiyun prev = node;
3997*4882a593Smuzhiyun } else {
3998*4882a593Smuzhiyun node = prev->next;
3999*4882a593Smuzhiyun }
4000*4882a593Smuzhiyun continue;
4001*4882a593Smuzhiyun }
4002*4882a593Smuzhiyun prev = node;
4003*4882a593Smuzhiyun node = node->next;
4004*4882a593Smuzhiyun }
4005*4882a593Smuzhiyun }
4006*4882a593Smuzhiyun
4007*4882a593Smuzhiyun int
wl_bss_cache_size(wl_bss_cache_ctrl_t * bss_cache_ctrl)4008*4882a593Smuzhiyun wl_bss_cache_size(wl_bss_cache_ctrl_t *bss_cache_ctrl)
4009*4882a593Smuzhiyun {
4010*4882a593Smuzhiyun wl_bss_cache_t *node, **bss_head;
4011*4882a593Smuzhiyun int bss_num = 0;
4012*4882a593Smuzhiyun
4013*4882a593Smuzhiyun bss_head = &bss_cache_ctrl->m_cache_head;
4014*4882a593Smuzhiyun
4015*4882a593Smuzhiyun node = *bss_head;
4016*4882a593Smuzhiyun for (;node;) {
4017*4882a593Smuzhiyun if (node->dirty > 1) {
4018*4882a593Smuzhiyun bss_num++;
4019*4882a593Smuzhiyun }
4020*4882a593Smuzhiyun node = node->next;
4021*4882a593Smuzhiyun }
4022*4882a593Smuzhiyun return bss_num;
4023*4882a593Smuzhiyun }
4024*4882a593Smuzhiyun
4025*4882a593Smuzhiyun void
wl_reset_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl)4026*4882a593Smuzhiyun wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
4027*4882a593Smuzhiyun {
4028*4882a593Smuzhiyun wl_bss_cache_t *node, **bss_head;
4029*4882a593Smuzhiyun
4030*4882a593Smuzhiyun bss_head = &bss_cache_ctrl->m_cache_head;
4031*4882a593Smuzhiyun
4032*4882a593Smuzhiyun /* reset dirty */
4033*4882a593Smuzhiyun node = *bss_head;
4034*4882a593Smuzhiyun for (;node;) {
4035*4882a593Smuzhiyun node->dirty += 1;
4036*4882a593Smuzhiyun node = node->next;
4037*4882a593Smuzhiyun }
4038*4882a593Smuzhiyun }
4039*4882a593Smuzhiyun
4040*4882a593Smuzhiyun static void
wl_bss_cache_dump(wl_rssi_cache_ctrl_t * rssi_cache_ctrl,wl_bss_cache_t * node)4041*4882a593Smuzhiyun wl_bss_cache_dump(
4042*4882a593Smuzhiyun #if defined(RSSIAVG)
4043*4882a593Smuzhiyun wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
4044*4882a593Smuzhiyun #endif /* RSSIAVG */
4045*4882a593Smuzhiyun wl_bss_cache_t *node)
4046*4882a593Smuzhiyun {
4047*4882a593Smuzhiyun int k = 0;
4048*4882a593Smuzhiyun int16 rssi;
4049*4882a593Smuzhiyun
4050*4882a593Smuzhiyun for (;node;) {
4051*4882a593Smuzhiyun #if defined(RSSIAVG)
4052*4882a593Smuzhiyun rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
4053*4882a593Smuzhiyun #else
4054*4882a593Smuzhiyun rssi = dtoh16(node->results.bss_info->RSSI);
4055*4882a593Smuzhiyun #endif /* RSSIAVG */
4056*4882a593Smuzhiyun k++;
4057*4882a593Smuzhiyun AEXT_TRACE("wlan", "dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
4058*4882a593Smuzhiyun k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID);
4059*4882a593Smuzhiyun node = node->next;
4060*4882a593Smuzhiyun }
4061*4882a593Smuzhiyun }
4062*4882a593Smuzhiyun
4063*4882a593Smuzhiyun #if defined(SORT_BSS_CHANNEL)
4064*4882a593Smuzhiyun static wl_bss_cache_t *
wl_bss_cache_sort_channel(wl_bss_cache_t ** bss_head,wl_bss_cache_t * leaf)4065*4882a593Smuzhiyun wl_bss_cache_sort_channel(wl_bss_cache_t **bss_head, wl_bss_cache_t *leaf)
4066*4882a593Smuzhiyun {
4067*4882a593Smuzhiyun wl_bss_cache_t *node, *prev;
4068*4882a593Smuzhiyun uint16 channel, channel_node;
4069*4882a593Smuzhiyun
4070*4882a593Smuzhiyun node = *bss_head;
4071*4882a593Smuzhiyun channel = wf_chspec_ctlchan(leaf->results.bss_info->chanspec);
4072*4882a593Smuzhiyun for (;node;) {
4073*4882a593Smuzhiyun channel_node = wf_chspec_ctlchan(node->results.bss_info->chanspec);
4074*4882a593Smuzhiyun if (channel_node > channel) {
4075*4882a593Smuzhiyun leaf->next = node;
4076*4882a593Smuzhiyun if (node == *bss_head)
4077*4882a593Smuzhiyun *bss_head = leaf;
4078*4882a593Smuzhiyun else
4079*4882a593Smuzhiyun prev->next = leaf;
4080*4882a593Smuzhiyun break;
4081*4882a593Smuzhiyun }
4082*4882a593Smuzhiyun prev = node;
4083*4882a593Smuzhiyun node = node->next;
4084*4882a593Smuzhiyun }
4085*4882a593Smuzhiyun if (node == NULL)
4086*4882a593Smuzhiyun prev->next = leaf;
4087*4882a593Smuzhiyun
4088*4882a593Smuzhiyun return *bss_head;
4089*4882a593Smuzhiyun }
4090*4882a593Smuzhiyun #endif /* SORT_BSS_CHANNEL */
4091*4882a593Smuzhiyun
4092*4882a593Smuzhiyun #if defined(SORT_BSS_RSSI)
4093*4882a593Smuzhiyun static wl_bss_cache_t *
wl_bss_cache_sort_rssi(wl_bss_cache_t ** bss_head,wl_bss_cache_t * leaf,wl_rssi_cache_ctrl_t * rssi_cache_ctrl)4094*4882a593Smuzhiyun wl_bss_cache_sort_rssi(wl_bss_cache_t **bss_head, wl_bss_cache_t *leaf
4095*4882a593Smuzhiyun #if defined(RSSIAVG)
4096*4882a593Smuzhiyun , wl_rssi_cache_ctrl_t *rssi_cache_ctrl
4097*4882a593Smuzhiyun #endif /* RSSIAVG */
4098*4882a593Smuzhiyun )
4099*4882a593Smuzhiyun {
4100*4882a593Smuzhiyun wl_bss_cache_t *node, *prev;
4101*4882a593Smuzhiyun int16 rssi, rssi_node;
4102*4882a593Smuzhiyun
4103*4882a593Smuzhiyun node = *bss_head;
4104*4882a593Smuzhiyun #if defined(RSSIAVG)
4105*4882a593Smuzhiyun rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID);
4106*4882a593Smuzhiyun #else
4107*4882a593Smuzhiyun rssi = dtoh16(leaf->results.bss_info->RSSI);
4108*4882a593Smuzhiyun #endif /* RSSIAVG */
4109*4882a593Smuzhiyun for (;node;) {
4110*4882a593Smuzhiyun #if defined(RSSIAVG)
4111*4882a593Smuzhiyun rssi_node = wl_get_avg_rssi(rssi_cache_ctrl,
4112*4882a593Smuzhiyun &node->results.bss_info->BSSID);
4113*4882a593Smuzhiyun #else
4114*4882a593Smuzhiyun rssi_node = dtoh16(node->results.bss_info->RSSI);
4115*4882a593Smuzhiyun #endif /* RSSIAVG */
4116*4882a593Smuzhiyun if (rssi > rssi_node) {
4117*4882a593Smuzhiyun leaf->next = node;
4118*4882a593Smuzhiyun if (node == *bss_head)
4119*4882a593Smuzhiyun *bss_head = leaf;
4120*4882a593Smuzhiyun else
4121*4882a593Smuzhiyun prev->next = leaf;
4122*4882a593Smuzhiyun break;
4123*4882a593Smuzhiyun }
4124*4882a593Smuzhiyun prev = node;
4125*4882a593Smuzhiyun node = node->next;
4126*4882a593Smuzhiyun }
4127*4882a593Smuzhiyun if (node == NULL)
4128*4882a593Smuzhiyun prev->next = leaf;
4129*4882a593Smuzhiyun
4130*4882a593Smuzhiyun return *bss_head;
4131*4882a593Smuzhiyun }
4132*4882a593Smuzhiyun #endif /* SORT_BSS_BY_RSSI */
4133*4882a593Smuzhiyun
4134*4882a593Smuzhiyun void
wl_update_bss_cache(wl_bss_cache_ctrl_t * bss_cache_ctrl,wl_rssi_cache_ctrl_t * rssi_cache_ctrl,wl_scan_results_v109_t * ss_list)4135*4882a593Smuzhiyun wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
4136*4882a593Smuzhiyun #if defined(RSSIAVG)
4137*4882a593Smuzhiyun wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
4138*4882a593Smuzhiyun #endif /* RSSIAVG */
4139*4882a593Smuzhiyun wl_scan_results_v109_t *ss_list)
4140*4882a593Smuzhiyun {
4141*4882a593Smuzhiyun wl_bss_cache_t *node, *node_target = NULL, *prev, *leaf, **bss_head;
4142*4882a593Smuzhiyun wl_bss_cache_t *node_rssi_prev = NULL, *node_rssi = NULL;
4143*4882a593Smuzhiyun wl_bss_info_v109_t *bi = NULL;
4144*4882a593Smuzhiyun int i, k=0, bss_num = 0;
4145*4882a593Smuzhiyun struct osl_timespec now, timeout;
4146*4882a593Smuzhiyun int16 rssi_min;
4147*4882a593Smuzhiyun bool rssi_replace = FALSE;
4148*4882a593Smuzhiyun
4149*4882a593Smuzhiyun if (!ss_list->count)
4150*4882a593Smuzhiyun return;
4151*4882a593Smuzhiyun
4152*4882a593Smuzhiyun osl_do_gettimeofday(&now);
4153*4882a593Smuzhiyun timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT;
4154*4882a593Smuzhiyun if (timeout.tv_sec < now.tv_sec) {
4155*4882a593Smuzhiyun /*
4156*4882a593Smuzhiyun * Integer overflow - assume long enough timeout to be assumed
4157*4882a593Smuzhiyun * to be infinite, i.e., the timeout would never happen.
4158*4882a593Smuzhiyun */
4159*4882a593Smuzhiyun AEXT_TRACE("wlan",
4160*4882a593Smuzhiyun "Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu\n",
4161*4882a593Smuzhiyun BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec);
4162*4882a593Smuzhiyun }
4163*4882a593Smuzhiyun
4164*4882a593Smuzhiyun bss_head = &bss_cache_ctrl->m_cache_head;
4165*4882a593Smuzhiyun
4166*4882a593Smuzhiyun // get the num of bss cache
4167*4882a593Smuzhiyun node = *bss_head;
4168*4882a593Smuzhiyun for (;node;) {
4169*4882a593Smuzhiyun node = node->next;
4170*4882a593Smuzhiyun bss_num++;
4171*4882a593Smuzhiyun }
4172*4882a593Smuzhiyun
4173*4882a593Smuzhiyun for (i=0; i < ss_list->count; i++) {
4174*4882a593Smuzhiyun node = *bss_head;
4175*4882a593Smuzhiyun prev = NULL;
4176*4882a593Smuzhiyun node_target = NULL;
4177*4882a593Smuzhiyun node_rssi_prev = NULL;
4178*4882a593Smuzhiyun bi = bi ? (wl_bss_info_v109_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
4179*4882a593Smuzhiyun
4180*4882a593Smuzhiyun // find the bss with same BSSID
4181*4882a593Smuzhiyun for (;node;) {
4182*4882a593Smuzhiyun if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
4183*4882a593Smuzhiyun if (node == *bss_head)
4184*4882a593Smuzhiyun *bss_head = node->next;
4185*4882a593Smuzhiyun else {
4186*4882a593Smuzhiyun prev->next = node->next;
4187*4882a593Smuzhiyun }
4188*4882a593Smuzhiyun break;
4189*4882a593Smuzhiyun }
4190*4882a593Smuzhiyun prev = node;
4191*4882a593Smuzhiyun node = node->next;
4192*4882a593Smuzhiyun }
4193*4882a593Smuzhiyun if (node)
4194*4882a593Smuzhiyun node_target = node;
4195*4882a593Smuzhiyun
4196*4882a593Smuzhiyun // find the bss with lowest RSSI
4197*4882a593Smuzhiyun if (!node_target && bss_num >= BSSCACHE_MAXCNT) {
4198*4882a593Smuzhiyun node = *bss_head;
4199*4882a593Smuzhiyun prev = NULL;
4200*4882a593Smuzhiyun rssi_min = dtoh16(bi->RSSI);
4201*4882a593Smuzhiyun for (;node;) {
4202*4882a593Smuzhiyun if (dtoh16(node->results.bss_info->RSSI) < rssi_min) {
4203*4882a593Smuzhiyun node_rssi = node;
4204*4882a593Smuzhiyun node_rssi_prev = prev;
4205*4882a593Smuzhiyun rssi_min = dtoh16(node->results.bss_info->RSSI);
4206*4882a593Smuzhiyun }
4207*4882a593Smuzhiyun prev = node;
4208*4882a593Smuzhiyun node = node->next;
4209*4882a593Smuzhiyun }
4210*4882a593Smuzhiyun if (dtoh16(bi->RSSI) > rssi_min) {
4211*4882a593Smuzhiyun rssi_replace = TRUE;
4212*4882a593Smuzhiyun node_target = node_rssi;
4213*4882a593Smuzhiyun if (node_rssi == *bss_head)
4214*4882a593Smuzhiyun *bss_head = node_rssi->next;
4215*4882a593Smuzhiyun else if (node_rssi) {
4216*4882a593Smuzhiyun node_rssi_prev->next = node_rssi->next;
4217*4882a593Smuzhiyun }
4218*4882a593Smuzhiyun }
4219*4882a593Smuzhiyun }
4220*4882a593Smuzhiyun
4221*4882a593Smuzhiyun k++;
4222*4882a593Smuzhiyun if (bss_num < BSSCACHE_MAXCNT) {
4223*4882a593Smuzhiyun bss_num++;
4224*4882a593Smuzhiyun AEXT_TRACE("wlan",
4225*4882a593Smuzhiyun "Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
4226*4882a593Smuzhiyun k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
4227*4882a593Smuzhiyun } else if (node_target) {
4228*4882a593Smuzhiyun if (rssi_replace) {
4229*4882a593Smuzhiyun AEXT_TRACE("wlan",
4230*4882a593Smuzhiyun "Replace %d with cached BSSID %pM(%3d) => %pM(%3d), "\
4231*4882a593Smuzhiyun "SSID \"%s\" => \"%s\"\n",
4232*4882a593Smuzhiyun k, &node_target->results.bss_info->BSSID,
4233*4882a593Smuzhiyun dtoh16(node_target->results.bss_info->RSSI),
4234*4882a593Smuzhiyun &bi->BSSID, dtoh16(bi->RSSI),
4235*4882a593Smuzhiyun node_target->results.bss_info->SSID, bi->SSID);
4236*4882a593Smuzhiyun } else {
4237*4882a593Smuzhiyun AEXT_TRACE("wlan",
4238*4882a593Smuzhiyun "Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
4239*4882a593Smuzhiyun k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
4240*4882a593Smuzhiyun }
4241*4882a593Smuzhiyun kfree(node_target);
4242*4882a593Smuzhiyun node_target = NULL;
4243*4882a593Smuzhiyun } else {
4244*4882a593Smuzhiyun AEXT_TRACE("wlan", "Skip %d BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
4245*4882a593Smuzhiyun k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID);
4246*4882a593Smuzhiyun continue;
4247*4882a593Smuzhiyun }
4248*4882a593Smuzhiyun
4249*4882a593Smuzhiyun leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL);
4250*4882a593Smuzhiyun if (!leaf) {
4251*4882a593Smuzhiyun AEXT_ERROR("wlan", "Memory alloc failure %d\n",
4252*4882a593Smuzhiyun dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t));
4253*4882a593Smuzhiyun return;
4254*4882a593Smuzhiyun }
4255*4882a593Smuzhiyun
4256*4882a593Smuzhiyun memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
4257*4882a593Smuzhiyun leaf->next = NULL;
4258*4882a593Smuzhiyun leaf->dirty = 0;
4259*4882a593Smuzhiyun leaf->tv = timeout;
4260*4882a593Smuzhiyun leaf->results.count = 1;
4261*4882a593Smuzhiyun leaf->results.version = ss_list->version;
4262*4882a593Smuzhiyun
4263*4882a593Smuzhiyun if (*bss_head == NULL)
4264*4882a593Smuzhiyun *bss_head = leaf;
4265*4882a593Smuzhiyun else {
4266*4882a593Smuzhiyun #if defined(SORT_BSS_CHANNEL)
4267*4882a593Smuzhiyun *bss_head = wl_bss_cache_sort_channel(bss_head, leaf);
4268*4882a593Smuzhiyun #elif defined(SORT_BSS_RSSI)
4269*4882a593Smuzhiyun *bss_head = wl_bss_cache_sort_rssi(bss_head, leaf
4270*4882a593Smuzhiyun #if defined(RSSIAVG)
4271*4882a593Smuzhiyun , rssi_cache_ctrl
4272*4882a593Smuzhiyun #endif /* RSSIAVG */
4273*4882a593Smuzhiyun );
4274*4882a593Smuzhiyun #else
4275*4882a593Smuzhiyun leaf->next = *bss_head;
4276*4882a593Smuzhiyun *bss_head = leaf;
4277*4882a593Smuzhiyun #endif /* SORT_BSS_BY_RSSI */
4278*4882a593Smuzhiyun }
4279*4882a593Smuzhiyun }
4280*4882a593Smuzhiyun wl_bss_cache_dump(
4281*4882a593Smuzhiyun #if defined(RSSIAVG)
4282*4882a593Smuzhiyun rssi_cache_ctrl,
4283*4882a593Smuzhiyun #endif /* RSSIAVG */
4284*4882a593Smuzhiyun *bss_head);
4285*4882a593Smuzhiyun }
4286*4882a593Smuzhiyun
4287*4882a593Smuzhiyun void
wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t * bss_cache_ctrl)4288*4882a593Smuzhiyun wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl)
4289*4882a593Smuzhiyun {
4290*4882a593Smuzhiyun AEXT_TRACE("wlan", "Enter\n");
4291*4882a593Smuzhiyun wl_free_bss_cache(bss_cache_ctrl);
4292*4882a593Smuzhiyun }
4293*4882a593Smuzhiyun #endif /* BSSCACHE */
4294