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