1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#define _RTL8723BS_RECV_C_
16
17#include <drv_types.h>
18#include <rtw_debug.h>
19#include <rtl8723b_hal.h>
20
21static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter)
22{
23 INIT_LIST_HEAD(&precvbuf->list);
24 spin_lock_init(&precvbuf->recvbuf_lock);
25
26 precvbuf->adapter = padapter;
27
28 return _SUCCESS;
29}
30
31static void update_recvframe_attrib(struct adapter *padapter,
32 union recv_frame *precvframe,
33 struct recv_stat *prxstat)
34{
35 struct rx_pkt_attrib *pattrib;
36 struct recv_stat report;
37 PRXREPORT prxreport = (PRXREPORT)&report;
38
39 report.rxdw0 = prxstat->rxdw0;
40 report.rxdw1 = prxstat->rxdw1;
41 report.rxdw2 = prxstat->rxdw2;
42 report.rxdw3 = prxstat->rxdw3;
43 report.rxdw4 = prxstat->rxdw4;
44 report.rxdw5 = prxstat->rxdw5;
45
46 pattrib = &precvframe->u.hdr.attrib;
47 memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
48
49
50 pattrib->pkt_rpt_type = prxreport->c2h_ind ? C2H_PACKET : NORMAL_RX;
51
52
53 if (pattrib->pkt_rpt_type == NORMAL_RX) {
54
55
56 pattrib->pkt_len = (u16)prxreport->pktlen;
57 pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3);
58 pattrib->physt = (u8)prxreport->physt;
59
60 pattrib->crc_err = (u8)prxreport->crc32;
61 pattrib->icv_err = (u8)prxreport->icverr;
62
63 pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1);
64 pattrib->encrypt = (u8)prxreport->security;
65
66 pattrib->qos = (u8)prxreport->qos;
67 pattrib->priority = (u8)prxreport->tid;
68
69 pattrib->amsdu = (u8)prxreport->amsdu;
70
71 pattrib->seq_num = (u16)prxreport->seq;
72 pattrib->frag_num = (u8)prxreport->frag;
73 pattrib->mfrag = (u8)prxreport->mf;
74 pattrib->mdata = (u8)prxreport->md;
75
76 pattrib->data_rate = (u8)prxreport->rx_rate;
77 } else {
78 pattrib->pkt_len = (u16)prxreport->pktlen;
79 }
80}
81
82
83
84
85
86
87static void update_recvframe_phyinfo(union recv_frame *precvframe,
88 struct phy_stat *pphy_status)
89{
90 struct adapter *padapter = precvframe->u.hdr.adapter;
91 struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
92 struct hal_com_data *p_hal_data = GET_HAL_DATA(padapter);
93 struct odm_phy_info *p_phy_info =
94 (struct odm_phy_info *)(&pattrib->phy_info);
95
96 u8 *wlanhdr;
97 u8 *my_bssid;
98 u8 *rx_bssid;
99 u8 *rx_ra;
100 u8 *my_hwaddr;
101 u8 *sa = NULL;
102
103 struct odm_packet_info pkt_info = {
104 .data_rate = 0x00,
105 .station_id = 0x00,
106 .bssid_match = false,
107 .to_self = false,
108 .is_beacon = false,
109 };
110
111
112 struct sta_priv *pstapriv;
113 struct sta_info *psta;
114
115 wlanhdr = get_recvframe_data(precvframe);
116 my_bssid = get_bssid(&padapter->mlmepriv);
117 rx_bssid = get_hdr_bssid(wlanhdr);
118 pkt_info.bssid_match = ((!IsFrameTypeCtrl(wlanhdr)) &&
119 !pattrib->icv_err && !pattrib->crc_err &&
120 !ether_addr_equal(rx_bssid, my_bssid));
121
122 rx_ra = get_ra(wlanhdr);
123 my_hwaddr = myid(&padapter->eeprompriv);
124 pkt_info.to_self = pkt_info.bssid_match &&
125 !ether_addr_equal(rx_ra, my_hwaddr);
126
127
128 pkt_info.is_beacon = pkt_info.bssid_match &&
129 (GetFrameSubType(wlanhdr) == WIFI_BEACON);
130
131 sa = get_ta(wlanhdr);
132
133 pkt_info.station_id = 0xFF;
134
135 pstapriv = &padapter->stapriv;
136 psta = rtw_get_stainfo(pstapriv, sa);
137 if (psta) {
138 pkt_info.station_id = psta->mac_id;
139
140
141 }
142 pkt_info.data_rate = pattrib->data_rate;
143
144
145
146 ODM_PhyStatusQuery(&p_hal_data->odmpriv, p_phy_info,
147 (u8 *)pphy_status, &(pkt_info));
148 if (psta)
149 psta->rssi = pattrib->phy_info.RecvSignalPower;
150
151 precvframe->u.hdr.psta = NULL;
152 if (
153 pkt_info.bssid_match &&
154 (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)
155 ) {
156 if (psta) {
157 precvframe->u.hdr.psta = psta;
158 rtl8723b_process_phy_info(padapter, precvframe);
159 }
160 } else if (pkt_info.to_self || pkt_info.is_beacon) {
161 u32 adhoc_state = WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE;
162 if (check_fwstate(&padapter->mlmepriv, adhoc_state))
163 if (psta)
164 precvframe->u.hdr.psta = psta;
165 rtl8723b_process_phy_info(padapter, precvframe);
166 }
167}
168
169static void rtl8723bs_c2h_packet_handler(struct adapter *padapter,
170 u8 *pbuf, u16 length)
171{
172 u8 *tmp = NULL;
173 u8 res = false;
174
175 if (length == 0)
176 return;
177
178
179
180 tmp = rtw_zmalloc(length);
181 if (tmp == NULL)
182 return;
183
184 memcpy(tmp, pbuf, length);
185
186 res = rtw_c2h_packet_wk_cmd(padapter, tmp, length);
187
188 if (res == false)
189 kfree(tmp);
190
191
192
193 return;
194}
195
196static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv,
197 struct recv_buf *precvbuf)
198{
199 union recv_frame *precvframe;
200
201 precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue);
202 if (!precvframe) {
203 DBG_8192C("%s: no enough recv frame!\n", __func__);
204 rtw_enqueue_recvbuf_to_head(precvbuf,
205 &precvpriv->recv_buf_pending_queue);
206
207
208
209 tasklet_schedule(&precvpriv->recv_tasklet);
210 }
211
212 return precvframe;
213}
214
215static inline bool rx_crc_err(struct recv_priv *precvpriv,
216 struct hal_com_data *p_hal_data,
217 struct rx_pkt_attrib *pattrib,
218 union recv_frame *precvframe)
219{
220
221 if ((!(p_hal_data->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) {
222 DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n",
223 __func__, __LINE__);
224 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
225 return true;
226 }
227
228 return false;
229}
230
231static inline bool pkt_exceeds_tail(struct recv_priv *precvpriv,
232 u8 *end, u8 *tail,
233 union recv_frame *precvframe)
234{
235 if (end > tail) {
236 DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n",
237 __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail);
238 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
239 return true;
240 }
241
242 return false;
243}
244
245static void rtl8723bs_recv_tasklet(void *priv)
246{
247 struct adapter *padapter;
248 struct hal_com_data *p_hal_data;
249 struct recv_priv *precvpriv;
250 struct recv_buf *precvbuf;
251 union recv_frame *precvframe;
252 struct rx_pkt_attrib *pattrib;
253 struct __queue *recv_buf_queue;
254 u8 *ptr;
255 u32 pkt_offset, skb_len, alloc_sz;
256 _pkt *pkt_copy = NULL;
257 u8 shift_sz = 0, rx_report_sz = 0;
258
259 padapter = priv;
260 p_hal_data = GET_HAL_DATA(padapter);
261 precvpriv = &padapter->recvpriv;
262 recv_buf_queue = &precvpriv->recv_buf_pending_queue;
263
264 do {
265 precvbuf = rtw_dequeue_recvbuf(recv_buf_queue);
266 if (!precvbuf)
267 break;
268
269 ptr = precvbuf->pdata;
270
271 while (ptr < precvbuf->ptail) {
272 precvframe = try_alloc_recvframe(precvpriv, precvbuf);
273 if(!precvframe)
274 return;
275
276
277 update_recvframe_attrib(padapter, precvframe,
278 (struct recv_stat *)ptr);
279
280 pattrib = &precvframe->u.hdr.attrib;
281
282 if(rx_crc_err(precvpriv, p_hal_data,
283 pattrib, precvframe))
284 break;
285
286 rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz;
287 pkt_offset = rx_report_sz +
288 pattrib->shift_sz +
289 pattrib->pkt_len;
290
291 if(pkt_exceeds_tail(precvpriv, ptr + pkt_offset,
292 precvbuf->ptail, precvframe))
293 break;
294
295 if ((pattrib->crc_err) || (pattrib->icv_err)) {
296 DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n",
297 __func__, pattrib->crc_err,
298 pattrib->icv_err);
299 rtw_free_recvframe(precvframe,
300 &precvpriv->free_recv_queue);
301 } else {
302
303
304 if (pattrib->qos)
305 shift_sz = 6;
306 else
307 shift_sz = 0;
308
309 skb_len = pattrib->pkt_len;
310
311
312
313 if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
314 if (skb_len <= 1650)
315 alloc_sz = 1664;
316 else
317 alloc_sz = skb_len + 14;
318 } else {
319 alloc_sz = skb_len;
320
321
322 alloc_sz += 14;
323 }
324
325 pkt_copy = rtw_skb_alloc(alloc_sz);
326
327 if (pkt_copy) {
328 pkt_copy->dev = padapter->pnetdev;
329 precvframe->u.hdr.pkt = pkt_copy;
330 skb_reserve(pkt_copy, 8 - ((SIZE_PTR)(pkt_copy->data) & 7));
331 skb_reserve(pkt_copy, shift_sz);
332 memcpy(pkt_copy->data, (ptr + rx_report_sz + pattrib->shift_sz), skb_len);
333 precvframe->u.hdr.rx_head = pkt_copy->head;
334 precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data;
335 precvframe->u.hdr.rx_end = skb_end_pointer(pkt_copy);
336 } else {
337 if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
338 DBG_8192C("%s: alloc_skb fail, drop frag frame\n", __func__);
339 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
340 break;
341 }
342
343 precvframe->u.hdr.pkt = rtw_skb_clone(precvbuf->pskb);
344 if (precvframe->u.hdr.pkt) {
345 _pkt *pkt_clone = precvframe->u.hdr.pkt;
346
347 pkt_clone->data = ptr + rx_report_sz + pattrib->shift_sz;
348 skb_reset_tail_pointer(pkt_clone);
349 precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail
350 = pkt_clone->data;
351 precvframe->u.hdr.rx_end = pkt_clone->data + skb_len;
352 } else {
353 DBG_8192C("%s: rtw_skb_clone fail\n", __func__);
354 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
355 break;
356 }
357 }
358
359 recvframe_put(precvframe, skb_len);
360
361
362 if (p_hal_data->ReceiveConfig & RCR_APPFCS)
363 recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN);
364
365
366 ptr += RXDESC_SIZE;
367
368
369 if (p_hal_data->ReceiveConfig & RCR_APP_BA_SSN) {
370
371 ptr += 4;
372 }
373
374 if (pattrib->pkt_rpt_type == NORMAL_RX) {
375 if (pattrib->physt)
376 update_recvframe_phyinfo(precvframe, (struct phy_stat *)ptr);
377
378 if (rtw_recv_entry(precvframe) != _SUCCESS) {
379 RT_TRACE(_module_rtl871x_recv_c_, _drv_dump_, ("%s: rtw_recv_entry(precvframe) != _SUCCESS\n", __func__));
380 }
381 } else if (pattrib->pkt_rpt_type == C2H_PACKET) {
382 C2H_EVT_HDR C2hEvent;
383
384 u16 len_c2h = pattrib->pkt_len;
385 u8 *pbuf_c2h = precvframe->u.hdr.rx_data;
386 u8 *pdata_c2h;
387
388 C2hEvent.CmdID = pbuf_c2h[0];
389 C2hEvent.CmdSeq = pbuf_c2h[1];
390 C2hEvent.CmdLen = (len_c2h-2);
391 pdata_c2h = pbuf_c2h+2;
392
393 if (C2hEvent.CmdID == C2H_CCX_TX_RPT)
394 CCX_FwC2HTxRpt_8723b(padapter, pdata_c2h, C2hEvent.CmdLen);
395 else
396 rtl8723bs_c2h_packet_handler(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len);
397
398 rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue);
399 }
400 }
401
402 pkt_offset = _RND8(pkt_offset);
403 precvbuf->pdata += pkt_offset;
404 ptr = precvbuf->pdata;
405 precvframe = NULL;
406 pkt_copy = NULL;
407 }
408
409 rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue);
410 } while (1);
411}
412
413
414
415
416
417
418
419s32 rtl8723bs_init_recv_priv(struct adapter *padapter)
420{
421 s32 res;
422 u32 i, n;
423 struct recv_priv *precvpriv;
424 struct recv_buf *precvbuf;
425
426 res = _SUCCESS;
427 precvpriv = &padapter->recvpriv;
428
429
430 _rtw_init_queue(&precvpriv->free_recv_buf_queue);
431 _rtw_init_queue(&precvpriv->recv_buf_pending_queue);
432
433 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
434 precvpriv->pallocated_recv_buf = rtw_zmalloc(n);
435 if (precvpriv->pallocated_recv_buf == NULL) {
436 res = _FAIL;
437 RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("alloc recv_buf fail!\n"));
438 goto exit;
439 }
440
441 precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4);
442
443
444 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
445 for (i = 0; i < NR_RECVBUFF; i++) {
446 res = initrecvbuf(precvbuf, padapter);
447 if (res == _FAIL)
448 break;
449
450 if (precvbuf->pskb == NULL) {
451 SIZE_PTR tmpaddr = 0;
452 SIZE_PTR alignment = 0;
453
454 precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
455
456 if (precvbuf->pskb) {
457 precvbuf->pskb->dev = padapter->pnetdev;
458
459 tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
460 alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
461 skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
462 }
463
464 if (precvbuf->pskb == NULL) {
465 DBG_871X("%s: alloc_skb fail!\n", __func__);
466 }
467 }
468
469 list_add_tail(&precvbuf->list, &precvpriv->free_recv_buf_queue.queue);
470
471 precvbuf++;
472 }
473 precvpriv->free_recv_buf_queue_cnt = i;
474
475 if (res == _FAIL)
476 goto initbuferror;
477
478
479 tasklet_init(
480 &precvpriv->recv_tasklet,
481 (void(*)(unsigned long))rtl8723bs_recv_tasklet,
482 (unsigned long)padapter
483 );
484
485 goto exit;
486
487initbuferror:
488 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
489 if (precvbuf) {
490 n = precvpriv->free_recv_buf_queue_cnt;
491 precvpriv->free_recv_buf_queue_cnt = 0;
492 for (i = 0; i < n ; i++) {
493 list_del_init(&precvbuf->list);
494 rtw_os_recvbuf_resource_free(padapter, precvbuf);
495 precvbuf++;
496 }
497 precvpriv->precv_buf = NULL;
498 }
499
500 if (precvpriv->pallocated_recv_buf) {
501 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
502 kfree(precvpriv->pallocated_recv_buf);
503 precvpriv->pallocated_recv_buf = NULL;
504 }
505
506exit:
507 return res;
508}
509
510
511
512
513
514
515
516void rtl8723bs_free_recv_priv(struct adapter *padapter)
517{
518 u32 i, n;
519 struct recv_priv *precvpriv;
520 struct recv_buf *precvbuf;
521
522 precvpriv = &padapter->recvpriv;
523
524
525 tasklet_kill(&precvpriv->recv_tasklet);
526
527
528 precvbuf = (struct recv_buf *)precvpriv->precv_buf;
529 if (precvbuf) {
530 n = NR_RECVBUFF;
531 precvpriv->free_recv_buf_queue_cnt = 0;
532 for (i = 0; i < n ; i++) {
533 list_del_init(&precvbuf->list);
534 rtw_os_recvbuf_resource_free(padapter, precvbuf);
535 precvbuf++;
536 }
537 precvpriv->precv_buf = NULL;
538 }
539
540 if (precvpriv->pallocated_recv_buf) {
541 n = NR_RECVBUFF * sizeof(struct recv_buf) + 4;
542 kfree(precvpriv->pallocated_recv_buf);
543 precvpriv->pallocated_recv_buf = NULL;
544 }
545}
546