1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#ifdef ATH_AR6K_11N_SUPPORT
25
26#include <a_config.h>
27#include <athdefs.h>
28#include <a_types.h>
29#include <a_osapi.h>
30#include <a_debug.h>
31#include "pkt_log.h"
32#include "aggr_recv_api.h"
33#include "aggr_rx_internal.h"
34#include "wmi.h"
35
36extern A_STATUS
37wmi_dot3_2_dix(void *osbuf);
38
39static void
40aggr_slice_amsdu(AGGR_INFO *p_aggr, RXTID *rxtid, void **osbuf);
41
42static void
43aggr_timeout(A_ATH_TIMER arg);
44
45static void
46aggr_deque_frms(AGGR_INFO *p_aggr, A_UINT8 tid, A_UINT16 seq_no, A_UINT8 order);
47
48static void
49aggr_dispatch_frames(AGGR_INFO *p_aggr, A_NETBUF_QUEUE_T *q);
50
51static void *
52aggr_get_osbuf(AGGR_INFO *p_aggr);
53
54void *
55aggr_init(ALLOC_NETBUFS netbuf_allocator)
56{
57 AGGR_INFO *p_aggr = NULL;
58 RXTID *rxtid;
59 A_UINT8 i;
60 A_STATUS status = A_OK;
61
62 A_PRINTF("In aggr_init..\n");
63
64 do {
65 p_aggr = A_MALLOC(sizeof(AGGR_INFO));
66 if(!p_aggr) {
67 A_PRINTF("Failed to allocate memory for aggr_node\n");
68 status = A_ERROR;
69 break;
70 }
71
72
73 A_MEMZERO(p_aggr, sizeof(AGGR_INFO));
74 p_aggr->aggr_sz = AGGR_SZ_DEFAULT;
75 A_INIT_TIMER(&p_aggr->timer, aggr_timeout, p_aggr);
76 p_aggr->timerScheduled = FALSE;
77 A_NETBUF_QUEUE_INIT(&p_aggr->freeQ);
78
79 p_aggr->netbuf_allocator = netbuf_allocator;
80 p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
81
82 for(i = 0; i < NUM_OF_TIDS; i++) {
83 rxtid = AGGR_GET_RXTID(p_aggr, i);
84 rxtid->aggr = FALSE;
85 rxtid->progress = FALSE;
86 rxtid->timerMon = FALSE;
87 A_NETBUF_QUEUE_INIT(&rxtid->q);
88 A_MUTEX_INIT(&rxtid->lock);
89 }
90 }while(FALSE);
91
92 A_PRINTF("going out of aggr_init..status %s\n",
93 (status == A_OK) ? "OK":"Error");
94
95 if(status != A_OK) {
96
97 aggr_module_destroy(p_aggr);
98 }
99 return ((status == A_OK) ? p_aggr : NULL);
100}
101
102
103static void
104aggr_delete_tid_state(AGGR_INFO *p_aggr, A_UINT8 tid)
105{
106 RXTID *rxtid;
107 RXTID_STATS *stats;
108
109 A_ASSERT(tid < NUM_OF_TIDS && p_aggr);
110
111 rxtid = AGGR_GET_RXTID(p_aggr, tid);
112 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
113
114 if(rxtid->aggr) {
115 aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
116 }
117
118 rxtid->aggr = FALSE;
119 rxtid->progress = FALSE;
120 rxtid->timerMon = FALSE;
121 rxtid->win_sz = 0;
122 rxtid->seq_next = 0;
123 rxtid->hold_q_sz = 0;
124
125 if(rxtid->hold_q) {
126 A_FREE(rxtid->hold_q);
127 rxtid->hold_q = NULL;
128 }
129
130 A_MEMZERO(stats, sizeof(RXTID_STATS));
131}
132
133void
134aggr_module_destroy(void *cntxt)
135{
136 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
137 RXTID *rxtid;
138 A_UINT8 i, k;
139 A_PRINTF("%s(): aggr = %p\n",_A_FUNCNAME_, p_aggr);
140 A_ASSERT(p_aggr);
141
142 if(p_aggr) {
143 if(p_aggr->timerScheduled) {
144 A_UNTIMEOUT(&p_aggr->timer);
145 p_aggr->timerScheduled = FALSE;
146 }
147
148 for(i = 0; i < NUM_OF_TIDS; i++) {
149 rxtid = AGGR_GET_RXTID(p_aggr, i);
150
151 if(rxtid->hold_q) {
152 for(k = 0; k< rxtid->hold_q_sz; k++) {
153 if(rxtid->hold_q[k].osbuf) {
154 A_NETBUF_FREE(rxtid->hold_q[k].osbuf);
155 }
156 }
157 A_FREE(rxtid->hold_q);
158 }
159
160 while(A_NETBUF_QUEUE_SIZE(&rxtid->q)) {
161 A_NETBUF_FREE(A_NETBUF_DEQUEUE(&rxtid->q));
162 }
163 if (A_IS_MUTEX_VALID(&rxtid->lock)) {
164 A_MUTEX_DELETE(&rxtid->lock);
165 }
166 }
167
168 while(A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
169 A_NETBUF_FREE(A_NETBUF_DEQUEUE(&p_aggr->freeQ));
170 }
171 A_FREE(p_aggr);
172 }
173 A_PRINTF("out aggr_module_destroy\n");
174}
175
176
177void
178aggr_register_rx_dispatcher(void *cntxt, void * dev, RX_CALLBACK fn)
179{
180 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
181
182 A_ASSERT(p_aggr && fn && dev);
183
184 p_aggr->rx_fn = fn;
185 p_aggr->dev = dev;
186}
187
188
189void
190aggr_process_bar(void *cntxt, A_UINT8 tid, A_UINT16 seq_no)
191{
192 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
193 RXTID_STATS *stats;
194
195 A_ASSERT(p_aggr);
196 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
197 stats->num_bar++;
198
199 aggr_deque_frms(p_aggr, tid, seq_no, ALL_SEQNO);
200}
201
202
203void
204aggr_recv_addba_req_evt(void *cntxt, A_UINT8 tid, A_UINT16 seq_no, A_UINT8 win_sz)
205{
206 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
207 RXTID *rxtid;
208 RXTID_STATS *stats;
209
210 A_ASSERT(p_aggr);
211 rxtid = AGGR_GET_RXTID(p_aggr, tid);
212 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
213
214 A_PRINTF("%s(): win_sz = %d aggr %d\n", _A_FUNCNAME_, win_sz, rxtid->aggr);
215 if(win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) {
216 A_PRINTF("win_sz %d, tid %d\n", win_sz, tid);
217 }
218
219 if(rxtid->aggr) {
220
221
222
223 aggr_delete_tid_state(p_aggr, tid);
224 }
225
226 rxtid->seq_next = seq_no;
227
228
229
230 rxtid->hold_q = A_MALLOC(HOLD_Q_SZ(win_sz));
231 if((rxtid->hold_q == NULL)) {
232 A_PRINTF("Failed to allocate memory, tid = %d\n", tid);
233 A_ASSERT(0);
234 }
235 A_MEMZERO(rxtid->hold_q, HOLD_Q_SZ(win_sz));
236
237
238 rxtid->win_sz = win_sz;
239
240
241
242 rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz);
243
244
245
246
247 if(A_NETBUF_QUEUE_SIZE(&rxtid->q) != 0) {
248 A_PRINTF("ERROR: Frames still on queue ?\n");
249 A_ASSERT(0);
250 }
251
252 rxtid->aggr = TRUE;
253}
254
255void
256aggr_recv_delba_req_evt(void *cntxt, A_UINT8 tid)
257{
258 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
259 RXTID *rxtid;
260
261 A_ASSERT(p_aggr);
262 A_PRINTF("%s(): tid %d\n", _A_FUNCNAME_, tid);
263
264 rxtid = AGGR_GET_RXTID(p_aggr, tid);
265
266 if(rxtid->aggr) {
267 aggr_delete_tid_state(p_aggr, tid);
268 }
269}
270
271static void
272aggr_deque_frms(AGGR_INFO *p_aggr, A_UINT8 tid, A_UINT16 seq_no, A_UINT8 order)
273{
274 RXTID *rxtid;
275 OSBUF_HOLD_Q *node;
276 A_UINT16 idx, idx_end, seq_end;
277 RXTID_STATS *stats;
278
279 A_ASSERT(p_aggr);
280 rxtid = AGGR_GET_RXTID(p_aggr, tid);
281 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
282
283
284 idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
285
286
287
288
289
290
291
292
293
294
295
296
297
298 seq_end = (seq_no) ? seq_no : rxtid->seq_next;
299 idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
300
301
302 A_MUTEX_LOCK(&rxtid->lock);
303 do {
304
305 node = &rxtid->hold_q[idx];
306
307 if((order == CONTIGUOUS_SEQNO) && (!node->osbuf))
308 break;
309
310
311
312
313
314 if(node->osbuf) {
315 if(node->is_amsdu) {
316 aggr_slice_amsdu(p_aggr, rxtid, &node->osbuf);
317 } else {
318 A_NETBUF_ENQUEUE(&rxtid->q, node->osbuf);
319 }
320 node->osbuf = NULL;
321 } else {
322 stats->num_hole++;
323 }
324
325
326 rxtid->seq_next = IEEE80211_NEXT_SEQ_NO(rxtid->seq_next);
327 idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
328 } while(idx != idx_end);
329
330 A_MUTEX_UNLOCK(&rxtid->lock);
331
332 stats->num_delivered += A_NETBUF_QUEUE_SIZE(&rxtid->q);
333 aggr_dispatch_frames(p_aggr, &rxtid->q);
334}
335
336static void *
337aggr_get_osbuf(AGGR_INFO *p_aggr)
338{
339 void *buf = NULL;
340
341
342
343
344
345
346 if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) {
347 p_aggr->netbuf_allocator(&p_aggr->freeQ, AGGR_NUM_OF_FREE_NETBUFS);
348 }
349
350 if (A_NETBUF_QUEUE_SIZE(&p_aggr->freeQ)) {
351 buf = A_NETBUF_DEQUEUE(&p_aggr->freeQ);
352 }
353
354 return buf;
355}
356
357
358static void
359aggr_slice_amsdu(AGGR_INFO *p_aggr, RXTID *rxtid, void **osbuf)
360{
361 void *new_buf;
362 A_UINT16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len;
363 A_UINT8 *framep;
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380 mac_hdr_len = sizeof(ATH_MAC_HDR);
381 framep = A_NETBUF_DATA(*osbuf) + mac_hdr_len;
382 amsdu_len = A_NETBUF_LEN(*osbuf) - mac_hdr_len;
383
384 while(amsdu_len > mac_hdr_len) {
385
386 payload_8023_len = A_BE2CPU16(((ATH_MAC_HDR *)framep)->typeOrLen);
387#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508
388#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46
389 if(payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN || payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) {
390 A_PRINTF("802.3 AMSDU frame bound check failed. len %d\n", payload_8023_len);
391 break;
392 }
393 frame_8023_len = payload_8023_len + mac_hdr_len;
394 new_buf = aggr_get_osbuf(p_aggr);
395 if(new_buf == NULL) {
396 A_PRINTF("No buffer available \n");
397 break;
398 }
399
400 A_MEMCPY(A_NETBUF_DATA(new_buf), framep, frame_8023_len);
401 A_NETBUF_PUT(new_buf, frame_8023_len);
402 if (wmi_dot3_2_dix(new_buf) != A_OK) {
403 A_PRINTF("dot3_2_dix err..\n");
404 A_NETBUF_FREE(new_buf);
405 break;
406 }
407
408 A_NETBUF_ENQUEUE(&rxtid->q, new_buf);
409
410
411 if ((amsdu_len - frame_8023_len) == 0) {
412 break;
413 }
414
415
416
417
418 frame_8023_len = ((frame_8023_len + 3) & ~3);
419
420 framep += frame_8023_len;
421 amsdu_len -= frame_8023_len;
422 }
423
424 A_NETBUF_FREE(*osbuf);
425 *osbuf = NULL;
426}
427
428void
429aggr_process_recv_frm(void *cntxt, A_UINT8 tid, A_UINT16 seq_no, A_BOOL is_amsdu, void **osbuf)
430{
431 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
432 RXTID *rxtid;
433 RXTID_STATS *stats;
434 A_UINT16 idx, st, cur, end;
435 A_UINT16 *log_idx;
436 OSBUF_HOLD_Q *node;
437 PACKET_LOG *log;
438
439 A_ASSERT(p_aggr);
440 A_ASSERT(tid < NUM_OF_TIDS);
441
442 rxtid = AGGR_GET_RXTID(p_aggr, tid);
443 stats = AGGR_GET_RXTID_STATS(p_aggr, tid);
444
445 stats->num_into_aggr++;
446
447 if(!rxtid->aggr) {
448 if(is_amsdu) {
449 aggr_slice_amsdu(p_aggr, rxtid, osbuf);
450 stats->num_amsdu++;
451 aggr_dispatch_frames(p_aggr, &rxtid->q);
452 }
453 return;
454 }
455
456
457 st = rxtid->seq_next;
458 cur = seq_no;
459 end = (st + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
460
461 log = &p_aggr->pkt_log;
462 log_idx = &log->last_idx;
463 log->info[*log_idx].cur = cur;
464 log->info[*log_idx].st = st;
465 log->info[*log_idx].end = end;
466 *log_idx = IEEE80211_NEXT_SEQ_NO(*log_idx);
467
468 if(((st < end) && (cur < st || cur > end)) ||
469 ((st > end) && (cur > end) && (cur < st))) {
470
471
472
473
474
475 A_UINT16 extended_end;
476
477 extended_end = (end + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO;
478
479 if(((end < extended_end) && (cur < end || cur > extended_end)) ||
480 ((end > extended_end) && (cur > extended_end) && (cur < end))) {
481
482 aggr_deque_frms(p_aggr, tid, 0, ALL_SEQNO);
483
484 if(cur >= rxtid->hold_q_sz-1) {
485 rxtid->seq_next = cur - (rxtid->hold_q_sz-1);
486 }else{
487 rxtid->seq_next = IEEE80211_MAX_SEQ_NO - (rxtid->hold_q_sz-2 - cur);
488 }
489 } else {
490
491 if(cur >= rxtid->hold_q_sz-1) {
492 st = cur - (rxtid->hold_q_sz-1);
493 }else{
494 st = IEEE80211_MAX_SEQ_NO - (rxtid->hold_q_sz-2 - cur);
495 }
496
497 aggr_deque_frms(p_aggr, tid, st, ALL_SEQNO);
498 }
499
500 stats->num_oow++;
501 }
502
503 idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz);
504
505
506 node = &rxtid->hold_q[idx];
507
508 A_MUTEX_LOCK(&rxtid->lock);
509 if(node->osbuf) {
510
511
512
513
514
515
516
517
518
519
520
521 A_NETBUF_FREE(node->osbuf);
522 stats->num_dups++;
523 }
524
525 node->osbuf = *osbuf;
526 node->is_amsdu = is_amsdu;
527 node->seq_no = seq_no;
528 if(node->is_amsdu) {
529 stats->num_amsdu++;
530 } else {
531 stats->num_mpdu++;
532 }
533 A_MUTEX_UNLOCK(&rxtid->lock);
534
535 *osbuf = NULL;
536 aggr_deque_frms(p_aggr, tid, 0, CONTIGUOUS_SEQNO);
537
538 if(p_aggr->timerScheduled) {
539 rxtid->progress = TRUE;
540 }else{
541 for(idx=0 ; idx<rxtid->hold_q_sz ; idx++) {
542 if(rxtid->hold_q[idx].osbuf) {
543
544
545
546 p_aggr->timerScheduled = TRUE;
547 A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
548 rxtid->progress = FALSE;
549 rxtid->timerMon = TRUE;
550 break;
551 }
552 }
553 }
554}
555
556
557
558
559
560
561void
562aggr_reset_state(void *cntxt)
563{
564 A_UINT8 tid;
565 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
566
567 A_ASSERT(p_aggr);
568
569 for(tid=0 ; tid<NUM_OF_TIDS ; tid++) {
570 aggr_delete_tid_state(p_aggr, tid);
571 }
572}
573
574
575static void
576aggr_timeout(A_ATH_TIMER arg)
577{
578 A_UINT8 i,j;
579 AGGR_INFO *p_aggr = (AGGR_INFO *)arg;
580 RXTID *rxtid;
581 RXTID_STATS *stats;
582
583
584
585
586
587 for(i = 0; i < NUM_OF_TIDS; i++) {
588 rxtid = AGGR_GET_RXTID(p_aggr, i);
589 stats = AGGR_GET_RXTID_STATS(p_aggr, i);
590
591 if(rxtid->aggr == FALSE ||
592 rxtid->timerMon == FALSE ||
593 rxtid->progress == TRUE) {
594 continue;
595 }
596
597 stats->num_timeouts++;
598 A_PRINTF("TO: st %d end %d\n", rxtid->seq_next, ((rxtid->seq_next + rxtid->hold_q_sz-1) & IEEE80211_MAX_SEQ_NO));
599 aggr_deque_frms(p_aggr, i, 0, ALL_SEQNO);
600 }
601
602 p_aggr->timerScheduled = FALSE;
603
604 for(i = 0; i < NUM_OF_TIDS; i++) {
605 rxtid = AGGR_GET_RXTID(p_aggr, i);
606
607 if(rxtid->aggr == TRUE && rxtid->hold_q) {
608 for(j = 0 ; j < rxtid->hold_q_sz ; j++)
609 {
610 if(rxtid->hold_q[j].osbuf)
611 {
612 p_aggr->timerScheduled = TRUE;
613 rxtid->timerMon = TRUE;
614 rxtid->progress = FALSE;
615 break;
616 }
617 }
618
619 if(j >= rxtid->hold_q_sz) {
620 rxtid->timerMon = FALSE;
621 }
622 }
623 }
624
625 if(p_aggr->timerScheduled) {
626
627 A_TIMEOUT_MS(&p_aggr->timer, AGGR_RX_TIMEOUT, 0);
628 }
629
630}
631
632static void
633aggr_dispatch_frames(AGGR_INFO *p_aggr, A_NETBUF_QUEUE_T *q)
634{
635 void *osbuf;
636
637 while((osbuf = A_NETBUF_DEQUEUE(q))) {
638 p_aggr->rx_fn(p_aggr->dev, osbuf);
639 }
640}
641
642void
643aggr_dump_stats(void *cntxt, PACKET_LOG **log_buf)
644{
645 AGGR_INFO *p_aggr = (AGGR_INFO *)cntxt;
646 RXTID *rxtid;
647 RXTID_STATS *stats;
648 A_UINT8 i;
649
650 *log_buf = &p_aggr->pkt_log;
651 A_PRINTF("\n\n================================================\n");
652 A_PRINTF("tid: num_into_aggr, dups, oow, mpdu, amsdu, delivered, timeouts, holes, bar, seq_next\n");
653 for(i = 0; i < NUM_OF_TIDS; i++) {
654 stats = AGGR_GET_RXTID_STATS(p_aggr, i);
655 rxtid = AGGR_GET_RXTID(p_aggr, i);
656 A_PRINTF("%d: %d %d %d %d %d %d %d %d %d : %d\n", i, stats->num_into_aggr, stats->num_dups,
657 stats->num_oow, stats->num_mpdu,
658 stats->num_amsdu, stats->num_delivered, stats->num_timeouts,
659 stats->num_hole, stats->num_bar,
660 rxtid->seq_next);
661 }
662 A_PRINTF("================================================\n\n");
663
664}
665
666#endif
667