Commit | Line | Data |
---|---|---|
762b759a LF |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright(c) 2007 - 2012 Realtek Corporation. */ | |
3 | ||
15865124 PP |
4 | #define _RTW_RECV_C_ |
5 | ||
6 | #include <osdep_service.h> | |
7 | #include <drv_types.h> | |
8 | #include <recv_osdep.h> | |
9 | #include <mlme_osdep.h> | |
10 | #include <ip.h> | |
11 | #include <if_ether.h> | |
12 | #include <ethernet.h> | |
13 | #include <usb_ops.h> | |
14 | #include <wifi.h> | |
15 | ||
16 | static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37}; | |
17 | static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; | |
18 | ||
19 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | |
20 | static u8 rtw_bridge_tunnel_header[] = { | |
21 | 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 | |
22 | }; | |
23 | ||
24 | static u8 rtw_rfc1042_header[] = { | |
25 | 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 | |
26 | }; | |
27 | ||
15865124 | 28 | void rtw_signal_stat_timer_hdl(struct timer_list *); |
15865124 PP |
29 | |
30 | void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) | |
31 | { | |
32 | ||
33 | memset((u8 *)psta_recvpriv, 0, sizeof (struct sta_recv_priv)); | |
34 | ||
35 | spin_lock_init(&psta_recvpriv->lock); | |
36 | ||
37 | _rtw_init_queue(&psta_recvpriv->defrag_q); | |
38 | ||
39 | } | |
40 | ||
41 | int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) | |
42 | { | |
43 | int i; | |
44 | ||
45 | struct recv_frame *precvframe; | |
46 | ||
47 | int res = _SUCCESS; | |
48 | ||
49 | spin_lock_init(&precvpriv->lock); | |
50 | ||
51 | _rtw_init_queue(&precvpriv->free_recv_queue); | |
52 | _rtw_init_queue(&precvpriv->recv_pending_queue); | |
53 | _rtw_init_queue(&precvpriv->uc_swdec_pending_queue); | |
54 | ||
55 | precvpriv->adapter = padapter; | |
56 | ||
57 | precvpriv->free_recvframe_cnt = NR_RECVFRAME; | |
58 | ||
59 | rtw_os_recv_resource_init(precvpriv, padapter); | |
60 | ||
61 | precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ); | |
62 | ||
63 | if (precvpriv->pallocated_frame_buf == NULL) { | |
64 | res = _FAIL; | |
65 | goto exit; | |
66 | } | |
67 | ||
68 | precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); | |
69 | ||
70 | precvframe = (struct recv_frame *)precvpriv->precv_frame_buf; | |
71 | ||
72 | for (i = 0; i < NR_RECVFRAME; i++) { | |
73 | INIT_LIST_HEAD(&(precvframe->list)); | |
74 | ||
75 | list_add_tail(&(precvframe->list), &(precvpriv->free_recv_queue.queue)); | |
76 | ||
77 | res = rtw_os_recv_resource_alloc(padapter, precvframe); | |
78 | ||
79 | precvframe->len = 0; | |
80 | ||
81 | precvframe->adapter = padapter; | |
82 | precvframe++; | |
83 | } | |
84 | precvpriv->rx_pending_cnt = 1; | |
85 | ||
86 | sema_init(&precvpriv->allrxreturnevt, 0); | |
87 | ||
88 | res = rtw_hal_init_recv_priv(padapter); | |
89 | ||
15865124 | 90 | timer_setup(&precvpriv->signal_stat_timer, rtw_signal_stat_timer_hdl, 0); |
15865124 PP |
91 | precvpriv->signal_stat_sampling_interval = 1000; /* ms */ |
92 | ||
93 | rtw_set_signal_stat_timer(precvpriv); | |
94 | exit: | |
95 | ||
96 | return res; | |
97 | } | |
98 | ||
99 | static void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv) | |
100 | { | |
101 | _rtw_spinlock_free(&precvpriv->lock); | |
102 | _rtw_spinlock_free(&precvpriv->free_recv_queue.lock); | |
103 | _rtw_spinlock_free(&precvpriv->recv_pending_queue.lock); | |
104 | ||
105 | _rtw_spinlock_free(&precvpriv->free_recv_buf_queue.lock); | |
106 | } | |
107 | ||
108 | void _rtw_free_recv_priv (struct recv_priv *precvpriv) | |
109 | { | |
110 | struct adapter *padapter = precvpriv->adapter; | |
111 | ||
112 | rtw_free_uc_swdec_pending_queue(padapter); | |
113 | ||
114 | rtw_mfree_recv_priv_lock(precvpriv); | |
115 | ||
116 | rtw_os_recv_resource_free(precvpriv); | |
117 | ||
118 | if (precvpriv->pallocated_frame_buf) { | |
119 | rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ); | |
120 | } | |
121 | ||
122 | rtw_hal_free_recv_priv(padapter); | |
123 | ||
124 | } | |
125 | ||
126 | struct recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue) | |
127 | { | |
128 | struct recv_frame *hdr; | |
129 | struct list_head *plist, *phead; | |
130 | struct adapter *padapter; | |
131 | struct recv_priv *precvpriv; | |
132 | ||
133 | if (list_empty(&pfree_recv_queue->queue)) { | |
134 | hdr = NULL; | |
135 | } else { | |
136 | phead = get_list_head(pfree_recv_queue); | |
137 | ||
138 | plist = phead->next; | |
139 | ||
140 | hdr = container_of(plist, struct recv_frame, list); | |
141 | ||
142 | list_del_init(&hdr->list); | |
143 | padapter = hdr->adapter; | |
144 | if (padapter != NULL) { | |
145 | precvpriv = &padapter->recvpriv; | |
146 | if (pfree_recv_queue == &precvpriv->free_recv_queue) | |
147 | precvpriv->free_recvframe_cnt--; | |
148 | } | |
149 | } | |
150 | ||
151 | return (struct recv_frame *)hdr; | |
152 | } | |
153 | ||
154 | struct recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue) | |
155 | { | |
156 | struct recv_frame *precvframe; | |
157 | ||
158 | spin_lock_bh(&pfree_recv_queue->lock); | |
159 | ||
160 | precvframe = _rtw_alloc_recvframe(pfree_recv_queue); | |
161 | ||
162 | spin_unlock_bh(&pfree_recv_queue->lock); | |
163 | ||
164 | return precvframe; | |
165 | } | |
166 | ||
167 | void rtw_init_recvframe(struct recv_frame *precvframe, struct recv_priv *precvpriv) | |
168 | { | |
169 | /* Perry: This can be removed */ | |
170 | INIT_LIST_HEAD(&precvframe->list); | |
171 | ||
172 | precvframe->len = 0; | |
173 | } | |
174 | ||
175 | int rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv_queue) | |
176 | { | |
177 | struct adapter *padapter; | |
178 | struct recv_priv *precvpriv; | |
179 | ||
180 | if (!precvframe) | |
181 | return _FAIL; | |
182 | padapter = precvframe->adapter; | |
183 | precvpriv = &padapter->recvpriv; | |
184 | if (precvframe->pkt) { | |
185 | dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */ | |
186 | precvframe->pkt = NULL; | |
187 | } | |
188 | ||
189 | spin_lock_bh(&pfree_recv_queue->lock); | |
190 | ||
191 | list_del_init(&(precvframe->list)); | |
192 | ||
193 | precvframe->len = 0; | |
194 | ||
195 | list_add_tail(&(precvframe->list), get_list_head(pfree_recv_queue)); | |
196 | ||
197 | if (padapter != NULL) { | |
198 | if (pfree_recv_queue == &precvpriv->free_recv_queue) | |
199 | precvpriv->free_recvframe_cnt++; | |
200 | } | |
201 | ||
202 | spin_unlock_bh(&pfree_recv_queue->lock); | |
203 | ||
204 | return _SUCCESS; | |
205 | } | |
206 | ||
207 | int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) | |
208 | { | |
209 | struct adapter *padapter = precvframe->adapter; | |
210 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
211 | ||
212 | list_del_init(&(precvframe->list)); | |
213 | list_add_tail(&(precvframe->list), get_list_head(queue)); | |
214 | ||
215 | if (padapter != NULL) { | |
216 | if (queue == &precvpriv->free_recv_queue) | |
217 | precvpriv->free_recvframe_cnt++; | |
218 | } | |
219 | ||
220 | return _SUCCESS; | |
221 | } | |
222 | ||
223 | int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) | |
224 | { | |
225 | int ret; | |
226 | ||
227 | spin_lock_bh(&queue->lock); | |
228 | ret = _rtw_enqueue_recvframe(precvframe, queue); | |
229 | spin_unlock_bh(&queue->lock); | |
230 | ||
231 | return ret; | |
232 | } | |
233 | ||
234 | /* | |
235 | caller : defrag ; recvframe_chk_defrag in recv_thread (passive) | |
236 | pframequeue: defrag_queue : will be accessed in recv_thread (passive) | |
237 | ||
238 | using spinlock to protect | |
239 | ||
240 | */ | |
241 | ||
242 | void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue) | |
243 | { | |
244 | struct recv_frame *hdr; | |
245 | struct list_head *plist, *phead; | |
246 | ||
247 | spin_lock(&pframequeue->lock); | |
248 | ||
249 | phead = get_list_head(pframequeue); | |
250 | plist = phead->next; | |
251 | ||
252 | while (phead != plist) { | |
253 | hdr = container_of(plist, struct recv_frame, list); | |
254 | ||
255 | plist = plist->next; | |
256 | ||
257 | rtw_free_recvframe((struct recv_frame *)hdr, pfree_recv_queue); | |
258 | } | |
259 | ||
260 | spin_unlock(&pframequeue->lock); | |
261 | ||
262 | } | |
263 | ||
264 | u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) | |
265 | { | |
266 | u32 cnt = 0; | |
267 | struct recv_frame *pending_frame; | |
268 | while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { | |
269 | rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); | |
270 | DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__); | |
271 | cnt++; | |
272 | } | |
273 | ||
274 | return cnt; | |
275 | } | |
276 | ||
277 | int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) | |
278 | { | |
279 | spin_lock_bh(&queue->lock); | |
280 | ||
281 | list_del_init(&precvbuf->list); | |
282 | list_add(&precvbuf->list, get_list_head(queue)); | |
283 | ||
284 | spin_unlock_bh(&queue->lock); | |
285 | ||
286 | return _SUCCESS; | |
287 | } | |
288 | ||
289 | int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) | |
290 | { | |
291 | unsigned long flags; | |
292 | ||
293 | spin_lock_irqsave(&queue->lock, flags); | |
294 | ||
295 | list_del_init(&precvbuf->list); | |
296 | ||
297 | list_add_tail(&precvbuf->list, get_list_head(queue)); | |
298 | spin_unlock_irqrestore(&queue->lock, flags); | |
299 | return _SUCCESS; | |
300 | } | |
301 | ||
302 | struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue) | |
303 | { | |
304 | struct recv_buf *precvbuf; | |
305 | struct list_head *plist, *phead; | |
306 | unsigned long flags; | |
307 | ||
308 | spin_lock_irqsave(&queue->lock, flags); | |
309 | ||
310 | if (list_empty(&queue->queue)) { | |
311 | precvbuf = NULL; | |
312 | } else { | |
313 | phead = get_list_head(queue); | |
314 | ||
315 | plist = phead->next; | |
316 | ||
317 | precvbuf = container_of(plist, struct recv_buf, list); | |
318 | ||
319 | list_del_init(&precvbuf->list); | |
320 | } | |
321 | ||
322 | spin_unlock_irqrestore(&queue->lock, flags); | |
323 | ||
324 | return precvbuf; | |
325 | } | |
326 | ||
327 | static int recvframe_chkmic(struct adapter *adapter, struct recv_frame *precvframe) | |
328 | { | |
329 | int i, res = _SUCCESS; | |
330 | u32 datalen; | |
331 | u8 miccode[8]; | |
332 | u8 bmic_err = false, brpt_micerror = true; | |
333 | u8 *pframe, *payload, *pframemic; | |
334 | u8 *mickey; | |
335 | struct sta_info *stainfo; | |
336 | struct rx_pkt_attrib *prxattrib = &precvframe->attrib; | |
337 | struct security_priv *psecuritypriv = &adapter->securitypriv; | |
338 | ||
339 | struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; | |
340 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); | |
341 | ||
342 | stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); | |
343 | ||
344 | if (prxattrib->encrypt == _TKIP_) { | |
345 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:prxattrib->encrypt==_TKIP_\n")); | |
346 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic:da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", | |
347 | prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5])); | |
348 | ||
349 | /* calculate mic code */ | |
350 | if (stainfo != NULL) { | |
351 | if (IS_MCAST(prxattrib->ra)) { | |
352 | mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; | |
353 | ||
354 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n")); | |
355 | ||
356 | if (!psecuritypriv) { | |
357 | res = _FAIL; | |
358 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n")); | |
359 | DBG_88E("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); | |
360 | goto exit; | |
361 | } | |
362 | } else { | |
363 | mickey = &stainfo->dot11tkiprxmickey.skey[0]; | |
364 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n recvframe_chkmic: unicast key\n")); | |
365 | } | |
366 | ||
367 | datalen = precvframe->len-prxattrib->hdrlen-prxattrib->iv_len-prxattrib->icv_len-8;/* icv_len included the mic code */ | |
368 | pframe = precvframe->rx_data; | |
369 | payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; | |
370 | ||
371 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len)); | |
372 | rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], | |
373 | (unsigned char)prxattrib->priority); /* care the length of the data */ | |
374 | ||
375 | pframemic = payload+datalen; | |
376 | ||
377 | bmic_err = false; | |
378 | ||
379 | for (i = 0; i < 8; i++) { | |
380 | if (miccode[i] != *(pframemic+i)) { | |
381 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, | |
382 | ("recvframe_chkmic:miccode[%d](%02x)!=*(pframemic+%d)(%02x) ", | |
383 | i, miccode[i], i, *(pframemic+i))); | |
384 | bmic_err = true; | |
385 | } | |
386 | } | |
387 | ||
388 | if (bmic_err) { | |
389 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, | |
390 | ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", | |
391 | *(pframemic-8), *(pframemic-7), *(pframemic-6), | |
392 | *(pframemic-5), *(pframemic-4), *(pframemic-3), | |
393 | *(pframemic-2), *(pframemic-1))); | |
394 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, | |
395 | ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", | |
396 | *(pframemic-16), *(pframemic-15), *(pframemic-14), | |
397 | *(pframemic-13), *(pframemic-12), *(pframemic-11), | |
398 | *(pframemic-10), *(pframemic-9))); | |
399 | { | |
400 | uint i; | |
401 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ======demp packet (len=%d)======\n", precvframe->len)); | |
402 | for (i = 0; i < precvframe->len; i = i+8) { | |
403 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", | |
404 | *(precvframe->rx_data+i), *(precvframe->rx_data+i+1), | |
405 | *(precvframe->rx_data+i+2), *(precvframe->rx_data+i+3), | |
406 | *(precvframe->rx_data+i+4), *(precvframe->rx_data+i+5), | |
407 | *(precvframe->rx_data+i+6), *(precvframe->rx_data+i+7))); | |
408 | } | |
409 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n ====== demp packet end [len=%d]======\n", precvframe->len)); | |
410 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("\n hrdlen=%d,\n", prxattrib->hdrlen)); | |
411 | } | |
412 | ||
413 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, | |
414 | ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ", | |
415 | prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], | |
416 | prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey)); | |
417 | ||
418 | /* double check key_index for some timing issue , */ | |
419 | /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ | |
420 | if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index)) | |
421 | brpt_micerror = false; | |
422 | ||
423 | if ((prxattrib->bdecrypted) && (brpt_micerror)) { | |
424 | rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra)); | |
425 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); | |
426 | DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); | |
427 | } else { | |
428 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); | |
429 | DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); | |
430 | } | |
431 | res = _FAIL; | |
432 | } else { | |
433 | /* mic checked ok */ | |
434 | if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) { | |
435 | psecuritypriv->bcheck_grpkey = true; | |
436 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true")); | |
437 | } | |
438 | } | |
439 | } else { | |
440 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo==NULL!!!\n")); | |
441 | } | |
442 | ||
443 | recvframe_pull_tail(precvframe, 8); | |
444 | } | |
445 | ||
446 | exit: | |
447 | ||
448 | return res; | |
449 | } | |
450 | ||
451 | /* decrypt and set the ivlen, icvlen of the recv_frame */ | |
452 | static struct recv_frame *decryptor(struct adapter *padapter, struct recv_frame *precv_frame) | |
453 | { | |
454 | struct rx_pkt_attrib *prxattrib = &precv_frame->attrib; | |
455 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
456 | struct recv_frame *return_packet = precv_frame; | |
457 | u32 res = _SUCCESS; | |
458 | ||
459 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt)); | |
460 | ||
461 | if (prxattrib->encrypt > 0) { | |
462 | u8 *iv = precv_frame->rx_data+prxattrib->hdrlen; | |
463 | prxattrib->key_index = (((iv[3])>>6)&0x3); | |
464 | ||
465 | if (prxattrib->key_index > WEP_KEYS) { | |
466 | DBG_88E("prxattrib->key_index(%d)>WEP_KEYS\n", prxattrib->key_index); | |
467 | ||
468 | switch (prxattrib->encrypt) { | |
469 | case _WEP40_: | |
470 | case _WEP104_: | |
471 | prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex; | |
472 | break; | |
473 | case _TKIP_: | |
474 | case _AES_: | |
475 | default: | |
476 | prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid; | |
477 | break; | |
478 | } | |
479 | } | |
480 | } | |
481 | ||
482 | if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt))) { | |
483 | psecuritypriv->hw_decrypted = false; | |
484 | ||
485 | switch (prxattrib->encrypt) { | |
486 | case _WEP40_: | |
487 | case _WEP104_: | |
488 | rtw_wep_decrypt(padapter, (u8 *)precv_frame); | |
489 | break; | |
490 | case _TKIP_: | |
491 | res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); | |
492 | break; | |
493 | case _AES_: | |
494 | res = rtw_aes_decrypt(padapter, (u8 *)precv_frame); | |
495 | break; | |
496 | default: | |
497 | break; | |
498 | } | |
499 | } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && | |
500 | (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_)) | |
501 | psecuritypriv->hw_decrypted = true; | |
502 | ||
503 | if (res == _FAIL) { | |
504 | rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue); | |
505 | return_packet = NULL; | |
506 | } else { | |
507 | prxattrib->bdecrypted = true; | |
508 | } | |
509 | ||
510 | return return_packet; | |
511 | } | |
512 | ||
513 | /* set the security information in the recv_frame */ | |
514 | static struct recv_frame *portctrl(struct adapter *adapter, struct recv_frame *precv_frame) | |
515 | { | |
516 | u8 *psta_addr, *ptr; | |
517 | uint auth_alg; | |
518 | struct recv_frame *pfhdr; | |
519 | struct sta_info *psta; | |
520 | struct sta_priv *pstapriv; | |
521 | struct recv_frame *prtnframe; | |
522 | u16 ether_type; | |
523 | u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ | |
524 | struct rx_pkt_attrib *pattrib; | |
525 | __be16 be_tmp; | |
526 | ||
527 | pstapriv = &adapter->stapriv; | |
528 | ||
529 | auth_alg = adapter->securitypriv.dot11AuthAlgrthm; | |
530 | ||
531 | ptr = precv_frame->rx_data; | |
532 | pfhdr = precv_frame; | |
533 | pattrib = &pfhdr->attrib; | |
534 | psta_addr = pattrib->ta; | |
535 | ||
536 | prtnframe = NULL; | |
537 | ||
538 | psta = rtw_get_stainfo(pstapriv, psta_addr); | |
539 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, | |
540 | ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", | |
541 | adapter->securitypriv.dot11AuthAlgrthm)); | |
542 | ||
543 | if (auth_alg == 2) { | |
544 | if ((psta != NULL) && (psta->ieee8021x_blocked)) { | |
545 | /* blocked */ | |
546 | /* only accept EAPOL frame */ | |
547 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n")); | |
548 | ||
549 | prtnframe = precv_frame; | |
550 | ||
551 | /* get ether_type */ | |
552 | ptr = ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE; | |
553 | memcpy(&be_tmp, ptr, 2); | |
554 | ether_type = ntohs(be_tmp); | |
555 | ||
556 | if (ether_type == eapol_type) { | |
557 | prtnframe = precv_frame; | |
558 | } else { | |
559 | /* free this frame */ | |
560 | rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue); | |
561 | prtnframe = NULL; | |
562 | } | |
563 | } else { | |
564 | /* allowed */ | |
565 | /* check decryption status, and decrypt the frame if needed */ | |
566 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n")); | |
567 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:precv_frame->hdr.attrib.privacy=%x\n", precv_frame->attrib.privacy)); | |
568 | ||
569 | if (pattrib->bdecrypted == 0) | |
570 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted)); | |
571 | ||
572 | prtnframe = precv_frame; | |
573 | /* check is the EAPOL frame or not (Rekey) */ | |
574 | if (ether_type == eapol_type) { | |
575 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type==0x888e\n")); | |
576 | /* check Rekey */ | |
577 | ||
578 | prtnframe = precv_frame; | |
579 | } else { | |
580 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type=0x%04x\n", ether_type)); | |
581 | } | |
582 | } | |
583 | } else { | |
584 | prtnframe = precv_frame; | |
585 | } | |
586 | ||
587 | return prtnframe; | |
588 | } | |
589 | ||
590 | static int recv_decache(struct recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) | |
591 | { | |
592 | int tid = precv_frame->attrib.priority; | |
593 | ||
594 | u16 seq_ctrl = ((precv_frame->attrib.seq_num&0xffff) << 4) | | |
595 | (precv_frame->attrib.frag_num & 0xf); | |
596 | ||
597 | if (tid > 15) { | |
598 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid)); | |
599 | ||
600 | return _FAIL; | |
601 | } | |
602 | ||
603 | if (1) {/* if (bretry) */ | |
604 | if (seq_ctrl == prxcache->tid_rxseq[tid]) { | |
605 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid])); | |
606 | ||
607 | return _FAIL; | |
608 | } | |
609 | } | |
610 | ||
611 | prxcache->tid_rxseq[tid] = seq_ctrl; | |
612 | ||
613 | return _SUCCESS; | |
614 | } | |
615 | ||
616 | void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame); | |
617 | void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame) | |
618 | { | |
619 | #ifdef CONFIG_88EU_AP_MODE | |
620 | unsigned char pwrbit; | |
621 | u8 *ptr = precv_frame->rx_data; | |
622 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
623 | struct sta_priv *pstapriv = &padapter->stapriv; | |
624 | struct sta_info *psta = NULL; | |
625 | ||
626 | psta = rtw_get_stainfo(pstapriv, pattrib->src); | |
627 | ||
628 | pwrbit = GetPwrMgt(ptr); | |
629 | ||
630 | if (psta) { | |
631 | if (pwrbit) { | |
632 | if (!(psta->state & WIFI_SLEEP_STATE)) | |
633 | stop_sta_xmit(padapter, psta); | |
634 | } else { | |
635 | if (psta->state & WIFI_SLEEP_STATE) | |
636 | wakeup_sta_to_xmit(padapter, psta); | |
637 | } | |
638 | } | |
639 | ||
640 | #endif | |
641 | } | |
642 | ||
643 | static void process_wmmps_data(struct adapter *padapter, struct recv_frame *precv_frame) | |
644 | { | |
645 | #ifdef CONFIG_88EU_AP_MODE | |
646 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
647 | struct sta_priv *pstapriv = &padapter->stapriv; | |
648 | struct sta_info *psta = NULL; | |
649 | ||
650 | psta = rtw_get_stainfo(pstapriv, pattrib->src); | |
651 | ||
652 | if (!psta) | |
653 | return; | |
654 | ||
655 | if (!psta->qos_option) | |
656 | return; | |
657 | ||
658 | if (!(psta->qos_info&0xf)) | |
659 | return; | |
660 | ||
661 | if (psta->state&WIFI_SLEEP_STATE) { | |
662 | u8 wmmps_ac = 0; | |
663 | ||
664 | switch (pattrib->priority) { | |
665 | case 1: | |
666 | case 2: | |
667 | wmmps_ac = psta->uapsd_bk&BIT(1); | |
668 | break; | |
669 | case 4: | |
670 | case 5: | |
671 | wmmps_ac = psta->uapsd_vi&BIT(1); | |
672 | break; | |
673 | case 6: | |
674 | case 7: | |
675 | wmmps_ac = psta->uapsd_vo&BIT(1); | |
676 | break; | |
677 | case 0: | |
678 | case 3: | |
679 | default: | |
680 | wmmps_ac = psta->uapsd_be&BIT(1); | |
681 | break; | |
682 | } | |
683 | ||
684 | if (wmmps_ac) { | |
685 | if (psta->sleepq_ac_len > 0) { | |
686 | /* process received triggered frame */ | |
687 | xmit_delivery_enabled_frames(padapter, psta); | |
688 | } else { | |
689 | /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */ | |
690 | issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0); | |
691 | } | |
692 | } | |
693 | } | |
694 | ||
695 | #endif | |
696 | } | |
697 | ||
698 | static void count_rx_stats(struct adapter *padapter, struct recv_frame *prframe, struct sta_info *sta) | |
699 | { | |
700 | int sz; | |
701 | struct sta_info *psta = NULL; | |
702 | struct stainfo_stats *pstats = NULL; | |
703 | struct rx_pkt_attrib *pattrib = &prframe->attrib; | |
704 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
705 | ||
706 | sz = get_recvframe_len(prframe); | |
707 | precvpriv->rx_bytes += sz; | |
708 | ||
709 | padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; | |
710 | ||
711 | if ((!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst))) | |
712 | padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; | |
713 | ||
714 | if (sta) | |
715 | psta = sta; | |
716 | else | |
717 | psta = prframe->psta; | |
718 | ||
719 | if (psta) { | |
720 | pstats = &psta->sta_stats; | |
721 | ||
722 | pstats->rx_data_pkts++; | |
723 | pstats->rx_bytes += sz; | |
724 | } | |
725 | } | |
726 | ||
727 | int sta2sta_data_frame( | |
728 | struct adapter *adapter, | |
729 | struct recv_frame *precv_frame, | |
730 | struct sta_info **psta | |
731 | ); | |
732 | ||
733 | int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, struct sta_info **psta) | |
734 | { | |
735 | u8 *ptr = precv_frame->rx_data; | |
736 | int ret = _SUCCESS; | |
737 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
738 | struct sta_priv *pstapriv = &adapter->stapriv; | |
739 | struct mlme_priv *pmlmepriv = &adapter->mlmepriv; | |
740 | u8 *mybssid = get_bssid(pmlmepriv); | |
741 | u8 *myhwaddr = myid(&adapter->eeprompriv); | |
742 | u8 *sta_addr = NULL; | |
743 | int bmcast = IS_MCAST(pattrib->dst); | |
744 | ||
745 | if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || | |
746 | (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { | |
747 | /* filter packets that SA is myself or multicast or broadcast */ | |
748 | if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { | |
749 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n")); | |
750 | ret = _FAIL; | |
751 | goto exit; | |
752 | } | |
753 | ||
754 | if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { | |
755 | ret = _FAIL; | |
756 | goto exit; | |
757 | } | |
758 | ||
759 | if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || | |
760 | !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || | |
761 | memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { | |
762 | ret = _FAIL; | |
763 | goto exit; | |
764 | } | |
765 | ||
766 | sta_addr = pattrib->src; | |
767 | } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { | |
768 | /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */ | |
769 | if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) { | |
770 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("bssid!=TA under STATION_MODE; drop pkt\n")); | |
771 | ret = _FAIL; | |
772 | goto exit; | |
773 | } | |
774 | sta_addr = pattrib->bssid; | |
775 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | |
776 | if (bmcast) { | |
777 | /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */ | |
778 | if (!IS_MCAST(pattrib->bssid)) { | |
779 | ret = _FAIL; | |
780 | goto exit; | |
781 | } | |
782 | } else { /* not mc-frame */ | |
783 | /* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */ | |
784 | if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) { | |
785 | ret = _FAIL; | |
786 | goto exit; | |
787 | } | |
788 | ||
789 | sta_addr = pattrib->src; | |
790 | } | |
791 | } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { | |
792 | memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); | |
793 | memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); | |
794 | memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); | |
795 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
796 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
797 | ||
798 | sta_addr = mybssid; | |
799 | } else { | |
800 | ret = _FAIL; | |
801 | } | |
802 | ||
803 | if (bmcast) | |
804 | *psta = rtw_get_bcmc_stainfo(adapter); | |
805 | else | |
806 | *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ | |
807 | ||
808 | if (*psta == NULL) { | |
809 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n")); | |
810 | if (adapter->registrypriv.mp_mode == 1) { | |
811 | if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) | |
812 | adapter->mppriv.rx_pktloss++; | |
813 | } | |
814 | ret = _FAIL; | |
815 | goto exit; | |
816 | } | |
817 | ||
818 | exit: | |
819 | ||
820 | return ret; | |
821 | } | |
822 | ||
823 | static int ap2sta_data_frame ( | |
824 | struct adapter *adapter, | |
825 | struct recv_frame *precv_frame, | |
826 | struct sta_info **psta) | |
827 | { | |
828 | u8 *ptr = precv_frame->rx_data; | |
829 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
830 | int ret = _SUCCESS; | |
831 | struct sta_priv *pstapriv = &adapter->stapriv; | |
832 | struct mlme_priv *pmlmepriv = &adapter->mlmepriv; | |
833 | u8 *mybssid = get_bssid(pmlmepriv); | |
834 | u8 *myhwaddr = myid(&adapter->eeprompriv); | |
835 | int bmcast = IS_MCAST(pattrib->dst); | |
836 | ||
837 | if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) && | |
838 | (check_fwstate(pmlmepriv, _FW_LINKED) == true || | |
839 | check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) { | |
840 | /* filter packets that SA is myself or multicast or broadcast */ | |
841 | if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { | |
842 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA==myself\n")); | |
843 | ret = _FAIL; | |
844 | goto exit; | |
845 | } | |
846 | ||
847 | /* da should be for me */ | |
848 | if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { | |
849 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, | |
850 | (" ap2sta_data_frame: compare DA fail; DA=%pM\n", (pattrib->dst))); | |
851 | ret = _FAIL; | |
852 | goto exit; | |
853 | } | |
854 | ||
855 | /* check BSSID */ | |
856 | if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || | |
857 | !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || | |
858 | (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { | |
859 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, | |
860 | (" ap2sta_data_frame: compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid))); | |
861 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid))); | |
862 | ||
863 | if (!bmcast) { | |
864 | DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid)); | |
865 | issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | |
866 | } | |
867 | ||
868 | ret = _FAIL; | |
869 | goto exit; | |
870 | } | |
871 | ||
872 | if (bmcast) | |
873 | *psta = rtw_get_bcmc_stainfo(adapter); | |
874 | else | |
875 | *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */ | |
876 | ||
877 | if (*psta == NULL) { | |
878 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("ap2sta: can't get psta under STATION_MODE ; drop pkt\n")); | |
879 | ret = _FAIL; | |
880 | goto exit; | |
881 | } | |
882 | ||
883 | /* if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { */ | |
884 | /* */ | |
885 | ||
886 | if (GetFrameSubType(ptr) & BIT(6)) { | |
887 | /* No data, will not indicate to upper layer, temporily count it here */ | |
888 | count_rx_stats(adapter, precv_frame, *psta); | |
889 | ret = RTW_RX_HANDLED; | |
890 | goto exit; | |
891 | } | |
892 | } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && | |
893 | (check_fwstate(pmlmepriv, _FW_LINKED) == true)) { | |
894 | memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); | |
895 | memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); | |
896 | memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); | |
897 | memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); | |
898 | memcpy(pattrib->ta, pattrib->src, ETH_ALEN); | |
899 | ||
900 | /* */ | |
901 | memcpy(pattrib->bssid, mybssid, ETH_ALEN); | |
902 | ||
903 | *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ | |
904 | if (*psta == NULL) { | |
905 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n")); | |
906 | ret = _FAIL; | |
907 | goto exit; | |
908 | } | |
909 | } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { | |
910 | /* Special case */ | |
911 | ret = RTW_RX_HANDLED; | |
912 | goto exit; | |
913 | } else { | |
914 | if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) { | |
915 | *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ | |
916 | if (*psta == NULL) { | |
917 | DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid)); | |
918 | ||
919 | issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | |
920 | } | |
921 | } | |
922 | ||
923 | ret = _FAIL; | |
924 | } | |
925 | ||
926 | exit: | |
927 | ||
928 | return ret; | |
929 | } | |
930 | ||
931 | static int sta2ap_data_frame(struct adapter *adapter, | |
932 | struct recv_frame *precv_frame, | |
933 | struct sta_info **psta) | |
934 | { | |
935 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
936 | struct sta_priv *pstapriv = &adapter->stapriv; | |
937 | struct mlme_priv *pmlmepriv = &adapter->mlmepriv; | |
938 | u8 *ptr = precv_frame->rx_data; | |
939 | unsigned char *mybssid = get_bssid(pmlmepriv); | |
940 | int ret = _SUCCESS; | |
941 | ||
942 | if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { | |
943 | /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */ | |
944 | if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { | |
945 | ret = _FAIL; | |
946 | goto exit; | |
947 | } | |
948 | ||
949 | *psta = rtw_get_stainfo(pstapriv, pattrib->src); | |
950 | if (*psta == NULL) { | |
951 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n")); | |
952 | DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src)); | |
953 | ||
954 | issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | |
955 | ||
956 | ret = RTW_RX_HANDLED; | |
957 | goto exit; | |
958 | } | |
959 | ||
960 | process_pwrbit_data(adapter, precv_frame); | |
961 | ||
962 | if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { | |
963 | process_wmmps_data(adapter, precv_frame); | |
964 | } | |
965 | ||
966 | if (GetFrameSubType(ptr) & BIT(6)) { | |
967 | /* No data, will not indicate to upper layer, temporily count it here */ | |
968 | count_rx_stats(adapter, precv_frame, *psta); | |
969 | ret = RTW_RX_HANDLED; | |
970 | goto exit; | |
971 | } | |
972 | } else { | |
973 | u8 *myhwaddr = myid(&adapter->eeprompriv); | |
974 | if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { | |
975 | ret = RTW_RX_HANDLED; | |
976 | goto exit; | |
977 | } | |
978 | DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src)); | |
979 | issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | |
980 | ret = RTW_RX_HANDLED; | |
981 | goto exit; | |
982 | } | |
983 | ||
984 | exit: | |
985 | ||
986 | return ret; | |
987 | } | |
988 | ||
989 | static int validate_recv_ctrl_frame(struct adapter *padapter, | |
990 | struct recv_frame *precv_frame) | |
991 | { | |
992 | #ifdef CONFIG_88EU_AP_MODE | |
993 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
994 | struct sta_priv *pstapriv = &padapter->stapriv; | |
995 | u8 *pframe = precv_frame->rx_data; | |
996 | /* uint len = precv_frame->len; */ | |
997 | ||
998 | if (GetFrameType(pframe) != WIFI_CTRL_TYPE) | |
999 | return _FAIL; | |
1000 | ||
1001 | /* receive the frames that ra(a1) is my address */ | |
1002 | if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN)) | |
1003 | return _FAIL; | |
1004 | ||
1005 | /* only handle ps-poll */ | |
1006 | if (GetFrameSubType(pframe) == WIFI_PSPOLL) { | |
1007 | u16 aid; | |
1008 | u8 wmmps_ac = 0; | |
1009 | struct sta_info *psta = NULL; | |
1010 | ||
1011 | aid = GetAid(pframe); | |
1012 | psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); | |
1013 | ||
1014 | if ((psta == NULL) || (psta->aid != aid)) | |
1015 | return _FAIL; | |
1016 | ||
1017 | /* for rx pkt statistics */ | |
1018 | psta->sta_stats.rx_ctrl_pkts++; | |
1019 | ||
1020 | switch (pattrib->priority) { | |
1021 | case 1: | |
1022 | case 2: | |
1023 | wmmps_ac = psta->uapsd_bk&BIT(0); | |
1024 | break; | |
1025 | case 4: | |
1026 | case 5: | |
1027 | wmmps_ac = psta->uapsd_vi&BIT(0); | |
1028 | break; | |
1029 | case 6: | |
1030 | case 7: | |
1031 | wmmps_ac = psta->uapsd_vo&BIT(0); | |
1032 | break; | |
1033 | case 0: | |
1034 | case 3: | |
1035 | default: | |
1036 | wmmps_ac = psta->uapsd_be&BIT(0); | |
1037 | break; | |
1038 | } | |
1039 | ||
1040 | if (wmmps_ac) | |
1041 | return _FAIL; | |
1042 | ||
1043 | if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { | |
1044 | DBG_88E("%s alive check-rx ps-poll\n", __func__); | |
1045 | psta->expire_to = pstapriv->expire_to; | |
1046 | psta->state ^= WIFI_STA_ALIVE_CHK_STATE; | |
1047 | } | |
1048 | ||
1049 | if ((psta->state&WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap&BIT(psta->aid))) { | |
1050 | struct list_head *xmitframe_plist, *xmitframe_phead; | |
1051 | struct xmit_frame *pxmitframe = NULL; | |
1052 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | |
1053 | ||
1054 | spin_lock_bh(&pxmitpriv->lock); | |
1055 | ||
1056 | xmitframe_phead = get_list_head(&psta->sleep_q); | |
1057 | xmitframe_plist = xmitframe_phead->next; | |
1058 | ||
1059 | if (xmitframe_phead != xmitframe_plist) { | |
1060 | pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); | |
1061 | ||
1062 | xmitframe_plist = xmitframe_plist->next; | |
1063 | ||
1064 | list_del_init(&pxmitframe->list); | |
1065 | ||
1066 | psta->sleepq_len--; | |
1067 | ||
1068 | if (psta->sleepq_len > 0) | |
1069 | pxmitframe->attrib.mdata = 1; | |
1070 | else | |
1071 | pxmitframe->attrib.mdata = 0; | |
1072 | ||
1073 | pxmitframe->attrib.triggered = 1; | |
1074 | ||
1075 | rtw_hal_xmitframe_enqueue(padapter, pxmitframe); | |
1076 | ||
1077 | if (psta->sleepq_len == 0) { | |
1078 | pstapriv->tim_bitmap &= ~BIT(psta->aid); | |
1079 | ||
1080 | /* upate BCN for TIM IE */ | |
1081 | /* update_BCNTIM(padapter); */ | |
1082 | update_beacon(padapter, _TIM_IE_, NULL, false); | |
1083 | } | |
1084 | } else { | |
1085 | if (pstapriv->tim_bitmap&BIT(psta->aid)) { | |
1086 | if (psta->sleepq_len == 0) { | |
1087 | DBG_88E("no buffered packets to xmit\n"); | |
1088 | ||
1089 | /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ | |
1090 | issue_nulldata(padapter, psta->hwaddr, 0, 0, 0); | |
1091 | } else { | |
1092 | DBG_88E("error!psta->sleepq_len=%d\n", psta->sleepq_len); | |
1093 | psta->sleepq_len = 0; | |
1094 | } | |
1095 | ||
1096 | pstapriv->tim_bitmap &= ~BIT(psta->aid); | |
1097 | ||
1098 | /* upate BCN for TIM IE */ | |
1099 | /* update_BCNTIM(padapter); */ | |
1100 | update_beacon(padapter, _TIM_IE_, NULL, false); | |
1101 | } | |
1102 | } | |
1103 | spin_unlock_bh(&pxmitpriv->lock); | |
1104 | } | |
1105 | } | |
1106 | ||
1107 | #endif | |
1108 | ||
1109 | return _FAIL; | |
1110 | } | |
1111 | ||
1112 | struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *precv_frame); | |
1113 | ||
1114 | static int validate_recv_mgnt_frame(struct adapter *padapter, | |
1115 | struct recv_frame *precv_frame) | |
1116 | { | |
1117 | struct sta_info *psta; | |
1118 | ||
1119 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n")); | |
1120 | ||
1121 | precv_frame = recvframe_chk_defrag(padapter, precv_frame); | |
1122 | if (precv_frame == NULL) { | |
1123 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__)); | |
1124 | return _SUCCESS; | |
1125 | } | |
1126 | ||
1127 | /* for rx pkt statistics */ | |
1128 | psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->rx_data)); | |
1129 | if (psta) { | |
1130 | psta->sta_stats.rx_mgnt_pkts++; | |
1131 | if (GetFrameSubType(precv_frame->rx_data) == WIFI_BEACON) { | |
1132 | psta->sta_stats.rx_beacon_pkts++; | |
1133 | } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBEREQ) { | |
1134 | psta->sta_stats.rx_probereq_pkts++; | |
1135 | } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBERSP) { | |
1136 | if (!memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->rx_data), ETH_ALEN)) | |
1137 | psta->sta_stats.rx_probersp_pkts++; | |
1138 | else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)) || | |
1139 | is_multicast_mac_addr(GetAddr1Ptr(precv_frame->rx_data))) | |
1140 | psta->sta_stats.rx_probersp_bm_pkts++; | |
1141 | else | |
1142 | psta->sta_stats.rx_probersp_uo_pkts++; | |
1143 | } | |
1144 | } | |
1145 | ||
1146 | mgt_dispatcher(padapter, precv_frame); | |
1147 | ||
1148 | return _SUCCESS; | |
1149 | } | |
1150 | ||
1151 | static int validate_recv_data_frame(struct adapter *adapter, | |
1152 | struct recv_frame *precv_frame) | |
1153 | { | |
1154 | u8 bretry; | |
1155 | u8 *psa, *pda, *pbssid; | |
1156 | struct sta_info *psta = NULL; | |
1157 | u8 *ptr = precv_frame->rx_data; | |
1158 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
1159 | struct security_priv *psecuritypriv = &adapter->securitypriv; | |
1160 | int ret = _SUCCESS; | |
1161 | ||
1162 | bretry = GetRetry(ptr); | |
1163 | pda = get_da(ptr); | |
1164 | psa = get_sa(ptr); | |
1165 | pbssid = get_hdr_bssid(ptr); | |
1166 | ||
1167 | if (pbssid == NULL) { | |
1168 | ret = _FAIL; | |
1169 | goto exit; | |
1170 | } | |
1171 | ||
1172 | memcpy(pattrib->dst, pda, ETH_ALEN); | |
1173 | memcpy(pattrib->src, psa, ETH_ALEN); | |
1174 | ||
1175 | memcpy(pattrib->bssid, pbssid, ETH_ALEN); | |
1176 | ||
1177 | switch (pattrib->to_fr_ds) { | |
1178 | case 0: | |
1179 | memcpy(pattrib->ra, pda, ETH_ALEN); | |
1180 | memcpy(pattrib->ta, psa, ETH_ALEN); | |
1181 | ret = sta2sta_data_frame(adapter, precv_frame, &psta); | |
1182 | break; | |
1183 | case 1: | |
1184 | memcpy(pattrib->ra, pda, ETH_ALEN); | |
1185 | memcpy(pattrib->ta, pbssid, ETH_ALEN); | |
1186 | ret = ap2sta_data_frame(adapter, precv_frame, &psta); | |
1187 | break; | |
1188 | case 2: | |
1189 | memcpy(pattrib->ra, pbssid, ETH_ALEN); | |
1190 | memcpy(pattrib->ta, psa, ETH_ALEN); | |
1191 | ret = sta2ap_data_frame(adapter, precv_frame, &psta); | |
1192 | break; | |
1193 | case 3: | |
1194 | memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); | |
1195 | memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); | |
1196 | ret = _FAIL; | |
1197 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n")); | |
1198 | break; | |
1199 | default: | |
1200 | ret = _FAIL; | |
1201 | break; | |
1202 | } | |
1203 | ||
1204 | if (ret == _FAIL) { | |
1205 | goto exit; | |
1206 | } else if (ret == RTW_RX_HANDLED) { | |
1207 | goto exit; | |
1208 | } | |
1209 | ||
1210 | if (psta == NULL) { | |
1211 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n")); | |
1212 | ret = _FAIL; | |
1213 | goto exit; | |
1214 | } | |
1215 | ||
1216 | /* psta->rssi = prxcmd->rssi; */ | |
1217 | /* psta->signal_quality = prxcmd->sq; */ | |
1218 | precv_frame->psta = psta; | |
1219 | ||
1220 | pattrib->amsdu = 0; | |
1221 | pattrib->ack_policy = 0; | |
1222 | /* parsing QC field */ | |
1223 | if (pattrib->qos == 1) { | |
1224 | pattrib->priority = GetPriority((ptr + 24)); | |
1225 | pattrib->ack_policy = GetAckpolicy((ptr + 24)); | |
1226 | pattrib->amsdu = GetAMsdu((ptr + 24)); | |
1227 | pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26; | |
1228 | ||
1229 | if (pattrib->priority != 0 && pattrib->priority != 3) | |
1230 | adapter->recvpriv.bIsAnyNonBEPkts = true; | |
1231 | } else { | |
1232 | pattrib->priority = 0; | |
1233 | pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24; | |
1234 | } | |
1235 | ||
1236 | if (pattrib->order)/* HT-CTRL 11n */ | |
1237 | pattrib->hdrlen += 4; | |
1238 | ||
1239 | precv_frame->preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; | |
1240 | ||
1241 | /* decache, drop duplicate recv packets */ | |
1242 | if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) { | |
1243 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decache : drop pkt\n")); | |
1244 | ret = _FAIL; | |
1245 | goto exit; | |
1246 | } | |
1247 | ||
1248 | if (pattrib->privacy) { | |
1249 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy)); | |
1250 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra))); | |
1251 | ||
1252 | GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); | |
1253 | ||
1254 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n pattrib->encrypt=%d\n", pattrib->encrypt)); | |
1255 | ||
1256 | SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); | |
1257 | } else { | |
1258 | pattrib->encrypt = 0; | |
1259 | pattrib->iv_len = 0; | |
1260 | pattrib->icv_len = 0; | |
1261 | } | |
1262 | ||
1263 | exit: | |
1264 | ||
1265 | return ret; | |
1266 | } | |
1267 | ||
1268 | static int validate_recv_frame(struct adapter *adapter, struct recv_frame *precv_frame) | |
1269 | { | |
1270 | /* shall check frame subtype, to / from ds, da, bssid */ | |
1271 | ||
1272 | /* then call check if rx seq/frag. duplicated. */ | |
1273 | ||
1274 | u8 type; | |
1275 | u8 subtype; | |
1276 | int retval = _SUCCESS; | |
1277 | u8 bDumpRxPkt; | |
1278 | struct rx_pkt_attrib *pattrib = &precv_frame->attrib; | |
1279 | u8 *ptr = precv_frame->rx_data; | |
1280 | u8 ver = (unsigned char) (*ptr)&0x3; | |
1281 | struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; | |
1282 | ||
1283 | if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { | |
1284 | int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); | |
1285 | if (ch_set_idx >= 0) | |
1286 | pmlmeext->channel_set[ch_set_idx].rx_count++; | |
1287 | } | |
1288 | ||
1289 | /* add version chk */ | |
1290 | if (ver != 0) { | |
1291 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! (ver!=0)\n")); | |
1292 | retval = _FAIL; | |
1293 | goto exit; | |
1294 | } | |
1295 | ||
1296 | type = GetFrameType(ptr); | |
1297 | subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ | |
1298 | ||
1299 | pattrib->to_fr_ds = get_tofr_ds(ptr); | |
1300 | ||
1301 | pattrib->frag_num = GetFragNum(ptr); | |
1302 | pattrib->seq_num = GetSequence(ptr); | |
1303 | ||
1304 | pattrib->pw_save = GetPwrMgt(ptr); | |
1305 | pattrib->mfrag = GetMFrag(ptr); | |
1306 | pattrib->mdata = GetMData(ptr); | |
1307 | pattrib->privacy = GetPrivacy(ptr); | |
1308 | pattrib->order = GetOrder(ptr); | |
1309 | ||
1310 | /* Dump rx packets */ | |
1311 | rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); | |
1312 | if (bDumpRxPkt == 1) {/* dump all rx packets */ | |
1313 | int i; | |
1314 | DBG_88E("#############################\n"); | |
1315 | ||
1316 | for (i = 0; i < 64; i = i+8) | |
1317 | DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), | |
1318 | *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); | |
1319 | DBG_88E("#############################\n"); | |
1320 | } else if (bDumpRxPkt == 2) { | |
1321 | if (type == WIFI_MGT_TYPE) { | |
1322 | int i; | |
1323 | DBG_88E("#############################\n"); | |
1324 | ||
1325 | for (i = 0; i < 64; i = i+8) | |
1326 | DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), | |
1327 | *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); | |
1328 | DBG_88E("#############################\n"); | |
1329 | } | |
1330 | } else if (bDumpRxPkt == 3) { | |
1331 | if (type == WIFI_DATA_TYPE) { | |
1332 | int i; | |
1333 | DBG_88E("#############################\n"); | |
1334 | ||
1335 | for (i = 0; i < 64; i = i+8) | |
1336 | DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr+i), | |
1337 | *(ptr+i+1), *(ptr+i+2), *(ptr+i+3), *(ptr+i+4), *(ptr+i+5), *(ptr+i+6), *(ptr+i+7)); | |
1338 | DBG_88E("#############################\n"); | |
1339 | } | |
1340 | } | |
1341 | switch (type) { | |
1342 | case WIFI_MGT_TYPE: /* mgnt */ | |
1343 | retval = validate_recv_mgnt_frame(adapter, precv_frame); | |
1344 | if (retval == _FAIL) | |
1345 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_mgnt_frame fail\n")); | |
1346 | retval = _FAIL; /* only data frame return _SUCCESS */ | |
1347 | break; | |
1348 | case WIFI_CTRL_TYPE: /* ctrl */ | |
1349 | retval = validate_recv_ctrl_frame(adapter, precv_frame); | |
1350 | if (retval == _FAIL) | |
1351 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_ctrl_frame fail\n")); | |
1352 | retval = _FAIL; /* only data frame return _SUCCESS */ | |
1353 | break; | |
1354 | case WIFI_DATA_TYPE: /* data */ | |
1355 | rtw_led_control(adapter, LED_CTL_RX); | |
1356 | pattrib->qos = (subtype & BIT(7)) ? 1 : 0; | |
1357 | retval = validate_recv_data_frame(adapter, precv_frame); | |
1358 | if (retval == _FAIL) { | |
1359 | struct recv_priv *precvpriv = &adapter->recvpriv; | |
1360 | precvpriv->rx_drop++; | |
1361 | } | |
1362 | break; | |
1363 | default: | |
1364 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail! type= 0x%x\n", type)); | |
1365 | retval = _FAIL; | |
1366 | break; | |
1367 | } | |
1368 | ||
1369 | exit: | |
1370 | ||
1371 | return retval; | |
1372 | } | |
1373 | ||
1374 | /* remove the wlanhdr and add the eth_hdr */ | |
1375 | ||
1376 | static int wlanhdr_to_ethhdr (struct recv_frame *precvframe) | |
1377 | { | |
1378 | int rmv_len; | |
1379 | u16 eth_type, len; | |
1380 | __be16 be_tmp; | |
1381 | u8 bsnaphdr; | |
1382 | u8 *psnap_type; | |
1383 | struct ieee80211_snap_hdr *psnap; | |
1384 | ||
1385 | int ret = _SUCCESS; | |
1386 | struct adapter *adapter = precvframe->adapter; | |
1387 | struct mlme_priv *pmlmepriv = &adapter->mlmepriv; | |
1388 | ||
1389 | u8 *ptr = get_recvframe_data(precvframe); /* point to frame_ctrl field */ | |
1390 | struct rx_pkt_attrib *pattrib = &precvframe->attrib; | |
1391 | ||
1392 | if (pattrib->encrypt) | |
1393 | recvframe_pull_tail(precvframe, pattrib->icv_len); | |
1394 | ||
1395 | psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len); | |
1396 | psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE; | |
1397 | /* convert hdr + possible LLC headers into Ethernet header */ | |
1398 | if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && | |
1399 | memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) && | |
1400 | memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2)) || | |
1401 | !memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) { | |
1402 | /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ | |
1403 | bsnaphdr = true; | |
1404 | } else { | |
1405 | /* Leave Ethernet header part of hdr and full payload */ | |
1406 | bsnaphdr = false; | |
1407 | } | |
1408 | ||
1409 | rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); | |
1410 | len = precvframe->len - rmv_len; | |
1411 | ||
1412 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, | |
1413 | ("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len)); | |
1414 | ||
1415 | memcpy(&be_tmp, ptr+rmv_len, 2); | |
1416 | eth_type = ntohs(be_tmp); /* pattrib->ether_type */ | |
1417 | pattrib->eth_type = eth_type; | |
1418 | ||
1419 | if ((check_fwstate(pmlmepriv, WIFI_MP_STATE))) { | |
1420 | ptr += rmv_len; | |
1421 | *ptr = 0x87; | |
1422 | *(ptr+1) = 0x12; | |
1423 | ||
1424 | eth_type = 0x8712; | |
1425 | /* append rx status for mp test packets */ | |
1426 | ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24); | |
1427 | memcpy(ptr, get_rxmem(precvframe), 24); | |
1428 | ptr += 24; | |
1429 | } else { | |
1430 | ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); | |
1431 | } | |
1432 | ||
1433 | memcpy(ptr, pattrib->dst, ETH_ALEN); | |
1434 | memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN); | |
1435 | ||
1436 | if (!bsnaphdr) { | |
1437 | be_tmp = htons(len); | |
1438 | memcpy(ptr+12, &be_tmp, 2); | |
1439 | } | |
1440 | ||
1441 | return ret; | |
1442 | } | |
1443 | ||
1444 | /* perform defrag */ | |
1445 | static struct recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q) | |
1446 | { | |
1447 | struct list_head *plist, *phead; | |
1448 | u8 wlanhdr_offset; | |
1449 | u8 curfragnum; | |
1450 | struct recv_frame *pfhdr, *pnfhdr; | |
1451 | struct recv_frame *prframe, *pnextrframe; | |
1452 | struct __queue *pfree_recv_queue; | |
1453 | ||
1454 | curfragnum = 0; | |
1455 | pfree_recv_queue = &adapter->recvpriv.free_recv_queue; | |
1456 | ||
1457 | phead = get_list_head(defrag_q); | |
1458 | plist = phead->next; | |
1459 | pfhdr = container_of(plist, struct recv_frame, list); | |
1460 | prframe = (struct recv_frame *)pfhdr; | |
1461 | list_del_init(&(prframe->list)); | |
1462 | ||
1463 | if (curfragnum != pfhdr->attrib.frag_num) { | |
1464 | /* the first fragment number must be 0 */ | |
1465 | /* free the whole queue */ | |
1466 | rtw_free_recvframe(prframe, pfree_recv_queue); | |
1467 | rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); | |
1468 | ||
1469 | return NULL; | |
1470 | } | |
1471 | ||
1472 | curfragnum++; | |
1473 | ||
1474 | plist = get_list_head(defrag_q); | |
1475 | plist = phead->next; | |
1476 | pfhdr = container_of(plist, struct recv_frame, list); | |
1477 | prframe = (struct recv_frame *)pfhdr; | |
1478 | list_del_init(&(prframe->list)); | |
1479 | ||
1480 | plist = plist->next; | |
1481 | ||
1482 | while (phead != plist) { | |
1483 | pnfhdr = container_of(plist, struct recv_frame, list); | |
1484 | pnextrframe = (struct recv_frame *)pnfhdr; | |
1485 | ||
1486 | /* check the fragment sequence (2nd ~n fragment frame) */ | |
1487 | ||
1488 | if (curfragnum != pnfhdr->attrib.frag_num) { | |
1489 | /* the fragment number must be increasing (after decache) */ | |
1490 | /* release the defrag_q & prframe */ | |
1491 | rtw_free_recvframe(prframe, pfree_recv_queue); | |
1492 | rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); | |
1493 | return NULL; | |
1494 | } | |
1495 | ||
1496 | curfragnum++; | |
1497 | ||
1498 | /* copy the 2nd~n fragment frame's payload to the first fragment */ | |
1499 | /* get the 2nd~last fragment frame's payload */ | |
1500 | ||
1501 | wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; | |
1502 | ||
1503 | recvframe_pull(pnextrframe, wlanhdr_offset); | |
1504 | ||
1505 | /* append to first fragment frame's tail (if privacy frame, pull the ICV) */ | |
1506 | recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); | |
1507 | ||
1508 | /* memcpy */ | |
1509 | memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); | |
1510 | ||
1511 | recvframe_put(prframe, pnfhdr->len); | |
1512 | ||
1513 | pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; | |
1514 | plist = plist->next; | |
1515 | } | |
1516 | ||
1517 | /* free the defrag_q queue and return the prframe */ | |
1518 | rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); | |
1519 | ||
1520 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n")); | |
1521 | ||
1522 | return prframe; | |
1523 | } | |
1524 | ||
1525 | /* check if need to defrag, if needed queue the frame to defrag_q */ | |
1526 | struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *precv_frame) | |
1527 | { | |
1528 | u8 ismfrag; | |
1529 | u8 fragnum; | |
1530 | u8 *psta_addr; | |
1531 | struct recv_frame *pfhdr; | |
1532 | struct sta_info *psta; | |
1533 | struct sta_priv *pstapriv; | |
1534 | struct list_head *phead; | |
1535 | struct recv_frame *prtnframe = NULL; | |
1536 | struct __queue *pfree_recv_queue, *pdefrag_q; | |
1537 | ||
1538 | pstapriv = &padapter->stapriv; | |
1539 | ||
1540 | pfhdr = precv_frame; | |
1541 | ||
1542 | pfree_recv_queue = &padapter->recvpriv.free_recv_queue; | |
1543 | ||
1544 | /* need to define struct of wlan header frame ctrl */ | |
1545 | ismfrag = pfhdr->attrib.mfrag; | |
1546 | fragnum = pfhdr->attrib.frag_num; | |
1547 | ||
1548 | psta_addr = pfhdr->attrib.ta; | |
1549 | psta = rtw_get_stainfo(pstapriv, psta_addr); | |
1550 | if (psta == NULL) { | |
1551 | u8 type = GetFrameType(pfhdr->rx_data); | |
1552 | if (type != WIFI_DATA_TYPE) { | |
1553 | psta = rtw_get_bcmc_stainfo(padapter); | |
1554 | pdefrag_q = &psta->sta_recvpriv.defrag_q; | |
1555 | } else { | |
1556 | pdefrag_q = NULL; | |
1557 | } | |
1558 | } else { | |
1559 | pdefrag_q = &psta->sta_recvpriv.defrag_q; | |
1560 | } | |
1561 | ||
1562 | if ((ismfrag == 0) && (fragnum == 0)) | |
1563 | prtnframe = precv_frame;/* isn't a fragment frame */ | |
1564 | ||
1565 | if (ismfrag == 1) { | |
1566 | /* 0~(n-1) fragment frame */ | |
1567 | /* enqueue to defraf_g */ | |
1568 | if (pdefrag_q != NULL) { | |
1569 | if (fragnum == 0) { | |
1570 | /* the first fragment */ | |
1571 | if (!list_empty(&pdefrag_q->queue)) { | |
1572 | /* free current defrag_q */ | |
1573 | rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); | |
1574 | } | |
1575 | } | |
1576 | ||
1577 | /* Then enqueue the 0~(n-1) fragment into the defrag_q */ | |
1578 | ||
1579 | phead = get_list_head(pdefrag_q); | |
1580 | list_add_tail(&pfhdr->list, phead); | |
1581 | ||
1582 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Enqueuq: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); | |
1583 | ||
1584 | prtnframe = NULL; | |
1585 | } else { | |
1586 | /* can't find this ta's defrag_queue, so free this recv_frame */ | |
1587 | if (precv_frame && pfree_recv_queue) | |
1588 | rtw_free_recvframe(precv_frame, pfree_recv_queue); | |
1589 | prtnframe = NULL; | |
1590 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); | |
1591 | } | |
1592 | } | |
1593 | ||
1594 | if ((ismfrag == 0) && (fragnum != 0)) { | |
1595 | /* the last fragment frame */ | |
1596 | /* enqueue the last fragment */ | |
1597 | if (pdefrag_q != NULL) { | |
1598 | phead = get_list_head(pdefrag_q); | |
1599 | list_add_tail(&pfhdr->list, phead); | |
1600 | ||
1601 | /* call recvframe_defrag to defrag */ | |
1602 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("defrag: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); | |
1603 | precv_frame = recvframe_defrag(padapter, pdefrag_q); | |
1604 | prtnframe = precv_frame; | |
1605 | } else { | |
1606 | /* can't find this ta's defrag_queue, so free this recv_frame */ | |
1607 | if (precv_frame && pfree_recv_queue) | |
1608 | rtw_free_recvframe(precv_frame, pfree_recv_queue); | |
1609 | prtnframe = NULL; | |
1610 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("Free because pdefrag_q==NULL: ismfrag=%d, fragnum=%d\n", ismfrag, fragnum)); | |
1611 | } | |
1612 | } | |
1613 | ||
1614 | if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) { | |
1615 | /* after defrag we must check tkip mic code */ | |
1616 | if (recvframe_chkmic(padapter, prtnframe) == _FAIL) { | |
1617 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic(padapter, prtnframe)==_FAIL\n")); | |
1618 | if (precv_frame && pfree_recv_queue) | |
1619 | rtw_free_recvframe(prtnframe, pfree_recv_queue); | |
1620 | prtnframe = NULL; | |
1621 | } | |
1622 | } | |
1623 | ||
1624 | return prtnframe; | |
1625 | } | |
1626 | ||
1627 | static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) | |
1628 | { | |
1629 | int a_len, padding_len; | |
1630 | u16 eth_type, nSubframe_Length; | |
1631 | u8 nr_subframes, i; | |
1632 | unsigned char *pdata; | |
1633 | struct rx_pkt_attrib *pattrib; | |
1634 | unsigned char *data_ptr; | |
1635 | struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; | |
1636 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
1637 | struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue); | |
1638 | int ret = _SUCCESS; | |
1639 | nr_subframes = 0; | |
1640 | ||
1641 | pattrib = &prframe->attrib; | |
1642 | ||
1643 | recvframe_pull(prframe, prframe->attrib.hdrlen); | |
1644 | ||
1645 | if (prframe->attrib.iv_len > 0) | |
1646 | recvframe_pull(prframe, prframe->attrib.iv_len); | |
1647 | ||
1648 | a_len = prframe->len; | |
1649 | ||
1650 | pdata = prframe->rx_data; | |
1651 | ||
1652 | while (a_len > ETH_HLEN) { | |
1653 | /* Offset 12 denote 2 mac address */ | |
1654 | nSubframe_Length = RTW_GET_BE16(pdata + 12); | |
1655 | ||
1656 | if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { | |
1657 | DBG_88E("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length); | |
1658 | goto exit; | |
1659 | } | |
1660 | ||
1661 | /* move the data point to data content */ | |
1662 | pdata += ETH_HLEN; | |
1663 | a_len -= ETH_HLEN; | |
1664 | ||
1665 | /* Allocate new skb for releasing to upper layer */ | |
1666 | sub_skb = dev_alloc_skb(nSubframe_Length + 12); | |
1667 | if (sub_skb) { | |
1668 | skb_reserve(sub_skb, 12); | |
1669 | data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); | |
1670 | memcpy(data_ptr, pdata, nSubframe_Length); | |
1671 | } else { | |
1672 | sub_skb = skb_clone(prframe->pkt, GFP_ATOMIC); | |
1673 | if (sub_skb) { | |
1674 | sub_skb->data = pdata; | |
1675 | sub_skb->len = nSubframe_Length; | |
1676 | skb_set_tail_pointer(sub_skb, nSubframe_Length); | |
1677 | } else { | |
1678 | DBG_88E("skb_clone() Fail!!! , nr_subframes=%d\n", nr_subframes); | |
1679 | break; | |
1680 | } | |
1681 | } | |
1682 | ||
1683 | subframes[nr_subframes++] = sub_skb; | |
1684 | ||
1685 | if (nr_subframes >= MAX_SUBFRAME_COUNT) { | |
1686 | DBG_88E("ParseSubframe(): Too many Subframes! Packets dropped!\n"); | |
1687 | break; | |
1688 | } | |
1689 | ||
1690 | pdata += nSubframe_Length; | |
1691 | a_len -= nSubframe_Length; | |
1692 | if (a_len != 0) { | |
1693 | padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4-1)); | |
1694 | if (padding_len == 4) { | |
1695 | padding_len = 0; | |
1696 | } | |
1697 | ||
1698 | if (a_len < padding_len) { | |
1699 | goto exit; | |
1700 | } | |
1701 | pdata += padding_len; | |
1702 | a_len -= padding_len; | |
1703 | } | |
1704 | } | |
1705 | ||
1706 | for (i = 0; i < nr_subframes; i++) { | |
1707 | sub_skb = subframes[i]; | |
1708 | /* convert hdr + possible LLC headers into Ethernet header */ | |
1709 | eth_type = RTW_GET_BE16(&sub_skb->data[6]); | |
1710 | if (sub_skb->len >= 8 && | |
1711 | ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) && | |
1712 | eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || | |
1713 | !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) { | |
1714 | /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ | |
1715 | skb_pull(sub_skb, SNAP_SIZE); | |
1716 | memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); | |
1717 | memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); | |
1718 | } else { | |
1719 | __be16 len; | |
1720 | /* Leave Ethernet header part of hdr and full payload */ | |
1721 | len = htons(sub_skb->len); | |
1722 | memcpy(skb_push(sub_skb, 2), &len, 2); | |
1723 | memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); | |
1724 | memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); | |
1725 | } | |
1726 | ||
1727 | /* Indicate the packets to upper layer */ | |
1728 | /* Insert NAT2.5 RX here! */ | |
1729 | sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); | |
1730 | sub_skb->dev = padapter->pnetdev; | |
1731 | ||
1732 | sub_skb->ip_summed = CHECKSUM_NONE; | |
1733 | ||
1734 | netif_rx(sub_skb); | |
1735 | } | |
1736 | ||
1737 | exit: | |
1738 | ||
1739 | prframe->len = 0; | |
1740 | rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */ | |
1741 | ||
1742 | return ret; | |
1743 | } | |
1744 | ||
1745 | static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) | |
1746 | { | |
1747 | u8 wsize = preorder_ctrl->wsize_b; | |
1748 | u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/* 4096; */ | |
1749 | ||
1750 | /* Rx Reorder initialize condition. */ | |
1751 | if (preorder_ctrl->indicate_seq == 0xFFFF) | |
1752 | preorder_ctrl->indicate_seq = seq_num; | |
1753 | ||
1754 | /* Drop out the packet which SeqNum is smaller than WinStart */ | |
1755 | if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) | |
1756 | return false; | |
1757 | ||
1758 | /* */ | |
1759 | /* Sliding window manipulation. Conditions includes: */ | |
1760 | /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */ | |
1761 | /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ | |
1762 | /* */ | |
1763 | if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { | |
1764 | preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; | |
1765 | } else if (SN_LESS(wend, seq_num)) { | |
1766 | if (seq_num >= (wsize - 1)) | |
1767 | preorder_ctrl->indicate_seq = seq_num + 1 - wsize; | |
1768 | else | |
1769 | preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; | |
1770 | } | |
1771 | ||
1772 | return true; | |
1773 | } | |
1774 | ||
1775 | int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, struct recv_frame *prframe); | |
1776 | int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, struct recv_frame *prframe) | |
1777 | { | |
1778 | struct rx_pkt_attrib *pattrib = &prframe->attrib; | |
1779 | struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; | |
1780 | struct list_head *phead, *plist; | |
1781 | struct recv_frame *hdr; | |
1782 | struct rx_pkt_attrib *pnextattrib; | |
1783 | ||
1784 | phead = get_list_head(ppending_recvframe_queue); | |
1785 | plist = phead->next; | |
1786 | ||
1787 | while (phead != plist) { | |
1788 | hdr = container_of(plist, struct recv_frame, list); | |
1789 | pnextattrib = &hdr->attrib; | |
1790 | ||
1791 | if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) | |
1792 | plist = plist->next; | |
1793 | else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) | |
1794 | return false; | |
1795 | else | |
1796 | break; | |
1797 | } | |
1798 | ||
1799 | list_del_init(&(prframe->list)); | |
1800 | ||
1801 | list_add_tail(&(prframe->list), plist); | |
1802 | return true; | |
1803 | } | |
1804 | ||
1805 | static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) | |
1806 | { | |
1807 | struct list_head *phead, *plist; | |
1808 | struct recv_frame *prframe; | |
1809 | struct rx_pkt_attrib *pattrib; | |
1810 | int bPktInBuf = false; | |
1811 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
1812 | struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; | |
1813 | ||
1814 | phead = get_list_head(ppending_recvframe_queue); | |
1815 | plist = phead->next; | |
1816 | ||
1817 | /* Handling some condition for forced indicate case. */ | |
1818 | if (bforced) { | |
1819 | if (list_empty(phead)) | |
1820 | return true; | |
1821 | ||
1822 | prframe = container_of(plist, struct recv_frame, list); | |
1823 | pattrib = &prframe->attrib; | |
1824 | preorder_ctrl->indicate_seq = pattrib->seq_num; | |
1825 | } | |
1826 | ||
1827 | /* Prepare indication list and indication. */ | |
1828 | /* Check if there is any packet need indicate. */ | |
1829 | while (!list_empty(phead)) { | |
1830 | prframe = container_of(plist, struct recv_frame, list); | |
1831 | pattrib = &prframe->attrib; | |
1832 | ||
1833 | if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { | |
1834 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, | |
1835 | ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n", | |
1836 | preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); | |
1837 | plist = plist->next; | |
1838 | list_del_init(&(prframe->list)); | |
1839 | ||
1840 | if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) | |
1841 | preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; | |
1842 | ||
1843 | /* Set this as a lock to make sure that only one thread is indicating packet. */ | |
1844 | ||
1845 | /* indicate this recv_frame */ | |
1846 | if (!pattrib->amsdu) { | |
1847 | if ((!padapter->bDriverStopped) && | |
1848 | (!padapter->bSurpriseRemoved)) | |
1849 | rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */ | |
1850 | } else if (pattrib->amsdu == 1) { | |
1851 | if (amsdu_to_msdu(padapter, prframe) != _SUCCESS) | |
1852 | rtw_free_recvframe(prframe, &precvpriv->free_recv_queue); | |
1853 | } else { | |
1854 | /* error condition; */ | |
1855 | } | |
1856 | ||
1857 | /* Update local variables. */ | |
1858 | bPktInBuf = false; | |
1859 | } else { | |
1860 | bPktInBuf = true; | |
1861 | break; | |
1862 | } | |
1863 | } | |
1864 | return bPktInBuf; | |
1865 | } | |
1866 | ||
1867 | static int recv_indicatepkt_reorder(struct adapter *padapter, struct recv_frame *prframe) | |
1868 | { | |
1869 | int retval = _SUCCESS; | |
1870 | struct rx_pkt_attrib *pattrib = &prframe->attrib; | |
1871 | struct recv_reorder_ctrl *preorder_ctrl = prframe->preorder_ctrl; | |
1872 | struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; | |
1873 | ||
1874 | if (!pattrib->amsdu) { | |
1875 | /* s1. */ | |
1876 | wlanhdr_to_ethhdr(prframe); | |
1877 | ||
1878 | if (pattrib->qos != 1) { | |
1879 | if (!padapter->bDriverStopped && | |
1880 | !padapter->bSurpriseRemoved) { | |
1881 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, | |
1882 | ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n")); | |
1883 | ||
1884 | rtw_recv_indicatepkt(padapter, prframe); | |
1885 | return _SUCCESS; | |
1886 | } | |
1887 | ||
1888 | return _FAIL; | |
1889 | } | |
1890 | ||
1891 | if (!preorder_ctrl->enable) { | |
1892 | /* indicate this recv_frame */ | |
1893 | preorder_ctrl->indicate_seq = pattrib->seq_num; | |
1894 | rtw_recv_indicatepkt(padapter, prframe); | |
1895 | ||
1896 | preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; | |
1897 | return _SUCCESS; | |
1898 | } | |
1899 | } else if (pattrib->amsdu == 1) { /* temp filter -> means didn't support A-MSDUs in a A-MPDU */ | |
1900 | if (!preorder_ctrl->enable) { | |
1901 | preorder_ctrl->indicate_seq = pattrib->seq_num; | |
1902 | retval = amsdu_to_msdu(padapter, prframe); | |
1903 | ||
1904 | preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1)%4096; | |
1905 | return retval; | |
1906 | } | |
1907 | } | |
1908 | ||
1909 | spin_lock_bh(&ppending_recvframe_queue->lock); | |
1910 | ||
1911 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, | |
1912 | ("recv_indicatepkt_reorder: indicate=%d seq=%d\n", | |
1913 | preorder_ctrl->indicate_seq, pattrib->seq_num)); | |
1914 | ||
1915 | /* s2. check if winstart_b(indicate_seq) needs to been updated */ | |
1916 | if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) | |
1917 | goto _err_exit; | |
1918 | ||
1919 | /* s3. Insert all packet into Reorder Queue to maintain its ordering. */ | |
1920 | if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) | |
1921 | goto _err_exit; | |
1922 | ||
1923 | /* s4. */ | |
1924 | /* Indication process. */ | |
1925 | /* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */ | |
1926 | /* with the SeqNum smaller than latest WinStart and buffer other packets. */ | |
1927 | /* */ | |
1928 | /* For Rx Reorder condition: */ | |
1929 | /* 1. All packets with SeqNum smaller than WinStart => Indicate */ | |
1930 | /* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */ | |
1931 | /* */ | |
1932 | ||
1933 | /* recv_indicatepkts_in_order(padapter, preorder_ctrl, true); */ | |
1934 | if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) { | |
1935 | _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); | |
1936 | spin_unlock_bh(&ppending_recvframe_queue->lock); | |
1937 | } else { | |
1938 | spin_unlock_bh(&ppending_recvframe_queue->lock); | |
1939 | _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); | |
1940 | } | |
1941 | ||
1942 | _success_exit: | |
1943 | ||
1944 | return _SUCCESS; | |
1945 | ||
1946 | _err_exit: | |
1947 | ||
1948 | spin_unlock_bh(&ppending_recvframe_queue->lock); | |
1949 | ||
1950 | return _FAIL; | |
1951 | } | |
1952 | ||
1953 | void rtw_reordering_ctrl_timeout_handler(void *pcontext) | |
1954 | { | |
1955 | struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; | |
1956 | struct adapter *padapter = preorder_ctrl->padapter; | |
1957 | struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; | |
1958 | ||
1959 | if (padapter->bDriverStopped || padapter->bSurpriseRemoved) | |
1960 | return; | |
1961 | ||
1962 | spin_lock_bh(&ppending_recvframe_queue->lock); | |
1963 | ||
1964 | if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true) | |
1965 | _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); | |
1966 | ||
1967 | spin_unlock_bh(&ppending_recvframe_queue->lock); | |
1968 | } | |
1969 | ||
1970 | static int process_recv_indicatepkts(struct adapter *padapter, struct recv_frame *prframe) | |
1971 | { | |
1972 | int retval = _SUCCESS; | |
1973 | /* struct recv_priv *precvpriv = &padapter->recvpriv; */ | |
1974 | /* struct rx_pkt_attrib *pattrib = &prframe->attrib; */ | |
1975 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
1976 | struct ht_priv *phtpriv = &pmlmepriv->htpriv; | |
1977 | ||
1978 | if (phtpriv->ht_option) { /* B/G/N Mode */ | |
1979 | /* prframe->preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ | |
1980 | ||
1981 | if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { | |
1982 | /* including perform A-MPDU Rx Ordering Buffer Control */ | |
1983 | if ((!padapter->bDriverStopped) && | |
1984 | (!padapter->bSurpriseRemoved)) { | |
1985 | retval = _FAIL; | |
1986 | return retval; | |
1987 | } | |
1988 | } | |
1989 | } else { /* B/G mode */ | |
1990 | retval = wlanhdr_to_ethhdr (prframe); | |
1991 | if (retval != _SUCCESS) { | |
1992 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("wlanhdr_to_ethhdr: drop pkt\n")); | |
1993 | return retval; | |
1994 | } | |
1995 | ||
1996 | if ((!padapter->bDriverStopped) && | |
1997 | (!padapter->bSurpriseRemoved)) { | |
1998 | /* indicate this recv_frame */ | |
1999 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n")); | |
2000 | rtw_recv_indicatepkt(padapter, prframe); | |
2001 | } else { | |
2002 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n")); | |
2003 | ||
2004 | RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); | |
2005 | retval = _FAIL; | |
2006 | return retval; | |
2007 | } | |
2008 | } | |
2009 | ||
2010 | return retval; | |
2011 | } | |
2012 | ||
2013 | static int recv_func_prehandle(struct adapter *padapter, struct recv_frame *rframe) | |
2014 | { | |
2015 | int ret = _SUCCESS; | |
2016 | struct rx_pkt_attrib *pattrib = &rframe->attrib; | |
2017 | struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; | |
2018 | struct mlme_priv *pmlmepriv = &padapter->mlmepriv; | |
2019 | ||
2020 | if (padapter->registrypriv.mp_mode == 1) { | |
2021 | if (pattrib->crc_err == 1) | |
2022 | padapter->mppriv.rx_crcerrpktcount++; | |
2023 | else | |
2024 | padapter->mppriv.rx_pktcount++; | |
2025 | ||
2026 | if (check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE) == false) { | |
2027 | RT_TRACE(_module_rtl871x_recv_c_, _drv_alert_, ("MP - Not in loopback mode , drop pkt\n")); | |
2028 | ret = _FAIL; | |
2029 | rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ | |
2030 | goto exit; | |
2031 | } | |
2032 | } | |
2033 | ||
2034 | /* check the frame crtl field and decache */ | |
2035 | ret = validate_recv_frame(padapter, rframe); | |
2036 | if (ret != _SUCCESS) { | |
2037 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("recv_func: validate_recv_frame fail! drop pkt\n")); | |
2038 | rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ | |
2039 | goto exit; | |
2040 | } | |
2041 | ||
2042 | exit: | |
2043 | return ret; | |
2044 | } | |
2045 | ||
2046 | static int recv_func_posthandle(struct adapter *padapter, struct recv_frame *prframe) | |
2047 | { | |
2048 | int ret = _SUCCESS; | |
2049 | struct recv_frame *orig_prframe = prframe; | |
2050 | struct recv_priv *precvpriv = &padapter->recvpriv; | |
2051 | struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; | |
2052 | ||
2053 | /* DATA FRAME */ | |
2054 | rtw_led_control(padapter, LED_CTL_RX); | |
2055 | ||
2056 | prframe = decryptor(padapter, prframe); | |
2057 | if (prframe == NULL) { | |
2058 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n")); | |
2059 | ret = _FAIL; | |
2060 | goto _recv_data_drop; | |
2061 | } | |
2062 | ||
2063 | prframe = recvframe_chk_defrag(padapter, prframe); | |
2064 | if (prframe == NULL) { | |
2065 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n")); | |
2066 | goto _recv_data_drop; | |
2067 | } | |
2068 | ||
2069 | prframe = portctrl(padapter, prframe); | |
2070 | if (prframe == NULL) { | |
2071 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n")); | |
2072 | ret = _FAIL; | |
2073 | goto _recv_data_drop; | |
2074 | } | |
2075 | ||
2076 | count_rx_stats(padapter, prframe, NULL); | |
2077 | ||
2078 | ret = process_recv_indicatepkts(padapter, prframe); | |
2079 | if (ret != _SUCCESS) { | |
2080 | RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recv_func: process_recv_indicatepkts fail!\n")); | |
2081 | rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ | |
2082 | goto _recv_data_drop; | |
2083 | } | |
2084 | return ret; | |
2085 | ||
2086 | _recv_data_drop: | |
2087 | precvpriv->rx_drop++; | |
2088 | return ret; | |
2089 | } | |
2090 | ||
2091 | static int recv_func(struct adapter *padapter, struct recv_frame *rframe) | |
2092 | { | |
2093 | int ret; | |
2094 | struct rx_pkt_attrib *prxattrib = &rframe->attrib; | |
2095 | struct security_priv *psecuritypriv = &padapter->securitypriv; | |
2096 | struct mlme_priv *mlmepriv = &padapter->mlmepriv; | |
2097 | struct recv_priv *recvpriv = &padapter->recvpriv; | |
2098 | ||
2099 | /* check if need to handle uc_swdec_pending_queue*/ | |
2100 | if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && | |
2101 | psecuritypriv->busetkipkey) { | |
2102 | struct recv_frame *pending_frame; | |
2103 | int cnt = 0; | |
2104 | ||
2105 | pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); | |
2106 | while (pending_frame) { | |
2107 | cnt++; | |
2108 | recv_func_posthandle(padapter, pending_frame); | |
2109 | } | |
2110 | } | |
2111 | ||
2112 | ret = recv_func_prehandle(padapter, rframe); | |
2113 | ||
2114 | if (ret == _SUCCESS) { | |
2115 | /* check if need to enqueue into uc_swdec_pending_queue*/ | |
2116 | if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && | |
2117 | !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 && | |
2118 | (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt) && | |
2119 | psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && | |
2120 | !psecuritypriv->busetkipkey) { | |
2121 | rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); | |
2122 | DBG_88E("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); | |
2123 | if (recvpriv->free_recvframe_cnt < NR_RECVFRAME/4) { | |
2124 | /* to prevent from recvframe starvation, | |
2125 | * get recvframe from uc_swdec_pending_queue to | |
2126 | * free_recvframe_cnt */ | |
2127 | rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); | |
2128 | if (rframe) | |
2129 | goto do_posthandle; | |
2130 | } | |
2131 | goto exit; | |
2132 | } | |
2133 | do_posthandle: | |
2134 | ret = recv_func_posthandle(padapter, rframe); | |
2135 | } | |
2136 | ||
2137 | exit: | |
2138 | return ret; | |
2139 | } | |
2140 | ||
2141 | s32 rtw_recv_entry(struct recv_frame *precvframe) | |
2142 | { | |
2143 | struct adapter *padapter; | |
2144 | struct recv_priv *precvpriv; | |
2145 | s32 ret = _SUCCESS; | |
2146 | ||
2147 | padapter = precvframe->adapter; | |
2148 | ||
2149 | precvpriv = &padapter->recvpriv; | |
2150 | ||
2151 | ret = recv_func(padapter, precvframe); | |
2152 | if (ret == _FAIL) { | |
2153 | RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n")); | |
2154 | goto _recv_entry_drop; | |
2155 | } | |
2156 | ||
2157 | precvpriv->rx_pkts++; | |
2158 | ||
2159 | return ret; | |
2160 | ||
2161 | _recv_entry_drop: | |
2162 | ||
2163 | if (padapter->registrypriv.mp_mode == 1) | |
2164 | padapter->mppriv.rx_pktloss = precvpriv->rx_drop; | |
2165 | ||
2166 | return ret; | |
2167 | } | |
2168 | ||
15865124 | 2169 | void rtw_signal_stat_timer_hdl(struct timer_list *t) |
15865124 | 2170 | { |
15865124 | 2171 | struct adapter *adapter = from_timer(adapter, t, recvpriv.signal_stat_timer); |
15865124 PP |
2172 | struct recv_priv *recvpriv = &adapter->recvpriv; |
2173 | ||
2174 | u32 tmp_s, tmp_q; | |
2175 | u8 avg_signal_strength = 0; | |
2176 | u8 avg_signal_qual = 0; | |
2177 | u8 _alpha = 3; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */ | |
2178 | ||
2179 | if (adapter->recvpriv.is_signal_dbg) { | |
2180 | /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */ | |
2181 | adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg; | |
2182 | adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); | |
2183 | } else { | |
2184 | if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */ | |
2185 | avg_signal_strength = recvpriv->signal_strength_data.avg_val; | |
2186 | /* after avg_vals are accquired, we can re-stat the signal values */ | |
2187 | recvpriv->signal_strength_data.update_req = 1; | |
2188 | } | |
2189 | ||
2190 | if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */ | |
2191 | avg_signal_qual = recvpriv->signal_qual_data.avg_val; | |
2192 | /* after avg_vals are accquired, we can re-stat the signal values */ | |
2193 | recvpriv->signal_qual_data.update_req = 1; | |
2194 | } | |
2195 | ||
2196 | /* update value of signal_strength, rssi, signal_qual */ | |
2197 | if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) { | |
2198 | tmp_s = (avg_signal_strength+(_alpha-1)*recvpriv->signal_strength); | |
2199 | if (tmp_s % _alpha) | |
2200 | tmp_s = tmp_s/_alpha + 1; | |
2201 | else | |
2202 | tmp_s = tmp_s/_alpha; | |
2203 | if (tmp_s > 100) | |
2204 | tmp_s = 100; | |
2205 | ||
2206 | tmp_q = (avg_signal_qual+(_alpha-1)*recvpriv->signal_qual); | |
2207 | if (tmp_q % _alpha) | |
2208 | tmp_q = tmp_q/_alpha + 1; | |
2209 | else | |
2210 | tmp_q = tmp_q/_alpha; | |
2211 | if (tmp_q > 100) | |
2212 | tmp_q = 100; | |
2213 | ||
2214 | recvpriv->signal_strength = tmp_s; | |
2215 | recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); | |
2216 | recvpriv->signal_qual = tmp_q; | |
2217 | } | |
2218 | } | |
2219 | rtw_set_signal_stat_timer(recvpriv); | |
2220 | } |