]>
Commit | Line | Data |
---|---|---|
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 | 27 | short 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 | 31 | EXPORT_SYMBOL(ieee80211_is_54g); |
8fc8598e | 32 | |
58af5800 | 33 | short ieee80211_is_shortslot(const struct ieee80211_network *net) |
8fc8598e | 34 | { |
58af5800 | 35 | return net->capability & WLAN_CAPABILITY_SHORT_SLOT; |
8fc8598e | 36 | } |
539b4f72 | 37 | EXPORT_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 | 43 | static 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 | 61 | static 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 | 78 | static 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 |
102 | static 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 |
127 | static 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 | 146 | static 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 | 165 | static 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 | 180 | static void init_mgmt_queue(struct ieee80211_device *ieee) |
8fc8598e JC |
181 | { |
182 | ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; | |
183 | } | |
184 | ||
fabdbdb2 | 185 | static 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 | ||
220 | void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); | |
221 | ||
222 | inline 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 |
289 | static inline void |
290 | softmac_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 | 326 | static 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 | ||
364 | struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); | |
fabdbdb2 AR |
365 | |
366 | static 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 | 394 | static 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 | 406 | static 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 | 418 | static 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 | */ | |
429 | void 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 | } | |
480 | out: | |
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 | 492 | EXPORT_SYMBOL(ieee80211_softmac_scan_syncro); |
8fc8598e | 493 | |
fabdbdb2 | 494 | static 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; |
528 | out: | |
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 | 539 | static 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 | 550 | static 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 | ||
564 | void 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 | 571 | EXPORT_SYMBOL(ieee80211_stop_send_beacons); |
8fc8598e JC |
572 | |
573 | void 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 | 580 | EXPORT_SYMBOL(ieee80211_start_send_beacons); |
8fc8598e | 581 | |
fabdbdb2 | 582 | static 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 | ||
601 | void 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 | 608 | EXPORT_SYMBOL(ieee80211_stop_scan); |
8fc8598e JC |
609 | |
610 | /* called with ieee->lock held */ | |
fabdbdb2 | 611 | static 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 |
631 | void 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 | 647 | EXPORT_SYMBOL(ieee80211_start_scan_syncro); |
8fc8598e | 648 | |
3590e78a BX |
649 | static inline struct sk_buff * |
650 | ieee80211_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 | 694 | static 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 |
846 | static 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 |
901 | static 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 |
930 | static 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 | 957 | static 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 |
966 | static 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 | 976 | static 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 |
986 | static inline struct sk_buff * |
987 | ieee80211_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 | ||
1225 | void 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 | 1255 | static void ieee80211_associate_abort_cb(unsigned long dev) |
8fc8598e JC |
1256 | { |
1257 | ieee80211_associate_abort((struct ieee80211_device *) dev); | |
1258 | } | |
1259 | ||
1260 | ||
fabdbdb2 | 1261 | static 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 |
1286 | static 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 | 1318 | static 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 | 1337 | static 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 | 1382 | static 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 | 1393 | static 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 | ||
1413 | inline 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 | ||
1513 | void 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 | 1538 | static 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 | 1564 | static 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 | ||
1582 | static 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 | 1620 | static 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 | ||
1638 | static 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 | ||
1665 | static inline void | |
1666 | ieee80211_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 | ||
1680 | static inline void | |
1681 | ieee80211_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 | ||
1696 | static inline void | |
1697 | ieee80211_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 |
1712 | static 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 |
1724 | static 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 | 1773 | static 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 | ||
1835 | out: | |
1836 | spin_unlock_irqrestore(&ieee->lock, flags); | |
1837 | ||
1838 | } | |
1839 | ||
1840 | void 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 | ||
1863 | void 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 |
1890 | EXPORT_SYMBOL(ieee80211_ps_tx_ack); |
1891 | ||
fabdbdb2 AR |
1892 | static 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 |
1922 | static 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 |
1981 | inline int |
1982 | ieee80211_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 | */ | |
2140 | void 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 | 2195 | EXPORT_SYMBOL(ieee80211_softmac_xmit); |
8fc8598e JC |
2196 | |
2197 | /* called with ieee->lock acquired */ | |
fabdbdb2 | 2198 | static 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 | ||
2223 | void 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 | 2237 | EXPORT_SYMBOL(ieee80211_reset_queue); |
8fc8598e JC |
2238 | |
2239 | void 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 | ||
2275 | exit : | |
0b4ef0a6 | 2276 | spin_unlock_irqrestore(&ieee->lock, flags); |
8fc8598e | 2277 | } |
539b4f72 | 2278 | EXPORT_SYMBOL(ieee80211_wake_queue); |
8fc8598e JC |
2279 | |
2280 | void 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 | 2293 | EXPORT_SYMBOL(ieee80211_stop_queue); |
8fc8598e | 2294 | |
8fc8598e JC |
2295 | /* called in user context only */ |
2296 | void 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 | 2322 | static 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 | 2332 | static 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 | ||
2442 | inline 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 |
2448 | void 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 */ | |
2486 | void 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 |
2505 | EXPORT_SYMBOL(ieee80211_disassociate); |
2506 | ||
fabdbdb2 | 2507 | static 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 | ||
2544 | exit: | |
e379a9a8 | 2545 | mutex_unlock(&ieee->wx_mutex); |
8fc8598e JC |
2546 | } |
2547 | ||
2548 | struct 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 | ||
2567 | struct 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 | 2586 | EXPORT_SYMBOL(ieee80211_get_beacon); |
8fc8598e JC |
2587 | |
2588 | void 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 | 2595 | EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); |
8fc8598e JC |
2596 | |
2597 | void 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 | ||
2614 | void 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 | 2621 | EXPORT_SYMBOL(ieee80211_softmac_start_protocol); |
8fc8598e JC |
2622 | |
2623 | void 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" | |
2676 | void 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 | ||
2749 | void 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 | ||
2767 | static 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 |
2777 | static 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 | ||
2787 | static 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 | ||
2810 | static 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 | ||
2841 | static 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 | ||
2872 | static 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 | ||
2948 | static 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 | 3098 | static 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 | ||
3123 | void | |
3124 | SendDisassociation( | |
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 | 3139 | EXPORT_SYMBOL(SendDisassociation); |
8fc8598e JC |
3140 | |
3141 | int 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); | |
3190 | out: | |
e379a9a8 | 3191 | mutex_unlock(&ieee->wx_mutex); |
8fc8598e JC |
3192 | |
3193 | return ret; | |
3194 | } | |
539b4f72 | 3195 | EXPORT_SYMBOL(ieee80211_wpa_supplicant_ioctl); |
8fc8598e JC |
3196 | |
3197 | void 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 | 3208 | EXPORT_SYMBOL(notify_wx_assoc_event); |