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