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
19 /* FIXME: add A freqs */
21 const long rtllib_wlan_frequencies[] = {
22 2412, 2417, 2422, 2427,
23 2432, 2437, 2442, 2447,
24 2452, 2457, 2462, 2467,
29 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
30 union iwreq_data *wrqu, char *b)
33 struct iw_freq *fwrq = &wrqu->freq;
37 if (ieee->iw_mode == IW_MODE_INFRA) {
42 /* if setting by freq convert to channel */
44 if ((fwrq->m >= (int) 2.412e8 &&
45 fwrq->m <= (int) 2.487e8)) {
46 int f = fwrq->m / 100000;
49 while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
52 /* hack to fall through */
58 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
62 } else { /* Set the channel */
64 if (ieee->active_channel_map[fwrq->m] != 1) {
68 ieee->current_network.channel = fwrq->m;
69 ieee->set_chan(ieee->dev, ieee->current_network.channel);
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);
86 int rtllib_wx_get_freq(struct rtllib_device *ieee,
87 struct iw_request_info *a,
88 union iwreq_data *wrqu, char *b)
90 struct iw_freq *fwrq = &wrqu->freq;
92 if (ieee->current_network.channel == 0)
94 fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
100 int rtllib_wx_get_wap(struct rtllib_device *ieee,
101 struct iw_request_info *info,
102 union iwreq_data *wrqu, char *extra)
106 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
108 if (ieee->iw_mode == IW_MODE_MONITOR)
111 /* We want avoid to give to the user inconsistent infos*/
112 spin_lock_irqsave(&ieee->lock, flags);
114 if (ieee->state != RTLLIB_LINKED &&
115 ieee->state != RTLLIB_LINKED_SCANNING &&
118 memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
120 memcpy(wrqu->ap_addr.sa_data,
121 ieee->current_network.bssid, ETH_ALEN);
123 spin_unlock_irqrestore(&ieee->lock, flags);
129 int rtllib_wx_set_wap(struct rtllib_device *ieee,
130 struct iw_request_info *info,
131 union iwreq_data *awrq,
136 u8 zero[] = {0, 0, 0, 0, 0, 0};
139 short ifup = ieee->proto_started;
140 struct sockaddr *temp = (struct sockaddr *)awrq;
142 rtllib_stop_scan_syncro(ieee);
145 /* use ifconfig hw ether */
146 if (ieee->iw_mode == IW_MODE_MASTER) {
151 if (temp->sa_family != ARPHRD_ETHER) {
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);
160 spin_unlock_irqrestore(&ieee->lock, flags);
167 rtllib_stop_protocol(ieee, true);
169 /* just to avoid to give inconsistent infos in the
170 * get wx method. not really needed otherwise
172 spin_lock_irqsave(&ieee->lock, flags);
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);
178 spin_unlock_irqrestore(&ieee->lock, flags);
181 rtllib_start_protocol(ieee);
187 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
188 union iwreq_data *wrqu, char *b)
193 if (ieee->iw_mode == IW_MODE_MONITOR)
196 /* We want avoid to give to the user inconsistent infos*/
197 spin_lock_irqsave(&ieee->lock, flags);
199 if (ieee->current_network.ssid[0] == '\0' ||
200 ieee->current_network.ssid_len == 0) {
205 if (ieee->state != RTLLIB_LINKED &&
206 ieee->state != RTLLIB_LINKED_SCANNING &&
207 ieee->ssid_set == 0) {
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;
217 spin_unlock_irqrestore(&ieee->lock, flags);
223 int rtllib_wx_set_rate(struct rtllib_device *ieee,
224 struct iw_request_info *info,
225 union iwreq_data *wrqu, char *extra)
228 u32 target_rate = wrqu->bitrate.value;
230 ieee->rate = target_rate/100000;
234 int rtllib_wx_get_rate(struct rtllib_device *ieee,
235 struct iw_request_info *info,
236 union iwreq_data *wrqu, char *extra)
239 tmp_rate = TxCountToDataRate(ieee,
240 ieee->softmac_stats.CurrentShowTxate);
241 wrqu->bitrate.value = tmp_rate * 500000;
247 int rtllib_wx_set_rts(struct rtllib_device *ieee,
248 struct iw_request_info *info,
249 union iwreq_data *wrqu, char *extra)
251 if (wrqu->rts.disabled || !wrqu->rts.fixed)
252 ieee->rts = DEFAULT_RTS_THRESHOLD;
254 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
255 wrqu->rts.value > MAX_RTS_THRESHOLD)
257 ieee->rts = wrqu->rts.value;
262 int rtllib_wx_get_rts(struct rtllib_device *ieee,
263 struct iw_request_info *info,
264 union iwreq_data *wrqu, char *extra)
266 wrqu->rts.value = ieee->rts;
267 wrqu->rts.fixed = 0; /* no auto select */
268 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
272 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
273 union iwreq_data *wrqu, char *b)
275 int set_mode_status = 0;
277 rtllib_stop_scan_syncro(ieee);
279 switch (wrqu->mode) {
280 case IW_MODE_MONITOR:
285 wrqu->mode = IW_MODE_INFRA;
288 set_mode_status = -EINVAL;
292 if (wrqu->mode == ieee->iw_mode)
295 if (wrqu->mode == IW_MODE_MONITOR) {
296 ieee->dev->type = ARPHRD_IEEE80211;
297 rtllib_EnableNetMonitorMode(ieee->dev, false);
299 ieee->dev->type = ARPHRD_ETHER;
300 if (ieee->iw_mode == IW_MODE_MONITOR)
301 rtllib_DisableNetMonitorMode(ieee->dev, false);
304 if (!ieee->proto_started) {
305 ieee->iw_mode = wrqu->mode;
307 rtllib_stop_protocol(ieee, true);
308 ieee->iw_mode = wrqu->mode;
309 rtllib_start_protocol(ieee);
314 return set_mode_status;
317 void rtllib_wx_sync_scan_wq(void *data)
319 struct rtllib_device *ieee = container_of_work_rsl(data,
320 struct rtllib_device, wx_sync_scan_wq);
322 enum ht_extchnl_offset chan_offset = 0;
323 enum ht_channel_width bandwidth = 0;
327 if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
328 rtllib_start_scan_syncro(ieee, 0);
332 chan = ieee->current_network.channel;
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);
340 rtllib_stop_all_queues(ieee);
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 */
350 if (ieee->ScanOperationBackupHandler)
351 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
353 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
354 ieee->pHTInfo->bCurBW40MHz) {
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);
364 rtllib_start_scan_syncro(ieee, 0);
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);
373 ieee->set_chan(ieee->dev, chan);
374 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
376 ieee->set_chan(ieee->dev, chan);
379 if (ieee->ScanOperationBackupHandler)
380 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
382 ieee->state = RTLLIB_LINKED;
383 ieee->link_change(ieee->dev);
385 /* Notify AP that I wake up again */
386 rtllib_sta_ps_send_null_frame(ieee, 0);
388 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
389 ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
390 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
391 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
394 if (ieee->data_hard_resume)
395 ieee->data_hard_resume(ieee->dev);
397 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
398 rtllib_start_send_beacons(ieee);
400 rtllib_wake_all_queues(ieee);
408 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
409 union iwreq_data *wrqu, char *b)
415 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
420 if (ieee->state == RTLLIB_LINKED) {
421 queue_work_rsl(ieee->wq, &ieee->wx_sync_scan_wq);
422 /* intentionally forget to up sem */
431 int rtllib_wx_set_essid(struct rtllib_device *ieee,
432 struct iw_request_info *a,
433 union iwreq_data *wrqu, char *extra)
440 rtllib_stop_scan_syncro(ieee);
443 proto_started = ieee->proto_started;
445 len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length :
448 if (len > IW_ESSID_MAX_SIZE) {
453 if (ieee->iw_mode == IW_MODE_MONITOR) {
458 for (i = 0; i < len; i++) {
466 rtllib_stop_protocol(ieee, true);
469 /* this is just to be sure that the GET wx callback
470 * has consisten infos. not needed otherwise
472 spin_lock_irqsave(&ieee->lock, flags);
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;
481 ieee->current_network.ssid[0] = '\0';
482 ieee->current_network.ssid_len = 0;
484 spin_unlock_irqrestore(&ieee->lock, flags);
487 rtllib_start_protocol(ieee);
493 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
494 union iwreq_data *wrqu, char *b)
496 wrqu->mode = ieee->iw_mode;
500 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
501 struct iw_request_info *info,
502 union iwreq_data *wrqu, char *extra)
505 int *parms = (int *)extra;
506 int enable = (parms[0] > 0);
507 short prev = ieee->raw_tx;
516 printk(KERN_INFO"raw TX is %s\n",
517 ieee->raw_tx ? "enabled" : "disabled");
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);
524 netif_carrier_on(ieee->dev);
527 if (prev && ieee->raw_tx == 1)
528 netif_carrier_off(ieee->dev);
536 int rtllib_wx_get_name(struct rtllib_device *ieee,
537 struct iw_request_info *info,
538 union iwreq_data *wrqu, char *extra)
540 strcpy(wrqu->name, "802.11");
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");
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)
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__);
569 if (wrqu->power.disabled) {
570 RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
571 ieee->ps = RTLLIB_PS_DISABLED;
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__,
580 if (wrqu->power.flags & IW_POWER_PERIOD)
581 ieee->ps_period = wrqu->power.value / 1000;
583 switch (wrqu->power.flags & IW_POWER_MODE) {
584 case IW_POWER_UNICAST_R:
585 ieee->ps = RTLLIB_PS_UNICAST;
587 case IW_POWER_MULTICAST_R:
588 ieee->ps = RTLLIB_PS_MBCAST;
591 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
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)
617 if (ieee->ps == RTLLIB_PS_DISABLED) {
618 wrqu->power.disabled = 1;
622 wrqu->power.disabled = 0;
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;
628 wrqu->power.flags = IW_POWER_PERIOD;
629 wrqu->power.value = ieee->ps_period * 1000;
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;
638 wrqu->power.flags |= IW_POWER_UNICAST_R;