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