Merge tag 'pci-v5.14-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaa...
[linux-2.6-microblaze.git] / drivers / staging / rtl8192e / rtllib_softmac_wx.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* IEEE 802.11 SoftMAC layer
3  * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
4  *
5  * Mostly extracted from the rtl8180-sa2400 driver for the
6  * in-kernel generic ieee802.11 stack.
7  *
8  * Some pieces of code might be stolen from ipw2100 driver
9  * copyright of who own it's copyright ;-)
10  *
11  * PS wx handler mostly stolen from hostap, copyright who
12  * own it's copyright ;-)
13  */
14 #include <linux/etherdevice.h>
15
16 #include "rtllib.h"
17 #include "dot11d.h"
18 /* FIXME: add A freqs */
19
20 const long rtllib_wlan_frequencies[] = {
21         2412, 2417, 2422, 2427,
22         2432, 2437, 2442, 2447,
23         2452, 2457, 2462, 2467,
24         2472, 2484
25 };
26 EXPORT_SYMBOL(rtllib_wlan_frequencies);
27
28
29 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
30                              union iwreq_data *wrqu, char *b)
31 {
32         int ret;
33         struct iw_freq *fwrq = &wrqu->freq;
34
35         mutex_lock(&ieee->wx_mutex);
36
37         if (ieee->iw_mode == IW_MODE_INFRA) {
38                 ret = 0;
39                 goto out;
40         }
41
42         /* if setting by freq convert to channel */
43         if (fwrq->e == 1) {
44                 if ((fwrq->m >= (int) 2.412e8 &&
45                      fwrq->m <= (int) 2.487e8)) {
46                         int f = fwrq->m / 100000;
47                         int c = 0;
48
49                         while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
50                                 c++;
51
52                         /* hack to fall through */
53                         fwrq->e = 0;
54                         fwrq->m = c + 1;
55                 }
56         }
57
58         if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
59                 ret = -EOPNOTSUPP;
60                 goto out;
61
62         } else { /* Set the channel */
63
64                 if (ieee->active_channel_map[fwrq->m] != 1) {
65                         ret = -EINVAL;
66                         goto out;
67                 }
68                 ieee->current_network.channel = fwrq->m;
69                 ieee->set_chan(ieee->dev, ieee->current_network.channel);
70
71                 if (ieee->iw_mode == IW_MODE_ADHOC ||
72                     ieee->iw_mode == IW_MODE_MASTER)
73                         if (ieee->state == RTLLIB_LINKED) {
74                                 rtllib_stop_send_beacons(ieee);
75                                 rtllib_start_send_beacons(ieee);
76                         }
77         }
78
79         ret = 0;
80 out:
81         mutex_unlock(&ieee->wx_mutex);
82         return ret;
83 }
84 EXPORT_SYMBOL(rtllib_wx_set_freq);
85
86
87 int rtllib_wx_get_freq(struct rtllib_device *ieee,
88                              struct iw_request_info *a,
89                              union iwreq_data *wrqu, char *b)
90 {
91         struct iw_freq *fwrq = &wrqu->freq;
92
93         if (ieee->current_network.channel == 0)
94                 return -1;
95         fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
96                   100000;
97         fwrq->e = 1;
98         return 0;
99 }
100 EXPORT_SYMBOL(rtllib_wx_get_freq);
101
102 int rtllib_wx_get_wap(struct rtllib_device *ieee,
103                             struct iw_request_info *info,
104                             union iwreq_data *wrqu, char *extra)
105 {
106         unsigned long flags;
107
108         wrqu->ap_addr.sa_family = ARPHRD_ETHER;
109
110         if (ieee->iw_mode == IW_MODE_MONITOR)
111                 return -1;
112
113         /* We want avoid to give to the user inconsistent infos*/
114         spin_lock_irqsave(&ieee->lock, flags);
115
116         if (ieee->state != RTLLIB_LINKED &&
117                 ieee->state != RTLLIB_LINKED_SCANNING &&
118                 ieee->wap_set == 0)
119
120                 eth_zero_addr(wrqu->ap_addr.sa_data);
121         else
122                 memcpy(wrqu->ap_addr.sa_data,
123                        ieee->current_network.bssid, ETH_ALEN);
124
125         spin_unlock_irqrestore(&ieee->lock, flags);
126
127         return 0;
128 }
129 EXPORT_SYMBOL(rtllib_wx_get_wap);
130
131
132 int rtllib_wx_set_wap(struct rtllib_device *ieee,
133                          struct iw_request_info *info,
134                          union iwreq_data *awrq,
135                          char *extra)
136 {
137
138         int ret = 0;
139         unsigned long flags;
140
141         short ifup = ieee->proto_started;
142         struct sockaddr *temp = (struct sockaddr *)awrq;
143
144         rtllib_stop_scan_syncro(ieee);
145
146         mutex_lock(&ieee->wx_mutex);
147         /* use ifconfig hw ether */
148         if (ieee->iw_mode == IW_MODE_MASTER) {
149                 ret = -1;
150                 goto out;
151         }
152
153         if (temp->sa_family != ARPHRD_ETHER) {
154                 ret = -EINVAL;
155                 goto out;
156         }
157
158         if (is_zero_ether_addr(temp->sa_data)) {
159                 spin_lock_irqsave(&ieee->lock, flags);
160                 ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
161                 ieee->wap_set = 0;
162                 spin_unlock_irqrestore(&ieee->lock, flags);
163                 ret = -1;
164                 goto out;
165         }
166
167
168         if (ifup)
169                 rtllib_stop_protocol(ieee, true);
170
171         /* just to avoid to give inconsistent infos in the
172          * get wx method. not really needed otherwise
173          */
174         spin_lock_irqsave(&ieee->lock, flags);
175
176         ieee->cannot_notify = false;
177         ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
178         ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
179
180         spin_unlock_irqrestore(&ieee->lock, flags);
181
182         if (ifup)
183                 rtllib_start_protocol(ieee);
184 out:
185         mutex_unlock(&ieee->wx_mutex);
186         return ret;
187 }
188 EXPORT_SYMBOL(rtllib_wx_set_wap);
189
190 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
191                          union iwreq_data *wrqu, char *b)
192 {
193         int len, ret = 0;
194         unsigned long flags;
195
196         if (ieee->iw_mode == IW_MODE_MONITOR)
197                 return -1;
198
199         /* We want avoid to give to the user inconsistent infos*/
200         spin_lock_irqsave(&ieee->lock, flags);
201
202         if (ieee->current_network.ssid[0] == '\0' ||
203                 ieee->current_network.ssid_len == 0) {
204                 ret = -1;
205                 goto out;
206         }
207
208         if (ieee->state != RTLLIB_LINKED &&
209                 ieee->state != RTLLIB_LINKED_SCANNING &&
210                 ieee->ssid_set == 0) {
211                 ret = -1;
212                 goto out;
213         }
214         len = ieee->current_network.ssid_len;
215         wrqu->essid.length = len;
216         strncpy(b, ieee->current_network.ssid, len);
217         wrqu->essid.flags = 1;
218
219 out:
220         spin_unlock_irqrestore(&ieee->lock, flags);
221
222         return ret;
223
224 }
225 EXPORT_SYMBOL(rtllib_wx_get_essid);
226
227 int rtllib_wx_set_rate(struct rtllib_device *ieee,
228                              struct iw_request_info *info,
229                              union iwreq_data *wrqu, char *extra)
230 {
231
232         u32 target_rate = wrqu->bitrate.value;
233
234         ieee->rate = target_rate/100000;
235         return 0;
236 }
237 EXPORT_SYMBOL(rtllib_wx_set_rate);
238
239 int rtllib_wx_get_rate(struct rtllib_device *ieee,
240                              struct iw_request_info *info,
241                              union iwreq_data *wrqu, char *extra)
242 {
243         u32 tmp_rate;
244
245         tmp_rate = TxCountToDataRate(ieee,
246                                      ieee->softmac_stats.CurrentShowTxate);
247         wrqu->bitrate.value = tmp_rate * 500000;
248
249         return 0;
250 }
251 EXPORT_SYMBOL(rtllib_wx_get_rate);
252
253
254 int rtllib_wx_set_rts(struct rtllib_device *ieee,
255                              struct iw_request_info *info,
256                              union iwreq_data *wrqu, char *extra)
257 {
258         if (wrqu->rts.disabled || !wrqu->rts.fixed)
259                 ieee->rts = DEFAULT_RTS_THRESHOLD;
260         else {
261                 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
262                                 wrqu->rts.value > MAX_RTS_THRESHOLD)
263                         return -EINVAL;
264                 ieee->rts = wrqu->rts.value;
265         }
266         return 0;
267 }
268 EXPORT_SYMBOL(rtllib_wx_set_rts);
269
270 int rtllib_wx_get_rts(struct rtllib_device *ieee,
271                              struct iw_request_info *info,
272                              union iwreq_data *wrqu, char *extra)
273 {
274         wrqu->rts.value = ieee->rts;
275         wrqu->rts.fixed = 0;    /* no auto select */
276         wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
277         return 0;
278 }
279 EXPORT_SYMBOL(rtllib_wx_get_rts);
280
281 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
282                              union iwreq_data *wrqu, char *b)
283 {
284         int set_mode_status = 0;
285
286         rtllib_stop_scan_syncro(ieee);
287         mutex_lock(&ieee->wx_mutex);
288         switch (wrqu->mode) {
289         case IW_MODE_MONITOR:
290         case IW_MODE_ADHOC:
291         case IW_MODE_INFRA:
292                 break;
293         case IW_MODE_AUTO:
294                 wrqu->mode = IW_MODE_INFRA;
295                 break;
296         default:
297                 set_mode_status = -EINVAL;
298                 goto out;
299         }
300
301         if (wrqu->mode == ieee->iw_mode)
302                 goto out;
303
304         if (wrqu->mode == IW_MODE_MONITOR) {
305                 ieee->dev->type = ARPHRD_IEEE80211;
306                 rtllib_EnableNetMonitorMode(ieee->dev, false);
307         } else {
308                 ieee->dev->type = ARPHRD_ETHER;
309                 if (ieee->iw_mode == IW_MODE_MONITOR)
310                         rtllib_DisableNetMonitorMode(ieee->dev, false);
311         }
312
313         if (!ieee->proto_started) {
314                 ieee->iw_mode = wrqu->mode;
315         } else {
316                 rtllib_stop_protocol(ieee, true);
317                 ieee->iw_mode = wrqu->mode;
318                 rtllib_start_protocol(ieee);
319         }
320
321 out:
322         mutex_unlock(&ieee->wx_mutex);
323         return set_mode_status;
324 }
325 EXPORT_SYMBOL(rtllib_wx_set_mode);
326
327 void rtllib_wx_sync_scan_wq(void *data)
328 {
329         struct rtllib_device *ieee = container_of_work_rsl(data,
330                                      struct rtllib_device, wx_sync_scan_wq);
331         short chan;
332         enum ht_extchnl_offset chan_offset = 0;
333         enum ht_channel_width bandwidth = 0;
334         int b40M = 0;
335
336         if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
337                 rtllib_start_scan_syncro(ieee, 0);
338                 goto out;
339         }
340
341         chan = ieee->current_network.channel;
342
343         if (ieee->LeisurePSLeave)
344                 ieee->LeisurePSLeave(ieee->dev);
345         /* notify AP to be in PS mode */
346         rtllib_sta_ps_send_null_frame(ieee, 1);
347         rtllib_sta_ps_send_null_frame(ieee, 1);
348
349         rtllib_stop_all_queues(ieee);
350
351         if (ieee->data_hard_stop)
352                 ieee->data_hard_stop(ieee->dev);
353         rtllib_stop_send_beacons(ieee);
354         ieee->state = RTLLIB_LINKED_SCANNING;
355         ieee->link_change(ieee->dev);
356         /* wait for ps packet to be kicked out successfully */
357         msleep(50);
358
359         if (ieee->ScanOperationBackupHandler)
360                 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
361
362         if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
363             ieee->pHTInfo->bCurBW40MHz) {
364                 b40M = 1;
365                 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
366                 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
367                 RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
368                          chan_offset, bandwidth);
369                 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
370                                        HT_EXTCHNL_OFFSET_NO_EXT);
371         }
372
373         rtllib_start_scan_syncro(ieee, 0);
374
375         if (b40M) {
376                 RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
377                 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
378                         ieee->set_chan(ieee->dev, chan + 2);
379                 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
380                         ieee->set_chan(ieee->dev, chan - 2);
381                 else
382                         ieee->set_chan(ieee->dev, chan);
383                 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
384         } else {
385                 ieee->set_chan(ieee->dev, chan);
386         }
387
388         if (ieee->ScanOperationBackupHandler)
389                 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
390
391         ieee->state = RTLLIB_LINKED;
392         ieee->link_change(ieee->dev);
393
394         /* Notify AP that I wake up again */
395         rtllib_sta_ps_send_null_frame(ieee, 0);
396
397         if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
398             ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
399                 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
400                 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
401         }
402
403         if (ieee->data_hard_resume)
404                 ieee->data_hard_resume(ieee->dev);
405
406         if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
407                 rtllib_start_send_beacons(ieee);
408
409         rtllib_wake_all_queues(ieee);
410
411 out:
412         mutex_unlock(&ieee->wx_mutex);
413
414 }
415
416 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
417                              union iwreq_data *wrqu, char *b)
418 {
419         int ret = 0;
420
421         mutex_lock(&ieee->wx_mutex);
422
423         if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
424                 ret = -1;
425                 goto out;
426         }
427
428         if (ieee->state == RTLLIB_LINKED) {
429                 schedule_work(&ieee->wx_sync_scan_wq);
430                 /* intentionally forget to up sem */
431                 return 0;
432         }
433
434 out:
435         mutex_unlock(&ieee->wx_mutex);
436         return ret;
437 }
438 EXPORT_SYMBOL(rtllib_wx_set_scan);
439
440 int rtllib_wx_set_essid(struct rtllib_device *ieee,
441                         struct iw_request_info *a,
442                         union iwreq_data *wrqu, char *extra)
443 {
444
445         int ret = 0, len, i;
446         short proto_started;
447         unsigned long flags;
448
449         rtllib_stop_scan_syncro(ieee);
450         mutex_lock(&ieee->wx_mutex);
451
452         proto_started = ieee->proto_started;
453
454         len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
455
456         if (ieee->iw_mode == IW_MODE_MONITOR) {
457                 ret = -1;
458                 goto out;
459         }
460
461         for (i = 0; i < len; i++) {
462                 if (extra[i] < 0) {
463                         ret = -1;
464                         goto out;
465                 }
466         }
467
468         if (proto_started)
469                 rtllib_stop_protocol(ieee, true);
470
471
472         /* this is just to be sure that the GET wx callback
473          * has consistent infos. not needed otherwise
474          */
475         spin_lock_irqsave(&ieee->lock, flags);
476
477         if (wrqu->essid.flags && wrqu->essid.length) {
478                 strncpy(ieee->current_network.ssid, extra, len);
479                 ieee->current_network.ssid_len = len;
480                 ieee->cannot_notify = false;
481                 ieee->ssid_set = 1;
482         } else {
483                 ieee->ssid_set = 0;
484                 ieee->current_network.ssid[0] = '\0';
485                 ieee->current_network.ssid_len = 0;
486         }
487         spin_unlock_irqrestore(&ieee->lock, flags);
488
489         if (proto_started)
490                 rtllib_start_protocol(ieee);
491 out:
492         mutex_unlock(&ieee->wx_mutex);
493         return ret;
494 }
495 EXPORT_SYMBOL(rtllib_wx_set_essid);
496
497 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
498                        union iwreq_data *wrqu, char *b)
499 {
500         wrqu->mode = ieee->iw_mode;
501         return 0;
502 }
503 EXPORT_SYMBOL(rtllib_wx_get_mode);
504
505 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
506                         struct iw_request_info *info,
507                         union iwreq_data *wrqu, char *extra)
508 {
509
510         int *parms = (int *)extra;
511         int enable = (parms[0] > 0);
512         short prev = ieee->raw_tx;
513
514         mutex_lock(&ieee->wx_mutex);
515
516         if (enable)
517                 ieee->raw_tx = 1;
518         else
519                 ieee->raw_tx = 0;
520
521         netdev_info(ieee->dev, "raw TX is %s\n",
522                     ieee->raw_tx ? "enabled" : "disabled");
523
524         if (ieee->iw_mode == IW_MODE_MONITOR) {
525                 if (prev == 0 && ieee->raw_tx) {
526                         if (ieee->data_hard_resume)
527                                 ieee->data_hard_resume(ieee->dev);
528
529                         netif_carrier_on(ieee->dev);
530                 }
531
532                 if (prev && ieee->raw_tx == 1)
533                         netif_carrier_off(ieee->dev);
534         }
535
536         mutex_unlock(&ieee->wx_mutex);
537
538         return 0;
539 }
540 EXPORT_SYMBOL(rtllib_wx_set_rawtx);
541
542 int rtllib_wx_get_name(struct rtllib_device *ieee,
543                              struct iw_request_info *info,
544                              union iwreq_data *wrqu, char *extra)
545 {
546         strcpy(wrqu->name, "802.11");
547
548         if (ieee->modulation & RTLLIB_CCK_MODULATION)
549                 strcat(wrqu->name, "b");
550         if (ieee->modulation & RTLLIB_OFDM_MODULATION)
551                 strcat(wrqu->name, "g");
552         if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
553                 strcat(wrqu->name, "n");
554         return 0;
555 }
556 EXPORT_SYMBOL(rtllib_wx_get_name);
557
558
559 /* this is mostly stolen from hostap */
560 int rtllib_wx_set_power(struct rtllib_device *ieee,
561                                  struct iw_request_info *info,
562                                  union iwreq_data *wrqu, char *extra)
563 {
564         int ret = 0;
565
566         if ((!ieee->sta_wake_up) ||
567             (!ieee->enter_sleep_state) ||
568             (!ieee->ps_is_queue_empty)) {
569                 netdev_warn(ieee->dev,
570                             "%s(): PS mode is tried to be use but driver missed a callback\n",
571                             __func__);
572                 return -1;
573         }
574
575         mutex_lock(&ieee->wx_mutex);
576
577         if (wrqu->power.disabled) {
578                 RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
579                 ieee->ps = RTLLIB_PS_DISABLED;
580                 goto exit;
581         }
582         if (wrqu->power.flags & IW_POWER_TIMEOUT) {
583                 ieee->ps_timeout = wrqu->power.value / 1000;
584                 RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
585                          ieee->ps_timeout);
586         }
587
588         if (wrqu->power.flags & IW_POWER_PERIOD)
589                 ieee->ps_period = wrqu->power.value / 1000;
590
591         switch (wrqu->power.flags & IW_POWER_MODE) {
592         case IW_POWER_UNICAST_R:
593                 ieee->ps = RTLLIB_PS_UNICAST;
594                 break;
595         case IW_POWER_MULTICAST_R:
596                 ieee->ps = RTLLIB_PS_MBCAST;
597                 break;
598         case IW_POWER_ALL_R:
599                 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
600                 break;
601
602         case IW_POWER_ON:
603                 break;
604
605         default:
606                 ret = -EINVAL;
607                 goto exit;
608
609         }
610 exit:
611         mutex_unlock(&ieee->wx_mutex);
612         return ret;
613
614 }
615 EXPORT_SYMBOL(rtllib_wx_set_power);
616
617 /* this is stolen from hostap */
618 int rtllib_wx_get_power(struct rtllib_device *ieee,
619                                  struct iw_request_info *info,
620                                  union iwreq_data *wrqu, char *extra)
621 {
622         mutex_lock(&ieee->wx_mutex);
623
624         if (ieee->ps == RTLLIB_PS_DISABLED) {
625                 wrqu->power.disabled = 1;
626                 goto exit;
627         }
628
629         wrqu->power.disabled = 0;
630
631         if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
632                 wrqu->power.flags = IW_POWER_TIMEOUT;
633                 wrqu->power.value = ieee->ps_timeout * 1000;
634         } else {
635                 wrqu->power.flags = IW_POWER_PERIOD;
636                 wrqu->power.value = ieee->ps_period * 1000;
637         }
638
639         if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
640             (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
641                 wrqu->power.flags |= IW_POWER_ALL_R;
642         else if (ieee->ps & RTLLIB_PS_MBCAST)
643                 wrqu->power.flags |= IW_POWER_MULTICAST_R;
644         else
645                 wrqu->power.flags |= IW_POWER_UNICAST_R;
646
647 exit:
648         mutex_unlock(&ieee->wx_mutex);
649         return 0;
650
651 }
652 EXPORT_SYMBOL(rtllib_wx_get_power);