diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 43dccd5b0291f98fcf184822d8a50374c142fc9c..d29e7dfe51fc478eae54afc5f2c7f09a79f249f8 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -266,7 +266,7 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, mwifiex_dbg(priv->adapter, ERROR, "Failed to stop CAC in FW\n"); cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, - GFP_KERNEL); + 0, GFP_KERNEL); mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n", rdr_event->reg_domain); mwifiex_dbg(priv->adapter, MSG, "radar detection type: %d\n", diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index a80516fd65c8c12f658346be54fee320b5c513b7..7bdb1ca7a6286cf85fa8800dd6ef3e4673001535 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2333,6 +2333,12 @@ enum ieee80211_sa_query_action { #define WLAN_OUI_TYPE_MICROSOFT_WMM 2 #define WLAN_OUI_TYPE_MICROSOFT_WPS 4 +#define WLAN_OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ +#define WLAN_VENDOR_VHT_TYPE 0x04 +#define WLAN_VENDOR_VHT_SUBTYPE 0x08 +#define WLAN_VENDOR_VHT_SUBTYPE2 0x00 +#define WLAN_VENDOR_VHT_SUBTYPE3 0x18 + /* * WMM/802.11e Tspec Element */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 66167138120a2d2108e88ec23e5184ac55ed37a1..fbd0923aff8e26d2def1279813ba2798c59d735d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -769,6 +769,7 @@ struct cfg80211_csa_settings { bool radar_required; bool block_tx; u8 count; + u8 sb_dfs_bw; /* from enum nl80211_sb_dfs_bw */ }; /** @@ -825,6 +826,10 @@ enum station_parameters_apply_mask { * @opmode_notif: operating mode field from Operating Mode Notification * @opmode_notif_used: information if operating mode field is used * @support_p2p_ps: information if station supports P2P PS mechanism + * @resp: last association response frame + * (or NULL for no change) + * @resp_len: length of last association response + * @rssi: received signal strength indicator */ struct station_parameters { const u8 *supported_rates; @@ -852,6 +857,9 @@ struct station_parameters { u8 opmode_notif; bool opmode_notif_used; int support_p2p_ps; + u8 *resp; + size_t resp_len; + u32 rssi; }; /** @@ -1071,6 +1079,7 @@ struct cfg80211_tid_stats { * @nonpeer_pm: non-peer mesh STA power save mode * @expected_throughput: expected throughput in kbps (including 802.11 headers) * towards this station. + * @max_rssi: maximum received signal strength indicator * @rx_beacon: number of beacons received from this peer * @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received * from this peer @@ -1116,6 +1125,7 @@ struct station_info { enum nl80211_mesh_power_mode nonpeer_pm; u32 expected_throughput; + u32 max_rssi; u64 rx_beacon; u64 rx_duration; @@ -1814,6 +1824,7 @@ enum cfg80211_assoc_req_flags { * @ht_capa_mask: The bits of ht_capa which are to be used. * @vht_capa: VHT capability override * @vht_capa_mask: VHT capability mask indicating which fields to use + * @vendor_wds: use WDS vendor specific capabilities */ struct cfg80211_assoc_request { struct cfg80211_bss *bss; @@ -1825,6 +1836,7 @@ struct cfg80211_assoc_request { struct ieee80211_ht_cap ht_capa; struct ieee80211_ht_cap ht_capa_mask; struct ieee80211_vht_cap vht_capa, vht_capa_mask; + int vendor_wds; }; /** @@ -3056,6 +3068,7 @@ enum wiphy_flags { WIPHY_FLAG_SUPPORTS_5_10_MHZ = BIT(22), WIPHY_FLAG_HAS_CHANNEL_SWITCH = BIT(23), WIPHY_FLAG_HAS_STATIC_WEP = BIT(24), + WIPHY_FLAG_DISABLE_11D_HINT = BIT(31), }; /** @@ -3819,6 +3832,9 @@ struct wireless_dev { u32 owner_nlportid; + u8 *vendor_events_filter; + u8 vendor_events_filter_len; + #ifdef CONFIG_CFG80211_WEXT /* wext data */ struct { @@ -5153,6 +5169,9 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, enum nl80211_connect_failed_reason reason, gfp_t gfp); +int cfg80211_rx_vendor_specific_mgmt(struct wireless_dev *wdev, int freq, + const u8 *buf, size_t len, gfp_t gfp); + /** * cfg80211_rx_mgmt - notification of received, unprocessed management frame * @wdev: wireless device receiving the frame @@ -5243,12 +5262,13 @@ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); * cfg80211_radar_event - radar detection event * @wiphy: the wiphy * @chandef: chandef for the current channel + * @radar_bit_map: Bit map of channels, on which radar was detected * @gfp: context flags * * This function is called when a radar is detected on the current chanenl. */ -void cfg80211_radar_event(struct wiphy *wiphy, - struct cfg80211_chan_def *chandef, gfp_t gfp); +void cfg80211_radar_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, + u8 radar_bit_map, gfp_t gfp); /** * cfg80211_cac_event - Channel availability check (CAC) event @@ -5596,6 +5616,9 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, * by .crit_proto_start() has expired. */ void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp); +void cfg80211_set_dfs_state_bit_map(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + u8 radar_bit_map, enum nl80211_dfs_state dfs_state); /** * ieee80211_get_num_supported_channels - get number of channels device has diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2c7d876e2a1ae522e8df3c2b9b59291790b33087..3deba85dde3779a365bd6d523091afae5075bfaa 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1489,6 +1489,50 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev); */ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif); +/** + * net_device_to_ieee80211_vif - return a vif from net_device + * @dev: the net_device to get the vif for + * + * This can be used by mac80211 drivers which needs to manipulate data + * path with tier own implementation of net_device_ops. + */ +struct ieee80211_vif *net_device_to_ieee80211_vif(struct net_device *dev); + +/** + * get_net_device_ops_from_wdev - extract the net_device from wdev + * @wdev: the wdev to get the net_device for + */ +const struct net_device_ops *get_net_device_ops_from_wdev( + struct wireless_dev *wdev); + +/** + * set_net_device_ops_from_wdev - replace the net_device to a wdev + * @wdev: the wdev to set the net_device for + */ +void set_net_device_ops_in_wdev(struct wireless_dev *wdev, + const struct net_device_ops *ops); + +/** + * copy_net_device_ops_from_wdev - clone a net_device_ops from wdev + * @wdev: the wdev to get the net_device_ops for + * @ops: the net_device_ops object to clone the ops to + */ +void copy_net_device_ops_from_wdev(struct wireless_dev *wdev, + struct net_device_ops *ops); + +/** + * ieee80211_vif_to_name - return the vif name + * @vif: the vif to get the wdev for + * + * This can be used by mac80211 drivers with direct cfg80211 APIs + * (like the vendor commands) that needs to get the name for a vif. + * + * Note that this function may return %NULL if the given wdev isn't + * associated with a vif that the driver knows about (e.g. monitor + * or AP_VLAN interfaces.) + */ +const char *ieee80211_vif_to_name(struct ieee80211_vif *vif); + /** * enum ieee80211_key_flags - key flags * @@ -1751,6 +1795,8 @@ struct ieee80211_sta_rates { * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only * valid if the STA is a TDLS peer in the first place. * @mfp: indicates whether the STA uses management frame protection or not. + * @vendor_wds: indicates whether the STA supports + * wds vendor specific capabilities. * @max_amsdu_subframes: indicates the maximal number of MSDUs in a single * A-MSDU. Taken from the Extended Capabilities element. 0 means * unlimited. @@ -1784,6 +1830,7 @@ struct ieee80211_sta { bool tdls; bool tdls_initiator; bool mfp; + int vendor_wds; u8 max_amsdu_subframes; u16 max_amsdu_len; bool support_p2p_ps; @@ -3640,6 +3687,9 @@ struct ieee80211_ops { void (*reconfig_complete)(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type); + int (*get_connection_alive)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); + #if IS_ENABLED(CONFIG_IPV6) void (*ipv6_addr_change)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -5740,6 +5790,15 @@ int ieee80211_reserve_tid(struct ieee80211_sta *sta, u8 tid); */ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); +/** + * ieee80211_drv_start_sw_scan - allow driver to fallback to sw scan from hw + * @hw: pointer as obtained from ieee80211_alloc_hw() + * + * Note: This function must be called from hw_scan callback only. + * + */ +void ieee80211_drv_start_sw_scan(struct ieee80211_hw *hw); + /** * ieee80211_tx_dequeue - dequeue a packet from a software tx queue * diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d3cbe48b286d8cffd598305eb3164aa55ba0998e..b10f1243c3b7ed11d0088eec31b1d9b533d2c558 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1936,6 +1936,10 @@ enum nl80211_commands { * attribute. * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute. * See &enum nl80211_nan_match_attributes. + * @NL80211_ATTR_VENDOR_WDS: used to enable the wds vendor specific capability + * @NL80211_ATTR_STA_RSSI: Received signal strength indication (u32) + * @NL80211_ATTR_RADAR_BIT_MAP: Bit map of channel where radar was detected + * @NL80211_ATTR_SB_DFS_BW: Sub Band DFS new operation bandwidth * * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also * used in various commands/events for specifying the BSSID. @@ -2341,6 +2345,11 @@ enum nl80211_attrs { NL80211_ATTR_BSSID, + NL80211_ATTR_VENDOR_WDS, + NL80211_ATTR_STA_RSSI, + NL80211_ATTR_RADAR_BIT_MAP, + NL80211_ATTR_SB_DFS_BW, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2698,6 +2707,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_TID_STATS, NL80211_STA_INFO_RX_DURATION, NL80211_STA_INFO_PAD, + NL80211_STA_INFO_MAX_RSSI, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -5128,4 +5138,12 @@ enum nl80211_nan_match_attributes { NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1 }; +enum nl80211_sb_dfs_bw { + NL80211_SB_DFS_BW_NORMAL, + NL80211_SB_DFS_BW_20, + NL80211_SB_DFS_BW_40, + NL80211_SB_DFS_BW_80, + NL80211_SB_DFS_BW_FULL, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 07001b6d36cc3771ccc1e75f1cf8f76b23013ec2..5e27811a409b5cb58f3435d9b60ec90c530a9b44 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -622,8 +622,10 @@ void sta_set_rate_info_tx(struct sta_info *sta, sband = sta->local->hw.wiphy->bands[ ieee80211_get_sdata_band(sta->sdata)]; - brate = sband->bitrates[rate->idx].bitrate; - rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); + if (sband) { + brate = sband->bitrates[rate->idx].bitrate; + rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); + } } if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) rinfo->bw = RATE_INFO_BW_40; @@ -2017,6 +2019,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, struct bss_parameters *params) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_supported_band *sband; enum nl80211_band band; u32 changed = 0; @@ -2024,6 +2027,9 @@ static int ieee80211_change_bss(struct wiphy *wiphy, return -ENOENT; band = ieee80211_get_sdata_band(sdata); + sband = wiphy->bands[band]; + if (!sband) + return -EINVAL; if (params->use_cts_prot >= 0) { sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index e75cbf6ecc26e4ec7bde777c385e001c0e49e371..fb37e0a0ffef219c61bb45bc7743d423ea4d827e 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1567,7 +1567,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, lockdep_assert_held(&local->mtx); - WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); + if (local->use_chanctx) + WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); mutex_lock(&local->chanctx_mtx); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 09f77e4a8a79d78f5722a85470bfa0862671e43e..3be8346ef51e18a252861078cf627d491098830b 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -972,6 +972,20 @@ drv_reconfig_complete(struct ieee80211_local *local, trace_drv_return_void(local); } +static inline int drv_get_connection_alive(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + int ret; + + check_sdata_in_driver(sdata); + + ret = local->ops->get_connection_alive(&local->hw, &sdata->vif); + + trace_drv_return_int(local, ret); + + return ret; +} + static inline void drv_set_default_unicast_key(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 62d13eabe17f6b917306f893465a324884060348..4a092c1ea6e1b59dcbe1c2edbbe41d8449121c3a 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -776,7 +776,7 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata) NL80211_IFTYPE_ADHOC); if (err > 0) cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef, - GFP_ATOMIC); + 0, GFP_ATOMIC); } static bool diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 34c2add2c455978936c5379218620d41269a43a6..e76d95b21efd596f26afbdd79ecad9bd35fd5a48 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -125,6 +125,9 @@ struct ieee80211_bss { /* Keep track of what bits of information we have valid info for. */ u8 valid_data; + + const u8 *vendor_vht; + u8 vendor_vht_len; }; /** @@ -145,6 +148,7 @@ enum ieee80211_bss_corrupt_data_flags { * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE + * @IEEE80211_BSS_VALID_VENDOR_VHT: vendor VHT was gathered from non-corrupt IE * * These are bss flags that are attached to a bss in the * @valid_data field of &struct ieee80211_bss. They show which parts @@ -154,7 +158,8 @@ enum ieee80211_bss_corrupt_data_flags { enum ieee80211_bss_valid_data_flags { IEEE80211_BSS_VALID_WMM = BIT(1), IEEE80211_BSS_VALID_RATES = BIT(2), - IEEE80211_BSS_VALID_ERP = BIT(3) + IEEE80211_BSS_VALID_ERP = BIT(3), + IEEE80211_BSS_VALID_VENDOR_VHT = BIT(4) }; typedef unsigned __bitwise__ ieee80211_tx_result; @@ -398,6 +403,9 @@ struct ieee80211_mgd_assoc_data { struct ieee80211_vht_cap ap_vht_cap; + const u8 *vendor_vht; + u8 vendor_vht_len; + size_t ie_len; u8 ie[]; }; @@ -525,6 +533,8 @@ struct ieee80211_if_managed { struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */ struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */ + int vendor_wds; + /* TDLS support */ u8 tdls_peer[ETH_ALEN] __aligned(2); struct delayed_work tdls_peer_del_work; @@ -1430,6 +1440,8 @@ struct ieee80211_csa_ie { struct ieee802_11_elems { const u8 *ie_start; size_t total_len; + u8 *vendor_events_filter; + u8 vendor_events_filter_len; /* pointers to IEs */ const struct ieee80211_tdls_lnkie *lnk_id; @@ -1467,6 +1479,8 @@ struct ieee802_11_elems { const u8 *opmode_notif; const struct ieee80211_sec_chan_offs_ie *sec_chan_offs; const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie; + const u8 *vendor_vht; + const u8 *vendor_ie_to_notify; /* length of them, respectively */ u8 ext_capab_len; @@ -1484,6 +1498,8 @@ struct ieee802_11_elems { u8 prep_len; u8 perr_len; u8 country_elem_len; + u8 vendor_vht_len; + u8 vendor_ie_to_notify_len; /* whether a parse error occurred while retrieving these elements */ bool parse_error; @@ -1890,12 +1906,13 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, struct ieee802_11_elems *elems, + u8 *vendor_events_filter, u8 vendor_events_filter_len, u64 filter, u32 crc); static inline void ieee802_11_parse_elems(const u8 *start, size_t len, bool action, struct ieee802_11_elems *elems) { - ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0); + ieee802_11_parse_elems_crc(start, len, action, elems, NULL, 0, 0, 0); } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index edd6f2945f694f1fc6103caad0b04856a9cd5875..ae29fc390b8aa1db14beaeb39fb2d641af4f408e 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -619,9 +619,6 @@ int ieee80211_key_link(struct ieee80211_key *key, pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; idx = key->conf.keyidx; - key->local = sdata->local; - key->sdata = sdata; - key->sta = sta; mutex_lock(&sdata->local->key_mtx); @@ -632,6 +629,21 @@ int ieee80211_key_link(struct ieee80211_key *key, else old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); + /* + * Silently accept key re-installation without really installing the + * new version of the key to avoid nonce reuse or replay issues. + */ + if (old_key && key->conf.keylen == old_key->conf.keylen && + !memcmp(key->conf.key, old_key->conf.key, key->conf.keylen)) { + ieee80211_key_free_unused(key); + ret = 0; + goto out; + } + + key->local = sdata->local; + key->sdata = sdata; + key->sta = sta; + increment_tailroom_need_count(sdata); ieee80211_key_replace(sdata, sta, pairwise, old_key, key); @@ -647,6 +659,7 @@ int ieee80211_key_link(struct ieee80211_key *key, ret = 0; } +out: mutex_unlock(&sdata->local->key_mtx); return ret; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1118c61f835dde97b801531163f22ede2177592d..ce1b13e37b0563d2086e69937b5cae61939eafa9 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -868,6 +868,20 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info); } + if (assoc_data->vendor_vht && sband->vht_cap.vht_supported) { + struct ieee80211_vht_cap *ap_vht_cap = + (struct ieee80211_vht_cap *) (assoc_data->vendor_vht + 7); + pos = skb_put(skb, 7); + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 5 + 2 + sizeof(struct ieee80211_vht_cap); + *pos++ = 0x00; /* Broadcom (Epigram) (00:90:4C) */ + *pos++ = 0x90; + *pos++ = 0x4C; + *pos++ = WLAN_VENDOR_VHT_TYPE; + *pos++ = WLAN_VENDOR_VHT_SUBTYPE; + ieee80211_add_vht_ie(sdata, skb, sband, ap_vht_cap); + } + /* add any remaining custom (i.e. vendor specific here) IEs */ if (assoc_data->ie_len) { noffset = assoc_data->ie_len; @@ -1022,6 +1036,10 @@ static void ieee80211_chswitch_work(struct work_struct *work) /* XXX: shouldn't really modify cfg80211-owned data! */ ifmgd->associated->channel = sdata->csa_chandef.chan; + if(ieee80211_vif_use_channel(sdata, &sdata->csa_chandef, + IEEE80211_CHANCTX_SHARED)) + sdata_info(sdata, "driver channel switch failed\n"); + ifmgd->csa_waiting_bcn = true; ieee80211_sta_reset_beacon_monitor(sdata); @@ -2276,6 +2294,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, bool beacon) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; bool already = false; if (!ieee80211_sdata_running(sdata)) @@ -2299,6 +2318,16 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, beacon_loss_count); ieee80211_cqm_beacon_loss_notify(&sdata->vif, GFP_KERNEL); + } else { + if (local->ops->get_connection_alive) { + if (drv_get_connection_alive(local, sdata)) { + mod_timer(&ifmgd->conn_mon_timer, + round_jiffies_up(jiffies + + IEEE80211_CONNECTION_IDLE_TIME)); + mutex_unlock(&sdata->local->mtx); + goto out; + } + } } /* @@ -2995,6 +3024,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, } sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; + if (!sband) { + mutex_unlock(&sdata->local->sta_mtx); + ret = false; + goto out; + } /* Set up internal HT/VHT capabilities */ if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) @@ -3005,6 +3039,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, elems.vht_cap_elem, sta); + if (elems.vendor_vht) { + struct ieee80211_vht_cap *vht_cap_ie = + (struct ieee80211_vht_cap *) (elems.vendor_vht + 7); + ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, vht_cap_ie, sta); + } + /* * Some APs, e.g. Netgear WNDR3700, report invalid HT operation data * in their association response, so ignore that data for our own @@ -3037,6 +3077,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, } sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS; + sta->sta.vendor_wds = ifmgd->vendor_wds; err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) @@ -3246,11 +3287,16 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, if (baselen > len) return; - ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, - false, &elems); + ieee802_11_parse_elems_crc(mgmt->u.probe_resp.variable, len - baselen, + false, &elems, sdata->wdev.vendor_events_filter, + sdata->wdev.vendor_events_filter_len, 0, 0); ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); + if (elems.vendor_ie_to_notify) + cfg80211_rx_vendor_specific_mgmt(&sdata->wdev, rx_status->freq, + (const u8 *)mgmt, len, GFP_ATOMIC); + if (ifmgd->associated && ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) ieee80211_reset_ap_probe(sdata); @@ -3306,6 +3352,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (baselen > len) return; + ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, + len - baselen, false, &elems, sdata->wdev.vendor_events_filter, + sdata->wdev.vendor_events_filter_len, 0, 0); + + if (elems.vendor_ie_to_notify) + cfg80211_rx_vendor_specific_mgmt(&sdata->wdev, rx_status->freq, + (const u8 *)mgmt, len, GFP_ATOMIC); + rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); if (!chanctx_conf) { @@ -3322,8 +3376,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { - ieee802_11_parse_elems(mgmt->u.beacon.variable, - len - baselen, false, &elems); ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); if (elems.tim && !elems.parse_error) { @@ -3434,7 +3486,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, len - baselen, false, &elems, - care_about_ies, ncrc); + NULL, 0, care_about_ies, ncrc); if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) && ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) { @@ -4708,6 +4760,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, assoc_data->capability = req->bss->capability; assoc_data->supp_rates = bss->supp_rates; assoc_data->supp_rates_len = bss->supp_rates_len; + assoc_data->vendor_vht = bss->vendor_vht; + assoc_data->vendor_vht_len = bss->vendor_vht_len; rcu_read_lock(); ht_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_OPERATION); @@ -4749,6 +4803,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED; } + ifmgd->vendor_wds = req->vendor_wds; + if (req->flags & ASSOC_REQ_USE_RRM) ifmgd->flags |= IEEE80211_STA_ENABLE_RRM; else diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 23d8ac8292796714df893e32072e44edb3617ca0..9558f0595101fc295eca4c31c7462eb35ffebf9b 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -171,6 +171,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, bss->valid_data |= IEEE80211_BSS_VALID_WMM; } + if (elems->vendor_vht && (!elems->parse_error || + !(bss->valid_data & IEEE80211_BSS_VALID_VENDOR_VHT))) { + bss->vendor_vht = elems->vendor_vht; + bss->vendor_vht_len = elems->vendor_vht_len; + if (!elems->parse_error) + bss->valid_data |= IEEE80211_BSS_VALID_VENDOR_VHT; + } + if (beacon) { struct ieee80211_supported_band *sband = local->hw.wiphy->bands[rx_status->band]; @@ -474,6 +482,17 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local, return 0; } +void ieee80211_drv_start_sw_scan(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + test_and_clear_bit(SCAN_HW_SCANNING, &local->scanning); + __set_bit(SCAN_SW_SCANNING, &local->scanning); + /* TODO: check remain on channel (scan for current channel requested) */ + + ieee80211_start_sw_scan(local, local->scan_sdata); +} +EXPORT_SYMBOL(ieee80211_drv_start_sw_scan); + static bool ieee80211_can_scan(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 545c79a42a779b949fe4cd62afee7e36685d358c..9677223bd7d2d88ff70f80a2282ef1ed48500695 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -723,6 +723,72 @@ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif) } EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev); +struct ieee80211_vif *net_device_to_ieee80211_vif(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata; + + if (!dev) + return NULL; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + return &sdata->vif; +} +EXPORT_SYMBOL_GPL(net_device_to_ieee80211_vif); + +const struct net_device_ops *get_net_device_ops_from_wdev( + struct wireless_dev *wdev) +{ + struct ieee80211_sub_if_data *sdata; + + if (!wdev) + return NULL; + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + return sdata->dev->netdev_ops; +} +EXPORT_SYMBOL_GPL(get_net_device_ops_from_wdev); + +void set_net_device_ops_in_wdev(struct wireless_dev *wdev, + const struct net_device_ops *ops) +{ + struct ieee80211_sub_if_data *sdata; + + if (!wdev || !ops) + return; + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + sdata->dev->netdev_ops = ops; +} +EXPORT_SYMBOL_GPL(set_net_device_ops_in_wdev); + +void copy_net_device_ops_from_wdev(struct wireless_dev *wdev, + struct net_device_ops *ops) +{ + struct ieee80211_sub_if_data *sdata; + + if (!wdev || !ops) + return; + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + if (!sdata->dev->netdev_ops) + return; + memcpy(ops, sdata->dev->netdev_ops, sizeof(struct net_device_ops)); +} +EXPORT_SYMBOL_GPL(copy_net_device_ops_from_wdev); + +const char *ieee80211_vif_to_name(struct ieee80211_vif *vif) +{ + struct ieee80211_sub_if_data *sdata; + + if (!vif) + return NULL; + + sdata = vif_to_sdata(vif); + + if (!sdata) + return NULL; + + return (const char *)sdata->name; +} +EXPORT_SYMBOL_GPL(ieee80211_vif_to_name); + /* * Nothing should have been stuffed into the workqueue during * the suspend->resume cycle. Since we can't check each caller @@ -766,8 +832,63 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_queue_delayed_work); +static u32 ieee802_11_parse_vendor_specific(const u8 *pos, u8 elen, + struct ieee802_11_elems *elems, bool calc_crc, u32 crc) +{ + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && pos[2] == 0xf2) { + /* Microsoft OUI (00:50:F2) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + if (elen >= 5 && pos[3] == 2) { + /* OUI Type 2 - WMM IE */ + if (pos[4] == 0) { + elems->wmm_info = pos; + elems->wmm_info_len = elen; + } else if (pos[4] == 1) { + elems->wmm_param = pos; + elems->wmm_param_len = elen; + } + } + } + + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x90 && pos[2] == 0x4c) { + /* Broadcom (Epigram) (00:90:4C) */ + + if (calc_crc) + crc = crc32_be(crc, pos - 2, elen + 2); + + if (elen >= 5 && pos[3] == WLAN_VENDOR_VHT_TYPE) { + if ((pos[4] == WLAN_VENDOR_VHT_SUBTYPE || + pos[4] == WLAN_VENDOR_VHT_SUBTYPE2 || + pos[4] == WLAN_VENDOR_VHT_SUBTYPE3)) { + elems->vendor_vht = pos; + elems->vendor_vht_len = elen; + } + } + } + + if (elen >= 4 && elems->vendor_events_filter && elems->vendor_events_filter_len >= 3) { + int i = 0, found = 1; + for (i = 0; i < elems->vendor_events_filter_len; i++) { + if (pos[i] != elems->vendor_events_filter[i]) { + found = 0; + break; + } + } + if (found) { + elems->vendor_ie_to_notify = pos; + elems->vendor_ie_to_notify_len = elen; + } + } + + return crc; +} + u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, struct ieee802_11_elems *elems, + u8 *vendor_events_filter, u8 vendor_events_filter_len, u64 filter, u32 crc) { size_t left = len; @@ -780,6 +901,8 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, memset(elems, 0, sizeof(*elems)); elems->ie_start = start; elems->total_len = len; + elems->vendor_events_filter = vendor_events_filter; + elems->vendor_events_filter_len = vendor_events_filter_len; while (left >= 2) { u8 id, elen; @@ -891,24 +1014,8 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, elems->challenge_len = elen; break; case WLAN_EID_VENDOR_SPECIFIC: - if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && - pos[2] == 0xf2) { - /* Microsoft OUI (00:50:F2) */ - - if (calc_crc) - crc = crc32_be(crc, pos - 2, elen + 2); - - if (elen >= 5 && pos[3] == 2) { - /* OUI Type 2 - WMM IE */ - if (pos[4] == 0) { - elems->wmm_info = pos; - elems->wmm_info_len = elen; - } else if (pos[4] == 1) { - elems->wmm_param = pos; - elems->wmm_param_len = elen; - } - } - } + crc = ieee802_11_parse_vendor_specific(pos, elen, elems, + calc_crc, crc); break; case WLAN_EID_RSN: elems->rsn = pos; @@ -1456,7 +1563,8 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, break; } - if (sband->vht_cap.vht_supported && have_80mhz) { + /* Don't add VHT capab. in 2GHZ, even if we support it */ + if (sband->vht_cap.vht_supported && have_80mhz && band != NL80211_BAND_2GHZ) { if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) goto out_err; pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, @@ -2837,7 +2945,7 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work) /* XXX: multi-channel is not supported yet */ WARN_ON(1); else - cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); + cfg80211_radar_event(local->hw.wiphy, &chandef, 0, GFP_KERNEL); } void ieee80211_radar_detected(struct ieee80211_hw *hw) diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 4ea786eae1ab363bef0376bab2bb2bc989718e3f..05a0fc645a30588ee0e3f01b0b2b1b300ab47bdc 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -181,7 +181,7 @@ config CFG80211_WEXT extensions with cfg80211-based drivers. config CFG80211_WEXT_EXPORT - bool + bool "Export cfg80211's wext compatibility symbols" depends on CFG80211 help Drivers should select this option if they require cfg80211's diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 5497d022fadabf17512c0f4c0b77ce50cce345dc..0f4043565dca35f3285c94a457e0f5cda18539c8 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -150,7 +150,7 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c, } } -static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) +int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c) { int width; @@ -251,6 +251,8 @@ static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq, if (!c || !(c->flags & IEEE80211_CHAN_RADAR)) continue; + printk(KERN_DEBUG "Setting the DFS state of channel %hu to 0x%02x\n", + c->hw_value, dfs_state); c->dfs_state = dfs_state; c->dfs_state_entered = jiffies; } @@ -277,6 +279,7 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy, cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2, width, dfs_state); } +EXPORT_SYMBOL(cfg80211_set_dfs_state); static u32 cfg80211_get_start_freq(u32 center_freq, u32 bandwidth) diff --git a/net/wireless/core.c b/net/wireless/core.c index 8201e6d7449e969182152fcc2641a7e0247b7770..d19fbe678339184c3241b8240105775cd87ea311 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -39,6 +39,7 @@ MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME); /* RCU-protected (and RTNL for writers) */ LIST_HEAD(cfg80211_rdev_list); +EXPORT_SYMBOL(cfg80211_rdev_list); int cfg80211_rdev_list_generation; /* for debugfs */ @@ -431,6 +432,8 @@ use_default_name: dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); } + rdev->scan_expire_time = IEEE80211_SCAN_RESULT_EXPIRE; + INIT_LIST_HEAD(&rdev->wiphy.wdev_list); INIT_LIST_HEAD(&rdev->beacon_registrations); spin_lock_init(&rdev->beacon_registrations_lock); @@ -529,9 +532,9 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) return -EINVAL; - /* DFS only works on one channel. */ + /* Two different channels allowed by WLAN driver during CSA */ if (WARN_ON(c->radar_detect_widths && - (c->num_different_channels > 1))) + (c->num_different_channels > 2))) return -EINVAL; if (WARN_ON(!c->n_limits)) @@ -957,6 +960,12 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) } EXPORT_SYMBOL(cfg80211_unregister_wdev); +struct workqueue_struct *cfg80211_get_cfg80211_wq(void) +{ + return cfg80211_wq; +} +EXPORT_SYMBOL(cfg80211_get_cfg80211_wq); + static const struct device_type wiphy_type = { .name = "wlan", }; diff --git a/net/wireless/core.h b/net/wireless/core.h index 5f5867f90fed5e61992baf06fbf330333889a390..5bd0ae19eb7280efde4e22cc1034f77c52aedb85 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -18,6 +18,7 @@ #define WIPHY_IDX_INVALID -1 +#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) struct cfg80211_registered_device { const struct cfg80211_ops *ops; @@ -75,6 +76,7 @@ struct cfg80211_registered_device { struct cfg80211_scan_request *scan_req; /* protected by RTNL */ struct sk_buff *scan_msg; struct cfg80211_sched_scan_request __rcu *sched_scan_req; + u32 scan_expire_time; unsigned long suspend_at; struct work_struct scan_done_wk; struct work_struct sched_scan_results_wk; @@ -493,6 +495,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); +int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c); + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 76775a2b421db31c33a323f4a671f470099051db..c48e158c6ceca0cdcb7788ee45c803d2d7b3a127 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -505,6 +505,13 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, nreg->frame_type = cpu_to_le16(frame_type); nreg->wdev = wdev; list_add(&nreg->list, &wdev->mgmt_registrations); + + if (frame_type == IEEE80211_STYPE_PROBE_RESP || + frame_type == IEEE80211_STYPE_BEACON) { + wdev->vendor_events_filter = nreg->match; + wdev->vendor_events_filter_len = nreg->match_len; + } + spin_unlock_bh(&wdev->mgmt_registrations_lock); /* process all unregistrations to avoid driver confusion */ @@ -762,7 +769,7 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) nl80211_radar_notify(rdev, &chandef, NL80211_RADAR_NOP_FINISHED, - NULL, GFP_ATOMIC); + NULL, 0, GFP_ATOMIC); continue; } @@ -782,26 +789,72 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) } +static void cfg80211_set_chans_dfs_state_bit_map (struct wiphy *wiphy, u32 center_freq, + u32 bandwidth, u8 radar_bit_map, u8 *bit_idx, + enum nl80211_dfs_state dfs_state) +{ + struct ieee80211_channel *c; + u32 freq; + + for (freq = center_freq - bandwidth/2 + 10; + freq <= center_freq + bandwidth/2 - 10; + freq += 20) { + if (radar_bit_map & (1 << *bit_idx)) { + c = ieee80211_get_channel(wiphy, freq); + if (!c || !(c->flags & IEEE80211_CHAN_RADAR)) { + *bit_idx++; + continue; + } + + c->dfs_state = dfs_state; + c->dfs_state_entered = jiffies; + } + (*bit_idx)++; + } +} + +void cfg80211_set_dfs_state_bit_map (struct wiphy *wiphy, struct cfg80211_chan_def *chandef, + u8 radar_bit_map, enum nl80211_dfs_state dfs_state) +{ + u8 bit_idx = 0; + u32 center_freq, bandwidth; + + center_freq = chandef->center_freq1; + bandwidth = cfg80211_chandef_get_width(chandef); + + cfg80211_set_chans_dfs_state_bit_map(wiphy, center_freq, bandwidth, + radar_bit_map, &bit_idx, dfs_state); + + if (NL80211_CHAN_WIDTH_80P80 != bandwidth) + return; + + center_freq = chandef->center_freq2; + cfg80211_set_chans_dfs_state_bit_map(wiphy, center_freq, bandwidth, + radar_bit_map, &bit_idx, dfs_state); +} +EXPORT_SYMBOL(cfg80211_set_dfs_state_bit_map); + + void cfg80211_radar_event(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, - gfp_t gfp) + u8 radar_bit_map, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); unsigned long timeout; trace_cfg80211_radar_event(wiphy, chandef); - /* only set the chandef supplied channel to unavailable, in - * case the radar is detected on only one of multiple channels - * spanned by the chandef. - */ - cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); + if (radar_bit_map) + cfg80211_set_dfs_state_bit_map(wiphy, chandef, radar_bit_map, + NL80211_DFS_UNAVAILABLE); + else + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS); queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, timeout); - nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); + nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, radar_bit_map, gfp); } EXPORT_SYMBOL(cfg80211_radar_event); @@ -837,6 +890,23 @@ void cfg80211_cac_event(struct net_device *netdev, } wdev->cac_started = false; - nl80211_radar_notify(rdev, chandef, event, netdev, gfp); + nl80211_radar_notify(rdev, chandef, event, netdev, 0, gfp); } EXPORT_SYMBOL(cfg80211_cac_event); + +int cfg80211_rx_vendor_specific_mgmt(struct wireless_dev *wdev, int freq, + const u8 *buf, size_t len, gfp_t gfp) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct cfg80211_mgmt_registration *reg; + int res = 0; + + list_for_each_entry(reg, &wdev->mgmt_registrations, list) { + res = nl80211_send_mgmt(rdev, wdev, reg->nlportid, freq, 0, buf, len, 0, gfp); + break; + } + + return res; +} +EXPORT_SYMBOL(cfg80211_rx_vendor_specific_mgmt); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c626f679e1c870204c62b0fa5a0d4661bfa06d32..a4d28e7ee71d8c549465f5e1c02eb77cc126addf 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -255,6 +255,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_RSSI] = { .type = NLA_U32 }, [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, @@ -389,6 +390,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY }, [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY, .len = IEEE80211_QOS_MAP_LEN_MAX }, + [NL80211_ATTR_VENDOR_WDS] = { .type = NLA_U32 }, [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, @@ -4206,6 +4208,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, PUT_SINFO(CONNECTED_TIME, connected_time, u32); PUT_SINFO(INACTIVE_TIME, inactive_time, u32); + PUT_SINFO(MAX_RSSI, max_rssi, u32); if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_RX_BYTES64)) && @@ -4883,6 +4886,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) !info->attrs[NL80211_ATTR_PEER_AID]) return -EINVAL; + if (!info->attrs[NL80211_ATTR_STA_RSSI]) + return -EINVAL; + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); params.supported_rates = nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); @@ -4891,6 +4897,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + if (info->attrs[NL80211_ATTR_FRAME]) { + params.resp = nla_data(info->attrs[NL80211_ATTR_FRAME]); + params.resp_len = nla_len(info->attrs[NL80211_ATTR_FRAME]); + } + if (info->attrs[NL80211_ATTR_STA_SUPPORT_P2P_PS]) { u8 tmp; @@ -4915,6 +4926,8 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) if (!params.aid || params.aid > IEEE80211_MAX_AID) return -EINVAL; + params.rssi = nla_get_u32(info->attrs[NL80211_ATTR_STA_RSSI]); + if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { params.capability = nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); @@ -7217,33 +7230,51 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, unsigned int cac_time_ms; int err; + printk(KERN_INFO "Starting radar detection\n"); + dfs_region = reg_get_dfs_region(wdev->wiphy); - if (dfs_region == NL80211_DFS_UNSET) + if (dfs_region == NL80211_DFS_UNSET) { + printk(KERN_ERR "DFS master region not specified\n"); return -EINVAL; + } err = nl80211_parse_chandef(rdev, info, &chandef); - if (err) + if (err) { + printk(KERN_ERR "Could not parse the channel definition\n"); return err; + } - if (netif_carrier_ok(dev)) + if (netif_carrier_ok(dev)) { + printk(KERN_ERR "Carrier isn't present on device\n"); return -EBUSY; + } - if (wdev->cac_started) + if (wdev->cac_started) { + printk(KERN_ERR "CAC already started\n"); return -EBUSY; + } err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, wdev->iftype); - if (err < 0) + if (err < 0) { + printk(KERN_ERR "Error looking for DFS-required channels\n"); return err; + } - if (err == 0) + if (err == 0) { + printk(KERN_ERR "No DFS-required channels found\n"); return -EINVAL; + } - if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) + if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) { + printk(KERN_ERR "Channels are not all in DFS_USABLE state\n"); return -EINVAL; + } - if (!rdev->ops->start_radar_detection) + if (!rdev->ops->start_radar_detection) { + printk(KERN_ERR "Device does not support radar detection\n"); return -EOPNOTSUPP; + } cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); if (WARN_ON(!cac_time_ms)) @@ -7255,7 +7286,10 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, wdev->cac_started = true; wdev->cac_start_time = jiffies; wdev->cac_time_ms = cac_time_ms; + } else { + printk(KERN_ERR "Start radar detection in device failed\n"); } + return err; } @@ -7394,6 +7428,12 @@ skip_beacons: if (err) return err; + if (info->attrs[NL80211_ATTR_SB_DFS_BW]) + params.sb_dfs_bw = nla_get_u8(info->attrs[NL80211_ATTR_SB_DFS_BW]); + + if (NL80211_SB_DFS_BW_FULL == params.sb_dfs_bw) + cfg80211_set_dfs_state(&rdev->wiphy, ¶ms.chandef, NL80211_DFS_AVAILABLE); + if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms.chandef, wdev->iftype)) return -EINVAL; @@ -7970,6 +8010,10 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + if (info->attrs[NL80211_ATTR_VENDOR_WDS]) { + req.vendor_wds = nla_get_u32(info->attrs[NL80211_ATTR_VENDOR_WDS]); + } + if (info->attrs[NL80211_ATTR_PREV_BSSID]) req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); @@ -14041,7 +14085,8 @@ void nl80211_radar_notify(struct cfg80211_registered_device *rdev, const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, - struct net_device *netdev, gfp_t gfp) + struct net_device *netdev, + u8 radar_bit_map, gfp_t gfp) { struct sk_buff *msg; void *hdr; @@ -14075,6 +14120,12 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, if (nl80211_send_chandef(msg, chandef)) goto nla_put_failure; + if (radar_bit_map) { + if (NL80211_RADAR_DETECTED == event && + nla_put_u8(msg, NL80211_ATTR_RADAR_BIT_MAP, radar_bit_map)) + goto nla_put_failure; + } + genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, @@ -14085,6 +14136,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, genlmsg_cancel(msg, hdr); nlmsg_free(msg); } +EXPORT_SYMBOL(nl80211_radar_notify); void cfg80211_probe_status(struct net_device *dev, const u8 *addr, u64 cookie, bool acked, gfp_t gfp) diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 7e3821d7fcc5eb185359d3b9c45bd3d526fd36c2..a858b164d77d208360aeef7a87c1d3ac8f41cf41 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -91,7 +91,8 @@ void nl80211_radar_notify(struct cfg80211_registered_device *rdev, const struct cfg80211_chan_def *chandef, enum nl80211_radar_event event, - struct net_device *netdev, gfp_t gfp); + struct net_device *netdev, + u8 radar_bit_map, gfp_t gfp); void nl80211_send_ap_stopped(struct wireless_dev *wdev); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5dbac37497386fffb23de9bf5fe384891f874eca..acd45975f153c5bd8380ede67b1fdc115b060146 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -109,6 +109,7 @@ static struct platform_device *reg_pdev; * (protected by RTNL, can be read under RCU) */ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; +EXPORT_SYMBOL(cfg80211_regdomain); /* * Number of devices that registered to the core @@ -1857,8 +1858,9 @@ __reg_process_hint_user(struct regulatory_request *user_request) if (reg_request_cell_base(lr)) return REG_REQ_IGNORE; + /* Don't do intersection between mac80211 and cfg80211 regdom */ if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) - return REG_REQ_INTERSECT; + return REG_REQ_OK; /* * If the user knows better the user should set the regdom * to their country before the IE is picked up diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 35ad69fd08383a2a8392170d2a580fc4549276d7..89aa8fa61e7c8e4228c17f2e52bf19d1631e9c03 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -70,8 +70,6 @@ module_param(bss_entries_limit, int, 0644); MODULE_PARM_DESC(bss_entries_limit, "limit to number of scan BSS entries (per wiphy, default 1000)"); -#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ) - static void bss_free(struct cfg80211_internal_bss *bss) { struct cfg80211_bss_ies *ies; @@ -400,7 +398,7 @@ void cfg80211_bss_age(struct cfg80211_registered_device *rdev, void cfg80211_bss_expire(struct cfg80211_registered_device *rdev) { - __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); + __cfg80211_bss_expire(rdev, jiffies - rdev->scan_expire_time); } const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len, @@ -661,7 +659,7 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, if (!is_valid_ether_addr(bss->pub.bssid)) continue; /* Don't get expired BSS structs */ - if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) && + if (time_after(now, bss->ts + rdev->scan_expire_time) && !atomic_read(&bss->hold)) continue; if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { @@ -1231,6 +1229,22 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) } EXPORT_SYMBOL(cfg80211_unlink_bss); +void cfg80211_set_scan_expire_time(struct wiphy *wiphy, unsigned long time) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + rdev->scan_expire_time = time; +} +EXPORT_SYMBOL(cfg80211_set_scan_expire_time); + +u32 cfg80211_get_scan_expire_time(struct wiphy *wiphy) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + return rdev->scan_expire_time; +} +EXPORT_SYMBOL(cfg80211_get_scan_expire_time); + #ifdef CONFIG_CFG80211_WEXT static struct cfg80211_registered_device * cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 35cc1de85dcc53ea18817a5a23a4745718277910..ece8a0ab7b1a9d8de99f68d9476912abe8e9060c 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -761,8 +761,9 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, * - country_ie + 2, the start of the country ie data, and * - and country_ie[1] which is the IE length */ - regulatory_hint_country_ie(wdev->wiphy, bss->channel->band, - country_ie + 2, country_ie[1]); + if (!(wdev->wiphy->flags & WIPHY_FLAG_DISABLE_11D_HINT)) + regulatory_hint_country_ie(wdev->wiphy, bss->channel->band, + country_ie + 2, country_ie[1]); kfree(country_ie); } diff --git a/net/wireless/util.c b/net/wireless/util.c index c921c2eed15d4fe9ee2025b5ed49180d9a8ed38d..ea5724f2b52820932677d42088f03c48303b0dca 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1637,20 +1637,29 @@ int cfg80211_iter_combinations(struct wiphy *wiphy, } } - if (radar_detect != (c->radar_detect_widths & radar_detect)) + if (radar_detect != (c->radar_detect_widths & radar_detect)) { + printk(KERN_DEBUG "combination %u, radar detect_widths 0x%02x", + i, c->radar_detect_widths); goto cont; + } if (radar_detect && c->radar_detect_regions && - !(c->radar_detect_regions & BIT(region))) + !(c->radar_detect_regions & BIT(region))) { + printk(KERN_DEBUG "radar_detect_regions 0x%x, region %d)", + c->radar_detect_regions, region); goto cont; + } /* Finally check that all iftypes that we're currently * using are actually part of this combination. If they * aren't then we can't use this combination and have * to continue to the next. */ - if ((all_iftypes & used_iftypes) != used_iftypes) + if ((all_iftypes & used_iftypes) != used_iftypes) { + printk(KERN_DEBUG "all_iftypes 0x%02x, used_iftypes 0x%02x", + all_iftypes, used_iftypes); goto cont; + } /* This combination covered all interface types and * supported the requested numbers, so we're good. @@ -1685,8 +1694,10 @@ int cfg80211_check_combinations(struct wiphy *wiphy, cfg80211_iter_sum_ifcombs, &num); if (err) return err; - if (num == 0) + if (num == 0) { + printk(KERN_ERR "No suitable interface combination found\n"); return -EBUSY; + } return 0; }