/* * Association firmware command response handler * * The response buffer for the association command has the following * memory layout. * * For cases where an association response was not received (indicated * by the CapInfo and AId field): * * .------------------------------------------------------------. * | Header(4 * sizeof(t_u16)): Standard command response hdr | * .------------------------------------------------------------. * | cap_info/Error Return(t_u16): | * | 0xFFFF(-1): Internal error | * | 0xFFFE(-2): Authentication unhandled message | * | 0xFFFD(-3): Authentication refused | * | 0xFFFC(-4): Timeout waiting for AP response | * .------------------------------------------------------------. * | status_code(t_u16): | * | If cap_info is -1: | * | An internal firmware failure prevented the | * | command from being processed. The status_code | * | will be set to 1. | * | | * | If cap_info is -2: | * | An authentication frame was received but was | * | not handled by the firmware. IEEE Status | * | code for the failure is returned. | * | | * | If cap_info is -3: | * | An authentication frame was received and the | * | status_code is the IEEE Status reported in the | * | response. | * | | * | If cap_info is -4: | * | (1) Association response timeout | * | (2) Authentication response timeout | * .------------------------------------------------------------. * | a_id(t_u16): 0xFFFF | * .------------------------------------------------------------. * * * For cases where an association response was received, the IEEE * standard association response frame is returned: * * .------------------------------------------------------------. * | Header(4 * sizeof(t_u16)): Standard command response hdr | * .------------------------------------------------------------. * | cap_info(t_u16): IEEE Capability | * .------------------------------------------------------------. * | status_code(t_u16): IEEE Status Code | * .------------------------------------------------------------. * | a_id(t_u16): IEEE Association ID | * .------------------------------------------------------------. * | IEEE IEs(variable): Any received IEs comprising the | * | remaining portion of a received | * | association response frame. | * .------------------------------------------------------------. * * For simplistic handling, the status_code field can be used to determine * an association success (0) or failure (non-zero). */ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; struct ieee_types_assoc_rsp *assoc_rsp; struct mwifiex_bssdescriptor *bss_desc; bool enable_data = true; u16 cap_info, status_code; assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); status_code = le16_to_cpu(assoc_rsp->status_code); priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, sizeof(priv->assoc_rsp_buf)); memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); if (status_code) { priv->adapter->dbg.num_cmd_assoc_failure++; dev_err(priv->adapter->dev, "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n", status_code, cap_info, le16_to_cpu(assoc_rsp->a_id)); if (cap_info == MWIFIEX_TIMEOUT_FOR_AP_RESP) { if (status_code == MWIFIEX_STATUS_CODE_AUTH_TIMEOUT) ret = WLAN_STATUS_AUTH_TIMEOUT; else ret = WLAN_STATUS_UNSPECIFIED_FAILURE; } else { ret = status_code; } goto done; } /* Send a Media Connected event, according to the Spec */ priv->media_connected = true; priv->adapter->ps_state = PS_STATE_AWAKE; priv->adapter->pps_uapsd_mode = false; priv->adapter->tx_lock_flag = false; /* Set the attempted BSSID Index to current */ bss_desc = priv->attempted_bss_desc; dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", bss_desc->ssid.ssid); /* Make a copy of current BSSID descriptor */ memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, sizeof(struct mwifiex_bssdescriptor)); /* Update curr_bss_params */ priv->curr_bss_params.bss_descriptor.channel = bss_desc->phy_param_set.ds_param_set.current_chan; priv->curr_bss_params.band = (u8) bss_desc->bss_band; if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) priv->curr_bss_params.wmm_enabled = true; else priv->curr_bss_params.wmm_enabled = false; if ((priv->wmm_required || bss_desc->bcn_ht_cap) && priv->curr_bss_params.wmm_enabled) priv->wmm_enabled = true; else priv->wmm_enabled = false; priv->curr_bss_params.wmm_uapsd_enabled = false; if (priv->wmm_enabled) priv->curr_bss_params.wmm_uapsd_enabled = ((bss_desc->wmm_ie.qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", priv->curr_pkt_filter); if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->wpa_is_gtk_set = false; if (priv->wmm_enabled) { /* Don't re-enable carrier until we get the WMM_GET_STATUS event */ enable_data = false; } else { /* Since WMM is not enabled, setup the queues with the defaults */ mwifiex_wmm_setup_queue_priorities(priv, NULL); mwifiex_wmm_setup_ac_downgrade(priv); } if (enable_data) dev_dbg(priv->adapter->dev, "info: post association, re-enabling data flow\n"); /* 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; mwifiex_save_curr_bcn(priv); priv->adapter->dbg.num_cmd_assoc_success++; dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); /* Add the ra_list here for infra mode as there will be only 1 ra always */ mwifiex_ralist_add(priv, priv->curr_bss_params.bss_descriptor.mac_address); if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->scan_block = true; done: /* Need to indicate IOCTL complete */ if (adapter->curr_cmd->wait_q_enabled) { if (ret) adapter->cmd_wait_q.status = -1; else adapter->cmd_wait_q.status = 0; } return ret; }
int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; struct ieee_types_assoc_rsp *assoc_rsp; struct mwifiex_bssdescriptor *bss_desc; u8 enable_data = true; assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, sizeof(priv->assoc_rsp_buf)); memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); if (le16_to_cpu(assoc_rsp->status_code)) { priv->adapter->dbg.num_cmd_assoc_failure++; dev_err(priv->adapter->dev, "ASSOC_RESP: failed, status code=%d err=%#x a_id=%#x\n", le16_to_cpu(assoc_rsp->status_code), le16_to_cpu(assoc_rsp->cap_info_bitmap), le16_to_cpu(assoc_rsp->a_id)); ret = le16_to_cpu(assoc_rsp->status_code); goto done; } priv->media_connected = true; priv->adapter->ps_state = PS_STATE_AWAKE; priv->adapter->pps_uapsd_mode = false; priv->adapter->tx_lock_flag = false; bss_desc = priv->attempted_bss_desc; dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n", bss_desc->ssid.ssid); memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, sizeof(struct mwifiex_bssdescriptor)); priv->curr_bss_params.bss_descriptor.channel = bss_desc->phy_param_set.ds_param_set.current_chan; priv->curr_bss_params.band = (u8) bss_desc->bss_band; if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) priv->curr_bss_params.wmm_enabled = true; else priv->curr_bss_params.wmm_enabled = false; if ((priv->wmm_required || bss_desc->bcn_ht_cap) && priv->curr_bss_params.wmm_enabled) priv->wmm_enabled = true; else priv->wmm_enabled = false; priv->curr_bss_params.wmm_uapsd_enabled = false; if (priv->wmm_enabled) priv->curr_bss_params.wmm_uapsd_enabled = ((bss_desc->wmm_ie.qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", priv->curr_pkt_filter); if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->wpa_is_gtk_set = false; if (priv->wmm_enabled) { enable_data = false; } else { mwifiex_wmm_setup_queue_priorities(priv, NULL); mwifiex_wmm_setup_ac_downgrade(priv); } if (enable_data) dev_dbg(priv->adapter->dev, "info: post association, re-enabling data flow\n"); 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; mwifiex_save_curr_bcn(priv); priv->adapter->dbg.num_cmd_assoc_success++; dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n"); mwifiex_ralist_add(priv, priv->curr_bss_params.bss_descriptor.mac_address); if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); if (netif_queue_stopped(priv->netdev)) netif_wake_queue(priv->netdev); if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->scan_block = true; done: if (adapter->curr_cmd->wait_q_enabled) { if (ret) adapter->cmd_wait_q.status = -1; else adapter->cmd_wait_q.status = 0; } return ret; }