1 // SPDX-License-Identifier: GPL-2.0
2 /* IEEE 802.11 SoftMAC layer
3 * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
5 * Mostly extracted from the rtl8180-sa2400 driver for the
6 * in-kernel generic ieee802.11 stack.
8 * Some pieces of code might be stolen from ipw2100 driver
9 * copyright of who own it's copyright ;-)
11 * PS wx handler mostly stolen from hostap, copyright who
12 * own it's copyright ;-)
16 #include <linux/etherdevice.h>
18 #include "ieee80211.h"
20 /* FIXME: add A freqs */
22 const long ieee80211_wlan_frequencies[] = {
23 2412, 2417, 2422, 2427,
24 2432, 2437, 2442, 2447,
25 2452, 2457, 2462, 2467,
28 EXPORT_SYMBOL(ieee80211_wlan_frequencies);
30 int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
31 union iwreq_data *wrqu, char *b)
34 struct iw_freq *fwrq = &wrqu->freq;
36 mutex_lock(&ieee->wx_mutex);
38 if (ieee->iw_mode == IW_MODE_INFRA) {
43 /* if setting by freq convert to channel */
45 if ((fwrq->m >= (int) 2.412e8 &&
46 fwrq->m <= (int) 2.487e8)) {
47 int f = fwrq->m / 100000;
50 while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
53 /* hack to fall through */
59 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
63 } else { /* Set the channel */
65 if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) {
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 || ieee->iw_mode == IW_MODE_MASTER)
73 if (ieee->state == IEEE80211_LINKED) {
74 ieee80211_stop_send_beacons(ieee);
75 ieee80211_start_send_beacons(ieee);
81 mutex_unlock(&ieee->wx_mutex);
84 EXPORT_SYMBOL(ieee80211_wx_set_freq);
86 int ieee80211_wx_get_freq(struct ieee80211_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 /* NM 0.7.0 will not accept channel any more. */
95 fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000;
97 /* fwrq->m = ieee->current_network.channel; */
102 EXPORT_SYMBOL(ieee80211_wx_get_freq);
104 int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
105 struct iw_request_info *info,
106 union iwreq_data *wrqu, char *extra)
110 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
112 if (ieee->iw_mode == IW_MODE_MONITOR)
115 /* We want avoid to give to the user inconsistent infos*/
116 spin_lock_irqsave(&ieee->lock, flags);
118 if (ieee->state != IEEE80211_LINKED &&
119 ieee->state != IEEE80211_LINKED_SCANNING &&
122 eth_zero_addr(wrqu->ap_addr.sa_data);
124 memcpy(wrqu->ap_addr.sa_data,
125 ieee->current_network.bssid, ETH_ALEN);
127 spin_unlock_irqrestore(&ieee->lock, flags);
131 EXPORT_SYMBOL(ieee80211_wx_get_wap);
133 int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
134 struct iw_request_info *info,
135 union iwreq_data *awrq,
142 short ifup = ieee->proto_started; /* dev->flags & IFF_UP; */
143 struct sockaddr *temp = (struct sockaddr *)awrq;
145 ieee->sync_scan_hurryup = 1;
147 mutex_lock(&ieee->wx_mutex);
148 /* use ifconfig hw ether */
149 if (ieee->iw_mode == IW_MODE_MASTER) {
154 if (temp->sa_family != ARPHRD_ETHER) {
160 ieee80211_stop_protocol(ieee);
162 /* just to avoid to give inconsistent infos in the
163 * get wx method. not really needed otherwise
165 spin_lock_irqsave(&ieee->lock, flags);
167 memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
168 ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
170 spin_unlock_irqrestore(&ieee->lock, flags);
173 ieee80211_start_protocol(ieee);
175 mutex_unlock(&ieee->wx_mutex);
178 EXPORT_SYMBOL(ieee80211_wx_set_wap);
180 int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a, union iwreq_data *wrqu, char *b)
185 if (ieee->iw_mode == IW_MODE_MONITOR)
188 /* We want avoid to give to the user inconsistent infos*/
189 spin_lock_irqsave(&ieee->lock, flags);
191 if (ieee->current_network.ssid[0] == '\0' ||
192 ieee->current_network.ssid_len == 0) {
197 if (ieee->state != IEEE80211_LINKED &&
198 ieee->state != IEEE80211_LINKED_SCANNING &&
199 ieee->ssid_set == 0) {
203 len = ieee->current_network.ssid_len;
204 wrqu->essid.length = len;
205 strncpy(b, ieee->current_network.ssid, len);
206 wrqu->essid.flags = 1;
209 spin_unlock_irqrestore(&ieee->lock, flags);
214 EXPORT_SYMBOL(ieee80211_wx_get_essid);
216 int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
217 struct iw_request_info *info,
218 union iwreq_data *wrqu, char *extra)
221 u32 target_rate = wrqu->bitrate.value;
223 ieee->rate = target_rate/100000;
224 /* FIXME: we might want to limit rate also in management protocols. */
227 EXPORT_SYMBOL(ieee80211_wx_set_rate);
229 int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
230 struct iw_request_info *info,
231 union iwreq_data *wrqu, char *extra)
235 tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate);
237 wrqu->bitrate.value = tmp_rate * 500000;
241 EXPORT_SYMBOL(ieee80211_wx_get_rate);
243 int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
244 struct iw_request_info *info,
245 union iwreq_data *wrqu, char *extra)
247 if (wrqu->rts.disabled || !wrqu->rts.fixed) {
248 ieee->rts = DEFAULT_RTS_THRESHOLD;
250 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
251 wrqu->rts.value > MAX_RTS_THRESHOLD)
253 ieee->rts = wrqu->rts.value;
257 EXPORT_SYMBOL(ieee80211_wx_set_rts);
259 int ieee80211_wx_get_rts(struct ieee80211_device *ieee,
260 struct iw_request_info *info,
261 union iwreq_data *wrqu, char *extra)
263 wrqu->rts.value = ieee->rts;
264 wrqu->rts.fixed = 0; /* no auto select */
265 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
268 EXPORT_SYMBOL(ieee80211_wx_get_rts);
270 int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
271 union iwreq_data *wrqu, char *b)
274 ieee->sync_scan_hurryup = 1;
276 mutex_lock(&ieee->wx_mutex);
278 if (wrqu->mode == ieee->iw_mode)
281 if (wrqu->mode == IW_MODE_MONITOR)
282 ieee->dev->type = ARPHRD_IEEE80211;
284 ieee->dev->type = ARPHRD_ETHER;
286 if (!ieee->proto_started) {
287 ieee->iw_mode = wrqu->mode;
289 ieee80211_stop_protocol(ieee);
290 ieee->iw_mode = wrqu->mode;
291 ieee80211_start_protocol(ieee);
295 mutex_unlock(&ieee->wx_mutex);
298 EXPORT_SYMBOL(ieee80211_wx_set_mode);
300 void ieee80211_wx_sync_scan_wq(struct work_struct *work)
302 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
304 enum ht_extension_chan_offset chan_offset = 0;
305 enum ht_channel_width bandwidth = 0;
308 chan = ieee->current_network.channel;
309 netif_carrier_off(ieee->dev);
311 if (ieee->data_hard_stop)
312 ieee->data_hard_stop(ieee->dev);
314 ieee80211_stop_send_beacons(ieee);
316 ieee->state = IEEE80211_LINKED_SCANNING;
317 ieee->link_change(ieee->dev);
318 ieee->InitialGainHandler(ieee->dev, IG_Backup);
319 if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) {
321 chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
322 bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
323 printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth);
324 ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
326 ieee80211_start_scan_syncro(ieee);
328 printk("Scan in 20M, back to 40M\n");
329 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
330 ieee->set_chan(ieee->dev, chan + 2);
331 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
332 ieee->set_chan(ieee->dev, chan - 2);
334 ieee->set_chan(ieee->dev, chan);
335 ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
337 ieee->set_chan(ieee->dev, chan);
340 ieee->InitialGainHandler(ieee->dev, IG_Restore);
341 ieee->state = IEEE80211_LINKED;
342 ieee->link_change(ieee->dev);
343 /* To prevent the immediately calling watch_dog after scan. */
344 if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 || ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
345 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
346 ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
348 if (ieee->data_hard_resume)
349 ieee->data_hard_resume(ieee->dev);
351 if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
352 ieee80211_start_send_beacons(ieee);
354 netif_carrier_on(ieee->dev);
355 mutex_unlock(&ieee->wx_mutex);
359 int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
360 union iwreq_data *wrqu, char *b)
364 mutex_lock(&ieee->wx_mutex);
366 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
371 if (ieee->state == IEEE80211_LINKED) {
372 queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
373 /* intentionally forget to up sem */
378 mutex_unlock(&ieee->wx_mutex);
381 EXPORT_SYMBOL(ieee80211_wx_set_scan);
383 int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
384 struct iw_request_info *a,
385 union iwreq_data *wrqu, char *extra)
392 ieee->sync_scan_hurryup = 1;
393 mutex_lock(&ieee->wx_mutex);
395 proto_started = ieee->proto_started;
397 if (wrqu->essid.length > IW_ESSID_MAX_SIZE) {
402 if (ieee->iw_mode == IW_MODE_MONITOR) {
408 ieee80211_stop_protocol(ieee);
411 /* this is just to be sure that the GET wx callback
412 * has consisten infos. not needed otherwise
414 spin_lock_irqsave(&ieee->lock, flags);
416 if (wrqu->essid.flags && wrqu->essid.length) {
417 /* first flush current network.ssid */
418 len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
419 strncpy(ieee->current_network.ssid, extra, len+1);
420 ieee->current_network.ssid_len = len+1;
424 ieee->current_network.ssid[0] = '\0';
425 ieee->current_network.ssid_len = 0;
427 spin_unlock_irqrestore(&ieee->lock, flags);
430 ieee80211_start_protocol(ieee);
432 mutex_unlock(&ieee->wx_mutex);
435 EXPORT_SYMBOL(ieee80211_wx_set_essid);
437 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
438 union iwreq_data *wrqu, char *b)
441 wrqu->mode = ieee->iw_mode;
444 EXPORT_SYMBOL(ieee80211_wx_get_mode);
446 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
447 struct iw_request_info *info,
448 union iwreq_data *wrqu, char *extra)
451 int *parms = (int *)extra;
452 int enable = (parms[0] > 0);
453 short prev = ieee->raw_tx;
455 mutex_lock(&ieee->wx_mutex);
462 printk(KERN_INFO"raw TX is %s\n",
463 ieee->raw_tx ? "enabled" : "disabled");
465 if (ieee->iw_mode == IW_MODE_MONITOR) {
466 if (prev == 0 && ieee->raw_tx) {
467 if (ieee->data_hard_resume)
468 ieee->data_hard_resume(ieee->dev);
470 netif_carrier_on(ieee->dev);
473 if (prev && ieee->raw_tx == 1)
474 netif_carrier_off(ieee->dev);
477 mutex_unlock(&ieee->wx_mutex);
481 EXPORT_SYMBOL(ieee80211_wx_set_rawtx);
483 int ieee80211_wx_get_name(struct ieee80211_device *ieee,
484 struct iw_request_info *info,
485 union iwreq_data *wrqu, char *extra)
487 strlcpy(wrqu->name, "802.11", IFNAMSIZ);
488 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
489 strlcat(wrqu->name, "b", IFNAMSIZ);
490 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
491 strlcat(wrqu->name, "/g", IFNAMSIZ);
492 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
493 strlcat(wrqu->name, "g", IFNAMSIZ);
496 if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
497 strlcat(wrqu->name, "/n", IFNAMSIZ);
499 if ((ieee->state == IEEE80211_LINKED) ||
500 (ieee->state == IEEE80211_LINKED_SCANNING))
501 strlcat(wrqu->name, " linked", IFNAMSIZ);
502 else if (ieee->state != IEEE80211_NOLINK)
503 strlcat(wrqu->name, " link..", IFNAMSIZ);
507 EXPORT_SYMBOL(ieee80211_wx_get_name);
509 /* this is mostly stolen from hostap */
510 int ieee80211_wx_set_power(struct ieee80211_device *ieee,
511 struct iw_request_info *info,
512 union iwreq_data *wrqu, char *extra)
516 mutex_lock(&ieee->wx_mutex);
518 if (wrqu->power.disabled) {
519 ieee->ps = IEEE80211_PS_DISABLED;
522 if (wrqu->power.flags & IW_POWER_TIMEOUT) {
523 /* ieee->ps_period = wrqu->power.value / 1000; */
524 ieee->ps_timeout = wrqu->power.value / 1000;
527 if (wrqu->power.flags & IW_POWER_PERIOD) {
529 /* ieee->ps_timeout = wrqu->power.value / 1000; */
530 ieee->ps_period = wrqu->power.value / 1000;
531 /* wrq->value / 1024; */
534 switch (wrqu->power.flags & IW_POWER_MODE) {
535 case IW_POWER_UNICAST_R:
536 ieee->ps = IEEE80211_PS_UNICAST;
538 case IW_POWER_MULTICAST_R:
539 ieee->ps = IEEE80211_PS_MBCAST;
542 ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
546 /* ieee->ps = IEEE80211_PS_DISABLED; */
555 mutex_unlock(&ieee->wx_mutex);
559 EXPORT_SYMBOL(ieee80211_wx_set_power);
561 /* this is stolen from hostap */
562 int ieee80211_wx_get_power(struct ieee80211_device *ieee,
563 struct iw_request_info *info,
564 union iwreq_data *wrqu, char *extra)
566 mutex_lock(&ieee->wx_mutex);
568 if (ieee->ps == IEEE80211_PS_DISABLED) {
569 wrqu->power.disabled = 1;
573 wrqu->power.disabled = 0;
575 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
576 wrqu->power.flags = IW_POWER_TIMEOUT;
577 wrqu->power.value = ieee->ps_timeout * 1000;
579 /* ret = -EOPNOTSUPP; */
581 wrqu->power.flags = IW_POWER_PERIOD;
582 wrqu->power.value = ieee->ps_period * 1000;
583 /* ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024; */
586 if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST))
587 wrqu->power.flags |= IW_POWER_ALL_R;
588 else if (ieee->ps & IEEE80211_PS_MBCAST)
589 wrqu->power.flags |= IW_POWER_MULTICAST_R;
591 wrqu->power.flags |= IW_POWER_UNICAST_R;
594 mutex_unlock(&ieee->wx_mutex);
598 EXPORT_SYMBOL(ieee80211_wx_get_power);