blob: 2e2f6a0c8f2dde2e1621470bf617a18deb84719c [file] [log] [blame]
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001/* 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 * Few lines might be stolen from other part of the ieee80211
8 * stack. Copyright who own it's copyright
9 *
10 * WPA code stolen from the ipw2200 driver.
11 * Copyright who own it's copyright.
12 *
13 * released under the GPL
14 */
15
16
17#include "ieee80211.h"
18
19#include <linux/random.h>
20#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070022#include <linux/version.h>
23#include <asm/uaccess.h>
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070024#include "dot11d.h"
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070025
26u8 rsn_authen_cipher_suite[16][4] = {
27 {0x00,0x0F,0xAC,0x00}, //Use group key, //Reserved
28 {0x00,0x0F,0xAC,0x01}, //WEP-40 //RSNA default
29 {0x00,0x0F,0xAC,0x02}, //TKIP //NONE //{used just as default}
30 {0x00,0x0F,0xAC,0x03}, //WRAP-historical
31 {0x00,0x0F,0xAC,0x04}, //CCMP
32 {0x00,0x0F,0xAC,0x05}, //WEP-104
33};
34
35short ieee80211_is_54g(struct ieee80211_network net)
36{
37 return ((net.rates_ex_len > 0) || (net.rates_len > 4));
38}
39
40short ieee80211_is_shortslot(struct ieee80211_network net)
41{
42 return (net.capability & WLAN_CAPABILITY_SHORT_SLOT);
43}
44
45/* returns the total length needed for pleacing the RATE MFIE
46 * tag and the EXTENDED RATE MFIE tag if needed.
47 * It encludes two bytes per tag for the tag itself and its len
48 */
49unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
50{
51 unsigned int rate_len = 0;
52
53 if (ieee->modulation & IEEE80211_CCK_MODULATION)
54 rate_len = IEEE80211_CCK_RATE_LEN + 2;
55
56 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
57
58 rate_len += IEEE80211_OFDM_RATE_LEN + 2;
59
60 return rate_len;
61}
62
63/* pleace the MFIE rate, tag to the memory (double) poined.
64 * Then it updates the pointer so that
65 * it points after the new MFIE tag added.
66 */
67void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p)
68{
69 u8 *tag = *tag_p;
70
71 if (ieee->modulation & IEEE80211_CCK_MODULATION){
72 *tag++ = MFIE_TYPE_RATES;
73 *tag++ = 4;
74 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
75 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
76 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
77 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
78 }
79
80 /* We may add an option for custom rates that specific HW might support */
81 *tag_p = tag;
82}
83
84void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p)
85{
86 u8 *tag = *tag_p;
87
88 if (ieee->modulation & IEEE80211_OFDM_MODULATION){
89
90 *tag++ = MFIE_TYPE_RATES_EX;
91 *tag++ = 8;
92 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
93 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
94 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
95 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
96 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
97 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
98 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
99 *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
100
101 }
102
103 /* We may add an option for custom rates that specific HW might support */
104 *tag_p = tag;
105}
106
107
108void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) {
109 u8 *tag = *tag_p;
110
111 *tag++ = MFIE_TYPE_GENERIC; //0
112 *tag++ = 7;
113 *tag++ = 0x00;
114 *tag++ = 0x50;
115 *tag++ = 0xf2;
116 *tag++ = 0x02;//5
117 *tag++ = 0x00;
118 *tag++ = 0x01;
119#ifdef SUPPORT_USPD
120 if(ieee->current_network.wmm_info & 0x80) {
121 *tag++ = 0x0f|MAX_SP_Len;
122 } else {
123 *tag++ = MAX_SP_Len;
124 }
125#else
126 *tag++ = MAX_SP_Len;
127#endif
128 *tag_p = tag;
129}
130
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700131void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) {
132 u8 *tag = *tag_p;
133
134 *tag++ = MFIE_TYPE_GENERIC; //0
135 *tag++ = 7;
136 *tag++ = 0x00;
137 *tag++ = 0xe0;
138 *tag++ = 0x4c;
139 *tag++ = 0x01;//5
140 *tag++ = 0x02;
141 *tag++ = 0x11;
142 *tag++ = 0x00;
143
144 *tag_p = tag;
145 printk(KERN_ALERT "This is enable turbo mode IE process\n");
146}
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700147
148void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
149{
150 int nh;
151 nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM;
152
153/*
154 * if the queue is full but we have newer frames then
155 * just overwrites the oldest.
156 *
157 * if (nh == ieee->mgmt_queue_tail)
158 * return -1;
159 */
160 ieee->mgmt_queue_head = nh;
161 ieee->mgmt_queue_ring[nh] = skb;
162
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700163}
164
165struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee)
166{
167 struct sk_buff *ret;
168
169 if(ieee->mgmt_queue_tail == ieee->mgmt_queue_head)
170 return NULL;
171
172 ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail];
173
174 ieee->mgmt_queue_tail =
175 (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM;
176
177 return ret;
178}
179
180void init_mgmt_queue(struct ieee80211_device *ieee)
181{
182 ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0;
183}
184
Florian Schilhabele2e86492010-07-15 19:03:27 +0200185u8
186MgntQuery_TxRateExcludeCCKRates(struct ieee80211_device *ieee)
187{
188 u16 i;
189 u8 QueryRate = 0;
190 u8 BasicRate;
191
192
193 for( i = 0; i < ieee->current_network.rates_len; i++)
194 {
195 BasicRate = ieee->current_network.rates[i]&0x7F;
196 if(!ieee80211_is_cck_rate(BasicRate))
197 {
198 if(QueryRate == 0)
199 {
200 QueryRate = BasicRate;
201 }
202 else
203 {
204 if(BasicRate < QueryRate)
205 {
206 QueryRate = BasicRate;
207 }
208 }
209 }
210 }
211
212 if(QueryRate == 0)
213 {
214 QueryRate = 12;
215 printk("No BasicRate found!!\n");
216 }
217 return QueryRate;
218}
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700219u8 MgntQuery_MgntFrameTxRate(struct ieee80211_device *ieee)
220{
221 PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
222 u8 rate;
223
Florian Schilhabele2e86492010-07-15 19:03:27 +0200224 if(pHTInfo->IOTAction & HT_IOT_ACT_WA_IOT_Broadcom)
225 {
226 rate = MgntQuery_TxRateExcludeCCKRates(ieee);
227 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700228 else
229 rate = ieee->basic_rate & 0x7f;
230
231 if(rate == 0){
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700232 if(ieee->mode == IEEE_A||
233 ieee->mode== IEEE_N_5G||
234 (ieee->mode== IEEE_N_24G&&!pHTInfo->bCurSuppCCK))
235 rate = 0x0c;
236 else
237 rate = 0x02;
238 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700239 return rate;
240}
241
242
243void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl);
244
245inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee)
246{
247 unsigned long flags;
248 short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
249 struct ieee80211_hdr_3addr *header=
250 (struct ieee80211_hdr_3addr *) skb->data;
251
252 cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8);
253 spin_lock_irqsave(&ieee->lock, flags);
254
255 /* called with 2nd param 0, no mgmt lock required */
256 ieee80211_sta_wakeup(ieee,0);
257
258 tcb_desc->queue_index = MGNT_QUEUE;
259 tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee);
260 tcb_desc->RATRIndex = 7;
261 tcb_desc->bTxDisableRateFallBack = 1;
262 tcb_desc->bTxUseDriverAssingedRate = 1;
263
264 if(single){
265 if(ieee->queue_stop){
266 enqueue_mgmt(ieee,skb);
267 }else{
Frederic Leroye2117ce2010-02-18 00:25:26 +0100268 header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700269
270 if (ieee->seq_ctrl[0] == 0xFFF)
271 ieee->seq_ctrl[0] = 0;
272 else
273 ieee->seq_ctrl[0]++;
274
275 /* avoid watchdog triggers */
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700276 ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700277 }
278
279 spin_unlock_irqrestore(&ieee->lock, flags);
280 }else{
281 spin_unlock_irqrestore(&ieee->lock, flags);
282 spin_lock_irqsave(&ieee->mgmt_tx_lock, flags);
283
Frederic Leroye2117ce2010-02-18 00:25:26 +0100284 header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700285
286 if (ieee->seq_ctrl[0] == 0xFFF)
287 ieee->seq_ctrl[0] = 0;
288 else
289 ieee->seq_ctrl[0]++;
290
291 /* check wether the managed packet queued greater than 5 */
292 if(!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\
293 (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\
294 (ieee->queue_stop) ) {
295 /* insert the skb packet to the management queue */
296 /* as for the completion function, it does not need
297 * to check it any more.
298 * */
299 printk("%s():insert to waitqueue!\n",__FUNCTION__);
300 skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index], skb);
301 } else {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700302 ieee->softmac_hard_start_xmit(skb,ieee->dev);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700303 }
304 spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags);
305 }
306}
307
308inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee)
309{
310
311 short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE;
312 struct ieee80211_hdr_3addr *header =
313 (struct ieee80211_hdr_3addr *) skb->data;
Florian Schilhabelab81f742010-07-15 19:03:38 +0200314 u16 fc,type,stype;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700315 cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8);
316
Florian Schilhabelab81f742010-07-15 19:03:38 +0200317 fc = header->frame_control;
318 type = WLAN_FC_GET_TYPE(fc);
319 stype = WLAN_FC_GET_STYPE(fc);
320
321
322 if(stype != IEEE80211_STYPE_PSPOLL)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700323 tcb_desc->queue_index = MGNT_QUEUE;
Florian Schilhabelab81f742010-07-15 19:03:38 +0200324 else
325 tcb_desc->queue_index = HIGH_QUEUE;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700326 tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee);
327 tcb_desc->RATRIndex = 7;
328 tcb_desc->bTxDisableRateFallBack = 1;
329 tcb_desc->bTxUseDriverAssingedRate = 1;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700330 if(single){
Florian Schilhabelab81f742010-07-15 19:03:38 +0200331 if(!(type == IEEE80211_FTYPE_CTL)) {
Frederic Leroye2117ce2010-02-18 00:25:26 +0100332 header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700333
334 if (ieee->seq_ctrl[0] == 0xFFF)
335 ieee->seq_ctrl[0] = 0;
336 else
337 ieee->seq_ctrl[0]++;
338
Florian Schilhabelab81f742010-07-15 19:03:38 +0200339 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700340 /* avoid watchdog triggers */
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700341 ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
342
343 }else{
Florian Schilhabelab81f742010-07-15 19:03:38 +0200344 if(!(type == IEEE80211_FTYPE_CTL)) {
Frederic Leroye2117ce2010-02-18 00:25:26 +0100345 header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700346
347 if (ieee->seq_ctrl[0] == 0xFFF)
348 ieee->seq_ctrl[0] = 0;
349 else
350 ieee->seq_ctrl[0]++;
351
Florian Schilhabelab81f742010-07-15 19:03:38 +0200352 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700353 ieee->softmac_hard_start_xmit(skb,ieee->dev);
354
355 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700356}
357
358inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee)
359{
360 unsigned int len,rate_len;
361 u8 *tag;
362 struct sk_buff *skb;
363 struct ieee80211_probe_request *req;
364
365 len = ieee->current_network.ssid_len;
366
367 rate_len = ieee80211_MFIE_rate_len(ieee);
368
369 skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) +
370 2 + len + rate_len + ieee->tx_headroom);
371 if (!skb)
372 return NULL;
373
374 skb_reserve(skb, ieee->tx_headroom);
375
376 req = (struct ieee80211_probe_request *) skb_put(skb,sizeof(struct ieee80211_probe_request));
Frederic Leroye2117ce2010-02-18 00:25:26 +0100377 req->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700378 req->header.duration_id = 0; //FIXME: is this OK ?
379
380 memset(req->header.addr1, 0xff, ETH_ALEN);
381 memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
382 memset(req->header.addr3, 0xff, ETH_ALEN);
383
384 tag = (u8 *) skb_put(skb,len+2+rate_len);
385
386 *tag++ = MFIE_TYPE_SSID;
387 *tag++ = len;
388 memcpy(tag, ieee->current_network.ssid, len);
389 tag += len;
390
391 ieee80211_MFIE_Brate(ieee,&tag);
392 ieee80211_MFIE_Grate(ieee,&tag);
393 return skb;
394}
395
396struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee);
397void ieee80211_send_beacon(struct ieee80211_device *ieee)
398{
399 struct sk_buff *skb;
400 if(!ieee->ieee_up)
401 return;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700402 skb = ieee80211_get_beacon_(ieee);
403
404 if (skb){
405 softmac_mgmt_xmit(skb, ieee);
406 ieee->softmac_stats.tx_beacons++;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700407 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700408
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700409 if(ieee->beacon_txing && ieee->ieee_up){
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700410 mod_timer(&ieee->beacon_timer,jiffies+(MSECS(ieee->current_network.beacon_interval-5)));
411 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700412}
413
414
415void ieee80211_send_beacon_cb(unsigned long _ieee)
416{
417 struct ieee80211_device *ieee =
418 (struct ieee80211_device *) _ieee;
419 unsigned long flags;
420
421 spin_lock_irqsave(&ieee->beacon_lock, flags);
422 ieee80211_send_beacon(ieee);
423 spin_unlock_irqrestore(&ieee->beacon_lock, flags);
424}
425
426
427void ieee80211_send_probe(struct ieee80211_device *ieee)
428{
429 struct sk_buff *skb;
430
431 skb = ieee80211_probe_req(ieee);
432 if (skb){
433 softmac_mgmt_xmit(skb, ieee);
434 ieee->softmac_stats.tx_probe_rq++;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700435 }
436}
437
438void ieee80211_send_probe_requests(struct ieee80211_device *ieee)
439{
440 if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)){
441 ieee80211_send_probe(ieee);
442 ieee80211_send_probe(ieee);
443 }
444}
445
446/* this performs syncro scan blocking the caller until all channels
447 * in the allowed channel map has been checked.
448 */
449void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
450{
451 short ch = 0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700452 u8 channel_map[MAX_CHANNEL_NUMBER+1];
453 memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700454 ieee->be_scan_inprogress = true;
455 down(&ieee->scan_sem);
456
457 while(1)
458 {
459
460 do{
461 ch++;
462 if (ch > MAX_CHANNEL_NUMBER)
463 goto out; /* scan completed */
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700464 }while(!channel_map[ch]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700465
466 /* this fuction can be called in two situations
467 * 1- We have switched to ad-hoc mode and we are
468 * performing a complete syncro scan before conclude
469 * there are no interesting cell and to create a
470 * new one. In this case the link state is
471 * IEEE80211_NOLINK until we found an interesting cell.
472 * If so the ieee8021_new_net, called by the RX path
473 * will set the state to IEEE80211_LINKED, so we stop
474 * scanning
475 * 2- We are linked and the root uses run iwlist scan.
476 * So we switch to IEEE80211_LINKED_SCANNING to remember
477 * that we are still logically linked (not interested in
478 * new network events, despite for updating the net list,
479 * but we are temporarly 'unlinked' as the driver shall
480 * not filter RX frames and the channel is changing.
481 * So the only situation in witch are interested is to check
482 * if the state become LINKED because of the #1 situation
483 */
484
485 if (ieee->state == IEEE80211_LINKED)
486 goto out;
487 ieee->set_chan(ieee->dev, ch);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700488 if(channel_map[ch] == 1)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700489 ieee80211_send_probe_requests(ieee);
490
491 /* this prevent excessive time wait when we
492 * need to wait for a syncro scan to end..
493 */
494 if(ieee->state < IEEE80211_LINKED)
495 ;
496 else
497 if (ieee->sync_scan_hurryup)
498 goto out;
499
500
501 msleep_interruptible_rsl(IEEE80211_SOFTMAC_SCAN_TIME);
502
503 }
504out:
505 if(ieee->state < IEEE80211_LINKED){
506 ieee->actscanning = false;
507 up(&ieee->scan_sem);
508 ieee->be_scan_inprogress = false;
509 }
510 else{
511 ieee->sync_scan_hurryup = 0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700512 if(IS_DOT11D_ENABLE(ieee))
513 DOT11D_ScanComplete(ieee);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700514 up(&ieee->scan_sem);
515 ieee->be_scan_inprogress = false;
516}
517}
518
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700519void ieee80211_softmac_scan_wq(struct work_struct *work)
520{
521 struct delayed_work *dwork = container_of(work, struct delayed_work, work);
522 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700523 u8 last_channel = ieee->current_network.channel; //recored init channel inorder not change current channel when comming out the scan unexpectedly. WB.
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700524 u8 channel_map[MAX_CHANNEL_NUMBER+1];
525 memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700526 if(!ieee->ieee_up)
527 return;
528 down(&ieee->scan_sem);
529 do{
530 ieee->current_network.channel =
531 (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER;
532 if (ieee->scan_watch_dog++ > MAX_CHANNEL_NUMBER)
533 {
534 //if current channel is not in channel map, set to default channel.
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700535 if (!channel_map[ieee->current_network.channel]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700536 ieee->current_network.channel = 6;
537 goto out; /* no good chans */
538 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700539 }while(!channel_map[ieee->current_network.channel]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700540 if (ieee->scanning == 0 )
541 goto out;
542 ieee->set_chan(ieee->dev, ieee->current_network.channel);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700543 if(channel_map[ieee->current_network.channel] == 1)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700544 ieee80211_send_probe_requests(ieee);
545
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700546 queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700547
548 up(&ieee->scan_sem);
549 return;
550out:
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700551 if(IS_DOT11D_ENABLE(ieee))
552 DOT11D_ScanComplete(ieee);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700553 ieee->current_network.channel = last_channel;
554 ieee->actscanning = false;
555 ieee->scan_watch_dog = 0;
556 ieee->scanning = 0;
557 up(&ieee->scan_sem);
558}
559
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700560void ieee80211_beacons_start(struct ieee80211_device *ieee)
561{
562 unsigned long flags;
563 spin_lock_irqsave(&ieee->beacon_lock,flags);
564
565 ieee->beacon_txing = 1;
566 ieee80211_send_beacon(ieee);
567
568 spin_unlock_irqrestore(&ieee->beacon_lock,flags);
569}
570
571void ieee80211_beacons_stop(struct ieee80211_device *ieee)
572{
573 unsigned long flags;
574
575 spin_lock_irqsave(&ieee->beacon_lock,flags);
576
577 ieee->beacon_txing = 0;
578 del_timer_sync(&ieee->beacon_timer);
579
580 spin_unlock_irqrestore(&ieee->beacon_lock,flags);
581
582}
583
584
585void ieee80211_stop_send_beacons(struct ieee80211_device *ieee)
586{
587 if(ieee->stop_send_beacons)
588 ieee->stop_send_beacons(ieee->dev);
589 if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
590 ieee80211_beacons_stop(ieee);
591}
592
593
594void ieee80211_start_send_beacons(struct ieee80211_device *ieee)
595{
596 if(ieee->start_send_beacons)
597 ieee->start_send_beacons(ieee->dev);
598 if(ieee->softmac_features & IEEE_SOFTMAC_BEACONS)
599 ieee80211_beacons_start(ieee);
600}
601
602
603void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee)
604{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700605
606 down(&ieee->scan_sem);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700607 ieee->scan_watch_dog = 0;
608 if (ieee->scanning == 1){
609 ieee->scanning = 0;
610
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700611 cancel_delayed_work(&ieee->softmac_scan_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700612 }
613
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700614 up(&ieee->scan_sem);
615}
616
617void ieee80211_stop_scan(struct ieee80211_device *ieee)
618{
619 if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
620 ieee80211_softmac_stop_scan(ieee);
621 else
622 ieee->stop_scan(ieee->dev);
623}
624
625/* called with ieee->lock held */
George Kadianakis55c7d5f2009-12-17 01:19:13 +0200626void ieee80211_rtl_start_scan(struct ieee80211_device *ieee)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700627{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700628 if(IS_DOT11D_ENABLE(ieee) )
629 {
630 if(IS_COUNTRY_IE_VALID(ieee))
631 {
632 RESET_CIE_WATCHDOG(ieee);
633 }
634 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700635 if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){
636 if (ieee->scanning == 0){
637 ieee->scanning = 1;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700638 queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, 0);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700639 }
640 }else
641 ieee->start_scan(ieee->dev);
642
643}
644
645/* called with wx_sem held */
646void ieee80211_start_scan_syncro(struct ieee80211_device *ieee)
647{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700648 if(IS_DOT11D_ENABLE(ieee) )
649 {
650 if(IS_COUNTRY_IE_VALID(ieee))
651 {
652 RESET_CIE_WATCHDOG(ieee);
653 }
654 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700655 ieee->sync_scan_hurryup = 0;
656 if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
657 ieee80211_softmac_scan_syncro(ieee);
658 else
659 ieee->scan_syncro(ieee->dev);
660
661}
662
663inline struct sk_buff *ieee80211_authentication_req(struct ieee80211_network *beacon,
664 struct ieee80211_device *ieee, int challengelen)
665{
666 struct sk_buff *skb;
667 struct ieee80211_authentication *auth;
668 int len = sizeof(struct ieee80211_authentication) + challengelen + ieee->tx_headroom;
669
670
671 skb = dev_alloc_skb(len);
672 if (!skb) return NULL;
673
674 skb_reserve(skb, ieee->tx_headroom);
675 auth = (struct ieee80211_authentication *)
676 skb_put(skb, sizeof(struct ieee80211_authentication));
677
Frederic Leroye2117ce2010-02-18 00:25:26 +0100678 auth->header.frame_control = IEEE80211_STYPE_AUTH;
679 if (challengelen) auth->header.frame_control |= IEEE80211_FCTL_WEP;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700680
681 auth->header.duration_id = 0x013a; //FIXME
682
683 memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN);
684 memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
685 memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN);
686
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700687 if(ieee->auth_mode == 0)
688 auth->algorithm = WLAN_AUTH_OPEN;
689 else if(ieee->auth_mode == 1)
690 auth->algorithm = WLAN_AUTH_SHARED_KEY;
691 else if(ieee->auth_mode == 2)
692 auth->algorithm = WLAN_AUTH_OPEN;//0x80;
693 printk("=================>%s():auth->algorithm is %d\n",__FUNCTION__,auth->algorithm);
694 auth->transaction = cpu_to_le16(ieee->associate_seq);
695 ieee->associate_seq++;
696
697 auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS);
698
699 return skb;
700
701}
702
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200703void constructWMMIE(u8* wmmie, u8* wmm_len,u8 oui_subtype)
704{
705 u8 szQoSOUI[] ={221, 0, 0x00, 0x50, 0xf2, 0x02, 0, 1};
706
707 if (oui_subtype == OUI_SUBTYPE_QOS_CAPABI)
708 {
709 szQoSOUI[0] = 46;
710 szQoSOUI[1] = *wmm_len;
711 memcpy(wmmie,szQoSOUI,3);
712 *wmm_len = 3;
713 }
714 else
715 {
716 szQoSOUI[1] = *wmm_len + 6;
717 szQoSOUI[6] = oui_subtype;
718 memcpy(wmmie, szQoSOUI, 8);
719 *(wmmie+8) = 0;
720 *wmm_len = 9;
721 }
722}
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700723
724static struct sk_buff* ieee80211_probe_resp(struct ieee80211_device *ieee, u8 *dest)
725{
726 u8 *tag;
727 int beacon_size;
728 struct ieee80211_probe_response *beacon_buf;
729 struct sk_buff *skb = NULL;
730 int encrypt;
731 int atim_len,erp_len;
732 struct ieee80211_crypt_data* crypt;
733
734 char *ssid = ieee->current_network.ssid;
735 int ssid_len = ieee->current_network.ssid_len;
736 int rate_len = ieee->current_network.rates_len+2;
737 int rate_ex_len = ieee->current_network.rates_ex_len;
738 int wpa_ie_len = ieee->wpa_ie_len;
739 u8 erpinfo_content = 0;
740
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200741 u8* tmp_ht_cap_buf=NULL;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700742 u8 tmp_ht_cap_len=0;
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200743 u8* tmp_ht_info_buf=NULL;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700744 u8 tmp_ht_info_len=0;
745 PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo;
746 u8* tmp_generic_ie_buf=NULL;
747 u8 tmp_generic_ie_len=0;
748
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200749
750 u8 wmmie[9] = {0};
751 u8 wmm_len = 0;
752
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700753 if(rate_ex_len > 0) rate_ex_len+=2;
754
755 if(ieee->current_network.capability & WLAN_CAPABILITY_IBSS)
756 atim_len = 4;
757 else
758 atim_len = 0;
759
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200760#if 0
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700761 if(ieee80211_is_54g(ieee->current_network))
762 erp_len = 3;
763 else
764 erp_len = 0;
765#else
766 if((ieee->current_network.mode == IEEE_G)
767 ||( ieee->current_network.mode == IEEE_N_24G && ieee->pHTInfo->bCurSuppCCK)) {
768 erp_len = 3;
769 erpinfo_content = 0;
770 if(ieee->current_network.buseprotection)
771 erpinfo_content |= ERP_UseProtection;
772 }
773 else
774 erp_len = 0;
775#endif
776
777
778 crypt = ieee->crypt[ieee->tx_keyidx];
779
780
781 encrypt = ieee->host_encrypt && crypt && crypt->ops &&
782 ((0 == strcmp(crypt->ops->name, "WEP") || wpa_ie_len));
783 //HT ralated element
784#if 1
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200785 if(ieee->pHTInfo->bCurrentHTSupport){
786 tmp_ht_cap_buf =(u8*) &(ieee->pHTInfo->SelfHTCap);
787 tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap);
788 tmp_ht_info_buf =(u8*) &(ieee->pHTInfo->SelfHTInfo);
789 tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo);
790
791 HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, &tmp_ht_cap_len,encrypt);
792
793 HTConstructInfoElement(ieee,tmp_ht_info_buf,&tmp_ht_info_len, encrypt);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700794
795
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200796 if(pHTInfo->bRegRT2RTAggregation)
797 {
798 tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer;
799 tmp_generic_ie_len = sizeof(ieee->pHTInfo->szRT2RTAggBuffer);
800 HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, &tmp_generic_ie_len);
801 }
802 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700803#endif
Florian Schilhabeld4dfd802010-07-15 19:04:00 +0200804
805 if(ieee->qos_support){
806
807 if(ieee->iw_mode == IW_MODE_ADHOC)
808 {
809 wmm_len = 1;
810 constructWMMIE(wmmie,&wmm_len,OUI_SUBTYPE_WMM_INFO);
811 }
812 }
813
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700814 beacon_size = sizeof(struct ieee80211_probe_response)+2+
815 ssid_len
816 +3 //channel
817 +rate_len
818 +rate_ex_len
819 +atim_len
820 +erp_len
821 +wpa_ie_len
822 // +tmp_ht_cap_len
823 // +tmp_ht_info_len
824 // +tmp_generic_ie_len
825// +wmm_len+2
826 +ieee->tx_headroom;
827 skb = dev_alloc_skb(beacon_size);
828 if (!skb)
829 return NULL;
830 skb_reserve(skb, ieee->tx_headroom);
831 beacon_buf = (struct ieee80211_probe_response*) skb_put(skb, (beacon_size - ieee->tx_headroom));
832 memcpy (beacon_buf->header.addr1, dest,ETH_ALEN);
833 memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
834 memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN);
835
836 beacon_buf->header.duration_id = 0; //FIXME
837 beacon_buf->beacon_interval =
838 cpu_to_le16(ieee->current_network.beacon_interval);
839 beacon_buf->capability =
840 cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS);
841 beacon_buf->capability |=
842 cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE); //add short preamble here
843
844 if(ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT))
845 cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT));
846
847 crypt = ieee->crypt[ieee->tx_keyidx];
Bartlomiej Zolnierkiewicz35c1b462009-07-03 16:08:32 +0200848
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700849 if (encrypt)
850 beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
851
852
Frederic Leroye2117ce2010-02-18 00:25:26 +0100853 beacon_buf->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700854 beacon_buf->info_element[0].id = MFIE_TYPE_SSID;
855 beacon_buf->info_element[0].len = ssid_len;
856
857 tag = (u8*) beacon_buf->info_element[0].data;
858
859 memcpy(tag, ssid, ssid_len);
860
861 tag += ssid_len;
862
863 *(tag++) = MFIE_TYPE_RATES;
864 *(tag++) = rate_len-2;
865 memcpy(tag,ieee->current_network.rates,rate_len-2);
866 tag+=rate_len-2;
867
868 *(tag++) = MFIE_TYPE_DS_SET;
869 *(tag++) = 1;
870 *(tag++) = ieee->current_network.channel;
871
872 if(atim_len){
873 u16 val16;
874 *(tag++) = MFIE_TYPE_IBSS_SET;
875 *(tag++) = 2;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700876 val16 = cpu_to_le16(ieee->current_network.atim_window);
877 memcpy((u8 *)tag, (u8 *)&val16, 2);
878 tag+=2;
879 }
880
881 if(erp_len){
882 *(tag++) = MFIE_TYPE_ERP;
883 *(tag++) = 1;
884 *(tag++) = erpinfo_content;
885 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700886
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700887 if(rate_ex_len){
888 *(tag++) = MFIE_TYPE_RATES_EX;
889 *(tag++) = rate_ex_len-2;
890 memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2);
891 tag+=rate_ex_len-2;
892 }
893
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700894 if (wpa_ie_len)
895 {
896 if (ieee->iw_mode == IW_MODE_ADHOC)
897 {//as Windows will set pairwise key same as the group key which is not allowed in Linux, so set this for IOT issue. WB 2008.07.07
898 memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4);
899 }
900 memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
901 tag += wpa_ie_len;
902 }
903
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700904 return skb;
905}
906
907
908struct sk_buff* ieee80211_assoc_resp(struct ieee80211_device *ieee, u8 *dest)
909{
910 struct sk_buff *skb;
911 u8* tag;
912
913 struct ieee80211_crypt_data* crypt;
914 struct ieee80211_assoc_response_frame *assoc;
915 short encrypt;
916
917 unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
918 int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len + ieee->tx_headroom;
919
920 skb = dev_alloc_skb(len);
921
922 if (!skb)
923 return NULL;
924
925 skb_reserve(skb, ieee->tx_headroom);
926
927 assoc = (struct ieee80211_assoc_response_frame *)
928 skb_put(skb,sizeof(struct ieee80211_assoc_response_frame));
929
Frederic Leroye2117ce2010-02-18 00:25:26 +0100930 assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700931 memcpy(assoc->header.addr1, dest,ETH_ALEN);
932 memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
933 memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
934 assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ?
935 WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS);
936
937
938 if(ieee->short_slot)
939 assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
940
941 if (ieee->host_encrypt)
942 crypt = ieee->crypt[ieee->tx_keyidx];
943 else crypt = NULL;
944
945 encrypt = ( crypt && crypt->ops);
946
947 if (encrypt)
948 assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
949
950 assoc->status = 0;
951 assoc->aid = cpu_to_le16(ieee->assoc_id);
952 if (ieee->assoc_id == 0x2007) ieee->assoc_id=0;
953 else ieee->assoc_id++;
954
955 tag = (u8*) skb_put(skb, rate_len);
956
957 ieee80211_MFIE_Brate(ieee, &tag);
958 ieee80211_MFIE_Grate(ieee, &tag);
959
960 return skb;
961}
962
963struct sk_buff* ieee80211_auth_resp(struct ieee80211_device *ieee,int status, u8 *dest)
964{
965 struct sk_buff *skb;
966 struct ieee80211_authentication *auth;
967 int len = ieee->tx_headroom + sizeof(struct ieee80211_authentication)+1;
968
969 skb = dev_alloc_skb(len);
970
971 if (!skb)
972 return NULL;
973
974 skb->len = sizeof(struct ieee80211_authentication);
975
976 auth = (struct ieee80211_authentication *)skb->data;
977
978 auth->status = cpu_to_le16(status);
979 auth->transaction = cpu_to_le16(2);
980 auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN);
981
982 memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN);
983 memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
984 memcpy(auth->header.addr1, dest, ETH_ALEN);
Frederic Leroye2117ce2010-02-18 00:25:26 +0100985 auth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700986 return skb;
987
988
989}
990
991struct sk_buff* ieee80211_null_func(struct ieee80211_device *ieee,short pwr)
992{
993 struct sk_buff *skb;
994 struct ieee80211_hdr_3addr* hdr;
995
996 skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr));
997
998 if (!skb)
999 return NULL;
1000
1001 hdr = (struct ieee80211_hdr_3addr*)skb_put(skb,sizeof(struct ieee80211_hdr_3addr));
1002
1003 memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN);
1004 memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN);
1005 memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN);
1006
Frederic Leroye2117ce2010-02-18 00:25:26 +01001007 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001008 IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS |
1009 (pwr ? IEEE80211_FCTL_PM:0));
1010
1011 return skb;
1012
1013
1014}
1015
1016
1017void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8* dest)
1018{
1019 struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest);
1020
1021 if (buf)
1022 softmac_mgmt_xmit(buf, ieee);
1023}
1024
1025
1026void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8* dest)
1027{
1028 struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest);
1029
1030 if (buf)
1031 softmac_mgmt_xmit(buf, ieee);
1032}
1033
1034
1035void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest)
1036{
1037
1038
1039 struct sk_buff *buf = ieee80211_probe_resp(ieee, dest);
1040 if (buf)
1041 softmac_mgmt_xmit(buf, ieee);
1042}
1043
1044
1045inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beacon,struct ieee80211_device *ieee)
1046{
1047 struct sk_buff *skb;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001048
1049 struct ieee80211_assoc_request_frame *hdr;
1050 u8 *tag;//,*rsn_ie;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001051 u8* ht_cap_buf = NULL;
1052 u8 ht_cap_len=0;
1053 u8* realtek_ie_buf=NULL;
1054 u8 realtek_ie_len=0;
1055 int wpa_ie_len= ieee->wpa_ie_len;
1056 unsigned int ckip_ie_len=0;
1057 unsigned int ccxrm_ie_len=0;
1058 unsigned int cxvernum_ie_len=0;
1059 struct ieee80211_crypt_data* crypt;
1060 int encrypt;
1061
1062 unsigned int rate_len = ieee80211_MFIE_rate_len(ieee);
1063 unsigned int wmm_info_len = beacon->qos_data.supported?9:0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001064 unsigned int turbo_info_len = beacon->Turbo_Enable?9:0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001065
1066 int len = 0;
1067
1068 crypt = ieee->crypt[ieee->tx_keyidx];
1069 encrypt = ieee->host_encrypt && crypt && crypt->ops && ((0 == strcmp(crypt->ops->name,"WEP") || wpa_ie_len));
1070
1071 //Include High Throuput capability && Realtek proprietary
1072 if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT)
1073 {
1074 ht_cap_buf = (u8*)&(ieee->pHTInfo->SelfHTCap);
1075 ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap);
1076 HTConstructCapabilityElement(ieee, ht_cap_buf, &ht_cap_len, encrypt);
1077 if(ieee->pHTInfo->bCurrentRT2RTAggregation)
1078 {
1079 realtek_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer;
1080 realtek_ie_len = sizeof( ieee->pHTInfo->szRT2RTAggBuffer);
1081 HTConstructRT2RTAggElement(ieee, realtek_ie_buf, &realtek_ie_len);
1082
1083 }
1084 }
1085 if(ieee->qos_support){
1086 wmm_info_len = beacon->qos_data.supported?9:0;
1087 }
1088
1089
1090 if(beacon->bCkipSupported)
1091 {
1092 ckip_ie_len = 30+2;
1093 }
1094 if(beacon->bCcxRmEnable)
1095 {
1096 ccxrm_ie_len = 6+2;
1097 }
1098 if( beacon->BssCcxVerNumber >= 2 )
1099 {
1100 cxvernum_ie_len = 5+2;
1101 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001102 len = sizeof(struct ieee80211_assoc_request_frame)+ 2
1103 + beacon->ssid_len//essid tagged val
1104 + rate_len//rates tagged val
1105 + wpa_ie_len
1106 + wmm_info_len
1107 + turbo_info_len
1108 + ht_cap_len
1109 + realtek_ie_len
1110 + ckip_ie_len
1111 + ccxrm_ie_len
1112 + cxvernum_ie_len
1113 + ieee->tx_headroom;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001114
1115 skb = dev_alloc_skb(len);
1116
1117 if (!skb)
1118 return NULL;
1119
1120 skb_reserve(skb, ieee->tx_headroom);
1121
1122 hdr = (struct ieee80211_assoc_request_frame *)
1123 skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)+2);
1124
1125
Frederic Leroye2117ce2010-02-18 00:25:26 +01001126 hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001127 hdr->header.duration_id= 37; //FIXME
1128 memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN);
1129 memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
1130 memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN);
1131
1132 memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN);//for HW security, John
1133
1134 hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS);
1135 if (beacon->capability & WLAN_CAPABILITY_PRIVACY )
1136 hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
1137
1138 if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
1139 hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); //add short_preamble here
1140
1141 if(ieee->short_slot)
1142 hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT);
1143 if (wmm_info_len) //QOS
1144 hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_QOS);
1145
1146 hdr->listen_interval = 0xa; //FIXME
1147
1148 hdr->info_element[0].id = MFIE_TYPE_SSID;
1149
1150 hdr->info_element[0].len = beacon->ssid_len;
1151 tag = skb_put(skb, beacon->ssid_len);
1152 memcpy(tag, beacon->ssid, beacon->ssid_len);
1153
1154 tag = skb_put(skb, rate_len);
1155
1156 ieee80211_MFIE_Brate(ieee, &tag);
1157 ieee80211_MFIE_Grate(ieee, &tag);
1158 // For CCX 1 S13, CKIP. Added by Annie, 2006-08-14.
1159 if( beacon->bCkipSupported )
1160 {
1161 static u8 AironetIeOui[] = {0x00, 0x01, 0x66}; // "4500-client"
1162 u8 CcxAironetBuf[30];
1163 OCTET_STRING osCcxAironetIE;
1164
1165 memset(CcxAironetBuf, 0,30);
1166 osCcxAironetIE.Octet = CcxAironetBuf;
1167 osCcxAironetIE.Length = sizeof(CcxAironetBuf);
1168 //
1169 // Ref. CCX test plan v3.61, 3.2.3.1 step 13.
1170 // We want to make the device type as "4500-client". 060926, by CCW.
1171 //
1172 memcpy(osCcxAironetIE.Octet, AironetIeOui, sizeof(AironetIeOui));
1173
1174 // CCX1 spec V1.13, A01.1 CKIP Negotiation (page23):
1175 // "The CKIP negotiation is started with the associate request from the client to the access point,
1176 // containing an Aironet element with both the MIC and KP bits set."
1177 osCcxAironetIE.Octet[IE_CISCO_FLAG_POSITION] |= (SUPPORT_CKIP_PK|SUPPORT_CKIP_MIC) ;
1178 tag = skb_put(skb, ckip_ie_len);
1179 *tag++ = MFIE_TYPE_AIRONET;
1180 *tag++ = osCcxAironetIE.Length;
1181 memcpy(tag,osCcxAironetIE.Octet,osCcxAironetIE.Length);
1182 tag += osCcxAironetIE.Length;
1183 }
1184
1185 if(beacon->bCcxRmEnable)
1186 {
1187 static u8 CcxRmCapBuf[] = {0x00, 0x40, 0x96, 0x01, 0x01, 0x00};
1188 OCTET_STRING osCcxRmCap;
1189
1190 osCcxRmCap.Octet = CcxRmCapBuf;
1191 osCcxRmCap.Length = sizeof(CcxRmCapBuf);
1192 tag = skb_put(skb,ccxrm_ie_len);
1193 *tag++ = MFIE_TYPE_GENERIC;
1194 *tag++ = osCcxRmCap.Length;
1195 memcpy(tag,osCcxRmCap.Octet,osCcxRmCap.Length);
1196 tag += osCcxRmCap.Length;
1197 }
1198
1199 if( beacon->BssCcxVerNumber >= 2 )
1200 {
1201 u8 CcxVerNumBuf[] = {0x00, 0x40, 0x96, 0x03, 0x00};
1202 OCTET_STRING osCcxVerNum;
1203 CcxVerNumBuf[4] = beacon->BssCcxVerNumber;
1204 osCcxVerNum.Octet = CcxVerNumBuf;
1205 osCcxVerNum.Length = sizeof(CcxVerNumBuf);
1206 tag = skb_put(skb,cxvernum_ie_len);
1207 *tag++ = MFIE_TYPE_GENERIC;
1208 *tag++ = osCcxVerNum.Length;
1209 memcpy(tag,osCcxVerNum.Octet,osCcxVerNum.Length);
1210 tag += osCcxVerNum.Length;
1211 }
1212 //HT cap element
1213 if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){
1214 if(ieee->pHTInfo->ePeerHTSpecVer != HT_SPEC_VER_EWC)
1215 {
1216 tag = skb_put(skb, ht_cap_len);
1217 *tag++ = MFIE_TYPE_HT_CAP;
1218 *tag++ = ht_cap_len - 2;
1219 memcpy(tag, ht_cap_buf,ht_cap_len -2);
1220 tag += ht_cap_len -2;
1221 }
1222 }
1223
1224
1225 //choose what wpa_supplicant gives to associate.
1226 tag = skb_put(skb, wpa_ie_len);
1227 if (wpa_ie_len){
1228 memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
1229 }
1230
1231 tag = skb_put(skb,wmm_info_len);
1232 if(wmm_info_len) {
1233 ieee80211_WMM_Info(ieee, &tag);
1234 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001235 tag = skb_put(skb,turbo_info_len);
1236 if(turbo_info_len) {
1237 ieee80211_TURBO_Info(ieee, &tag);
1238 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001239
1240 if(ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){
1241 if(ieee->pHTInfo->ePeerHTSpecVer == HT_SPEC_VER_EWC)
1242 {
1243 tag = skb_put(skb, ht_cap_len);
1244 *tag++ = MFIE_TYPE_GENERIC;
1245 *tag++ = ht_cap_len - 2;
1246 memcpy(tag, ht_cap_buf,ht_cap_len - 2);
1247 tag += ht_cap_len -2;
1248 }
1249
1250 if(ieee->pHTInfo->bCurrentRT2RTAggregation){
1251 tag = skb_put(skb, realtek_ie_len);
1252 *tag++ = MFIE_TYPE_GENERIC;
1253 *tag++ = realtek_ie_len - 2;
1254 memcpy(tag, realtek_ie_buf,realtek_ie_len -2 );
1255 }
1256 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001257 return skb;
1258}
1259
1260void ieee80211_associate_abort(struct ieee80211_device *ieee)
1261{
1262
1263 unsigned long flags;
1264 spin_lock_irqsave(&ieee->lock, flags);
1265
1266 ieee->associate_seq++;
1267
1268 /* don't scan, and avoid to have the RX path possibily
1269 * try again to associate. Even do not react to AUTH or
1270 * ASSOC response. Just wait for the retry wq to be scheduled.
1271 * Here we will check if there are good nets to associate
1272 * with, so we retry or just get back to NO_LINK and scanning
1273 */
1274 if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING){
1275 IEEE80211_DEBUG_MGMT("Authentication failed\n");
1276 ieee->softmac_stats.no_auth_rs++;
1277 }else{
1278 IEEE80211_DEBUG_MGMT("Association failed\n");
1279 ieee->softmac_stats.no_ass_rs++;
1280 }
1281
1282 ieee->state = IEEE80211_ASSOCIATING_RETRY;
1283
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001284 queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, \
1285 IEEE80211_SOFTMAC_ASSOC_RETRY_TIME);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001286
1287 spin_unlock_irqrestore(&ieee->lock, flags);
1288}
1289
1290void ieee80211_associate_abort_cb(unsigned long dev)
1291{
1292 ieee80211_associate_abort((struct ieee80211_device *) dev);
1293}
1294
1295
1296void ieee80211_associate_step1(struct ieee80211_device *ieee)
1297{
1298 struct ieee80211_network *beacon = &ieee->current_network;
1299 struct sk_buff *skb;
1300
1301 IEEE80211_DEBUG_MGMT("Stopping scan\n");
1302
1303 ieee->softmac_stats.tx_auth_rq++;
1304 skb=ieee80211_authentication_req(beacon, ieee, 0);
1305
1306 if (!skb)
1307 ieee80211_associate_abort(ieee);
1308 else{
1309 ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING ;
1310 IEEE80211_DEBUG_MGMT("Sending authentication request\n");
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001311 softmac_mgmt_xmit(skb, ieee);
1312 //BUGON when you try to add_timer twice, using mod_timer may be better, john0709
1313 if(!timer_pending(&ieee->associate_timer)){
1314 ieee->associate_timer.expires = jiffies + (HZ / 2);
1315 add_timer(&ieee->associate_timer);
1316 }
1317 //dev_kfree_skb_any(skb);//edit by thomas
1318 }
1319}
1320
George Kadianakis55c7d5f2009-12-17 01:19:13 +02001321void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001322{
1323 u8 *c;
1324 struct sk_buff *skb;
1325 struct ieee80211_network *beacon = &ieee->current_network;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001326
1327 ieee->associate_seq++;
1328 ieee->softmac_stats.tx_auth_rq++;
1329
1330 skb = ieee80211_authentication_req(beacon, ieee, chlen+2);
1331 if (!skb)
1332 ieee80211_associate_abort(ieee);
1333 else{
1334 c = skb_put(skb, chlen+2);
1335 *(c++) = MFIE_TYPE_CHALLENGE;
1336 *(c++) = chlen;
1337 memcpy(c, challenge, chlen);
1338
1339 IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n");
1340
1341 ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr ));
1342
1343 softmac_mgmt_xmit(skb, ieee);
1344 mod_timer(&ieee->associate_timer, jiffies + (HZ/2));
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001345 }
1346 kfree(challenge);
1347}
1348
1349void ieee80211_associate_step2(struct ieee80211_device *ieee)
1350{
1351 struct sk_buff* skb;
1352 struct ieee80211_network *beacon = &ieee->current_network;
1353
1354 del_timer_sync(&ieee->associate_timer);
1355
1356 IEEE80211_DEBUG_MGMT("Sending association request\n");
1357
1358 ieee->softmac_stats.tx_ass_rq++;
1359 skb=ieee80211_association_req(beacon, ieee);
1360 if (!skb)
1361 ieee80211_associate_abort(ieee);
1362 else{
1363 softmac_mgmt_xmit(skb, ieee);
1364 mod_timer(&ieee->associate_timer, jiffies + (HZ/2));
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001365 }
1366}
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02001367
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001368void ieee80211_associate_complete_wq(struct work_struct *work)
1369{
1370 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq);
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02001371
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001372 printk(KERN_INFO "Associated successfully\n");
1373 ieee->is_roaming = false;
1374 if(ieee80211_is_54g(ieee->current_network) &&
1375 (ieee->modulation & IEEE80211_OFDM_MODULATION)){
1376
1377 ieee->rate = 108;
1378 printk(KERN_INFO"Using G rates:%d\n", ieee->rate);
1379 }else{
1380 ieee->rate = 22;
1381 printk(KERN_INFO"Using B rates:%d\n", ieee->rate);
1382 }
1383 if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT)
1384 {
1385 printk("Successfully associated, ht enabled\n");
1386 HTOnAssocRsp(ieee);
1387 }
1388 else
1389 {
1390 printk("Successfully associated, ht not enabled(%d, %d)\n", ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bEnableHT);
1391 memset(ieee->dot11HTOperationalRateSet, 0, 16);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001392 }
1393 ieee->LinkDetectInfo.SlotNum = 2 * (1 + ieee->current_network.beacon_interval/500);
1394 // To prevent the immediately calling watch_dog after association.
1395 if(ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 )
1396 {
1397 ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
1398 ieee->LinkDetectInfo.NumRecvDataInPeriod= 1;
1399 }
1400 ieee->link_change(ieee->dev);
1401 if(ieee->is_silent_reset == 0){
1402 printk("============>normal associate\n");
1403 notify_wx_assoc_event(ieee);
1404 }
1405 else if(ieee->is_silent_reset == 1)
1406 {
1407 printk("==================>silent reset associate\n");
1408 ieee->is_silent_reset = 0;
1409 }
1410
1411 if (ieee->data_hard_resume)
1412 ieee->data_hard_resume(ieee->dev);
1413 netif_carrier_on(ieee->dev);
1414}
1415
1416void ieee80211_associate_complete(struct ieee80211_device *ieee)
1417{
1418// int i;
1419// struct net_device* dev = ieee->dev;
1420 del_timer_sync(&ieee->associate_timer);
1421
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001422 ieee->state = IEEE80211_LINKED;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001423 queue_work(ieee->wq, &ieee->associate_complete_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001424}
1425
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001426void ieee80211_associate_procedure_wq(struct work_struct *work)
1427{
1428 struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq);
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02001429
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001430 ieee->sync_scan_hurryup = 1;
1431 down(&ieee->wx_sem);
1432
1433 if (ieee->data_hard_stop)
1434 ieee->data_hard_stop(ieee->dev);
1435
1436 ieee80211_stop_scan(ieee);
1437 printk("===>%s(), chan:%d\n", __FUNCTION__, ieee->current_network.channel);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001438 HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
1439
Florian Schilhabel26cc7152010-07-15 19:02:59 +02001440 if(ieee->eRFPowerState == eRfOff)
1441 {
1442 printk("=============>%s():Rf state is eRfOff, schedule ipsleave wq again,return\n",__FUNCTION__);
1443 up(&ieee->wx_sem);
1444 return;
1445 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001446 ieee->associate_seq = 1;
1447 ieee80211_associate_step1(ieee);
1448
1449 up(&ieee->wx_sem);
1450}
1451
1452inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee80211_network *net)
1453{
1454 u8 tmp_ssid[IW_ESSID_MAX_SIZE+1];
1455 int tmp_ssid_len = 0;
1456
1457 short apset,ssidset,ssidbroad,apmatch,ssidmatch;
1458
1459 /* we are interested in new new only if we are not associated
1460 * and we are not associating / authenticating
1461 */
1462 if (ieee->state != IEEE80211_NOLINK)
1463 return;
1464
1465 if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS))
1466 return;
1467
1468 if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS))
1469 return;
1470
Florian Schilhabeld5471392010-07-14 14:42:43 +02001471 if ((ieee->iw_mode == IW_MODE_ADHOC) && (net->channel > ieee->ibss_maxjoin_chal))
1472 return;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001473
1474 if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC){
1475 /* if the user specified the AP MAC, we need also the essid
1476 * This could be obtained by beacons or, if the network does not
1477 * broadcast it, it can be put manually.
1478 */
Florian Schilhabel124a27e2010-07-15 19:03:49 +02001479 apset = ieee->wap_set;
1480 ssidset = ieee->ssid_set;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001481 ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0');
1482 apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0);
1483 ssidmatch = (ieee->current_network.ssid_len == net->ssid_len)&&\
1484 (!strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len));
1485
1486
1487 if ( /* if the user set the AP check if match.
1488 * if the network does not broadcast essid we check the user supplyed ANY essid
1489 * if the network does broadcast and the user does not set essid it is OK
1490 * if the network does broadcast and the user did set essid chech if essid match
1491 */
1492 ( apset && apmatch &&
1493 ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
1494 /* if the ap is not set, check that the user set the bssid
1495 * and the network does bradcast and that those two bssid matches
1496 */
1497 (!apset && ssidset && ssidbroad && ssidmatch)
1498 ){
1499 /* if the essid is hidden replace it with the
1500 * essid provided by the user.
1501 */
1502 if (!ssidbroad){
1503 strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE);
1504 tmp_ssid_len = ieee->current_network.ssid_len;
1505 }
1506 memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network));
1507
1508 if (!ssidbroad){
1509 strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE);
1510 ieee->current_network.ssid_len = tmp_ssid_len;
1511 }
1512 printk(KERN_INFO"Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d, mode:%x\n",ieee->current_network.ssid,ieee->current_network.channel, ieee->current_network.qos_data.supported, ieee->pHTInfo->bEnableHT, ieee->current_network.bssht.bdSupportHT, ieee->current_network.mode);
1513
1514 //ieee->pHTInfo->IOTAction = 0;
1515 HTResetIOTSetting(ieee->pHTInfo);
1516 if (ieee->iw_mode == IW_MODE_INFRA){
1517 /* Join the network for the first time */
1518 ieee->AsocRetryCount = 0;
1519 //for HT by amy 080514
1520 if((ieee->current_network.qos_data.supported == 1) &&
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001521 ieee->current_network.bssht.bdSupportHT)
1522/*WB, 2008.09.09:bCurrentHTSupport and bEnableHT two flags are going to put together to check whether we are in HT now, so needn't to check bEnableHT flags here. That's is to say we will set to HT support whenever joined AP has the ability to support HT. And whether we are in HT or not, please check bCurrentHTSupport&&bEnableHT now please.*/
1523 {
1524 // ieee->pHTInfo->bCurrentHTSupport = true;
1525 HTResetSelfAndSavePeerSetting(ieee, &(ieee->current_network));
1526 }
1527 else
1528 {
1529 ieee->pHTInfo->bCurrentHTSupport = false;
1530 }
1531
1532 ieee->state = IEEE80211_ASSOCIATING;
1533 if(ieee->LedControlHandler != NULL)
1534 ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001535 queue_work(ieee->wq, &ieee->associate_procedure_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001536 }else{
1537 if(ieee80211_is_54g(ieee->current_network) &&
1538 (ieee->modulation & IEEE80211_OFDM_MODULATION)){
1539 ieee->rate = 108;
1540 ieee->SetWirelessMode(ieee->dev, IEEE_G);
1541 printk(KERN_INFO"Using G rates\n");
1542 }else{
1543 ieee->rate = 22;
1544 ieee->SetWirelessMode(ieee->dev, IEEE_B);
1545 printk(KERN_INFO"Using B rates\n");
1546 }
1547 memset(ieee->dot11HTOperationalRateSet, 0, 16);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001548 ieee->state = IEEE80211_LINKED;
1549 }
1550
1551 }
1552 }
1553
1554}
1555
1556void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee)
1557{
1558 unsigned long flags;
1559 struct ieee80211_network *target;
1560
1561 spin_lock_irqsave(&ieee->lock, flags);
1562
1563 list_for_each_entry(target, &ieee->network_list, list) {
1564
1565 /* if the state become different that NOLINK means
1566 * we had found what we are searching for
1567 */
1568
1569 if (ieee->state != IEEE80211_NOLINK)
1570 break;
1571
1572 if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies))
1573 ieee80211_softmac_new_net(ieee, target);
1574 }
1575
1576 spin_unlock_irqrestore(&ieee->lock, flags);
1577
1578}
1579
1580
1581static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen)
1582{
1583 struct ieee80211_authentication *a;
1584 u8 *t;
1585 if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){
1586 IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len);
1587 return 0xcafe;
1588 }
1589 *challenge = NULL;
1590 a = (struct ieee80211_authentication*) skb->data;
1591 if(skb->len > (sizeof(struct ieee80211_authentication) +3)){
1592 t = skb->data + sizeof(struct ieee80211_authentication);
1593
1594 if(*(t++) == MFIE_TYPE_CHALLENGE){
1595 *chlen = *(t++);
Julia Lawall32414872010-05-11 20:26:57 +02001596 *challenge = kmalloc(*chlen, GFP_ATOMIC);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001597 memcpy(*challenge, t, *chlen);
1598 }
1599 }
1600
1601 return cpu_to_le16(a->status);
1602
1603}
1604
1605
1606int auth_rq_parse(struct sk_buff *skb,u8* dest)
1607{
1608 struct ieee80211_authentication *a;
1609
1610 if (skb->len < (sizeof(struct ieee80211_authentication)-sizeof(struct ieee80211_info_element))){
1611 IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len);
1612 return -1;
1613 }
1614 a = (struct ieee80211_authentication*) skb->data;
1615
1616 memcpy(dest,a->header.addr2, ETH_ALEN);
1617
1618 if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN)
1619 return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
1620
1621 return WLAN_STATUS_SUCCESS;
1622}
1623
1624static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src)
1625{
1626 u8 *tag;
1627 u8 *skbend;
1628 u8 *ssid=NULL;
1629 u8 ssidlen = 0;
1630
1631 struct ieee80211_hdr_3addr *header =
1632 (struct ieee80211_hdr_3addr *) skb->data;
1633
1634 if (skb->len < sizeof (struct ieee80211_hdr_3addr ))
1635 return -1; /* corrupted */
1636
Florian Schilhabelc9b4d3e2010-07-15 19:03:15 +02001637 if((memcmp(header->addr3,ieee->current_network.bssid,ETH_ALEN) != 0)&&
1638 (memcmp(header->addr3,"\xff\xff\xff\xff\xff\xff",ETH_ALEN) != 0)) {
1639 return -1;
1640 }
1641
1642 if(memcmp(header->addr3,ieee->current_network.bssid,ETH_ALEN) == 0) {
1643 }
1644
1645 if(memcmp(header->addr3,"\xff\xff\xff\xff\xff\xff",ETH_ALEN) == 0) {
1646 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001647 memcpy(src,header->addr2, ETH_ALEN);
1648
1649 skbend = (u8*)skb->data + skb->len;
1650
1651 tag = skb->data + sizeof (struct ieee80211_hdr_3addr );
1652
1653 while (tag+1 < skbend){
1654 if (*tag == 0){
1655 ssid = tag+2;
1656 ssidlen = *(tag+1);
1657 break;
1658 }
1659 tag++; /* point to the len field */
1660 tag = tag + *(tag); /* point to the last data byte of the tag */
1661 tag++; /* point to the next tag */
1662 }
1663
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001664 if (ssidlen == 0) return 1;
1665
1666 if (!ssid) return 1; /* ssid not found in tagged param */
1667 return (!strncmp(ssid, ieee->current_network.ssid, ssidlen));
1668
1669}
1670
1671int assoc_rq_parse(struct sk_buff *skb,u8* dest)
1672{
1673 struct ieee80211_assoc_request_frame *a;
1674
1675 if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) -
1676 sizeof(struct ieee80211_info_element))) {
1677
1678 IEEE80211_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len);
1679 return -1;
1680 }
1681
1682 a = (struct ieee80211_assoc_request_frame*) skb->data;
1683
1684 memcpy(dest,a->header.addr2,ETH_ALEN);
1685
1686 return 0;
1687}
1688
1689static inline u16 assoc_parse(struct ieee80211_device *ieee, struct sk_buff *skb, int *aid)
1690{
1691 struct ieee80211_assoc_response_frame *response_head;
1692 u16 status_code;
1693
1694 if (skb->len < sizeof(struct ieee80211_assoc_response_frame)){
1695 IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len);
1696 return 0xcafe;
1697 }
1698
1699 response_head = (struct ieee80211_assoc_response_frame*) skb->data;
1700 *aid = le16_to_cpu(response_head->aid) & 0x3fff;
1701
1702 status_code = le16_to_cpu(response_head->status);
1703 if((status_code==WLAN_STATUS_ASSOC_DENIED_RATES || \
1704 status_code==WLAN_STATUS_CAPS_UNSUPPORTED)&&
1705 ((ieee->mode == IEEE_G) &&
1706 (ieee->current_network.mode == IEEE_N_24G) &&
1707 (ieee->AsocRetryCount++ < (RT_ASOC_RETRY_LIMIT-1)))) {
1708 ieee->pHTInfo->IOTAction |= HT_IOT_ACT_PURE_N_MODE;
1709 }else {
1710 ieee->AsocRetryCount = 0;
1711 }
1712
1713 return le16_to_cpu(response_head->status);
1714}
1715
1716static inline void
1717ieee80211_rx_probe_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
1718{
1719 u8 dest[ETH_ALEN];
1720
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001721 ieee->softmac_stats.rx_probe_rq++;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001722 if (probe_rq_parse(ieee, skb, dest)){
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001723 ieee->softmac_stats.tx_probe_rs++;
1724 ieee80211_resp_to_probe(ieee, dest);
1725 }
1726}
1727
1728static inline void
1729ieee80211_rx_auth_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
1730{
1731 u8 dest[ETH_ALEN];
1732 int status;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001733 ieee->softmac_stats.rx_auth_rq++;
1734
Joe Perches810ba6a2010-03-24 22:17:03 -07001735 status = auth_rq_parse(skb, dest);
1736 if (status != -1) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001737 ieee80211_resp_to_auth(ieee, status, dest);
1738 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001739
1740}
1741
1742static inline void
1743ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
1744{
1745
1746 u8 dest[ETH_ALEN];
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001747
1748 ieee->softmac_stats.rx_ass_rq++;
1749 if (assoc_rq_parse(skb,dest) != -1){
1750 ieee80211_resp_to_assoc_rq(ieee, dest);
1751 }
1752
Joe Perches0ee9f672009-12-06 11:34:52 -08001753 printk(KERN_INFO"New client associated: %pM\n", dest);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001754 //FIXME
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001755}
1756
1757
1758
1759void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr)
1760{
1761
1762 struct sk_buff *buf = ieee80211_null_func(ieee, pwr);
1763
1764 if (buf)
1765 softmac_ps_mgmt_xmit(buf, ieee);
1766
1767}
1768
1769
1770short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, u32 *time_l)
1771{
1772 int timeout = ieee->ps_timeout;
1773 u8 dtim;
1774 /*if(ieee->ps == IEEE80211_PS_DISABLED ||
1775 ieee->iw_mode != IW_MODE_INFRA ||
1776 ieee->state != IEEE80211_LINKED)
1777
1778 return 0;
1779 */
1780 dtim = ieee->current_network.dtim_data;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001781 if(!(dtim & IEEE80211_DTIM_VALID))
1782 return 0;
1783 timeout = ieee->current_network.beacon_interval; //should we use ps_timeout value or beacon_interval
1784 //printk("VALID\n");
1785 ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID;
1786
1787 if(dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST)& ieee->ps))
1788 return 2;
1789
1790 if(!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout)))
1791 return 0;
1792
1793 if(!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout)))
1794 return 0;
1795
1796 if((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) &&
1797 (ieee->mgmt_queue_tail != ieee->mgmt_queue_head))
1798 return 0;
1799
1800 if(time_l){
1801 *time_l = ieee->current_network.last_dtim_sta_time[0]
1802 + (ieee->current_network.beacon_interval);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001803 }
1804
1805 if(time_h){
1806 *time_h = ieee->current_network.last_dtim_sta_time[1];
1807 if(time_l && *time_l < ieee->current_network.last_dtim_sta_time[0])
1808 *time_h += 1;
1809 }
1810
1811 return 1;
1812
1813
1814}
1815
1816inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
1817{
1818
1819 u32 th,tl;
1820 short sleep;
1821
1822 unsigned long flags,flags2;
1823
1824 spin_lock_irqsave(&ieee->lock, flags);
1825
1826 if((ieee->ps == IEEE80211_PS_DISABLED ||
1827 ieee->iw_mode != IW_MODE_INFRA ||
1828 ieee->state != IEEE80211_LINKED)){
1829
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001830 spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
1831
1832 ieee80211_sta_wakeup(ieee, 1);
1833
1834 spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
1835 }
1836
1837 sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl);
1838 /* 2 wake, 1 sleep, 0 do nothing */
1839 if(sleep == 0)
1840 goto out;
1841
1842 if(sleep == 1){
1843
1844 if(ieee->sta_sleep == 1)
1845 ieee->enter_sleep_state(ieee->dev,th,tl);
1846
1847 else if(ieee->sta_sleep == 0){
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001848 spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
1849
1850 if(ieee->ps_is_queue_empty(ieee->dev)){
1851
1852
1853 ieee->sta_sleep = 2;
1854
1855 ieee->ack_tx_to_ieee = 1;
1856
1857 ieee80211_sta_ps_send_null_frame(ieee,1);
1858
1859 ieee->ps_th = th;
1860 ieee->ps_tl = tl;
1861 }
1862 spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
1863
1864 }
1865
1866
1867 }else if(sleep == 2){
1868//#warning CHECK_LOCK_HERE
1869 spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
1870
1871 ieee80211_sta_wakeup(ieee,1);
1872
1873 spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
1874 }
1875
1876out:
1877 spin_unlock_irqrestore(&ieee->lock, flags);
1878
1879}
1880
1881void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl)
1882{
1883 if(ieee->sta_sleep == 0){
1884 if(nl){
1885 printk("Warning: driver is probably failing to report TX ps error\n");
1886 ieee->ack_tx_to_ieee = 1;
1887 ieee80211_sta_ps_send_null_frame(ieee, 0);
1888 }
1889 return;
1890
1891 }
1892
1893 if(ieee->sta_sleep == 1)
1894 ieee->sta_wake_up(ieee->dev);
1895
1896 ieee->sta_sleep = 0;
1897
1898 if(nl){
1899 ieee->ack_tx_to_ieee = 1;
1900 ieee80211_sta_ps_send_null_frame(ieee, 0);
1901 }
1902}
1903
1904void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success)
1905{
1906 unsigned long flags,flags2;
1907
1908 spin_lock_irqsave(&ieee->lock, flags);
1909
1910 if(ieee->sta_sleep == 2){
1911 /* Null frame with PS bit set */
1912 if(success){
1913 ieee->sta_sleep = 1;
1914 ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl);
1915 }
1916 /* if the card report not success we can't be sure the AP
1917 * has not RXed so we can't assume the AP believe us awake
1918 */
1919 }
1920 /* 21112005 - tx again null without PS bit if lost */
1921 else {
1922
1923 if((ieee->sta_sleep == 0) && !success){
1924 spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2);
1925 ieee80211_sta_ps_send_null_frame(ieee, 0);
1926 spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2);
1927 }
1928 }
1929 spin_unlock_irqrestore(&ieee->lock, flags);
1930}
1931void ieee80211_process_action(struct ieee80211_device* ieee, struct sk_buff* skb)
1932{
Bartlomiej Zolnierkiewiczb4fcc8a2009-06-13 18:37:33 +02001933 struct rtl_ieee80211_hdr *header =
1934 (struct rtl_ieee80211_hdr *)skb->data;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001935 u8* act = ieee80211_get_payload(header);
1936 u8 tmp = 0;
1937// IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
1938 if (act == NULL)
1939 {
1940 IEEE80211_DEBUG(IEEE80211_DL_ERR, "error to get payload of action frame\n");
1941 return;
1942 }
1943 tmp = *act;
1944 act ++;
1945 switch (tmp)
1946 {
1947 case ACT_CAT_BA:
1948 if (*act == ACT_ADDBAREQ)
1949 ieee80211_rx_ADDBAReq(ieee, skb);
1950 else if (*act == ACT_ADDBARSP)
1951 ieee80211_rx_ADDBARsp(ieee, skb);
1952 else if (*act == ACT_DELBA)
1953 ieee80211_rx_DELBA(ieee, skb);
1954 break;
1955 default:
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001956 break;
1957 }
1958 return;
1959
1960}
1961inline int
1962ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
1963 struct ieee80211_rx_stats *rx_stats, u16 type,
1964 u16 stype)
1965{
1966 struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data;
1967 u16 errcode;
1968 u8* challenge;
1969 int chlen=0;
1970 int aid;
1971 struct ieee80211_assoc_response_frame *assoc_resp;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001972 bool bSupportNmode = true, bHalfSupportNmode = false; //default support N mode, disable halfNmode
1973
1974 if(!ieee->proto_started)
1975 return 0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001976
Frederic Leroye2117ce2010-02-18 00:25:26 +01001977 switch (WLAN_FC_GET_STYPE(header->frame_control)) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001978
1979 case IEEE80211_STYPE_ASSOC_RESP:
1980 case IEEE80211_STYPE_REASSOC_RESP:
1981
1982 IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n",
Frederic Leroye2117ce2010-02-18 00:25:26 +01001983 WLAN_FC_GET_STYPE(header->frame_control));
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001984 if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
1985 ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED &&
1986 ieee->iw_mode == IW_MODE_INFRA){
1987 struct ieee80211_network network_resp;
1988 struct ieee80211_network *network = &network_resp;
1989
1990 if (0 == (errcode=assoc_parse(ieee,skb, &aid))){
1991 ieee->state=IEEE80211_LINKED;
1992 ieee->assoc_id = aid;
1993 ieee->softmac_stats.rx_ass_ok++;
1994 /* station support qos */
1995 /* Let the register setting defaultly with Legacy station */
1996 if(ieee->qos_support) {
1997 assoc_resp = (struct ieee80211_assoc_response_frame*)skb->data;
1998 memset(network, 0, sizeof(*network));
1999 if (ieee80211_parse_info_param(ieee,assoc_resp->info_element,\
2000 rx_stats->len - sizeof(*assoc_resp),\
2001 network,rx_stats)){
2002 return 1;
2003 }
2004 else
2005 { //filling the PeerHTCap. //maybe not neccesary as we can get its info from current_network.
2006 memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen);
2007 memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen);
2008 }
2009 if (ieee->handle_assoc_response != NULL)
2010 ieee->handle_assoc_response(ieee->dev, (struct ieee80211_assoc_response_frame*)header, network);
2011 }
2012 ieee80211_associate_complete(ieee);
2013 } else {
2014 /* aid could not been allocated */
2015 ieee->softmac_stats.rx_ass_err++;
2016 printk(
2017 "Association response status code 0x%x\n",
2018 errcode);
2019 IEEE80211_DEBUG_MGMT(
2020 "Association response status code 0x%x\n",
2021 errcode);
2022 if(ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002023 queue_work(ieee->wq, &ieee->associate_procedure_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002024 } else {
2025 ieee80211_associate_abort(ieee);
2026 }
2027 }
2028 }
2029 break;
2030
2031 case IEEE80211_STYPE_ASSOC_REQ:
2032 case IEEE80211_STYPE_REASSOC_REQ:
2033
2034 if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
2035 ieee->iw_mode == IW_MODE_MASTER)
2036
2037 ieee80211_rx_assoc_rq(ieee, skb);
2038 break;
2039
2040 case IEEE80211_STYPE_AUTH:
2041
2042 if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){
2043 if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING &&
2044 ieee->iw_mode == IW_MODE_INFRA){
2045
2046 IEEE80211_DEBUG_MGMT("Received authentication response");
2047
2048 if (0 == (errcode=auth_parse(skb, &challenge, &chlen))){
2049 if(ieee->open_wep || !challenge){
2050 ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED;
2051 ieee->softmac_stats.rx_auth_rs_ok++;
2052 if(!(ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE))
2053 {
2054 if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
2055 {
2056 // WEP or TKIP encryption
2057 if(IsHTHalfNmodeAPs(ieee))
2058 {
2059 bSupportNmode = true;
2060 bHalfSupportNmode = true;
2061 }
2062 else
2063 {
2064 bSupportNmode = false;
2065 bHalfSupportNmode = false;
2066 }
2067 printk("==========>to link with AP using SEC(%d, %d)", bSupportNmode, bHalfSupportNmode);
2068 }
2069 }
2070 /* Dummy wirless mode setting to avoid encryption issue */
2071 if(bSupportNmode) {
2072 //N mode setting
2073 ieee->SetWirelessMode(ieee->dev, \
2074 ieee->current_network.mode);
2075 }else{
2076 //b/g mode setting
2077 /*TODO*/
2078 ieee->SetWirelessMode(ieee->dev, IEEE_G);
2079 }
2080
2081 if (ieee->current_network.mode == IEEE_N_24G && bHalfSupportNmode == true)
2082 {
2083 printk("===============>entern half N mode\n");
2084 ieee->bHalfWirelessN24GMode = true;
2085 }
2086 else
2087 ieee->bHalfWirelessN24GMode = false;
2088
2089 ieee80211_associate_step2(ieee);
2090 }else{
George Kadianakis55c7d5f2009-12-17 01:19:13 +02002091 ieee80211_rtl_auth_challenge(ieee, challenge, chlen);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002092 }
2093 }else{
2094 ieee->softmac_stats.rx_auth_rs_err++;
2095 IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
2096
2097 printk("Authentication respose status code 0x%x",errcode);
2098 ieee80211_associate_abort(ieee);
2099 }
2100
2101 }else if (ieee->iw_mode == IW_MODE_MASTER){
2102 ieee80211_rx_auth_rq(ieee, skb);
2103 }
2104 }
2105 break;
2106
2107 case IEEE80211_STYPE_PROBE_REQ:
2108
2109 if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) &&
2110 ((ieee->iw_mode == IW_MODE_ADHOC ||
2111 ieee->iw_mode == IW_MODE_MASTER) &&
2112 ieee->state == IEEE80211_LINKED)){
2113 ieee80211_rx_probe_rq(ieee, skb);
2114 }
2115 break;
2116
2117 case IEEE80211_STYPE_DISASSOC:
2118 case IEEE80211_STYPE_DEAUTH:
2119 /* FIXME for now repeat all the association procedure
2120 * both for disassociation and deauthentication
2121 */
2122 if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) &&
2123 ieee->state == IEEE80211_LINKED &&
2124 ieee->iw_mode == IW_MODE_INFRA){
Frederic Leroye2117ce2010-02-18 00:25:26 +01002125 printk("==========>received disassoc/deauth(%x) frame, reason code:%x\n",WLAN_FC_GET_STYPE(header->frame_control), ((struct ieee80211_disassoc*)skb->data)->reason);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002126 ieee->state = IEEE80211_ASSOCIATING;
2127 ieee->softmac_stats.reassoc++;
2128 ieee->is_roaming = true;
2129 ieee80211_disassociate(ieee);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002130 RemovePeerTS(ieee, header->addr2);
2131 if(ieee->LedControlHandler != NULL)
2132 ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK); //added by amy for LED 090318
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002133 queue_work(ieee->wq, &ieee->associate_procedure_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002134 }
2135 break;
2136 case IEEE80211_STYPE_MANAGE_ACT:
2137 ieee80211_process_action(ieee,skb);
2138 break;
2139 default:
2140 return -1;
2141 break;
2142 }
2143
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002144 return 0;
2145}
2146
2147/* following are for a simplier TX queue management.
2148 * Instead of using netif_[stop/wake]_queue the driver
2149 * will uses these two function (plus a reset one), that
2150 * will internally uses the kernel netif_* and takes
2151 * care of the ieee802.11 fragmentation.
2152 * So the driver receives a fragment per time and might
2153 * call the stop function when it want without take care
André Goddard Rosabbc9a992009-11-14 13:09:06 -02002154 * to have enough room to TX an entire packet.
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002155 * This might be useful if each fragment need it's own
2156 * descriptor, thus just keep a total free memory > than
André Goddard Rosabbc9a992009-11-14 13:09:06 -02002157 * the max fragmentation threshold is not enough.. If the
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002158 * ieee802.11 stack passed a TXB struct then you needed
2159 * to keep N free descriptors where
2160 * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD
2161 * In this way you need just one and the 802.11 stack
2162 * will take care of buffering fragments and pass them to
2163 * to the driver later, when it wakes the queue.
2164 */
2165void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device *ieee)
2166{
2167
2168 unsigned int queue_index = txb->queue_index;
2169 unsigned long flags;
2170 int i;
2171 cb_desc *tcb_desc = NULL;
2172
2173 spin_lock_irqsave(&ieee->lock,flags);
2174
2175 /* called with 2nd parm 0, no tx mgmt lock required */
2176 ieee80211_sta_wakeup(ieee,0);
2177
2178 /* update the tx status */
Florian Schilhabela99840b2010-02-19 20:11:54 +01002179 ieee->stats.tx_bytes += txb->payload_size;
2180 ieee->stats.tx_packets++;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002181 tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
2182 if(tcb_desc->bMulticast) {
2183 ieee->stats.multicast++;
2184 }
2185#if 1
2186 /* if xmit available, just xmit it immediately, else just insert it to the wait queue */
2187 for(i = 0; i < txb->nr_frags; i++) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002188 if ((skb_queue_len(&ieee->skb_waitQ[queue_index]) != 0) ||
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002189 (!ieee->check_nic_enough_desc(ieee->dev,queue_index))||\
2190 (ieee->queue_stop)) {
2191 /* insert the skb packet to the wait queue */
2192 /* as for the completion function, it does not need
2193 * to check it any more.
2194 * */
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002195 skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002196 }else{
2197 ieee->softmac_data_hard_start_xmit(
2198 txb->fragments[i],
2199 ieee->dev,ieee->rate);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002200 }
2201 }
2202#endif
2203 ieee80211_txb_free(txb);
2204
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002205 spin_unlock_irqrestore(&ieee->lock,flags);
2206
2207}
2208
2209/* called with ieee->lock acquired */
2210void ieee80211_resume_tx(struct ieee80211_device *ieee)
2211{
2212 int i;
2213 for(i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) {
2214
2215 if (ieee->queue_stop){
2216 ieee->tx_pending.frag = i;
2217 return;
2218 }else{
2219
2220 ieee->softmac_data_hard_start_xmit(
2221 ieee->tx_pending.txb->fragments[i],
2222 ieee->dev,ieee->rate);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002223 ieee->stats.tx_packets++;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002224 }
2225 }
2226
2227
2228 ieee80211_txb_free(ieee->tx_pending.txb);
2229 ieee->tx_pending.txb = NULL;
2230}
2231
2232
2233void ieee80211_reset_queue(struct ieee80211_device *ieee)
2234{
2235 unsigned long flags;
2236
2237 spin_lock_irqsave(&ieee->lock,flags);
2238 init_mgmt_queue(ieee);
2239 if (ieee->tx_pending.txb){
2240 ieee80211_txb_free(ieee->tx_pending.txb);
2241 ieee->tx_pending.txb = NULL;
2242 }
2243 ieee->queue_stop = 0;
2244 spin_unlock_irqrestore(&ieee->lock,flags);
2245
2246}
2247
George Kadianakis55c7d5f2009-12-17 01:19:13 +02002248void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002249{
2250
2251 unsigned long flags;
2252 struct sk_buff *skb;
2253 struct ieee80211_hdr_3addr *header;
2254
2255 spin_lock_irqsave(&ieee->lock,flags);
2256 if (! ieee->queue_stop) goto exit;
2257
2258 ieee->queue_stop = 0;
2259
2260 if(ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){
2261 while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){
2262
2263 header = (struct ieee80211_hdr_3addr *) skb->data;
2264
Frederic Leroye2117ce2010-02-18 00:25:26 +01002265 header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002266
2267 if (ieee->seq_ctrl[0] == 0xFFF)
2268 ieee->seq_ctrl[0] = 0;
2269 else
2270 ieee->seq_ctrl[0]++;
2271
2272 ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002273 }
2274 }
2275 if (!ieee->queue_stop && ieee->tx_pending.txb)
2276 ieee80211_resume_tx(ieee);
2277
2278 if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){
2279 ieee->softmac_stats.swtxawake++;
2280 netif_wake_queue(ieee->dev);
2281 }
2282
2283exit :
2284 spin_unlock_irqrestore(&ieee->lock,flags);
2285}
2286
2287
George Kadianakis55c7d5f2009-12-17 01:19:13 +02002288void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002289{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002290
2291 if (! netif_queue_stopped(ieee->dev)){
2292 netif_stop_queue(ieee->dev);
2293 ieee->softmac_stats.swtxstop++;
2294 }
2295 ieee->queue_stop = 1;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002296
2297}
2298
2299
2300inline void ieee80211_randomize_cell(struct ieee80211_device *ieee)
2301{
2302
2303 get_random_bytes(ieee->current_network.bssid, ETH_ALEN);
2304
2305 /* an IBSS cell address must have the two less significant
2306 * bits of the first byte = 2
2307 */
2308 ieee->current_network.bssid[0] &= ~0x01;
2309 ieee->current_network.bssid[0] |= 0x02;
2310}
2311
2312/* called in user context only */
2313void ieee80211_start_master_bss(struct ieee80211_device *ieee)
2314{
2315 ieee->assoc_id = 1;
2316
2317 if (ieee->current_network.ssid_len == 0){
2318 strncpy(ieee->current_network.ssid,
2319 IEEE80211_DEFAULT_TX_ESSID,
2320 IW_ESSID_MAX_SIZE);
2321
2322 ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID);
2323 ieee->ssid_set = 1;
2324 }
2325
2326 memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN);
2327
2328 ieee->set_chan(ieee->dev, ieee->current_network.channel);
2329 ieee->state = IEEE80211_LINKED;
2330 ieee->link_change(ieee->dev);
2331 notify_wx_assoc_event(ieee);
2332
2333 if (ieee->data_hard_resume)
2334 ieee->data_hard_resume(ieee->dev);
2335
2336 netif_carrier_on(ieee->dev);
2337}
2338
2339void ieee80211_start_monitor_mode(struct ieee80211_device *ieee)
2340{
2341 if(ieee->raw_tx){
2342
2343 if (ieee->data_hard_resume)
2344 ieee->data_hard_resume(ieee->dev);
2345
2346 netif_carrier_on(ieee->dev);
2347 }
2348}
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02002349
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002350void ieee80211_start_ibss_wq(struct work_struct *work)
2351{
2352
2353 struct delayed_work *dwork = container_of(work, struct delayed_work, work);
2354 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002355 /* iwconfig mode ad-hoc will schedule this and return
2356 * on the other hand this will block further iwconfig SET
2357 * operations because of the wx_sem hold.
2358 * Anyway some most set operations set a flag to speed-up
2359 * (abort) this wq (when syncro scanning) before sleeping
2360 * on the semaphore
2361 */
2362 if(!ieee->proto_started){
2363 printk("==========oh driver down return\n");
2364 return;
2365 }
2366 down(&ieee->wx_sem);
2367 //FIXME:set back to 20M whenever HT for ibss is not ready. Otherwise,after being connected to 40M AP, it will still stay in 40M when set to ibss mode. WB 2009.02.04
2368 HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
2369
2370 if (ieee->current_network.ssid_len == 0){
2371 strcpy(ieee->current_network.ssid,IEEE80211_DEFAULT_TX_ESSID);
2372 ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID);
2373 ieee->ssid_set = 1;
2374 }
2375
2376 /* check if we have this cell in our network list */
2377 ieee80211_softmac_check_all_nets(ieee);
2378
2379
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002380// if((IS_DOT11D_ENABLE(ieee)) && (ieee->state == IEEE80211_NOLINK))
2381 if (ieee->state == IEEE80211_NOLINK)
Florian Schilhabeld5471392010-07-14 14:42:43 +02002382 ieee->current_network.channel = ieee->IbssStartChnl;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002383 /* if not then the state is not linked. Maybe the user swithced to
2384 * ad-hoc mode just after being in monitor mode, or just after
2385 * being very few time in managed mode (so the card have had no
2386 * time to scan all the chans..) or we have just run up the iface
2387 * after setting ad-hoc mode. So we have to give another try..
2388 * Here, in ibss mode, should be safe to do this without extra care
2389 * (in bss mode we had to make sure no-one tryed to associate when
2390 * we had just checked the ieee->state and we was going to start the
2391 * scan) beacause in ibss mode the ieee80211_new_net function, when
2392 * finds a good net, just set the ieee->state to IEEE80211_LINKED,
2393 * so, at worst, we waste a bit of time to initiate an unneeded syncro
2394 * scan, that will stop at the first round because it sees the state
2395 * associated.
2396 */
2397 if (ieee->state == IEEE80211_NOLINK)
2398 ieee80211_start_scan_syncro(ieee);
2399
2400 /* the network definitively is not here.. create a new cell */
2401 if (ieee->state == IEEE80211_NOLINK){
2402 printk("creating new IBSS cell\n");
2403 if(!ieee->wap_set)
2404 ieee80211_randomize_cell(ieee);
2405
2406 if(ieee->modulation & IEEE80211_CCK_MODULATION){
2407
2408 ieee->current_network.rates_len = 4;
2409
2410 ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB;
2411 ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB;
2412 ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB;
2413 ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB;
2414
2415 }else
2416 ieee->current_network.rates_len = 0;
2417
2418 if(ieee->modulation & IEEE80211_OFDM_MODULATION){
2419 ieee->current_network.rates_ex_len = 8;
2420
2421 ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
2422 ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
2423 ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
2424 ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
2425 ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
2426 ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
2427 ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
2428 ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
2429
2430 ieee->rate = 108;
2431 }else{
2432 ieee->current_network.rates_ex_len = 0;
2433 ieee->rate = 22;
2434 }
2435
2436 // By default, WMM function will be disabled in IBSS mode
2437 ieee->current_network.QoS_Enable = 0;
2438 ieee->SetWirelessMode(ieee->dev, IEEE_G);
2439 ieee->current_network.atim_window = 0;
2440 ieee->current_network.capability = WLAN_CAPABILITY_IBSS;
2441 if(ieee->short_slot)
2442 ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT;
2443
2444 }
2445
2446 ieee->state = IEEE80211_LINKED;
2447
2448 ieee->set_chan(ieee->dev, ieee->current_network.channel);
2449 ieee->link_change(ieee->dev);
2450 if(ieee->LedControlHandler != NULL)
2451 ieee->LedControlHandler(ieee->dev,LED_CTL_LINK);
2452 notify_wx_assoc_event(ieee);
2453
2454 ieee80211_start_send_beacons(ieee);
2455
2456 if (ieee->data_hard_resume)
2457 ieee->data_hard_resume(ieee->dev);
2458 netif_carrier_on(ieee->dev);
2459
2460 up(&ieee->wx_sem);
2461}
2462
2463inline void ieee80211_start_ibss(struct ieee80211_device *ieee)
2464{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002465 queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 150);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002466}
2467
2468/* this is called only in user context, with wx_sem held */
2469void ieee80211_start_bss(struct ieee80211_device *ieee)
2470{
2471 unsigned long flags;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002472 //
2473 // Ref: 802.11d 11.1.3.3
2474 // STA shall not start a BSS unless properly formed Beacon frame including a Country IE.
2475 //
2476 if(IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee))
2477 {
2478 if(! ieee->bGlobalDomain)
2479 {
2480 return;
2481 }
2482 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002483 /* check if we have already found the net we
2484 * are interested in (if any).
2485 * if not (we are disassociated and we are not
2486 * in associating / authenticating phase) start the background scanning.
2487 */
2488 ieee80211_softmac_check_all_nets(ieee);
2489
2490 /* ensure no-one start an associating process (thus setting
2491 * the ieee->state to ieee80211_ASSOCIATING) while we
2492 * have just cheked it and we are going to enable scan.
2493 * The ieee80211_new_net function is always called with
2494 * lock held (from both ieee80211_softmac_check_all_nets and
2495 * the rx path), so we cannot be in the middle of such function
2496 */
2497 spin_lock_irqsave(&ieee->lock, flags);
2498
2499 if (ieee->state == IEEE80211_NOLINK){
2500 ieee->actscanning = true;
George Kadianakis55c7d5f2009-12-17 01:19:13 +02002501 ieee80211_rtl_start_scan(ieee);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002502 }
2503 spin_unlock_irqrestore(&ieee->lock, flags);
2504}
2505
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002506void ieee80211_link_change_wq(struct work_struct *work)
2507{
2508 struct delayed_work *dwork = container_of(work, struct delayed_work, work);
2509 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, link_change_wq);
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02002510
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002511 ieee->link_change(ieee->dev);
2512}
2513/* called only in userspace context */
2514void ieee80211_disassociate(struct ieee80211_device *ieee)
2515{
2516
2517
2518 netif_carrier_off(ieee->dev);
2519 if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)
2520 ieee80211_reset_queue(ieee);
2521
2522 if (ieee->data_hard_stop)
2523 ieee->data_hard_stop(ieee->dev);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002524 if(IS_DOT11D_ENABLE(ieee))
2525 Dot11d_Reset(ieee);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002526 ieee->state = IEEE80211_NOLINK;
2527 ieee->is_set_key = false;
2528
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002529 queue_delayed_work(ieee->wq, &ieee->link_change_wq, 0);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002530
Florian Schilhabel124a27e2010-07-15 19:03:49 +02002531
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002532 notify_wx_assoc_event(ieee);
2533
2534}
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02002535
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002536void ieee80211_associate_retry_wq(struct work_struct *work)
2537{
2538 struct delayed_work *dwork = container_of(work, struct delayed_work, work);
2539 struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002540 unsigned long flags;
2541
2542 down(&ieee->wx_sem);
2543 if(!ieee->proto_started)
2544 goto exit;
2545
2546 if(ieee->state != IEEE80211_ASSOCIATING_RETRY)
2547 goto exit;
2548
2549 /* until we do not set the state to IEEE80211_NOLINK
2550 * there are no possibility to have someone else trying
2551 * to start an association procdure (we get here with
2552 * ieee->state = IEEE80211_ASSOCIATING).
2553 * When we set the state to IEEE80211_NOLINK it is possible
2554 * that the RX path run an attempt to associate, but
2555 * both ieee80211_softmac_check_all_nets and the
2556 * RX path works with ieee->lock held so there are no
2557 * problems. If we are still disassociated then start a scan.
2558 * the lock here is necessary to ensure no one try to start
2559 * an association procedure when we have just checked the
2560 * state and we are going to start the scan.
2561 */
2562 ieee->beinretry = true;
2563 ieee->state = IEEE80211_NOLINK;
2564
2565 ieee80211_softmac_check_all_nets(ieee);
2566
2567 spin_lock_irqsave(&ieee->lock, flags);
2568
2569 if(ieee->state == IEEE80211_NOLINK)
2570 {
2571 ieee->actscanning = true;
George Kadianakis55c7d5f2009-12-17 01:19:13 +02002572 ieee80211_rtl_start_scan(ieee);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002573 }
2574 spin_unlock_irqrestore(&ieee->lock, flags);
2575
2576 ieee->beinretry = false;
2577exit:
2578 up(&ieee->wx_sem);
2579}
2580
2581struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee)
2582{
2583 u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff};
2584
2585 struct sk_buff *skb;
2586 struct ieee80211_probe_response *b;
2587
2588 skb = ieee80211_probe_resp(ieee, broadcast_addr);
2589
2590 if (!skb)
2591 return NULL;
2592
2593 b = (struct ieee80211_probe_response *) skb->data;
Frederic Leroye2117ce2010-02-18 00:25:26 +01002594 b->header.frame_control = cpu_to_le16(IEEE80211_STYPE_BEACON);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002595
2596 return skb;
2597
2598}
2599
2600struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee)
2601{
2602 struct sk_buff *skb;
2603 struct ieee80211_probe_response *b;
2604
2605 skb = ieee80211_get_beacon_(ieee);
2606 if(!skb)
2607 return NULL;
2608
2609 b = (struct ieee80211_probe_response *) skb->data;
Frederic Leroye2117ce2010-02-18 00:25:26 +01002610 b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002611
2612 if (ieee->seq_ctrl[0] == 0xFFF)
2613 ieee->seq_ctrl[0] = 0;
2614 else
2615 ieee->seq_ctrl[0]++;
2616
2617 return skb;
2618}
2619
2620void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee)
2621{
2622 ieee->sync_scan_hurryup = 1;
2623 down(&ieee->wx_sem);
2624 ieee80211_stop_protocol(ieee);
2625 up(&ieee->wx_sem);
2626}
2627
2628
2629void ieee80211_stop_protocol(struct ieee80211_device *ieee)
2630{
2631 if (!ieee->proto_started)
2632 return;
2633
2634 ieee->proto_started = 0;
2635
2636 ieee80211_stop_send_beacons(ieee);
2637 del_timer_sync(&ieee->associate_timer);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002638 cancel_delayed_work(&ieee->associate_retry_wq);
2639 cancel_delayed_work(&ieee->start_ibss_wq);
2640 cancel_delayed_work(&ieee->link_change_wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002641 ieee80211_stop_scan(ieee);
2642
2643 ieee80211_disassociate(ieee);
2644 RemoveAllTS(ieee); //added as we disconnect from the previous BSS, Remove all TS
2645}
2646
2647void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee)
2648{
2649 ieee->sync_scan_hurryup = 0;
2650 down(&ieee->wx_sem);
2651 ieee80211_start_protocol(ieee);
2652 up(&ieee->wx_sem);
2653}
2654
2655void ieee80211_start_protocol(struct ieee80211_device *ieee)
2656{
2657 short ch = 0;
2658 int i = 0;
2659 if (ieee->proto_started)
2660 return;
2661
2662 ieee->proto_started = 1;
2663
2664 if (ieee->current_network.channel == 0){
2665 do{
2666 ch++;
2667 if (ch > MAX_CHANNEL_NUMBER)
2668 return; /* no channel found */
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002669 }while(!GET_DOT11D_INFO(ieee)->channel_map[ch]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002670 ieee->current_network.channel = ch;
2671 }
2672
2673 if (ieee->current_network.beacon_interval == 0)
2674 ieee->current_network.beacon_interval = 100;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002675
2676 for(i = 0; i < 17; i++) {
2677 ieee->last_rxseq_num[i] = -1;
2678 ieee->last_rxfrag_num[i] = -1;
2679 ieee->last_packet_time[i] = 0;
2680 }
2681
2682 ieee->init_wmmparam_flag = 0;//reinitialize AC_xx_PARAM registers.
2683
2684
2685 /* if the user set the MAC of the ad-hoc cell and then
2686 * switch to managed mode, shall we make sure that association
2687 * attempts does not fail just because the user provide the essid
2688 * and the nic is still checking for the AP MAC ??
2689 */
2690 if (ieee->iw_mode == IW_MODE_INFRA)
2691 ieee80211_start_bss(ieee);
2692
2693 else if (ieee->iw_mode == IW_MODE_ADHOC)
2694 ieee80211_start_ibss(ieee);
2695
2696 else if (ieee->iw_mode == IW_MODE_MASTER)
2697 ieee80211_start_master_bss(ieee);
2698
2699 else if(ieee->iw_mode == IW_MODE_MONITOR)
2700 ieee80211_start_monitor_mode(ieee);
2701}
2702
2703
2704#define DRV_NAME "Ieee80211"
2705void ieee80211_softmac_init(struct ieee80211_device *ieee)
2706{
2707 int i;
2708 memset(&ieee->current_network, 0, sizeof(struct ieee80211_network));
2709
2710 ieee->state = IEEE80211_NOLINK;
2711 ieee->sync_scan_hurryup = 0;
2712 for(i = 0; i < 5; i++) {
2713 ieee->seq_ctrl[i] = 0;
2714 }
Julia Lawall7a6cb0d2010-05-13 22:00:05 +02002715 ieee->pDot11dInfo = kzalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002716 if (!ieee->pDot11dInfo)
2717 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for DOT11D\n");
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002718 //added for AP roaming
2719 ieee->LinkDetectInfo.SlotNum = 2;
2720 ieee->LinkDetectInfo.NumRecvBcnInPeriod=0;
2721 ieee->LinkDetectInfo.NumRecvDataInPeriod=0;
2722
2723 ieee->assoc_id = 0;
2724 ieee->queue_stop = 0;
2725 ieee->scanning = 0;
2726 ieee->softmac_features = 0; //so IEEE2100-like driver are happy
2727 ieee->wap_set = 0;
2728 ieee->ssid_set = 0;
2729 ieee->proto_started = 0;
2730 ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE;
2731 ieee->rate = 22;
2732 ieee->ps = IEEE80211_PS_DISABLED;
2733 ieee->sta_sleep = 0;
2734 ieee->Regdot11HTOperationalRateSet[0]= 0xff;//support MCS 0~7
2735 ieee->Regdot11HTOperationalRateSet[1]= 0xff;//support MCS 8~15
2736 ieee->Regdot11HTOperationalRateSet[4]= 0x01;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002737 ieee->actscanning = false;
2738 ieee->beinretry = false;
2739 ieee->is_set_key = false;
2740 init_mgmt_queue(ieee);
2741
2742 ieee->sta_edca_param[0] = 0x0000A403;
2743 ieee->sta_edca_param[1] = 0x0000A427;
2744 ieee->sta_edca_param[2] = 0x005E4342;
2745 ieee->sta_edca_param[3] = 0x002F3262;
2746 ieee->aggregation = true;
2747 ieee->enable_rx_imm_BA = 1;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002748 ieee->tx_pending.txb = NULL;
2749
2750 init_timer(&ieee->associate_timer);
2751 ieee->associate_timer.data = (unsigned long)ieee;
2752 ieee->associate_timer.function = ieee80211_associate_abort_cb;
2753
2754 init_timer(&ieee->beacon_timer);
2755 ieee->beacon_timer.data = (unsigned long) ieee;
2756 ieee->beacon_timer.function = ieee80211_send_beacon_cb;
2757
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002758#ifdef PF_SYNCTHREAD
2759 ieee->wq = create_workqueue(DRV_NAME,0);
2760#else
2761 ieee->wq = create_workqueue(DRV_NAME);
2762#endif
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002763
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002764 INIT_DELAYED_WORK(&ieee->link_change_wq,ieee80211_link_change_wq);
2765 INIT_DELAYED_WORK(&ieee->start_ibss_wq,ieee80211_start_ibss_wq);
2766 INIT_WORK(&ieee->associate_complete_wq, ieee80211_associate_complete_wq);
2767 INIT_WORK(&ieee->associate_procedure_wq, ieee80211_associate_procedure_wq);
2768 INIT_DELAYED_WORK(&ieee->softmac_scan_wq,ieee80211_softmac_scan_wq);
2769 INIT_DELAYED_WORK(&ieee->associate_retry_wq, ieee80211_associate_retry_wq);
2770 INIT_WORK(&ieee->wx_sync_scan_wq,ieee80211_wx_sync_scan_wq);
2771
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002772 sema_init(&ieee->wx_sem, 1);
2773 sema_init(&ieee->scan_sem, 1);
2774
2775 spin_lock_init(&ieee->mgmt_tx_lock);
2776 spin_lock_init(&ieee->beacon_lock);
2777
2778 tasklet_init(&ieee->ps_task,
2779 (void(*)(unsigned long)) ieee80211_sta_ps,
2780 (unsigned long)ieee);
2781
2782}
2783
2784void ieee80211_softmac_free(struct ieee80211_device *ieee)
2785{
2786 down(&ieee->wx_sem);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002787 if(NULL != ieee->pDot11dInfo)
2788 {
2789 kfree(ieee->pDot11dInfo);
2790 ieee->pDot11dInfo = NULL;
2791 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002792 del_timer_sync(&ieee->associate_timer);
2793
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002794 cancel_delayed_work(&ieee->associate_retry_wq);
2795 destroy_workqueue(ieee->wq);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002796
2797 up(&ieee->wx_sem);
2798}
2799
2800/********************************************************
2801 * Start of WPA code. *
2802 * this is stolen from the ipw2200 driver *
2803 ********************************************************/
2804
2805
2806static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value)
2807{
2808 /* This is called when wpa_supplicant loads and closes the driver
2809 * interface. */
2810 printk("%s WPA\n",value ? "enabling" : "disabling");
2811 ieee->wpa_enabled = value;
2812 memset(ieee->ap_mac_addr, 0, 6); //reset ap_mac_addr everytime it starts wpa.
2813 return 0;
2814}
2815
2816
2817void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, int wpa_ie_len)
2818{
2819 /* make sure WPA is enabled */
2820 ieee80211_wpa_enable(ieee, 1);
2821
2822 ieee80211_disassociate(ieee);
2823}
2824
2825
2826static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, int reason)
2827{
2828
2829 int ret = 0;
2830
2831 switch (command) {
2832 case IEEE_MLME_STA_DEAUTH:
2833 // silently ignore
2834 break;
2835
2836 case IEEE_MLME_STA_DISASSOC:
2837 ieee80211_disassociate(ieee);
2838 break;
2839
2840 default:
2841 printk("Unknown MLME request: %d\n", command);
2842 ret = -EOPNOTSUPP;
2843 }
2844
2845 return ret;
2846}
2847
2848
2849static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee,
2850 struct ieee_param *param, int plen)
2851{
2852 u8 *buf;
2853
2854 if (param->u.wpa_ie.len > MAX_WPA_IE_LEN ||
2855 (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL))
2856 return -EINVAL;
2857
2858 if (param->u.wpa_ie.len) {
Julia Lawall94002c02010-05-15 23:21:43 +02002859 buf = kmemdup(param->u.wpa_ie.data, param->u.wpa_ie.len,
2860 GFP_KERNEL);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002861 if (buf == NULL)
2862 return -ENOMEM;
2863
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002864 kfree(ieee->wpa_ie);
2865 ieee->wpa_ie = buf;
2866 ieee->wpa_ie_len = param->u.wpa_ie.len;
2867 } else {
2868 kfree(ieee->wpa_ie);
2869 ieee->wpa_ie = NULL;
2870 ieee->wpa_ie_len = 0;
2871 }
2872
2873 ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len);
2874 return 0;
2875}
2876
2877#define AUTH_ALG_OPEN_SYSTEM 0x1
2878#define AUTH_ALG_SHARED_KEY 0x2
2879#define AUTH_ALG_LEAP 0x4
2880static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value)
2881{
2882
2883 struct ieee80211_security sec = {
2884 .flags = SEC_AUTH_MODE,
2885 };
2886 int ret = 0;
2887
2888 if (value & AUTH_ALG_SHARED_KEY) {
2889 sec.auth_mode = WLAN_AUTH_SHARED_KEY;
2890 ieee->open_wep = 0;
2891 ieee->auth_mode = 1;
2892 } else if (value & AUTH_ALG_OPEN_SYSTEM){
2893 sec.auth_mode = WLAN_AUTH_OPEN;
2894 ieee->open_wep = 1;
2895 ieee->auth_mode = 0;
2896 }
2897 else if (value & AUTH_ALG_LEAP){
Bartlomiej Zolnierkiewiczb4fcc8a2009-06-13 18:37:33 +02002898 sec.auth_mode = RTL_WLAN_AUTH_LEAP;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002899 ieee->open_wep = 1;
2900 ieee->auth_mode = 2;
2901 }
2902
2903
2904 if (ieee->set_security)
2905 ieee->set_security(ieee->dev, &sec);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07002906
2907 return ret;
2908}
2909
2910static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value)
2911{
2912 int ret=0;
2913 unsigned long flags;
2914
2915 switch (name) {
2916 case IEEE_PARAM_WPA_ENABLED:
2917 ret = ieee80211_wpa_enable(ieee, value);
2918 break;
2919
2920 case IEEE_PARAM_TKIP_COUNTERMEASURES:
2921 ieee->tkip_countermeasures=value;
2922 break;
2923
2924 case IEEE_PARAM_DROP_UNENCRYPTED: {
2925 /* HACK:
2926 *
2927 * wpa_supplicant calls set_wpa_enabled when the driver
2928 * is loaded and unloaded, regardless of if WPA is being
2929 * used. No other calls are made which can be used to
2930 * determine if encryption will be used or not prior to
2931 * association being expected. If encryption is not being
2932 * used, drop_unencrypted is set to false, else true -- we
2933 * can use this to determine if the CAP_PRIVACY_ON bit should
2934 * be set.
2935 */
2936 struct ieee80211_security sec = {
2937 .flags = SEC_ENABLED,
2938 .enabled = value,
2939 };
2940 ieee->drop_unencrypted = value;
2941 /* We only change SEC_LEVEL for open mode. Others
2942 * are set by ipw_wpa_set_encryption.
2943 */
2944 if (!value) {
2945 sec.flags |= SEC_LEVEL;
2946 sec.level = SEC_LEVEL_0;
2947 }
2948 else {
2949 sec.flags |= SEC_LEVEL;
2950 sec.level = SEC_LEVEL_1;
2951 }
2952 if (ieee->set_security)
2953 ieee->set_security(ieee->dev, &sec);
2954 break;
2955 }
2956
2957 case IEEE_PARAM_PRIVACY_INVOKED:
2958 ieee->privacy_invoked=value;
2959 break;
2960
2961 case IEEE_PARAM_AUTH_ALGS:
2962 ret = ieee80211_wpa_set_auth_algs(ieee, value);
2963 break;
2964
2965 case IEEE_PARAM_IEEE_802_1X:
2966 ieee->ieee802_1x=value;
2967 break;
2968 case IEEE_PARAM_WPAX_SELECT:
2969 // added for WPA2 mixed mode
2970 spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags);
2971 ieee->wpax_type_set = 1;
2972 ieee->wpax_type_notify = value;
2973 spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags);
2974 break;
2975
2976 default:
2977 printk("Unknown WPA param: %d\n",name);
2978 ret = -EOPNOTSUPP;
2979 }
2980
2981 return ret;
2982}
2983
2984/* implementation borrowed from hostap driver */
2985
2986static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee,
2987 struct ieee_param *param, int param_len)
2988{
2989 int ret = 0;
2990
2991 struct ieee80211_crypto_ops *ops;
2992 struct ieee80211_crypt_data **crypt;
2993
2994 struct ieee80211_security sec = {
2995 .flags = 0,
2996 };
2997
2998 param->u.crypt.err = 0;
2999 param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
3000
3001 if (param_len !=
3002 (int) ((char *) param->u.crypt.key - (char *) param) +
3003 param->u.crypt.key_len) {
3004 printk("Len mismatch %d, %d\n", param_len,
3005 param->u.crypt.key_len);
3006 return -EINVAL;
3007 }
3008 if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
3009 param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
3010 param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
3011 if (param->u.crypt.idx >= WEP_KEYS)
3012 return -EINVAL;
3013 crypt = &ieee->crypt[param->u.crypt.idx];
3014 } else {
3015 return -EINVAL;
3016 }
3017
3018 if (strcmp(param->u.crypt.alg, "none") == 0) {
3019 if (crypt) {
3020 sec.enabled = 0;
3021 // FIXME FIXME
3022 //sec.encrypt = 0;
3023 sec.level = SEC_LEVEL_0;
3024 sec.flags |= SEC_ENABLED | SEC_LEVEL;
3025 ieee80211_crypt_delayed_deinit(ieee, crypt);
3026 }
3027 goto done;
3028 }
3029 sec.enabled = 1;
3030// FIXME FIXME
3031// sec.encrypt = 1;
3032 sec.flags |= SEC_ENABLED;
3033
3034 /* IPW HW cannot build TKIP MIC, host decryption still needed. */
3035 if (!(ieee->host_encrypt || ieee->host_decrypt) &&
3036 strcmp(param->u.crypt.alg, "TKIP"))
3037 goto skip_host_crypt;
3038
3039 ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -03003040 if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003041 ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -03003042 /* set WEP40 first, it will be modified according to WEP104 or
3043 * WEP40 at other place */
3044 else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003045 ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -03003046 else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003047 ops = ieee80211_get_crypto_ops(param->u.crypt.alg);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003048 if (ops == NULL) {
3049 printk("unknown crypto alg '%s'\n", param->u.crypt.alg);
3050 param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG;
3051 ret = -EINVAL;
3052 goto done;
3053 }
3054
3055 if (*crypt == NULL || (*crypt)->ops != ops) {
3056 struct ieee80211_crypt_data *new_crypt;
3057
3058 ieee80211_crypt_delayed_deinit(ieee, crypt);
3059
Julia Lawall32414872010-05-11 20:26:57 +02003060 new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003061 if (new_crypt == NULL) {
3062 ret = -ENOMEM;
3063 goto done;
3064 }
3065 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
3066 new_crypt->ops = ops;
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +02003067
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -03003068 if (new_crypt->ops)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003069 new_crypt->priv =
3070 new_crypt->ops->init(param->u.crypt.idx);
3071
3072 if (new_crypt->priv == NULL) {
3073 kfree(new_crypt);
3074 param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED;
3075 ret = -EINVAL;
3076 goto done;
3077 }
3078
3079 *crypt = new_crypt;
3080 }
3081
3082 if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key &&
3083 (*crypt)->ops->set_key(param->u.crypt.key,
3084 param->u.crypt.key_len, param->u.crypt.seq,
3085 (*crypt)->priv) < 0) {
3086 printk("key setting failed\n");
3087 param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED;
3088 ret = -EINVAL;
3089 goto done;
3090 }
3091
3092 skip_host_crypt:
3093 if (param->u.crypt.set_tx) {
3094 ieee->tx_keyidx = param->u.crypt.idx;
3095 sec.active_key = param->u.crypt.idx;
3096 sec.flags |= SEC_ACTIVE_KEY;
3097 } else
3098 sec.flags &= ~SEC_ACTIVE_KEY;
3099
3100 if (param->u.crypt.alg != NULL) {
3101 memcpy(sec.keys[param->u.crypt.idx],
3102 param->u.crypt.key,
3103 param->u.crypt.key_len);
3104 sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
3105 sec.flags |= (1 << param->u.crypt.idx);
3106
3107 if (strcmp(param->u.crypt.alg, "WEP") == 0) {
3108 sec.flags |= SEC_LEVEL;
3109 sec.level = SEC_LEVEL_1;
3110 } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
3111 sec.flags |= SEC_LEVEL;
3112 sec.level = SEC_LEVEL_2;
3113 } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
3114 sec.flags |= SEC_LEVEL;
3115 sec.level = SEC_LEVEL_3;
3116 }
3117 }
3118 done:
3119 if (ieee->set_security)
3120 ieee->set_security(ieee->dev, &sec);
3121
3122 /* Do not reset port if card is in Managed mode since resetting will
3123 * generate new IEEE 802.11 authentication which may end up in looping
3124 * with IEEE 802.1X. If your hardware requires a reset after WEP
3125 * configuration (for example... Prism2), implement the reset_port in
3126 * the callbacks structures used to initialize the 802.11 stack. */
3127 if (ieee->reset_on_keychange &&
3128 ieee->iw_mode != IW_MODE_INFRA &&
3129 ieee->reset_port &&
3130 ieee->reset_port(ieee->dev)) {
3131 printk("reset_port failed\n");
3132 param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED;
3133 return -EINVAL;
3134 }
3135
3136 return ret;
3137}
3138
3139inline struct sk_buff *ieee80211_disassociate_skb(
3140 struct ieee80211_network *beacon,
3141 struct ieee80211_device *ieee,
3142 u8 asRsn)
3143{
3144 struct sk_buff *skb;
3145 struct ieee80211_disassoc *disass;
3146
3147 skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc));
3148 if (!skb)
3149 return NULL;
3150
3151 disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc));
Frederic Leroye2117ce2010-02-18 00:25:26 +01003152 disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003153 disass->header.duration_id = 0;
3154
3155 memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN);
3156 memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN);
3157 memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN);
3158
3159 disass->reason = asRsn;
3160 return skb;
3161}
3162
3163
3164void
3165SendDisassociation(
3166 struct ieee80211_device *ieee,
3167 u8* asSta,
3168 u8 asRsn
3169)
3170{
3171 struct ieee80211_network *beacon = &ieee->current_network;
3172 struct sk_buff *skb;
3173 skb = ieee80211_disassociate_skb(beacon,ieee,asRsn);
3174 if (skb){
3175 softmac_mgmt_xmit(skb, ieee);
3176 //dev_kfree_skb_any(skb);//edit by thomas
3177 }
3178}
3179
3180int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p)
3181{
3182 struct ieee_param *param;
3183 int ret=0;
3184
3185 down(&ieee->wx_sem);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003186
3187 if (p->length < sizeof(struct ieee_param) || !p->pointer){
3188 ret = -EINVAL;
3189 goto out;
3190 }
3191
Julia Lawall32414872010-05-11 20:26:57 +02003192 param = kmalloc(p->length, GFP_KERNEL);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07003193 if (param == NULL){
3194 ret = -ENOMEM;
3195 goto out;
3196 }
3197 if (copy_from_user(param, p->pointer, p->length)) {
3198 kfree(param);
3199 ret = -EFAULT;
3200 goto out;
3201 }
3202
3203 switch (param->cmd) {
3204
3205 case IEEE_CMD_SET_WPA_PARAM:
3206 ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name,
3207 param->u.wpa_param.value);
3208 break;
3209
3210 case IEEE_CMD_SET_WPA_IE:
3211 ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length);
3212 break;
3213
3214 case IEEE_CMD_SET_ENCRYPTION:
3215 ret = ieee80211_wpa_set_encryption(ieee, param, p->length);
3216 break;
3217
3218 case IEEE_CMD_MLME:
3219 ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command,
3220 param->u.mlme.reason_code);
3221 break;
3222
3223 default:
3224 printk("Unknown WPA supplicant request: %d\n",param->cmd);
3225 ret = -EOPNOTSUPP;
3226 break;
3227 }
3228
3229 if (ret == 0 && copy_to_user(p->pointer, param, p->length))
3230 ret = -EFAULT;
3231
3232 kfree(param);
3233out:
3234 up(&ieee->wx_sem);
3235
3236 return ret;
3237}
3238
3239void notify_wx_assoc_event(struct ieee80211_device *ieee)
3240{
3241 union iwreq_data wrqu;
3242 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
3243 if (ieee->state == IEEE80211_LINKED)
3244 memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN);
3245 else
3246 memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
3247 wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL);
3248}