diff options
Diffstat (limited to 'drivers/net/wireless/marvell')
37 files changed, 1234 insertions, 308 deletions
diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 36b234bc5be8..caf8bc231b2e 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -3,7 +3,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on USB || MMC || SPI depends on CFG80211 - select LIB80211 select FW_LOADER help A library for Marvell Libertas 8xxx devices. diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index b700c213d10c..2e2c193716d9 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -15,7 +15,7 @@ #include <linux/slab.h> #include <linux/ieee80211.h> #include <net/cfg80211.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "decl.h" #include "cfg.h" @@ -486,6 +486,7 @@ static int lbs_add_wps_enrollee_tlv(u8 *tlv, const u8 *ie, size_t ie_len) */ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct lbs_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/cmd.c b/drivers/net/wireless/marvell/libertas/cmd.c index 104d2b6dc9af..5a525da434c2 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.c +++ b/drivers/net/wireless/marvell/libertas/cmd.c @@ -1132,7 +1132,7 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) if (!cmdarray[i].cmdbuf) { lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n"); ret = -1; - goto done; + goto free_cmd_array; } } @@ -1140,8 +1140,17 @@ int lbs_allocate_cmd_buffer(struct lbs_private *priv) init_waitqueue_head(&cmdarray[i].cmdwait_q); lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]); } - ret = 0; + return 0; +free_cmd_array: + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + if (cmdarray[i].cmdbuf) { + kfree(cmdarray[i].cmdbuf); + cmdarray[i].cmdbuf = NULL; + } + } + kfree(priv->cmd_array); + priv->cmd_array = NULL; done: return ret; } diff --git a/drivers/net/wireless/marvell/libertas/cmd.h b/drivers/net/wireless/marvell/libertas/cmd.h index 3c193074662b..d7be232f5739 100644 --- a/drivers/net/wireless/marvell/libertas/cmd.h +++ b/drivers/net/wireless/marvell/libertas/cmd.h @@ -116,11 +116,6 @@ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, int8_t p2, int usesnr); -int lbs_set_data_rate(struct lbs_private *priv, u8 rate); - -int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, - uint16_t cmd_action); - int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep); diff --git a/drivers/net/wireless/marvell/libertas/cmdresp.c b/drivers/net/wireless/marvell/libertas/cmdresp.c index 74cb7551f427..f2aa659e7714 100644 --- a/drivers/net/wireless/marvell/libertas/cmdresp.c +++ b/drivers/net/wireless/marvell/libertas/cmdresp.c @@ -8,7 +8,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/sched.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <net/cfg80211.h> #include "cfg.h" diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index 8690b0114e23..b722a6587fd3 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1052,7 +1052,7 @@ static int if_spi_init_card(struct if_spi_card *card) "attached to SPI bus_num %d, chip_select %d. " "spi->max_speed_hz=%d\n", card->card_id, card->card_rev, - card->spi->master->bus_num, + card->spi->controller->bus_num, spi_get_chipselect(card->spi, 0), card->spi->max_speed_hz); err = if_spi_prog_helper_firmware(card, helper); diff --git a/drivers/net/wireless/marvell/libertas/mesh.h b/drivers/net/wireless/marvell/libertas/mesh.h index 44c4cd0230a8..e37db10e82a9 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.h +++ b/drivers/net/wireless/marvell/libertas/mesh.h @@ -7,7 +7,6 @@ #include <net/iw_handler.h> -#include <net/lib80211.h> #include "host.h" #include "dev.h" diff --git a/drivers/net/wireless/marvell/libertas/radiotap.h b/drivers/net/wireless/marvell/libertas/radiotap.h index 1ed5608d353f..d543bfe739dc 100644 --- a/drivers/net/wireless/marvell/libertas/radiotap.h +++ b/drivers/net/wireless/marvell/libertas/radiotap.h @@ -2,7 +2,7 @@ #include <net/ieee80211_radiotap.h> struct tx_radiotap_hdr { - struct ieee80211_radiotap_header hdr; + struct ieee80211_radiotap_header_fixed hdr; u8 rate; u8 txpower; u8 rts_retries; @@ -31,7 +31,7 @@ struct tx_radiotap_hdr { #define IEEE80211_FC_DSTODS 0x0300 struct rx_radiotap_hdr { - struct ieee80211_radiotap_header hdr; + struct ieee80211_radiotap_header_fixed hdr; u8 flags; u8 rate; u8 antsignal; diff --git a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h index 631b5da09f86..a5d4c09fb918 100644 --- a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h +++ b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h @@ -484,12 +484,9 @@ void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd, void lbtf_cmd_response_rx(struct lbtf_private *priv); /* main.c */ -struct chan_freq_power *lbtf_get_region_cfp_table(u8 region, - int *cfp_no); struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev, const struct lbtf_ops *ops); int lbtf_remove_card(struct lbtf_private *priv); -int lbtf_start_card(struct lbtf_private *priv); int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb); void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail); void lbtf_bcn_sent(struct lbtf_private *priv); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 199d33ed3bb9..b47a832b9ae2 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -267,7 +267,7 @@ static int lbtf_op_start(struct ieee80211_hw *hw) return 0; } -static void lbtf_op_stop(struct ieee80211_hw *hw) +static void lbtf_op_stop(struct ieee80211_hw *hw, bool suspend) { struct lbtf_private *priv = hw->priv; unsigned long flags; @@ -473,6 +473,10 @@ static int lbtf_op_get_survey(struct ieee80211_hw *hw, int idx, } static const struct ieee80211_ops lbtf_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = lbtf_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = lbtf_op_start, diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index da211372a481..032b93a41d99 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -117,12 +117,12 @@ void mwifiex_dfs_cac_work_queue(struct work_struct *work) dfs_cac_work); chandef = priv->dfs_chandef; - if (priv->wdev.cac_started) { + if (priv->wdev.links[0].cac_started) { mwifiex_dbg(priv->adapter, MSG, "CAC timer finished; No radar detected\n"); cfg80211_cac_event(priv->netdev, &chandef, NL80211_RADAR_CAC_FINISHED, - GFP_KERNEL); + GFP_KERNEL, 0); } } @@ -174,7 +174,7 @@ int mwifiex_stop_radar_detection(struct mwifiex_private *priv, */ void mwifiex_abort_cac(struct mwifiex_private *priv) { - if (priv->wdev.cac_started) { + if (priv->wdev.links[0].cac_started) { if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) mwifiex_dbg(priv->adapter, ERROR, "failed to stop CAC in FW\n"); @@ -182,7 +182,8 @@ void mwifiex_abort_cac(struct mwifiex_private *priv) "Aborting delayed work for CAC.\n"); cancel_delayed_work_sync(&priv->dfs_cac_work); cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, - NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); + NL80211_RADAR_CAC_ABORTED, GFP_KERNEL, + 0); } } @@ -221,7 +222,7 @@ int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, NL80211_RADAR_DETECTED, - GFP_KERNEL); + GFP_KERNEL, 0); } break; default: @@ -288,6 +289,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) mwifiex_dbg(priv->adapter, MSG, "indicating channel switch completion to kernel\n"); wiphy_lock(priv->wdev.wiphy); - cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0, 0); + cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0); wiphy_unlock(priv->wdev.wiphy); } diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index 90e401100898..66f0f5377ac1 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -392,12 +392,10 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, chan_list = (struct mwifiex_ie_types_chan_list_param_set *) *buffer; - memset(chan_list, 0, - sizeof(struct mwifiex_ie_types_chan_list_param_set)); + memset(chan_list, 0, struct_size(chan_list, chan_scan_param, 1)); chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); - chan_list->header.len = cpu_to_le16( - sizeof(struct mwifiex_ie_types_chan_list_param_set) - - sizeof(struct mwifiex_ie_types_header)); + chan_list->header.len = + cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); chan_list->chan_scan_param[0].chan_number = bss_desc->bcn_ht_oper->primary_chan; chan_list->chan_scan_param[0].radio_type = @@ -411,8 +409,8 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, (bss_desc->bcn_ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET)); - *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set); - ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set); + *buffer += struct_size(chan_list, chan_scan_param, 1); + ret_len += struct_size(chan_list, chan_scan_param, 1); } if (bss_desc->bcn_bss_co_2040) { @@ -883,8 +881,6 @@ void mwifiex_update_ampdu_txwinsize(struct mwifiex_adapter *adapter) struct mwifiex_private *priv; for (i = 0; i < adapter->priv_num; i++) { - if (!adapter->priv[i]) - continue; priv = adapter->priv[i]; tx_win_size = priv->add_ba_param.tx_win_size; diff --git a/drivers/net/wireless/marvell/mwifiex/11n.h b/drivers/net/wireless/marvell/mwifiex/11n.h index 7738ebe1fec1..773bd5c0f007 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.h +++ b/drivers/net/wireless/marvell/mwifiex/11n.h @@ -108,9 +108,7 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream( for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv) - ba_stream_num += list_count_nodes( - &priv->tx_ba_stream_tbl_ptr); + ba_stream_num += list_count_nodes(&priv->tx_ba_stream_tbl_ptr); } if (adapter->fw_api_ver == MWIFIEX_FW_V15) { diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 10690e82358b..cb948ca34373 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -810,8 +810,6 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (!priv) - continue; spin_lock_bh(&priv->rx_reorder_tbl_lock); list_for_each_entry(tbl, &priv->rx_reorder_tbl_ptr, list) @@ -834,8 +832,6 @@ static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter, dev_dbg(adapter->dev, "Update rxwinsize %d\n", coex_flag); for (i = 0; i < adapter->priv_num; i++) { - if (!adapter->priv[i]) - continue; priv = adapter->priv[i]; rx_win_size = priv->add_ba_param.rx_win_size; if (coex_flag) { @@ -882,17 +878,16 @@ void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter) u8 count = 0; for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - priv = adapter->priv[i]; - if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { - if (priv->media_connected) - count++; - } - if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { - if (priv->bss_started) - count++; - } + priv = adapter->priv[i]; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + if (priv->media_connected) + count++; } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + if (priv->bss_started) + count++; + } + if (count >= MWIFIEX_BSS_COEX_COUNT) break; } diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 3604abcbcff9..a099fdaafa45 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -221,6 +221,26 @@ mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, return 0; } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + if (ieee80211_is_auth(mgmt->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "auth: send auth to %pM\n", mgmt->da); + if (ieee80211_is_deauth(mgmt->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "auth: send deauth to %pM\n", mgmt->da); + if (ieee80211_is_disassoc(mgmt->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "assoc: send disassoc to %pM\n", mgmt->da); + if (ieee80211_is_assoc_resp(mgmt->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "assoc: send assoc resp to %pM\n", + mgmt->da); + if (ieee80211_is_reassoc_resp(mgmt->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "assoc: send reassoc resp to %pM\n", + mgmt->da); + } + pkt_len = len + ETH_ALEN; skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN + MWIFIEX_MGMT_FRAME_HEADER_SIZE + @@ -268,6 +288,8 @@ mwifiex_cfg80211_update_mgmt_frame_registrations(struct wiphy *wiphy, if (mask != priv->mgmt_frame_mask) { priv->mgmt_frame_mask = mask; + if (priv->host_mlme_reg) + priv->mgmt_frame_mask |= HOST_MLME_MGMT_MASK; mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, HostCmd_ACT_GEN_SET, 0, &priv->mgmt_frame_mask, false); @@ -388,7 +410,7 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, static int mwifiex_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - int *dbm) + unsigned int link_id, int *dbm) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv = mwifiex_get_priv(adapter, @@ -503,6 +525,9 @@ mwifiex_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, wiphy_dbg(wiphy, "set default mgmt key, key index=%d\n", key_index); + if (priv->adapter->host_mlme_enabled) + return 0; + memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key)); encrypt_key.key_len = WLAN_KEY_LEN_CCMP; encrypt_key.key_index = key_index; @@ -848,6 +873,7 @@ static int mwifiex_deinit_priv_params(struct mwifiex_private *priv) struct mwifiex_adapter *adapter = priv->adapter; unsigned long flags; + priv->host_mlme_reg = false; priv->mgmt_frame_mask = 0; if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, HostCmd_ACT_GEN_SET, 0, @@ -926,6 +952,8 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, return -EOPNOTSUPP; } + priv->bss_num = mwifiex_get_unused_bss_num(adapter, priv->bss_type); + spin_lock_irqsave(&adapter->main_proc_lock, flags); adapter->main_locked = false; spin_unlock_irqrestore(&adapter->main_proc_lock, flags); @@ -1878,7 +1906,7 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_sta_node *sta_node; u8 deauth_mac[ETH_ALEN]; - if (!priv->bss_started && priv->wdev.cac_started) { + if (!priv->bss_started && priv->wdev.links[0].cac_started) { mwifiex_dbg(priv->adapter, INFO, "%s: abort CAC!\n", __func__); mwifiex_abort_cac(priv); } @@ -3359,7 +3387,7 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, } if (!wowlan->patterns[i].pkt_offset) { - if (!(byte_seq[0] & 0x01) && + if (is_unicast_ether_addr(byte_seq) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; continue; @@ -3480,7 +3508,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv && priv->netdev) + if (priv->netdev) netif_device_detach(priv->netdev); } @@ -3552,7 +3580,7 @@ static int mwifiex_cfg80211_resume(struct wiphy *wiphy) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv && priv->netdev) + if (priv->netdev) netif_device_attach(priv->netdev); } @@ -3631,6 +3659,9 @@ static int mwifiex_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, if (!ISSUPP_FIRMWARE_SUPPLICANT(priv->adapter->fw_cap_info)) return -EOPNOTSUPP; + if (priv->adapter->host_mlme_enabled) + return 0; + return mwifiex_send_cmd(priv, HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG, HostCmd_ACT_GEN_SET, 0, data, true); } @@ -3946,11 +3977,42 @@ mwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy, } static int +mwifiex_cfg80211_uap_add_station(struct mwifiex_private *priv, const u8 *mac, + struct station_parameters *params) +{ + struct mwifiex_sta_info add_sta; + int ret; + + memcpy(add_sta.peer_mac, mac, ETH_ALEN); + add_sta.params = params; + + ret = mwifiex_send_cmd(priv, HostCmd_CMD_ADD_NEW_STATION, + HostCmd_ACT_ADD_STA, 0, (void *)&add_sta, true); + + if (!ret) { + struct station_info *sinfo; + + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + + cfg80211_new_sta(priv->netdev, mac, sinfo, GFP_KERNEL); + kfree(sinfo); + } + + return ret; +} + +static int mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_parameters *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + if (priv->adapter->host_mlme_enabled && + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)) + return mwifiex_cfg80211_uap_add_station(priv, mac, params); + if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) return -EOPNOTSUPP; @@ -3976,7 +4038,7 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, return -EBUSY; } - if (priv->wdev.cac_started) + if (priv->wdev.links[0].cac_started) return -EBUSY; if (cfg80211_chandef_identical(¶ms->chandef, @@ -4143,7 +4205,7 @@ static int mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_chan_def *chandef, - u32 cac_time_ms) + u32 cac_time_ms, int link_id) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_radar_params radar_params; @@ -4188,6 +4250,10 @@ mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + if (priv->adapter->host_mlme_enabled && + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)) + return 0; + /* we support change_station handler only for TDLS peers*/ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) return -EOPNOTSUPP; @@ -4204,8 +4270,307 @@ mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, return ret; } +static int +mwifiex_cfg80211_authenticate(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_auth_request *req) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb; + u16 pkt_len, auth_alg; + int ret; + struct mwifiex_ieee80211_mgmt *mgmt; + struct mwifiex_txinfo *tx_info; + u32 tx_control = 0, pkt_type = PKT_TYPE_MGMT; + u8 trans = 1, status_code = 0; + u8 *varptr = NULL; + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { + mwifiex_dbg(priv->adapter, ERROR, "Interface role is AP\n"); + return -EFAULT; + } + + if (priv->wdev.iftype != NL80211_IFTYPE_STATION) { + mwifiex_dbg(priv->adapter, ERROR, + "Interface type is not correct (type %d)\n", + priv->wdev.iftype); + return -EINVAL; + } + + if (priv->auth_alg != WLAN_AUTH_SAE && + (priv->auth_flag & HOST_MLME_AUTH_PENDING)) { + mwifiex_dbg(priv->adapter, ERROR, "Pending auth on going\n"); + return -EBUSY; + } + + if (!priv->host_mlme_reg) { + priv->host_mlme_reg = true; + priv->mgmt_frame_mask |= HOST_MLME_MGMT_MASK; + mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, + HostCmd_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false); + } + + switch (req->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + auth_alg = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + auth_alg = WLAN_AUTH_SHARED_KEY; + break; + case NL80211_AUTHTYPE_FT: + auth_alg = WLAN_AUTH_FT; + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + auth_alg = WLAN_AUTH_LEAP; + break; + case NL80211_AUTHTYPE_SAE: + auth_alg = WLAN_AUTH_SAE; + break; + default: + mwifiex_dbg(priv->adapter, ERROR, + "unsupported auth type=%d\n", req->auth_type); + return -EOPNOTSUPP; + } + + if (!priv->auth_flag) { + ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, + req->bss->channel, + AUTH_TX_DEFAULT_WAIT_TIME); + + if (!ret) { + priv->roc_cfg.cookie = get_random_u32() | 1; + priv->roc_cfg.chan = *req->bss->channel; + } else { + return -EFAULT; + } + } + + priv->sec_info.authentication_mode = auth_alg; + + mwifiex_cancel_scan(adapter); + + pkt_len = (u16)req->ie_len + req->auth_data_len + + MWIFIEX_MGMT_HEADER_LEN + MWIFIEX_AUTH_BODY_LEN; + if (req->auth_data_len >= 4) + pkt_len -= 4; + + skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + + pkt_len + sizeof(pkt_len)); + if (!skb) { + mwifiex_dbg(priv->adapter, ERROR, + "allocate skb failed for management frame\n"); + return -ENOMEM; + } + + tx_info = MWIFIEX_SKB_TXCB(skb); + memset(tx_info, 0, sizeof(*tx_info)); + tx_info->bss_num = priv->bss_num; + tx_info->bss_type = priv->bss_type; + tx_info->pkt_len = pkt_len; + + skb_reserve(skb, MWIFIEX_MIN_DATA_HEADER_LEN + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(pkt_len)); + memcpy(skb_push(skb, sizeof(pkt_len)), &pkt_len, sizeof(pkt_len)); + memcpy(skb_push(skb, sizeof(tx_control)), + &tx_control, sizeof(tx_control)); + memcpy(skb_push(skb, sizeof(pkt_type)), &pkt_type, sizeof(pkt_type)); + + mgmt = (struct mwifiex_ieee80211_mgmt *)skb_put(skb, pkt_len); + memset(mgmt, 0, pkt_len); + mgmt->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); + memcpy(mgmt->da, req->bss->bssid, ETH_ALEN); + memcpy(mgmt->sa, priv->curr_addr, ETH_ALEN); + memcpy(mgmt->bssid, req->bss->bssid, ETH_ALEN); + eth_broadcast_addr(mgmt->addr4); + + if (req->auth_data_len >= 4) { + if (req->auth_type == NL80211_AUTHTYPE_SAE) { + __le16 *pos = (__le16 *)req->auth_data; + + trans = le16_to_cpu(pos[0]); + status_code = le16_to_cpu(pos[1]); + } + memcpy((u8 *)(&mgmt->auth.variable), req->auth_data + 4, + req->auth_data_len - 4); + varptr = (u8 *)&mgmt->auth.variable + + (req->auth_data_len - 4); + } + + mgmt->auth.auth_alg = cpu_to_le16(auth_alg); + mgmt->auth.auth_transaction = cpu_to_le16(trans); + mgmt->auth.status_code = cpu_to_le16(status_code); + + if (req->ie && req->ie_len) { + if (!varptr) + varptr = (u8 *)&mgmt->auth.variable; + memcpy((u8 *)varptr, req->ie, req->ie_len); + } + + priv->auth_flag = HOST_MLME_AUTH_PENDING; + priv->auth_alg = auth_alg; + + skb->priority = WMM_HIGHEST_PRIORITY; + __net_timestamp(skb); + + mwifiex_dbg(priv->adapter, MSG, + "auth: send authentication to %pM\n", req->bss->bssid); + + mwifiex_queue_tx_pkt(priv, skb); + + return 0; +} + +static int +mwifiex_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_assoc_request *req) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_adapter *adapter = priv->adapter; + int ret; + struct cfg80211_ssid req_ssid; + const u8 *ssid_ie; + + if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) { + mwifiex_dbg(adapter, ERROR, + "%s: reject infra assoc request in non-STA role\n", + dev->name); + return -EINVAL; + } + + if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags) || + test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags)) { + mwifiex_dbg(adapter, ERROR, + "%s: Ignore association.\t" + "Card removed or FW in bad state\n", + dev->name); + return -EFAULT; + } + + if (priv->auth_alg == WLAN_AUTH_SAE) + priv->auth_flag = HOST_MLME_AUTH_DONE; + + if (priv->auth_flag && !(priv->auth_flag & HOST_MLME_AUTH_DONE)) + return -EBUSY; + + if (priv->roc_cfg.cookie) { + ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE, + &priv->roc_cfg.chan, 0); + if (!ret) + memset(&priv->roc_cfg, 0, + sizeof(struct mwifiex_roc_cfg)); + else + return -EFAULT; + } + + if (!mwifiex_stop_bg_scan(priv)) + cfg80211_sched_scan_stopped_locked(priv->wdev.wiphy, 0); + + memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); + rcu_read_lock(); + ssid_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); + + if (!ssid_ie) + goto ssid_err; + + req_ssid.ssid_len = ssid_ie[1]; + if (req_ssid.ssid_len > IEEE80211_MAX_SSID_LEN) { + mwifiex_dbg(adapter, ERROR, "invalid SSID - aborting\n"); + goto ssid_err; + } + + memcpy(req_ssid.ssid, ssid_ie + 2, req_ssid.ssid_len); + if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { + mwifiex_dbg(adapter, ERROR, "invalid SSID - aborting\n"); + goto ssid_err; + } + rcu_read_unlock(); + + /* As this is new association, clear locally stored + * keys and security related flags + */ + priv->sec_info.wpa_enabled = false; + priv->sec_info.wpa2_enabled = false; + priv->wep_key_curr_index = 0; + priv->sec_info.encryption_mode = 0; + priv->sec_info.is_authtype_auto = 0; + if (mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1)) { + mwifiex_dbg(priv->adapter, ERROR, "deleting the crypto keys\n"); + return -EFAULT; + } + + if (req->crypto.n_ciphers_pairwise) + priv->sec_info.encryption_mode = + req->crypto.ciphers_pairwise[0]; + + if (req->crypto.cipher_group) + priv->sec_info.encryption_mode = req->crypto.cipher_group; + + if (req->ie) + mwifiex_set_gen_ie(priv, req->ie, req->ie_len); + + memcpy(priv->cfg_bssid, req->bss->bssid, ETH_ALEN); + + mwifiex_dbg(adapter, MSG, + "assoc: send association to %pM\n", req->bss->bssid); + + cfg80211_ref_bss(adapter->wiphy, req->bss); + ret = mwifiex_bss_start(priv, req->bss, &req_ssid); + if (ret) { + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + eth_zero_addr(priv->cfg_bssid); + } + + if (priv->assoc_rsp_size) { + priv->req_bss = req->bss; + adapter->assoc_resp_received = true; + queue_work(adapter->host_mlme_workqueue, + &adapter->host_mlme_work); + } + + cfg80211_put_bss(priv->adapter->wiphy, req->bss); + + return 0; + +ssid_err: + rcu_read_unlock(); + return -EFAULT; +} + +static int +mwifiex_cfg80211_deauthenticate(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_deauth_request *req) +{ + return mwifiex_cfg80211_disconnect(wiphy, dev, req->reason_code); +} + +static int +mwifiex_cfg80211_disassociate(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_disassoc_request *req) +{ + return mwifiex_cfg80211_disconnect(wiphy, dev, req->reason_code); +} + +static int +mwifiex_cfg80211_probe_client(struct wiphy *wiphy, + struct net_device *dev, const u8 *peer, + u64 *cookie) +{ + /* hostapd looks for NL80211_CMD_PROBE_CLIENT support; otherwise, + * it requires monitor-mode support (which mwifiex doesn't support). + * Provide fake probe_client support to work around this. + */ + return -EOPNOTSUPP; +} + /* station cfg80211 operations */ -static struct cfg80211_ops mwifiex_cfg80211_ops = { +static const struct cfg80211_ops mwifiex_cfg80211_ops = { .add_virtual_intf = mwifiex_add_virtual_intf, .del_virtual_intf = mwifiex_del_virtual_intf, .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, @@ -4340,32 +4705,82 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; u8 *country_code; u32 thr, retry; + struct cfg80211_ops *ops; + + ops = devm_kmemdup(adapter->dev, &mwifiex_cfg80211_ops, + sizeof(mwifiex_cfg80211_ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; /* create a new wiphy for use with cfg80211 */ - wiphy = wiphy_new(&mwifiex_cfg80211_ops, - sizeof(struct mwifiex_adapter *)); + wiphy = wiphy_new(ops, sizeof(struct mwifiex_adapter *)); if (!wiphy) { mwifiex_dbg(adapter, ERROR, "%s: creating new wiphy\n", __func__); return -ENOMEM; } + if (adapter->host_mlme_enabled) { + ops->auth = mwifiex_cfg80211_authenticate; + ops->assoc = mwifiex_cfg80211_associate; + ops->deauth = mwifiex_cfg80211_deauthenticate; + ops->disassoc = mwifiex_cfg80211_disassociate; + ops->disconnect = NULL; + ops->connect = NULL; + ops->probe_client = mwifiex_cfg80211_probe_client; + } wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; - wiphy->mgmt_stypes = mwifiex_mgmt_stypes; + if (adapter->host_mlme_enabled) { + memcpy(adapter->mwifiex_mgmt_stypes, + mwifiex_mgmt_stypes, + NUM_NL80211_IFTYPES * + sizeof(struct ieee80211_txrx_stypes)); + + adapter->mwifiex_mgmt_stypes[NL80211_IFTYPE_AP].tx = 0xffff; + adapter->mwifiex_mgmt_stypes[NL80211_IFTYPE_AP].rx = + BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4); + wiphy->mgmt_stypes = adapter->mwifiex_mgmt_stypes; + } else { + wiphy->mgmt_stypes = mwifiex_mgmt_stypes; + } wiphy->max_remain_on_channel_duration = 5000; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_AP); + wiphy->max_num_akm_suites = CFG80211_MAX_NUM_AKM_SUITES; + if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info)) wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); - wiphy->bands[NL80211_BAND_2GHZ] = &mwifiex_band_2ghz; - if (adapter->config_bands & BAND_A) - wiphy->bands[NL80211_BAND_5GHZ] = &mwifiex_band_5ghz; - else + wiphy->bands[NL80211_BAND_2GHZ] = devm_kmemdup(adapter->dev, + &mwifiex_band_2ghz, + sizeof(mwifiex_band_2ghz), + GFP_KERNEL); + if (!wiphy->bands[NL80211_BAND_2GHZ]) { + ret = -ENOMEM; + goto err; + } + + if (adapter->config_bands & BAND_A) { + wiphy->bands[NL80211_BAND_5GHZ] = devm_kmemdup(adapter->dev, + &mwifiex_band_5ghz, + sizeof(mwifiex_band_5ghz), + GFP_KERNEL); + if (!wiphy->bands[NL80211_BAND_5GHZ]) { + ret = -ENOMEM; + goto err; + } + } else { wiphy->bands[NL80211_BAND_5GHZ] = NULL; + } if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; @@ -4393,14 +4808,18 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) ether_addr_copy(wiphy->perm_addr, adapter->perm_addr); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | - WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | + wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_PS_ON_BY_DEFAULT; + if (adapter->host_mlme_enabled) + wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS; + else + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME; + if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP; @@ -4430,6 +4849,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) NL80211_FEATURE_LOW_PRIORITY_SCAN | NL80211_FEATURE_NEED_OBSS_SCAN; + if (adapter->host_mlme_enabled) + wiphy->features |= NL80211_FEATURE_SAE; + if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info)) wiphy->features |= NL80211_FEATURE_HT_IBSS; @@ -4459,8 +4881,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) if (ret < 0) { mwifiex_dbg(adapter, ERROR, "%s: wiphy_register failed: %d\n", __func__, ret); - wiphy_free(wiphy); - return ret; + goto err; } if (!adapter->regd) { @@ -4502,4 +4923,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) adapter->wiphy = wiphy; return ret; + +err: + wiphy_free(wiphy); + + return ret; } diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 9eff29a25544..b30ed321c625 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -5,7 +5,7 @@ * Copyright 2011-2020 NXP */ -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "decl.h" #include "ioctl.h" #include "util.h" @@ -482,7 +482,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) if ((adapter->event_cause & EVENT_ID_MASK) == EVENT_RADAR_DETECTED) { for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv && mwifiex_is_11h_active(priv)) { + if (mwifiex_is_11h_active(priv)) { adapter->event_cause |= ((priv->bss_num & 0xff) << 16) | ((priv->bss_type & 0xff) << 24); @@ -635,6 +635,8 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, case HostCmd_CMD_UAP_STA_DEAUTH: case HOST_CMD_APCMD_SYS_RESET: case HOST_CMD_APCMD_STA_LIST: + case HostCmd_CMD_CHAN_REPORT_REQUEST: + case HostCmd_CMD_ADD_NEW_STATION: ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action, cmd_oid, data_buf, cmd_ptr); @@ -924,6 +926,26 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) return ret; } +void mwifiex_process_assoc_resp(struct mwifiex_adapter *adapter) +{ + struct cfg80211_rx_assoc_resp_data assoc_resp = { + .uapsd_queues = -1, + }; + struct mwifiex_private *priv = + mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + + if (priv->assoc_rsp_size) { + assoc_resp.links[0].bss = priv->req_bss; + assoc_resp.buf = priv->assoc_rsp_buf; + assoc_resp.len = priv->assoc_rsp_size; + wiphy_lock(priv->wdev.wiphy); + cfg80211_rx_assoc_resp(priv->netdev, + &assoc_resp); + wiphy_unlock(priv->wdev.wiphy); + priv->assoc_rsp_size = 0; + } +} + /* * This function handles the timeout of command sending. * @@ -1672,6 +1694,13 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, if (adapter->fw_api_ver == MWIFIEX_FW_V15) adapter->scan_chan_gap_enabled = true; + if (adapter->key_api_major_ver != KEY_API_VER_MAJOR_V2) + adapter->host_mlme_enabled = false; + + mwifiex_dbg(adapter, MSG, "host_mlme: %s, key_api: %d\n", + adapter->host_mlme_enabled ? "enable" : "disable", + adapter->key_api_major_ver); + return 0; } diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index f9c9fec7c792..9deaf59dcb62 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -566,14 +566,8 @@ mwifiex_verext_write(struct file *file, const char __user *ubuf, int ret; u32 versionstrsel; struct mwifiex_private *priv = (void *)file->private_data; - char buf[16]; - memset(buf, 0, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - ret = kstrtou32(buf, 10, &versionstrsel); + ret = kstrtou32_from_user(ubuf, count, 10, &versionstrsel); if (ret) return ret; @@ -874,19 +868,14 @@ mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf, { bool timeshare_coex; struct mwifiex_private *priv = file->private_data; - char kbuf[16]; int ret; if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) return -EOPNOTSUPP; - memset(kbuf, 0, sizeof(kbuf)); - - if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) - return -EFAULT; - - if (kstrtobool(kbuf, ×hare_coex)) - return -EINVAL; + ret = kstrtobool_from_user(ubuf, count, ×hare_coex); + if (ret) + return ret; ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, HostCmd_ACT_GEN_SET, 0, ×hare_coex, true); @@ -970,9 +959,6 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, mwifiex_dfs_dir); - if (!priv->dfs_dev_dir) - return; - MWIFIEX_DFS_ADD_FILE(info); MWIFIEX_DFS_ADD_FILE(debug); MWIFIEX_DFS_ADD_FILE(getlog); diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index 326ffb05d791..84603f1e7f6e 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -31,6 +31,29 @@ * + sizeof(tx_control) */ +#define FRMCTL_LEN 2 +#define DURATION_LEN 2 +#define SEQCTL_LEN 2 +/* special FW 4 address management header */ +#define MWIFIEX_MGMT_HEADER_LEN (FRMCTL_LEN + DURATION_LEN + ETH_ALEN + \ + ETH_ALEN + ETH_ALEN + SEQCTL_LEN + ETH_ALEN) + +#define AUTH_ALG_LEN 2 +#define AUTH_TRANSACTION_LEN 2 +#define AUTH_STATUS_LEN 2 +#define MWIFIEX_AUTH_BODY_LEN (AUTH_ALG_LEN + AUTH_TRANSACTION_LEN + \ + AUTH_STATUS_LEN) + +#define HOST_MLME_AUTH_PENDING BIT(0) +#define HOST_MLME_AUTH_DONE BIT(1) + +#define HOST_MLME_MGMT_MASK (BIT(IEEE80211_STYPE_AUTH >> 4) | \ + BIT(IEEE80211_STYPE_DEAUTH >> 4) | \ + BIT(IEEE80211_STYPE_DISASSOC >> 4)) +#define AUTH_TX_DEFAULT_WAIT_TIME 2400 + +#define WLAN_AUTH_NONE 0xFFFF + #define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2 #define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16 #define MWIFIEX_MAX_TDLS_PEER_SUPPORTED 8 diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 62f3c9a52a1d..4a96281792cc 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -210,6 +210,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_RANDOM_MAC (PROPRIETARY_TLV_BASE_ID + 236) #define TLV_TYPE_CHAN_ATTR_CFG (PROPRIETARY_TLV_BASE_ID + 237) #define TLV_TYPE_MAX_CONN (PROPRIETARY_TLV_BASE_ID + 279) +#define TLV_TYPE_HOST_MLME (PROPRIETARY_TLV_BASE_ID + 307) +#define TLV_TYPE_UAP_STA_FLAGS (PROPRIETARY_TLV_BASE_ID + 313) +#define TLV_TYPE_SAE_PWE_MODE (PROPRIETARY_TLV_BASE_ID + 339) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -405,6 +408,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_STA_CONFIGURE 0x023f #define HostCmd_CMD_CHAN_REGION_CFG 0x0242 #define HostCmd_CMD_PACKET_AGGR_CTRL 0x0251 +#define HostCmd_CMD_ADD_NEW_STATION 0x025f #define PROTOCOL_NO_SECURITY 0x01 #define PROTOCOL_STATIC_WEP 0x02 @@ -415,6 +419,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define KEY_MGMT_NONE 0x04 #define KEY_MGMT_PSK 0x02 #define KEY_MGMT_EAP 0x01 +#define KEY_MGMT_PSK_SHA256 0x100 +#define KEY_MGMT_SAE 0x400 #define CIPHER_TKIP 0x04 #define CIPHER_AES_CCMP 0x08 #define VALID_CIPHER_BITMAP 0x0c @@ -500,6 +506,9 @@ enum mwifiex_channel_flags { #define HostCmd_ACT_GET_TX 0x0008 #define HostCmd_ACT_GET_BOTH 0x000c +#define HostCmd_ACT_REMOVE_STA 0x0 +#define HostCmd_ACT_ADD_STA 0x1 + #define RF_ANTENNA_AUTO 0xFFFF #define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) \ @@ -744,6 +753,25 @@ struct uap_rxpd { u8 flags; } __packed; +struct mwifiex_auth { + __le16 auth_alg; + __le16 auth_transaction; + __le16 status_code; + /* possibly followed by Challenge text */ + u8 variable[]; +} __packed; + +struct mwifiex_ieee80211_mgmt { + __le16 frame_control; + __le16 duration; + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 seq_ctrl; + u8 addr4[ETH_ALEN]; + struct mwifiex_auth auth; +} __packed; + struct mwifiex_fw_chan_stats { u8 chan_num; u8 bandcfg; @@ -770,7 +798,7 @@ struct mwifiex_chan_scan_param_set { struct mwifiex_ie_types_chan_list_param_set { struct mwifiex_ie_types_header header; - struct mwifiex_chan_scan_param_set chan_scan_param[1]; + struct mwifiex_chan_scan_param_set chan_scan_param[]; } __packed; struct mwifiex_ie_types_rxba_sync { @@ -803,6 +831,11 @@ struct mwifiex_ie_types_ssid_param_set { u8 ssid[]; } __packed; +struct mwifiex_ie_types_host_mlme { + struct mwifiex_ie_types_header header; + u8 host_mlme; +} __packed; + struct mwifiex_ie_types_num_probes { struct mwifiex_ie_types_header header; __le16 num_probes; @@ -842,7 +875,7 @@ struct mwifiex_ietypes_chanstats { struct mwifiex_ie_types_wildcard_ssid_params { struct mwifiex_ie_types_header header; u8 max_ssid_length; - u8 ssid[1]; + u8 ssid[]; } __packed; #define TSF_DATA_SIZE 8 @@ -906,6 +939,13 @@ struct mwifiex_ie_types_tdls_idle_timeout { __le16 value; } __packed; +#define MWIFIEX_AUTHTYPE_SAE 6 + +struct mwifiex_ie_types_sae_pwe_mode { + struct mwifiex_ie_types_header header; + u8 pwe[]; +} __packed; + struct mwifiex_ie_types_rsn_param_set { struct mwifiex_ie_types_header header; u8 rsn_ie[]; @@ -1587,7 +1627,7 @@ struct host_cmd_ds_802_11_scan_rsp { struct host_cmd_ds_802_11_scan_ext { u32 reserved; - u8 tlv_buffer[1]; + u8 tlv_buffer[]; } __packed; struct mwifiex_ie_types_bss_mode { @@ -2298,6 +2338,20 @@ struct host_cmd_ds_sta_configure { u8 tlv_buffer[]; } __packed; +struct mwifiex_ie_types_sta_flag { + struct mwifiex_ie_types_header header; + __le32 sta_flags; +} __packed; + +struct host_cmd_ds_add_station { + __le16 action; + __le16 aid; + u8 peer_mac[ETH_ALEN]; + __le32 listen_interval; + __le16 cap_info; + u8 tlv[]; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2376,6 +2430,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_chan_region_cfg reg_cfg; struct host_cmd_ds_pkt_aggr_ctrl pkt_aggr_ctrl; struct host_cmd_ds_sta_configure sta_cfg; + struct host_cmd_ds_add_station sta_info; } params; } __packed; diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index c9c58419c37b..8b61e45cd667 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -81,6 +81,9 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + priv->sec_info.wep_enabled = 0; priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; priv->sec_info.encryption_mode = 0; @@ -220,6 +223,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->cmd_resp_received = false; adapter->event_received = false; adapter->data_received = false; + adapter->assoc_resp_received = false; + adapter->priv_link_lost = NULL; + adapter->host_mlme_link_lost = false; clear_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags); @@ -362,15 +368,13 @@ static void mwifiex_invalidate_lists(struct mwifiex_adapter *adapter) list_del(&adapter->bss_prio_tbl[i].bss_prio_head); for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - priv = adapter->priv[i]; - for (j = 0; j < MAX_NUM_TID; ++j) - list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); - list_del(&priv->tx_ba_stream_tbl_ptr); - list_del(&priv->rx_reorder_tbl_ptr); - list_del(&priv->sta_list); - list_del(&priv->auto_tdls_list); - } + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + list_del(&priv->sta_list); + list_del(&priv->auto_tdls_list); } } @@ -419,13 +423,11 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) spin_lock_init(&adapter->mwifiex_cmd_lock); spin_lock_init(&adapter->queue_lock); for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - priv = adapter->priv[i]; - spin_lock_init(&priv->wmm.ra_list_spinlock); - spin_lock_init(&priv->curr_bcn_buf_lock); - spin_lock_init(&priv->sta_list_spinlock); - spin_lock_init(&priv->auto_tdls_lock); - } + priv = adapter->priv[i]; + spin_lock_init(&priv->wmm.ra_list_spinlock); + spin_lock_init(&priv->curr_bcn_buf_lock); + spin_lock_init(&priv->sta_list_spinlock); + spin_lock_init(&priv->auto_tdls_lock); } /* Initialize cmd_free_q */ @@ -449,8 +451,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) } for (i = 0; i < adapter->priv_num; i++) { - if (!adapter->priv[i]) - continue; priv = adapter->priv[i]; for (j = 0; j < MAX_NUM_TID; ++j) INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list); @@ -500,31 +500,24 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) mwifiex_init_adapter(adapter); for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - priv = adapter->priv[i]; + priv = adapter->priv[i]; - /* Initialize private structure */ - ret = mwifiex_init_priv(priv); - if (ret) - return -1; - } + /* Initialize private structure */ + ret = mwifiex_init_priv(priv); + if (ret) + return -1; } if (adapter->mfg_mode) { adapter->hw_status = MWIFIEX_HW_STATUS_READY; ret = -EINPROGRESS; } else { for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - ret = mwifiex_sta_init_cmd(adapter->priv[i], - first_sta, true); - if (ret == -1) - return -1; - - first_sta = false; - } - - + ret = mwifiex_sta_init_cmd(adapter->priv[i], + first_sta, true); + if (ret == -1) + return -1; + first_sta = false; } } @@ -631,13 +624,11 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) /* 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]; + priv = adapter->priv[i]; - mwifiex_clean_auto_tdls(priv); - mwifiex_abort_cac(priv); - mwifiex_free_priv(priv); - } + mwifiex_clean_auto_tdls(priv); + mwifiex_abort_cac(priv); + mwifiex_free_priv(priv); } atomic_set(&adapter->tx_queued, 0); diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index e8825f302de8..74747d3a379a 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -8,7 +8,7 @@ #ifndef _MWIFIEX_IOCTL_H_ #define _MWIFIEX_IOCTL_H_ -#include <net/lib80211.h> +#define NUM_WEP_KEYS 4 enum { MWIFIEX_SCAN_TYPE_UNCHANGED = 0, @@ -158,6 +158,11 @@ struct mwifiex_bss_info { u8 bssid[ETH_ALEN]; }; +struct mwifiex_sta_info { + u8 peer_mac[ETH_ALEN]; + struct station_parameters *params; +}; + #define MAX_NUM_TID 8 #define MAX_RX_WINSIZE 64 diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 9d98a1908dd6..5a1a0287c1d5 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -382,7 +382,9 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, struct mwifiex_ie_types_ss_param_set *ss_tlv; struct mwifiex_ie_types_rates_param_set *rates_tlv; struct mwifiex_ie_types_auth_type *auth_tlv; + struct mwifiex_ie_types_sae_pwe_mode *sae_pwe_tlv; struct mwifiex_ie_types_chan_list_param_set *chan_tlv; + struct mwifiex_ie_types_host_mlme *host_mlme_tlv; u8 rates[MWIFIEX_SUPPORTED_RATES]; u32 rates_size; u16 tmp_cap; @@ -460,6 +462,24 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); + if (priv->sec_info.authentication_mode == WLAN_AUTH_SAE) { + auth_tlv->auth_type = cpu_to_le16(MWIFIEX_AUTHTYPE_SAE); + if (bss_desc->bcn_rsnx_ie && + bss_desc->bcn_rsnx_ie->ieee_hdr.len && + (bss_desc->bcn_rsnx_ie->data[0] & + WLAN_RSNX_CAPA_SAE_H2E)) { + sae_pwe_tlv = + (struct mwifiex_ie_types_sae_pwe_mode *)pos; + sae_pwe_tlv->header.type = + cpu_to_le16(TLV_TYPE_SAE_PWE_MODE); + sae_pwe_tlv->header.len = + cpu_to_le16(sizeof(sae_pwe_tlv->pwe[0])); + sae_pwe_tlv->pwe[0] = bss_desc->bcn_rsnx_ie->data[0]; + pos += sizeof(sae_pwe_tlv->header) + + sizeof(sae_pwe_tlv->pwe[0]); + } + } + if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && (!bss_desc->disable_11n) && @@ -491,6 +511,16 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, sizeof(struct mwifiex_chan_scan_param_set); } + if (priv->adapter->host_mlme_enabled) { + host_mlme_tlv = (struct mwifiex_ie_types_host_mlme *)pos; + host_mlme_tlv->header.type = cpu_to_le16(TLV_TYPE_HOST_MLME); + host_mlme_tlv->header.len = + cpu_to_le16(sizeof(host_mlme_tlv->host_mlme)); + host_mlme_tlv->host_mlme = 1; + pos += sizeof(host_mlme_tlv->header) + + sizeof(host_mlme_tlv->host_mlme); + } + if (!priv->wps.session_enable) { if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); @@ -633,7 +663,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, bool enable_data = true; u16 cap_info, status_code, aid; const u8 *ie_ptr; - struct ieee80211_ht_operation *assoc_resp_ht_oper; if (!priv->attempted_bss_desc) { mwifiex_dbg(priv->adapter, ERROR, @@ -641,7 +670,21 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, goto done; } - assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; + if (adapter->host_mlme_enabled) { + struct ieee80211_mgmt *hdr; + + hdr = (struct ieee80211_mgmt *)&resp->params; + if (!memcmp(hdr->bssid, + priv->attempted_bss_desc->mac_address, + ETH_ALEN)) + assoc_rsp = (struct ieee_types_assoc_rsp *) + &hdr->u.assoc_resp; + else + assoc_rsp = + (struct ieee_types_assoc_rsp *)&resp->params; + } else { + 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); @@ -680,6 +723,9 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, mwifiex_dbg(priv->adapter, ERROR, "ASSOC_RESP: UNSPECIFIED failure\n"); } + + if (priv->adapter->host_mlme_enabled) + priv->assoc_rsp_size = 0; } else { ret = status_code; } @@ -732,14 +778,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, priv->assoc_rsp_size - sizeof(struct ieee_types_assoc_rsp)); - if (ie_ptr) { - assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr - + sizeof(struct ieee_types_header)); - priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; - priv->ht_param_present = true; - } else { - priv->ht_param_present = false; - } + + priv->ht_param_present = ie_ptr ? true : false; mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", @@ -778,7 +818,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, priv->adapter->dbg.num_cmd_assoc_success++; - mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n"); + mwifiex_dbg(priv->adapter, MSG, "assoc: associated with %pM\n", + priv->attempted_bss_desc->mac_address); /* Add the ra_list here for infra mode as there will be only 1 ra always */ @@ -1491,6 +1532,20 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) if (!priv->media_connected) return 0; + if (priv->adapter->host_mlme_enabled) { + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + priv->host_mlme_reg = false; + priv->mgmt_frame_mask = 0; + if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG, + HostCmd_ACT_GEN_SET, 0, + &priv->mgmt_frame_mask, false)) { + mwifiex_dbg(priv->adapter, ERROR, + "could not unregister mgmt frame rx\n"); + return -1; + } + } + switch (priv->bss_mode) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -1520,8 +1575,7 @@ void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv) - mwifiex_deauthenticate(priv, NULL); + mwifiex_deauthenticate(priv, NULL); } } EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all); diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index d99127dc466e..855019fe5485 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -127,10 +127,8 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) /* Free private structures */ for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - mwifiex_free_curr_bcn(adapter->priv[i]); - kfree(adapter->priv[i]); - } + mwifiex_free_curr_bcn(adapter->priv[i]); + kfree(adapter->priv[i]); } if (adapter->nd_info) { @@ -530,6 +528,11 @@ static void mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) destroy_workqueue(adapter->rx_workqueue); adapter->rx_workqueue = NULL; } + + if (adapter->host_mlme_workqueue) { + destroy_workqueue(adapter->host_mlme_workqueue); + adapter->host_mlme_workqueue = NULL; + } } /* @@ -802,6 +805,10 @@ mwifiex_bypass_tx_queue(struct mwifiex_private *priv, "bypass txqueue; eth type %#x, mgmt %d\n", ntohs(eth_hdr->h_proto), mwifiex_is_skb_mgmt_frame(skb)); + if (eth_hdr->h_proto == htons(ETH_P_PAE)) + mwifiex_dbg(priv->adapter, MSG, + "key: send EAPOL to %pM\n", + eth_hdr->h_dest); return true; } @@ -1162,7 +1169,7 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter) } for (i = 0; i < adapter->priv_num; i++) { - if (!adapter->priv[i] || !adapter->priv[i]->netdev) + if (!adapter->priv[i]->netdev) continue; priv = adapter->priv[i]; p += sprintf(p, "\n[interface : \"%s\"]\n", @@ -1201,7 +1208,7 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter) debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL); if (debug_info) { for (i = 0; i < adapter->priv_num; i++) { - if (!adapter->priv[i] || !adapter->priv[i]->netdev) + if (!adapter->priv[i]->netdev) continue; priv = adapter->priv[i]; mwifiex_get_debug_info(priv, debug_info); @@ -1384,6 +1391,35 @@ int is_command_pending(struct mwifiex_adapter *adapter) return !is_cmd_pend_q_empty; } +/* This is the host mlme work queue function. + * It handles the host mlme operations. + */ +static void mwifiex_host_mlme_work_queue(struct work_struct *work) +{ + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, host_mlme_work); + + if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags)) + return; + + /* Check for host mlme disconnection */ + if (adapter->host_mlme_link_lost) { + if (adapter->priv_link_lost) { + mwifiex_reset_connect_state(adapter->priv_link_lost, + WLAN_REASON_DEAUTH_LEAVING, + true); + adapter->priv_link_lost = NULL; + } + adapter->host_mlme_link_lost = false; + } + + /* Check for host mlme Assoc Resp */ + if (adapter->assoc_resp_received) { + mwifiex_process_assoc_resp(adapter); + adapter->assoc_resp_received = false; + } +} + /* * This is the RX work queue function. * @@ -1434,7 +1470,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv && priv->netdev) { + if (priv->netdev) { mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); @@ -1459,8 +1495,6 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (!priv) - continue; rtnl_lock(); if (priv->netdev && priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) { @@ -1558,6 +1592,18 @@ mwifiex_reinit_sw(struct mwifiex_adapter *adapter) INIT_WORK(&adapter->rx_work, mwifiex_rx_work_queue); } + if (adapter->host_mlme_enabled) { + adapter->host_mlme_workqueue = + alloc_workqueue("MWIFIEX_HOST_MLME_WORK_QUEUE", + WQ_HIGHPRI | + WQ_MEM_RECLAIM | + WQ_UNBOUND, 0); + if (!adapter->host_mlme_workqueue) + goto err_kmalloc; + INIT_WORK(&adapter->host_mlme_work, + mwifiex_host_mlme_work_queue); + } + /* Register the device. Fill up the private data structure with * relevant information from the card. Some code extracted from * mwifiex_register_dev() @@ -1633,7 +1679,8 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) } ret = devm_request_irq(dev, adapter->irq_wakeup, - mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW, + mwifiex_irq_wakeup_handler, + IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN, "wifi_wake", adapter); if (ret) { dev_err(dev, "Failed to request irq_wakeup %d (%d)\n", @@ -1641,7 +1688,6 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) goto err_exit; } - disable_irq(adapter->irq_wakeup); if (device_init_wakeup(dev, true)) { dev_err(dev, "fail to init wakeup for mwifiex\n"); goto err_exit; @@ -1721,6 +1767,18 @@ mwifiex_add_card(void *card, struct completion *fw_done, goto err_registerdev; } + if (adapter->host_mlme_enabled) { + adapter->host_mlme_workqueue = + alloc_workqueue("MWIFIEX_HOST_MLME_WORK_QUEUE", + WQ_HIGHPRI | + WQ_MEM_RECLAIM | + WQ_UNBOUND, 0); + if (!adapter->host_mlme_workqueue) + goto err_kmalloc; + INIT_WORK(&adapter->host_mlme_work, + mwifiex_host_mlme_work_queue); + } + if (mwifiex_init_hw_fw(adapter, true)) { pr_err("%s: firmware init failed\n", __func__); goto err_init_fw; diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 318b42b1896f..0674dcf7a537 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -19,7 +19,6 @@ #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <net/sock.h> -#include <net/lib80211.h> #include <linux/vmalloc.h> #include <linux/firmware.h> #include <linux/ctype.h> @@ -28,11 +27,9 @@ #include <linux/inetdevice.h> #include <linux/devcoredump.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/gfp.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -426,6 +423,8 @@ struct mwifiex_bssdescriptor { u16 wpa_offset; struct ieee_types_generic *bcn_rsn_ie; u16 rsn_offset; + struct ieee_types_generic *bcn_rsnx_ie; + u16 rsnx_offset; struct ieee_types_generic *bcn_wapi_ie; u16 wapi_offset; u8 *beacon_buf; @@ -527,6 +526,8 @@ struct mwifiex_private { u8 bss_priority; u8 bss_num; u8 bss_started; + u8 auth_flag; + u16 auth_alg; u8 frame_type; u8 curr_addr[ETH_ALEN]; u8 media_connected; @@ -572,7 +573,6 @@ struct mwifiex_private { u16 listen_interval; u16 atim_window; u8 adhoc_channel; - u8 adhoc_is_link_sensed; u8 adhoc_state; struct mwifiex_802_11_security sec_info; struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; @@ -610,6 +610,7 @@ struct mwifiex_private { #define MWIFIEX_ASSOC_RSP_BUF_SIZE 500 u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE]; u32 assoc_rsp_size; + struct cfg80211_bss *req_bss; #define MWIFIEX_GENIE_BUF_SIZE 256 u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE]; @@ -649,6 +650,7 @@ struct mwifiex_private { u16 gen_idx; u8 ap_11n_enabled; u8 ap_11ac_enabled; + bool host_mlme_reg; u32 mgmt_frame_mask; struct mwifiex_roc_cfg roc_cfg; bool scan_aborting; @@ -679,7 +681,6 @@ struct mwifiex_private { struct mwifiex_ds_mem_rw mem_rw; struct sk_buff_head bypass_txq; struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX]; - u8 assoc_resp_ht_param; bool ht_param_present; }; @@ -795,10 +796,9 @@ struct mwifiex_auto_tdls_peer { u8 mac_addr[ETH_ALEN]; u8 tdls_status; int rssi; - long rssi_jiffies; + unsigned long rssi_jiffies; u8 failure_count; u8 do_discover; - u8 do_setup; }; #define MWIFIEX_TYPE_AGGR_DATA_V2 11 @@ -878,6 +878,8 @@ struct mwifiex_adapter { struct work_struct main_work; struct workqueue_struct *rx_workqueue; struct work_struct rx_work; + struct workqueue_struct *host_mlme_workqueue; + struct work_struct host_mlme_work; bool rx_work_enabled; bool rx_processing; bool delay_main_work; @@ -909,6 +911,9 @@ struct mwifiex_adapter { u8 cmd_resp_received; u8 event_received; u8 data_received; + u8 assoc_resp_received; + struct mwifiex_private *priv_link_lost; + u8 host_mlme_link_lost; u16 seq_num; struct cmd_ctrl_node *cmd_pool; struct cmd_ctrl_node *curr_cmd; @@ -998,6 +1003,8 @@ struct mwifiex_adapter { bool is_up; bool ext_scan; + bool host_mlme_enabled; + struct ieee80211_txrx_stypes mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES]; u8 fw_api_ver; u8 key_api_major_ver, key_api_minor_ver; u8 max_p2p_conn, max_sta_conn; @@ -1063,6 +1070,9 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb); int mwifiex_uap_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb); +void mwifiex_host_mlme_disconnect(struct mwifiex_private *priv, + u16 reason_code, u8 *sa); + int mwifiex_process_mgmt_packet(struct mwifiex_private *priv, struct sk_buff *skb); @@ -1094,6 +1104,7 @@ void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); +void mwifiex_process_assoc_resp(struct mwifiex_adapter *adapter); int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb); int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, @@ -1288,11 +1299,12 @@ mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter, int i; for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - if ((adapter->priv[i]->bss_num == bss_num) && - (adapter->priv[i]->bss_type == bss_type)) - break; - } + if (adapter->priv[i]->bss_mode == NL80211_IFTYPE_UNSPECIFIED) + continue; + + if ((adapter->priv[i]->bss_num == bss_num) && + (adapter->priv[i]->bss_type == bss_type)) + break; } return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); } @@ -1308,11 +1320,9 @@ mwifiex_get_priv(struct mwifiex_adapter *adapter, int i; for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - if (bss_role == MWIFIEX_BSS_ROLE_ANY || - GET_BSS_ROLE(adapter->priv[i]) == bss_role) - break; - } + if (bss_role == MWIFIEX_BSS_ROLE_ANY || + GET_BSS_ROLE(adapter->priv[i]) == bss_role) + break; } return ((i < adapter->priv_num) ? adapter->priv[i] : NULL); @@ -1330,12 +1340,10 @@ mwifiex_get_unused_bss_num(struct mwifiex_adapter *adapter, u8 bss_type) memset(index, 0, sizeof(index)); for (i = 0; i < adapter->priv_num; i++) - if (adapter->priv[i]) { - if (adapter->priv[i]->bss_type == bss_type && - !(adapter->priv[i]->bss_mode == - NL80211_IFTYPE_UNSPECIFIED)) { - index[adapter->priv[i]->bss_num] = 1; - } + if (adapter->priv[i]->bss_type == bss_type && + !(adapter->priv[i]->bss_mode == + NL80211_IFTYPE_UNSPECIFIED)) { + index[adapter->priv[i]->bss_num] = 1; } for (j = 0; j < MWIFIEX_MAX_BSS_NUM; j++) if (!index[j]) diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index a2ddac363b10..cab889af4c4a 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -664,15 +664,14 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, /* Copy the current channel TLV to the command being prepared */ - memcpy(chan_tlv_out->chan_scan_param + tlv_idx, + memcpy(&chan_tlv_out->chan_scan_param[tlv_idx], tmp_chan_list, - sizeof(chan_tlv_out->chan_scan_param)); + sizeof(*chan_tlv_out->chan_scan_param)); /* Increment the TLV header length by the size appended */ le16_unaligned_add_cpu(&chan_tlv_out->header.len, - sizeof( - chan_tlv_out->chan_scan_param)); + sizeof(*chan_tlv_out->chan_scan_param)); /* * The tlv buffer length is set to the number of bytes @@ -1372,6 +1371,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, bss_entry->rsn_offset = (u16) (current_ptr - bss_entry->beacon_buf); break; + case WLAN_EID_RSNX: + bss_entry->bcn_rsnx_ie = + (struct ieee_types_generic *)current_ptr; + bss_entry->rsnx_offset = + (u16)(current_ptr - bss_entry->beacon_buf); + break; case WLAN_EID_BSS_AC_ACCESS_DELAY: bss_entry->bcn_wapi_ie = (struct ieee_types_generic *) current_ptr; @@ -2046,8 +2051,6 @@ void mwifiex_cancel_scan(struct mwifiex_adapter *adapter) spin_unlock_bh(&adapter->mwifiex_cmd_lock); for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (!priv) - continue; if (priv->scan_request) { struct cfg80211_scan_info info = { .aborted = true, @@ -2369,12 +2372,11 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX && bgscan_cfg_in->chan_list[chan_idx].chan_number; chan_idx++) { - temp_chan = chan_list_tlv->chan_scan_param + chan_idx; + temp_chan = &chan_list_tlv->chan_scan_param[chan_idx]; /* Increment the TLV header length by size appended */ le16_unaligned_add_cpu(&chan_list_tlv->header.len, - sizeof( - chan_list_tlv->chan_scan_param)); + sizeof(*chan_list_tlv->chan_scan_param)); temp_chan->chan_number = bgscan_cfg_in->chan_list[chan_idx].chan_number; @@ -2413,7 +2415,7 @@ int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv, chan_scan_param); le16_unaligned_add_cpu(&chan_list_tlv->header.len, chan_num * - sizeof(chan_list_tlv->chan_scan_param[0])); + sizeof(*chan_list_tlv->chan_scan_param)); } tlv_pos += (sizeof(chan_list_tlv->header) @@ -2532,8 +2534,7 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv, ext_scan_resp = &resp->params.ext_scan; tlv = (void *)ext_scan_resp->tlv_buffer; - buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN - - 1); + buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN); while (buf_left >= sizeof(struct mwifiex_ie_types_header)) { type = le16_to_cpu(tlv->type); diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 75f53c2f1e1f..490ffd981164 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -332,6 +332,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = { .can_auto_tdls = false, .can_ext_scan = false, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { @@ -348,6 +349,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { @@ -364,6 +366,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { @@ -380,6 +383,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8977 = { @@ -397,6 +401,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8977 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8978 = { @@ -414,6 +419,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8978 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = true, + .host_mlme = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { @@ -432,6 +438,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { @@ -448,6 +455,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { .can_auto_tdls = true, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8987 = { @@ -465,6 +473,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8987 = { .can_auto_tdls = true, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { @@ -481,6 +490,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, + .host_mlme = false, }; static struct memory_type_mapping generic_mem_type_map[] = { @@ -574,6 +584,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) card->can_auto_tdls = data->can_auto_tdls; card->can_ext_scan = data->can_ext_scan; card->fw_ready_extra_delay = data->fw_ready_extra_delay; + card->host_mlme = data->host_mlme; INIT_WORK(&card->work, mwifiex_sdio_work); } @@ -979,7 +990,6 @@ static struct sdio_driver mwifiex_sdio = { .probe = mwifiex_sdio_probe, .remove = mwifiex_sdio_remove, .drv = { - .owner = THIS_MODULE, .coredump = mwifiex_sdio_coredump, .pm = &mwifiex_sdio_pm_ops, } @@ -2512,6 +2522,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter) adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl); } + adapter->host_mlme_enabled = card->host_mlme; + return 0; } @@ -3183,7 +3195,7 @@ static struct mwifiex_if_ops sdio_ops = { .up_dev = mwifiex_sdio_up_dev, }; -module_driver(mwifiex_sdio, sdio_register_driver, sdio_unregister_driver); +module_sdio_driver(mwifiex_sdio); MODULE_AUTHOR("Marvell International Ltd."); MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION); @@ -3192,6 +3204,7 @@ MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(SD8786_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8787_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8797_DEFAULT_FW_NAME); +MODULE_FIRMWARE(SD8801_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8897_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8887_DEFAULT_FW_NAME); MODULE_FIRMWARE(SD8977_DEFAULT_FW_NAME); diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.h b/drivers/net/wireless/marvell/mwifiex/sdio.h index cb63ad55d675..65d142286c46 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.h +++ b/drivers/net/wireless/marvell/mwifiex/sdio.h @@ -256,6 +256,7 @@ struct sdio_mmc_card { bool can_auto_tdls; bool can_ext_scan; bool fw_ready_extra_delay; + bool host_mlme; struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; @@ -280,6 +281,7 @@ struct mwifiex_sdio_device { bool can_auto_tdls; bool can_ext_scan; bool fw_ready_extra_delay; + bool host_mlme; }; /* diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 7b69d27e0c0e..9c53825f222d 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1398,6 +1398,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_UAP_STA_DEAUTH: break; + case HostCmd_CMD_ADD_NEW_STATION: + break; case HOST_CMD_APCMD_SYS_RESET: break; case HostCmd_CMD_MEF_CFG: diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index df9cdd10a494..400348abeee5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -135,6 +135,9 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, priv->media_connected = false; + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + priv->scan_block = false; priv->port_open = false; @@ -174,17 +177,14 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, 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) { + 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 @@ -222,8 +222,12 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, 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); + if (adapter->host_mlme_enabled && adapter->host_mlme_link_lost) + mwifiex_host_mlme_disconnect(adapter->priv_link_lost, + reason_code, NULL); + else + cfg80211_disconnected(priv->netdev, reason_code, NULL, + 0, !from_ap, GFP_KERNEL); } eth_zero_addr(priv->cfg_bssid); @@ -746,7 +750,15 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) if (priv->media_connected) { reason_code = get_unaligned_le16(adapter->event_body); - mwifiex_reset_connect_state(priv, reason_code, true); + if (adapter->host_mlme_enabled) { + adapter->priv_link_lost = priv; + adapter->host_mlme_link_lost = true; + queue_work(adapter->host_mlme_workqueue, + &adapter->host_mlme_work); + } else { + mwifiex_reset_connect_state(priv, reason_code, + true); + } } break; @@ -828,7 +840,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_ADHOC_BCN_LOST: mwifiex_dbg(adapter, EVENT, "event: ADHOC_BCN_LOST\n"); - priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) @@ -999,10 +1010,17 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_REMAIN_ON_CHAN_EXPIRED: mwifiex_dbg(adapter, EVENT, "event: Remain on channel expired\n"); - cfg80211_remain_on_channel_expired(&priv->wdev, - priv->roc_cfg.cookie, - &priv->roc_cfg.chan, - GFP_ATOMIC); + + if (adapter->host_mlme_enabled && + (priv->auth_flag & HOST_MLME_AUTH_PENDING)) { + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + } else { + cfg80211_remain_on_channel_expired(&priv->wdev, + priv->roc_cfg.cookie, + &priv->roc_cfg.chan, + GFP_ATOMIC); + } memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg)); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 32a27fad7b79..f79589cafe57 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -339,7 +339,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, ret = mwifiex_associate(priv, bss_desc); } - if (bss) + if (bss && !priv->adapter->host_mlme_enabled) cfg80211_put_bss(priv->adapter->wiphy, bss); } else { /* Adhoc mode */ @@ -351,8 +351,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, goto done; } - priv->adhoc_is_link_sensed = false; - ret = mwifiex_check_network_compatibility(priv, bss_desc); mwifiex_stop_net_dev_queue(priv->netdev, adapter); @@ -503,8 +501,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) if (disconnect_on_suspend) { for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv) - mwifiex_deauthenticate(priv, NULL); + mwifiex_deauthenticate(priv, NULL); } } @@ -548,7 +545,7 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q, adapter->hs_activate_wait_q_woken, - (10 * HZ)) <= 0) { + (5 * HZ)) <= 0) { mwifiex_dbg(adapter, ERROR, "hs_activate_wait_q terminated\n"); return false; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_tx.c b/drivers/net/wireless/marvell/mwifiex/sta_tx.c index 70c2790b8e35..9d0ef04ebe02 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_tx.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_tx.c @@ -36,7 +36,7 @@ void mwifiex_process_sta_txpd(struct mwifiex_private *priv, struct txpd *local_tx_pd; struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb); unsigned int pad; - u16 pkt_type, pkt_offset; + u16 pkt_type, pkt_length, pkt_offset; int hroom = adapter->intf_hdr_len; pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0; @@ -49,9 +49,10 @@ void mwifiex_process_sta_txpd(struct mwifiex_private *priv, memset(local_tx_pd, 0, sizeof(struct txpd)); local_tx_pd->bss_num = priv->bss_num; local_tx_pd->bss_type = priv->bss_type; - local_tx_pd->tx_pkt_length = cpu_to_le16((u16)(skb->len - - (sizeof(struct txpd) + - pad))); + pkt_length = (u16)(skb->len - (sizeof(struct txpd) + pad)); + if (pkt_type == PKT_TYPE_MGMT) + pkt_length -= MWIFIEX_MGMT_FRAME_HEADER_SIZE; + local_tx_pd->tx_pkt_length = cpu_to_le16(pkt_length); local_tx_pd->priority = (u8) skb->priority; local_tx_pd->pkt_delay_2ms = diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 6c60621b6ccc..0a5f340876c3 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -1306,7 +1306,6 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb) peer->mac_addr, NL80211_TDLS_SETUP, 0, GFP_ATOMIC); - peer->do_setup = false; priv->check_tdls_tx = false; } else if (peer->failure_count < MWIFIEX_TDLS_MAX_FAIL_COUNT && @@ -1439,8 +1438,8 @@ void mwifiex_check_auto_tdls(struct timer_list *t) spin_lock_bh(&priv->auto_tdls_lock); list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) { - if ((jiffies - tdls_peer->rssi_jiffies) > - (MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) { + if (time_after(jiffies, tdls_peer->rssi_jiffies + + MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) { tdls_peer->rssi = 0; tdls_peer->do_discover = true; priv->check_tdls_tx = true; @@ -1465,7 +1464,6 @@ void mwifiex_check_auto_tdls(struct timer_list *t) tdls_peer->failure_count < MWIFIEX_TDLS_MAX_FAIL_COUNT) { priv->check_tdls_tx = true; - tdls_peer->do_setup = true; mwifiex_dbg(priv->adapter, INFO, "check TDLS with peer=%pM\t" "rssi=%d\n", tdls_peer->mac_addr, diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index 491e36611909..1c0ceac6b27f 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -46,31 +46,26 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST; + bss_config->protocol = 0; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + bss_config->protocol |= PROTOCOL_WPA; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + bss_config->protocol |= PROTOCOL_WPA2; + + bss_config->key_mgmt = 0; for (i = 0; i < params->crypto.n_akm_suites; i++) { switch (params->crypto.akm_suites[i]) { case WLAN_AKM_SUITE_8021X: - if (params->crypto.wpa_versions & - NL80211_WPA_VERSION_1) { - bss_config->protocol = PROTOCOL_WPA; - bss_config->key_mgmt = KEY_MGMT_EAP; - } - if (params->crypto.wpa_versions & - NL80211_WPA_VERSION_2) { - bss_config->protocol |= PROTOCOL_WPA2; - bss_config->key_mgmt = KEY_MGMT_EAP; - } + bss_config->key_mgmt |= KEY_MGMT_EAP; break; case WLAN_AKM_SUITE_PSK: - if (params->crypto.wpa_versions & - NL80211_WPA_VERSION_1) { - bss_config->protocol = PROTOCOL_WPA; - bss_config->key_mgmt = KEY_MGMT_PSK; - } - if (params->crypto.wpa_versions & - NL80211_WPA_VERSION_2) { - bss_config->protocol |= PROTOCOL_WPA2; - bss_config->key_mgmt = KEY_MGMT_PSK; - } + bss_config->key_mgmt |= KEY_MGMT_PSK; + break; + case WLAN_AKM_SUITE_PSK_SHA256: + bss_config->key_mgmt |= KEY_MGMT_PSK_SHA256; + break; + case WLAN_AKM_SUITE_SAE: + bss_config->key_mgmt |= KEY_MGMT_SAE; break; default: break; @@ -751,6 +746,28 @@ mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action, return 0; } +/* This function prepares AP start up command with or without host MLME + */ +static void mwifiex_cmd_uap_bss_start(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd) +{ + struct mwifiex_ie_types_host_mlme *tlv; + int size; + + cmd->command = cpu_to_le16(HostCmd_CMD_UAP_BSS_START); + size = S_DS_GEN; + + if (priv->adapter->host_mlme_enabled) { + tlv = (struct mwifiex_ie_types_host_mlme *)((u8 *)cmd + size); + tlv->header.type = cpu_to_le16(TLV_TYPE_HOST_MLME); + tlv->header.len = cpu_to_le16(sizeof(tlv->host_mlme)); + tlv->host_mlme = 1; + size += sizeof(struct mwifiex_ie_types_host_mlme); + } + + cmd->size = cpu_to_le16(size); +} + /* This function prepares AP specific deauth command with mac supplied in * function parameter. */ @@ -768,6 +785,144 @@ static int mwifiex_cmd_uap_sta_deauth(struct mwifiex_private *priv, return 0; } +/* This function prepares AP specific add station command. + */ +static int mwifiex_cmd_uap_add_station(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_add_station *new_sta = &cmd->params.sta_info; + struct mwifiex_sta_info *add_sta = (struct mwifiex_sta_info *)data_buf; + struct station_parameters *params = add_sta->params; + struct mwifiex_sta_node *sta_ptr; + u8 *pos; + u8 qos_capa; + u16 header_len = sizeof(struct mwifiex_ie_types_header); + u16 tlv_len; + int size; + struct mwifiex_ie_types_data *tlv; + struct mwifiex_ie_types_sta_flag *sta_flag; + int i; + + cmd->command = cpu_to_le16(HostCmd_CMD_ADD_NEW_STATION); + new_sta->action = cpu_to_le16(cmd_action); + size = sizeof(struct host_cmd_ds_add_station) + S_DS_GEN; + + if (cmd_action == HostCmd_ACT_ADD_STA) + sta_ptr = mwifiex_add_sta_entry(priv, add_sta->peer_mac); + else + sta_ptr = mwifiex_get_sta_entry(priv, add_sta->peer_mac); + + if (!sta_ptr) + return -1; + + memcpy(new_sta->peer_mac, add_sta->peer_mac, ETH_ALEN); + + if (cmd_action == HostCmd_ACT_REMOVE_STA) { + cmd->size = cpu_to_le16(size); + return 0; + } + + new_sta->aid = cpu_to_le16(params->aid); + new_sta->listen_interval = cpu_to_le32(params->listen_interval); + new_sta->cap_info = cpu_to_le16(params->capability); + + pos = new_sta->tlv; + + if (params->sta_flags_set & NL80211_STA_FLAG_WME) + sta_ptr->is_wmm_enabled = 1; + sta_flag = (struct mwifiex_ie_types_sta_flag *)pos; + sta_flag->header.type = cpu_to_le16(TLV_TYPE_UAP_STA_FLAGS); + sta_flag->header.len = cpu_to_le16(sizeof(__le32)); + sta_flag->sta_flags = cpu_to_le32(params->sta_flags_set); + pos += sizeof(struct mwifiex_ie_types_sta_flag); + size += sizeof(struct mwifiex_ie_types_sta_flag); + + if (params->ext_capab_len) { + tlv = (struct mwifiex_ie_types_data *)pos; + tlv->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY); + tlv_len = params->ext_capab_len; + tlv->header.len = cpu_to_le16(tlv_len); + memcpy(tlv->data, params->ext_capab, tlv_len); + pos += (header_len + tlv_len); + size += (header_len + tlv_len); + } + + if (params->link_sta_params.supported_rates_len) { + tlv = (struct mwifiex_ie_types_data *)pos; + tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + tlv_len = params->link_sta_params.supported_rates_len; + tlv->header.len = cpu_to_le16(tlv_len); + memcpy(tlv->data, + params->link_sta_params.supported_rates, tlv_len); + pos += (header_len + tlv_len); + size += (header_len + tlv_len); + } + + if (params->uapsd_queues || params->max_sp) { + tlv = (struct mwifiex_ie_types_data *)pos; + tlv->header.type = cpu_to_le16(WLAN_EID_QOS_CAPA); + tlv_len = sizeof(qos_capa); + tlv->header.len = cpu_to_le16(tlv_len); + qos_capa = params->uapsd_queues | (params->max_sp << 5); + memcpy(tlv->data, &qos_capa, tlv_len); + pos += (header_len + tlv_len); + size += (header_len + tlv_len); + sta_ptr->is_wmm_enabled = 1; + } + + if (params->link_sta_params.ht_capa) { + tlv = (struct mwifiex_ie_types_data *)pos; + tlv->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + tlv_len = sizeof(struct ieee80211_ht_cap); + tlv->header.len = cpu_to_le16(tlv_len); + memcpy(tlv->data, params->link_sta_params.ht_capa, tlv_len); + pos += (header_len + tlv_len); + size += (header_len + tlv_len); + sta_ptr->is_11n_enabled = 1; + sta_ptr->max_amsdu = + le16_to_cpu(params->link_sta_params.ht_capa->cap_info) & + IEEE80211_HT_CAP_MAX_AMSDU ? + MWIFIEX_TX_DATA_BUF_SIZE_8K : + MWIFIEX_TX_DATA_BUF_SIZE_4K; + } + + if (params->link_sta_params.vht_capa) { + tlv = (struct mwifiex_ie_types_data *)pos; + tlv->header.type = cpu_to_le16(WLAN_EID_VHT_CAPABILITY); + tlv_len = sizeof(struct ieee80211_vht_cap); + tlv->header.len = cpu_to_le16(tlv_len); + memcpy(tlv->data, params->link_sta_params.vht_capa, tlv_len); + pos += (header_len + tlv_len); + size += (header_len + tlv_len); + sta_ptr->is_11ac_enabled = 1; + } + + if (params->link_sta_params.opmode_notif_used) { + tlv = (struct mwifiex_ie_types_data *)pos; + tlv->header.type = cpu_to_le16(WLAN_EID_OPMODE_NOTIF); + tlv_len = sizeof(u8); + tlv->header.len = cpu_to_le16(tlv_len); + memcpy(tlv->data, ¶ms->link_sta_params.opmode_notif, + tlv_len); + pos += (header_len + tlv_len); + size += (header_len + tlv_len); + } + + for (i = 0; i < MAX_NUM_TID; i++) { + if (sta_ptr->is_11n_enabled) + sta_ptr->ampdu_sta[i] = + priv->aggr_prio_tbl[i].ampdu_user; + else + sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; + } + + memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); + cmd->size = cpu_to_le16(size); + + return 0; +} + /* This function prepares the AP specific commands before sending them * to the firmware. * This is a generic function which calls specific command preparation @@ -785,6 +940,8 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, return -1; break; case HostCmd_CMD_UAP_BSS_START: + mwifiex_cmd_uap_bss_start(priv, cmd); + break; case HostCmd_CMD_UAP_BSS_STOP: case HOST_CMD_APCMD_SYS_RESET: case HOST_CMD_APCMD_STA_LIST: @@ -800,6 +957,11 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, data_buf)) return -1; break; + case HostCmd_CMD_ADD_NEW_STATION: + if (mwifiex_cmd_uap_add_station(priv, cmd, cmd_action, + data_buf)) + return -1; + break; default: mwifiex_dbg(priv->adapter, ERROR, "PREP_CMD: unknown cmd %#x\n", cmd_no); diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 515e6db410f2..6085cd50970d 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -745,8 +745,6 @@ static void mwifiex_usb_port_resync(struct mwifiex_adapter *adapter) if (adapter->usb_mc_status) { for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (!priv) - continue; if ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP && !priv->bss_started) || (priv->bss_role == MWIFIEX_BSS_ROLE_STA && @@ -758,8 +756,6 @@ static void mwifiex_usb_port_resync(struct mwifiex_adapter *adapter) } else { for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (!priv) - continue; if ((priv->bss_role == MWIFIEX_BSS_ROLE_UAP && priv->bss_started) || (priv->bss_role == MWIFIEX_BSS_ROLE_STA && @@ -770,8 +766,7 @@ static void mwifiex_usb_port_resync(struct mwifiex_adapter *adapter) } for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv) - priv->usb_port = active_port; + priv->usb_port = active_port; } for (i = 0; i < MWIFIEX_TX_DATA_PORT; i++) { if (active_port == card->port[i].tx_data_ep) diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 745b1d925b21..1f1f6280a0f2 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -370,6 +370,45 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, return 0; } + +/* This function sends deauth packet to the kernel. */ +void mwifiex_host_mlme_disconnect(struct mwifiex_private *priv, + u16 reason_code, u8 *sa) +{ + u8 frame_buf[100]; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)frame_buf; + + memset(frame_buf, 0, sizeof(frame_buf)); + mgmt->frame_control = cpu_to_le16(IEEE80211_STYPE_DEAUTH); + mgmt->duration = 0; + mgmt->seq_ctrl = 0; + mgmt->u.deauth.reason_code = cpu_to_le16(reason_code); + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { + eth_broadcast_addr(mgmt->da); + memcpy(mgmt->sa, + priv->curr_bss_params.bss_descriptor.mac_address, + ETH_ALEN); + memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN); + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + } else { + memcpy(mgmt->da, priv->curr_addr, ETH_ALEN); + memcpy(mgmt->sa, sa, ETH_ALEN); + memcpy(mgmt->bssid, priv->curr_addr, ETH_ALEN); + } + + if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) { + wiphy_lock(priv->wdev.wiphy); + cfg80211_rx_mlme_mgmt(priv->netdev, frame_buf, 26); + wiphy_unlock(priv->wdev.wiphy); + } else { + cfg80211_rx_mgmt(&priv->wdev, + priv->bss_chandef.chan->center_freq, + 0, frame_buf, 26, 0); + } +} + /* * This function processes the received management packet and send it * to the kernel. @@ -417,6 +456,73 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, pkt_len -= ETH_ALEN; rx_pd->rx_pkt_length = cpu_to_le16(pkt_len); + if (priv->host_mlme_reg && + (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) && + (ieee80211_is_auth(ieee_hdr->frame_control) || + ieee80211_is_deauth(ieee_hdr->frame_control) || + ieee80211_is_disassoc(ieee_hdr->frame_control))) { + if (ieee80211_is_auth(ieee_hdr->frame_control)) { + if (priv->auth_flag & HOST_MLME_AUTH_PENDING) { + if (priv->auth_alg != WLAN_AUTH_SAE) { + priv->auth_flag &= + ~HOST_MLME_AUTH_PENDING; + priv->auth_flag |= + HOST_MLME_AUTH_DONE; + } + } else { + return 0; + } + + mwifiex_dbg(priv->adapter, MSG, + "auth: receive authentication from %pM\n", + ieee_hdr->addr3); + } else { + if (!priv->wdev.connected) + return 0; + + if (ieee80211_is_deauth(ieee_hdr->frame_control)) { + mwifiex_dbg(priv->adapter, MSG, + "auth: receive deauth from %pM\n", + ieee_hdr->addr3); + priv->auth_flag = 0; + priv->auth_alg = WLAN_AUTH_NONE; + } else { + mwifiex_dbg + (priv->adapter, MSG, + "assoc: receive disassoc from %pM\n", + ieee_hdr->addr3); + } + } + + wiphy_lock(priv->wdev.wiphy); + cfg80211_rx_mlme_mgmt(priv->netdev, skb->data, pkt_len); + wiphy_unlock(priv->wdev.wiphy); + } + + if (priv->adapter->host_mlme_enabled && + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)) { + if (ieee80211_is_auth(ieee_hdr->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "auth: receive auth from %pM\n", + ieee_hdr->addr2); + if (ieee80211_is_deauth(ieee_hdr->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "auth: receive deauth from %pM\n", + ieee_hdr->addr2); + if (ieee80211_is_disassoc(ieee_hdr->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "assoc: receive disassoc from %pM\n", + ieee_hdr->addr2); + if (ieee80211_is_assoc_req(ieee_hdr->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "assoc: receive assoc req from %pM\n", + ieee_hdr->addr2); + if (ieee80211_is_reassoc_req(ieee_hdr->frame_control)) + mwifiex_dbg(priv->adapter, MSG, + "assoc: receive reassoc req from %pM\n", + ieee_hdr->addr2); + } + cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq, CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len, 0); diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 00a5679b5c51..bcb61dab7dc8 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -454,8 +454,6 @@ int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (!priv) - continue; if (adapter->if_ops.is_port_ready && !adapter->if_ops.is_port_ready(priv)) continue; @@ -477,8 +475,6 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; ++i) { priv = adapter->priv[i]; - if (!priv) - continue; if (!priv->port_open && (priv->bss_mode != NL80211_IFTYPE_ADHOC)) continue; @@ -871,7 +867,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, } } else { memcpy(ra, skb->data, ETH_ALEN); - if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb)) + if (is_multicast_ether_addr(ra) || mwifiex_is_skb_mgmt_frame(skb)) eth_broadcast_addr(ra); ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); } @@ -1491,9 +1487,6 @@ void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; ++i) { priv = adapter->priv[i]; - if (!priv) - continue; - if (adapter->if_ops.is_port_ready && !adapter->if_ops.is_port_ready(priv)) continue; diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index 13bcb123d122..bab9ef37a1ab 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -587,13 +587,18 @@ static int mwl8k_request_firmware(struct mwl8k_priv *priv, char *fw_image, } struct mwl8k_cmd_pkt { - __le16 code; - __le16 length; - __u8 seq_num; - __u8 macid; - __le16 result; - char payload[]; + /* New members MUST be added within the __struct_group() macro below. */ + __struct_group(mwl8k_cmd_pkt_hdr, hdr, __packed, + __le16 code; + __le16 length; + __u8 seq_num; + __u8 macid; + __le16 result; + ); + char payload[]; } __packed; +static_assert(offsetof(struct mwl8k_cmd_pkt, payload) == sizeof(struct mwl8k_cmd_pkt_hdr), + "struct member likely outside of __struct_group()"); /* * Firmware loading. @@ -2201,7 +2206,7 @@ static void mwl8k_enable_bsses(struct ieee80211_hw *hw, bool enable, /* Timeout firmware commands after 10s */ #define MWL8K_CMD_TIMEOUT_MS 10000 -static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) +static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt_hdr *cmd) { DECLARE_COMPLETION_ONSTACK(cmd_wait); struct mwl8k_priv *priv = hw->priv; @@ -2209,7 +2214,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) dma_addr_t dma_addr; unsigned int dma_size; int rc; - unsigned long timeout = 0; + unsigned long time_left = 0; u8 buf[32]; u32 bitmap = 0; @@ -2256,8 +2261,8 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) iowrite32(MWL8K_H2A_INT_DUMMY, regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS); - timeout = wait_for_completion_timeout(&cmd_wait, - msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); + time_left = wait_for_completion_timeout(&cmd_wait, + msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS)); priv->hostcmd_wait = NULL; @@ -2265,7 +2270,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) dma_unmap_single(&priv->pdev->dev, dma_addr, dma_size, DMA_BIDIRECTIONAL); - if (!timeout) { + if (!time_left) { wiphy_err(hw->wiphy, "Command %s timeout after %u ms\n", mwl8k_cmd_name(cmd->code, buf, sizeof(buf)), MWL8K_CMD_TIMEOUT_MS); @@ -2273,7 +2278,7 @@ static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd) } else { int ms; - ms = MWL8K_CMD_TIMEOUT_MS - jiffies_to_msecs(timeout); + ms = MWL8K_CMD_TIMEOUT_MS - jiffies_to_msecs(time_left); rc = cmd->result ? -EINVAL : 0; if (rc) @@ -2298,7 +2303,7 @@ exit: static int mwl8k_post_pervif_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct mwl8k_cmd_pkt *cmd) + struct mwl8k_cmd_pkt_hdr *cmd) { if (vif != NULL) cmd->macid = MWL8K_VIF(vif)->macid; @@ -2350,7 +2355,7 @@ static void mwl8k_setup_5ghz_band(struct ieee80211_hw *hw) * CMD_GET_HW_SPEC (STA version). */ struct mwl8k_cmd_get_hw_spec_sta { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __u8 hw_rev; __u8 host_interface; __le16 num_mcaddrs; @@ -2499,7 +2504,7 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) * CMD_GET_HW_SPEC (AP version). */ struct mwl8k_cmd_get_hw_spec_ap { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __u8 hw_rev; __u8 host_interface; __le16 num_wcb; @@ -2593,7 +2598,7 @@ done: * CMD_SET_HW_SPEC. */ struct mwl8k_cmd_set_hw_spec { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __u8 hw_rev; __u8 host_interface; __le16 num_mcaddrs; @@ -2670,7 +2675,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) * CMD_MAC_MULTICAST_ADR. */ struct mwl8k_cmd_mac_multicast_adr { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 numaddr; __u8 addr[][ETH_ALEN]; @@ -2681,7 +2686,7 @@ struct mwl8k_cmd_mac_multicast_adr { #define MWL8K_ENABLE_RX_ALL_MULTICAST 0x0004 #define MWL8K_ENABLE_RX_BROADCAST 0x0008 -static struct mwl8k_cmd_pkt * +static struct mwl8k_cmd_pkt_hdr * __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, struct netdev_hw_addr_list *mc_list) { @@ -2718,7 +2723,7 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST); cmd->numaddr = cpu_to_le16(mc_count); netdev_hw_addr_list_for_each(ha, mc_list) { - memcpy(cmd->addr[i], ha->addr, ETH_ALEN); + memcpy(cmd->addr[i++], ha->addr, ETH_ALEN); } } @@ -2729,7 +2734,7 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti, * CMD_GET_STAT. */ struct mwl8k_cmd_get_stat { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 stats[64]; } __packed; @@ -2771,7 +2776,7 @@ static int mwl8k_cmd_get_stat(struct ieee80211_hw *hw, * CMD_RADIO_CONTROL. */ struct mwl8k_cmd_radio_control { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 control; __le16 radio_on; @@ -2832,7 +2837,7 @@ mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble) #define MWL8K_RF_TX_POWER_LEVEL_TOTAL 8 struct mwl8k_cmd_rf_tx_power { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 support_level; __le16 current_level; @@ -2866,7 +2871,7 @@ static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm) #define MWL8K_TX_POWER_LEVEL_TOTAL 12 struct mwl8k_cmd_tx_power { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 band; __le16 channel; @@ -2925,7 +2930,7 @@ static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw, * CMD_RF_ANTENNA. */ struct mwl8k_cmd_rf_antenna { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 antenna; __le16 mode; } __packed; @@ -2958,7 +2963,7 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask) * CMD_SET_BEACON. */ struct mwl8k_cmd_set_beacon { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 beacon_len; __u8 beacon[]; }; @@ -2988,7 +2993,7 @@ static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, * CMD_SET_PRE_SCAN. */ struct mwl8k_cmd_set_pre_scan { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; } __packed; static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) @@ -3013,7 +3018,7 @@ static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw) * CMD_BBP_REG_ACCESS. */ struct mwl8k_cmd_bbp_reg_access { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 offset; u8 value; @@ -3054,7 +3059,7 @@ mwl8k_cmd_bbp_reg_access(struct ieee80211_hw *hw, * CMD_SET_POST_SCAN. */ struct mwl8k_cmd_set_post_scan { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 isibss; __u8 bssid[ETH_ALEN]; } __packed; @@ -3142,7 +3147,7 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv, * CMD_SET_RF_CHANNEL. */ struct mwl8k_cmd_set_rf_channel { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __u8 current_channel; __le32 channel_flags; @@ -3211,7 +3216,7 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw, #define MWL8K_FRAME_PROT_11N_HT_ALL 0x06 struct mwl8k_cmd_update_set_aid { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 aid; /* AP's MAC address (BSSID) */ @@ -3283,7 +3288,7 @@ mwl8k_cmd_set_aid(struct ieee80211_hw *hw, * CMD_SET_RATE. */ struct mwl8k_cmd_set_rate { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __u8 legacy_rates[14]; /* Bitmap for supported MCS codes. */ @@ -3319,7 +3324,7 @@ mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif, #define MWL8K_FJ_BEACON_MAXLEN 128 struct mwl8k_cmd_finalize_join { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 sleep_interval; /* Number of beacon periods to sleep */ __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN]; } __packed; @@ -3358,7 +3363,7 @@ static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame, * CMD_SET_RTS_THRESHOLD. */ struct mwl8k_cmd_set_rts_threshold { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 threshold; } __packed; @@ -3388,7 +3393,7 @@ mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) * CMD_SET_SLOT. */ struct mwl8k_cmd_set_slot { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __u8 short_slot; } __packed; @@ -3417,7 +3422,7 @@ static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time) * CMD_SET_EDCA_PARAMS. */ struct mwl8k_cmd_set_edca_params { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; /* See MWL8K_SET_EDCA_XXX below */ __le16 action; @@ -3502,7 +3507,7 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum, * CMD_SET_WMM_MODE. */ struct mwl8k_cmd_set_wmm_mode { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; } __packed; @@ -3533,7 +3538,7 @@ static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable) * CMD_MIMO_CONFIG. */ struct mwl8k_cmd_mimo_config { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; __u8 rx_antenna_map; __u8 tx_antenna_map; @@ -3564,7 +3569,7 @@ static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx) * CMD_USE_FIXED_RATE (STA version). */ struct mwl8k_cmd_use_fixed_rate_sta { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; __le32 allow_rate_drop; __le32 num_rates; @@ -3606,7 +3611,7 @@ static int mwl8k_cmd_use_fixed_rate_sta(struct ieee80211_hw *hw) * CMD_USE_FIXED_RATE (AP version). */ struct mwl8k_cmd_use_fixed_rate_ap { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; __le32 allow_rate_drop; __le32 num_rates; @@ -3647,7 +3652,7 @@ mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt) * CMD_ENABLE_SNIFFER. */ struct mwl8k_cmd_enable_sniffer { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; } __packed; @@ -3671,7 +3676,7 @@ static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable) } struct mwl8k_cmd_update_mac_addr { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; union { struct { __le16 mac_type; @@ -3756,7 +3761,7 @@ static inline int mwl8k_cmd_del_mac_addr(struct ieee80211_hw *hw, * CMD_SET_RATEADAPT_MODE. */ struct mwl8k_cmd_set_rate_adapt_mode { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 action; __le16 mode; } __packed; @@ -3785,7 +3790,7 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode) * CMD_GET_WATCHDOG_BITMAP. */ struct mwl8k_cmd_get_watchdog_bitmap { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; u8 bitmap; } __packed; @@ -3865,7 +3870,7 @@ done: * CMD_BSS_START. */ struct mwl8k_cmd_bss_start { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 enable; } __packed; @@ -3960,7 +3965,7 @@ struct mwl8k_destroy_ba_stream { } __packed; struct mwl8k_cmd_bastream { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; union { struct mwl8k_create_ba_stream create_params; @@ -4070,7 +4075,7 @@ static void mwl8k_destroy_ba(struct ieee80211_hw *hw, * CMD_SET_NEW_STN. */ struct mwl8k_cmd_set_new_stn { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le16 aid; __u8 mac_addr[6]; __le16 stn_id; @@ -4206,7 +4211,7 @@ static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, #define MIC_KEY_LENGTH 8 struct mwl8k_cmd_update_encryption { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; __le32 reserved; @@ -4216,7 +4221,7 @@ struct mwl8k_cmd_update_encryption { } __packed; struct mwl8k_cmd_set_key { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; __le32 action; __le32 reserved; @@ -4504,7 +4509,7 @@ struct peer_capability_info { } __packed; struct mwl8k_cmd_update_stadb { - struct mwl8k_cmd_pkt header; + struct mwl8k_cmd_pkt_hdr header; /* See STADB_ACTION_TYPE */ __le32 action; @@ -4766,7 +4771,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) return rc; } -static void mwl8k_stop(struct ieee80211_hw *hw) +static void mwl8k_stop(struct ieee80211_hw *hw, bool suspend) { struct mwl8k_priv *priv = hw->priv; int i; @@ -5174,7 +5179,7 @@ mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list) { - struct mwl8k_cmd_pkt *cmd; + struct mwl8k_cmd_pkt_hdr *cmd; /* * Synthesize and return a command packet that programs the @@ -5234,7 +5239,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct mwl8k_priv *priv = hw->priv; - struct mwl8k_cmd_pkt *cmd = (void *)(unsigned long)multicast; + struct mwl8k_cmd_pkt_hdr *cmd = (void *)(unsigned long)multicast; /* * AP firmware doesn't allow fine-grained control over @@ -5610,6 +5615,10 @@ static void mwl8k_sw_scan_complete(struct ieee80211_hw *hw, } static const struct ieee80211_ops mwl8k_ops = { + .add_chanctx = ieee80211_emulate_add_chanctx, + .remove_chanctx = ieee80211_emulate_remove_chanctx, + .change_chanctx = ieee80211_emulate_change_chanctx, + .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, .tx = mwl8k_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, .start = mwl8k_start, @@ -6017,7 +6026,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) struct mwl8k_priv *priv = hw->priv; struct mwl8k_vif *vif, *tmp_vif; - mwl8k_stop(hw); + mwl8k_stop(hw, false); mwl8k_rxq_deinit(hw, 0); /* |