| /* |
| * Header file describing the BCOL TCPKA interfaces/public functions |
| * |
| * Provides type definitions and function prototypes used to link the |
| * DHD OS, bus, and protocol modules. |
| * |
| * Copyright (C) 1999-2017, Broadcom Corporation |
| * |
| * Unless you and Broadcom execute a separate written software license |
| * agreement governing use of this software, this software is licensed to you |
| * under the terms of the GNU General Public License version 2 (the "GPL"), |
| * available at http://www.broadcom.com/licenses/GPLv2.php, with the |
| * following added to such license: |
| * |
| * As a special exception, the copyright holders of this software give you |
| * permission to link this software with independent modules, and to copy and |
| * distribute the resulting executable under terms of your choice, provided that |
| * you also meet, for each linked independent module, the terms and conditions of |
| * the license of that module. An independent module is a module which is not |
| * derived from this software. The special exception does not apply to any |
| * modifications of the software. |
| * |
| * Notwithstanding the above, under no circumstances may you combine this |
| * software in any way with any other Broadcom software provided under a license |
| * other than the GPL, without Broadcom's express prior written consent. |
| * |
| * |
| * <<Broadcom-WL-IPTag/Open:>> |
| * |
| * $Id:$ |
| */ |
| |
| #ifndef _DHD_BCOL_TCPKA_PUB_ |
| #define _DHD_BCOL_TCPKA_PUB_ |
| |
| #include <typedefs.h> |
| #include <osl.h> |
| #include <dhd_bcol_tcpka.h> |
| #include <bcmtcp.h> |
| #include <dhd_ip.h> |
| #include <dhd.h> |
| |
| #ifdef TCPKA_DEBUG |
| #define DHD_TCPKA_INFO(x) printf x |
| #else |
| #define DHD_TCPKA_INFO(x) |
| #endif |
| |
| enum { |
| BCOL_TCPKA_SYNC_MODE_OFF = 0, |
| BCOL_TCPKA_SYNC_MODE_ON |
| }; |
| |
| enum { |
| BCOL_TCPKA_SYNC_STATE_NONE = 0, |
| BCOL_TCPKA_SYNC_STATE_TRAC, |
| BCOL_TCPKA_SYNC_STATE_READY, |
| BCOL_TCPKA_SYNC_STATE_BUSY, |
| BCOL_TCPKA_SYNC_STATE_DONE |
| }; |
| |
| typedef struct { |
| uint8 sess_id; |
| uint8 gpio_slot; |
| uint8 type; |
| uint16 len; |
| uint8 data[1]; |
| } tcpka_noti_cfg_t; |
| |
| #define TCPKA_NOTI_BLOCK_ALL -2 |
| |
| #ifdef TCPKA_DEBUG |
| static inline char * |
| dhd_bcol_ipv6_ntoa(uint8 *ia, char *buf) |
| { |
| snprintf(buf, 64, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" |
| "%02x%02x:%02x%02x:%02x%02x:%02x%02x", |
| ia[0], ia[1], ia[2], ia[3], ia[4], ia[5], ia[6], ia[7], |
| ia[8], ia[9], ia[10], ia[11], ia[12], ia[13], ia[14], ia[15]); |
| |
| return (buf); |
| } |
| |
| static inline void dhd_bcol_dump_tcpka6_conn(tcpka6_conn_t *tcpka) |
| { |
| uint8 ipbuf[64]; |
| printf("%s: dump %s:\n", __func__, CMD_STR_TCPKA6_CONN_ADD); |
| printf("sess_id=%d, dst_mac=%02x:%02x:%02x:%02x:%02x:%02x\n", tcpka->sess_id, |
| tcpka->dst_mac.octet[0], tcpka->dst_mac.octet[1], |
| tcpka->dst_mac.octet[2], tcpka->dst_mac.octet[3], |
| tcpka->dst_mac.octet[4], tcpka->dst_mac.octet[5]); |
| printf("srcip=%s dstip=%s", dhd_bcol_ipv6_ntoa((uint8 *)&tcpka->src_ip, ipbuf), |
| dhd_bcol_ipv6_ntoa((uint8 *)&tcpka->dst_ip, ipbuf)); |
| printf("srcport=%d, dstport=%d, seq=%u, ack=%u\n", |
| tcpka->srcport, tcpka->dstport, tcpka->seq, tcpka->ack); |
| printf("window=%u, tsval=%u, tsecr=%u, last_payload_len=%u\n", |
| tcpka->tcpwin, tcpka->tsval, tcpka->tsecr, tcpka->last_payload_len); |
| printf("ka_payload_len=%d\n", tcpka->ka_payload_len); |
| } |
| |
| static inline void dhd_bcol_dump_tcpka_conn(tcpka_conn_t *tcpka) |
| { |
| printf("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_ADD); |
| printf("sess_id=%d, dst_mac=%02x:%02x:%02x:%02x:%02x:%02x\n", tcpka->sess_id, |
| tcpka->dst_mac.octet[0], tcpka->dst_mac.octet[1], |
| tcpka->dst_mac.octet[2], tcpka->dst_mac.octet[3], |
| tcpka->dst_mac.octet[4], tcpka->dst_mac.octet[5]); |
| printf("ipid=%u, srcport=%d, dstport=%d, seq=%u, ack=%u\n", |
| tcpka->ipid, tcpka->srcport, tcpka->dstport, tcpka->seq, tcpka->ack); |
| printf("window=%u, tsval=%u, tsecr=%u, last_payload_len=%u\n", |
| tcpka->tcpwin, tcpka->tsval, tcpka->tsecr, tcpka->last_payload_len); |
| printf("ka_payload_len=%d\n", tcpka->ka_payload_len); |
| } |
| |
| static inline void dhd_bcol_dump_tcpka_conn_sess(tcpka_conn_sess_t *tcpka) |
| { |
| printf("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_EN); |
| printf("sess_id=%d, flag=%x\n", tcpka->sess_id, tcpka->flag); |
| if (tcpka->flag) { |
| printf("tcp keepalive timers:interval=%d\n", tcpka->tcp_keepalive_timers.interval); |
| printf("retry_interval=%d. retry_count=%d\n", |
| tcpka->tcp_keepalive_timers.retry_interval, |
| tcpka->tcp_keepalive_timers.retry_count); |
| } |
| } |
| #else |
| #define dhd_bcol_dump_tcpka_conn(x) |
| #define dhd_bcol_dump_tcpka6_conn(x) |
| #define dhd_bcol_dump_tcpka_conn_sess(x) |
| #endif /* TCPKA_DEBUG */ |
| |
| static inline int dhd_bcol_tcpka_check_xmit(dhd_pub_t *dhdp, void *pkt) |
| { |
| uint8 *new_ether_hdr; /* Ethernet header of the new packet */ |
| uint16 new_ether_type; /* Ethernet type of the new packet */ |
| uint8 *new_ip_hdr; /* IP header of the new packet */ |
| uint8 *new_tcp_hdr; /* TCP header of the new packet */ |
| uint32 new_ip_hdr_len; /* IP header length of the new packet */ |
| uint32 cur_framelen; |
| uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ |
| uint16 new_ip_payload_len; /* Total payload length of IPv6 packet for the new packet */ |
| uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ |
| uint32 tcp_option_len; |
| tcpka_conn_t *tcpka, tcpka_orig; |
| tcpka6_conn_t *tcpka6, tcpka6_orig; |
| struct tcphdr *tcph; /* TCP header */ |
| uint8 *payload; /* TCP data begin pointer */ |
| uint16 last_payload_len = 0; |
| |
| cur_framelen = PKTLEN(dhdp->osh, pkt); |
| |
| if (tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_OFF || |
| (!tcpka_sync.tcpka_conn && !tcpka_sync.tcpka6_conn)) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: mode %d, tcpka_conn %p, tcpka6_conn %p, cur_framelen %d\n", __func__, tcpka_sync.tcpka_sync_mode, tcpka_sync.tcpka_conn, tcpka_sync.tcpka6_conn, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| |
| /* config is going */ |
| if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_BUSY) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: sync state busy, cur_framelen: %d\n", __func__, cur_framelen)); |
| } |
| return BCME_BUSY; |
| } |
| |
| if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_NONE) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: sync_state %d, cur_framelen %d\n", __func__, tcpka_sync.tcpka_sync_state, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| |
| /* get the right tcpka_conn for IPv6 or IPv4 */ |
| if (tcpka_sync.sess_type) { |
| tcpka6 = tcpka_sync.tcpka6_conn; |
| if (!tcpka6 || !tcpka6->sess_id) { |
| DHD_ERROR(("%s: tcpka6 config has no vaild session id\n", __func__)); |
| return BCME_NOTREADY; |
| } |
| memcpy(&tcpka6_orig, tcpka6, sizeof(tcpka6_conn_t)); |
| } else { |
| tcpka = tcpka_sync.tcpka_conn; |
| if (!tcpka || !tcpka->sess_id) { |
| DHD_ERROR(("%s: tcpka config has no vaild session id\n", __func__)); |
| return BCME_NOTREADY; |
| } |
| memcpy(&tcpka_orig, tcpka, sizeof(tcpka_conn_t)); |
| } |
| |
| new_ether_hdr = PKTDATA(dhdp->osh, pkt); |
| if (cur_framelen < TCPACKSZMIN) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: cur_framelen: %d\n", __func__, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| |
| new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; |
| if ((new_ether_type != ETHER_TYPE_IP) && (new_ether_type != ETHER_TYPE_IPV6)) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: new_ether_type: %d, cur_framelen: %d\n", __func__, new_ether_type, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| |
| new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; |
| if (((IP_VER(new_ip_hdr) != IP_VER_4) || (IPV4_PROT(new_ip_hdr) != IP_PROT_TCP)) && |
| ((IP_VER(new_ip_hdr) != IP_VER_6) || (IPV6_PROT(new_ip_hdr) != IP_PROT_TCP))) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: wrong ip header, cur_framelen: %d\n", __func__, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| |
| new_tcp_hdr = (uint8 *)tcp_hdr((struct sk_buff *)pkt); |
| /* if session type is IPV4 and packet is IPv4 */ |
| if ((IP_VER(new_ip_hdr) == IP_VER_4) && (tcpka_sync.sess_type == 0)) { |
| new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); |
| #ifdef BCOL_TCPKA_SYNC_MATCHED_BY_PORT |
| /* If TCP port number does not match, skip. */ |
| if (tcpka->srcport == 0) { |
| /* skip the src port match */ |
| uint16 srcport = ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]); |
| uint16 dstport = ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]); |
| if (dstport != tcpka->dstport) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: wrong port dst(%d,%d), cur_framelen: %d\n", __func__, dstport, tcpka->dstport, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| tcpka->srcport = srcport; |
| } else { |
| uint16 srcport = ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]); |
| uint16 dstport = ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]); |
| if ((srcport != tcpka->srcport) || (dstport != tcpka->dstport)) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: wrong port src(%d, %d), dst(%d, %d), cur_framelen: %d\n", __func__, srcport, tcpka->srcport, dstport, tcpka->dstport, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| } |
| memcpy(tcpka->src_ip.addr, &new_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN); |
| memcpy(tcpka->dst_ip.addr, &new_ip_hdr[IPV4_DEST_IP_OFFSET], IPV4_ADDR_LEN); |
| #else |
| /* If either of IP address or TCP port number does not match, skip. */ |
| if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], tcpka->src_ip.addr, IPV4_ADDR_LEN) || |
| memcmp(&new_ip_hdr[IPV4_DEST_IP_OFFSET], tcpka->dst_ip.addr, IPV4_ADDR_LEN) || |
| (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->srcport) || |
| (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka->dstport)) { |
| return BCME_NOTFOUND; |
| } |
| #endif /* BCOL_TCPKA_SYNC_MATCHED_BY_PORT */ |
| /* update the destination mac */ |
| memcpy(tcpka->dst_mac.octet, new_ether_hdr, ETHER_ADDR_LEN); |
| /* update the ID of IP */ |
| tcpka->ipid = ntoh16_ua(&new_ip_hdr[IPV4_ID_OFFSET]); |
| |
| DHD_TCPKA_INFO(("%s: before\n", __func__)); |
| dhd_bcol_dump_tcpka_conn(tcpka); |
| |
| tcpka->seq = ntoh32_ua(&new_tcp_hdr[TCP_SEQ_NUM_OFFSET]); |
| tcpka->ack = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); |
| tcpka->tcpwin = ntoh16_ua(&new_tcp_hdr[TCP_WINDOW_OFFSET]); |
| #ifdef TCPKA_BYPASS |
| tcpka->bypass = TRUE; |
| #endif |
| } |
| else if ((IP_VER(new_ip_hdr) == IP_VER_6) && (tcpka_sync.sess_type == 1)) { |
| #ifdef BCOL_TCPKA_SYNC_MATCHED_BY_PORT |
| /* If TCP port number does not match, skip. */ |
| if (tcpka6->srcport == 0) { |
| /* skip the src port match */ |
| if ((ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka6->dstport)) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: %d, wrong port, cur_framelen: %d\n", __func__, __LINE__, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| tcpka6->srcport = ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]); |
| } else { |
| if ((ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka6->srcport) || |
| (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka6->dstport)) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: %d, wrong port, cur_framelen: %d\n", __func__, __LINE__, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| } |
| /* update the dst mac, src ip, dst ip */ |
| memcpy(tcpka6->src_ip, &new_ip_hdr[IPV6_SRC_IP_OFFSET], IPV6_ADDR_LEN); |
| memcpy(tcpka6->dst_ip, &new_ip_hdr[IPV6_DEST_IP_OFFSET], IPV6_ADDR_LEN); |
| #else |
| /* If either of IP address or TCP port number does not match, skip. */ |
| if (memcmp(&new_ip_hdr[IPV6_SRC_IP_OFFSET], tcpka6->src_ip, IPV6_ADDR_LEN) || |
| memcmp(&new_ip_hdr[IPV6_DEST_IP_OFFSET], tcpka6->dst_ip, IPV6_ADDR_LEN) || |
| (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka6->srcport) || |
| (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka6->dstport)) { |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: %d, wrong port, cur_framelen: %d\n", __func__, __LINE__, cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| #endif /* BCOL_TCPKA_SYNC_MATCHED_BY_PORT */ |
| memcpy(tcpka6->dst_mac.octet, new_ether_hdr, ETHER_ADDR_LEN); |
| |
| DHD_TCPKA_INFO(("%s: before\n", __func__)); |
| dhd_bcol_dump_tcpka6_conn(tcpka6); |
| |
| tcpka6->seq = ntoh32_ua(&new_tcp_hdr[TCP_SEQ_NUM_OFFSET]); |
| tcpka6->ack = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); |
| tcpka6->tcpwin = ntoh16_ua(&new_tcp_hdr[TCP_WINDOW_OFFSET]); |
| #ifdef TCPKA_BYPASS |
| tcpka6->bypass = TRUE; |
| #endif |
| } |
| else { |
| DHD_TCPKA_INFO(("%s: curr sess type %d, pkt type %d. Skip it.\n", __func__, |
| tcpka_sync.sess_type, IP_VER(new_ip_hdr))); |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: wrong pkt type %d, cur_framelen: %d\n", __func__, IP_VER(new_ip_hdr), cur_framelen)); |
| } |
| return BCME_NOTFOUND; |
| } |
| |
| new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); |
| |
| /* TCP options */ |
| tcp_option_len = new_tcp_hdr_len - TCP_MIN_HEADER_LEN; |
| if (tcp_option_len) { |
| uint8 *new_tcp_opt_hdr = new_tcp_hdr + TCP_MIN_HEADER_LEN; |
| uint32 i = 0; |
| uint8 kind, length; |
| bool opt_end = false; |
| |
| do { |
| kind = new_tcp_opt_hdr[i]; |
| i++; |
| |
| switch (kind) { |
| case 0: /* End of option list. */ |
| opt_end = true; |
| break; |
| case 1: /* No operation. */ |
| break; |
| case 8: /* Timestamp */ |
| length = new_tcp_opt_hdr[i]; |
| i++; |
| if (length != 10) { |
| DHD_ERROR(("%s: tcp opt timestamp has wrong length(%d).\n", |
| __func__, length)); |
| opt_end = true; |
| break; |
| } |
| if (tcpka_sync.sess_type == 0) { |
| tcpka->tsval = ntoh32_ua(&new_tcp_opt_hdr[i]); |
| i+=4; |
| tcpka->tsecr = ntoh32_ua(&new_tcp_opt_hdr[i]); |
| i+=4; |
| } |
| else if (tcpka_sync.sess_type == 1) { |
| tcpka6->tsval = ntoh32_ua(&new_tcp_opt_hdr[i]); |
| i+=4; |
| tcpka6->tsecr = ntoh32_ua(&new_tcp_opt_hdr[i]); |
| i+=4; |
| } |
| break; |
| default: /* just skip */ |
| length = new_tcp_opt_hdr[i]; |
| i = i + 1 + length; |
| break; |
| } |
| |
| if (opt_end) break; |
| } while(i < tcp_option_len); |
| } |
| |
| /* check the sess type for IPv4 or IPv6 and set the payload len */ |
| if (!tcpka_sync.sess_type) { |
| new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); |
| tcpka->last_payload_len = new_ip_total_len - (new_ip_hdr_len + new_tcp_hdr_len); |
| last_payload_len = tcpka->last_payload_len; |
| dhd_bcol_dump_tcpka_conn(tcpka); |
| } else if (tcpka_sync.sess_type) { |
| new_ip_payload_len = IPV6_PAYLOAD_LEN(new_ip_hdr); |
| tcpka6->last_payload_len = new_ip_payload_len - new_tcp_hdr_len; |
| last_payload_len = tcpka6->last_payload_len; |
| dhd_bcol_dump_tcpka6_conn(tcpka6); |
| } |
| DHD_TCPKA_INFO(("%s: last_payload_len %d\n", __func__, last_payload_len)); |
| |
| if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_DONE) { |
| /* free all packets from target session after sync done */ |
| DHD_ERROR(("%s: FREE post-sync packet, payload %d\n", __func__, last_payload_len)); |
| return BCME_BUSY; |
| } |
| |
| if (tcpka_sync.tcpka_noti_capture.type != -1) { |
| DHD_ERROR(("%s: got len %d v%s pkt, capture_type %d\n", |
| __func__, |
| last_payload_len, |
| tcpka_sync.sess_type ? "6" : "4", |
| tcpka_sync.tcpka_noti_capture.type)); |
| } |
| |
| if ((last_payload_len >= 2) && |
| (tcpka_sync.tcpka_noti_capture.min_len <= last_payload_len) && |
| (tcpka_sync.tcpka_noti_capture.max_len >= last_payload_len) && |
| (tcpka_sync.tcpka_noti_capture.type >= 0)) { |
| int buflen = 0; |
| tcpka_noti_cfg_t *np = NULL; |
| uint16 weave_pkt_len = 0; |
| |
| tcph = tcp_hdr((struct sk_buff *)pkt); |
| /* Find tcp payload */ |
| payload = (unsigned char *)((unsigned char *)tcph + (tcph->doff * 4)); |
| //prhex("TCPDATA", payload, last_payload_len); |
| |
| weave_pkt_len = *(uint16 *)payload; |
| DHD_ERROR(("%s: tcpka_noti, weave_pkt_len %d, payload_len %d\n", __func__, weave_pkt_len, last_payload_len)); |
| if ((weave_pkt_len + 2) != last_payload_len) { |
| /* This TCP segment is not complete weave msg */ |
| goto done; |
| } |
| buflen = sizeof(tcpka_noti_cfg_t) + last_payload_len - 1; |
| if (tcpka_sync.tcpka_noti_buf) { |
| MFREE(dhdp->osh, tcpka_sync.tcpka_noti_buf, |
| tcpka_sync.tcpka_noti_buf_len); |
| tcpka_sync.tcpka_noti_buf = NULL; |
| } |
| |
| if (tcpka_sync.tcpka_noti_buf == NULL) |
| tcpka_sync.tcpka_noti_buf_len = 0; |
| |
| if ((tcpka_sync.tcpka_noti_buf = |
| (unsigned char *)MALLOCZ(dhdp->osh, buflen)) != NULL) { |
| tcpka_sync.tcpka_noti_buf_len = buflen; |
| |
| np = (tcpka_noti_cfg_t *)tcpka_sync.tcpka_noti_buf; |
| memset(np, 0, buflen); |
| np->len = last_payload_len; |
| memcpy(np->data, payload, last_payload_len); |
| np->sess_id = TCPKA_DEFAULT_SESS_ID; |
| np->gpio_slot = 0; |
| np->type = tcpka_sync.tcpka_noti_capture.type; |
| DHD_ERROR(("%s: Captured tcpka_noti pyaload %d bytes\n", |
| __func__, last_payload_len)); |
| } else { |
| DHD_ERROR(("%s: Failed to allocate memory %d bytes " |
| "for tcpka noti buf\n", __func__, buflen)); |
| } |
| } |
| |
| done: |
| |
| if (tcpka_sync.tcpka_drop && last_payload_len > 0) { |
| DHD_ERROR(("%s: Free len %d v%s pkt\n", |
| __func__, last_payload_len, tcpka_sync.sess_type ? "6" : "4")); |
| if (tcpka_sync.sess_type) { |
| memcpy(tcpka6, &tcpka6_orig, sizeof(tcpka6_conn_t)); |
| } else { |
| memcpy(tcpka, &tcpka_orig, sizeof(tcpka_conn_t)); |
| } |
| return BCME_BUSY; |
| } |
| |
| tcpka_sync.tcpka_sync_state = BCOL_TCPKA_SYNC_STATE_READY; |
| tcpka_sync.tcpka_sk = ((struct sk_buff *)pkt)->sk; |
| |
| if (tcpka_sync.tcpka_drop) { |
| DHD_ERROR(("%s: packet sent, last_payload_len: %d\n", __func__, last_payload_len)); |
| } |
| return BCME_OK; |
| } |
| #endif /* _DHD_BCOL_TCPKA_PUB_ */ |