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 ;-)
14 #include <linux/etherdevice.h>
18 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
19 union iwreq_data *wrqu, char *b)
22 struct iw_freq *fwrq = &wrqu->freq;
24 mutex_lock(&ieee->wx_mutex);
26 if (ieee->iw_mode == IW_MODE_INFRA) {
31 /* if setting by freq convert to channel */
33 if ((fwrq->m >= (int)2.412e8 &&
34 fwrq->m <= (int)2.487e8)) {
35 fwrq->m = ieee80211_freq_khz_to_channel(fwrq->m / 100);
40 if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
44 } else { /* Set the channel */
46 if (ieee->active_channel_map[fwrq->m] != 1) {
50 ieee->current_network.channel = fwrq->m;
51 ieee->set_chan(ieee->dev, ieee->current_network.channel);
56 mutex_unlock(&ieee->wx_mutex);
59 EXPORT_SYMBOL(rtllib_wx_set_freq);
61 int rtllib_wx_get_freq(struct rtllib_device *ieee,
62 struct iw_request_info *a,
63 union iwreq_data *wrqu, char *b)
65 struct iw_freq *fwrq = &wrqu->freq;
67 if (ieee->current_network.channel == 0)
69 fwrq->m = ieee80211_channel_to_freq_khz(ieee->current_network.channel,
70 NL80211_BAND_2GHZ) * 100;
74 EXPORT_SYMBOL(rtllib_wx_get_freq);
76 int rtllib_wx_get_wap(struct rtllib_device *ieee,
77 struct iw_request_info *info,
78 union iwreq_data *wrqu, char *extra)
82 wrqu->ap_addr.sa_family = ARPHRD_ETHER;
84 if (ieee->iw_mode == IW_MODE_MONITOR)
87 /* We want avoid to give to the user inconsistent infos*/
88 spin_lock_irqsave(&ieee->lock, flags);
90 if (ieee->link_state != MAC80211_LINKED &&
91 ieee->link_state != MAC80211_LINKED_SCANNING &&
94 eth_zero_addr(wrqu->ap_addr.sa_data);
96 memcpy(wrqu->ap_addr.sa_data,
97 ieee->current_network.bssid, ETH_ALEN);
99 spin_unlock_irqrestore(&ieee->lock, flags);
103 EXPORT_SYMBOL(rtllib_wx_get_wap);
105 int rtllib_wx_set_wap(struct rtllib_device *ieee,
106 struct iw_request_info *info,
107 union iwreq_data *awrq,
113 short ifup = ieee->proto_started;
114 struct sockaddr *temp = (struct sockaddr *)awrq;
116 rtllib_stop_scan_syncro(ieee);
118 mutex_lock(&ieee->wx_mutex);
119 /* use ifconfig hw ether */
121 if (temp->sa_family != ARPHRD_ETHER) {
126 if (is_zero_ether_addr(temp->sa_data)) {
127 spin_lock_irqsave(&ieee->lock, flags);
128 ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
130 spin_unlock_irqrestore(&ieee->lock, flags);
136 rtllib_stop_protocol(ieee);
138 /* just to avoid to give inconsistent infos in the
139 * get wx method. not really needed otherwise
141 spin_lock_irqsave(&ieee->lock, flags);
143 ieee->cannot_notify = false;
144 ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
145 ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
147 spin_unlock_irqrestore(&ieee->lock, flags);
150 rtllib_start_protocol(ieee);
152 mutex_unlock(&ieee->wx_mutex);
155 EXPORT_SYMBOL(rtllib_wx_set_wap);
157 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
158 union iwreq_data *wrqu, char *b)
163 if (ieee->iw_mode == IW_MODE_MONITOR)
166 /* We want avoid to give to the user inconsistent infos*/
167 spin_lock_irqsave(&ieee->lock, flags);
169 if (ieee->current_network.ssid[0] == '\0' ||
170 ieee->current_network.ssid_len == 0) {
175 if (ieee->link_state != MAC80211_LINKED &&
176 ieee->link_state != MAC80211_LINKED_SCANNING &&
177 ieee->ssid_set == 0) {
181 len = ieee->current_network.ssid_len;
182 wrqu->essid.length = len;
183 strncpy(b, ieee->current_network.ssid, len);
184 wrqu->essid.flags = 1;
187 spin_unlock_irqrestore(&ieee->lock, flags);
191 EXPORT_SYMBOL(rtllib_wx_get_essid);
193 int rtllib_wx_set_rate(struct rtllib_device *ieee,
194 struct iw_request_info *info,
195 union iwreq_data *wrqu, char *extra)
197 u32 target_rate = wrqu->bitrate.value;
199 ieee->rate = target_rate / 100000;
202 EXPORT_SYMBOL(rtllib_wx_set_rate);
204 int rtllib_wx_get_rate(struct rtllib_device *ieee,
205 struct iw_request_info *info,
206 union iwreq_data *wrqu, char *extra)
210 tmp_rate = tx_count_to_data_rate(ieee,
211 ieee->softmac_stats.CurrentShowTxate);
212 wrqu->bitrate.value = tmp_rate * 500000;
216 EXPORT_SYMBOL(rtllib_wx_get_rate);
218 int rtllib_wx_set_rts(struct rtllib_device *ieee,
219 struct iw_request_info *info,
220 union iwreq_data *wrqu, char *extra)
222 if (wrqu->rts.disabled || !wrqu->rts.fixed) {
223 ieee->rts = DEFAULT_RTS_THRESHOLD;
225 if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
226 wrqu->rts.value > MAX_RTS_THRESHOLD)
228 ieee->rts = wrqu->rts.value;
232 EXPORT_SYMBOL(rtllib_wx_set_rts);
234 int rtllib_wx_get_rts(struct rtllib_device *ieee,
235 struct iw_request_info *info,
236 union iwreq_data *wrqu, char *extra)
238 wrqu->rts.value = ieee->rts;
239 wrqu->rts.fixed = 0; /* no auto select */
240 wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
243 EXPORT_SYMBOL(rtllib_wx_get_rts);
245 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
246 union iwreq_data *wrqu, char *b)
248 int set_mode_status = 0;
250 rtllib_stop_scan_syncro(ieee);
251 mutex_lock(&ieee->wx_mutex);
252 switch (wrqu->mode) {
253 case IW_MODE_MONITOR:
257 wrqu->mode = IW_MODE_INFRA;
260 set_mode_status = -EINVAL;
264 if (wrqu->mode == ieee->iw_mode)
267 if (wrqu->mode == IW_MODE_MONITOR) {
268 ieee->dev->type = ARPHRD_IEEE80211;
269 rtllib_enable_net_monitor_mode(ieee->dev, false);
271 ieee->dev->type = ARPHRD_ETHER;
272 if (ieee->iw_mode == IW_MODE_MONITOR)
273 rtllib_disable_net_monitor_mode(ieee->dev, false);
276 if (!ieee->proto_started) {
277 ieee->iw_mode = wrqu->mode;
279 rtllib_stop_protocol(ieee);
280 ieee->iw_mode = wrqu->mode;
281 rtllib_start_protocol(ieee);
285 mutex_unlock(&ieee->wx_mutex);
286 return set_mode_status;
288 EXPORT_SYMBOL(rtllib_wx_set_mode);
290 void rtllib_wx_sync_scan_wq(void *data)
292 struct rtllib_device *ieee = container_of(data, struct rtllib_device, wx_sync_scan_wq);
294 enum ht_extchnl_offset chan_offset = 0;
295 enum ht_channel_width bandwidth = 0;
298 mutex_lock(&ieee->wx_mutex);
299 if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
300 rtllib_start_scan_syncro(ieee);
304 chan = ieee->current_network.channel;
306 ieee->leisure_ps_leave(ieee->dev);
307 /* notify AP to be in PS mode */
308 rtllib_sta_ps_send_null_frame(ieee, 1);
309 rtllib_sta_ps_send_null_frame(ieee, 1);
311 rtllib_stop_all_queues(ieee);
312 ieee->link_state = MAC80211_LINKED_SCANNING;
313 ieee->link_change(ieee->dev);
314 /* wait for ps packet to be kicked out successfully */
317 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
319 if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht &&
320 ieee->ht_info->cur_bw_40mhz) {
322 chan_offset = ieee->ht_info->CurSTAExtChnlOffset;
323 bandwidth = (enum ht_channel_width)ieee->ht_info->cur_bw_40mhz;
324 ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20,
325 HT_EXTCHNL_OFFSET_NO_EXT);
328 rtllib_start_scan_syncro(ieee);
331 if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
332 ieee->set_chan(ieee->dev, chan + 2);
333 else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
334 ieee->set_chan(ieee->dev, chan - 2);
336 ieee->set_chan(ieee->dev, chan);
337 ieee->set_bw_mode_handler(ieee->dev, bandwidth, chan_offset);
339 ieee->set_chan(ieee->dev, chan);
342 ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
344 ieee->link_state = MAC80211_LINKED;
345 ieee->link_change(ieee->dev);
347 /* Notify AP that I wake up again */
348 rtllib_sta_ps_send_null_frame(ieee, 0);
350 if (ieee->link_detect_info.NumRecvBcnInPeriod == 0 ||
351 ieee->link_detect_info.NumRecvDataInPeriod == 0) {
352 ieee->link_detect_info.NumRecvBcnInPeriod = 1;
353 ieee->link_detect_info.NumRecvDataInPeriod = 1;
355 rtllib_wake_all_queues(ieee);
358 mutex_unlock(&ieee->wx_mutex);
361 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
362 union iwreq_data *wrqu, char *b)
366 if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
371 if (ieee->link_state == MAC80211_LINKED) {
372 schedule_work(&ieee->wx_sync_scan_wq);
373 /* intentionally forget to up sem */
380 EXPORT_SYMBOL(rtllib_wx_set_scan);
382 int rtllib_wx_set_essid(struct rtllib_device *ieee,
383 struct iw_request_info *a,
384 union iwreq_data *wrqu, char *extra)
390 rtllib_stop_scan_syncro(ieee);
391 mutex_lock(&ieee->wx_mutex);
393 proto_started = ieee->proto_started;
395 len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
397 if (ieee->iw_mode == IW_MODE_MONITOR) {
403 rtllib_stop_protocol(ieee);
405 /* this is just to be sure that the GET wx callback
406 * has consistent infos. not needed otherwise
408 spin_lock_irqsave(&ieee->lock, flags);
410 if (wrqu->essid.flags && wrqu->essid.length) {
411 strncpy(ieee->current_network.ssid, extra, len);
412 ieee->current_network.ssid_len = len;
413 ieee->cannot_notify = false;
417 ieee->current_network.ssid[0] = '\0';
418 ieee->current_network.ssid_len = 0;
420 spin_unlock_irqrestore(&ieee->lock, flags);
423 rtllib_start_protocol(ieee);
425 mutex_unlock(&ieee->wx_mutex);
428 EXPORT_SYMBOL(rtllib_wx_set_essid);
430 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
431 union iwreq_data *wrqu, char *b)
433 wrqu->mode = ieee->iw_mode;
436 EXPORT_SYMBOL(rtllib_wx_get_mode);
438 int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info,
439 union iwreq_data *wrqu, char *extra)
441 const char *n = ieee->mode & (WIRELESS_MODE_N_24G) ? "n" : "";
443 scnprintf(wrqu->name, sizeof(wrqu->name), "802.11bg%s", n);
446 EXPORT_SYMBOL(rtllib_wx_get_name);
448 /* this is mostly stolen from hostap */
449 int rtllib_wx_set_power(struct rtllib_device *ieee,
450 struct iw_request_info *info,
451 union iwreq_data *wrqu, char *extra)
455 if ((!ieee->sta_wake_up) ||
456 (!ieee->enter_sleep_state) ||
457 (!ieee->ps_is_queue_empty)) {
458 netdev_warn(ieee->dev,
459 "%s(): PS mode is tried to be use but driver missed a callback\n",
464 mutex_lock(&ieee->wx_mutex);
466 if (wrqu->power.disabled) {
467 ieee->ps = RTLLIB_PS_DISABLED;
470 if (wrqu->power.flags & IW_POWER_TIMEOUT)
471 ieee->ps_timeout = wrqu->power.value / 1000;
473 if (wrqu->power.flags & IW_POWER_PERIOD)
474 ieee->ps_period = wrqu->power.value / 1000;
476 switch (wrqu->power.flags & IW_POWER_MODE) {
477 case IW_POWER_UNICAST_R:
478 ieee->ps = RTLLIB_PS_UNICAST;
480 case IW_POWER_MULTICAST_R:
481 ieee->ps = RTLLIB_PS_MBCAST;
484 ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
495 mutex_unlock(&ieee->wx_mutex);
498 EXPORT_SYMBOL(rtllib_wx_set_power);
500 /* this is stolen from hostap */
501 int rtllib_wx_get_power(struct rtllib_device *ieee,
502 struct iw_request_info *info,
503 union iwreq_data *wrqu, char *extra)
505 mutex_lock(&ieee->wx_mutex);
507 if (ieee->ps == RTLLIB_PS_DISABLED) {
508 wrqu->power.disabled = 1;
512 wrqu->power.disabled = 0;
514 if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
515 wrqu->power.flags = IW_POWER_TIMEOUT;
516 wrqu->power.value = ieee->ps_timeout * 1000;
518 wrqu->power.flags = IW_POWER_PERIOD;
519 wrqu->power.value = ieee->ps_period * 1000;
522 if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
523 (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
524 wrqu->power.flags |= IW_POWER_ALL_R;
525 else if (ieee->ps & RTLLIB_PS_MBCAST)
526 wrqu->power.flags |= IW_POWER_MULTICAST_R;
528 wrqu->power.flags |= IW_POWER_UNICAST_R;
531 mutex_unlock(&ieee->wx_mutex);
534 EXPORT_SYMBOL(rtllib_wx_get_power);