static int wifi_resume(struct platform_device *pdev) { DHD_TRACE(("##> %s\n", __FUNCTION__)); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 if (dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); #endif /* (OOB_INTR_ONLY) */ return 0; }
static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) { DHD_TRACE(("##> %s\n", __FUNCTION__)); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ defined(BCMSDIO) bcmsdh_oob_intr_set(0); #endif /* (OOB_INTR_ONLY) */ return 0; }
void *wifi_get_country_code(char *ccode) { DHD_TRACE(("%s\n", __FUNCTION__)); if (!ccode) return NULL; if (wifi_control_data && wifi_control_data->get_country_code) { return wifi_control_data->get_country_code(ccode); } return NULL; }
/* * channel list parsing from cscan tlv list */ int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, int channel_num, int *bytes_left) { char* str = *list_str; int idx = 0; if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); return -1; } while (*bytes_left > 0) { if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { *list_str = str; DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); return idx; } /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ *bytes_left -= 1; str += 1; if (str[0] == 0) { /* All channels */ channel_list[idx] = 0x0; } else { channel_list[idx] = (uint16)str[0]; DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); } *bytes_left -= 1; str += 1; if (idx++ > 255) { DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); return -1; } } *list_str = str; return idx; }
int dhd_check_module_mac(dhd_pub_t *dhd) { int ret = -1; unsigned char cis_buf[250] = {0}; unsigned char mac_buf[20] = {0}; unsigned char otp_mac_buf[20] = {0}; const char *macfilepath = MACINFO_EFS; /* Try reading out from CIS */ cis_rw_t *cish = (cis_rw_t *)&cis_buf[8]; struct file *fp_mac = NULL; cish->source = 0; cish->byteoff = 0; cish->nbytes = sizeof(cis_buf); strcpy(cis_buf, "cisdump"); ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, sizeof(cis_buf), 0, 0); if (ret < 0) { DHD_TRACE(("%s: CIS reading failed, err=%d\n", __func__, ret)); return ret; } else { unsigned char mac_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #ifdef DUMP_CIS dump_cis(cis_buf, 48); #endif mac_id[0] = cis_buf[CIS_MAC_OFFSET]; mac_id[1] = cis_buf[CIS_MAC_OFFSET + 1]; mac_id[2] = cis_buf[CIS_MAC_OFFSET + 2]; mac_id[3] = cis_buf[CIS_MAC_OFFSET + 3]; mac_id[4] = cis_buf[CIS_MAC_OFFSET + 4]; mac_id[5] = cis_buf[CIS_MAC_OFFSET + 5]; sprintf(otp_mac_buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", mac_id[0], mac_id[1], mac_id[2], mac_id[3], mac_id[4], mac_id[5]); DHD_ERROR(("[WIFI]mac_id is setted from OTP \n")); } fp_mac = filp_open(macfilepath, O_RDONLY, 0); if (!IS_ERR(fp_mac)) { DHD_ERROR(("[WIFI]Check Mac address in .mac.info \n")); kernel_read(fp_mac, fp_mac->f_pos, mac_buf, sizeof(mac_buf)); if (strncmp(mac_buf , otp_mac_buf , 17) != 0) { DHD_ERROR(("[WIFI]file MAC is wrong. Write OTP MAC in .mac.info \n")); dhd_write_mac_file(macfilepath, otp_mac_buf, sizeof(otp_mac_buf)); } } return ret; }
static int wifi_add_dev(void) { int ret; DHD_TRACE(("## Calling platform_driver_register\n")); ret = platform_driver_register(&wifi_device); if (ret) return ret; ret = platform_driver_register(&wifi_device_legacy); return ret; }
static int wifi_suspend(struct platform_device *pdev, pm_message_t state) { DHD_TRACE(("##> %s\n", __FUNCTION__)); #if defined(BCMHOST) if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) return -EBUSY; #endif #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1 bcmsdh_oob_intr_set(0); #endif /* (OOB_INTR_ONLY) */ return 0; }
static int dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, void *params, int plen, void *arg, int len, bool set) { int bcmerror = 0; int val_size; const bcm_iovar_t *vi = NULL; u32 actionid; DHD_TRACE(("%s: Enter\n", __func__)); ASSERT(name); ASSERT(len >= 0); /* Get MUST have return space */ ASSERT(set || (arg && len)); /* Set does NOT take qualifiers */ ASSERT(!set || (!params && !plen)); vi = bcm_iovar_lookup(dhd_iovars, name); if (vi == NULL) { bcmerror = -ENOTSUPP; goto exit; } DHD_CTL(("%s: %s %s, len %d plen %d\n", __func__, name, (set ? "set" : "get"), len, plen)); /* set up 'params' pointer in case this is a set command so that * the convenience int and bool code can be common to set and get */ if (params == NULL) { params = arg; plen = len; } if (vi->type == IOVT_VOID) val_size = 0; else if (vi->type == IOVT_BUFFER) val_size = len; else /* all other types are integer sized */ val_size = sizeof(int); actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); exit: return bcmerror; }
int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len) { dhd_prot_t *prot = dhd->prot; cdc_ioctl_t *msg = &prot->msg; int ret = 0; uint32 flags, id; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); if (prot == 0) { DHD_ERROR(("dhdcdc_set_ioctl: dhd->prot NULL. idx=%d, cmd=0x%x", ifidx, cmd)); goto done; } memset(msg, 0, sizeof(cdc_ioctl_t)); msg->cmd = htol32(cmd); msg->len = htol32(len); msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET; CDC_SET_IF_IDX(msg, ifidx); msg->flags |= htol32(msg->flags); if (buf) memcpy(prot->buf, buf, len); if ((ret = dhdcdc_msg(dhd)) < 0) goto done; if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) goto done; flags = ltoh32(msg->flags); id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; if (id != prot->reqid) { DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); ret = -EINVAL; goto done; } /* Check the ERROR flag */ if (flags & CDCF_IOC_ERROR) { ret = ltoh32(msg->status); /* Cache error from dongle */ dhd->dongle_error = ret; } done: return ret; }
void dhd_arp_offload_add_ip(dhd_pub_t *dhd, u32 ipaddr) { #ifdef ARP_OFFLOAD_SUPPORT int iov_len = 0; char iovbuf[32]; int retcode; dhd_os_proto_block(dhd); iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf)); retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len); dhd_os_proto_unblock(dhd); if (retcode) DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", __FUNCTION__, retcode)); else DHD_TRACE(("%s: ARP ipaddr entry added\n", __FUNCTION__)); #endif /* ARP_OFFLOAD_SUPPORT */ }
static int dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, void *params, int plen, void *arg, int len, bool set) { int bcmerror = 0; int val_size; const bcm_iovar_t *vi = NULL; uint32 actionid; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ASSERT(name); ASSERT(len >= 0); ASSERT(set || (arg && len)); ASSERT(!set || (!params && !plen)); if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { bcmerror = BCME_UNSUPPORTED; goto exit; } DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, name, (set ? "set" : "get"), len, plen)); if (params == NULL) { params = arg; plen = len; } if (vi->type == IOVT_VOID) val_size = 0; else if (vi->type == IOVT_BUFFER) val_size = len; else val_size = sizeof(int); actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); exit: return bcmerror; }
int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf) { #ifdef BDC struct bdc_header *h; #endif uint8 bdc_ver; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); #ifdef BDC /* Pop BDC header used to convey priority for buses that don't */ if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); return BCME_ERROR; } h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", __FUNCTION__, *ifidx)); return BCME_ERROR; } bdc_ver = (h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT; if ((bdc_ver != BDC_PROTO_VER) && (bdc_ver != 2)) { DHD_ERROR(("%s: non-BDC packet received, flags 0x%x, BDC %d\n", dhd_ifname(dhd, *ifidx), h->flags, bdc_ver)); return BCME_ERROR; } if (h->flags & BDC_FLAG_SUM_GOOD) { DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", dhd_ifname(dhd, *ifidx), h->flags)); PKTSETSUMGOOD(pktbuf, TRUE); } PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); #endif /* BDC */ return 0; }
static int dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) { int ret; dhd_prot_t *prot = dhd->prot; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); do { ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, len+sizeof(cdc_ioctl_t)); if (ret < 0) break; } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); return ret; }
/* * data parsing from ComboScan tlv list */ int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, int input_size, int *bytes_left) { char* str = *list_str; uint16 short_temp; uint32 int_temp; if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); return -1; } /* Clean all dest bytes */ memset(dst, 0, dst_size); while (*bytes_left > 0) { if (str[0] != token) { DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", __FUNCTION__, token, str[0], *bytes_left)); return -1; } *bytes_left -= 1; str += 1; if (input_size == 1) { memcpy(dst, str, input_size); } else if (input_size == 2) { memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), input_size); } else if (input_size == 4) { memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), input_size); } *bytes_left -= input_size; str += input_size; *list_str = str; return 1; } return 1; }
static int dhdcdc_msg(dhd_pub_t *dhd) { dhd_prot_t *prot = dhd->prot; int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); DHD_TRACE(("%s: Enter\n", __FUNCTION__)); /* NOTE : cdc->msg.len holds the desired length of the buffer to be * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area * is actually sent to the dongle */ if (len > CDC_MAX_MSG_SIZE) len = CDC_MAX_MSG_SIZE; /* Send request */ return dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); }
void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) { /* get_country_code was added after 2.6.39 */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) struct wifi_platform_data *plat_data; if (!ccode || !adapter || !adapter->wifi_plat_data) return NULL; plat_data = adapter->wifi_plat_data; DHD_TRACE(("%s\n", __FUNCTION__)); if (plat_data->get_country_code) { return plat_data->get_country_code(ccode); } #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ return NULL; }
wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) { int i; if (dhd_wifi_platdata == NULL) return NULL; for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && (adapter->bus_num == -1 || adapter->bus_num == bus_num) && (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { DHD_TRACE(("found adapter info '%s'\n", adapter->name)); return adapter; } } return NULL; }
static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, tcpack_sup_module_t *tcpack_sup_mod) { uint i; tdata_psh_info_t *tdata_psh_info; DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); if (tcpack_sup_mod == NULL) { DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", __FUNCTION__, __LINE__)); return; } for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; tdata_psh_info->next = NULL; _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); } tcpdata_info->tdata_psh_info_tail = NULL; } #ifdef DHDTCPACK_SUP_DBG DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); #endif /* DHDTCPACK_SUP_DBG */ i = 0; /* Be sure we recollected all tdata_psh_info elements */ while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; tdata_psh_info->next = NULL; i++; } ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); tcpack_sup_mod->tdata_psh_info_pool = NULL; return; }
void dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete) { iscan_buf_t *iscanbuf_free = 0; iscan_buf_t *iscanbuf_prv = 0; iscan_buf_t *iscanbuf_cur; dhd_pub_t *dhd = dhd_bus_pub(dhdp); DHD_TRACE(("%s: Entered\n", __FUNCTION__)); dhd_iscan_lock(); iscanbuf_cur = iscan_chain; /* If iscan_delete is null then delete the entire * chain or else delete specific one provided */ if (!iscan_delete) { while (iscanbuf_cur) { iscanbuf_free = iscanbuf_cur; iscanbuf_cur = iscanbuf_cur->next; iscanbuf_free->next = 0; MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t)); } iscan_chain = 0; } else { while (iscanbuf_cur) { if (iscanbuf_cur == iscan_delete) break; iscanbuf_prv = iscanbuf_cur; iscanbuf_cur = iscanbuf_cur->next; } if (iscanbuf_prv) iscanbuf_prv->next = iscan_delete->next; iscan_delete->next = 0; MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t)); if (!iscanbuf_prv) iscan_chain = 0; } dhd_iscan_unlock(); }
int wl_android_wifi_off(struct net_device *dev) { int ret = 0; if (!dev) { DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); return -EINVAL; } dhd_net_if_lock(dev); if (g_wifi_on) { dhd_dev_reset(dev, 1); sdioh_stop(NULL); dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); g_wifi_on = 0; } dhd_net_if_unlock(dev); return ret; }
/* * module init */ int sdio_function_init(void) { int error = 0; sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__)); gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL); if (!gInstance) return -ENOMEM; bzero(&sdmmc_dev, sizeof(sdmmc_dev)); error = sdio_register_driver(&bcmsdh_sdmmc_driver); #if defined(CONFIG_BRCM_LGE_WL_HOSTWAKEUP) if (!error) { dhd_register_early_suspend(); DHD_TRACE(("%s: registered with Android PM\n", __FUNCTION__)); } #endif /* defined(CONFIG_BRCM_LGE_WL_HOSTWAKEUP) */ return error; }
void dhd_late_resume(struct early_suspend *h) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) dhd_mmc_suspend = FALSE; #endif printk(KERN_ERR "%s: enter\n", __FUNCTION__); DHD_TRACE(("%s: enter\n", __FUNCTION__)); if(dhd_suspend_context == TRUE ){ disable_irq(dhd_wifi_sleep->host_wake_irq); /*Do the resume operations*/ dhd_resume(); }else printk("%s: Do not dhd_suspend mode setting.\n",__FUNCTION__); //#if defined(CONFIG_LGE_BCM432X_PATCH) && defined(PKT_FILTER_SUPPORT) #if 0 //hyeok-multi dhd_pkt_enable_filter(0, dhd_early_suspend_ctrl.bus); #endif /* CONFIG_LGE_BCM432X_PATCH */ return; }
int wl_android_wifi_off(struct net_device *dev) { int ret = 0; DHD_ERROR(("%s in\n", __FUNCTION__)); if (!dev) { DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); return -EINVAL; } dhd_net_if_lock(dev); if (g_wifi_on) { dhd_dev_reset(dev, 1); if (dhd_download_fw_on_driverload) msleep(100); sdioh_stop(NULL); dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); g_wifi_on = FALSE; } dhd_net_if_unlock(dev); return ret; }
int wl_android_wifi_off(struct net_device *dev) { int ret = 0; printk("%s in\n", __FUNCTION__); if (!dev) { DHD_TRACE(("%s: dev is null\n", __FUNCTION__)); return -EINVAL; } dhd_net_if_lock(dev); if (g_wifi_on) { #ifdef PROP_TXSTATUS dhd_wlfc_deinit(bcmsdh_get_drvdata()); #endif dhd_dev_reset(dev, 1); sdioh_stop(NULL); dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); g_wifi_on = FALSE; } dhd_net_if_unlock(dev); return ret; }
int wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata, wl_event_msg_t *event, void **data_ptr) { /* check whether packet is a BRCM event pkt */ bcm_event_t *pvt_data = (bcm_event_t *)pktdata; char *event_data; uint32 type, status; uint16 flags; int evlen; if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) return (BCME_ERROR); /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) return (BCME_ERROR); *data_ptr = &pvt_data[1]; event_data = *data_ptr; /* memcpy since BRCM event pkt may be unaligned. */ memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); type = ntoh32_ua((void *)&event->event_type); flags = ntoh16_ua((void *)&event->flags); status = ntoh32_ua((void *)&event->status); evlen = ntoh32_ua((void *)&event->datalen) + sizeof(bcm_event_t); switch (type) { case WLC_E_IF: { dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { if (ifevent->action == WLC_E_IF_ADD) dhd_add_if(dhd, ifevent->ifidx, NULL, event->ifname, pvt_data->eth.ether_dhost, ifevent->flags, ifevent->bssidx); else dhd_del_if(dhd, ifevent->ifidx); } else { DHD_ERROR(("%s: Invalid ifidx %d for %s\n", __FUNCTION__, ifevent->ifidx, event->ifname)); } } /* send up the if event: btamp user needs it */ *ifidx = dhd_ifname2idx(dhd, event->ifname); /* push up to external supp/auth */ dhd_event(dhd, (char *)pvt_data, evlen, *ifidx); break; /* fall through */ /* These are what external supplicant/authenticator wants */ case WLC_E_LINK: case WLC_E_ASSOC_IND: case WLC_E_REASSOC_IND: case WLC_E_DISASSOC_IND: case WLC_E_MIC_ERROR: default: /* Fall through: this should get _everything_ */ *ifidx = dhd_ifname2idx(dhd, event->ifname); /* push up to external supp/auth */ dhd_event(dhd, (char *)pvt_data, evlen, *ifidx); DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", __FUNCTION__, type, flags, status)); /* put it back to WLC_E_NDIS_LINK */ if (type == WLC_E_NDIS_LINK) { uint32 temp; temp = ntoh32_ua((void *)&event->event_type); DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); temp = ntoh32(WLC_E_NDIS_LINK); memcpy((void *)(&pvt_data->event.event_type), &temp, sizeof(pvt_data->event.event_type)); } break; } #ifdef SHOW_EVENTS wl_show_host_event(event, event_data); #endif /* SHOW_EVENTS */ return (BCME_OK); }
int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) { int bcmerror = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); switch (ioc->cmd) { case DHD_GET_MAGIC: if (buflen < sizeof(int)) bcmerror = BCME_BUFTOOSHORT; else *(int*)buf = DHD_IOCTL_MAGIC; break; case DHD_GET_VERSION: if (buflen < sizeof(int)) bcmerror = -BCME_BUFTOOSHORT; else *(int*)buf = DHD_IOCTL_VERSION; break; case DHD_GET_VAR: case DHD_SET_VAR: { char *arg; uint arglen; /* scan past the name to any arguments */ for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--); if (*arg) { bcmerror = BCME_BUFTOOSHORT; break; } /* account for the NUL terminator */ arg++, arglen--; /* call with the appropriate arguments */ if (ioc->cmd == DHD_GET_VAR) bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, buf, buflen, IOV_GET); else bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); if (bcmerror != BCME_UNSUPPORTED) break; /* not in generic table, try protocol module */ if (ioc->cmd == DHD_GET_VAR) bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, arglen, buf, buflen, IOV_GET); else bcmerror = dhd_prot_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); if (bcmerror != BCME_UNSUPPORTED) break; /* if still not found, try bus module */ if (ioc->cmd == DHD_GET_VAR) bcmerror = dhd_bus_iovar_op(dhd_pub, buf, arg, arglen, buf, buflen, IOV_GET); else bcmerror = dhd_bus_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); break; } default: bcmerror = BCME_UNSUPPORTED; } return bcmerror; }
static int dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, void *params, int plen, void *arg, int len, int val_size) { int bcmerror = 0; int32 int_val = 0; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) goto exit; if (plen >= (int)sizeof(int_val)) bcopy(params, &int_val, sizeof(int_val)); switch (actionid) { case IOV_GVAL(IOV_VERSION): /* Need to have checked buffer length */ strncpy((char*)arg, dhd_version, len); break; case IOV_GVAL(IOV_MSGLEVEL): int_val = (int32)dhd_msg_level; bcopy(&int_val, arg, val_size); break; case IOV_SVAL(IOV_MSGLEVEL): dhd_msg_level = int_val; break; case IOV_GVAL(IOV_BCMERRORSTR): strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); ((char *)arg)[BCME_STRLEN - 1] = 0x00; break; case IOV_GVAL(IOV_BCMERROR): int_val = (int32)dhd_pub->bcmerror; bcopy(&int_val, arg, val_size); break; case IOV_GVAL(IOV_WDTICK): int_val = (int32)dhd_watchdog_ms; bcopy(&int_val, arg, val_size); break; case IOV_SVAL(IOV_WDTICK): if (!dhd_pub->up) { bcmerror = BCME_NOTUP; break; } dhd_os_wd_timer(dhd_pub, (uint)int_val); break; case IOV_GVAL(IOV_DUMP): bcmerror = dhd_dump(dhd_pub, arg, len); break; case IOV_SVAL(IOV_CLEARCOUNTS): dhd_pub->tx_packets = dhd_pub->rx_packets = 0; dhd_pub->tx_errors = dhd_pub->rx_errors = 0; dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; dhd_pub->rx_dropped = 0; dhd_pub->rx_readahead_cnt = 0; dhd_pub->tx_realloc = 0; dhd_pub->rx_flushed = 0; memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); dhd_bus_clearcounts(dhd_pub); break; case IOV_GVAL(IOV_IOCTLTIMEOUT): { int_val = (int32)dhd_os_get_ioctl_resp_timeout(); bcopy(&int_val, arg, sizeof(int_val)); break; } case IOV_SVAL(IOV_IOCTLTIMEOUT): { if (int_val <= 0) bcmerror = BCME_BADARG; else dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); break; } default: bcmerror = BCME_UNSUPPORTED; break; } exit: return bcmerror; }
bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) { uint8 *ether_hdr; /* Ethernet header of the new packet */ uint16 ether_type; /* Ethernet type of the new packet */ uint8 *ip_hdr; /* IP header of the new packet */ uint8 *tcp_hdr; /* TCP header of the new packet */ uint32 ip_hdr_len; /* IP header length of the new packet */ uint32 cur_framelen; uint16 ip_total_len; /* Total length of IP packet for the new packet */ uint32 tcp_hdr_len; /* TCP header length of the new packet */ uint32 tcp_seq_num; /* TCP sequence number of the new packet */ uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ tcpack_sup_module_t *tcpack_sup_mod; tcpdata_info_t *tcpdata_info = NULL; tdata_psh_info_t *tdata_psh_info; int i; bool ret = FALSE; if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) goto exit; ether_hdr = PKTDATA(dhdp->osh, pkt); cur_framelen = PKTLEN(dhdp->osh, pkt); ether_type = ether_hdr[12] << 8 | ether_hdr[13]; if (ether_type != ETHER_TYPE_IP) { DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", __FUNCTION__, __LINE__, ether_type)); goto exit; } DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); ip_hdr = ether_hdr + ETHER_HDR_LEN; cur_framelen -= ETHER_HDR_LEN; ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); ip_hdr_len = IPV4_HLEN(ip_hdr); if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); goto exit; } tcp_hdr = ip_hdr + ip_hdr_len; cur_framelen -= ip_hdr_len; ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); /* This packet is mere TCP ACK, so do nothing */ if (ip_total_len == ip_hdr_len + tcp_hdr_len) { DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); goto exit; } ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); goto exit; } DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", __FUNCTION__, __LINE__, IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), tcp_hdr[TCP_FLAGS_OFFSET])); dhd_os_tcpacklock(dhdp); tcpack_sup_mod = dhdp->tcpack_sup_module; if (!tcpack_sup_mod) { DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ret = BCME_ERROR; dhd_os_tcpackunlock(dhdp); goto exit; } /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ i = 0; while (i < tcpack_sup_mod->tcpdata_info_cnt) { tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; uint32 now_in_ms = OSL_SYSUPTIME(); DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR " TCP port %d %d\n", __FUNCTION__, __LINE__, i, IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->src_ip_addr)), IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->dst_ip_addr)), ntoh16_ua(tdata_info_tmp->src_tcp_port), ntoh16_ua(tdata_info_tmp->dst_tcp_port))); /* If both IP address and TCP port number match, we found it so break. */ if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], tdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN * 2) == 0 && memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], tdata_info_tmp->src_tcp_port, TCP_PORT_LEN * 2) == 0) { tcpdata_info = tdata_info_tmp; tcpdata_info->last_used_time = now_in_ms; break; } if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { tdata_psh_info_t *tdata_psh_info_tmp; tcpdata_info_t *last_tdata_info; while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; tdata_psh_info_tmp->next = NULL; DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); } #ifdef DHDTCPACK_SUP_DBG DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); #endif /* DHDTCPACK_SUP_DBG */ tcpack_sup_mod->tcpdata_info_cnt--; ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); last_tdata_info = &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; if (i < tcpack_sup_mod->tcpdata_info_cnt) { ASSERT(last_tdata_info != tdata_info_tmp); bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); } bzero(last_tdata_info, sizeof(tcpdata_info_t)); DHD_TRACE(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ } else i++; } tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; end_tcp_seq_num = tcp_seq_num + tcp_data_len; if (tcpdata_info == NULL) { ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); if (i >= TCPDATA_INFO_MAXNUM) { DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); dhd_os_tcpackunlock(dhdp); goto exit; } tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; /* No TCP flow with the same IP addr and TCP port is found * in tcp_data_info_tbl. So add this flow to the table. */ DHD_TRACE(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR " TCP port %d %d\n", __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], tcpdata_info->src_ip_addr, IPV4_ADDR_LEN * 2); bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], tcpdata_info->src_tcp_port, TCP_PORT_LEN * 2); tcpdata_info->last_used_time = OSL_SYSUPTIME(); tcpack_sup_mod->tcpdata_info_cnt++; } ASSERT(tcpdata_info != NULL); tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); #ifdef DHDTCPACK_SUP_DBG DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); #endif /* DHDTCPACK_SUP_DBG */ if (tdata_psh_info == NULL) { DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); ret = BCME_ERROR; dhd_os_tcpackunlock(dhdp); goto exit; } tdata_psh_info->end_seq = end_tcp_seq_num; #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) tack_tbl.cnt[4]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); ASSERT(tdata_psh_info->next == NULL); if (tcpdata_info->tdata_psh_info_head == NULL) tcpdata_info->tdata_psh_info_head = tdata_psh_info; else { ASSERT(tcpdata_info->tdata_psh_info_tail); tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; } tcpdata_info->tdata_psh_info_tail = tdata_psh_info; dhd_os_tcpackunlock(dhdp); exit: return ret; }
bool dhd_tcpack_suppress(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; uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ tcpack_sup_module_t *tcpack_sup_mod; tcpack_info_t *tcpack_info_tbl; int i; bool ret = FALSE; bool set_dotxinrx = TRUE; if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) goto exit; new_ether_hdr = PKTDATA(dhdp->osh, pkt); cur_framelen = PKTLEN(dhdp->osh, pkt); if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", __FUNCTION__, __LINE__, cur_framelen)); goto exit; } new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; if (new_ether_type != ETHER_TYPE_IP) { DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); goto exit; } DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; cur_framelen -= ETHER_HDR_LEN; ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); goto exit; } new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; cur_framelen -= new_ip_hdr_len; ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); /* is it an ack ? Allow only ACK flag, not to suppress others. */ if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); goto exit; } new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); /* This packet has TCP data, so just send */ if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); goto exit; } ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); DHD_TRACE(("%s %d: TCP ACK with zero DATA length" " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", __FUNCTION__, __LINE__, IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ dhd_os_tcpacklock(dhdp); #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) counter_printlog(&tack_tbl); tack_tbl.cnt[0]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ tcpack_sup_mod = dhdp->tcpack_sup_module; tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; if (!tcpack_sup_mod) { DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); ret = BCME_ERROR; dhd_os_tcpackunlock(dhdp); goto exit; } if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) tack_tbl.cnt[5]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ } else set_dotxinrx = FALSE; for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; uint32 old_ip_hdr_len, old_tcp_hdr_len; uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); break; } if (PKTDATA(dhdp->osh, oldpkt) == NULL) { DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); break; } old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); /* If either of IP address or TCP port number does not match, skip. */ if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) continue; old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { /* New packet has higher TCP ACK number, so it replaces the old packet */ if (new_ip_hdr_len == old_ip_hdr_len && new_tcp_hdr_len == old_tcp_hdr_len) { ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); PKTFREE(dhdp->osh, pkt, FALSE); DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) tack_tbl.cnt[2]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ ret = TRUE; } else { #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) tack_tbl.cnt[6]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d" " ACK %u -> %u\n", __FUNCTION__, __LINE__, new_ip_hdr_len, old_ip_hdr_len, new_tcp_hdr_len, old_tcp_hdr_len, old_tcpack_num, new_tcp_ack_num)); } } else if (new_tcp_ack_num == old_tcpack_num) { set_dotxinrx = TRUE; /* TCPACK retransmission */ #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) tack_tbl.cnt[3]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ } else { DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, new_tcp_ack_num, pkt)); } dhd_os_tcpackunlock(dhdp); goto exit; } if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { /* No TCPACK packet with the same IP addr and TCP port is found * in tcp_ack_info_tbl. So add this packet to the table. */ DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", __FUNCTION__, __LINE__, pkt, new_ether_hdr, tcpack_sup_mod->tcpack_info_cnt)); tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; tcpack_sup_mod->tcpack_info_cnt++; #if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) tack_tbl.cnt[1]++; #endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ } else { ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", __FUNCTION__, __LINE__)); } dhd_os_tcpackunlock(dhdp); exit: /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) dhd_bus_set_dotxinrx(dhdp->bus, TRUE); return ret; }
static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, uint8 *tcp_hdr, uint32 tcp_ack_num) { tcpack_sup_module_t *tcpack_sup_mod; int i; tcpdata_info_t *tcpdata_info = NULL; tdata_psh_info_t *tdata_psh_info = NULL; bool ret = FALSE; if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) goto exit; tcpack_sup_mod = dhdp->tcpack_sup_module; if (!tcpack_sup_mod) { DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); goto exit; } DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), tcp_ack_num)); for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR " TCP port %d %d\n", __FUNCTION__, __LINE__, i, IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->src_ip_addr)), IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->dst_ip_addr)), ntoh16_ua(tcpdata_info_tmp->src_tcp_port), ntoh16_ua(tcpdata_info_tmp->dst_tcp_port))); /* If either IP address or TCP port number does not match, skip. */ if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], tcpdata_info_tmp->dst_ip_addr, IPV4_ADDR_LEN) == 0 && memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], tcpdata_info_tmp->src_ip_addr, IPV4_ADDR_LEN) == 0 && memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], tcpdata_info_tmp->dst_tcp_port, TCP_PORT_LEN) == 0 && memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], tcpdata_info_tmp->src_tcp_port, TCP_PORT_LEN) == 0) { tcpdata_info = tcpdata_info_tmp; break; } } if (tcpdata_info == NULL) { DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); goto exit; } if (tcpdata_info->tdata_psh_info_head == NULL) { DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); } while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; tdata_psh_info->next = NULL; _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); ret = TRUE; } else break; } if (tdata_psh_info == NULL) tcpdata_info->tdata_psh_info_tail = NULL; #ifdef DHDTCPACK_SUP_DBG DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); #endif /* DHDTCPACK_SUP_DBG */ exit: return ret; }