diff options
Diffstat (limited to 'drivers/staging/rtl8192e/rtllib_softmac.c')
-rw-r--r-- | drivers/staging/rtl8192e/rtllib_softmac.c | 4150 |
1 files changed, 4150 insertions, 0 deletions
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c new file mode 100644 index 00000000000..a843de99ed3 --- /dev/null +++ b/drivers/staging/rtl8192e/rtllib_softmac.c | |||
@@ -0,0 +1,4150 @@ | |||
1 | /* IEEE 802.11 SoftMAC layer | ||
2 | * Copyright (c) 2005 Andrea Merello <andreamrl@tiscali.it> | ||
3 | * | ||
4 | * Mostly extracted from the rtl8180-sa2400 driver for the | ||
5 | * in-kernel generic ieee802.11 stack. | ||
6 | * | ||
7 | * Few lines might be stolen from other part of the rtllib | ||
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 "rtllib.h" | ||
18 | #include "rtl_core.h" | ||
19 | |||
20 | #include <linux/random.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/version.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #ifdef ENABLE_DOT11D | ||
25 | #include "dot11d.h" | ||
26 | #endif | ||
27 | |||
28 | #ifdef RTK_DMP_PLATFORM | ||
29 | #include <linux/usb_setting.h> | ||
30 | #endif | ||
31 | extern void _setup_timer( struct timer_list*, void*, unsigned long ); | ||
32 | u8 rsn_authen_cipher_suite[16][4] = { | ||
33 | {0x00,0x0F,0xAC,0x00}, | ||
34 | {0x00,0x0F,0xAC,0x01}, | ||
35 | {0x00,0x0F,0xAC,0x02}, | ||
36 | {0x00,0x0F,0xAC,0x03}, | ||
37 | {0x00,0x0F,0xAC,0x04}, | ||
38 | {0x00,0x0F,0xAC,0x05}, | ||
39 | }; | ||
40 | |||
41 | short rtllib_is_54g(struct rtllib_network *net) | ||
42 | { | ||
43 | return ((net->rates_ex_len > 0) || (net->rates_len > 4)); | ||
44 | } | ||
45 | |||
46 | short rtllib_is_shortslot(struct rtllib_network net) | ||
47 | { | ||
48 | return (net.capability & WLAN_CAPABILITY_SHORT_SLOT_TIME); | ||
49 | } | ||
50 | |||
51 | /* returns the total length needed for pleacing the RATE MFIE | ||
52 | * tag and the EXTENDED RATE MFIE tag if needed. | ||
53 | * It encludes two bytes per tag for the tag itself and its len | ||
54 | */ | ||
55 | unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee) | ||
56 | { | ||
57 | unsigned int rate_len = 0; | ||
58 | |||
59 | if (ieee->modulation & RTLLIB_CCK_MODULATION) | ||
60 | rate_len = RTLLIB_CCK_RATE_LEN + 2; | ||
61 | |||
62 | if (ieee->modulation & RTLLIB_OFDM_MODULATION) | ||
63 | |||
64 | rate_len += RTLLIB_OFDM_RATE_LEN + 2; | ||
65 | |||
66 | return rate_len; | ||
67 | } | ||
68 | |||
69 | /* pleace the MFIE rate, tag to the memory (double) poined. | ||
70 | * Then it updates the pointer so that | ||
71 | * it points after the new MFIE tag added. | ||
72 | */ | ||
73 | void rtllib_MFIE_Brate(struct rtllib_device *ieee, u8 **tag_p) | ||
74 | { | ||
75 | u8 *tag = *tag_p; | ||
76 | |||
77 | if (ieee->modulation & RTLLIB_CCK_MODULATION){ | ||
78 | *tag++ = MFIE_TYPE_RATES; | ||
79 | *tag++ = 4; | ||
80 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_1MB; | ||
81 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_2MB; | ||
82 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_5MB; | ||
83 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_11MB; | ||
84 | } | ||
85 | |||
86 | /* We may add an option for custom rates that specific HW might support */ | ||
87 | *tag_p = tag; | ||
88 | } | ||
89 | |||
90 | void rtllib_MFIE_Grate(struct rtllib_device *ieee, u8 **tag_p) | ||
91 | { | ||
92 | u8 *tag = *tag_p; | ||
93 | |||
94 | if (ieee->modulation & RTLLIB_OFDM_MODULATION){ | ||
95 | |||
96 | *tag++ = MFIE_TYPE_RATES_EX; | ||
97 | *tag++ = 8; | ||
98 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_6MB; | ||
99 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_9MB; | ||
100 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_12MB; | ||
101 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_18MB; | ||
102 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_24MB; | ||
103 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_36MB; | ||
104 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_48MB; | ||
105 | *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_54MB; | ||
106 | |||
107 | } | ||
108 | |||
109 | /* We may add an option for custom rates that specific HW might support */ | ||
110 | *tag_p = tag; | ||
111 | } | ||
112 | |||
113 | void rtllib_WMM_Info(struct rtllib_device *ieee, u8 **tag_p) { | ||
114 | u8 *tag = *tag_p; | ||
115 | |||
116 | *tag++ = MFIE_TYPE_GENERIC; | ||
117 | *tag++ = 7; | ||
118 | *tag++ = 0x00; | ||
119 | *tag++ = 0x50; | ||
120 | *tag++ = 0xf2; | ||
121 | *tag++ = 0x02; | ||
122 | *tag++ = 0x00; | ||
123 | *tag++ = 0x01; | ||
124 | #ifdef SUPPORT_USPD | ||
125 | if (ieee->current_network.wmm_info & 0x80) { | ||
126 | *tag++ = 0x0f|MAX_SP_Len; | ||
127 | } else { | ||
128 | *tag++ = MAX_SP_Len; | ||
129 | } | ||
130 | #else | ||
131 | *tag++ = MAX_SP_Len; | ||
132 | #endif | ||
133 | *tag_p = tag; | ||
134 | } | ||
135 | |||
136 | void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p) { | ||
137 | u8 *tag = *tag_p; | ||
138 | |||
139 | *tag++ = MFIE_TYPE_GENERIC; | ||
140 | *tag++ = 7; | ||
141 | *tag++ = 0x00; | ||
142 | *tag++ = 0xe0; | ||
143 | *tag++ = 0x4c; | ||
144 | *tag++ = 0x01; | ||
145 | *tag++ = 0x02; | ||
146 | *tag++ = 0x11; | ||
147 | *tag++ = 0x00; | ||
148 | |||
149 | *tag_p = tag; | ||
150 | printk(KERN_ALERT "This is enable turbo mode IE process\n"); | ||
151 | } | ||
152 | |||
153 | void enqueue_mgmt(struct rtllib_device *ieee, struct sk_buff *skb) | ||
154 | { | ||
155 | int nh; | ||
156 | nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM; | ||
157 | |||
158 | /* | ||
159 | * if the queue is full but we have newer frames then | ||
160 | * just overwrites the oldest. | ||
161 | * | ||
162 | * if (nh == ieee->mgmt_queue_tail) | ||
163 | * return -1; | ||
164 | */ | ||
165 | ieee->mgmt_queue_head = nh; | ||
166 | ieee->mgmt_queue_ring[nh] = skb; | ||
167 | |||
168 | } | ||
169 | |||
170 | struct sk_buff *dequeue_mgmt(struct rtllib_device *ieee) | ||
171 | { | ||
172 | struct sk_buff *ret; | ||
173 | |||
174 | if (ieee->mgmt_queue_tail == ieee->mgmt_queue_head) | ||
175 | return NULL; | ||
176 | |||
177 | ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; | ||
178 | |||
179 | ieee->mgmt_queue_tail = | ||
180 | (ieee->mgmt_queue_tail+1) % MGMT_QUEUE_NUM; | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | void init_mgmt_queue(struct rtllib_device *ieee) | ||
186 | { | ||
187 | ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; | ||
188 | } | ||
189 | |||
190 | |||
191 | u8 | ||
192 | MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee) | ||
193 | { | ||
194 | u16 i; | ||
195 | u8 QueryRate = 0; | ||
196 | u8 BasicRate; | ||
197 | |||
198 | |||
199 | for ( i = 0; i < ieee->current_network.rates_len; i++) | ||
200 | { | ||
201 | BasicRate = ieee->current_network.rates[i]&0x7F; | ||
202 | if (!rtllib_is_cck_rate(BasicRate)) | ||
203 | { | ||
204 | if (QueryRate == 0) | ||
205 | { | ||
206 | QueryRate = BasicRate; | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | if (BasicRate < QueryRate) | ||
211 | { | ||
212 | QueryRate = BasicRate; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | if (QueryRate == 0) | ||
219 | { | ||
220 | QueryRate = 12; | ||
221 | printk("No BasicRate found!!\n"); | ||
222 | } | ||
223 | return QueryRate; | ||
224 | } | ||
225 | |||
226 | u8 MgntQuery_MgntFrameTxRate(struct rtllib_device *ieee) | ||
227 | { | ||
228 | PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; | ||
229 | u8 rate; | ||
230 | |||
231 | if (pHTInfo->IOTAction & HT_IOT_ACT_MGNT_USE_CCK_6M) | ||
232 | rate = 0x0c; | ||
233 | else | ||
234 | rate = ieee->basic_rate & 0x7f; | ||
235 | |||
236 | if (rate == 0){ | ||
237 | if (ieee->mode == IEEE_A|| | ||
238 | ieee->mode== IEEE_N_5G|| | ||
239 | (ieee->mode== IEEE_N_24G&&!pHTInfo->bCurSuppCCK)) | ||
240 | rate = 0x0c; | ||
241 | else | ||
242 | rate = 0x02; | ||
243 | } | ||
244 | |||
245 | return rate; | ||
246 | } | ||
247 | |||
248 | |||
249 | void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl); | ||
250 | |||
251 | inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee) | ||
252 | { | ||
253 | unsigned long flags; | ||
254 | short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; | ||
255 | struct rtllib_hdr_3addr *header= | ||
256 | (struct rtllib_hdr_3addr *) skb->data; | ||
257 | |||
258 | cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8); | ||
259 | spin_lock_irqsave(&ieee->lock, flags); | ||
260 | |||
261 | /* called with 2nd param 0, no mgmt lock required */ | ||
262 | rtllib_sta_wakeup(ieee,0); | ||
263 | |||
264 | if (header->frame_ctl == RTLLIB_STYPE_BEACON) | ||
265 | tcb_desc->queue_index = BEACON_QUEUE; | ||
266 | else | ||
267 | tcb_desc->queue_index = MGNT_QUEUE; | ||
268 | |||
269 | if (ieee->disable_mgnt_queue) | ||
270 | tcb_desc->queue_index = HIGH_QUEUE; | ||
271 | |||
272 | tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); | ||
273 | tcb_desc->RATRIndex = 7; | ||
274 | tcb_desc->bTxDisableRateFallBack = 1; | ||
275 | tcb_desc->bTxUseDriverAssingedRate = 1; | ||
276 | if (single) { | ||
277 | if (ieee->queue_stop){ | ||
278 | enqueue_mgmt(ieee,skb); | ||
279 | }else{ | ||
280 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0]<<4); | ||
281 | |||
282 | if (ieee->seq_ctrl[0] == 0xFFF) | ||
283 | ieee->seq_ctrl[0] = 0; | ||
284 | else | ||
285 | ieee->seq_ctrl[0]++; | ||
286 | |||
287 | /* avoid watchdog triggers */ | ||
288 | ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); | ||
289 | } | ||
290 | |||
291 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
292 | }else{ | ||
293 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
294 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); | ||
295 | |||
296 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | ||
297 | |||
298 | if (ieee->seq_ctrl[0] == 0xFFF) | ||
299 | ieee->seq_ctrl[0] = 0; | ||
300 | else | ||
301 | ieee->seq_ctrl[0]++; | ||
302 | |||
303 | /* check wether the managed packet queued greater than 5 */ | ||
304 | if (!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\ | ||
305 | (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\ | ||
306 | (ieee->queue_stop) ) { | ||
307 | /* insert the skb packet to the management queue */ | ||
308 | /* as for the completion function, it does not need | ||
309 | * to check it any more. | ||
310 | * */ | ||
311 | printk("%s():insert to waitqueue, queue_index:%d!\n",__func__,tcb_desc->queue_index); | ||
312 | skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index], skb); | ||
313 | } else { | ||
314 | ieee->softmac_hard_start_xmit(skb,ieee->dev); | ||
315 | } | ||
316 | spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, | ||
321 | struct rtllib_device *ieee) | ||
322 | { | ||
323 | short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; | ||
324 | struct rtllib_hdr_3addr *header = | ||
325 | (struct rtllib_hdr_3addr *) skb->data; | ||
326 | u16 fc,type,stype; | ||
327 | cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8); | ||
328 | |||
329 | fc = header->frame_ctl; | ||
330 | type = WLAN_FC_GET_TYPE(fc); | ||
331 | stype = WLAN_FC_GET_STYPE(fc); | ||
332 | |||
333 | |||
334 | if (stype != RTLLIB_STYPE_PSPOLL) | ||
335 | tcb_desc->queue_index = MGNT_QUEUE; | ||
336 | else | ||
337 | tcb_desc->queue_index = HIGH_QUEUE; | ||
338 | |||
339 | if (ieee->disable_mgnt_queue) | ||
340 | tcb_desc->queue_index = HIGH_QUEUE; | ||
341 | |||
342 | |||
343 | tcb_desc->data_rate = MgntQuery_MgntFrameTxRate(ieee); | ||
344 | tcb_desc->RATRIndex = 7; | ||
345 | tcb_desc->bTxDisableRateFallBack = 1; | ||
346 | tcb_desc->bTxUseDriverAssingedRate = 1; | ||
347 | if (single) { | ||
348 | if (type != RTLLIB_FTYPE_CTL) { | ||
349 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | ||
350 | |||
351 | if (ieee->seq_ctrl[0] == 0xFFF) | ||
352 | ieee->seq_ctrl[0] = 0; | ||
353 | else | ||
354 | ieee->seq_ctrl[0]++; | ||
355 | |||
356 | } | ||
357 | /* avoid watchdog triggers */ | ||
358 | ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); | ||
359 | |||
360 | } else { | ||
361 | if (type != RTLLIB_FTYPE_CTL) { | ||
362 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | ||
363 | |||
364 | if (ieee->seq_ctrl[0] == 0xFFF) | ||
365 | ieee->seq_ctrl[0] = 0; | ||
366 | else | ||
367 | ieee->seq_ctrl[0]++; | ||
368 | } | ||
369 | ieee->softmac_hard_start_xmit(skb,ieee->dev); | ||
370 | |||
371 | } | ||
372 | } | ||
373 | |||
374 | inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) | ||
375 | { | ||
376 | unsigned int len,rate_len; | ||
377 | u8 *tag; | ||
378 | struct sk_buff *skb; | ||
379 | struct rtllib_probe_request *req; | ||
380 | |||
381 | len = ieee->current_network.ssid_len; | ||
382 | |||
383 | rate_len = rtllib_MFIE_rate_len(ieee); | ||
384 | |||
385 | #ifdef USB_USE_ALIGNMENT | ||
386 | u32 Tmpaddr; | ||
387 | int alignment; | ||
388 | skb = dev_alloc_skb(sizeof(struct rtllib_probe_request) + | ||
389 | 2 + len + rate_len + ieee->tx_headroom + USB_512B_ALIGNMENT_SIZE); | ||
390 | #else | ||
391 | skb = dev_alloc_skb(sizeof(struct rtllib_probe_request) + | ||
392 | 2 + len + rate_len + ieee->tx_headroom); | ||
393 | #endif | ||
394 | |||
395 | if (!skb) | ||
396 | return NULL; | ||
397 | |||
398 | #ifdef USB_USE_ALIGNMENT | ||
399 | Tmpaddr = (u32)skb->data; | ||
400 | alignment = Tmpaddr & 0x1ff; | ||
401 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
402 | #endif | ||
403 | |||
404 | skb_reserve(skb, ieee->tx_headroom); | ||
405 | |||
406 | req = (struct rtllib_probe_request *) skb_put(skb,sizeof(struct rtllib_probe_request)); | ||
407 | req->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_PROBE_REQ); | ||
408 | req->header.duration_id = 0; | ||
409 | |||
410 | memset(req->header.addr1, 0xff, ETH_ALEN); | ||
411 | memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
412 | memset(req->header.addr3, 0xff, ETH_ALEN); | ||
413 | |||
414 | tag = (u8 *) skb_put(skb,len+2+rate_len); | ||
415 | |||
416 | *tag++ = MFIE_TYPE_SSID; | ||
417 | *tag++ = len; | ||
418 | memcpy(tag, ieee->current_network.ssid, len); | ||
419 | tag += len; | ||
420 | |||
421 | rtllib_MFIE_Brate(ieee,&tag); | ||
422 | rtllib_MFIE_Grate(ieee,&tag); | ||
423 | |||
424 | return skb; | ||
425 | } | ||
426 | |||
427 | struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee); | ||
428 | |||
429 | void rtllib_send_beacon(struct rtllib_device *ieee) | ||
430 | { | ||
431 | struct sk_buff *skb; | ||
432 | if (!ieee->ieee_up) | ||
433 | return; | ||
434 | skb = rtllib_get_beacon_(ieee); | ||
435 | |||
436 | if (skb){ | ||
437 | softmac_mgmt_xmit(skb, ieee); | ||
438 | ieee->softmac_stats.tx_beacons++; | ||
439 | } | ||
440 | |||
441 | if (ieee->beacon_txing && ieee->ieee_up){ | ||
442 | mod_timer(&ieee->beacon_timer,jiffies+(MSECS(ieee->current_network.beacon_interval-5))); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | void rtllib_send_beacon_cb(unsigned long _ieee) | ||
448 | { | ||
449 | struct rtllib_device *ieee = | ||
450 | (struct rtllib_device *) _ieee; | ||
451 | unsigned long flags; | ||
452 | |||
453 | spin_lock_irqsave(&ieee->beacon_lock, flags); | ||
454 | rtllib_send_beacon(ieee); | ||
455 | spin_unlock_irqrestore(&ieee->beacon_lock, flags); | ||
456 | } | ||
457 | |||
458 | /* | ||
459 | * Description: | ||
460 | * Enable network monitor mode, all rx packets will be received. | ||
461 | */ | ||
462 | void rtllib_EnableNetMonitorMode(struct net_device* dev, | ||
463 | bool bInitState) | ||
464 | { | ||
465 | struct rtllib_device* ieee = netdev_priv_rsl(dev); | ||
466 | |||
467 | printk("========>Enter Monitor Mode\n"); | ||
468 | |||
469 | ieee->AllowAllDestAddrHandler(dev, true, !bInitState); | ||
470 | } | ||
471 | |||
472 | |||
473 | /* | ||
474 | * Description: | ||
475 | * Disable network network monitor mode, only packets destinated to | ||
476 | * us will be received. | ||
477 | */ | ||
478 | void rtllib_DisableNetMonitorMode(struct net_device* dev, | ||
479 | bool bInitState) | ||
480 | { | ||
481 | struct rtllib_device* ieee = netdev_priv_rsl(dev); | ||
482 | |||
483 | printk("========>Exit Monitor Mode\n"); | ||
484 | |||
485 | ieee->AllowAllDestAddrHandler(dev, false, !bInitState); | ||
486 | } | ||
487 | |||
488 | |||
489 | /* | ||
490 | * Description: | ||
491 | * This enables the specialized promiscuous mode required by Intel. | ||
492 | * In this mode, Intel intends to hear traffics from/to other STAs in the same BSS. | ||
493 | * Therefore we don't have to disable checking BSSID and we only need to allow all dest. | ||
494 | * BUT: if we enable checking BSSID then we can't recv packets from other STA. | ||
495 | */ | ||
496 | void rtllib_EnableIntelPromiscuousMode(struct net_device* dev, | ||
497 | bool bInitState) | ||
498 | { | ||
499 | bool bFilterOutNonAssociatedBSSID = false; | ||
500 | |||
501 | struct rtllib_device* ieee = netdev_priv_rsl(dev); | ||
502 | |||
503 | printk("========>Enter Intel Promiscuous Mode\n"); | ||
504 | |||
505 | ieee->AllowAllDestAddrHandler(dev, true, !bInitState); | ||
506 | ieee->SetHwRegHandler(dev, HW_VAR_CECHK_BSSID, (u8*)&bFilterOutNonAssociatedBSSID); | ||
507 | |||
508 | ieee->bNetPromiscuousMode = true; | ||
509 | } | ||
510 | |||
511 | |||
512 | /* | ||
513 | * Description: | ||
514 | * This disables the specialized promiscuous mode required by Intel. | ||
515 | * See MgntEnableIntelPromiscuousMode for detail. | ||
516 | */ | ||
517 | void rtllib_DisableIntelPromiscuousMode(struct net_device* dev, | ||
518 | bool bInitState) | ||
519 | { | ||
520 | bool bFilterOutNonAssociatedBSSID = true; | ||
521 | |||
522 | struct rtllib_device* ieee = netdev_priv_rsl(dev); | ||
523 | |||
524 | printk("========>Exit Intel Promiscuous Mode\n"); | ||
525 | |||
526 | ieee->AllowAllDestAddrHandler(dev, false, !bInitState); | ||
527 | ieee->SetHwRegHandler(dev, HW_VAR_CECHK_BSSID, (u8*)&bFilterOutNonAssociatedBSSID); | ||
528 | |||
529 | ieee->bNetPromiscuousMode = false; | ||
530 | } | ||
531 | |||
532 | void rtllib_send_probe(struct rtllib_device *ieee, u8 is_mesh) | ||
533 | { | ||
534 | struct sk_buff *skb; | ||
535 | skb = rtllib_probe_req(ieee); | ||
536 | if (skb){ | ||
537 | softmac_mgmt_xmit(skb, ieee); | ||
538 | ieee->softmac_stats.tx_probe_rq++; | ||
539 | } | ||
540 | } | ||
541 | |||
542 | |||
543 | void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh) | ||
544 | { | ||
545 | if (ieee->active_scan && (ieee->softmac_features & | ||
546 | IEEE_SOFTMAC_PROBERQ)) { | ||
547 | rtllib_send_probe(ieee, 0); | ||
548 | rtllib_send_probe(ieee, 0); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | void rtllib_softmac_hint11d_wq(void *data) | ||
553 | { | ||
554 | #ifdef CONFIG_CRDA | ||
555 | struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, softmac_hint11d_wq); | ||
556 | PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); | ||
557 | struct wireless_dev *wdev = &ieee->wdev; | ||
558 | |||
559 | regulatory_hint_11d(wdev->wiphy, pDot11dInfo->CountryIeBuf, pDot11dInfo->CountryIeLen); | ||
560 | #endif | ||
561 | } | ||
562 | |||
563 | void rtllib_update_active_chan_map(struct rtllib_device *ieee) | ||
564 | { | ||
565 | #ifdef ENABLE_DOT11D | ||
566 | memcpy(ieee->active_channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); | ||
567 | #else | ||
568 | memcpy(ieee->active_channel_map, ieee->channel_map, MAX_CHANNEL_NUMBER+1); | ||
569 | #endif | ||
570 | } | ||
571 | |||
572 | /* this performs syncro scan blocking the caller until all channels | ||
573 | * in the allowed channel map has been checked. | ||
574 | */ | ||
575 | void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) | ||
576 | { | ||
577 | short ch = 0; | ||
578 | |||
579 | rtllib_update_active_chan_map(ieee); | ||
580 | |||
581 | ieee->be_scan_inprogress = true; | ||
582 | |||
583 | down(&ieee->scan_sem); | ||
584 | |||
585 | while(1) | ||
586 | { | ||
587 | |||
588 | do { | ||
589 | ch++; | ||
590 | if (ch > MAX_CHANNEL_NUMBER) | ||
591 | goto out; /* scan completed */ | ||
592 | } while(!ieee->active_channel_map[ch]); | ||
593 | |||
594 | /* this fuction can be called in two situations | ||
595 | * 1- We have switched to ad-hoc mode and we are | ||
596 | * performing a complete syncro scan before conclude | ||
597 | * there are no interesting cell and to create a | ||
598 | * new one. In this case the link state is | ||
599 | * RTLLIB_NOLINK until we found an interesting cell. | ||
600 | * If so the ieee8021_new_net, called by the RX path | ||
601 | * will set the state to RTLLIB_LINKED, so we stop | ||
602 | * scanning | ||
603 | * 2- We are linked and the root uses run iwlist scan. | ||
604 | * So we switch to RTLLIB_LINKED_SCANNING to remember | ||
605 | * that we are still logically linked (not interested in | ||
606 | * new network events, despite for updating the net list, | ||
607 | * but we are temporarly 'unlinked' as the driver shall | ||
608 | * not filter RX frames and the channel is changing. | ||
609 | * So the only situation in witch are interested is to check | ||
610 | * if the state become LINKED because of the #1 situation | ||
611 | */ | ||
612 | |||
613 | if (ieee->state == RTLLIB_LINKED) | ||
614 | goto out; | ||
615 | if (ieee->sync_scan_hurryup){ | ||
616 | printk("============>sync_scan_hurryup out\n"); | ||
617 | goto out; | ||
618 | } | ||
619 | |||
620 | ieee->set_chan(ieee->dev, ch); | ||
621 | if (ieee->active_channel_map[ch] == 1) | ||
622 | rtllib_send_probe_requests(ieee, 0); | ||
623 | |||
624 | /* this prevent excessive time wait when we | ||
625 | * need to wait for a syncro scan to end.. | ||
626 | */ | ||
627 | msleep_interruptible_rsl(RTLLIB_SOFTMAC_SCAN_TIME); | ||
628 | } | ||
629 | out: | ||
630 | ieee->actscanning = false; | ||
631 | ieee->sync_scan_hurryup = 0; | ||
632 | |||
633 | if (ieee->state >= RTLLIB_LINKED){ | ||
634 | #ifdef ENABLE_DOT11D | ||
635 | if (IS_DOT11D_ENABLE(ieee)) | ||
636 | DOT11D_ScanComplete(ieee); | ||
637 | #endif | ||
638 | } | ||
639 | up(&ieee->scan_sem); | ||
640 | |||
641 | ieee->be_scan_inprogress = false; | ||
642 | |||
643 | #ifndef FOR_MOBLIN | ||
644 | { | ||
645 | union iwreq_data wrqu; | ||
646 | memset(&wrqu, 0, sizeof(wrqu)); | ||
647 | wireless_send_event(ieee->dev,SIOCGIWSCAN,&wrqu,NULL); | ||
648 | } | ||
649 | #endif | ||
650 | } | ||
651 | |||
652 | void rtllib_softmac_scan_wq(void *data) | ||
653 | { | ||
654 | struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, softmac_scan_wq); | ||
655 | u8 last_channel = ieee->current_network.channel; | ||
656 | |||
657 | rtllib_update_active_chan_map(ieee); | ||
658 | |||
659 | if (!ieee->ieee_up) | ||
660 | return; | ||
661 | if (rtllib_act_scanning(ieee,true) == true) | ||
662 | return; | ||
663 | |||
664 | down(&ieee->scan_sem); | ||
665 | |||
666 | if (ieee->eRFPowerState == eRfOff) | ||
667 | { | ||
668 | printk("======>%s():rf state is eRfOff, return\n",__func__); | ||
669 | goto out1; | ||
670 | } | ||
671 | |||
672 | do{ | ||
673 | ieee->current_network.channel = | ||
674 | (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; | ||
675 | if (ieee->scan_watch_dog++ > MAX_CHANNEL_NUMBER) | ||
676 | { | ||
677 | if (!ieee->active_channel_map[ieee->current_network.channel]) | ||
678 | ieee->current_network.channel = 6; | ||
679 | goto out; /* no good chans */ | ||
680 | } | ||
681 | } while(!ieee->active_channel_map[ieee->current_network.channel]); | ||
682 | |||
683 | if (ieee->scanning_continue == 0 ) | ||
684 | goto out; | ||
685 | |||
686 | ieee->set_chan(ieee->dev, ieee->current_network.channel); | ||
687 | |||
688 | if (ieee->active_channel_map[ieee->current_network.channel] == 1) | ||
689 | rtllib_send_probe_requests(ieee, 0); | ||
690 | |||
691 | queue_delayed_work_rsl(ieee->wq, &ieee->softmac_scan_wq, MSECS(RTLLIB_SOFTMAC_SCAN_TIME)); | ||
692 | |||
693 | up(&ieee->scan_sem); | ||
694 | return; | ||
695 | |||
696 | out: | ||
697 | #ifdef ENABLE_DOT11D | ||
698 | if (IS_DOT11D_ENABLE(ieee)) | ||
699 | DOT11D_ScanComplete(ieee); | ||
700 | #endif | ||
701 | ieee->current_network.channel = last_channel; | ||
702 | |||
703 | out1: | ||
704 | ieee->actscanning = false; | ||
705 | ieee->scan_watch_dog = 0; | ||
706 | ieee->scanning_continue = 0; | ||
707 | up(&ieee->scan_sem); | ||
708 | } | ||
709 | |||
710 | |||
711 | |||
712 | void rtllib_beacons_start(struct rtllib_device *ieee) | ||
713 | { | ||
714 | unsigned long flags; | ||
715 | spin_lock_irqsave(&ieee->beacon_lock,flags); | ||
716 | |||
717 | ieee->beacon_txing = 1; | ||
718 | rtllib_send_beacon(ieee); | ||
719 | |||
720 | spin_unlock_irqrestore(&ieee->beacon_lock,flags); | ||
721 | } | ||
722 | |||
723 | void rtllib_beacons_stop(struct rtllib_device *ieee) | ||
724 | { | ||
725 | unsigned long flags; | ||
726 | |||
727 | spin_lock_irqsave(&ieee->beacon_lock,flags); | ||
728 | |||
729 | ieee->beacon_txing = 0; | ||
730 | del_timer_sync(&ieee->beacon_timer); | ||
731 | |||
732 | spin_unlock_irqrestore(&ieee->beacon_lock,flags); | ||
733 | |||
734 | } | ||
735 | |||
736 | |||
737 | void rtllib_stop_send_beacons(struct rtllib_device *ieee) | ||
738 | { | ||
739 | if (ieee->stop_send_beacons) | ||
740 | ieee->stop_send_beacons(ieee->dev); | ||
741 | if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) | ||
742 | rtllib_beacons_stop(ieee); | ||
743 | } | ||
744 | |||
745 | |||
746 | void rtllib_start_send_beacons(struct rtllib_device *ieee) | ||
747 | { | ||
748 | if (ieee->start_send_beacons) | ||
749 | ieee->start_send_beacons(ieee->dev); | ||
750 | if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) | ||
751 | rtllib_beacons_start(ieee); | ||
752 | } | ||
753 | |||
754 | |||
755 | void rtllib_softmac_stop_scan(struct rtllib_device *ieee) | ||
756 | { | ||
757 | |||
758 | |||
759 | down(&ieee->scan_sem); | ||
760 | ieee->scan_watch_dog = 0; | ||
761 | if (ieee->scanning_continue == 1){ | ||
762 | ieee->scanning_continue = 0; | ||
763 | ieee->actscanning = 0; | ||
764 | |||
765 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40) | ||
766 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) | ||
767 | cancel_delayed_work(&ieee->softmac_scan_wq); | ||
768 | #endif | ||
769 | #else | ||
770 | del_timer_sync(&ieee->scan_timer); | ||
771 | #endif | ||
772 | } | ||
773 | |||
774 | up(&ieee->scan_sem); | ||
775 | } | ||
776 | |||
777 | void rtllib_stop_scan(struct rtllib_device *ieee) | ||
778 | { | ||
779 | if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ | ||
780 | rtllib_softmac_stop_scan(ieee); | ||
781 | }else{ | ||
782 | if (ieee->rtllib_stop_hw_scan) | ||
783 | ieee->rtllib_stop_hw_scan(ieee->dev); | ||
784 | } | ||
785 | } | ||
786 | |||
787 | void rtllib_stop_scan_syncro(struct rtllib_device *ieee) | ||
788 | { | ||
789 | if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ | ||
790 | ieee->sync_scan_hurryup = 1; | ||
791 | }else{ | ||
792 | if (ieee->rtllib_stop_hw_scan) | ||
793 | ieee->rtllib_stop_hw_scan(ieee->dev); | ||
794 | } | ||
795 | } | ||
796 | |||
797 | bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan) | ||
798 | { | ||
799 | if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ | ||
800 | if (sync_scan){ | ||
801 | return ieee->be_scan_inprogress; | ||
802 | }else{ | ||
803 | return (ieee->actscanning ||ieee->be_scan_inprogress); | ||
804 | } | ||
805 | }else{ | ||
806 | return test_bit(STATUS_SCANNING, &ieee->status); | ||
807 | } | ||
808 | } | ||
809 | |||
810 | /* called with ieee->lock held */ | ||
811 | void rtllib_start_scan(struct rtllib_device *ieee) | ||
812 | { | ||
813 | RT_TRACE(COMP_DBG, "===>%s()\n",__func__); | ||
814 | if (ieee->rtllib_ips_leave_wq != NULL) | ||
815 | ieee->rtllib_ips_leave_wq(ieee->dev); | ||
816 | |||
817 | |||
818 | #ifdef ENABLE_DOT11D | ||
819 | if (IS_DOT11D_ENABLE(ieee) ) | ||
820 | { | ||
821 | if (IS_COUNTRY_IE_VALID(ieee)) | ||
822 | { | ||
823 | RESET_CIE_WATCHDOG(ieee); | ||
824 | } | ||
825 | } | ||
826 | #endif | ||
827 | if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { | ||
828 | if (ieee->scanning_continue == 0) { | ||
829 | ieee->actscanning = true; | ||
830 | ieee->scanning_continue = 1; | ||
831 | queue_delayed_work_rsl(ieee->wq, &ieee->softmac_scan_wq, 0); | ||
832 | } | ||
833 | } else { | ||
834 | if (ieee->rtllib_start_hw_scan) | ||
835 | ieee->rtllib_start_hw_scan(ieee->dev); | ||
836 | } | ||
837 | |||
838 | } | ||
839 | |||
840 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,40) | ||
841 | void rtllib_softmac_scan_cb(unsigned long _dev) | ||
842 | { | ||
843 | unsigned long flags; | ||
844 | struct rtllib_device *ieee = (struct rtllib_device *)_dev; | ||
845 | |||
846 | spin_lock_irqsave(&ieee->lock, flags); | ||
847 | rtllib_start_scan(ieee); | ||
848 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
849 | } | ||
850 | #endif | ||
851 | |||
852 | /* called with wx_sem held */ | ||
853 | void rtllib_start_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) | ||
854 | { | ||
855 | #ifdef ENABLE_DOT11D | ||
856 | if (IS_DOT11D_ENABLE(ieee) ) | ||
857 | { | ||
858 | if (IS_COUNTRY_IE_VALID(ieee)) | ||
859 | { | ||
860 | RESET_CIE_WATCHDOG(ieee); | ||
861 | } | ||
862 | } | ||
863 | #endif | ||
864 | ieee->sync_scan_hurryup = 0; | ||
865 | if (ieee->softmac_features & IEEE_SOFTMAC_SCAN){ | ||
866 | rtllib_softmac_scan_syncro(ieee, is_mesh); | ||
867 | }else{ | ||
868 | if (ieee->rtllib_start_hw_scan) | ||
869 | ieee->rtllib_start_hw_scan(ieee->dev); | ||
870 | } | ||
871 | |||
872 | } | ||
873 | |||
874 | inline struct sk_buff *rtllib_authentication_req(struct rtllib_network *beacon, | ||
875 | struct rtllib_device *ieee, int challengelen,u8 * daddr) | ||
876 | { | ||
877 | struct sk_buff *skb; | ||
878 | struct rtllib_authentication *auth; | ||
879 | int len = 0; | ||
880 | len = sizeof(struct rtllib_authentication) + challengelen + ieee->tx_headroom + 4; | ||
881 | #ifdef USB_USE_ALIGNMENT | ||
882 | u32 Tmpaddr; | ||
883 | int alignment; | ||
884 | skb = dev_alloc_skb(len + USB_512B_ALIGNMENT_SIZE); | ||
885 | #else | ||
886 | skb = dev_alloc_skb(len); | ||
887 | #endif | ||
888 | |||
889 | if (!skb) return NULL; | ||
890 | |||
891 | #ifdef USB_USE_ALIGNMENT | ||
892 | Tmpaddr = (u32)skb->data; | ||
893 | alignment = Tmpaddr & 0x1ff; | ||
894 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
895 | #endif | ||
896 | |||
897 | skb_reserve(skb, ieee->tx_headroom); | ||
898 | |||
899 | auth = (struct rtllib_authentication *) | ||
900 | skb_put(skb, sizeof(struct rtllib_authentication)); | ||
901 | |||
902 | auth->header.frame_ctl = RTLLIB_STYPE_AUTH; | ||
903 | if (challengelen) auth->header.frame_ctl |= RTLLIB_FCTL_WEP; | ||
904 | |||
905 | auth->header.duration_id = 0x013a; | ||
906 | memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); | ||
907 | memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
908 | memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); | ||
909 | if (ieee->auth_mode == 0) | ||
910 | auth->algorithm = WLAN_AUTH_OPEN; | ||
911 | else if (ieee->auth_mode == 1) | ||
912 | auth->algorithm = WLAN_AUTH_SHARED_KEY; | ||
913 | else if (ieee->auth_mode == 2) | ||
914 | auth->algorithm = WLAN_AUTH_OPEN; | ||
915 | auth->transaction = cpu_to_le16(ieee->associate_seq); | ||
916 | ieee->associate_seq++; | ||
917 | |||
918 | auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); | ||
919 | |||
920 | return skb; | ||
921 | |||
922 | } | ||
923 | |||
924 | void constructWMMIE(u8* wmmie, u8* wmm_len,u8 oui_subtype) | ||
925 | { | ||
926 | u8 szQoSOUI[] ={221, 0, 0x00, 0x50, 0xf2, 0x02, 0, 1}; | ||
927 | |||
928 | if (oui_subtype == OUI_SUBTYPE_QOS_CAPABI) | ||
929 | { | ||
930 | szQoSOUI[0] = 46; | ||
931 | szQoSOUI[1] = *wmm_len; | ||
932 | memcpy(wmmie,szQoSOUI,3); | ||
933 | *wmm_len = 3; | ||
934 | } | ||
935 | else | ||
936 | { | ||
937 | szQoSOUI[1] = *wmm_len + 6; | ||
938 | szQoSOUI[6] = oui_subtype; | ||
939 | memcpy(wmmie, szQoSOUI, 8); | ||
940 | *(wmmie+8) = 0; | ||
941 | *wmm_len = 9; | ||
942 | } | ||
943 | } | ||
944 | |||
945 | static struct sk_buff* rtllib_probe_resp(struct rtllib_device *ieee, u8 *dest) | ||
946 | { | ||
947 | u8 *tag; | ||
948 | int beacon_size; | ||
949 | struct rtllib_probe_response *beacon_buf; | ||
950 | struct sk_buff *skb = NULL; | ||
951 | int encrypt; | ||
952 | int atim_len,erp_len; | ||
953 | struct rtllib_crypt_data* crypt; | ||
954 | |||
955 | char *ssid = ieee->current_network.ssid; | ||
956 | int ssid_len = ieee->current_network.ssid_len; | ||
957 | int rate_len = ieee->current_network.rates_len+2; | ||
958 | int rate_ex_len = ieee->current_network.rates_ex_len; | ||
959 | int wpa_ie_len = ieee->wpa_ie_len; | ||
960 | u8 erpinfo_content = 0; | ||
961 | |||
962 | u8* tmp_ht_cap_buf = NULL; | ||
963 | u8 tmp_ht_cap_len = 0; | ||
964 | u8* tmp_ht_info_buf = NULL; | ||
965 | u8 tmp_ht_info_len = 0; | ||
966 | PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; | ||
967 | u8* tmp_generic_ie_buf = NULL; | ||
968 | u8 tmp_generic_ie_len = 0; | ||
969 | |||
970 | if (rate_ex_len > 0) | ||
971 | rate_ex_len+=2; | ||
972 | |||
973 | if (ieee->current_network.capability & WLAN_CAPABILITY_IBSS) | ||
974 | atim_len = 4; | ||
975 | else | ||
976 | atim_len = 0; | ||
977 | |||
978 | if ((ieee->current_network.mode == IEEE_G) | ||
979 | ||( ieee->current_network.mode == IEEE_N_24G && ieee->pHTInfo->bCurSuppCCK)) { | ||
980 | erp_len = 3; | ||
981 | erpinfo_content = 0; | ||
982 | if (ieee->current_network.buseprotection) | ||
983 | erpinfo_content |= ERP_UseProtection; | ||
984 | } | ||
985 | else | ||
986 | erp_len = 0; | ||
987 | |||
988 | crypt = ieee->crypt[ieee->tx_keyidx]; | ||
989 | encrypt = ieee->host_encrypt && crypt && crypt->ops && | ||
990 | ((0 == strcmp(crypt->ops->name, "WEP") || wpa_ie_len)); | ||
991 | if (ieee->pHTInfo->bCurrentHTSupport){ | ||
992 | tmp_ht_cap_buf =(u8*) &(ieee->pHTInfo->SelfHTCap); | ||
993 | tmp_ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); | ||
994 | tmp_ht_info_buf =(u8*) &(ieee->pHTInfo->SelfHTInfo); | ||
995 | tmp_ht_info_len = sizeof(ieee->pHTInfo->SelfHTInfo); | ||
996 | HTConstructCapabilityElement(ieee, tmp_ht_cap_buf, &tmp_ht_cap_len,encrypt, false); | ||
997 | HTConstructInfoElement(ieee,tmp_ht_info_buf,&tmp_ht_info_len, encrypt); | ||
998 | |||
999 | |||
1000 | if (pHTInfo->bRegRT2RTAggregation) | ||
1001 | { | ||
1002 | tmp_generic_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; | ||
1003 | tmp_generic_ie_len = sizeof(ieee->pHTInfo->szRT2RTAggBuffer); | ||
1004 | HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf, &tmp_generic_ie_len); | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | beacon_size = sizeof(struct rtllib_probe_response)+2+ | ||
1009 | ssid_len | ||
1010 | +3 | ||
1011 | +rate_len | ||
1012 | +rate_ex_len | ||
1013 | +atim_len | ||
1014 | +erp_len | ||
1015 | +wpa_ie_len | ||
1016 | +ieee->tx_headroom; | ||
1017 | #ifdef USB_USE_ALIGNMENT | ||
1018 | u32 Tmpaddr=0; | ||
1019 | int alignment=0; | ||
1020 | skb = dev_alloc_skb(beacon_size + USB_512B_ALIGNMENT_SIZE); | ||
1021 | #else | ||
1022 | skb = dev_alloc_skb(beacon_size); | ||
1023 | #endif | ||
1024 | if (!skb) | ||
1025 | return NULL; | ||
1026 | |||
1027 | #ifdef USB_USE_ALIGNMENT | ||
1028 | Tmpaddr = (u32)skb->data; | ||
1029 | alignment = Tmpaddr & 0x1ff; | ||
1030 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
1031 | #endif | ||
1032 | |||
1033 | skb_reserve(skb, ieee->tx_headroom); | ||
1034 | |||
1035 | beacon_buf = (struct rtllib_probe_response*) skb_put(skb, (beacon_size - ieee->tx_headroom)); | ||
1036 | memcpy (beacon_buf->header.addr1, dest,ETH_ALEN); | ||
1037 | memcpy (beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
1038 | memcpy (beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); | ||
1039 | |||
1040 | beacon_buf->header.duration_id = 0; | ||
1041 | beacon_buf->beacon_interval = | ||
1042 | cpu_to_le16(ieee->current_network.beacon_interval); | ||
1043 | beacon_buf->capability = | ||
1044 | cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); | ||
1045 | beacon_buf->capability |= | ||
1046 | cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE); | ||
1047 | |||
1048 | if (ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)) | ||
1049 | cpu_to_le16((beacon_buf->capability |= WLAN_CAPABILITY_SHORT_SLOT_TIME)); | ||
1050 | |||
1051 | crypt = ieee->crypt[ieee->tx_keyidx]; | ||
1052 | if (encrypt) | ||
1053 | beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); | ||
1054 | |||
1055 | |||
1056 | beacon_buf->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_PROBE_RESP); | ||
1057 | beacon_buf->info_element[0].id = MFIE_TYPE_SSID; | ||
1058 | beacon_buf->info_element[0].len = ssid_len; | ||
1059 | |||
1060 | tag = (u8*) beacon_buf->info_element[0].data; | ||
1061 | |||
1062 | memcpy(tag, ssid, ssid_len); | ||
1063 | |||
1064 | tag += ssid_len; | ||
1065 | |||
1066 | *(tag++) = MFIE_TYPE_RATES; | ||
1067 | *(tag++) = rate_len-2; | ||
1068 | memcpy(tag,ieee->current_network.rates,rate_len-2); | ||
1069 | tag+=rate_len-2; | ||
1070 | |||
1071 | *(tag++) = MFIE_TYPE_DS_SET; | ||
1072 | *(tag++) = 1; | ||
1073 | *(tag++) = ieee->current_network.channel; | ||
1074 | |||
1075 | if (atim_len){ | ||
1076 | u16 val16; | ||
1077 | *(tag++) = MFIE_TYPE_IBSS_SET; | ||
1078 | *(tag++) = 2; | ||
1079 | val16 = cpu_to_le16(ieee->current_network.atim_window); | ||
1080 | memcpy((u8 *)tag, (u8 *)&val16, 2); | ||
1081 | tag+=2; | ||
1082 | } | ||
1083 | |||
1084 | if (erp_len){ | ||
1085 | *(tag++) = MFIE_TYPE_ERP; | ||
1086 | *(tag++) = 1; | ||
1087 | *(tag++) = erpinfo_content; | ||
1088 | } | ||
1089 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
1090 | if (tmp_ht_cap_len){ | ||
1091 | *(tag++) = MFIE_TYPE_HT_CAP; | ||
1092 | *(tag++) = tmp_ht_cap_len - 2; | ||
1093 | memcpy(tag, tmp_ht_cap_buf, tmp_ht_cap_len - 2); | ||
1094 | tag += tmp_ht_cap_len - 2; | ||
1095 | } | ||
1096 | #endif | ||
1097 | if (rate_ex_len){ | ||
1098 | *(tag++) = MFIE_TYPE_RATES_EX; | ||
1099 | *(tag++) = rate_ex_len-2; | ||
1100 | memcpy(tag,ieee->current_network.rates_ex,rate_ex_len-2); | ||
1101 | tag+=rate_ex_len-2; | ||
1102 | } | ||
1103 | |||
1104 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
1105 | if (tmp_ht_info_len){ | ||
1106 | *(tag++) = MFIE_TYPE_HT_INFO; | ||
1107 | *(tag++) = tmp_ht_info_len - 2; | ||
1108 | memcpy(tag, tmp_ht_info_buf, tmp_ht_info_len -2); | ||
1109 | tag += tmp_ht_info_len - 2; | ||
1110 | } | ||
1111 | #endif | ||
1112 | |||
1113 | if (wpa_ie_len) | ||
1114 | { | ||
1115 | if (ieee->iw_mode == IW_MODE_ADHOC) | ||
1116 | { | ||
1117 | memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); | ||
1118 | } | ||
1119 | memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); | ||
1120 | tag += ieee->wpa_ie_len; | ||
1121 | } | ||
1122 | |||
1123 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
1124 | if (tmp_generic_ie_len) | ||
1125 | { | ||
1126 | (*tag++) = 0xdd; | ||
1127 | (*tag++) = tmp_generic_ie_len - 2; | ||
1128 | memcpy(tag,tmp_generic_ie_buf,tmp_generic_ie_len -2); | ||
1129 | tag += tmp_generic_ie_len -2; | ||
1130 | |||
1131 | } | ||
1132 | #endif | ||
1133 | |||
1134 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
1135 | if (wmm_len) { | ||
1136 | memcpy(tag,wmmie,wmm_len); | ||
1137 | tag += wmm_len; | ||
1138 | } | ||
1139 | #endif | ||
1140 | return skb; | ||
1141 | } | ||
1142 | |||
1143 | struct sk_buff* rtllib_assoc_resp(struct rtllib_device *ieee, u8 *dest) | ||
1144 | { | ||
1145 | struct sk_buff *skb; | ||
1146 | u8* tag; | ||
1147 | |||
1148 | struct rtllib_crypt_data* crypt; | ||
1149 | struct rtllib_assoc_response_frame *assoc; | ||
1150 | short encrypt; | ||
1151 | |||
1152 | unsigned int rate_len = rtllib_MFIE_rate_len(ieee); | ||
1153 | int len = sizeof(struct rtllib_assoc_response_frame) + rate_len + ieee->tx_headroom; | ||
1154 | |||
1155 | #ifdef USB_USE_ALIGNMENT | ||
1156 | u32 Tmpaddr=0; | ||
1157 | int alignment=0; | ||
1158 | skb = dev_alloc_skb(len + USB_512B_ALIGNMENT_SIZE); | ||
1159 | #else | ||
1160 | skb = dev_alloc_skb(len); | ||
1161 | #endif | ||
1162 | |||
1163 | if (!skb) | ||
1164 | return NULL; | ||
1165 | |||
1166 | #ifdef USB_USE_ALIGNMENT | ||
1167 | Tmpaddr = (u32)skb->data; | ||
1168 | alignment = Tmpaddr & 0x1ff; | ||
1169 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
1170 | #endif | ||
1171 | |||
1172 | skb_reserve(skb, ieee->tx_headroom); | ||
1173 | |||
1174 | assoc = (struct rtllib_assoc_response_frame *) | ||
1175 | skb_put(skb,sizeof(struct rtllib_assoc_response_frame)); | ||
1176 | |||
1177 | assoc->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_ASSOC_RESP); | ||
1178 | memcpy(assoc->header.addr1, dest,ETH_ALEN); | ||
1179 | memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); | ||
1180 | memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
1181 | assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? | ||
1182 | WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS); | ||
1183 | |||
1184 | |||
1185 | if (ieee->short_slot) | ||
1186 | assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); | ||
1187 | |||
1188 | if (ieee->host_encrypt) | ||
1189 | crypt = ieee->crypt[ieee->tx_keyidx]; | ||
1190 | else | ||
1191 | crypt = NULL; | ||
1192 | |||
1193 | encrypt = ( crypt && crypt->ops); | ||
1194 | |||
1195 | if (encrypt) | ||
1196 | assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); | ||
1197 | |||
1198 | assoc->status = 0; | ||
1199 | assoc->aid = cpu_to_le16(ieee->assoc_id); | ||
1200 | if (ieee->assoc_id == 0x2007) | ||
1201 | ieee->assoc_id=0; | ||
1202 | else | ||
1203 | ieee->assoc_id++; | ||
1204 | |||
1205 | tag = (u8*) skb_put(skb, rate_len); | ||
1206 | rtllib_MFIE_Brate(ieee, &tag); | ||
1207 | rtllib_MFIE_Grate(ieee, &tag); | ||
1208 | |||
1209 | return skb; | ||
1210 | } | ||
1211 | |||
1212 | struct sk_buff* rtllib_auth_resp(struct rtllib_device *ieee,int status, u8 *dest) | ||
1213 | { | ||
1214 | struct sk_buff *skb = NULL; | ||
1215 | struct rtllib_authentication *auth; | ||
1216 | int len = ieee->tx_headroom + sizeof(struct rtllib_authentication)+1; | ||
1217 | #ifdef USB_USE_ALIGNMENT | ||
1218 | u32 Tmpaddr=0; | ||
1219 | int alignment=0; | ||
1220 | skb = dev_alloc_skb(len + USB_512B_ALIGNMENT_SIZE); | ||
1221 | #else | ||
1222 | skb = dev_alloc_skb(len); | ||
1223 | #endif | ||
1224 | if (!skb) | ||
1225 | return NULL; | ||
1226 | |||
1227 | skb->len = sizeof(struct rtllib_authentication); | ||
1228 | |||
1229 | #ifdef USB_USE_ALIGNMENT | ||
1230 | Tmpaddr = (u32)skb->data; | ||
1231 | alignment = Tmpaddr & 0x1ff; | ||
1232 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
1233 | #endif | ||
1234 | |||
1235 | skb_reserve(skb, ieee->tx_headroom); | ||
1236 | |||
1237 | auth = (struct rtllib_authentication *) | ||
1238 | skb_put(skb, sizeof(struct rtllib_authentication)); | ||
1239 | |||
1240 | auth->status = cpu_to_le16(status); | ||
1241 | auth->transaction = cpu_to_le16(2); | ||
1242 | auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); | ||
1243 | |||
1244 | memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); | ||
1245 | memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
1246 | memcpy(auth->header.addr1, dest, ETH_ALEN); | ||
1247 | auth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_AUTH); | ||
1248 | return skb; | ||
1249 | |||
1250 | |||
1251 | } | ||
1252 | |||
1253 | struct sk_buff* rtllib_null_func(struct rtllib_device *ieee,short pwr) | ||
1254 | { | ||
1255 | struct sk_buff *skb; | ||
1256 | struct rtllib_hdr_3addr* hdr; | ||
1257 | |||
1258 | #ifdef USB_USE_ALIGNMENT | ||
1259 | u32 Tmpaddr=0; | ||
1260 | int alignment=0; | ||
1261 | skb = dev_alloc_skb(sizeof(struct rtllib_hdr_3addr) + ieee->tx_headroom + USB_512B_ALIGNMENT_SIZE); | ||
1262 | #else | ||
1263 | skb = dev_alloc_skb(sizeof(struct rtllib_hdr_3addr)+ieee->tx_headroom); | ||
1264 | #endif | ||
1265 | if (!skb) | ||
1266 | return NULL; | ||
1267 | |||
1268 | #ifdef USB_USE_ALIGNMENT | ||
1269 | Tmpaddr = (u32)skb->data; | ||
1270 | alignment = Tmpaddr & 0x1ff; | ||
1271 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
1272 | #endif | ||
1273 | skb_reserve(skb, ieee->tx_headroom); | ||
1274 | |||
1275 | hdr = (struct rtllib_hdr_3addr*)skb_put(skb,sizeof(struct rtllib_hdr_3addr)); | ||
1276 | |||
1277 | memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); | ||
1278 | memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
1279 | memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); | ||
1280 | |||
1281 | hdr->frame_ctl = cpu_to_le16(RTLLIB_FTYPE_DATA | | ||
1282 | RTLLIB_STYPE_NULLFUNC | RTLLIB_FCTL_TODS | | ||
1283 | (pwr ? RTLLIB_FCTL_PM:0)); | ||
1284 | |||
1285 | return skb; | ||
1286 | |||
1287 | |||
1288 | } | ||
1289 | |||
1290 | struct sk_buff* rtllib_pspoll_func(struct rtllib_device *ieee) | ||
1291 | { | ||
1292 | struct sk_buff *skb; | ||
1293 | struct rtllib_pspoll_hdr* hdr; | ||
1294 | |||
1295 | #ifdef USB_USE_ALIGNMENT | ||
1296 | u32 Tmpaddr=0; | ||
1297 | int alignment=0; | ||
1298 | skb = dev_alloc_skb(sizeof(struct rtllib_pspoll_hdr) + ieee->tx_headroom + USB_512B_ALIGNMENT_SIZE); | ||
1299 | #else | ||
1300 | skb = dev_alloc_skb(sizeof(struct rtllib_pspoll_hdr)+ieee->tx_headroom); | ||
1301 | #endif | ||
1302 | if (!skb) | ||
1303 | return NULL; | ||
1304 | |||
1305 | #ifdef USB_USE_ALIGNMENT | ||
1306 | Tmpaddr = (u32)skb->data; | ||
1307 | alignment = Tmpaddr & 0x1ff; | ||
1308 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
1309 | #endif | ||
1310 | skb_reserve(skb, ieee->tx_headroom); | ||
1311 | |||
1312 | hdr = (struct rtllib_pspoll_hdr*)skb_put(skb,sizeof(struct rtllib_pspoll_hdr)); | ||
1313 | |||
1314 | memcpy(hdr->bssid, ieee->current_network.bssid, ETH_ALEN); | ||
1315 | memcpy(hdr->ta, ieee->dev->dev_addr, ETH_ALEN); | ||
1316 | |||
1317 | hdr->aid = cpu_to_le16(ieee->assoc_id | 0xc000); | ||
1318 | hdr->frame_ctl = cpu_to_le16(RTLLIB_FTYPE_CTL |RTLLIB_STYPE_PSPOLL | RTLLIB_FCTL_PM); | ||
1319 | |||
1320 | return skb; | ||
1321 | |||
1322 | } | ||
1323 | |||
1324 | void rtllib_resp_to_assoc_rq(struct rtllib_device *ieee, u8* dest) | ||
1325 | { | ||
1326 | struct sk_buff *buf = rtllib_assoc_resp(ieee, dest); | ||
1327 | |||
1328 | if (buf) | ||
1329 | softmac_mgmt_xmit(buf, ieee); | ||
1330 | } | ||
1331 | |||
1332 | |||
1333 | void rtllib_resp_to_auth(struct rtllib_device *ieee, int s, u8* dest) | ||
1334 | { | ||
1335 | struct sk_buff *buf = rtllib_auth_resp(ieee, s, dest); | ||
1336 | |||
1337 | if (buf) | ||
1338 | softmac_mgmt_xmit(buf, ieee); | ||
1339 | } | ||
1340 | |||
1341 | |||
1342 | void rtllib_resp_to_probe(struct rtllib_device *ieee, u8 *dest) | ||
1343 | { | ||
1344 | |||
1345 | struct sk_buff *buf = rtllib_probe_resp(ieee, dest); | ||
1346 | if (buf) | ||
1347 | softmac_mgmt_xmit(buf, ieee); | ||
1348 | } | ||
1349 | |||
1350 | |||
1351 | inline int SecIsInPMKIDList(struct rtllib_device *ieee, u8 *bssid) | ||
1352 | { | ||
1353 | int i = 0; | ||
1354 | |||
1355 | do | ||
1356 | { | ||
1357 | if ((ieee->PMKIDList[i].bUsed) && (memcmp(ieee->PMKIDList[i].Bssid, bssid, ETH_ALEN) == 0)) | ||
1358 | { | ||
1359 | break; | ||
1360 | } | ||
1361 | else | ||
1362 | { | ||
1363 | i++; | ||
1364 | } | ||
1365 | } while (i < NUM_PMKID_CACHE); | ||
1366 | |||
1367 | if (i == NUM_PMKID_CACHE) | ||
1368 | { | ||
1369 | i = -1; | ||
1370 | } | ||
1371 | else | ||
1372 | { | ||
1373 | } | ||
1374 | |||
1375 | return (i); | ||
1376 | |||
1377 | } | ||
1378 | |||
1379 | |||
1380 | inline struct sk_buff *rtllib_association_req(struct rtllib_network *beacon,struct rtllib_device *ieee) | ||
1381 | { | ||
1382 | struct sk_buff *skb; | ||
1383 | |||
1384 | struct rtllib_assoc_request_frame *hdr; | ||
1385 | u8 *tag, *ies; | ||
1386 | int i; | ||
1387 | u8* ht_cap_buf = NULL; | ||
1388 | u8 ht_cap_len=0; | ||
1389 | u8* realtek_ie_buf=NULL; | ||
1390 | u8 realtek_ie_len=0; | ||
1391 | int wpa_ie_len= ieee->wpa_ie_len; | ||
1392 | int wps_ie_len = ieee->wps_ie_len; | ||
1393 | unsigned int ckip_ie_len=0; | ||
1394 | unsigned int ccxrm_ie_len=0; | ||
1395 | unsigned int cxvernum_ie_len=0; | ||
1396 | struct rtllib_crypt_data* crypt; | ||
1397 | int encrypt; | ||
1398 | int PMKCacheIdx; | ||
1399 | |||
1400 | unsigned int rate_len = (beacon->rates_len?(beacon->rates_len+2):0) + (beacon->rates_ex_len?(beacon->rates_ex_len)+2:0); | ||
1401 | |||
1402 | unsigned int wmm_info_len = beacon->qos_data.supported?9:0; | ||
1403 | unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; | ||
1404 | |||
1405 | int len = 0; | ||
1406 | crypt = ieee->crypt[ieee->tx_keyidx]; | ||
1407 | if (crypt != NULL) { | ||
1408 | encrypt = ieee->host_encrypt && crypt && crypt->ops && ((0 == strcmp(crypt->ops->name,"WEP") || wpa_ie_len)); | ||
1409 | } else { | ||
1410 | encrypt = 0; | ||
1411 | } | ||
1412 | |||
1413 | #ifdef ENABLE_TKIP11N | ||
1414 | if (ieee->bForcedBgMode == true) | ||
1415 | #else | ||
1416 | if ((ieee->rtllib_ap_sec_type && (ieee->rtllib_ap_sec_type(ieee)&SEC_ALG_TKIP)) ||(ieee->bForcedBgMode == true)) | ||
1417 | #endif | ||
1418 | { | ||
1419 | ieee->pHTInfo->bEnableHT = 0; | ||
1420 | ieee->mode = WIRELESS_MODE_G; | ||
1421 | } | ||
1422 | |||
1423 | if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT) | ||
1424 | { | ||
1425 | ht_cap_buf = (u8*)&(ieee->pHTInfo->SelfHTCap); | ||
1426 | ht_cap_len = sizeof(ieee->pHTInfo->SelfHTCap); | ||
1427 | HTConstructCapabilityElement(ieee, ht_cap_buf, &ht_cap_len, encrypt, true); | ||
1428 | if (ieee->pHTInfo->bCurrentRT2RTAggregation) { | ||
1429 | realtek_ie_buf = ieee->pHTInfo->szRT2RTAggBuffer; | ||
1430 | realtek_ie_len = sizeof( ieee->pHTInfo->szRT2RTAggBuffer); | ||
1431 | HTConstructRT2RTAggElement(ieee, realtek_ie_buf, &realtek_ie_len); | ||
1432 | |||
1433 | } | ||
1434 | } | ||
1435 | |||
1436 | if (beacon->bCkipSupported) | ||
1437 | { | ||
1438 | ckip_ie_len = 30+2; | ||
1439 | } | ||
1440 | if (beacon->bCcxRmEnable) | ||
1441 | { | ||
1442 | ccxrm_ie_len = 6+2; | ||
1443 | } | ||
1444 | if ( beacon->BssCcxVerNumber >= 2 ) | ||
1445 | { | ||
1446 | cxvernum_ie_len = 5+2; | ||
1447 | } | ||
1448 | |||
1449 | PMKCacheIdx = SecIsInPMKIDList(ieee, ieee->current_network.bssid); | ||
1450 | if (PMKCacheIdx >= 0) | ||
1451 | { | ||
1452 | wpa_ie_len += 18; | ||
1453 | printk("[PMK cache]: WPA2 IE length: %x\n", wpa_ie_len); | ||
1454 | } | ||
1455 | len = sizeof(struct rtllib_assoc_request_frame)+ 2 | ||
1456 | + beacon->ssid_len | ||
1457 | + rate_len | ||
1458 | + wpa_ie_len | ||
1459 | + wps_ie_len | ||
1460 | + wmm_info_len | ||
1461 | + turbo_info_len | ||
1462 | + ht_cap_len | ||
1463 | + realtek_ie_len | ||
1464 | + ckip_ie_len | ||
1465 | + ccxrm_ie_len | ||
1466 | + cxvernum_ie_len | ||
1467 | + ieee->tx_headroom; | ||
1468 | |||
1469 | #ifdef USB_USE_ALIGNMENT | ||
1470 | u32 Tmpaddr=0; | ||
1471 | int alignment=0; | ||
1472 | skb = dev_alloc_skb(len + USB_512B_ALIGNMENT_SIZE); | ||
1473 | #else | ||
1474 | skb = dev_alloc_skb(len); | ||
1475 | #endif | ||
1476 | |||
1477 | if (!skb) | ||
1478 | return NULL; | ||
1479 | |||
1480 | #ifdef USB_USE_ALIGNMENT | ||
1481 | Tmpaddr = (u32)skb->data; | ||
1482 | alignment = Tmpaddr & 0x1ff; | ||
1483 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
1484 | #endif | ||
1485 | |||
1486 | skb_reserve(skb, ieee->tx_headroom); | ||
1487 | |||
1488 | hdr = (struct rtllib_assoc_request_frame *) | ||
1489 | skb_put(skb, sizeof(struct rtllib_assoc_request_frame)+2); | ||
1490 | |||
1491 | |||
1492 | hdr->header.frame_ctl = RTLLIB_STYPE_ASSOC_REQ; | ||
1493 | hdr->header.duration_id= 37; | ||
1494 | memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); | ||
1495 | memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
1496 | memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); | ||
1497 | |||
1498 | memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN); | ||
1499 | |||
1500 | hdr->capability = cpu_to_le16(WLAN_CAPABILITY_ESS); | ||
1501 | if (beacon->capability & WLAN_CAPABILITY_PRIVACY ) | ||
1502 | hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); | ||
1503 | |||
1504 | if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) | ||
1505 | hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); | ||
1506 | |||
1507 | if (ieee->short_slot && (beacon->capability&WLAN_CAPABILITY_SHORT_SLOT_TIME)) | ||
1508 | hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); | ||
1509 | |||
1510 | |||
1511 | hdr->listen_interval = beacon->listen_interval; | ||
1512 | |||
1513 | hdr->info_element[0].id = MFIE_TYPE_SSID; | ||
1514 | |||
1515 | hdr->info_element[0].len = beacon->ssid_len; | ||
1516 | tag = skb_put(skb, beacon->ssid_len); | ||
1517 | memcpy(tag, beacon->ssid, beacon->ssid_len); | ||
1518 | |||
1519 | tag = skb_put(skb, rate_len); | ||
1520 | |||
1521 | if (beacon->rates_len){ | ||
1522 | *tag++ = MFIE_TYPE_RATES; | ||
1523 | *tag++ = beacon->rates_len; | ||
1524 | for (i=0;i<beacon->rates_len;i++){ | ||
1525 | *tag++ = beacon->rates[i]; | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | if (beacon->rates_ex_len){ | ||
1530 | *tag++ = MFIE_TYPE_RATES_EX; | ||
1531 | *tag++ = beacon->rates_ex_len; | ||
1532 | for (i=0;i<beacon->rates_ex_len;i++){ | ||
1533 | *tag++ = beacon->rates_ex[i]; | ||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | if ( beacon->bCkipSupported ) | ||
1538 | { | ||
1539 | static u8 AironetIeOui[] = {0x00, 0x01, 0x66}; | ||
1540 | u8 CcxAironetBuf[30]; | ||
1541 | OCTET_STRING osCcxAironetIE; | ||
1542 | |||
1543 | memset(CcxAironetBuf, 0,30); | ||
1544 | osCcxAironetIE.Octet = CcxAironetBuf; | ||
1545 | osCcxAironetIE.Length = sizeof(CcxAironetBuf); | ||
1546 | memcpy(osCcxAironetIE.Octet, AironetIeOui, sizeof(AironetIeOui)); | ||
1547 | |||
1548 | osCcxAironetIE.Octet[IE_CISCO_FLAG_POSITION] |= (SUPPORT_CKIP_PK|SUPPORT_CKIP_MIC) ; | ||
1549 | tag = skb_put(skb, ckip_ie_len); | ||
1550 | *tag++ = MFIE_TYPE_AIRONET; | ||
1551 | *tag++ = osCcxAironetIE.Length; | ||
1552 | memcpy(tag,osCcxAironetIE.Octet,osCcxAironetIE.Length); | ||
1553 | tag += osCcxAironetIE.Length; | ||
1554 | } | ||
1555 | |||
1556 | if (beacon->bCcxRmEnable) | ||
1557 | { | ||
1558 | static u8 CcxRmCapBuf[] = {0x00, 0x40, 0x96, 0x01, 0x01, 0x00}; | ||
1559 | OCTET_STRING osCcxRmCap; | ||
1560 | |||
1561 | osCcxRmCap.Octet = CcxRmCapBuf; | ||
1562 | osCcxRmCap.Length = sizeof(CcxRmCapBuf); | ||
1563 | tag = skb_put(skb,ccxrm_ie_len); | ||
1564 | *tag++ = MFIE_TYPE_GENERIC; | ||
1565 | *tag++ = osCcxRmCap.Length; | ||
1566 | memcpy(tag,osCcxRmCap.Octet,osCcxRmCap.Length); | ||
1567 | tag += osCcxRmCap.Length; | ||
1568 | } | ||
1569 | |||
1570 | if ( beacon->BssCcxVerNumber >= 2 ) | ||
1571 | { | ||
1572 | u8 CcxVerNumBuf[] = {0x00, 0x40, 0x96, 0x03, 0x00}; | ||
1573 | OCTET_STRING osCcxVerNum; | ||
1574 | CcxVerNumBuf[4] = beacon->BssCcxVerNumber; | ||
1575 | osCcxVerNum.Octet = CcxVerNumBuf; | ||
1576 | osCcxVerNum.Length = sizeof(CcxVerNumBuf); | ||
1577 | tag = skb_put(skb,cxvernum_ie_len); | ||
1578 | *tag++ = MFIE_TYPE_GENERIC; | ||
1579 | *tag++ = osCcxVerNum.Length; | ||
1580 | memcpy(tag,osCcxVerNum.Octet,osCcxVerNum.Length); | ||
1581 | tag += osCcxVerNum.Length; | ||
1582 | } | ||
1583 | if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){ | ||
1584 | if (ieee->pHTInfo->ePeerHTSpecVer != HT_SPEC_VER_EWC) | ||
1585 | { | ||
1586 | tag = skb_put(skb, ht_cap_len); | ||
1587 | *tag++ = MFIE_TYPE_HT_CAP; | ||
1588 | *tag++ = ht_cap_len - 2; | ||
1589 | memcpy(tag, ht_cap_buf,ht_cap_len -2); | ||
1590 | tag += ht_cap_len -2; | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | |||
1595 | if (wpa_ie_len){ | ||
1596 | tag = skb_put(skb, ieee->wpa_ie_len); | ||
1597 | memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); | ||
1598 | |||
1599 | if (PMKCacheIdx >= 0) | ||
1600 | { | ||
1601 | tag = skb_put(skb, 18); | ||
1602 | *tag = 1; | ||
1603 | *(tag + 1) = 0; | ||
1604 | memcpy((tag + 2), &ieee->PMKIDList[PMKCacheIdx].PMKID, 16); | ||
1605 | } | ||
1606 | } | ||
1607 | if (wmm_info_len) { | ||
1608 | tag = skb_put(skb,wmm_info_len); | ||
1609 | rtllib_WMM_Info(ieee, &tag); | ||
1610 | } | ||
1611 | |||
1612 | if (wps_ie_len && ieee->wps_ie) { | ||
1613 | tag = skb_put(skb, wps_ie_len); | ||
1614 | memcpy(tag, ieee->wps_ie, wps_ie_len); | ||
1615 | } | ||
1616 | |||
1617 | tag = skb_put(skb,turbo_info_len); | ||
1618 | if (turbo_info_len) | ||
1619 | rtllib_TURBO_Info(ieee, &tag); | ||
1620 | |||
1621 | if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT){ | ||
1622 | if (ieee->pHTInfo->ePeerHTSpecVer == HT_SPEC_VER_EWC) | ||
1623 | { | ||
1624 | tag = skb_put(skb, ht_cap_len); | ||
1625 | *tag++ = MFIE_TYPE_GENERIC; | ||
1626 | *tag++ = ht_cap_len - 2; | ||
1627 | memcpy(tag, ht_cap_buf,ht_cap_len - 2); | ||
1628 | tag += ht_cap_len -2; | ||
1629 | } | ||
1630 | |||
1631 | if (ieee->pHTInfo->bCurrentRT2RTAggregation){ | ||
1632 | tag = skb_put(skb, realtek_ie_len); | ||
1633 | *tag++ = MFIE_TYPE_GENERIC; | ||
1634 | *tag++ = realtek_ie_len - 2; | ||
1635 | memcpy(tag, realtek_ie_buf,realtek_ie_len -2 ); | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | if (ieee->assocreq_ies){ | ||
1640 | kfree(ieee->assocreq_ies); | ||
1641 | ieee->assocreq_ies = NULL; | ||
1642 | } | ||
1643 | ies = &(hdr->info_element[0].id); | ||
1644 | ieee->assocreq_ies_len = (skb->data + skb->len) - ies; | ||
1645 | ieee->assocreq_ies = kmalloc(ieee->assocreq_ies_len, GFP_ATOMIC); | ||
1646 | if (ieee->assocreq_ies) | ||
1647 | memcpy(ieee->assocreq_ies, ies, ieee->assocreq_ies_len); | ||
1648 | else{ | ||
1649 | printk("%s()Warning: can't alloc memory for assocreq_ies\n", __func__); | ||
1650 | ieee->assocreq_ies_len = 0; | ||
1651 | } | ||
1652 | |||
1653 | return skb; | ||
1654 | } | ||
1655 | |||
1656 | void rtllib_associate_abort(struct rtllib_device *ieee) | ||
1657 | { | ||
1658 | |||
1659 | unsigned long flags; | ||
1660 | spin_lock_irqsave(&ieee->lock, flags); | ||
1661 | |||
1662 | ieee->associate_seq++; | ||
1663 | |||
1664 | /* don't scan, and avoid to have the RX path possibily | ||
1665 | * try again to associate. Even do not react to AUTH or | ||
1666 | * ASSOC response. Just wait for the retry wq to be scheduled. | ||
1667 | * Here we will check if there are good nets to associate | ||
1668 | * with, so we retry or just get back to NO_LINK and scanning | ||
1669 | */ | ||
1670 | if (ieee->state == RTLLIB_ASSOCIATING_AUTHENTICATING){ | ||
1671 | RTLLIB_DEBUG_MGMT("Authentication failed\n"); | ||
1672 | ieee->softmac_stats.no_auth_rs++; | ||
1673 | }else{ | ||
1674 | RTLLIB_DEBUG_MGMT("Association failed\n"); | ||
1675 | ieee->softmac_stats.no_ass_rs++; | ||
1676 | } | ||
1677 | |||
1678 | ieee->state = RTLLIB_ASSOCIATING_RETRY; | ||
1679 | |||
1680 | queue_delayed_work_rsl(ieee->wq, &ieee->associate_retry_wq, \ | ||
1681 | RTLLIB_SOFTMAC_ASSOC_RETRY_TIME); | ||
1682 | |||
1683 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
1684 | } | ||
1685 | |||
1686 | void rtllib_associate_abort_cb(unsigned long dev) | ||
1687 | { | ||
1688 | rtllib_associate_abort((struct rtllib_device *) dev); | ||
1689 | } | ||
1690 | |||
1691 | void rtllib_associate_step1(struct rtllib_device *ieee,u8 * daddr) | ||
1692 | { | ||
1693 | struct rtllib_network *beacon = &ieee->current_network; | ||
1694 | struct sk_buff *skb; | ||
1695 | |||
1696 | RTLLIB_DEBUG_MGMT("Stopping scan\n"); | ||
1697 | |||
1698 | ieee->softmac_stats.tx_auth_rq++; | ||
1699 | |||
1700 | skb=rtllib_authentication_req(beacon, ieee, 0,daddr); | ||
1701 | |||
1702 | if (!skb) | ||
1703 | rtllib_associate_abort(ieee); | ||
1704 | else{ | ||
1705 | ieee->state = RTLLIB_ASSOCIATING_AUTHENTICATING ; | ||
1706 | RTLLIB_DEBUG_MGMT("Sending authentication request\n"); | ||
1707 | softmac_mgmt_xmit(skb, ieee); | ||
1708 | if (!timer_pending(&ieee->associate_timer)){ | ||
1709 | ieee->associate_timer.expires = jiffies + (HZ / 2); | ||
1710 | add_timer(&ieee->associate_timer); | ||
1711 | } | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | void rtllib_auth_challenge(struct rtllib_device *ieee, u8 *challenge, int chlen) | ||
1716 | { | ||
1717 | u8 *c; | ||
1718 | struct sk_buff *skb; | ||
1719 | struct rtllib_network *beacon = &ieee->current_network; | ||
1720 | |||
1721 | ieee->associate_seq++; | ||
1722 | ieee->softmac_stats.tx_auth_rq++; | ||
1723 | |||
1724 | skb = rtllib_authentication_req(beacon, ieee, chlen+2,beacon->bssid); | ||
1725 | |||
1726 | if (!skb) | ||
1727 | rtllib_associate_abort(ieee); | ||
1728 | else{ | ||
1729 | c = skb_put(skb, chlen+2); | ||
1730 | *(c++) = MFIE_TYPE_CHALLENGE; | ||
1731 | *(c++) = chlen; | ||
1732 | memcpy(c, challenge, chlen); | ||
1733 | |||
1734 | RTLLIB_DEBUG_MGMT("Sending authentication challenge response\n"); | ||
1735 | |||
1736 | rtllib_encrypt_fragment(ieee, skb, sizeof(struct rtllib_hdr_3addr )); | ||
1737 | |||
1738 | softmac_mgmt_xmit(skb, ieee); | ||
1739 | mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); | ||
1740 | } | ||
1741 | kfree(challenge); | ||
1742 | } | ||
1743 | |||
1744 | void rtllib_associate_step2(struct rtllib_device *ieee) | ||
1745 | { | ||
1746 | struct sk_buff* skb; | ||
1747 | struct rtllib_network *beacon = &ieee->current_network; | ||
1748 | |||
1749 | del_timer_sync(&ieee->associate_timer); | ||
1750 | |||
1751 | RTLLIB_DEBUG_MGMT("Sending association request\n"); | ||
1752 | |||
1753 | ieee->softmac_stats.tx_ass_rq++; | ||
1754 | skb=rtllib_association_req(beacon, ieee); | ||
1755 | if (!skb) | ||
1756 | rtllib_associate_abort(ieee); | ||
1757 | else{ | ||
1758 | softmac_mgmt_xmit(skb, ieee); | ||
1759 | mod_timer(&ieee->associate_timer, jiffies + (HZ/2)); | ||
1760 | } | ||
1761 | } | ||
1762 | |||
1763 | #define CANCELLED 2 | ||
1764 | void rtllib_associate_complete_wq(void *data) | ||
1765 | { | ||
1766 | struct rtllib_device *ieee = (struct rtllib_device *)container_of_work_rsl(data, struct rtllib_device, associate_complete_wq); | ||
1767 | PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(ieee->PowerSaveControl)); | ||
1768 | printk(KERN_INFO "Associated successfully\n"); | ||
1769 | if (ieee->is_silent_reset == 0){ | ||
1770 | printk("normal associate\n"); | ||
1771 | notify_wx_assoc_event(ieee); | ||
1772 | } | ||
1773 | |||
1774 | netif_carrier_on(ieee->dev); | ||
1775 | ieee->is_roaming = false; | ||
1776 | if (rtllib_is_54g(&ieee->current_network) && | ||
1777 | (ieee->modulation & RTLLIB_OFDM_MODULATION)){ | ||
1778 | |||
1779 | ieee->rate = 108; | ||
1780 | printk(KERN_INFO"Using G rates:%d\n", ieee->rate); | ||
1781 | }else{ | ||
1782 | ieee->rate = 22; | ||
1783 | ieee->SetWirelessMode(ieee->dev, IEEE_B); | ||
1784 | printk(KERN_INFO"Using B rates:%d\n", ieee->rate); | ||
1785 | } | ||
1786 | if (ieee->pHTInfo->bCurrentHTSupport&&ieee->pHTInfo->bEnableHT) | ||
1787 | { | ||
1788 | printk("Successfully associated, ht enabled\n"); | ||
1789 | HTOnAssocRsp(ieee); | ||
1790 | } else { | ||
1791 | printk("Successfully associated, ht not enabled(%d, %d)\n", | ||
1792 | ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bEnableHT); | ||
1793 | memset(ieee->dot11HTOperationalRateSet, 0, 16); | ||
1794 | } | ||
1795 | ieee->LinkDetectInfo.SlotNum = 2 * (1 + ieee->current_network.beacon_interval/500); | ||
1796 | if (ieee->LinkDetectInfo.NumRecvBcnInPeriod==0||ieee->LinkDetectInfo.NumRecvDataInPeriod==0 ) | ||
1797 | { | ||
1798 | ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1; | ||
1799 | ieee->LinkDetectInfo.NumRecvDataInPeriod= 1; | ||
1800 | } | ||
1801 | pPSC->LpsIdleCount = 0; | ||
1802 | ieee->link_change(ieee->dev); | ||
1803 | |||
1804 | if (ieee->is_silent_reset == 1) { | ||
1805 | printk("silent reset associate\n"); | ||
1806 | ieee->is_silent_reset = 0; | ||
1807 | } | ||
1808 | |||
1809 | if (ieee->data_hard_resume) | ||
1810 | ieee->data_hard_resume(ieee->dev); | ||
1811 | |||
1812 | #ifdef RTK_DMP_PLATFORM | ||
1813 | kobject_hotplug(&ieee->dev->class_dev.kobj, KOBJ_LINKUP); | ||
1814 | #endif | ||
1815 | } | ||
1816 | |||
1817 | static void rtllib_sta_send_associnfo(struct rtllib_device *ieee) | ||
1818 | { | ||
1819 | char *buf; | ||
1820 | size_t len; | ||
1821 | int i; | ||
1822 | union iwreq_data wrqu; | ||
1823 | |||
1824 | return; | ||
1825 | |||
1826 | |||
1827 | buf = kmalloc(50 + 2 * (ieee->assocreq_ies_len + ieee->assocresp_ies_len), GFP_ATOMIC); | ||
1828 | if (!buf) | ||
1829 | return; | ||
1830 | |||
1831 | len = sprintf(buf, "ASSOCINFO("); | ||
1832 | if (ieee->assocreq_ies) { | ||
1833 | len += sprintf(buf + len, "ReqIEs="); | ||
1834 | for (i = 0; i < ieee->assocreq_ies_len; i++) { | ||
1835 | len += sprintf(buf + len, "%02x", ieee->assocreq_ies[i]); | ||
1836 | } | ||
1837 | } | ||
1838 | if (ieee->assocresp_ies) { | ||
1839 | if (ieee->assocreq_ies) | ||
1840 | len += sprintf(buf + len, " "); | ||
1841 | len += sprintf(buf + len, "RespIEs="); | ||
1842 | for (i = 0; i < ieee->assocresp_ies_len; i++) { | ||
1843 | len += sprintf(buf + len, "%02x", ieee->assocresp_ies[i]); | ||
1844 | } | ||
1845 | } | ||
1846 | len += sprintf(buf + len, ")"); | ||
1847 | |||
1848 | if (len > IW_CUSTOM_MAX) { | ||
1849 | len = sprintf(buf, "ASSOCRESPIE="); | ||
1850 | for (i = 0; i < ieee->assocresp_ies_len; i++) { | ||
1851 | len += sprintf(buf + len, "%02x", ieee->assocresp_ies[i]); | ||
1852 | } | ||
1853 | } | ||
1854 | |||
1855 | if (len <= IW_CUSTOM_MAX) { | ||
1856 | memset(&wrqu, 0, sizeof(wrqu)); | ||
1857 | wrqu.data.length = len; | ||
1858 | wireless_send_event(ieee->dev, IWEVCUSTOM, &wrqu, buf); | ||
1859 | } | ||
1860 | |||
1861 | kfree(buf); | ||
1862 | } | ||
1863 | |||
1864 | void rtllib_associate_complete(struct rtllib_device *ieee) | ||
1865 | { | ||
1866 | del_timer_sync(&ieee->associate_timer); | ||
1867 | |||
1868 | ieee->state = RTLLIB_LINKED; | ||
1869 | rtllib_sta_send_associnfo(ieee); | ||
1870 | |||
1871 | queue_work_rsl(ieee->wq, &ieee->associate_complete_wq); | ||
1872 | } | ||
1873 | |||
1874 | void rtllib_associate_procedure_wq(void *data) | ||
1875 | { | ||
1876 | struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, associate_procedure_wq); | ||
1877 | rtllib_stop_scan_syncro(ieee); | ||
1878 | if (ieee->rtllib_ips_leave != NULL) | ||
1879 | ieee->rtllib_ips_leave(ieee->dev); | ||
1880 | down(&ieee->wx_sem); | ||
1881 | |||
1882 | if (ieee->data_hard_stop) | ||
1883 | ieee->data_hard_stop(ieee->dev); | ||
1884 | |||
1885 | rtllib_stop_scan(ieee); | ||
1886 | RT_TRACE(COMP_DBG, "===>%s(), chan:%d\n", __func__, ieee->current_network.channel); | ||
1887 | HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); | ||
1888 | if (ieee->eRFPowerState == eRfOff) | ||
1889 | { | ||
1890 | RT_TRACE(COMP_DBG, "=============>%s():Rf state is eRfOff, schedule ipsleave wq again,return\n",__func__); | ||
1891 | if (ieee->rtllib_ips_leave_wq != NULL) | ||
1892 | ieee->rtllib_ips_leave_wq(ieee->dev); | ||
1893 | up(&ieee->wx_sem); | ||
1894 | return; | ||
1895 | } | ||
1896 | ieee->associate_seq = 1; | ||
1897 | |||
1898 | rtllib_associate_step1(ieee, ieee->current_network.bssid); | ||
1899 | |||
1900 | up(&ieee->wx_sem); | ||
1901 | } | ||
1902 | |||
1903 | inline void rtllib_softmac_new_net(struct rtllib_device *ieee, struct rtllib_network *net) | ||
1904 | { | ||
1905 | u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; | ||
1906 | int tmp_ssid_len = 0; | ||
1907 | |||
1908 | short apset,ssidset,ssidbroad,apmatch,ssidmatch; | ||
1909 | |||
1910 | /* we are interested in new new only if we are not associated | ||
1911 | * and we are not associating / authenticating | ||
1912 | */ | ||
1913 | if (ieee->state != RTLLIB_NOLINK) | ||
1914 | return; | ||
1915 | |||
1916 | if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_ESS)) | ||
1917 | return; | ||
1918 | |||
1919 | if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) | ||
1920 | return; | ||
1921 | |||
1922 | if ((ieee->iw_mode == IW_MODE_ADHOC) && (net->channel > ieee->ibss_maxjoin_chal)) { | ||
1923 | return; | ||
1924 | } | ||
1925 | if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) | ||
1926 | { | ||
1927 | /* if the user specified the AP MAC, we need also the essid | ||
1928 | * This could be obtained by beacons or, if the network does not | ||
1929 | * broadcast it, it can be put manually. | ||
1930 | */ | ||
1931 | apset = ieee->wap_set; | ||
1932 | ssidset = ieee->ssid_set; | ||
1933 | ssidbroad = !(net->ssid_len == 0 || net->ssid[0]== '\0'); | ||
1934 | apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN)==0); | ||
1935 | if (!ssidbroad){ | ||
1936 | ssidmatch = (ieee->current_network.ssid_len == net->hidden_ssid_len)&&\ | ||
1937 | (!strncmp(ieee->current_network.ssid, net->hidden_ssid, net->hidden_ssid_len)); | ||
1938 | if (net->hidden_ssid_len > 0) | ||
1939 | { | ||
1940 | strncpy(net->ssid, net->hidden_ssid, net->hidden_ssid_len); | ||
1941 | net->ssid_len = net->hidden_ssid_len; | ||
1942 | ssidbroad = 1; | ||
1943 | } | ||
1944 | } | ||
1945 | else | ||
1946 | ssidmatch = (ieee->current_network.ssid_len == net->ssid_len)&&\ | ||
1947 | (!strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); | ||
1948 | |||
1949 | if ( /* if the user set the AP check if match. | ||
1950 | * if the network does not broadcast essid we check the user supplyed ANY essid | ||
1951 | * if the network does broadcast and the user does not set essid it is OK | ||
1952 | * if the network does broadcast and the user did set essid chech if essid match | ||
1953 | */ | ||
1954 | ( apset && apmatch && | ||
1955 | ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) | ||
1956 | /* if the ap is not set, check that the user set the bssid | ||
1957 | * and the network does bradcast and that those two bssid matches | ||
1958 | */ | ||
1959 | || (!apset && ssidset && ssidbroad && ssidmatch) || (ieee->is_roaming && ssidset && ssidbroad && ssidmatch) | ||
1960 | ){ | ||
1961 | /* if the essid is hidden replace it with the | ||
1962 | * essid provided by the user. | ||
1963 | */ | ||
1964 | if (!ssidbroad){ | ||
1965 | strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); | ||
1966 | tmp_ssid_len = ieee->current_network.ssid_len; | ||
1967 | } | ||
1968 | memcpy(&ieee->current_network, net, sizeof(struct rtllib_network)); | ||
1969 | if (!ssidbroad){ | ||
1970 | strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); | ||
1971 | ieee->current_network.ssid_len = tmp_ssid_len; | ||
1972 | } | ||
1973 | printk(KERN_INFO"Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d, mode:%x cur_net.flags:0x%x\n",ieee->current_network.ssid,ieee->current_network.channel, ieee->current_network.qos_data.supported, ieee->pHTInfo->bEnableHT, ieee->current_network.bssht.bdSupportHT, ieee->current_network.mode, ieee->current_network.flags); | ||
1974 | |||
1975 | if ((rtllib_act_scanning(ieee, false)) && !(ieee->softmac_features & IEEE_SOFTMAC_SCAN)){ | ||
1976 | rtllib_stop_scan_syncro(ieee); | ||
1977 | } | ||
1978 | |||
1979 | ieee->hwscan_ch_bk = ieee->current_network.channel; | ||
1980 | HTResetIOTSetting(ieee->pHTInfo); | ||
1981 | ieee->wmm_acm = 0; | ||
1982 | if (ieee->iw_mode == IW_MODE_INFRA) { | ||
1983 | /* Join the network for the first time */ | ||
1984 | ieee->AsocRetryCount = 0; | ||
1985 | if ((ieee->current_network.qos_data.supported == 1) && | ||
1986 | ieee->current_network.bssht.bdSupportHT) | ||
1987 | HTResetSelfAndSavePeerSetting(ieee, &(ieee->current_network)); | ||
1988 | else | ||
1989 | ieee->pHTInfo->bCurrentHTSupport = false; | ||
1990 | |||
1991 | ieee->state = RTLLIB_ASSOCIATING; | ||
1992 | if (ieee->LedControlHandler != NULL) | ||
1993 | ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK); | ||
1994 | queue_delayed_work_rsl(ieee->wq, &ieee->associate_procedure_wq, 0); | ||
1995 | } else { | ||
1996 | if (rtllib_is_54g(&ieee->current_network) && | ||
1997 | (ieee->modulation & RTLLIB_OFDM_MODULATION)){ | ||
1998 | ieee->rate = 108; | ||
1999 | ieee->SetWirelessMode(ieee->dev, IEEE_G); | ||
2000 | printk(KERN_INFO"Using G rates\n"); | ||
2001 | }else{ | ||
2002 | ieee->rate = 22; | ||
2003 | ieee->SetWirelessMode(ieee->dev, IEEE_B); | ||
2004 | printk(KERN_INFO"Using B rates\n"); | ||
2005 | } | ||
2006 | memset(ieee->dot11HTOperationalRateSet, 0, 16); | ||
2007 | ieee->state = RTLLIB_LINKED; | ||
2008 | } | ||
2009 | |||
2010 | } | ||
2011 | } | ||
2012 | |||
2013 | } | ||
2014 | |||
2015 | void rtllib_softmac_check_all_nets(struct rtllib_device *ieee) | ||
2016 | { | ||
2017 | unsigned long flags; | ||
2018 | struct rtllib_network *target; | ||
2019 | |||
2020 | spin_lock_irqsave(&ieee->lock, flags); | ||
2021 | |||
2022 | list_for_each_entry(target, &ieee->network_list, list) { | ||
2023 | |||
2024 | /* if the state become different that NOLINK means | ||
2025 | * we had found what we are searching for | ||
2026 | */ | ||
2027 | |||
2028 | if (ieee->state != RTLLIB_NOLINK) | ||
2029 | break; | ||
2030 | |||
2031 | if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) | ||
2032 | rtllib_softmac_new_net(ieee, target); | ||
2033 | } | ||
2034 | |||
2035 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
2036 | |||
2037 | } | ||
2038 | |||
2039 | |||
2040 | static inline u16 auth_parse(struct sk_buff *skb, u8** challenge, int *chlen) | ||
2041 | { | ||
2042 | struct rtllib_authentication *a; | ||
2043 | u8 *t; | ||
2044 | if (skb->len < (sizeof(struct rtllib_authentication)-sizeof(struct rtllib_info_element))){ | ||
2045 | RTLLIB_DEBUG_MGMT("invalid len in auth resp: %d\n",skb->len); | ||
2046 | return 0xcafe; | ||
2047 | } | ||
2048 | *challenge = NULL; | ||
2049 | a = (struct rtllib_authentication*) skb->data; | ||
2050 | if (skb->len > (sizeof(struct rtllib_authentication) +3)){ | ||
2051 | t = skb->data + sizeof(struct rtllib_authentication); | ||
2052 | |||
2053 | if (*(t++) == MFIE_TYPE_CHALLENGE){ | ||
2054 | *chlen = *(t++); | ||
2055 | *challenge = (u8*)kmalloc(*chlen, GFP_ATOMIC); | ||
2056 | memcpy(*challenge, t, *chlen); | ||
2057 | } | ||
2058 | } | ||
2059 | |||
2060 | return cpu_to_le16(a->status); | ||
2061 | |||
2062 | } | ||
2063 | |||
2064 | |||
2065 | int auth_rq_parse(struct sk_buff *skb,u8* dest) | ||
2066 | { | ||
2067 | struct rtllib_authentication *a; | ||
2068 | |||
2069 | if (skb->len < (sizeof(struct rtllib_authentication)-sizeof(struct rtllib_info_element))){ | ||
2070 | RTLLIB_DEBUG_MGMT("invalid len in auth request: %d\n",skb->len); | ||
2071 | return -1; | ||
2072 | } | ||
2073 | a = (struct rtllib_authentication*) skb->data; | ||
2074 | |||
2075 | memcpy(dest,a->header.addr2, ETH_ALEN); | ||
2076 | |||
2077 | if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) | ||
2078 | return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; | ||
2079 | |||
2080 | return WLAN_STATUS_SUCCESS; | ||
2081 | } | ||
2082 | |||
2083 | static short probe_rq_parse(struct rtllib_device *ieee, struct sk_buff *skb, u8 *src) | ||
2084 | { | ||
2085 | u8 *tag; | ||
2086 | u8 *skbend; | ||
2087 | u8 *ssid=NULL; | ||
2088 | u8 ssidlen = 0; | ||
2089 | |||
2090 | struct rtllib_hdr_3addr *header = | ||
2091 | (struct rtllib_hdr_3addr *) skb->data; | ||
2092 | |||
2093 | if (skb->len < sizeof (struct rtllib_hdr_3addr )) | ||
2094 | return -1; /* corrupted */ | ||
2095 | if ((memcmp(header->addr3,ieee->current_network.bssid,ETH_ALEN) != 0)&& | ||
2096 | (memcmp(header->addr3,"\xff\xff\xff\xff\xff\xff",ETH_ALEN) != 0)) { | ||
2097 | return -1; | ||
2098 | } | ||
2099 | |||
2100 | if (memcmp(header->addr3,ieee->current_network.bssid,ETH_ALEN) == 0) { | ||
2101 | } | ||
2102 | |||
2103 | if (memcmp(header->addr3,"\xff\xff\xff\xff\xff\xff",ETH_ALEN) == 0) { | ||
2104 | } | ||
2105 | memcpy(src,header->addr2, ETH_ALEN); | ||
2106 | |||
2107 | skbend = (u8*)skb->data + skb->len; | ||
2108 | |||
2109 | tag = skb->data + sizeof (struct rtllib_hdr_3addr ); | ||
2110 | |||
2111 | while (tag+1 < skbend){ | ||
2112 | if (*tag == 0){ | ||
2113 | ssid = tag+2; | ||
2114 | ssidlen = *(tag+1); | ||
2115 | break; | ||
2116 | } | ||
2117 | tag++; /* point to the len field */ | ||
2118 | tag = tag + *(tag); /* point to the last data byte of the tag */ | ||
2119 | tag++; /* point to the next tag */ | ||
2120 | } | ||
2121 | |||
2122 | if (ssidlen == 0) return 1; | ||
2123 | |||
2124 | if (!ssid) return 1; /* ssid not found in tagged param */ | ||
2125 | return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); | ||
2126 | |||
2127 | } | ||
2128 | |||
2129 | int assoc_rq_parse(struct sk_buff *skb,u8* dest) | ||
2130 | { | ||
2131 | struct rtllib_assoc_request_frame *a; | ||
2132 | |||
2133 | if (skb->len < (sizeof(struct rtllib_assoc_request_frame) - | ||
2134 | sizeof(struct rtllib_info_element))) { | ||
2135 | |||
2136 | RTLLIB_DEBUG_MGMT("invalid len in auth request:%d \n", skb->len); | ||
2137 | return -1; | ||
2138 | } | ||
2139 | |||
2140 | a = (struct rtllib_assoc_request_frame*) skb->data; | ||
2141 | |||
2142 | memcpy(dest,a->header.addr2,ETH_ALEN); | ||
2143 | |||
2144 | return 0; | ||
2145 | } | ||
2146 | |||
2147 | static inline u16 assoc_parse(struct rtllib_device *ieee, struct sk_buff *skb, int *aid) | ||
2148 | { | ||
2149 | struct rtllib_assoc_response_frame *response_head; | ||
2150 | u16 status_code; | ||
2151 | |||
2152 | if (skb->len < sizeof(struct rtllib_assoc_response_frame)){ | ||
2153 | RTLLIB_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); | ||
2154 | return 0xcafe; | ||
2155 | } | ||
2156 | |||
2157 | response_head = (struct rtllib_assoc_response_frame*) skb->data; | ||
2158 | *aid = le16_to_cpu(response_head->aid) & 0x3fff; | ||
2159 | |||
2160 | status_code = le16_to_cpu(response_head->status); | ||
2161 | if ((status_code==WLAN_STATUS_ASSOC_DENIED_RATES || \ | ||
2162 | status_code==WLAN_STATUS_CAPS_UNSUPPORTED)&& | ||
2163 | ((ieee->mode == IEEE_G) && | ||
2164 | (ieee->current_network.mode == IEEE_N_24G) && | ||
2165 | (ieee->AsocRetryCount++ < (RT_ASOC_RETRY_LIMIT-1)))) { | ||
2166 | ieee->pHTInfo->IOTAction |= HT_IOT_ACT_PURE_N_MODE; | ||
2167 | }else { | ||
2168 | ieee->AsocRetryCount = 0; | ||
2169 | } | ||
2170 | |||
2171 | return le16_to_cpu(response_head->status); | ||
2172 | } | ||
2173 | |||
2174 | void rtllib_rx_probe_rq(struct rtllib_device *ieee, struct sk_buff *skb) | ||
2175 | { | ||
2176 | u8 dest[ETH_ALEN]; | ||
2177 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
2178 | struct sta_info *psta = NULL; | ||
2179 | #endif | ||
2180 | ieee->softmac_stats.rx_probe_rq++; | ||
2181 | if (probe_rq_parse(ieee, skb, dest) > 0){ | ||
2182 | ieee->softmac_stats.tx_probe_rs++; | ||
2183 | rtllib_resp_to_probe(ieee, dest); | ||
2184 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
2185 | if (ieee->iw_mode == IW_MODE_ADHOC){ | ||
2186 | psta = GetStaInfo(ieee, dest); | ||
2187 | if (NULL != psta) | ||
2188 | psta->LastActiveTime = jiffies; | ||
2189 | } | ||
2190 | #endif | ||
2191 | } | ||
2192 | } | ||
2193 | |||
2194 | static inline void rtllib_rx_auth_rq(struct rtllib_device *ieee, struct sk_buff *skb) | ||
2195 | { | ||
2196 | u8 dest[ETH_ALEN]; | ||
2197 | int status; | ||
2198 | ieee->softmac_stats.rx_auth_rq++; | ||
2199 | |||
2200 | if ((status = auth_rq_parse(skb, dest))!= -1){ | ||
2201 | rtllib_resp_to_auth(ieee, status, dest); | ||
2202 | } | ||
2203 | |||
2204 | } | ||
2205 | |||
2206 | static inline void rtllib_rx_assoc_rq(struct rtllib_device *ieee, struct sk_buff *skb) | ||
2207 | { | ||
2208 | |||
2209 | u8 dest[ETH_ALEN]; | ||
2210 | |||
2211 | ieee->softmac_stats.rx_ass_rq++; | ||
2212 | if (assoc_rq_parse(skb,dest) != -1){ | ||
2213 | rtllib_resp_to_assoc_rq(ieee, dest); | ||
2214 | } | ||
2215 | |||
2216 | printk(KERN_INFO"New client associated: "MAC_FMT"\n", MAC_ARG(dest)); | ||
2217 | } | ||
2218 | |||
2219 | |||
2220 | void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr) | ||
2221 | { | ||
2222 | |||
2223 | struct sk_buff *buf = rtllib_null_func(ieee, pwr); | ||
2224 | |||
2225 | if (buf) | ||
2226 | softmac_ps_mgmt_xmit(buf, ieee); | ||
2227 | |||
2228 | } | ||
2229 | |||
2230 | void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee) | ||
2231 | { | ||
2232 | |||
2233 | struct sk_buff *buf = rtllib_pspoll_func(ieee); | ||
2234 | |||
2235 | if (buf) | ||
2236 | softmac_ps_mgmt_xmit(buf, ieee); | ||
2237 | |||
2238 | } | ||
2239 | |||
2240 | short rtllib_sta_ps_sleep(struct rtllib_device *ieee, u32 *time_h, u32 *time_l) | ||
2241 | { | ||
2242 | int timeout = ieee->ps_timeout; | ||
2243 | u8 dtim; | ||
2244 | PRT_POWER_SAVE_CONTROL pPSC = (PRT_POWER_SAVE_CONTROL)(&(ieee->PowerSaveControl)); | ||
2245 | /*if (ieee->ps == RTLLIB_PS_DISABLED || | ||
2246 | ieee->iw_mode != IW_MODE_INFRA || | ||
2247 | ieee->state != RTLLIB_LINKED) | ||
2248 | |||
2249 | return 0; | ||
2250 | */ | ||
2251 | |||
2252 | if (ieee->LPSDelayCnt) | ||
2253 | { | ||
2254 | ieee->LPSDelayCnt --; | ||
2255 | return 0; | ||
2256 | } | ||
2257 | |||
2258 | dtim = ieee->current_network.dtim_data; | ||
2259 | if (!(dtim & RTLLIB_DTIM_VALID)) | ||
2260 | return 0; | ||
2261 | timeout = ieee->current_network.beacon_interval; | ||
2262 | ieee->current_network.dtim_data = RTLLIB_DTIM_INVALID; | ||
2263 | /* there's no need to nofity AP that I find you buffered with broadcast packet */ | ||
2264 | if (dtim & (RTLLIB_DTIM_UCAST & ieee->ps)) | ||
2265 | return 2; | ||
2266 | |||
2267 | if (!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))){ | ||
2268 | return 0; | ||
2269 | } | ||
2270 | if (!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))){ | ||
2271 | return 0; | ||
2272 | } | ||
2273 | if ((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE ) && | ||
2274 | (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) | ||
2275 | return 0; | ||
2276 | |||
2277 | if (time_l){ | ||
2278 | if (ieee->bAwakePktSent == true) { | ||
2279 | pPSC->LPSAwakeIntvl = 1; | ||
2280 | } else { | ||
2281 | u8 MaxPeriod = 1; | ||
2282 | |||
2283 | if (pPSC->LPSAwakeIntvl == 0) | ||
2284 | pPSC->LPSAwakeIntvl = 1; | ||
2285 | if (pPSC->RegMaxLPSAwakeIntvl == 0) | ||
2286 | MaxPeriod = 1; | ||
2287 | else if (pPSC->RegMaxLPSAwakeIntvl == 0xFF) | ||
2288 | MaxPeriod = ieee->current_network.dtim_period; | ||
2289 | else | ||
2290 | MaxPeriod = pPSC->RegMaxLPSAwakeIntvl; | ||
2291 | pPSC->LPSAwakeIntvl = (pPSC->LPSAwakeIntvl >= MaxPeriod) ? MaxPeriod : (pPSC->LPSAwakeIntvl + 1); | ||
2292 | } | ||
2293 | { | ||
2294 | u8 LPSAwakeIntvl_tmp = 0; | ||
2295 | u8 period = ieee->current_network.dtim_period; | ||
2296 | u8 count = ieee->current_network.tim.tim_count; | ||
2297 | if (count == 0 ) { | ||
2298 | if (pPSC->LPSAwakeIntvl > period) | ||
2299 | LPSAwakeIntvl_tmp = period + (pPSC->LPSAwakeIntvl - period) -((pPSC->LPSAwakeIntvl-period)%period); | ||
2300 | else | ||
2301 | LPSAwakeIntvl_tmp = pPSC->LPSAwakeIntvl; | ||
2302 | |||
2303 | } else { | ||
2304 | if (pPSC->LPSAwakeIntvl > ieee->current_network.tim.tim_count) | ||
2305 | LPSAwakeIntvl_tmp = count + (pPSC->LPSAwakeIntvl - count) -((pPSC->LPSAwakeIntvl-count)%period); | ||
2306 | else | ||
2307 | LPSAwakeIntvl_tmp = pPSC->LPSAwakeIntvl; | ||
2308 | } | ||
2309 | |||
2310 | *time_l = ieee->current_network.last_dtim_sta_time[0] | ||
2311 | + MSECS(ieee->current_network.beacon_interval * LPSAwakeIntvl_tmp); | ||
2312 | } | ||
2313 | } | ||
2314 | |||
2315 | if (time_h) { | ||
2316 | *time_h = ieee->current_network.last_dtim_sta_time[1]; | ||
2317 | if (time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) | ||
2318 | *time_h += 1; | ||
2319 | } | ||
2320 | |||
2321 | return 1; | ||
2322 | |||
2323 | |||
2324 | } | ||
2325 | |||
2326 | inline void rtllib_sta_ps(struct rtllib_device *ieee) | ||
2327 | { | ||
2328 | |||
2329 | u32 th,tl; | ||
2330 | short sleep; | ||
2331 | |||
2332 | unsigned long flags,flags2; | ||
2333 | |||
2334 | spin_lock_irqsave(&ieee->lock, flags); | ||
2335 | |||
2336 | if ((ieee->ps == RTLLIB_PS_DISABLED || | ||
2337 | ieee->iw_mode != IW_MODE_INFRA || | ||
2338 | ieee->state != RTLLIB_LINKED)){ | ||
2339 | |||
2340 | RT_TRACE(COMP_DBG, "=====>%s(): no need to ps,wake up!! ieee->ps is %d,ieee->iw_mode is %d,ieee->state is %d\n", | ||
2341 | __func__,ieee->ps,ieee->iw_mode,ieee->state); | ||
2342 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); | ||
2343 | |||
2344 | rtllib_sta_wakeup(ieee, 1); | ||
2345 | |||
2346 | spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); | ||
2347 | } | ||
2348 | |||
2349 | sleep = rtllib_sta_ps_sleep(ieee,&th, &tl); | ||
2350 | /* 2 wake, 1 sleep, 0 do nothing */ | ||
2351 | if (sleep == 0) | ||
2352 | { | ||
2353 | goto out; | ||
2354 | } | ||
2355 | if (sleep == 1){ | ||
2356 | if (ieee->sta_sleep == LPS_IS_SLEEP){ | ||
2357 | ieee->enter_sleep_state(ieee->dev,th,tl); | ||
2358 | } | ||
2359 | |||
2360 | else if (ieee->sta_sleep == LPS_IS_WAKE){ | ||
2361 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); | ||
2362 | |||
2363 | if (ieee->ps_is_queue_empty(ieee->dev)){ | ||
2364 | ieee->sta_sleep = LPS_WAIT_NULL_DATA_SEND; | ||
2365 | ieee->ack_tx_to_ieee = 1; | ||
2366 | rtllib_sta_ps_send_null_frame(ieee,1); | ||
2367 | ieee->ps_th = th; | ||
2368 | ieee->ps_tl = tl; | ||
2369 | } | ||
2370 | spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); | ||
2371 | |||
2372 | } | ||
2373 | |||
2374 | ieee->bAwakePktSent = false; | ||
2375 | |||
2376 | }else if (sleep == 2){ | ||
2377 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); | ||
2378 | |||
2379 | rtllib_sta_wakeup(ieee,1); | ||
2380 | |||
2381 | spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); | ||
2382 | } | ||
2383 | |||
2384 | out: | ||
2385 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
2386 | |||
2387 | } | ||
2388 | |||
2389 | void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl) | ||
2390 | { | ||
2391 | if (ieee->sta_sleep == LPS_IS_WAKE){ | ||
2392 | if (nl){ | ||
2393 | if (ieee->pHTInfo->IOTAction & HT_IOT_ACT_NULL_DATA_POWER_SAVING) | ||
2394 | { | ||
2395 | ieee->ack_tx_to_ieee = 1; | ||
2396 | rtllib_sta_ps_send_null_frame(ieee, 0); | ||
2397 | } | ||
2398 | else | ||
2399 | { | ||
2400 | ieee->ack_tx_to_ieee = 1; | ||
2401 | rtllib_sta_ps_send_pspoll_frame(ieee); | ||
2402 | } | ||
2403 | } | ||
2404 | return; | ||
2405 | |||
2406 | } | ||
2407 | |||
2408 | if (ieee->sta_sleep == LPS_IS_SLEEP) | ||
2409 | ieee->sta_wake_up(ieee->dev); | ||
2410 | if (nl){ | ||
2411 | /* | ||
2412 | ieee->ack_tx_to_ieee = 1; | ||
2413 | printk("%s(3): notify AP we are awaked ++++++++++ SendNullFunctionData\n", __func__); | ||
2414 | rtllib_sta_ps_send_null_frame(ieee, 0); | ||
2415 | */ | ||
2416 | if (ieee->pHTInfo->IOTAction & HT_IOT_ACT_NULL_DATA_POWER_SAVING) | ||
2417 | { | ||
2418 | ieee->ack_tx_to_ieee = 1; | ||
2419 | rtllib_sta_ps_send_null_frame(ieee, 0); | ||
2420 | } | ||
2421 | else | ||
2422 | { | ||
2423 | ieee->ack_tx_to_ieee = 1; | ||
2424 | ieee->polling = true; | ||
2425 | rtllib_sta_ps_send_pspoll_frame(ieee); | ||
2426 | } | ||
2427 | |||
2428 | } else { | ||
2429 | ieee->sta_sleep = LPS_IS_WAKE; | ||
2430 | ieee->polling = false; | ||
2431 | } | ||
2432 | } | ||
2433 | |||
2434 | void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success) | ||
2435 | { | ||
2436 | unsigned long flags,flags2; | ||
2437 | |||
2438 | spin_lock_irqsave(&ieee->lock, flags); | ||
2439 | |||
2440 | if (ieee->sta_sleep == LPS_WAIT_NULL_DATA_SEND){ | ||
2441 | /* Null frame with PS bit set */ | ||
2442 | if (success){ | ||
2443 | ieee->sta_sleep = LPS_IS_SLEEP; | ||
2444 | ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl); | ||
2445 | } | ||
2446 | /* if the card report not success we can't be sure the AP | ||
2447 | * has not RXed so we can't assume the AP believe us awake | ||
2448 | */ | ||
2449 | } else {/* 21112005 - tx again null without PS bit if lost */ | ||
2450 | |||
2451 | if ((ieee->sta_sleep == LPS_IS_WAKE) && !success){ | ||
2452 | spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); | ||
2453 | if (ieee->pHTInfo->IOTAction & HT_IOT_ACT_NULL_DATA_POWER_SAVING) | ||
2454 | { | ||
2455 | rtllib_sta_ps_send_null_frame(ieee, 0); | ||
2456 | } | ||
2457 | else | ||
2458 | { | ||
2459 | rtllib_sta_ps_send_pspoll_frame(ieee); | ||
2460 | } | ||
2461 | spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); | ||
2462 | } | ||
2463 | } | ||
2464 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
2465 | } | ||
2466 | |||
2467 | void rtllib_process_action(struct rtllib_device* ieee, struct sk_buff* skb) | ||
2468 | { | ||
2469 | struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; | ||
2470 | u8* act = rtllib_get_payload((struct rtllib_hdr *)header); | ||
2471 | u8 category = 0; | ||
2472 | |||
2473 | if (act == NULL) { | ||
2474 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "error to get payload of action frame\n"); | ||
2475 | return; | ||
2476 | } | ||
2477 | |||
2478 | category = *act; | ||
2479 | act ++; | ||
2480 | switch (category) { | ||
2481 | case ACT_CAT_BA: | ||
2482 | switch (*act) { | ||
2483 | case ACT_ADDBAREQ: | ||
2484 | rtllib_rx_ADDBAReq(ieee, skb); | ||
2485 | break; | ||
2486 | case ACT_ADDBARSP: | ||
2487 | rtllib_rx_ADDBARsp(ieee, skb); | ||
2488 | break; | ||
2489 | case ACT_DELBA: | ||
2490 | rtllib_rx_DELBA(ieee, skb); | ||
2491 | break; | ||
2492 | } | ||
2493 | break; | ||
2494 | default: | ||
2495 | break; | ||
2496 | } | ||
2497 | return; | ||
2498 | } | ||
2499 | |||
2500 | inline int rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats) | ||
2501 | { | ||
2502 | u16 errcode; | ||
2503 | int aid; | ||
2504 | u8* ies; | ||
2505 | struct rtllib_assoc_response_frame *assoc_resp; | ||
2506 | struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; | ||
2507 | |||
2508 | RTLLIB_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", | ||
2509 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
2510 | |||
2511 | if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && | ||
2512 | ieee->state == RTLLIB_ASSOCIATING_AUTHENTICATED && | ||
2513 | (ieee->iw_mode == IW_MODE_INFRA)) | ||
2514 | { | ||
2515 | if (0 == (errcode=assoc_parse(ieee,skb, &aid))){ | ||
2516 | struct rtllib_network *network = kzalloc(sizeof(struct rtllib_network), GFP_ATOMIC); | ||
2517 | |||
2518 | if (!network) | ||
2519 | return 1; | ||
2520 | memset(network,0,sizeof(*network)); | ||
2521 | ieee->state=RTLLIB_LINKED; | ||
2522 | ieee->assoc_id = aid; | ||
2523 | ieee->softmac_stats.rx_ass_ok++; | ||
2524 | /* station support qos */ | ||
2525 | /* Let the register setting defaultly with Legacy station */ | ||
2526 | assoc_resp = (struct rtllib_assoc_response_frame*)skb->data; | ||
2527 | if (ieee->current_network.qos_data.supported == 1) { | ||
2528 | if (rtllib_parse_info_param(ieee,assoc_resp->info_element,\ | ||
2529 | rx_stats->len - sizeof(*assoc_resp),\ | ||
2530 | network,rx_stats)){ | ||
2531 | kfree(network); | ||
2532 | return 1; | ||
2533 | } | ||
2534 | else | ||
2535 | { | ||
2536 | memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen); | ||
2537 | memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen); | ||
2538 | } | ||
2539 | if (ieee->handle_assoc_response != NULL) | ||
2540 | ieee->handle_assoc_response(ieee->dev, (struct rtllib_assoc_response_frame*)header, network); | ||
2541 | kfree(network); | ||
2542 | } | ||
2543 | |||
2544 | if (ieee->assocresp_ies){ | ||
2545 | kfree(ieee->assocresp_ies); | ||
2546 | ieee->assocresp_ies = NULL; | ||
2547 | } | ||
2548 | ies = &(assoc_resp->info_element[0].id); | ||
2549 | ieee->assocresp_ies_len = (skb->data + skb->len) - ies; | ||
2550 | ieee->assocresp_ies = kmalloc(ieee->assocresp_ies_len, GFP_ATOMIC); | ||
2551 | if (ieee->assocresp_ies) | ||
2552 | memcpy(ieee->assocresp_ies, ies, ieee->assocresp_ies_len); | ||
2553 | else{ | ||
2554 | printk("%s()Warning: can't alloc memory for assocresp_ies\n", __func__); | ||
2555 | ieee->assocresp_ies_len = 0; | ||
2556 | } | ||
2557 | rtllib_associate_complete(ieee); | ||
2558 | } else { | ||
2559 | /* aid could not been allocated */ | ||
2560 | ieee->softmac_stats.rx_ass_err++; | ||
2561 | printk( | ||
2562 | "Association response status code 0x%x\n", | ||
2563 | errcode); | ||
2564 | RTLLIB_DEBUG_MGMT( | ||
2565 | "Association response status code 0x%x\n", | ||
2566 | errcode); | ||
2567 | if (ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT) { | ||
2568 | queue_delayed_work_rsl(ieee->wq, &ieee->associate_procedure_wq, 0); | ||
2569 | } else { | ||
2570 | rtllib_associate_abort(ieee); | ||
2571 | } | ||
2572 | } | ||
2573 | } | ||
2574 | |||
2575 | return 0; | ||
2576 | } | ||
2577 | |||
2578 | inline int rtllib_rx_auth(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats) | ||
2579 | { | ||
2580 | u16 errcode; | ||
2581 | u8* challenge; | ||
2582 | int chlen=0; | ||
2583 | bool bSupportNmode = true, bHalfSupportNmode = false; | ||
2584 | |||
2585 | if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE){ | ||
2586 | if (ieee->state == RTLLIB_ASSOCIATING_AUTHENTICATING && | ||
2587 | (ieee->iw_mode == IW_MODE_INFRA)) { | ||
2588 | RTLLIB_DEBUG_MGMT("Received authentication response"); | ||
2589 | |||
2590 | if (0 == (errcode=auth_parse(skb, &challenge, &chlen))) { | ||
2591 | if (ieee->open_wep || !challenge){ | ||
2592 | ieee->state = RTLLIB_ASSOCIATING_AUTHENTICATED; | ||
2593 | ieee->softmac_stats.rx_auth_rs_ok++; | ||
2594 | if (!(ieee->pHTInfo->IOTAction&HT_IOT_ACT_PURE_N_MODE)) | ||
2595 | { | ||
2596 | if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) | ||
2597 | { | ||
2598 | if (IsHTHalfNmodeAPs(ieee)) | ||
2599 | { | ||
2600 | bSupportNmode = true; | ||
2601 | bHalfSupportNmode = true; | ||
2602 | } | ||
2603 | else | ||
2604 | { | ||
2605 | bSupportNmode = false; | ||
2606 | bHalfSupportNmode = false; | ||
2607 | } | ||
2608 | } | ||
2609 | } | ||
2610 | /* Dummy wirless mode setting to avoid encryption issue */ | ||
2611 | if (bSupportNmode) { | ||
2612 | ieee->SetWirelessMode(ieee->dev, \ | ||
2613 | ieee->current_network.mode); | ||
2614 | }else{ | ||
2615 | /*TODO*/ | ||
2616 | ieee->SetWirelessMode(ieee->dev, IEEE_G); | ||
2617 | } | ||
2618 | |||
2619 | if (ieee->current_network.mode == IEEE_N_24G && bHalfSupportNmode == true) | ||
2620 | { | ||
2621 | printk("===============>entern half N mode\n"); | ||
2622 | ieee->bHalfWirelessN24GMode = true; | ||
2623 | } | ||
2624 | else | ||
2625 | ieee->bHalfWirelessN24GMode = false; | ||
2626 | |||
2627 | rtllib_associate_step2(ieee); | ||
2628 | }else{ | ||
2629 | rtllib_auth_challenge(ieee, challenge, chlen); | ||
2630 | } | ||
2631 | }else{ | ||
2632 | ieee->softmac_stats.rx_auth_rs_err++; | ||
2633 | RTLLIB_DEBUG_MGMT("Authentication respose status code 0x%x",errcode); | ||
2634 | |||
2635 | printk("Authentication respose status code 0x%x",errcode); | ||
2636 | rtllib_associate_abort(ieee); | ||
2637 | } | ||
2638 | |||
2639 | }else if (ieee->iw_mode == IW_MODE_MASTER){ | ||
2640 | rtllib_rx_auth_rq(ieee, skb); | ||
2641 | } | ||
2642 | } | ||
2643 | |||
2644 | return 0; | ||
2645 | } | ||
2646 | |||
2647 | inline int rtllib_rx_deauth(struct rtllib_device *ieee, struct sk_buff *skb) | ||
2648 | { | ||
2649 | struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; | ||
2650 | |||
2651 | if (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0) | ||
2652 | return 0; | ||
2653 | |||
2654 | /* FIXME for now repeat all the association procedure | ||
2655 | * both for disassociation and deauthentication | ||
2656 | */ | ||
2657 | if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && | ||
2658 | ieee->state == RTLLIB_LINKED && | ||
2659 | (ieee->iw_mode == IW_MODE_INFRA)) { | ||
2660 | printk(KERN_INFO "==========>received disassoc/deauth(%x) " | ||
2661 | "frame, reason code:%x\n", | ||
2662 | WLAN_FC_GET_STYPE(header->frame_ctl), | ||
2663 | ((struct rtllib_disassoc*)skb->data)->reason); | ||
2664 | ieee->state = RTLLIB_ASSOCIATING; | ||
2665 | ieee->softmac_stats.reassoc++; | ||
2666 | ieee->is_roaming = true; | ||
2667 | ieee->LinkDetectInfo.bBusyTraffic = false; | ||
2668 | rtllib_disassociate(ieee); | ||
2669 | RemovePeerTS(ieee, header->addr2); | ||
2670 | if (ieee->LedControlHandler != NULL) | ||
2671 | ieee->LedControlHandler(ieee->dev, LED_CTL_START_TO_LINK); | ||
2672 | |||
2673 | if (!(ieee->rtllib_ap_sec_type(ieee)&(SEC_ALG_CCMP|SEC_ALG_TKIP))) | ||
2674 | queue_delayed_work_rsl(ieee->wq, &ieee->associate_procedure_wq, 5); | ||
2675 | } | ||
2676 | |||
2677 | return 0; | ||
2678 | } | ||
2679 | |||
2680 | inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee, struct sk_buff *skb, | ||
2681 | struct rtllib_rx_stats *rx_stats, u16 type, | ||
2682 | u16 stype) | ||
2683 | { | ||
2684 | struct rtllib_hdr_3addr *header = (struct rtllib_hdr_3addr *) skb->data; | ||
2685 | |||
2686 | if (!ieee->proto_started) | ||
2687 | return 0; | ||
2688 | |||
2689 | switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { | ||
2690 | |||
2691 | case RTLLIB_STYPE_ASSOC_RESP: | ||
2692 | case RTLLIB_STYPE_REASSOC_RESP: | ||
2693 | |||
2694 | if (rtllib_rx_assoc_resp(ieee, skb, rx_stats) == 1) | ||
2695 | return 1; | ||
2696 | |||
2697 | break; | ||
2698 | |||
2699 | case RTLLIB_STYPE_ASSOC_REQ: | ||
2700 | case RTLLIB_STYPE_REASSOC_REQ: | ||
2701 | |||
2702 | if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && | ||
2703 | ieee->iw_mode == IW_MODE_MASTER) | ||
2704 | |||
2705 | rtllib_rx_assoc_rq(ieee, skb); | ||
2706 | break; | ||
2707 | |||
2708 | case RTLLIB_STYPE_AUTH: | ||
2709 | |||
2710 | rtllib_rx_auth(ieee, skb, rx_stats); | ||
2711 | |||
2712 | break; | ||
2713 | case RTLLIB_STYPE_DISASSOC: | ||
2714 | case RTLLIB_STYPE_DEAUTH: | ||
2715 | |||
2716 | rtllib_rx_deauth(ieee, skb); | ||
2717 | |||
2718 | break; | ||
2719 | |||
2720 | case RTLLIB_STYPE_MANAGE_ACT: | ||
2721 | rtllib_process_action(ieee,skb); | ||
2722 | break; | ||
2723 | #ifdef COMPATIBLE_WITH_RALINK_MESH | ||
2724 | case RTLLIB_STYPE_MESH_ACT: | ||
2725 | rtllib_process_action_mesh(ieee,skb,rx_stats); | ||
2726 | break; | ||
2727 | #endif | ||
2728 | default: | ||
2729 | return -1; | ||
2730 | break; | ||
2731 | } | ||
2732 | |||
2733 | return 0; | ||
2734 | } | ||
2735 | |||
2736 | /* following are for a simplier TX queue management. | ||
2737 | * Instead of using netif_[stop/wake]_queue the driver | ||
2738 | * will uses these two function (plus a reset one), that | ||
2739 | * will internally uses the kernel netif_* and takes | ||
2740 | * care of the ieee802.11 fragmentation. | ||
2741 | * So the driver receives a fragment per time and might | ||
2742 | * call the stop function when it want without take care | ||
2743 | * to have enought room to TX an entire packet. | ||
2744 | * This might be useful if each fragment need it's own | ||
2745 | * descriptor, thus just keep a total free memory > than | ||
2746 | * the max fragmentation treshold is not enought.. If the | ||
2747 | * ieee802.11 stack passed a TXB struct then you needed | ||
2748 | * to keep N free descriptors where | ||
2749 | * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD | ||
2750 | * In this way you need just one and the 802.11 stack | ||
2751 | * will take care of buffering fragments and pass them to | ||
2752 | * to the driver later, when it wakes the queue. | ||
2753 | */ | ||
2754 | void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee) | ||
2755 | { | ||
2756 | |||
2757 | unsigned int queue_index = txb->queue_index; | ||
2758 | unsigned long flags; | ||
2759 | int i; | ||
2760 | cb_desc *tcb_desc = NULL; | ||
2761 | unsigned long queue_len = 0; | ||
2762 | |||
2763 | spin_lock_irqsave(&ieee->lock,flags); | ||
2764 | |||
2765 | /* called with 2nd parm 0, no tx mgmt lock required */ | ||
2766 | rtllib_sta_wakeup(ieee,0); | ||
2767 | |||
2768 | /* update the tx status */ | ||
2769 | tcb_desc = (cb_desc *)(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); | ||
2770 | if (tcb_desc->bMulticast) { | ||
2771 | ieee->stats.multicast++; | ||
2772 | } | ||
2773 | #if 1 | ||
2774 | /* if xmit available, just xmit it immediately, else just insert it to the wait queue */ | ||
2775 | for (i = 0; i < txb->nr_frags; i++) { | ||
2776 | #ifdef USB_TX_DRIVER_AGGREGATION_ENABLE | ||
2777 | queue_len = skb_queue_len(&ieee->skb_drv_aggQ[queue_index]); | ||
2778 | #else | ||
2779 | queue_len = skb_queue_len(&ieee->skb_waitQ[queue_index]); | ||
2780 | #endif | ||
2781 | if ((queue_len != 0) ||\ | ||
2782 | (!ieee->check_nic_enough_desc(ieee->dev,queue_index))||\ | ||
2783 | (ieee->queue_stop)) { | ||
2784 | /* insert the skb packet to the wait queue */ | ||
2785 | /* as for the completion function, it does not need | ||
2786 | * to check it any more. | ||
2787 | * */ | ||
2788 | #ifdef WIFI_TEST | ||
2789 | if (1) | ||
2790 | #else | ||
2791 | if (queue_len < 200) | ||
2792 | #endif | ||
2793 | { | ||
2794 | #ifdef USB_TX_DRIVER_AGGREGATION_ENABLE | ||
2795 | skb_queue_tail(&ieee->skb_drv_aggQ[queue_index], txb->fragments[i]); | ||
2796 | #else | ||
2797 | skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]); | ||
2798 | #endif | ||
2799 | }else{ | ||
2800 | kfree_skb(txb->fragments[i]); | ||
2801 | } | ||
2802 | }else{ | ||
2803 | ieee->softmac_data_hard_start_xmit( | ||
2804 | txb->fragments[i], | ||
2805 | ieee->dev,ieee->rate); | ||
2806 | } | ||
2807 | } | ||
2808 | #endif | ||
2809 | rtllib_txb_free(txb); | ||
2810 | |||
2811 | spin_unlock_irqrestore(&ieee->lock,flags); | ||
2812 | |||
2813 | } | ||
2814 | |||
2815 | /* called with ieee->lock acquired */ | ||
2816 | void rtllib_resume_tx(struct rtllib_device *ieee) | ||
2817 | { | ||
2818 | int i; | ||
2819 | for (i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { | ||
2820 | |||
2821 | if (ieee->queue_stop){ | ||
2822 | ieee->tx_pending.frag = i; | ||
2823 | return; | ||
2824 | }else{ | ||
2825 | |||
2826 | ieee->softmac_data_hard_start_xmit( | ||
2827 | ieee->tx_pending.txb->fragments[i], | ||
2828 | ieee->dev,ieee->rate); | ||
2829 | ieee->stats.tx_packets++; | ||
2830 | } | ||
2831 | } | ||
2832 | |||
2833 | rtllib_txb_free(ieee->tx_pending.txb); | ||
2834 | ieee->tx_pending.txb = NULL; | ||
2835 | } | ||
2836 | |||
2837 | |||
2838 | void rtllib_reset_queue(struct rtllib_device *ieee) | ||
2839 | { | ||
2840 | unsigned long flags; | ||
2841 | |||
2842 | spin_lock_irqsave(&ieee->lock,flags); | ||
2843 | init_mgmt_queue(ieee); | ||
2844 | if (ieee->tx_pending.txb){ | ||
2845 | rtllib_txb_free(ieee->tx_pending.txb); | ||
2846 | ieee->tx_pending.txb = NULL; | ||
2847 | } | ||
2848 | ieee->queue_stop = 0; | ||
2849 | spin_unlock_irqrestore(&ieee->lock,flags); | ||
2850 | |||
2851 | } | ||
2852 | |||
2853 | void rtllib_wake_queue(struct rtllib_device *ieee) | ||
2854 | { | ||
2855 | |||
2856 | unsigned long flags; | ||
2857 | struct sk_buff *skb; | ||
2858 | struct rtllib_hdr_3addr *header; | ||
2859 | |||
2860 | spin_lock_irqsave(&ieee->lock,flags); | ||
2861 | if (! ieee->queue_stop) goto exit; | ||
2862 | |||
2863 | ieee->queue_stop = 0; | ||
2864 | |||
2865 | if (ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE){ | ||
2866 | while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))){ | ||
2867 | |||
2868 | header = (struct rtllib_hdr_3addr *) skb->data; | ||
2869 | |||
2870 | header->seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | ||
2871 | |||
2872 | if (ieee->seq_ctrl[0] == 0xFFF) | ||
2873 | ieee->seq_ctrl[0] = 0; | ||
2874 | else | ||
2875 | ieee->seq_ctrl[0]++; | ||
2876 | |||
2877 | ieee->softmac_data_hard_start_xmit(skb,ieee->dev,ieee->basic_rate); | ||
2878 | } | ||
2879 | } | ||
2880 | if (!ieee->queue_stop && ieee->tx_pending.txb) | ||
2881 | rtllib_resume_tx(ieee); | ||
2882 | |||
2883 | if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)){ | ||
2884 | ieee->softmac_stats.swtxawake++; | ||
2885 | netif_wake_queue(ieee->dev); | ||
2886 | } | ||
2887 | |||
2888 | exit : | ||
2889 | spin_unlock_irqrestore(&ieee->lock,flags); | ||
2890 | } | ||
2891 | |||
2892 | |||
2893 | void rtllib_stop_queue(struct rtllib_device *ieee) | ||
2894 | { | ||
2895 | |||
2896 | if (! netif_queue_stopped(ieee->dev)){ | ||
2897 | netif_stop_queue(ieee->dev); | ||
2898 | ieee->softmac_stats.swtxstop++; | ||
2899 | } | ||
2900 | ieee->queue_stop = 1; | ||
2901 | |||
2902 | } | ||
2903 | |||
2904 | void rtllib_stop_all_queues(struct rtllib_device *ieee) | ||
2905 | { | ||
2906 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) | ||
2907 | unsigned int i; | ||
2908 | for (i=0; i < ieee->dev->num_tx_queues; i++) | ||
2909 | netdev_get_tx_queue(ieee->dev,i)->trans_start = jiffies; | ||
2910 | #else | ||
2911 | ieee->dev->trans_start = jiffies; | ||
2912 | #endif | ||
2913 | |||
2914 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | ||
2915 | netif_carrier_off(ieee->dev); | ||
2916 | #else | ||
2917 | netif_tx_stop_all_queues(ieee->dev); | ||
2918 | #endif | ||
2919 | } | ||
2920 | |||
2921 | void rtllib_wake_all_queues(struct rtllib_device *ieee) | ||
2922 | { | ||
2923 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | ||
2924 | netif_carrier_on(ieee->dev); | ||
2925 | #else | ||
2926 | netif_tx_wake_all_queues(ieee->dev); | ||
2927 | #endif | ||
2928 | } | ||
2929 | |||
2930 | inline void rtllib_randomize_cell(struct rtllib_device *ieee) | ||
2931 | { | ||
2932 | |||
2933 | get_random_bytes(ieee->current_network.bssid, ETH_ALEN); | ||
2934 | |||
2935 | /* an IBSS cell address must have the two less significant | ||
2936 | * bits of the first byte = 2 | ||
2937 | */ | ||
2938 | ieee->current_network.bssid[0] &= ~0x01; | ||
2939 | ieee->current_network.bssid[0] |= 0x02; | ||
2940 | } | ||
2941 | |||
2942 | /* called in user context only */ | ||
2943 | void rtllib_start_master_bss(struct rtllib_device *ieee) | ||
2944 | { | ||
2945 | ieee->assoc_id = 1; | ||
2946 | |||
2947 | if (ieee->current_network.ssid_len == 0){ | ||
2948 | strncpy(ieee->current_network.ssid, | ||
2949 | RTLLIB_DEFAULT_TX_ESSID, | ||
2950 | IW_ESSID_MAX_SIZE); | ||
2951 | |||
2952 | ieee->current_network.ssid_len = strlen(RTLLIB_DEFAULT_TX_ESSID); | ||
2953 | ieee->ssid_set = 1; | ||
2954 | } | ||
2955 | |||
2956 | memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); | ||
2957 | |||
2958 | ieee->set_chan(ieee->dev, ieee->current_network.channel); | ||
2959 | ieee->state = RTLLIB_LINKED; | ||
2960 | ieee->link_change(ieee->dev); | ||
2961 | notify_wx_assoc_event(ieee); | ||
2962 | |||
2963 | if (ieee->data_hard_resume) | ||
2964 | ieee->data_hard_resume(ieee->dev); | ||
2965 | |||
2966 | netif_carrier_on(ieee->dev); | ||
2967 | } | ||
2968 | |||
2969 | void rtllib_start_monitor_mode(struct rtllib_device *ieee) | ||
2970 | { | ||
2971 | /* reset hardware status */ | ||
2972 | if (ieee->raw_tx){ | ||
2973 | if (ieee->data_hard_resume) | ||
2974 | ieee->data_hard_resume(ieee->dev); | ||
2975 | |||
2976 | netif_carrier_on(ieee->dev); | ||
2977 | } | ||
2978 | } | ||
2979 | |||
2980 | void rtllib_start_ibss_wq(void *data) | ||
2981 | { | ||
2982 | struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, start_ibss_wq); | ||
2983 | /* iwconfig mode ad-hoc will schedule this and return | ||
2984 | * on the other hand this will block further iwconfig SET | ||
2985 | * operations because of the wx_sem hold. | ||
2986 | * Anyway some most set operations set a flag to speed-up | ||
2987 | * (abort) this wq (when syncro scanning) before sleeping | ||
2988 | * on the semaphore | ||
2989 | */ | ||
2990 | if (!ieee->proto_started){ | ||
2991 | printk("==========oh driver down return\n"); | ||
2992 | return; | ||
2993 | } | ||
2994 | down(&ieee->wx_sem); | ||
2995 | |||
2996 | if (ieee->current_network.ssid_len == 0){ | ||
2997 | strcpy(ieee->current_network.ssid,RTLLIB_DEFAULT_TX_ESSID); | ||
2998 | ieee->current_network.ssid_len = strlen(RTLLIB_DEFAULT_TX_ESSID); | ||
2999 | ieee->ssid_set = 1; | ||
3000 | } | ||
3001 | |||
3002 | ieee->state = RTLLIB_NOLINK; | ||
3003 | #ifdef ADHOC_11N | ||
3004 | ieee->mode = IEEE_N_24G; | ||
3005 | #else | ||
3006 | ieee->mode = IEEE_G; | ||
3007 | #endif | ||
3008 | /* check if we have this cell in our network list */ | ||
3009 | rtllib_softmac_check_all_nets(ieee); | ||
3010 | |||
3011 | |||
3012 | /* if not then the state is not linked. Maybe the user swithced to | ||
3013 | * ad-hoc mode just after being in monitor mode, or just after | ||
3014 | * being very few time in managed mode (so the card have had no | ||
3015 | * time to scan all the chans..) or we have just run up the iface | ||
3016 | * after setting ad-hoc mode. So we have to give another try.. | ||
3017 | * Here, in ibss mode, should be safe to do this without extra care | ||
3018 | * (in bss mode we had to make sure no-one tryed to associate when | ||
3019 | * we had just checked the ieee->state and we was going to start the | ||
3020 | * scan) beacause in ibss mode the rtllib_new_net function, when | ||
3021 | * finds a good net, just set the ieee->state to RTLLIB_LINKED, | ||
3022 | * so, at worst, we waste a bit of time to initiate an unneeded syncro | ||
3023 | * scan, that will stop at the first round because it sees the state | ||
3024 | * associated. | ||
3025 | */ | ||
3026 | if (ieee->state == RTLLIB_NOLINK) | ||
3027 | rtllib_start_scan_syncro(ieee, 0); | ||
3028 | |||
3029 | /* the network definitively is not here.. create a new cell */ | ||
3030 | if (ieee->state == RTLLIB_NOLINK){ | ||
3031 | printk("creating new IBSS cell\n"); | ||
3032 | ieee->current_network.channel = ieee->IbssStartChnl; | ||
3033 | if (!ieee->wap_set) | ||
3034 | rtllib_randomize_cell(ieee); | ||
3035 | |||
3036 | if (ieee->modulation & RTLLIB_CCK_MODULATION){ | ||
3037 | |||
3038 | ieee->current_network.rates_len = 4; | ||
3039 | |||
3040 | ieee->current_network.rates[0] = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_1MB; | ||
3041 | ieee->current_network.rates[1] = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_2MB; | ||
3042 | ieee->current_network.rates[2] = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_5MB; | ||
3043 | ieee->current_network.rates[3] = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_11MB; | ||
3044 | |||
3045 | }else | ||
3046 | ieee->current_network.rates_len = 0; | ||
3047 | |||
3048 | if (ieee->modulation & RTLLIB_OFDM_MODULATION){ | ||
3049 | ieee->current_network.rates_ex_len = 8; | ||
3050 | |||
3051 | /*ieee->current_network.rates_ex[0] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_6MB; | ||
3052 | ieee->current_network.rates_ex[1] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_9MB; | ||
3053 | ieee->current_network.rates_ex[2] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_12MB; | ||
3054 | ieee->current_network.rates_ex[3] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_18MB; | ||
3055 | ieee->current_network.rates_ex[4] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_24MB; | ||
3056 | ieee->current_network.rates_ex[5] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_36MB; | ||
3057 | ieee->current_network.rates_ex[6] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_48MB; | ||
3058 | ieee->current_network.rates_ex[7] = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_54MB;*/ | ||
3059 | |||
3060 | ieee->current_network.rates_ex[0] = RTLLIB_OFDM_RATE_6MB; | ||
3061 | ieee->current_network.rates_ex[1] = RTLLIB_OFDM_RATE_9MB; | ||
3062 | ieee->current_network.rates_ex[2] = RTLLIB_OFDM_RATE_12MB; | ||
3063 | ieee->current_network.rates_ex[3] = RTLLIB_OFDM_RATE_18MB; | ||
3064 | ieee->current_network.rates_ex[4] = RTLLIB_OFDM_RATE_24MB; | ||
3065 | ieee->current_network.rates_ex[5] = RTLLIB_OFDM_RATE_36MB; | ||
3066 | ieee->current_network.rates_ex[6] = RTLLIB_OFDM_RATE_48MB; | ||
3067 | ieee->current_network.rates_ex[7] = RTLLIB_OFDM_RATE_54MB; | ||
3068 | |||
3069 | ieee->rate = 108; | ||
3070 | }else{ | ||
3071 | ieee->current_network.rates_ex_len = 0; | ||
3072 | ieee->rate = 22; | ||
3073 | } | ||
3074 | |||
3075 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
3076 | #ifdef ADHOC_11N | ||
3077 | ieee->current_network.qos_data.supported = 1; | ||
3078 | #else | ||
3079 | ieee->current_network.qos_data.supported = 0; | ||
3080 | #endif | ||
3081 | ieee->SetWirelessMode(ieee->dev, ieee->mode); | ||
3082 | #else | ||
3083 | ieee->current_network.qos_data.supported = 0; | ||
3084 | ieee->SetWirelessMode(ieee->dev, IEEE_G); | ||
3085 | #endif | ||
3086 | ieee->current_network.mode = ieee->mode; | ||
3087 | ieee->current_network.atim_window = 0; | ||
3088 | ieee->current_network.capability = WLAN_CAPABILITY_IBSS; | ||
3089 | } | ||
3090 | |||
3091 | printk("%s(): ieee->mode = %d\n", __func__, ieee->mode); | ||
3092 | if ((ieee->mode == IEEE_N_24G) || (ieee->mode == IEEE_N_5G)) | ||
3093 | HTUseDefaultSetting(ieee); | ||
3094 | else | ||
3095 | ieee->pHTInfo->bCurrentHTSupport = false; | ||
3096 | |||
3097 | ieee->SetHwRegHandler(ieee->dev, HW_VAR_MEDIA_STATUS, (u8 *)(&ieee->state)); | ||
3098 | |||
3099 | ieee->state = RTLLIB_LINKED; | ||
3100 | ieee->link_change(ieee->dev); | ||
3101 | |||
3102 | HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); | ||
3103 | if (ieee->LedControlHandler != NULL) | ||
3104 | ieee->LedControlHandler(ieee->dev,LED_CTL_LINK); | ||
3105 | |||
3106 | rtllib_start_send_beacons(ieee); | ||
3107 | |||
3108 | notify_wx_assoc_event(ieee); | ||
3109 | |||
3110 | if (ieee->data_hard_resume) | ||
3111 | ieee->data_hard_resume(ieee->dev); | ||
3112 | |||
3113 | netif_carrier_on(ieee->dev); | ||
3114 | |||
3115 | up(&ieee->wx_sem); | ||
3116 | } | ||
3117 | |||
3118 | inline void rtllib_start_ibss(struct rtllib_device *ieee) | ||
3119 | { | ||
3120 | queue_delayed_work_rsl(ieee->wq, &ieee->start_ibss_wq, MSECS(150)); | ||
3121 | } | ||
3122 | |||
3123 | /* this is called only in user context, with wx_sem held */ | ||
3124 | void rtllib_start_bss(struct rtllib_device *ieee) | ||
3125 | { | ||
3126 | unsigned long flags; | ||
3127 | #ifdef ENABLE_DOT11D | ||
3128 | if (IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) | ||
3129 | { | ||
3130 | if (! ieee->bGlobalDomain) | ||
3131 | { | ||
3132 | return; | ||
3133 | } | ||
3134 | } | ||
3135 | #endif | ||
3136 | /* check if we have already found the net we | ||
3137 | * are interested in (if any). | ||
3138 | * if not (we are disassociated and we are not | ||
3139 | * in associating / authenticating phase) start the background scanning. | ||
3140 | */ | ||
3141 | rtllib_softmac_check_all_nets(ieee); | ||
3142 | |||
3143 | /* ensure no-one start an associating process (thus setting | ||
3144 | * the ieee->state to rtllib_ASSOCIATING) while we | ||
3145 | * have just cheked it and we are going to enable scan. | ||
3146 | * The rtllib_new_net function is always called with | ||
3147 | * lock held (from both rtllib_softmac_check_all_nets and | ||
3148 | * the rx path), so we cannot be in the middle of such function | ||
3149 | */ | ||
3150 | spin_lock_irqsave(&ieee->lock, flags); | ||
3151 | |||
3152 | if (ieee->state == RTLLIB_NOLINK) { | ||
3153 | rtllib_start_scan(ieee); | ||
3154 | } | ||
3155 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
3156 | } | ||
3157 | |||
3158 | void rtllib_link_change_wq(void *data) | ||
3159 | { | ||
3160 | struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, link_change_wq); | ||
3161 | ieee->link_change(ieee->dev); | ||
3162 | } | ||
3163 | /* called only in userspace context */ | ||
3164 | void rtllib_disassociate(struct rtllib_device *ieee) | ||
3165 | { | ||
3166 | netif_carrier_off(ieee->dev); | ||
3167 | if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) | ||
3168 | rtllib_reset_queue(ieee); | ||
3169 | |||
3170 | if (ieee->data_hard_stop) | ||
3171 | ieee->data_hard_stop(ieee->dev); | ||
3172 | #ifdef ENABLE_DOT11D | ||
3173 | if (IS_DOT11D_ENABLE(ieee)) | ||
3174 | Dot11d_Reset(ieee); | ||
3175 | #endif | ||
3176 | ieee->state = RTLLIB_NOLINK; | ||
3177 | ieee->is_set_key = false; | ||
3178 | ieee->wap_set = 0; | ||
3179 | |||
3180 | queue_delayed_work_rsl(ieee->wq, &ieee->link_change_wq, 0); | ||
3181 | |||
3182 | |||
3183 | #ifndef FOR_ANDROID_X86 | ||
3184 | notify_wx_assoc_event(ieee); | ||
3185 | #endif | ||
3186 | } | ||
3187 | |||
3188 | void rtllib_associate_retry_wq(void *data) | ||
3189 | { | ||
3190 | struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, associate_retry_wq); | ||
3191 | unsigned long flags; | ||
3192 | |||
3193 | down(&ieee->wx_sem); | ||
3194 | if (!ieee->proto_started) | ||
3195 | goto exit; | ||
3196 | |||
3197 | if (ieee->state != RTLLIB_ASSOCIATING_RETRY) | ||
3198 | goto exit; | ||
3199 | |||
3200 | /* until we do not set the state to RTLLIB_NOLINK | ||
3201 | * there are no possibility to have someone else trying | ||
3202 | * to start an association procdure (we get here with | ||
3203 | * ieee->state = RTLLIB_ASSOCIATING). | ||
3204 | * When we set the state to RTLLIB_NOLINK it is possible | ||
3205 | * that the RX path run an attempt to associate, but | ||
3206 | * both rtllib_softmac_check_all_nets and the | ||
3207 | * RX path works with ieee->lock held so there are no | ||
3208 | * problems. If we are still disassociated then start a scan. | ||
3209 | * the lock here is necessary to ensure no one try to start | ||
3210 | * an association procedure when we have just checked the | ||
3211 | * state and we are going to start the scan. | ||
3212 | */ | ||
3213 | ieee->beinretry = true; | ||
3214 | ieee->state = RTLLIB_NOLINK; | ||
3215 | |||
3216 | rtllib_softmac_check_all_nets(ieee); | ||
3217 | |||
3218 | spin_lock_irqsave(&ieee->lock, flags); | ||
3219 | |||
3220 | if (ieee->state == RTLLIB_NOLINK) | ||
3221 | { | ||
3222 | rtllib_start_scan(ieee); | ||
3223 | } | ||
3224 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
3225 | |||
3226 | ieee->beinretry = false; | ||
3227 | exit: | ||
3228 | up(&ieee->wx_sem); | ||
3229 | } | ||
3230 | |||
3231 | struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee) | ||
3232 | { | ||
3233 | u8 broadcast_addr[] = {0xff,0xff,0xff,0xff,0xff,0xff}; | ||
3234 | |||
3235 | struct sk_buff *skb; | ||
3236 | struct rtllib_probe_response *b; | ||
3237 | skb = rtllib_probe_resp(ieee, broadcast_addr); | ||
3238 | |||
3239 | if (!skb) | ||
3240 | return NULL; | ||
3241 | |||
3242 | b = (struct rtllib_probe_response *) skb->data; | ||
3243 | b->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_BEACON); | ||
3244 | |||
3245 | return skb; | ||
3246 | |||
3247 | } | ||
3248 | |||
3249 | struct sk_buff *rtllib_get_beacon(struct rtllib_device *ieee) | ||
3250 | { | ||
3251 | struct sk_buff *skb; | ||
3252 | struct rtllib_probe_response *b; | ||
3253 | |||
3254 | skb = rtllib_get_beacon_(ieee); | ||
3255 | if (!skb) | ||
3256 | return NULL; | ||
3257 | |||
3258 | b = (struct rtllib_probe_response *) skb->data; | ||
3259 | b->header.seq_ctl = cpu_to_le16(ieee->seq_ctrl[0] << 4); | ||
3260 | |||
3261 | if (ieee->seq_ctrl[0] == 0xFFF) | ||
3262 | ieee->seq_ctrl[0] = 0; | ||
3263 | else | ||
3264 | ieee->seq_ctrl[0]++; | ||
3265 | |||
3266 | return skb; | ||
3267 | } | ||
3268 | |||
3269 | void rtllib_softmac_stop_protocol(struct rtllib_device *ieee, u8 mesh_flag, u8 shutdown) | ||
3270 | { | ||
3271 | rtllib_stop_scan_syncro(ieee); | ||
3272 | down(&ieee->wx_sem); | ||
3273 | rtllib_stop_protocol(ieee,shutdown); | ||
3274 | up(&ieee->wx_sem); | ||
3275 | } | ||
3276 | |||
3277 | |||
3278 | void rtllib_stop_protocol(struct rtllib_device *ieee, u8 shutdown) | ||
3279 | { | ||
3280 | if (!ieee->proto_started) | ||
3281 | return; | ||
3282 | |||
3283 | if (shutdown){ | ||
3284 | ieee->proto_started = 0; | ||
3285 | ieee->proto_stoppping = 1; | ||
3286 | if (ieee->rtllib_ips_leave != NULL) | ||
3287 | ieee->rtllib_ips_leave(ieee->dev); | ||
3288 | } | ||
3289 | |||
3290 | rtllib_stop_send_beacons(ieee); | ||
3291 | del_timer_sync(&ieee->associate_timer); | ||
3292 | cancel_delayed_work(&ieee->associate_retry_wq); | ||
3293 | cancel_delayed_work(&ieee->start_ibss_wq); | ||
3294 | cancel_delayed_work(&ieee->link_change_wq); | ||
3295 | rtllib_stop_scan(ieee); | ||
3296 | |||
3297 | if (ieee->state <= RTLLIB_ASSOCIATING_AUTHENTICATED) | ||
3298 | ieee->state = RTLLIB_NOLINK; | ||
3299 | |||
3300 | if (ieee->state == RTLLIB_LINKED){ | ||
3301 | if (ieee->iw_mode == IW_MODE_INFRA) | ||
3302 | SendDisassociation(ieee,1,deauth_lv_ss); | ||
3303 | rtllib_disassociate(ieee); | ||
3304 | } | ||
3305 | |||
3306 | if (shutdown){ | ||
3307 | RemoveAllTS(ieee); | ||
3308 | ieee->proto_stoppping = 0; | ||
3309 | } | ||
3310 | if (ieee->assocreq_ies) { | ||
3311 | kfree(ieee->assocreq_ies); | ||
3312 | ieee->assocreq_ies = NULL; | ||
3313 | ieee->assocreq_ies_len = 0; | ||
3314 | } | ||
3315 | if (ieee->assocresp_ies) { | ||
3316 | kfree(ieee->assocresp_ies); | ||
3317 | ieee->assocresp_ies = NULL; | ||
3318 | ieee->assocresp_ies_len = 0; | ||
3319 | } | ||
3320 | } | ||
3321 | |||
3322 | void rtllib_softmac_start_protocol(struct rtllib_device *ieee, u8 mesh_flag) | ||
3323 | { | ||
3324 | down(&ieee->wx_sem); | ||
3325 | rtllib_start_protocol(ieee); | ||
3326 | up(&ieee->wx_sem); | ||
3327 | } | ||
3328 | |||
3329 | void rtllib_start_protocol(struct rtllib_device *ieee) | ||
3330 | { | ||
3331 | short ch = 0; | ||
3332 | int i = 0; | ||
3333 | |||
3334 | rtllib_update_active_chan_map(ieee); | ||
3335 | |||
3336 | if (ieee->proto_started) | ||
3337 | return; | ||
3338 | |||
3339 | ieee->proto_started = 1; | ||
3340 | |||
3341 | if (ieee->current_network.channel == 0) { | ||
3342 | do { | ||
3343 | ch++; | ||
3344 | if (ch > MAX_CHANNEL_NUMBER) | ||
3345 | return; /* no channel found */ | ||
3346 | } while(!ieee->active_channel_map[ch]); | ||
3347 | ieee->current_network.channel = ch; | ||
3348 | } | ||
3349 | |||
3350 | if (ieee->current_network.beacon_interval == 0) | ||
3351 | ieee->current_network.beacon_interval = 100; | ||
3352 | |||
3353 | for (i = 0; i < 17; i++) { | ||
3354 | ieee->last_rxseq_num[i] = -1; | ||
3355 | ieee->last_rxfrag_num[i] = -1; | ||
3356 | ieee->last_packet_time[i] = 0; | ||
3357 | } | ||
3358 | |||
3359 | if (ieee->UpdateBeaconInterruptHandler) | ||
3360 | ieee->UpdateBeaconInterruptHandler(ieee->dev, false); | ||
3361 | |||
3362 | ieee->wmm_acm = 0; | ||
3363 | /* if the user set the MAC of the ad-hoc cell and then | ||
3364 | * switch to managed mode, shall we make sure that association | ||
3365 | * attempts does not fail just because the user provide the essid | ||
3366 | * and the nic is still checking for the AP MAC ?? | ||
3367 | */ | ||
3368 | if (ieee->iw_mode == IW_MODE_INFRA) { | ||
3369 | rtllib_start_bss(ieee); | ||
3370 | } else if (ieee->iw_mode == IW_MODE_ADHOC) { | ||
3371 | if (ieee->UpdateBeaconInterruptHandler) | ||
3372 | ieee->UpdateBeaconInterruptHandler(ieee->dev, true); | ||
3373 | |||
3374 | rtllib_start_ibss(ieee); | ||
3375 | |||
3376 | } else if (ieee->iw_mode == IW_MODE_MASTER) { | ||
3377 | rtllib_start_master_bss(ieee); | ||
3378 | } else if (ieee->iw_mode == IW_MODE_MONITOR) { | ||
3379 | rtllib_start_monitor_mode(ieee); | ||
3380 | } | ||
3381 | } | ||
3382 | |||
3383 | void rtllib_softmac_init(struct rtllib_device *ieee) | ||
3384 | { | ||
3385 | int i; | ||
3386 | memset(&ieee->current_network, 0, sizeof(struct rtllib_network)); | ||
3387 | |||
3388 | ieee->state = RTLLIB_NOLINK; | ||
3389 | for (i = 0; i < 5; i++) { | ||
3390 | ieee->seq_ctrl[i] = 0; | ||
3391 | } | ||
3392 | #ifdef ENABLE_DOT11D | ||
3393 | ieee->pDot11dInfo = kmalloc(sizeof(struct rt_dot11d_info), GFP_ATOMIC); | ||
3394 | if (!ieee->pDot11dInfo) | ||
3395 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc memory for DOT11D\n"); | ||
3396 | memset(ieee->pDot11dInfo, 0, sizeof(struct rt_dot11d_info)); | ||
3397 | #endif | ||
3398 | ieee->LinkDetectInfo.SlotIndex = 0; | ||
3399 | ieee->LinkDetectInfo.SlotNum = 2; | ||
3400 | ieee->LinkDetectInfo.NumRecvBcnInPeriod=0; | ||
3401 | ieee->LinkDetectInfo.NumRecvDataInPeriod=0; | ||
3402 | ieee->LinkDetectInfo.NumTxOkInPeriod =0; | ||
3403 | ieee->LinkDetectInfo.NumRxOkInPeriod =0; | ||
3404 | ieee->LinkDetectInfo.NumRxUnicastOkInPeriod=0; | ||
3405 | ieee->bIsAggregateFrame = false; | ||
3406 | ieee->assoc_id = 0; | ||
3407 | ieee->queue_stop = 0; | ||
3408 | ieee->scanning_continue = 0; | ||
3409 | ieee->softmac_features = 0; | ||
3410 | ieee->wap_set = 0; | ||
3411 | ieee->ssid_set = 0; | ||
3412 | ieee->proto_started = 0; | ||
3413 | ieee->proto_stoppping = 0; | ||
3414 | ieee->basic_rate = RTLLIB_DEFAULT_BASIC_RATE; | ||
3415 | ieee->rate = 22; | ||
3416 | ieee->ps = RTLLIB_PS_DISABLED; | ||
3417 | ieee->sta_sleep = LPS_IS_WAKE; | ||
3418 | |||
3419 | ieee->Regdot11HTOperationalRateSet[0]= 0xff; | ||
3420 | ieee->Regdot11HTOperationalRateSet[1]= 0xff; | ||
3421 | ieee->Regdot11HTOperationalRateSet[4]= 0x01; | ||
3422 | |||
3423 | ieee->Regdot11TxHTOperationalRateSet[0]= 0xff; | ||
3424 | ieee->Regdot11TxHTOperationalRateSet[1]= 0xff; | ||
3425 | ieee->Regdot11TxHTOperationalRateSet[4]= 0x01; | ||
3426 | |||
3427 | ieee->FirstIe_InScan = false; | ||
3428 | ieee->actscanning = false; | ||
3429 | ieee->beinretry = false; | ||
3430 | ieee->is_set_key = false; | ||
3431 | init_mgmt_queue(ieee); | ||
3432 | |||
3433 | ieee->sta_edca_param[0] = 0x0000A403; | ||
3434 | ieee->sta_edca_param[1] = 0x0000A427; | ||
3435 | ieee->sta_edca_param[2] = 0x005E4342; | ||
3436 | ieee->sta_edca_param[3] = 0x002F3262; | ||
3437 | ieee->aggregation = true; | ||
3438 | ieee->enable_rx_imm_BA = 1; | ||
3439 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,40) | ||
3440 | _setup_timer(&ieee->scan_timer, | ||
3441 | rtllib_softmac_scan_cb, | ||
3442 | (unsigned long) ieee); | ||
3443 | #endif | ||
3444 | ieee->tx_pending.txb = NULL; | ||
3445 | |||
3446 | _setup_timer(&ieee->associate_timer, | ||
3447 | rtllib_associate_abort_cb, | ||
3448 | (unsigned long) ieee); | ||
3449 | |||
3450 | _setup_timer(&ieee->beacon_timer, | ||
3451 | rtllib_send_beacon_cb, | ||
3452 | (unsigned long) ieee); | ||
3453 | |||
3454 | #if defined(RTL8192U) || defined(RTL8192SU) || defined(RTL8192SE) | ||
3455 | _setup_timer(&ieee->ibss_wait_timer, | ||
3456 | rtllib_ibss_wait_timeout, | ||
3457 | (unsigned long) ieee); | ||
3458 | #endif | ||
3459 | |||
3460 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | ||
3461 | #ifdef PF_SYNCTHREAD | ||
3462 | ieee->wq = create_workqueue(DRV_NAME,0); | ||
3463 | #else | ||
3464 | ieee->wq = create_workqueue(DRV_NAME); | ||
3465 | #endif | ||
3466 | #endif | ||
3467 | |||
3468 | INIT_DELAYED_WORK_RSL(&ieee->link_change_wq,(void*)rtllib_link_change_wq,ieee); | ||
3469 | INIT_DELAYED_WORK_RSL(&ieee->start_ibss_wq,(void*)rtllib_start_ibss_wq,ieee); | ||
3470 | INIT_WORK_RSL(&ieee->associate_complete_wq, (void*)rtllib_associate_complete_wq,ieee); | ||
3471 | INIT_DELAYED_WORK_RSL(&ieee->associate_procedure_wq, (void*)rtllib_associate_procedure_wq,ieee); | ||
3472 | INIT_DELAYED_WORK_RSL(&ieee->softmac_scan_wq,(void*)rtllib_softmac_scan_wq,ieee); | ||
3473 | INIT_DELAYED_WORK_RSL(&ieee->softmac_hint11d_wq,(void*)rtllib_softmac_hint11d_wq,ieee); | ||
3474 | INIT_DELAYED_WORK_RSL(&ieee->associate_retry_wq, (void*)rtllib_associate_retry_wq,ieee); | ||
3475 | INIT_WORK_RSL(&ieee->wx_sync_scan_wq,(void*)rtllib_wx_sync_scan_wq,ieee); | ||
3476 | |||
3477 | sema_init(&ieee->wx_sem, 1); | ||
3478 | sema_init(&ieee->scan_sem, 1); | ||
3479 | sema_init(&ieee->ips_sem,1); | ||
3480 | |||
3481 | spin_lock_init(&ieee->mgmt_tx_lock); | ||
3482 | spin_lock_init(&ieee->beacon_lock); | ||
3483 | |||
3484 | tasklet_init(&ieee->ps_task, | ||
3485 | (void(*)(unsigned long)) rtllib_sta_ps, | ||
3486 | (unsigned long)ieee); | ||
3487 | |||
3488 | } | ||
3489 | |||
3490 | void rtllib_softmac_free(struct rtllib_device *ieee) | ||
3491 | { | ||
3492 | down(&ieee->wx_sem); | ||
3493 | #ifdef ENABLE_DOT11D | ||
3494 | if (NULL != ieee->pDot11dInfo) | ||
3495 | { | ||
3496 | kfree(ieee->pDot11dInfo); | ||
3497 | ieee->pDot11dInfo = NULL; | ||
3498 | } | ||
3499 | #endif | ||
3500 | del_timer_sync(&ieee->associate_timer); | ||
3501 | |||
3502 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | ||
3503 | cancel_delayed_work(&ieee->associate_retry_wq); | ||
3504 | destroy_workqueue(ieee->wq); | ||
3505 | #endif | ||
3506 | |||
3507 | up(&ieee->wx_sem); | ||
3508 | } | ||
3509 | |||
3510 | /******************************************************** | ||
3511 | * Start of WPA code. * | ||
3512 | * this is stolen from the ipw2200 driver * | ||
3513 | ********************************************************/ | ||
3514 | |||
3515 | |||
3516 | static int rtllib_wpa_enable(struct rtllib_device *ieee, int value) | ||
3517 | { | ||
3518 | /* This is called when wpa_supplicant loads and closes the driver | ||
3519 | * interface. */ | ||
3520 | printk("%s WPA\n",value ? "enabling" : "disabling"); | ||
3521 | ieee->wpa_enabled = value; | ||
3522 | memset(ieee->ap_mac_addr, 0, 6); | ||
3523 | return 0; | ||
3524 | } | ||
3525 | |||
3526 | |||
3527 | void rtllib_wpa_assoc_frame(struct rtllib_device *ieee, char *wpa_ie, int wpa_ie_len) | ||
3528 | { | ||
3529 | /* make sure WPA is enabled */ | ||
3530 | rtllib_wpa_enable(ieee, 1); | ||
3531 | |||
3532 | rtllib_disassociate(ieee); | ||
3533 | } | ||
3534 | |||
3535 | |||
3536 | static int rtllib_wpa_mlme(struct rtllib_device *ieee, int command, int reason) | ||
3537 | { | ||
3538 | |||
3539 | int ret = 0; | ||
3540 | |||
3541 | switch (command) { | ||
3542 | case IEEE_MLME_STA_DEAUTH: | ||
3543 | break; | ||
3544 | |||
3545 | case IEEE_MLME_STA_DISASSOC: | ||
3546 | rtllib_disassociate(ieee); | ||
3547 | break; | ||
3548 | |||
3549 | default: | ||
3550 | printk("Unknown MLME request: %d\n", command); | ||
3551 | ret = -EOPNOTSUPP; | ||
3552 | } | ||
3553 | |||
3554 | return ret; | ||
3555 | } | ||
3556 | |||
3557 | |||
3558 | static int rtllib_wpa_set_wpa_ie(struct rtllib_device *ieee, | ||
3559 | struct ieee_param *param, int plen) | ||
3560 | { | ||
3561 | u8 *buf; | ||
3562 | |||
3563 | if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || | ||
3564 | (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) | ||
3565 | return -EINVAL; | ||
3566 | |||
3567 | if (param->u.wpa_ie.len) { | ||
3568 | buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); | ||
3569 | if (buf == NULL) | ||
3570 | return -ENOMEM; | ||
3571 | |||
3572 | memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); | ||
3573 | kfree(ieee->wpa_ie); | ||
3574 | ieee->wpa_ie = buf; | ||
3575 | ieee->wpa_ie_len = param->u.wpa_ie.len; | ||
3576 | } else { | ||
3577 | kfree(ieee->wpa_ie); | ||
3578 | ieee->wpa_ie = NULL; | ||
3579 | ieee->wpa_ie_len = 0; | ||
3580 | } | ||
3581 | |||
3582 | rtllib_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); | ||
3583 | return 0; | ||
3584 | } | ||
3585 | |||
3586 | #define AUTH_ALG_OPEN_SYSTEM 0x1 | ||
3587 | #define AUTH_ALG_SHARED_KEY 0x2 | ||
3588 | #define AUTH_ALG_LEAP 0x4 | ||
3589 | static int rtllib_wpa_set_auth_algs(struct rtllib_device *ieee, int value) | ||
3590 | { | ||
3591 | |||
3592 | struct rtllib_security sec = { | ||
3593 | .flags = SEC_AUTH_MODE, | ||
3594 | }; | ||
3595 | int ret = 0; | ||
3596 | |||
3597 | if (value & AUTH_ALG_SHARED_KEY) { | ||
3598 | sec.auth_mode = WLAN_AUTH_SHARED_KEY; | ||
3599 | ieee->open_wep = 0; | ||
3600 | ieee->auth_mode = 1; | ||
3601 | } else if (value & AUTH_ALG_OPEN_SYSTEM){ | ||
3602 | sec.auth_mode = WLAN_AUTH_OPEN; | ||
3603 | ieee->open_wep = 1; | ||
3604 | ieee->auth_mode = 0; | ||
3605 | } | ||
3606 | else if (value & AUTH_ALG_LEAP){ | ||
3607 | sec.auth_mode = WLAN_AUTH_LEAP >> 6; | ||
3608 | ieee->open_wep = 1; | ||
3609 | ieee->auth_mode = 2; | ||
3610 | } | ||
3611 | |||
3612 | |||
3613 | if (ieee->set_security) | ||
3614 | ieee->set_security(ieee->dev, &sec); | ||
3615 | |||
3616 | return ret; | ||
3617 | } | ||
3618 | |||
3619 | static int rtllib_wpa_set_param(struct rtllib_device *ieee, u8 name, u32 value) | ||
3620 | { | ||
3621 | int ret=0; | ||
3622 | unsigned long flags; | ||
3623 | |||
3624 | switch (name) { | ||
3625 | case IEEE_PARAM_WPA_ENABLED: | ||
3626 | ret = rtllib_wpa_enable(ieee, value); | ||
3627 | break; | ||
3628 | |||
3629 | case IEEE_PARAM_TKIP_COUNTERMEASURES: | ||
3630 | ieee->tkip_countermeasures=value; | ||
3631 | break; | ||
3632 | |||
3633 | case IEEE_PARAM_DROP_UNENCRYPTED: | ||
3634 | { | ||
3635 | /* HACK: | ||
3636 | * | ||
3637 | * wpa_supplicant calls set_wpa_enabled when the driver | ||
3638 | * is loaded and unloaded, regardless of if WPA is being | ||
3639 | * used. No other calls are made which can be used to | ||
3640 | * determine if encryption will be used or not prior to | ||
3641 | * association being expected. If encryption is not being | ||
3642 | * used, drop_unencrypted is set to false, else true -- we | ||
3643 | * can use this to determine if the CAP_PRIVACY_ON bit should | ||
3644 | * be set. | ||
3645 | */ | ||
3646 | struct rtllib_security sec = { | ||
3647 | .flags = SEC_ENABLED, | ||
3648 | .enabled = value, | ||
3649 | }; | ||
3650 | ieee->drop_unencrypted = value; | ||
3651 | /* We only change SEC_LEVEL for open mode. Others | ||
3652 | * are set by ipw_wpa_set_encryption. | ||
3653 | */ | ||
3654 | if (!value) { | ||
3655 | sec.flags |= SEC_LEVEL; | ||
3656 | sec.level = SEC_LEVEL_0; | ||
3657 | } | ||
3658 | else { | ||
3659 | sec.flags |= SEC_LEVEL; | ||
3660 | sec.level = SEC_LEVEL_1; | ||
3661 | } | ||
3662 | if (ieee->set_security) | ||
3663 | ieee->set_security(ieee->dev, &sec); | ||
3664 | break; | ||
3665 | } | ||
3666 | |||
3667 | case IEEE_PARAM_PRIVACY_INVOKED: | ||
3668 | ieee->privacy_invoked=value; | ||
3669 | break; | ||
3670 | |||
3671 | case IEEE_PARAM_AUTH_ALGS: | ||
3672 | ret = rtllib_wpa_set_auth_algs(ieee, value); | ||
3673 | break; | ||
3674 | |||
3675 | case IEEE_PARAM_IEEE_802_1X: | ||
3676 | ieee->ieee802_1x=value; | ||
3677 | break; | ||
3678 | case IEEE_PARAM_WPAX_SELECT: | ||
3679 | spin_lock_irqsave(&ieee->wpax_suitlist_lock,flags); | ||
3680 | spin_unlock_irqrestore(&ieee->wpax_suitlist_lock,flags); | ||
3681 | break; | ||
3682 | |||
3683 | default: | ||
3684 | printk("Unknown WPA param: %d\n",name); | ||
3685 | ret = -EOPNOTSUPP; | ||
3686 | } | ||
3687 | |||
3688 | return ret; | ||
3689 | } | ||
3690 | |||
3691 | /* implementation borrowed from hostap driver */ | ||
3692 | static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, | ||
3693 | struct ieee_param *param, int param_len, u8 is_mesh) | ||
3694 | { | ||
3695 | int ret = 0; | ||
3696 | struct rtllib_crypto_ops *ops; | ||
3697 | struct rtllib_crypt_data **crypt; | ||
3698 | |||
3699 | struct rtllib_security sec = { | ||
3700 | .flags = 0, | ||
3701 | }; | ||
3702 | |||
3703 | param->u.crypt.err = 0; | ||
3704 | param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
3705 | |||
3706 | if (param_len != | ||
3707 | (int) ((char *) param->u.crypt.key - (char *) param) + | ||
3708 | param->u.crypt.key_len) { | ||
3709 | printk("Len mismatch %d, %d\n", param_len, | ||
3710 | param->u.crypt.key_len); | ||
3711 | return -EINVAL; | ||
3712 | } | ||
3713 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
3714 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
3715 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
3716 | if (param->u.crypt.idx >= WEP_KEYS) | ||
3717 | return -EINVAL; | ||
3718 | crypt = &ieee->crypt[param->u.crypt.idx]; | ||
3719 | } else { | ||
3720 | return -EINVAL; | ||
3721 | } | ||
3722 | |||
3723 | if (strcmp(param->u.crypt.alg, "none") == 0) { | ||
3724 | if (crypt) { | ||
3725 | sec.enabled = 0; | ||
3726 | sec.level = SEC_LEVEL_0; | ||
3727 | sec.flags |= SEC_ENABLED | SEC_LEVEL; | ||
3728 | rtllib_crypt_delayed_deinit(ieee, crypt); | ||
3729 | } | ||
3730 | goto done; | ||
3731 | } | ||
3732 | sec.enabled = 1; | ||
3733 | sec.flags |= SEC_ENABLED; | ||
3734 | |||
3735 | /* IPW HW cannot build TKIP MIC, host decryption still needed. */ | ||
3736 | if (!(ieee->host_encrypt || ieee->host_decrypt) && | ||
3737 | strcmp(param->u.crypt.alg, "TKIP")) | ||
3738 | goto skip_host_crypt; | ||
3739 | |||
3740 | ops = rtllib_get_crypto_ops(param->u.crypt.alg); | ||
3741 | if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
3742 | request_module("rtllib_crypt_wep"); | ||
3743 | ops = rtllib_get_crypto_ops(param->u.crypt.alg); | ||
3744 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
3745 | request_module("rtllib_crypt_tkip"); | ||
3746 | ops = rtllib_get_crypto_ops(param->u.crypt.alg); | ||
3747 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
3748 | request_module("rtllib_crypt_ccmp"); | ||
3749 | ops = rtllib_get_crypto_ops(param->u.crypt.alg); | ||
3750 | } | ||
3751 | if (ops == NULL) { | ||
3752 | printk("unknown crypto alg '%s'\n", param->u.crypt.alg); | ||
3753 | param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; | ||
3754 | ret = -EINVAL; | ||
3755 | goto done; | ||
3756 | } | ||
3757 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
3758 | struct rtllib_crypt_data *new_crypt; | ||
3759 | |||
3760 | rtllib_crypt_delayed_deinit(ieee, crypt); | ||
3761 | |||
3762 | new_crypt = (struct rtllib_crypt_data *) | ||
3763 | kmalloc(sizeof(*new_crypt), GFP_KERNEL); | ||
3764 | if (new_crypt == NULL) { | ||
3765 | ret = -ENOMEM; | ||
3766 | goto done; | ||
3767 | } | ||
3768 | memset(new_crypt, 0, sizeof(struct rtllib_crypt_data)); | ||
3769 | new_crypt->ops = ops; | ||
3770 | if (new_crypt->ops) | ||
3771 | new_crypt->priv = | ||
3772 | new_crypt->ops->init(param->u.crypt.idx); | ||
3773 | |||
3774 | if (new_crypt->priv == NULL) { | ||
3775 | kfree(new_crypt); | ||
3776 | param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; | ||
3777 | ret = -EINVAL; | ||
3778 | goto done; | ||
3779 | } | ||
3780 | |||
3781 | *crypt = new_crypt; | ||
3782 | } | ||
3783 | |||
3784 | if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && | ||
3785 | (*crypt)->ops->set_key(param->u.crypt.key, | ||
3786 | param->u.crypt.key_len, param->u.crypt.seq, | ||
3787 | (*crypt)->priv) < 0) { | ||
3788 | printk("key setting failed\n"); | ||
3789 | param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; | ||
3790 | ret = -EINVAL; | ||
3791 | goto done; | ||
3792 | } | ||
3793 | |||
3794 | skip_host_crypt: | ||
3795 | if (param->u.crypt.set_tx) { | ||
3796 | ieee->tx_keyidx = param->u.crypt.idx; | ||
3797 | sec.active_key = param->u.crypt.idx; | ||
3798 | sec.flags |= SEC_ACTIVE_KEY; | ||
3799 | } else | ||
3800 | sec.flags &= ~SEC_ACTIVE_KEY; | ||
3801 | |||
3802 | if (param->u.crypt.alg != NULL) { | ||
3803 | memcpy(sec.keys[param->u.crypt.idx], | ||
3804 | param->u.crypt.key, | ||
3805 | param->u.crypt.key_len); | ||
3806 | sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; | ||
3807 | sec.flags |= (1 << param->u.crypt.idx); | ||
3808 | |||
3809 | if (strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
3810 | sec.flags |= SEC_LEVEL; | ||
3811 | sec.level = SEC_LEVEL_1; | ||
3812 | } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
3813 | sec.flags |= SEC_LEVEL; | ||
3814 | sec.level = SEC_LEVEL_2; | ||
3815 | } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
3816 | sec.flags |= SEC_LEVEL; | ||
3817 | sec.level = SEC_LEVEL_3; | ||
3818 | } | ||
3819 | } | ||
3820 | done: | ||
3821 | if (ieee->set_security) | ||
3822 | ieee->set_security(ieee->dev, &sec); | ||
3823 | |||
3824 | /* Do not reset port if card is in Managed mode since resetting will | ||
3825 | * generate new IEEE 802.11 authentication which may end up in looping | ||
3826 | * with IEEE 802.1X. If your hardware requires a reset after WEP | ||
3827 | * configuration (for example... Prism2), implement the reset_port in | ||
3828 | * the callbacks structures used to initialize the 802.11 stack. */ | ||
3829 | if (ieee->reset_on_keychange && | ||
3830 | ieee->iw_mode != IW_MODE_INFRA && | ||
3831 | ieee->reset_port && | ||
3832 | ieee->reset_port(ieee->dev)) { | ||
3833 | printk("reset_port failed\n"); | ||
3834 | param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; | ||
3835 | return -EINVAL; | ||
3836 | } | ||
3837 | |||
3838 | return ret; | ||
3839 | } | ||
3840 | |||
3841 | inline struct sk_buff *rtllib_disauth_skb( struct rtllib_network *beacon, | ||
3842 | struct rtllib_device *ieee, u16 asRsn) | ||
3843 | { | ||
3844 | struct sk_buff *skb; | ||
3845 | struct rtllib_disauth *disauth; | ||
3846 | #ifdef USB_USE_ALIGNMENT | ||
3847 | u32 Tmpaddr=0; | ||
3848 | int alignment=0; | ||
3849 | int len = sizeof(struct rtllib_disauth) + ieee->tx_headroom + USB_512B_ALIGNMENT_SIZE; | ||
3850 | #else | ||
3851 | int len = sizeof(struct rtllib_disauth) + ieee->tx_headroom; | ||
3852 | |||
3853 | #endif | ||
3854 | skb = dev_alloc_skb(len); | ||
3855 | if (!skb) { | ||
3856 | return NULL; | ||
3857 | } | ||
3858 | |||
3859 | #ifdef USB_USE_ALIGNMENT | ||
3860 | Tmpaddr = (u32)skb->data; | ||
3861 | alignment = Tmpaddr & 0x1ff; | ||
3862 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
3863 | #endif | ||
3864 | skb_reserve(skb, ieee->tx_headroom); | ||
3865 | |||
3866 | disauth = (struct rtllib_disauth *) skb_put(skb,sizeof(struct rtllib_disauth)); | ||
3867 | disauth->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_DEAUTH); | ||
3868 | disauth->header.duration_id = 0; | ||
3869 | |||
3870 | memcpy(disauth->header.addr1, beacon->bssid, ETH_ALEN); | ||
3871 | memcpy(disauth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
3872 | memcpy(disauth->header.addr3, beacon->bssid, ETH_ALEN); | ||
3873 | |||
3874 | disauth->reason = cpu_to_le16(asRsn); | ||
3875 | return skb; | ||
3876 | } | ||
3877 | |||
3878 | inline struct sk_buff *rtllib_disassociate_skb( struct rtllib_network *beacon, | ||
3879 | struct rtllib_device *ieee, u16 asRsn) | ||
3880 | { | ||
3881 | struct sk_buff *skb; | ||
3882 | struct rtllib_disassoc *disass; | ||
3883 | #ifdef USB_USE_ALIGNMENT | ||
3884 | u32 Tmpaddr=0; | ||
3885 | int alignment=0; | ||
3886 | int len = sizeof(struct rtllib_disassoc) + ieee->tx_headroom + USB_512B_ALIGNMENT_SIZE; | ||
3887 | #else | ||
3888 | int len = sizeof(struct rtllib_disassoc) + ieee->tx_headroom; | ||
3889 | #endif | ||
3890 | skb = dev_alloc_skb(len); | ||
3891 | |||
3892 | if (!skb) { | ||
3893 | return NULL; | ||
3894 | } | ||
3895 | |||
3896 | #ifdef USB_USE_ALIGNMENT | ||
3897 | Tmpaddr = (u32)skb->data; | ||
3898 | alignment = Tmpaddr & 0x1ff; | ||
3899 | skb_reserve(skb,(USB_512B_ALIGNMENT_SIZE - alignment)); | ||
3900 | #endif | ||
3901 | skb_reserve(skb, ieee->tx_headroom); | ||
3902 | |||
3903 | disass = (struct rtllib_disassoc *) skb_put(skb,sizeof(struct rtllib_disassoc)); | ||
3904 | disass->header.frame_ctl = cpu_to_le16(RTLLIB_STYPE_DISASSOC); | ||
3905 | disass->header.duration_id = 0; | ||
3906 | |||
3907 | memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); | ||
3908 | memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); | ||
3909 | memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); | ||
3910 | |||
3911 | disass->reason = cpu_to_le16(asRsn); | ||
3912 | return skb; | ||
3913 | } | ||
3914 | |||
3915 | void SendDisassociation(struct rtllib_device *ieee, bool deauth, u16 asRsn) | ||
3916 | { | ||
3917 | struct rtllib_network *beacon = &ieee->current_network; | ||
3918 | struct sk_buff *skb; | ||
3919 | |||
3920 | if (deauth) { | ||
3921 | skb = rtllib_disauth_skb(beacon,ieee,asRsn); | ||
3922 | } else { | ||
3923 | skb = rtllib_disassociate_skb(beacon,ieee,asRsn); | ||
3924 | } | ||
3925 | |||
3926 | if (skb){ | ||
3927 | softmac_mgmt_xmit(skb, ieee); | ||
3928 | } | ||
3929 | } | ||
3930 | |||
3931 | u8 rtllib_ap_sec_type(struct rtllib_device *ieee) | ||
3932 | { | ||
3933 | static u8 ccmp_ie[4] = {0x00,0x50,0xf2,0x04}; | ||
3934 | static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; | ||
3935 | int wpa_ie_len= ieee->wpa_ie_len; | ||
3936 | struct rtllib_crypt_data* crypt; | ||
3937 | int encrypt; | ||
3938 | |||
3939 | crypt = ieee->crypt[ieee->tx_keyidx]; | ||
3940 | encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY) ||\ | ||
3941 | (ieee->host_encrypt && crypt && crypt->ops && \ | ||
3942 | (0 == strcmp(crypt->ops->name,"WEP"))); | ||
3943 | |||
3944 | /* simply judge */ | ||
3945 | if (encrypt && (wpa_ie_len == 0)) { | ||
3946 | return SEC_ALG_WEP; | ||
3947 | } else if ((wpa_ie_len != 0)) { | ||
3948 | if (((ieee->wpa_ie[0] == 0xdd) && (!memcmp(&(ieee->wpa_ie[14]),ccmp_ie,4))) || | ||
3949 | ((ieee->wpa_ie[0] == 0x30) && (!memcmp(&ieee->wpa_ie[10],ccmp_rsn_ie, 4)))) | ||
3950 | return SEC_ALG_CCMP; | ||
3951 | else | ||
3952 | return SEC_ALG_TKIP; | ||
3953 | } else { | ||
3954 | return SEC_ALG_NONE; | ||
3955 | } | ||
3956 | } | ||
3957 | |||
3958 | int rtllib_wpa_supplicant_ioctl(struct rtllib_device *ieee, struct iw_point *p, u8 is_mesh) | ||
3959 | { | ||
3960 | struct ieee_param *param; | ||
3961 | int ret=0; | ||
3962 | |||
3963 | down(&ieee->wx_sem); | ||
3964 | |||
3965 | if (p->length < sizeof(struct ieee_param) || !p->pointer){ | ||
3966 | ret = -EINVAL; | ||
3967 | goto out; | ||
3968 | } | ||
3969 | |||
3970 | param = (struct ieee_param *)kmalloc(p->length, GFP_KERNEL); | ||
3971 | if (param == NULL){ | ||
3972 | ret = -ENOMEM; | ||
3973 | goto out; | ||
3974 | } | ||
3975 | if (copy_from_user(param, p->pointer, p->length)) { | ||
3976 | kfree(param); | ||
3977 | ret = -EFAULT; | ||
3978 | goto out; | ||
3979 | } | ||
3980 | |||
3981 | switch (param->cmd) { | ||
3982 | |||
3983 | case IEEE_CMD_SET_WPA_PARAM: | ||
3984 | ret = rtllib_wpa_set_param(ieee, param->u.wpa_param.name, | ||
3985 | param->u.wpa_param.value); | ||
3986 | break; | ||
3987 | |||
3988 | case IEEE_CMD_SET_WPA_IE: | ||
3989 | ret = rtllib_wpa_set_wpa_ie(ieee, param, p->length); | ||
3990 | break; | ||
3991 | |||
3992 | case IEEE_CMD_SET_ENCRYPTION: | ||
3993 | ret = rtllib_wpa_set_encryption(ieee, param, p->length, 0); | ||
3994 | break; | ||
3995 | |||
3996 | case IEEE_CMD_MLME: | ||
3997 | ret = rtllib_wpa_mlme(ieee, param->u.mlme.command, | ||
3998 | param->u.mlme.reason_code); | ||
3999 | break; | ||
4000 | |||
4001 | default: | ||
4002 | printk("Unknown WPA supplicant request: %d\n",param->cmd); | ||
4003 | ret = -EOPNOTSUPP; | ||
4004 | break; | ||
4005 | } | ||
4006 | |||
4007 | if (ret == 0 && copy_to_user(p->pointer, param, p->length)) | ||
4008 | ret = -EFAULT; | ||
4009 | |||
4010 | kfree(param); | ||
4011 | out: | ||
4012 | up(&ieee->wx_sem); | ||
4013 | |||
4014 | return ret; | ||
4015 | } | ||
4016 | |||
4017 | void | ||
4018 | rtllib_MgntDisconnectIBSS(struct rtllib_device* rtllib) | ||
4019 | { | ||
4020 | u8 OpMode; | ||
4021 | u8 i; | ||
4022 | bool bFilterOutNonAssociatedBSSID = false; | ||
4023 | |||
4024 | rtllib->state = RTLLIB_NOLINK; | ||
4025 | |||
4026 | for (i=0;i<6;i++) rtllib->current_network.bssid[i]= 0x55; | ||
4027 | |||
4028 | rtllib->OpMode = RT_OP_MODE_NO_LINK; | ||
4029 | rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_BSSID, rtllib->current_network.bssid); | ||
4030 | OpMode = RT_OP_MODE_NO_LINK; | ||
4031 | rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_MEDIA_STATUS, &OpMode); | ||
4032 | rtllib_stop_send_beacons(rtllib); | ||
4033 | |||
4034 | bFilterOutNonAssociatedBSSID = false; | ||
4035 | rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_CECHK_BSSID, (u8*)(&bFilterOutNonAssociatedBSSID)); | ||
4036 | notify_wx_assoc_event(rtllib); | ||
4037 | |||
4038 | } | ||
4039 | |||
4040 | void | ||
4041 | rtllib_MlmeDisassociateRequest( | ||
4042 | struct rtllib_device* rtllib, | ||
4043 | u8* asSta, | ||
4044 | u8 asRsn | ||
4045 | ) | ||
4046 | { | ||
4047 | u8 i; | ||
4048 | u8 OpMode; | ||
4049 | |||
4050 | RemovePeerTS(rtllib, asSta); | ||
4051 | |||
4052 | |||
4053 | if (memcpy(rtllib->current_network.bssid,asSta,6) == 0) | ||
4054 | { | ||
4055 | rtllib->state = RTLLIB_NOLINK; | ||
4056 | |||
4057 | for (i=0;i<6;i++) rtllib->current_network.bssid[i] = 0x22; | ||
4058 | OpMode = RT_OP_MODE_NO_LINK; | ||
4059 | rtllib->OpMode = RT_OP_MODE_NO_LINK; | ||
4060 | rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_MEDIA_STATUS, (u8 *)(&OpMode) ); | ||
4061 | rtllib_disassociate(rtllib); | ||
4062 | |||
4063 | rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_BSSID, rtllib->current_network.bssid); | ||
4064 | |||
4065 | } | ||
4066 | |||
4067 | } | ||
4068 | |||
4069 | void | ||
4070 | rtllib_MgntDisconnectAP( | ||
4071 | struct rtllib_device* rtllib, | ||
4072 | u8 asRsn | ||
4073 | ) | ||
4074 | { | ||
4075 | bool bFilterOutNonAssociatedBSSID = false; | ||
4076 | |||
4077 | |||
4078 | #ifdef TO_DO | ||
4079 | if ( pMgntInfo->SecurityInfo.AuthMode > RT_802_11AuthModeAutoSwitch || | ||
4080 | (pMgntInfo->bAPSuportCCKM && pMgntInfo->bCCX8021xenable) ) | ||
4081 | { | ||
4082 | SecClearAllKeys(rtllib->dev); | ||
4083 | RT_TRACE(COMP_SEC, DBG_LOUD,("======>CCKM clear key...")) | ||
4084 | } | ||
4085 | #endif | ||
4086 | bFilterOutNonAssociatedBSSID = false; | ||
4087 | rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_CECHK_BSSID, (u8*)(&bFilterOutNonAssociatedBSSID)); | ||
4088 | rtllib_MlmeDisassociateRequest( rtllib, rtllib->current_network.bssid, asRsn ); | ||
4089 | |||
4090 | rtllib->state = RTLLIB_NOLINK; | ||
4091 | } | ||
4092 | |||
4093 | bool | ||
4094 | rtllib_MgntDisconnect( | ||
4095 | struct rtllib_device* rtllib, | ||
4096 | u8 asRsn | ||
4097 | ) | ||
4098 | { | ||
4099 | if (rtllib->ps != RTLLIB_PS_DISABLED) | ||
4100 | { | ||
4101 | #ifndef RTL8190P | ||
4102 | rtllib->sta_wake_up(rtllib->dev); | ||
4103 | #endif | ||
4104 | } | ||
4105 | |||
4106 | #ifdef TO_DO | ||
4107 | if (pMgntInfo->mActingAsAp) | ||
4108 | { | ||
4109 | RT_TRACE(COMP_MLME, DBG_LOUD, ("MgntDisconnect() ===> AP_DisassociateAllStation\n")); | ||
4110 | AP_DisassociateAllStation(rtllib->dev, unspec_reason); | ||
4111 | return true; | ||
4112 | } | ||
4113 | #endif | ||
4114 | |||
4115 | if ( rtllib->state == RTLLIB_LINKED ) | ||
4116 | { | ||
4117 | if ( rtllib->iw_mode == IW_MODE_ADHOC ) | ||
4118 | { | ||
4119 | rtllib_MgntDisconnectIBSS(rtllib); | ||
4120 | } | ||
4121 | if ( rtllib->iw_mode == IW_MODE_INFRA ) | ||
4122 | { | ||
4123 | #ifdef TO_DO_LIST | ||
4124 | SecClearAllKeys(Adapter); | ||
4125 | #endif | ||
4126 | rtllib_MgntDisconnectAP(rtllib, asRsn); | ||
4127 | } | ||
4128 | |||
4129 | } | ||
4130 | |||
4131 | return true; | ||
4132 | } | ||
4133 | |||
4134 | void notify_wx_assoc_event(struct rtllib_device *ieee) | ||
4135 | { | ||
4136 | union iwreq_data wrqu; | ||
4137 | |||
4138 | if (ieee->cannot_notify) | ||
4139 | return; | ||
4140 | |||
4141 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
4142 | if (ieee->state == RTLLIB_LINKED) | ||
4143 | memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); | ||
4144 | else{ | ||
4145 | |||
4146 | printk("%s(): Tell user space disconnected\n",__func__); | ||
4147 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
4148 | } | ||
4149 | wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); | ||
4150 | } | ||