Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /* |
2 | * --------------------------------------------------------------------------- | |
3 | * FILE: sme_wext.c | |
4 | * | |
5 | * PURPOSE: | |
6 | * Handlers for ioctls from iwconfig. | |
7 | * These provide the control plane operations. | |
8 | * | |
9 | * Copyright (C) 2007-2009 by Cambridge Silicon Radio Ltd. | |
10 | * | |
11 | * Refer to LICENSE.txt included with this source code for details on | |
12 | * the license terms. | |
13 | * | |
14 | * --------------------------------------------------------------------------- | |
15 | */ | |
16 | #include <linux/types.h> | |
17 | #include <linux/etherdevice.h> | |
18 | #include <linux/if_arp.h> | |
19 | #include <asm/uaccess.h> | |
20 | #include <linux/ctype.h> | |
21 | #include "unifi_priv.h" | |
22 | #include <linux/rtnetlink.h> | |
23 | ||
24 | #define CHECK_INITED(_priv) \ | |
25 | do { \ | |
26 | if (_priv->init_progress != UNIFI_INIT_COMPLETED) { \ | |
27 | unifi_trace(_priv, UDBG2, "%s unifi not ready, failing wext call\n", __FUNCTION__); \ | |
28 | return -ENODEV; \ | |
29 | } \ | |
30 | } while (0) | |
31 | ||
95edd09e GKH |
32 | /* Workaround for the wpa_supplicant hanging issue - disabled on Android */ |
33 | #ifndef ANDROID_BUILD | |
635d2b00 | 34 | #define CSR_WIFI_WEXT_HANG_WORKAROUND |
95edd09e | 35 | #endif |
635d2b00 GKH |
36 | |
37 | #ifdef CSR_WIFI_WEXT_HANG_WORKAROUND | |
38 | # define UF_RTNL_LOCK() rtnl_lock() | |
39 | # define UF_RTNL_UNLOCK() rtnl_unlock() | |
40 | #else | |
41 | # define UF_RTNL_LOCK() | |
42 | # define UF_RTNL_UNLOCK() | |
43 | #endif | |
44 | ||
45 | ||
46 | /* | |
47 | * --------------------------------------------------------------------------- | |
48 | * Helper functions | |
49 | * --------------------------------------------------------------------------- | |
50 | */ | |
51 | ||
52 | /* | |
53 | * --------------------------------------------------------------------------- | |
54 | * wext_freq_to_channel | |
55 | * channel_to_mhz | |
56 | * | |
57 | * These functions convert between channel number and frequency. | |
58 | * | |
59 | * Arguments: | |
60 | * ch Channel number, as defined in 802.11 specs | |
61 | * m, e Mantissa and exponent as provided by wireless extension. | |
62 | * | |
63 | * Returns: | |
64 | * channel or frequency (in MHz) value | |
65 | * --------------------------------------------------------------------------- | |
66 | */ | |
67 | static int | |
68 | wext_freq_to_channel(int m, int e) | |
69 | { | |
70 | int mhz; | |
71 | ||
72 | mhz = m; | |
73 | while (e < 6) { | |
74 | mhz /= 10; | |
75 | e++; | |
76 | } | |
77 | while (e > 6) { | |
78 | mhz *= 10; | |
79 | e--; | |
80 | } | |
81 | ||
82 | if (mhz >= 5000) { | |
83 | return ((mhz - 5000) / 5); | |
84 | } | |
85 | ||
86 | if (mhz == 2482) { | |
87 | return 14; | |
88 | } | |
89 | ||
90 | if (mhz >= 2407) { | |
91 | return ((mhz - 2407) / 5); | |
92 | } | |
93 | ||
94 | return 0; | |
95 | } /* wext_freq_to_channel() */ | |
96 | ||
97 | static int | |
98 | channel_to_mhz(int ch, int dot11a) | |
99 | { | |
100 | ||
101 | if (ch == 0) return 0; | |
102 | if (ch > 200) return 0; | |
103 | ||
104 | /* 5G */ | |
105 | if (dot11a) { | |
106 | return (5000 + (5 * ch)); | |
107 | } | |
108 | ||
109 | /* 2.4G */ | |
110 | if (ch == 14) { | |
111 | return 2484; | |
112 | } | |
113 | ||
114 | if ((ch < 14) && (ch > 0)) { | |
115 | return (2407 + (5 * ch)); | |
116 | } | |
117 | ||
118 | return 0; | |
119 | } | |
120 | #ifdef CSR_SUPPORT_WEXT_AP | |
121 | void uf_sme_wext_ap_set_defaults(unifi_priv_t *priv) | |
122 | { | |
3f596cad | 123 | memcpy(priv->ap_config.ssid.ssid, "defaultssid", sizeof("defaultssid")); |
635d2b00 GKH |
124 | |
125 | priv->ap_config.ssid.length = 8; | |
126 | priv->ap_config.channel = 6; | |
127 | priv->ap_config.if_index = 1; | |
128 | priv->ap_config.credentials.authType = 0; | |
129 | priv->ap_config.max_connections=8; | |
130 | ||
131 | priv->group_sec_config.apGroupkeyTimeout = 0; | |
132 | priv->group_sec_config.apStrictGtkRekey = 0; | |
133 | priv->group_sec_config.apGmkTimeout = 0; | |
134 | priv->group_sec_config.apResponseTimeout = 100; /* Default*/ | |
135 | priv->group_sec_config.apRetransLimit = 3; /* Default*/ | |
136 | /* Set default params even if they may not be used*/ | |
137 | /* Until Here*/ | |
138 | ||
139 | priv->ap_mac_config.preamble = CSR_WIFI_SME_USE_LONG_PREAMBLE; | |
140 | priv->ap_mac_config.shortSlotTimeEnabled = FALSE; | |
141 | priv->ap_mac_config.ctsProtectionType=CSR_WIFI_SME_CTS_PROTECTION_AUTOMATIC; | |
142 | ||
143 | priv->ap_mac_config.wmmEnabled = TRUE; | |
144 | priv->ap_mac_config.wmmApParams[0].cwMin=4; | |
145 | priv->ap_mac_config.wmmApParams[0].cwMax=10; | |
146 | priv->ap_mac_config.wmmApParams[0].aifs=3; | |
147 | priv->ap_mac_config.wmmApParams[0].txopLimit=0; | |
148 | priv->ap_mac_config.wmmApParams[0].admissionControlMandatory=FALSE; | |
149 | priv->ap_mac_config.wmmApParams[1].cwMin=4; | |
150 | priv->ap_mac_config.wmmApParams[1].cwMax=10; | |
151 | priv->ap_mac_config.wmmApParams[1].aifs=7; | |
152 | priv->ap_mac_config.wmmApParams[1].txopLimit=0; | |
153 | priv->ap_mac_config.wmmApParams[1].admissionControlMandatory=FALSE; | |
154 | priv->ap_mac_config.wmmApParams[2].cwMin=3; | |
155 | priv->ap_mac_config.wmmApParams[2].cwMax=4; | |
156 | priv->ap_mac_config.wmmApParams[2].aifs=1; | |
157 | priv->ap_mac_config.wmmApParams[2].txopLimit=94; | |
158 | priv->ap_mac_config.wmmApParams[2].admissionControlMandatory=FALSE; | |
159 | priv->ap_mac_config.wmmApParams[3].cwMin=2; | |
160 | priv->ap_mac_config.wmmApParams[3].cwMax=3; | |
161 | priv->ap_mac_config.wmmApParams[3].aifs=1; | |
162 | priv->ap_mac_config.wmmApParams[3].txopLimit=47; | |
163 | priv->ap_mac_config.wmmApParams[3].admissionControlMandatory=FALSE; | |
164 | ||
165 | priv->ap_mac_config.wmmApBcParams[0].cwMin=4; | |
166 | priv->ap_mac_config.wmmApBcParams[0].cwMax=10; | |
167 | priv->ap_mac_config.wmmApBcParams[0].aifs=3; | |
168 | priv->ap_mac_config.wmmApBcParams[0].txopLimit=0; | |
169 | priv->ap_mac_config.wmmApBcParams[0].admissionControlMandatory=FALSE; | |
170 | priv->ap_mac_config.wmmApBcParams[1].cwMin=4; | |
171 | priv->ap_mac_config.wmmApBcParams[1].cwMax=10; | |
172 | priv->ap_mac_config.wmmApBcParams[1].aifs=7; | |
173 | priv->ap_mac_config.wmmApBcParams[1].txopLimit=0; | |
174 | priv->ap_mac_config.wmmApBcParams[1].admissionControlMandatory=FALSE; | |
175 | priv->ap_mac_config.wmmApBcParams[2].cwMin=3; | |
176 | priv->ap_mac_config.wmmApBcParams[2].cwMax=4; | |
177 | priv->ap_mac_config.wmmApBcParams[2].aifs=2; | |
178 | priv->ap_mac_config.wmmApBcParams[2].txopLimit=94; | |
179 | priv->ap_mac_config.wmmApBcParams[2].admissionControlMandatory=FALSE; | |
180 | priv->ap_mac_config.wmmApBcParams[3].cwMin=2; | |
181 | priv->ap_mac_config.wmmApBcParams[3].cwMax=3; | |
182 | priv->ap_mac_config.wmmApBcParams[3].aifs=2; | |
183 | priv->ap_mac_config.wmmApBcParams[3].txopLimit=47; | |
184 | priv->ap_mac_config.wmmApBcParams[3].admissionControlMandatory=FALSE; | |
185 | ||
186 | priv->ap_mac_config.accessType=CSR_WIFI_AP_ACCESS_TYPE_NONE; | |
187 | priv->ap_mac_config.macAddressListCount=0; | |
188 | priv->ap_mac_config.macAddressList=NULL; | |
189 | ||
190 | priv->ap_mac_config.apHtParams.rxStbc=1; | |
191 | priv->ap_mac_config.apHtParams.rifsModeAllowed=TRUE; | |
192 | priv->ap_mac_config.apHtParams.greenfieldSupported=FALSE; | |
193 | priv->ap_mac_config.apHtParams.shortGi20MHz=TRUE; | |
194 | priv->ap_mac_config.apHtParams.htProtection=0; | |
195 | priv->ap_mac_config.apHtParams.dualCtsProtection=FALSE; | |
196 | ||
197 | priv->ap_mac_config.phySupportedBitmap = | |
198 | (CSR_WIFI_SME_AP_PHY_SUPPORT_B|CSR_WIFI_SME_AP_PHY_SUPPORT_G|CSR_WIFI_SME_AP_PHY_SUPPORT_N); | |
199 | priv->ap_mac_config.beaconInterval= 100; | |
200 | priv->ap_mac_config.dtimPeriod=3; | |
201 | priv->ap_mac_config.maxListenInterval=0x00ff;/* Set it to a large value | |
202 | to enable different types of | |
203 | devices to join us */ | |
204 | priv->ap_mac_config.supportedRatesCount = | |
3f596cad | 205 | uf_configure_supported_rates(priv->ap_mac_config.supportedRates, priv->ap_mac_config.phySupportedBitmap); |
635d2b00 GKH |
206 | } |
207 | #endif | |
208 | /* | |
209 | * --------------------------------------------------------------------------- | |
210 | * uf_sme_wext_set_defaults | |
211 | * | |
212 | * Set up power-on defaults for driver config. | |
213 | * | |
214 | * Note: The SME Management API *cannot* be used in this function. | |
215 | * | |
216 | * Arguments: | |
217 | * priv Pointer to device private context struct | |
218 | * | |
219 | * Returns: | |
220 | * None. | |
221 | * --------------------------------------------------------------------------- | |
222 | */ | |
223 | void | |
224 | uf_sme_wext_set_defaults(unifi_priv_t *priv) | |
225 | { | |
226 | memset(&priv->connection_config, 0, sizeof(CsrWifiSmeConnectionConfig)); | |
227 | ||
228 | priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE; | |
229 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
230 | priv->connection_config.encryptionModeMask = CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE; | |
231 | priv->connection_config.privacyMode = CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED; | |
232 | priv->connection_config.wmmQosInfo = 0xFF; | |
233 | priv->connection_config.ifIndex = CSR_WIFI_SME_RADIO_IF_BOTH; | |
234 | priv->connection_config.adhocJoinOnly = FALSE; | |
235 | priv->connection_config.adhocChannel = 6; | |
236 | ||
237 | priv->wep_tx_key_index = 0; | |
238 | ||
239 | priv->wext_wireless_stats.qual.qual = 0; | |
240 | priv->wext_wireless_stats.qual.level = 0; | |
241 | priv->wext_wireless_stats.qual.noise = 0; | |
242 | priv->wext_wireless_stats.qual.updated = 0x70; | |
243 | #ifdef CSR_SUPPORT_WEXT_AP | |
244 | /* Initialize the default configuration for AP */ | |
245 | uf_sme_wext_ap_set_defaults(priv); | |
246 | #endif | |
247 | ||
248 | ||
249 | } /* uf_sme_wext_set_defaults() */ | |
250 | ||
251 | ||
252 | /* | |
253 | * --------------------------------------------------------------------------- | |
254 | * WEXT methods | |
255 | * --------------------------------------------------------------------------- | |
256 | */ | |
257 | ||
258 | /* | |
259 | * --------------------------------------------------------------------------- | |
260 | * unifi_giwname - handler for SIOCGIWNAME | |
261 | * unifi_siwfreq - handler for SIOCSIWFREQ | |
262 | * unifi_giwfreq - handler for SIOCGIWFREQ | |
263 | * unifi_siwmode - handler for SIOCSIWMODE | |
264 | * unifi_giwmode - handler for SIOCGIWMODE | |
265 | * unifi_giwrange - handler for SIOCGIWRANGE | |
266 | * unifi_siwap - handler for SIOCSIWAP | |
267 | * unifi_giwap - handler for SIOCGIWAP | |
268 | * unifi_siwscan - handler for SIOCSIWSCAN | |
269 | * unifi_giwscan - handler for SIOCGIWSCAN | |
270 | * unifi_siwessid - handler for SIOCSIWESSID | |
271 | * unifi_giwessid - handler for SIOCGIWESSID | |
272 | * unifi_siwencode - handler for SIOCSIWENCODE | |
273 | * unifi_giwencode - handler for SIOCGIWENCODE | |
274 | * | |
275 | * Handler functions for IW extensions. | |
276 | * These are registered via the unifi_iw_handler_def struct below | |
277 | * and called by the generic IW driver support code. | |
278 | * See include/net/iw_handler.h. | |
279 | * | |
280 | * Arguments: | |
281 | * None. | |
282 | * | |
283 | * Returns: | |
284 | * None. | |
285 | * --------------------------------------------------------------------------- | |
286 | */ | |
287 | static int | |
288 | iwprivsdefs(struct net_device *dev, struct iw_request_info *info, | |
289 | union iwreq_data *wrqu, char *extra) | |
290 | { | |
291 | int r; | |
292 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
293 | unifi_priv_t *priv = interfacePriv->privPtr; | |
294 | CsrWifiSmeMibConfig mibConfig; | |
295 | CsrWifiSmePowerConfig powerConfig; | |
296 | ||
297 | unifi_trace(priv, UDBG1, "iwprivs80211defaults: reload defaults\n"); | |
298 | ||
299 | uf_sme_wext_set_defaults(priv); | |
300 | ||
301 | /* Get, modify and set the MIB data */ | |
302 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
303 | if (r) { | |
304 | unifi_error(priv, "iwprivs80211defaults: Get CsrWifiSmeMibConfigValue failed.\n"); | |
305 | return r; | |
306 | } | |
307 | mibConfig.dot11RtsThreshold = 2347; | |
308 | mibConfig.dot11FragmentationThreshold = 2346; | |
309 | r = sme_mgt_mib_config_set(priv, &mibConfig); | |
310 | if (r) { | |
311 | unifi_error(priv, "iwprivs80211defaults: Set CsrWifiSmeMibConfigValue failed.\n"); | |
312 | return r; | |
313 | } | |
314 | ||
315 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW; | |
316 | powerConfig.listenIntervalTu = 100; | |
317 | powerConfig.rxDtims = 1; | |
318 | ||
319 | r = sme_mgt_power_config_set(priv, &powerConfig); | |
320 | if (r) { | |
321 | unifi_error(priv, "iwprivs80211defaults: Set unifi_PowerConfigValue failed.\n"); | |
322 | return r; | |
323 | } | |
324 | ||
325 | return 0; | |
326 | } /* iwprivsdefs() */ | |
327 | ||
328 | static int | |
329 | iwprivs80211ps(struct net_device *dev, struct iw_request_info *info, | |
330 | union iwreq_data *wrqu, char *extra) | |
331 | { | |
332 | int r = 0; | |
333 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
334 | unifi_priv_t *priv = interfacePriv->privPtr; | |
335 | ||
336 | int ps_mode = (int)(*extra); | |
337 | CsrWifiSmePowerConfig powerConfig; | |
338 | ||
339 | unifi_trace(priv, UDBG1, "iwprivs80211ps: power save mode = %d\n", ps_mode); | |
340 | ||
341 | r = sme_mgt_power_config_get(priv, &powerConfig); | |
342 | if (r) { | |
343 | unifi_error(priv, "iwprivs80211ps: Get unifi_PowerConfigValue failed.\n"); | |
344 | return r; | |
345 | } | |
346 | ||
347 | switch (ps_mode) { | |
348 | case CSR_PMM_ACTIVE_MODE: | |
349 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW; | |
350 | break; | |
351 | case CSR_PMM_POWER_SAVE: | |
352 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH; | |
353 | break; | |
354 | case CSR_PMM_FAST_POWER_SAVE: | |
355 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_MED; | |
356 | break; | |
357 | default: | |
358 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO; | |
359 | break; | |
360 | } | |
361 | ||
362 | r = sme_mgt_power_config_set(priv, &powerConfig); | |
363 | if (r) { | |
364 | unifi_error(priv, "iwprivs80211ps: Set unifi_PowerConfigValue failed.\n"); | |
365 | } | |
366 | ||
367 | return r; | |
368 | } | |
369 | ||
370 | static int | |
371 | iwprivg80211ps(struct net_device *dev, struct iw_request_info *info, | |
372 | union iwreq_data *wrqu, char *extra) | |
373 | { | |
374 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
375 | unifi_priv_t *priv = interfacePriv->privPtr; | |
376 | ||
377 | CsrWifiSmePowerConfig powerConfig; | |
378 | int r; | |
379 | ||
380 | r = sme_mgt_power_config_get(priv, &powerConfig); | |
381 | if (r) { | |
382 | unifi_error(priv, "iwprivg80211ps: Get 802.11 power mode failed.\n"); | |
383 | return r; | |
384 | } | |
385 | ||
386 | switch (powerConfig.powerSaveLevel) { | |
387 | case CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW: | |
388 | snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING, | |
389 | "Power save mode: %d (Active)", | |
390 | powerConfig.powerSaveLevel); | |
391 | break; | |
392 | case CSR_WIFI_SME_POWER_SAVE_LEVEL_MED: | |
393 | snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING, | |
394 | "Power save mode: %d (Fast)", | |
395 | powerConfig.powerSaveLevel); | |
396 | break; | |
397 | case CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH: | |
398 | snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING, | |
399 | "Power save mode: %d (Full)", | |
400 | powerConfig.powerSaveLevel); | |
401 | break; | |
402 | case CSR_WIFI_SME_POWER_SAVE_LEVEL_AUTO: | |
403 | snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING, | |
404 | "Power save mode: %d (Auto)", | |
405 | powerConfig.powerSaveLevel); | |
406 | break; | |
407 | default: | |
408 | snprintf(extra, IWPRIV_POWER_SAVE_MAX_STRING, | |
409 | "Power save mode: %d (Unknown)", | |
410 | powerConfig.powerSaveLevel); | |
411 | break; | |
412 | } | |
413 | ||
414 | wrqu->data.length = strlen(extra) + 1; | |
415 | ||
416 | return 0; | |
417 | } | |
418 | ||
419 | static int | |
420 | iwprivssmedebug(struct net_device *dev, struct iw_request_info *info, | |
421 | union iwreq_data *wrqu, char *extra) | |
422 | { | |
423 | /* No longer supported on the API */ | |
424 | #if defined (CSR_WIFI_HIP_DEBUG_OFFLINE) | |
425 | unifi_debug_buf_dump(); | |
426 | #endif | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
431 | #ifdef CSR_SUPPORT_WEXT_AP | |
432 | #define PARAM_TYPE_INT 0 | |
433 | #define PARAM_TYPE_STRING 1 | |
434 | #define CSR_WIFI_MAX_SSID_LEN 32 | |
435 | #define CSR_WIFI_MAX_SEC_LEN 16 | |
436 | #define CSR_WIFI_MAX_KEY_LEN 65 | |
437 | ||
438 | static int hex_look_up(char x) | |
439 | { | |
440 | if(x>='0' && x<='9') | |
441 | return (x-48); | |
442 | if(x>= 'a' && x <= 'f') | |
443 | return (x-87); | |
444 | return -1; | |
445 | } | |
446 | ||
447 | static int power (int a, int b) | |
448 | { | |
449 | int i; | |
450 | int num =1; | |
451 | for(i=0;i<b;i++) | |
452 | num *=a; | |
453 | return num; | |
454 | } | |
455 | ||
456 | static int decode_parameter_from_string(unifi_priv_t* priv, char **str_ptr, | |
457 | const char *token, int param_type, | |
458 | void *dst, int param_max_len) | |
459 | { | |
7e6f5794 | 460 | u8 int_str[7] = "0"; |
26a6b2e1 | 461 | u32 param_str_len; |
3f596cad | 462 | u8 *param_str_begin, *param_str_end; |
7e6f5794 | 463 | u8 *orig_str = *str_ptr; |
635d2b00 GKH |
464 | |
465 | if (!strncmp(*str_ptr, token, strlen(token))) { | |
466 | strsep(str_ptr, "=,"); | |
467 | param_str_begin = *str_ptr; | |
468 | strsep(str_ptr, "=,"); | |
469 | if (*str_ptr == NULL) { | |
470 | param_str_len = strlen(param_str_begin); | |
471 | } else { | |
472 | param_str_end = *str_ptr-1; | |
473 | param_str_len = param_str_end - param_str_begin; | |
474 | } | |
3f596cad | 475 | unifi_trace(priv, UDBG2, "'token:%s', len:%d, ", token, param_str_len); |
635d2b00 | 476 | if (param_str_len > param_max_len) { |
3f596cad | 477 | unifi_notice(priv, "extracted param len:%d is > MAX:%d\n", param_str_len, param_max_len); |
635d2b00 GKH |
478 | param_str_len = param_max_len; |
479 | } | |
480 | switch (param_type) { | |
481 | case PARAM_TYPE_INT: | |
482 | { | |
3f596cad LL |
483 | u32 *pdst_int = dst, num =0; |
484 | int i, j=0; | |
635d2b00 GKH |
485 | if (param_str_len > sizeof(int_str)) { |
486 | param_str_len = sizeof(int_str); | |
487 | } | |
488 | memcpy(int_str, param_str_begin, param_str_len); | |
489 | for(i = param_str_len; i>0;i--) { | |
490 | if(int_str[i-1] >= '0' && int_str[i-1] <='9') { | |
3f596cad | 491 | num += ((int_str[i-1]-'0')*power(10, j)); |
635d2b00 GKH |
492 | j++; |
493 | } else { | |
3f596cad | 494 | unifi_error(priv, "decode_parameter_from_string:not a number %c\n", (int_str[i-1])); |
635d2b00 GKH |
495 | return -1; |
496 | } | |
497 | } | |
498 | *pdst_int = num; | |
3f596cad | 499 | unifi_trace(priv, UDBG2, "decode_parameter_from_string:decoded int = %d\n", *pdst_int); |
635d2b00 GKH |
500 | } |
501 | break; | |
502 | default: | |
503 | memcpy(dst, param_str_begin, param_str_len); | |
504 | *((char *)dst + param_str_len) = 0; | |
3f596cad | 505 | unifi_trace(priv, UDBG2, "decode_parameter_from_string:decoded string = %s\n", (char *)dst); |
635d2b00 GKH |
506 | break; |
507 | } | |
508 | } else { | |
3f596cad | 509 | unifi_error(priv, "decode_parameter_from_string: Token:%s not found in %s \n", token, orig_str); |
635d2b00 GKH |
510 | return -1; |
511 | } | |
512 | return 0; | |
513 | } | |
514 | static int store_ap_advanced_config_from_string(unifi_priv_t *priv, char *param_str) | |
515 | { | |
516 | char * str_ptr=param_str; | |
3f596cad | 517 | int ret = 0, tmp_var; |
635d2b00 GKH |
518 | char phy_mode[6]; |
519 | CsrWifiSmeApMacConfig * ap_mac_config = &priv->ap_mac_config; | |
520 | ||
521 | /* Check for BI */ | |
522 | ret = decode_parameter_from_string(priv, &str_ptr, "BI=", | |
523 | PARAM_TYPE_INT, &tmp_var, 5); | |
524 | if(ret) { | |
3f596cad | 525 | unifi_error(priv, "store_ap_advanced_config_from_string: BI not found\n"); |
635d2b00 GKH |
526 | return -1; |
527 | } | |
528 | ap_mac_config->beaconInterval = tmp_var; | |
529 | ret = decode_parameter_from_string(priv, &str_ptr, "DTIM_PER=", | |
530 | PARAM_TYPE_INT, &tmp_var, 5); | |
531 | if(ret) { | |
3f596cad | 532 | unifi_error(priv, "store_ap_advanced_config_from_string: DTIM_PER not found\n"); |
635d2b00 GKH |
533 | return -1; |
534 | } | |
535 | ap_mac_config->dtimPeriod = tmp_var; | |
536 | ret = decode_parameter_from_string(priv, &str_ptr, "WMM=", | |
537 | PARAM_TYPE_INT, &tmp_var, 5); | |
538 | if(ret) { | |
3f596cad | 539 | unifi_error(priv, "store_ap_advanced_config_from_string: WMM not found\n"); |
635d2b00 GKH |
540 | return -1; |
541 | } | |
542 | ap_mac_config->wmmEnabled = tmp_var; | |
543 | ret = decode_parameter_from_string(priv, &str_ptr, "PHY=", | |
544 | PARAM_TYPE_STRING, phy_mode, 5); | |
545 | if(ret) { | |
3f596cad | 546 | unifi_error(priv, "store_ap_advanced_config_from_string: PHY not found\n"); |
635d2b00 | 547 | } else { |
3f596cad | 548 | if(strstr(phy_mode, "b")){ |
635d2b00 GKH |
549 | ap_mac_config->phySupportedBitmap = CSR_WIFI_SME_AP_PHY_SUPPORT_B; |
550 | } | |
3f596cad | 551 | if(strstr(phy_mode, "g")) { |
635d2b00 GKH |
552 | ap_mac_config->phySupportedBitmap |= CSR_WIFI_SME_AP_PHY_SUPPORT_G; |
553 | } | |
3f596cad | 554 | if(strstr(phy_mode, "n")) { |
635d2b00 GKH |
555 | ap_mac_config->phySupportedBitmap |= CSR_WIFI_SME_AP_PHY_SUPPORT_N; |
556 | } | |
557 | ap_mac_config->supportedRatesCount = | |
558 | uf_configure_supported_rates(ap_mac_config->supportedRates, ap_mac_config->phySupportedBitmap); | |
559 | } | |
560 | return ret; | |
561 | } | |
562 | ||
3f596cad | 563 | static int store_ap_config_from_string( unifi_priv_t * priv, char *param_str) |
635d2b00 GKH |
564 | |
565 | { | |
566 | char *str_ptr = param_str; | |
567 | char sub_cmd[16]; | |
568 | char sec[CSR_WIFI_MAX_SEC_LEN]; | |
569 | char key[CSR_WIFI_MAX_KEY_LEN]; | |
3f596cad | 570 | int ret = 0, tmp_var; |
635d2b00 GKH |
571 | CsrWifiSmeApConfig_t *ap_config = &priv->ap_config; |
572 | CsrWifiSmeApMacConfig * ap_mac_config = &priv->ap_mac_config; | |
573 | memset(sub_cmd, 0, sizeof(sub_cmd)); | |
3f596cad LL |
574 | if(!strstr(param_str, "END")) { |
575 | unifi_error(priv, "store_ap_config_from_string:Invalid config string:%s\n", param_str); | |
635d2b00 GKH |
576 | return -1; |
577 | } | |
3f596cad | 578 | if (decode_parameter_from_string(priv, &str_ptr, "ASCII_CMD=", |
635d2b00 GKH |
579 | PARAM_TYPE_STRING, sub_cmd, 6) != 0) { |
580 | return -1; | |
581 | } | |
582 | if (strncmp(sub_cmd, "AP_CFG", 6)) { | |
583 | ||
3f596cad | 584 | if(!strncmp(sub_cmd , "ADVCFG", 6)) { |
635d2b00 GKH |
585 | return store_ap_advanced_config_from_string(priv, str_ptr); |
586 | } | |
3f596cad | 587 | unifi_error(priv, "store_ap_config_from_string: sub_cmd:%s != 'AP_CFG or ADVCFG'!\n", sub_cmd); |
635d2b00 GKH |
588 | return -1; |
589 | } | |
590 | memset(ap_config, 0, sizeof(CsrWifiSmeApConfig_t)); | |
3f596cad | 591 | ret = decode_parameter_from_string(priv, &str_ptr, "SSID=", |
635d2b00 GKH |
592 | PARAM_TYPE_STRING, ap_config->ssid.ssid, |
593 | CSR_WIFI_MAX_SSID_LEN); | |
594 | if(ret) { | |
3f596cad | 595 | unifi_error(priv, "store_ap_config_from_string: SSID not found\n"); |
635d2b00 GKH |
596 | return -1; |
597 | } | |
598 | ap_config->ssid.length = strlen(ap_config->ssid.ssid); | |
599 | ||
600 | ret = decode_parameter_from_string(priv, &str_ptr, "SEC=", | |
601 | PARAM_TYPE_STRING, sec, CSR_WIFI_MAX_SEC_LEN); | |
602 | if(ret) { | |
3f596cad | 603 | unifi_error(priv, "store_ap_config_from_string: SEC not found\n"); |
635d2b00 GKH |
604 | return -1; |
605 | } | |
3f596cad LL |
606 | ret = decode_parameter_from_string(priv, &str_ptr, "KEY=", |
607 | PARAM_TYPE_STRING, key, CSR_WIFI_MAX_KEY_LEN); | |
608 | if(!strcasecmp(sec, "open")) { | |
609 | unifi_trace(priv, UDBG2, "store_ap_config_from_string: security open"); | |
635d2b00 GKH |
610 | ap_config->credentials.authType = CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM; |
611 | if(ret) { | |
3f596cad | 612 | unifi_notice(priv, "store_ap_config_from_string: KEY not found:fine with Open\n"); |
635d2b00 GKH |
613 | } |
614 | } | |
3f596cad LL |
615 | else if(!strcasecmp(sec, "wpa2-psk")) { |
616 | int i, j=0; | |
635d2b00 GKH |
617 | CsrWifiNmeApAuthPers *pers = |
618 | ((CsrWifiNmeApAuthPers *)&(ap_config->credentials.nmeAuthType.authTypePersonal)); | |
7e6f5794 | 619 | u8 *psk = pers->authPers_credentials.psk.psk; |
635d2b00 | 620 | |
3f596cad | 621 | unifi_trace(priv, UDBG2, "store_ap_config_from_string: security WPA2"); |
635d2b00 | 622 | if(ret) { |
3f596cad | 623 | unifi_error(priv, "store_ap_config_from_string: KEY not found for WPA2\n"); |
635d2b00 GKH |
624 | return -1; |
625 | } | |
626 | ap_config->credentials.authType = CSR_WIFI_SME_AP_AUTH_TYPE_PERSONAL; | |
627 | pers->authSupport = CSR_WIFI_SME_RSN_AUTH_WPA2PSK; | |
628 | pers->rsnCapabilities =0; | |
629 | pers->wapiCapabilities =0; | |
630 | pers->pskOrPassphrase=CSR_WIFI_NME_AP_CREDENTIAL_TYPE_PSK; | |
631 | pers->authPers_credentials.psk.encryptionMode = | |
632 | (CSR_WIFI_NME_ENCRYPTION_CIPHER_PAIRWISE_CCMP |CSR_WIFI_NME_ENCRYPTION_CIPHER_GROUP_CCMP) ; | |
633 | for(i=0;i<32;i++){ | |
634 | psk[i] = (16*hex_look_up(key[j]))+hex_look_up(key[j+1]); | |
635 | j+=2; | |
636 | } | |
637 | ||
638 | } else { | |
3f596cad | 639 | unifi_notice(priv, "store_ap_config_from_string: Unknown security: Assuming Open"); |
635d2b00 GKH |
640 | ap_config->credentials.authType = CSR_WIFI_SME_AP_AUTH_TYPE_OPEN_SYSTEM; |
641 | return -1; | |
642 | } | |
643 | /* Get the decoded value in a temp int variable to ensure that other fields within the struct | |
644 | which are of type other than int are not over written */ | |
3f596cad | 645 | ret = decode_parameter_from_string(priv, &str_ptr, "CHANNEL=", PARAM_TYPE_INT, &tmp_var, 5); |
635d2b00 GKH |
646 | if(ret) |
647 | return -1; | |
648 | ap_config->channel = tmp_var; | |
3f596cad | 649 | ret = decode_parameter_from_string(priv, &str_ptr, "PREAMBLE=", PARAM_TYPE_INT, &tmp_var, 5); |
635d2b00 GKH |
650 | if(ret) |
651 | return -1; | |
652 | ap_mac_config->preamble = tmp_var; | |
3f596cad | 653 | ret = decode_parameter_from_string(priv, &str_ptr, "MAX_SCB=", PARAM_TYPE_INT, &tmp_var, 5); |
635d2b00 GKH |
654 | ap_config->max_connections = tmp_var; |
655 | return ret; | |
656 | } | |
657 | ||
658 | static int | |
659 | iwprivsapstart(struct net_device *dev, struct iw_request_info *info, | |
660 | union iwreq_data *wrqu, char *extra) | |
661 | { | |
662 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
663 | unifi_priv_t *priv = interfacePriv->privPtr; | |
664 | int r; | |
665 | ||
666 | unifi_trace(priv, UDBG1, "iwprivsapstart\n" ); | |
3f596cad | 667 | r = sme_ap_start(priv, interfacePriv->InterfaceTag, &priv->ap_config); |
635d2b00 | 668 | if(r) { |
3f596cad | 669 | unifi_error(priv, "iwprivsapstart AP START failed : %d\n", -r); |
635d2b00 GKH |
670 | } |
671 | return r; | |
672 | } | |
673 | ||
674 | static int | |
675 | iwprivsapconfig(struct net_device *dev, struct iw_request_info *info, | |
676 | union iwreq_data *wrqu, char *extra) | |
677 | { | |
678 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
679 | unifi_priv_t *priv = interfacePriv->privPtr; | |
680 | char *cfg_str = NULL; | |
681 | int r; | |
682 | ||
683 | unifi_trace(priv, UDBG1, "iwprivsapconfig\n" ); | |
684 | if (wrqu->data.length != 0) { | |
685 | char *str; | |
686 | if (!(cfg_str = kmalloc(wrqu->data.length+1, GFP_KERNEL))) | |
687 | { | |
688 | return -ENOMEM; | |
689 | } | |
690 | if (copy_from_user(cfg_str, wrqu->data.pointer, wrqu->data.length)) { | |
691 | kfree(cfg_str); | |
692 | return -EFAULT; | |
693 | } | |
694 | cfg_str[wrqu->data.length] = 0; | |
3f596cad LL |
695 | unifi_trace(priv, UDBG2, "length:%d\n", wrqu->data.length); |
696 | unifi_trace(priv, UDBG2, "AP configuration string:%s\n", cfg_str); | |
635d2b00 | 697 | str = cfg_str; |
3f596cad LL |
698 | if ((r = store_ap_config_from_string(priv, str))) { |
699 | unifi_error(priv, "iwprivsapconfig:Failed to decode the string %d\n", r); | |
635d2b00 GKH |
700 | kfree(cfg_str); |
701 | return -EIO; | |
702 | ||
703 | } | |
704 | } else { | |
3f596cad | 705 | unifi_error(priv, "iwprivsapconfig argument length = 0 \n"); |
635d2b00 GKH |
706 | return -EIO; |
707 | } | |
708 | r = sme_ap_config(priv, &priv->ap_mac_config, &priv->group_sec_config); | |
709 | if(r) { | |
3f596cad | 710 | unifi_error(priv, "iwprivsapstop AP Config failed : %d\n", -r); |
635d2b00 GKH |
711 | } else if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || |
712 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
713 | unifi_trace(priv, UDBG1, "iwprivsapconfig: Starting the AP"); | |
3f596cad | 714 | r = sme_ap_start(priv, interfacePriv->InterfaceTag, &priv->ap_config); |
635d2b00 | 715 | if(r) { |
3f596cad | 716 | unifi_error(priv, "iwprivsapstart AP START failed : %d\n", -r); |
635d2b00 GKH |
717 | } |
718 | } | |
719 | kfree(cfg_str); | |
720 | return r; | |
721 | } | |
722 | ||
723 | static int | |
724 | iwprivsapstop(struct net_device *dev, struct iw_request_info *info, | |
725 | union iwreq_data *wrqu, char *extra) | |
726 | { | |
727 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
728 | unifi_priv_t *priv = interfacePriv->privPtr; | |
729 | int r; | |
8c87f69a | 730 | u16 interface_tag = interfacePriv->InterfaceTag; |
635d2b00 GKH |
731 | |
732 | unifi_trace(priv, UDBG1, "iwprivsapstop\n" ); | |
3f596cad | 733 | r = sme_ap_stop(priv, interface_tag); |
635d2b00 | 734 | if(r) { |
3f596cad | 735 | unifi_error(priv, "iwprivsapstop AP STOP failed : %d\n", -r); |
635d2b00 GKH |
736 | } |
737 | return r; | |
738 | } | |
739 | ||
740 | #ifdef ANDROID_BUILD | |
741 | static int | |
742 | iwprivsapfwreload(struct net_device *dev, struct iw_request_info *info, | |
743 | union iwreq_data *wrqu, char *extra) | |
744 | { | |
745 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
746 | unifi_priv_t *priv = interfacePriv->privPtr; | |
747 | ||
748 | unifi_trace(priv, UDBG1, "iwprivsapfwreload\n" ); | |
749 | return 0; | |
750 | } | |
751 | ||
752 | static int | |
753 | iwprivsstackstart(struct net_device *dev, struct iw_request_info *info, | |
754 | union iwreq_data *wrqu, char *extra) | |
755 | { | |
756 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
757 | unifi_priv_t *priv = interfacePriv->privPtr; | |
758 | unifi_trace(priv, UDBG1, "iwprivsstackstart\n" ); | |
759 | return 0; | |
760 | } | |
761 | ||
762 | static int | |
763 | iwprivsstackstop(struct net_device *dev, struct iw_request_info *info, | |
764 | union iwreq_data *wrqu, char *extra) | |
765 | { | |
766 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
767 | unifi_priv_t *priv = interfacePriv->privPtr; | |
768 | int r = 0; | |
8c87f69a | 769 | u16 interface_tag = interfacePriv->InterfaceTag; |
635d2b00 GKH |
770 | |
771 | unifi_trace(priv, UDBG1, "iwprivsstackstop\n" ); | |
772 | ||
773 | switch(interfacePriv->interfaceMode) { | |
774 | case CSR_WIFI_ROUTER_CTRL_MODE_STA: | |
775 | case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI: | |
776 | case CSR_WIFI_ROUTER_CTRL_MODE_IBSS: | |
777 | r = sme_mgt_disconnect(priv); | |
778 | break; | |
779 | case CSR_WIFI_ROUTER_CTRL_MODE_AP: | |
780 | case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO: | |
3f596cad | 781 | r = sme_ap_stop(priv, interface_tag); |
635d2b00 GKH |
782 | break; |
783 | default : | |
784 | break; | |
785 | } | |
786 | ||
787 | if(r) { | |
3f596cad | 788 | unifi_error(priv, "iwprivsstackstop Stack stop failed : %d\n", -r); |
635d2b00 GKH |
789 | } |
790 | return 0; | |
791 | } | |
792 | #endif /* ANDROID_BUILD */ | |
793 | #endif /* CSR_SUPPORT_WEXT_AP */ | |
794 | ||
795 | #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE | |
796 | static int | |
797 | iwprivsconfwapi(struct net_device *dev, struct iw_request_info *info, | |
798 | union iwreq_data *wrqu, char *extra) | |
799 | { | |
7e6f5794 | 800 | u8 enable; |
635d2b00 GKH |
801 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); |
802 | unifi_priv_t *priv = interfacePriv->privPtr; | |
635d2b00 GKH |
803 | |
804 | unifi_trace(priv, UDBG1, "iwprivsconfwapi\n" ); | |
805 | ||
806 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
807 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
808 | unifi_error(priv, "iwprivsconfwapi: not permitted in Mode %d\n", | |
809 | interfacePriv->interfaceMode); | |
810 | return -EPERM; | |
811 | } | |
812 | ||
7e6f5794 | 813 | enable = *(u8*)(extra); |
635d2b00 GKH |
814 | |
815 | if (enable) { | |
816 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
817 | priv->connection_config.authModeMask |= (CSR_WIFI_SME_AUTH_MODE_WAPI_WAIPSK | CSR_WIFI_SME_AUTH_MODE_WAPI_WAI); | |
818 | priv->connection_config.encryptionModeMask |= | |
819 | CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_SMS4 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_SMS4; | |
820 | } else { | |
821 | priv->connection_config.authModeMask &= ~(CSR_WIFI_SME_AUTH_MODE_WAPI_WAIPSK | CSR_WIFI_SME_AUTH_MODE_WAPI_WAI); | |
822 | priv->connection_config.encryptionModeMask &= | |
823 | ~(CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_SMS4 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_SMS4); | |
824 | } | |
825 | ||
635d2b00 GKH |
826 | return 0; |
827 | } | |
828 | ||
829 | static int | |
830 | iwprivswpikey(struct net_device *dev, struct iw_request_info *info, | |
831 | union iwreq_data *wrqu, char *extra) | |
832 | { | |
833 | int r = 0, i; | |
834 | CsrWifiSmeKey key; | |
835 | unifiio_wapi_key_t inKey; | |
836 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
837 | unifi_priv_t *priv = interfacePriv->privPtr; | |
635d2b00 GKH |
838 | |
839 | unifi_trace(priv, UDBG1, "iwprivswpikey\n" ); | |
840 | ||
841 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
842 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
843 | unifi_error(priv, "iwprivswpikey: not permitted in Mode %d\n", | |
844 | interfacePriv->interfaceMode); | |
845 | return -EPERM; | |
846 | } | |
847 | ||
848 | inKey = *(unifiio_wapi_key_t*)(extra); | |
849 | ||
850 | if (inKey.unicastKey) { | |
851 | key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE; | |
852 | } else { | |
853 | key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP; | |
854 | } | |
855 | ||
856 | key.keyIndex = inKey.keyIndex; | |
857 | ||
858 | /* memcpy(key.keyRsc, inKey.keyRsc, 16); */ | |
859 | for (i = 0; i < 16; i+= 2) | |
860 | { | |
861 | key.keyRsc[i/2] = inKey.keyRsc[i+1] << 8 | inKey.keyRsc[i]; | |
862 | } | |
863 | ||
864 | memcpy(key.address.a, inKey.address, 6); | |
865 | key.keyLength = 32; | |
866 | memcpy(key.key, inKey.key, 32); | |
867 | key.authenticator = 0; | |
868 | key.wepTxKey = 0; | |
869 | ||
870 | unifi_trace(priv, UDBG1, "keyType = %d, keyIndex = %d, wepTxKey = %d, keyRsc = %x:%x, auth = %d, address = %x:%x, " | |
871 | "keylength = %d, key = %x:%x\n", key.keyType, key.keyIndex, key.wepTxKey, | |
872 | key.keyRsc[0], key.keyRsc[7], key.authenticator, | |
873 | key.address.a[0], key.address.a[5], key.keyLength, key.key[0], | |
874 | key.key[15]); | |
875 | ||
876 | r = sme_mgt_key(priv, &key, CSR_WIFI_SME_LIST_ACTION_ADD); | |
877 | if (r) { | |
878 | unifi_error(priv, "SETKEYS request was rejected with result %d\n", r); | |
879 | return convert_sme_error(r); | |
880 | } | |
881 | ||
635d2b00 GKH |
882 | return r; |
883 | } | |
884 | #endif | |
885 | ||
886 | ||
887 | static int | |
888 | unifi_giwname(struct net_device *dev, struct iw_request_info *info, | |
889 | union iwreq_data *wrqu, char *extra) | |
890 | { | |
891 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
892 | unifi_priv_t *priv = interfacePriv->privPtr; | |
893 | char *name = wrqu->name; | |
894 | unifi_trace(priv, UDBG2, "unifi_giwname\n"); | |
895 | ||
896 | if (priv->if_index == CSR_INDEX_5G) { | |
897 | strcpy(name, "IEEE 802.11-a"); | |
898 | } else { | |
899 | strcpy(name, "IEEE 802.11-bgn"); | |
900 | } | |
901 | return 0; | |
902 | } /* unifi_giwname() */ | |
903 | ||
904 | ||
905 | static int | |
906 | unifi_siwfreq(struct net_device *dev, struct iw_request_info *info, | |
907 | union iwreq_data *wrqu, char *extra) | |
908 | { | |
909 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
910 | unifi_priv_t *priv = interfacePriv->privPtr; | |
911 | struct iw_freq *freq = (struct iw_freq *)wrqu; | |
912 | ||
635d2b00 GKH |
913 | unifi_trace(priv, UDBG2, "unifi_siwfreq\n"); |
914 | ||
915 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
916 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
917 | unifi_error(priv, "unifi_siwfreq: not permitted in Mode %d\n", | |
918 | interfacePriv->interfaceMode); | |
919 | return -EPERM; | |
920 | } | |
921 | ||
922 | ||
923 | /* | |
924 | * Channel is stored in the connection configuration, | |
925 | * and set later when ask for a connection. | |
926 | */ | |
927 | if ((freq->e == 0) && (freq->m <= 1000)) { | |
928 | priv->connection_config.adhocChannel = freq->m; | |
929 | } else { | |
930 | priv->connection_config.adhocChannel = wext_freq_to_channel(freq->m, freq->e); | |
931 | } | |
932 | ||
635d2b00 GKH |
933 | return 0; |
934 | } /* unifi_siwfreq() */ | |
935 | ||
936 | ||
937 | static int | |
938 | unifi_giwfreq(struct net_device *dev, struct iw_request_info *info, | |
939 | union iwreq_data *wrqu, char *extra) | |
940 | { | |
941 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
942 | unifi_priv_t *priv = interfacePriv->privPtr; | |
943 | struct iw_freq *freq = (struct iw_freq *)wrqu; | |
944 | int err = 0; | |
945 | CsrWifiSmeConnectionInfo connectionInfo; | |
946 | ||
635d2b00 GKH |
947 | unifi_trace(priv, UDBG2, "unifi_giwfreq\n"); |
948 | CHECK_INITED(priv); | |
949 | ||
950 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
951 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
952 | unifi_error(priv, "unifi_giwfreq: not permitted in Mode %d\n", | |
953 | interfacePriv->interfaceMode); | |
954 | return -EPERM; | |
955 | } | |
956 | ||
957 | ||
958 | UF_RTNL_UNLOCK(); | |
959 | err = sme_mgt_connection_info_get(priv, &connectionInfo); | |
960 | UF_RTNL_LOCK(); | |
961 | ||
962 | freq->m = channel_to_mhz(connectionInfo.channelNumber, | |
963 | (connectionInfo.networkType80211 == CSR_WIFI_SME_RADIO_IF_GHZ_5_0)); | |
964 | freq->e = 6; | |
965 | ||
635d2b00 GKH |
966 | return convert_sme_error(err); |
967 | } /* unifi_giwfreq() */ | |
968 | ||
969 | ||
970 | static int | |
971 | unifi_siwmode(struct net_device *dev, struct iw_request_info *info, | |
972 | union iwreq_data *wrqu, char *extra) | |
973 | { | |
974 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
975 | unifi_priv_t *priv = interfacePriv->privPtr; | |
976 | ||
635d2b00 GKH |
977 | unifi_trace(priv, UDBG2, "unifi_siwmode\n"); |
978 | ||
979 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
980 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
981 | unifi_error(priv, "unifi_siwmode: not permitted in Mode %d\n", | |
982 | interfacePriv->interfaceMode); | |
983 | return -EPERM; | |
984 | } | |
985 | ||
986 | ||
987 | switch(wrqu->mode) { | |
988 | case IW_MODE_ADHOC: | |
989 | priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_ADHOC; | |
990 | break; | |
991 | case IW_MODE_INFRA: | |
992 | priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE; | |
993 | break; | |
994 | case IW_MODE_AUTO: | |
995 | priv->connection_config.bssType = CSR_WIFI_SME_BSS_TYPE_ANY_BSS; | |
996 | break; | |
997 | default: | |
998 | unifi_notice(priv, "Unknown IW MODE value.\n"); | |
999 | } | |
1000 | ||
1001 | /* Clear the SSID and BSSID configuration */ | |
1002 | priv->connection_config.ssid.length = 0; | |
1003 | memset(priv->connection_config.bssid.a, 0xFF, ETH_ALEN); | |
1004 | ||
635d2b00 GKH |
1005 | return 0; |
1006 | } /* unifi_siwmode() */ | |
1007 | ||
1008 | ||
1009 | ||
1010 | static int | |
1011 | unifi_giwmode(struct net_device *dev, struct iw_request_info *info, | |
1012 | union iwreq_data *wrqu, char *extra) | |
1013 | { | |
1014 | int r = 0; | |
1015 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1016 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1017 | CsrWifiSmeConnectionConfig connectionConfig; | |
1018 | ||
635d2b00 GKH |
1019 | unifi_trace(priv, UDBG2, "unifi_giwmode\n"); |
1020 | CHECK_INITED(priv); | |
1021 | ||
1022 | unifi_trace(priv, UDBG2, "unifi_giwmode: Exisitng mode = 0x%x\n", | |
1023 | interfacePriv->interfaceMode); | |
1024 | switch(interfacePriv->interfaceMode) { | |
1025 | case CSR_WIFI_ROUTER_CTRL_MODE_STA: | |
1026 | case CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI: | |
1027 | wrqu->mode = IW_MODE_INFRA; | |
1028 | break; | |
1029 | case CSR_WIFI_ROUTER_CTRL_MODE_AP: | |
1030 | case CSR_WIFI_ROUTER_CTRL_MODE_P2PGO: | |
1031 | wrqu->mode = IW_MODE_MASTER; | |
1032 | break; | |
1033 | case CSR_WIFI_ROUTER_CTRL_MODE_IBSS: | |
1034 | wrqu->mode = IW_MODE_ADHOC; | |
1035 | break; | |
1036 | case CSR_WIFI_ROUTER_CTRL_MODE_P2P: | |
1037 | case CSR_WIFI_ROUTER_CTRL_MODE_NONE: | |
1038 | UF_RTNL_UNLOCK(); | |
1039 | r = sme_mgt_connection_config_get(priv, &connectionConfig); | |
1040 | UF_RTNL_LOCK(); | |
1041 | if (r == 0) { | |
1042 | switch(connectionConfig.bssType) { | |
1043 | case CSR_WIFI_SME_BSS_TYPE_ADHOC: | |
1044 | wrqu->mode = IW_MODE_ADHOC; | |
1045 | break; | |
1046 | case CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE: | |
1047 | wrqu->mode = IW_MODE_INFRA; | |
1048 | break; | |
1049 | default: | |
1050 | wrqu->mode = IW_MODE_AUTO; | |
1051 | unifi_notice(priv, "Unknown IW MODE value.\n"); | |
1052 | } | |
1053 | } | |
1054 | break; | |
1055 | default: | |
1056 | wrqu->mode = IW_MODE_AUTO; | |
1057 | unifi_notice(priv, "Unknown IW MODE value.\n"); | |
1058 | ||
1059 | } | |
1060 | unifi_trace(priv, UDBG4, "unifi_giwmode: mode = 0x%x\n", wrqu->mode); | |
635d2b00 GKH |
1061 | return r; |
1062 | } /* unifi_giwmode() */ | |
1063 | ||
1064 | ||
1065 | ||
1066 | static int | |
1067 | unifi_giwrange(struct net_device *dev, struct iw_request_info *info, | |
1068 | union iwreq_data *wrqu, char *extra) | |
1069 | { | |
1070 | struct iw_point *dwrq = &wrqu->data; | |
1071 | struct iw_range *range = (struct iw_range *) extra; | |
1072 | int i; | |
1073 | ||
1074 | unifi_trace(NULL, UDBG2, "unifi_giwrange\n"); | |
1075 | ||
1076 | dwrq->length = sizeof(struct iw_range); | |
1077 | memset(range, 0, sizeof(*range)); | |
1078 | range->min_nwid = 0x0000; | |
1079 | range->max_nwid = 0x0000; | |
1080 | ||
1081 | /* | |
1082 | * Don't report the frequency/channel table, then the channel | |
1083 | * number returned elsewhere will be printed as a channel number. | |
1084 | */ | |
1085 | ||
1086 | /* Ranges of values reported in quality structs */ | |
1087 | range->max_qual.qual = 40; /* Max expected qual value */ | |
1088 | range->max_qual.level = -120; /* Noise floor in dBm */ | |
1089 | range->max_qual.noise = -120; /* Noise floor in dBm */ | |
1090 | ||
1091 | ||
1092 | /* space for IW_MAX_BITRATES (8 up to WE15, 32 later) */ | |
1093 | i = 0; | |
1094 | #if WIRELESS_EXT > 15 | |
1095 | range->bitrate[i++] = 2 * 500000; | |
1096 | range->bitrate[i++] = 4 * 500000; | |
1097 | range->bitrate[i++] = 11 * 500000; | |
1098 | range->bitrate[i++] = 22 * 500000; | |
1099 | range->bitrate[i++] = 12 * 500000; | |
1100 | range->bitrate[i++] = 18 * 500000; | |
1101 | range->bitrate[i++] = 24 * 500000; | |
1102 | range->bitrate[i++] = 36 * 500000; | |
1103 | range->bitrate[i++] = 48 * 500000; | |
1104 | range->bitrate[i++] = 72 * 500000; | |
1105 | range->bitrate[i++] = 96 * 500000; | |
1106 | range->bitrate[i++] = 108 * 500000; | |
1107 | #else | |
1108 | range->bitrate[i++] = 2 * 500000; | |
1109 | range->bitrate[i++] = 4 * 500000; | |
1110 | range->bitrate[i++] = 11 * 500000; | |
1111 | range->bitrate[i++] = 22 * 500000; | |
1112 | range->bitrate[i++] = 24 * 500000; | |
1113 | range->bitrate[i++] = 48 * 500000; | |
1114 | range->bitrate[i++] = 96 * 500000; | |
1115 | range->bitrate[i++] = 108 * 500000; | |
1116 | #endif /* WIRELESS_EXT < 16 */ | |
1117 | range->num_bitrates = i; | |
1118 | ||
1119 | range->max_encoding_tokens = NUM_WEPKEYS; | |
1120 | range->num_encoding_sizes = 2; | |
1121 | range->encoding_size[0] = 5; | |
1122 | range->encoding_size[1] = 13; | |
1123 | ||
1124 | range->we_version_source = 20; | |
1125 | range->we_version_compiled = WIRELESS_EXT; | |
1126 | ||
1127 | /* Number of channels available in h/w */ | |
1128 | range->num_channels = 14; | |
1129 | /* Number of entries in freq[] array */ | |
1130 | range->num_frequency = 14; | |
1131 | for (i = 0; (i < range->num_frequency) && (i < IW_MAX_FREQUENCIES); i++) { | |
1132 | int chan = i + 1; | |
1133 | range->freq[i].i = chan; | |
1134 | range->freq[i].m = channel_to_mhz(chan, 0); | |
1135 | range->freq[i].e = 6; | |
1136 | } | |
1137 | if ((i+3) < IW_MAX_FREQUENCIES) { | |
1138 | range->freq[i].i = 36; | |
1139 | range->freq[i].m = channel_to_mhz(36, 1); | |
1140 | range->freq[i].e = 6; | |
1141 | range->freq[i+1].i = 40; | |
1142 | range->freq[i+1].m = channel_to_mhz(40, 1); | |
1143 | range->freq[i+1].e = 6; | |
1144 | range->freq[i+2].i = 44; | |
1145 | range->freq[i+2].m = channel_to_mhz(44, 1); | |
1146 | range->freq[i+2].e = 6; | |
1147 | range->freq[i+3].i = 48; | |
1148 | range->freq[i+3].m = channel_to_mhz(48, 1); | |
1149 | range->freq[i+3].e = 6; | |
1150 | } | |
1151 | ||
1152 | #if WIRELESS_EXT > 16 | |
1153 | /* Event capability (kernel + driver) */ | |
1154 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | |
1155 | IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | | |
1156 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | |
1157 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | |
1158 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | |
1159 | range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | | |
1160 | IW_EVENT_CAPA_MASK(IWEVCUSTOM) | | |
1161 | IW_EVENT_CAPA_MASK(IWEVREGISTERED) | | |
1162 | IW_EVENT_CAPA_MASK(IWEVEXPIRED)); | |
1163 | #endif /* WIRELESS_EXT > 16 */ | |
1164 | ||
1165 | #if WIRELESS_EXT > 17 | |
1166 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | |
1167 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | |
1168 | #endif /* WIRELESS_EXT > 17 */ | |
1169 | ||
1170 | ||
1171 | return 0; | |
1172 | } /* unifi_giwrange() */ | |
1173 | ||
1174 | ||
1175 | static int | |
1176 | unifi_siwap(struct net_device *dev, struct iw_request_info *info, | |
1177 | union iwreq_data *wrqu, char *extra) | |
1178 | { | |
1179 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1180 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1181 | int err = 0; | |
635d2b00 | 1182 | |
635d2b00 GKH |
1183 | CHECK_INITED(priv); |
1184 | ||
1185 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
1186 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
1187 | unifi_error(priv, "unifi_siwap: not permitted in Mode %d\n", | |
1188 | interfacePriv->interfaceMode); | |
1189 | return -EPERM; | |
1190 | } | |
1191 | ||
1192 | ||
1193 | if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) { | |
1194 | return -EINVAL; | |
1195 | } | |
1196 | ||
a6737c73 AS |
1197 | unifi_trace(priv, UDBG1, "unifi_siwap: asked for %pM\n", |
1198 | wrqu->ap_addr.sa_data); | |
635d2b00 | 1199 | |
6a5c2319 | 1200 | if (is_zero_ether_addr(wrqu->ap_addr.sa_data)) { |
635d2b00 GKH |
1201 | priv->ignore_bssid_join = FALSE; |
1202 | err = sme_mgt_disconnect(priv); | |
1203 | if (err) { | |
1204 | unifi_trace(priv, UDBG4, "unifi_siwap: Disconnect failed, status %d\n", err); | |
1205 | } | |
1206 | return 0; | |
1207 | } | |
1208 | ||
1209 | if (priv->ignore_bssid_join) { | |
1210 | unifi_trace(priv, UDBG4, "unifi_siwap: ignoring second join\n"); | |
1211 | priv->ignore_bssid_join = FALSE; | |
1212 | } else { | |
1213 | memcpy(priv->connection_config.bssid.a, wrqu->ap_addr.sa_data, ETH_ALEN); | |
1214 | unifi_trace(priv, UDBG1, "unifi_siwap: Joining %X:%X:%X:%X:%X:%X\n", | |
1215 | priv->connection_config.bssid.a[0], | |
1216 | priv->connection_config.bssid.a[1], | |
1217 | priv->connection_config.bssid.a[2], | |
1218 | priv->connection_config.bssid.a[3], | |
1219 | priv->connection_config.bssid.a[4], | |
1220 | priv->connection_config.bssid.a[5]); | |
1221 | err = sme_mgt_connect(priv); | |
1222 | if (err) { | |
1223 | unifi_error(priv, "unifi_siwap: Join failed, status %d\n", err); | |
635d2b00 GKH |
1224 | return convert_sme_error(err); |
1225 | } | |
1226 | } | |
635d2b00 GKH |
1227 | |
1228 | return 0; | |
1229 | } /* unifi_siwap() */ | |
1230 | ||
1231 | ||
1232 | static int | |
1233 | unifi_giwap(struct net_device *dev, struct iw_request_info *info, | |
1234 | union iwreq_data *wrqu, char *extra) | |
1235 | { | |
1236 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1237 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1238 | CsrWifiSmeConnectionInfo connectionInfo; | |
1239 | int r = 0; | |
7e6f5794 | 1240 | u8 *bssid; |
635d2b00 | 1241 | |
635d2b00 GKH |
1242 | CHECK_INITED(priv); |
1243 | unifi_trace(priv, UDBG2, "unifi_giwap\n"); | |
1244 | ||
1245 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
1246 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
1247 | unifi_error(priv, "iwprivswpikey: not permitted in Mode %d\n", | |
1248 | interfacePriv->interfaceMode); | |
1249 | return -EPERM; | |
1250 | } | |
1251 | ||
1252 | UF_RTNL_UNLOCK(); | |
1253 | r = sme_mgt_connection_info_get(priv, &connectionInfo); | |
1254 | UF_RTNL_LOCK(); | |
1255 | ||
1256 | if (r == 0) { | |
1257 | bssid = connectionInfo.bssid.a; | |
1258 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | |
a6737c73 | 1259 | unifi_trace(priv, UDBG4, "unifi_giwap: BSSID = %pM\n", bssid); |
635d2b00 GKH |
1260 | |
1261 | memcpy(wrqu->ap_addr.sa_data, bssid, ETH_ALEN); | |
1262 | } else { | |
1263 | memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); | |
1264 | } | |
1265 | ||
635d2b00 GKH |
1266 | return 0; |
1267 | } /* unifi_giwap() */ | |
1268 | ||
1269 | ||
1270 | static int | |
1271 | unifi_siwscan(struct net_device *dev, struct iw_request_info *info, | |
1272 | union iwreq_data *wrqu, char *extra) | |
1273 | { | |
1274 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1275 | unifi_priv_t *priv = interfacePriv->privPtr; | |
635d2b00 GKH |
1276 | int r; |
1277 | CsrWifiSsid scan_ssid; | |
1278 | unsigned char *channel_list = NULL; | |
1279 | int chans_good = 0; | |
1280 | #if WIRELESS_EXT > 17 | |
1281 | struct iw_point *data = &wrqu->data; | |
1282 | struct iw_scan_req *req = (struct iw_scan_req *) extra; | |
1283 | #endif | |
1284 | ||
635d2b00 GKH |
1285 | CHECK_INITED(priv); |
1286 | ||
1287 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
1288 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
1289 | unifi_error(priv, "unifi_siwscan: not permitted in Mode %d\n", | |
1290 | interfacePriv->interfaceMode); | |
1291 | return -EPERM; | |
1292 | } | |
1293 | ||
1294 | ||
635d2b00 GKH |
1295 | #if WIRELESS_EXT > 17 |
1296 | /* Providing a valid channel list will force an active scan */ | |
1297 | if (req) { | |
1298 | if ((req->num_channels > 0) && (req->num_channels < IW_MAX_FREQUENCIES)) { | |
1299 | channel_list = kmalloc(req->num_channels, GFP_KERNEL); | |
1300 | if (channel_list) { | |
1301 | int i; | |
1302 | for (i = 0; i < req->num_channels; i++) { | |
1303 | /* Convert frequency to channel number */ | |
1304 | int ch = wext_freq_to_channel(req->channel_list[i].m, | |
1305 | req->channel_list[i].e); | |
1306 | if (ch) { | |
1307 | channel_list[chans_good++] = ch; | |
1308 | } | |
1309 | } | |
1310 | unifi_trace(priv, UDBG1, | |
1311 | "SIWSCAN: Scanning %d channels\n", chans_good); | |
1312 | } else { | |
1313 | /* Fall back to scanning all */ | |
1314 | unifi_error(priv, "SIWSCAN: Can't alloc channel_list (%d)\n", | |
1315 | req->num_channels); | |
1316 | } | |
1317 | } | |
1318 | } | |
1319 | ||
1320 | if (req && (data->flags & IW_SCAN_THIS_ESSID)) { | |
1321 | memcpy(scan_ssid.ssid, req->essid, req->essid_len); | |
1322 | scan_ssid.length = req->essid_len; | |
1323 | unifi_trace(priv, UDBG1, | |
1324 | "SIWSCAN: Scanning for %.*s\n", | |
1325 | scan_ssid.length, scan_ssid.ssid); | |
1326 | } else | |
1327 | #endif | |
1328 | { | |
1329 | unifi_trace(priv, UDBG1, "SIWSCAN: Scanning for all APs\n"); | |
1330 | scan_ssid.length = 0; | |
1331 | } | |
1332 | ||
1333 | r = sme_mgt_scan_full(priv, &scan_ssid, chans_good, channel_list); | |
1334 | if (r) { | |
1335 | unifi_error(priv, "SIWSCAN: Scan returned error %d\n", r); | |
1336 | } else { | |
1337 | unifi_trace(priv, UDBG1, "SIWSCAN: Scan done\n"); | |
1338 | wext_send_scan_results_event(priv); | |
1339 | } | |
1340 | ||
1341 | if (channel_list) { | |
1342 | kfree(channel_list); | |
1343 | } | |
1344 | ||
635d2b00 GKH |
1345 | return r; |
1346 | ||
1347 | } /* unifi_siwscan() */ | |
1348 | ||
1349 | ||
1350 | static const unsigned char * | |
1351 | unifi_find_info_element(int id, const unsigned char *info, int len) | |
1352 | { | |
1353 | const unsigned char *ie = info; | |
1354 | ||
1355 | while (len > 1) | |
1356 | { | |
1357 | int e_id, e_len; | |
1358 | e_id = ie[0]; | |
1359 | e_len = ie[1]; | |
1360 | ||
1361 | /* Return if we find a match */ | |
1362 | if (e_id == id) | |
1363 | { | |
1364 | return ie; | |
1365 | } | |
1366 | ||
1367 | len -= (e_len + 2); | |
1368 | ie += (e_len + 2); | |
1369 | } | |
1370 | ||
1371 | return NULL; | |
1372 | } /* unifi_find_info_element() */ | |
1373 | ||
1374 | ||
1375 | /* | |
1376 | * Translate scan data returned from the card to a card independent | |
1377 | * format that the Wireless Tools will understand - Jean II | |
1378 | */ | |
1379 | int | |
1380 | unifi_translate_scan(struct net_device *dev, | |
1381 | struct iw_request_info *info, | |
1382 | char *current_ev, char *end_buf, | |
1383 | CsrWifiSmeScanResult *scan_data, | |
1384 | int scan_index) | |
1385 | { | |
1386 | struct iw_event iwe; /* Temporary buffer */ | |
1387 | unsigned char *info_elems; | |
1388 | int info_elem_len; | |
1389 | const unsigned char *elem; | |
1390 | u16 capabilities; | |
1391 | int signal, noise, snr; | |
1392 | char *start_buf = current_ev; | |
1393 | char *current_val; /* For rates */ | |
1394 | int i, r; | |
1395 | ||
1396 | info_elems = scan_data->informationElements; | |
1397 | info_elem_len = scan_data->informationElementsLength; | |
1398 | ||
1399 | if (!scan_data->informationElementsLength || !scan_data->informationElements) { | |
1400 | unifi_error(NULL, "*** NULL SCAN IEs ***\n"); | |
1401 | return -EIO; | |
1402 | } | |
1403 | ||
1404 | /* get capinfo bits */ | |
1405 | capabilities = scan_data->capabilityInformation; | |
1406 | ||
1407 | unifi_trace(NULL, UDBG5, "Capabilities: 0x%x\n", capabilities); | |
1408 | ||
1409 | /* First entry *MUST* be the AP MAC address */ | |
1410 | memset(&iwe, 0, sizeof(iwe)); | |
1411 | iwe.cmd = SIOCGIWAP; | |
1412 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | |
1413 | memcpy(iwe.u.ap_addr.sa_data, scan_data->bssid.a, ETH_ALEN); | |
1414 | iwe.len = IW_EV_ADDR_LEN; | |
1415 | r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_ADDR_LEN); | |
1416 | if (r < 0) { | |
1417 | return r; | |
1418 | } | |
1419 | start_buf += r; | |
1420 | ||
1421 | /* Other entries will be displayed in the order we give them */ | |
1422 | ||
1423 | /* Add the ESSID */ | |
1424 | /* find SSID in Info Elems */ | |
1425 | elem = unifi_find_info_element(IE_SSID_ID, info_elems, info_elem_len); | |
1426 | if (elem) { | |
1427 | int e_len = elem[1]; | |
1428 | const unsigned char *e_ptr = elem + 2; | |
1429 | unsigned char buf[33]; | |
1430 | ||
1431 | memset(&iwe, 0, sizeof(iwe)); | |
1432 | iwe.cmd = SIOCGIWESSID; | |
1433 | iwe.u.essid.length = e_len; | |
1434 | if (iwe.u.essid.length > 32) { | |
1435 | iwe.u.essid.length = 32; | |
1436 | } | |
1437 | iwe.u.essid.flags = scan_index; | |
1438 | memcpy(buf, e_ptr, iwe.u.essid.length); | |
1439 | buf[iwe.u.essid.length] = '\0'; | |
1440 | r = uf_iwe_stream_add_point(info, start_buf, end_buf, &iwe, buf); | |
1441 | if (r < 0) { | |
1442 | return r; | |
1443 | } | |
1444 | start_buf += r; | |
1445 | ||
1446 | } | |
1447 | ||
1448 | /* Add mode */ | |
1449 | memset(&iwe, 0, sizeof(iwe)); | |
1450 | iwe.cmd = SIOCGIWMODE; | |
1451 | if (scan_data->bssType == CSR_WIFI_SME_BSS_TYPE_INFRASTRUCTURE) { | |
1452 | iwe.u.mode = IW_MODE_INFRA; | |
1453 | } else { | |
1454 | iwe.u.mode = IW_MODE_ADHOC; | |
1455 | } | |
1456 | iwe.len = IW_EV_UINT_LEN; | |
1457 | r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_UINT_LEN); | |
1458 | if (r < 0) { | |
1459 | return r; | |
1460 | } | |
1461 | start_buf += r; | |
1462 | ||
1463 | /* Add frequency. iwlist will convert to channel using table given in giwrange */ | |
1464 | memset(&iwe, 0, sizeof(iwe)); | |
1465 | iwe.cmd = SIOCGIWFREQ; | |
1466 | iwe.u.freq.m = scan_data->channelFrequency; | |
1467 | iwe.u.freq.e = 6; | |
1468 | r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_FREQ_LEN); | |
1469 | if (r < 0) { | |
1470 | return r; | |
1471 | } | |
1472 | start_buf += r; | |
1473 | ||
1474 | ||
1475 | /* Add quality statistics */ | |
1476 | iwe.cmd = IWEVQUAL; | |
1477 | /* | |
1478 | * level and noise below are mapped into an unsigned 8 bit number, | |
1479 | * ranging from [-192; 63]. The way this is achieved is simply to | |
1480 | * add 0x100 onto the number if it is negative, | |
1481 | * once clipped to the correct range. | |
1482 | */ | |
1483 | signal = scan_data->rssi; /* This value is in dBm */ | |
1484 | /* Clip range of snr */ | |
1485 | snr = (scan_data->snr > 0) ? scan_data->snr : 0; /* In dB relative, from 0 - 255 */ | |
1486 | snr = (snr < 255) ? snr : 255; | |
1487 | noise = signal - snr; | |
1488 | ||
1489 | /* Clip range of signal */ | |
1490 | signal = (signal < 63) ? signal : 63; | |
1491 | signal = (signal > -192) ? signal : -192; | |
1492 | ||
1493 | /* Clip range of noise */ | |
1494 | noise = (noise < 63) ? noise : 63; | |
1495 | noise = (noise > -192) ? noise : -192; | |
1496 | ||
1497 | /* Make u8 */ | |
1498 | signal = ( signal < 0 ) ? signal + 0x100 : signal; | |
1499 | noise = ( noise < 0 ) ? noise + 0x100 : noise; | |
1500 | ||
1501 | iwe.u.qual.level = (u8)signal; /* -192 : 63 */ | |
1502 | iwe.u.qual.noise = (u8)noise; /* -192 : 63 */ | |
1503 | iwe.u.qual.qual = snr; /* 0 : 255 */ | |
1504 | iwe.u.qual.updated = 0; | |
1505 | #if WIRELESS_EXT > 16 | |
1506 | iwe.u.qual.updated |= IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED | | |
1507 | IW_QUAL_QUAL_UPDATED; | |
1508 | #if WIRELESS_EXT > 18 | |
1509 | iwe.u.qual.updated |= IW_QUAL_DBM; | |
1510 | #endif | |
1511 | #endif | |
1512 | r = uf_iwe_stream_add_event(info, start_buf, end_buf, &iwe, IW_EV_QUAL_LEN); | |
1513 | if (r < 0) { | |
1514 | return r; | |
1515 | } | |
1516 | start_buf += r; | |
1517 | ||
1518 | /* Add encryption capability */ | |
1519 | iwe.cmd = SIOCGIWENCODE; | |
1520 | if (capabilities & SIG_CAP_PRIVACY) { | |
1521 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | |
1522 | } else { | |
1523 | iwe.u.data.flags = IW_ENCODE_DISABLED; | |
1524 | } | |
1525 | iwe.u.data.length = 0; | |
1526 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | |
1527 | r = uf_iwe_stream_add_point(info, start_buf, end_buf, &iwe, ""); | |
1528 | if (r < 0) { | |
1529 | return r; | |
1530 | } | |
1531 | start_buf += r; | |
1532 | ||
1533 | ||
1534 | /* | |
1535 | * Rate : stuffing multiple values in a single event require a bit | |
1536 | * more of magic - Jean II | |
1537 | */ | |
1538 | current_val = start_buf + IW_EV_LCP_LEN; | |
1539 | ||
1540 | iwe.cmd = SIOCGIWRATE; | |
1541 | /* Those two flags are ignored... */ | |
1542 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | |
1543 | ||
1544 | elem = unifi_find_info_element(IE_SUPPORTED_RATES_ID, | |
1545 | info_elems, info_elem_len); | |
1546 | if (elem) { | |
1547 | int e_len = elem[1]; | |
1548 | const unsigned char *e_ptr = elem + 2; | |
1549 | ||
1550 | /* | |
1551 | * Count how many rates we have. | |
1552 | * Zero marks the end of the list, if the list is not truncated. | |
1553 | */ | |
1554 | /* Max 8 values */ | |
1555 | for (i = 0; i < e_len; i++) { | |
1556 | if (e_ptr[i] == 0) { | |
1557 | break; | |
1558 | } | |
1559 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | |
1560 | iwe.u.bitrate.value = ((e_ptr[i] & 0x7f) * 500000); | |
1561 | /* Add new value to event */ | |
1562 | r = uf_iwe_stream_add_value(info, start_buf, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); | |
1563 | if (r < 0) { | |
1564 | return r; | |
1565 | } | |
1566 | current_val +=r; | |
1567 | ||
1568 | } | |
1569 | } | |
1570 | elem = unifi_find_info_element(IE_EXTENDED_SUPPORTED_RATES_ID, | |
1571 | info_elems, info_elem_len); | |
1572 | if (elem) { | |
1573 | int e_len = elem[1]; | |
1574 | const unsigned char *e_ptr = elem + 2; | |
1575 | ||
1576 | /* | |
1577 | * Count how many rates we have. | |
1578 | * Zero marks the end of the list, if the list is not truncated. | |
1579 | */ | |
1580 | /* Max 8 values */ | |
1581 | for (i = 0; i < e_len; i++) { | |
1582 | if (e_ptr[i] == 0) { | |
1583 | break; | |
1584 | } | |
1585 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | |
1586 | iwe.u.bitrate.value = ((e_ptr[i] & 0x7f) * 500000); | |
1587 | /* Add new value to event */ | |
1588 | r = uf_iwe_stream_add_value(info, start_buf, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); | |
1589 | if (r < 0) { | |
1590 | return r; | |
1591 | } | |
1592 | current_val +=r; | |
1593 | } | |
1594 | } | |
1595 | /* Check if we added any rates event */ | |
1596 | if ((current_val - start_buf) > IW_EV_LCP_LEN) { | |
1597 | start_buf = current_val; | |
1598 | } | |
1599 | ||
1600 | ||
1601 | #if WIRELESS_EXT > 17 | |
1602 | memset(&iwe, 0, sizeof(iwe)); | |
1603 | iwe.cmd = IWEVGENIE; | |
1604 | iwe.u.data.length = info_elem_len; | |
1605 | ||
1606 | r = uf_iwe_stream_add_point(info, start_buf, end_buf, &iwe, info_elems); | |
1607 | if (r < 0) { | |
1608 | return r; | |
1609 | } | |
1610 | ||
1611 | start_buf += r; | |
1612 | #endif /* WE > 17 */ | |
1613 | ||
1614 | return (start_buf - current_ev); | |
1615 | } /* unifi_translate_scan() */ | |
1616 | ||
1617 | ||
1618 | ||
1619 | static int | |
1620 | unifi_giwscan(struct net_device *dev, struct iw_request_info *info, | |
1621 | union iwreq_data *wrqu, char *extra) | |
1622 | { | |
1623 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1624 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1625 | struct iw_point *dwrq = &wrqu->data; | |
1626 | int r; | |
1627 | ||
1628 | CHECK_INITED(priv); | |
1629 | ||
1630 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
1631 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
1632 | unifi_error(priv, "unifi_giwscan: not permitted in Mode %d\n", | |
1633 | interfacePriv->interfaceMode); | |
1634 | return -EPERM; | |
1635 | } | |
1636 | ||
1637 | ||
1638 | unifi_trace(priv, UDBG1, | |
1639 | "unifi_giwscan: buffer (%d bytes) \n", | |
1640 | dwrq->length); | |
1641 | UF_RTNL_UNLOCK(); | |
1642 | r = sme_mgt_scan_results_get_async(priv, info, extra, dwrq->length); | |
1643 | UF_RTNL_LOCK(); | |
1644 | if (r < 0) { | |
1645 | unifi_trace(priv, UDBG1, | |
1646 | "unifi_giwscan: buffer (%d bytes) not big enough.\n", | |
1647 | dwrq->length); | |
1648 | return r; | |
1649 | } | |
1650 | ||
1651 | dwrq->length = r; | |
1652 | dwrq->flags = 0; | |
1653 | ||
1654 | return 0; | |
1655 | } /* unifi_giwscan() */ | |
1656 | ||
1657 | ||
1658 | /* | |
1659 | * --------------------------------------------------------------------------- | |
1660 | * unifi_siwessid | |
1661 | * | |
1662 | * Request to join a network or start and AdHoc. | |
1663 | * | |
1664 | * Arguments: | |
1665 | * dev Pointer to network device struct. | |
1666 | * info Pointer to broken-out ioctl request. | |
1667 | * data Pointer to argument data. | |
1668 | * essid Pointer to string giving name of network to join | |
1669 | * or start | |
1670 | * | |
1671 | * Returns: | |
1672 | * 0 on success and everything complete | |
1673 | * -EINPROGRESS to have the higher level call the commit method. | |
1674 | * --------------------------------------------------------------------------- | |
1675 | */ | |
1676 | static int | |
1677 | unifi_siwessid(struct net_device *dev, struct iw_request_info *info, | |
1678 | struct iw_point *data, char *essid) | |
1679 | { | |
1680 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1681 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1682 | int len; | |
1683 | int err = 0; | |
1684 | ||
635d2b00 GKH |
1685 | CHECK_INITED(priv); |
1686 | ||
1687 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
1688 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
1689 | unifi_error(priv, "unifi_siwessid: not permitted in Mode %d\n", | |
1690 | interfacePriv->interfaceMode); | |
1691 | return -EPERM; | |
1692 | } | |
1693 | ||
1694 | ||
1695 | len = 0; | |
1696 | if (data->flags & 1) { | |
1697 | /* Limit length */ | |
1698 | len = data->length; | |
1699 | if (len > UNIFI_MAX_SSID_LEN) { | |
1700 | len = UNIFI_MAX_SSID_LEN; | |
1701 | } | |
1702 | } | |
1703 | ||
1704 | #ifdef UNIFI_DEBUG | |
1705 | { | |
1706 | char essid_str[UNIFI_MAX_SSID_LEN+1]; | |
1707 | int i; | |
1708 | ||
1709 | for (i = 0; i < len; i++) { | |
1710 | essid_str[i] = (isprint(essid[i]) ? essid[i] : '?'); | |
1711 | } | |
1712 | essid_str[i] = '\0'; | |
1713 | ||
1714 | unifi_trace(priv, UDBG1, "unifi_siwessid: asked for '%*s' (%d)\n", len, essid_str, len); | |
1715 | unifi_trace(priv, UDBG2, " with authModeMask = %d", priv->connection_config.authModeMask); | |
1716 | } | |
1717 | #endif | |
1718 | ||
1719 | memset(priv->connection_config.bssid.a, 0xFF, ETH_ALEN); | |
1720 | if (len) { | |
1721 | if (essid[len - 1] == 0) { | |
1722 | len --; | |
1723 | } | |
1724 | ||
1725 | memcpy(priv->connection_config.ssid.ssid, essid, len); | |
1726 | priv->connection_config.ssid.length = len; | |
1727 | ||
1728 | } else { | |
1729 | priv->connection_config.ssid.length = 0; | |
1730 | } | |
1731 | ||
1732 | UF_RTNL_UNLOCK(); | |
1733 | err = sme_mgt_connect(priv); | |
1734 | UF_RTNL_LOCK(); | |
1735 | if (err) { | |
1736 | unifi_error(priv, "unifi_siwessid: Join failed, status %d\n", err); | |
635d2b00 GKH |
1737 | return convert_sme_error(err); |
1738 | } | |
1739 | ||
635d2b00 GKH |
1740 | return 0; |
1741 | } /* unifi_siwessid() */ | |
1742 | ||
1743 | ||
1744 | static int | |
1745 | unifi_giwessid(struct net_device *dev, struct iw_request_info *info, | |
1746 | union iwreq_data *wrqu, char *essid) | |
1747 | { | |
1748 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1749 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1750 | struct iw_point *data = &wrqu->essid; | |
1751 | CsrWifiSmeConnectionInfo connectionInfo; | |
1752 | int r = 0; | |
1753 | ||
635d2b00 GKH |
1754 | unifi_trace(priv, UDBG2, "unifi_giwessid\n"); |
1755 | CHECK_INITED(priv); | |
1756 | ||
1757 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
1758 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
1759 | unifi_error(priv, "unifi_giwessid: not permitted in Mode %d\n", | |
1760 | interfacePriv->interfaceMode); | |
1761 | return -EPERM; | |
1762 | } | |
1763 | ||
1764 | UF_RTNL_UNLOCK(); | |
1765 | r = sme_mgt_connection_info_get(priv, &connectionInfo); | |
1766 | UF_RTNL_LOCK(); | |
1767 | ||
1768 | if (r == 0) { | |
1769 | data->length = connectionInfo.ssid.length; | |
1770 | strncpy(essid, | |
1771 | connectionInfo.ssid.ssid, | |
1772 | data->length); | |
1773 | data->flags = 1; /* active */ | |
1774 | ||
1775 | unifi_trace(priv, UDBG2, "unifi_giwessid: %.*s\n", | |
1776 | data->length, essid); | |
1777 | } | |
1778 | ||
635d2b00 GKH |
1779 | |
1780 | return 0; | |
1781 | } /* unifi_giwessid() */ | |
1782 | ||
1783 | ||
1784 | static int | |
1785 | unifi_siwrate(struct net_device *dev, struct iw_request_info *info, | |
1786 | union iwreq_data *wrqu, char *extra) | |
1787 | { | |
1788 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1789 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1790 | struct iw_param *args = &wrqu->bitrate; | |
1791 | CsrWifiSmeMibConfig mibConfig; | |
1792 | int r; | |
1793 | ||
635d2b00 GKH |
1794 | CHECK_INITED(priv); |
1795 | unifi_trace(priv, UDBG2, "unifi_siwrate\n"); | |
1796 | ||
1797 | /* | |
1798 | * If args->fixed == 0, value is max rate or -1 for best | |
1799 | * If args->fixed == 1, value is rate to set or -1 for best | |
1800 | * args->disabled and args->flags are not used in SIOCSIWRATE | |
1801 | */ | |
1802 | ||
1803 | /* Get, modify and set the MIB data */ | |
1804 | UF_RTNL_UNLOCK(); | |
1805 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
1806 | UF_RTNL_LOCK(); | |
1807 | if (r) { | |
1808 | unifi_error(priv, "unifi_siwrate: Get CsrWifiSmeMibConfigValue failed.\n"); | |
1809 | return r; | |
1810 | } | |
1811 | ||
1812 | /* Default to auto rate algorithm */ | |
1813 | /* in 500Kbit/s, 0 means auto */ | |
1814 | mibConfig.unifiFixTxDataRate = 0; | |
1815 | ||
1816 | if (args->value != -1) { | |
1817 | mibConfig.unifiFixTxDataRate = args->value / 500000; | |
1818 | } | |
1819 | ||
1820 | /* 1 means rate is a maximum, 2 means rate is a set value */ | |
1821 | if (args->fixed == 1) { | |
1822 | mibConfig.unifiFixMaxTxDataRate = 0; | |
1823 | } else { | |
1824 | mibConfig.unifiFixMaxTxDataRate = 1; | |
1825 | } | |
1826 | UF_RTNL_UNLOCK(); | |
1827 | r = sme_mgt_mib_config_set(priv, &mibConfig); | |
1828 | UF_RTNL_LOCK(); | |
1829 | if (r) { | |
1830 | unifi_error(priv, "unifi_siwrate: Set CsrWifiSmeMibConfigValue failed.\n"); | |
1831 | return r; | |
1832 | } | |
1833 | ||
635d2b00 GKH |
1834 | |
1835 | return 0; | |
1836 | } /* unifi_siwrate() */ | |
1837 | ||
1838 | ||
1839 | ||
1840 | static int | |
1841 | unifi_giwrate(struct net_device *dev, struct iw_request_info *info, | |
1842 | union iwreq_data *wrqu, char *extra) | |
1843 | { | |
1844 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1845 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1846 | struct iw_param *args = &wrqu->bitrate; | |
1847 | int r; | |
1848 | int bitrate, flag; | |
1849 | CsrWifiSmeMibConfig mibConfig; | |
1850 | CsrWifiSmeConnectionStats connectionStats; | |
1851 | ||
635d2b00 GKH |
1852 | unifi_trace(priv, UDBG2, "unifi_giwrate\n"); |
1853 | CHECK_INITED(priv); | |
1854 | ||
1855 | flag = 0; | |
1856 | bitrate = 0; | |
1857 | UF_RTNL_UNLOCK(); | |
1858 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
1859 | UF_RTNL_LOCK(); | |
1860 | if (r) { | |
1861 | unifi_error(priv, "unifi_giwrate: Get CsrWifiSmeMibConfigValue failed.\n"); | |
1862 | return r; | |
1863 | } | |
1864 | ||
1865 | bitrate = mibConfig.unifiFixTxDataRate; | |
1866 | flag = mibConfig.unifiFixMaxTxDataRate; | |
1867 | ||
1868 | /* Used the value returned by the SME if MIB returns 0 */ | |
1869 | if (bitrate == 0) { | |
1870 | UF_RTNL_UNLOCK(); | |
1871 | r = sme_mgt_connection_stats_get(priv, &connectionStats); | |
1872 | UF_RTNL_LOCK(); | |
1873 | /* Ignore errors, we may be disconnected */ | |
1874 | if (r == 0) { | |
1875 | bitrate = connectionStats.unifiTxDataRate; | |
1876 | } | |
1877 | } | |
1878 | ||
1879 | args->value = bitrate * 500000; | |
1880 | args->fixed = !flag; | |
1881 | ||
635d2b00 GKH |
1882 | return 0; |
1883 | } /* unifi_giwrate() */ | |
1884 | ||
1885 | ||
1886 | static int | |
1887 | unifi_siwrts(struct net_device *dev, struct iw_request_info *info, | |
1888 | union iwreq_data *wrqu, char *extra) | |
1889 | { | |
1890 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1891 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1892 | int val = wrqu->rts.value; | |
1893 | int r = 0; | |
1894 | CsrWifiSmeMibConfig mibConfig; | |
1895 | ||
1896 | unifi_trace(priv, UDBG2, "unifi_siwrts\n"); | |
1897 | CHECK_INITED(priv); | |
1898 | ||
1899 | if (wrqu->rts.disabled) { | |
1900 | val = 2347; | |
1901 | } | |
1902 | ||
1903 | if ( (val < 0) || (val > 2347) ) | |
1904 | { | |
1905 | return -EINVAL; | |
1906 | } | |
1907 | ||
1908 | /* Get, modify and set the MIB data */ | |
1909 | UF_RTNL_UNLOCK(); | |
1910 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
1911 | UF_RTNL_LOCK(); | |
1912 | if (r) { | |
1913 | unifi_error(priv, "unifi_siwrts: Get CsrWifiSmeMibConfigValue failed.\n"); | |
1914 | return r; | |
1915 | } | |
1916 | mibConfig.dot11RtsThreshold = val; | |
1917 | UF_RTNL_UNLOCK(); | |
1918 | r = sme_mgt_mib_config_set(priv, &mibConfig); | |
1919 | UF_RTNL_LOCK(); | |
1920 | if (r) { | |
1921 | unifi_error(priv, "unifi_siwrts: Set CsrWifiSmeMibConfigValue failed.\n"); | |
1922 | return r; | |
1923 | } | |
1924 | ||
1925 | return 0; | |
1926 | } | |
1927 | ||
1928 | ||
1929 | static int | |
1930 | unifi_giwrts(struct net_device *dev, struct iw_request_info *info, | |
1931 | union iwreq_data *wrqu, char *extra) | |
1932 | { | |
1933 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1934 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1935 | int r; | |
1936 | int rts_thresh; | |
1937 | CsrWifiSmeMibConfig mibConfig; | |
1938 | ||
1939 | unifi_trace(priv, UDBG2, "unifi_giwrts\n"); | |
1940 | CHECK_INITED(priv); | |
1941 | ||
1942 | UF_RTNL_UNLOCK(); | |
1943 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
1944 | UF_RTNL_LOCK(); | |
1945 | if (r) { | |
1946 | unifi_error(priv, "unifi_giwrts: Get CsrWifiSmeMibConfigValue failed.\n"); | |
1947 | return r; | |
1948 | } | |
1949 | ||
1950 | rts_thresh = mibConfig.dot11RtsThreshold; | |
1951 | if (rts_thresh > 2347) { | |
1952 | rts_thresh = 2347; | |
1953 | } | |
1954 | ||
1955 | wrqu->rts.value = rts_thresh; | |
1956 | wrqu->rts.disabled = (rts_thresh == 2347); | |
1957 | wrqu->rts.fixed = 1; | |
1958 | ||
1959 | return 0; | |
1960 | } | |
1961 | ||
1962 | ||
1963 | static int | |
1964 | unifi_siwfrag(struct net_device *dev, struct iw_request_info *info, | |
1965 | union iwreq_data *wrqu, char *extra) | |
1966 | { | |
1967 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
1968 | unifi_priv_t *priv = interfacePriv->privPtr; | |
1969 | int val = wrqu->frag.value; | |
1970 | int r = 0; | |
1971 | CsrWifiSmeMibConfig mibConfig; | |
1972 | ||
1973 | unifi_trace(priv, UDBG2, "unifi_siwfrag\n"); | |
1974 | CHECK_INITED(priv); | |
1975 | ||
1976 | if (wrqu->frag.disabled) | |
1977 | val = 2346; | |
1978 | ||
1979 | if ( (val < 256) || (val > 2347) ) | |
1980 | return -EINVAL; | |
1981 | ||
1982 | /* Get, modify and set the MIB data */ | |
1983 | UF_RTNL_UNLOCK(); | |
1984 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
1985 | UF_RTNL_LOCK(); | |
1986 | if (r) { | |
1987 | unifi_error(priv, "unifi_siwfrag: Get CsrWifiSmeMibConfigValue failed.\n"); | |
1988 | return r; | |
1989 | } | |
1990 | /* Fragmentation Threashold must be even */ | |
1991 | mibConfig.dot11FragmentationThreshold = (val & ~0x1); | |
1992 | UF_RTNL_UNLOCK(); | |
1993 | r = sme_mgt_mib_config_set(priv, &mibConfig); | |
1994 | UF_RTNL_LOCK(); | |
1995 | if (r) { | |
1996 | unifi_error(priv, "unifi_siwfrag: Set CsrWifiSmeMibConfigValue failed.\n"); | |
1997 | return r; | |
1998 | } | |
1999 | ||
2000 | return 0; | |
2001 | } | |
2002 | ||
2003 | ||
2004 | static int | |
2005 | unifi_giwfrag(struct net_device *dev, struct iw_request_info *info, | |
2006 | union iwreq_data *wrqu, char *extra) | |
2007 | { | |
2008 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2009 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2010 | int r; | |
2011 | int frag_thresh; | |
2012 | CsrWifiSmeMibConfig mibConfig; | |
2013 | ||
2014 | unifi_trace(priv, UDBG2, "unifi_giwfrag\n"); | |
2015 | CHECK_INITED(priv); | |
2016 | ||
2017 | UF_RTNL_UNLOCK(); | |
2018 | r = sme_mgt_mib_config_get(priv, &mibConfig); | |
2019 | UF_RTNL_LOCK(); | |
2020 | if (r) { | |
2021 | unifi_error(priv, "unifi_giwfrag: Get CsrWifiSmeMibConfigValue failed.\n"); | |
2022 | return r; | |
2023 | } | |
2024 | ||
2025 | frag_thresh = mibConfig.dot11FragmentationThreshold; | |
2026 | ||
2027 | /* Build the return structure */ | |
2028 | wrqu->frag.value = frag_thresh; | |
2029 | wrqu->frag.disabled = (frag_thresh >= 2346); | |
2030 | wrqu->frag.fixed = 1; | |
2031 | ||
2032 | return 0; | |
2033 | } | |
2034 | ||
2035 | ||
2036 | static int | |
2037 | unifi_siwencode(struct net_device *dev, struct iw_request_info *info, | |
2038 | union iwreq_data *wrqu, char *extra) | |
2039 | { | |
2040 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2041 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2042 | struct iw_point *erq = &wrqu->encoding; | |
2043 | int index; | |
2044 | int rc = 0; | |
2045 | int privacy = -1; | |
2046 | CsrWifiSmeKey sme_key; | |
2047 | ||
635d2b00 GKH |
2048 | unifi_trace(priv, UDBG2, "unifi_siwencode\n"); |
2049 | ||
2050 | CHECK_INITED(priv); | |
2051 | ||
2052 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2053 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2054 | unifi_error(priv, "unifi_siwencode: not permitted in Mode %d\n", | |
2055 | interfacePriv->interfaceMode); | |
2056 | return -EPERM; | |
2057 | } | |
2058 | ||
2059 | ||
2060 | /* | |
2061 | * Key index is encoded in the flags. | |
2062 | * 0 - use current default, | |
2063 | * 1-4 - if a key value is given set that key | |
2064 | * if not use that key | |
2065 | */ | |
2066 | index = (erq->flags & IW_ENCODE_INDEX); /* key number, 1-4 */ | |
2067 | if ((index < 0) || (index > 4)) { | |
2068 | unifi_error(priv, "unifi_siwencode: Request to set an invalid key (index:%d)", index); | |
2069 | return -EINVAL; | |
2070 | } | |
2071 | ||
2072 | /* | |
2073 | * Basic checking: do we have a key to set ? | |
2074 | * The IW_ENCODE_NOKEY flag is set when no key is present (only change flags), | |
2075 | * but older versions rely on sending a key id 1-4. | |
2076 | */ | |
2077 | if (erq->length > 0) { | |
2078 | ||
2079 | /* Check the size of the key */ | |
2080 | if ((erq->length > LARGE_KEY_SIZE) || (erq->length < SMALL_KEY_SIZE)) { | |
2081 | unifi_error(priv, "unifi_siwencode: Request to set an invalid key (length:%d)", | |
2082 | erq->length); | |
2083 | return -EINVAL; | |
2084 | } | |
2085 | ||
2086 | /* Check the index (none (i.e. 0) means use current) */ | |
2087 | if ((index < 1) || (index > 4)) { | |
2088 | /* If we do not have a previous key, use 1 as default */ | |
2089 | if (!priv->wep_tx_key_index) { | |
2090 | priv->wep_tx_key_index = 1; | |
2091 | } | |
2092 | index = priv->wep_tx_key_index; | |
2093 | } | |
2094 | ||
2095 | /* If we didn't have a key and a valid index is set, we want to remember it*/ | |
2096 | if (!priv->wep_tx_key_index) { | |
2097 | priv->wep_tx_key_index = index; | |
2098 | } | |
2099 | ||
2100 | unifi_trace(priv, UDBG1, "Tx key Index is %d\n", priv->wep_tx_key_index); | |
2101 | ||
2102 | privacy = 1; | |
2103 | ||
2104 | /* Check if the key is not marked as invalid */ | |
2105 | if ((erq->flags & IW_ENCODE_NOKEY) == 0) { | |
2106 | ||
2107 | unifi_trace(priv, UDBG1, "New %s key (len=%d, index=%d)\n", | |
2108 | (priv->wep_tx_key_index == index) ? "tx" : "", | |
2109 | erq->length, index); | |
2110 | ||
2111 | sme_key.wepTxKey = (priv->wep_tx_key_index == index); | |
2112 | if (priv->wep_tx_key_index == index) { | |
2113 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE; | |
2114 | } else { | |
2115 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP; | |
2116 | } | |
2117 | /* Key index is zero based in SME but 1 based in wext */ | |
2118 | sme_key.keyIndex = (index - 1); | |
2119 | sme_key.keyLength = erq->length; | |
2120 | sme_key.authenticator = 0; | |
2121 | memset(sme_key.address.a, 0xFF, ETH_ALEN); | |
2122 | memcpy(sme_key.key, extra, erq->length); | |
2123 | ||
2124 | UF_RTNL_UNLOCK(); | |
2125 | rc = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD); | |
2126 | UF_RTNL_LOCK(); | |
2127 | if (rc) { | |
2128 | unifi_error(priv, "unifi_siwencode: Set key failed (%d)", rc); | |
2129 | return convert_sme_error(rc); | |
2130 | } | |
2131 | ||
2132 | /* Store the key to be reported by the SIOCGIWENCODE handler */ | |
2133 | priv->wep_keys[index - 1].len = erq->length; | |
2134 | memcpy(priv->wep_keys[index - 1].key, extra, erq->length); | |
2135 | } | |
2136 | } else { | |
2137 | /* | |
2138 | * No additional key data, so it must be a request to change the | |
2139 | * active key. | |
2140 | */ | |
2141 | if (index != 0) { | |
2142 | unifi_trace(priv, UDBG1, "Tx key Index is %d\n", index - 1); | |
2143 | ||
2144 | /* Store the index to be reported by the SIOCGIWENCODE handler */ | |
2145 | priv->wep_tx_key_index = index; | |
2146 | ||
2147 | sme_key.wepTxKey = 1; | |
2148 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE; | |
2149 | ||
2150 | /* Key index is zero based in SME but 1 based in wext */ | |
2151 | sme_key.keyIndex = (index - 1); | |
2152 | sme_key.keyLength = 0; | |
2153 | sme_key.authenticator = 0; | |
2154 | UF_RTNL_UNLOCK(); | |
2155 | rc = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD); | |
2156 | UF_RTNL_LOCK(); | |
2157 | if (rc) { | |
2158 | unifi_error(priv, "unifi_siwencode: Set key failed (%d)", rc); | |
2159 | return convert_sme_error(rc); | |
2160 | } | |
2161 | ||
2162 | /* Turn on encryption */ | |
2163 | privacy = 1; | |
2164 | } | |
2165 | } | |
2166 | ||
2167 | /* Read the flags */ | |
2168 | if (erq->flags & IW_ENCODE_DISABLED) { | |
2169 | /* disable encryption */ | |
2170 | unifi_trace(priv, UDBG1, "disable WEP encryption\n"); | |
2171 | privacy = 0; | |
2172 | ||
2173 | priv->wep_tx_key_index = 0; | |
2174 | ||
2175 | unifi_trace(priv, UDBG1, "IW_ENCODE_DISABLED: CSR_WIFI_SME_AUTH_MODE_80211_OPEN\n"); | |
2176 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
2177 | } | |
2178 | ||
2179 | if (erq->flags & IW_ENCODE_RESTRICTED) { | |
2180 | /* Use shared key auth */ | |
2181 | unifi_trace(priv, UDBG1, "IW_ENCODE_RESTRICTED: CSR_WIFI_SME_AUTH_MODE_80211_SHARED\n"); | |
2182 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_SHARED; | |
2183 | ||
2184 | /* Turn on encryption */ | |
2185 | privacy = 1; | |
2186 | } | |
2187 | if (erq->flags & IW_ENCODE_OPEN) { | |
2188 | unifi_trace(priv, UDBG1, "IW_ENCODE_OPEN: CSR_WIFI_SME_AUTH_MODE_80211_OPEN\n"); | |
2189 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
2190 | } | |
2191 | ||
2192 | /* Commit the changes to flags if needed */ | |
2193 | if (privacy != -1) { | |
2194 | priv->connection_config.privacyMode = privacy ? CSR_WIFI_SME_80211_PRIVACY_MODE_ENABLED : CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED; | |
2195 | priv->connection_config.encryptionModeMask = privacy ? (CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP40 | | |
2196 | CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP104 | | |
2197 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40 | | |
2198 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104) : | |
2199 | CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE; | |
2200 | } | |
2201 | ||
635d2b00 GKH |
2202 | return convert_sme_error(rc); |
2203 | ||
2204 | } /* unifi_siwencode() */ | |
2205 | ||
2206 | ||
2207 | ||
2208 | static int | |
2209 | unifi_giwencode(struct net_device *dev, struct iw_request_info *info, | |
2210 | union iwreq_data *wrqu, char *extra) | |
2211 | { | |
2212 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2213 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2214 | struct iw_point *erq = &wrqu->encoding; | |
2215 | ||
2216 | unifi_trace(priv, UDBG2, "unifi_giwencode\n"); | |
2217 | ||
2218 | CHECK_INITED(priv); | |
2219 | ||
2220 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2221 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2222 | unifi_error(priv, "unifi_giwencode: not permitted in Mode %d\n", | |
2223 | interfacePriv->interfaceMode); | |
2224 | return -EPERM; | |
2225 | } | |
2226 | ||
2227 | ||
2228 | if (priv->connection_config.authModeMask == CSR_WIFI_SME_AUTH_MODE_80211_SHARED) { | |
2229 | erq->flags = IW_ENCODE_RESTRICTED; | |
2230 | } | |
2231 | else { | |
2232 | if (priv->connection_config.privacyMode == CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED) { | |
2233 | erq->flags = IW_ENCODE_DISABLED; | |
2234 | } else { | |
2235 | erq->flags = IW_ENCODE_OPEN; | |
2236 | } | |
2237 | } | |
2238 | ||
2239 | erq->length = 0; | |
2240 | ||
2241 | if (erq->flags != IW_ENCODE_DISABLED) { | |
2242 | int index = priv->wep_tx_key_index; | |
2243 | ||
2244 | if ((index > 0) && (index <= NUM_WEPKEYS)) { | |
2245 | erq->flags |= (index & IW_ENCODE_INDEX); | |
2246 | erq->length = priv->wep_keys[index - 1].len; | |
2247 | memcpy(extra, priv->wep_keys[index - 1].key, erq->length); | |
2248 | } else { | |
2249 | unifi_notice(priv, "unifi_giwencode: Surprise, do not have a valid key index (%d)\n", | |
2250 | index); | |
2251 | } | |
2252 | } | |
2253 | ||
2254 | return 0; | |
2255 | } /* unifi_giwencode() */ | |
2256 | ||
2257 | ||
2258 | static int | |
2259 | unifi_siwpower(struct net_device *dev, struct iw_request_info *info, | |
2260 | union iwreq_data *wrqu, char *extra) | |
2261 | { | |
2262 | struct iw_param *args = &wrqu->power; | |
2263 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2264 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2265 | int listen_interval, wake_for_dtim; | |
2266 | int r = 0; | |
2267 | CsrWifiSmePowerConfig powerConfig; | |
2268 | ||
2269 | unifi_trace(priv, UDBG2, "unifi_siwpower\n"); | |
2270 | ||
2271 | CHECK_INITED(priv); | |
2272 | ||
2273 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2274 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2275 | unifi_error(priv, "unifi_siwpower: not permitted in Mode %d\n", | |
2276 | interfacePriv->interfaceMode); | |
2277 | return -EPERM; | |
2278 | } | |
2279 | ||
2280 | UF_RTNL_UNLOCK(); | |
2281 | r = sme_mgt_power_config_get(priv, &powerConfig); | |
2282 | UF_RTNL_LOCK(); | |
2283 | if (r) { | |
2284 | unifi_error(priv, "unifi_siwpower: Get unifi_PowerConfigValue failed.\n"); | |
2285 | return r; | |
2286 | } | |
2287 | ||
2288 | listen_interval = -1; | |
2289 | wake_for_dtim = -1; | |
2290 | if (args->disabled) { | |
2291 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW; | |
2292 | } | |
2293 | else | |
2294 | { | |
2295 | powerConfig.powerSaveLevel = CSR_WIFI_SME_POWER_SAVE_LEVEL_HIGH; | |
2296 | ||
2297 | switch (args->flags & IW_POWER_TYPE) { | |
2298 | case 0: | |
2299 | /* not specified */ | |
2300 | break; | |
2301 | case IW_POWER_PERIOD: | |
2302 | listen_interval = args->value / 1000; | |
2303 | break; | |
2304 | default: | |
2305 | return -EINVAL; | |
2306 | } | |
2307 | ||
2308 | switch (args->flags & IW_POWER_MODE) { | |
2309 | case 0: | |
2310 | /* not specified */ | |
2311 | break; | |
2312 | case IW_POWER_UNICAST_R: | |
2313 | /* not interested in broadcast packets */ | |
2314 | wake_for_dtim = 0; | |
2315 | break; | |
2316 | case IW_POWER_ALL_R: | |
2317 | /* yes, we are interested in broadcast packets */ | |
2318 | wake_for_dtim = 1; | |
2319 | break; | |
2320 | default: | |
2321 | return -EINVAL; | |
2322 | } | |
2323 | } | |
2324 | ||
2325 | if (listen_interval > 0) { | |
2326 | powerConfig.listenIntervalTu = listen_interval; | |
2327 | unifi_trace(priv, UDBG4, "unifi_siwpower: new Listen Interval = %d.\n", | |
2328 | powerConfig.listenIntervalTu); | |
2329 | } | |
2330 | ||
2331 | if (wake_for_dtim >= 0) { | |
2332 | powerConfig.rxDtims = wake_for_dtim; | |
2333 | } | |
2334 | UF_RTNL_UNLOCK(); | |
2335 | r = sme_mgt_power_config_set(priv, &powerConfig); | |
2336 | UF_RTNL_LOCK(); | |
2337 | if (r) { | |
2338 | unifi_error(priv, "unifi_siwpower: Set unifi_PowerConfigValue failed.\n"); | |
2339 | return r; | |
2340 | } | |
2341 | ||
2342 | return 0; | |
2343 | } /* unifi_siwpower() */ | |
2344 | ||
2345 | ||
2346 | static int | |
2347 | unifi_giwpower(struct net_device *dev, struct iw_request_info *info, | |
2348 | union iwreq_data *wrqu, char *extra) | |
2349 | { | |
2350 | struct iw_param *args = &wrqu->power; | |
2351 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2352 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2353 | CsrWifiSmePowerConfig powerConfig; | |
2354 | int r; | |
2355 | ||
2356 | unifi_trace(priv, UDBG2, "unifi_giwpower\n"); | |
2357 | ||
2358 | CHECK_INITED(priv); | |
2359 | ||
2360 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2361 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2362 | unifi_error(priv, "unifi_giwpower: not permitted in Mode %d\n", | |
2363 | interfacePriv->interfaceMode); | |
2364 | return -EPERM; | |
2365 | } | |
2366 | ||
2367 | ||
2368 | args->flags = 0; | |
2369 | UF_RTNL_UNLOCK(); | |
2370 | r = sme_mgt_power_config_get(priv, &powerConfig); | |
2371 | UF_RTNL_LOCK(); | |
2372 | if (r) { | |
2373 | unifi_error(priv, "unifi_giwpower: Get unifi_PowerConfigValue failed.\n"); | |
2374 | return r; | |
2375 | } | |
2376 | ||
2377 | unifi_trace(priv, UDBG4, "unifi_giwpower: mode=%d\n", | |
2378 | powerConfig.powerSaveLevel); | |
2379 | ||
2380 | args->disabled = (powerConfig.powerSaveLevel == CSR_WIFI_SME_POWER_SAVE_LEVEL_LOW); | |
2381 | if (args->disabled) { | |
2382 | args->flags = 0; | |
2383 | return 0; | |
2384 | } | |
2385 | ||
2386 | args->value = powerConfig.listenIntervalTu * 1000; | |
2387 | args->flags |= IW_POWER_PERIOD; | |
2388 | ||
2389 | if (powerConfig.rxDtims) { | |
2390 | args->flags |= IW_POWER_ALL_R; | |
2391 | } else { | |
2392 | args->flags |= IW_POWER_UNICAST_R; | |
2393 | } | |
2394 | ||
2395 | return 0; | |
2396 | } /* unifi_giwpower() */ | |
2397 | ||
2398 | ||
2399 | /* | |
2400 | * --------------------------------------------------------------------------- | |
2401 | * unifi_siwcommit - handler for SIOCSIWCOMMIT | |
2402 | * | |
2403 | * Apply all the parameters that have been set. | |
2404 | * In practice this means: | |
2405 | * - do a scan | |
2406 | * - join a network or start an AdHoc | |
2407 | * - authenticate and associate. | |
2408 | * | |
2409 | * Arguments: | |
2410 | * None. | |
2411 | * | |
2412 | * Returns: | |
2413 | * None. | |
2414 | * --------------------------------------------------------------------------- | |
2415 | */ | |
2416 | static int | |
2417 | unifi_siwcommit(struct net_device *dev, struct iw_request_info *info, | |
2418 | union iwreq_data *wrqu, char *extra) | |
2419 | { | |
2420 | return 0; | |
2421 | } /* unifi_siwcommit() */ | |
2422 | ||
2423 | ||
2424 | ||
2425 | static int | |
2426 | unifi_siwmlme(struct net_device *dev, struct iw_request_info *info, | |
2427 | union iwreq_data *wrqu, char *extra) | |
2428 | { | |
2429 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2430 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2431 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | |
635d2b00 GKH |
2432 | |
2433 | unifi_trace(priv, UDBG2, "unifi_siwmlme\n"); | |
2434 | CHECK_INITED(priv); | |
2435 | ||
2436 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2437 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2438 | unifi_error(priv, "unifi_siwmlme: not permitted in Mode %d\n", | |
2439 | interfacePriv->interfaceMode); | |
2440 | return -EPERM; | |
2441 | } | |
2442 | ||
2443 | ||
2444 | switch (mlme->cmd) { | |
2445 | case IW_MLME_DEAUTH: | |
2446 | case IW_MLME_DISASSOC: | |
2447 | UF_RTNL_UNLOCK(); | |
2448 | sme_mgt_disconnect(priv); | |
2449 | UF_RTNL_LOCK(); | |
2450 | break; | |
2451 | default: | |
635d2b00 GKH |
2452 | return -EOPNOTSUPP; |
2453 | } | |
2454 | ||
635d2b00 GKH |
2455 | return 0; |
2456 | } /* unifi_siwmlme() */ | |
2457 | ||
2458 | ||
2459 | /* | |
2460 | * --------------------------------------------------------------------------- | |
2461 | * unifi_siwgenie | |
2462 | * unifi_giwgenie | |
2463 | * | |
2464 | * WPA : Generic IEEE 802.11 information element (e.g., for WPA/RSN/WMM). | |
2465 | * Handlers for SIOCSIWGENIE, SIOCGIWGENIE - set/get generic IE | |
2466 | * | |
2467 | * The host program (e.g. wpa_supplicant) uses this call to set the | |
2468 | * additional IEs to accompany the next (Associate?) request. | |
2469 | * | |
2470 | * Arguments: | |
2471 | * None. | |
2472 | * | |
2473 | * Returns: | |
2474 | * None. | |
2475 | * Notes: | |
2476 | * From wireless.h: | |
2477 | * This ioctl uses struct iw_point and data buffer that includes IE id | |
2478 | * and len fields. More than one IE may be included in the | |
2479 | * request. Setting the generic IE to empty buffer (len=0) removes the | |
2480 | * generic IE from the driver. | |
2481 | * --------------------------------------------------------------------------- | |
2482 | */ | |
2483 | static int | |
2484 | unifi_siwgenie(struct net_device *dev, struct iw_request_info *info, | |
2485 | union iwreq_data *wrqu, char *extra) | |
2486 | { | |
2487 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2488 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2489 | int len; | |
2490 | ||
635d2b00 GKH |
2491 | unifi_trace(priv, UDBG2, "unifi_siwgenie\n"); |
2492 | ||
2493 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2494 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2495 | unifi_error(priv, "unifi_siwgenie: not permitted in Mode %d\n", | |
2496 | interfacePriv->interfaceMode); | |
2497 | return -EPERM; | |
2498 | } | |
2499 | ||
2500 | ||
2501 | if ( priv->connection_config.mlmeAssociateReqInformationElements) { | |
2502 | kfree( priv->connection_config.mlmeAssociateReqInformationElements); | |
2503 | } | |
2504 | priv->connection_config.mlmeAssociateReqInformationElementsLength = 0; | |
2505 | priv->connection_config.mlmeAssociateReqInformationElements = NULL; | |
2506 | ||
2507 | len = wrqu->data.length; | |
2508 | if (len == 0) { | |
635d2b00 GKH |
2509 | return 0; |
2510 | } | |
2511 | ||
2512 | priv->connection_config.mlmeAssociateReqInformationElements = kmalloc(len, GFP_KERNEL); | |
2513 | if (priv->connection_config.mlmeAssociateReqInformationElements == NULL) { | |
635d2b00 GKH |
2514 | return -ENOMEM; |
2515 | } | |
2516 | ||
2517 | priv->connection_config.mlmeAssociateReqInformationElementsLength = len; | |
2518 | memcpy( priv->connection_config.mlmeAssociateReqInformationElements, extra, len); | |
2519 | ||
635d2b00 GKH |
2520 | return 0; |
2521 | } /* unifi_siwgenie() */ | |
2522 | ||
2523 | ||
2524 | static int | |
2525 | unifi_giwgenie(struct net_device *dev, struct iw_request_info *info, | |
2526 | union iwreq_data *wrqu, char *extra) | |
2527 | { | |
2528 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2529 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2530 | int len; | |
2531 | ||
635d2b00 GKH |
2532 | unifi_trace(priv, UDBG2, "unifi_giwgenie\n"); |
2533 | ||
2534 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2535 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2536 | unifi_error(priv, "unifi_giwgenie: not permitted in Mode %d\n", | |
2537 | interfacePriv->interfaceMode); | |
2538 | return -EPERM; | |
2539 | } | |
2540 | ||
2541 | ||
2542 | len = priv->connection_config.mlmeAssociateReqInformationElementsLength; | |
2543 | ||
2544 | if (len == 0) { | |
2545 | wrqu->data.length = 0; | |
2546 | return 0; | |
2547 | } | |
2548 | ||
2549 | if (wrqu->data.length < len) { | |
2550 | return -E2BIG; | |
2551 | } | |
2552 | ||
2553 | wrqu->data.length = len; | |
2554 | memcpy(extra, priv->connection_config.mlmeAssociateReqInformationElements, len); | |
2555 | ||
635d2b00 GKH |
2556 | return 0; |
2557 | } /* unifi_giwgenie() */ | |
2558 | ||
2559 | ||
2560 | /* | |
2561 | * --------------------------------------------------------------------------- | |
2562 | * unifi_siwauth | |
2563 | * unifi_giwauth | |
2564 | * | |
2565 | * Handlers for SIOCSIWAUTH, SIOCGIWAUTH | |
2566 | * Set/get various authentication parameters. | |
2567 | * | |
2568 | * Arguments: | |
2569 | * | |
2570 | * | |
2571 | * Returns: | |
2572 | * None. | |
2573 | * --------------------------------------------------------------------------- | |
2574 | */ | |
2575 | static int | |
2576 | _unifi_siwauth(struct net_device *dev, struct iw_request_info *info, | |
2577 | union iwreq_data *wrqu, char *extra) | |
2578 | { | |
2579 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2580 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2581 | CsrWifiSmeAuthModeMask new_auth; | |
2582 | ||
635d2b00 GKH |
2583 | unifi_trace(priv, UDBG2, "unifi_siwauth\n"); |
2584 | ||
2585 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2586 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2587 | unifi_error(priv, "unifi_siwauth: not permitted in Mode %d\n", | |
2588 | interfacePriv->interfaceMode); | |
2589 | return -EPERM; | |
2590 | } | |
2591 | ||
2592 | ||
2593 | /* | |
2594 | * This ioctl is safe to call even when UniFi is powered off. | |
2595 | * wpa_supplicant calls it to test whether we support WPA. | |
2596 | */ | |
2597 | ||
2598 | switch (wrqu->param.flags & IW_AUTH_INDEX) { | |
2599 | ||
2600 | case IW_AUTH_WPA_ENABLED: | |
2601 | unifi_trace(priv, UDBG1, "IW_AUTH_WPA_ENABLED: %d\n", wrqu->param.value); | |
2602 | ||
2603 | if (wrqu->param.value == 0) { | |
2604 | unifi_trace(priv, UDBG5, "IW_AUTH_WPA_ENABLED: CSR_WIFI_SME_AUTH_MODE_80211_OPEN\n"); | |
2605 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
2606 | } | |
2607 | break; | |
2608 | ||
2609 | case IW_AUTH_PRIVACY_INVOKED: | |
2610 | unifi_trace(priv, UDBG1, "IW_AUTH_PRIVACY_INVOKED: %d\n", wrqu->param.value); | |
2611 | ||
2612 | priv->connection_config.privacyMode = wrqu->param.value ? CSR_WIFI_SME_80211_PRIVACY_MODE_ENABLED : CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED; | |
2613 | if (wrqu->param.value == CSR_WIFI_SME_80211_PRIVACY_MODE_DISABLED) | |
2614 | { | |
2615 | priv->connection_config.encryptionModeMask = CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE; | |
2616 | } | |
2617 | break; | |
2618 | ||
2619 | case IW_AUTH_80211_AUTH_ALG: | |
2620 | /* | |
2621 | IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 | |
2622 | IW_AUTH_ALG_SHARED_KEY 0x00000002 | |
2623 | IW_AUTH_ALG_LEAP 0x00000004 | |
2624 | */ | |
2625 | new_auth = 0; | |
2626 | if (wrqu->param.value & IW_AUTH_ALG_OPEN_SYSTEM) { | |
2627 | unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: %d (IW_AUTH_ALG_OPEN_SYSTEM)\n", wrqu->param.value); | |
2628 | new_auth |= CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
2629 | } | |
2630 | if (wrqu->param.value & IW_AUTH_ALG_SHARED_KEY) { | |
2631 | unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: %d (IW_AUTH_ALG_SHARED_KEY)\n", wrqu->param.value); | |
2632 | new_auth |= CSR_WIFI_SME_AUTH_MODE_80211_SHARED; | |
2633 | } | |
2634 | if (wrqu->param.value & IW_AUTH_ALG_LEAP) { | |
2635 | /* Initial exchanges using open-system to set EAP */ | |
2636 | unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: %d (IW_AUTH_ALG_LEAP)\n", wrqu->param.value); | |
2637 | new_auth |= CSR_WIFI_SME_AUTH_MODE_8021X_OTHER1X; | |
2638 | } | |
2639 | if (new_auth == 0) { | |
2640 | unifi_trace(priv, UDBG1, "IW_AUTH_80211_AUTH_ALG: invalid value %d\n", | |
2641 | wrqu->param.value); | |
2642 | return -EINVAL; | |
2643 | } else { | |
2644 | priv->connection_config.authModeMask = new_auth; | |
2645 | } | |
2646 | break; | |
2647 | ||
2648 | case IW_AUTH_WPA_VERSION: | |
2649 | unifi_trace(priv, UDBG1, "IW_AUTH_WPA_VERSION: %d\n", wrqu->param.value); | |
2650 | priv->ignore_bssid_join = TRUE; | |
2651 | /* | |
2652 | IW_AUTH_WPA_VERSION_DISABLED 0x00000001 | |
2653 | IW_AUTH_WPA_VERSION_WPA 0x00000002 | |
2654 | IW_AUTH_WPA_VERSION_WPA2 0x00000004 | |
2655 | */ | |
2656 | ||
2657 | if (!(wrqu->param.value & IW_AUTH_WPA_VERSION_DISABLED)) { | |
2658 | ||
2659 | priv->connection_config.authModeMask = CSR_WIFI_SME_AUTH_MODE_80211_OPEN; | |
2660 | ||
2661 | if (wrqu->param.value & IW_AUTH_WPA_VERSION_WPA) { | |
2662 | unifi_trace(priv, UDBG4, "IW_AUTH_WPA_VERSION: WPA, WPA-PSK\n"); | |
2663 | priv->connection_config.authModeMask |= (CSR_WIFI_SME_AUTH_MODE_8021X_WPA | CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK); | |
2664 | } | |
2665 | if (wrqu->param.value & IW_AUTH_WPA_VERSION_WPA2) { | |
2666 | unifi_trace(priv, UDBG4, "IW_AUTH_WPA_VERSION: WPA2, WPA2-PSK\n"); | |
2667 | priv->connection_config.authModeMask |= (CSR_WIFI_SME_AUTH_MODE_8021X_WPA2 | CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK); | |
2668 | } | |
2669 | } | |
2670 | break; | |
2671 | ||
2672 | case IW_AUTH_CIPHER_PAIRWISE: | |
2673 | unifi_trace(priv, UDBG1, "IW_AUTH_CIPHER_PAIRWISE: %d\n", wrqu->param.value); | |
2674 | /* | |
2675 | * one of: | |
2676 | IW_AUTH_CIPHER_NONE 0x00000001 | |
2677 | IW_AUTH_CIPHER_WEP40 0x00000002 | |
2678 | IW_AUTH_CIPHER_TKIP 0x00000004 | |
2679 | IW_AUTH_CIPHER_CCMP 0x00000008 | |
2680 | IW_AUTH_CIPHER_WEP104 0x00000010 | |
2681 | */ | |
2682 | ||
2683 | priv->connection_config.encryptionModeMask = CSR_WIFI_SME_ENCRYPTION_CIPHER_NONE; | |
2684 | ||
2685 | if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) { | |
2686 | priv->connection_config.encryptionModeMask |= | |
2687 | CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP40 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40; | |
2688 | } | |
2689 | if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) { | |
2690 | priv->connection_config.encryptionModeMask |= | |
2691 | CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_WEP104 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104; | |
2692 | } | |
2693 | if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) { | |
2694 | priv->connection_config.encryptionModeMask |= | |
2695 | CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_TKIP | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP; | |
2696 | } | |
2697 | if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) { | |
2698 | priv->connection_config.encryptionModeMask |= | |
2699 | CSR_WIFI_SME_ENCRYPTION_CIPHER_PAIRWISE_CCMP | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP; | |
2700 | } | |
2701 | ||
2702 | break; | |
2703 | ||
2704 | case IW_AUTH_CIPHER_GROUP: | |
2705 | unifi_trace(priv, UDBG1, "IW_AUTH_CIPHER_GROUP: %d\n", wrqu->param.value); | |
2706 | /* | |
2707 | * Use the WPA version and the group cipher suite to set the permitted | |
2708 | * group key in the MIB. f/w uses this value to validate WPA and RSN IEs | |
2709 | * in the probe responses from the desired BSS(ID) | |
2710 | */ | |
2711 | ||
2712 | priv->connection_config.encryptionModeMask &= ~(CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40 | | |
2713 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104 | | |
2714 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP | | |
2715 | CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP); | |
2716 | if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) { | |
2717 | priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP40; | |
2718 | } | |
2719 | if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) { | |
2720 | priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_WEP104; | |
2721 | } | |
2722 | if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) { | |
2723 | priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_TKIP; | |
2724 | } | |
2725 | if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) { | |
2726 | priv->connection_config.encryptionModeMask |= CSR_WIFI_SME_ENCRYPTION_CIPHER_GROUP_CCMP; | |
2727 | } | |
2728 | ||
2729 | break; | |
2730 | ||
2731 | case IW_AUTH_KEY_MGMT: | |
2732 | unifi_trace(priv, UDBG1, "IW_AUTH_KEY_MGMT: %d\n", wrqu->param.value); | |
2733 | /* | |
2734 | IW_AUTH_KEY_MGMT_802_1X 1 | |
2735 | IW_AUTH_KEY_MGMT_PSK 2 | |
2736 | */ | |
2737 | if (priv->connection_config.authModeMask & (CSR_WIFI_SME_AUTH_MODE_8021X_WPA | CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK)) { | |
2738 | /* Check for explicitly set mode. */ | |
2739 | if (wrqu->param.value == IW_AUTH_KEY_MGMT_802_1X) { | |
2740 | priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPAPSK; | |
2741 | } | |
2742 | if (wrqu->param.value == IW_AUTH_KEY_MGMT_PSK) { | |
2743 | priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPA; | |
2744 | } | |
2745 | unifi_trace(priv, UDBG5, "IW_AUTH_KEY_MGMT: WPA: %d\n", | |
2746 | priv->connection_config.authModeMask); | |
2747 | } | |
2748 | if (priv->connection_config.authModeMask & (CSR_WIFI_SME_AUTH_MODE_8021X_WPA2 | CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK)) { | |
2749 | /* Check for explicitly set mode. */ | |
2750 | if (wrqu->param.value == IW_AUTH_KEY_MGMT_802_1X) { | |
2751 | priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPA2PSK; | |
2752 | } | |
2753 | if (wrqu->param.value == IW_AUTH_KEY_MGMT_PSK) { | |
2754 | priv->connection_config.authModeMask &= ~CSR_WIFI_SME_AUTH_MODE_8021X_WPA2; | |
2755 | } | |
2756 | unifi_trace(priv, UDBG5, "IW_AUTH_KEY_MGMT: WPA2: %d\n", | |
2757 | priv->connection_config.authModeMask); | |
2758 | } | |
2759 | ||
2760 | break; | |
2761 | case IW_AUTH_TKIP_COUNTERMEASURES: | |
2762 | /* | |
2763 | * Set to true at the start of the 60 second backup-off period | |
2764 | * following 2 MichaelMIC failures within 60s. | |
2765 | */ | |
2766 | unifi_trace(priv, UDBG1, "IW_AUTH_TKIP_COUNTERMEASURES: %d\n", wrqu->param.value); | |
2767 | break; | |
2768 | ||
2769 | case IW_AUTH_DROP_UNENCRYPTED: | |
2770 | /* | |
2771 | * Set to true on init. | |
2772 | * Set to false just before associate if encryption will not be | |
2773 | * required. | |
2774 | * | |
2775 | * Note this is not the same as the 802.1X controlled port | |
2776 | */ | |
2777 | unifi_trace(priv, UDBG1, "IW_AUTH_DROP_UNENCRYPTED: %d\n", wrqu->param.value); | |
2778 | break; | |
2779 | ||
2780 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | |
2781 | /* | |
2782 | * This is set by wpa_supplicant to allow unencrypted EAPOL messages | |
2783 | * even if pairwise keys are set when not using WPA. IEEE 802.1X | |
2784 | * specifies that these frames are not encrypted, but WPA encrypts | |
2785 | * them when pairwise keys are in use. | |
2786 | * I think the UniFi f/w handles this decision for us. | |
2787 | */ | |
2788 | unifi_trace(priv, UDBG1, "IW_AUTH_RX_UNENCRYPTED_EAPOL: %d\n", wrqu->param.value); | |
2789 | break; | |
2790 | ||
2791 | case IW_AUTH_ROAMING_CONTROL: | |
2792 | unifi_trace(priv, UDBG1, "IW_AUTH_ROAMING_CONTROL: %d\n", wrqu->param.value); | |
2793 | break; | |
2794 | ||
2795 | default: | |
2796 | unifi_trace(priv, UDBG1, "Unsupported auth param %d to 0x%X\n", | |
2797 | wrqu->param.flags & IW_AUTH_INDEX, | |
2798 | wrqu->param.value); | |
2799 | return -EOPNOTSUPP; | |
2800 | } | |
2801 | ||
2802 | unifi_trace(priv, UDBG2, "authModeMask = %d", priv->connection_config.authModeMask); | |
635d2b00 GKH |
2803 | |
2804 | return 0; | |
2805 | } /* _unifi_siwauth() */ | |
2806 | ||
2807 | ||
2808 | static int | |
2809 | unifi_siwauth(struct net_device *dev, struct iw_request_info *info, | |
2810 | union iwreq_data *wrqu, char *extra) | |
2811 | { | |
2812 | int err = 0; | |
2813 | ||
2814 | UF_RTNL_UNLOCK(); | |
2815 | err = _unifi_siwauth(dev, info, wrqu, extra); | |
2816 | UF_RTNL_LOCK(); | |
2817 | ||
2818 | return err; | |
2819 | } /* unifi_siwauth() */ | |
2820 | ||
2821 | ||
2822 | static int | |
2823 | unifi_giwauth(struct net_device *dev, struct iw_request_info *info, | |
2824 | union iwreq_data *wrqu, char *extra) | |
2825 | { | |
2826 | unifi_trace(NULL, UDBG2, "unifi_giwauth\n"); | |
2827 | return -EOPNOTSUPP; | |
2828 | } /* unifi_giwauth() */ | |
2829 | ||
2830 | /* | |
2831 | * --------------------------------------------------------------------------- | |
2832 | * unifi_siwencodeext | |
2833 | * unifi_giwencodeext | |
2834 | * | |
2835 | * Handlers for SIOCSIWENCODEEXT, SIOCGIWENCODEEXT - set/get | |
2836 | * encoding token & mode | |
2837 | * | |
2838 | * Arguments: | |
2839 | * None. | |
2840 | * | |
2841 | * Returns: | |
2842 | * None. | |
2843 | * | |
2844 | * Notes: | |
2845 | * For WPA/WPA2 we don't take note of the IW_ENCODE_EXT_SET_TX_KEY flag. | |
2846 | * This flag means "use this key to encode transmissions"; we just | |
2847 | * assume only one key will be set and that is the one to use. | |
2848 | * --------------------------------------------------------------------------- | |
2849 | */ | |
2850 | static int | |
2851 | _unifi_siwencodeext(struct net_device *dev, struct iw_request_info *info, | |
2852 | union iwreq_data *wrqu, char *extra) | |
2853 | { | |
2854 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
2855 | unifi_priv_t *priv = interfacePriv->privPtr; | |
2856 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | |
2857 | int r = 0; | |
2858 | unsigned char *keydata; | |
2859 | unsigned char tkip_key[32]; | |
2860 | int keyid; | |
2861 | unsigned char *a = (unsigned char *)ext->addr.sa_data; | |
2862 | CsrWifiSmeKey sme_key; | |
2863 | CsrWifiSmeKeyType key_type; | |
2864 | ||
635d2b00 GKH |
2865 | CHECK_INITED(priv); |
2866 | ||
2867 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
2868 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
2869 | unifi_error(priv, "unifi_siwencodeext: not permitted in Mode %d\n", | |
2870 | interfacePriv->interfaceMode); | |
2871 | return -EPERM; | |
2872 | } | |
2873 | ||
2874 | ||
2875 | unifi_trace(priv, UDBG1, "siwencodeext: flags=0x%X, alg=%d, ext_flags=0x%X, len=%d, index=%d,\n", | |
2876 | wrqu->encoding.flags, ext->alg, ext->ext_flags, | |
2877 | ext->key_len, (wrqu->encoding.flags & IW_ENCODE_INDEX)); | |
a6737c73 | 2878 | unifi_trace(priv, UDBG3, " addr=%pM\n", a); |
635d2b00 GKH |
2879 | |
2880 | if ((ext->key_len == 0) && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { | |
2881 | /* This means use a different key (given by key_idx) for Tx. */ | |
2882 | /* NYI */ | |
2883 | unifi_trace(priv, UDBG1, KERN_ERR "unifi_siwencodeext: NYI should change tx key id here!!\n"); | |
2884 | return -ENOTSUPP; | |
2885 | } | |
2886 | ||
2887 | memset(&sme_key, 0, sizeof(sme_key)); | |
2888 | ||
2889 | keydata = (unsigned char *)(ext + 1); | |
2890 | keyid = (wrqu->encoding.flags & IW_ENCODE_INDEX); | |
2891 | ||
2892 | /* | |
2893 | * Check for request to delete keys for an address. | |
2894 | */ | |
2895 | /* Pick out request for no privacy. */ | |
2896 | if (ext->alg == IW_ENCODE_ALG_NONE) { | |
2897 | ||
2898 | unifi_trace(priv, UDBG1, "Deleting %s key %d\n", | |
2899 | (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ? "GROUP" : "PAIRWISE", | |
2900 | keyid); | |
2901 | ||
2902 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | |
2903 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP; | |
2904 | } else { | |
2905 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE; | |
2906 | } | |
2907 | sme_key.keyIndex = (keyid - 1); | |
2908 | sme_key.keyLength = 0; | |
2909 | sme_key.authenticator = 0; | |
2910 | memcpy(sme_key.address.a, a, ETH_ALEN); | |
2911 | UF_RTNL_UNLOCK(); | |
2912 | r = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_REMOVE); | |
2913 | UF_RTNL_LOCK(); | |
2914 | if (r) { | |
2915 | unifi_error(priv, "Delete key request was rejected with result %d\n", r); | |
2916 | return convert_sme_error(r); | |
2917 | } | |
2918 | ||
2919 | return 0; | |
2920 | } | |
2921 | ||
2922 | /* | |
2923 | * Request is to set a key, not delete | |
2924 | */ | |
2925 | ||
2926 | /* Pick out WEP and use set_wep_key(). */ | |
2927 | if (ext->alg == IW_ENCODE_ALG_WEP) { | |
2928 | /* WEP-40, WEP-104 */ | |
2929 | ||
2930 | /* Check for valid key length */ | |
2931 | if (!((ext->key_len == 5) || (ext->key_len == 13))) { | |
2932 | unifi_trace(priv, UDBG1, KERN_ERR "Invalid length for WEP key: %d\n", ext->key_len); | |
2933 | return -EINVAL; | |
2934 | } | |
2935 | ||
2936 | unifi_trace(priv, UDBG1, "Setting WEP key %d tx:%d\n", | |
2937 | keyid, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY); | |
2938 | ||
2939 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | |
2940 | sme_key.wepTxKey = TRUE; | |
2941 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_PAIRWISE; | |
2942 | } else { | |
2943 | sme_key.wepTxKey = FALSE; | |
2944 | sme_key.keyType = CSR_WIFI_SME_KEY_TYPE_GROUP; | |
2945 | } | |
2946 | sme_key.keyIndex = (keyid - 1); | |
2947 | sme_key.keyLength = ext->key_len; | |
2948 | sme_key.authenticator = 0; | |
2949 | memset(sme_key.address.a, 0xFF, ETH_ALEN); | |
2950 | memcpy(sme_key.key, keydata, ext->key_len); | |
2951 | UF_RTNL_UNLOCK(); | |
2952 | r = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD); | |
2953 | UF_RTNL_LOCK(); | |
2954 | if (r) { | |
2955 | unifi_error(priv, "siwencodeext: Set key failed (%d)", r); | |
2956 | return convert_sme_error(r); | |
2957 | } | |
2958 | ||
2959 | return 0; | |
2960 | } | |
2961 | ||
2962 | /* | |
2963 | * | |
2964 | * If we reach here, we are dealing with a WPA/WPA2 key | |
2965 | * | |
2966 | */ | |
2967 | if (ext->key_len > 32) { | |
2968 | return -EINVAL; | |
2969 | } | |
2970 | ||
2971 | /* | |
2972 | * TKIP keys from wpa_supplicant need swapping. | |
2973 | * What about other supplicants (when they come along)? | |
2974 | */ | |
2975 | if ((ext->alg == IW_ENCODE_ALG_TKIP) && (ext->key_len == 32)) { | |
2976 | memcpy(tkip_key, keydata, 16); | |
2977 | memcpy(tkip_key + 16, keydata + 24, 8); | |
2978 | memcpy(tkip_key + 24, keydata + 16, 8); | |
2979 | keydata = tkip_key; | |
2980 | } | |
2981 | ||
2982 | key_type = (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) ? | |
2983 | CSR_WIFI_SME_KEY_TYPE_GROUP : /* Group Key */ | |
2984 | CSR_WIFI_SME_KEY_TYPE_PAIRWISE; /* Pairwise Key */ | |
2985 | ||
2986 | sme_key.keyType = key_type; | |
2987 | sme_key.keyIndex = (keyid - 1); | |
2988 | sme_key.keyLength = ext->key_len; | |
2989 | sme_key.authenticator = 0; | |
2990 | memcpy(sme_key.address.a, ext->addr.sa_data, ETH_ALEN); | |
2991 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { | |
2992 | ||
8c4a1271 AS |
2993 | unifi_trace(priv, UDBG5, "RSC first 6 bytes = %*phC\n", |
2994 | 6, ext->rx_seq); | |
635d2b00 GKH |
2995 | |
2996 | /* memcpy((u8*)(&sme_key.keyRsc), ext->rx_seq, 8); */ | |
2997 | sme_key.keyRsc[0] = ext->rx_seq[1] << 8 | ext->rx_seq[0]; | |
2998 | sme_key.keyRsc[1] = ext->rx_seq[3] << 8 | ext->rx_seq[2]; | |
2999 | sme_key.keyRsc[2] = ext->rx_seq[5] << 8 | ext->rx_seq[4]; | |
3000 | sme_key.keyRsc[3] = ext->rx_seq[7] << 8 | ext->rx_seq[6]; | |
3001 | ||
3002 | } | |
3003 | ||
3004 | memcpy(sme_key.key, keydata, ext->key_len); | |
3005 | UF_RTNL_UNLOCK(); | |
3006 | r = sme_mgt_key(priv, &sme_key, CSR_WIFI_SME_LIST_ACTION_ADD); | |
3007 | UF_RTNL_LOCK(); | |
3008 | if (r) { | |
3009 | unifi_error(priv, "SETKEYS request was rejected with result %d\n", r); | |
3010 | return convert_sme_error(r); | |
3011 | } | |
3012 | ||
635d2b00 GKH |
3013 | return r; |
3014 | } /* _unifi_siwencodeext() */ | |
3015 | ||
3016 | ||
3017 | static int | |
3018 | unifi_siwencodeext(struct net_device *dev, struct iw_request_info *info, | |
3019 | union iwreq_data *wrqu, char *extra) | |
3020 | { | |
3021 | int err = 0; | |
3022 | ||
3023 | err = _unifi_siwencodeext(dev, info, wrqu, extra); | |
3024 | ||
3025 | return err; | |
3026 | } /* unifi_siwencodeext() */ | |
3027 | ||
3028 | ||
3029 | static int | |
3030 | unifi_giwencodeext(struct net_device *dev, struct iw_request_info *info, | |
3031 | union iwreq_data *wrqu, char *extra) | |
3032 | { | |
3033 | return -EOPNOTSUPP; | |
3034 | } /* unifi_giwencodeext() */ | |
3035 | ||
3036 | ||
3037 | /* | |
3038 | * --------------------------------------------------------------------------- | |
3039 | * unifi_siwpmksa | |
3040 | * | |
3041 | * SIOCSIWPMKSA - PMKSA cache operation | |
3042 | * The caller passes a pmksa structure: | |
3043 | * - cmd one of ADD, REMOVE, FLUSH | |
3044 | * - bssid MAC address | |
3045 | * - pmkid ID string (16 bytes) | |
3046 | * | |
3047 | * Arguments: | |
3048 | * None. | |
3049 | * | |
3050 | * Returns: | |
3051 | * None. | |
3052 | * | |
3053 | * Notes: | |
3054 | * This is not needed since we provide a siwgenie method. | |
3055 | * --------------------------------------------------------------------------- | |
3056 | */ | |
3057 | #define UNIFI_PMKID_KEY_SIZE 16 | |
3058 | static int | |
3059 | unifi_siwpmksa(struct net_device *dev, struct iw_request_info *info, | |
3060 | union iwreq_data *wrqu, char *extra) | |
3061 | { | |
3062 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
3063 | unifi_priv_t *priv = interfacePriv->privPtr; | |
3064 | struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; | |
3065 | CsrResult r = 0; | |
3066 | CsrWifiSmePmkidList pmkid_list; | |
3067 | CsrWifiSmePmkid pmkid; | |
3068 | CsrWifiSmeListAction action; | |
3069 | ||
3070 | CHECK_INITED(priv); | |
3071 | ||
3072 | if(interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_AP || | |
3073 | interfacePriv->interfaceMode == CSR_WIFI_ROUTER_CTRL_MODE_P2PGO) { | |
3074 | unifi_error(priv, "unifi_siwpmksa: not permitted in Mode %d\n", | |
3075 | interfacePriv->interfaceMode); | |
3076 | return -EPERM; | |
3077 | } | |
3078 | ||
3079 | ||
a6737c73 AS |
3080 | unifi_trace(priv, UDBG1, "SIWPMKSA: cmd %d, %pM\n", pmksa->cmd, |
3081 | pmksa->bssid.sa_data); | |
635d2b00 GKH |
3082 | |
3083 | pmkid_list.pmkids = NULL; | |
3084 | switch (pmksa->cmd) { | |
3085 | case IW_PMKSA_ADD: | |
3086 | pmkid_list.pmkids = &pmkid; | |
3087 | action = CSR_WIFI_SME_LIST_ACTION_ADD; | |
3088 | pmkid_list.pmkidsCount = 1; | |
3089 | memcpy(pmkid.bssid.a, pmksa->bssid.sa_data, ETH_ALEN); | |
3090 | memcpy(pmkid.pmkid, pmksa->pmkid, UNIFI_PMKID_KEY_SIZE); | |
3091 | break; | |
3092 | case IW_PMKSA_REMOVE: | |
3093 | pmkid_list.pmkids = &pmkid; | |
3094 | action = CSR_WIFI_SME_LIST_ACTION_REMOVE; | |
3095 | pmkid_list.pmkidsCount = 1; | |
3096 | memcpy(pmkid.bssid.a, pmksa->bssid.sa_data, ETH_ALEN); | |
3097 | memcpy(pmkid.pmkid, pmksa->pmkid, UNIFI_PMKID_KEY_SIZE); | |
3098 | break; | |
3099 | case IW_PMKSA_FLUSH: | |
3100 | /* Replace current PMKID's with an empty list */ | |
3101 | pmkid_list.pmkidsCount = 0; | |
3102 | action = CSR_WIFI_SME_LIST_ACTION_FLUSH; | |
3103 | break; | |
3104 | default: | |
3105 | unifi_notice(priv, "SIWPMKSA: Unknown command (0x%x)\n", pmksa->cmd); | |
3106 | return -EINVAL; | |
3107 | } | |
3108 | ||
3109 | /* Set the Value the pmkid's will have 1 added OR 1 removed OR be cleared at this point */ | |
3110 | UF_RTNL_UNLOCK(); | |
3111 | r = sme_mgt_pmkid(priv, action, &pmkid_list); | |
3112 | UF_RTNL_LOCK(); | |
3113 | if (r) { | |
3114 | unifi_error(priv, "SIWPMKSA: Set PMKID's Failed.\n"); | |
3115 | } | |
3116 | ||
3117 | return r; | |
3118 | ||
3119 | } /* unifi_siwpmksa() */ | |
3120 | ||
3121 | ||
3122 | /* | |
3123 | * --------------------------------------------------------------------------- | |
3124 | * unifi_get_wireless_stats | |
3125 | * | |
3126 | * get_wireless_stats method for Linux wireless extensions. | |
3127 | * | |
3128 | * Arguments: | |
3129 | * dev Pointer to associated netdevice. | |
3130 | * | |
3131 | * Returns: | |
3132 | * Pointer to iw_statistics struct. | |
3133 | * --------------------------------------------------------------------------- | |
3134 | */ | |
3135 | struct iw_statistics * | |
3136 | unifi_get_wireless_stats(struct net_device *dev) | |
3137 | { | |
3138 | netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); | |
3139 | unifi_priv_t *priv = interfacePriv->privPtr; | |
3140 | ||
3141 | if (priv->init_progress != UNIFI_INIT_COMPLETED) { | |
3142 | return NULL; | |
3143 | } | |
3144 | ||
3145 | return &priv->wext_wireless_stats; | |
3146 | } /* unifi_get_wireless_stats() */ | |
3147 | ||
3148 | ||
3149 | /* | |
3150 | * Structures to export the Wireless Handlers | |
3151 | */ | |
3152 | ||
3153 | static const struct iw_priv_args unifi_private_args[] = { | |
3154 | /*{ cmd, set_args, get_args, name } */ | |
3155 | { SIOCIWS80211POWERSAVEPRIV, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | |
3156 | IW_PRIV_TYPE_NONE, "iwprivs80211ps" }, | |
3157 | { SIOCIWG80211POWERSAVEPRIV, IW_PRIV_TYPE_NONE, | |
3158 | IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IWPRIV_POWER_SAVE_MAX_STRING, "iwprivg80211ps" }, | |
3159 | { SIOCIWS80211RELOADDEFAULTSPRIV, IW_PRIV_TYPE_NONE, | |
3160 | IW_PRIV_TYPE_NONE, "iwprivsdefs" }, | |
3161 | { SIOCIWSSMEDEBUGPRIV, IW_PRIV_TYPE_CHAR | IWPRIV_SME_DEBUG_MAX_STRING, IW_PRIV_TYPE_NONE, "iwprivssmedebug" }, | |
3162 | #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE | |
3163 | { SIOCIWSCONFWAPIPRIV, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, | |
3164 | IW_PRIV_TYPE_NONE, "iwprivsconfwapi" }, | |
3165 | { SIOCIWSWAPIKEYPRIV, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(unifiio_wapi_key_t), | |
3166 | IW_PRIV_TYPE_NONE, "iwprivswpikey" }, | |
3167 | #endif | |
3168 | #ifdef CSR_SUPPORT_WEXT_AP | |
3169 | { SIOCIWSAPCFGPRIV, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_NONE, "AP_SET_CFG" }, | |
3f596cad | 3170 | { SIOCIWSAPSTARTPRIV, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED|IWPRIV_SME_MAX_STRING, "AP_BSS_START" }, |
635d2b00 GKH |
3171 | { SIOCIWSAPSTOPPRIV, IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|0, |
3172 | IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|0, "AP_BSS_STOP" }, | |
3173 | #ifdef ANDROID_BUILD | |
3174 | { SIOCIWSFWRELOADPRIV, IW_PRIV_TYPE_CHAR |256, | |
3175 | IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|0, "WL_FW_RELOAD" }, | |
3176 | { SIOCIWSSTACKSTART, 0, | |
3177 | IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|IWPRIV_SME_MAX_STRING, "START" }, | |
3178 | { SIOCIWSSTACKSTOP, 0, | |
3179 | IW_PRIV_TYPE_CHAR |IW_PRIV_SIZE_FIXED|IWPRIV_SME_MAX_STRING, "STOP" }, | |
3180 | #endif /* ANDROID_BUILD */ | |
3181 | #endif /* CSR_SUPPORT_WEXT_AP */ | |
3182 | }; | |
3183 | ||
3184 | static const iw_handler unifi_handler[] = | |
3185 | { | |
3186 | (iw_handler) unifi_siwcommit, /* SIOCSIWCOMMIT */ | |
3187 | (iw_handler) unifi_giwname, /* SIOCGIWNAME */ | |
3188 | (iw_handler) NULL, /* SIOCSIWNWID */ | |
3189 | (iw_handler) NULL, /* SIOCGIWNWID */ | |
3190 | (iw_handler) unifi_siwfreq, /* SIOCSIWFREQ */ | |
3191 | (iw_handler) unifi_giwfreq, /* SIOCGIWFREQ */ | |
3192 | (iw_handler) unifi_siwmode, /* SIOCSIWMODE */ | |
3193 | (iw_handler) unifi_giwmode, /* SIOCGIWMODE */ | |
3194 | (iw_handler) NULL, /* SIOCSIWSENS */ | |
3195 | (iw_handler) NULL, /* SIOCGIWSENS */ | |
3196 | (iw_handler) NULL, /* SIOCSIWRANGE */ | |
3197 | (iw_handler) unifi_giwrange, /* SIOCGIWRANGE */ | |
3198 | (iw_handler) NULL, /* SIOCSIWPRIV */ | |
3199 | (iw_handler) NULL, /* SIOCGIWPRIV */ | |
3200 | (iw_handler) NULL, /* SIOCSIWSTATS */ | |
3201 | (iw_handler) NULL, /* SIOCGIWSTATS */ | |
3202 | (iw_handler) NULL, /* SIOCSIWSPY */ | |
3203 | (iw_handler) NULL, /* SIOCGIWSPY */ | |
3204 | (iw_handler) NULL, /* SIOCSIWTHRSPY */ | |
3205 | (iw_handler) NULL, /* SIOCGIWTHRSPY */ | |
3206 | (iw_handler) unifi_siwap, /* SIOCSIWAP */ | |
3207 | (iw_handler) unifi_giwap, /* SIOCGIWAP */ | |
3208 | #if WIRELESS_EXT > 17 | |
3209 | /* WPA : IEEE 802.11 MLME requests */ | |
3210 | unifi_siwmlme, /* SIOCSIWMLME, request MLME operation */ | |
3211 | #else | |
3212 | (iw_handler) NULL, /* -- hole -- */ | |
3213 | #endif | |
3214 | (iw_handler) NULL, /* SIOCGIWAPLIST */ | |
3215 | (iw_handler) unifi_siwscan, /* SIOCSIWSCAN */ | |
3216 | (iw_handler) unifi_giwscan, /* SIOCGIWSCAN */ | |
3217 | (iw_handler) unifi_siwessid, /* SIOCSIWESSID */ | |
3218 | (iw_handler) unifi_giwessid, /* SIOCGIWESSID */ | |
3219 | (iw_handler) NULL, /* SIOCSIWNICKN */ | |
3220 | (iw_handler) NULL, /* SIOCGIWNICKN */ | |
3221 | (iw_handler) NULL, /* -- hole -- */ | |
3222 | (iw_handler) NULL, /* -- hole -- */ | |
3223 | unifi_siwrate, /* SIOCSIWRATE */ | |
3224 | unifi_giwrate, /* SIOCGIWRATE */ | |
3225 | unifi_siwrts, /* SIOCSIWRTS */ | |
3226 | unifi_giwrts, /* SIOCGIWRTS */ | |
3227 | unifi_siwfrag, /* SIOCSIWFRAG */ | |
3228 | unifi_giwfrag, /* SIOCGIWFRAG */ | |
3229 | (iw_handler) NULL, /* SIOCSIWTXPOW */ | |
3230 | (iw_handler) NULL, /* SIOCGIWTXPOW */ | |
3231 | (iw_handler) NULL, /* SIOCSIWRETRY */ | |
3232 | (iw_handler) NULL, /* SIOCGIWRETRY */ | |
3233 | unifi_siwencode, /* SIOCSIWENCODE */ | |
3234 | unifi_giwencode, /* SIOCGIWENCODE */ | |
3235 | unifi_siwpower, /* SIOCSIWPOWER */ | |
3236 | unifi_giwpower, /* SIOCGIWPOWER */ | |
3237 | #if WIRELESS_EXT > 17 | |
3238 | (iw_handler) NULL, /* -- hole -- */ | |
3239 | (iw_handler) NULL, /* -- hole -- */ | |
3240 | ||
3241 | /* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). */ | |
3242 | unifi_siwgenie, /* SIOCSIWGENIE */ /* set generic IE */ | |
3243 | unifi_giwgenie, /* SIOCGIWGENIE */ /* get generic IE */ | |
3244 | ||
3245 | /* WPA : Authentication mode parameters */ | |
3246 | unifi_siwauth, /* SIOCSIWAUTH */ /* set authentication mode params */ | |
3247 | unifi_giwauth, /* SIOCGIWAUTH */ /* get authentication mode params */ | |
3248 | ||
3249 | /* WPA : Extended version of encoding configuration */ | |
3250 | unifi_siwencodeext, /* SIOCSIWENCODEEXT */ /* set encoding token & mode */ | |
3251 | unifi_giwencodeext, /* SIOCGIWENCODEEXT */ /* get encoding token & mode */ | |
3252 | ||
3253 | /* WPA2 : PMKSA cache management */ | |
3254 | unifi_siwpmksa, /* SIOCSIWPMKSA */ /* PMKSA cache operation */ | |
3255 | (iw_handler) NULL, /* -- hole -- */ | |
3256 | #endif /* WIRELESS_EXT > 17 */ | |
3257 | }; | |
3258 | ||
3259 | ||
3260 | static const iw_handler unifi_private_handler[] = | |
3261 | { | |
3262 | iwprivs80211ps, /* SIOCIWFIRSTPRIV */ | |
3263 | iwprivg80211ps, /* SIOCIWFIRSTPRIV + 1 */ | |
3264 | iwprivsdefs, /* SIOCIWFIRSTPRIV + 2 */ | |
3265 | (iw_handler) NULL, | |
3266 | #ifdef CSR_WIFI_SECURITY_WAPI_ENABLE | |
3267 | iwprivsconfwapi, /* SIOCIWFIRSTPRIV + 4 */ | |
3268 | (iw_handler) NULL, /* SIOCIWFIRSTPRIV + 5 */ | |
3269 | iwprivswpikey, /* SIOCIWFIRSTPRIV + 6 */ | |
3270 | #else | |
3271 | (iw_handler) NULL, | |
3272 | (iw_handler) NULL, | |
3273 | (iw_handler) NULL, | |
3274 | #endif | |
3275 | (iw_handler) NULL, | |
3276 | iwprivssmedebug, /* SIOCIWFIRSTPRIV + 8 */ | |
3277 | #ifdef CSR_SUPPORT_WEXT_AP | |
3278 | (iw_handler) NULL, | |
3279 | iwprivsapconfig, | |
3280 | (iw_handler) NULL, | |
3281 | iwprivsapstart, | |
3282 | (iw_handler) NULL, | |
3283 | iwprivsapstop, | |
3284 | (iw_handler) NULL, | |
3285 | #ifdef ANDROID_BUILD | |
3286 | iwprivsapfwreload, | |
3287 | (iw_handler) NULL, | |
3288 | iwprivsstackstart, | |
3289 | (iw_handler) NULL, | |
3290 | iwprivsstackstop, | |
3291 | #else | |
3292 | (iw_handler) NULL, | |
3293 | (iw_handler) NULL, | |
3294 | (iw_handler) NULL, | |
3295 | (iw_handler) NULL, | |
3296 | (iw_handler) NULL, | |
3297 | #endif /* ANDROID_BUILD */ | |
3298 | #else | |
3299 | (iw_handler) NULL, | |
3300 | (iw_handler) NULL, | |
3301 | (iw_handler) NULL, | |
3302 | (iw_handler) NULL, | |
3303 | (iw_handler) NULL, | |
3304 | (iw_handler) NULL, | |
3305 | (iw_handler) NULL, | |
3306 | (iw_handler) NULL, | |
3307 | (iw_handler) NULL, | |
3308 | (iw_handler) NULL, | |
3309 | (iw_handler) NULL, | |
3310 | (iw_handler) NULL, | |
3311 | #endif /* CSR_SUPPORT_WEXT_AP */ | |
3312 | }; | |
3313 | ||
3314 | struct iw_handler_def unifi_iw_handler_def = | |
3315 | { | |
3316 | .num_standard = sizeof(unifi_handler) / sizeof(iw_handler), | |
3317 | .num_private = sizeof(unifi_private_handler) / sizeof(iw_handler), | |
3318 | .num_private_args = sizeof(unifi_private_args) / sizeof(struct iw_priv_args), | |
3319 | .standard = (iw_handler *) unifi_handler, | |
3320 | .private = (iw_handler *) unifi_private_handler, | |
3321 | .private_args = (struct iw_priv_args *) unifi_private_args, | |
3322 | #if IW_HANDLER_VERSION >= 6 | |
3323 | .get_wireless_stats = unifi_get_wireless_stats, | |
3324 | #endif | |
3325 | }; | |
3326 | ||
3327 |