2 * IP Packet Parser Module.
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_ip.c 502735 2014-09-16 00:53:02Z $
11 #include <proto/ethernet.h>
12 #include <proto/vlan.h>
13 #include <proto/802.3.h>
14 #include <proto/bcmip.h>
15 #include <bcmendian.h>
21 #ifdef DHDTCPACK_SUPPRESS
23 #include <dhd_proto.h>
24 #include <proto/bcmtcp.h>
25 #endif /* DHDTCPACK_SUPPRESS */
28 /* 802.3 llc/snap header */
29 static const uint8 llc_snap_hdr
[SNAP_HDR_LEN
] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
31 pkt_frag_t
pkt_frag_info(osl_t
*osh
, void *p
)
35 uint8
*pt
; /* Pointer to type field */
37 struct ipv4_hdr
*iph
; /* IP frame pointer */
38 int ipl
; /* IP frame length */
43 frame
= PKTDATA(osh
, p
);
44 length
= PKTLEN(osh
, p
);
46 /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
47 if (length
< ETHER_HDR_LEN
) {
48 DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__
, length
));
49 return DHD_PKT_FRAG_NONE
;
50 } else if (ntoh16(*(uint16
*)(frame
+ ETHER_TYPE_OFFSET
)) >= ETHER_TYPE_MIN
) {
51 /* Frame is Ethernet II */
52 pt
= frame
+ ETHER_TYPE_OFFSET
;
53 } else if (length
>= ETHER_HDR_LEN
+ SNAP_HDR_LEN
+ ETHER_TYPE_LEN
&&
54 !bcmp(llc_snap_hdr
, frame
+ ETHER_HDR_LEN
, SNAP_HDR_LEN
)) {
55 pt
= frame
+ ETHER_HDR_LEN
+ SNAP_HDR_LEN
;
57 DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__
));
58 return DHD_PKT_FRAG_NONE
;
61 ethertype
= ntoh16(*(uint16
*)pt
);
63 /* Skip VLAN tag, if any */
64 if (ethertype
== ETHER_TYPE_8021Q
) {
67 if (pt
+ ETHER_TYPE_LEN
> frame
+ length
) {
68 DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__
, length
));
69 return DHD_PKT_FRAG_NONE
;
72 ethertype
= ntoh16(*(uint16
*)pt
);
75 if (ethertype
!= ETHER_TYPE_IP
) {
76 DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n",
77 __FUNCTION__
, ethertype
, length
));
78 return DHD_PKT_FRAG_NONE
;
81 iph
= (struct ipv4_hdr
*)(pt
+ ETHER_TYPE_LEN
);
82 ipl
= (uint
)(length
- (pt
+ ETHER_TYPE_LEN
- frame
));
84 /* We support IPv4 only */
85 if ((ipl
< IPV4_OPTIONS_OFFSET
) || (IP_VER(iph
) != IP_VER_4
)) {
86 DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__
, ipl
));
87 return DHD_PKT_FRAG_NONE
;
90 iph_frag
= ntoh16(iph
->frag
);
92 if (iph_frag
& IPV4_FRAG_DONT
) {
93 return DHD_PKT_FRAG_NONE
;
94 } else if ((iph_frag
& IPV4_FRAG_MORE
) == 0) {
95 return DHD_PKT_FRAG_LAST
;
97 return (iph_frag
& IPV4_FRAG_OFFSET_MASK
)? DHD_PKT_FRAG_CONT
: DHD_PKT_FRAG_FIRST
;
101 bool pkt_is_dhcp(osl_t
*osh
, void *p
)
105 uint8
*pt
; /* Pointer to type field */
107 struct ipv4_hdr
*iph
; /* IP frame pointer */
108 int ipl
; /* IP frame length */
113 frame
= PKTDATA(osh
, p
);
114 length
= PKTLEN(osh
, p
);
116 /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
117 if (length
< ETHER_HDR_LEN
) {
118 DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__
, length
));
120 } else if (ntoh16(*(uint16
*)(frame
+ ETHER_TYPE_OFFSET
)) >= ETHER_TYPE_MIN
) {
121 /* Frame is Ethernet II */
122 pt
= frame
+ ETHER_TYPE_OFFSET
;
123 } else if (length
>= ETHER_HDR_LEN
+ SNAP_HDR_LEN
+ ETHER_TYPE_LEN
&&
124 !bcmp(llc_snap_hdr
, frame
+ ETHER_HDR_LEN
, SNAP_HDR_LEN
)) {
125 pt
= frame
+ ETHER_HDR_LEN
+ SNAP_HDR_LEN
;
127 DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__
));
131 ethertype
= ntoh16(*(uint16
*)pt
);
133 /* Skip VLAN tag, if any */
134 if (ethertype
== ETHER_TYPE_8021Q
) {
137 if (pt
+ ETHER_TYPE_LEN
> frame
+ length
) {
138 DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__
, length
));
142 ethertype
= ntoh16(*(uint16
*)pt
);
145 if (ethertype
!= ETHER_TYPE_IP
) {
146 DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n",
147 __FUNCTION__
, ethertype
, length
));
151 iph
= (struct ipv4_hdr
*)(pt
+ ETHER_TYPE_LEN
);
152 ipl
= (uint
)(length
- (pt
+ ETHER_TYPE_LEN
- frame
));
154 /* We support IPv4 only */
155 if ((ipl
< (IPV4_OPTIONS_OFFSET
+ 2)) || (IP_VER(iph
) != IP_VER_4
)) {
156 DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__
, ipl
));
160 src_port
= ntoh16(*(uint16
*)(pt
+ ETHER_TYPE_LEN
+ IPV4_OPTIONS_OFFSET
));
162 return (src_port
== 0x43 || src_port
== 0x44);
165 #ifdef DHDTCPACK_SUPPRESS
168 void *pkt_in_q
; /* TCP ACK packet that is already in txq or DelayQ */
169 void *pkt_ether_hdr
; /* Ethernet header pointer of pkt_in_q */
173 struct timer_list timer
;
176 typedef struct _tdata_psh_info_t
{
177 uint32 end_seq
; /* end seq# of a received TCP PSH DATA pkt */
178 struct _tdata_psh_info_t
*next
; /* next pointer of the link chain */
182 uint8 src_ip_addr
[IPV4_ADDR_LEN
]; /* SRC ip addrs of this TCP stream */
183 uint8 dst_ip_addr
[IPV4_ADDR_LEN
]; /* DST ip addrs of this TCP stream */
184 uint8 src_tcp_port
[TCP_PORT_LEN
]; /* SRC tcp ports of this TCP stream */
185 uint8 dst_tcp_port
[TCP_PORT_LEN
]; /* DST tcp ports of this TCP stream */
186 tdata_psh_info_t
*tdata_psh_info_head
; /* Head of received TCP PSH DATA chain */
187 tdata_psh_info_t
*tdata_psh_info_tail
; /* Tail of received TCP PSH DATA chain */
188 uint32 last_used_time
; /* The last time this tcpdata_info was used(in ms) */
191 /* TCPACK SUPPRESS module */
194 tcpack_info_t tcpack_info_tbl
[TCPACK_INFO_MAXNUM
]; /* Info of TCP ACK to send */
195 int tcpdata_info_cnt
;
196 tcpdata_info_t tcpdata_info_tbl
[TCPDATA_INFO_MAXNUM
]; /* Info of received TCP DATA */
197 tdata_psh_info_t
*tdata_psh_info_pool
; /* Pointer to tdata_psh_info elements pool */
198 tdata_psh_info_t
*tdata_psh_info_free
; /* free tdata_psh_info elements chain in pool */
199 #ifdef DHDTCPACK_SUP_DBG
200 int psh_info_enq_num
; /* Number of free TCP PSH DATA info elements in pool */
201 #endif /* DHDTCPACK_SUP_DBG */
202 } tcpack_sup_module_t
;
204 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
205 counter_tbl_t tack_tbl
= {"tcpACK", 0, 1000, 10, {0, }, 1};
206 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
209 _tdata_psh_info_pool_enq(tcpack_sup_module_t
*tcpack_sup_mod
,
210 tdata_psh_info_t
*tdata_psh_info
)
212 if ((tcpack_sup_mod
== NULL
) || (tdata_psh_info
== NULL
)) {
213 DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__
, __LINE__
,
214 tcpack_sup_mod
, tdata_psh_info
));
218 ASSERT(tdata_psh_info
->next
== NULL
);
219 tdata_psh_info
->next
= tcpack_sup_mod
->tdata_psh_info_free
;
220 tcpack_sup_mod
->tdata_psh_info_free
= tdata_psh_info
;
221 #ifdef DHDTCPACK_SUP_DBG
222 tcpack_sup_mod
->psh_info_enq_num
++;
226 static tdata_psh_info_t
*
227 _tdata_psh_info_pool_deq(tcpack_sup_module_t
*tcpack_sup_mod
)
229 tdata_psh_info_t
*tdata_psh_info
= NULL
;
231 if (tcpack_sup_mod
== NULL
) {
232 DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__
, __LINE__
,
237 tdata_psh_info
= tcpack_sup_mod
->tdata_psh_info_free
;
238 if (tdata_psh_info
== NULL
)
239 DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__
, __LINE__
));
241 tcpack_sup_mod
->tdata_psh_info_free
= tdata_psh_info
->next
;
242 tdata_psh_info
->next
= NULL
;
243 #ifdef DHDTCPACK_SUP_DBG
244 tcpack_sup_mod
->psh_info_enq_num
--;
245 #endif /* DHDTCPACK_SUP_DBG */
248 return tdata_psh_info
;
251 static int _tdata_psh_info_pool_init(dhd_pub_t
*dhdp
,
252 tcpack_sup_module_t
*tcpack_sup_mod
)
254 tdata_psh_info_t
*tdata_psh_info_pool
= NULL
;
257 DHD_TRACE(("%s %d: Enter\n", __FUNCTION__
, __LINE__
));
259 if (tcpack_sup_mod
== NULL
)
262 ASSERT(tcpack_sup_mod
->tdata_psh_info_pool
== NULL
);
263 ASSERT(tcpack_sup_mod
->tdata_psh_info_free
== NULL
);
265 tdata_psh_info_pool
=
266 MALLOC(dhdp
->osh
, sizeof(tdata_psh_info_t
) * TCPDATA_PSH_INFO_MAXNUM
);
268 if (tdata_psh_info_pool
== NULL
)
270 bzero(tdata_psh_info_pool
, sizeof(tdata_psh_info_t
) * TCPDATA_PSH_INFO_MAXNUM
);
271 #ifdef DHDTCPACK_SUP_DBG
272 tcpack_sup_mod
->psh_info_enq_num
= 0;
273 #endif /* DHDTCPACK_SUP_DBG */
275 /* Enqueue newly allocated tcpdata psh info elements to the pool */
276 for (i
= 0; i
< TCPDATA_PSH_INFO_MAXNUM
; i
++)
277 _tdata_psh_info_pool_enq(tcpack_sup_mod
, &tdata_psh_info_pool
[i
]);
279 ASSERT(tcpack_sup_mod
->tdata_psh_info_free
!= NULL
);
280 tcpack_sup_mod
->tdata_psh_info_pool
= tdata_psh_info_pool
;
285 static void _tdata_psh_info_pool_deinit(dhd_pub_t
*dhdp
,
286 tcpack_sup_module_t
*tcpack_sup_mod
)
289 tdata_psh_info_t
*tdata_psh_info
;
291 DHD_TRACE(("%s %d: Enter\n", __FUNCTION__
, __LINE__
));
293 if (tcpack_sup_mod
== NULL
) {
294 DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n",
295 __FUNCTION__
, __LINE__
));
299 for (i
= 0; i
< tcpack_sup_mod
->tcpdata_info_cnt
; i
++) {
300 tcpdata_info_t
*tcpdata_info
= &tcpack_sup_mod
->tcpdata_info_tbl
[i
];
301 /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */
302 while ((tdata_psh_info
= tcpdata_info
->tdata_psh_info_head
)) {
303 tcpdata_info
->tdata_psh_info_head
= tdata_psh_info
->next
;
304 tdata_psh_info
->next
= NULL
;
305 _tdata_psh_info_pool_enq(tcpack_sup_mod
, tdata_psh_info
);
307 tcpdata_info
->tdata_psh_info_tail
= NULL
;
309 #ifdef DHDTCPACK_SUP_DBG
310 DHD_ERROR(("%s %d: PSH INFO ENQ %d\n",
311 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->psh_info_enq_num
));
312 #endif /* DHDTCPACK_SUP_DBG */
315 /* Be sure we recollected all tdata_psh_info elements */
316 while ((tdata_psh_info
= tcpack_sup_mod
->tdata_psh_info_free
)) {
317 tcpack_sup_mod
->tdata_psh_info_free
= tdata_psh_info
->next
;
318 tdata_psh_info
->next
= NULL
;
321 ASSERT(i
== TCPDATA_PSH_INFO_MAXNUM
);
322 MFREE(dhdp
->osh
, tcpack_sup_mod
->tdata_psh_info_pool
,
323 sizeof(tdata_psh_info_t
) * TCPDATA_PSH_INFO_MAXNUM
);
324 tcpack_sup_mod
->tdata_psh_info_pool
= NULL
;
329 static void dhd_tcpack_send(ulong data
)
331 tcpack_sup_module_t
*tcpack_sup_mod
;
332 tcpack_info_t
*cur_tbl
= (tcpack_info_t
*)data
;
341 dhdp
= cur_tbl
->dhdp
;
346 dhd_os_tcpacklock(dhdp
);
348 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
349 pkt
= cur_tbl
->pkt_in_q
;
350 ifidx
= cur_tbl
->ifidx
;
352 dhd_os_tcpackunlock(dhdp
);
355 cur_tbl
->pkt_in_q
= NULL
;
356 cur_tbl
->pkt_ether_hdr
= NULL
;
358 cur_tbl
->supp_cnt
= 0;
359 if (--tcpack_sup_mod
->tcpack_info_cnt
< 0) {
360 DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n",
361 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->tcpack_info_cnt
));
364 dhd_os_tcpackunlock(dhdp
);
366 dhd_sendpkt(dhdp
, ifidx
, pkt
);
369 int dhd_tcpack_suppress_set(dhd_pub_t
*dhdp
, uint8 mode
)
373 dhd_os_tcpacklock(dhdp
);
375 if (dhdp
->tcpack_sup_mode
== mode
) {
376 DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__
, __LINE__
, mode
));
380 if (mode
>= TCPACK_SUP_LAST_MODE
||
382 mode
== TCPACK_SUP_DELAYTX
||
385 DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__
, __LINE__
, mode
));
390 DHD_TRACE(("%s: %d -> %d\n",
391 __FUNCTION__
, dhdp
->tcpack_sup_mode
, mode
));
393 /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */
394 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_DELAYTX
) {
395 tcpack_sup_module_t
*tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
396 /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */
397 _tdata_psh_info_pool_deinit(dhdp
, tcpack_sup_mod
);
398 tcpack_sup_mod
->tcpdata_info_cnt
= 0;
399 bzero(tcpack_sup_mod
->tcpdata_info_tbl
,
400 sizeof(tcpdata_info_t
) * TCPDATA_INFO_MAXNUM
);
401 /* For half duplex bus interface, tx precedes rx by default */
403 dhd_bus_set_dotxinrx(dhdp
->bus
, TRUE
);
406 dhdp
->tcpack_sup_mode
= mode
;
408 if (mode
== TCPACK_SUP_OFF
) {
409 ASSERT(dhdp
->tcpack_sup_module
!= NULL
);
410 MFREE(dhdp
->osh
, dhdp
->tcpack_sup_module
, sizeof(tcpack_sup_module_t
));
411 dhdp
->tcpack_sup_module
= NULL
;
415 if (dhdp
->tcpack_sup_module
== NULL
) {
416 tcpack_sup_module_t
*tcpack_sup_mod
=
417 MALLOC(dhdp
->osh
, sizeof(tcpack_sup_module_t
));
418 if (tcpack_sup_mod
== NULL
) {
419 DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__
, __LINE__
));
420 dhdp
->tcpack_sup_mode
= TCPACK_SUP_OFF
;
424 bzero(tcpack_sup_mod
, sizeof(tcpack_sup_module_t
));
425 dhdp
->tcpack_sup_module
= tcpack_sup_mod
;
428 if (mode
== TCPACK_SUP_DELAYTX
) {
429 ret
= _tdata_psh_info_pool_init(dhdp
, dhdp
->tcpack_sup_module
);
431 DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__
, __LINE__
, ret
));
433 dhd_bus_set_dotxinrx(dhdp
->bus
, FALSE
);
436 if (mode
== TCPACK_SUP_HOLD
) {
438 tcpack_sup_module_t
*tcpack_sup_mod
=
439 (tcpack_sup_module_t
*)dhdp
->tcpack_sup_module
;
440 dhdp
->tcpack_sup_ratio
= TCPACK_SUPP_RATIO
;
441 dhdp
->tcpack_sup_delay
= TCPACK_DELAY_TIME
;
442 for (i
= 0; i
< TCPACK_INFO_MAXNUM
; i
++)
444 tcpack_sup_mod
->tcpack_info_tbl
[i
].dhdp
= dhdp
;
445 init_timer(&tcpack_sup_mod
->tcpack_info_tbl
[i
].timer
);
446 tcpack_sup_mod
->tcpack_info_tbl
[i
].timer
.data
=
447 (ulong
)&tcpack_sup_mod
->tcpack_info_tbl
[i
];
448 tcpack_sup_mod
->tcpack_info_tbl
[i
].timer
.function
= dhd_tcpack_send
;
453 dhd_os_tcpackunlock(dhdp
);
458 dhd_tcpack_info_tbl_clean(dhd_pub_t
*dhdp
)
460 tcpack_sup_module_t
*tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
463 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_OFF
)
466 dhd_os_tcpacklock(dhdp
);
468 if (!tcpack_sup_mod
) {
469 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
470 __FUNCTION__
, __LINE__
));
471 dhd_os_tcpackunlock(dhdp
);
475 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_HOLD
) {
476 for (i
= 0; i
< TCPACK_INFO_MAXNUM
; i
++) {
477 if (tcpack_sup_mod
->tcpack_info_tbl
[i
].pkt_in_q
) {
478 PKTFREE(dhdp
->osh
, tcpack_sup_mod
->tcpack_info_tbl
[i
].pkt_in_q
,
480 tcpack_sup_mod
->tcpack_info_tbl
[i
].pkt_in_q
= NULL
;
481 tcpack_sup_mod
->tcpack_info_tbl
[i
].pkt_ether_hdr
= NULL
;
482 tcpack_sup_mod
->tcpack_info_tbl
[i
].ifidx
= 0;
483 tcpack_sup_mod
->tcpack_info_tbl
[i
].supp_cnt
= 0;
487 tcpack_sup_mod
->tcpack_info_cnt
= 0;
488 bzero(tcpack_sup_mod
->tcpack_info_tbl
, sizeof(tcpack_info_t
) * TCPACK_INFO_MAXNUM
);
491 dhd_os_tcpackunlock(dhdp
);
493 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_HOLD
) {
494 for (i
= 0; i
< TCPACK_INFO_MAXNUM
; i
++) {
495 del_timer_sync(&tcpack_sup_mod
->tcpack_info_tbl
[i
].timer
);
503 inline int dhd_tcpack_check_xmit(dhd_pub_t
*dhdp
, void *pkt
)
506 tcpack_sup_module_t
*tcpack_sup_mod
;
507 tcpack_info_t
*tcpack_info_tbl
;
513 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_OFF
)
516 pdata
= PKTDATA(dhdp
->osh
, pkt
);
517 pktlen
= PKTLEN(dhdp
->osh
, pkt
) - dhd_prot_hdrlen(dhdp
, pdata
);
519 if (pktlen
< TCPACKSZMIN
|| pktlen
> TCPACKSZMAX
) {
520 DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
521 __FUNCTION__
, __LINE__
, pktlen
));
525 dhd_os_tcpacklock(dhdp
);
526 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
528 if (!tcpack_sup_mod
) {
529 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
531 dhd_os_tcpackunlock(dhdp
);
534 tbl_cnt
= tcpack_sup_mod
->tcpack_info_cnt
;
535 tcpack_info_tbl
= tcpack_sup_mod
->tcpack_info_tbl
;
537 ASSERT(tbl_cnt
<= TCPACK_INFO_MAXNUM
);
539 for (i
= 0; i
< tbl_cnt
; i
++) {
540 if (tcpack_info_tbl
[i
].pkt_in_q
== pkt
) {
541 DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n",
542 __FUNCTION__
, __LINE__
, pkt
, i
, tbl_cnt
));
543 /* This pkt is being transmitted so remove the tcp_ack_info of it. */
544 if (i
< tbl_cnt
- 1) {
545 bcopy(&tcpack_info_tbl
[tbl_cnt
- 1],
546 &tcpack_info_tbl
[i
], sizeof(tcpack_info_t
));
548 bzero(&tcpack_info_tbl
[tbl_cnt
- 1], sizeof(tcpack_info_t
));
549 if (--tcpack_sup_mod
->tcpack_info_cnt
< 0) {
550 DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n",
551 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->tcpack_info_cnt
));
557 dhd_os_tcpackunlock(dhdp
);
563 static INLINE
bool dhd_tcpdata_psh_acked(dhd_pub_t
*dhdp
, uint8
*ip_hdr
,
564 uint8
*tcp_hdr
, uint32 tcp_ack_num
)
566 tcpack_sup_module_t
*tcpack_sup_mod
;
568 tcpdata_info_t
*tcpdata_info
= NULL
;
569 tdata_psh_info_t
*tdata_psh_info
= NULL
;
572 if (dhdp
->tcpack_sup_mode
!= TCPACK_SUP_DELAYTX
)
575 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
577 if (!tcpack_sup_mod
) {
578 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
582 DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
583 " TCP port %d %d, ack %u\n", __FUNCTION__
, __LINE__
,
584 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_SRC_IP_OFFSET
])),
585 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_DEST_IP_OFFSET
])),
586 ntoh16_ua(&tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
587 ntoh16_ua(&tcp_hdr
[TCP_DEST_PORT_OFFSET
]),
590 for (i
= 0; i
< tcpack_sup_mod
->tcpdata_info_cnt
; i
++) {
591 tcpdata_info_t
*tcpdata_info_tmp
= &tcpack_sup_mod
->tcpdata_info_tbl
[i
];
592 DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
593 " TCP port %d %d\n", __FUNCTION__
, __LINE__
, i
,
594 IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp
->src_ip_addr
)),
595 IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp
->dst_ip_addr
)),
596 ntoh16_ua(tcpdata_info_tmp
->src_tcp_port
),
597 ntoh16_ua(tcpdata_info_tmp
->dst_tcp_port
)));
599 /* If either IP address or TCP port number does not match, skip. */
600 if (memcmp(&ip_hdr
[IPV4_SRC_IP_OFFSET
],
601 tcpdata_info_tmp
->dst_ip_addr
, IPV4_ADDR_LEN
) == 0 &&
602 memcmp(&ip_hdr
[IPV4_DEST_IP_OFFSET
],
603 tcpdata_info_tmp
->src_ip_addr
, IPV4_ADDR_LEN
) == 0 &&
604 memcmp(&tcp_hdr
[TCP_SRC_PORT_OFFSET
],
605 tcpdata_info_tmp
->dst_tcp_port
, TCP_PORT_LEN
) == 0 &&
606 memcmp(&tcp_hdr
[TCP_DEST_PORT_OFFSET
],
607 tcpdata_info_tmp
->src_tcp_port
, TCP_PORT_LEN
) == 0) {
608 tcpdata_info
= tcpdata_info_tmp
;
613 if (tcpdata_info
== NULL
) {
614 DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__
, __LINE__
));
618 if (tcpdata_info
->tdata_psh_info_head
== NULL
) {
619 DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__
, __LINE__
));
622 while ((tdata_psh_info
= tcpdata_info
->tdata_psh_info_head
)) {
623 if (IS_TCPSEQ_GE(tcp_ack_num
, tdata_psh_info
->end_seq
)) {
624 DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n",
625 __FUNCTION__
, __LINE__
, tcp_ack_num
, tdata_psh_info
->end_seq
));
626 tcpdata_info
->tdata_psh_info_head
= tdata_psh_info
->next
;
627 tdata_psh_info
->next
= NULL
;
628 _tdata_psh_info_pool_enq(tcpack_sup_mod
, tdata_psh_info
);
633 if (tdata_psh_info
== NULL
)
634 tcpdata_info
->tdata_psh_info_tail
= NULL
;
636 #ifdef DHDTCPACK_SUP_DBG
637 DHD_TRACE(("%s %d: PSH INFO ENQ %d\n",
638 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->psh_info_enq_num
));
639 #endif /* DHDTCPACK_SUP_DBG */
646 dhd_tcpack_suppress(dhd_pub_t
*dhdp
, void *pkt
)
648 uint8
*new_ether_hdr
; /* Ethernet header of the new packet */
649 uint16 new_ether_type
; /* Ethernet type of the new packet */
650 uint8
*new_ip_hdr
; /* IP header of the new packet */
651 uint8
*new_tcp_hdr
; /* TCP header of the new packet */
652 uint32 new_ip_hdr_len
; /* IP header length of the new packet */
654 uint32 new_tcp_ack_num
; /* TCP acknowledge number of the new packet */
655 uint16 new_ip_total_len
; /* Total length of IP packet for the new packet */
656 uint32 new_tcp_hdr_len
; /* TCP header length of the new packet */
657 tcpack_sup_module_t
*tcpack_sup_mod
;
658 tcpack_info_t
*tcpack_info_tbl
;
661 bool set_dotxinrx
= TRUE
;
663 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_OFF
)
666 new_ether_hdr
= PKTDATA(dhdp
->osh
, pkt
);
667 cur_framelen
= PKTLEN(dhdp
->osh
, pkt
);
669 if (cur_framelen
< TCPACKSZMIN
|| cur_framelen
> TCPACKSZMAX
) {
670 DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
671 __FUNCTION__
, __LINE__
, cur_framelen
));
675 new_ether_type
= new_ether_hdr
[12] << 8 | new_ether_hdr
[13];
677 if (new_ether_type
!= ETHER_TYPE_IP
) {
678 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
679 __FUNCTION__
, __LINE__
, new_ether_type
));
683 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__
, __LINE__
, new_ether_type
));
685 new_ip_hdr
= new_ether_hdr
+ ETHER_HDR_LEN
;
686 cur_framelen
-= ETHER_HDR_LEN
;
688 ASSERT(cur_framelen
>= IPV4_MIN_HEADER_LEN
);
690 new_ip_hdr_len
= IPV4_HLEN(new_ip_hdr
);
691 if (IP_VER(new_ip_hdr
) != IP_VER_4
|| IPV4_PROT(new_ip_hdr
) != IP_PROT_TCP
) {
692 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
693 __FUNCTION__
, __LINE__
, IP_VER(new_ip_hdr
), IPV4_PROT(new_ip_hdr
)));
697 new_tcp_hdr
= new_ip_hdr
+ new_ip_hdr_len
;
698 cur_framelen
-= new_ip_hdr_len
;
700 ASSERT(cur_framelen
>= TCP_MIN_HEADER_LEN
);
702 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__
, __LINE__
));
704 /* is it an ack ? Allow only ACK flag, not to suppress others. */
705 if (new_tcp_hdr
[TCP_FLAGS_OFFSET
] != TCP_FLAG_ACK
) {
706 DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n",
707 __FUNCTION__
, __LINE__
, new_tcp_hdr
[TCP_FLAGS_OFFSET
]));
711 new_ip_total_len
= ntoh16_ua(&new_ip_hdr
[IPV4_PKTLEN_OFFSET
]);
712 new_tcp_hdr_len
= 4 * TCP_HDRLEN(new_tcp_hdr
[TCP_HLEN_OFFSET
]);
714 /* This packet has TCP data, so just send */
715 if (new_ip_total_len
> new_ip_hdr_len
+ new_tcp_hdr_len
) {
716 DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__
, __LINE__
));
720 ASSERT(new_ip_total_len
== new_ip_hdr_len
+ new_tcp_hdr_len
);
722 new_tcp_ack_num
= ntoh32_ua(&new_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
724 DHD_TRACE(("%s %d: TCP ACK with zero DATA length"
725 " IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
" TCP port %d %d\n",
726 __FUNCTION__
, __LINE__
,
727 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr
[IPV4_SRC_IP_OFFSET
])),
728 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr
[IPV4_DEST_IP_OFFSET
])),
729 ntoh16_ua(&new_tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
730 ntoh16_ua(&new_tcp_hdr
[TCP_DEST_PORT_OFFSET
])));
732 /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */
733 dhd_os_tcpacklock(dhdp
);
734 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
735 counter_printlog(&tack_tbl
);
737 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
739 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
740 tcpack_info_tbl
= tcpack_sup_mod
->tcpack_info_tbl
;
742 if (!tcpack_sup_mod
) {
743 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
745 dhd_os_tcpackunlock(dhdp
);
749 if (dhd_tcpdata_psh_acked(dhdp
, new_ip_hdr
, new_tcp_hdr
, new_tcp_ack_num
)) {
750 /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */
751 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
753 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
755 set_dotxinrx
= FALSE
;
757 for (i
= 0; i
< tcpack_sup_mod
->tcpack_info_cnt
; i
++) {
758 void *oldpkt
; /* TCPACK packet that is already in txq or DelayQ */
759 uint8
*old_ether_hdr
, *old_ip_hdr
, *old_tcp_hdr
;
760 uint32 old_ip_hdr_len
, old_tcp_hdr_len
;
761 uint32 old_tcpack_num
; /* TCP ACK number of old TCPACK packet in Q */
763 if ((oldpkt
= tcpack_info_tbl
[i
].pkt_in_q
) == NULL
) {
764 DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n",
765 __FUNCTION__
, __LINE__
, i
, tcpack_sup_mod
->tcpack_info_cnt
));
769 if (PKTDATA(dhdp
->osh
, oldpkt
) == NULL
) {
770 DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n",
771 __FUNCTION__
, __LINE__
, i
, tcpack_sup_mod
->tcpack_info_cnt
));
775 old_ether_hdr
= tcpack_info_tbl
[i
].pkt_ether_hdr
;
776 old_ip_hdr
= old_ether_hdr
+ ETHER_HDR_LEN
;
777 old_ip_hdr_len
= IPV4_HLEN(old_ip_hdr
);
778 old_tcp_hdr
= old_ip_hdr
+ old_ip_hdr_len
;
779 old_tcp_hdr_len
= 4 * TCP_HDRLEN(old_tcp_hdr
[TCP_HLEN_OFFSET
]);
781 DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
782 " TCP port %d %d\n", __FUNCTION__
, __LINE__
, oldpkt
, i
,
783 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr
[IPV4_SRC_IP_OFFSET
])),
784 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr
[IPV4_DEST_IP_OFFSET
])),
785 ntoh16_ua(&old_tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
786 ntoh16_ua(&old_tcp_hdr
[TCP_DEST_PORT_OFFSET
])));
788 /* If either of IP address or TCP port number does not match, skip. */
789 if (memcmp(&new_ip_hdr
[IPV4_SRC_IP_OFFSET
],
790 &old_ip_hdr
[IPV4_SRC_IP_OFFSET
], IPV4_ADDR_LEN
* 2) ||
791 memcmp(&new_tcp_hdr
[TCP_SRC_PORT_OFFSET
],
792 &old_tcp_hdr
[TCP_SRC_PORT_OFFSET
], TCP_PORT_LEN
* 2))
795 old_tcpack_num
= ntoh32_ua(&old_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
797 if (IS_TCPSEQ_GT(new_tcp_ack_num
, old_tcpack_num
)) {
798 /* New packet has higher TCP ACK number, so it replaces the old packet */
799 if (new_ip_hdr_len
== old_ip_hdr_len
&&
800 new_tcp_hdr_len
== old_tcp_hdr_len
) {
801 ASSERT(memcmp(new_ether_hdr
, old_ether_hdr
, ETHER_HDR_LEN
) == 0);
802 bcopy(new_ip_hdr
, old_ip_hdr
, new_ip_total_len
);
803 PKTFREE(dhdp
->osh
, pkt
, FALSE
);
804 DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n",
805 __FUNCTION__
, __LINE__
, old_tcpack_num
, new_tcp_ack_num
));
806 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
808 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
811 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
813 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
814 DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d"
815 " ACK %u -> %u\n", __FUNCTION__
, __LINE__
,
816 new_ip_hdr_len
, old_ip_hdr_len
,
817 new_tcp_hdr_len
, old_tcp_hdr_len
,
818 old_tcpack_num
, new_tcp_ack_num
));
820 } else if (new_tcp_ack_num
== old_tcpack_num
) {
822 /* TCPACK retransmission */
823 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
825 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
827 DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n",
828 __FUNCTION__
, __LINE__
, old_tcpack_num
, oldpkt
,
829 new_tcp_ack_num
, pkt
));
831 dhd_os_tcpackunlock(dhdp
);
835 if (i
== tcpack_sup_mod
->tcpack_info_cnt
&& i
< TCPACK_INFO_MAXNUM
) {
836 /* No TCPACK packet with the same IP addr and TCP port is found
837 * in tcp_ack_info_tbl. So add this packet to the table.
839 DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
840 __FUNCTION__
, __LINE__
, pkt
, new_ether_hdr
,
841 tcpack_sup_mod
->tcpack_info_cnt
));
843 tcpack_info_tbl
[tcpack_sup_mod
->tcpack_info_cnt
].pkt_in_q
= pkt
;
844 tcpack_info_tbl
[tcpack_sup_mod
->tcpack_info_cnt
].pkt_ether_hdr
= new_ether_hdr
;
845 tcpack_sup_mod
->tcpack_info_cnt
++;
846 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
848 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
850 ASSERT(i
== tcpack_sup_mod
->tcpack_info_cnt
);
851 DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
852 __FUNCTION__
, __LINE__
));
854 dhd_os_tcpackunlock(dhdp
);
857 /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */
858 if (dhdp
->tcpack_sup_mode
== TCPACK_SUP_DELAYTX
&& set_dotxinrx
)
859 dhd_bus_set_dotxinrx(dhdp
->bus
, TRUE
);
865 dhd_tcpdata_info_get(dhd_pub_t
*dhdp
, void *pkt
)
867 uint8
*ether_hdr
; /* Ethernet header of the new packet */
868 uint16 ether_type
; /* Ethernet type of the new packet */
869 uint8
*ip_hdr
; /* IP header of the new packet */
870 uint8
*tcp_hdr
; /* TCP header of the new packet */
871 uint32 ip_hdr_len
; /* IP header length of the new packet */
873 uint16 ip_total_len
; /* Total length of IP packet for the new packet */
874 uint32 tcp_hdr_len
; /* TCP header length of the new packet */
875 uint32 tcp_seq_num
; /* TCP sequence number of the new packet */
876 uint16 tcp_data_len
; /* TCP DATA length that excludes IP and TCP headers */
877 uint32 end_tcp_seq_num
; /* TCP seq number of the last byte in the new packet */
878 tcpack_sup_module_t
*tcpack_sup_mod
;
879 tcpdata_info_t
*tcpdata_info
= NULL
;
880 tdata_psh_info_t
*tdata_psh_info
;
885 if (dhdp
->tcpack_sup_mode
!= TCPACK_SUP_DELAYTX
)
888 ether_hdr
= PKTDATA(dhdp
->osh
, pkt
);
889 cur_framelen
= PKTLEN(dhdp
->osh
, pkt
);
891 ether_type
= ether_hdr
[12] << 8 | ether_hdr
[13];
893 if (ether_type
!= ETHER_TYPE_IP
) {
894 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
895 __FUNCTION__
, __LINE__
, ether_type
));
899 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__
, __LINE__
, ether_type
));
901 ip_hdr
= ether_hdr
+ ETHER_HDR_LEN
;
902 cur_framelen
-= ETHER_HDR_LEN
;
904 ASSERT(cur_framelen
>= IPV4_MIN_HEADER_LEN
);
906 ip_hdr_len
= IPV4_HLEN(ip_hdr
);
907 if (IP_VER(ip_hdr
) != IP_VER_4
|| IPV4_PROT(ip_hdr
) != IP_PROT_TCP
) {
908 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
909 __FUNCTION__
, __LINE__
, IP_VER(ip_hdr
), IPV4_PROT(ip_hdr
)));
913 tcp_hdr
= ip_hdr
+ ip_hdr_len
;
914 cur_framelen
-= ip_hdr_len
;
916 ASSERT(cur_framelen
>= TCP_MIN_HEADER_LEN
);
918 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__
, __LINE__
));
920 ip_total_len
= ntoh16_ua(&ip_hdr
[IPV4_PKTLEN_OFFSET
]);
921 tcp_hdr_len
= 4 * TCP_HDRLEN(tcp_hdr
[TCP_HLEN_OFFSET
]);
923 /* This packet is mere TCP ACK, so do nothing */
924 if (ip_total_len
== ip_hdr_len
+ tcp_hdr_len
) {
925 DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__
, __LINE__
));
929 ASSERT(ip_total_len
> ip_hdr_len
+ tcp_hdr_len
);
931 if ((tcp_hdr
[TCP_FLAGS_OFFSET
] & TCP_FLAG_PSH
) == 0) {
932 DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__
, __LINE__
));
936 DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length"
937 " IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
" TCP port %d %d, flag 0x%x\n",
938 __FUNCTION__
, __LINE__
,
939 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_SRC_IP_OFFSET
])),
940 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_DEST_IP_OFFSET
])),
941 ntoh16_ua(&tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
942 ntoh16_ua(&tcp_hdr
[TCP_DEST_PORT_OFFSET
]),
943 tcp_hdr
[TCP_FLAGS_OFFSET
]));
945 dhd_os_tcpacklock(dhdp
);
946 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
948 if (!tcpack_sup_mod
) {
949 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
951 dhd_os_tcpackunlock(dhdp
);
955 /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */
957 while (i
< tcpack_sup_mod
->tcpdata_info_cnt
) {
958 tcpdata_info_t
*tdata_info_tmp
= &tcpack_sup_mod
->tcpdata_info_tbl
[i
];
959 uint32 now_in_ms
= OSL_SYSUPTIME();
960 DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
961 " TCP port %d %d\n", __FUNCTION__
, __LINE__
, i
,
962 IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp
->src_ip_addr
)),
963 IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp
->dst_ip_addr
)),
964 ntoh16_ua(tdata_info_tmp
->src_tcp_port
),
965 ntoh16_ua(tdata_info_tmp
->dst_tcp_port
)));
967 /* If both IP address and TCP port number match, we found it so break. */
968 if (memcmp(&ip_hdr
[IPV4_SRC_IP_OFFSET
],
969 tdata_info_tmp
->src_ip_addr
, IPV4_ADDR_LEN
* 2) == 0 &&
970 memcmp(&tcp_hdr
[TCP_SRC_PORT_OFFSET
],
971 tdata_info_tmp
->src_tcp_port
, TCP_PORT_LEN
* 2) == 0) {
972 tcpdata_info
= tdata_info_tmp
;
973 tcpdata_info
->last_used_time
= now_in_ms
;
977 if (now_in_ms
- tdata_info_tmp
->last_used_time
> TCPDATA_INFO_TIMEOUT
) {
978 tdata_psh_info_t
*tdata_psh_info_tmp
;
979 tcpdata_info_t
*last_tdata_info
;
981 while ((tdata_psh_info_tmp
= tdata_info_tmp
->tdata_psh_info_head
)) {
982 tdata_info_tmp
->tdata_psh_info_head
= tdata_psh_info_tmp
->next
;
983 tdata_psh_info_tmp
->next
= NULL
;
984 DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n",
985 __FUNCTION__
, __LINE__
, tdata_psh_info_tmp
->end_seq
));
986 _tdata_psh_info_pool_enq(tcpack_sup_mod
, tdata_psh_info_tmp
);
988 #ifdef DHDTCPACK_SUP_DBG
989 DHD_ERROR(("%s %d: PSH INFO ENQ %d\n",
990 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->psh_info_enq_num
));
991 #endif /* DHDTCPACK_SUP_DBG */
992 tcpack_sup_mod
->tcpdata_info_cnt
--;
993 ASSERT(tcpack_sup_mod
->tcpdata_info_cnt
>= 0);
996 &tcpack_sup_mod
->tcpdata_info_tbl
[tcpack_sup_mod
->tcpdata_info_cnt
];
997 if (i
< tcpack_sup_mod
->tcpdata_info_cnt
) {
998 ASSERT(last_tdata_info
!= tdata_info_tmp
);
999 bcopy(last_tdata_info
, tdata_info_tmp
, sizeof(tcpdata_info_t
));
1001 bzero(last_tdata_info
, sizeof(tcpdata_info_t
));
1002 DHD_ERROR(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n",
1003 __FUNCTION__
, __LINE__
, i
, tcpack_sup_mod
->tcpdata_info_cnt
));
1004 /* Don't increase "i" here, so that the prev last tcpdata_info is checked */
1009 tcp_seq_num
= ntoh32_ua(&tcp_hdr
[TCP_SEQ_NUM_OFFSET
]);
1010 tcp_data_len
= ip_total_len
- ip_hdr_len
- tcp_hdr_len
;
1011 end_tcp_seq_num
= tcp_seq_num
+ tcp_data_len
;
1013 if (tcpdata_info
== NULL
) {
1014 ASSERT(i
== tcpack_sup_mod
->tcpdata_info_cnt
);
1015 if (i
>= TCPDATA_INFO_MAXNUM
) {
1016 DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d"
1017 " IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
" TCP port %d %d\n",
1018 __FUNCTION__
, __LINE__
, i
, tcpack_sup_mod
->tcpdata_info_cnt
,
1019 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_SRC_IP_OFFSET
])),
1020 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_DEST_IP_OFFSET
])),
1021 ntoh16_ua(&tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
1022 ntoh16_ua(&tcp_hdr
[TCP_DEST_PORT_OFFSET
])));
1023 dhd_os_tcpackunlock(dhdp
);
1026 tcpdata_info
= &tcpack_sup_mod
->tcpdata_info_tbl
[i
];
1028 /* No TCP flow with the same IP addr and TCP port is found
1029 * in tcp_data_info_tbl. So add this flow to the table.
1031 DHD_ERROR(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
1032 " TCP port %d %d\n",
1033 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->tcpdata_info_cnt
,
1034 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_SRC_IP_OFFSET
])),
1035 IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr
[IPV4_DEST_IP_OFFSET
])),
1036 ntoh16_ua(&tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
1037 ntoh16_ua(&tcp_hdr
[TCP_DEST_PORT_OFFSET
])));
1039 bcopy(&ip_hdr
[IPV4_SRC_IP_OFFSET
], tcpdata_info
->src_ip_addr
,
1041 bcopy(&tcp_hdr
[TCP_SRC_PORT_OFFSET
], tcpdata_info
->src_tcp_port
,
1044 tcpdata_info
->last_used_time
= OSL_SYSUPTIME();
1045 tcpack_sup_mod
->tcpdata_info_cnt
++;
1048 ASSERT(tcpdata_info
!= NULL
);
1050 tdata_psh_info
= _tdata_psh_info_pool_deq(tcpack_sup_mod
);
1051 #ifdef DHDTCPACK_SUP_DBG
1052 DHD_TRACE(("%s %d: PSH INFO ENQ %d\n",
1053 __FUNCTION__
, __LINE__
, tcpack_sup_mod
->psh_info_enq_num
));
1054 #endif /* DHDTCPACK_SUP_DBG */
1056 if (tdata_psh_info
== NULL
) {
1057 DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__
, __LINE__
));
1059 dhd_os_tcpackunlock(dhdp
);
1062 tdata_psh_info
->end_seq
= end_tcp_seq_num
;
1064 #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
1066 #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
1068 DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n",
1069 __FUNCTION__
, __LINE__
, tdata_psh_info
->end_seq
));
1071 ASSERT(tdata_psh_info
->next
== NULL
);
1073 if (tcpdata_info
->tdata_psh_info_head
== NULL
)
1074 tcpdata_info
->tdata_psh_info_head
= tdata_psh_info
;
1076 ASSERT(tcpdata_info
->tdata_psh_info_tail
);
1077 tcpdata_info
->tdata_psh_info_tail
->next
= tdata_psh_info
;
1079 tcpdata_info
->tdata_psh_info_tail
= tdata_psh_info
;
1081 dhd_os_tcpackunlock(dhdp
);
1088 dhd_tcpack_hold(dhd_pub_t
*dhdp
, void *pkt
, int ifidx
)
1090 uint8
*new_ether_hdr
; /* Ethernet header of the new packet */
1091 uint16 new_ether_type
; /* Ethernet type of the new packet */
1092 uint8
*new_ip_hdr
; /* IP header of the new packet */
1093 uint8
*new_tcp_hdr
; /* TCP header of the new packet */
1094 uint32 new_ip_hdr_len
; /* IP header length of the new packet */
1095 uint32 cur_framelen
;
1096 uint32 new_tcp_ack_num
; /* TCP acknowledge number of the new packet */
1097 uint16 new_ip_total_len
; /* Total length of IP packet for the new packet */
1098 uint32 new_tcp_hdr_len
; /* TCP header length of the new packet */
1099 tcpack_sup_module_t
*tcpack_sup_mod
;
1100 tcpack_info_t
*tcpack_info_tbl
;
1101 int i
, free_slot
= TCPACK_INFO_MAXNUM
;
1104 if (dhdp
->tcpack_sup_mode
!= TCPACK_SUP_HOLD
) {
1108 if (dhdp
->tcpack_sup_ratio
== 1) {
1112 new_ether_hdr
= PKTDATA(dhdp
->osh
, pkt
);
1113 cur_framelen
= PKTLEN(dhdp
->osh
, pkt
);
1115 if (cur_framelen
< TCPACKSZMIN
|| cur_framelen
> TCPACKSZMAX
) {
1116 DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
1117 __FUNCTION__
, __LINE__
, cur_framelen
));
1121 new_ether_type
= new_ether_hdr
[12] << 8 | new_ether_hdr
[13];
1123 if (new_ether_type
!= ETHER_TYPE_IP
) {
1124 DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
1125 __FUNCTION__
, __LINE__
, new_ether_type
));
1129 DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__
, __LINE__
, new_ether_type
));
1131 new_ip_hdr
= new_ether_hdr
+ ETHER_HDR_LEN
;
1132 cur_framelen
-= ETHER_HDR_LEN
;
1134 ASSERT(cur_framelen
>= IPV4_MIN_HEADER_LEN
);
1136 new_ip_hdr_len
= IPV4_HLEN(new_ip_hdr
);
1137 if (IP_VER(new_ip_hdr
) != IP_VER_4
|| IPV4_PROT(new_ip_hdr
) != IP_PROT_TCP
) {
1138 DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
1139 __FUNCTION__
, __LINE__
, IP_VER(new_ip_hdr
), IPV4_PROT(new_ip_hdr
)));
1143 new_tcp_hdr
= new_ip_hdr
+ new_ip_hdr_len
;
1144 cur_framelen
-= new_ip_hdr_len
;
1146 ASSERT(cur_framelen
>= TCP_MIN_HEADER_LEN
);
1148 DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__
, __LINE__
));
1150 /* is it an ack ? Allow only ACK flag, not to suppress others. */
1151 if (new_tcp_hdr
[TCP_FLAGS_OFFSET
] != TCP_FLAG_ACK
) {
1152 DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n",
1153 __FUNCTION__
, __LINE__
, new_tcp_hdr
[TCP_FLAGS_OFFSET
]));
1157 new_ip_total_len
= ntoh16_ua(&new_ip_hdr
[IPV4_PKTLEN_OFFSET
]);
1158 new_tcp_hdr_len
= 4 * TCP_HDRLEN(new_tcp_hdr
[TCP_HLEN_OFFSET
]);
1160 /* This packet has TCP data, so just send */
1161 if (new_ip_total_len
> new_ip_hdr_len
+ new_tcp_hdr_len
) {
1162 DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__
, __LINE__
));
1166 ASSERT(new_ip_total_len
== new_ip_hdr_len
+ new_tcp_hdr_len
);
1168 new_tcp_ack_num
= ntoh32_ua(&new_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
1170 DHD_TRACE(("%s %d: TCP ACK with zero DATA length"
1171 " IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
" TCP port %d %d\n",
1172 __FUNCTION__
, __LINE__
,
1173 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr
[IPV4_SRC_IP_OFFSET
])),
1174 IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr
[IPV4_DEST_IP_OFFSET
])),
1175 ntoh16_ua(&new_tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
1176 ntoh16_ua(&new_tcp_hdr
[TCP_DEST_PORT_OFFSET
])));
1178 /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */
1179 dhd_os_tcpacklock(dhdp
);
1181 tcpack_sup_mod
= dhdp
->tcpack_sup_module
;
1182 tcpack_info_tbl
= tcpack_sup_mod
->tcpack_info_tbl
;
1184 if (!tcpack_sup_mod
) {
1185 DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__
, __LINE__
));
1186 dhd_os_tcpackunlock(dhdp
);
1192 for (i
= 0; i
< TCPACK_INFO_MAXNUM
; i
++) {
1193 void *oldpkt
; /* TCPACK packet that is already in txq or DelayQ */
1194 uint8
*old_ether_hdr
, *old_ip_hdr
, *old_tcp_hdr
;
1195 uint32 old_ip_hdr_len
, old_tcp_hdr_len
;
1196 uint32 old_tcpack_num
; /* TCP ACK number of old TCPACK packet in Q */
1198 if ((oldpkt
= tcpack_info_tbl
[i
].pkt_in_q
) == NULL
) {
1199 if (free_slot
== TCPACK_INFO_MAXNUM
) {
1205 if (PKTDATA(dhdp
->osh
, oldpkt
) == NULL
) {
1206 DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n",
1207 __FUNCTION__
, __LINE__
, i
));
1209 dhd_os_tcpackunlock(dhdp
);
1213 old_ether_hdr
= tcpack_info_tbl
[i
].pkt_ether_hdr
;
1214 old_ip_hdr
= old_ether_hdr
+ ETHER_HDR_LEN
;
1215 old_ip_hdr_len
= IPV4_HLEN(old_ip_hdr
);
1216 old_tcp_hdr
= old_ip_hdr
+ old_ip_hdr_len
;
1217 old_tcp_hdr_len
= 4 * TCP_HDRLEN(old_tcp_hdr
[TCP_HLEN_OFFSET
]);
1219 DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR
" "IPV4_ADDR_STR
1220 " TCP port %d %d\n", __FUNCTION__
, __LINE__
, oldpkt
, i
,
1221 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr
[IPV4_SRC_IP_OFFSET
])),
1222 IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr
[IPV4_DEST_IP_OFFSET
])),
1223 ntoh16_ua(&old_tcp_hdr
[TCP_SRC_PORT_OFFSET
]),
1224 ntoh16_ua(&old_tcp_hdr
[TCP_DEST_PORT_OFFSET
])));
1226 /* If either of IP address or TCP port number does not match, skip. */
1227 if (memcmp(&new_ip_hdr
[IPV4_SRC_IP_OFFSET
],
1228 &old_ip_hdr
[IPV4_SRC_IP_OFFSET
], IPV4_ADDR_LEN
* 2) ||
1229 memcmp(&new_tcp_hdr
[TCP_SRC_PORT_OFFSET
],
1230 &old_tcp_hdr
[TCP_SRC_PORT_OFFSET
], TCP_PORT_LEN
* 2)) {
1234 old_tcpack_num
= ntoh32_ua(&old_tcp_hdr
[TCP_ACK_NUM_OFFSET
]);
1236 if (IS_TCPSEQ_GE(new_tcp_ack_num
, old_tcpack_num
)) {
1237 tcpack_info_tbl
[i
].supp_cnt
++;
1238 if (tcpack_info_tbl
[i
].supp_cnt
>= dhdp
->tcpack_sup_ratio
) {
1239 tcpack_info_tbl
[i
].pkt_in_q
= NULL
;
1240 tcpack_info_tbl
[i
].pkt_ether_hdr
= NULL
;
1241 tcpack_info_tbl
[i
].ifidx
= 0;
1242 tcpack_info_tbl
[i
].supp_cnt
= 0;
1245 tcpack_info_tbl
[i
].pkt_in_q
= pkt
;
1246 tcpack_info_tbl
[i
].pkt_ether_hdr
= new_ether_hdr
;
1247 tcpack_info_tbl
[i
].ifidx
= ifidx
;
1249 PKTFREE(dhdp
->osh
, oldpkt
, TRUE
);
1251 PKTFREE(dhdp
->osh
, pkt
, TRUE
);
1253 dhd_os_tcpackunlock(dhdp
);
1256 del_timer_sync(&tcpack_info_tbl
[i
].timer
);
1261 if (free_slot
< TCPACK_INFO_MAXNUM
) {
1262 /* No TCPACK packet with the same IP addr and TCP port is found
1263 * in tcp_ack_info_tbl. So add this packet to the table.
1265 DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
1266 __FUNCTION__
, __LINE__
, pkt
, new_ether_hdr
,
1269 tcpack_info_tbl
[free_slot
].pkt_in_q
= pkt
;
1270 tcpack_info_tbl
[free_slot
].pkt_ether_hdr
= new_ether_hdr
;
1271 tcpack_info_tbl
[free_slot
].ifidx
= ifidx
;
1272 tcpack_info_tbl
[free_slot
].supp_cnt
= 1;
1273 mod_timer(&tcpack_sup_mod
->tcpack_info_tbl
[free_slot
].timer
,
1274 jiffies
+ msecs_to_jiffies(dhdp
->tcpack_sup_delay
));
1275 tcpack_sup_mod
->tcpack_info_cnt
++;
1277 DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
1278 __FUNCTION__
, __LINE__
));
1280 dhd_os_tcpackunlock(dhdp
);
1285 #endif /* DHDTCPACK_SUPPRESS */