/* * This function resets the connection state. * * The function is invoked after receiving a disconnect event from firmware, * and performs the following actions - * - Set media status to disconnected * - Clean up Tx and Rx packets * - Resets SNR/NF/RSSI value in driver * - Resets security configurations in driver * - Enables auto data rate * - Saves the previous SSID and BSSID so that they can * be used for re-association, if required * - Erases current SSID and BSSID information * - Sends a disconnect event to upper layers/applications. */ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, bool from_ap) { struct mwifiex_adapter *adapter = priv->adapter; if (!priv->media_connected) return; mwifiex_dbg(adapter, INFO, "info: handles disconnect event\n"); priv->media_connected = false; priv->scan_block = false; priv->port_open = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { mwifiex_disable_all_tdls_links(priv); if (priv->adapter->auto_tdls) mwifiex_clean_auto_tdls(priv); } /* Free Tx and Rx packets, report disconnect to upper layer */ mwifiex_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; priv->sec_info.wpa_enabled = false; priv->sec_info.wpa2_enabled = false; priv->wpa_ie_len = 0; priv->sec_info.wapi_enabled = false; priv->wapi_ie_len = 0; priv->sec_info.wapi_key_on = false; priv->sec_info.encryption_mode = 0; /* Enable auto data rate */ priv->is_data_rate_auto = true; priv->data_rate = 0; priv->assoc_resp_ht_param = 0; priv->ht_param_present = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) mwifiex_hist_data_reset(priv); if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { priv->adhoc_state = ADHOC_IDLE; priv->adhoc_is_link_sensed = false; } /* * Memorize the previous SSID and BSSID so * it could be used for re-assoc */ mwifiex_dbg(adapter, INFO, "info: previous SSID=%s, SSID len=%u\n", priv->prev_ssid.ssid, priv->prev_ssid.ssid_len); mwifiex_dbg(adapter, INFO, "info: current SSID=%s, SSID len=%u\n", priv->curr_bss_params.bss_descriptor.ssid.ssid, priv->curr_bss_params.bss_descriptor.ssid.ssid_len); memcpy(&priv->prev_ssid, &priv->curr_bss_params.bss_descriptor.ssid, sizeof(struct cfg80211_ssid)); memcpy(priv->prev_bssid, priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN); /* Need to erase the current SSID and BSSID info */ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params)); adapter->tx_lock_flag = false; adapter->pps_uapsd_mode = false; if (test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags) && adapter->curr_cmd) return; priv->media_connected = false; mwifiex_dbg(adapter, MSG, "info: successfully disconnected from %pM: reason code %d\n", priv->cfg_bssid, reason_code); if (priv->bss_mode == NL80211_IFTYPE_STATION || priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { cfg80211_disconnected(priv->netdev, reason_code, NULL, 0, !from_ap, GFP_KERNEL); } eth_zero_addr(priv->cfg_bssid); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) return; mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG, HostCmd_ACT_GEN_REMOVE, 0, NULL, false); }
/* * This function is used to shutdown the driver. * * The following operations are performed sequentially - * - Check if already shut down * - Make sure the main process has stopped * - Clean up the Tx and Rx queues * - Delete BSS priority tables * - Free the adapter * - Notify completion */ int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) { int ret = -EINPROGRESS; struct mwifiex_private *priv; s32 i; unsigned long flags; struct sk_buff *skb; /* mwifiex already shutdown */ if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY) return 0; adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING; /* wait for mwifiex_process to complete */ if (adapter->mwifiex_processing) { mwifiex_dbg(adapter, WARN, "main process is still running\n"); return ret; } /* cancel current command */ if (adapter->curr_cmd) { mwifiex_dbg(adapter, WARN, "curr_cmd is still in processing\n"); del_timer_sync(&adapter->cmd_timer); mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd); adapter->curr_cmd = NULL; } /* shut down mwifiex */ mwifiex_dbg(adapter, MSG, "info: shutdown mwifiex...\n"); /* Clean up Tx/Rx queues and delete BSS priority table */ for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { priv = adapter->priv[i]; mwifiex_clean_auto_tdls(priv); mwifiex_abort_cac(priv); mwifiex_clean_txrx(priv); mwifiex_delete_bss_prio_tbl(priv); } } atomic_set(&adapter->tx_queued, 0); while ((skb = skb_dequeue(&adapter->tx_data_q))) mwifiex_write_data_complete(adapter, skb, 0, 0); spin_lock_irqsave(&adapter->rx_proc_lock, flags); while ((skb = skb_dequeue(&adapter->rx_data_q))) { struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); atomic_dec(&adapter->rx_pending); priv = adapter->priv[rx_info->bss_num]; if (priv) priv->stats.rx_dropped++; dev_kfree_skb_any(skb); } spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); spin_lock(&adapter->mwifiex_lock); mwifiex_adapter_cleanup(adapter); spin_unlock(&adapter->mwifiex_lock); /* Notify completion */ ret = mwifiex_shutdown_fw_complete(adapter); return ret; }