1 /* IEEE 802.11 SoftMAC layer
2  * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it>
3  *
4  * Mostly extracted from the rtl8180-sa2400 driver for the
5  * in-kernel generic ieee802.11 stack.
6  *
7  * Some pieces of code might be stolen from ipw2100 driver
8  * copyright of who own it's copyright ;-)
9  *
10  * PS wx handler mostly stolen from hostap, copyright who
11  * own it's copyright ;-)
12  *
13  * released under the GPL
14  */
15 
16 
17 #include <linux/etherdevice.h>
18 
19 #include "ieee80211.h"
20 #include "dot11d.h"
21 /* FIXME: add A freqs */
22 
23 const long ieee80211_wlan_frequencies[] = {
24 	2412, 2417, 2422, 2427,
25 	2432, 2437, 2442, 2447,
26 	2452, 2457, 2462, 2467,
27 	2472, 2484
28 };
29 
30 
31 int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
32 			     union iwreq_data *wrqu, char *b)
33 {
34 	int ret;
35 	struct iw_freq *fwrq = & wrqu->freq;
36 
37 	down(&ieee->wx_sem);
38 
39 	if(ieee->iw_mode == IW_MODE_INFRA){
40 		ret = -EOPNOTSUPP;
41 		goto out;
42 	}
43 
44 	/* if setting by freq convert to channel */
45 	if (fwrq->e == 1) {
46 		if ((fwrq->m >= (int) 2.412e8 &&
47 		     fwrq->m <= (int) 2.487e8)) {
48 			int f = fwrq->m / 100000;
49 			int c = 0;
50 
51 			while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
52 				c++;
53 
54 			/* hack to fall through */
55 			fwrq->e = 0;
56 			fwrq->m = c + 1;
57 		}
58 	}
59 
60 	if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){
61 		ret = -EOPNOTSUPP;
62 		goto out;
63 
64 	}else { /* Set the channel */
65 
66 		if (!(GET_DOT11D_INFO(ieee)->channel_map)[fwrq->m]) {
67 			ret = -EINVAL;
68 			goto out;
69 		}
70 		ieee->current_network.channel = fwrq->m;
71 		ieee->set_chan(ieee->dev, ieee->current_network.channel);
72 
73 		if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
74 			if(ieee->state == IEEE80211_LINKED){
75 
76 			ieee80211_stop_send_beacons(ieee);
77 			ieee80211_start_send_beacons(ieee);
78 			}
79 	}
80 
81 	ret = 0;
82 out:
83 	up(&ieee->wx_sem);
84 	return ret;
85 }
86 
87 
88 int ieee80211_wx_get_freq(struct ieee80211_device *ieee,
89 			     struct iw_request_info *a,
90 			     union iwreq_data *wrqu, char *b)
91 {
92 	struct iw_freq *fwrq = & wrqu->freq;
93 
94 	if (ieee->current_network.channel == 0)
95 		return -1;
96 	//NM 0.7.0 will not accept channel any more.
97 	fwrq->m = ieee80211_wlan_frequencies[ieee->current_network.channel-1] * 100000;
98 	fwrq->e = 1;
99 //	fwrq->m = ieee->current_network.channel;
100 //	fwrq->e = 0;
101 
102 	return 0;
103 }
104 
105 int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
106 			    struct iw_request_info *info,
107 			    union iwreq_data *wrqu, char *extra)
108 {
109 	unsigned long flags;
110 
111 	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
112 
113 	if (ieee->iw_mode == IW_MODE_MONITOR)
114 		return -1;
115 
116 	/* We want avoid to give to the user inconsistent infos*/
117 	spin_lock_irqsave(&ieee->lock, flags);
118 
119 	if (ieee->state != IEEE80211_LINKED &&
120 		ieee->state != IEEE80211_LINKED_SCANNING &&
121 		ieee->wap_set == 0)
122 
123 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
124 	else
125 		memcpy(wrqu->ap_addr.sa_data,
126 		       ieee->current_network.bssid, ETH_ALEN);
127 
128 	spin_unlock_irqrestore(&ieee->lock, flags);
129 
130 	return 0;
131 }
132 
133 
134 int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
135 			 struct iw_request_info *info,
136 			 union iwreq_data *awrq,
137 			 char *extra)
138 {
139 
140 	int ret = 0;
141 	unsigned long flags;
142 
143 	short ifup = ieee->proto_started;//dev->flags & IFF_UP;
144 	struct sockaddr *temp = (struct sockaddr *)awrq;
145 
146 	ieee->sync_scan_hurryup = 1;
147 
148 	down(&ieee->wx_sem);
149 	/* use ifconfig hw ether */
150 	if (ieee->iw_mode == IW_MODE_MASTER){
151 		ret = -1;
152 		goto out;
153 	}
154 
155 	if (temp->sa_family != ARPHRD_ETHER){
156 		ret = -EINVAL;
157 		goto out;
158 	}
159 
160 	if (ifup)
161 		ieee80211_stop_protocol(ieee);
162 
163 	/* just to avoid to give inconsistent infos in the
164 	 * get wx method. not really needed otherwise
165 	 */
166 	spin_lock_irqsave(&ieee->lock, flags);
167 
168 	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
169 	ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
170 
171 	spin_unlock_irqrestore(&ieee->lock, flags);
172 
173 	if (ifup)
174 		ieee80211_start_protocol(ieee);
175 out:
176 	up(&ieee->wx_sem);
177 	return ret;
178 }
179 
180  int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
181 {
182 	int len,ret = 0;
183 	unsigned long flags;
184 
185 	if (ieee->iw_mode == IW_MODE_MONITOR)
186 		return -1;
187 
188 	/* We want avoid to give to the user inconsistent infos*/
189 	spin_lock_irqsave(&ieee->lock, flags);
190 
191 	if (ieee->current_network.ssid[0] == '\0' ||
192 		ieee->current_network.ssid_len == 0){
193 		ret = -1;
194 		goto out;
195 	}
196 
197 	if (ieee->state != IEEE80211_LINKED &&
198 		ieee->state != IEEE80211_LINKED_SCANNING &&
199 		ieee->ssid_set == 0){
200 		ret = -1;
201 		goto out;
202 	}
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;
207 
208 out:
209 	spin_unlock_irqrestore(&ieee->lock, flags);
210 
211 	return ret;
212 
213 }
214 
215 int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
216 			     struct iw_request_info *info,
217 			     union iwreq_data *wrqu, char *extra)
218 {
219 
220 	u32 target_rate = wrqu->bitrate.value;
221 
222 	ieee->rate = target_rate/100000;
223 	//FIXME: we might want to limit rate also in management protocols.
224 	return 0;
225 }
226 
227 
228 
229 int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
230 			     struct iw_request_info *info,
231 			     union iwreq_data *wrqu, char *extra)
232 {
233 	u32 tmp_rate;
234 	tmp_rate = TxCountToDataRate(ieee, ieee->softmac_stats.CurrentShowTxate);
235 
236 	wrqu->bitrate.value = tmp_rate * 500000;
237 
238 	return 0;
239 }
240 
241 
242 int ieee80211_wx_set_rts(struct ieee80211_device *ieee,
243 			     struct iw_request_info *info,
244 			     union iwreq_data *wrqu, char *extra)
245 {
246 	if (wrqu->rts.disabled || !wrqu->rts.fixed)
247 		ieee->rts = DEFAULT_RTS_THRESHOLD;
248 	else
249 	{
250 		if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
251 				wrqu->rts.value > MAX_RTS_THRESHOLD)
252 			return -EINVAL;
253 		ieee->rts = wrqu->rts.value;
254 	}
255 	return 0;
256 }
257 
258 int ieee80211_wx_get_rts(struct ieee80211_device *ieee,
259 			     struct iw_request_info *info,
260 			     union iwreq_data *wrqu, char *extra)
261 {
262 	wrqu->rts.value = ieee->rts;
263 	wrqu->rts.fixed = 0;	/* no auto select */
264 	wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
265 	return 0;
266 }
267 int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
268 			     union iwreq_data *wrqu, char *b)
269 {
270 
271 	ieee->sync_scan_hurryup = 1;
272 
273 	down(&ieee->wx_sem);
274 
275 	if (wrqu->mode == ieee->iw_mode)
276 		goto out;
277 
278 	if (wrqu->mode == IW_MODE_MONITOR){
279 
280 		ieee->dev->type = ARPHRD_IEEE80211;
281 	}else{
282 		ieee->dev->type = ARPHRD_ETHER;
283 	}
284 
285 	if (!ieee->proto_started){
286 		ieee->iw_mode = wrqu->mode;
287 	}else{
288 		ieee80211_stop_protocol(ieee);
289 		ieee->iw_mode = wrqu->mode;
290 		ieee80211_start_protocol(ieee);
291 	}
292 
293 out:
294 	up(&ieee->wx_sem);
295 	return 0;
296 }
297 
298 void ieee80211_wx_sync_scan_wq(struct work_struct *work)
299 {
300 	struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
301 	short chan;
302 	HT_EXTCHNL_OFFSET chan_offset=0;
303 	HT_CHANNEL_WIDTH bandwidth=0;
304 	int b40M = 0;
305 	static int count = 0;
306 	chan = ieee->current_network.channel;
307 	netif_carrier_off(ieee->dev);
308 
309 	if (ieee->data_hard_stop)
310 		ieee->data_hard_stop(ieee->dev);
311 
312 	ieee80211_stop_send_beacons(ieee);
313 
314 	ieee->state = IEEE80211_LINKED_SCANNING;
315 	ieee->link_change(ieee->dev);
316 	ieee->InitialGainHandler(ieee->dev,IG_Backup);
317 	if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT && ieee->pHTInfo->bCurBW40MHz) {
318 		b40M = 1;
319 		chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
320 		bandwidth = (HT_CHANNEL_WIDTH)ieee->pHTInfo->bCurBW40MHz;
321 		printk("Scan in 40M, force to 20M first:%d, %d\n", chan_offset, bandwidth);
322 		ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
323 		}
324 	ieee80211_start_scan_syncro(ieee);
325 	if (b40M) {
326 		printk("Scan in 20M, back to 40M\n");
327 		if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
328 			ieee->set_chan(ieee->dev, chan + 2);
329 		else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
330 			ieee->set_chan(ieee->dev, chan - 2);
331 		else
332 			ieee->set_chan(ieee->dev, chan);
333 		ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
334 	} else {
335 		ieee->set_chan(ieee->dev, chan);
336 	}
337 
338 	ieee->InitialGainHandler(ieee->dev,IG_Restore);
339 	ieee->state = IEEE80211_LINKED;
340 	ieee->link_change(ieee->dev);
341 	// To prevent the immediately calling watch_dog after scan.
342 	if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 )
343 	{
344 		ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
345 		ieee->LinkDetectInfo.NumRecvDataInPeriod= 1;
346 	}
347 	if (ieee->data_hard_resume)
348 		ieee->data_hard_resume(ieee->dev);
349 
350 	if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
351 		ieee80211_start_send_beacons(ieee);
352 
353 	netif_carrier_on(ieee->dev);
354 	count = 0;
355 	up(&ieee->wx_sem);
356 
357 }
358 
359 int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
360 			     union iwreq_data *wrqu, char *b)
361 {
362 	int ret = 0;
363 
364 	down(&ieee->wx_sem);
365 
366 	if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
367 		ret = -1;
368 		goto out;
369 	}
370 
371 	if ( ieee->state == IEEE80211_LINKED){
372 		queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
373 		/* intentionally forget to up sem */
374 		return 0;
375 	}
376 
377 out:
378 	up(&ieee->wx_sem);
379 	return ret;
380 }
381 
382 int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
383 			      struct iw_request_info *a,
384 			      union iwreq_data *wrqu, char *extra)
385 {
386 
387 	int ret=0,len;
388 	short proto_started;
389 	unsigned long flags;
390 
391 	ieee->sync_scan_hurryup = 1;
392 	down(&ieee->wx_sem);
393 
394 	proto_started = ieee->proto_started;
395 
396 	if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
397 		ret= -E2BIG;
398 		goto out;
399 	}
400 
401 	if (ieee->iw_mode == IW_MODE_MONITOR){
402 		ret= -1;
403 		goto out;
404 	}
405 
406 	if(proto_started)
407 		ieee80211_stop_protocol(ieee);
408 
409 
410 	/* this is just to be sure that the GET wx callback
411 	 * has consisten infos. not needed otherwise
412 	 */
413 	spin_lock_irqsave(&ieee->lock, flags);
414 
415 	if (wrqu->essid.flags && wrqu->essid.length) {
416 		//first flush current network.ssid
417 		len = ((wrqu->essid.length-1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length-1) : IW_ESSID_MAX_SIZE;
418 		strncpy(ieee->current_network.ssid, extra, len+1);
419 		ieee->current_network.ssid_len = len+1;
420 		ieee->ssid_set = 1;
421 	}
422 	else{
423 		ieee->ssid_set = 0;
424 		ieee->current_network.ssid[0] = '\0';
425 		ieee->current_network.ssid_len = 0;
426 	}
427 	spin_unlock_irqrestore(&ieee->lock, flags);
428 
429 	if (proto_started)
430 		ieee80211_start_protocol(ieee);
431 out:
432 	up(&ieee->wx_sem);
433 	return ret;
434 }
435 
436  int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
437 			     union iwreq_data *wrqu, char *b)
438 {
439 
440 	wrqu->mode = ieee->iw_mode;
441 	return 0;
442 }
443 
444  int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
445 			       struct iw_request_info *info,
446 			       union iwreq_data *wrqu, char *extra)
447 {
448 
449 	int *parms = (int *)extra;
450 	int enable = (parms[0] > 0);
451 	short prev = ieee->raw_tx;
452 
453 	down(&ieee->wx_sem);
454 
455 	if(enable)
456 		ieee->raw_tx = 1;
457 	else
458 		ieee->raw_tx = 0;
459 
460 	printk(KERN_INFO"raw TX is %s\n",
461 	      ieee->raw_tx ? "enabled" : "disabled");
462 
463 	if(ieee->iw_mode == IW_MODE_MONITOR)
464 	{
465 		if(prev == 0 && ieee->raw_tx){
466 			if (ieee->data_hard_resume)
467 				ieee->data_hard_resume(ieee->dev);
468 
469 			netif_carrier_on(ieee->dev);
470 		}
471 
472 		if(prev && ieee->raw_tx == 1)
473 			netif_carrier_off(ieee->dev);
474 	}
475 
476 	up(&ieee->wx_sem);
477 
478 	return 0;
479 }
480 
481 int ieee80211_wx_get_name(struct ieee80211_device *ieee,
482 			     struct iw_request_info *info,
483 			     union iwreq_data *wrqu, char *extra)
484 {
485 	strcpy(wrqu->name, "802.11");
486 	if(ieee->modulation & IEEE80211_CCK_MODULATION){
487 		strcat(wrqu->name, "b");
488 		if(ieee->modulation & IEEE80211_OFDM_MODULATION)
489 			strcat(wrqu->name, "/g");
490 	}else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
491 		strcat(wrqu->name, "g");
492 	if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
493 		strcat(wrqu->name, "/n");
494 
495 	if((ieee->state == IEEE80211_LINKED) ||
496 		(ieee->state == IEEE80211_LINKED_SCANNING))
497 		strcat(wrqu->name," linked");
498 	else if(ieee->state != IEEE80211_NOLINK)
499 		strcat(wrqu->name," link..");
500 
501 
502 	return 0;
503 }
504 
505 
506 /* this is mostly stolen from hostap */
507 int ieee80211_wx_set_power(struct ieee80211_device *ieee,
508 				 struct iw_request_info *info,
509 				 union iwreq_data *wrqu, char *extra)
510 {
511 	int ret = 0;
512 	down(&ieee->wx_sem);
513 
514 	if (wrqu->power.disabled){
515 		ieee->ps = IEEE80211_PS_DISABLED;
516 		goto exit;
517 	}
518 	if (wrqu->power.flags & IW_POWER_TIMEOUT) {
519 		//ieee->ps_period = wrqu->power.value / 1000;
520 		ieee->ps_timeout = wrqu->power.value / 1000;
521 	}
522 
523 	if (wrqu->power.flags & IW_POWER_PERIOD) {
524 
525 		//ieee->ps_timeout = wrqu->power.value / 1000;
526 		ieee->ps_period = wrqu->power.value / 1000;
527 		//wrq->value / 1024;
528 
529 	}
530 	switch (wrqu->power.flags & IW_POWER_MODE) {
531 	case IW_POWER_UNICAST_R:
532 		ieee->ps = IEEE80211_PS_UNICAST;
533 		break;
534 	case IW_POWER_MULTICAST_R:
535 		ieee->ps = IEEE80211_PS_MBCAST;
536 		break;
537 	case IW_POWER_ALL_R:
538 		ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
539 		break;
540 
541 	case IW_POWER_ON:
542 	//	ieee->ps = IEEE80211_PS_DISABLED;
543 		break;
544 
545 	default:
546 		ret = -EINVAL;
547 		goto exit;
548 
549 	}
550 exit:
551 	up(&ieee->wx_sem);
552 	return ret;
553 
554 }
555 
556 /* this is stolen from hostap */
557 int ieee80211_wx_get_power(struct ieee80211_device *ieee,
558 				 struct iw_request_info *info,
559 				 union iwreq_data *wrqu, char *extra)
560 {
561 	int ret =0;
562 
563 	down(&ieee->wx_sem);
564 
565 	if(ieee->ps == IEEE80211_PS_DISABLED){
566 		wrqu->power.disabled = 1;
567 		goto exit;
568 	}
569 
570 	wrqu->power.disabled = 0;
571 
572 	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
573 		wrqu->power.flags = IW_POWER_TIMEOUT;
574 		wrqu->power.value = ieee->ps_timeout * 1000;
575 	} else {
576 //		ret = -EOPNOTSUPP;
577 //		goto exit;
578 		wrqu->power.flags = IW_POWER_PERIOD;
579 		wrqu->power.value = ieee->ps_period * 1000;
580 //ieee->current_network.dtim_period * ieee->current_network.beacon_interval * 1024;
581 	}
582 
583        if ((ieee->ps & (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST)) == (IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST))
584 		wrqu->power.flags |= IW_POWER_ALL_R;
585 	else if (ieee->ps & IEEE80211_PS_MBCAST)
586 		wrqu->power.flags |= IW_POWER_MULTICAST_R;
587 	else
588 		wrqu->power.flags |= IW_POWER_UNICAST_R;
589 
590 exit:
591 	up(&ieee->wx_sem);
592 	return ret;
593 
594 }
595 EXPORT_SYMBOL(ieee80211_wx_get_essid);
596 EXPORT_SYMBOL(ieee80211_wx_set_essid);
597 EXPORT_SYMBOL(ieee80211_wx_set_rate);
598 EXPORT_SYMBOL(ieee80211_wx_get_rate);
599 EXPORT_SYMBOL(ieee80211_wx_set_wap);
600 EXPORT_SYMBOL(ieee80211_wx_get_wap);
601 EXPORT_SYMBOL(ieee80211_wx_set_mode);
602 EXPORT_SYMBOL(ieee80211_wx_get_mode);
603 EXPORT_SYMBOL(ieee80211_wx_set_scan);
604 EXPORT_SYMBOL(ieee80211_wx_get_freq);
605 EXPORT_SYMBOL(ieee80211_wx_set_freq);
606 EXPORT_SYMBOL(ieee80211_wx_set_rawtx);
607 EXPORT_SYMBOL(ieee80211_wx_get_name);
608 EXPORT_SYMBOL(ieee80211_wx_set_power);
609 EXPORT_SYMBOL(ieee80211_wx_get_power);
610 EXPORT_SYMBOL(ieee80211_wlan_frequencies);
611 EXPORT_SYMBOL(ieee80211_wx_set_rts);
612 EXPORT_SYMBOL(ieee80211_wx_get_rts);
613