int hdd_setP2pNoa( struct net_device *dev, tANI_U8 *command ) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); VOS_STATUS status = VOS_STATUS_SUCCESS; tP2pPsConfig NoA; int count, duration, interval; char *param; param = strchr(command, ' '); if (param == NULL) return -1; param++; sscanf(param, "%d %d %d", &count, &duration, &interval); VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: P2P_SET GO NoA: count=%d duration=%d interval=%d \n", __func__, count, duration, interval); /* PS Selection * Periodic NoA (2) * Single NOA (4) */ NoA.opp_ps = 0; NoA.ctWindow = 0; if (count == 1) { NoA.duration = 0; NoA.single_noa_duration = duration; NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA; } else { NoA.duration = duration; NoA.single_noa_duration = 0; NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA; } NoA.interval = interval; NoA.count = count; NoA.sessionid = pAdapter->sessionId; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " "interval %d count %d single noa duration %d " "PsSelection %x \n", __func__, NoA.opp_ps, NoA.ctWindow, NoA.duration, NoA.interval, NoA.count, NoA.single_noa_duration, NoA.psSelection); sme_p2pSetPs(hHal, &NoA); return status; }
static eHalStatus hdd_ScanRequestCallback(tHalHandle halHandle, void *pContext, tANI_U32 scanId, eCsrScanStatus status) { struct net_device *dev = (struct net_device *) pContext; hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); union iwreq_data wrqu; int we_event; char *msg; ENTER(); hddLog(LOGW,"%s called with halHandle = %p, pContext = %p, scanID = %d," " returned status = %d", __func__, halHandle, pContext, (int) scanId, (int) status); /* if there is a scan request pending when the wlan driver is unloaded we may be invoked as SME flushes its pending queue. If that is the case, the underlying net_device may have already been destroyed, so do some quick sanity before proceeding */ if (pAdapter->dev != dev) { hddLog(LOGW, "%s: device mismatch %p vs %p", __func__, pAdapter->dev, dev); return eHAL_STATUS_SUCCESS; } /* Check the scanId */ if (pHddCtx->scan_info.scanId != scanId) { hddLog(LOGW, "%s called with mismatched scanId pHddCtx->scan_info.scanId = %d " "scanId = %d ", __func__, (int) pHddCtx->scan_info.scanId, (int) scanId); } /* Scan is no longer pending */ pHddCtx->scan_info.mScanPending = VOS_FALSE; // notify any applications that may be interested memset(&wrqu, '\0', sizeof(wrqu)); we_event = SIOCGIWSCAN; msg = NULL; wireless_send_event(dev, we_event, &wrqu, msg); EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return eHAL_STATUS_SUCCESS; }
static eHalStatus hdd_CscanRequestCallback(tHalHandle halHandle, void *pContext, tANI_U32 scanId, eCsrScanStatus status) { struct net_device *dev = (struct net_device *) pContext; hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); union iwreq_data wrqu; int we_event; char *msg; VOS_STATUS vos_status = VOS_STATUS_SUCCESS; ENTER(); hddLog(LOG1,"%s called with halHandle = %p, pContext = %p, scanID = %d," " returned status = %d", __func__, halHandle, pContext, (int) scanId, (int) status); if (pwextBuf->scanId != scanId) { hddLog(LOGW, "%s called with mismatched scanId pWextState->scanId = %d " "scanId = %d ", __func__, (int) pwextBuf->scanId, (int) scanId); } pwextBuf->mScanPending = VOS_FALSE; memset(&wrqu, '\0', sizeof(wrqu)); we_event = SIOCGIWSCAN; msg = NULL; wireless_send_event(dev, we_event, &wrqu, msg); vos_status = vos_event_set(&pwextBuf->vosevent); if (!VOS_IS_STATUS_SUCCESS(vos_status)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("ERROR: HDD vos_event_set failed!!")); return VOS_STATUS_E_FAILURE; } EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return eHAL_STATUS_SUCCESS; }
static eHalStatus hdd_ScanRequestCallback(tHalHandle halHandle, void *pContext, tANI_U32 scanId, eCsrScanStatus status) { struct net_device *dev = (struct net_device *) pContext; hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); union iwreq_data wrqu; int we_event; char *msg; ENTER(); hddLog(LOGW,"%s called with halHandle = %p, pContext = %p, scanID = %d," " returned status = %d", __func__, halHandle, pContext, (int) scanId, (int) status); if (pAdapter->dev != dev) { hddLog(LOGW, "%s: device mismatch %p vs %p", __func__, pAdapter->dev, dev); return eHAL_STATUS_SUCCESS; } if (pHddCtx->scan_info.scanId != scanId) { hddLog(LOGW, "%s called with mismatched scanId pHddCtx->scan_info.scanId = %d " "scanId = %d ", __func__, (int) pHddCtx->scan_info.scanId, (int) scanId); } pHddCtx->scan_info.mScanPending = VOS_FALSE; memset(&wrqu, '\0', sizeof(wrqu)); we_event = SIOCGIWSCAN; msg = NULL; wireless_send_event(dev, we_event, &wrqu, msg); EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return eHAL_STATUS_SUCCESS; }
int hdd_setP2pPs( struct net_device *dev, void *msgData ) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); VOS_STATUS status = VOS_STATUS_SUCCESS; tP2pPsConfig NoA; p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData; NoA.opp_ps = pappNoA->opp_ps; NoA.ctWindow = pappNoA->ctWindow; NoA.duration = pappNoA->duration; NoA.interval = pappNoA->interval; NoA.count = pappNoA->count; NoA.single_noa_duration = pappNoA->single_noa_duration; NoA.psSelection = pappNoA->psSelection; NoA.sessionid = pAdapter->sessionId; sme_p2pSetPs(hHal, &NoA); return status; }
int wlan_hdd_del_virtual_intf( struct wiphy *wiphy, struct net_device *dev ) { hdd_context_t *pHddCtx = (hdd_context_t*) wiphy_priv(wiphy); hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev); ENTER(); hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d", __func__,pVirtAdapter->device_mode); if (pHddCtx->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:LOGP in Progress. Ignore!!!", __func__); return -EAGAIN; } wlan_hdd_release_intf_addr( pHddCtx, pVirtAdapter->macAddressCurrent.bytes ); hdd_stop_adapter( pHddCtx, pVirtAdapter ); hdd_close_adapter( pHddCtx, pVirtAdapter, TRUE ); EXIT(); return 0; }
int hdd_setP2pOpps( struct net_device *dev, tANI_U8 *command ) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); VOS_STATUS status = VOS_STATUS_SUCCESS; tP2pPsConfig NoA; char *param; int legacy_ps, opp_ps, ctwindow; param = strchr(command, ' '); if (param == NULL) return -1; param++; sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow); VOS_TRACE (VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d \n", __func__, legacy_ps, opp_ps, ctwindow); /* PS Selection * Opportunistic Power Save (1) */ /* From wpa_cli user need to use separate command to set ctWindow and Opps * When user want to set ctWindow during that time other parameters * values are coming from wpa_supplicant as -1. * Example : User want to set ctWindow with 30 then wpa_cli command : * P2P_SET ctwindow 30 * Command Received at hdd_hostapd_ioctl is as below: * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30) */ if (ctwindow != -1) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "Opportunistic Power Save is %s \n", (TRUE == pAdapter->ops) ? "Enable" : "Disable" ); if (ctwindow != pAdapter->ctw) { pAdapter->ctw = ctwindow; if(pAdapter->ops) { NoA.opp_ps = pAdapter->ops; NoA.ctWindow = pAdapter->ctw; NoA.duration = 0; NoA.single_noa_duration = 0; NoA.interval = 0; NoA.count = 0; NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC; NoA.sessionid = pAdapter->sessionId; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " "interval %d count %d single noa duration %d " "PsSelection %x \n", __func__, NoA.opp_ps, NoA.ctWindow, NoA.duration, NoA.interval, NoA.count, NoA.single_noa_duration, NoA.psSelection); sme_p2pSetPs(hHal, &NoA); } return 0; } } if (opp_ps != -1) { pAdapter->ops = opp_ps; if ((opp_ps != -1) && (pAdapter->ctw)) { NoA.opp_ps = opp_ps; NoA.ctWindow = pAdapter->ctw; NoA.duration = 0; NoA.single_noa_duration = 0; NoA.interval = 0; NoA.count = 0; NoA.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC; NoA.sessionid = pAdapter->sessionId; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " "interval %d count %d single noa duration %d " "PsSelection %x \n", __func__, NoA.opp_ps, NoA.ctWindow, NoA.duration, NoA.interval, NoA.count, NoA.single_noa_duration, NoA.psSelection); sme_p2pSetPs(hHal, &NoA); } } return status; }
int wlan_hdd_action( struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, bool channel_type_valid, const u8 *buf, size_t len, u64 *cookie ) #endif //LINUX_VERSION_CODE { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR( dev ); hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter ); tANI_U16 extendedWait = 0; tANI_U8 type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]); tANI_U8 subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]); tActionFrmType actionFrmType; bool noack = 0; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) hdd_adapter_t *goAdapter; #endif #ifdef WLAN_FEATURE_P2P_DEBUG if ((type == SIR_MAC_MGMT_FRAME) && (subType == SIR_MAC_MGMT_ACTION) && (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME)) { actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; if(actionFrmType > MAX_P2P_ACTION_FRAME_TYPE) { hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] unknown[%d] ---> OTA", actionFrmType); } else { hddLog(VOS_TRACE_LEVEL_ERROR,"[P2P] %s ---> OTA", p2p_action_frame_type[actionFrmType]); if( (actionFrmType == WLAN_HDD_PROV_DIS_REQ) && (globalP2PConnectionStatus == P2P_NOT_ACTIVE) ) { globalP2PConnectionStatus = P2P_GO_NEG_PROCESS; hddLog(LOGE,"[P2P State]Inactive state to " "GO negotation progress state"); } else if( (actionFrmType == WLAN_HDD_GO_NEG_CNF) && (globalP2PConnectionStatus == P2P_GO_NEG_PROCESS) ) { globalP2PConnectionStatus = P2P_GO_NEG_COMPLETED; hddLog(LOGE,"[P2P State]GO nego progress to GO nego" " completed state"); } } } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)) noack = dont_wait_for_ack; #endif //If the wait is coming as 0 with off channel set //then set the wait to 200 ms if (offchan && !wait) wait = ACTION_FRAME_DEFAULT_WAIT; hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d", __func__,pAdapter->device_mode); //Call sme API to send out a action frame. // OR can we send it directly through data path?? // After tx completion send tx status back. if ( ( WLAN_HDD_SOFTAP == pAdapter->device_mode ) || ( WLAN_HDD_P2P_GO == pAdapter->device_mode ) ) { if (type == SIR_MAC_MGMT_FRAME) { if (subType == SIR_MAC_MGMT_PROBE_RSP) { /* Drop Probe response recieved from supplicant, as for GO and SAP PE itself sends probe response */ goto err_rem_channel; } else if ((subType == SIR_MAC_MGMT_DISASSOC) || (subType == SIR_MAC_MGMT_DEAUTH)) { /* During EAP failure or P2P Group Remove supplicant * is sending del_station command to driver. From * del_station function, Driver will send deauth frame to * p2p client. No need to send disassoc frame from here. * so Drop the frame here and send tx indication back to * supplicant. */ tANI_U8 dstMac[ETH_ALEN] = {0}; memcpy(&dstMac, &buf[WLAN_HDD_80211_FRM_DA_OFFSET], ETH_ALEN); hddLog(VOS_TRACE_LEVEL_INFO, "%s: Deauth/Disassoc received for STA:" "%02x:%02x:%02x:%02x:%02x:%02x", __func__, dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5]); goto err_rem_channel; } } } if( NULL != cfgState->buf ) return -EBUSY; hddLog( LOG1, "Action frame tx request"); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) goAdapter = hdd_get_adapter( pAdapter->pHddCtx, WLAN_HDD_P2P_GO ); //If GO adapter exists and operating on same frequency //then we will not request remain on channel if( goAdapter && ( ieee80211_frequency_to_channel(chan->center_freq) == goAdapter->sessionCtx.ap.operatingChannel ) ) { goto send_frame; } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) if( offchan && wait) { int status; // In case of P2P Client mode if we are already // on the same channel then send the frame directly if((cfgState->remain_on_chan_ctx != NULL) && (cfgState->current_freq == chan->center_freq) ) { hddLog(LOG1,"action frame: extending the wait time\n"); extendedWait = (tANI_U16)wait; goto send_frame; } INIT_COMPLETION(pAdapter->offchannel_tx_event); status = wlan_hdd_request_remain_on_channel(wiphy, dev, chan, channel_type, wait, cookie, OFF_CHANNEL_ACTION_TX); if(0 != status) { if( (-EBUSY == status) && (cfgState->current_freq == chan->center_freq) ) { goto send_frame; } goto err_rem_channel; } /* Wait for driver to be ready on the requested channel */ status = wait_for_completion_interruptible_timeout( &pAdapter->offchannel_tx_event, msecs_to_jiffies(WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX)); if(!status) { hddLog( LOGE, "Not able to complete remain on channel request" " within timeout period"); goto err_rem_channel; } } else if ( offchan ) { /* Check before sending action frame whether we already remain on channel */ if(NULL == cfgState->remain_on_chan_ctx) { goto err_rem_channel; } } send_frame: #endif if(!noack) { cfgState->buf = vos_mem_malloc( len ); //buf; if( cfgState->buf == NULL ) return -ENOMEM; cfgState->len = len; vos_mem_copy( cfgState->buf, buf, len); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) if( cfgState->remain_on_chan_ctx ) { cfgState->action_cookie = cfgState->remain_on_chan_ctx->cookie; *cookie = cfgState->action_cookie; } else { #endif *cookie = (tANI_U32) cfgState->buf; cfgState->action_cookie = *cookie; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) } #endif } if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) || (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) || ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode ) ) { tANI_U8 sessionId = pAdapter->sessionId; if ((type == SIR_MAC_MGMT_FRAME) && (subType == SIR_MAC_MGMT_ACTION) && (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == WLAN_HDD_PUBLIC_ACTION_FRAME)) { actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; hddLog(LOG1, "Tx Action Frame %u \n", actionFrmType); if (actionFrmType == WLAN_HDD_PROV_DIS_REQ) { cfgState->actionFrmState = HDD_PD_REQ_ACK_PENDING; hddLog(LOG1, "%s: HDD_PD_REQ_ACK_PENDING \n", __func__); } else if (actionFrmType == WLAN_HDD_GO_NEG_REQ) { cfgState->actionFrmState = HDD_GO_NEG_REQ_ACK_PENDING; hddLog(LOG1, "%s: HDD_GO_NEG_REQ_ACK_PENDING \n", __func__); } } if (eHAL_STATUS_SUCCESS != sme_sendAction( WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId, buf, len, extendedWait, noack)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: sme_sendAction returned fail", __func__); goto err; } } else if( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) || ( WLAN_HDD_P2P_GO == pAdapter->device_mode ) ) { if( VOS_STATUS_SUCCESS != WLANSAP_SendAction( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, buf, len, 0 ) ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: WLANSAP_SendAction returned fail", __func__); goto err; } } return 0; err: if(!noack) { hdd_sendActionCnf( pAdapter, FALSE ); } return 0; err_rem_channel: *cookie = (tANI_U32)cfgState; cfg80211_mgmt_tx_status( pAdapter->dev, *cookie, buf, len, FALSE, GFP_KERNEL ); return 0; }
int wlan_hdd_cfg80211_cancel_remain_on_channel( struct wiphy *wiphy, struct net_device *dev, u64 cookie ) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter ); int status = 0; hddLog( LOG1, "Cancel remain on channel req"); if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:LOGP in Progress. Ignore!!!", __func__); return -EAGAIN; } /* FIXME cancel currently running remain on chan. * Need to check cookie and cancel accordingly */ if( (cfgState->remain_on_chan_ctx == NULL) || (cfgState->remain_on_chan_ctx->cookie != cookie) ) { hddLog( LOGE, "%s: No Remain on channel pending with specified cookie value", __func__); return -EINVAL; } /* wait until remain on channel ready event received * for already issued remain on channel request */ status = wait_for_completion_interruptible_timeout(&pAdapter->rem_on_chan_ready_event, msecs_to_jiffies(WAIT_REM_CHAN_READY)); if (!status) { hddLog( LOGE, "%s: timeout waiting for remain on channel ready indication", __func__); } INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); /* Issue abort remain on chan request to sme. * The remain on channel callback will make sure the remain_on_chan * expired event is sent. */ if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) || ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) || ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode ) ) { tANI_U8 sessionId = pAdapter->sessionId; sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ), sessionId ); } else if ( (WLAN_HDD_SOFTAP== pAdapter->device_mode) || (WLAN_HDD_P2P_GO == pAdapter->device_mode) ) { WLANSAP_CancelRemainOnChannel( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext); } else { hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid device_mode = %d", __func__, pAdapter->device_mode); return -EIO; } wait_for_completion_interruptible_timeout(&pAdapter->cancel_rem_on_chan_var, msecs_to_jiffies(WAIT_CANCEL_REM_CHAN)); return 0; }
static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie, rem_on_channel_request_type_t request_type ) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); hdd_remain_on_chan_ctx_t *pRemainChanCtx; hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter ); hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d", __func__,pAdapter->device_mode); hddLog( LOG1, "chan(hw_val)0x%x chan(centerfreq) %d chan type 0x%x, duration %d", chan->hw_value, chan->center_freq, channel_type, duration ); //Cancel existing remain On Channel if any wlan_hdd_cancel_existing_remain_on_channel(pAdapter); /* When P2P-GO and if we are trying to unload the driver then * wlan driver is keep on receiving the remain on channel command * and which is resulting in crash. So not allowing any remain on * channel requets when Load/Unload is in progress*/ if (((hdd_context_t*)pAdapter->pHddCtx)->isLoadUnloadInProgress) { hddLog( LOGE, "%s: Wlan Load/Unload is in progress", __func__); return -EBUSY; } if (((hdd_context_t*)pAdapter->pHddCtx)->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:LOGP in Progress. Ignore!!!", __func__); return -EAGAIN; } pRemainChanCtx = vos_mem_malloc( sizeof(hdd_remain_on_chan_ctx_t) ); if( NULL == pRemainChanCtx ) { hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Not able to allocate memory for Channel context", __func__); return -ENOMEM; } vos_mem_copy( &pRemainChanCtx->chan, chan, sizeof(struct ieee80211_channel) ); pRemainChanCtx->chan_type = channel_type; pRemainChanCtx->duration = duration; pRemainChanCtx->dev = dev; *cookie = (tANI_U32) pRemainChanCtx; pRemainChanCtx->cookie = *cookie; pRemainChanCtx->rem_on_chan_request = request_type; cfgState->remain_on_chan_ctx = pRemainChanCtx; cfgState->current_freq = chan->center_freq; INIT_COMPLETION(pAdapter->rem_on_chan_ready_event); //call sme API to start remain on channel. if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) || ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) || ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode ) ) { tANI_U8 sessionId = pAdapter->sessionId; //call sme API to start remain on channel. sme_RemainOnChannel( WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId, chan->hw_value, duration, wlan_hdd_remain_on_channel_callback, pAdapter ); sme_RegisterMgmtFrame(WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId, (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 ); } else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) || ( WLAN_HDD_P2P_GO == pAdapter->device_mode ) ) { //call sme API to start remain on channel. if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, chan->hw_value, duration, wlan_hdd_remain_on_channel_callback, pAdapter )) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: WLANSAP_RemainOnChannel returned fail", __func__); cfgState->remain_on_chan_ctx = NULL; vos_mem_free (pRemainChanCtx); return -EINVAL; } if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 )) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__); WLANSAP_CancelRemainOnChannel( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext); return -EINVAL; } } return 0; }
int iw_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); tCsrScanRequest scanRequest; v_U32_t scanId = 0; eHalStatus status = eHAL_STATUS_SUCCESS; struct iw_scan_req *scanReq = (struct iw_scan_req *)extra; hdd_adapter_t *con_sap_adapter; uint16_t con_dfs_ch; ENTER(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter !!!",__func__); #ifdef WLAN_BTAMP_FEATURE //Scan not supported when AMP traffic is on. if( VOS_TRUE == WLANBAP_AmpSessionOn() ) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: No scanning when AMP is on",__func__); return eHAL_STATUS_SUCCESS; } #endif /* Block All Scan during DFS operation and send null scan result */ con_sap_adapter = hdd_get_con_sap_adapter(pAdapter); if (con_sap_adapter) { con_dfs_ch = con_sap_adapter->sessionCtx.ap.sapConfig.channel; if (con_dfs_ch == AUTO_CHANNEL_SELECT) con_dfs_ch = con_sap_adapter->sessionCtx.ap.operatingChannel; if (VOS_IS_DFS_CH(con_dfs_ch)) { hddLog(LOGW, "%s:##In DFS Master mode. Scan aborted", __func__); return -EOPNOTSUPP; } } if(pAdapter->scan_info.mScanPending == TRUE) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:mScanPending is TRUE !!!",__func__); return eHAL_STATUS_SUCCESS; } if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__); return eHAL_STATUS_SUCCESS; } vos_mem_zero( &scanRequest, sizeof(scanRequest)); if (NULL != wrqu->data.pointer) { /* set scanType, active or passive */ if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) || (eSIR_ACTIVE_SCAN == pHddCtx->ioctl_scan_mode)) { scanRequest.scanType = eSIR_ACTIVE_SCAN; } else { scanRequest.scanType = eSIR_PASSIVE_SCAN; } /* set bssid using sockaddr from iw_scan_req */ vos_mem_copy(scanRequest.bssid, &scanReq->bssid.sa_data, sizeof(scanRequest.bssid) ); if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { if(scanReq->essid_len) { scanRequest.SSIDs.numOfSSIDs = 1; scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(sizeof(tCsrSSIDInfo)); if(scanRequest.SSIDs.SSIDList) { scanRequest.SSIDs.SSIDList->SSID.length = scanReq->essid_len; vos_mem_copy(scanRequest.SSIDs.SSIDList-> SSID.ssId,scanReq->essid,scanReq->essid_len); } else { scanRequest.SSIDs.numOfSSIDs = 0; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Unable to allocate memory",__func__); VOS_ASSERT(0); } } } /* set min and max channel time */ scanRequest.minChnTime = scanReq->min_channel_time; scanRequest.maxChnTime = scanReq->max_channel_time; } else { if (pHddCtx->ioctl_scan_mode == eSIR_ACTIVE_SCAN) { /* set the scan type to active */ scanRequest.scanType = eSIR_ACTIVE_SCAN; } else { scanRequest.scanType = eSIR_PASSIVE_SCAN; } vos_mem_set( scanRequest.bssid, sizeof( tCsrBssid ), 0xff ); /* set min and max channel time to zero */ scanRequest.minChnTime = 0; scanRequest.maxChnTime = 0; } /* set BSSType to default type */ scanRequest.BSSType = eCSR_BSS_TYPE_ANY; /*Scan all the channels */ scanRequest.ChannelInfo.numOfChannels = 0; scanRequest.ChannelInfo.ChannelList = NULL; /* set requestType to full scan */ scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; /* if previous genIE is not NULL, update ScanIE */ if (0 != pwextBuf->genIE.length) { memset( &pAdapter->scan_info.scanAddIE, 0, sizeof(pAdapter->scan_info.scanAddIE) ); memcpy( pAdapter->scan_info.scanAddIE.addIEdata, pwextBuf->genIE.addIEdata, pwextBuf->genIE.length ); pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length; pwextBuf->roamProfile.pAddIEScan = pAdapter->scan_info.scanAddIE.addIEdata; pwextBuf->roamProfile.nAddIEScanLength = pAdapter->scan_info.scanAddIE.length; /* clear previous genIE after use it */ memset( &pwextBuf->genIE, 0, sizeof(pwextBuf->genIE) ); } /* push addIEScan in scanRequset if exist */ if (pAdapter->scan_info.scanAddIE.addIEdata && pAdapter->scan_info.scanAddIE.length) { scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length; scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata; } status = sme_ScanRequest((WLAN_HDD_GET_CTX(pAdapter))->hHal, pAdapter->sessionId, &scanRequest, &scanId, &hdd_ScanRequestCallback, dev); if (!HAL_STATUS_SUCCESS(status)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:sme_ScanRequest fail %d!!!",__func__, status); goto error; } pAdapter->scan_info.mScanPending = TRUE; pAdapter->scan_info.scanId = scanId; error: if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len)) vos_mem_free(scanRequest.SSIDs.SSIDList); EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return status; }
/**============================================================================ @brief hdd_hard_start_xmit() - Function registered with the Linux OS for transmitting packets. There are 2 versions of this function. One that uses locked queue and other that uses lockless queues. Both have been retained to do some performance testing @param skb : [in] pointer to OS packet (sk_buff) @param dev : [in] pointer to Libra network device @return : NET_XMIT_DROP if packets are dropped : NET_XMIT_SUCCESS if packet is enqueued succesfully ===========================================================================*/ int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { VOS_STATUS status; WLANTL_ACEnumType ac; sme_QosWmmUpType up; skb_list_node_t *pktNode = NULL; hdd_list_node_t *anchor = NULL; v_SIZE_t pktListSize = 0; hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); v_BOOL_t granted; hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; v_BOOL_t txSuspended = VOS_FALSE; ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled; //Get TL AC corresponding to Qdisc queue index/AC. ac = hdd_QdiscAcToTlAC[skb->queue_mapping]; //user priority from IP header, which is already extracted and set from //select_queue call back function up = skb->priority; ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac]; #ifdef HDD_WMM_DEBUG VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Classified as ac %d up %d", __FUNCTION__, ac, up); #endif // HDD_WMM_DEBUG spin_lock(&pAdapter->wmm_tx_queue[ac].lock); /*For every increment of 10 pkts in the queue, we inform TL about pending pkts. * We check for +1 in the logic,to take care of Zero count which * occurs very frequently in low traffic cases */ if((pAdapter->wmm_tx_queue[ac].count + 1) % 10 == 0) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s:Queue is Filling up.Inform TL again about pending packets", __FUNCTION__); WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, pHddStaCtx->conn_info.staId[0], ac ); } //If we have already reached the max queue size, disable the TX queue if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size) { ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressured; ++pAdapter->hdd_stats.hddTxRxStats.txXmitBackPressuredAC[ac]; netif_tx_stop_queue(netdev_get_tx_queue(dev, skb_get_queue_mapping(skb))); pAdapter->isTxSuspended[ac] = VOS_TRUE; txSuspended = VOS_TRUE; } spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); if (VOS_TRUE == txSuspended) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: TX queue full for AC=%d Disable OS TX queue", __FUNCTION__, ac ); return NETDEV_TX_BUSY; } //Use the skb->cb field to hold the list node information pktNode = (skb_list_node_t *)&skb->cb; //Stick the OS packet inside this node. pktNode->skb = skb; //Stick the User Priority inside this node pktNode->userPriority = up; INIT_LIST_HEAD(&pktNode->anchor); //Insert the OS packet into the appropriate AC queue spin_lock(&pAdapter->wmm_tx_queue[ac].lock); status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac], &pktNode->anchor, &pktListSize ); spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); if ( !VOS_IS_STATUS_SUCCESS( status ) ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s:Insert Tx queue failed. Pkt dropped", __FUNCTION__); ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; ++pAdapter->stats.tx_dropped; kfree_skb(skb); return NETDEV_TX_OK; } ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueued; ++pAdapter->hdd_stats.hddTxRxStats.txXmitQueuedAC[ac]; //Make sure we have access to this access category if (likely(pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) || ( pHddStaCtx->conn_info.uIsAuthenticated == VOS_FALSE)) { granted = VOS_TRUE; } else { status = hdd_wmm_acquire_access( pAdapter, ac, &granted ); } if ( granted && ( pktListSize == 1 )) { //Let TL know we have a packet to send for this AC //VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s:Indicating Packet to TL", __FUNCTION__); status = WLANTL_STAPktPending( (WLAN_HDD_GET_CTX(pAdapter))->pvosContext, pHddStaCtx->conn_info.staId[0], ac ); if ( !VOS_IS_STATUS_SUCCESS( status ) ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Failed to signal TL for AC=%d", __FUNCTION__, ac ); //Remove the packet from queue. It must be at the back of the queue, as TX thread cannot preempt us in the middle //as we are in a soft irq context. Also it must be the same packet that we just allocated. spin_lock(&pAdapter->wmm_tx_queue[ac].lock); status = hdd_list_remove_back( &pAdapter->wmm_tx_queue[ac], &anchor ); spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; kfree_skb(skb); return NETDEV_TX_OK; } } dev->trans_start = jiffies; return NETDEV_TX_OK; }
int iw_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); tCsrScanResultInfo *pScanResult; eHalStatus status = eHAL_STATUS_SUCCESS; hdd_scan_info_t scanInfo; tScanResultHandle pResult; int i = 0; VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter buffer length %d!!!", __func__, (wrqu->data.length)?wrqu->data.length:IW_SCAN_MAX_DATA); ENTER(); if (TRUE == pHddCtx->scan_info.mScanPending) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:mScanPending is TRUE !!!",__func__); return -EAGAIN; } if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__); return -EAGAIN; } scanInfo.dev = dev; scanInfo.start = extra; scanInfo.info = info; if (0 == wrqu->data.length) { scanInfo.end = extra + IW_SCAN_MAX_DATA; } else { scanInfo.end = extra + wrqu->data.length; } status = sme_ScanGetResult(hHal,pAdapter->sessionId,NULL,&pResult); if (NULL == pResult) { hddLog(LOG1,"iw_get_scan: NULL Scan Result "); return 0; } pScanResult = sme_ScanResultGetFirst(hHal, pResult); while (pScanResult) { status = hdd_IndicateScanResult(&scanInfo, pScanResult); if (0 != status) { break; } i++; pScanResult = sme_ScanResultGetNext(hHal, pResult); } sme_ScanResultPurge(hHal, pResult); EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit total %d BSS reported !!!",__func__, i); return status; }
int iw_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); tCsrScanRequest scanRequest; v_U32_t scanId = 0; eHalStatus status = eHAL_STATUS_SUCCESS; struct iw_scan_req *scanReq = (struct iw_scan_req *)extra; ENTER(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter !!!",__func__); #ifdef WLAN_BTAMP_FEATURE if( VOS_TRUE == WLANBAP_AmpSessionOn() ) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: No scanning when AMP is on",__func__); return eHAL_STATUS_SUCCESS; } #endif if(pHddCtx->scan_info.mScanPending == TRUE) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:mScanPending is TRUE !!!",__func__); return eHAL_STATUS_SUCCESS; } if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__); return eHAL_STATUS_SUCCESS; } vos_mem_zero( &scanRequest, sizeof(scanRequest)); if (NULL != wrqu->data.pointer) { if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) || (eSIR_ACTIVE_SCAN == pHddCtx->scan_info.scan_mode)) { scanRequest.scanType = eSIR_ACTIVE_SCAN; } else { scanRequest.scanType = eSIR_PASSIVE_SCAN; } vos_mem_copy(scanRequest.bssid, &scanReq->bssid.sa_data, sizeof(scanRequest.bssid) ); if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { if(scanReq->essid_len) { scanRequest.SSIDs.numOfSSIDs = 1; scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(sizeof(tCsrSSIDInfo)); if(scanRequest.SSIDs.SSIDList) { scanRequest.SSIDs.SSIDList->SSID.length = scanReq->essid_len; vos_mem_copy(scanRequest.SSIDs.SSIDList-> SSID.ssId,scanReq->essid,scanReq->essid_len); } else { scanRequest.SSIDs.numOfSSIDs = 0; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Unable to allocate memory",__func__); VOS_ASSERT(0); } } } scanRequest.minChnTime = scanReq->min_channel_time; scanRequest.maxChnTime = scanReq->max_channel_time; } else { if(pHddCtx->scan_info.scan_mode == eSIR_ACTIVE_SCAN) { scanRequest.scanType = eSIR_ACTIVE_SCAN; } else { scanRequest.scanType = eSIR_PASSIVE_SCAN; } vos_mem_set( scanRequest.bssid, sizeof( tCsrBssid ), 0xff ); scanRequest.minChnTime = 0; scanRequest.maxChnTime = 0; } scanRequest.BSSType = eCSR_BSS_TYPE_ANY; scanRequest.ChannelInfo.numOfChannels = 0; scanRequest.ChannelInfo.ChannelList = NULL; scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; if (0 != pwextBuf->genIE.length) { memset( &pHddCtx->scan_info.scanAddIE, 0, sizeof(pHddCtx->scan_info.scanAddIE) ); memcpy( pHddCtx->scan_info.scanAddIE.addIEdata, pwextBuf->genIE.addIEdata, pwextBuf->genIE.length ); pHddCtx->scan_info.scanAddIE.length = pwextBuf->genIE.length; if (SIR_MAC_MAX_IE_LENGTH >= pwextBuf->genIE.length) { memcpy( pwextBuf->roamProfile.addIEScan, pHddCtx->scan_info.scanAddIE.addIEdata, pHddCtx->scan_info.scanAddIE.length); pwextBuf->roamProfile.nAddIEScanLength = pHddCtx->scan_info.scanAddIE.length; } else { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "Invalid ScanIE, Length is %d", pwextBuf->genIE.length); } memset( &pwextBuf->genIE, 0, sizeof(pwextBuf->genIE) ); } if (pHddCtx->scan_info.scanAddIE.addIEdata && pHddCtx->scan_info.scanAddIE.length) { scanRequest.uIEFieldLen = pHddCtx->scan_info.scanAddIE.length; scanRequest.pIEField = pHddCtx->scan_info.scanAddIE.addIEdata; } status = sme_ScanRequest( (WLAN_HDD_GET_CTX(pAdapter))->hHal, pAdapter->sessionId,&scanRequest, &scanId, &hdd_ScanRequestCallback, dev ); if (!HAL_STATUS_SUCCESS(status)) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:sme_ScanRequest fail %d!!!",__func__, status); goto error; } pHddCtx->scan_info.mScanPending = TRUE; pHddCtx->scan_info.scanId = scanId; error: if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len)) vos_mem_free(scanRequest.SSIDs.SSIDList); EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return status; }
static eHalStatus hdd_IndicateScanResult(hdd_scan_info_t *scanInfo, tCsrScanResultInfo *scan_result) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(scanInfo->dev) ; tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); tSirBssDescription *descriptor = &scan_result->BssDescriptor; struct iw_event event; char *current_event = scanInfo->start; char *end = scanInfo->end; char *last_event; char *current_pad; v_U16_t ie_length = 0; v_U16_t capabilityInfo; char *modestr; int error; char custom[MAX_CUSTOM_LEN]; char *p; hddLog( LOG1, "hdd_IndicateScanResult %02x:%02x:%02x:%02x:%02x:%02x", descriptor->bssId[0], descriptor->bssId[1], descriptor->bssId[2], descriptor->bssId[3], descriptor->bssId[4], descriptor->bssId[5]); error = 0; last_event = current_event; vos_mem_zero(&event, sizeof (event)); event.cmd = SIOCGIWAP; event.u.ap_addr.sa_family = ARPHRD_ETHER; vos_mem_copy (event.u.ap_addr.sa_data, descriptor->bssId, sizeof (descriptor->bssId)); current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_ADDR_LEN); if (last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWAP "); return -E2BIG; } last_event = current_event; vos_mem_zero(&event, sizeof (struct iw_event)); event.cmd = SIOCGIWNAME; switch (descriptor->nwType) { case eSIR_11A_NW_TYPE: modestr = "a"; break; case eSIR_11B_NW_TYPE: modestr = "b"; break; case eSIR_11G_NW_TYPE: modestr = "g"; break; case eSIR_11N_NW_TYPE: modestr = "n"; break; default: hddLog( LOGW, "%s: Unknown network type [%d]", __func__, descriptor->nwType); modestr = "?"; break; } snprintf(event.u.name, IFNAMSIZ, "IEEE 802.11%s", modestr); current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_CHAR_LEN); if (last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWNAME"); return -E2BIG; } last_event = current_event; vos_mem_zero( &event, sizeof (struct iw_event)); event.cmd = SIOCGIWFREQ; event.u.freq.m = descriptor->channelId; event.u.freq.e = 0; event.u.freq.i = 0; current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_FREQ_LEN); if (last_event == current_event) { return -E2BIG; } last_event = current_event; vos_mem_zero( &event, sizeof (struct iw_event)); event.cmd = SIOCGIWMODE; capabilityInfo = descriptor->capabilityInfo; if (SIR_MAC_GET_ESS(capabilityInfo)) { event.u.mode = IW_MODE_INFRA; } else if (SIR_MAC_GET_IBSS(capabilityInfo)) { event.u.mode = IW_MODE_ADHOC; } else { event.u.mode = IW_MODE_AUTO; } current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_UINT_LEN); if (last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWMODE"); return -E2BIG; } ie_length = GET_IE_LEN_IN_BSS( descriptor->length ); if (ie_length > 0) { static tDot11fBeaconIEs dot11BeaconIEs; tDot11fIESSID *pDot11SSID; tDot11fIESuppRates *pDot11SuppRates; tDot11fIEExtSuppRates *pDot11ExtSuppRates; tDot11fIEHTCaps *pDot11IEHTCaps; int numBasicRates = 0; int maxNumRates = 0; pDot11IEHTCaps = NULL; dot11fUnpackBeaconIEs ((tpAniSirGlobal) hHal, (tANI_U8 *) descriptor->ieFields, ie_length, &dot11BeaconIEs); pDot11SSID = &dot11BeaconIEs.SSID; if (pDot11SSID->present ) { last_event = current_event; vos_mem_zero (&event, sizeof (struct iw_event)); event.cmd = SIOCGIWESSID; event.u.data.flags = 1; event.u.data.length = scan_result->ssId.length; current_event = iwe_stream_add_point (scanInfo->info,current_event, end, &event, (char *)scan_result->ssId.ssId); if(last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWESSID"); return -E2BIG; } } if( hdd_GetWPARSNIEs( ( tANI_U8 *) descriptor->ieFields, ie_length, &last_event, ¤t_event, scanInfo ) < 0 ) { hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWESSID"); return -E2BIG; } last_event = current_event; current_pad = current_event + IW_EV_LCP_LEN; vos_mem_zero( &event, sizeof (struct iw_event)); event.cmd = SIOCGIWRATE; pDot11SuppRates = &dot11BeaconIEs.SuppRates; if (pDot11SuppRates->present ) { int i; numBasicRates = pDot11SuppRates->num_rates; for (i=0; i<pDot11SuppRates->num_rates; i++) { if (0 != (pDot11SuppRates->rates[i] & 0x7F)) { event.u.bitrate.value = hdd_TranslateABGRateToMbpsRate ( &pDot11SuppRates->rates[i]); current_pad = iwe_stream_add_value (scanInfo->info,current_event, current_pad, end, &event, IW_EV_PARAM_LEN); } } } pDot11ExtSuppRates = &dot11BeaconIEs.ExtSuppRates; if (pDot11ExtSuppRates->present ) { int i,no_of_rates; maxNumRates = numBasicRates + pDot11ExtSuppRates->num_rates; maxNumRates = VOS_MIN(maxNumRates , IW_MAX_BITRATES); if((maxNumRates - numBasicRates) > MAX_RATES) { no_of_rates = MAX_RATES; hddLog( LOGW, "Accessing array out of bound that array is pDot11ExtSuppRates->rates "); } else { no_of_rates = maxNumRates - numBasicRates; } for ( i=0; i< no_of_rates ; i++ ) { if (0 != (pDot11ExtSuppRates->rates[i] & 0x7F)) { event.u.bitrate.value = hdd_TranslateABGRateToMbpsRate ( &pDot11ExtSuppRates->rates[i]); current_pad = iwe_stream_add_value (scanInfo->info,current_event, current_pad, end, &event, IW_EV_PARAM_LEN); } } } if ((current_pad - current_event) >= IW_EV_LCP_LEN) { current_event = current_pad; } else { if (last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for SIOCGIWRATE"); return -E2BIG; } } last_event = current_event; vos_mem_zero (&event, sizeof (struct iw_event)); event.cmd = SIOCGIWENCODE; if (SIR_MAC_GET_PRIVACY(capabilityInfo)) { event.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; } else { event.u.data.flags = IW_ENCODE_DISABLED; } event.u.data.length = 0; current_event = iwe_stream_add_point(scanInfo->info,current_event, end, &event, (char *)pDot11SSID->ssid); if(last_event == current_event) { return -E2BIG; } } last_event = current_event; vos_mem_zero( &event, sizeof (struct iw_event)); event.cmd = IWEVQUAL; event.u.qual.qual = descriptor->rssi; event.u.qual.noise = descriptor->sinr; if (( eConnectionState_Associated == pAdapter->sessionCtx.station.conn_info.connState ) && ( VOS_TRUE == vos_mem_compare(descriptor->bssId, pAdapter->sessionCtx.station.conn_info.bssId, WNI_CFG_BSSID_LEN))) { event.u.qual.level = pAdapter->rssi; } else { event.u.qual.level = VOS_MIN ((descriptor->rssi + descriptor->sinr), 0); } event.u.qual.updated = IW_QUAL_ALL_UPDATED; current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_QUAL_LEN); if(last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for IWEVQUAL"); return -E2BIG; } event.cmd = IWEVCUSTOM; p = custom; p += scnprintf(p, MAX_CUSTOM_LEN, " Age: %lu", vos_timer_get_system_ticks() - descriptor->nReceivedTime); event.u.data.length = p - custom; current_event = iwe_stream_add_point (scanInfo->info,current_event, end, &event, custom); if(last_event == current_event) { hddLog( LOGW, "hdd_IndicateScanResult: no space for IWEVCUSTOM (age)"); return -E2BIG; } scanInfo->start = current_event; return 0; }
int iw_set_cscan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); tCsrScanRequest scanRequest; v_U32_t scanId = 0; eHalStatus status = eHAL_STATUS_SUCCESS; v_U8_t channelIdx; ENTER(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter !!!",__func__); #ifdef WLAN_BTAMP_FEATURE //Scan not supported when AMP traffic is on. if( VOS_TRUE == WLANBAP_AmpSessionOn() ) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: No scanning when AMP is on",__func__); return eHAL_STATUS_SUCCESS; } #endif if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__); return eHAL_STATUS_SUCCESS; } vos_mem_zero( &scanRequest, sizeof(scanRequest)); if (NULL != wrqu->data.pointer) { char *str_ptr = NULL; tCsrSSIDInfo *SsidInfo = NULL; int num_ssid = 0; int i, j, ssid_start; hdd_scan_pending_option_e scanPendingOption = WEXT_SCAN_PENDING_GIVEUP; str_ptr = extra; i = WEXT_CSCAN_HEADER_SIZE; if( WEXT_CSCAN_PENDING_SECTION == str_ptr[i] ) { scanPendingOption = (hdd_scan_pending_option_e)str_ptr[++i]; ++i; } pHddCtx->scan_info.scan_pending_option = scanPendingOption; if(pHddCtx->scan_info.mScanPending == TRUE) { hddLog(LOG1,"%s: mScanPending is TRUE",__func__); /* If any scan is pending, just giveup this scan request */ if(WEXT_SCAN_PENDING_GIVEUP == scanPendingOption) { pHddCtx->scan_info.waitScanResult = FALSE; return eHAL_STATUS_SUCCESS; } /* If any scan pending, wait till finish current scan, and try this scan request when previous scan finish */ else if(WEXT_SCAN_PENDING_DELAY == scanPendingOption) { pHddCtx->scan_info.waitScanResult = TRUE; vos_event_reset(&pHddCtx->scan_info.scan_finished_event); if(vos_wait_single_event(&pHddCtx->scan_info.scan_finished_event, WEXT_CSCAN_SCAN_DONE_WAIT_TIME)) { hddLog(LOG1,"%s: Previous SCAN does not finished on time",__func__); return eHAL_STATUS_SUCCESS; } } /* Piggyback previous scan result */ else if(WEXT_SCAN_PENDING_PIGGYBACK == scanPendingOption) { pHddCtx->scan_info.waitScanResult = TRUE; return eHAL_STATUS_SUCCESS; } } pHddCtx->scan_info.waitScanResult = FALSE; /* Check for scan IE */ while( WEXT_CSCAN_SSID_SECTION == str_ptr[i] ) { /* ssid_len */ if(str_ptr[++i] != WEXT_CSCAN_CHANNEL_SECTION) { /* total number of ssid's */ num_ssid++; /* increment length filed */ i += str_ptr[i] + 1; } /* i should be saved and it will be pointing to 'C' */ } VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: numSsid %d !!!",__func__, num_ssid); if( num_ssid ) { /* To be fixed in SME and PE: override the number of ssid with 1, * as SME and PE does not handle multiple SSID in scan request * */ scanRequest.SSIDs.numOfSSIDs = num_ssid; /* Allocate num_ssid tCsrSSIDInfo structure */ SsidInfo = scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(num_ssid*sizeof(tCsrSSIDInfo)); if(NULL == scanRequest.SSIDs.SSIDList) { hddLog(VOS_TRACE_LEVEL_ERROR, "memory alloc failed SSIDInfo buffer"); return -ENOMEM; } /* copy all the ssid's and their length */ ssid_start = WEXT_CSCAN_HEADER_SIZE + 1;/* skipping 'S' */ for(j = 0; j < num_ssid; j++) { if( SIR_MAC_MAX_SSID_LENGTH < str_ptr[ssid_start]){ scanRequest.SSIDs.numOfSSIDs -= 1; } else{ /* get the ssid length */ SsidInfo->SSID.length = str_ptr[ssid_start++]; vos_mem_copy(SsidInfo->SSID.ssId, &str_ptr[ssid_start], SsidInfo->SSID.length); hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "SSID number %d: %s", j, SsidInfo->SSID.ssId); } /* skipping length */ ssid_start += str_ptr[ssid_start - 1] + 1; /* Store next ssid info */ SsidInfo++; } } /* Check for Channel IE */ if ( WEXT_CSCAN_CHANNEL_SECTION == str_ptr[i]) { if( str_ptr[++i] == 0 ) { scanRequest.ChannelInfo.numOfChannels = 0; scanRequest.ChannelInfo.ChannelList = NULL; i++; } else { /* increment the counter */ scanRequest.ChannelInfo.numOfChannels = str_ptr[i++]; /* store temp channel list */ /* SME expects 1 byte channel content */ scanRequest.ChannelInfo.ChannelList = vos_mem_malloc(scanRequest.ChannelInfo.numOfChannels * sizeof(v_U8_t)); if(NULL == scanRequest.ChannelInfo.ChannelList) { hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "memory alloc failed for channel list creation"); status = -ENOMEM; goto exit_point; } for(channelIdx = 0; channelIdx < scanRequest.ChannelInfo.numOfChannels; channelIdx++) { /* SCAN request from upper layer has 2 bytes channel */ scanRequest.ChannelInfo.ChannelList[channelIdx] = (v_U8_t)str_ptr[i]; i += sizeof(v_U16_t); } } } /* Set default */ scanRequest.scanType = eSIR_ACTIVE_SCAN; scanRequest.minChnTime = 0; scanRequest.maxChnTime = 0; /* Now i is pointing to passive dwell dwell time */ /* 'P',min dwell time, max dwell time */ /* next two offsets contain min and max channel time */ if( WEXT_CSCAN_PASV_DWELL_SECTION == (str_ptr[i]) ) { /* No SSID specified, num_ssid == 0, then start paasive scan */ if (!num_ssid || (eSIR_PASSIVE_SCAN == pHddCtx->scan_info.scan_mode)) { scanRequest.scanType = eSIR_PASSIVE_SCAN; scanRequest.minChnTime = (v_U8_t)str_ptr[++i];//scanReq->min_channel_time; scanRequest.maxChnTime = (v_U8_t)str_ptr[++i];//scanReq->max_channel_time; i++; } else { i += 3; } } /* H indicates active channel time */ if( WEXT_CSCAN_HOME_DWELL_SECTION == (str_ptr[i]) ) { if (num_ssid || (eSIR_ACTIVE_SCAN == pHddCtx->scan_info.scan_mode)) { scanRequest.scanType = eSIR_ACTIVE_SCAN; scanRequest.minChnTime = str_ptr[++i];//scanReq->min_channel_time; scanRequest.maxChnTime = str_ptr[++i];//scanReq->max_channel_time; i++; } else { i +=3; } } scanRequest.BSSType = eCSR_BSS_TYPE_ANY; /* set requestType to full scan */ scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; pHddCtx->scan_info.mScanPending = TRUE; /* if previous genIE is not NULL, update ScanIE */ if(0 != pwextBuf->genIE.length) { memset( &pHddCtx->scan_info.scanAddIE, 0, sizeof(pHddCtx->scan_info.scanAddIE) ); memcpy( pHddCtx->scan_info.scanAddIE.addIEdata, pwextBuf->genIE.addIEdata, pwextBuf->genIE.length ); pHddCtx->scan_info.scanAddIE.length = pwextBuf->genIE.length; pwextBuf->roamProfile.pAddIEScan = pHddCtx->scan_info.scanAddIE.addIEdata; pwextBuf->roamProfile.nAddIEScanLength = pHddCtx->scan_info.scanAddIE.length; /* clear previous genIE after use it */ memset( &pwextBuf->genIE, 0, sizeof(pwextBuf->genIE) ); } /* push addIEScan in scanRequset if exist */ if (pHddCtx->scan_info.scanAddIE.addIEdata && pHddCtx->scan_info.scanAddIE.length) { scanRequest.uIEFieldLen = pHddCtx->scan_info.scanAddIE.length; scanRequest.pIEField = pHddCtx->scan_info.scanAddIE.addIEdata; } status = sme_ScanRequest( (WLAN_HDD_GET_CTX(pAdapter))->hHal, pAdapter->sessionId,&scanRequest, &scanId, &hdd_ScanRequestCallback, dev ); if( !HAL_STATUS_SUCCESS(status) ) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: SME scan fail status %d !!!",__func__, status); pHddCtx->scan_info.mScanPending = FALSE; status = -EINVAL; goto exit_point; } pHddCtx->scan_info.scanId = scanId; } //end of data->pointer else { status = -1; } exit_point: /* free ssidlist */ if (scanRequest.SSIDs.SSIDList) { vos_mem_free(scanRequest.SSIDs.SSIDList); } /* free the channel list */ if(scanRequest.ChannelInfo.ChannelList) { vos_mem_free((void*)scanRequest.ChannelInfo.ChannelList); } EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return status; }
int hdd_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { v_U16_t rt_hdr_len; struct ieee80211_hdr *hdr; hdd_adapter_t *pPgBkAdapter, *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); struct ieee80211_radiotap_header *rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; /*Supplicant sends the EAPOL packet on monitor interface*/ pPgBkAdapter = pAdapter->sessionCtx.monitor.pAdapterForTx; if(pPgBkAdapter == NULL) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: No Adapter to piggy back. Dropping the pkt on monitor inf", __func__); goto fail; /* too short to be possibly valid */ } /* check if toal skb length is greater then radio tab header length of not */ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) goto fail; /* too short to be possibly valid */ /* check if radio tap header version is correct or not */ if (unlikely(rtap_hdr->it_version)) goto fail; /* only version 0 is supported */ /*Strip off the radio tap header*/ rt_hdr_len = ieee80211_get_radiotap_len(skb->data); /* check if skb length if greator then total radio tap header length ot not*/ if (unlikely(skb->len < rt_hdr_len)) goto fail; /* Update the trans_start for this netdev */ dev->trans_start = jiffies; /* * fix up the pointers accounting for the radiotap * header still being in there. */ skb_set_mac_header(skb, rt_hdr_len); skb_set_network_header(skb, rt_hdr_len); skb_set_transport_header(skb, rt_hdr_len); /* Pull rtap header out of the skb */ skb_pull(skb, rt_hdr_len); /*Supplicant adds: radiotap Hdr + radiotap data + 80211 Header. So after * radio tap header and 802.11 header starts */ hdr = (struct ieee80211_hdr *)skb->data; /* Send data frames through the normal Data path. In this path we will * conver rcvd 802.11 packet to 802.3 packet */ if ( (hdr->frame_control & HDD_FRAME_TYPE_MASK) == HDD_FRAME_TYPE_DATA) { v_U8_t da[6]; v_U8_t sa[6]; memcpy (da, hdr->addr1, VOS_MAC_ADDR_SIZE); memcpy (sa, hdr->addr2, VOS_MAC_ADDR_SIZE); /* Pull 802.11 MAC header */ skb_pull(skb, HDD_80211_HEADER_LEN); if ( HDD_FRAME_SUBTYPE_QOSDATA == (hdr->frame_control & HDD_FRAME_SUBTYPE_MASK)) { skb_pull(skb, HDD_80211_HEADER_QOS_CTL); } /* Pull LLC header */ skb_pull(skb, HDD_LLC_HDR_LEN); /* Create space for Ethernet header */ skb_push(skb, HDD_MAC_HDR_SIZE*2); memcpy(&skb->data[0], da, HDD_MAC_HDR_SIZE); memcpy(&skb->data[HDD_DEST_ADDR_OFFSET], sa, HDD_MAC_HDR_SIZE); /* Only EAPOL Data packets are allowed through monitor interface */ if (vos_be16_to_cpu( (*(unsigned short*)&skb->data[HDD_ETHERTYPE_802_1_X_FRAME_OFFSET]) ) != HDD_ETHERTYPE_802_1_X) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: Not a Eapol packet. Drop this frame", __func__); //If not EAPOL frames, drop them. kfree_skb(skb); return NETDEV_TX_OK; } skb->protocol = htons(HDD_ETHERTYPE_802_1_X); hdd_hostapd_select_queue(pPgBkAdapter->dev, skb); return hdd_softap_hard_start_xmit( skb, pPgBkAdapter->dev ); } else { VOS_STATUS status; WLANTL_ACEnumType ac = 0; skb_list_node_t *pktNode = NULL; v_SIZE_t pktListSize = 0; spin_lock(&pAdapter->wmm_tx_queue[ac].lock); //If we have already reached the max queue size, disable the TX queue if ( pAdapter->wmm_tx_queue[ac].count == pAdapter->wmm_tx_queue[ac].max_size) { /* We want to process one packet at a time, so lets disable all TX queues * and re-enable the queues once we get TX feedback for this packet */ netif_tx_stop_all_queues(pAdapter->dev); pAdapter->isTxSuspended[ac] = VOS_TRUE; spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); return NETDEV_TX_BUSY; } spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); //Use the skb->cb field to hold the list node information pktNode = (skb_list_node_t *)&skb->cb; //Stick the OS packet inside this node. pktNode->skb = skb; INIT_LIST_HEAD(&pktNode->anchor); //Insert the OS packet into the appropriate AC queue spin_lock(&pAdapter->wmm_tx_queue[ac].lock); status = hdd_list_insert_back_size( &pAdapter->wmm_tx_queue[ac], &pktNode->anchor, &pktListSize ); spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); if ( !VOS_IS_STATUS_SUCCESS( status ) ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:Insert Tx queue failed. Pkt dropped", __FUNCTION__); kfree_skb(skb); return NETDEV_TX_OK; } if ( pktListSize == 1 ) { /* In this context we cannot acquire any mutex etc. And to transmit * this packet we need to call SME API. So to take care of this we will * schedule a workqueue */ schedule_work(&pPgBkAdapter->monTxWorkQueue); } return NETDEV_TX_OK; } fail: VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Packet Rcvd at Monitor interface is not proper," " Dropping the packet", __func__); kfree_skb(skb); return NETDEV_TX_OK; }
int iw_set_cscan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev) ; hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); tCsrScanRequest scanRequest; v_U32_t scanId = 0; eHalStatus status = eHAL_STATUS_SUCCESS; v_U8_t channelIdx; ENTER(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: enter !!!",__func__); #ifdef WLAN_BTAMP_FEATURE if( VOS_TRUE == WLANBAP_AmpSessionOn() ) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: No scanning when AMP is on",__func__); return eHAL_STATUS_SUCCESS; } #endif if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:LOGP in Progress. Ignore!!!",__func__); return eHAL_STATUS_SUCCESS; } vos_mem_zero( &scanRequest, sizeof(scanRequest)); if (NULL != wrqu->data.pointer) { char *str_ptr = NULL; tCsrSSIDInfo *SsidInfo = NULL; int num_ssid = 0; int i, j, ssid_start; hdd_scan_pending_option_e scanPendingOption = WEXT_SCAN_PENDING_GIVEUP; str_ptr = extra; i = WEXT_CSCAN_HEADER_SIZE; if( WEXT_CSCAN_PENDING_SECTION == str_ptr[i] ) { scanPendingOption = (hdd_scan_pending_option_e)str_ptr[++i]; ++i; } pHddCtx->scan_info.scan_pending_option = scanPendingOption; if(pHddCtx->scan_info.mScanPending == TRUE) { hddLog(LOG1,"%s: mScanPending is TRUE",__func__); if(WEXT_SCAN_PENDING_GIVEUP == scanPendingOption) { pHddCtx->scan_info.waitScanResult = FALSE; return eHAL_STATUS_SUCCESS; } else if(WEXT_SCAN_PENDING_DELAY == scanPendingOption) { pHddCtx->scan_info.waitScanResult = TRUE; vos_event_reset(&pHddCtx->scan_info.scan_finished_event); if(vos_wait_single_event(&pHddCtx->scan_info.scan_finished_event, WEXT_CSCAN_SCAN_DONE_WAIT_TIME)) { hddLog(LOG1,"%s: Previous SCAN does not finished on time",__func__); return eHAL_STATUS_SUCCESS; } } else if(WEXT_SCAN_PENDING_PIGGYBACK == scanPendingOption) { pHddCtx->scan_info.waitScanResult = TRUE; return eHAL_STATUS_SUCCESS; } } pHddCtx->scan_info.waitScanResult = FALSE; while( WEXT_CSCAN_SSID_SECTION == str_ptr[i] ) { if(str_ptr[++i] != WEXT_CSCAN_CHANNEL_SECTION) { num_ssid++; i += str_ptr[i] + 1; } } VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: numSsid %d !!!",__func__, num_ssid); if( num_ssid ) { scanRequest.SSIDs.numOfSSIDs = num_ssid; SsidInfo = scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(num_ssid*sizeof(tCsrSSIDInfo)); if(NULL == scanRequest.SSIDs.SSIDList) { hddLog(VOS_TRACE_LEVEL_ERROR, "memory alloc failed SSIDInfo buffer"); return -ENOMEM; } ssid_start = WEXT_CSCAN_HEADER_SIZE + 1; for(j = 0; j < num_ssid; j++) { if( SIR_MAC_MAX_SSID_LENGTH < str_ptr[ssid_start]){ scanRequest.SSIDs.numOfSSIDs -= 1; } else{ SsidInfo->SSID.length = str_ptr[ssid_start++]; vos_mem_copy(SsidInfo->SSID.ssId, &str_ptr[ssid_start], SsidInfo->SSID.length); hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "SSID number %d: %s\n", j, SsidInfo->SSID.ssId); } ssid_start += str_ptr[ssid_start - 1] + 1; SsidInfo++; } } if ( WEXT_CSCAN_CHANNEL_SECTION == str_ptr[i]) { if( str_ptr[++i] == 0 ) { scanRequest.ChannelInfo.numOfChannels = 0; scanRequest.ChannelInfo.ChannelList = NULL; i++; } else { scanRequest.ChannelInfo.numOfChannels = str_ptr[i++]; scanRequest.ChannelInfo.ChannelList = vos_mem_malloc(scanRequest.ChannelInfo.numOfChannels * sizeof(v_U8_t)); if(NULL == scanRequest.ChannelInfo.ChannelList) { hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "memory alloc failed for channel list creation"); status = -ENOMEM; goto exit_point; } for(channelIdx = 0; channelIdx < scanRequest.ChannelInfo.numOfChannels; channelIdx++) { scanRequest.ChannelInfo.ChannelList[channelIdx] = (v_U8_t)str_ptr[i]; i += sizeof(v_U16_t); } } } scanRequest.scanType = eSIR_ACTIVE_SCAN; scanRequest.minChnTime = 0; scanRequest.maxChnTime = 0; if( WEXT_CSCAN_PASV_DWELL_SECTION == (str_ptr[i]) ) { if (!num_ssid || (eSIR_PASSIVE_SCAN == pHddCtx->scan_info.scan_mode)) { scanRequest.scanType = eSIR_PASSIVE_SCAN; scanRequest.minChnTime = (v_U8_t)str_ptr[++i]; scanRequest.maxChnTime = (v_U8_t)str_ptr[++i]; i++; } else { i += 3; } } if( WEXT_CSCAN_HOME_DWELL_SECTION == (str_ptr[i]) ) { if (num_ssid || (eSIR_ACTIVE_SCAN == pHddCtx->scan_info.scan_mode)) { scanRequest.scanType = eSIR_ACTIVE_SCAN; scanRequest.minChnTime = str_ptr[++i]; scanRequest.maxChnTime = str_ptr[++i]; i++; } else { i +=3; } } scanRequest.BSSType = eCSR_BSS_TYPE_ANY; scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; pHddCtx->scan_info.mScanPending = TRUE; if(0 != pwextBuf->genIE.length) { memset( &pHddCtx->scan_info.scanAddIE, 0, sizeof(pHddCtx->scan_info.scanAddIE) ); memcpy( pHddCtx->scan_info.scanAddIE.addIEdata, pwextBuf->genIE.addIEdata, pwextBuf->genIE.length ); pHddCtx->scan_info.scanAddIE.length = pwextBuf->genIE.length; if (SIR_MAC_MAX_IE_LENGTH >= pwextBuf->genIE.length) { memcpy( pwextBuf->roamProfile.addIEScan, pHddCtx->scan_info.scanAddIE.addIEdata, pHddCtx->scan_info.scanAddIE.length); pwextBuf->roamProfile.nAddIEScanLength = pHddCtx->scan_info.scanAddIE.length; } else { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "Invalid ScanIE, Length is %d", pwextBuf->genIE.length); } memset( &pwextBuf->genIE, 0, sizeof(pwextBuf->genIE) ); } if (pHddCtx->scan_info.scanAddIE.addIEdata && pHddCtx->scan_info.scanAddIE.length) { scanRequest.uIEFieldLen = pHddCtx->scan_info.scanAddIE.length; scanRequest.pIEField = pHddCtx->scan_info.scanAddIE.addIEdata; } status = sme_ScanRequest( (WLAN_HDD_GET_CTX(pAdapter))->hHal, pAdapter->sessionId,&scanRequest, &scanId, &hdd_ScanRequestCallback, dev ); if( !HAL_STATUS_SUCCESS(status) ) { VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: SME scan fail status %d !!!",__func__, status); pHddCtx->scan_info.mScanPending = FALSE; status = -EINVAL; goto exit_point; } pHddCtx->scan_info.scanId = scanId; } else { status = -1; } exit_point: if (scanRequest.SSIDs.SSIDList) { vos_mem_free(scanRequest.SSIDs.SSIDList); } if(scanRequest.ChannelInfo.ChannelList) { vos_mem_free((void*)scanRequest.ChannelInfo.ChannelList); } EXIT(); VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: exit !!!",__func__); return status; }
/**============================================================================ @brief hdd_stats() - Function registered with the Linux OS for device TX/RX statistic @param dev : [in] pointer to Libra network device @return : pointer to net_device_stats structure ===========================================================================*/ struct net_device_stats* hdd_stats(struct net_device *dev) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); return &pAdapter->stats; }
static eHalStatus hdd_IndicateScanResult(hdd_scan_info_t *scanInfo, tCsrScanResultInfo *scan_result) { hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(scanInfo->dev) ; tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); tSirBssDescription *descriptor = &scan_result->BssDescriptor; struct iw_event event; char *current_event = scanInfo->start; char *end = scanInfo->end; char *last_event; char *current_pad; v_U16_t ie_length = 0; v_U16_t capabilityInfo; char *modestr; int error; char custom[MAX_CUSTOM_LEN]; char *p; hddLog( LOG1, "hdd_IndicateScanResult " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(descriptor->bssId)); error = 0; last_event = current_event; vos_mem_zero(&event, sizeof (event)); /* BSSID */ event.cmd = SIOCGIWAP; event.u.ap_addr.sa_family = ARPHRD_ETHER; vos_mem_copy (event.u.ap_addr.sa_data, descriptor->bssId, sizeof (descriptor->bssId)); current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_ADDR_LEN); if (last_event == current_event) { /* no space to add event */ /* Error code may be E2BIG */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWAP "); return -E2BIG; } last_event = current_event; vos_mem_zero(&event, sizeof (struct iw_event)); /* Protocol Name */ event.cmd = SIOCGIWNAME; switch (descriptor->nwType) { case eSIR_11A_NW_TYPE: modestr = "a"; break; case eSIR_11B_NW_TYPE: modestr = "b"; break; case eSIR_11G_NW_TYPE: modestr = "g"; break; case eSIR_11N_NW_TYPE: modestr = "n"; break; default: hddLog( LOGW, "%s: Unknown network type [%d]", __func__, descriptor->nwType); modestr = "?"; break; } snprintf(event.u.name, IFNAMSIZ, "IEEE 802.11%s", modestr); current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_CHAR_LEN); if (last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWNAME"); /* Error code, may be E2BIG */ return -E2BIG; } last_event = current_event; vos_mem_zero( &event, sizeof (struct iw_event)); /*Freq*/ event.cmd = SIOCGIWFREQ; event.u.freq.m = descriptor->channelId; event.u.freq.e = 0; event.u.freq.i = 0; current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_FREQ_LEN); if (last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWFREQ"); return -E2BIG; } last_event = current_event; vos_mem_zero( &event, sizeof (struct iw_event)); /* BSS Mode */ event.cmd = SIOCGIWMODE; capabilityInfo = descriptor->capabilityInfo; if (SIR_MAC_GET_ESS(capabilityInfo)) { event.u.mode = IW_MODE_MASTER; } else if (SIR_MAC_GET_IBSS(capabilityInfo)) { event.u.mode = IW_MODE_ADHOC; } else { /* neither ESS or IBSS */ event.u.mode = IW_MODE_AUTO; } current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_UINT_LEN); if (last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWMODE"); return -E2BIG; } /* To extract SSID */ ie_length = GET_IE_LEN_IN_BSS( descriptor->length ); if (ie_length > 0) { /* dot11BeaconIEs is a large struct, so we make it static to avoid stack overflow. This API is only invoked via ioctl, so it is serialized by the kernel rtnl_lock and hence does not need to be reentrant */ static tDot11fBeaconIEs dot11BeaconIEs; tDot11fIESSID *pDot11SSID; tDot11fIESuppRates *pDot11SuppRates; tDot11fIEExtSuppRates *pDot11ExtSuppRates; tDot11fIEHTCaps *pDot11IEHTCaps; int numBasicRates = 0; int maxNumRates = 0; pDot11IEHTCaps = NULL; dot11fUnpackBeaconIEs ((tpAniSirGlobal) hHal, (tANI_U8 *) descriptor->ieFields, ie_length, &dot11BeaconIEs); pDot11SSID = &dot11BeaconIEs.SSID; if (pDot11SSID->present ) { last_event = current_event; vos_mem_zero (&event, sizeof (struct iw_event)); event.cmd = SIOCGIWESSID; event.u.data.flags = 1; event.u.data.length = scan_result->ssId.length; current_event = iwe_stream_add_point (scanInfo->info,current_event, end, &event, (char *)scan_result->ssId.ssId); if(last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWESSID"); return -E2BIG; } } if( hdd_GetWPARSNIEs( ( tANI_U8 *) descriptor->ieFields, ie_length, &last_event, ¤t_event, scanInfo ) < 0 ) { hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWESSID"); return -E2BIG; } last_event = current_event; current_pad = current_event + IW_EV_LCP_LEN; vos_mem_zero( &event, sizeof (struct iw_event)); /*Rates*/ event.cmd = SIOCGIWRATE; pDot11SuppRates = &dot11BeaconIEs.SuppRates; if (pDot11SuppRates->present ) { int i; numBasicRates = pDot11SuppRates->num_rates; for (i=0; i<pDot11SuppRates->num_rates; i++) { if (0 != (pDot11SuppRates->rates[i] & 0x7F)) { event.u.bitrate.value = hdd_TranslateABGRateToMbpsRate ( &pDot11SuppRates->rates[i]); current_pad = iwe_stream_add_value (scanInfo->info,current_event, current_pad, end, &event, IW_EV_PARAM_LEN); } } } pDot11ExtSuppRates = &dot11BeaconIEs.ExtSuppRates; if (pDot11ExtSuppRates->present ) { int i,no_of_rates; maxNumRates = numBasicRates + pDot11ExtSuppRates->num_rates; /* Check to make sure the total number of rates doesn't exceed IW_MAX_BITRATES */ maxNumRates = VOS_MIN(maxNumRates , IW_MAX_BITRATES); if((maxNumRates - numBasicRates) > MAX_RATES) { no_of_rates = MAX_RATES; hddLog( LOGW, "Accessing array out of bound that array is pDot11ExtSuppRates->rates "); } else { no_of_rates = maxNumRates - numBasicRates; } for ( i=0; i< no_of_rates ; i++ ) { if (0 != (pDot11ExtSuppRates->rates[i] & 0x7F)) { event.u.bitrate.value = hdd_TranslateABGRateToMbpsRate ( &pDot11ExtSuppRates->rates[i]); current_pad = iwe_stream_add_value (scanInfo->info,current_event, current_pad, end, &event, IW_EV_PARAM_LEN); } } } if ((current_pad - current_event) >= IW_EV_LCP_LEN) { current_event = current_pad; } else { if (last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWRATE"); return -E2BIG; } } last_event = current_event; vos_mem_zero (&event, sizeof (struct iw_event)); event.cmd = SIOCGIWENCODE; if (SIR_MAC_GET_PRIVACY(capabilityInfo)) { event.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; } else { event.u.data.flags = IW_ENCODE_DISABLED; } event.u.data.length = 0; current_event = iwe_stream_add_point(scanInfo->info,current_event, end, &event, (char *)pDot11SSID->ssid); if(last_event == current_event) { /* no space to add event Error code, may be E2BIG */ hddLog( LOGE, "hdd_IndicateScanResult: no space for SIOCGIWENCODE"); return -E2BIG; } } last_event = current_event; vos_mem_zero( &event, sizeof (struct iw_event)); /*RSSI*/ event.cmd = IWEVQUAL; event.u.qual.qual = descriptor->rssi; event.u.qual.noise = descriptor->sinr; /*To keep the rssi icon of the connected AP in the scan window *and the rssi icon of the wireless networks in sync */ if (( eConnectionState_Associated == pAdapter->sessionCtx.station.conn_info.connState ) && ( VOS_TRUE == vos_mem_compare(descriptor->bssId, pAdapter->sessionCtx.station.conn_info.bssId, VOS_MAC_ADDR_SIZE))) { event.u.qual.level = pAdapter->rssi; } else { event.u.qual.level = VOS_MIN ((descriptor->rssi + descriptor->sinr), 0); } event.u.qual.updated = IW_QUAL_ALL_UPDATED; current_event = iwe_stream_add_event(scanInfo->info,current_event, end, &event, IW_EV_QUAL_LEN); if(last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for IWEVQUAL"); return -E2BIG; } /* AGE */ event.cmd = IWEVCUSTOM; p = custom; p += scnprintf(p, MAX_CUSTOM_LEN, " Age: %lu", vos_timer_get_system_ticks() - descriptor->nReceivedTime); event.u.data.length = p - custom; current_event = iwe_stream_add_point (scanInfo->info,current_event, end, &event, custom); if(last_event == current_event) { /* no space to add event */ hddLog( LOGE, "hdd_IndicateScanResult: no space for IWEVCUSTOM (age)"); return -E2BIG; } scanInfo->start = current_event; return 0; }