1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3 * IP Packet Parser Module.
4 *
5 * Copyright (C) 1999-2019, Broadcom.
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: dhd_ip.c 813282 2019-04-04 09:42:28Z $
29 */
30 #include <typedefs.h>
31 #include <osl.h>
32
33 #include <ethernet.h>
34 #include <vlan.h>
35 #include <802.3.h>
36 #include <bcmip.h>
37 #include <bcmendian.h>
38
39 #include <dhd_dbg.h>
40
41 #include <dhd_ip.h>
42 #include <dhd_config.h>
43
44 #if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK)
45 #include <dhd_bus.h>
46 #include <dhd_proto.h>
47 #include <bcmtcp.h>
48 #endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */
49
50 /* special values */
51 /* 802.3 llc/snap header */
52 static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
53
pkt_frag_info(osl_t * osh,void * p)54 pkt_frag_t pkt_frag_info(osl_t *osh, void *p)
55 {
56 uint8 *frame;
57 int length;
58 uint8 *pt; /* Pointer to type field */
59 uint16 ethertype;
60 struct ipv4_hdr *iph; /* IP frame pointer */
61 int ipl; /* IP frame length */
62 uint16 iph_frag;
63
64 ASSERT(osh && p);
65
66 frame = PKTDATA(osh, p);
67 length = PKTLEN(osh, p);
68
69 /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
70 if (length < ETHER_HDR_LEN) {
71 DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length));
72 return DHD_PKT_FRAG_NONE;
73 } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) {
74 /* Frame is Ethernet II */
75 pt = frame + ETHER_TYPE_OFFSET;
76 } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
77 !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
78 pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
79 } else {
80 DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__));
81 return DHD_PKT_FRAG_NONE;
82 }
83
84 ethertype = ntoh16(*(uint16 *)pt);
85
86 /* Skip VLAN tag, if any */
87 if (ethertype == ETHER_TYPE_8021Q) {
88 pt += VLAN_TAG_LEN;
89
90 if (pt + ETHER_TYPE_LEN > frame + length) {
91 DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length));
92 return DHD_PKT_FRAG_NONE;
93 }
94
95 ethertype = ntoh16(*(uint16 *)pt);
96 }
97
98 if (ethertype != ETHER_TYPE_IP) {
99 DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n",
100 __FUNCTION__, ethertype, length));
101 return DHD_PKT_FRAG_NONE;
102 }
103
104 iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN);
105 ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame));
106
107 /* We support IPv4 only */
108 if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) {
109 DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl));
110 return DHD_PKT_FRAG_NONE;
111 }
112
113 iph_frag = ntoh16(iph->frag);
114
115 if (iph_frag & IPV4_FRAG_DONT) {
116 return DHD_PKT_FRAG_NONE;
117 } else if ((iph_frag & IPV4_FRAG_MORE) == 0) {
118 return DHD_PKT_FRAG_LAST;
119 } else {
120 return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST;
121 }
122 }
123
124 #ifdef DHDTCPACK_SUPPRESS
125
126 typedef struct {
127 void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */
128 void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */
129 int ifidx;
130 uint8 supp_cnt;
131 dhd_pub_t *dhdp;
132 #ifndef TCPACK_SUPPRESS_HOLD_HRT
133 timer_list_compat_t timer;
134 #else
135 struct tasklet_hrtimer timer;
136 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
137 } tcpack_info_t;
138
139 typedef struct _tdata_psh_info_t {
140 uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */
141 struct _tdata_psh_info_t *next; /* next pointer of the link chain */
142 } tdata_psh_info_t;
143
144 typedef struct {
145 struct {
146 uint8 src[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */
147 uint8 dst[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */
148 } ip_addr;
149 struct {
150 uint8 src[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */
151 uint8 dst[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */
152 } tcp_port;
153 tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */
154 tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */
155 uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */
156 } tcpdata_info_t;
157
158 /* TCPACK SUPPRESS module */
159 typedef struct {
160 int tcpack_info_cnt;
161 tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */
162 int tcpdata_info_cnt;
163 tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */
164 tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */
165 tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */
166 #ifdef DHDTCPACK_SUP_DBG
167 int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */
168 #endif /* DHDTCPACK_SUP_DBG */
169 } tcpack_sup_module_t;
170
171 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
172 counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1};
173 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
174
175 static void
_tdata_psh_info_pool_enq(tcpack_sup_module_t * tcpack_sup_mod,tdata_psh_info_t * tdata_psh_info)176 _tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod,
177 tdata_psh_info_t *tdata_psh_info)
178 {
179 if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) {
180 DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__,
181 tcpack_sup_mod, tdata_psh_info));
182 return;
183 }
184
185 ASSERT(tdata_psh_info->next == NULL);
186 tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free;
187 tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info;
188 #ifdef DHDTCPACK_SUP_DBG
189 tcpack_sup_mod->psh_info_enq_num++;
190 #endif // endif
191 }
192
193 static tdata_psh_info_t*
_tdata_psh_info_pool_deq(tcpack_sup_module_t * tcpack_sup_mod)194 _tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod)
195 {
196 tdata_psh_info_t *tdata_psh_info = NULL;
197
198 if (tcpack_sup_mod == NULL) {
199 DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__,
200 tcpack_sup_mod));
201 return NULL;
202 }
203
204 tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free;
205 if (tdata_psh_info == NULL)
206 DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__));
207 else {
208 tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next;
209 tdata_psh_info->next = NULL;
210 #ifdef DHDTCPACK_SUP_DBG
211 tcpack_sup_mod->psh_info_enq_num--;
212 #endif /* DHDTCPACK_SUP_DBG */
213 }
214
215 return tdata_psh_info;
216 }
217
218 #ifdef BCMSDIO
_tdata_psh_info_pool_init(dhd_pub_t * dhdp,tcpack_sup_module_t * tcpack_sup_mod)219 static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp,
220 tcpack_sup_module_t *tcpack_sup_mod)
221 {
222 tdata_psh_info_t *tdata_psh_info_pool = NULL;
223 uint i;
224
225 DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__));
226
227 if (tcpack_sup_mod == NULL)
228 return BCME_ERROR;
229
230 ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL);
231 ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL);
232
233 tdata_psh_info_pool =
234 MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
235
236 if (tdata_psh_info_pool == NULL)
237 return BCME_NOMEM;
238 bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
239 #ifdef DHDTCPACK_SUP_DBG
240 tcpack_sup_mod->psh_info_enq_num = 0;
241 #endif /* DHDTCPACK_SUP_DBG */
242
243 /* Enqueue newly allocated tcpdata psh info elements to the pool */
244 for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++)
245 _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]);
246
247 ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL);
248 tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool;
249
250 return BCME_OK;
251 }
252
_tdata_psh_info_pool_deinit(dhd_pub_t * dhdp,tcpack_sup_module_t * tcpack_sup_mod)253 static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp,
254 tcpack_sup_module_t *tcpack_sup_mod)
255 {
256 uint i;
257 tdata_psh_info_t *tdata_psh_info;
258
259 DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__));
260
261 if (tcpack_sup_mod == NULL) {
262 DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n",
263 __FUNCTION__, __LINE__));
264 return;
265 }
266
267 for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) {
268 tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i];
269 /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */
270 while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) {
271 tcpdata_info->tdata_psh_info_head = tdata_psh_info->next;
272 tdata_psh_info->next = NULL;
273 _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info);
274 }
275 tcpdata_info->tdata_psh_info_tail = NULL;
276 }
277 #ifdef DHDTCPACK_SUP_DBG
278 DHD_ERROR(("%s %d: PSH INFO ENQ %d\n",
279 __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
280 #endif /* DHDTCPACK_SUP_DBG */
281
282 i = 0;
283 /* Be sure we recollected all tdata_psh_info elements */
284 while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) {
285 tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next;
286 tdata_psh_info->next = NULL;
287 i++;
288 }
289 ASSERT(i == TCPDATA_PSH_INFO_MAXNUM);
290 MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool,
291 sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
292 tcpack_sup_mod->tdata_psh_info_pool = NULL;
293
294 return;
295 }
296 #endif /* BCMSDIO */
297
298 #ifdef BCMPCIE
299 #ifndef TCPACK_SUPPRESS_HOLD_HRT
dhd_tcpack_send(ulong data)300 static void dhd_tcpack_send(ulong data)
301 #else
302 static enum hrtimer_restart dhd_tcpack_send(struct hrtimer *timer)
303 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
304 {
305 tcpack_sup_module_t *tcpack_sup_mod;
306 tcpack_info_t *cur_tbl;
307 dhd_pub_t *dhdp;
308 int ifidx;
309 void* pkt;
310 unsigned long flags;
311
312 #ifndef TCPACK_SUPPRESS_HOLD_HRT
313 cur_tbl = (tcpack_info_t *)data;
314 #else
315 cur_tbl = container_of(timer, tcpack_info_t, timer.timer);
316 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
317
318 if (!cur_tbl) {
319 goto done;
320 }
321
322 dhdp = cur_tbl->dhdp;
323 if (!dhdp) {
324 goto done;
325 }
326
327 flags = dhd_os_tcpacklock(dhdp);
328
329 if (unlikely(dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD)) {
330 dhd_os_tcpackunlock(dhdp, flags);
331 goto done;
332 }
333
334 tcpack_sup_mod = dhdp->tcpack_sup_module;
335 if (!tcpack_sup_mod) {
336 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
337 __FUNCTION__, __LINE__));
338 dhd_os_tcpackunlock(dhdp, flags);
339 goto done;
340 }
341 pkt = cur_tbl->pkt_in_q;
342 ifidx = cur_tbl->ifidx;
343 if (!pkt) {
344 dhd_os_tcpackunlock(dhdp, flags);
345 goto done;
346 }
347 cur_tbl->pkt_in_q = NULL;
348 cur_tbl->pkt_ether_hdr = NULL;
349 cur_tbl->ifidx = 0;
350 cur_tbl->supp_cnt = 0;
351 if (--tcpack_sup_mod->tcpack_info_cnt < 0) {
352 DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n",
353 __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt));
354 }
355
356 dhd_os_tcpackunlock(dhdp, flags);
357
358 dhd_sendpkt(dhdp, ifidx, pkt);
359
360 done:
361 #ifndef TCPACK_SUPPRESS_HOLD_HRT
362 return;
363 #else
364 return HRTIMER_NORESTART;
365 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
366 }
367 #endif /* BCMPCIE */
368
dhd_tcpack_suppress_set(dhd_pub_t * dhdp,uint8 mode)369 int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
370 {
371 int ret = BCME_OK;
372 unsigned long flags;
373 tcpack_sup_module_t *tcpack_sup_module;
374 uint8 invalid_mode = FALSE;
375 int prev_mode;
376 int i = 0;
377
378 flags = dhd_os_tcpacklock(dhdp);
379 tcpack_sup_module = dhdp->tcpack_sup_module;
380 prev_mode = dhdp->tcpack_sup_mode;
381
382 if (prev_mode == mode) {
383 DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode));
384 goto exit;
385 }
386
387 invalid_mode |= (mode >= TCPACK_SUP_LAST_MODE);
388 #ifdef BCMSDIO
389 invalid_mode |= (mode == TCPACK_SUP_HOLD);
390 #endif /* BCMSDIO */
391 #ifdef BCMPCIE
392 invalid_mode |= ((mode == TCPACK_SUP_REPLACE) || (mode == TCPACK_SUP_DELAYTX));
393 #endif /* BCMPCIE */
394
395 if (invalid_mode) {
396 DHD_ERROR(("%s %d: Invalid TCP ACK Suppress mode %d\n",
397 __FUNCTION__, __LINE__, mode));
398 ret = BCME_BADARG;
399 goto exit;
400 }
401
402 printf("%s: TCP ACK Suppress mode %d -> mode %d\n",
403 __FUNCTION__, dhdp->tcpack_sup_mode, mode);
404
405 /* Pre-process routines to change a new mode as per previous mode */
406 switch (prev_mode) {
407 case TCPACK_SUP_OFF:
408 if (tcpack_sup_module == NULL) {
409 tcpack_sup_module = MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t));
410 if (tcpack_sup_module == NULL) {
411 DHD_ERROR(("%s[%d]: Failed to allocate the new memory for "
412 "tcpack_sup_module\n", __FUNCTION__, __LINE__));
413 dhdp->tcpack_sup_mode = TCPACK_SUP_OFF;
414 ret = BCME_NOMEM;
415 goto exit;
416 }
417 dhdp->tcpack_sup_module = tcpack_sup_module;
418 }
419 bzero(tcpack_sup_module, sizeof(tcpack_sup_module_t));
420 break;
421 #ifdef BCMSDIO
422 case TCPACK_SUP_DELAYTX:
423 if (tcpack_sup_module) {
424 /* We won't need tdata_psh_info pool and
425 * tcpddata_info_tbl anymore
426 */
427 _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_module);
428 tcpack_sup_module->tcpdata_info_cnt = 0;
429 bzero(tcpack_sup_module->tcpdata_info_tbl,
430 sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM);
431 }
432
433 /* For half duplex bus interface, tx precedes rx by default */
434 if (dhdp->bus) {
435 dhd_bus_set_dotxinrx(dhdp->bus, TRUE);
436 }
437
438 if (tcpack_sup_module == NULL) {
439 DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n",
440 __FUNCTION__, __LINE__));
441 dhdp->tcpack_sup_mode = TCPACK_SUP_OFF;
442 goto exit;
443 }
444 break;
445 #endif /* BCMSDIO */
446 }
447
448 /* Update a new mode */
449 dhdp->tcpack_sup_mode = mode;
450
451 /* Process for a new mode */
452 switch (mode) {
453 case TCPACK_SUP_OFF:
454 ASSERT(tcpack_sup_module != NULL);
455 /* Clean up timer/data structure for
456 * any remaining/pending packet or timer.
457 */
458 if (tcpack_sup_module) {
459 /* Check if previous mode is TCAPACK_SUP_HOLD */
460 if (prev_mode == TCPACK_SUP_HOLD) {
461 for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
462 tcpack_info_t *tcpack_info_tbl =
463 &tcpack_sup_module->tcpack_info_tbl[i];
464 #ifndef TCPACK_SUPPRESS_HOLD_HRT
465 del_timer(&tcpack_info_tbl->timer);
466 #else
467 hrtimer_cancel(&tcpack_info_tbl->timer.timer);
468 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
469 if (tcpack_info_tbl->pkt_in_q) {
470 PKTFREE(dhdp->osh,
471 tcpack_info_tbl->pkt_in_q, TRUE);
472 tcpack_info_tbl->pkt_in_q = NULL;
473 }
474 }
475 }
476 MFREE(dhdp->osh, tcpack_sup_module, sizeof(tcpack_sup_module_t));
477 dhdp->tcpack_sup_module = NULL;
478 } else {
479 DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n",
480 __FUNCTION__, __LINE__));
481 }
482 break;
483 #ifdef BCMSDIO
484 case TCPACK_SUP_REPLACE:
485 /* There is nothing to configure for this mode */
486 break;
487 case TCPACK_SUP_DELAYTX:
488 ret = _tdata_psh_info_pool_init(dhdp, tcpack_sup_module);
489 if (ret != BCME_OK) {
490 DHD_ERROR(("%s %d: pool init fail with %d\n",
491 __FUNCTION__, __LINE__, ret));
492 break;
493 }
494 if (dhdp->bus) {
495 dhd_bus_set_dotxinrx(dhdp->bus, FALSE);
496 }
497 break;
498 #endif /* BCMSDIO */
499 #ifdef BCMPCIE
500 case TCPACK_SUP_HOLD:
501 dhdp->tcpack_sup_ratio = dhdp->conf->tcpack_sup_ratio;
502 dhdp->tcpack_sup_delay = dhdp->conf->tcpack_sup_delay;
503 for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
504 tcpack_info_t *tcpack_info_tbl =
505 &tcpack_sup_module->tcpack_info_tbl[i];
506 tcpack_info_tbl->dhdp = dhdp;
507 #ifndef TCPACK_SUPPRESS_HOLD_HRT
508 init_timer_compat(&tcpack_info_tbl->timer,
509 dhd_tcpack_send, tcpack_info_tbl);
510 #else
511 tasklet_hrtimer_init(&tcpack_info_tbl->timer,
512 dhd_tcpack_send, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
513 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
514 }
515 break;
516 #endif /* BCMPCIE */
517 }
518
519 exit:
520 dhd_os_tcpackunlock(dhdp, flags);
521 return ret;
522 }
523
524 void
dhd_tcpack_info_tbl_clean(dhd_pub_t * dhdp)525 dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp)
526 {
527 tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
528 int i;
529 unsigned long flags;
530
531 if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
532 goto exit;
533
534 flags = dhd_os_tcpacklock(dhdp);
535
536 if (!tcpack_sup_mod) {
537 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
538 __FUNCTION__, __LINE__));
539 dhd_os_tcpackunlock(dhdp, flags);
540 goto exit;
541 }
542
543 if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) {
544 for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
545 if (tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q) {
546 PKTFREE(dhdp->osh, tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q,
547 TRUE);
548 tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q = NULL;
549 tcpack_sup_mod->tcpack_info_tbl[i].pkt_ether_hdr = NULL;
550 tcpack_sup_mod->tcpack_info_tbl[i].ifidx = 0;
551 tcpack_sup_mod->tcpack_info_tbl[i].supp_cnt = 0;
552 }
553 }
554 } else {
555 tcpack_sup_mod->tcpack_info_cnt = 0;
556 bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM);
557 }
558
559 dhd_os_tcpackunlock(dhdp, flags);
560
561 if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) {
562 for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
563 #ifndef TCPACK_SUPPRESS_HOLD_HRT
564 del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer);
565 #else
566 hrtimer_cancel(&tcpack_sup_mod->tcpack_info_tbl[i].timer.timer);
567 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
568 }
569 }
570
571 exit:
572 return;
573 }
574
dhd_tcpack_check_xmit(dhd_pub_t * dhdp,void * pkt)575 inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
576 {
577 uint8 i;
578 tcpack_sup_module_t *tcpack_sup_mod;
579 tcpack_info_t *tcpack_info_tbl;
580 int tbl_cnt;
581 int ret = BCME_OK;
582 void *pdata;
583 uint32 pktlen;
584 unsigned long flags;
585
586 if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
587 goto exit;
588
589 pdata = PKTDATA(dhdp->osh, pkt);
590 pktlen = PKTLEN(dhdp->osh, pkt) - dhd_prot_hdrlen(dhdp, pdata);
591
592 if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) {
593 DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
594 __FUNCTION__, __LINE__, pktlen));
595 goto exit;
596 }
597
598 flags = dhd_os_tcpacklock(dhdp);
599 tcpack_sup_mod = dhdp->tcpack_sup_module;
600
601 if (!tcpack_sup_mod) {
602 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
603 ret = BCME_ERROR;
604 dhd_os_tcpackunlock(dhdp, flags);
605 goto exit;
606 }
607 tbl_cnt = tcpack_sup_mod->tcpack_info_cnt;
608 tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl;
609
610 ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM);
611
612 for (i = 0; i < tbl_cnt; i++) {
613 if (tcpack_info_tbl[i].pkt_in_q == pkt) {
614 DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n",
615 __FUNCTION__, __LINE__, pkt, i, tbl_cnt));
616 /* This pkt is being transmitted so remove the tcp_ack_info of it. */
617 if (i < tbl_cnt - 1) {
618 bcopy(&tcpack_info_tbl[tbl_cnt - 1],
619 &tcpack_info_tbl[i], sizeof(tcpack_info_t));
620 }
621 bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t));
622 if (--tcpack_sup_mod->tcpack_info_cnt < 0) {
623 DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n",
624 __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt));
625 ret = BCME_ERROR;
626 }
627 break;
628 }
629 }
630 dhd_os_tcpackunlock(dhdp, flags);
631
632 exit:
633 return ret;
634 }
635
dhd_tcpdata_psh_acked(dhd_pub_t * dhdp,uint8 * ip_hdr,uint8 * tcp_hdr,uint32 tcp_ack_num)636 static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr,
637 uint8 *tcp_hdr, uint32 tcp_ack_num)
638 {
639 tcpack_sup_module_t *tcpack_sup_mod;
640 int i;
641 tcpdata_info_t *tcpdata_info = NULL;
642 tdata_psh_info_t *tdata_psh_info = NULL;
643 bool ret = FALSE;
644
645 if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX)
646 goto exit;
647
648 tcpack_sup_mod = dhdp->tcpack_sup_module;
649
650 if (!tcpack_sup_mod) {
651 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
652 goto exit;
653 }
654
655 DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
656 " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__,
657 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
658 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
659 ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
660 ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]),
661 tcp_ack_num));
662
663 for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) {
664 tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i];
665 DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
666 " TCP port %d %d\n", __FUNCTION__, __LINE__, i,
667 IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->ip_addr.src)),
668 IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->ip_addr.dst)),
669 ntoh16_ua(tcpdata_info_tmp->tcp_port.src),
670 ntoh16_ua(tcpdata_info_tmp->tcp_port.dst)));
671
672 /* If either IP address or TCP port number does not match, skip. */
673 if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET],
674 tcpdata_info_tmp->ip_addr.dst, IPV4_ADDR_LEN) == 0 &&
675 memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET],
676 tcpdata_info_tmp->ip_addr.src, IPV4_ADDR_LEN) == 0 &&
677 memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET],
678 tcpdata_info_tmp->tcp_port.dst, TCP_PORT_LEN) == 0 &&
679 memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET],
680 tcpdata_info_tmp->tcp_port.src, TCP_PORT_LEN) == 0) {
681 tcpdata_info = tcpdata_info_tmp;
682 break;
683 }
684 }
685
686 if (tcpdata_info == NULL) {
687 DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__));
688 goto exit;
689 }
690
691 if (tcpdata_info->tdata_psh_info_head == NULL) {
692 DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__));
693 }
694
695 while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) {
696 if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) {
697 DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n",
698 __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq));
699 tcpdata_info->tdata_psh_info_head = tdata_psh_info->next;
700 tdata_psh_info->next = NULL;
701 _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info);
702 ret = TRUE;
703 } else
704 break;
705 }
706 if (tdata_psh_info == NULL)
707 tcpdata_info->tdata_psh_info_tail = NULL;
708
709 #ifdef DHDTCPACK_SUP_DBG
710 DHD_TRACE(("%s %d: PSH INFO ENQ %d\n",
711 __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
712 #endif /* DHDTCPACK_SUP_DBG */
713
714 exit:
715 return ret;
716 }
717
718 bool
dhd_tcpack_suppress(dhd_pub_t * dhdp,void * pkt)719 dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
720 {
721 uint8 *new_ether_hdr; /* Ethernet header of the new packet */
722 uint16 new_ether_type; /* Ethernet type of the new packet */
723 uint8 *new_ip_hdr; /* IP header of the new packet */
724 uint8 *new_tcp_hdr; /* TCP header of the new packet */
725 uint32 new_ip_hdr_len; /* IP header length of the new packet */
726 uint32 cur_framelen;
727 uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */
728 uint16 new_ip_total_len; /* Total length of IP packet for the new packet */
729 uint32 new_tcp_hdr_len; /* TCP header length of the new packet */
730 tcpack_sup_module_t *tcpack_sup_mod;
731 tcpack_info_t *tcpack_info_tbl;
732 int i;
733 bool ret = FALSE;
734 bool set_dotxinrx = TRUE;
735 unsigned long flags;
736
737 if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
738 goto exit;
739
740 new_ether_hdr = PKTDATA(dhdp->osh, pkt);
741 cur_framelen = PKTLEN(dhdp->osh, pkt);
742
743 if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) {
744 DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
745 __FUNCTION__, __LINE__, cur_framelen));
746 goto exit;
747 }
748
749 new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13];
750
751 if (new_ether_type != ETHER_TYPE_IP) {
752 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
753 __FUNCTION__, __LINE__, new_ether_type));
754 goto exit;
755 }
756
757 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type));
758
759 new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN;
760 cur_framelen -= ETHER_HDR_LEN;
761
762 ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
763
764 new_ip_hdr_len = IPV4_HLEN(new_ip_hdr);
765 if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) {
766 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
767 __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr)));
768 goto exit;
769 }
770
771 new_tcp_hdr = new_ip_hdr + new_ip_hdr_len;
772 cur_framelen -= new_ip_hdr_len;
773
774 ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
775
776 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));
777
778 /* is it an ack ? Allow only ACK flag, not to suppress others. */
779 if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) {
780 DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n",
781 __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET]));
782 goto exit;
783 }
784
785 new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]);
786 new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]);
787
788 /* This packet has TCP data, so just send */
789 if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) {
790 DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__));
791 goto exit;
792 }
793
794 ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len);
795
796 new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]);
797
798 DHD_TRACE(("%s %d: TCP ACK with zero DATA length"
799 " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n",
800 __FUNCTION__, __LINE__,
801 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])),
802 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])),
803 ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]),
804 ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET])));
805
806 /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */
807 flags = dhd_os_tcpacklock(dhdp);
808 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
809 counter_printlog(&tack_tbl);
810 tack_tbl.cnt[0]++;
811 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
812
813 tcpack_sup_mod = dhdp->tcpack_sup_module;
814 tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl;
815
816 if (!tcpack_sup_mod) {
817 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
818 ret = BCME_ERROR;
819 dhd_os_tcpackunlock(dhdp, flags);
820 goto exit;
821 }
822
823 if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) {
824 /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */
825 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
826 tack_tbl.cnt[5]++;
827 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
828 } else
829 set_dotxinrx = FALSE;
830
831 for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) {
832 void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */
833 uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr;
834 uint32 old_ip_hdr_len, old_tcp_hdr_len;
835 uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */
836
837 if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) {
838 DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n",
839 __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt));
840 break;
841 }
842
843 if (PKTDATA(dhdp->osh, oldpkt) == NULL) {
844 DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n",
845 __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt));
846 break;
847 }
848
849 old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr;
850 old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN;
851 old_ip_hdr_len = IPV4_HLEN(old_ip_hdr);
852 old_tcp_hdr = old_ip_hdr + old_ip_hdr_len;
853 old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]);
854
855 DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
856 " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i,
857 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])),
858 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])),
859 ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]),
860 ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET])));
861
862 /* If either of IP address or TCP port number does not match, skip.
863 * Note that src/dst addr fields in ip header are contiguous being 8 bytes in total.
864 * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total.
865 */
866 if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET],
867 &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) ||
868 memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET],
869 &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2))
870 continue;
871
872 old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]);
873
874 if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) {
875 /* New packet has higher TCP ACK number, so it replaces the old packet */
876 if (new_ip_hdr_len == old_ip_hdr_len &&
877 new_tcp_hdr_len == old_tcp_hdr_len) {
878 ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0);
879 bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len);
880 PKTFREE(dhdp->osh, pkt, FALSE);
881 DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n",
882 __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num));
883 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
884 tack_tbl.cnt[2]++;
885 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
886 ret = TRUE;
887 } else {
888 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
889 tack_tbl.cnt[6]++;
890 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
891 DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d"
892 " ACK %u -> %u\n", __FUNCTION__, __LINE__,
893 new_ip_hdr_len, old_ip_hdr_len,
894 new_tcp_hdr_len, old_tcp_hdr_len,
895 old_tcpack_num, new_tcp_ack_num));
896 }
897 } else if (new_tcp_ack_num == old_tcpack_num) {
898 set_dotxinrx = TRUE;
899 /* TCPACK retransmission */
900 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
901 tack_tbl.cnt[3]++;
902 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
903 } else {
904 DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n",
905 __FUNCTION__, __LINE__, old_tcpack_num, oldpkt,
906 new_tcp_ack_num, pkt));
907 }
908 dhd_os_tcpackunlock(dhdp, flags);
909 goto exit;
910 }
911
912 if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) {
913 /* No TCPACK packet with the same IP addr and TCP port is found
914 * in tcp_ack_info_tbl. So add this packet to the table.
915 */
916 DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
917 __FUNCTION__, __LINE__, pkt, new_ether_hdr,
918 tcpack_sup_mod->tcpack_info_cnt));
919
920 tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt;
921 tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr;
922 tcpack_sup_mod->tcpack_info_cnt++;
923 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
924 tack_tbl.cnt[1]++;
925 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
926 } else {
927 ASSERT(i == tcpack_sup_mod->tcpack_info_cnt);
928 DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
929 __FUNCTION__, __LINE__));
930 }
931 dhd_os_tcpackunlock(dhdp, flags);
932
933 exit:
934 /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */
935 if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx)
936 dhd_bus_set_dotxinrx(dhdp->bus, TRUE);
937
938 return ret;
939 }
940
941 bool
dhd_tcpdata_info_get(dhd_pub_t * dhdp,void * pkt)942 dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt)
943 {
944 uint8 *ether_hdr; /* Ethernet header of the new packet */
945 uint16 ether_type; /* Ethernet type of the new packet */
946 uint8 *ip_hdr; /* IP header of the new packet */
947 uint8 *tcp_hdr; /* TCP header of the new packet */
948 uint32 ip_hdr_len; /* IP header length of the new packet */
949 uint32 cur_framelen;
950 uint16 ip_total_len; /* Total length of IP packet for the new packet */
951 uint32 tcp_hdr_len; /* TCP header length of the new packet */
952 uint32 tcp_seq_num; /* TCP sequence number of the new packet */
953 uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */
954 uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */
955 tcpack_sup_module_t *tcpack_sup_mod;
956 tcpdata_info_t *tcpdata_info = NULL;
957 tdata_psh_info_t *tdata_psh_info;
958
959 int i;
960 bool ret = FALSE;
961 unsigned long flags;
962
963 if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX)
964 goto exit;
965
966 ether_hdr = PKTDATA(dhdp->osh, pkt);
967 cur_framelen = PKTLEN(dhdp->osh, pkt);
968
969 ether_type = ether_hdr[12] << 8 | ether_hdr[13];
970
971 if (ether_type != ETHER_TYPE_IP) {
972 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
973 __FUNCTION__, __LINE__, ether_type));
974 goto exit;
975 }
976
977 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type));
978
979 ip_hdr = ether_hdr + ETHER_HDR_LEN;
980 cur_framelen -= ETHER_HDR_LEN;
981
982 ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
983
984 ip_hdr_len = IPV4_HLEN(ip_hdr);
985 if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) {
986 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
987 __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr)));
988 goto exit;
989 }
990
991 tcp_hdr = ip_hdr + ip_hdr_len;
992 cur_framelen -= ip_hdr_len;
993
994 ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
995
996 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));
997
998 ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]);
999 tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]);
1000
1001 /* This packet is mere TCP ACK, so do nothing */
1002 if (ip_total_len == ip_hdr_len + tcp_hdr_len) {
1003 DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__));
1004 goto exit;
1005 }
1006
1007 ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len);
1008
1009 if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) {
1010 DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__));
1011 goto exit;
1012 }
1013
1014 DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length"
1015 " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n",
1016 __FUNCTION__, __LINE__,
1017 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
1018 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
1019 ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
1020 ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]),
1021 tcp_hdr[TCP_FLAGS_OFFSET]));
1022
1023 flags = dhd_os_tcpacklock(dhdp);
1024 tcpack_sup_mod = dhdp->tcpack_sup_module;
1025
1026 if (!tcpack_sup_mod) {
1027 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
1028 ret = BCME_ERROR;
1029 dhd_os_tcpackunlock(dhdp, flags);
1030 goto exit;
1031 }
1032
1033 /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */
1034 i = 0;
1035 while (i < tcpack_sup_mod->tcpdata_info_cnt) {
1036 tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i];
1037 uint32 now_in_ms = OSL_SYSUPTIME();
1038 DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
1039 " TCP port %d %d\n", __FUNCTION__, __LINE__, i,
1040 IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->ip_addr.src)),
1041 IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->ip_addr.dst)),
1042 ntoh16_ua(tdata_info_tmp->tcp_port.src),
1043 ntoh16_ua(tdata_info_tmp->tcp_port.dst)));
1044
1045 /* If both IP address and TCP port number match, we found it so break.
1046 * Note that src/dst addr fields in ip header are contiguous being 8 bytes in total.
1047 * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total.
1048 */
1049 if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET],
1050 (void *)&tdata_info_tmp->ip_addr, IPV4_ADDR_LEN * 2) == 0 &&
1051 memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET],
1052 (void *)&tdata_info_tmp->tcp_port, TCP_PORT_LEN * 2) == 0) {
1053 tcpdata_info = tdata_info_tmp;
1054 tcpdata_info->last_used_time = now_in_ms;
1055 break;
1056 }
1057
1058 if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) {
1059 tdata_psh_info_t *tdata_psh_info_tmp;
1060 tcpdata_info_t *last_tdata_info;
1061
1062 while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) {
1063 tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next;
1064 tdata_psh_info_tmp->next = NULL;
1065 DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n",
1066 __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq));
1067 _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp);
1068 }
1069 #ifdef DHDTCPACK_SUP_DBG
1070 DHD_ERROR(("%s %d: PSH INFO ENQ %d\n",
1071 __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
1072 #endif /* DHDTCPACK_SUP_DBG */
1073 tcpack_sup_mod->tcpdata_info_cnt--;
1074 ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0);
1075
1076 last_tdata_info =
1077 &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt];
1078 if (i < tcpack_sup_mod->tcpdata_info_cnt) {
1079 ASSERT(last_tdata_info != tdata_info_tmp);
1080 bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t));
1081 }
1082 bzero(last_tdata_info, sizeof(tcpdata_info_t));
1083 DHD_INFO(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n",
1084 __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt));
1085 /* Don't increase "i" here, so that the prev last tcpdata_info is checked */
1086 } else
1087 i++;
1088 }
1089
1090 tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]);
1091 tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len;
1092 end_tcp_seq_num = tcp_seq_num + tcp_data_len;
1093
1094 if (tcpdata_info == NULL) {
1095 ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt);
1096 if (i >= TCPDATA_INFO_MAXNUM) {
1097 DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d"
1098 " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n",
1099 __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt,
1100 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
1101 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
1102 ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
1103 ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET])));
1104 dhd_os_tcpackunlock(dhdp, flags);
1105 goto exit;
1106 }
1107 tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i];
1108
1109 /* No TCP flow with the same IP addr and TCP port is found
1110 * in tcp_data_info_tbl. So add this flow to the table.
1111 */
1112 DHD_INFO(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
1113 " TCP port %d %d\n",
1114 __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt,
1115 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
1116 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
1117 ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
1118 ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET])));
1119 /* Note that src/dst addr fields in ip header are contiguous being 8 bytes in total.
1120 * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total.
1121 */
1122 bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], (void *)&tcpdata_info->ip_addr,
1123 IPV4_ADDR_LEN * 2);
1124 bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], (void *)&tcpdata_info->tcp_port,
1125 TCP_PORT_LEN * 2);
1126
1127 tcpdata_info->last_used_time = OSL_SYSUPTIME();
1128 tcpack_sup_mod->tcpdata_info_cnt++;
1129 }
1130
1131 ASSERT(tcpdata_info != NULL);
1132
1133 tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod);
1134 #ifdef DHDTCPACK_SUP_DBG
1135 DHD_TRACE(("%s %d: PSH INFO ENQ %d\n",
1136 __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
1137 #endif /* DHDTCPACK_SUP_DBG */
1138
1139 if (tdata_psh_info == NULL) {
1140 DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__));
1141 ret = BCME_ERROR;
1142 dhd_os_tcpackunlock(dhdp, flags);
1143 goto exit;
1144 }
1145 tdata_psh_info->end_seq = end_tcp_seq_num;
1146
1147 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
1148 tack_tbl.cnt[4]++;
1149 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
1150
1151 DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n",
1152 __FUNCTION__, __LINE__, tdata_psh_info->end_seq));
1153
1154 ASSERT(tdata_psh_info->next == NULL);
1155
1156 if (tcpdata_info->tdata_psh_info_head == NULL)
1157 tcpdata_info->tdata_psh_info_head = tdata_psh_info;
1158 else {
1159 ASSERT(tcpdata_info->tdata_psh_info_tail);
1160 tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info;
1161 }
1162 tcpdata_info->tdata_psh_info_tail = tdata_psh_info;
1163
1164 dhd_os_tcpackunlock(dhdp, flags);
1165
1166 exit:
1167 return ret;
1168 }
1169
1170 bool
dhd_tcpack_hold(dhd_pub_t * dhdp,void * pkt,int ifidx)1171 dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx)
1172 {
1173 uint8 *new_ether_hdr; /* Ethernet header of the new packet */
1174 uint16 new_ether_type; /* Ethernet type of the new packet */
1175 uint8 *new_ip_hdr; /* IP header of the new packet */
1176 uint8 *new_tcp_hdr; /* TCP header of the new packet */
1177 uint32 new_ip_hdr_len; /* IP header length of the new packet */
1178 uint32 cur_framelen;
1179 uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */
1180 uint16 new_ip_total_len; /* Total length of IP packet for the new packet */
1181 uint32 new_tcp_hdr_len; /* TCP header length of the new packet */
1182 tcpack_sup_module_t *tcpack_sup_mod;
1183 tcpack_info_t *tcpack_info_tbl;
1184 int i, free_slot = TCPACK_INFO_MAXNUM;
1185 bool hold = FALSE;
1186 unsigned long flags;
1187
1188 if (dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD) {
1189 goto exit;
1190 }
1191
1192 if (dhdp->tcpack_sup_ratio == 1) {
1193 goto exit;
1194 }
1195
1196 new_ether_hdr = PKTDATA(dhdp->osh, pkt);
1197 cur_framelen = PKTLEN(dhdp->osh, pkt);
1198
1199 if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) {
1200 DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
1201 __FUNCTION__, __LINE__, cur_framelen));
1202 goto exit;
1203 }
1204
1205 new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13];
1206
1207 if (new_ether_type != ETHER_TYPE_IP) {
1208 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
1209 __FUNCTION__, __LINE__, new_ether_type));
1210 goto exit;
1211 }
1212
1213 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type));
1214
1215 new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN;
1216 cur_framelen -= ETHER_HDR_LEN;
1217
1218 ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
1219
1220 new_ip_hdr_len = IPV4_HLEN(new_ip_hdr);
1221 if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) {
1222 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
1223 __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr)));
1224 goto exit;
1225 }
1226
1227 new_tcp_hdr = new_ip_hdr + new_ip_hdr_len;
1228 cur_framelen -= new_ip_hdr_len;
1229
1230 ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
1231
1232 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));
1233
1234 /* is it an ack ? Allow only ACK flag, not to suppress others. */
1235 if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) {
1236 DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n",
1237 __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET]));
1238 goto exit;
1239 }
1240
1241 new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]);
1242 new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]);
1243
1244 /* This packet has TCP data, so just send */
1245 if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) {
1246 DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__));
1247 goto exit;
1248 }
1249
1250 ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len);
1251
1252 new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]);
1253
1254 DHD_TRACE(("%s %d: TCP ACK with zero DATA length"
1255 " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n",
1256 __FUNCTION__, __LINE__,
1257 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])),
1258 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])),
1259 ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]),
1260 ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET])));
1261
1262 /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */
1263 flags = dhd_os_tcpacklock(dhdp);
1264
1265 tcpack_sup_mod = dhdp->tcpack_sup_module;
1266 tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl;
1267
1268 if (!tcpack_sup_mod) {
1269 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
1270 dhd_os_tcpackunlock(dhdp, flags);
1271 goto exit;
1272 }
1273
1274 hold = TRUE;
1275
1276 for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
1277 void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */
1278 uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr;
1279 uint32 old_ip_hdr_len;
1280 uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */
1281
1282 if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) {
1283 if (free_slot == TCPACK_INFO_MAXNUM) {
1284 free_slot = i;
1285 }
1286 continue;
1287 }
1288
1289 if (PKTDATA(dhdp->osh, oldpkt) == NULL) {
1290 DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n",
1291 __FUNCTION__, __LINE__, i));
1292 hold = FALSE;
1293 dhd_os_tcpackunlock(dhdp, flags);
1294 goto exit;
1295 }
1296
1297 old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr;
1298 old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN;
1299 old_ip_hdr_len = IPV4_HLEN(old_ip_hdr);
1300 old_tcp_hdr = old_ip_hdr + old_ip_hdr_len;
1301
1302 DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
1303 " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i,
1304 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])),
1305 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])),
1306 ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]),
1307 ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET])));
1308
1309 /* If either of IP address or TCP port number does not match, skip. */
1310 if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET],
1311 &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) ||
1312 memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET],
1313 &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) {
1314 continue;
1315 }
1316
1317 old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]);
1318
1319 if (IS_TCPSEQ_GE(new_tcp_ack_num, old_tcpack_num)) {
1320 tcpack_info_tbl[i].supp_cnt++;
1321 if (tcpack_info_tbl[i].supp_cnt >= dhdp->tcpack_sup_ratio) {
1322 tcpack_info_tbl[i].pkt_in_q = NULL;
1323 tcpack_info_tbl[i].pkt_ether_hdr = NULL;
1324 tcpack_info_tbl[i].ifidx = 0;
1325 tcpack_info_tbl[i].supp_cnt = 0;
1326 hold = FALSE;
1327 } else {
1328 tcpack_info_tbl[i].pkt_in_q = pkt;
1329 tcpack_info_tbl[i].pkt_ether_hdr = new_ether_hdr;
1330 tcpack_info_tbl[i].ifidx = ifidx;
1331 }
1332 PKTFREE(dhdp->osh, oldpkt, TRUE);
1333 } else {
1334 PKTFREE(dhdp->osh, pkt, TRUE);
1335 }
1336 dhd_os_tcpackunlock(dhdp, flags);
1337
1338 if (!hold) {
1339 #ifndef TCPACK_SUPPRESS_HOLD_HRT
1340 del_timer_sync(&tcpack_info_tbl[i].timer);
1341 #else
1342 hrtimer_cancel(&tcpack_sup_mod->tcpack_info_tbl[i].timer.timer);
1343 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
1344 }
1345 goto exit;
1346 }
1347
1348 if (free_slot < TCPACK_INFO_MAXNUM) {
1349 /* No TCPACK packet with the same IP addr and TCP port is found
1350 * in tcp_ack_info_tbl. So add this packet to the table.
1351 */
1352 DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
1353 __FUNCTION__, __LINE__, pkt, new_ether_hdr,
1354 free_slot));
1355
1356 tcpack_info_tbl[free_slot].pkt_in_q = pkt;
1357 tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr;
1358 tcpack_info_tbl[free_slot].ifidx = ifidx;
1359 tcpack_info_tbl[free_slot].supp_cnt = 1;
1360 #ifndef TCPACK_SUPPRESS_HOLD_HRT
1361 mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer,
1362 jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay));
1363 #else
1364 tasklet_hrtimer_start(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer,
1365 ktime_set(0, dhdp->tcpack_sup_delay*1000000),
1366 HRTIMER_MODE_REL);
1367 #endif /* TCPACK_SUPPRESS_HOLD_HRT */
1368 tcpack_sup_mod->tcpack_info_cnt++;
1369 } else {
1370 DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
1371 __FUNCTION__, __LINE__));
1372 }
1373 dhd_os_tcpackunlock(dhdp, flags);
1374
1375 exit:
1376 return hold;
1377 }
1378 #endif /* DHDTCPACK_SUPPRESS */
1379
1380 #ifdef DHDTCPSYNC_FLOOD_BLK
1381 tcp_hdr_flag_t
dhd_tcpdata_get_flag(dhd_pub_t * dhdp,void * pkt)1382 dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt)
1383 {
1384 uint8 *ether_hdr; /* Ethernet header of the new packet */
1385 uint16 ether_type; /* Ethernet type of the new packet */
1386 uint8 *ip_hdr; /* IP header of the new packet */
1387 uint8 *tcp_hdr; /* TCP header of the new packet */
1388 uint32 ip_hdr_len; /* IP header length of the new packet */
1389 uint32 cur_framelen;
1390 uint8 flags;
1391
1392 ether_hdr = PKTDATA(dhdp->osh, pkt);
1393 cur_framelen = PKTLEN(dhdp->osh, pkt);
1394
1395 ether_type = ether_hdr[12] << 8 | ether_hdr[13];
1396
1397 if (ether_type != ETHER_TYPE_IP) {
1398 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
1399 __FUNCTION__, __LINE__, ether_type));
1400 return FLAG_OTHERS;
1401 }
1402
1403 ip_hdr = ether_hdr + ETHER_HDR_LEN;
1404 cur_framelen -= ETHER_HDR_LEN;
1405
1406 if (cur_framelen < IPV4_MIN_HEADER_LEN) {
1407 return FLAG_OTHERS;
1408 }
1409
1410 ip_hdr_len = IPV4_HLEN(ip_hdr);
1411 if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) {
1412 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
1413 __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr)));
1414 return FLAG_OTHERS;
1415 }
1416
1417 tcp_hdr = ip_hdr + ip_hdr_len;
1418
1419 flags = (uint8)tcp_hdr[TCP_FLAGS_OFFSET];
1420
1421 if (flags & TCP_FLAG_SYN) {
1422 if (flags & TCP_FLAG_ACK) {
1423 return FLAG_SYNCACK;
1424 }
1425 return FLAG_SYNC;
1426 }
1427 return FLAG_OTHERS;
1428 }
1429 #endif /* DHDTCPSYNC_FLOOD_BLK */
1430