2 * IP Packet Parser Module.
4 * Copyright (C) 1999-2015, Broadcom Corporation
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:
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.
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.
24 * $Id: dhd_ip.c 536341 2015-02-22 02:47:39Z $
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>
39 #ifdef DHDTCPACK_SUPPRESS
41 #include <dhd_proto.h>
42 #include <proto/bcmtcp.h>
43 #endif /* DHDTCPACK_SUPPRESS */
46 /* 802.3 llc/snap header */
47 static const uint8 llc_snap_hdr
[SNAP_HDR_LEN
] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
50 pkt_frag_t
pkt_frag_info(osl_t
*osh
, void *p
)
53 struct ether_header
*eh
;
61 ret
= DHD_PKT_FRAG_NONE
;
63 /* Smaller than ether header */
64 if (len
< ETHER_HDR_LEN
+ ETHER_TYPE_LEN
)
67 /* Smaller than SNAP 802.3 */
68 if (len
< ETHER_HDR_LEN
+ SNAP_HDR_LEN
+ ETHER_TYPE_LEN
)
71 eh
= mtod(m
, struct ether_header
*);
74 if (ntoh16(eh
->ether_type
) != ETHER_TYPE_IP
)
77 if (m
->m_flags
& M_FIRSTFRAG
){ /* first */
79 ret
= DHD_PKT_FRAG_FIRST
;
81 } else if (m
->m_flags
& M_LASTFRAG
){ /* last */
83 ret
= DHD_PKT_FRAG_LAST
;
85 } else if ((m
->m_flags
& M_FRAG
) == 0){ /* no frag */
87 ret
= DHD_PKT_FRAG_NONE
;
89 } else if (m
->m_flags
& M_FRAG
){ /* frag */
91 ret
= DHD_PKT_FRAG_CONT
;
97 pkt_frag_t
pkt_frag_info(osl_t
*osh
, void *p
)
101 uint8
*pt
; /* Pointer to type field */
103 struct ipv4_hdr
*iph
; /* IP frame pointer */
104 int ipl
; /* IP frame length */
109 frame
= PKTDATA(osh
, p
);
110 length
= PKTLEN(osh
, p
);
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
;
123 DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__
));
124 return DHD_PKT_FRAG_NONE
;
127 ethertype
= ntoh16(*(uint16
*)pt
);
129 /* Skip VLAN tag, if any */
130 if (ethertype
== ETHER_TYPE_8021Q
) {
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
;
138 ethertype
= ntoh16(*(uint16
*)pt
);
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
;
147 iph
= (struct ipv4_hdr
*)(pt
+ ETHER_TYPE_LEN
);
148 ipl
= (uint
)(length
- (pt
+ ETHER_TYPE_LEN
- frame
));
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
;
156 iph_frag
= ntoh16(iph
->frag
);
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
;
163 return (iph_frag
& IPV4_FRAG_OFFSET_MASK
)? DHD_PKT_FRAG_CONT
: DHD_PKT_FRAG_FIRST
;
168 bool pkt_is_dhcp(osl_t
*osh
, void *p
)
172 uint8
*pt
; /* Pointer to type field */
174 struct ipv4_hdr
*iph
; /* IP frame pointer */
175 int ipl
; /* IP frame length */
180 frame
= PKTDATA(osh
, p
);
181 length
= PKTLEN(osh
, p
);
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
));
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
;
194 DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__
));
198 ethertype
= ntoh16(*(uint16
*)pt
);
200 /* Skip VLAN tag, if any */
201 if (ethertype
== ETHER_TYPE_8021Q
) {
204 if (pt
+ ETHER_TYPE_LEN
> frame
+ length
) {
205 DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__
, length
));
209 ethertype
= ntoh16(*(uint16
*)pt
);
212 if (ethertype
!= ETHER_TYPE_IP
) {
213 DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n",
214 __FUNCTION__
, ethertype
, length
));
218 iph
= (struct ipv4_hdr
*)(pt
+ ETHER_TYPE_LEN
);
219 ipl
= (uint
)(length
- (pt
+ ETHER_TYPE_LEN
- frame
));
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
));
227 src_port
= ntoh16(*(uint16
*)(pt
+ ETHER_TYPE_LEN
+ IPV4_OPTIONS_OFFSET
));
229 return (src_port
== 0x43 || src_port
== 0x44);
232 #ifdef DHDTCPACK_SUPPRESS
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 */
240 struct timer_list timer
;
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 */
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 */
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 */
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) */
262 /* TCPACK SUPPRESS module */
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
;
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 */
280 _tdata_psh_info_pool_enq(tcpack_sup_module_t
*tcpack_sup_mod
,
281 tdata_psh_info_t
*tdata_psh_info
)
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
));
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
++;
297 static tdata_psh_info_t
*
298 _tdata_psh_info_pool_deq(tcpack_sup_module_t
*tcpack_sup_mod
)
300 tdata_psh_info_t
*tdata_psh_info
= NULL
;
302 if (tcpack_sup_mod
== NULL
) {
303 DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__
, __LINE__
,
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__
));
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 */
319 return tdata_psh_info
;
323 static void dhd_tcpack_send(ulong data
)
325 tcpack_sup_module_t
*tcpack_sup_mod
;
326 tcpack_info_t
*cur_tbl
= (tcpack_info_t
*)data
;
336 dhdp
= cur_tbl
->dhdp
;
341 flags
= dhd_os_tcpacklock(dhdp
);
343 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
344 pkt
= cur_tbl
->pkt_in_q
;
345 ifidx
= cur_tbl
->ifidx
;
347 dhd_os_tcpackunlock(dhdp
, flags
);
350 cur_tbl
->pkt_in_q
= NULL
;
351 cur_tbl
->pkt_ether_hdr
= NULL
;
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
));
359 dhd_os_tcpackunlock(dhdp
, flags
);
361 dhd_sendpkt(dhdp
, ifidx
, pkt
);
364 int dhd_tcpack_suppress_set(dhd_pub_t
*dhdp
, uint8 mode
)
369 flags
= dhd_os_tcpacklock(dhdp
);
371 if (dhdp
->tcpack_sup_mode
== mode
) {
372 DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__
, __LINE__
, mode
));
376 if (mode
>= TCPACK_SUP_LAST_MODE
||
377 mode
== TCPACK_SUP_DELAYTX
||
379 DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__
, __LINE__
, mode
));
384 DHD_TRACE(("%s: %d -> %d\n",
385 __FUNCTION__
, dhdp
->tcpack_sup_mode
, mode
));
387 dhdp
->tcpack_sup_mode
= mode
;
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
;
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
;
407 bzero(tcpack_sup_mod
, sizeof(tcpack_sup_module_t
));
408 dhdp
->tcpack_sup_module
= tcpack_sup_mod
;
412 if (mode
== TCPACK_SUP_HOLD
) {
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
++)
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
;
429 dhd_os_tcpackunlock(dhdp
, flags
);
434 dhd_tcpack_info_tbl_clean(dhd_pub_t
*dhdp
)
436 tcpack_sup_module_t
*tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
440 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_OFF
)
443 flags
= dhd_os_tcpacklock(dhdp
);
445 if (!tcpack_sup_mod
) {
446 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
447 __FUNCTION__
, __LINE__
));
448 dhd_os_tcpackunlock(dhdp
, flags
);
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
,
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;
464 tcpack_sup_mod
->tcpack_info_cnt
= 0;
465 bzero(tcpack_sup_mod
->tcpack_info_tbl
, sizeof(tcpack_info_t
) * TCPACK_INFO_MAXNUM
);
468 dhd_os_tcpackunlock(dhdp
, flags
);
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
);
480 inline int dhd_tcpack_check_xmit(dhd_pub_t
*dhdp
, void *pkt
)
483 tcpack_sup_module_t
*tcpack_sup_mod
;
484 tcpack_info_t
*tcpack_info_tbl
;
491 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_OFF
)
494 pdata
= PKTDATA(dhdp
->osh
, pkt
);
495 pktlen
= PKTLEN(dhdp
->osh
, pkt
) - dhd_prot_hdrlen(dhdp
, pdata
);
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
));
503 flags
= dhd_os_tcpacklock(dhdp
);
504 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
506 if (!tcpack_sup_mod
) {
507 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
509 dhd_os_tcpackunlock(dhdp
, flags
);
512 tbl_cnt
= tcpack_sup_mod
->tcpack_info_cnt
;
513 tcpack_info_tbl
= tcpack_sup_mod
->tcpack_info_tbl
;
515 ASSERT(tbl_cnt
<= TCPACK_INFO_MAXNUM
);
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
));
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
));
535 dhd_os_tcpackunlock(dhdp
, flags
);
541 static INLINE
bool dhd_tcpdata_psh_acked(dhd_pub_t
*dhdp
, uint8
*ip_hdr
,
542 uint8
*tcp_hdr
, uint32 tcp_ack_num
)
544 tcpack_sup_module_t
*tcpack_sup_mod
;
546 tcpdata_info_t
*tcpdata_info
= NULL
;
547 tdata_psh_info_t
*tdata_psh_info
= NULL
;
550 if (dhdp
->tcpack_sup_mode
!= TCPACK_SUP_DELAYTX
)
553 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
555 if (!tcpack_sup_mod
) {
556 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
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
]),
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
)));
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
;
591 if (tcpdata_info
== NULL
) {
592 DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__
, __LINE__
));
596 if (tcpdata_info
->tdata_psh_info_head
== NULL
) {
597 DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__
, __LINE__
));
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
);
611 if (tdata_psh_info
== NULL
)
612 tcpdata_info
->tdata_psh_info_tail
= NULL
;
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 */
624 dhd_tcpack_suppress(dhd_pub_t
*dhdp
, void *pkt
)
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 */
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
;
639 bool set_dotxinrx
= TRUE
;
643 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_OFF
)
646 new_ether_hdr
= PKTDATA(dhdp
->osh
, pkt
);
647 cur_framelen
= PKTLEN(dhdp
->osh
, pkt
);
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
));
655 new_ether_type
= new_ether_hdr
[12] << 8 | new_ether_hdr
[13];
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
));
663 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__
, __LINE__
, new_ether_type
));
665 new_ip_hdr
= new_ether_hdr
+ ETHER_HDR_LEN
;
666 cur_framelen
-= ETHER_HDR_LEN
;
668 ASSERT(cur_framelen
>= IPV4_MIN_HEADER_LEN
);
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
)));
677 new_tcp_hdr
= new_ip_hdr
+ new_ip_hdr_len
;
678 cur_framelen
-= new_ip_hdr_len
;
680 ASSERT(cur_framelen
>= TCP_MIN_HEADER_LEN
);
682 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__
, __LINE__
));
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
]));
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
]);
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__
));
700 ASSERT(new_ip_total_len
== new_ip_hdr_len
+ new_tcp_hdr_len
);
702 new_tcp_ack_num
= ntoh32_ua(&new_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
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
])));
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
);
717 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
719 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
720 tcpack_info_tbl
= tcpack_sup_mod
->tcpack_info_tbl
;
722 if (!tcpack_sup_mod
) {
723 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
725 dhd_os_tcpackunlock(dhdp
, flags
);
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)
733 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
735 set_dotxinrx
= FALSE
;
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 */
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
));
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
));
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
]);
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
])));
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.
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))
778 old_tcpack_num
= ntoh32_ua(&old_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
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)
791 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
794 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
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
));
803 } else if (new_tcp_ack_num
== old_tcpack_num
) {
805 /* TCPACK retransmission */
806 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
808 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
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
));
814 dhd_os_tcpackunlock(dhdp
, flags
);
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.
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
));
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)
831 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
833 ASSERT(i
== tcpack_sup_mod
->tcpack_info_cnt
);
834 DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
835 __FUNCTION__
, __LINE__
));
837 dhd_os_tcpackunlock(dhdp
, flags
);
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
);
848 dhd_tcpdata_info_get(dhd_pub_t
*dhdp
, void *pkt
)
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 */
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
;
869 if (dhdp
->tcpack_sup_mode
!= TCPACK_SUP_DELAYTX
)
872 ether_hdr
= PKTDATA(dhdp
->osh
, pkt
);
873 cur_framelen
= PKTLEN(dhdp
->osh
, pkt
);
875 ether_type
= ether_hdr
[12] << 8 | ether_hdr
[13];
877 if (ether_type
!= ETHER_TYPE_IP
) {
878 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
879 __FUNCTION__
, __LINE__
, ether_type
));
883 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__
, __LINE__
, ether_type
));
885 ip_hdr
= ether_hdr
+ ETHER_HDR_LEN
;
886 cur_framelen
-= ETHER_HDR_LEN
;
888 ASSERT(cur_framelen
>= IPV4_MIN_HEADER_LEN
);
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
)));
897 tcp_hdr
= ip_hdr
+ ip_hdr_len
;
898 cur_framelen
-= ip_hdr_len
;
900 ASSERT(cur_framelen
>= TCP_MIN_HEADER_LEN
);
902 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__
, __LINE__
));
904 ip_total_len
= ntoh16_ua(&ip_hdr
[IPV4_PKTLEN_OFFSET
]);
905 tcp_hdr_len
= 4 * TCP_HDRLEN(tcp_hdr
[TCP_HLEN_OFFSET
]);
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__
));
913 ASSERT(ip_total_len
> ip_hdr_len
+ tcp_hdr_len
);
915 if ((tcp_hdr
[TCP_FLAGS_OFFSET
] & TCP_FLAG_PSH
) == 0) {
916 DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__
, __LINE__
));
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
]));
929 flags
= dhd_os_tcpacklock(dhdp
);
930 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
932 if (!tcpack_sup_mod
) {
933 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
935 dhd_os_tcpackunlock(dhdp
, flags
);
939 /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */
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
)));
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.
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
;
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
;
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
);
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);
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
));
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 */
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
;
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
);
1013 tcpdata_info
= &tcpack_sup_mod
->tcpdata_info_tbl
[i
];
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.
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.
1028 bcopy(&ip_hdr
[IPV4_SRC_IP_OFFSET
], (void *)&tcpdata_info
->ip_addr
,
1030 bcopy(&tcp_hdr
[TCP_SRC_PORT_OFFSET
], (void *)&tcpdata_info
->tcp_port
,
1033 tcpdata_info
->last_used_time
= OSL_SYSUPTIME();
1034 tcpack_sup_mod
->tcpdata_info_cnt
++;
1037 ASSERT(tcpdata_info
!= NULL
);
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 */
1045 if (tdata_psh_info
== NULL
) {
1046 DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__
, __LINE__
));
1048 dhd_os_tcpackunlock(dhdp
, flags
);
1051 tdata_psh_info
->end_seq
= end_tcp_seq_num
;
1053 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
1055 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
1057 DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n",
1058 __FUNCTION__
, __LINE__
, tdata_psh_info
->end_seq
));
1060 ASSERT(tdata_psh_info
->next
== NULL
);
1062 if (tcpdata_info
->tdata_psh_info_head
== NULL
)
1063 tcpdata_info
->tdata_psh_info_head
= tdata_psh_info
;
1065 ASSERT(tcpdata_info
->tdata_psh_info_tail
);
1066 tcpdata_info
->tdata_psh_info_tail
->next
= tdata_psh_info
;
1068 tcpdata_info
->tdata_psh_info_tail
= tdata_psh_info
;
1070 dhd_os_tcpackunlock(dhdp
, flags
);
1077 dhd_tcpack_hold(dhd_pub_t
*dhdp
, void *pkt
, int ifidx
)
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
;
1092 unsigned long flags
;
1094 if (dhdp
->tcpack_sup_mode
!= TCPACK_SUP_HOLD
) {
1098 if (dhdp
->tcpack_sup_ratio
== 1) {
1102 new_ether_hdr
= PKTDATA(dhdp
->osh
, pkt
);
1103 cur_framelen
= PKTLEN(dhdp
->osh
, pkt
);
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
));
1111 new_ether_type
= new_ether_hdr
[12] << 8 | new_ether_hdr
[13];
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
));
1119 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__
, __LINE__
, new_ether_type
));
1121 new_ip_hdr
= new_ether_hdr
+ ETHER_HDR_LEN
;
1122 cur_framelen
-= ETHER_HDR_LEN
;
1124 ASSERT(cur_framelen
>= IPV4_MIN_HEADER_LEN
);
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
)));
1133 new_tcp_hdr
= new_ip_hdr
+ new_ip_hdr_len
;
1134 cur_framelen
-= new_ip_hdr_len
;
1136 ASSERT(cur_framelen
>= TCP_MIN_HEADER_LEN
);
1138 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__
, __LINE__
));
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
]));
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
]);
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__
));
1156 ASSERT(new_ip_total_len
== new_ip_hdr_len
+ new_tcp_hdr_len
);
1158 new_tcp_ack_num
= ntoh32_ua(&new_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
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
])));
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
);
1171 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
1172 tcpack_info_tbl
= tcpack_sup_mod
->tcpack_info_tbl
;
1174 if (!tcpack_sup_mod
) {
1175 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
1176 dhd_os_tcpackunlock(dhdp
, flags
);
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 */
1188 if ((oldpkt
= tcpack_info_tbl
[i
].pkt_in_q
) == NULL
) {
1189 if (free_slot
== TCPACK_INFO_MAXNUM
) {
1195 if (PKTDATA(dhdp
->osh
, oldpkt
) == NULL
) {
1196 DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n",
1197 __FUNCTION__
, __LINE__
, i
));
1199 dhd_os_tcpackunlock(dhdp
, flags
);
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
]);
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
])));
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)) {
1224 old_tcpack_num
= ntoh32_ua(&old_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
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;
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
;
1239 PKTFREE(dhdp
->osh
, oldpkt
, TRUE
);
1241 PKTFREE(dhdp
->osh
, pkt
, TRUE
);
1243 dhd_os_tcpackunlock(dhdp
, flags
);
1246 del_timer_sync(&tcpack_info_tbl
[i
].timer
);
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.
1255 DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
1256 __FUNCTION__
, __LINE__
, pkt
, new_ether_hdr
,
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
++;
1267 DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
1268 __FUNCTION__
, __LINE__
));
1270 dhd_os_tcpackunlock(dhdp
, flags
);
1275 #endif /* DHDTCPACK_SUPPRESS */