diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r-- | drivers/net/wireless/mwifiex/11h.c | 101 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/cfg80211.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/fw.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/init.c | 82 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/join.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.c | 87 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/main.h | 27 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/scan.c | 37 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_event.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_ioctl.c | 52 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/wmm.c | 5 |
12 files changed, 351 insertions, 115 deletions
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c new file mode 100644 index 000000000000..8d683070bdb3 --- /dev/null +++ b/drivers/net/wireless/mwifiex/11h.c @@ -0,0 +1,101 @@ +/* + * Marvell Wireless LAN device driver: 802.11h + * + * Copyright (C) 2013, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "main.h" +#include "fw.h" + + +/* This function appends 11h info to a buffer while joining an + * infrastructure BSS + */ +static void +mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, + struct mwifiex_bssdescriptor *bss_desc) +{ + struct mwifiex_ie_types_header *ie_header; + struct mwifiex_ie_types_pwr_capability *cap; + struct mwifiex_ie_types_local_pwr_constraint *constraint; + struct ieee80211_supported_band *sband; + u8 radio_type; + int i; + + if (!buffer || !(*buffer)) + return; + + radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + sband = priv->wdev->wiphy->bands[radio_type]; + + cap = (struct mwifiex_ie_types_pwr_capability *)*buffer; + cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY); + cap->header.len = cpu_to_le16(2); + cap->min_pwr = 0; + cap->max_pwr = 0; + *buffer += sizeof(*cap); + + constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer; + constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT); + constraint->header.len = cpu_to_le16(2); + constraint->chan = bss_desc->channel; + constraint->constraint = bss_desc->local_constraint; + *buffer += sizeof(*constraint); + + ie_header = (struct mwifiex_ie_types_header *)*buffer; + ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); + ie_header->len = cpu_to_le16(2 * sband->n_channels + 2); + *buffer += sizeof(*ie_header); + *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS; + *(*buffer)++ = 2 * sband->n_channels; + for (i = 0; i < sband->n_channels; i++) { + *(*buffer)++ = ieee80211_frequency_to_channel( + sband->channels[i].center_freq); + *(*buffer)++ = 1; /* one channel in the subband */ + } +} + +/* Enable or disable the 11h extensions in the firmware */ +static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) +{ + u32 enable = flag; + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11H_I, &enable); +} + +/* This functions processes TLV buffer for a pending BSS Join command. + * + * Activate 11h functionality in the firmware if the spectrum management + * capability bit is found in the network we are joining. Also, necessary + * TLVs are set based on requested network's 11h capability. + */ +void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, + struct mwifiex_bssdescriptor *bss_desc) +{ + if (bss_desc->sensed_11h) { + /* Activate 11h functions in firmware, turns on capability + * bit + */ + mwifiex_11h_activate(priv, true); + bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT; + mwifiex_11h_process_infra_join(priv, buffer, bss_desc); + } else { + /* Deactivate 11h functions in the firmware */ + mwifiex_11h_activate(priv, false); + bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT; + } +} diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index ecf28464367f..a42a506fd32b 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -40,6 +40,7 @@ mwifiex-y += sta_rx.o mwifiex-y += uap_txrx.o mwifiex-y += cfg80211.o mwifiex-y += ethtool.o +mwifiex-y += 11h.o mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MWIFIEX) += mwifiex.o diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 00a82817eb6b..ef5fa890a286 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -20,6 +20,9 @@ #include "cfg80211.h" #include "main.h" +static char *reg_alpha2; +module_param(reg_alpha2, charp, 0); + static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { { .max = 2, .types = BIT(NL80211_IFTYPE_STATION), @@ -2475,6 +2478,27 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { #endif }; +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support mwifiex_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT, + .n_patterns = MWIFIEX_MAX_FILTERS, + .pattern_min_len = 1, + .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN, + .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN, +}; +#endif + +static bool mwifiex_is_valid_alpha2(const char *alpha2) +{ + if (!alpha2 || strlen(alpha2) != 2) + return false; + + if (isalpha(alpha2[0]) && isalpha(alpha2[1])) + return true; + + return false; +} + /* * This function registers the device with CFG802.11 subsystem. * @@ -2527,16 +2551,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_CUSTOM_REGULATORY | + WIPHY_FLAG_STRICT_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom); #ifdef CONFIG_PM - wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; - wiphy->wowlan.n_patterns = MWIFIEX_MAX_FILTERS; - wiphy->wowlan.pattern_min_len = 1; - wiphy->wowlan.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN; - wiphy->wowlan.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN; + wiphy->wowlan = &mwifiex_wowlan_support; #endif wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | @@ -2568,10 +2589,16 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy_free(wiphy); return ret; } - country_code = mwifiex_11d_code_2_region(priv->adapter->region_code); - if (country_code) - dev_info(adapter->dev, - "ignoring F/W country code %2.2s\n", country_code); + + if (reg_alpha2 && mwifiex_is_valid_alpha2(reg_alpha2)) { + wiphy_info(wiphy, "driver hint alpha2: %2.2s\n", reg_alpha2); + regulatory_hint(wiphy, reg_alpha2); + } else { + country_code = mwifiex_11d_code_2_region(adapter->region_code); + if (country_code) + wiphy_info(wiphy, "ignoring F/W country code %2.2s\n", + country_code); + } adapter->wiphy = wiphy; return ret; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index d6ada7354c14..1b45aa533300 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -245,6 +245,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HT_BW_20 0 #define HT_BW_40 1 +#define DFS_CHAN_MOVE_TIME 10000 + #define HostCmd_CMD_GET_HW_SPEC 0x0003 #define HostCmd_CMD_802_11_SCAN 0x0006 #define HostCmd_CMD_802_11_GET_LOG 0x000b @@ -438,6 +440,7 @@ enum P2P_MODES { #define EVENT_BW_CHANGE 0x00000048 #define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c #define EVENT_HOSTWAKE_STAIE 0x0000004d +#define EVENT_CHANNEL_SWITCH_ANN 0x00000050 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_ID_MASK 0xffff @@ -975,6 +978,7 @@ enum SNMP_MIB_INDEX { LONG_RETRY_LIM_I = 7, FRAG_THRESH_I = 8, DOT11D_I = 9, + DOT11H_I = 10, }; #define MAX_SNMP_BUF_SIZE 128 @@ -1206,6 +1210,18 @@ struct host_cmd_ds_sta_deauth { __le16 reason; } __packed; +struct mwifiex_ie_types_pwr_capability { + struct mwifiex_ie_types_header header; + s8 min_pwr; + s8 max_pwr; +}; + +struct mwifiex_ie_types_local_pwr_constraint { + struct mwifiex_ie_types_header header; + u8 chan; + u8 constraint; +}; + struct mwifiex_ie_types_wmm_param_set { struct mwifiex_ie_types_header header; u8 wmm_ie[1]; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index c7f11c0c3bb7..caaf4bd56b30 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -52,84 +52,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv) return 0; } -static void scan_delay_timer_fn(unsigned long data) -{ - struct mwifiex_private *priv = (struct mwifiex_private *)data; - struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node, *tmp_node; - unsigned long flags; - - if (adapter->surprise_removed) - return; - - if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) { - /* - * Abort scan operation by cancelling all pending scan - * commands - */ - spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); - list_for_each_entry_safe(cmd_node, tmp_node, - &adapter->scan_pending_q, list) { - list_del(&cmd_node->list); - mwifiex_insert_cmd_to_free_q(adapter, cmd_node); - } - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = false; - adapter->scan_delay_cnt = 0; - adapter->empty_tx_q_cnt = 0; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - - if (priv->scan_request) { - dev_dbg(adapter->dev, "info: aborting scan\n"); - cfg80211_scan_done(priv->scan_request, 1); - priv->scan_request = NULL; - } else { - priv->scan_aborting = false; - dev_dbg(adapter->dev, "info: scan already aborted\n"); - } - goto done; - } - - if (!atomic_read(&priv->adapter->is_tx_received)) { - adapter->empty_tx_q_cnt++; - if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) { - /* - * No Tx traffic for 200msec. Get scan command from - * scan pending queue and put to cmd pending queue to - * resume scan operation - */ - adapter->scan_delay_cnt = 0; - adapter->empty_tx_q_cnt = 0; - spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); - cmd_node = list_first_entry(&adapter->scan_pending_q, - struct cmd_ctrl_node, list); - list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); - - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, - true); - queue_work(adapter->workqueue, &adapter->main_work); - goto done; - } - } else { - adapter->empty_tx_q_cnt = 0; - } - - /* Delay scan operation further by 20msec */ - mod_timer(&priv->scan_delay_timer, jiffies + - msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); - adapter->scan_delay_cnt++; - -done: - if (atomic_read(&priv->adapter->is_tx_received)) - atomic_set(&priv->adapter->is_tx_received, false); - - return; -} - /* * This function initializes the private structure and sets default * values to the members. @@ -211,8 +133,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->scan_block = false; - setup_timer(&priv->scan_delay_timer, scan_delay_timer_fn, - (unsigned long)priv); + priv->csa_chan = 0; + priv->csa_expire_time = 0; return mwifiex_add_bss_prio_tbl(priv); } diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 122175af18c6..1c8a771e8e81 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -534,6 +534,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); + mwifiex_11h_process_join(priv, &pos, bss_desc); + cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); /* Set the Capability info at last */ diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 5bc7ef8d04d6..e15ab72fb03d 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -28,6 +28,84 @@ const char driver_version[] = "mwifiex " VERSION " (%s) "; static char *cal_data_cfg; module_param(cal_data_cfg, charp, 0); +static void scan_delay_timer_fn(unsigned long data) +{ + struct mwifiex_private *priv = (struct mwifiex_private *)data; + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node, *tmp_node; + unsigned long flags; + + if (adapter->surprise_removed) + return; + + if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) { + /* + * Abort scan operation by cancelling all pending scan + * commands + */ + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, list) { + list_del(&cmd_node->list); + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + adapter->scan_delay_cnt = 0; + adapter->empty_tx_q_cnt = 0; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: aborting scan\n"); + cfg80211_scan_done(priv->scan_request, 1); + priv->scan_request = NULL; + } else { + priv->scan_aborting = false; + dev_dbg(adapter->dev, "info: scan already aborted\n"); + } + goto done; + } + + if (!atomic_read(&priv->adapter->is_tx_received)) { + adapter->empty_tx_q_cnt++; + if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) { + /* + * No Tx traffic for 200msec. Get scan command from + * scan pending queue and put to cmd pending queue to + * resume scan operation + */ + adapter->scan_delay_cnt = 0; + adapter->empty_tx_q_cnt = 0; + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + cmd_node = list_first_entry(&adapter->scan_pending_q, + struct cmd_ctrl_node, list); + list_del(&cmd_node->list); + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); + + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, + true); + queue_work(adapter->workqueue, &adapter->main_work); + goto done; + } + } else { + adapter->empty_tx_q_cnt = 0; + } + + /* Delay scan operation further by 20msec */ + mod_timer(&priv->scan_delay_timer, jiffies + + msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); + adapter->scan_delay_cnt++; + +done: + if (atomic_read(&priv->adapter->is_tx_received)) + atomic_set(&priv->adapter->is_tx_received, false); + + return; +} + /* * This function registers the device and performs all the necessary * initializations. @@ -75,6 +153,10 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, adapter->priv[i]->adapter = adapter; adapter->priv_num++; + + setup_timer(&adapter->priv[i]->scan_delay_timer, + scan_delay_timer_fn, + (unsigned long)adapter->priv[i]); } mwifiex_init_lock_list(adapter); @@ -587,9 +669,8 @@ static void mwifiex_set_multicast_list(struct net_device *dev) mcast_list.mode = MWIFIEX_ALL_MULTI_MODE; } else { mcast_list.mode = MWIFIEX_MULTICAST_MODE; - if (netdev_mc_count(dev)) - mcast_list.num_multicast_addr = - mwifiex_copy_mcast_addr(&mcast_list, dev); + mcast_list.num_multicast_addr = + mwifiex_copy_mcast_addr(&mcast_list, dev); } mwifiex_request_set_multicast_list(priv, &mcast_list); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 0832c2437daf..3da73d36acdf 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -309,6 +309,9 @@ struct mwifiex_bssdescriptor { u16 wapi_offset; u8 *beacon_buf; u32 beacon_buf_size; + u8 sensed_11h; + u8 local_constraint; + u8 chan_sw_ie_present; }; struct mwifiex_current_bss_params { @@ -510,6 +513,8 @@ struct mwifiex_private { u32 mgmt_frame_mask; struct mwifiex_roc_cfg roc_cfg; bool scan_aborting; + u8 csa_chan; + unsigned long csa_expire_time; }; enum mwifiex_ba_status { @@ -1018,6 +1023,24 @@ static inline bool mwifiex_is_skb_mgmt_frame(struct sk_buff *skb) return (*(u32 *)skb->data == PKT_TYPE_MGMT); } +/* This function retrieves channel closed for operation by Channel + * Switch Announcement. + */ +static inline u8 +mwifiex_11h_get_csa_closed_channel(struct mwifiex_private *priv) +{ + if (!priv->csa_chan) + return 0; + + /* Clear csa channel, if DFS channel move time has passed */ + if (jiffies > priv->csa_expire_time) { + priv->csa_chan = 0; + priv->csa_expire_time = 0; + } + + return priv->csa_chan; +} + int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); @@ -1119,6 +1142,10 @@ u8 *mwifiex_11d_code_2_region(u8 code); void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, struct mwifiex_sta_node *node); +void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv); + extern const struct ethtool_ops mwifiex_ethtool_ops; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 801b6b728379..c447d9bd1aa9 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -391,6 +391,12 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, return 0; } + if (bss_desc->chan_sw_ie_present) { + dev_err(adapter->dev, + "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n"); + return -1; + } + if (mwifiex_is_bss_wapi(priv, bss_desc)) { dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); return 0; @@ -569,6 +575,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, return -1; } + /* Check csa channel expiry before preparing scan list */ + mwifiex_11h_get_csa_closed_channel(priv); + chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); /* Set the temp channel struct pointer to the start of the desired @@ -598,6 +607,11 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, while (tlv_idx < max_chan_per_scan && tmp_chan_list->chan_number && !done_early) { + if (tmp_chan_list->chan_number == priv->csa_chan) { + tmp_chan_list++; + continue; + } + dev_dbg(priv->adapter->dev, "info: Scan: Chan(%3d), Radio(%d)," " Mode(%d, %d), Dur(%d)\n", @@ -1169,6 +1183,19 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, bss_entry->erp_flags = *(current_ptr + 2); break; + case WLAN_EID_PWR_CONSTRAINT: + bss_entry->local_constraint = *(current_ptr + 2); + bss_entry->sensed_11h = true; + break; + + case WLAN_EID_CHANNEL_SWITCH: + bss_entry->chan_sw_ie_present = true; + case WLAN_EID_PWR_CAPABILITY: + case WLAN_EID_TPC_REPORT: + case WLAN_EID_QUIET: + bss_entry->sensed_11h = true; + break; + case WLAN_EID_EXT_SUPP_RATES: /* * Only process extended supported rate @@ -1575,6 +1602,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, goto check_next_scan; } + /* Check csa channel expiry before parsing scan response */ + mwifiex_11h_get_csa_closed_channel(priv); + bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", bytes_left); @@ -1727,6 +1757,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, struct ieee80211_channel *chan; u8 band; + /* Skip entry if on csa closed channel */ + if (channel == priv->csa_chan) { + dev_dbg(adapter->dev, + "Dropping entry on csa closed channel\n"); + continue; + } + band = BAND_G; if (chan_band_tlv) { chan_band = diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 41aafc7454ed..ea265ec0e522 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -427,6 +427,17 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; + case EVENT_CHANNEL_SWITCH_ANN: + dev_dbg(adapter->dev, "event: Channel Switch Announcement\n"); + priv->csa_expire_time = + jiffies + msecs_to_jiffies(DFS_CHAN_MOVE_TIME); + priv->csa_chan = priv->curr_bss_params.bss_descriptor.channel; + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_DEAUTHENTICATE, + HostCmd_ACT_GEN_SET, 0, + priv->curr_bss_params.bss_descriptor.mac_address); + break; + default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 1a8a19dbd635..206c3e038072 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -104,16 +104,14 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, } else { priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; - if (mcast_list->num_multicast_addr) { - dev_dbg(priv->adapter->dev, - "info: Set multicast list=%d\n", - mcast_list->num_multicast_addr); - /* Send multicast addresses to firmware */ - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_MAC_MULTICAST_ADR, - HostCmd_ACT_GEN_SET, 0, - mcast_list); - } + dev_dbg(priv->adapter->dev, + "info: Set multicast list=%d\n", + mcast_list->num_multicast_addr); + /* Send multicast addresses to firmware */ + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, + mcast_list); } } dev_dbg(priv->adapter->dev, @@ -180,6 +178,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, */ bss_desc->disable_11ac = true; + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT) + bss_desc->sensed_11h = true; + return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); } @@ -257,30 +258,37 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, } if (priv->bss_mode == NL80211_IFTYPE_STATION) { + u8 config_bands; + /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL); if (ret) goto done; - if (bss_desc) { - u8 config_bands = 0; + if (!bss_desc) + return -1; - if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band) - == HostCmd_SCAN_RADIO_TYPE_BG) - config_bands = BAND_B | BAND_G | BAND_GN | - BAND_GAC; - else - config_bands = BAND_A | BAND_AN | BAND_AAC; + if (mwifiex_band_to_radio_type(bss_desc->bss_band) == + HostCmd_SCAN_RADIO_TYPE_BG) + config_bands = BAND_B | BAND_G | BAND_GN | BAND_GAC; + else + config_bands = BAND_A | BAND_AN | BAND_AAC; - if (!((config_bands | adapter->fw_bands) & - ~adapter->fw_bands)) - adapter->config_bands = config_bands; - } + if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) + adapter->config_bands = config_bands; ret = mwifiex_check_network_compatibility(priv, bss_desc); if (ret) goto done; + if (mwifiex_11h_get_csa_closed_channel(priv) == + (u8)bss_desc->channel) { + dev_err(adapter->dev, + "Attempt to reconnect on csa closed chan(%d)\n", + bss_desc->channel); + goto done; + } + dev_dbg(adapter->dev, "info: SSID found in scan list ... " "associating...\n"); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 4be3d33ceae8..944e8846f6fc 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -37,6 +37,9 @@ /* Offset for TOS field in the IP header */ #define IPTOS_OFFSET 5 +static bool enable_tx_amsdu; +module_param(enable_tx_amsdu, bool, 0644); + /* WMM information IE */ static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07, 0x00, 0x50, 0xf2, 0x02, @@ -1233,7 +1236,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) mwifiex_send_delba(priv, tid_del, ra, 1); } } - if (mwifiex_is_amsdu_allowed(priv, tid) && + if (enable_tx_amsdu && mwifiex_is_amsdu_allowed(priv, tid) && mwifiex_is_11n_aggragation_possible(priv, ptr, adapter->tx_buf_size)) mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, |