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