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