xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/infineon/bcmdhd/dhd_ip.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * IP Packet Parser Module.
3  *
4  * Portions of this code are copyright (c) 2022 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