1 // SPDX-License-Identifier: GPL-2.0
2 /* IEEE 802.11 SoftMAC layer
3  * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
4  *
5  * Mostly extracted from the rtl8180-sa2400 driver for the
6  * in-kernel generic ieee802.11 stack.
7  *
8  * Some pieces of code might be stolen from ipw2100 driver
9  * copyright of who own it's copyright ;-)
10  *
11  * PS wx handler mostly stolen from hostap, copyright who
12  * own it's copyright ;-)
13  */
14 #include <linux/etherdevice.h>
15 
16 #include "rtllib.h"
17 #include "dot11d.h"
18 
rtllib_wx_set_freq(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)19 int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
20 			     union iwreq_data *wrqu, char *b)
21 {
22 	int ret;
23 	struct iw_freq *fwrq = &wrqu->freq;
24 
25 	mutex_lock(&ieee->wx_mutex);
26 
27 	if (ieee->iw_mode == IW_MODE_INFRA) {
28 		ret = 0;
29 		goto out;
30 	}
31 
32 	/* if setting by freq convert to channel */
33 	if (fwrq->e == 1) {
34 		if ((fwrq->m >= (int)2.412e8 &&
35 		     fwrq->m <= (int)2.487e8)) {
36 			fwrq->m = ieee80211_freq_khz_to_channel(fwrq->m / 100);
37 			fwrq->e = 0;
38 		}
39 	}
40 
41 	if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
42 		ret = -EOPNOTSUPP;
43 		goto out;
44 
45 	} else { /* Set the channel */
46 
47 		if (ieee->active_channel_map[fwrq->m] != 1) {
48 			ret = -EINVAL;
49 			goto out;
50 		}
51 		ieee->current_network.channel = fwrq->m;
52 		ieee->set_chan(ieee->dev, ieee->current_network.channel);
53 
54 		if (ieee->iw_mode == IW_MODE_ADHOC)
55 			if (ieee->link_state == MAC80211_LINKED) {
56 				rtllib_stop_send_beacons(ieee);
57 				rtllib_start_send_beacons(ieee);
58 			}
59 	}
60 
61 	ret = 0;
62 out:
63 	mutex_unlock(&ieee->wx_mutex);
64 	return ret;
65 }
66 EXPORT_SYMBOL(rtllib_wx_set_freq);
67 
rtllib_wx_get_freq(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)68 int rtllib_wx_get_freq(struct rtllib_device *ieee,
69 			     struct iw_request_info *a,
70 			     union iwreq_data *wrqu, char *b)
71 {
72 	struct iw_freq *fwrq = &wrqu->freq;
73 
74 	if (ieee->current_network.channel == 0)
75 		return -1;
76 	fwrq->m = ieee80211_channel_to_freq_khz(ieee->current_network.channel,
77 						NL80211_BAND_2GHZ) * 100;
78 	fwrq->e = 1;
79 	return 0;
80 }
81 EXPORT_SYMBOL(rtllib_wx_get_freq);
82 
rtllib_wx_get_wap(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)83 int rtllib_wx_get_wap(struct rtllib_device *ieee,
84 			    struct iw_request_info *info,
85 			    union iwreq_data *wrqu, char *extra)
86 {
87 	unsigned long flags;
88 
89 	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
90 
91 	if (ieee->iw_mode == IW_MODE_MONITOR)
92 		return -1;
93 
94 	/* We want avoid to give to the user inconsistent infos*/
95 	spin_lock_irqsave(&ieee->lock, flags);
96 
97 	if (ieee->link_state != MAC80211_LINKED &&
98 		ieee->link_state != MAC80211_LINKED_SCANNING &&
99 		ieee->wap_set == 0)
100 
101 		eth_zero_addr(wrqu->ap_addr.sa_data);
102 	else
103 		memcpy(wrqu->ap_addr.sa_data,
104 		       ieee->current_network.bssid, ETH_ALEN);
105 
106 	spin_unlock_irqrestore(&ieee->lock, flags);
107 
108 	return 0;
109 }
110 EXPORT_SYMBOL(rtllib_wx_get_wap);
111 
rtllib_wx_set_wap(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * awrq,char * extra)112 int rtllib_wx_set_wap(struct rtllib_device *ieee,
113 			 struct iw_request_info *info,
114 			 union iwreq_data *awrq,
115 			 char *extra)
116 {
117 	int ret = 0;
118 	unsigned long flags;
119 
120 	short ifup = ieee->proto_started;
121 	struct sockaddr *temp = (struct sockaddr *)awrq;
122 
123 	rtllib_stop_scan_syncro(ieee);
124 
125 	mutex_lock(&ieee->wx_mutex);
126 	/* use ifconfig hw ether */
127 
128 	if (temp->sa_family != ARPHRD_ETHER) {
129 		ret = -EINVAL;
130 		goto out;
131 	}
132 
133 	if (is_zero_ether_addr(temp->sa_data)) {
134 		spin_lock_irqsave(&ieee->lock, flags);
135 		ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
136 		ieee->wap_set = 0;
137 		spin_unlock_irqrestore(&ieee->lock, flags);
138 		ret = -1;
139 		goto out;
140 	}
141 
142 	if (ifup)
143 		rtllib_stop_protocol(ieee, true);
144 
145 	/* just to avoid to give inconsistent infos in the
146 	 * get wx method. not really needed otherwise
147 	 */
148 	spin_lock_irqsave(&ieee->lock, flags);
149 
150 	ieee->cannot_notify = false;
151 	ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
152 	ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
153 
154 	spin_unlock_irqrestore(&ieee->lock, flags);
155 
156 	if (ifup)
157 		rtllib_start_protocol(ieee);
158 out:
159 	mutex_unlock(&ieee->wx_mutex);
160 	return ret;
161 }
162 EXPORT_SYMBOL(rtllib_wx_set_wap);
163 
rtllib_wx_get_essid(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)164 int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
165 			 union iwreq_data *wrqu, char *b)
166 {
167 	int len, ret = 0;
168 	unsigned long flags;
169 
170 	if (ieee->iw_mode == IW_MODE_MONITOR)
171 		return -1;
172 
173 	/* We want avoid to give to the user inconsistent infos*/
174 	spin_lock_irqsave(&ieee->lock, flags);
175 
176 	if (ieee->current_network.ssid[0] == '\0' ||
177 		ieee->current_network.ssid_len == 0) {
178 		ret = -1;
179 		goto out;
180 	}
181 
182 	if (ieee->link_state != MAC80211_LINKED &&
183 		ieee->link_state != MAC80211_LINKED_SCANNING &&
184 		ieee->ssid_set == 0) {
185 		ret = -1;
186 		goto out;
187 	}
188 	len = ieee->current_network.ssid_len;
189 	wrqu->essid.length = len;
190 	strncpy(b, ieee->current_network.ssid, len);
191 	wrqu->essid.flags = 1;
192 
193 out:
194 	spin_unlock_irqrestore(&ieee->lock, flags);
195 
196 	return ret;
197 }
198 EXPORT_SYMBOL(rtllib_wx_get_essid);
199 
rtllib_wx_set_rate(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)200 int rtllib_wx_set_rate(struct rtllib_device *ieee,
201 			     struct iw_request_info *info,
202 			     union iwreq_data *wrqu, char *extra)
203 {
204 	u32 target_rate = wrqu->bitrate.value;
205 
206 	ieee->rate = target_rate / 100000;
207 	return 0;
208 }
209 EXPORT_SYMBOL(rtllib_wx_set_rate);
210 
rtllib_wx_get_rate(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)211 int rtllib_wx_get_rate(struct rtllib_device *ieee,
212 			     struct iw_request_info *info,
213 			     union iwreq_data *wrqu, char *extra)
214 {
215 	u32 tmp_rate;
216 
217 	tmp_rate = TxCountToDataRate(ieee,
218 				     ieee->softmac_stats.CurrentShowTxate);
219 	wrqu->bitrate.value = tmp_rate * 500000;
220 
221 	return 0;
222 }
223 EXPORT_SYMBOL(rtllib_wx_get_rate);
224 
rtllib_wx_set_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)225 int rtllib_wx_set_rts(struct rtllib_device *ieee,
226 			     struct iw_request_info *info,
227 			     union iwreq_data *wrqu, char *extra)
228 {
229 	if (wrqu->rts.disabled || !wrqu->rts.fixed) {
230 		ieee->rts = DEFAULT_RTS_THRESHOLD;
231 	} else {
232 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
233 				wrqu->rts.value > MAX_RTS_THRESHOLD)
234 			return -EINVAL;
235 		ieee->rts = wrqu->rts.value;
236 	}
237 	return 0;
238 }
239 EXPORT_SYMBOL(rtllib_wx_set_rts);
240 
rtllib_wx_get_rts(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)241 int rtllib_wx_get_rts(struct rtllib_device *ieee,
242 			     struct iw_request_info *info,
243 			     union iwreq_data *wrqu, char *extra)
244 {
245 	wrqu->rts.value = ieee->rts;
246 	wrqu->rts.fixed = 0;	/* no auto select */
247 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
248 	return 0;
249 }
250 EXPORT_SYMBOL(rtllib_wx_get_rts);
251 
rtllib_wx_set_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)252 int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
253 			     union iwreq_data *wrqu, char *b)
254 {
255 	int set_mode_status = 0;
256 
257 	rtllib_stop_scan_syncro(ieee);
258 	mutex_lock(&ieee->wx_mutex);
259 	switch (wrqu->mode) {
260 	case IW_MODE_MONITOR:
261 	case IW_MODE_ADHOC:
262 	case IW_MODE_INFRA:
263 		break;
264 	case IW_MODE_AUTO:
265 		wrqu->mode = IW_MODE_INFRA;
266 		break;
267 	default:
268 		set_mode_status = -EINVAL;
269 		goto out;
270 	}
271 
272 	if (wrqu->mode == ieee->iw_mode)
273 		goto out;
274 
275 	if (wrqu->mode == IW_MODE_MONITOR) {
276 		ieee->dev->type = ARPHRD_IEEE80211;
277 		rtllib_EnableNetMonitorMode(ieee->dev, false);
278 	} else {
279 		ieee->dev->type = ARPHRD_ETHER;
280 		if (ieee->iw_mode == IW_MODE_MONITOR)
281 			rtllib_DisableNetMonitorMode(ieee->dev, false);
282 	}
283 
284 	if (!ieee->proto_started) {
285 		ieee->iw_mode = wrqu->mode;
286 	} else {
287 		rtllib_stop_protocol(ieee, true);
288 		ieee->iw_mode = wrqu->mode;
289 		rtllib_start_protocol(ieee);
290 	}
291 
292 out:
293 	mutex_unlock(&ieee->wx_mutex);
294 	return set_mode_status;
295 }
296 EXPORT_SYMBOL(rtllib_wx_set_mode);
297 
rtllib_wx_sync_scan_wq(void * data)298 void rtllib_wx_sync_scan_wq(void *data)
299 {
300 	struct rtllib_device *ieee = container_of(data, struct rtllib_device, wx_sync_scan_wq);
301 	short chan;
302 	enum ht_extchnl_offset chan_offset = 0;
303 	enum ht_channel_width bandwidth = 0;
304 	int b40M = 0;
305 
306 	mutex_lock(&ieee->wx_mutex);
307 	if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
308 		rtllib_start_scan_syncro(ieee);
309 		goto out;
310 	}
311 
312 	chan = ieee->current_network.channel;
313 
314 	ieee->leisure_ps_leave(ieee->dev);
315 	/* notify AP to be in PS mode */
316 	rtllib_sta_ps_send_null_frame(ieee, 1);
317 	rtllib_sta_ps_send_null_frame(ieee, 1);
318 
319 	rtllib_stop_all_queues(ieee);
320 	rtllib_stop_send_beacons(ieee);
321 	ieee->link_state = MAC80211_LINKED_SCANNING;
322 	ieee->link_change(ieee->dev);
323 	/* wait for ps packet to be kicked out successfully */
324 	msleep(50);
325 
326 	ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
327 
328 	if (ieee->ht_info->bCurrentHTSupport && ieee->ht_info->enable_ht &&
329 	    ieee->ht_info->bCurBW40MHz) {
330 		b40M = 1;
331 		chan_offset = ieee->ht_info->CurSTAExtChnlOffset;
332 		bandwidth = (enum ht_channel_width)ieee->ht_info->bCurBW40MHz;
333 		ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20,
334 				       HT_EXTCHNL_OFFSET_NO_EXT);
335 	}
336 
337 	rtllib_start_scan_syncro(ieee);
338 
339 	if (b40M) {
340 		if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
341 			ieee->set_chan(ieee->dev, chan + 2);
342 		else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
343 			ieee->set_chan(ieee->dev, chan - 2);
344 		else
345 			ieee->set_chan(ieee->dev, chan);
346 		ieee->set_bw_mode_handler(ieee->dev, bandwidth, chan_offset);
347 	} else {
348 		ieee->set_chan(ieee->dev, chan);
349 	}
350 
351 	ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
352 
353 	ieee->link_state = MAC80211_LINKED;
354 	ieee->link_change(ieee->dev);
355 
356 	/* Notify AP that I wake up again */
357 	rtllib_sta_ps_send_null_frame(ieee, 0);
358 
359 	if (ieee->link_detect_info.NumRecvBcnInPeriod == 0 ||
360 	    ieee->link_detect_info.NumRecvDataInPeriod == 0) {
361 		ieee->link_detect_info.NumRecvBcnInPeriod = 1;
362 		ieee->link_detect_info.NumRecvDataInPeriod = 1;
363 	}
364 	if (ieee->iw_mode == IW_MODE_ADHOC)
365 		rtllib_start_send_beacons(ieee);
366 
367 	rtllib_wake_all_queues(ieee);
368 
369 out:
370 	mutex_unlock(&ieee->wx_mutex);
371 }
372 
rtllib_wx_set_scan(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)373 int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
374 			     union iwreq_data *wrqu, char *b)
375 {
376 	int ret = 0;
377 
378 	if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
379 		ret = -1;
380 		goto out;
381 	}
382 
383 	if (ieee->link_state == MAC80211_LINKED) {
384 		schedule_work(&ieee->wx_sync_scan_wq);
385 		/* intentionally forget to up sem */
386 		return 0;
387 	}
388 
389 out:
390 	return ret;
391 }
392 EXPORT_SYMBOL(rtllib_wx_set_scan);
393 
rtllib_wx_set_essid(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * extra)394 int rtllib_wx_set_essid(struct rtllib_device *ieee,
395 			struct iw_request_info *a,
396 			union iwreq_data *wrqu, char *extra)
397 {
398 	int ret = 0, len;
399 	short proto_started;
400 	unsigned long flags;
401 
402 	rtllib_stop_scan_syncro(ieee);
403 	mutex_lock(&ieee->wx_mutex);
404 
405 	proto_started = ieee->proto_started;
406 
407 	len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
408 
409 	if (ieee->iw_mode == IW_MODE_MONITOR) {
410 		ret = -1;
411 		goto out;
412 	}
413 
414 	if (proto_started)
415 		rtllib_stop_protocol(ieee, true);
416 
417 	/* this is just to be sure that the GET wx callback
418 	 * has consistent infos. not needed otherwise
419 	 */
420 	spin_lock_irqsave(&ieee->lock, flags);
421 
422 	if (wrqu->essid.flags && wrqu->essid.length) {
423 		strncpy(ieee->current_network.ssid, extra, len);
424 		ieee->current_network.ssid_len = len;
425 		ieee->cannot_notify = false;
426 		ieee->ssid_set = 1;
427 	} else {
428 		ieee->ssid_set = 0;
429 		ieee->current_network.ssid[0] = '\0';
430 		ieee->current_network.ssid_len = 0;
431 	}
432 	spin_unlock_irqrestore(&ieee->lock, flags);
433 
434 	if (proto_started)
435 		rtllib_start_protocol(ieee);
436 out:
437 	mutex_unlock(&ieee->wx_mutex);
438 	return ret;
439 }
440 EXPORT_SYMBOL(rtllib_wx_set_essid);
441 
rtllib_wx_get_mode(struct rtllib_device * ieee,struct iw_request_info * a,union iwreq_data * wrqu,char * b)442 int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
443 		       union iwreq_data *wrqu, char *b)
444 {
445 	wrqu->mode = ieee->iw_mode;
446 	return 0;
447 }
448 EXPORT_SYMBOL(rtllib_wx_get_mode);
449 
rtllib_wx_set_rawtx(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)450 int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
451 			struct iw_request_info *info,
452 			union iwreq_data *wrqu, char *extra)
453 {
454 	int *parms = (int *)extra;
455 	int enable = (parms[0] > 0);
456 	short prev = ieee->raw_tx;
457 
458 	mutex_lock(&ieee->wx_mutex);
459 
460 	if (enable)
461 		ieee->raw_tx = 1;
462 	else
463 		ieee->raw_tx = 0;
464 
465 	netdev_info(ieee->dev, "raw TX is %s\n",
466 		    ieee->raw_tx ? "enabled" : "disabled");
467 
468 	if (ieee->iw_mode == IW_MODE_MONITOR) {
469 		if (prev == 0 && ieee->raw_tx)
470 			netif_carrier_on(ieee->dev);
471 
472 		if (prev && ieee->raw_tx == 1)
473 			netif_carrier_off(ieee->dev);
474 	}
475 
476 	mutex_unlock(&ieee->wx_mutex);
477 
478 	return 0;
479 }
480 EXPORT_SYMBOL(rtllib_wx_set_rawtx);
481 
rtllib_wx_get_name(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)482 int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info,
483 		       union iwreq_data *wrqu, char *extra)
484 {
485 	const char *n = ieee->mode & (WIRELESS_MODE_N_24G) ? "n" : "";
486 
487 	scnprintf(wrqu->name, sizeof(wrqu->name), "802.11bg%s", n);
488 	return 0;
489 }
490 EXPORT_SYMBOL(rtllib_wx_get_name);
491 
492 /* this is mostly stolen from hostap */
rtllib_wx_set_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)493 int rtllib_wx_set_power(struct rtllib_device *ieee,
494 				 struct iw_request_info *info,
495 				 union iwreq_data *wrqu, char *extra)
496 {
497 	int ret = 0;
498 
499 	if ((!ieee->sta_wake_up) ||
500 	    (!ieee->enter_sleep_state) ||
501 	    (!ieee->ps_is_queue_empty)) {
502 		netdev_warn(ieee->dev,
503 			    "%s(): PS mode is tried to be use but driver missed a callback\n",
504 			    __func__);
505 		return -1;
506 	}
507 
508 	mutex_lock(&ieee->wx_mutex);
509 
510 	if (wrqu->power.disabled) {
511 		ieee->ps = RTLLIB_PS_DISABLED;
512 		goto exit;
513 	}
514 	if (wrqu->power.flags & IW_POWER_TIMEOUT)
515 		ieee->ps_timeout = wrqu->power.value / 1000;
516 
517 	if (wrqu->power.flags & IW_POWER_PERIOD)
518 		ieee->ps_period = wrqu->power.value / 1000;
519 
520 	switch (wrqu->power.flags & IW_POWER_MODE) {
521 	case IW_POWER_UNICAST_R:
522 		ieee->ps = RTLLIB_PS_UNICAST;
523 		break;
524 	case IW_POWER_MULTICAST_R:
525 		ieee->ps = RTLLIB_PS_MBCAST;
526 		break;
527 	case IW_POWER_ALL_R:
528 		ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
529 		break;
530 
531 	case IW_POWER_ON:
532 		break;
533 
534 	default:
535 		ret = -EINVAL;
536 		goto exit;
537 	}
538 exit:
539 	mutex_unlock(&ieee->wx_mutex);
540 	return ret;
541 }
542 EXPORT_SYMBOL(rtllib_wx_set_power);
543 
544 /* this is stolen from hostap */
rtllib_wx_get_power(struct rtllib_device * ieee,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)545 int rtllib_wx_get_power(struct rtllib_device *ieee,
546 				 struct iw_request_info *info,
547 				 union iwreq_data *wrqu, char *extra)
548 {
549 	mutex_lock(&ieee->wx_mutex);
550 
551 	if (ieee->ps == RTLLIB_PS_DISABLED) {
552 		wrqu->power.disabled = 1;
553 		goto exit;
554 	}
555 
556 	wrqu->power.disabled = 0;
557 
558 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
559 		wrqu->power.flags = IW_POWER_TIMEOUT;
560 		wrqu->power.value = ieee->ps_timeout * 1000;
561 	} else {
562 		wrqu->power.flags = IW_POWER_PERIOD;
563 		wrqu->power.value = ieee->ps_period * 1000;
564 	}
565 
566 	if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
567 	    (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
568 		wrqu->power.flags |= IW_POWER_ALL_R;
569 	else if (ieee->ps & RTLLIB_PS_MBCAST)
570 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
571 	else
572 		wrqu->power.flags |= IW_POWER_UNICAST_R;
573 
574 exit:
575 	mutex_unlock(&ieee->wx_mutex);
576 	return 0;
577 }
578 EXPORT_SYMBOL(rtllib_wx_get_power);
579