dhd_ip.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. /*
  2. * IP Packet Parser Module.
  3. *
  4. * Copyright (C) 1999-2014, 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 519554 2014-12-08 06:23:43Z $
  25. */
  26. #include <typedefs.h>
  27. #include <osl.h>
  28. #include <proto/ethernet.h>
  29. #include <proto/vlan.h>
  30. #include <proto/802.3.h>
  31. #include <proto/bcmip.h>
  32. #include <bcmendian.h>
  33. #include <dhd_dbg.h>
  34. #include <dhd_ip.h>
  35. #ifdef DHDTCPACK_SUPPRESS
  36. #include <dhd_bus.h>
  37. #include <proto/bcmtcp.h>
  38. #endif /* DHDTCPACK_SUPPRESS */
  39. /* special values */
  40. /* 802.3 llc/snap header */
  41. static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
  42. pkt_frag_t pkt_frag_info(osl_t *osh, void *p)
  43. {
  44. uint8 *frame;
  45. int length;
  46. uint8 *pt; /* Pointer to type field */
  47. uint16 ethertype;
  48. struct ipv4_hdr *iph; /* IP frame pointer */
  49. int ipl; /* IP frame length */
  50. uint16 iph_frag;
  51. ASSERT(osh && p);
  52. frame = PKTDATA(osh, p);
  53. length = PKTLEN(osh, p);
  54. /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
  55. if (length < ETHER_HDR_LEN) {
  56. DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length));
  57. return DHD_PKT_FRAG_NONE;
  58. } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) {
  59. /* Frame is Ethernet II */
  60. pt = frame + ETHER_TYPE_OFFSET;
  61. } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
  62. !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
  63. pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
  64. } else {
  65. DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__));
  66. return DHD_PKT_FRAG_NONE;
  67. }
  68. ethertype = ntoh16(*(uint16 *)pt);
  69. /* Skip VLAN tag, if any */
  70. if (ethertype == ETHER_TYPE_8021Q) {
  71. pt += VLAN_TAG_LEN;
  72. if (pt + ETHER_TYPE_LEN > frame + length) {
  73. DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length));
  74. return DHD_PKT_FRAG_NONE;
  75. }
  76. ethertype = ntoh16(*(uint16 *)pt);
  77. }
  78. if (ethertype != ETHER_TYPE_IP) {
  79. DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n",
  80. __FUNCTION__, ethertype, length));
  81. return DHD_PKT_FRAG_NONE;
  82. }
  83. iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN);
  84. ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame));
  85. /* We support IPv4 only */
  86. if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) {
  87. DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl));
  88. return DHD_PKT_FRAG_NONE;
  89. }
  90. iph_frag = ntoh16(iph->frag);
  91. if (iph_frag & IPV4_FRAG_DONT) {
  92. return DHD_PKT_FRAG_NONE;
  93. } else if ((iph_frag & IPV4_FRAG_MORE) == 0) {
  94. return DHD_PKT_FRAG_LAST;
  95. } else {
  96. return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST;
  97. }
  98. }
  99. #ifdef DHDTCPACK_SUPPRESS
  100. typedef struct {
  101. void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */
  102. void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */
  103. } tcpack_info_t;
  104. typedef struct _tdata_psh_info_t {
  105. uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */
  106. struct _tdata_psh_info_t *next; /* next pointer of the link chain */
  107. } tdata_psh_info_t;
  108. typedef struct {
  109. uint8 src_ip_addr[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */
  110. uint8 dst_ip_addr[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */
  111. uint8 src_tcp_port[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */
  112. uint8 dst_tcp_port[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */
  113. tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */
  114. tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */
  115. uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */
  116. } tcpdata_info_t;
  117. /* TCPACK SUPPRESS module */
  118. typedef struct {
  119. int tcpack_info_cnt;
  120. tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */
  121. int tcpdata_info_cnt;
  122. tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */
  123. tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */
  124. tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */
  125. #ifdef DHDTCPACK_SUP_DBG
  126. int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */
  127. #endif /* DHDTCPACK_SUP_DBG */
  128. } tcpack_sup_module_t;
  129. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  130. counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1};
  131. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  132. static void
  133. _tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod,
  134. tdata_psh_info_t *tdata_psh_info)
  135. {
  136. if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) {
  137. DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__,
  138. tcpack_sup_mod, tdata_psh_info));
  139. return;
  140. }
  141. ASSERT(tdata_psh_info->next == NULL);
  142. tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free;
  143. tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info;
  144. #ifdef DHDTCPACK_SUP_DBG
  145. tcpack_sup_mod->psh_info_enq_num++;
  146. #endif
  147. }
  148. static tdata_psh_info_t*
  149. _tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod)
  150. {
  151. tdata_psh_info_t *tdata_psh_info = NULL;
  152. if (tcpack_sup_mod == NULL) {
  153. DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__,
  154. tcpack_sup_mod));
  155. return NULL;
  156. }
  157. tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free;
  158. if (tdata_psh_info == NULL)
  159. DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__));
  160. else {
  161. tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next;
  162. tdata_psh_info->next = NULL;
  163. #ifdef DHDTCPACK_SUP_DBG
  164. tcpack_sup_mod->psh_info_enq_num--;
  165. #endif /* DHDTCPACK_SUP_DBG */
  166. }
  167. return tdata_psh_info;
  168. }
  169. static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp,
  170. tcpack_sup_module_t *tcpack_sup_mod)
  171. {
  172. tdata_psh_info_t *tdata_psh_info_pool = NULL;
  173. uint i;
  174. DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__));
  175. if (tcpack_sup_mod == NULL)
  176. return BCME_ERROR;
  177. ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL);
  178. ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL);
  179. tdata_psh_info_pool =
  180. MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
  181. if (tdata_psh_info_pool == NULL)
  182. return BCME_NOMEM;
  183. bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
  184. #ifdef DHDTCPACK_SUP_DBG
  185. tcpack_sup_mod->psh_info_enq_num = 0;
  186. #endif /* DHDTCPACK_SUP_DBG */
  187. /* Enqueue newly allocated tcpdata psh info elements to the pool */
  188. for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++)
  189. _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]);
  190. ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL);
  191. tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool;
  192. return BCME_OK;
  193. }
  194. static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp,
  195. tcpack_sup_module_t *tcpack_sup_mod)
  196. {
  197. uint i;
  198. tdata_psh_info_t *tdata_psh_info;
  199. DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__));
  200. if (tcpack_sup_mod == NULL) {
  201. DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n",
  202. __FUNCTION__, __LINE__));
  203. return;
  204. }
  205. for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) {
  206. tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i];
  207. /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */
  208. while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) {
  209. tcpdata_info->tdata_psh_info_head = tdata_psh_info->next;
  210. tdata_psh_info->next = NULL;
  211. _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info);
  212. }
  213. tcpdata_info->tdata_psh_info_tail = NULL;
  214. }
  215. #ifdef DHDTCPACK_SUP_DBG
  216. DHD_ERROR(("%s %d: PSH INFO ENQ %d\n",
  217. __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
  218. #endif /* DHDTCPACK_SUP_DBG */
  219. i = 0;
  220. /* Be sure we recollected all tdata_psh_info elements */
  221. while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) {
  222. tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next;
  223. tdata_psh_info->next = NULL;
  224. i++;
  225. }
  226. ASSERT(i == TCPDATA_PSH_INFO_MAXNUM);
  227. MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool,
  228. sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
  229. tcpack_sup_mod->tdata_psh_info_pool = NULL;
  230. return;
  231. }
  232. int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
  233. {
  234. int ret = BCME_OK;
  235. dhd_os_tcpacklock(dhdp);
  236. if (dhdp->tcpack_sup_mode == mode) {
  237. DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode));
  238. goto exit;
  239. }
  240. if (mode > TCPACK_SUP_DELAYTX) {
  241. DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode));
  242. ret = BCME_BADARG;
  243. goto exit;
  244. }
  245. DHD_TRACE(("%s: %d -> %d\n",
  246. __FUNCTION__, dhdp->tcpack_sup_mode, mode));
  247. /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */
  248. if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) {
  249. tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
  250. /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */
  251. _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod);
  252. tcpack_sup_mod->tcpdata_info_cnt = 0;
  253. bzero(tcpack_sup_mod->tcpdata_info_tbl,
  254. sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM);
  255. /* For half duplex bus interface, tx precedes rx by default */
  256. if (dhdp->bus)
  257. dhd_bus_set_dotxinrx(dhdp->bus, TRUE);
  258. }
  259. dhdp->tcpack_sup_mode = mode;
  260. if (mode == TCPACK_SUP_OFF) {
  261. ASSERT(dhdp->tcpack_sup_module != NULL);
  262. MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t));
  263. dhdp->tcpack_sup_module = NULL;
  264. goto exit;
  265. }
  266. if (dhdp->tcpack_sup_module == NULL) {
  267. tcpack_sup_module_t *tcpack_sup_mod =
  268. MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t));
  269. if (tcpack_sup_mod == NULL) {
  270. DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__));
  271. dhdp->tcpack_sup_mode = TCPACK_SUP_OFF;
  272. ret = BCME_NOMEM;
  273. goto exit;
  274. }
  275. bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t));
  276. dhdp->tcpack_sup_module = tcpack_sup_mod;
  277. }
  278. if (mode == TCPACK_SUP_DELAYTX) {
  279. ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module);
  280. if (ret != BCME_OK)
  281. DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret));
  282. else if (dhdp->bus)
  283. dhd_bus_set_dotxinrx(dhdp->bus, FALSE);
  284. }
  285. exit:
  286. dhd_os_tcpackunlock(dhdp);
  287. return ret;
  288. }
  289. void
  290. dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp)
  291. {
  292. tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
  293. if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
  294. goto exit;
  295. dhd_os_tcpacklock(dhdp);
  296. if (!tcpack_sup_mod) {
  297. DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
  298. __FUNCTION__, __LINE__));
  299. dhd_os_tcpackunlock(dhdp);
  300. goto exit;
  301. }
  302. tcpack_sup_mod->tcpack_info_cnt = 0;
  303. bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM);
  304. dhd_os_tcpackunlock(dhdp);
  305. exit:
  306. return;
  307. }
  308. inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
  309. {
  310. uint8 i;
  311. tcpack_sup_module_t *tcpack_sup_mod;
  312. tcpack_info_t *tcpack_info_tbl;
  313. int tbl_cnt;
  314. uint pushed_len;
  315. int ret = BCME_OK;
  316. void *pdata;
  317. uint32 pktlen;
  318. if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
  319. goto exit;
  320. pdata = PKTDATA(dhdp->osh, pkt);
  321. /* Length of BDC(+WLFC) headers pushed */
  322. pushed_len = BDC_HEADER_LEN + (((struct bdc_header *)pdata)->dataOffset * 4);
  323. pktlen = PKTLEN(dhdp->osh, pkt) - pushed_len;
  324. if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) {
  325. DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
  326. __FUNCTION__, __LINE__, pktlen));
  327. goto exit;
  328. }
  329. dhd_os_tcpacklock(dhdp);
  330. tcpack_sup_mod = dhdp->tcpack_sup_module;
  331. if (!tcpack_sup_mod) {
  332. DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
  333. ret = BCME_ERROR;
  334. dhd_os_tcpackunlock(dhdp);
  335. goto exit;
  336. }
  337. tbl_cnt = tcpack_sup_mod->tcpack_info_cnt;
  338. tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl;
  339. ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM);
  340. for (i = 0; i < tbl_cnt; i++) {
  341. if (tcpack_info_tbl[i].pkt_in_q == pkt) {
  342. DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n",
  343. __FUNCTION__, __LINE__, pkt, i, tbl_cnt));
  344. /* This pkt is being transmitted so remove the tcp_ack_info of it. */
  345. if (i < tbl_cnt - 1) {
  346. bcopy(&tcpack_info_tbl[tbl_cnt - 1],
  347. &tcpack_info_tbl[i], sizeof(tcpack_info_t));
  348. }
  349. bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t));
  350. if (--tcpack_sup_mod->tcpack_info_cnt < 0) {
  351. DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n",
  352. __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt));
  353. ret = BCME_ERROR;
  354. }
  355. break;
  356. }
  357. }
  358. dhd_os_tcpackunlock(dhdp);
  359. exit:
  360. return ret;
  361. }
  362. static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr,
  363. uint8 *tcp_hdr, uint32 tcp_ack_num)
  364. {
  365. tcpack_sup_module_t *tcpack_sup_mod;
  366. int i;
  367. tcpdata_info_t *tcpdata_info = NULL;
  368. tdata_psh_info_t *tdata_psh_info = NULL;
  369. bool ret = FALSE;
  370. if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX)
  371. goto exit;
  372. tcpack_sup_mod = dhdp->tcpack_sup_module;
  373. if (!tcpack_sup_mod) {
  374. DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
  375. goto exit;
  376. }
  377. DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
  378. " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__,
  379. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
  380. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
  381. ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
  382. ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]),
  383. tcp_ack_num));
  384. for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) {
  385. tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i];
  386. DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
  387. " TCP port %d %d\n", __FUNCTION__, __LINE__, i,
  388. IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->src_ip_addr)),
  389. IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->dst_ip_addr)),
  390. ntoh16_ua(tcpdata_info_tmp->src_tcp_port),
  391. ntoh16_ua(tcpdata_info_tmp->dst_tcp_port)));
  392. /* If either IP address or TCP port number does not match, skip. */
  393. if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET],
  394. tcpdata_info_tmp->dst_ip_addr, IPV4_ADDR_LEN) == 0 &&
  395. memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET],
  396. tcpdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN) == 0 &&
  397. memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET],
  398. tcpdata_info_tmp->dst_tcp_port, TCP_PORT_LEN) == 0 &&
  399. memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET],
  400. tcpdata_info_tmp->src_tcp_port, TCP_PORT_LEN) == 0) {
  401. tcpdata_info = tcpdata_info_tmp;
  402. break;
  403. }
  404. }
  405. if (tcpdata_info == NULL) {
  406. DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__));
  407. goto exit;
  408. }
  409. if (tcpdata_info->tdata_psh_info_head == NULL) {
  410. DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__));
  411. }
  412. while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) {
  413. if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) {
  414. DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n",
  415. __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq));
  416. tcpdata_info->tdata_psh_info_head = tdata_psh_info->next;
  417. tdata_psh_info->next = NULL;
  418. _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info);
  419. ret = TRUE;
  420. } else
  421. break;
  422. }
  423. if (tdata_psh_info == NULL)
  424. tcpdata_info->tdata_psh_info_tail = NULL;
  425. #ifdef DHDTCPACK_SUP_DBG
  426. DHD_TRACE(("%s %d: PSH INFO ENQ %d\n",
  427. __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
  428. #endif /* DHDTCPACK_SUP_DBG */
  429. exit:
  430. return ret;
  431. }
  432. bool
  433. dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
  434. {
  435. uint8 *new_ether_hdr; /* Ethernet header of the new packet */
  436. uint16 new_ether_type; /* Ethernet type of the new packet */
  437. uint8 *new_ip_hdr; /* IP header of the new packet */
  438. uint8 *new_tcp_hdr; /* TCP header of the new packet */
  439. uint32 new_ip_hdr_len; /* IP header length of the new packet */
  440. uint32 cur_framelen;
  441. uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */
  442. uint16 new_ip_total_len; /* Total length of IP packet for the new packet */
  443. uint32 new_tcp_hdr_len; /* TCP header length of the new packet */
  444. tcpack_sup_module_t *tcpack_sup_mod;
  445. tcpack_info_t *tcpack_info_tbl;
  446. int i;
  447. bool ret = FALSE;
  448. bool set_dotxinrx = TRUE;
  449. if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
  450. goto exit;
  451. new_ether_hdr = PKTDATA(dhdp->osh, pkt);
  452. cur_framelen = PKTLEN(dhdp->osh, pkt);
  453. if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) {
  454. DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
  455. __FUNCTION__, __LINE__, cur_framelen));
  456. goto exit;
  457. }
  458. new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13];
  459. if (new_ether_type != ETHER_TYPE_IP) {
  460. DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
  461. __FUNCTION__, __LINE__, new_ether_type));
  462. goto exit;
  463. }
  464. DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type));
  465. new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN;
  466. cur_framelen -= ETHER_HDR_LEN;
  467. ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
  468. new_ip_hdr_len = IPV4_HLEN(new_ip_hdr);
  469. if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) {
  470. DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
  471. __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr)));
  472. goto exit;
  473. }
  474. new_tcp_hdr = new_ip_hdr + new_ip_hdr_len;
  475. cur_framelen -= new_ip_hdr_len;
  476. ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
  477. DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));
  478. /* is it an ack ? Allow only ACK flag, not to suppress others. */
  479. if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) {
  480. DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n",
  481. __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET]));
  482. goto exit;
  483. }
  484. new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]);
  485. new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]);
  486. /* This packet has TCP data, so just send */
  487. if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) {
  488. DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__));
  489. goto exit;
  490. }
  491. ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len);
  492. new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]);
  493. DHD_TRACE(("%s %d: TCP ACK with zero DATA length"
  494. " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n",
  495. __FUNCTION__, __LINE__,
  496. IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])),
  497. IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])),
  498. ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]),
  499. ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET])));
  500. /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */
  501. dhd_os_tcpacklock(dhdp);
  502. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  503. counter_printlog(&tack_tbl);
  504. tack_tbl.cnt[0]++;
  505. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  506. tcpack_sup_mod = dhdp->tcpack_sup_module;
  507. tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl;
  508. if (!tcpack_sup_mod) {
  509. DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
  510. ret = BCME_ERROR;
  511. dhd_os_tcpackunlock(dhdp);
  512. goto exit;
  513. }
  514. if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) {
  515. /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */
  516. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  517. tack_tbl.cnt[5]++;
  518. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  519. } else
  520. set_dotxinrx = FALSE;
  521. for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) {
  522. void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */
  523. uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr;
  524. uint32 old_ip_hdr_len, old_tcp_hdr_len;
  525. uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */
  526. if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) {
  527. DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n",
  528. __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt));
  529. break;
  530. }
  531. if (PKTDATA(dhdp->osh, oldpkt) == NULL) {
  532. DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n",
  533. __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt));
  534. break;
  535. }
  536. old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr;
  537. old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN;
  538. old_ip_hdr_len = IPV4_HLEN(old_ip_hdr);
  539. old_tcp_hdr = old_ip_hdr + old_ip_hdr_len;
  540. old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]);
  541. DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
  542. " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i,
  543. IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])),
  544. IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])),
  545. ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]),
  546. ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET])));
  547. /* If either of IP address or TCP port number does not match, skip. */
  548. if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET],
  549. &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) ||
  550. memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET],
  551. &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2))
  552. continue;
  553. old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]);
  554. if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) {
  555. /* New packet has higher TCP ACK number, so it replaces the old packet */
  556. if (new_ip_hdr_len == old_ip_hdr_len &&
  557. new_tcp_hdr_len == old_tcp_hdr_len) {
  558. ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0);
  559. bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len);
  560. PKTFREE(dhdp->osh, pkt, FALSE);
  561. DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n",
  562. __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num));
  563. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  564. tack_tbl.cnt[2]++;
  565. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  566. ret = TRUE;
  567. } else
  568. DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d\n",
  569. __FUNCTION__, __LINE__, new_ip_hdr_len, old_ip_hdr_len,
  570. new_tcp_hdr_len, old_tcp_hdr_len));
  571. } else if (new_tcp_ack_num == old_tcpack_num) {
  572. set_dotxinrx = TRUE;
  573. /* TCPACK retransmission */
  574. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  575. tack_tbl.cnt[3]++;
  576. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  577. } else {
  578. DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n",
  579. __FUNCTION__, __LINE__, old_tcpack_num, oldpkt,
  580. new_tcp_ack_num, pkt));
  581. }
  582. dhd_os_tcpackunlock(dhdp);
  583. goto exit;
  584. }
  585. if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) {
  586. /* No TCPACK packet with the same IP addr and TCP port is found
  587. * in tcp_ack_info_tbl. So add this packet to the table.
  588. */
  589. DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
  590. __FUNCTION__, __LINE__, pkt, new_ether_hdr,
  591. tcpack_sup_mod->tcpack_info_cnt));
  592. tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt;
  593. tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr;
  594. tcpack_sup_mod->tcpack_info_cnt++;
  595. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  596. tack_tbl.cnt[1]++;
  597. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  598. } else {
  599. ASSERT(i == tcpack_sup_mod->tcpack_info_cnt);
  600. DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
  601. __FUNCTION__, __LINE__));
  602. }
  603. dhd_os_tcpackunlock(dhdp);
  604. exit:
  605. /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */
  606. if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx)
  607. dhd_bus_set_dotxinrx(dhdp->bus, TRUE);
  608. return ret;
  609. }
  610. bool
  611. dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt)
  612. {
  613. uint8 *ether_hdr; /* Ethernet header of the new packet */
  614. uint16 ether_type; /* Ethernet type of the new packet */
  615. uint8 *ip_hdr; /* IP header of the new packet */
  616. uint8 *tcp_hdr; /* TCP header of the new packet */
  617. uint32 ip_hdr_len; /* IP header length of the new packet */
  618. uint32 cur_framelen;
  619. uint16 ip_total_len; /* Total length of IP packet for the new packet */
  620. uint32 tcp_hdr_len; /* TCP header length of the new packet */
  621. uint32 tcp_seq_num; /* TCP sequence number of the new packet */
  622. uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */
  623. uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */
  624. tcpack_sup_module_t *tcpack_sup_mod;
  625. tcpdata_info_t *tcpdata_info = NULL;
  626. tdata_psh_info_t *tdata_psh_info;
  627. int i;
  628. bool ret = FALSE;
  629. if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX)
  630. goto exit;
  631. ether_hdr = PKTDATA(dhdp->osh, pkt);
  632. cur_framelen = PKTLEN(dhdp->osh, pkt);
  633. ether_type = ether_hdr[12] << 8 | ether_hdr[13];
  634. if (ether_type != ETHER_TYPE_IP) {
  635. DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
  636. __FUNCTION__, __LINE__, ether_type));
  637. goto exit;
  638. }
  639. DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type));
  640. ip_hdr = ether_hdr + ETHER_HDR_LEN;
  641. cur_framelen -= ETHER_HDR_LEN;
  642. ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
  643. ip_hdr_len = IPV4_HLEN(ip_hdr);
  644. if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) {
  645. DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
  646. __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr)));
  647. goto exit;
  648. }
  649. tcp_hdr = ip_hdr + ip_hdr_len;
  650. cur_framelen -= ip_hdr_len;
  651. ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
  652. DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));
  653. ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]);
  654. tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]);
  655. /* This packet is mere TCP ACK, so do nothing */
  656. if (ip_total_len == ip_hdr_len + tcp_hdr_len) {
  657. DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__));
  658. goto exit;
  659. }
  660. ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len);
  661. if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) {
  662. DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__));
  663. goto exit;
  664. }
  665. DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length"
  666. " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n",
  667. __FUNCTION__, __LINE__,
  668. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
  669. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
  670. ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
  671. ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]),
  672. tcp_hdr[TCP_FLAGS_OFFSET]));
  673. dhd_os_tcpacklock(dhdp);
  674. tcpack_sup_mod = dhdp->tcpack_sup_module;
  675. if (!tcpack_sup_mod) {
  676. DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
  677. ret = BCME_ERROR;
  678. dhd_os_tcpackunlock(dhdp);
  679. goto exit;
  680. }
  681. /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */
  682. i = 0;
  683. while (i < tcpack_sup_mod->tcpdata_info_cnt) {
  684. tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i];
  685. uint32 now_in_ms = OSL_SYSUPTIME();
  686. DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
  687. " TCP port %d %d\n", __FUNCTION__, __LINE__, i,
  688. IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->src_ip_addr)),
  689. IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->dst_ip_addr)),
  690. ntoh16_ua(tdata_info_tmp->src_tcp_port),
  691. ntoh16_ua(tdata_info_tmp->dst_tcp_port)));
  692. /* If both IP address and TCP port number match, we found it so break. */
  693. if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET],
  694. tdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN * 2) == 0 &&
  695. memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET],
  696. tdata_info_tmp->src_tcp_port, TCP_PORT_LEN * 2) == 0) {
  697. tcpdata_info = tdata_info_tmp;
  698. tcpdata_info->last_used_time = now_in_ms;
  699. break;
  700. }
  701. if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) {
  702. tdata_psh_info_t *tdata_psh_info_tmp;
  703. tcpdata_info_t *last_tdata_info;
  704. while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) {
  705. tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next;
  706. tdata_psh_info_tmp->next = NULL;
  707. DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n",
  708. __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq));
  709. _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp);
  710. }
  711. #ifdef DHDTCPACK_SUP_DBG
  712. DHD_ERROR(("%s %d: PSH INFO ENQ %d\n",
  713. __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
  714. #endif /* DHDTCPACK_SUP_DBG */
  715. tcpack_sup_mod->tcpdata_info_cnt--;
  716. ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0);
  717. last_tdata_info =
  718. &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt];
  719. if (i < tcpack_sup_mod->tcpdata_info_cnt) {
  720. ASSERT(last_tdata_info != tdata_info_tmp);
  721. bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t));
  722. }
  723. bzero(last_tdata_info, sizeof(tcpdata_info_t));
  724. DHD_INFO(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n",
  725. __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt));
  726. /* Don't increase "i" here, so that the prev last tcpdata_info is checked */
  727. } else
  728. i++;
  729. }
  730. tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]);
  731. tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len;
  732. end_tcp_seq_num = tcp_seq_num + tcp_data_len;
  733. if (tcpdata_info == NULL) {
  734. ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt);
  735. if (i >= TCPDATA_INFO_MAXNUM) {
  736. DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d"
  737. " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n",
  738. __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt,
  739. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
  740. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
  741. ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
  742. ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET])));
  743. dhd_os_tcpackunlock(dhdp);
  744. goto exit;
  745. }
  746. tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i];
  747. /* No TCP flow with the same IP addr and TCP port is found
  748. * in tcp_data_info_tbl. So add this flow to the table.
  749. */
  750. DHD_INFO(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
  751. " TCP port %d %d\n",
  752. __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt,
  753. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
  754. IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])),
  755. ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]),
  756. ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET])));
  757. bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], tcpdata_info->src_ip_addr,
  758. IPV4_ADDR_LEN * 2);
  759. bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], tcpdata_info->src_tcp_port,
  760. TCP_PORT_LEN * 2);
  761. tcpdata_info->last_used_time = OSL_SYSUPTIME();
  762. tcpack_sup_mod->tcpdata_info_cnt++;
  763. }
  764. ASSERT(tcpdata_info != NULL);
  765. tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod);
  766. #ifdef DHDTCPACK_SUP_DBG
  767. DHD_TRACE(("%s %d: PSH INFO ENQ %d\n",
  768. __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num));
  769. #endif /* DHDTCPACK_SUP_DBG */
  770. if (tdata_psh_info == NULL) {
  771. DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__));
  772. ret = BCME_ERROR;
  773. dhd_os_tcpackunlock(dhdp);
  774. goto exit;
  775. }
  776. tdata_psh_info->end_seq = end_tcp_seq_num;
  777. #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
  778. tack_tbl.cnt[4]++;
  779. #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
  780. DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n",
  781. __FUNCTION__, __LINE__, tdata_psh_info->end_seq));
  782. ASSERT(tdata_psh_info->next == NULL);
  783. if (tcpdata_info->tdata_psh_info_head == NULL)
  784. tcpdata_info->tdata_psh_info_head = tdata_psh_info;
  785. else {
  786. ASSERT(tcpdata_info->tdata_psh_info_tail);
  787. tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info;
  788. }
  789. tcpdata_info->tdata_psh_info_tail = tdata_psh_info;
  790. dhd_os_tcpackunlock(dhdp);
  791. exit:
  792. return ret;
  793. }
  794. #endif /* DHDTCPACK_SUPPRESS */