• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/rtl8187se/ieee80211/
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 "ieee80211.h"
18
19
20const long ieee80211_wlan_frequencies[] = {
21	2412, 2417, 2422, 2427,
22	2432, 2437, 2442, 2447,
23	2452, 2457, 2462, 2467,
24	2472, 2484
25};
26
27
28int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info *a,
29			     union iwreq_data *wrqu, char *b)
30{
31	int ret;
32	struct iw_freq *fwrq = & wrqu->freq;
33//	printk("in %s\n",__func__);
34	down(&ieee->wx_sem);
35
36	if(ieee->iw_mode == IW_MODE_INFRA){
37		ret = -EOPNOTSUPP;
38		goto out;
39	}
40
41	/* if setting by freq convert to channel */
42	if (fwrq->e == 1) {
43		if ((fwrq->m >= (int) 2.412e8 &&
44		     fwrq->m <= (int) 2.487e8)) {
45			int f = fwrq->m / 100000;
46			int c = 0;
47
48			while ((c < 14) && (f != ieee80211_wlan_frequencies[c]))
49				c++;
50
51			/* hack to fall through */
52			fwrq->e = 0;
53			fwrq->m = c + 1;
54		}
55	}
56
57	if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){
58		ret = -EOPNOTSUPP;
59		goto out;
60
61	}else { /* Set the channel */
62
63
64		ieee->current_network.channel = fwrq->m;
65		ieee->set_chan(ieee->dev, ieee->current_network.channel);
66
67		if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
68			if(ieee->state == IEEE80211_LINKED){
69
70			ieee80211_stop_send_beacons(ieee);
71			ieee80211_start_send_beacons(ieee);
72			}
73	}
74
75	ret = 0;
76out:
77	up(&ieee->wx_sem);
78	return ret;
79}
80
81
82int ieee80211_wx_get_freq(struct ieee80211_device *ieee,
83			     struct iw_request_info *a,
84			     union iwreq_data *wrqu, char *b)
85{
86	struct iw_freq *fwrq = & wrqu->freq;
87
88	if (ieee->current_network.channel == 0)
89		return -1;
90
91	fwrq->m = ieee->current_network.channel;
92	fwrq->e = 0;
93
94	return 0;
95}
96
97int ieee80211_wx_get_wap(struct ieee80211_device *ieee,
98			    struct iw_request_info *info,
99			    union iwreq_data *wrqu, char *extra)
100{
101	unsigned long flags;
102
103	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
104
105	if (ieee->iw_mode == IW_MODE_MONITOR)
106		return -1;
107
108	/* We want avoid to give to the user inconsistent infos*/
109	spin_lock_irqsave(&ieee->lock, flags);
110
111	if (ieee->state != IEEE80211_LINKED &&
112		ieee->state != IEEE80211_LINKED_SCANNING &&
113		ieee->wap_set == 0)
114
115		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
116	else
117		memcpy(wrqu->ap_addr.sa_data,
118		       ieee->current_network.bssid, ETH_ALEN);
119
120	spin_unlock_irqrestore(&ieee->lock, flags);
121
122	return 0;
123}
124
125
126int ieee80211_wx_set_wap(struct ieee80211_device *ieee,
127			 struct iw_request_info *info,
128			 union iwreq_data *awrq,
129			 char *extra)
130{
131
132	int ret = 0;
133	u8 zero[] = {0,0,0,0,0,0};
134	unsigned long flags;
135
136	short ifup = ieee->proto_started;//dev->flags & IFF_UP;
137	struct sockaddr *temp = (struct sockaddr *)awrq;
138
139	//printk("=======Set WAP:");
140	ieee->sync_scan_hurryup = 1;
141
142	down(&ieee->wx_sem);
143	/* use ifconfig hw ether */
144	if (ieee->iw_mode == IW_MODE_MASTER){
145		ret = -1;
146		goto out;
147	}
148
149	if (temp->sa_family != ARPHRD_ETHER){
150		ret = -EINVAL;
151		goto out;
152	}
153
154	if (ifup)
155		ieee80211_stop_protocol(ieee);
156
157	/* just to avoid to give inconsistent infos in the
158	 * get wx method. not really needed otherwise
159	 */
160	spin_lock_irqsave(&ieee->lock, flags);
161
162	memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN);
163	ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0;
164	//printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]);
165
166	spin_unlock_irqrestore(&ieee->lock, flags);
167
168	if (ifup)
169		ieee80211_start_protocol(ieee);
170
171out:
172	up(&ieee->wx_sem);
173	return ret;
174}
175
176 int ieee80211_wx_get_essid(struct ieee80211_device *ieee, struct iw_request_info *a,union iwreq_data *wrqu,char *b)
177{
178	int len,ret = 0;
179	unsigned long flags;
180
181	if (ieee->iw_mode == IW_MODE_MONITOR)
182		return -1;
183
184	/* We want avoid to give to the user inconsistent infos*/
185	spin_lock_irqsave(&ieee->lock, flags);
186
187	if (ieee->current_network.ssid[0] == '\0' ||
188		ieee->current_network.ssid_len == 0){
189		ret = -1;
190		goto out;
191	}
192
193	if (ieee->state != IEEE80211_LINKED &&
194		ieee->state != IEEE80211_LINKED_SCANNING &&
195		ieee->ssid_set == 0){
196		ret = -1;
197		goto out;
198	}
199	len = ieee->current_network.ssid_len;
200	wrqu->essid.length = len;
201	strncpy(b,ieee->current_network.ssid,len);
202	wrqu->essid.flags = 1;
203
204out:
205	spin_unlock_irqrestore(&ieee->lock, flags);
206
207	return ret;
208
209}
210
211int ieee80211_wx_set_rate(struct ieee80211_device *ieee,
212			     struct iw_request_info *info,
213			     union iwreq_data *wrqu, char *extra)
214{
215
216	u32 target_rate = wrqu->bitrate.value;
217
218	//added by lizhaoming for auto mode
219	if(target_rate == -1){
220	ieee->rate = 110;
221	} else {
222	ieee->rate = target_rate/100000;
223	}
224	return 0;
225}
226
227
228
229int ieee80211_wx_get_rate(struct ieee80211_device *ieee,
230			     struct iw_request_info *info,
231			     union iwreq_data *wrqu, char *extra)
232{
233
234	wrqu->bitrate.value = ieee->rate * 100000;
235
236	return 0;
237}
238
239int ieee80211_wx_set_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
240			     union iwreq_data *wrqu, char *b)
241{
242
243	ieee->sync_scan_hurryup = 1;
244
245	down(&ieee->wx_sem);
246
247	if (wrqu->mode == ieee->iw_mode)
248		goto out;
249
250	if (wrqu->mode == IW_MODE_MONITOR){
251
252		ieee->dev->type = ARPHRD_IEEE80211;
253	}else{
254		ieee->dev->type = ARPHRD_ETHER;
255	}
256
257	if (!ieee->proto_started){
258		ieee->iw_mode = wrqu->mode;
259	}else{
260		ieee80211_stop_protocol(ieee);
261		ieee->iw_mode = wrqu->mode;
262		ieee80211_start_protocol(ieee);
263	}
264
265out:
266	up(&ieee->wx_sem);
267	return 0;
268}
269
270
271void ieee80211_wx_sync_scan_wq(struct work_struct *work)
272{
273	struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq);
274	short chan;
275
276	chan = ieee->current_network.channel;
277
278	if (ieee->data_hard_stop)
279		ieee->data_hard_stop(ieee->dev);
280
281	ieee80211_stop_send_beacons(ieee);
282
283	ieee->state = IEEE80211_LINKED_SCANNING;
284	ieee->link_change(ieee->dev);
285
286	ieee80211_start_scan_syncro(ieee);
287
288	ieee->set_chan(ieee->dev, chan);
289
290	ieee->state = IEEE80211_LINKED;
291	ieee->link_change(ieee->dev);
292
293	if (ieee->data_hard_resume)
294		ieee->data_hard_resume(ieee->dev);
295
296	if(ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
297		ieee80211_start_send_beacons(ieee);
298
299	//YJ,add,080828, In prevent of lossing ping packet during scanning
300	//ieee80211_sta_ps_send_null_frame(ieee, false);
301	//YJ,add,080828,end
302
303	up(&ieee->wx_sem);
304
305}
306
307int ieee80211_wx_set_scan(struct ieee80211_device *ieee, struct iw_request_info *a,
308			     union iwreq_data *wrqu, char *b)
309{
310	int ret = 0;
311
312	down(&ieee->wx_sem);
313
314	if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)){
315		ret = -1;
316		goto out;
317	}
318	//YJ,add,080828
319	//In prevent of lossing ping packet during scanning
320	//ieee80211_sta_ps_send_null_frame(ieee, true);
321	//YJ,add,080828,end
322
323	if ( ieee->state == IEEE80211_LINKED){
324		queue_work(ieee->wq, &ieee->wx_sync_scan_wq);
325		/* intentionally forget to up sem */
326		return 0;
327	}
328
329out:
330	up(&ieee->wx_sem);
331	return ret;
332}
333
334int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
335			      struct iw_request_info *a,
336			      union iwreq_data *wrqu, char *extra)
337{
338
339	int ret=0,len;
340	short proto_started;
341	unsigned long flags;
342
343	ieee->sync_scan_hurryup = 1;
344
345	down(&ieee->wx_sem);
346
347	proto_started = ieee->proto_started;
348
349	if (wrqu->essid.length > IW_ESSID_MAX_SIZE){
350		ret= -E2BIG;
351		goto out;
352	}
353
354	if (ieee->iw_mode == IW_MODE_MONITOR){
355		ret= -1;
356		goto out;
357	}
358
359	if(proto_started)
360		ieee80211_stop_protocol(ieee);
361
362	/* this is just to be sure that the GET wx callback
363	 * has consisten infos. not needed otherwise
364	 */
365	spin_lock_irqsave(&ieee->lock, flags);
366
367	if (wrqu->essid.flags && wrqu->essid.length) {
368//YJ,modified,080819
369		len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE;
370		memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819
371		strncpy(ieee->current_network.ssid, extra, len);
372		ieee->current_network.ssid_len = len;
373		ieee->ssid_set = 1;
374//YJ,modified,080819,end
375
376		//YJ,add,080819,for hidden ap
377		if(len == 0){
378			memset(ieee->current_network.bssid, 0, ETH_ALEN);
379			ieee->current_network.capability = 0;
380		}
381		//YJ,add,080819,for hidden ap,end
382	}
383	else{
384		ieee->ssid_set = 0;
385		ieee->current_network.ssid[0] = '\0';
386		ieee->current_network.ssid_len = 0;
387	}
388	//printk("==========set essid %s!\n",ieee->current_network.ssid);
389	spin_unlock_irqrestore(&ieee->lock, flags);
390
391	if (proto_started)
392		ieee80211_start_protocol(ieee);
393out:
394	up(&ieee->wx_sem);
395	return ret;
396}
397
398 int ieee80211_wx_get_mode(struct ieee80211_device *ieee, struct iw_request_info *a,
399			     union iwreq_data *wrqu, char *b)
400{
401
402	wrqu->mode = ieee->iw_mode;
403	return 0;
404}
405
406 int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
407			       struct iw_request_info *info,
408			       union iwreq_data *wrqu, char *extra)
409{
410
411	int *parms = (int *)extra;
412	int enable = (parms[0] > 0);
413	short prev = ieee->raw_tx;
414
415	down(&ieee->wx_sem);
416
417	if(enable)
418		ieee->raw_tx = 1;
419	else
420		ieee->raw_tx = 0;
421
422	printk(KERN_INFO"raw TX is %s\n",
423	      ieee->raw_tx ? "enabled" : "disabled");
424
425	if(ieee->iw_mode == IW_MODE_MONITOR)
426	{
427		if(prev == 0 && ieee->raw_tx){
428			if (ieee->data_hard_resume)
429				ieee->data_hard_resume(ieee->dev);
430
431			netif_carrier_on(ieee->dev);
432		}
433
434		if(prev && ieee->raw_tx == 1)
435			netif_carrier_off(ieee->dev);
436	}
437
438	up(&ieee->wx_sem);
439
440	return 0;
441}
442
443int ieee80211_wx_get_name(struct ieee80211_device *ieee,
444			     struct iw_request_info *info,
445			     union iwreq_data *wrqu, char *extra)
446{
447	strlcpy(wrqu->name, "802.11", IFNAMSIZ);
448	if(ieee->modulation & IEEE80211_CCK_MODULATION){
449		strlcat(wrqu->name, "b", IFNAMSIZ);
450		if(ieee->modulation & IEEE80211_OFDM_MODULATION)
451			strlcat(wrqu->name, "/g", IFNAMSIZ);
452	}else if(ieee->modulation & IEEE80211_OFDM_MODULATION)
453		strlcat(wrqu->name, "g", IFNAMSIZ);
454
455	if((ieee->state == IEEE80211_LINKED) ||
456		(ieee->state == IEEE80211_LINKED_SCANNING))
457		strlcat(wrqu->name,"  link", IFNAMSIZ);
458	else if(ieee->state != IEEE80211_NOLINK)
459		strlcat(wrqu->name," .....", IFNAMSIZ);
460
461
462	return 0;
463}
464
465
466/* this is mostly stolen from hostap */
467int ieee80211_wx_set_power(struct ieee80211_device *ieee,
468				 struct iw_request_info *info,
469				 union iwreq_data *wrqu, char *extra)
470{
471	int ret = 0;
472
473	if(
474		(!ieee->sta_wake_up) ||
475		(!ieee->ps_request_tx_ack) ||
476		(!ieee->enter_sleep_state) ||
477		(!ieee->ps_is_queue_empty)){
478
479		printk("ERROR. PS mode tried to be use but driver missed a callback\n\n");
480
481		return -1;
482	}
483
484	down(&ieee->wx_sem);
485
486	if (wrqu->power.disabled){
487		ieee->ps = IEEE80211_PS_DISABLED;
488
489		goto exit;
490	}
491	switch (wrqu->power.flags & IW_POWER_MODE) {
492	case IW_POWER_UNICAST_R:
493		ieee->ps = IEEE80211_PS_UNICAST;
494
495		break;
496	case IW_POWER_ALL_R:
497		ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST;
498		break;
499
500	case IW_POWER_ON:
501		ieee->ps = IEEE80211_PS_DISABLED;
502		break;
503
504	default:
505		ret = -EINVAL;
506		goto exit;
507	}
508
509	if (wrqu->power.flags & IW_POWER_TIMEOUT) {
510
511		ieee->ps_timeout = wrqu->power.value / 1000;
512		printk("Timeout %d\n",ieee->ps_timeout);
513	}
514
515	if (wrqu->power.flags & IW_POWER_PERIOD) {
516
517		ret = -EOPNOTSUPP;
518		goto exit;
519		//wrq->value / 1024;
520
521	}
522exit:
523	up(&ieee->wx_sem);
524	return ret;
525
526}
527
528/* this is stolen from hostap */
529int ieee80211_wx_get_power(struct ieee80211_device *ieee,
530				 struct iw_request_info *info,
531				 union iwreq_data *wrqu, char *extra)
532{
533	int ret =0;
534
535	down(&ieee->wx_sem);
536
537	if(ieee->ps == IEEE80211_PS_DISABLED){
538		wrqu->power.disabled = 1;
539		goto exit;
540	}
541
542	wrqu->power.disabled = 0;
543
544//	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
545		wrqu->power.flags = IW_POWER_TIMEOUT;
546		wrqu->power.value = ieee->ps_timeout * 1000;
547//	} else {
548//		ret = -EOPNOTSUPP;
549//		goto exit;
550		//wrqu->power.flags = IW_POWER_PERIOD;
551		//wrqu->power.value = ieee->current_network.dtim_period *
552		//	ieee->current_network.beacon_interval * 1024;
553//	}
554
555
556	if (ieee->ps & IEEE80211_PS_MBCAST)
557		wrqu->power.flags |= IW_POWER_ALL_R;
558	else
559		wrqu->power.flags |= IW_POWER_UNICAST_R;
560
561exit:
562	up(&ieee->wx_sem);
563	return ret;
564
565}
566