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