staging: rtl8192e: Fix sparse (non-endian) messages - Part I
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / rtl8192e / rtllib_softmac_wx.c
blob22988fbd444babc9d8d4ee15f331ad8ea01b5430
1 /* IEEE 802.11 SoftMAC layer
2 * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
4 * Mostly extracted from the rtl8180-sa2400 driver for the
5 * in-kernel generic ieee802.11 stack.
7 * Some pieces of code might be stolen from ipw2100 driver
8 * copyright of who own it's copyright ;-)
10 * PS wx handler mostly stolen from hostap, copyright who
11 * own it's copyright ;-)
13 * released under the GPL
17 #include "rtllib.h"
18 #include "rtl_core.h"
19 #include "dot11d.h"
20 /* FIXME: add A freqs */
22 const long rtllib_wlan_frequencies[] = {
23 2412, 2417, 2422, 2427,
24 2432, 2437, 2442, 2447,
25 2452, 2457, 2462, 2467,
26 2472, 2484
30 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
31 union iwreq_data *wrqu, char *b)
33 int ret;
34 struct iw_freq *fwrq = &wrqu->freq;
36 down(&ieee->wx_sem);
38 if (ieee->iw_mode == IW_MODE_INFRA) {
39 ret = 0;
40 goto out;
43 /* if setting by freq convert to channel */
44 if (fwrq->e == 1) {
45 if ((fwrq->m >= (int) 2.412e8 &&
46 fwrq->m <= (int) 2.487e8)) {
47 int f = fwrq->m / 100000;
48 int c = 0;
50 while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
51 c++;
53 /* hack to fall through */
54 fwrq->e = 0;
55 fwrq->m = c + 1;
59 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
60 ret = -EOPNOTSUPP;
61 goto out;
63 } else { /* Set the channel */
65 if (ieee->active_channel_map[fwrq->m] != 1) {
66 ret = -EINVAL;
67 goto out;
69 ieee->current_network.channel = fwrq->m;
70 ieee->set_chan(ieee->dev, ieee->current_network.channel);
72 if (ieee->iw_mode == IW_MODE_ADHOC ||
73 ieee->iw_mode == IW_MODE_MASTER)
74 if (ieee->state == RTLLIB_LINKED) {
75 rtllib_stop_send_beacons(ieee);
76 rtllib_start_send_beacons(ieee);
80 ret = 0;
81 out:
82 up(&ieee->wx_sem);
83 return ret;
87 int rtllib_wx_get_freq(struct rtllib_device *ieee,
88 struct iw_request_info *a,
89 union iwreq_data *wrqu, char *b)
91 struct iw_freq *fwrq = &wrqu->freq;
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;
101 int rtllib_wx_get_wap(struct rtllib_device *ieee,
102 struct iw_request_info *info,
103 union iwreq_data *wrqu, char *extra)
105 unsigned long flags;
107 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
109 if (ieee->iw_mode == IW_MODE_MONITOR)
110 return -1;
112 /* We want avoid to give to the user inconsistent infos*/
113 spin_lock_irqsave(&ieee->lock, flags);
115 if (ieee->state != RTLLIB_LINKED &&
116 ieee->state != RTLLIB_LINKED_SCANNING &&
117 ieee->wap_set == 0)
119 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
120 else
121 memcpy(wrqu->ap_addr.sa_data,
122 ieee->current_network.bssid, ETH_ALEN);
124 spin_unlock_irqrestore(&ieee->lock, flags);
126 return 0;
130 int rtllib_wx_set_wap(struct rtllib_device *ieee,
131 struct iw_request_info *info,
132 union iwreq_data *awrq,
133 char *extra)
136 int ret = 0;
137 u8 zero[] = {0, 0, 0, 0, 0, 0};
138 unsigned long flags;
140 short ifup = ieee->proto_started;
141 struct sockaddr *temp = (struct sockaddr *)awrq;
143 rtllib_stop_scan_syncro(ieee);
145 down(&ieee->wx_sem);
146 /* use ifconfig hw ether */
147 if (ieee->iw_mode == IW_MODE_MASTER) {
148 ret = -1;
149 goto out;
152 if (temp->sa_family != ARPHRD_ETHER) {
153 ret = -EINVAL;
154 goto out;
157 if (memcmp(temp->sa_data, zero, ETH_ALEN) == 0) {
158 spin_lock_irqsave(&ieee->lock, flags);
159 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
160 ieee->wap_set = 0;
161 spin_unlock_irqrestore(&ieee->lock, flags);
162 ret = -1;
163 goto out;
167 if (ifup)
168 rtllib_stop_protocol(ieee, true);
170 /* just to avoid to give inconsistent infos in the
171 * get wx method. not really needed otherwise
173 spin_lock_irqsave(&ieee->lock, flags);
175 ieee->cannot_notify = false;
176 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
177 ieee->wap_set = (memcmp(temp->sa_data, zero, ETH_ALEN) != 0);
179 spin_unlock_irqrestore(&ieee->lock, flags);
181 if (ifup)
182 rtllib_start_protocol(ieee);
183 out:
184 up(&ieee->wx_sem);
185 return ret;
188 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
189 union iwreq_data *wrqu, char *b)
191 int len, ret = 0;
192 unsigned long flags;
194 if (ieee->iw_mode == IW_MODE_MONITOR)
195 return -1;
197 /* We want avoid to give to the user inconsistent infos*/
198 spin_lock_irqsave(&ieee->lock, flags);
200 if (ieee->current_network.ssid[0] == '\0' ||
201 ieee->current_network.ssid_len == 0) {
202 ret = -1;
203 goto out;
206 if (ieee->state != RTLLIB_LINKED &&
207 ieee->state != RTLLIB_LINKED_SCANNING &&
208 ieee->ssid_set == 0) {
209 ret = -1;
210 goto out;
212 len = ieee->current_network.ssid_len;
213 wrqu->essid.length = len;
214 strncpy(b, ieee->current_network.ssid, len);
215 wrqu->essid.flags = 1;
217 out:
218 spin_unlock_irqrestore(&ieee->lock, flags);
220 return ret;
224 int rtllib_wx_set_rate(struct rtllib_device *ieee,
225 struct iw_request_info *info,
226 union iwreq_data *wrqu, char *extra)
229 u32 target_rate = wrqu->bitrate.value;
231 ieee->rate = target_rate/100000;
232 return 0;
235 int rtllib_wx_get_rate(struct rtllib_device *ieee,
236 struct iw_request_info *info,
237 union iwreq_data *wrqu, char *extra)
239 u32 tmp_rate = 0;
240 tmp_rate = TxCountToDataRate(ieee,
241 ieee->softmac_stats.CurrentShowTxate);
242 wrqu->bitrate.value = tmp_rate * 500000;
244 return 0;
248 int rtllib_wx_set_rts(struct rtllib_device *ieee,
249 struct iw_request_info *info,
250 union iwreq_data *wrqu, char *extra)
252 if (wrqu->rts.disabled || !wrqu->rts.fixed)
253 ieee->rts = DEFAULT_RTS_THRESHOLD;
254 else {
255 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
256 wrqu->rts.value > MAX_RTS_THRESHOLD)
257 return -EINVAL;
258 ieee->rts = wrqu->rts.value;
260 return 0;
263 int rtllib_wx_get_rts(struct rtllib_device *ieee,
264 struct iw_request_info *info,
265 union iwreq_data *wrqu, char *extra)
267 wrqu->rts.value = ieee->rts;
268 wrqu->rts.fixed = 0; /* no auto select */
269 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
270 return 0;
273 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
274 union iwreq_data *wrqu, char *b)
276 int set_mode_status = 0;
278 rtllib_stop_scan_syncro(ieee);
279 down(&ieee->wx_sem);
280 switch (wrqu->mode) {
281 case IW_MODE_MONITOR:
282 case IW_MODE_ADHOC:
283 case IW_MODE_INFRA:
284 break;
285 case IW_MODE_AUTO:
286 wrqu->mode = IW_MODE_INFRA;
287 break;
288 default:
289 set_mode_status = -EINVAL;
290 goto out;
293 if (wrqu->mode == ieee->iw_mode)
294 goto out;
296 if (wrqu->mode == IW_MODE_MONITOR) {
297 ieee->dev->type = ARPHRD_IEEE80211;
298 rtllib_EnableNetMonitorMode(ieee->dev, false);
299 } else {
300 ieee->dev->type = ARPHRD_ETHER;
301 if (ieee->iw_mode == IW_MODE_MONITOR)
302 rtllib_DisableNetMonitorMode(ieee->dev, false);
305 if (!ieee->proto_started) {
306 ieee->iw_mode = wrqu->mode;
307 } else {
308 rtllib_stop_protocol(ieee, true);
309 ieee->iw_mode = wrqu->mode;
310 rtllib_start_protocol(ieee);
313 out:
314 up(&ieee->wx_sem);
315 return set_mode_status;
318 void rtllib_wx_sync_scan_wq(void *data)
320 struct rtllib_device *ieee = container_of_work_rsl(data,
321 struct rtllib_device, wx_sync_scan_wq);
322 short chan;
323 enum ht_extchnl_offset chan_offset = 0;
324 enum ht_channel_width bandwidth = 0;
325 int b40M = 0;
326 static int count;
328 if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
329 rtllib_start_scan_syncro(ieee, 0);
330 goto out;
333 chan = ieee->current_network.channel;
335 if (ieee->LeisurePSLeave)
336 ieee->LeisurePSLeave(ieee->dev);
337 /* notify AP to be in PS mode */
338 rtllib_sta_ps_send_null_frame(ieee, 1);
339 rtllib_sta_ps_send_null_frame(ieee, 1);
341 rtllib_stop_all_queues(ieee);
343 if (ieee->data_hard_stop)
344 ieee->data_hard_stop(ieee->dev);
345 rtllib_stop_send_beacons(ieee);
346 ieee->state = RTLLIB_LINKED_SCANNING;
347 ieee->link_change(ieee->dev);
348 /* wait for ps packet to be kicked out successfully */
349 msleep(50);
351 if (ieee->ScanOperationBackupHandler)
352 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
354 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
355 ieee->pHTInfo->bCurBW40MHz) {
356 b40M = 1;
357 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
358 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
359 RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
360 chan_offset, bandwidth);
361 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
362 HT_EXTCHNL_OFFSET_NO_EXT);
365 rtllib_start_scan_syncro(ieee, 0);
367 if (b40M) {
368 RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
369 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
370 ieee->set_chan(ieee->dev, chan + 2);
371 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
372 ieee->set_chan(ieee->dev, chan - 2);
373 else
374 ieee->set_chan(ieee->dev, chan);
375 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
376 } else {
377 ieee->set_chan(ieee->dev, chan);
380 if (ieee->ScanOperationBackupHandler)
381 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
383 ieee->state = RTLLIB_LINKED;
384 ieee->link_change(ieee->dev);
386 /* Notify AP that I wake up again */
387 rtllib_sta_ps_send_null_frame(ieee, 0);
389 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
390 ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
391 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
392 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
395 if (ieee->data_hard_resume)
396 ieee->data_hard_resume(ieee->dev);
398 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
399 rtllib_start_send_beacons(ieee);
401 rtllib_wake_all_queues(ieee);
403 count = 0;
404 out:
405 up(&ieee->wx_sem);
409 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
410 union iwreq_data *wrqu, char *b)
412 int ret = 0;
414 down(&ieee->wx_sem);
416 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
417 ret = -1;
418 goto out;
421 if (ieee->state == RTLLIB_LINKED) {
422 queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq);
423 /* intentionally forget to up sem */
424 return 0;
427 out:
428 up(&ieee->wx_sem);
429 return ret;
432 int rtllib_wx_set_essid(struct rtllib_device *ieee,
433 struct iw_request_info *a,
434 union iwreq_data *wrqu, char *extra)
437 int ret = 0, len, i;
438 short proto_started;
439 unsigned long flags;
441 rtllib_stop_scan_syncro(ieee);
442 down(&ieee->wx_sem);
444 proto_started = ieee->proto_started;
446 len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length :
447 IW_ESSID_MAX_SIZE;
449 if (len > IW_ESSID_MAX_SIZE) {
450 ret = -E2BIG;
451 goto out;
454 if (ieee->iw_mode == IW_MODE_MONITOR) {
455 ret = -1;
456 goto out;
459 for (i = 0; i < len; i++) {
460 if (extra[i] < 0) {
461 ret = -1;
462 goto out;
466 if (proto_started)
467 rtllib_stop_protocol(ieee, true);
470 /* this is just to be sure that the GET wx callback
471 * has consisten infos. not needed otherwise
473 spin_lock_irqsave(&ieee->lock, flags);
475 if (wrqu->essid.flags && wrqu->essid.length) {
476 strncpy(ieee->current_network.ssid, extra, len);
477 ieee->current_network.ssid_len = len;
478 ieee->cannot_notify = false;
479 ieee->ssid_set = 1;
480 } else {
481 ieee->ssid_set = 0;
482 ieee->current_network.ssid[0] = '\0';
483 ieee->current_network.ssid_len = 0;
485 spin_unlock_irqrestore(&ieee->lock, flags);
487 if (proto_started)
488 rtllib_start_protocol(ieee);
489 out:
490 up(&ieee->wx_sem);
491 return ret;
494 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
495 union iwreq_data *wrqu, char *b)
497 wrqu->mode = ieee->iw_mode;
498 return 0;
501 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
502 struct iw_request_info *info,
503 union iwreq_data *wrqu, char *extra)
506 int *parms = (int *)extra;
507 int enable = (parms[0] > 0);
508 short prev = ieee->raw_tx;
510 down(&ieee->wx_sem);
512 if (enable)
513 ieee->raw_tx = 1;
514 else
515 ieee->raw_tx = 0;
517 printk(KERN_INFO"raw TX is %s\n",
518 ieee->raw_tx ? "enabled" : "disabled");
520 if (ieee->iw_mode == IW_MODE_MONITOR) {
521 if (prev == 0 && ieee->raw_tx) {
522 if (ieee->data_hard_resume)
523 ieee->data_hard_resume(ieee->dev);
525 netif_carrier_on(ieee->dev);
528 if (prev && ieee->raw_tx == 1)
529 netif_carrier_off(ieee->dev);
532 up(&ieee->wx_sem);
534 return 0;
537 int rtllib_wx_get_name(struct rtllib_device *ieee,
538 struct iw_request_info *info,
539 union iwreq_data *wrqu, char *extra)
541 strcpy(wrqu->name, "802.11");
543 if (ieee->modulation & RTLLIB_CCK_MODULATION)
544 strcat(wrqu->name, "b");
545 if (ieee->modulation & RTLLIB_OFDM_MODULATION)
546 strcat(wrqu->name, "g");
547 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
548 strcat(wrqu->name, "n");
549 return 0;
553 /* this is mostly stolen from hostap */
554 int rtllib_wx_set_power(struct rtllib_device *ieee,
555 struct iw_request_info *info,
556 union iwreq_data *wrqu, char *extra)
558 int ret = 0;
560 if ((!ieee->sta_wake_up) ||
561 (!ieee->enter_sleep_state) ||
562 (!ieee->ps_is_queue_empty)) {
563 RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tryied to be use "
564 "but driver missed a callback\n\n", __func__);
565 return -1;
568 down(&ieee->wx_sem);
570 if (wrqu->power.disabled) {
571 RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
572 ieee->ps = RTLLIB_PS_DISABLED;
573 goto exit;
575 if (wrqu->power.flags & IW_POWER_TIMEOUT) {
576 ieee->ps_timeout = wrqu->power.value / 1000;
577 RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
578 ieee->ps_timeout);
581 if (wrqu->power.flags & IW_POWER_PERIOD)
582 ieee->ps_period = wrqu->power.value / 1000;
584 switch (wrqu->power.flags & IW_POWER_MODE) {
585 case IW_POWER_UNICAST_R:
586 ieee->ps = RTLLIB_PS_UNICAST;
587 break;
588 case IW_POWER_MULTICAST_R:
589 ieee->ps = RTLLIB_PS_MBCAST;
590 break;
591 case IW_POWER_ALL_R:
592 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
593 break;
595 case IW_POWER_ON:
596 break;
598 default:
599 ret = -EINVAL;
600 goto exit;
603 exit:
604 up(&ieee->wx_sem);
605 return ret;
609 /* this is stolen from hostap */
610 int rtllib_wx_get_power(struct rtllib_device *ieee,
611 struct iw_request_info *info,
612 union iwreq_data *wrqu, char *extra)
614 int ret = 0;
616 down(&ieee->wx_sem);
618 if (ieee->ps == RTLLIB_PS_DISABLED) {
619 wrqu->power.disabled = 1;
620 goto exit;
623 wrqu->power.disabled = 0;
625 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
626 wrqu->power.flags = IW_POWER_TIMEOUT;
627 wrqu->power.value = ieee->ps_timeout * 1000;
628 } else {
629 wrqu->power.flags = IW_POWER_PERIOD;
630 wrqu->power.value = ieee->ps_period * 1000;
633 if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
634 (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
635 wrqu->power.flags |= IW_POWER_ALL_R;
636 else if (ieee->ps & RTLLIB_PS_MBCAST)
637 wrqu->power.flags |= IW_POWER_MULTICAST_R;
638 else
639 wrqu->power.flags |= IW_POWER_UNICAST_R;
641 exit:
642 up(&ieee->wx_sem);
643 return ret;