1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. |
4 | * |
5 | * Contact Information: wlanfae <wlanfae@realtek.com> |
6 | */ |
7 | #include <linux/string.h> |
8 | #include "rtl_core.h" |
9 | #include "rtl_wx.h" |
10 | |
11 | #define RATE_COUNT 12 |
12 | static u32 rtl8192_rates[] = { |
13 | 1000000, 2000000, 5500000, 11000000, 6000000, 9000000, 12000000, |
14 | 18000000, 24000000, 36000000, 48000000, 54000000 |
15 | }; |
16 | |
17 | #ifndef ENETDOWN |
18 | #define ENETDOWN 1 |
19 | #endif |
20 | |
21 | static int _rtl92e_wx_get_freq(struct net_device *dev, |
22 | struct iw_request_info *a, |
23 | union iwreq_data *wrqu, char *b) |
24 | { |
25 | struct r8192_priv *priv = rtllib_priv(dev); |
26 | |
27 | return rtllib_wx_get_freq(ieee: priv->rtllib, a, wrqu, b); |
28 | } |
29 | |
30 | static int _rtl92e_wx_get_mode(struct net_device *dev, |
31 | struct iw_request_info *a, |
32 | union iwreq_data *wrqu, char *b) |
33 | { |
34 | struct r8192_priv *priv = rtllib_priv(dev); |
35 | |
36 | return rtllib_wx_get_mode(ieee: priv->rtllib, a, wrqu, b); |
37 | } |
38 | |
39 | static int _rtl92e_wx_get_rate(struct net_device *dev, |
40 | struct iw_request_info *info, |
41 | union iwreq_data *wrqu, char *) |
42 | { |
43 | struct r8192_priv *priv = rtllib_priv(dev); |
44 | |
45 | return rtllib_wx_get_rate(ieee: priv->rtllib, info, wrqu, extra); |
46 | } |
47 | |
48 | static int _rtl92e_wx_set_rate(struct net_device *dev, |
49 | struct iw_request_info *info, |
50 | union iwreq_data *wrqu, char *) |
51 | { |
52 | int ret; |
53 | struct r8192_priv *priv = rtllib_priv(dev); |
54 | |
55 | if (priv->hw_radio_off) |
56 | return 0; |
57 | |
58 | mutex_lock(&priv->wx_mutex); |
59 | |
60 | ret = rtllib_wx_set_rate(ieee: priv->rtllib, info, wrqu, extra); |
61 | |
62 | mutex_unlock(lock: &priv->wx_mutex); |
63 | |
64 | return ret; |
65 | } |
66 | |
67 | static int _rtl92e_wx_set_rts(struct net_device *dev, |
68 | struct iw_request_info *info, |
69 | union iwreq_data *wrqu, char *) |
70 | { |
71 | int ret; |
72 | struct r8192_priv *priv = rtllib_priv(dev); |
73 | |
74 | if (priv->hw_radio_off) |
75 | return 0; |
76 | |
77 | mutex_lock(&priv->wx_mutex); |
78 | |
79 | ret = rtllib_wx_set_rts(ieee: priv->rtllib, info, wrqu, extra); |
80 | |
81 | mutex_unlock(lock: &priv->wx_mutex); |
82 | |
83 | return ret; |
84 | } |
85 | |
86 | static int _rtl92e_wx_get_rts(struct net_device *dev, |
87 | struct iw_request_info *info, |
88 | union iwreq_data *wrqu, char *) |
89 | { |
90 | struct r8192_priv *priv = rtllib_priv(dev); |
91 | |
92 | return rtllib_wx_get_rts(ieee: priv->rtllib, info, wrqu, extra); |
93 | } |
94 | |
95 | static int _rtl92e_wx_set_power(struct net_device *dev, |
96 | struct iw_request_info *info, |
97 | union iwreq_data *wrqu, char *) |
98 | { |
99 | int ret; |
100 | struct r8192_priv *priv = rtllib_priv(dev); |
101 | |
102 | if (priv->hw_radio_off) { |
103 | netdev_warn(dev, format: "%s(): Can't set Power: Radio is Off.\n" , |
104 | __func__); |
105 | return 0; |
106 | } |
107 | mutex_lock(&priv->wx_mutex); |
108 | |
109 | ret = rtllib_wx_set_power(ieee: priv->rtllib, info, wrqu, extra); |
110 | |
111 | mutex_unlock(lock: &priv->wx_mutex); |
112 | |
113 | return ret; |
114 | } |
115 | |
116 | static int _rtl92e_wx_get_power(struct net_device *dev, |
117 | struct iw_request_info *info, |
118 | union iwreq_data *wrqu, char *) |
119 | { |
120 | struct r8192_priv *priv = rtllib_priv(dev); |
121 | |
122 | return rtllib_wx_get_power(ieee: priv->rtllib, info, wrqu, extra); |
123 | } |
124 | |
125 | static int _rtl92e_wx_set_mode(struct net_device *dev, |
126 | struct iw_request_info *a, |
127 | union iwreq_data *wrqu, char *b) |
128 | { |
129 | struct r8192_priv *priv = rtllib_priv(dev); |
130 | |
131 | enum rt_rf_power_state rt_state; |
132 | int ret; |
133 | |
134 | if (priv->hw_radio_off) |
135 | return 0; |
136 | rt_state = priv->rtllib->rf_power_state; |
137 | mutex_lock(&priv->wx_mutex); |
138 | if (wrqu->mode == IW_MODE_MONITOR) { |
139 | if (rt_state == rf_off) { |
140 | if (priv->rtllib->rf_off_reason > |
141 | RF_CHANGE_BY_IPS) { |
142 | netdev_warn(dev, format: "%s(): RF is OFF.\n" , |
143 | __func__); |
144 | mutex_unlock(lock: &priv->wx_mutex); |
145 | return -1; |
146 | } |
147 | netdev_info(dev, |
148 | format: "=========>%s(): rtl92e_ips_leave\n" , |
149 | __func__); |
150 | mutex_lock(&priv->rtllib->ips_mutex); |
151 | rtl92e_ips_leave(dev); |
152 | mutex_unlock(lock: &priv->rtllib->ips_mutex); |
153 | } |
154 | } |
155 | ret = rtllib_wx_set_mode(ieee: priv->rtllib, a, wrqu, b); |
156 | |
157 | mutex_unlock(lock: &priv->wx_mutex); |
158 | return ret; |
159 | } |
160 | |
161 | static int _rtl92e_wx_get_range(struct net_device *dev, |
162 | struct iw_request_info *info, |
163 | union iwreq_data *wrqu, char *) |
164 | { |
165 | struct iw_range *range = (struct iw_range *)extra; |
166 | struct r8192_priv *priv = rtllib_priv(dev); |
167 | u16 val; |
168 | int i; |
169 | |
170 | wrqu->data.length = sizeof(*range); |
171 | memset(range, 0, sizeof(*range)); |
172 | |
173 | /* ~130 Mb/s real (802.11n) */ |
174 | range->throughput = 130 * 1000 * 1000; |
175 | |
176 | range->max_qual.qual = 100; |
177 | range->max_qual.level = 0; |
178 | range->max_qual.noise = 0; |
179 | range->max_qual.updated = 7; /* Updated all three */ |
180 | |
181 | range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ |
182 | range->avg_qual.level = 0; |
183 | range->avg_qual.noise = 0; |
184 | range->avg_qual.updated = 7; /* Updated all three */ |
185 | |
186 | range->num_bitrates = min(RATE_COUNT, IW_MAX_BITRATES); |
187 | |
188 | for (i = 0; i < range->num_bitrates; i++) |
189 | range->bitrate[i] = rtl8192_rates[i]; |
190 | |
191 | range->max_rts = DEFAULT_RTS_THRESHOLD; |
192 | range->min_frag = MIN_FRAG_THRESHOLD; |
193 | range->max_frag = MAX_FRAG_THRESHOLD; |
194 | |
195 | range->min_pmp = 0; |
196 | range->max_pmp = 5000000; |
197 | range->min_pmt = 0; |
198 | range->max_pmt = 65535 * 1000; |
199 | range->pmp_flags = IW_POWER_PERIOD; |
200 | range->pmt_flags = IW_POWER_TIMEOUT; |
201 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; |
202 | range->we_version_compiled = WIRELESS_EXT; |
203 | range->we_version_source = 18; |
204 | |
205 | for (i = 0, val = 0; i < 14; i++) { |
206 | if ((priv->rtllib->active_channel_map)[i + 1]) { |
207 | s32 freq_khz; |
208 | |
209 | range->freq[val].i = i + 1; |
210 | freq_khz = ieee80211_channel_to_freq_khz(chan: i + 1, band: NL80211_BAND_2GHZ); |
211 | range->freq[val].m = freq_khz * 100; |
212 | range->freq[val].e = 1; |
213 | val++; |
214 | } |
215 | |
216 | if (val == IW_MAX_FREQUENCIES) |
217 | break; |
218 | } |
219 | range->num_frequency = val; |
220 | range->num_channels = val; |
221 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | |
222 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; |
223 | range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; |
224 | |
225 | /* Event capability (kernel + driver) */ |
226 | |
227 | return 0; |
228 | } |
229 | |
230 | static int _rtl92e_wx_set_scan(struct net_device *dev, |
231 | struct iw_request_info *a, |
232 | union iwreq_data *wrqu, char *b) |
233 | { |
234 | struct r8192_priv *priv = rtllib_priv(dev); |
235 | struct rtllib_device *ieee = priv->rtllib; |
236 | enum rt_rf_power_state rt_state; |
237 | int ret; |
238 | |
239 | if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) { |
240 | if ((ieee->link_state >= RTLLIB_ASSOCIATING) && |
241 | (ieee->link_state <= RTLLIB_ASSOCIATING_AUTHENTICATED)) |
242 | return 0; |
243 | if ((priv->rtllib->link_state == MAC80211_LINKED) && |
244 | (priv->rtllib->CntAfterLink < 2)) |
245 | return 0; |
246 | } |
247 | |
248 | if (priv->hw_radio_off) { |
249 | netdev_info(dev, format: "================>%s(): hwradio off\n" , |
250 | __func__); |
251 | return 0; |
252 | } |
253 | rt_state = priv->rtllib->rf_power_state; |
254 | if (!priv->up) |
255 | return -ENETDOWN; |
256 | if (priv->rtllib->link_detect_info.busy_traffic) |
257 | return -EAGAIN; |
258 | |
259 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { |
260 | struct iw_scan_req *req = (struct iw_scan_req *)b; |
261 | |
262 | if (req->essid_len) { |
263 | int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE); |
264 | |
265 | ieee->current_network.ssid_len = len; |
266 | memcpy(ieee->current_network.ssid, req->essid, len); |
267 | } |
268 | } |
269 | |
270 | mutex_lock(&priv->wx_mutex); |
271 | |
272 | priv->rtllib->first_ie_in_scan = true; |
273 | |
274 | if (priv->rtllib->link_state != MAC80211_LINKED) { |
275 | if (rt_state == rf_off) { |
276 | if (priv->rtllib->rf_off_reason > |
277 | RF_CHANGE_BY_IPS) { |
278 | netdev_warn(dev, format: "%s(): RF is OFF.\n" , |
279 | __func__); |
280 | mutex_unlock(lock: &priv->wx_mutex); |
281 | return -1; |
282 | } |
283 | mutex_lock(&priv->rtllib->ips_mutex); |
284 | rtl92e_ips_leave(dev); |
285 | mutex_unlock(lock: &priv->rtllib->ips_mutex); |
286 | } |
287 | rtllib_stop_scan(ieee: priv->rtllib); |
288 | if (priv->rtllib->rf_power_state != rf_off) { |
289 | priv->rtllib->actscanning = true; |
290 | |
291 | ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP); |
292 | |
293 | rtllib_start_scan_syncro(ieee: priv->rtllib); |
294 | |
295 | ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE); |
296 | } |
297 | ret = 0; |
298 | } else { |
299 | priv->rtllib->actscanning = true; |
300 | ret = rtllib_wx_set_scan(ieee: priv->rtllib, a, wrqu, b); |
301 | } |
302 | |
303 | mutex_unlock(lock: &priv->wx_mutex); |
304 | return ret; |
305 | } |
306 | |
307 | static int _rtl92e_wx_get_scan(struct net_device *dev, |
308 | struct iw_request_info *a, |
309 | union iwreq_data *wrqu, char *b) |
310 | { |
311 | int ret; |
312 | struct r8192_priv *priv = rtllib_priv(dev); |
313 | |
314 | if (!priv->up) |
315 | return -ENETDOWN; |
316 | |
317 | if (priv->hw_radio_off) |
318 | return 0; |
319 | |
320 | mutex_lock(&priv->wx_mutex); |
321 | |
322 | ret = rtllib_wx_get_scan(ieee: priv->rtllib, info: a, wrqu, key: b); |
323 | |
324 | mutex_unlock(lock: &priv->wx_mutex); |
325 | |
326 | return ret; |
327 | } |
328 | |
329 | static int _rtl92e_wx_set_essid(struct net_device *dev, |
330 | struct iw_request_info *a, |
331 | union iwreq_data *wrqu, char *b) |
332 | { |
333 | struct r8192_priv *priv = rtllib_priv(dev); |
334 | int ret; |
335 | |
336 | if (priv->hw_radio_off) { |
337 | netdev_info(dev, |
338 | format: "=========>%s():hw radio off,or Rf state is rf_off, return\n" , |
339 | __func__); |
340 | return 0; |
341 | } |
342 | mutex_lock(&priv->wx_mutex); |
343 | ret = rtllib_wx_set_essid(ieee: priv->rtllib, a, wrqu, extra: b); |
344 | |
345 | mutex_unlock(lock: &priv->wx_mutex); |
346 | |
347 | return ret; |
348 | } |
349 | |
350 | static int _rtl92e_wx_get_essid(struct net_device *dev, |
351 | struct iw_request_info *a, |
352 | union iwreq_data *wrqu, char *b) |
353 | { |
354 | int ret; |
355 | struct r8192_priv *priv = rtllib_priv(dev); |
356 | |
357 | mutex_lock(&priv->wx_mutex); |
358 | |
359 | ret = rtllib_wx_get_essid(ieee: priv->rtllib, a, wrqu, b); |
360 | |
361 | mutex_unlock(lock: &priv->wx_mutex); |
362 | |
363 | return ret; |
364 | } |
365 | |
366 | static int _rtl92e_wx_set_nick(struct net_device *dev, |
367 | struct iw_request_info *info, |
368 | union iwreq_data *wrqu, char *) |
369 | { |
370 | struct r8192_priv *priv = rtllib_priv(dev); |
371 | |
372 | if (wrqu->data.length > IW_ESSID_MAX_SIZE) |
373 | return -E2BIG; |
374 | mutex_lock(&priv->wx_mutex); |
375 | wrqu->data.length = min_t(size_t, wrqu->data.length, |
376 | sizeof(priv->nick)); |
377 | memset(priv->nick, 0, sizeof(priv->nick)); |
378 | memcpy(priv->nick, extra, wrqu->data.length); |
379 | mutex_unlock(lock: &priv->wx_mutex); |
380 | return 0; |
381 | } |
382 | |
383 | static int _rtl92e_wx_get_nick(struct net_device *dev, |
384 | struct iw_request_info *info, |
385 | union iwreq_data *wrqu, char *) |
386 | { |
387 | struct r8192_priv *priv = rtllib_priv(dev); |
388 | |
389 | mutex_lock(&priv->wx_mutex); |
390 | wrqu->data.length = strlen(priv->nick); |
391 | memcpy(extra, priv->nick, wrqu->data.length); |
392 | wrqu->data.flags = 1; /* active */ |
393 | mutex_unlock(lock: &priv->wx_mutex); |
394 | return 0; |
395 | } |
396 | |
397 | static int _rtl92e_wx_set_freq(struct net_device *dev, |
398 | struct iw_request_info *a, |
399 | union iwreq_data *wrqu, char *b) |
400 | { |
401 | int ret; |
402 | struct r8192_priv *priv = rtllib_priv(dev); |
403 | |
404 | if (priv->hw_radio_off) |
405 | return 0; |
406 | |
407 | mutex_lock(&priv->wx_mutex); |
408 | |
409 | ret = rtllib_wx_set_freq(ieee: priv->rtllib, a, wrqu, b); |
410 | |
411 | mutex_unlock(lock: &priv->wx_mutex); |
412 | return ret; |
413 | } |
414 | |
415 | static int _rtl92e_wx_get_name(struct net_device *dev, |
416 | struct iw_request_info *info, |
417 | union iwreq_data *wrqu, char *) |
418 | { |
419 | struct r8192_priv *priv = rtllib_priv(dev); |
420 | |
421 | return rtllib_wx_get_name(ieee: priv->rtllib, info, wrqu, extra); |
422 | } |
423 | |
424 | static int _rtl92e_wx_set_frag(struct net_device *dev, |
425 | struct iw_request_info *info, |
426 | union iwreq_data *wrqu, char *) |
427 | { |
428 | struct r8192_priv *priv = rtllib_priv(dev); |
429 | |
430 | if (priv->hw_radio_off) |
431 | return 0; |
432 | |
433 | if (wrqu->frag.disabled) { |
434 | priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD; |
435 | } else { |
436 | if (wrqu->frag.value < MIN_FRAG_THRESHOLD || |
437 | wrqu->frag.value > MAX_FRAG_THRESHOLD) |
438 | return -EINVAL; |
439 | |
440 | priv->rtllib->fts = wrqu->frag.value & ~0x1; |
441 | } |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | static int _rtl92e_wx_get_frag(struct net_device *dev, |
447 | struct iw_request_info *info, |
448 | union iwreq_data *wrqu, char *) |
449 | { |
450 | struct r8192_priv *priv = rtllib_priv(dev); |
451 | |
452 | wrqu->frag.value = priv->rtllib->fts; |
453 | wrqu->frag.fixed = 0; /* no auto select */ |
454 | wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); |
455 | |
456 | return 0; |
457 | } |
458 | |
459 | static int _rtl92e_wx_set_wap(struct net_device *dev, |
460 | struct iw_request_info *info, |
461 | union iwreq_data *awrq, char *) |
462 | { |
463 | int ret; |
464 | struct r8192_priv *priv = rtllib_priv(dev); |
465 | |
466 | if (priv->hw_radio_off) |
467 | return 0; |
468 | |
469 | mutex_lock(&priv->wx_mutex); |
470 | |
471 | ret = rtllib_wx_set_wap(ieee: priv->rtllib, info, awrq, extra); |
472 | |
473 | mutex_unlock(lock: &priv->wx_mutex); |
474 | |
475 | return ret; |
476 | } |
477 | |
478 | static int _rtl92e_wx_get_wap(struct net_device *dev, |
479 | struct iw_request_info *info, |
480 | union iwreq_data *wrqu, char *) |
481 | { |
482 | struct r8192_priv *priv = rtllib_priv(dev); |
483 | |
484 | return rtllib_wx_get_wap(ieee: priv->rtllib, info, wrqu, ext: extra); |
485 | } |
486 | |
487 | static int _rtl92e_wx_get_enc(struct net_device *dev, |
488 | struct iw_request_info *info, |
489 | union iwreq_data *wrqu, char *key) |
490 | { |
491 | struct r8192_priv *priv = rtllib_priv(dev); |
492 | |
493 | return rtllib_wx_get_encode(ieee: priv->rtllib, info, wrqu, key); |
494 | } |
495 | |
496 | static int _rtl92e_wx_set_enc(struct net_device *dev, |
497 | struct iw_request_info *info, |
498 | union iwreq_data *wrqu, char *key) |
499 | { |
500 | struct r8192_priv *priv = rtllib_priv(dev); |
501 | int ret; |
502 | |
503 | struct rtllib_device *ieee = priv->rtllib; |
504 | u32 hwkey[4] = {0, 0, 0, 0}; |
505 | u8 mask = 0xff; |
506 | u32 key_idx = 0; |
507 | u8 zero_addr[4][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, |
508 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, |
509 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, |
510 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} }; |
511 | int i; |
512 | |
513 | if (priv->hw_radio_off) |
514 | return 0; |
515 | |
516 | if (!priv->up) |
517 | return -ENETDOWN; |
518 | |
519 | priv->rtllib->wx_set_enc = 1; |
520 | mutex_lock(&priv->rtllib->ips_mutex); |
521 | rtl92e_ips_leave(dev); |
522 | mutex_unlock(lock: &priv->rtllib->ips_mutex); |
523 | mutex_lock(&priv->wx_mutex); |
524 | |
525 | ret = rtllib_wx_set_encode(ieee: priv->rtllib, info, wrqu, key); |
526 | mutex_unlock(lock: &priv->wx_mutex); |
527 | |
528 | if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { |
529 | ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; |
530 | rtl92e_cam_reset(dev); |
531 | memset(priv->rtllib->swcamtable, 0, |
532 | sizeof(struct sw_cam_table) * 32); |
533 | goto end_hw_sec; |
534 | } |
535 | if (wrqu->encoding.length != 0) { |
536 | for (i = 0; i < 4; i++) { |
537 | hwkey[i] |= key[4 * i + 0] & mask; |
538 | if (i == 1 && (4 * i + 1) == wrqu->encoding.length) |
539 | mask = 0x00; |
540 | if (i == 3 && (4 * i + 1) == wrqu->encoding.length) |
541 | mask = 0x00; |
542 | hwkey[i] |= (key[4 * i + 1] & mask) << 8; |
543 | hwkey[i] |= (key[4 * i + 2] & mask) << 16; |
544 | hwkey[i] |= (key[4 * i + 3] & mask) << 24; |
545 | } |
546 | |
547 | switch (wrqu->encoding.flags & IW_ENCODE_INDEX) { |
548 | case 0: |
549 | key_idx = ieee->crypt_info.tx_keyidx; |
550 | break; |
551 | case 1: |
552 | key_idx = 0; |
553 | break; |
554 | case 2: |
555 | key_idx = 1; |
556 | break; |
557 | case 3: |
558 | key_idx = 2; |
559 | break; |
560 | case 4: |
561 | key_idx = 3; |
562 | break; |
563 | default: |
564 | break; |
565 | } |
566 | if (wrqu->encoding.length == 0x5) { |
567 | ieee->pairwise_key_type = KEY_TYPE_WEP40; |
568 | rtl92e_enable_hw_security_config(dev); |
569 | } |
570 | |
571 | else if (wrqu->encoding.length == 0xd) { |
572 | ieee->pairwise_key_type = KEY_TYPE_WEP104; |
573 | rtl92e_enable_hw_security_config(dev); |
574 | rtl92e_set_key(dev, EntryNo: key_idx, KeyIndex: key_idx, KEY_TYPE_WEP104, |
575 | MacAddr: zero_addr[key_idx], DefaultKey: 0, KeyContent: hwkey); |
576 | rtl92e_set_swcam(dev, EntryNo: key_idx, KeyIndex: key_idx, KEY_TYPE_WEP104, |
577 | MacAddr: zero_addr[key_idx], KeyContent: hwkey); |
578 | } else { |
579 | netdev_info(dev, |
580 | format: "wrong type in WEP, not WEP40 and WEP104\n" ); |
581 | } |
582 | } |
583 | |
584 | end_hw_sec: |
585 | priv->rtllib->wx_set_enc = 0; |
586 | return ret; |
587 | } |
588 | |
589 | #define R8192_MAX_RETRY 255 |
590 | static int _rtl92e_wx_set_retry(struct net_device *dev, |
591 | struct iw_request_info *info, |
592 | union iwreq_data *wrqu, char *) |
593 | { |
594 | struct r8192_priv *priv = rtllib_priv(dev); |
595 | int err = 0; |
596 | |
597 | if (priv->hw_radio_off) |
598 | return 0; |
599 | |
600 | mutex_lock(&priv->wx_mutex); |
601 | |
602 | if (wrqu->retry.flags & IW_RETRY_LIFETIME || |
603 | wrqu->retry.disabled) { |
604 | err = -EINVAL; |
605 | goto exit; |
606 | } |
607 | if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) { |
608 | err = -EINVAL; |
609 | goto exit; |
610 | } |
611 | |
612 | if (wrqu->retry.value > R8192_MAX_RETRY) { |
613 | err = -EINVAL; |
614 | goto exit; |
615 | } |
616 | if (wrqu->retry.flags & IW_RETRY_MAX) |
617 | priv->retry_rts = wrqu->retry.value; |
618 | else |
619 | priv->retry_data = wrqu->retry.value; |
620 | |
621 | rtl92e_commit(dev); |
622 | exit: |
623 | mutex_unlock(lock: &priv->wx_mutex); |
624 | |
625 | return err; |
626 | } |
627 | |
628 | static int _rtl92e_wx_get_retry(struct net_device *dev, |
629 | struct iw_request_info *info, |
630 | union iwreq_data *wrqu, char *) |
631 | { |
632 | struct r8192_priv *priv = rtllib_priv(dev); |
633 | |
634 | wrqu->retry.disabled = 0; /* can't be disabled */ |
635 | |
636 | if ((wrqu->retry.flags & IW_RETRY_TYPE) == |
637 | IW_RETRY_LIFETIME) |
638 | return -EINVAL; |
639 | |
640 | if (wrqu->retry.flags & IW_RETRY_MAX) { |
641 | wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; |
642 | wrqu->retry.value = priv->retry_rts; |
643 | } else { |
644 | wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; |
645 | wrqu->retry.value = priv->retry_data; |
646 | } |
647 | return 0; |
648 | } |
649 | |
650 | static int _rtl92e_wx_set_encode_ext(struct net_device *dev, |
651 | struct iw_request_info *info, |
652 | union iwreq_data *wrqu, char *) |
653 | { |
654 | int ret = 0; |
655 | struct r8192_priv *priv = rtllib_priv(dev); |
656 | struct rtllib_device *ieee = priv->rtllib; |
657 | |
658 | if (priv->hw_radio_off) |
659 | return 0; |
660 | |
661 | mutex_lock(&priv->wx_mutex); |
662 | |
663 | priv->rtllib->wx_set_enc = 1; |
664 | mutex_lock(&priv->rtllib->ips_mutex); |
665 | rtl92e_ips_leave(dev); |
666 | mutex_unlock(lock: &priv->rtllib->ips_mutex); |
667 | |
668 | ret = rtllib_wx_set_encode_ext(ieee, info, wrqu, extra); |
669 | { |
670 | const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
671 | const u8 zero[ETH_ALEN] = {0}; |
672 | u32 key[4] = {0}; |
673 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
674 | struct iw_point *encoding = &wrqu->encoding; |
675 | u8 idx = 0, alg = 0, group = 0; |
676 | |
677 | if ((encoding->flags & IW_ENCODE_DISABLED) || |
678 | ext->alg == IW_ENCODE_ALG_NONE) { |
679 | ieee->pairwise_key_type = ieee->group_key_type |
680 | = KEY_TYPE_NA; |
681 | rtl92e_cam_reset(dev); |
682 | memset(priv->rtllib->swcamtable, 0, |
683 | sizeof(struct sw_cam_table) * 32); |
684 | goto end_hw_sec; |
685 | } |
686 | alg = (ext->alg == IW_ENCODE_ALG_CCMP) ? KEY_TYPE_CCMP : |
687 | ext->alg; |
688 | idx = encoding->flags & IW_ENCODE_INDEX; |
689 | if (idx) |
690 | idx--; |
691 | group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY; |
692 | |
693 | if ((!group) || (alg == KEY_TYPE_WEP40)) { |
694 | if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40)) |
695 | alg = KEY_TYPE_WEP104; |
696 | ieee->pairwise_key_type = alg; |
697 | rtl92e_enable_hw_security_config(dev); |
698 | } |
699 | memcpy((u8 *)key, ext->key, 16); |
700 | |
701 | if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) { |
702 | if (ext->key_len == 13) |
703 | ieee->pairwise_key_type = alg = KEY_TYPE_WEP104; |
704 | rtl92e_set_key(dev, EntryNo: idx, KeyIndex: idx, KeyType: alg, MacAddr: zero, DefaultKey: 0, KeyContent: key); |
705 | rtl92e_set_swcam(dev, EntryNo: idx, KeyIndex: idx, KeyType: alg, MacAddr: zero, KeyContent: key); |
706 | } else if (group) { |
707 | ieee->group_key_type = alg; |
708 | rtl92e_set_key(dev, EntryNo: idx, KeyIndex: idx, KeyType: alg, MacAddr: broadcast_addr, DefaultKey: 0, |
709 | KeyContent: key); |
710 | rtl92e_set_swcam(dev, EntryNo: idx, KeyIndex: idx, KeyType: alg, MacAddr: broadcast_addr, KeyContent: key); |
711 | } else { |
712 | if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && |
713 | ieee->ht_info->current_ht_support) |
714 | rtl92e_writeb(dev, x: 0x173, y: 1); |
715 | rtl92e_set_key(dev, EntryNo: 4, KeyIndex: idx, KeyType: alg, |
716 | MacAddr: (u8 *)ieee->ap_mac_addr, DefaultKey: 0, KeyContent: key); |
717 | rtl92e_set_swcam(dev, EntryNo: 4, KeyIndex: idx, KeyType: alg, MacAddr: (u8 *)ieee->ap_mac_addr, KeyContent: key); |
718 | } |
719 | } |
720 | |
721 | end_hw_sec: |
722 | priv->rtllib->wx_set_enc = 0; |
723 | mutex_unlock(lock: &priv->wx_mutex); |
724 | return ret; |
725 | } |
726 | |
727 | static int _rtl92e_wx_set_auth(struct net_device *dev, |
728 | struct iw_request_info *info, |
729 | union iwreq_data *data, char *) |
730 | { |
731 | int ret = 0; |
732 | |
733 | struct r8192_priv *priv = rtllib_priv(dev); |
734 | |
735 | if (priv->hw_radio_off) |
736 | return 0; |
737 | |
738 | mutex_lock(&priv->wx_mutex); |
739 | ret = rtllib_wx_set_auth(ieee: priv->rtllib, info, data: &data->param, extra); |
740 | mutex_unlock(lock: &priv->wx_mutex); |
741 | return ret; |
742 | } |
743 | |
744 | static int _rtl92e_wx_set_mlme(struct net_device *dev, |
745 | struct iw_request_info *info, |
746 | union iwreq_data *wrqu, char *) |
747 | { |
748 | int ret = 0; |
749 | |
750 | struct r8192_priv *priv = rtllib_priv(dev); |
751 | |
752 | if (priv->hw_radio_off) |
753 | return 0; |
754 | |
755 | mutex_lock(&priv->wx_mutex); |
756 | ret = rtllib_wx_set_mlme(ieee: priv->rtllib, info, wrqu, extra); |
757 | mutex_unlock(lock: &priv->wx_mutex); |
758 | return ret; |
759 | } |
760 | |
761 | static int _rtl92e_wx_set_gen_ie(struct net_device *dev, |
762 | struct iw_request_info *info, |
763 | union iwreq_data *data, char *) |
764 | { |
765 | int ret = 0; |
766 | |
767 | struct r8192_priv *priv = rtllib_priv(dev); |
768 | |
769 | if (priv->hw_radio_off) |
770 | return 0; |
771 | |
772 | mutex_lock(&priv->wx_mutex); |
773 | ret = rtllib_wx_set_gen_ie(ieee: priv->rtllib, ie: extra, len: data->data.length); |
774 | mutex_unlock(lock: &priv->wx_mutex); |
775 | return ret; |
776 | } |
777 | |
778 | static int _rtl92e_wx_get_gen_ie(struct net_device *dev, |
779 | struct iw_request_info *info, |
780 | union iwreq_data *data, char *) |
781 | { |
782 | int ret = 0; |
783 | struct r8192_priv *priv = rtllib_priv(dev); |
784 | struct rtllib_device *ieee = priv->rtllib; |
785 | |
786 | if (ieee->wpa_ie_len == 0 || !ieee->wpa_ie) { |
787 | data->data.length = 0; |
788 | return 0; |
789 | } |
790 | |
791 | if (data->data.length < ieee->wpa_ie_len) |
792 | return -E2BIG; |
793 | |
794 | data->data.length = ieee->wpa_ie_len; |
795 | memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); |
796 | return ret; |
797 | } |
798 | |
799 | #define IW_IOCTL(x) ((x) - SIOCSIWCOMMIT) |
800 | static iw_handler r8192_wx_handlers[] = { |
801 | [IW_IOCTL(SIOCGIWNAME)] = _rtl92e_wx_get_name, |
802 | [IW_IOCTL(SIOCSIWFREQ)] = _rtl92e_wx_set_freq, |
803 | [IW_IOCTL(SIOCGIWFREQ)] = _rtl92e_wx_get_freq, |
804 | [IW_IOCTL(SIOCSIWMODE)] = _rtl92e_wx_set_mode, |
805 | [IW_IOCTL(SIOCGIWMODE)] = _rtl92e_wx_get_mode, |
806 | [IW_IOCTL(SIOCGIWRANGE)] = _rtl92e_wx_get_range, |
807 | [IW_IOCTL(SIOCSIWAP)] = _rtl92e_wx_set_wap, |
808 | [IW_IOCTL(SIOCGIWAP)] = _rtl92e_wx_get_wap, |
809 | [IW_IOCTL(SIOCSIWSCAN)] = _rtl92e_wx_set_scan, |
810 | [IW_IOCTL(SIOCGIWSCAN)] = _rtl92e_wx_get_scan, |
811 | [IW_IOCTL(SIOCSIWESSID)] = _rtl92e_wx_set_essid, |
812 | [IW_IOCTL(SIOCGIWESSID)] = _rtl92e_wx_get_essid, |
813 | [IW_IOCTL(SIOCSIWNICKN)] = _rtl92e_wx_set_nick, |
814 | [IW_IOCTL(SIOCGIWNICKN)] = _rtl92e_wx_get_nick, |
815 | [IW_IOCTL(SIOCSIWRATE)] = _rtl92e_wx_set_rate, |
816 | [IW_IOCTL(SIOCGIWRATE)] = _rtl92e_wx_get_rate, |
817 | [IW_IOCTL(SIOCSIWRTS)] = _rtl92e_wx_set_rts, |
818 | [IW_IOCTL(SIOCGIWRTS)] = _rtl92e_wx_get_rts, |
819 | [IW_IOCTL(SIOCSIWFRAG)] = _rtl92e_wx_set_frag, |
820 | [IW_IOCTL(SIOCGIWFRAG)] = _rtl92e_wx_get_frag, |
821 | [IW_IOCTL(SIOCSIWRETRY)] = _rtl92e_wx_set_retry, |
822 | [IW_IOCTL(SIOCGIWRETRY)] = _rtl92e_wx_get_retry, |
823 | [IW_IOCTL(SIOCSIWENCODE)] = _rtl92e_wx_set_enc, |
824 | [IW_IOCTL(SIOCGIWENCODE)] = _rtl92e_wx_get_enc, |
825 | [IW_IOCTL(SIOCSIWPOWER)] = _rtl92e_wx_set_power, |
826 | [IW_IOCTL(SIOCGIWPOWER)] = _rtl92e_wx_get_power, |
827 | [IW_IOCTL(SIOCSIWGENIE)] = _rtl92e_wx_set_gen_ie, |
828 | [IW_IOCTL(SIOCGIWGENIE)] = _rtl92e_wx_get_gen_ie, |
829 | [IW_IOCTL(SIOCSIWMLME)] = _rtl92e_wx_set_mlme, |
830 | [IW_IOCTL(SIOCSIWAUTH)] = _rtl92e_wx_set_auth, |
831 | [IW_IOCTL(SIOCSIWENCODEEXT)] = _rtl92e_wx_set_encode_ext, |
832 | }; |
833 | |
834 | static struct iw_statistics *_rtl92e_get_wireless_stats(struct net_device *dev) |
835 | { |
836 | struct r8192_priv *priv = rtllib_priv(dev); |
837 | struct rtllib_device *ieee = priv->rtllib; |
838 | struct iw_statistics *wstats = &priv->wstats; |
839 | int tmp_level = 0; |
840 | int tmp_qual = 0; |
841 | int tmp_noise = 0; |
842 | |
843 | if (ieee->link_state < MAC80211_LINKED) { |
844 | wstats->qual.qual = 10; |
845 | wstats->qual.level = 0; |
846 | wstats->qual.noise = 0x100 - 100; /* -100 dBm */ |
847 | wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; |
848 | return wstats; |
849 | } |
850 | |
851 | tmp_level = (&ieee->current_network)->stats.rssi; |
852 | tmp_qual = (&ieee->current_network)->stats.signal; |
853 | tmp_noise = (&ieee->current_network)->stats.noise; |
854 | |
855 | wstats->qual.level = tmp_level; |
856 | wstats->qual.qual = tmp_qual; |
857 | wstats->qual.noise = tmp_noise; |
858 | wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; |
859 | return wstats; |
860 | } |
861 | |
862 | const struct iw_handler_def r8192_wx_handlers_def = { |
863 | .standard = r8192_wx_handlers, |
864 | .num_standard = ARRAY_SIZE(r8192_wx_handlers), |
865 | .get_wireless_stats = _rtl92e_get_wireless_stats, |
866 | }; |
867 | |