chan_freq_power_t * wlan_get_cfp_by_band_and_channel(pmlan_adapter pmadapter, t_u8 band, t_u16 channel, region_chan_t * region_channel) { region_chan_t *rc; chan_freq_power_t *cfp = MNULL; int i, j; ENTER(); for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) { rc = ®ion_channel[j]; if (!rc->valid || !rc->pcfp) continue; switch (rc->band) { case BAND_A: switch (band) { case BAND_AN: case BAND_A | BAND_AN: case BAND_A: /* Matching BAND_A */ break; default: continue; } break; case BAND_B: case BAND_G: switch (band) { case BAND_GN: case BAND_B | BAND_G | BAND_GN: case BAND_G | BAND_GN: case BAND_B | BAND_G: case BAND_B: /* Matching BAND_B/G */ case BAND_G: case 0: break; default: continue; } break; default: continue; } if (channel == FIRST_VALID_CHANNEL) cfp = &rc->pcfp[0]; else { for (i = 0; i < rc->num_cfp; i++) { if (rc->pcfp[i].channel == channel) { cfp = &rc->pcfp[i]; break; } } } } if (!cfp && channel) PRINTM(MCMND, "wlan_get_cfp_by_band_and_channel(): cannot find " "cfp by band %d & channel %d\n", band, channel); LEAVE(); return cfp; }
/** * @brief configure deep sleep * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req) { moal_private *priv = (moal_private *) netdev_priv(dev); mlan_ioctl_req *ioctl_req = NULL; mlan_ds_pm_cfg *pm = NULL; deep_sleep_para param; int ret = 0; ENTER(); memset(¶m, 0, sizeof(param)); /* Sanity check */ if (req->ifr_data == NULL) { PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n"); ret = -EFAULT; goto done; } if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *) & param, sizeof(param)); ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); if (ioctl_req == NULL) { LEAVE(); return -ENOMEM; } pm = (mlan_ds_pm_cfg *) ioctl_req->pbuf; pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP; ioctl_req->req_id = MLAN_IOCTL_PM_CFG; if (!param.action) { /* Get deep_sleep status from MLAN */ ioctl_req->action = MLAN_ACT_GET; } else { /* Set deep_sleep in MLAN */ ioctl_req->action = MLAN_ACT_SET; if (param.deep_sleep == MTRUE) { pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON; pm->param.auto_deep_sleep.idletime = param.idle_time; } else { pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF; } } if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { ret = -EFAULT; goto done; } if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) param.deep_sleep = MTRUE; else param.deep_sleep = MFALSE; param.idle_time = pm->param.auto_deep_sleep.idletime; /* Copy to user */ if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { PRINTM(MERROR, "Copy to user failed!\n"); ret = -EFAULT; goto done; } done: if (ioctl_req) kfree(ioctl_req); LEAVE(); return ret; }
/** * @brief uap power mode ioctl handler * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req) { moal_private *priv = (moal_private *) netdev_priv(dev); mlan_ioctl_req *ioctl_req = NULL; mlan_ds_pm_cfg *pm_cfg = NULL; mlan_ds_ps_mgmt ps_mgmt; int ret = 0; ENTER(); memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt)); /* Sanity check */ if (req->ifr_data == NULL) { PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n"); ret = -EFAULT; goto done; } if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } PRINTM(MIOCTL, "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d " "inact_to=%d min_awake=%d max_awake=%d\n", ps_mgmt.flags, (int) ps_mgmt.ps_mode, (int) ps_mgmt.sleep_param.ctrl_bitmap, (int) ps_mgmt.sleep_param.min_sleep, (int) ps_mgmt.sleep_param.max_sleep, (int) ps_mgmt.inact_param.inactivity_to, (int) ps_mgmt.inact_param.min_awake, (int) ps_mgmt.inact_param.max_awake); if (ps_mgmt. flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM | PS_FLAG_INACT_SLEEP_PARAM)) { PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n", ps_mgmt.flags); ret = -EINVAL; goto done; } if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) { PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n", (int) ps_mgmt.flags); ret = -EINVAL; goto done; } ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); if (ioctl_req == NULL) { ret = -ENOMEM; goto done; } pm_cfg = (mlan_ds_pm_cfg *) ioctl_req->pbuf; pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE; ioctl_req->req_id = MLAN_IOCTL_PM_CFG; if (ps_mgmt.flags) { ioctl_req->action = MLAN_ACT_SET; memcpy(&pm_cfg->param.ps_mgmt, &ps_mgmt, sizeof(mlan_ds_ps_mgmt)); } else { ioctl_req->action = MLAN_ACT_GET; } if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { ret = -EFAULT; if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32))) PRINTM(MERROR, "Copy to user failed!\n"); goto done; } if (!ps_mgmt.flags) { /* Copy to user */ if (copy_to_user (req->ifr_data, &pm_cfg->param.ps_mgmt, sizeof(mlan_ds_ps_mgmt))) { PRINTM(MERROR, "Copy to user failed!\n"); ret = -EFAULT; goto done; } } done: if (ioctl_req) kfree(ioctl_req); LEAVE(); return ret; }
/** * @brief This function generates domain_info from parsed_region_chan * * @param pmadapter Pointer to mlan_adapter structure * @param parsed_region_chan Pointer to parsed_region_chan_11d_t * * @return MLAN_STATUS_SUCCESS */ static mlan_status wlan_11d_generate_domain_info(pmlan_adapter pmadapter, parsed_region_chan_11d_t *parsed_region_chan) { t_u8 no_of_sub_band = 0; t_u8 no_of_chan = parsed_region_chan->no_of_chan; t_u8 no_of_parsed_chan = 0; t_u8 first_chan = 0, next_chan = 0, max_pwr = 0; t_u8 i, flag = MFALSE; wlan_802_11d_domain_reg_t *domain_info = &pmadapter->domain_reg; ENTER(); /* Should be only place that clear domain_reg (besides init) */ memset(pmadapter, domain_info, 0, sizeof(wlan_802_11d_domain_reg_t)); /* Set country code */ memcpy(pmadapter, domain_info->country_code, wlan_11d_code_2_region(pmadapter, (t_u8)pmadapter->region_code), COUNTRY_CODE_LEN); PRINTM(MINFO, "11D: Number of channel = %d\n", no_of_chan); HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan, sizeof(parsed_region_chan_11d_t)); /* Set channel and power */ for (i = 0; i < no_of_chan; i++) { if (!flag) { flag = MTRUE; next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan; max_pwr = parsed_region_chan->chan_pwr[i].pwr; no_of_parsed_chan = 1; continue; } if (parsed_region_chan->chan_pwr[i].chan == next_chan + 1 && parsed_region_chan->chan_pwr[i].pwr == max_pwr) { next_chan++; no_of_parsed_chan++; } else { domain_info->sub_band[no_of_sub_band].first_chan = first_chan; domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan; domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr; no_of_sub_band++; no_of_parsed_chan = 1; next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan; max_pwr = parsed_region_chan->chan_pwr[i].pwr; } } if (flag) { domain_info->sub_band[no_of_sub_band].first_chan = first_chan; domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan; domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr; no_of_sub_band++; } domain_info->no_of_sub_band = no_of_sub_band; PRINTM(MINFO, "11D: Number of sub-band =0x%x\n", domain_info->no_of_sub_band); HEXDUMP("11D: domain_info", (t_u8 *)domain_info, COUNTRY_CODE_LEN + 1 + sizeof(IEEEtypes_SubbandSet_t) * no_of_sub_band); LEAVE(); return MLAN_STATUS_SUCCESS; }
/** * @brief uap hs_cfg ioctl handler * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req) { moal_private *priv = (moal_private *) netdev_priv(dev); mlan_ds_hs_cfg hscfg; ds_hs_cfg hs_cfg; t_u16 action; int ret = 0; ENTER(); memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); memset(&hs_cfg, 0, sizeof(ds_hs_cfg)); /* Sanity check */ if (req->ifr_data == NULL) { PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n"); ret = -EFAULT; goto done; } if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } PRINTM(MIOCTL, "ioctl hscfg: flags=0x%lx condition=0x%lx gpio=%d gap=0x%lx\n", hs_cfg.flags, hs_cfg.conditions, (int) hs_cfg.gpio, hs_cfg.gap); if (hs_cfg.flags & HS_CFG_FLAG_SET) { action = MLAN_ACT_SET; if (hs_cfg.flags != HS_CFG_FLAG_ALL) { woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg); } if (hs_cfg.flags & HS_CFG_FLAG_CONDITION) hscfg.conditions = hs_cfg.conditions; if (hs_cfg.flags & HS_CFG_FLAG_GPIO) hscfg.gpio = hs_cfg.gpio; if (hs_cfg.flags & HS_CFG_FLAG_GAP) hscfg.gap = hs_cfg.gap; /* Issue IOCTL to set up parameters */ hscfg.is_invoke_hostcmd = MFALSE; if (MLAN_STATUS_SUCCESS != woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) { ret = -EFAULT; goto done; } } else { action = MLAN_ACT_GET; } /* Issue IOCTL to invoke hostcmd */ hscfg.is_invoke_hostcmd = MTRUE; if (MLAN_STATUS_SUCCESS != woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) { ret = -EFAULT; goto done; } if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) { hs_cfg.flags = HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO | HS_CFG_FLAG_GAP; hs_cfg.conditions = hscfg.conditions; hs_cfg.gpio = hscfg.gpio; hs_cfg.gap = hscfg.gap; /* Copy to user */ if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) { PRINTM(MERROR, "Copy to user failed!\n"); ret = -EFAULT; goto done; } } done: LEAVE(); return ret; }
/** * @brief This function handles disconnect event, reports disconnect * to upper layer, cleans tx/rx packets, * resets link state etc. * * @param priv A pointer to mlan_private structure * @param drv_disconnect Flag indicating the driver should disconnect * and flush pending packets. * * @return N/A */ t_void wlan_reset_connect_state(pmlan_private priv, t_u8 drv_disconnect) { mlan_adapter *pmadapter = priv->adapter; mlan_status ret = MLAN_STATUS_SUCCESS; state_11d_t enable; ENTER(); if (priv->media_connected != MTRUE) { LEAVE(); return; } PRINTM(MINFO, "Handles disconnect event.\n"); if (drv_disconnect) { priv->media_connected = MFALSE; wlan_11h_check_update_radar_det_state(priv); } if (priv->port_ctrl_mode == MTRUE) { /* Close the port on Disconnect */ PRINTM(MINFO, "DISC: port_status = CLOSED\n"); priv->port_open = MFALSE; } priv->scan_block = MFALSE; /* Reset SNR/NF/RSSI values */ priv->data_rssi_last = 0; priv->data_nf_last = 0; priv->data_rssi_avg = 0; priv->data_nf_avg = 0; priv->bcn_rssi_last = 0; priv->bcn_nf_last = 0; priv->bcn_rssi_avg = 0; priv->bcn_nf_avg = 0; priv->rxpd_rate = 0; priv->rxpd_htinfo = 0; priv->sec_info.ewpa_enabled = MFALSE; priv->sec_info.wpa_enabled = MFALSE; priv->sec_info.wpa2_enabled = MFALSE; priv->wpa_ie_len = 0; priv->sec_info.wapi_enabled = MFALSE; priv->wapi_ie_len = 0; priv->sec_info.wapi_key_on = MFALSE; priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE; /* Enable auto data rate */ priv->is_data_rate_auto = MTRUE; priv->data_rate = 0; if (priv->bss_mode == MLAN_BSS_MODE_IBSS) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = MFALSE; priv->intf_state_11h.adhoc_auto_sel_chan = MTRUE; } if (drv_disconnect) { /* Free Tx and Rx packets, report disconnect to upper layer */ wlan_clean_txrx(priv); /* Need to erase the current SSID and BSSID info */ memset(pmadapter, &priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); } pmadapter->tx_lock_flag = MFALSE; pmadapter->pps_uapsd_mode = MFALSE; if ((wlan_11d_is_enabled(priv)) && (priv->state_11d.user_enable_11d == DISABLE_11D)) { priv->state_11d.enable_11d = DISABLE_11D; enable = DISABLE_11D; /* Send cmd to FW to enable/disable 11D function */ ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, Dot11D_i, MNULL, &enable); if (ret) PRINTM(MERROR, "11D: Failed to enable 11D\n"); } if (pmadapter->num_cmd_timeout && pmadapter->curr_cmd && (pmadapter->cmd_timer_is_set == MFALSE)) { LEAVE(); return; } wlan_recv_event(priv, MLAN_EVENT_ID_FW_DISCONNECTED, MNULL); LEAVE(); }
/** * @brief This function generates 11D info from user specified regioncode * and download to FW * * @param pmpriv A pointer to mlan_private structure * @param band Band to create * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_11d_create_dnld_countryinfo(mlan_private *pmpriv, t_u8 band) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = pmpriv->adapter; region_chan_t *region_chan; parsed_region_chan_11d_t parsed_region_chan; t_u8 j; ENTER(); /* Only valid if 11D is enabled */ if (wlan_11d_is_enabled(pmpriv)) { PRINTM(MINFO, "11D: Band[%d]\n", band); /* Update parsed_region_chan; download domain info to FW */ /* Find region channel */ for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) { region_chan = &pmadapter->region_channel[j]; PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j, region_chan->band); if (!region_chan || !region_chan->valid || !region_chan->pcfp) continue; switch (region_chan->band) { case BAND_A: switch (band) { case BAND_A: case BAND_AN: case BAND_A | BAND_AN: case BAND_A | BAND_AN | BAND_AAC: break; default: continue; } break; case BAND_B: case BAND_G: switch (band) { case BAND_B: case BAND_G: case BAND_G | BAND_B: case BAND_GN: case BAND_G | BAND_GN: case BAND_B | BAND_G | BAND_GN: case BAND_B | BAND_G | BAND_GN | BAND_GAC: break; default: continue; } break; default: continue; } break; } /* Check if region channel found */ if (j >= MAX_REGION_CHANNEL_NUM) { PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n", band); LEAVE(); return MLAN_STATUS_FAILURE; } /* Generate parsed region channel info from region channel */ memset(pmadapter, &parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t)); wlan_11d_generate_parsed_region_chan(pmadapter, region_chan, &parsed_region_chan); /* Generate domain info from parsed region channel info */ wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan); /* Set domain info */ ret = wlan_11d_send_domain_info(pmpriv, MNULL); if (ret) { PRINTM(MERROR, "11D: Error sending domain info to FW\n"); } } LEAVE(); return ret; }
/** @brief This function handles client driver suspend * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ int woal_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); mmc_pm_flag_t pm_flags = 0; moal_handle *handle = NULL; struct sdio_mmc_card *cardp; int i; int ret = MLAN_STATUS_SUCCESS; int hs_actived = 0; mlan_ds_ps_info pm_info; ENTER(); PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n"); if (func) { pm_flags = sdio_get_host_pm_caps(func); PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), pm_flags); if (!(pm_flags & MMC_PM_KEEP_POWER)) { PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n", sdio_func_id(func)); LEAVE(); return -ENOSYS; } cardp = sdio_get_drvdata(func); if (!cardp || !cardp->handle) { PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } } else { PRINTM(MERROR, "sdio_func is not specified\n"); LEAVE(); return MLAN_STATUS_SUCCESS; } handle = cardp->handle; handle->suspend_fail = MFALSE; memset(&pm_info, 0, sizeof(pm_info)); if (MLAN_STATUS_SUCCESS == woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), &pm_info)) { if (pm_info.is_suspend_allowed == MFALSE) { PRINTM(MCMND, "suspend not allowed!"); ret = -EBUSY; goto done; } } for (i = 0; i < handle->priv_num; i++) netif_device_detach(handle->priv[i]->netdev); if (pm_keep_power) { /* Enable the Host Sleep */ #ifdef MMC_PM_FUNC_SUSPENDED handle->suspend_notify_req = MTRUE; #endif hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY)); #ifdef MMC_PM_FUNC_SUSPENDED handle->suspend_notify_req = MFALSE; #endif if (hs_actived) { #ifdef MMC_PM_SKIP_RESUME_PROBE PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER and " "MMC_PM_SKIP_RESUME_PROBE\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER | MMC_PM_SKIP_RESUME_PROBE); #else PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n"); ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); #endif } else { PRINTM(MCMND, "HS not actived, suspend fail!"); ret = -EBUSY; goto done; } } /* Indicate device suspended */ handle->is_suspended = MTRUE; done: PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n"); LEAVE(); return ret; }
/** * @brief This function tells firmware to send a NULL data packet. * * @param priv A pointer to mlan_private structure * @param flags Transmit Pkt Flags * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise failure */ mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags) { pmlan_adapter pmadapter = priv->adapter; TxPD *ptx_pd; /* sizeof(TxPD) + Interface specific header */ #define NULL_PACKET_HDR 256 t_u32 data_len = NULL_PACKET_HDR; pmlan_buffer pmbuf = MNULL; t_u8 *ptr; mlan_status ret = MLAN_STATUS_SUCCESS; #ifdef DEBUG_LEVEL1 t_u32 sec, usec; #endif ENTER(); if (pmadapter->surprise_removed == MTRUE) { ret = MLAN_STATUS_FAILURE; goto done; } if (priv->media_connected == MFALSE) { ret = MLAN_STATUS_FAILURE; goto done; } if (pmadapter->data_sent == MTRUE) { ret = MLAN_STATUS_FAILURE; goto done; } pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0, MOAL_MALLOC_BUFFER); if (!pmbuf) { ret = MLAN_STATUS_FAILURE; goto done; } memset(pmadapter, pmbuf->pbuf, 0, data_len); pmbuf->bss_index = priv->bss_index; pmbuf->buf_type = MLAN_BUF_TYPE_DATA; ptr = pmbuf->pbuf + pmbuf->data_offset; pmbuf->data_len = sizeof(TxPD) + INTF_HEADER_LEN; ptx_pd = (TxPD *) (ptr + INTF_HEADER_LEN); ptx_pd->tx_control = priv->pkt_tx_ctrl; ptx_pd->flags = flags; ptx_pd->priority = WMM_HIGHEST_PRIORITY; ptx_pd->tx_pkt_offset = sizeof(TxPD); /* Set the BSS number to TxPD */ ptx_pd->bss_num = GET_BSS_NUM(priv); ptx_pd->bss_type = priv->bss_type; endian_convert_TxPD(ptx_pd); ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf, MNULL); switch (ret) { case MLAN_STATUS_RESOURCE: wlan_free_mlan_buffer(pmadapter, pmbuf); PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n"); pmadapter->dbg.num_tx_host_to_card_failure++; goto done; case MLAN_STATUS_FAILURE: pmadapter->data_sent = MFALSE; wlan_free_mlan_buffer(pmadapter, pmbuf); PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n"); pmadapter->dbg.num_tx_host_to_card_failure++; goto done; case MLAN_STATUS_SUCCESS: wlan_free_mlan_buffer(pmadapter, pmbuf); PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n"); pmadapter->tx_lock_flag = MTRUE; break; case MLAN_STATUS_PENDING: pmadapter->data_sent = MFALSE; pmadapter->tx_lock_flag = MTRUE; break; default: break; } PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec); DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + INTF_HEADER_LEN); done: LEAVE(); return ret; }
/** * @brief Debug print display of the input measurement report * * @param pmeas_rpt Pointer to measurement report to display * * @return N/A */ static void wlan_meas_dump_meas_rpt(const HostCmd_DS_MEASUREMENT_REPORT *pmeas_rpt) { ENTER(); PRINTM(MINFO, "Meas: Rpt: ------------------------------\n"); PRINTM(MINFO, "Meas: Rpt: mac_addr: " MACSTR "\n", MAC2STR(pmeas_rpt->mac_addr)); PRINTM(MINFO, "Meas: Rpt: dlgTkn: %d\n", pmeas_rpt->dialog_token); PRINTM(MINFO, "Meas: Rpt: rptMode: (%x): Rfs[%c] ICp[%c] Lt[%c]\n", *(t_u8 *)&pmeas_rpt->rpt_mode, pmeas_rpt->rpt_mode.refused ? 'X' : ' ', pmeas_rpt->rpt_mode.incapable ? 'X' : ' ', pmeas_rpt->rpt_mode.late ? 'X' : ' '); #ifdef DEBUG_LEVEL2 PRINTM(MINFO, "Meas: Rpt: measTyp: %s\n", wlan_meas_get_meas_type_str(pmeas_rpt->meas_type)); #endif switch (pmeas_rpt->meas_type) { case WLAN_MEAS_BASIC: PRINTM(MINFO, "Meas: Rpt: chan: %u\n", pmeas_rpt->rpt.basic.channel); PRINTM(MINFO, "Meas: Rpt: strt: %llu\n", wlan_le64_to_cpu(pmeas_rpt->rpt.basic.start_time)); PRINTM(MINFO, "Meas: Rpt: dur: %u\n", wlan_le16_to_cpu(pmeas_rpt->rpt.basic.duration)); PRINTM(MINFO, "Meas: Rpt: bas: (%x): unmsd[%c], radar[%c]\n", *(t_u8 *)&(pmeas_rpt->rpt.basic.map), pmeas_rpt->rpt.basic.map.unmeasured ? 'X' : ' ', pmeas_rpt->rpt.basic.map.radar ? 'X' : ' '); PRINTM(MINFO, "Meas: Rpt: bas: unidSig[%c] ofdm[%c] bss[%c]\n", pmeas_rpt->rpt.basic.map.unidentified_sig ? 'X' : ' ', pmeas_rpt->rpt.basic.map.ofdm_preamble ? 'X' : ' ', pmeas_rpt->rpt.basic.map.bss ? 'X' : ' '); break; default: PRINTM(MINFO, "Meas: Rpt: <unhandled>\n"); break; } PRINTM(MINFO, "Meas: Rpt: ------------------------------\n"); LEAVE(); }
/** * @brief Debug print display of the input measurement request * * @param pmeas_req Pointer to the measurement request to display * * @return N/A */ static void wlan_meas_dump_meas_req(const HostCmd_DS_MEASUREMENT_REQUEST *pmeas_req) { ENTER(); PRINTM(MINFO, "Meas: Req: ------------------------------\n"); PRINTM(MINFO, "Meas: Req: mac_addr: " MACSTR "\n", MAC2STR(pmeas_req->mac_addr)); PRINTM(MINFO, "Meas: Req: dlgTkn: %d\n", pmeas_req->dialog_token); PRINTM(MINFO, "Meas: Req: mode: dm[%c] rpt[%c] req[%c]\n", pmeas_req->req_mode.duration_mandatory ? 'X' : ' ', pmeas_req->req_mode.report ? 'X' : ' ', pmeas_req->req_mode.request ? 'X' : ' '); PRINTM(MINFO, "Meas: Req: : en[%c] par[%c]\n", pmeas_req->req_mode.enable ? 'X' : ' ', pmeas_req->req_mode.parallel ? 'X' : ' '); #ifdef DEBUG_LEVEL2 PRINTM(MINFO, "Meas: Req: measTyp: %s\n", wlan_meas_get_meas_type_str(pmeas_req->meas_type)); #endif switch (pmeas_req->meas_type) { case WLAN_MEAS_BASIC: /* Lazy cheat, fields of bas, cca, rpi union match on the request */ PRINTM(MINFO, "Meas: Req: chan: %u\n", pmeas_req->req.basic.channel); PRINTM(MINFO, "Meas: Req: strt: %llu\n", wlan_le64_to_cpu(pmeas_req->req.basic.start_time)); PRINTM(MINFO, "Meas: Req: dur: %u\n", wlan_le16_to_cpu(pmeas_req->req.basic.duration)); break; default: PRINTM(MINFO, "Meas: Req: <unhandled>\n"); break; } PRINTM(MINFO, "Meas: Req: ------------------------------\n"); LEAVE(); }
/** * @brief This function sets region table. * * @param pmpriv A pointer to mlan_private structure * @param region The region code * @param band The band * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_set_regiontable(mlan_private * pmpriv, t_u8 region, t_u8 band) { mlan_adapter *pmadapter = pmpriv->adapter; int i = 0, j; chan_freq_power_t *cfp; int cfp_no; region_chan_t region_chan_old[MAX_REGION_CHANNEL_NUM]; ENTER(); memcpy(pmadapter, region_chan_old, pmadapter->region_channel, sizeof(pmadapter->region_channel)); memset(pmadapter, pmadapter->region_channel, 0, sizeof(pmadapter->region_channel)); if (band & (BAND_B | BAND_G | BAND_GN)) { cfp = wlan_get_region_cfp_table(pmadapter, region, BAND_G | BAND_B | BAND_GN, &cfp_no); if (cfp) { pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no; pmadapter->region_channel[i].pcfp = cfp; } else { PRINTM(MERROR, "wrong region code %#x in Band B-G\n", region); LEAVE(); return MLAN_STATUS_FAILURE; } pmadapter->region_channel[i].valid = MTRUE; pmadapter->region_channel[i].region = region; if (band & BAND_GN) pmadapter->region_channel[i].band = BAND_G; else pmadapter->region_channel[i].band = (band & BAND_G) ? BAND_G : BAND_B; for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) { if (region_chan_old[j].band & (BAND_B | BAND_G)) break; } if ((j < MAX_REGION_CHANNEL_NUM) && region_chan_old[j].valid) wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no, region_chan_old[j].pcfp, region_chan_old[j].num_cfp); else wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no, MNULL, 0); i++; } if (band & (BAND_A | BAND_AN)) { cfp = wlan_get_region_cfp_table(pmadapter, region, BAND_A, &cfp_no); if (cfp) { pmadapter->region_channel[i].num_cfp = (t_u8) cfp_no; pmadapter->region_channel[i].pcfp = cfp; } else { PRINTM(MERROR, "wrong region code %#x in Band A\n", region); LEAVE(); return MLAN_STATUS_FAILURE; } pmadapter->region_channel[i].valid = MTRUE; pmadapter->region_channel[i].region = region; pmadapter->region_channel[i].band = BAND_A; for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++) { if (region_chan_old[j].band & BAND_A) break; } if ((j < MAX_REGION_CHANNEL_NUM) && region_chan_old[j].valid) wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no, region_chan_old[j].pcfp, region_chan_old[j].num_cfp); else wlan_cfp_copy_dynamic(pmadapter, cfp, cfp_no, MNULL, 0); } LEAVE(); return MLAN_STATUS_SUCCESS; }
/** * @brief Get supported data rates * * @param pmpriv A pointer to mlan_private structure * @param bss_mode The specified BSS mode (Infra/IBSS) * @param config_bands The specified band configuration * @param rates The buf to return the supported rates * * @return The number of Rates */ t_u32 wlan_get_supported_rates(mlan_private * pmpriv, t_u32 bss_mode, t_u8 config_bands, WLAN_802_11_RATES rates) { t_u32 k = 0; ENTER(); if (bss_mode == MLAN_BSS_MODE_INFRA) { /* Infra. mode */ switch (config_bands) { case BAND_B: PRINTM(MINFO, "Infra Band=%d SupportedRates_B\n", config_bands); k = wlan_copy_rates(rates, k, SupportedRates_B, sizeof(SupportedRates_B)); break; case BAND_G: case BAND_G | BAND_GN: PRINTM(MINFO, "Infra band=%d SupportedRates_G\n", config_bands); k = wlan_copy_rates(rates, k, SupportedRates_G, sizeof(SupportedRates_G)); break; case BAND_B | BAND_G: case BAND_A | BAND_B | BAND_G: case BAND_A | BAND_B: case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN: case BAND_B | BAND_G | BAND_GN: PRINTM(MINFO, "Infra band=%d SupportedRates_BG\n", config_bands); #ifdef WIFI_DIRECT_SUPPORT if (pmpriv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) k = wlan_copy_rates(rates, k, SupportedRates_G, sizeof(SupportedRates_G)); else k = wlan_copy_rates(rates, k, SupportedRates_BG, sizeof(SupportedRates_BG)); #else k = wlan_copy_rates(rates, k, SupportedRates_BG, sizeof(SupportedRates_BG)); #endif break; case BAND_A: case BAND_A | BAND_G: PRINTM(MINFO, "Infra band=%d SupportedRates_A\n", config_bands); k = wlan_copy_rates(rates, k, SupportedRates_A, sizeof(SupportedRates_A)); break; case BAND_AN: case BAND_A | BAND_AN: case BAND_A | BAND_G | BAND_AN | BAND_GN: PRINTM(MINFO, "Infra band=%d SupportedRates_A\n", config_bands); k = wlan_copy_rates(rates, k, SupportedRates_A, sizeof(SupportedRates_A)); break; case BAND_GN: PRINTM(MINFO, "Infra band=%d SupportedRates_N\n", config_bands); k = wlan_copy_rates(rates, k, SupportedRates_N, sizeof(SupportedRates_N)); break; } } else { /* Ad-hoc mode */ switch (config_bands) { case BAND_B: PRINTM(MINFO, "Band: Adhoc B\n"); k = wlan_copy_rates(rates, k, AdhocRates_B, sizeof(AdhocRates_B)); break; case BAND_G: case BAND_G | BAND_GN: PRINTM(MINFO, "Band: Adhoc G only\n"); k = wlan_copy_rates(rates, k, AdhocRates_G, sizeof(AdhocRates_G)); break; case BAND_B | BAND_G: case BAND_B | BAND_G | BAND_GN: PRINTM(MINFO, "Band: Adhoc BG\n"); k = wlan_copy_rates(rates, k, AdhocRates_BG, sizeof(AdhocRates_BG)); break; case BAND_A: case BAND_AN: case BAND_A | BAND_AN: PRINTM(MINFO, "Band: Adhoc A\n"); k = wlan_copy_rates(rates, k, AdhocRates_A, sizeof(AdhocRates_A)); break; } } LEAVE(); return k; }
/** * @brief Find the channel frequency power info for a specific frequency * * @param pmadapter A pointer to mlan_adapter structure * @param band It can be BAND_A, BAND_G or BAND_B * @param freq The frequency to search for * * @return Pointer to chan_freq_power_t structure; MNULL if not found */ chan_freq_power_t * wlan_find_cfp_by_band_and_freq(mlan_adapter * pmadapter, t_u8 band, t_u32 freq) { chan_freq_power_t *cfp = MNULL; region_chan_t *rc; int i, j; ENTER(); for (j = 0; !cfp && (j < MAX_REGION_CHANNEL_NUM); j++) { rc = &pmadapter->region_channel[j]; /* Any station(s) with 11D enabled */ if (wlan_count_priv_cond(pmadapter, wlan_11d_is_enabled, wlan_is_station) > 0) rc = &pmadapter->universal_channel[j]; if (!rc->valid || !rc->pcfp) continue; switch (rc->band) { case BAND_A: switch (band) { case BAND_AN: case BAND_A | BAND_AN: case BAND_A: /* Matching BAND_A */ break; default: continue; } break; case BAND_B: case BAND_G: switch (band) { case BAND_GN: case BAND_B | BAND_G | BAND_GN: case BAND_G | BAND_GN: case BAND_B | BAND_G: case BAND_B: case BAND_G: case 0: break; default: continue; } break; default: continue; } for (i = 0; i < rc->num_cfp; i++) { if (rc->pcfp[i].freq == freq) { cfp = &rc->pcfp[i]; break; } } } if (!cfp && freq) PRINTM(MERROR, "wlan_find_cfp_by_band_and_freq(): cannot find cfp by " "band %d & freq %d\n", band, freq); LEAVE(); return cfp; }
/** * @brief The main process * * @param pmlan_adapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status mlan_main_process(IN t_void * pmlan_adapter) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; pmlan_callbacks pcb; ENTER(); MASSERT(pmlan_adapter); pcb = &pmadapter->callbacks; pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); /* Check if already processing */ if (pmadapter->mlan_processing) { pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); goto exit_main_proc; } else { pmadapter->mlan_processing = MTRUE; pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); } process_start: do { /* Is MLAN shutting down or not ready? */ if ((pmadapter->hw_status == WlanHardwareStatusClosing) || (pmadapter->hw_status == WlanHardwareStatusNotReady)) break; /* Handle pending SDIO interrupts if any */ if (pmadapter->sdio_ireg) { if (pmadapter->hs_activated == MTRUE) wlan_process_hs_config(pmadapter); wlan_process_int_status(pmadapter); } /* Need to wake up the card ? */ if ((pmadapter->ps_state == PS_STATE_SLEEP) && (pmadapter->pm_wakeup_card_req && !pmadapter->pm_wakeup_fw_try) && (util_peek_list (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, pcb->moal_spin_lock, pcb->moal_spin_unlock) || !wlan_bypass_tx_list_empty(pmadapter) || !wlan_wmm_lists_empty(pmadapter) )) { pmadapter->pm_wakeup_fw_try = MTRUE; wlan_pm_wakeup_card(pmadapter); continue; } if (IS_CARD_RX_RCVD(pmadapter)) { pmadapter->pm_wakeup_fw_try = MFALSE; if (pmadapter->ps_state == PS_STATE_SLEEP) pmadapter->ps_state = PS_STATE_AWAKE; } else { /* We have tried to wakeup the card already */ if (pmadapter->pm_wakeup_fw_try) break; if (pmadapter->ps_state != PS_STATE_AWAKE || (pmadapter->tx_lock_flag == MTRUE)) break; if (pmadapter->scan_processing || pmadapter->data_sent || (wlan_bypass_tx_list_empty(pmadapter) && wlan_wmm_lists_empty(pmadapter)) ) { if (pmadapter->cmd_sent || pmadapter->curr_cmd || (!util_peek_list (pmadapter->pmoal_handle, &pmadapter->cmd_pending_q, pcb->moal_spin_lock, pcb->moal_spin_unlock))) { break; } } } /* Check for Cmd Resp */ if (pmadapter->cmd_resp_received) { pmadapter->cmd_resp_received = MFALSE; wlan_process_cmdresp(pmadapter); /* call moal back when init_fw is done */ if (pmadapter->hw_status == WlanHardwareStatusInitdone) { pmadapter->hw_status = WlanHardwareStatusReady; wlan_init_fw_complete(pmadapter); } } /* Check for event */ if (pmadapter->event_received) { pmadapter->event_received = MFALSE; wlan_process_event(pmadapter); } /* Check if we need to confirm Sleep Request received previously */ if (pmadapter->ps_state == PS_STATE_PRE_SLEEP) { if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) { wlan_check_ps_cond(pmadapter); } } /* * The ps_state may have been changed during processing of * Sleep Request event. */ if ((pmadapter->ps_state == PS_STATE_SLEEP) || (pmadapter->ps_state == PS_STATE_PRE_SLEEP) || (pmadapter->ps_state == PS_STATE_SLEEP_CFM) || (pmadapter->tx_lock_flag == MTRUE) ) continue; if (!pmadapter->cmd_sent && !pmadapter->curr_cmd) { if (wlan_exec_next_cmd(pmadapter) == MLAN_STATUS_FAILURE) { ret = MLAN_STATUS_FAILURE; break; } } if (!pmadapter->scan_processing && !pmadapter->data_sent && !wlan_bypass_tx_list_empty(pmadapter)) { PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n"); wlan_process_bypass_tx(pmadapter); if (pmadapter->hs_activated == MTRUE) { pmadapter->is_hs_configured = MFALSE; wlan_host_sleep_activated_event(wlan_get_priv (pmadapter, MLAN_BSS_ROLE_ANY), MFALSE); } } if (!pmadapter->scan_processing && !pmadapter->data_sent && !wlan_wmm_lists_empty(pmadapter)) { wlan_wmm_process_tx(pmadapter); if (pmadapter->hs_activated == MTRUE) { pmadapter->is_hs_configured = MFALSE; wlan_host_sleep_activated_event(wlan_get_priv (pmadapter, MLAN_BSS_ROLE_ANY), MFALSE); } } #ifdef STA_SUPPORT if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent && !pmadapter->curr_cmd && !IS_COMMAND_PENDING(pmadapter) && wlan_bypass_tx_list_empty(pmadapter) && wlan_wmm_lists_empty(pmadapter)) { if (wlan_send_null_packet (wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA), MRVDRV_TxPD_POWER_MGMT_NULL_PACKET | MRVDRV_TxPD_POWER_MGMT_LAST_PACKET) == MLAN_STATUS_SUCCESS) { pmadapter->delay_null_pkt = MFALSE; } break; } #endif } while (MTRUE); if ((pmadapter->sdio_ireg) || IS_CARD_RX_RCVD(pmadapter)) { goto process_start; } pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); pmadapter->mlan_processing = MFALSE; pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmain_proc_lock); exit_main_proc: if (pmadapter->hw_status == WlanHardwareStatusClosing) mlan_shutdown_fw(pmadapter); LEAVE(); return ret; }
/** * @brief This function fill the txpd for tx packet * * @param priv A pointer to mlan_private structure * @param pmbuf A pointer to the mlan_buffer for process * * @return headptr or MNULL */ t_void * wlan_ops_sta_process_txpd(IN t_void * priv, IN pmlan_buffer pmbuf) { mlan_private *pmpriv = (mlan_private *) priv; pmlan_adapter pmadapter = pmpriv->adapter; TxPD *plocal_tx_pd; t_u8 *head_ptr = MNULL; t_u32 pkt_type; t_u32 tx_control; ENTER(); if (!pmbuf->data_len) { PRINTM(MERROR, "STA Tx Error: Invalid packet length: %d\n", pmbuf->data_len); pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID; goto done; } if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) { memcpy(pmpriv->adapter, &pkt_type, pmbuf->pbuf + pmbuf->data_offset, sizeof(pkt_type)); memcpy(pmpriv->adapter, &tx_control, pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), sizeof(tx_control)); pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control); pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control); } if (pmbuf->data_offset < (sizeof(TxPD) + INTF_HEADER_LEN + DMA_ALIGNMENT)) { PRINTM(MERROR, "not enough space for TxPD: %d\n", pmbuf->data_len); pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID; goto done; } /* head_ptr should be aligned */ head_ptr = pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) - INTF_HEADER_LEN; head_ptr = (t_u8 *) ((t_ptr) head_ptr & ~((t_ptr) (DMA_ALIGNMENT - 1))); plocal_tx_pd = (TxPD *) (head_ptr + INTF_HEADER_LEN); memset(pmadapter, plocal_tx_pd, 0, sizeof(TxPD)); /* Set the BSS number to TxPD */ plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv); plocal_tx_pd->bss_type = pmpriv->bss_type; plocal_tx_pd->tx_pkt_length = (t_u16) pmbuf->data_len; plocal_tx_pd->priority = (t_u8) pmbuf->priority; plocal_tx_pd->pkt_delay_2ms = wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf); if (plocal_tx_pd->priority < NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl)) /* * Set the priority specific tx_control field, setting of 0 will * cause the default value to be used later in this function */ plocal_tx_pd->tx_control = pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd-> priority]; if (pmadapter->pps_uapsd_mode) { if (MTRUE == wlan_check_last_packet_indication(pmpriv)) { pmadapter->tx_lock_flag = MTRUE; plocal_tx_pd->flags = MRVDRV_TxPD_POWER_MGMT_LAST_PACKET; } } /* Offset of actual data */ plocal_tx_pd->tx_pkt_offset = (t_u16) ((t_ptr) pmbuf->pbuf + pmbuf->data_offset - (t_ptr) plocal_tx_pd); if (!plocal_tx_pd->tx_control) { /* TxCtrl set by user or default */ plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl; } if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) { plocal_tx_pd->tx_pkt_type = (t_u16) pkt_type; plocal_tx_pd->tx_control = tx_control; } endian_convert_TxPD(plocal_tx_pd); /* Adjust the data offset and length to include TxPD in pmbuf */ pmbuf->data_len += pmbuf->data_offset; pmbuf->data_offset = (t_u32) (head_ptr - pmbuf->pbuf); pmbuf->data_len -= pmbuf->data_offset; done: LEAVE(); return head_ptr; }
/** * @brief This function handles events generated by firmware * * @param priv A pointer to mlan_private structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_ops_sta_process_event(IN t_void * priv) { pmlan_private pmpriv = (pmlan_private) priv; pmlan_adapter pmadapter = pmpriv->adapter; mlan_status ret = MLAN_STATUS_SUCCESS; t_u32 eventcause = pmadapter->event_cause; t_u8 event_buf[100]; t_u8 *evt_buf = MNULL; pmlan_buffer pmbuf = pmadapter->pmlan_buffer_event; pmlan_callbacks pcb = &pmadapter->callbacks; mlan_event *pevent = (mlan_event *) event_buf; ENTER(); if (eventcause != EVENT_PS_AWAKE && eventcause != EVENT_PS_SLEEP && pmbuf->data_len > sizeof(eventcause)) DBG_HEXDUMP(MEVT_D, "EVENT", pmbuf->pbuf + pmbuf->data_offset, pmbuf->data_len); switch (eventcause) { case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: PRINTM(MERROR, "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n"); break; case EVENT_LINK_SENSED: PRINTM(MEVENT, "EVENT: LINK_SENSED\n"); pmpriv->adhoc_is_link_sensed = MTRUE; wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, MNULL); break; case EVENT_DEAUTHENTICATED: PRINTM(MEVENT, "EVENT: Deauthenticated\n"); pmadapter->dbg.num_event_deauth++; wlan_handle_disconnect_event(pmpriv); break; case EVENT_DISASSOCIATED: PRINTM(MEVENT, "EVENT: Disassociated\n"); pmadapter->dbg.num_event_disassoc++; wlan_handle_disconnect_event(pmpriv); break; case EVENT_LINK_LOST: PRINTM(MEVENT, "EVENT: Link lost\n"); pmadapter->dbg.num_event_link_lost++; wlan_handle_disconnect_event(pmpriv); break; case EVENT_PS_SLEEP: PRINTM(MINFO, "EVENT: SLEEP\n"); PRINTM(MEVENT, "_"); /* Handle unexpected PS SLEEP event */ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) break; pmadapter->ps_state = PS_STATE_PRE_SLEEP; wlan_check_ps_cond(pmadapter); break; case EVENT_PS_AWAKE: PRINTM(MINFO, "EVENT: AWAKE \n"); PRINTM(MEVENT, "|"); if (!pmadapter->pps_uapsd_mode && pmpriv->media_connected && (pmpriv->port_open || !pmpriv->port_ctrl_mode) && pmadapter->sleep_period.period) { pmadapter->pps_uapsd_mode = MTRUE; PRINTM(MEVENT, "PPS/UAPSD mode activated\n"); } /* Handle unexpected PS AWAKE event */ if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) break; pmadapter->tx_lock_flag = MFALSE; if (pmadapter->pps_uapsd_mode && pmadapter->gen_null_pkt) { if (MTRUE == wlan_check_last_packet_indication(pmpriv)) { if (!pmadapter->data_sent) { if (wlan_send_null_packet(pmpriv, MRVDRV_TxPD_POWER_MGMT_NULL_PACKET | MRVDRV_TxPD_POWER_MGMT_LAST_PACKET) == MLAN_STATUS_SUCCESS) { return MLAN_STATUS_SUCCESS; } } } } pmadapter->ps_state = PS_STATE_AWAKE; pmadapter->pm_wakeup_card_req = MFALSE; pmadapter->pm_wakeup_fw_try = MFALSE; break; case EVENT_HS_ACT_REQ: PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n"); ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, 0, 0, MNULL, MNULL); break; case EVENT_MIC_ERR_UNICAST: PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL); break; case EVENT_MIC_ERR_MULTICAST: PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL); break; case EVENT_MIB_CHANGED: case EVENT_INIT_DONE: break; case EVENT_ADHOC_BCN_LOST: PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n"); pmpriv->adhoc_is_link_sensed = MFALSE; wlan_clean_txrx(pmpriv); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, MNULL); break; case EVENT_BG_SCAN_REPORT: PRINTM(MEVENT, "EVENT: BGS_REPORT\n"); /* Clear the previous scan result */ memset(pmadapter, pmadapter->pscan_table, 0x00, sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST); pmadapter->num_in_scan_table = 0; pmadapter->pbcn_buf_end = pmadapter->bcn_buf; ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_BG_SCAN_QUERY, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); break; case EVENT_PORT_RELEASE: PRINTM(MEVENT, "EVENT: PORT RELEASE\n"); /* Open the port for e-supp mode */ if (pmpriv->port_ctrl_mode == MTRUE) { PRINTM(MINFO, "PORT_REL: port_status = OPEN\n"); pmpriv->port_open = MTRUE; } pmpriv->scan_block = MFALSE; wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL); break; case EVENT_STOP_TX: PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause); wlan_11h_tx_disable(pmpriv); // this fn will send event up to MOAL break; case EVENT_START_TX: PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause); wlan_11h_tx_enable(pmpriv); // this fn will send event up to MOAL break; case EVENT_CHANNEL_SWITCH: PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause); /* To be handled for 'chanswann' private command */ break; case EVENT_CHANNEL_SWITCH_ANN: PRINTM(MEVENT, "EVENT: Channel Switch Announcement\n"); /* Here, pass up event first, as handling will send deauth */ wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN, MNULL); wlan_11h_handle_event_chanswann(pmpriv); break; case EVENT_RADAR_DETECTED: PRINTM(MEVENT, "EVENT: Radar Detected\n"); /* Send as passthru first, this event can cause other events */ memset(pmadapter, pevent, 0x00, sizeof(event_buf)); pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU; pevent->event_len = pmbuf->data_len; memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmbuf->pbuf + pmbuf->data_offset, pevent->event_len); wlan_recv_event(pmpriv, pevent->event_id, pevent); /* Then handle event */ if (pmadapter->state_rdh.stage == RDH_OFF) { pmadapter->state_rdh.stage = RDH_CHK_INTFS; wlan_11h_radar_detected_handling(pmadapter); } else { PRINTM(MEVENT, "Ignore Event Radar Detected - handling" " already in progress.\n"); } break; case EVENT_CHANNEL_REPORT_RDY: PRINTM(MEVENT, "EVENT: Channel Report Ready\n"); /* Allocate memory for event buffer */ ret = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf); if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) { memset(pmadapter, evt_buf, 0x00, MAX_EVENT_SIZE); /* Setup event buffer */ pevent = (pmlan_event) evt_buf; pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY; pevent->event_len = pmbuf->data_len - sizeof(eventcause); /* Copy event data */ memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause), pevent->event_len); /* Handle / pass event data */ ret = wlan_11h_handle_event_chanrpt_ready(pmpriv, pevent); /* Also send this event as passthru */ pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU; pevent->event_len = pmbuf->data_len; memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmbuf->pbuf + pmbuf->data_offset, pevent->event_len); wlan_recv_event(pmpriv, pevent->event_id, pevent); /* Now done with buffer */ pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf); } /* Send up this Event to unblock MOAL waitqueue */ wlan_recv_event(pmpriv, MLAN_EVENT_ID_DRV_MEAS_REPORT, MNULL); break; case EVENT_EXT_SCAN_REPORT: PRINTM(MEVENT, "EVENT: EXT_SCAN Report (%#x)\n", eventcause); ret = wlan_handle_event_ext_scan_report(priv, pmbuf); break; case EVENT_MEAS_REPORT_RDY: PRINTM(MEVENT, "EVENT: Measurement Report Ready (%#x)\n", eventcause); wlan_prepare_cmd(priv, HostCmd_CMD_MEASUREMENT_REPORT, HostCmd_ACT_GEN_SET, 0, 0, MNULL); break; case EVENT_WMM_STATUS_CHANGE: if (pmbuf && pmbuf->data_len > sizeof(eventcause) + sizeof(MrvlIEtypesHeader_t)) { PRINTM(MEVENT, "EVENT: WMM status changed: %d\n", pmbuf->data_len); evt_buf = (pmbuf->pbuf + pmbuf->data_offset + sizeof(eventcause)); wlan_ret_wmm_get_status(pmpriv, evt_buf, pmbuf->data_len - sizeof(eventcause)); } else { PRINTM(MEVENT, "EVENT: WMM status changed\n"); ret = wlan_cmd_wmm_status_change(pmpriv); } break; case EVENT_RSSI_LOW: PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL); break; case EVENT_SNR_LOW: PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL); break; case EVENT_MAX_FAIL: PRINTM(MEVENT, "EVENT: MAX_FAIL\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL); break; case EVENT_RSSI_HIGH: PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL); break; case EVENT_SNR_HIGH: PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL); break; case EVENT_DATA_RSSI_LOW: PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL); break; case EVENT_DATA_SNR_LOW: PRINTM(MEVENT, "EVENT: Data SNR_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL); break; case EVENT_DATA_RSSI_HIGH: PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL); break; case EVENT_DATA_SNR_HIGH: PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL); break; case EVENT_LINK_QUALITY: PRINTM(MEVENT, "EVENT: Link Quality\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL); break; case EVENT_PRE_BEACON_LOST: PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL); break; case EVENT_IBSS_COALESCED: PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n"); ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); break; case EVENT_ADDBA: PRINTM(MEVENT, "EVENT: ADDBA Request\n"); wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP, HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body); break; case EVENT_DELBA: PRINTM(MEVENT, "EVENT: DELBA Request\n"); wlan_11n_delete_bastream(pmpriv, pmadapter->event_body); break; case EVENT_BA_STREAM_TIMEOUT: PRINTM(MEVENT, "EVENT: BA Stream timeout\n"); wlan_11n_ba_stream_timeout(pmpriv, (HostCmd_DS_11N_BATIMEOUT *) pmadapter-> event_body); break; case EVENT_RXBA_SYNC: PRINTM(MEVENT, "EVENT: RXBA_SYNC\n"); wlan_11n_rxba_sync_event(pmpriv, pmadapter->event_body, pmbuf->data_len - sizeof(eventcause)); break; case EVENT_AMSDU_AGGR_CTRL: PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n", *(t_u16 *) pmadapter->event_body); pmadapter->tx_buf_size = MIN(pmadapter->curr_tx_buf_size, wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body)); PRINTM(MEVENT, "tx_buf_size %d\n", pmadapter->tx_buf_size); break; case EVENT_WEP_ICV_ERR: PRINTM(MEVENT, "EVENT: WEP ICV error\n"); pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR; pevent->event_len = sizeof(Event_WEP_ICV_ERR); memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body, pevent->event_len); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent); break; case EVENT_BW_CHANGE: PRINTM(MEVENT, "EVENT: BW Change\n"); pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED; pevent->event_len = sizeof(t_u8); /* Copy event body from the event buffer */ memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmadapter->event_body, pevent->event_len); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent); break; #ifdef WFD_SUPPORT case EVENT_WFD_GENERIC_EVENT: case EVENT_WFD_SERVICE_DISCOVERY: PRINTM(MEVENT, "EVENT: WFD event %d\n", eventcause); /* Allocate memory for event buffer */ ret = pcb->moal_malloc(pmadapter->pmoal_handle, MAX_EVENT_SIZE, MLAN_MEM_DEF, &evt_buf); if ((ret == MLAN_STATUS_SUCCESS) && evt_buf) { pevent = (pmlan_event) evt_buf; pevent->bss_index = pmpriv->bss_index; pevent->event_id = MLAN_EVENT_ID_DRV_PASSTHRU; pevent->event_len = pmbuf->data_len; memcpy(pmadapter, (t_u8 *) pevent->event_buf, pmbuf->pbuf + pmbuf->data_offset, pevent->event_len); wlan_recv_event(pmpriv, pevent->event_id, pevent); pcb->moal_mfree(pmadapter->pmoal_handle, evt_buf); } break; #endif /* WFD_SUPPORT */ default: PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL); break; } LEAVE(); return ret; }
/** * @brief Deaggregate the received AMSDU packet * * @param priv A pointer to mlan_private structure * @param pmbuf A pointer to aggregated data packet * * @return MLAN_STATUS_SUCCESS --success, otherwise fail */ mlan_status wlan_11n_deaggregate_pkt(mlan_private * priv, pmlan_buffer pmbuf) { t_u16 pkt_len; int total_pkt_len; t_u8 *data; int pad; mlan_status ret = MLAN_STATUS_FAILURE; RxPacketHdr_t *prx_pkt; mlan_buffer *daggr_mbuf = MNULL; /* mlan_adapter *pmadapter = priv->adapter; */ t_u8 rfc1042_eth_hdr[MLAN_MAC_ADDR_LENGTH] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; ENTER(); data = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset); total_pkt_len = pmbuf->data_len; /* Sanity test */ if (total_pkt_len > MLAN_RX_DATA_BUF_SIZE) { PRINTM(MERROR, "Total packet length greater than tx buffer" " size %d\n", total_pkt_len); goto done; } pmbuf->use_count = wlan_11n_get_num_aggrpkts(data, total_pkt_len); while (total_pkt_len > 0) { prx_pkt = (RxPacketHdr_t *) data; /* Length will be in network format, change it to host */ pkt_len = mlan_ntohs((*(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)))); if (pkt_len > total_pkt_len) { PRINTM(MERROR, "Error in packet length: total_pkt_len = %d, pkt_len = %d\n", total_pkt_len, pkt_len); break; } pad = (((pkt_len + sizeof(Eth803Hdr_t)) & 3)) ? (4 - ((pkt_len + sizeof(Eth803Hdr_t)) & 3)) : 0; total_pkt_len -= pkt_len + pad + sizeof(Eth803Hdr_t); if (memcmp(pmadapter, &prx_pkt->rfc1042_hdr, rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { memmove(pmadapter, data + LLC_SNAP_LEN, data, (2 * MLAN_MAC_ADDR_LENGTH)); data += LLC_SNAP_LEN; pkt_len += sizeof(Eth803Hdr_t) - LLC_SNAP_LEN; } else { *(t_u16 *) (data + (2 * MLAN_MAC_ADDR_LENGTH)) = (t_u16) 0; pkt_len += sizeof(Eth803Hdr_t); } #ifndef CONFIG_MLAN_WMSDK daggr_mbuf = wlan_alloc_mlan_buffer(pmadapter, pkt_len, 0, MFALSE); if (daggr_mbuf == MNULL) { PRINTM(MERROR, "Error allocating daggr mlan_buffer\n"); LEAVE(); return MLAN_STATUS_FAILURE; } daggr_mbuf->bss_index = pmbuf->bss_index; daggr_mbuf->buf_type = pmbuf->buf_type; daggr_mbuf->data_len = pkt_len; daggr_mbuf->in_ts_sec = pmbuf->in_ts_sec; daggr_mbuf->in_ts_usec = pmbuf->in_ts_usec; daggr_mbuf->pparent = pmbuf; daggr_mbuf->priority = pmbuf->priority; memcpy(pmadapter, daggr_mbuf->pbuf + daggr_mbuf->data_offset, data, pkt_len); #else /* This part is customized for WMSDK. We do not need and will not allocate the mlan buffer. */ wrapper_deliver_amsdu_subframe(pmbuf, data, pkt_len); ret = MLAN_STATUS_SUCCESS; #endif /* CONFIG_MLAN_WMSDK */ #ifndef CONFIG_MLAN_WMSDK #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) ret = wlan_uap_recv_packet(priv, daggr_mbuf); else #endif /* UAP_SUPPORT */ ret = pmadapter->callbacks.moal_recv_packet(pmadapter->pmoal_handle, daggr_mbuf); #endif /* CONFIG_MLAN_WMSDK */ switch (ret) { case MLAN_STATUS_PENDING: break; case MLAN_STATUS_FAILURE: PRINTM(MERROR, "Deaggr, send to moal failed\n"); daggr_mbuf->status_code = MLAN_ERROR_PKT_INVALID; case MLAN_STATUS_SUCCESS: #ifndef CONFIG_MLAN_WMSDK wlan_recv_packet_complete(pmadapter, daggr_mbuf, ret); #endif /* CONFIG_MLAN_WMSDK */ break; default: break; } data += pkt_len + pad; } done: LEAVE(); return ret; }
/** * @brief read handler for BT char dev * * @param filp pointer to structure file * @param buf pointer to char buffer * @param count size of receive buffer * @param f_pos pointer to loff_t type data * @return number of bytes read */ ssize_t chardev_read(struct file * filp, char *buf, size_t count, loff_t * f_pos) { struct char_dev *dev = (struct char_dev *)filp->private_data; struct m_dev *m_dev = dev->m_dev; DECLARE_WAITQUEUE(wait, current); ssize_t ret = 0; struct sk_buff *skb = NULL; ENTER(); if (!dev || !dev->m_dev) { LEAVE(); return -ENXIO; } /* Wait for rx data */ add_wait_queue(&m_dev->req_wait_q, &wait); while (1) { set_current_state(TASK_INTERRUPTIBLE); skb = skb_dequeue(&m_dev->rx_q); if (skb) break; if (!test_bit(HCI_UP, &m_dev->flags)) { ret = -EBUSY; break; } if (filp->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -EINTR; break; } schedule(); } set_current_state(TASK_RUNNING); remove_wait_queue(&m_dev->req_wait_q, &wait); if (!skb) goto out; if (m_dev->read_continue_flag == 0) { /* Put type byte before the data */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); PRINTM(DATA, "Read: pkt_type: 0x%x, len=%d @%lu\n", bt_cb(skb)->pkt_type, skb->len, jiffies); } DBG_HEXDUMP(DAT_D, "chardev_read", skb->data, skb->len); if (skb->len > count) { /* user data length is smaller than the skb length */ if (copy_to_user(buf, skb->data, count)) { ret = -EFAULT; goto outf; } skb_pull(skb, count); skb_queue_head(&m_dev->rx_q, skb); m_dev->read_continue_flag = 1; wake_up_interruptible(&m_dev->req_wait_q); ret = count; goto out; } else { if (copy_to_user(buf, skb->data, skb->len)) { ret = -EFAULT; goto outf; } m_dev->read_continue_flag = 0; ret = skb->len; } outf: kfree_skb(skb); out: LEAVE(); return ret; }
/** * @brief Aggregate multiple packets into one single AMSDU packet * * @param priv A pointer to mlan_private structure * @param pra_list Pointer to the RA List table containing the pointers * to packets. * @param headroom Any interface specific headroom that may be need. TxPD * will be formed leaving this headroom. * @param ptrindex Pointer index * * @return Final packet size or MLAN_STATUS_FAILURE */ int wlan_11n_aggregate_pkt(mlan_private * priv, raListTbl * pra_list, int headroom, int ptrindex) { int pkt_size = 0; pmlan_adapter pmadapter = priv->adapter; mlan_buffer *pmbuf_aggr, *pmbuf_src; t_u8 *data; int pad = 0; mlan_status ret = MLAN_STATUS_SUCCESS; #ifdef DEBUG_LEVEL1 t_u32 sec, usec; #endif mlan_tx_param tx_param; #ifdef STA_SUPPORT TxPD *ptx_pd = MNULL; #endif t_u32 max_amsdu_size = MIN(pra_list->max_amsdu, pmadapter->tx_buf_size); ENTER(); PRINTM(MDAT_D, "Handling Aggr packet\n"); if ((pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL))) { if (!(pmbuf_aggr = wlan_alloc_mlan_buffer(pmadapter, pmadapter->tx_buf_size, 0, MTRUE))) { PRINTM(MERROR, "Error allocating mlan_buffer\n"); pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); LEAVE(); return MLAN_STATUS_FAILURE; } data = pmbuf_aggr->pbuf + headroom; pmbuf_aggr->bss_index = pmbuf_src->bss_index; pmbuf_aggr->buf_type = pmbuf_src->buf_type; pmbuf_aggr->priority = pmbuf_src->priority; pmbuf_aggr->pbuf = data; pmbuf_aggr->data_offset = 0; /* Form AMSDU */ wlan_11n_form_amsdu_txpd(priv, pmbuf_aggr); pkt_size = sizeof(TxPD); #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) ptx_pd = (TxPD *) pmbuf_aggr->pbuf; #endif } else { pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); goto exit; } while (pmbuf_src && ((pkt_size + (pmbuf_src->data_len + LLC_SNAP_LEN) + headroom) <= max_amsdu_size)) { pmbuf_src = (pmlan_buffer) util_dequeue_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); pra_list->total_pkts--; /* decrement for every PDU taken from the list */ priv->wmm.pkts_queued[ptrindex]--; util_scalar_decrement(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); pkt_size += wlan_11n_form_amsdu_pkt(pmadapter, (data + pkt_size), pmbuf_src->pbuf + pmbuf_src->data_offset, pmbuf_src->data_len, &pad); DBG_HEXDUMP(MDAT_D, "pmbuf_src", pmbuf_src, sizeof(mlan_buffer)); wlan_write_data_complete(pmadapter, pmbuf_src, MLAN_STATUS_SUCCESS); pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) { pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); LEAVE(); return MLAN_STATUS_FAILURE; } pmbuf_src = (pmlan_buffer) util_peek_list(pmadapter->pmoal_handle, &pra_list->buf_head, MNULL, MNULL); } pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); /* Last AMSDU packet does not need padding */ pkt_size -= pad; pmbuf_aggr->data_len = pkt_size; wlan_11n_update_pktlen_amsdu_txpd(priv, pmbuf_aggr); pmbuf_aggr->data_len += headroom; pmbuf_aggr->pbuf = data - headroom; tx_param.next_pkt_len = ((pmbuf_src) ? pmbuf_src->data_len + sizeof(TxPD) : 0); ret = wlan_sdio_host_to_card(pmadapter, MLAN_TYPE_DATA, pmbuf_aggr, &tx_param); switch (ret) { case MLAN_STATUS_RESOURCE: pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (!wlan_is_ralist_valid(priv, pra_list, ptrindex)) { pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID; wlan_write_data_complete(pmadapter, pmbuf_aggr, MLAN_STATUS_FAILURE); LEAVE(); return MLAN_STATUS_FAILURE; } #ifdef STA_SUPPORT /* reset tx_lock_flag */ if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && pmadapter->pps_uapsd_mode && (pmadapter->tx_lock_flag == MTRUE)) { pmadapter->tx_lock_flag = MFALSE; ptx_pd->flags = 0; } #endif util_enqueue_list_head(pmadapter->pmoal_handle, &pra_list->buf_head, (pmlan_linked_list) pmbuf_aggr, MNULL, MNULL); pra_list->total_pkts++; /* add back only one: aggregated packet is requeued as one */ priv->wmm.pkts_queued[ptrindex]++; util_scalar_increment(pmadapter->pmoal_handle, &priv->wmm.tx_pkts_queued, MNULL, MNULL); pmbuf_aggr->flags |= MLAN_BUF_FLAG_REQUEUED_PKT; pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n"); pmbuf_aggr->status_code = MLAN_ERROR_PKT_INVALID; break; case MLAN_STATUS_FAILURE: pmadapter->data_sent = MFALSE; PRINTM(MERROR, "Error: host_to_card failed: 0x%X\n", ret); pmbuf_aggr->status_code = MLAN_ERROR_DATA_TX_FAIL; pmadapter->dbg.num_tx_host_to_card_failure++; wlan_write_data_complete(pmadapter, pmbuf_aggr, ret); goto exit; case MLAN_STATUS_PENDING: pmadapter->data_sent = MFALSE; break; case MLAN_STATUS_SUCCESS: wlan_write_data_complete(pmadapter, pmbuf_aggr, ret); break; default: break; } if (ret != MLAN_STATUS_RESOURCE) { pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); if (wlan_is_ralist_valid(priv, pra_list, ptrindex)) { priv->wmm.packets_out[ptrindex]++; priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list; } pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur = pmadapter->bssprio_tbl[priv->bss_priority].bssprio_cur->pnext; pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle, priv->wmm.ra_list_spinlock); } PRINTM_GET_SYS_TIME(MDATA, &sec, &usec); PRINTM_NETINTF(MDATA, priv); PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec); exit: LEAVE(); return (pkt_size + headroom); }
/** * @brief This function parses country info from AP and * download country info to FW * * @param pmpriv A pointer to mlan_private structure * @param pbss_desc A pointer to BSS descriptor * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = pmpriv->adapter; parsed_region_chan_11d_t region_chan; parsed_region_chan_11d_t bssdesc_region_chan; t_u32 i, j; ENTER(); /* Only valid if 11D is enabled */ if (wlan_11d_is_enabled(pmpriv)) { memset(pmadapter, ®ion_chan, 0, sizeof(parsed_region_chan_11d_t)); memset(pmadapter, &bssdesc_region_chan, 0, sizeof(parsed_region_chan_11d_t)); memcpy(pmadapter, ®ion_chan, &pmadapter->parsed_region_chan, sizeof(parsed_region_chan_11d_t)); if (pbss_desc) { /* Parse domain info if available */ ret = wlan_11d_parse_domain_info(pmadapter, &pbss_desc-> country_info, (t_u8)pbss_desc-> bss_band, &bssdesc_region_chan); if (ret == MLAN_STATUS_SUCCESS) { /* Update the channel-power table */ for (i = 0; ((i < bssdesc_region_chan.no_of_chan) && (i < MAX_NO_OF_CHAN)); i++) { for (j = 0; ((j < region_chan.no_of_chan) && (j < MAX_NO_OF_CHAN)); j++) { /* * Channel already exists, use minimum * of existing tx power and tx_power * received from country info of the * current AP */ if (region_chan.chan_pwr[i]. chan == bssdesc_region_chan. chan_pwr[j].chan && region_chan.chan_pwr[i]. band == bssdesc_region_chan. chan_pwr[j].band) { region_chan.chan_pwr[j]. pwr = MIN(region_chan. chan_pwr[j]. pwr, bssdesc_region_chan. chan_pwr[i]. pwr); break; } } } } } /* Generate domain info */ wlan_11d_generate_domain_info(pmadapter, ®ion_chan); /* Set domain info */ ret = wlan_11d_send_domain_info(pmpriv, MNULL); if (ret) { PRINTM(MERROR, "11D: Error sending domain info to FW\n"); } } LEAVE(); return ret; }
/** * @brief This function handles events generated by firmware * * @param priv A pointer to mlan_private structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status mlan_process_sta_event(IN t_void * priv) { pmlan_private pmpriv = (pmlan_private) priv; pmlan_adapter pmadapter = pmpriv->adapter; mlan_status ret = MLAN_STATUS_SUCCESS; t_u32 eventcause = pmadapter->event_cause; t_u8 event_buf[100]; mlan_event *pevent = (mlan_event *) event_buf; ENTER(); /* Clear BSS_NO_BITS from event */ eventcause &= EVENT_ID_MASK; switch (eventcause) { case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: PRINTM(MERROR, "Invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL, ignoring it\n"); break; case EVENT_LINK_SENSED: PRINTM(MEVENT, "EVENT: LINK_SENSED\n"); pmpriv->adhoc_is_link_sensed = MTRUE; wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, MNULL); break; case EVENT_DEAUTHENTICATED: PRINTM(MEVENT, "EVENT: Deauthenticated\n"); pmadapter->dbg.num_event_deauth++; wlan_handle_disconnect_event(pmpriv); break; case EVENT_DISASSOCIATED: PRINTM(MEVENT, "EVENT: Disassociated\n"); pmadapter->dbg.num_event_disassoc++; wlan_handle_disconnect_event(pmpriv); break; case EVENT_LINK_LOST: PRINTM(MEVENT, "EVENT: Link lost\n"); pmadapter->dbg.num_event_link_lost++; wlan_handle_disconnect_event(pmpriv); break; case EVENT_PS_SLEEP: PRINTM(MINFO, "EVENT: SLEEP\n"); PRINTM(MEVENT, "_"); pmadapter->ps_state = PS_STATE_PRE_SLEEP; wlan_check_ps_cond(pmadapter); break; case EVENT_PS_AWAKE: PRINTM(MINFO, "EVENT: AWAKE \n"); PRINTM(MEVENT, "|"); pmadapter->tx_lock_flag = MFALSE; if (pmadapter->sleep_period.period) { if (MTRUE == wlan_check_last_packet_indication(pmpriv)) { if (!pmadapter->data_sent && pmpriv->gen_null_pkg) { wlan_send_null_packet(pmpriv, MRVDRV_TxPD_POWER_MGMT_NULL_PACKET | MRVDRV_TxPD_POWER_MGMT_LAST_PACKET); pmadapter->ps_state = PS_STATE_SLEEP; return MLAN_STATUS_SUCCESS; } } } pmadapter->ps_state = PS_STATE_AWAKE; pmadapter->pm_wakeup_card_req = MFALSE; pmadapter->pm_wakeup_fw_try = MFALSE; break; case EVENT_DEEP_SLEEP_AWAKE: wlan_pm_reset_card(pmadapter); PRINTM(MEVENT, "EVENT: DS_AWAKE\n"); if (pmadapter->is_deep_sleep == MTRUE) { pmadapter->is_deep_sleep = MFALSE; } wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DS_AWAKE, MNULL); break; case EVENT_HS_ACT_REQ: PRINTM(MEVENT, "EVENT: HS_ACT_REQ\n"); ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_HS_CFG_ENH, 0, 0, MNULL, MNULL); break; case EVENT_MIC_ERR_UNICAST: PRINTM(MEVENT, "EVENT: UNICAST MIC ERROR\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_UNI, MNULL); break; case EVENT_MIC_ERR_MULTICAST: PRINTM(MEVENT, "EVENT: MULTICAST MIC ERROR\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MIC_ERR_MUL, MNULL); break; case EVENT_MIB_CHANGED: case EVENT_INIT_DONE: break; case EVENT_ADHOC_BCN_LOST: PRINTM(MEVENT, "EVENT: ADHOC_BCN_LOST\n"); pmpriv->adhoc_is_link_sensed = MFALSE; wlan_clean_txrx(pmpriv); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, MNULL); break; case EVENT_BG_SCAN_REPORT: PRINTM(MEVENT, "EVENT: BGS_REPORT\n"); /* Clear the previous scan result */ memset(pmadapter->pscan_table, 0x00, sizeof(BSSDescriptor_t) * MRVDRV_MAX_BSSID_LIST); pmadapter->num_in_scan_table = 0; pmadapter->pbcn_buf_end = pmadapter->bcn_buf; ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_BG_SCAN_QUERY, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); break; case EVENT_STOP_TX: PRINTM(MEVENT, "EVENT: Stop Tx (%#x)\n", eventcause); wlan_11h_tx_disable(pmpriv); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_STOP_TX, MNULL); break; case EVENT_START_TX: PRINTM(MEVENT, "EVENT: Start Tx (%#x)\n", eventcause); wlan_11h_tx_enable(pmpriv); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_START_TX, MNULL); break; case EVENT_CHANNEL_SWITCH: PRINTM(MEVENT, "EVENT: Channel Switch (%#x)\n", eventcause); /* To be handled for 'chanswann' private command */ break; case EVENT_MEAS_REPORT_RDY: PRINTM(MINFO, "EVENT: Measurement Report Ready (%#x)\n", eventcause); /* To be handled for 'measreq' private command */ break; case EVENT_WMM_STATUS_CHANGE: PRINTM(MEVENT, "EVENT: WMM status changed\n"); ret = (mlan_status) wlan_cmd_wmm_status_change(pmpriv); break; case EVENT_RSSI_LOW: PRINTM(MEVENT, "EVENT: Beacon RSSI_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW, MNULL); break; case EVENT_SNR_LOW: PRINTM(MEVENT, "EVENT: Beacon SNR_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_LOW, MNULL); break; case EVENT_MAX_FAIL: PRINTM(MEVENT, "EVENT: MAX_FAIL\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_MAX_FAIL, MNULL); break; case EVENT_RSSI_HIGH: PRINTM(MEVENT, "EVENT: Beacon RSSI_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, MNULL); break; case EVENT_SNR_HIGH: PRINTM(MEVENT, "EVENT: Beacon SNR_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BCN_SNR_HIGH, MNULL); break; case EVENT_DATA_RSSI_LOW: PRINTM(MEVENT, "EVENT: Data RSSI_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_LOW, MNULL); break; case EVENT_DATA_SNR_LOW: PRINTM(MEVENT, "EVENT: Data SNR_LOW\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_LOW, MNULL); break; case EVENT_DATA_RSSI_HIGH: PRINTM(MEVENT, "EVENT: Data RSSI_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, MNULL); break; case EVENT_DATA_SNR_HIGH: PRINTM(MEVENT, "EVENT: Data SNR_HIGH\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_DATA_SNR_HIGH, MNULL); break; case EVENT_LINK_QUALITY: PRINTM(MEVENT, "EVENT: Link Quality\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_LINK_QUALITY, MNULL); break; case EVENT_PRE_BEACON_LOST: PRINTM(MEVENT, "EVENT: Pre-Beacon Lost\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PRE_BCN_LOST, MNULL); break; case EVENT_IBSS_COALESCED: PRINTM(MEVENT, "EVENT: IBSS_COALESCED\n"); ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, HostCmd_ACT_GEN_GET, 0, MNULL, MNULL); break; case EVENT_PORT_RELEASE: PRINTM(MEVENT, "EVENT: PORT RELEASE\n"); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_PORT_RELEASE, MNULL); break; case EVENT_ADDBA: PRINTM(MEVENT, "EVENT: ADDBA Request\n"); wlan_prepare_cmd(pmpriv, HostCmd_CMD_11N_ADDBA_RSP, HostCmd_ACT_GEN_SET, 0, MNULL, pmadapter->event_body); break; case EVENT_DELBA: PRINTM(MEVENT, "EVENT: DELBA Request\n"); wlan_11n_delete_bastream(pmpriv, pmadapter->event_body); break; case EVENT_BA_STREAM_TIEMOUT: PRINTM(MEVENT, "EVENT: BA Stream timeout\n"); wlan_11n_ba_stream_timeout(pmpriv, (HostCmd_DS_11N_BATIMEOUT *) pmadapter-> event_body); break; case EVENT_AMSDU_AGGR_CTRL: PRINTM(MEVENT, "EVENT: AMSDU_AGGR_CTRL %d\n", *(t_u16 *) pmadapter->event_body); pmpriv->adapter->tx_buf_size = MIN(pmpriv->adapter->max_tx_buf_size, wlan_le16_to_cpu(*(t_u16 *) pmadapter->event_body)); PRINTM(MEVENT, "tx_buf_size %d\n", pmpriv->adapter->tx_buf_size); break; case EVENT_WEP_ICV_ERR: PRINTM(MEVENT, "EVENT: WEP ICV error\n"); pevent->bss_num = pmpriv->bss_num; pevent->event_id = MLAN_EVENT_ID_FW_WEP_ICV_ERR; pevent->event_len = sizeof(Event_WEP_ICV_ERR); memcpy((t_u8 *) pevent->event_buf, pmadapter->event_body, pevent->event_len); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_WEP_ICV_ERR, pevent); break; case EVENT_BW_CHANGE: PRINTM(MEVENT, "EVENT: BW Change\n"); pevent->bss_num = pmpriv->bss_num; pevent->event_id = MLAN_EVENT_ID_FW_BW_CHANGED; pevent->event_len = sizeof(t_u8); /* Copy event body from the event buffer */ memcpy((t_u8 *) pevent->event_buf, pmadapter->event_body, pevent->event_len); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_BW_CHANGED, pevent); break; default: PRINTM(MEVENT, "EVENT: unknown event id: %#x\n", eventcause); wlan_recv_event(pmpriv, MLAN_EVENT_ID_FW_UNKNOWN, MNULL); break; } LEAVE(); return ret; }
/** * @brief This function parses country information for region channel * * @param pmadapter Pointer to mlan_adapter structure * @param country_info Country information * @param band Chan band * @param parsed_region_chan Pointer to parsed_region_chan_11d_t * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status wlan_11d_parse_domain_info(pmlan_adapter pmadapter, IEEEtypes_CountryInfoFullSet_t *country_info, t_u8 band, parsed_region_chan_11d_t *parsed_region_chan) { t_u8 no_of_sub_band, no_of_chan; t_u8 last_chan, first_chan, cur_chan = 0; t_u8 idx = 0; t_u8 j, i; ENTER(); /* * Validation Rules: * 1. Valid Region Code * 2. First Chan increment * 3. Channel range no overlap * 4. Channel is valid? * 5. Channel is supported by Region? * 6. Others */ HEXDUMP("country_info", (t_u8 *)country_info, 30); /* Step 1: Check region_code */ if (!(*(country_info->country_code)) || (country_info->len <= COUNTRY_CODE_LEN)) { /* No region info or wrong region info: treat as no 11D info */ LEAVE(); return MLAN_STATUS_FAILURE; } no_of_sub_band = (country_info->len - COUNTRY_CODE_LEN) / sizeof(IEEEtypes_SubbandSet_t); for (j = 0, last_chan = 0; j < no_of_sub_band; j++) { if (country_info->sub_band[j].first_chan <= last_chan) { /* Step2&3: Check First Chan Num increment and no overlap */ PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n", country_info->sub_band[j].first_chan, last_chan); continue; } first_chan = country_info->sub_band[j].first_chan; no_of_chan = country_info->sub_band[j].no_of_chan; for (i = 0; idx < MAX_NO_OF_CHAN && i < no_of_chan; i++) { /* Step 4 : Channel is supported? */ if (wlan_11d_get_chan (pmadapter, band, first_chan, i, &cur_chan) == MFALSE) { /* Chan is not found in UN table */ PRINTM(MWARN, "11D: channel is not supported: %d\n", i); break; } last_chan = cur_chan; /* Step 5: We don't need to check if cur_chan is supported by mrvl in region */ parsed_region_chan->chan_pwr[idx].chan = cur_chan; parsed_region_chan->chan_pwr[idx].band = band; parsed_region_chan->chan_pwr[idx].pwr = country_info->sub_band[j].max_tx_pwr; idx++; } /* Step 6: Add other checking if any */ } parsed_region_chan->no_of_chan = idx; PRINTM(MINFO, "11D: number of channel=0x%x\n", parsed_region_chan->no_of_chan); HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan->chan_pwr, sizeof(chan_power_11d_t) * idx); LEAVE(); return MLAN_STATUS_SUCCESS; }
/** * @brief This function handles disconnect event, reports disconnect * to upper layer, cleans tx/rx packets, * resets link state etc. * * @param priv A pointer to mlan_private structure * * @return N/A */ t_void wlan_reset_connect_state(pmlan_private priv) { mlan_adapter *pmadapter = priv->adapter; mlan_status ret = MLAN_STATUS_SUCCESS; state_11d_t enable; ENTER(); if (priv->media_connected != MTRUE) { LEAVE(); return; } PRINTM(MINFO, "Handles disconnect event.\n"); priv->media_connected = MFALSE; /* Free Tx and Rx packets, report disconnect to upper layer */ wlan_clean_txrx(priv); /* Reset SNR/NF/RSSI values */ priv->data_rssi_last = 0; priv->data_nf_last = 0; priv->data_rssi_avg = 0; priv->data_nf_avg = 0; priv->bcn_rssi_last = 0; priv->bcn_nf_last = 0; priv->bcn_rssi_avg = 0; priv->bcn_nf_avg = 0; priv->rxpd_rate = 0; priv->rxpd_htinfo = 0; PRINTM(MINFO, "Current SSID=%s, SSID Length=%u\n", priv->curr_bss_params.bss_descriptor.ssid.ssid, priv->curr_bss_params.bss_descriptor.ssid.ssid_len); PRINTM(MINFO, "Previous SSID=%s, SSID Length=%u\n", priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); priv->sec_info.ewpa_enabled = MFALSE; priv->sec_info.wpa_enabled = MFALSE; priv->sec_info.wpa2_enabled = MFALSE; priv->wpa_ie_len = 0; priv->sec_info.wapi_enabled = MFALSE; priv->wapi_ie_len = 0; priv->sec_info.wapi_key_on = MFALSE; priv->sec_info.encryption_mode = MLAN_ENCRYPTION_MODE_NONE; /* Enable auto data rate */ priv->is_data_rate_auto = MTRUE; priv->data_rate = 0; if (priv->bss_mode == MLAN_BSS_MODE_IBSS) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = MFALSE; priv->adhoc_auto_sel = MTRUE; } /* * Memorize the previous SSID and BSSID so * it could be used for re-assoc */ memcpy(&priv->prev_ssid, &priv->curr_bss_params.bss_descriptor.ssid, sizeof(mlan_802_11_ssid)); memcpy(priv->prev_bssid, priv->curr_bss_params.bss_descriptor.mac_address, MLAN_MAC_ADDR_LENGTH); /* Need to erase the current SSID and BSSID info */ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); pmadapter->tx_lock_flag = MFALSE; pmadapter->ps_state = PS_STATE_AWAKE; pmadapter->pm_wakeup_card_req = MFALSE; if ((wlan_11d_get_state(priv) == ENABLE_11D) && (pmadapter->state_11d.user_enable_11d == DISABLE_11D)) { pmadapter->state_11d.enable_11d = DISABLE_11D; enable = DISABLE_11D; /* Send cmd to FW to enable/disable 11D function */ ret = wlan_prepare_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, HostCmd_ACT_GEN_SET, Dot11D_i, MNULL, &enable); if (ret) PRINTM(MERROR, "11D: Failed to enable 11D\n"); } if (pmadapter->num_cmd_timeout && pmadapter->curr_cmd && (pmadapter->cmd_timer_is_set == MFALSE)) { LEAVE(); return; } wlan_recv_event(priv, MLAN_EVENT_ID_FW_DISCONNECTED, MNULL); LEAVE(); }
/** * @brief uap addba reject tbl * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int woal_uap_addba_reject(struct net_device *dev, struct ifreq *req) { moal_private *priv = (moal_private *) netdev_priv(dev); mlan_ioctl_req *ioctl_req = NULL; mlan_ds_11n_cfg *cfg_11n = NULL; addba_reject_para param; int ret = 0; int i = 0; ENTER(); memset(¶m, 0, sizeof(param)); /* Sanity check */ if (req->ifr_data == NULL) { PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n"); ret = -EFAULT; goto done; } if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *) & param, sizeof(param)); ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); if (ioctl_req == NULL) { LEAVE(); return -ENOMEM; } cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf; cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT; ioctl_req->req_id = MLAN_IOCTL_11N_CFG; if (!param.action) { /* Get addba_reject tbl from MLAN */ ioctl_req->action = MLAN_ACT_GET; } else { /* Set addba_reject tbl in MLAN */ ioctl_req->action = MLAN_ACT_SET; for (i = 0; i < MAX_NUM_TID; i++) { cfg_11n->param.addba_reject[i] = param.addba_reject[i]; } } if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { ret = -EFAULT; goto done; } for (i = 0; i < MAX_NUM_TID; i++) { param.addba_reject[i] = cfg_11n->param.addba_reject[i]; } /* Copy to user */ if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { PRINTM(MERROR, "Copy to user failed!\n"); ret = -EFAULT; goto done; } done: if (ioctl_req) kfree(ioctl_req); LEAVE(); return ret; }
/** * @brief This function registers MOAL to MLAN module. * * @param pmdevice A pointer to a mlan_device structure * allocated in MOAL * @param ppmlan_adapter A pointer to a t_void pointer to store * mlan_adapter structure pointer as the context * * @return MLAN_STATUS_SUCCESS * The registration succeeded. * MLAN_STATUS_FAILURE * The registration failed. * * mlan_status mlan_register ( * IN pmlan_device pmdevice, * OUT t_void **ppmlan_adapter * ); * * Comments * MOAL constructs mlan_device data structure to pass moal_handle and * mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to * the ppmlan_adapter buffer provided by MOAL. * Headers: * declared in mlan_decl.h * See Also * mlan_unregister */ mlan_status mlan_register(IN pmlan_device pmdevice, OUT t_void ** ppmlan_adapter) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_adapter pmadapter = MNULL; pmlan_callbacks pcb = MNULL; t_u8 i = 0; t_u32 j = 0; MASSERT(pmdevice); MASSERT(ppmlan_adapter); MASSERT(pmdevice->callbacks.moal_print); #ifdef DEBUG_LEVEL1 print_callback = pmdevice->callbacks.moal_print; #endif assert_callback = pmdevice->callbacks.moal_assert; ENTER(); MASSERT(pmdevice->callbacks.moal_malloc); MASSERT(pmdevice->callbacks.moal_memset); MASSERT(pmdevice->callbacks.moal_memmove); /* Allocate memory for adapter structure */ if ((pmdevice->callbacks. moal_malloc(pmdevice->pmoal_handle, sizeof(mlan_adapter), MLAN_MEM_DEF, (t_u8 **) & pmadapter) != MLAN_STATUS_SUCCESS) || !pmadapter) { ret = MLAN_STATUS_FAILURE; goto exit_register; } pmdevice->callbacks.moal_memset(pmadapter, pmadapter, 0, sizeof(mlan_adapter)); pcb = &pmadapter->callbacks; /* Save callback functions */ pmdevice->callbacks.moal_memmove(pmadapter->pmoal_handle, pcb, &pmdevice->callbacks, sizeof(mlan_callbacks)); /* Assertion for all callback functions */ MASSERT(pcb->moal_init_fw_complete); MASSERT(pcb->moal_shutdown_fw_complete); MASSERT(pcb->moal_send_packet_complete); MASSERT(pcb->moal_recv_packet); MASSERT(pcb->moal_recv_event); MASSERT(pcb->moal_ioctl_complete); MASSERT(pcb->moal_write_reg); MASSERT(pcb->moal_read_reg); MASSERT(pcb->moal_alloc_mlan_buffer); MASSERT(pcb->moal_free_mlan_buffer); MASSERT(pcb->moal_write_data_sync); MASSERT(pcb->moal_read_data_sync); MASSERT(pcb->moal_mfree); MASSERT(pcb->moal_memcpy); MASSERT(pcb->moal_memcmp); MASSERT(pcb->moal_get_system_time); MASSERT(pcb->moal_init_timer); MASSERT(pcb->moal_free_timer); MASSERT(pcb->moal_start_timer); MASSERT(pcb->moal_stop_timer); MASSERT(pcb->moal_init_lock); MASSERT(pcb->moal_free_lock); MASSERT(pcb->moal_spin_lock); MASSERT(pcb->moal_spin_unlock); /* Save pmoal_handle */ pmadapter->pmoal_handle = pmdevice->pmoal_handle; if ((pmdevice->int_mode == INT_MODE_GPIO) && (pmdevice->gpio_pin == 0)) { PRINTM(MERROR, "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n"); ret = MLAN_STATUS_FAILURE; goto error; } pmadapter->init_para.int_mode = pmdevice->int_mode; pmadapter->init_para.gpio_pin = pmdevice->gpio_pin; /* card specific probing has been deferred until now .. */ if (MLAN_STATUS_SUCCESS != (ret = wlan_sdio_probe(pmadapter))) { ret = MLAN_STATUS_FAILURE; goto error; } #ifdef MFG_CMD_SUPPORT pmadapter->init_para.mfg_mode = pmdevice->mfg_mode; #endif #ifdef SDIO_MULTI_PORT_TX_AGGR pmadapter->init_para.mpa_tx_cfg = pmdevice->mpa_tx_cfg; #endif #ifdef SDIO_MULTI_PORT_RX_AGGR pmadapter->init_para.mpa_rx_cfg = pmdevice->mpa_rx_cfg; #endif pmadapter->init_para.auto_ds = pmdevice->auto_ds; pmadapter->init_para.ps_mode = pmdevice->ps_mode; if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K || pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K || pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_8K) pmadapter->init_para.max_tx_buf = pmdevice->max_tx_buf; #if defined(STA_SUPPORT) pmadapter->init_para.cfg_11d = pmdevice->cfg_11d; #endif for (i = 0; i < MLAN_MAX_BSS_NUM; i++) { pmadapter->priv[i] = MNULL; if (pmdevice->bss_attr[i].active == MTRUE) { /* For valid bss_attr, allocate memory for private structure */ if ((pcb-> moal_malloc(pmadapter->pmoal_handle, sizeof(mlan_private), MLAN_MEM_DEF, (t_u8 **) & pmadapter->priv[i]) != MLAN_STATUS_SUCCESS) || !pmadapter->priv[i]) { ret = MLAN_STATUS_FAILURE; goto error; } memset(pmadapter, pmadapter->priv[i], 0, sizeof(mlan_private)); pmadapter->priv[i]->adapter = pmadapter; /* Save bss_type, frame_type & bss_priority */ pmadapter->priv[i]->bss_type = (t_u8) pmdevice->bss_attr[i].bss_type; pmadapter->priv[i]->frame_type = (t_u8) pmdevice->bss_attr[i].frame_type; pmadapter->priv[i]->bss_priority = (t_u8) pmdevice->bss_attr[i].bss_priority; if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_STA) pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_STA; else if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_UAP) pmadapter->priv[i]->bss_role = MLAN_BSS_ROLE_UAP; /* Save bss_index and bss_num */ pmadapter->priv[i]->bss_index = i; pmadapter->priv[i]->bss_num = (t_u8) pmdevice->bss_attr[i].bss_num; /* init function table */ for (j = 0; j < (sizeof(ops) / sizeof(ops[0])); j++) { if (ops[j].bss_role == GET_BSS_ROLE(pmadapter->priv[i])) { memcpy(pmadapter, &pmadapter->priv[i]->ops, &ops[j], sizeof(mlan_operations)); } } } } /* Initialize lock variables */ if (wlan_init_lock_list(pmadapter) != MLAN_STATUS_SUCCESS) { ret = MLAN_STATUS_FAILURE; goto error; } /* Initialize timers */ if (wlan_init_timer(pmadapter) != MLAN_STATUS_SUCCESS) { ret = MLAN_STATUS_FAILURE; goto error; } /* Return pointer of mlan_adapter to MOAL */ *ppmlan_adapter = pmadapter; goto exit_register; error: PRINTM(MINFO, "Leave mlan_register with error\n"); /* Free timers */ wlan_free_timer(pmadapter); /* Free lock variables */ wlan_free_lock_list(pmadapter); for (i = 0; i < MLAN_MAX_BSS_NUM; i++) { if (pmadapter->priv[i]) pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter->priv[i]); } pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *) pmadapter); exit_register: LEAVE(); return ret; }
/** * @brief uap addba parameter handler * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int woal_uap_addba_param(struct net_device *dev, struct ifreq *req) { moal_private *priv = (moal_private *) netdev_priv(dev); mlan_ioctl_req *ioctl_req = NULL; mlan_ds_11n_cfg *cfg_11n = NULL; addba_param param; int ret = 0; ENTER(); memset(¶m, 0, sizeof(param)); /* Sanity check */ if (req->ifr_data == NULL) { PRINTM(MERROR, "uap_addba_param() corrupt data\n"); ret = -EFAULT; goto done; } if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } PRINTM(MIOCTL, "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d\n", (int) param.action, (int) param.timeout, (int) param.txwinsize, (int) param.rxwinsize); ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); if (ioctl_req == NULL) { LEAVE(); return -ENOMEM; } cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf; cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM; ioctl_req->req_id = MLAN_IOCTL_11N_CFG; if (!param.action) { /* Get addba param from MLAN */ ioctl_req->action = MLAN_ACT_GET; } else { /* Set addba param in MLAN */ ioctl_req->action = MLAN_ACT_SET; cfg_11n->param.addba_param.timeout = param.timeout; cfg_11n->param.addba_param.txwinsize = param.txwinsize; cfg_11n->param.addba_param.rxwinsize = param.rxwinsize; } if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { ret = -EFAULT; goto done; } param.timeout = cfg_11n->param.addba_param.timeout; param.txwinsize = cfg_11n->param.addba_param.txwinsize; param.rxwinsize = cfg_11n->param.addba_param.rxwinsize; /* Copy to user */ if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { PRINTM(MERROR, "Copy to user failed!\n"); ret = -EFAULT; goto done; } done: if (ioctl_req) kfree(ioctl_req); LEAVE(); return ret; }
/** * @brief Shutdown firmware * * @param pmlan_adapter A pointer to mlan_adapter structure * * @return MLAN_STATUS_SUCCESS * The firmware shutdown call succeeded. * MLAN_STATUS_PENDING * The firmware shutdown call is pending. * MLAN_STATUS_FAILURE * The firmware shutdown call failed. */ mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter) { mlan_status ret = MLAN_STATUS_PENDING; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; mlan_private *priv = MNULL; pmlan_callbacks pcb; t_s32 i = 0; ENTER(); MASSERT(pmlan_adapter); /* mlan already shutdown */ if (pmadapter->hw_status == WlanHardwareStatusNotReady) return MLAN_STATUS_SUCCESS; pmadapter->hw_status = WlanHardwareStatusClosing; /* wait for mlan_process to complete */ if (pmadapter->mlan_processing) { PRINTM(MWARN, "mlan main processing is still running\n"); return ret; } /* shut down mlan */ PRINTM(MINFO, "Shutdown mlan...\n"); pcb = &pmadapter->callbacks; /* Clean up Tx/Rx queues and delete BSS priority table */ for (i = 0; i < MLAN_MAX_BSS_NUM; i++) { if (pmadapter->priv[i]) { priv = pmadapter->priv[i]; wlan_clean_txrx(priv); wlan_delete_bsspriotbl(priv); #ifdef UAP_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { wlan_delete_station_list(priv); } #endif /* UAP_SUPPORT */ } } if (pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pmlan_lock) != MLAN_STATUS_SUCCESS) { ret = MLAN_STATUS_FAILURE; goto exit_shutdown_fw; } /* Free adapter structure */ wlan_free_adapter(pmadapter); if (pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pmlan_lock) != MLAN_STATUS_SUCCESS) { ret = MLAN_STATUS_FAILURE; goto exit_shutdown_fw; } /* Notify completion */ ret = wlan_shutdown_fw_complete(pmadapter); exit_shutdown_fw: LEAVE(); return ret; }
/** * @brief uap BSS config ioctl handler * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail */ static int woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req) { moal_private *priv = (moal_private *) netdev_priv(dev); int ret = 0; mlan_ds_bss *bss = NULL; mlan_ioctl_req *ioctl_req = NULL; int offset = 0; t_u32 action = 0; ENTER(); /* Sanity check */ if (req->ifr_data == NULL) { PRINTM(MERROR, "uap_bss_ioctl() corrupt data\n"); ret = -EFAULT; goto done; } /* Get action */ if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } offset += sizeof(action); /* Allocate an IOCTL request buffer */ ioctl_req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); if (ioctl_req == NULL) { ret = -ENOMEM; goto done; } bss = (mlan_ds_bss *) ioctl_req->pbuf; bss->sub_command = MLAN_OID_UAP_BSS_CONFIG; ioctl_req->req_id = MLAN_IOCTL_BSS; if (action == 1) { ioctl_req->action = MLAN_ACT_SET; } else { ioctl_req->action = MLAN_ACT_GET; } if (ioctl_req->action == MLAN_ACT_SET) { /* Get the BSS config from user */ if (copy_from_user (&bss->param.bss_config, req->ifr_data + offset, sizeof(mlan_uap_bss_param))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; } } if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { ret = -EFAULT; goto done; } if (ioctl_req->action == MLAN_ACT_GET) { offset = sizeof(action); /* Copy to user : BSS config */ if (copy_to_user (req->ifr_data + offset, &bss->param.bss_config, sizeof(mlan_uap_bss_param))) { PRINTM(MERROR, "Copy to user failed!\n"); ret = -EFAULT; goto done; } } done: if (ioctl_req) kfree(ioctl_req); LEAVE(); return ret; }
/** * @brief This function downloads the firmware * * @param pmlan_adapter A pointer to a t_void pointer to store * mlan_adapter structure pointer * @param pmfw A pointer to firmware image * * @return MLAN_STATUS_SUCCESS * The firmware download succeeded. * MLAN_STATUS_FAILURE * The firmware download failed. */ mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter, IN pmlan_fw_image pmfw) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_adapter *pmadapter = (mlan_adapter *) pmlan_adapter; t_u32 poll_num = 1; t_u32 winner = 0; ENTER(); MASSERT(pmlan_adapter); /* Card specific probing */ ret = wlan_sdio_probe(pmadapter); if (ret == MLAN_STATUS_FAILURE) { PRINTM(MERROR, "WLAN SDIO probe failed\n", ret); LEAVE(); return ret; } /* Check if firmware is already running */ ret = wlan_check_fw_status(pmadapter, poll_num); if (ret == MLAN_STATUS_SUCCESS) { PRINTM(MMSG, "WLAN FW already running! Skip FW download\n"); goto done; } poll_num = MAX_FIRMWARE_POLL_TRIES; /* Check if other interface is downloading */ ret = wlan_check_winner_status(pmadapter, &winner); if (ret == MLAN_STATUS_FAILURE) { PRINTM(MFATAL, "WLAN read winner status failed!\n"); goto done; } if (winner) { PRINTM(MMSG, "WLAN is not the winner (0x%x). Skip FW download\n", winner); poll_num = MAX_MULTI_INTERFACE_POLL_TRIES; goto poll_fw; } if (pmfw) { /* Download helper/firmware */ ret = wlan_dnld_fw(pmadapter, pmfw); if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret); LEAVE(); return ret; } } poll_fw: /* Check if the firmware is downloaded successfully or not */ ret = wlan_check_fw_status(pmadapter, poll_num); if (ret != MLAN_STATUS_SUCCESS) { PRINTM(MFATAL, "FW failed to be active in time!\n"); ret = MLAN_STATUS_FAILURE; LEAVE(); return ret; } done: /* re-enable host interrupt for mlan after fw dnld is successful */ wlan_enable_host_int(pmadapter); LEAVE(); return ret; }