1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <linux/etherdevice.h> |
9 | #include <drv_types.h> |
10 | #include <rtw_debug.h> |
11 | #include <rtw_mp.h> |
12 | #include <hal_btcoex.h> |
13 | #include <linux/jiffies.h> |
14 | #include <linux/kernel.h> |
15 | |
16 | #define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30) |
17 | |
18 | static int wpa_set_auth_algs(struct net_device *dev, u32 value) |
19 | { |
20 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
21 | int ret = 0; |
22 | |
23 | if ((value & IW_AUTH_ALG_SHARED_KEY) && (value & IW_AUTH_ALG_OPEN_SYSTEM)) { |
24 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
25 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; |
26 | padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; |
27 | } else if (value & IW_AUTH_ALG_SHARED_KEY) { |
28 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
29 | |
30 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; |
31 | padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; |
32 | } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { |
33 | /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */ |
34 | if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) { |
35 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; |
36 | padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; |
37 | } |
38 | } else { |
39 | ret = -EINVAL; |
40 | } |
41 | |
42 | return ret; |
43 | } |
44 | |
45 | static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) |
46 | { |
47 | int ret = 0; |
48 | u8 max_idx; |
49 | u32 wep_key_idx, wep_key_len, wep_total_len; |
50 | struct ndis_802_11_wep *pwep = NULL; |
51 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
52 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
53 | struct security_priv *psecuritypriv = &padapter->securitypriv; |
54 | |
55 | param->u.crypt.err = 0; |
56 | param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; |
57 | |
58 | if (param_len < (u32)((u8 *)param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) { |
59 | ret = -EINVAL; |
60 | goto exit; |
61 | } |
62 | |
63 | if (param->sta_addr[0] != 0xff || param->sta_addr[1] != 0xff || |
64 | param->sta_addr[2] != 0xff || param->sta_addr[3] != 0xff || |
65 | param->sta_addr[4] != 0xff || param->sta_addr[5] != 0xff) { |
66 | ret = -EINVAL; |
67 | goto exit; |
68 | } |
69 | |
70 | if (strcmp(param->u.crypt.alg, "WEP" ) == 0) |
71 | max_idx = WEP_KEYS - 1; |
72 | else |
73 | max_idx = BIP_MAX_KEYID; |
74 | |
75 | if (param->u.crypt.idx > max_idx) { |
76 | netdev_err(dev, format: "Error crypt.idx %d > %d\n" , param->u.crypt.idx, max_idx); |
77 | ret = -EINVAL; |
78 | goto exit; |
79 | } |
80 | |
81 | if (strcmp(param->u.crypt.alg, "WEP" ) == 0) { |
82 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
83 | padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; |
84 | padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; |
85 | |
86 | wep_key_idx = param->u.crypt.idx; |
87 | wep_key_len = param->u.crypt.key_len; |
88 | |
89 | if (wep_key_len > 0) { |
90 | wep_key_len = wep_key_len <= 5 ? 5 : 13; |
91 | wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, key_material); |
92 | /* Allocate a full structure to avoid potentially running off the end. */ |
93 | pwep = kzalloc(size: sizeof(*pwep), GFP_KERNEL); |
94 | if (!pwep) { |
95 | ret = -ENOMEM; |
96 | goto exit; |
97 | } |
98 | |
99 | pwep->key_length = wep_key_len; |
100 | pwep->length = wep_total_len; |
101 | |
102 | if (wep_key_len == 13) { |
103 | padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; |
104 | padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; |
105 | } |
106 | } else { |
107 | ret = -EINVAL; |
108 | goto exit; |
109 | } |
110 | |
111 | pwep->key_index = wep_key_idx; |
112 | pwep->key_index |= 0x80000000; |
113 | |
114 | memcpy(pwep->key_material, param->u.crypt.key, pwep->key_length); |
115 | |
116 | if (param->u.crypt.set_tx) { |
117 | if (rtw_set_802_11_add_wep(padapter, wep: pwep) == (u8)_FAIL) |
118 | ret = -EOPNOTSUPP; |
119 | } else { |
120 | /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ |
121 | /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to fw/cam */ |
122 | |
123 | if (wep_key_idx >= WEP_KEYS) { |
124 | ret = -EOPNOTSUPP; |
125 | goto exit; |
126 | } |
127 | |
128 | memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->key_material, pwep->key_length); |
129 | psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->key_length; |
130 | rtw_set_key(adapter: padapter, psecuritypriv, keyid: wep_key_idx, set_tx: 0, enqueue: true); |
131 | } |
132 | |
133 | goto exit; |
134 | } |
135 | |
136 | if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */ |
137 | struct sta_info *psta, *pbcmc_sta; |
138 | struct sta_priv *pstapriv = &padapter->stapriv; |
139 | |
140 | if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) { /* sta mode */ |
141 | psta = rtw_get_stainfo(pstapriv, hwaddr: get_bssid(pmlmepriv)); |
142 | if (!psta) { |
143 | /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ |
144 | } else { |
145 | /* Jeff: don't disable ieee8021x_blocked while clearing key */ |
146 | if (strcmp(param->u.crypt.alg, "none" ) != 0) |
147 | psta->ieee8021x_blocked = false; |
148 | |
149 | if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) || |
150 | (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) { |
151 | psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; |
152 | } |
153 | |
154 | if (param->u.crypt.set_tx == 1) { /* pairwise key */ |
155 | memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
156 | |
157 | if (strcmp(param->u.crypt.alg, "TKIP" ) == 0) { /* set mic key */ |
158 | /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ |
159 | memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8); |
160 | memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8); |
161 | |
162 | padapter->securitypriv.busetkipkey = false; |
163 | /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ |
164 | } |
165 | |
166 | rtw_setstakey_cmd(padapter, sta: psta, unicast_key: true, enqueue: true); |
167 | } else { /* group key */ |
168 | if (strcmp(param->u.crypt.alg, "TKIP" ) == 0 || strcmp(param->u.crypt.alg, "CCMP" ) == 0) { |
169 | memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
170 | /* only TKIP group key need to install this */ |
171 | if (param->u.crypt.key_len > 16) { |
172 | memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[16], 8); |
173 | memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[24], 8); |
174 | } |
175 | padapter->securitypriv.binstallGrpkey = true; |
176 | |
177 | padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; |
178 | |
179 | rtw_set_key(adapter: padapter, psecuritypriv: &padapter->securitypriv, keyid: param->u.crypt.idx, set_tx: 1, enqueue: true); |
180 | } else if (strcmp(param->u.crypt.alg, "BIP" ) == 0) { |
181 | /* printk("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */ |
182 | /* save the IGTK key, length 16 bytes */ |
183 | memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
184 | /*printk("IGTK key below:\n"); |
185 | for (no = 0;no<16;no++) |
186 | printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); |
187 | printk("\n");*/ |
188 | padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; |
189 | padapter->securitypriv.binstallBIPkey = true; |
190 | } |
191 | } |
192 | } |
193 | |
194 | pbcmc_sta = rtw_get_bcmc_stainfo(padapter); |
195 | if (!pbcmc_sta) { |
196 | /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ |
197 | } else { |
198 | /* Jeff: don't disable ieee8021x_blocked while clearing key */ |
199 | if (strcmp(param->u.crypt.alg, "none" ) != 0) |
200 | pbcmc_sta->ieee8021x_blocked = false; |
201 | |
202 | if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) || |
203 | (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) { |
204 | pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; |
205 | } |
206 | } |
207 | } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { |
208 | /* adhoc mode */ |
209 | } |
210 | } |
211 | |
212 | exit: |
213 | |
214 | kfree(objp: pwep); |
215 | return ret; |
216 | } |
217 | |
218 | static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen) |
219 | { |
220 | u8 *buf = NULL; |
221 | int group_cipher = 0, pairwise_cipher = 0; |
222 | int ret = 0; |
223 | u8 null_addr[] = {0, 0, 0, 0, 0, 0}; |
224 | |
225 | if (ielen > MAX_WPA_IE_LEN || !pie) { |
226 | _clr_fwstate_(pmlmepriv: &padapter->mlmepriv, WIFI_UNDER_WPS); |
227 | if (!pie) |
228 | return ret; |
229 | else |
230 | return -EINVAL; |
231 | } |
232 | |
233 | if (ielen) { |
234 | buf = rtw_zmalloc(ielen); |
235 | if (!buf) { |
236 | ret = -ENOMEM; |
237 | goto exit; |
238 | } |
239 | |
240 | memcpy(buf, pie, ielen); |
241 | |
242 | if (ielen < RSN_HEADER_LEN) { |
243 | ret = -1; |
244 | goto exit; |
245 | } |
246 | |
247 | if (rtw_parse_wpa_ie(wpa_ie: buf, wpa_ie_len: ielen, group_cipher: &group_cipher, pairwise_cipher: &pairwise_cipher, NULL) == _SUCCESS) { |
248 | padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; |
249 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; |
250 | memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); |
251 | } |
252 | |
253 | if (rtw_parse_wpa2_ie(wpa_ie: buf, wpa_ie_len: ielen, group_cipher: &group_cipher, pairwise_cipher: &pairwise_cipher, NULL) == _SUCCESS) { |
254 | padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; |
255 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; |
256 | memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); |
257 | } |
258 | |
259 | if (group_cipher == 0) |
260 | group_cipher = WPA_CIPHER_NONE; |
261 | if (pairwise_cipher == 0) |
262 | pairwise_cipher = WPA_CIPHER_NONE; |
263 | |
264 | switch (group_cipher) { |
265 | case WPA_CIPHER_NONE: |
266 | padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; |
267 | padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; |
268 | break; |
269 | case WPA_CIPHER_WEP40: |
270 | padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; |
271 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
272 | break; |
273 | case WPA_CIPHER_TKIP: |
274 | padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; |
275 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; |
276 | break; |
277 | case WPA_CIPHER_CCMP: |
278 | padapter->securitypriv.dot118021XGrpPrivacy = _AES_; |
279 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; |
280 | break; |
281 | case WPA_CIPHER_WEP104: |
282 | padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; |
283 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
284 | break; |
285 | } |
286 | |
287 | switch (pairwise_cipher) { |
288 | case WPA_CIPHER_NONE: |
289 | padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; |
290 | padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; |
291 | break; |
292 | case WPA_CIPHER_WEP40: |
293 | padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; |
294 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
295 | break; |
296 | case WPA_CIPHER_TKIP: |
297 | padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; |
298 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; |
299 | break; |
300 | case WPA_CIPHER_CCMP: |
301 | padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; |
302 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; |
303 | break; |
304 | case WPA_CIPHER_WEP104: |
305 | padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; |
306 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; |
307 | break; |
308 | } |
309 | |
310 | _clr_fwstate_(pmlmepriv: &padapter->mlmepriv, WIFI_UNDER_WPS); |
311 | {/* set wps_ie */ |
312 | u16 cnt = 0; |
313 | u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; |
314 | |
315 | while (cnt < ielen) { |
316 | eid = buf[cnt]; |
317 | |
318 | if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(p: &buf[cnt + 2], q: wps_oui, size: 4))) { |
319 | padapter->securitypriv.wps_ie_len = ((buf[cnt + 1] + 2) < MAX_WPS_IE_LEN) ? (buf[cnt + 1] + 2) : MAX_WPS_IE_LEN; |
320 | |
321 | memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len); |
322 | |
323 | set_fwstate(pmlmepriv: &padapter->mlmepriv, WIFI_UNDER_WPS); |
324 | |
325 | cnt += buf[cnt + 1] + 2; |
326 | |
327 | break; |
328 | } else { |
329 | cnt += buf[cnt + 1] + 2; /* goto next */ |
330 | } |
331 | } |
332 | } |
333 | } |
334 | |
335 | /* TKIP and AES disallow multicast packets until installing group key */ |
336 | if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ || |
337 | padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ || |
338 | padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) |
339 | /* WPS open need to enable multicast */ |
340 | /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true) */ |
341 | rtw_hal_set_hwreg(padapter, variable: HW_VAR_OFF_RCR_AM, val: null_addr); |
342 | |
343 | exit: |
344 | |
345 | kfree(objp: buf); |
346 | |
347 | return ret; |
348 | } |
349 | |
350 | static int wpa_set_param(struct net_device *dev, u8 name, u32 value) |
351 | { |
352 | uint ret = 0; |
353 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
354 | |
355 | switch (name) { |
356 | case IEEE_PARAM_WPA_ENABLED: |
357 | |
358 | padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; /* 802.1x */ |
359 | |
360 | /* ret = ieee80211_wpa_enable(ieee, value); */ |
361 | |
362 | switch ((value) & 0xff) { |
363 | case 1: /* WPA */ |
364 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */ |
365 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; |
366 | break; |
367 | case 2: /* WPA2 */ |
368 | padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */ |
369 | padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; |
370 | break; |
371 | } |
372 | |
373 | break; |
374 | |
375 | case IEEE_PARAM_TKIP_COUNTERMEASURES: |
376 | /* ieee->tkip_countermeasures =value; */ |
377 | break; |
378 | |
379 | case IEEE_PARAM_DROP_UNENCRYPTED: |
380 | { |
381 | /* HACK: |
382 | * |
383 | * wpa_supplicant calls set_wpa_enabled when the driver |
384 | * is loaded and unloaded, regardless of if WPA is being |
385 | * used. No other calls are made which can be used to |
386 | * determine if encryption will be used or not prior to |
387 | * association being expected. If encryption is not being |
388 | * used, drop_unencrypted is set to false, else true -- we |
389 | * can use this to determine if the CAP_PRIVACY_ON bit should |
390 | * be set. |
391 | */ |
392 | break; |
393 | } |
394 | case IEEE_PARAM_PRIVACY_INVOKED: |
395 | |
396 | /* ieee->privacy_invoked =value; */ |
397 | |
398 | break; |
399 | |
400 | case IEEE_PARAM_AUTH_ALGS: |
401 | |
402 | ret = wpa_set_auth_algs(dev, value); |
403 | |
404 | break; |
405 | |
406 | case IEEE_PARAM_IEEE_802_1X: |
407 | |
408 | /* ieee->ieee802_1x =value; */ |
409 | |
410 | break; |
411 | |
412 | case IEEE_PARAM_WPAX_SELECT: |
413 | |
414 | /* added for WPA2 mixed mode */ |
415 | /* |
416 | spin_lock_irqsave(&ieee->wpax_suitlist_lock, flags); |
417 | ieee->wpax_type_set = 1; |
418 | ieee->wpax_type_notify = value; |
419 | spin_unlock_irqrestore(&ieee->wpax_suitlist_lock, flags); |
420 | */ |
421 | |
422 | break; |
423 | |
424 | default: |
425 | |
426 | ret = -EOPNOTSUPP; |
427 | |
428 | break; |
429 | } |
430 | |
431 | return ret; |
432 | } |
433 | |
434 | static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) |
435 | { |
436 | int ret = 0; |
437 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
438 | |
439 | switch (command) { |
440 | case IEEE_MLME_STA_DEAUTH: |
441 | |
442 | if (!rtw_set_802_11_disassociate(padapter)) |
443 | ret = -1; |
444 | |
445 | break; |
446 | |
447 | case IEEE_MLME_STA_DISASSOC: |
448 | |
449 | if (!rtw_set_802_11_disassociate(padapter)) |
450 | ret = -1; |
451 | |
452 | break; |
453 | |
454 | default: |
455 | ret = -EOPNOTSUPP; |
456 | break; |
457 | } |
458 | |
459 | return ret; |
460 | } |
461 | |
462 | static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) |
463 | { |
464 | struct ieee_param *param; |
465 | uint ret = 0; |
466 | |
467 | /* down(&ieee->wx_sem); */ |
468 | |
469 | if (!p->pointer || p->length != sizeof(struct ieee_param)) |
470 | return -EINVAL; |
471 | |
472 | param = rtw_malloc(p->length); |
473 | if (!param) |
474 | return -ENOMEM; |
475 | |
476 | if (copy_from_user(to: param, from: p->pointer, n: p->length)) { |
477 | kfree(objp: param); |
478 | return -EFAULT; |
479 | } |
480 | |
481 | switch (param->cmd) { |
482 | case IEEE_CMD_SET_WPA_PARAM: |
483 | ret = wpa_set_param(dev, name: param->u.wpa_param.name, value: param->u.wpa_param.value); |
484 | break; |
485 | |
486 | case IEEE_CMD_SET_WPA_IE: |
487 | /* ret = wpa_set_wpa_ie(dev, param, p->length); */ |
488 | ret = rtw_set_wpa_ie(padapter: rtw_netdev_priv(netdev: dev), pie: (char *)param->u.wpa_ie.data, ielen: (u16)param->u.wpa_ie.len); |
489 | break; |
490 | |
491 | case IEEE_CMD_SET_ENCRYPTION: |
492 | ret = wpa_set_encryption(dev, param, param_len: p->length); |
493 | break; |
494 | |
495 | case IEEE_CMD_MLME: |
496 | ret = wpa_mlme(dev, command: param->u.mlme.command, reason: param->u.mlme.reason_code); |
497 | break; |
498 | |
499 | default: |
500 | ret = -EOPNOTSUPP; |
501 | break; |
502 | } |
503 | |
504 | if (ret == 0 && copy_to_user(to: p->pointer, from: param, n: p->length)) |
505 | ret = -EFAULT; |
506 | |
507 | kfree(objp: param); |
508 | |
509 | /* up(&ieee->wx_sem); */ |
510 | return ret; |
511 | } |
512 | |
513 | static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) |
514 | { |
515 | int ret = 0; |
516 | u32 wep_key_idx, wep_key_len, wep_total_len; |
517 | struct ndis_802_11_wep *pwep = NULL; |
518 | struct sta_info *psta = NULL, *pbcmc_sta = NULL; |
519 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
520 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
521 | struct security_priv *psecuritypriv = &padapter->securitypriv; |
522 | struct sta_priv *pstapriv = &padapter->stapriv; |
523 | char *txkey = padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey; |
524 | char *rxkey = padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey; |
525 | char *grpkey = psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey; |
526 | |
527 | param->u.crypt.err = 0; |
528 | param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; |
529 | |
530 | /* sizeof(struct ieee_param) = 64 bytes; */ |
531 | /* if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) */ |
532 | if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) { |
533 | ret = -EINVAL; |
534 | goto exit; |
535 | } |
536 | |
537 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && |
538 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && |
539 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { |
540 | if (param->u.crypt.idx >= WEP_KEYS) { |
541 | ret = -EINVAL; |
542 | goto exit; |
543 | } |
544 | } else { |
545 | psta = rtw_get_stainfo(pstapriv, hwaddr: param->sta_addr); |
546 | if (!psta) |
547 | /* ret = -EINVAL; */ |
548 | goto exit; |
549 | } |
550 | |
551 | if (strcmp(param->u.crypt.alg, "none" ) == 0 && !psta) { |
552 | /* todo:clear default encryption keys */ |
553 | |
554 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; |
555 | psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; |
556 | psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; |
557 | psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; |
558 | |
559 | goto exit; |
560 | } |
561 | |
562 | if (strcmp(param->u.crypt.alg, "WEP" ) == 0 && !psta) { |
563 | wep_key_idx = param->u.crypt.idx; |
564 | wep_key_len = param->u.crypt.key_len; |
565 | |
566 | if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) { |
567 | ret = -EINVAL; |
568 | goto exit; |
569 | } |
570 | |
571 | if (wep_key_len > 0) { |
572 | wep_key_len = wep_key_len <= 5 ? 5 : 13; |
573 | wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, key_material); |
574 | /* Allocate a full structure to avoid potentially running off the end. */ |
575 | pwep = kzalloc(size: sizeof(*pwep), GFP_KERNEL); |
576 | if (!pwep) |
577 | goto exit; |
578 | |
579 | pwep->key_length = wep_key_len; |
580 | pwep->length = wep_total_len; |
581 | } |
582 | |
583 | pwep->key_index = wep_key_idx; |
584 | |
585 | memcpy(pwep->key_material, param->u.crypt.key, pwep->key_length); |
586 | |
587 | if (param->u.crypt.set_tx) { |
588 | psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; |
589 | psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; |
590 | psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; |
591 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; |
592 | |
593 | if (pwep->key_length == 13) { |
594 | psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; |
595 | psecuritypriv->dot118021XGrpPrivacy = _WEP104_; |
596 | } |
597 | |
598 | psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx; |
599 | |
600 | memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->key_material, pwep->key_length); |
601 | |
602 | psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->key_length; |
603 | |
604 | rtw_ap_set_wep_key(padapter, key: pwep->key_material, keylen: pwep->key_length, keyid: wep_key_idx, set_tx: 1); |
605 | } else { |
606 | /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */ |
607 | /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to cam */ |
608 | |
609 | memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->key_material, pwep->key_length); |
610 | |
611 | psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->key_length; |
612 | |
613 | rtw_ap_set_wep_key(padapter, key: pwep->key_material, keylen: pwep->key_length, keyid: wep_key_idx, set_tx: 0); |
614 | } |
615 | |
616 | goto exit; |
617 | } |
618 | |
619 | if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */ |
620 | if (param->u.crypt.set_tx == 1) { |
621 | if (strcmp(param->u.crypt.alg, "WEP" ) == 0) { |
622 | memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
623 | |
624 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; |
625 | if (param->u.crypt.key_len == 13) |
626 | psecuritypriv->dot118021XGrpPrivacy = _WEP104_; |
627 | |
628 | } else if (strcmp(param->u.crypt.alg, "TKIP" ) == 0) { |
629 | psecuritypriv->dot118021XGrpPrivacy = _TKIP_; |
630 | |
631 | memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
632 | |
633 | /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ |
634 | /* set mic key */ |
635 | memcpy(txkey, ¶m->u.crypt.key[16], 8); |
636 | memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[24], 8); |
637 | |
638 | psecuritypriv->busetkipkey = true; |
639 | |
640 | } else if (strcmp(param->u.crypt.alg, "CCMP" ) == 0) { |
641 | psecuritypriv->dot118021XGrpPrivacy = _AES_; |
642 | |
643 | memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
644 | } else { |
645 | psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; |
646 | } |
647 | |
648 | psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; |
649 | |
650 | psecuritypriv->binstallGrpkey = true; |
651 | |
652 | psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */ |
653 | |
654 | rtw_ap_set_group_key(padapter, key: param->u.crypt.key, alg: psecuritypriv->dot118021XGrpPrivacy, keyid: param->u.crypt.idx); |
655 | |
656 | pbcmc_sta = rtw_get_bcmc_stainfo(padapter); |
657 | if (pbcmc_sta) { |
658 | pbcmc_sta->ieee8021x_blocked = false; |
659 | pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ |
660 | } |
661 | } |
662 | |
663 | goto exit; |
664 | } |
665 | |
666 | if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */ |
667 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { |
668 | if (param->u.crypt.set_tx == 1) { |
669 | memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
670 | |
671 | if (strcmp(param->u.crypt.alg, "WEP" ) == 0) { |
672 | psta->dot118021XPrivacy = _WEP40_; |
673 | if (param->u.crypt.key_len == 13) |
674 | psta->dot118021XPrivacy = _WEP104_; |
675 | } else if (strcmp(param->u.crypt.alg, "TKIP" ) == 0) { |
676 | psta->dot118021XPrivacy = _TKIP_; |
677 | |
678 | /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ |
679 | /* set mic key */ |
680 | memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8); |
681 | memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8); |
682 | |
683 | psecuritypriv->busetkipkey = true; |
684 | |
685 | } else if (strcmp(param->u.crypt.alg, "CCMP" ) == 0) { |
686 | psta->dot118021XPrivacy = _AES_; |
687 | } else { |
688 | psta->dot118021XPrivacy = _NO_PRIVACY_; |
689 | } |
690 | |
691 | rtw_ap_set_pairwise_key(padapter, psta); |
692 | |
693 | psta->ieee8021x_blocked = false; |
694 | |
695 | } else { /* group key??? */ |
696 | if (strcmp(param->u.crypt.alg, "WEP" ) == 0) { |
697 | memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
698 | |
699 | psecuritypriv->dot118021XGrpPrivacy = _WEP40_; |
700 | if (param->u.crypt.key_len == 13) |
701 | psecuritypriv->dot118021XGrpPrivacy = _WEP104_; |
702 | } else if (strcmp(param->u.crypt.alg, "TKIP" ) == 0) { |
703 | psecuritypriv->dot118021XGrpPrivacy = _TKIP_; |
704 | |
705 | memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
706 | |
707 | /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ |
708 | /* set mic key */ |
709 | memcpy(txkey, ¶m->u.crypt.key[16], 8); |
710 | memcpy(rxkey, ¶m->u.crypt.key[24], 8); |
711 | |
712 | psecuritypriv->busetkipkey = true; |
713 | |
714 | } else if (strcmp(param->u.crypt.alg, "CCMP" ) == 0) { |
715 | psecuritypriv->dot118021XGrpPrivacy = _AES_; |
716 | |
717 | memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); |
718 | } else { |
719 | psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; |
720 | } |
721 | |
722 | psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx; |
723 | |
724 | psecuritypriv->binstallGrpkey = true; |
725 | |
726 | psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* */ |
727 | |
728 | rtw_ap_set_group_key(padapter, key: param->u.crypt.key, alg: psecuritypriv->dot118021XGrpPrivacy, keyid: param->u.crypt.idx); |
729 | |
730 | pbcmc_sta = rtw_get_bcmc_stainfo(padapter); |
731 | if (pbcmc_sta) { |
732 | pbcmc_sta->ieee8021x_blocked = false; |
733 | pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ |
734 | } |
735 | } |
736 | } |
737 | } |
738 | |
739 | exit: |
740 | kfree(objp: pwep); |
741 | |
742 | return ret; |
743 | } |
744 | |
745 | static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len) |
746 | { |
747 | int ret = 0; |
748 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
749 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
750 | struct sta_priv *pstapriv = &padapter->stapriv; |
751 | unsigned char *pbuf = param->u.bcn_ie.buf; |
752 | |
753 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
754 | return -EINVAL; |
755 | |
756 | memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2); |
757 | |
758 | if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0)) |
759 | pstapriv->max_num_sta = NUM_STA; |
760 | |
761 | if (rtw_check_beacon_data(padapter, pbuf, len: (len - 12 - 2)) == _SUCCESS)/* 12 = param header, 2:no packed */ |
762 | ret = 0; |
763 | else |
764 | ret = -EINVAL; |
765 | |
766 | return ret; |
767 | } |
768 | |
769 | static void rtw_hostapd_sta_flush(struct net_device *dev) |
770 | { |
771 | /* _irqL irqL; */ |
772 | /* struct list_head *phead, *plist; */ |
773 | /* struct sta_info *psta = NULL; */ |
774 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
775 | /* struct sta_priv *pstapriv = &padapter->stapriv; */ |
776 | |
777 | flush_all_cam_entry(padapter); /* clear CAM */ |
778 | |
779 | rtw_sta_flush(padapter); |
780 | } |
781 | |
782 | static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) |
783 | { |
784 | int ret = 0; |
785 | struct sta_info *psta = NULL; |
786 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
787 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
788 | struct sta_priv *pstapriv = &padapter->stapriv; |
789 | |
790 | if (check_fwstate(pmlmepriv, state: (_FW_LINKED | WIFI_AP_STATE)) != true) |
791 | return -EINVAL; |
792 | |
793 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && |
794 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && |
795 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { |
796 | return -EINVAL; |
797 | } |
798 | |
799 | /* |
800 | psta = rtw_get_stainfo(pstapriv, param->sta_addr); |
801 | if (psta) |
802 | { |
803 | rtw_free_stainfo(padapter, psta); |
804 | |
805 | psta = NULL; |
806 | } |
807 | */ |
808 | /* psta = rtw_alloc_stainfo(pstapriv, param->sta_addr); */ |
809 | psta = rtw_get_stainfo(pstapriv, hwaddr: param->sta_addr); |
810 | if (psta) { |
811 | int flags = param->u.add_sta.flags; |
812 | |
813 | psta->aid = param->u.add_sta.aid;/* aid = 1~2007 */ |
814 | |
815 | memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16); |
816 | |
817 | /* check wmm cap. */ |
818 | if (WLAN_STA_WME & flags) |
819 | psta->qos_option = 1; |
820 | else |
821 | psta->qos_option = 0; |
822 | |
823 | if (pmlmepriv->qospriv.qos_option == 0) |
824 | psta->qos_option = 0; |
825 | |
826 | /* chec 802.11n ht cap. */ |
827 | if (WLAN_STA_HT & flags) { |
828 | psta->htpriv.ht_option = true; |
829 | psta->qos_option = 1; |
830 | memcpy((void *)&psta->htpriv.ht_cap, (void *)¶m->u.add_sta.ht_cap, sizeof(struct ieee80211_ht_cap)); |
831 | } else { |
832 | psta->htpriv.ht_option = false; |
833 | } |
834 | |
835 | if (!pmlmepriv->htpriv.ht_option) |
836 | psta->htpriv.ht_option = false; |
837 | |
838 | update_sta_info_apmode(padapter, psta); |
839 | |
840 | } else { |
841 | ret = -ENOMEM; |
842 | } |
843 | |
844 | return ret; |
845 | } |
846 | |
847 | static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) |
848 | { |
849 | int ret = 0; |
850 | struct sta_info *psta = NULL; |
851 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
852 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
853 | struct sta_priv *pstapriv = &padapter->stapriv; |
854 | |
855 | if (check_fwstate(pmlmepriv, state: (_FW_LINKED | WIFI_AP_STATE)) != true) |
856 | return -EINVAL; |
857 | |
858 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && |
859 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && |
860 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { |
861 | return -EINVAL; |
862 | } |
863 | |
864 | psta = rtw_get_stainfo(pstapriv, hwaddr: param->sta_addr); |
865 | if (psta) { |
866 | u8 updated = false; |
867 | |
868 | spin_lock_bh(lock: &pstapriv->asoc_list_lock); |
869 | if (list_empty(head: &psta->asoc_list) == false) { |
870 | list_del_init(entry: &psta->asoc_list); |
871 | pstapriv->asoc_list_cnt--; |
872 | updated = ap_free_sta(padapter, psta, active: true, reason: WLAN_REASON_DEAUTH_LEAVING); |
873 | } |
874 | spin_unlock_bh(lock: &pstapriv->asoc_list_lock); |
875 | |
876 | associated_clients_update(padapter, updated); |
877 | |
878 | psta = NULL; |
879 | } |
880 | |
881 | return ret; |
882 | } |
883 | |
884 | static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len) |
885 | { |
886 | int ret = 0; |
887 | struct sta_info *psta = NULL; |
888 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
889 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
890 | struct sta_priv *pstapriv = &padapter->stapriv; |
891 | struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param; |
892 | struct sta_data *psta_data = (struct sta_data *)param_ex->data; |
893 | |
894 | if (check_fwstate(pmlmepriv, state: (_FW_LINKED | WIFI_AP_STATE)) != true) |
895 | return -EINVAL; |
896 | |
897 | if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff && |
898 | param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff && |
899 | param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff) { |
900 | return -EINVAL; |
901 | } |
902 | |
903 | psta = rtw_get_stainfo(pstapriv, hwaddr: param_ex->sta_addr); |
904 | if (psta) { |
905 | psta_data->aid = (u16)psta->aid; |
906 | psta_data->capability = psta->capability; |
907 | psta_data->flags = psta->flags; |
908 | |
909 | /* |
910 | nonerp_set : BIT(0) |
911 | no_short_slot_time_set : BIT(1) |
912 | no_short_preamble_set : BIT(2) |
913 | no_ht_gf_set : BIT(3) |
914 | no_ht_set : BIT(4) |
915 | ht_20mhz_set : BIT(5) |
916 | */ |
917 | |
918 | psta_data->sta_set = ((psta->nonerp_set) | |
919 | (psta->no_short_slot_time_set << 1) | |
920 | (psta->no_short_preamble_set << 2) | |
921 | (psta->no_ht_gf_set << 3) | |
922 | (psta->no_ht_set << 4) | |
923 | (psta->ht_20mhz_set << 5)); |
924 | |
925 | psta_data->tx_supp_rates_len = psta->bssratelen; |
926 | memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen); |
927 | memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct ieee80211_ht_cap)); |
928 | psta_data->rx_pkts = psta->sta_stats.rx_data_pkts; |
929 | psta_data->rx_bytes = psta->sta_stats.rx_bytes; |
930 | psta_data->rx_drops = psta->sta_stats.rx_drops; |
931 | |
932 | psta_data->tx_pkts = psta->sta_stats.tx_pkts; |
933 | psta_data->tx_bytes = psta->sta_stats.tx_bytes; |
934 | psta_data->tx_drops = psta->sta_stats.tx_drops; |
935 | |
936 | } else { |
937 | ret = -1; |
938 | } |
939 | |
940 | return ret; |
941 | } |
942 | |
943 | static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) |
944 | { |
945 | int ret = 0; |
946 | struct sta_info *psta = NULL; |
947 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
948 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
949 | struct sta_priv *pstapriv = &padapter->stapriv; |
950 | |
951 | if (check_fwstate(pmlmepriv, state: (_FW_LINKED | WIFI_AP_STATE)) != true) |
952 | return -EINVAL; |
953 | |
954 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && |
955 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && |
956 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { |
957 | return -EINVAL; |
958 | } |
959 | |
960 | psta = rtw_get_stainfo(pstapriv, hwaddr: param->sta_addr); |
961 | if (psta) { |
962 | if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC)) { |
963 | int wpa_ie_len; |
964 | int copy_len; |
965 | |
966 | wpa_ie_len = psta->wpa_ie[1]; |
967 | |
968 | copy_len = ((wpa_ie_len + 2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)) : (wpa_ie_len + 2); |
969 | |
970 | param->u.wpa_ie.len = copy_len; |
971 | |
972 | memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len); |
973 | } |
974 | } else { |
975 | ret = -1; |
976 | } |
977 | |
978 | return ret; |
979 | } |
980 | |
981 | static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len) |
982 | { |
983 | int ret = 0; |
984 | unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; |
985 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
986 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
987 | struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; |
988 | int ie_len; |
989 | |
990 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
991 | return -EINVAL; |
992 | |
993 | ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */ |
994 | |
995 | kfree(objp: pmlmepriv->wps_beacon_ie); |
996 | pmlmepriv->wps_beacon_ie = NULL; |
997 | |
998 | if (ie_len > 0) { |
999 | pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len); |
1000 | pmlmepriv->wps_beacon_ie_len = ie_len; |
1001 | if (!pmlmepriv->wps_beacon_ie) |
1002 | return -EINVAL; |
1003 | |
1004 | memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len); |
1005 | |
1006 | update_beacon(padapter, ie_id: WLAN_EID_VENDOR_SPECIFIC, oui: wps_oui, tx: true); |
1007 | |
1008 | pmlmeext->bstart_bss = true; |
1009 | } |
1010 | |
1011 | return ret; |
1012 | } |
1013 | |
1014 | static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len) |
1015 | { |
1016 | int ret = 0; |
1017 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
1018 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1019 | int ie_len; |
1020 | |
1021 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
1022 | return -EINVAL; |
1023 | |
1024 | ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */ |
1025 | |
1026 | kfree(objp: pmlmepriv->wps_probe_resp_ie); |
1027 | pmlmepriv->wps_probe_resp_ie = NULL; |
1028 | |
1029 | if (ie_len > 0) { |
1030 | pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len); |
1031 | pmlmepriv->wps_probe_resp_ie_len = ie_len; |
1032 | if (!pmlmepriv->wps_probe_resp_ie) |
1033 | return -EINVAL; |
1034 | |
1035 | memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len); |
1036 | } |
1037 | |
1038 | return ret; |
1039 | } |
1040 | |
1041 | static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len) |
1042 | { |
1043 | int ret = 0; |
1044 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
1045 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1046 | int ie_len; |
1047 | |
1048 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
1049 | return -EINVAL; |
1050 | |
1051 | ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */ |
1052 | |
1053 | kfree(objp: pmlmepriv->wps_assoc_resp_ie); |
1054 | pmlmepriv->wps_assoc_resp_ie = NULL; |
1055 | |
1056 | if (ie_len > 0) { |
1057 | pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len); |
1058 | pmlmepriv->wps_assoc_resp_ie_len = ie_len; |
1059 | if (!pmlmepriv->wps_assoc_resp_ie) |
1060 | return -EINVAL; |
1061 | |
1062 | memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len); |
1063 | } |
1064 | |
1065 | return ret; |
1066 | } |
1067 | |
1068 | static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len) |
1069 | { |
1070 | int ret = 0; |
1071 | struct adapter *adapter = rtw_netdev_priv(netdev: dev); |
1072 | struct mlme_priv *mlmepriv = &adapter->mlmepriv; |
1073 | struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; |
1074 | struct mlme_ext_info *mlmeinfo = &mlmeext->mlmext_info; |
1075 | int ie_len; |
1076 | u8 *ssid_ie; |
1077 | char ssid[NDIS_802_11_LENGTH_SSID + 1]; |
1078 | signed int ssid_len; |
1079 | u8 ignore_broadcast_ssid; |
1080 | |
1081 | if (check_fwstate(pmlmepriv: mlmepriv, WIFI_AP_STATE) != true) |
1082 | return -EPERM; |
1083 | |
1084 | if (param->u.bcn_ie.reserved[0] != 0xea) |
1085 | return -EINVAL; |
1086 | |
1087 | mlmeinfo->hidden_ssid_mode = ignore_broadcast_ssid = param->u.bcn_ie.reserved[1]; |
1088 | |
1089 | ie_len = len - 12 - 2;/* 12 = param header, 2:no packed */ |
1090 | ssid_ie = rtw_get_ie(pbuf: param->u.bcn_ie.buf, index: WLAN_EID_SSID, len: &ssid_len, limit: ie_len); |
1091 | |
1092 | if (ssid_ie && ssid_len > 0 && ssid_len <= NDIS_802_11_LENGTH_SSID) { |
1093 | struct wlan_bssid_ex *pbss_network = &mlmepriv->cur_network.network; |
1094 | struct wlan_bssid_ex *pbss_network_ext = &mlmeinfo->network; |
1095 | |
1096 | memcpy(ssid, ssid_ie + 2, ssid_len); |
1097 | ssid[ssid_len] = 0x0; |
1098 | |
1099 | memcpy(pbss_network->ssid.ssid, (void *)ssid, ssid_len); |
1100 | pbss_network->ssid.ssid_length = ssid_len; |
1101 | memcpy(pbss_network_ext->ssid.ssid, (void *)ssid, ssid_len); |
1102 | pbss_network_ext->ssid.ssid_length = ssid_len; |
1103 | } |
1104 | |
1105 | return ret; |
1106 | } |
1107 | |
1108 | static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len) |
1109 | { |
1110 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
1111 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1112 | |
1113 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
1114 | return -EINVAL; |
1115 | |
1116 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && |
1117 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && |
1118 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { |
1119 | return -EINVAL; |
1120 | } |
1121 | |
1122 | rtw_acl_remove_sta(padapter, addr: param->sta_addr); |
1123 | return 0; |
1124 | } |
1125 | |
1126 | static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len) |
1127 | { |
1128 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
1129 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1130 | |
1131 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
1132 | return -EINVAL; |
1133 | |
1134 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && |
1135 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && |
1136 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { |
1137 | return -EINVAL; |
1138 | } |
1139 | |
1140 | return rtw_acl_add_sta(padapter, addr: param->sta_addr); |
1141 | } |
1142 | |
1143 | static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len) |
1144 | { |
1145 | int ret = 0; |
1146 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
1147 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |
1148 | |
1149 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) |
1150 | return -EINVAL; |
1151 | |
1152 | rtw_set_macaddr_acl(padapter, mode: param->u.mlme.command); |
1153 | |
1154 | return ret; |
1155 | } |
1156 | |
1157 | static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p) |
1158 | { |
1159 | struct ieee_param *param; |
1160 | int ret = 0; |
1161 | struct adapter *padapter = rtw_netdev_priv(netdev: dev); |
1162 | |
1163 | /* |
1164 | * this function is expect to call in master mode, which allows no power saving |
1165 | * so, we just check hw_init_completed |
1166 | */ |
1167 | |
1168 | if (!padapter->hw_init_completed) |
1169 | return -EPERM; |
1170 | |
1171 | if (!p->pointer || p->length != sizeof(*param)) |
1172 | return -EINVAL; |
1173 | |
1174 | param = rtw_malloc(p->length); |
1175 | if (!param) |
1176 | return -ENOMEM; |
1177 | |
1178 | if (copy_from_user(to: param, from: p->pointer, n: p->length)) { |
1179 | kfree(objp: param); |
1180 | return -EFAULT; |
1181 | } |
1182 | |
1183 | switch (param->cmd) { |
1184 | case RTL871X_HOSTAPD_FLUSH: |
1185 | |
1186 | rtw_hostapd_sta_flush(dev); |
1187 | |
1188 | break; |
1189 | |
1190 | case RTL871X_HOSTAPD_ADD_STA: |
1191 | |
1192 | ret = rtw_add_sta(dev, param); |
1193 | |
1194 | break; |
1195 | |
1196 | case RTL871X_HOSTAPD_REMOVE_STA: |
1197 | |
1198 | ret = rtw_del_sta(dev, param); |
1199 | |
1200 | break; |
1201 | |
1202 | case RTL871X_HOSTAPD_SET_BEACON: |
1203 | |
1204 | ret = rtw_set_beacon(dev, param, len: p->length); |
1205 | |
1206 | break; |
1207 | |
1208 | case RTL871X_SET_ENCRYPTION: |
1209 | |
1210 | ret = rtw_set_encryption(dev, param, param_len: p->length); |
1211 | |
1212 | break; |
1213 | |
1214 | case RTL871X_HOSTAPD_GET_WPAIE_STA: |
1215 | |
1216 | ret = rtw_get_sta_wpaie(dev, param); |
1217 | |
1218 | break; |
1219 | |
1220 | case RTL871X_HOSTAPD_SET_WPS_BEACON: |
1221 | |
1222 | ret = rtw_set_wps_beacon(dev, param, len: p->length); |
1223 | |
1224 | break; |
1225 | |
1226 | case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP: |
1227 | |
1228 | ret = rtw_set_wps_probe_resp(dev, param, len: p->length); |
1229 | |
1230 | break; |
1231 | |
1232 | case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP: |
1233 | |
1234 | ret = rtw_set_wps_assoc_resp(dev, param, len: p->length); |
1235 | |
1236 | break; |
1237 | |
1238 | case RTL871X_HOSTAPD_SET_HIDDEN_SSID: |
1239 | |
1240 | ret = rtw_set_hidden_ssid(dev, param, len: p->length); |
1241 | |
1242 | break; |
1243 | |
1244 | case RTL871X_HOSTAPD_GET_INFO_STA: |
1245 | |
1246 | ret = rtw_ioctl_get_sta_data(dev, param, len: p->length); |
1247 | |
1248 | break; |
1249 | |
1250 | case RTL871X_HOSTAPD_SET_MACADDR_ACL: |
1251 | |
1252 | ret = rtw_ioctl_set_macaddr_acl(dev, param, len: p->length); |
1253 | |
1254 | break; |
1255 | |
1256 | case RTL871X_HOSTAPD_ACL_ADD_STA: |
1257 | |
1258 | ret = rtw_ioctl_acl_add_sta(dev, param, len: p->length); |
1259 | |
1260 | break; |
1261 | |
1262 | case RTL871X_HOSTAPD_ACL_REMOVE_STA: |
1263 | |
1264 | ret = rtw_ioctl_acl_remove_sta(dev, param, len: p->length); |
1265 | |
1266 | break; |
1267 | |
1268 | default: |
1269 | ret = -EOPNOTSUPP; |
1270 | break; |
1271 | } |
1272 | |
1273 | if (ret == 0 && copy_to_user(to: p->pointer, from: param, n: p->length)) |
1274 | ret = -EFAULT; |
1275 | |
1276 | kfree(objp: param); |
1277 | return ret; |
1278 | } |
1279 | |
1280 | /* copy from net/wireless/wext.c end */ |
1281 | |
1282 | int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
1283 | { |
1284 | struct iwreq *wrq = (struct iwreq *)rq; |
1285 | int ret = 0; |
1286 | |
1287 | switch (cmd) { |
1288 | case RTL_IOCTL_WPA_SUPPLICANT: |
1289 | ret = wpa_supplicant_ioctl(dev, p: &wrq->u.data); |
1290 | break; |
1291 | case RTL_IOCTL_HOSTAPD: |
1292 | ret = rtw_hostapd_ioctl(dev, p: &wrq->u.data); |
1293 | break; |
1294 | default: |
1295 | ret = -EOPNOTSUPP; |
1296 | break; |
1297 | } |
1298 | |
1299 | return ret; |
1300 | } |
1301 | |