Among various cleanups and improvements, we have the following:

* client FILS authentication support in mac80211 (Jouni)
  * AP/VLAN multicast improvements (Michael Braun)
  * config/advertising support for differing beacon intervals on
    multiple virtual interfaces (Purushottam Kushwaha, myself)
  * deprecate the old WDS mode for cfg80211-based drivers, the
    mode is hardly usable since it doesn't support any "modern"
    features like WPA encryption (2003), HT (2009) or VHT (2014),
    I'm not even sure WEP (introduced in 1997) could be done.
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCgAGBQJYEy/9AAoJEGt7eEactAAd/V0P/0FmHGS8HjlSjm+1p6sbWKbt
 5v8bb3cuKHQiYiUM6euIXql2OYuOEHVAQEpNoPXN9CsfKFYgbIH6yW6d8HtKNedV
 n9lmMy/U6yJX9nYt7yMIQ3kLkbEg+YU58B9Hf47waWXLLSNVumS8rfNBn43EoNQf
 VKWYPWpetsCRIWJ1fnLuxvMHCtOOYCxH+491BUonof32+DKPEAsAbnszZ2ElufTR
 7KNyA3K6leOtTd5Ml52dvLOGNc+h2C83VAMxiShq/6r8OnlX5tPifaubzd9n3m41
 jiJJH/92ESrtF2AaWEm8slcgtcfHS/O7y/FSoV4r0PMSvPTBdjwQ9nqCsbONd831
 vjj6c6YWNxgHPcISX0XcWz+FHnLJdUGaDUtHjAJYw4oH4gaRXwfSw0U+jvdlSMUf
 2CBUArk5f0OEguzwa/5X4Jio3OPPIj4jY/lKplcpLOUu8K2FWTLDuIlww/FHXovs
 rDzTLQeXZkx+MkszkTJN42qSEfOFly91J6OA2Wju+emBqrLIbkAGmvyLVg8U8BQd
 gG7oltgmZ6Xg6fEnUQqpIDO7UJlQ+GXAU04SpNDMv1j/ueUJskxlr3hYM7E9ueQv
 LJcZcVV0RAwNRw52cEsdcYCMLuSMYRrO1OHlkl0wd+x2hFrUCWnVzUgLEUhNBV+c
 ICmNMr96nKhrZI217yzF
 =SjfQ
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-davem-2016-10-28' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
Among various cleanups and improvements, we have the following:
 * client FILS authentication support in mac80211 (Jouni)
 * AP/VLAN multicast improvements (Michael Braun)
 * config/advertising support for differing beacon intervals on
   multiple virtual interfaces (Purushottam Kushwaha, myself)
 * deprecate the old WDS mode for cfg80211-based drivers, the
   mode is hardly usable since it doesn't support any "modern"
   features like WPA encryption (2003), HT (2009) or VHT (2014),
   I'm not even sure WEP (introduced in 1997) could be done.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-10-29 17:28:45 -04:00
commit 32ab0a38f0
45 changed files with 1388 additions and 426 deletions

View File

@ -60,7 +60,7 @@ modprobe mac80211_hwsim
hostapd hostapd.conf hostapd hostapd.conf
# Run wpa_supplicant (station) for wlan1 # Run wpa_supplicant (station) for wlan1
wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf wpa_supplicant -Dnl80211 -iwlan1 -c wpa_supplicant.conf
More test cases are available in hostap.git: More test cases are available in hostap.git:

View File

@ -17,6 +17,19 @@ menuconfig WLAN
if WLAN if WLAN
config WIRELESS_WDS
bool "mac80211-based legacy WDS support" if EXPERT
help
This option enables the deprecated WDS support, the newer
mac80211-based 4-addr AP/client support supersedes it with
a much better feature set (HT, VHT, ...)
We plan to remove this option and code, so if you find
that you have to enable it, please let us know on the
linux-wireless@vger.kernel.org mailing list, so we can
help you migrate to 4-addr AP/client (or, if it's really
necessary, give up on our plan of removing it).
source "drivers/net/wireless/admtek/Kconfig" source "drivers/net/wireless/admtek/Kconfig"
source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/atmel/Kconfig" source "drivers/net/wireless/atmel/Kconfig"

View File

@ -7881,6 +7881,7 @@ int ath10k_mac_register(struct ath10k *ar)
ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF); ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
ieee80211_hw_set(ar->hw, QUEUE_CONTROL); ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags))
ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);

View File

@ -734,9 +734,11 @@ static const struct ieee80211_iface_limit if_limits[] = {
BIT(NL80211_IFTYPE_P2P_GO) }, BIT(NL80211_IFTYPE_P2P_GO) },
}; };
#ifdef CONFIG_WIRELESS_WDS
static const struct ieee80211_iface_limit wds_limits[] = { static const struct ieee80211_iface_limit wds_limits[] = {
{ .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) },
}; };
#endif
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
@ -774,6 +776,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
BIT(NL80211_CHAN_WIDTH_40), BIT(NL80211_CHAN_WIDTH_40),
#endif #endif
}, },
#ifdef CONFIG_WIRELESS_WDS
{ {
.limits = wds_limits, .limits = wds_limits,
.n_limits = ARRAY_SIZE(wds_limits), .n_limits = ARRAY_SIZE(wds_limits),
@ -781,6 +784,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
.num_different_channels = 1, .num_different_channels = 1,
.beacon_int_infra_match = true, .beacon_int_infra_match = true,
}, },
#endif
}; };
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
@ -851,7 +855,9 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_MESH_POINT) |
#ifdef CONFIG_WIRELESS_WDS
BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_WDS) |
#endif
BIT(NL80211_IFTYPE_OCB); BIT(NL80211_IFTYPE_OCB);
if (ath9k_is_chanctx_enabled()) if (ath9k_is_chanctx_enabled())

View File

@ -5591,7 +5591,9 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_STATION) |
#ifdef CONFIG_WIRELESS_WDS
BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_WDS) |
#endif
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;

View File

@ -3838,7 +3838,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
hw->wiphy->interface_modes = hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_STATION) |
#ifdef CONFIG_WIRELESS_WDS
BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_WDS) |
#endif
BIT(NL80211_IFTYPE_ADHOC); BIT(NL80211_IFTYPE_ADHOC);
hw->queues = 1; /* FIXME: hardware has more queues */ hw->queues = 1; /* FIXME: hardware has more queues */
hw->max_rates = 2; hw->max_rates = 2;

View File

@ -414,23 +414,24 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif, struct brcmf_cfg80211_vif *vif,
enum nl80211_iftype new_type) enum nl80211_iftype new_type)
{ {
int iftype_num[NUM_NL80211_IFTYPES];
struct brcmf_cfg80211_vif *pos; struct brcmf_cfg80211_vif *pos;
bool check_combos = false; bool check_combos = false;
int ret = 0; int ret = 0;
struct iface_combination_params params = {
.num_different_channels = 1,
};
memset(&iftype_num[0], 0, sizeof(iftype_num));
list_for_each_entry(pos, &cfg->vif_list, list) list_for_each_entry(pos, &cfg->vif_list, list)
if (pos == vif) { if (pos == vif) {
iftype_num[new_type]++; params.iftype_num[new_type]++;
} else { } else {
/* concurrent interfaces so need check combinations */ /* concurrent interfaces so need check combinations */
check_combos = true; check_combos = true;
iftype_num[pos->wdev.iftype]++; params.iftype_num[pos->wdev.iftype]++;
} }
if (check_combos) if (check_combos)
ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); ret = cfg80211_check_combinations(cfg->wiphy, &params);
return ret; return ret;
} }
@ -438,15 +439,16 @@ static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg,
static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype new_type) enum nl80211_iftype new_type)
{ {
int iftype_num[NUM_NL80211_IFTYPES];
struct brcmf_cfg80211_vif *pos; struct brcmf_cfg80211_vif *pos;
struct iface_combination_params params = {
.num_different_channels = 1,
};
memset(&iftype_num[0], 0, sizeof(iftype_num));
list_for_each_entry(pos, &cfg->vif_list, list) list_for_each_entry(pos, &cfg->vif_list, list)
iftype_num[pos->wdev.iftype]++; params.iftype_num[pos->wdev.iftype]++;
iftype_num[new_type]++; params.iftype_num[new_type]++;
return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); return cfg80211_check_combinations(cfg->wiphy, &params);
} }
static void convert_key_from_CPU(struct brcmf_wsec_key *key, static void convert_key_from_CPU(struct brcmf_wsec_key *key,

View File

@ -2249,35 +2249,51 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
} }
#define HWSIM_COMMON_OPS \
.tx = mac80211_hwsim_tx, \
.start = mac80211_hwsim_start, \
.stop = mac80211_hwsim_stop, \
.add_interface = mac80211_hwsim_add_interface, \
.change_interface = mac80211_hwsim_change_interface, \
.remove_interface = mac80211_hwsim_remove_interface, \
.config = mac80211_hwsim_config, \
.configure_filter = mac80211_hwsim_configure_filter, \
.bss_info_changed = mac80211_hwsim_bss_info_changed, \
.sta_add = mac80211_hwsim_sta_add, \
.sta_remove = mac80211_hwsim_sta_remove, \
.sta_notify = mac80211_hwsim_sta_notify, \
.set_tim = mac80211_hwsim_set_tim, \
.conf_tx = mac80211_hwsim_conf_tx, \
.get_survey = mac80211_hwsim_get_survey, \
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \
.ampdu_action = mac80211_hwsim_ampdu_action, \
.flush = mac80211_hwsim_flush, \
.get_tsf = mac80211_hwsim_get_tsf, \
.set_tsf = mac80211_hwsim_set_tsf, \
.get_et_sset_count = mac80211_hwsim_get_et_sset_count, \
.get_et_stats = mac80211_hwsim_get_et_stats, \
.get_et_strings = mac80211_hwsim_get_et_strings,
static const struct ieee80211_ops mac80211_hwsim_ops = { static const struct ieee80211_ops mac80211_hwsim_ops = {
.tx = mac80211_hwsim_tx, HWSIM_COMMON_OPS
.start = mac80211_hwsim_start,
.stop = mac80211_hwsim_stop,
.add_interface = mac80211_hwsim_add_interface,
.change_interface = mac80211_hwsim_change_interface,
.remove_interface = mac80211_hwsim_remove_interface,
.config = mac80211_hwsim_config,
.configure_filter = mac80211_hwsim_configure_filter,
.bss_info_changed = mac80211_hwsim_bss_info_changed,
.sta_add = mac80211_hwsim_sta_add,
.sta_remove = mac80211_hwsim_sta_remove,
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
.get_survey = mac80211_hwsim_get_survey,
CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
.ampdu_action = mac80211_hwsim_ampdu_action,
.sw_scan_start = mac80211_hwsim_sw_scan, .sw_scan_start = mac80211_hwsim_sw_scan,
.sw_scan_complete = mac80211_hwsim_sw_scan_complete, .sw_scan_complete = mac80211_hwsim_sw_scan_complete,
.flush = mac80211_hwsim_flush,
.get_tsf = mac80211_hwsim_get_tsf,
.set_tsf = mac80211_hwsim_set_tsf,
.get_et_sset_count = mac80211_hwsim_get_et_sset_count,
.get_et_stats = mac80211_hwsim_get_et_stats,
.get_et_strings = mac80211_hwsim_get_et_strings,
}; };
static struct ieee80211_ops mac80211_hwsim_mchan_ops; static const struct ieee80211_ops mac80211_hwsim_mchan_ops = {
HWSIM_COMMON_OPS
.hw_scan = mac80211_hwsim_hw_scan,
.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan,
.sw_scan_start = NULL,
.sw_scan_complete = NULL,
.remain_on_channel = mac80211_hwsim_roc,
.cancel_remain_on_channel = mac80211_hwsim_croc,
.add_chanctx = mac80211_hwsim_add_chanctx,
.remove_chanctx = mac80211_hwsim_remove_chanctx,
.change_chanctx = mac80211_hwsim_change_chanctx,
.assign_vif_chanctx = mac80211_hwsim_assign_vif_chanctx,
.unassign_vif_chanctx = mac80211_hwsim_unassign_vif_chanctx,
};
struct hwsim_new_radio_params { struct hwsim_new_radio_params {
unsigned int channels; unsigned int channels;
@ -3362,21 +3378,6 @@ static int __init init_mac80211_hwsim(void)
if (channels < 1) if (channels < 1)
return -EINVAL; return -EINVAL;
mac80211_hwsim_mchan_ops = mac80211_hwsim_ops;
mac80211_hwsim_mchan_ops.hw_scan = mac80211_hwsim_hw_scan;
mac80211_hwsim_mchan_ops.cancel_hw_scan = mac80211_hwsim_cancel_hw_scan;
mac80211_hwsim_mchan_ops.sw_scan_start = NULL;
mac80211_hwsim_mchan_ops.sw_scan_complete = NULL;
mac80211_hwsim_mchan_ops.remain_on_channel = mac80211_hwsim_roc;
mac80211_hwsim_mchan_ops.cancel_remain_on_channel = mac80211_hwsim_croc;
mac80211_hwsim_mchan_ops.add_chanctx = mac80211_hwsim_add_chanctx;
mac80211_hwsim_mchan_ops.remove_chanctx = mac80211_hwsim_remove_chanctx;
mac80211_hwsim_mchan_ops.change_chanctx = mac80211_hwsim_change_chanctx;
mac80211_hwsim_mchan_ops.assign_vif_chanctx =
mac80211_hwsim_assign_vif_chanctx;
mac80211_hwsim_mchan_ops.unassign_vif_chanctx =
mac80211_hwsim_unassign_vif_chanctx;
spin_lock_init(&hwsim_radio_lock); spin_lock_init(&hwsim_radio_lock);
err = register_pernet_device(&hwsim_net_ops); err = register_pernet_device(&hwsim_net_ops);

View File

@ -1362,11 +1362,13 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
if (rt2x00dev->bcn->limit > 0) if (rt2x00dev->bcn->limit > 0)
rt2x00dev->hw->wiphy->interface_modes |= rt2x00dev->hw->wiphy->interface_modes |=
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_MESH_POINT) |
#endif #endif
BIT(NL80211_IFTYPE_WDS); #ifdef CONFIG_WIRELESS_WDS
BIT(NL80211_IFTYPE_WDS) |
#endif
BIT(NL80211_IFTYPE_AP);
rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; rt2x00dev->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;

View File

@ -6086,6 +6086,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
ieee80211_hw_set(wl->hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(wl->hw, SUPPORTS_DYNAMIC_PS);
ieee80211_hw_set(wl->hw, SIGNAL_DBM); ieee80211_hw_set(wl->hw, SIGNAL_DBM);
ieee80211_hw_set(wl->hw, SUPPORTS_PS); ieee80211_hw_set(wl->hw, SUPPORTS_PS);
ieee80211_hw_set(wl->hw, SUPPORTS_TX_FRAG);
wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->cipher_suites = cipher_suites;
wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);

View File

@ -1576,6 +1576,9 @@ struct ieee80211_vht_operation {
#define WLAN_AUTH_SHARED_KEY 1 #define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2 #define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3 #define WLAN_AUTH_SAE 3
#define WLAN_AUTH_FILS_SK 4
#define WLAN_AUTH_FILS_SK_PFS 5
#define WLAN_AUTH_FILS_PK 6
#define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128 #define WLAN_AUTH_CHALLENGE_LEN 128
@ -1960,6 +1963,26 @@ enum ieee80211_eid {
WLAN_EID_VENDOR_SPECIFIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221,
WLAN_EID_QOS_PARAMETER = 222, WLAN_EID_QOS_PARAMETER = 222,
WLAN_EID_CAG_NUMBER = 237,
WLAN_EID_AP_CSN = 239,
WLAN_EID_FILS_INDICATION = 240,
WLAN_EID_DILS = 241,
WLAN_EID_FRAGMENT = 242,
WLAN_EID_EXTENSION = 255
};
/* Element ID Extensions for Element ID 255 */
enum ieee80211_eid_ext {
WLAN_EID_EXT_ASSOC_DELAY_INFO = 1,
WLAN_EID_EXT_FILS_REQ_PARAMS = 2,
WLAN_EID_EXT_FILS_KEY_CONFIRM = 3,
WLAN_EID_EXT_FILS_SESSION = 4,
WLAN_EID_EXT_FILS_HLP_CONTAINER = 5,
WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN = 6,
WLAN_EID_EXT_KEY_DELIVERY = 7,
WLAN_EID_EXT_FILS_WRAPPED_DATA = 8,
WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
WLAN_EID_EXT_FILS_NONCE = 13,
}; };
/* Action category code */ /* Action category code */
@ -2073,6 +2096,9 @@ enum ieee80211_key_len {
#define IEEE80211_GCMP_MIC_LEN 16 #define IEEE80211_GCMP_MIC_LEN 16
#define IEEE80211_GCMP_PN_LEN 6 #define IEEE80211_GCMP_PN_LEN 6
#define FILS_NONCE_LEN 16
#define FILS_MAX_KEK_LEN 64
/* Public action codes */ /* Public action codes */
enum ieee80211_pub_actioncode { enum ieee80211_pub_actioncode {
WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4, WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,

View File

@ -771,6 +771,30 @@ struct cfg80211_csa_settings {
u8 count; u8 count;
}; };
/**
* struct iface_combination_params - input parameters for interface combinations
*
* Used to pass interface combination parameters
*
* @num_different_channels: the number of different channels we want
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
* width where radar detection is needed, as in the definition of
* &struct ieee80211_iface_combination.@radar_detect_widths
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
* @new_beacon_int: set this to the beacon interval of a new interface
* that's not operating yet, if such is to be checked as part of
* the verification
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
u32 new_beacon_int;
};
/** /**
* enum station_parameters_apply_mask - station parameter values to apply * enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp) * @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
@ -1761,9 +1785,11 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
* @key_len: length of WEP key for shared key authentication * @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication * @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication * @key: WEP key for shared key authentication
* @sae_data: Non-IE data to use with SAE or %NULL. This starts with * @auth_data: Fields and elements in Authentication frames. This contains
* Authentication transaction sequence number field. * the authentication frame body (non-IE and IE data), excluding the
* @sae_data_len: Length of sae_data buffer in octets * Authentication algorithm number, i.e., starting at the Authentication
* transaction sequence number field.
* @auth_data_len: Length of auth_data buffer in octets
*/ */
struct cfg80211_auth_request { struct cfg80211_auth_request {
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
@ -1772,8 +1798,8 @@ struct cfg80211_auth_request {
enum nl80211_auth_type auth_type; enum nl80211_auth_type auth_type;
const u8 *key; const u8 *key;
u8 key_len, key_idx; u8 key_len, key_idx;
const u8 *sae_data; const u8 *auth_data;
size_t sae_data_len; size_t auth_data_len;
}; };
/** /**
@ -1814,6 +1840,12 @@ enum cfg80211_assoc_req_flags {
* @ht_capa_mask: The bits of ht_capa which are to be used. * @ht_capa_mask: The bits of ht_capa which are to be used.
* @vht_capa: VHT capability override * @vht_capa: VHT capability override
* @vht_capa_mask: VHT capability mask indicating which fields to use * @vht_capa_mask: VHT capability mask indicating which fields to use
* @fils_kek: FILS KEK for protecting (Re)Association Request/Response frame or
* %NULL if FILS is not used.
* @fils_kek_len: Length of fils_kek in octets
* @fils_nonces: FILS nonces (part of AAD) for protecting (Re)Association
* Request/Response frame or %NULL if FILS is not used. This field starts
* with 16 octets of STA Nonce followed by 16 octets of AP Nonce.
*/ */
struct cfg80211_assoc_request { struct cfg80211_assoc_request {
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
@ -1825,6 +1857,9 @@ struct cfg80211_assoc_request {
struct ieee80211_ht_cap ht_capa; struct ieee80211_ht_cap ht_capa;
struct ieee80211_ht_cap ht_capa_mask; struct ieee80211_ht_cap ht_capa_mask;
struct ieee80211_vht_cap vht_capa, vht_capa_mask; struct ieee80211_vht_cap vht_capa, vht_capa_mask;
const u8 *fils_kek;
size_t fils_kek_len;
const u8 *fils_nonces;
}; };
/** /**
@ -2015,6 +2050,18 @@ struct cfg80211_connect_params {
const u8 *prev_bssid; const u8 *prev_bssid;
}; };
/**
* enum cfg80211_connect_params_changed - Connection parameters being updated
*
* This enum provides information of all connect parameters that
* have to be updated as part of update_connect_params() call.
*
* @UPDATE_ASSOC_IES: Indicates whether association request IEs are updated
*/
enum cfg80211_connect_params_changed {
UPDATE_ASSOC_IES = BIT(0),
};
/** /**
* enum wiphy_params_flags - set_wiphy_params bitfield values * enum wiphy_params_flags - set_wiphy_params bitfield values
* @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed * @WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed
@ -2536,9 +2583,18 @@ struct cfg80211_nan_func {
* cases, the result of roaming is indicated with a call to * cases, the result of roaming is indicated with a call to
* cfg80211_roamed() or cfg80211_roamed_bss(). * cfg80211_roamed() or cfg80211_roamed_bss().
* (invoked with the wireless_dev mutex held) * (invoked with the wireless_dev mutex held)
* @disconnect: Disconnect from the BSS/ESS. Once done, call * @update_connect_params: Update the connect parameters while connected to a
* cfg80211_disconnected(). * BSS. The updated parameters can be used by driver/firmware for
* subsequent BSS selection (roaming) decisions and to form the
* Authentication/(Re)Association Request frames. This call does not
* request an immediate disassociation or reassociation with the current
* BSS, i.e., this impacts only subsequent (re)associations. The bits in
* changed are defined in &enum cfg80211_connect_params_changed.
* (invoked with the wireless_dev mutex held) * (invoked with the wireless_dev mutex held)
* @disconnect: Disconnect from the BSS/ESS or stop connection attempts if
* connection is in progress. Once done, call cfg80211_disconnected() in
* case connection was already established (invoked with the
* wireless_dev mutex held), otherwise call cfg80211_connect_timeout().
* *
* @join_ibss: Join the specified IBSS (or create if necessary). Once done, call * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
* cfg80211_ibss_joined(), also call that function when changing BSSID due * cfg80211_ibss_joined(), also call that function when changing BSSID due
@ -2706,6 +2762,8 @@ struct cfg80211_nan_func {
* @nan_change_conf: changes NAN configuration. The changed parameters must * @nan_change_conf: changes NAN configuration. The changed parameters must
* be specified in @changes (using &enum cfg80211_nan_conf_changes); * be specified in @changes (using &enum cfg80211_nan_conf_changes);
* All other parameters must be ignored. * All other parameters must be ignored.
*
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
*/ */
struct cfg80211_ops { struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -2820,6 +2878,10 @@ struct cfg80211_ops {
int (*connect)(struct wiphy *wiphy, struct net_device *dev, int (*connect)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme); struct cfg80211_connect_params *sme);
int (*update_connect_params)(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_connect_params *sme,
u32 changed);
int (*disconnect)(struct wiphy *wiphy, struct net_device *dev, int (*disconnect)(struct wiphy *wiphy, struct net_device *dev,
u16 reason_code); u16 reason_code);
@ -2982,6 +3044,10 @@ struct cfg80211_ops {
struct wireless_dev *wdev, struct wireless_dev *wdev,
struct cfg80211_nan_conf *conf, struct cfg80211_nan_conf *conf,
u32 changes); u32 changes);
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
}; };
/* /*
@ -3080,6 +3146,12 @@ struct ieee80211_iface_limit {
* only in special cases. * only in special cases.
* @radar_detect_widths: bitmap of channel widths supported for radar detection * @radar_detect_widths: bitmap of channel widths supported for radar detection
* @radar_detect_regions: bitmap of regions supported for radar detection * @radar_detect_regions: bitmap of regions supported for radar detection
* @beacon_int_min_gcd: This interface combination supports different
* beacon intervals.
* = 0 - all beacon intervals for different interface must be same.
* > 0 - any beacon interval for the interface part of this combination AND
* *GCD* of all beacon intervals from beaconing interfaces of this
* combination must be greater or equal to this value.
* *
* With this structure the driver can describe which interface * With this structure the driver can describe which interface
* combinations it supports concurrently. * combinations it supports concurrently.
@ -3138,6 +3210,7 @@ struct ieee80211_iface_combination {
bool beacon_int_infra_match; bool beacon_int_infra_match;
u8 radar_detect_widths; u8 radar_detect_widths;
u8 radar_detect_regions; u8 radar_detect_regions;
u32 beacon_int_min_gcd;
}; };
struct ieee80211_txrx_stypes { struct ieee80211_txrx_stypes {
@ -3745,8 +3818,8 @@ struct cfg80211_cached_keys;
* @beacon_interval: beacon interval used on this device for transmitting * @beacon_interval: beacon interval used on this device for transmitting
* beacons, 0 when not valid * beacons, 0 when not valid
* @address: The address for this device, valid only if @netdev is %NULL * @address: The address for this device, valid only if @netdev is %NULL
* @p2p_started: true if this is a P2P Device that has been started * @is_running: true if this is a non-netdev device that has been started, e.g.
* @nan_started: true if this is a NAN interface that has been started * the P2P Device.
* @cac_started: true if DFS channel availability check has been started * @cac_started: true if DFS channel availability check has been started
* @cac_start_time: timestamp (jiffies) when the dfs state was entered. * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
* @cac_time_ms: CAC time in ms * @cac_time_ms: CAC time in ms
@ -3778,7 +3851,7 @@ struct wireless_dev {
struct mutex mtx; struct mutex mtx;
bool use_4addr, p2p_started, nan_started; bool use_4addr, is_running;
u8 address[ETH_ALEN] __aligned(sizeof(u16)); u8 address[ETH_ALEN] __aligned(sizeof(u16));
@ -3835,6 +3908,13 @@ static inline u8 *wdev_address(struct wireless_dev *wdev)
return wdev->address; return wdev->address;
} }
static inline bool wdev_running(struct wireless_dev *wdev)
{
if (wdev->netdev)
return netif_running(wdev->netdev);
return wdev->is_running;
}
/** /**
* wdev_priv - return wiphy priv from wireless_dev * wdev_priv - return wiphy priv from wireless_dev
* *
@ -4139,6 +4219,27 @@ static inline const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
return cfg80211_find_ie_match(eid, ies, len, NULL, 0, 0); return cfg80211_find_ie_match(eid, ies, len, NULL, 0, 0);
} }
/**
* cfg80211_find_ext_ie - find information element with EID Extension in data
*
* @ext_eid: element ID Extension
* @ies: data consisting of IEs
* @len: length of data
*
* Return: %NULL if the extended element ID could not be found or if
* the element is invalid (claims to be longer than the given
* data), or a pointer to the first byte of the requested
* element, that is the byte containing the element ID.
*
* Note: There are no checks on the element length other than
* having to fit into the given data.
*/
static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len)
{
return cfg80211_find_ie_match(WLAN_EID_EXTENSION, ies, len,
&ext_eid, 1, 2);
}
/** /**
* cfg80211_find_vendor_ie - find vendor specific information element in data * cfg80211_find_vendor_ie - find vendor specific information element in data
* *
@ -4539,7 +4640,8 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
* moves to cfg80211 in this call * moves to cfg80211 in this call
* @buf: authentication frame (header + body) * @buf: authentication frame (header + body)
* @len: length of the frame data * @len: length of the frame data
* @uapsd_queues: bitmap of ACs configured to uapsd. -1 if n/a. * @uapsd_queues: bitmap of queues configured for uapsd. Same format
* as the AC bitmap in the QoS info field
* *
* After being asked to associate via cfg80211_ops::assoc() the driver must * After being asked to associate via cfg80211_ops::assoc() the driver must
* call either this function or cfg80211_auth_timeout(). * call either this function or cfg80211_auth_timeout().
@ -5575,36 +5677,20 @@ unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy);
* cfg80211_check_combinations - check interface combinations * cfg80211_check_combinations - check interface combinations
* *
* @wiphy: the wiphy * @wiphy: the wiphy
* @num_different_channels: the number of different channels we want * @params: the interface combinations parameter
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
* width where radar detection is needed, as in the definition of
* &struct ieee80211_iface_combination.@radar_detect_widths
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
* *
* This function can be called by the driver to check whether a * This function can be called by the driver to check whether a
* combination of interfaces and their types are allowed according to * combination of interfaces and their types are allowed according to
* the interface combinations. * the interface combinations.
*/ */
int cfg80211_check_combinations(struct wiphy *wiphy, int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels, struct iface_combination_params *params);
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES]);
/** /**
* cfg80211_iter_combinations - iterate over matching combinations * cfg80211_iter_combinations - iterate over matching combinations
* *
* @wiphy: the wiphy * @wiphy: the wiphy
* @num_different_channels: the number of different channels we want * @params: the interface combinations parameter
* to use for verification
* @radar_detect: a bitmap where each bit corresponds to a channel
* width where radar detection is needed, as in the definition of
* &struct ieee80211_iface_combination.@radar_detect_widths
* @iftype_num: array with the numbers of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
* @iter: function to call for each matching combination * @iter: function to call for each matching combination
* @data: pointer to pass to iter function * @data: pointer to pass to iter function
* *
@ -5613,9 +5699,7 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
* purposes. * purposes.
*/ */
int cfg80211_iter_combinations(struct wiphy *wiphy, int cfg80211_iter_combinations(struct wiphy *wiphy,
const int num_different_channels, struct iface_combination_params *params,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES],
void (*iter)(const struct ieee80211_iface_combination *c, void (*iter)(const struct ieee80211_iface_combination *c,
void *data), void *data),
void *data); void *data);

View File

@ -333,9 +333,9 @@ enum ieee80211_radiotap_type {
#define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS 0x0003 #define IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS 0x0003
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK 0x00F0 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK 0x00F0
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU 0x0000 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU 0x0000
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU 0x0010 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ 0x0010
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU 0x0020 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU 0x0020
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ 0x0030 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU 0x0030
#define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN 0x00F0 #define IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN 0x00F0
#define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT 0x00 #define IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT 0x00

View File

@ -1438,7 +1438,7 @@ enum ieee80211_vif_flags {
struct ieee80211_vif { struct ieee80211_vif {
enum nl80211_iftype type; enum nl80211_iftype type;
struct ieee80211_bss_conf bss_conf; struct ieee80211_bss_conf bss_conf;
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN] __aligned(2);
bool p2p; bool p2p;
bool csa_active; bool csa_active;
bool mu_mimo_owner; bool mu_mimo_owner;
@ -1745,7 +1745,8 @@ struct ieee80211_sta_rates {
* @drv_priv: data area for driver use, will always be aligned to * @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information. * sizeof(void *), size is determined in hw information.
* @uapsd_queues: bitmap of queues configured for uapsd. Only valid * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
* if wme is supported. * if wme is supported. The bits order is like in
* IEEE80211_WMM_IE_STA_QOSINFO_AC_*.
* @max_sp: max Service Period. Only valid if wme is supported. * @max_sp: max Service Period. Only valid if wme is supported.
* @bandwidth: current bandwidth the station can receive with * @bandwidth: current bandwidth the station can receive with
* @rx_nss: in HT/VHT, the maximum number of spatial streams the * @rx_nss: in HT/VHT, the maximum number of spatial streams the
@ -2025,6 +2026,10 @@ struct ieee80211_txq {
* drivers, mac80211 packet loss mechanism will not be triggered and driver * drivers, mac80211 packet loss mechanism will not be triggered and driver
* is completely depending on firmware event for station kickout. * is completely depending on firmware event for station kickout.
* *
* @IEEE80211_HW_SUPPORTS_TX_FRAG: Hardware does fragmentation by itself.
* The stack will not do fragmentation.
* The callback for @set_frag_threshold should be set as well.
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/ */
enum ieee80211_hw_flags { enum ieee80211_hw_flags {
@ -2066,6 +2071,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TX_AMSDU, IEEE80211_HW_TX_AMSDU,
IEEE80211_HW_TX_FRAG_LIST, IEEE80211_HW_TX_FRAG_LIST,
IEEE80211_HW_REPORTS_LOW_ACK, IEEE80211_HW_REPORTS_LOW_ACK,
IEEE80211_HW_SUPPORTS_TX_FRAG,
/* keep last, obviously */ /* keep last, obviously */
NUM_IEEE80211_HW_FLAGS NUM_IEEE80211_HW_FLAGS
@ -3093,8 +3099,9 @@ enum ieee80211_reconfig_type {
* The callback must be atomic. * The callback must be atomic.
* *
* @set_frag_threshold: Configuration of fragmentation threshold. Assign this * @set_frag_threshold: Configuration of fragmentation threshold. Assign this
* if the device does fragmentation by itself; if this callback is * if the device does fragmentation by itself. Note that to prevent the
* implemented then the stack will not do fragmentation. * stack from doing fragmentation IEEE80211_HW_SUPPORTS_TX_FRAG
* should be set as well.
* The callback can sleep. * The callback can sleep.
* *
* @set_rts_threshold: Configuration of RTS threshold (if device needs it) * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
@ -4087,6 +4094,10 @@ void ieee80211_sta_pspoll(struct ieee80211_sta *sta);
* This must be used in conjunction with ieee80211_sta_ps_transition() * This must be used in conjunction with ieee80211_sta_ps_transition()
* and possibly ieee80211_sta_pspoll(); calls to all three must be * and possibly ieee80211_sta_pspoll(); calls to all three must be
* serialized. * serialized.
* %IEEE80211_NUM_TIDS can be passed as the tid if the tid is unknown.
* In this case, mac80211 will not check that this tid maps to an AC
* that is trigger enabled and assume that the caller did the proper
* checks.
*/ */
void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid); void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid);

View File

@ -600,6 +600,20 @@
* *
* @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface. * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
* *
* @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform
* multicast to unicast conversion. When enabled, all multicast packets
* with ethertype ARP, IPv4 or IPv6 (possibly within an 802.1Q header)
* will be sent out to each station once with the destination (multicast)
* MAC address replaced by the station's MAC address. Note that this may
* break certain expectations of the receiver, e.g. the ability to drop
* unicast IP packets encapsulated in multicast L2 frames, or the ability
* to not send destination unreachable messages in such cases.
* This can only be toggled per BSS. Configure this on an interface of
* type %NL80211_IFTYPE_AP. It applies to all its VLAN interfaces
* (%NL80211_IFTYPE_AP_VLAN), except for those in 4addr (WDS) mode.
* If %NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED is not present with this
* command, the feature is disabled.
*
* @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
* mesh config parameters may be given. * mesh config parameters may be given.
* @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
@ -874,6 +888,12 @@
* This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and * This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
* %NL80211_ATTR_COOKIE. * %NL80211_ATTR_COOKIE.
* *
* @NL80211_CMD_UPDATE_CONNECT_PARAMS: Update one or more connect parameters
* for subsequent roaming cases if the driver or firmware uses internal
* BSS selection. This command can be issued only while connected and it
* does not result in a change for the current association. Currently,
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
* @NL80211_CMD_MAX: highest used command number * @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@ -1069,6 +1089,10 @@ enum nl80211_commands {
NL80211_CMD_CHANGE_NAN_CONFIG, NL80211_CMD_CHANGE_NAN_CONFIG,
NL80211_CMD_NAN_MATCH, NL80211_CMD_NAN_MATCH,
NL80211_CMD_SET_MULTICAST_TO_UNICAST,
NL80211_CMD_UPDATE_CONNECT_PARAMS,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
@ -1638,8 +1662,16 @@ enum nl80211_commands {
* the connection request from a station. nl80211_connect_failed_reason * the connection request from a station. nl80211_connect_failed_reason
* enum has different reasons of connection failure. * enum has different reasons of connection failure.
* *
* @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames.
* with the Authentication transaction sequence number field. * This contains the authentication frame body (non-IE and IE data),
* excluding the Authentication algorithm number, i.e., starting at the
* Authentication transaction sequence number field. It is used with
* authentication algorithms that need special fields to be added into
* the frames (SAE and FILS). Currently, only the SAE cases use the
* initial two fields (Authentication transaction sequence number and
* Status code). However, those fields are included in the attribute data
* for all authentication algorithms to keep the attribute definition
* consistent.
* *
* @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from * @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION) * association request when used with NL80211_CMD_NEW_STATION)
@ -1936,6 +1968,14 @@ enum nl80211_commands {
* attribute. * attribute.
* @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute. * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
* See &enum nl80211_nan_match_attributes. * See &enum nl80211_nan_match_attributes.
* @NL80211_ATTR_FILS_KEK: KEK for FILS (Re)Association Request/Response frame
* protection.
* @NL80211_ATTR_FILS_NONCES: Nonces (part of AAD) for FILS (Re)Association
* Request/Response frame protection. This attribute contains the 16 octet
* STA Nonce followed by 16 octets of AP Nonce.
*
* @NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED: Indicates whether or not multicast
* packets should be send out as unicast to all stations (flag attribute).
* *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
@ -2195,7 +2235,7 @@ enum nl80211_attrs {
NL80211_ATTR_CONN_FAILED_REASON, NL80211_ATTR_CONN_FAILED_REASON,
NL80211_ATTR_SAE_DATA, NL80211_ATTR_AUTH_DATA,
NL80211_ATTR_VHT_CAPABILITY, NL80211_ATTR_VHT_CAPABILITY,
@ -2336,6 +2376,11 @@ enum nl80211_attrs {
NL80211_ATTR_NAN_FUNC, NL80211_ATTR_NAN_FUNC,
NL80211_ATTR_NAN_MATCH, NL80211_ATTR_NAN_MATCH,
NL80211_ATTR_FILS_KEK,
NL80211_ATTR_FILS_NONCES,
NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
@ -2347,6 +2392,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER #define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
/* /*
* Allow user space programs to use #ifdef on new attributes by defining them * Allow user space programs to use #ifdef on new attributes by defining them
@ -3660,6 +3706,9 @@ enum nl80211_bss_status {
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
* @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals * @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
* @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key
* @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS
* @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key
* @__NL80211_AUTHTYPE_NUM: internal * @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@ -3672,6 +3721,9 @@ enum nl80211_auth_type {
NL80211_AUTHTYPE_FT, NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP, NL80211_AUTHTYPE_NETWORK_EAP,
NL80211_AUTHTYPE_SAE, NL80211_AUTHTYPE_SAE,
NL80211_AUTHTYPE_FILS_SK,
NL80211_AUTHTYPE_FILS_SK_PFS,
NL80211_AUTHTYPE_FILS_PK,
/* keep last */ /* keep last */
__NL80211_AUTHTYPE_NUM, __NL80211_AUTHTYPE_NUM,
@ -4280,6 +4332,9 @@ enum nl80211_iface_limit_attrs {
* of supported channel widths for radar detection. * of supported channel widths for radar detection.
* @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap * @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap
* of supported regulatory regions for radar detection. * of supported regulatory regions for radar detection.
* @NL80211_IFACE_COMB_BI_MIN_GCD: u32 attribute specifying the minimum GCD of
* different beacon intervals supported by all the interface combinations
* in this group (if not present, all beacon intervals be identical).
* @NUM_NL80211_IFACE_COMB: number of attributes * @NUM_NL80211_IFACE_COMB: number of attributes
* @MAX_NL80211_IFACE_COMB: highest attribute number * @MAX_NL80211_IFACE_COMB: highest attribute number
* *
@ -4287,8 +4342,8 @@ enum nl80211_iface_limit_attrs {
* limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2 * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
* => allows an AP and a STA that must match BIs * => allows an AP and a STA that must match BIs
* *
* numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8 * numbers = [ #{AP, P2P-GO} <= 8 ], BI min gcd, channels = 1, max = 8,
* => allows 8 of AP/GO * => allows 8 of AP/GO that can have BI gcd >= min gcd
* *
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2 * numbers = [ #{STA} <= 2 ], channels = 2, max = 2
* => allows two STAs on different channels * => allows two STAs on different channels
@ -4314,6 +4369,7 @@ enum nl80211_if_combination_attrs {
NL80211_IFACE_COMB_NUM_CHANNELS, NL80211_IFACE_COMB_NUM_CHANNELS,
NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
NL80211_IFACE_COMB_BI_MIN_GCD,
/* keep last */ /* keep last */
NUM_NL80211_IFACE_COMB, NUM_NL80211_IFACE_COMB,
@ -4634,6 +4690,8 @@ enum nl80211_feature_flags {
* configuration (AP/mesh) with HT rates. * configuration (AP/mesh) with HT rates.
* @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate * @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
* configuration (AP/mesh) with VHT rates. * configuration (AP/mesh) with VHT rates.
* @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
* with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
* *
* @NUM_NL80211_EXT_FEATURES: number of extended features. * @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index. * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@ -4648,6 +4706,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
NL80211_EXT_FEATURE_BEACON_RATE_HT, NL80211_EXT_FEATURE_BEACON_RATE_HT,
NL80211_EXT_FEATURE_BEACON_RATE_VHT, NL80211_EXT_FEATURE_BEACON_RATE_VHT,
NL80211_EXT_FEATURE_FILS_STA,
/* add new features before the definition below */ /* add new features before the definition below */
NUM_NL80211_EXT_FEATURES, NUM_NL80211_EXT_FEATURES,

View File

@ -19,6 +19,7 @@ mac80211-y := \
aes_gcm.o \ aes_gcm.o \
aes_cmac.o \ aes_cmac.o \
aes_gmac.o \ aes_gmac.o \
fils_aead.o \
cfg.o \ cfg.o \
ethtool.o \ ethtool.o \
rx.o \ rx.o \

View File

@ -23,7 +23,7 @@
#define AAD_LEN 20 #define AAD_LEN 20
static void gf_mulx(u8 *pad) void gf_mulx(u8 *pad)
{ {
int i, carry; int i, carry;
@ -35,9 +35,9 @@ static void gf_mulx(u8 *pad)
pad[AES_BLOCK_SIZE - 1] ^= 0x87; pad[AES_BLOCK_SIZE - 1] ^= 0x87;
} }
static void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac, const u8 *addr[], const size_t *len, u8 *mac,
size_t mac_len) size_t mac_len)
{ {
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end; const u8 *pos, *end;

View File

@ -11,6 +11,10 @@
#include <linux/crypto.h> #include <linux/crypto.h>
void gf_mulx(u8 *pad);
void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac,
size_t mac_len);
struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[],
size_t key_len); size_t key_len);
void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,

View File

@ -315,11 +315,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
mutex_lock(&sta->ampdu_mlme.mtx); mutex_lock(&sta->ampdu_mlme.mtx);
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) { if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
tid_agg_rx = rcu_dereference_protected( if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
sta->ampdu_mlme.tid_rx[tid],
lockdep_is_held(&sta->ampdu_mlme.mtx));
if (tid_agg_rx->dialog_token == dialog_token) {
ht_dbg_ratelimited(sta->sdata, ht_dbg_ratelimited(sta->sdata,
"updated AddBA Req from %pM on tid %u\n", "updated AddBA Req from %pM on tid %u\n",
sta->sta.addr, tid); sta->sta.addr, tid);
@ -396,7 +392,6 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
} }
/* update data */ /* update data */
tid_agg_rx->dialog_token = dialog_token;
tid_agg_rx->ssn = start_seq_num; tid_agg_rx->ssn = start_seq_num;
tid_agg_rx->head_seq_num = start_seq_num; tid_agg_rx->head_seq_num = start_seq_num;
tid_agg_rx->buf_size = buf_size; tid_agg_rx->buf_size = buf_size;
@ -418,6 +413,7 @@ end:
if (status == WLAN_STATUS_SUCCESS) { if (status == WLAN_STATUS_SUCCESS) {
__set_bit(tid, sta->ampdu_mlme.agg_session_valid); __set_bit(tid, sta->ampdu_mlme.agg_session_valid);
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg); __clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
} }
mutex_unlock(&sta->ampdu_mlme.mtx); mutex_unlock(&sta->ampdu_mlme.mtx);

View File

@ -357,10 +357,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
if (mac_addr) { if (mac_addr) {
if (ieee80211_vif_is_mesh(&sdata->vif)) sta = sta_info_get_bss(sdata, mac_addr);
sta = sta_info_get(sdata, mac_addr);
else
sta = sta_info_get_bss(sdata, mac_addr);
/* /*
* The ASSOC test makes sure the driver is ready to * The ASSOC test makes sure the driver is ready to
* receive the key. When wpa_supplicant has roamed * receive the key. When wpa_supplicant has roamed
@ -867,6 +864,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
} }
sdata->needed_rx_chains = sdata->local->rx_chains; sdata->needed_rx_chains = sdata->local->rx_chains;
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
err = ieee80211_vif_use_channel(sdata, &params->chandef, err = ieee80211_vif_use_channel(sdata, &params->chandef,
IEEE80211_CHANCTX_SHARED); IEEE80211_CHANCTX_SHARED);
@ -897,7 +896,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
vlan->vif.type); vlan->vif.type);
} }
sdata->vif.bss_conf.beacon_int = params->beacon_interval;
sdata->vif.bss_conf.dtim_period = params->dtim_period; sdata->vif.bss_conf.dtim_period = params->dtim_period;
sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p; sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p;
@ -1523,9 +1521,6 @@ static int ieee80211_change_station(struct wiphy *wiphy,
goto out_err; goto out_err;
if (params->vlan && params->vlan != sta->sdata->dev) { if (params->vlan && params->vlan != sta->sdata->dev) {
bool prev_4addr = false;
bool new_4addr = false;
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
if (params->vlan->ieee80211_ptr->use_4addr) { if (params->vlan->ieee80211_ptr->use_4addr) {
@ -1535,26 +1530,21 @@ static int ieee80211_change_station(struct wiphy *wiphy,
} }
rcu_assign_pointer(vlansdata->u.vlan.sta, sta); rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
new_4addr = true;
__ieee80211_check_fast_rx_iface(vlansdata); __ieee80211_check_fast_rx_iface(vlansdata);
} }
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
sta->sdata->u.vlan.sta) { sta->sdata->u.vlan.sta)
RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL); RCU_INIT_POINTER(sta->sdata->u.vlan.sta, NULL);
prev_4addr = true;
} if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
ieee80211_vif_dec_num_mcast(sta->sdata);
sta->sdata = vlansdata; sta->sdata = vlansdata;
ieee80211_check_fast_xmit(sta); ieee80211_check_fast_xmit(sta);
if (sta->sta_state == IEEE80211_STA_AUTHORIZED && if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
prev_4addr != new_4addr) { ieee80211_vif_inc_num_mcast(sta->sdata);
if (new_4addr)
atomic_dec(&sta->sdata->bss->num_mcast_sta);
else
atomic_inc(&sta->sdata->bss->num_mcast_sta);
}
ieee80211_send_layer2_update(sta); ieee80211_send_layer2_update(sta);
} }
@ -2480,13 +2470,6 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
smps_mode == IEEE80211_SMPS_AUTOMATIC) smps_mode == IEEE80211_SMPS_AUTOMATIC)
return 0; return 0;
/* If no associated stations, there's no need to do anything */
if (!atomic_read(&sdata->u.ap.num_mcast_sta)) {
sdata->smps_mode = smps_mode;
ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
return 0;
}
ht_dbg(sdata, ht_dbg(sdata,
"SMPS %d requested in AP mode, sending Action frame to %d stations\n", "SMPS %d requested in AP mode, sending Action frame to %d stations\n",
smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta)); smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));

View File

@ -210,6 +210,7 @@ static const char *hw_flag_names[] = {
FLAG(TX_AMSDU), FLAG(TX_AMSDU),
FLAG(TX_FRAG_LIST), FLAG(TX_FRAG_LIST),
FLAG(REPORTS_LOW_ACK), FLAG(REPORTS_LOW_ACK),
FLAG(SUPPORTS_TX_FRAG),
#undef FLAG #undef FLAG
}; };

View File

@ -477,6 +477,7 @@ IEEE80211_IF_FILE_RW(tdls_wider_bw);
IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC); IEEE80211_IF_FILE(num_mcast_sta, u.ap.num_mcast_sta, ATOMIC);
IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC); IEEE80211_IF_FILE(num_sta_ps, u.ap.ps.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC); IEEE80211_IF_FILE(dtim_count, u.ap.ps.dtim_count, DEC);
IEEE80211_IF_FILE(num_mcast_sta_vlan, u.vlan.num_mcast_sta, ATOMIC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast( static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@ -684,6 +685,13 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD_MODE(tkip_mic_test, 0200); DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
} }
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
/* add num_mcast_sta_vlan using name num_mcast_sta */
debugfs_create_file("num_mcast_sta", 0400, sdata->vif.debugfs_dir,
sdata, &num_mcast_sta_vlan_ops);
}
static void add_ibss_files(struct ieee80211_sub_if_data *sdata) static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD_MODE(tsf, 0600); DEBUGFS_ADD_MODE(tsf, 0600);
@ -787,6 +795,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
add_ap_files(sdata); add_ap_files(sdata);
break; break;
case NL80211_IFTYPE_AP_VLAN:
add_vlan_files(sdata);
break;
case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_WDS:
add_wds_files(sdata); add_wds_files(sdata);
break; break;

View File

@ -199,13 +199,18 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
"TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
for (i = 0; i < IEEE80211_NUM_TIDS; i++) { for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
bool tid_rx_valid;
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]);
tid_rx_valid = test_bit(i, sta->ampdu_mlme.agg_session_valid);
p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx); p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
tid_rx_valid);
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
tid_rx ? tid_rx->dialog_token : 0); tid_rx_valid ?
sta->ampdu_mlme.tid_rx_token[i] : 0);
p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
tid_rx ? tid_rx->ssn : 0); tid_rx ? tid_rx->ssn : 0);

342
net/mac80211/fils_aead.c Normal file
View File

@ -0,0 +1,342 @@
/*
* FILS AEAD for (Re)Association Request/Response frames
* Copyright 2016, Qualcomm Atheros, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <crypto/aes.h>
#include <crypto/algapi.h>
#include <crypto/skcipher.h>
#include "ieee80211_i.h"
#include "aes_cmac.h"
#include "fils_aead.h"
static int aes_s2v(struct crypto_cipher *tfm,
size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
{
u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
size_t i;
const u8 *data[2];
size_t data_len[2], data_elems;
/* D = AES-CMAC(K, <zero>) */
memset(tmp, 0, AES_BLOCK_SIZE);
data[0] = tmp;
data_len[0] = AES_BLOCK_SIZE;
aes_cmac_vector(tfm, 1, data, data_len, d, AES_BLOCK_SIZE);
for (i = 0; i < num_elem - 1; i++) {
/* D = dbl(D) xor AES_CMAC(K, Si) */
gf_mulx(d); /* dbl */
aes_cmac_vector(tfm, 1, &addr[i], &len[i], tmp,
AES_BLOCK_SIZE);
crypto_xor(d, tmp, AES_BLOCK_SIZE);
}
if (len[i] >= AES_BLOCK_SIZE) {
/* len(Sn) >= 128 */
size_t j;
const u8 *pos;
/* T = Sn xorend D */
/* Use a temporary buffer to perform xorend on Sn (addr[i]) to
* avoid modifying the const input argument.
*/
data[0] = addr[i];
data_len[0] = len[i] - AES_BLOCK_SIZE;
pos = addr[i] + data_len[0];
for (j = 0; j < AES_BLOCK_SIZE; j++)
tmp[j] = pos[j] ^ d[j];
data[1] = tmp;
data_len[1] = AES_BLOCK_SIZE;
data_elems = 2;
} else {
/* len(Sn) < 128 */
/* T = dbl(D) xor pad(Sn) */
gf_mulx(d); /* dbl */
memset(tmp, 0, AES_BLOCK_SIZE);
memcpy(tmp, addr[i], len[i]);
tmp[len[i]] = 0x80;
crypto_xor(d, tmp, AES_BLOCK_SIZE);
data[0] = d;
data_len[0] = sizeof(d);
data_elems = 1;
}
/* V = AES-CMAC(K, T) */
aes_cmac_vector(tfm, data_elems, data, data_len, v, AES_BLOCK_SIZE);
return 0;
}
/* Note: addr[] and len[] needs to have one extra slot at the end. */
static int aes_siv_encrypt(const u8 *key, size_t key_len,
const u8 *plain, size_t plain_len,
size_t num_elem, const u8 *addr[],
size_t len[], u8 *out)
{
u8 v[AES_BLOCK_SIZE];
struct crypto_cipher *tfm;
struct crypto_skcipher *tfm2;
struct skcipher_request *req;
int res;
struct scatterlist src[1], dst[1];
u8 *tmp;
key_len /= 2; /* S2V key || CTR key */
addr[num_elem] = plain;
len[num_elem] = plain_len;
num_elem++;
/* S2V */
tfm = crypto_alloc_cipher("aes", 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
/* K1 for S2V */
res = crypto_cipher_setkey(tfm, key, key_len);
if (!res)
res = aes_s2v(tfm, num_elem, addr, len, v);
crypto_free_cipher(tfm);
if (res)
return res;
/* Use a temporary buffer of the plaintext to handle need for
* overwriting this during AES-CTR.
*/
tmp = kmemdup(plain, plain_len, GFP_KERNEL);
if (!tmp)
return -ENOMEM;
/* IV for CTR before encrypted data */
memcpy(out, v, AES_BLOCK_SIZE);
/* Synthetic IV to be used as the initial counter in CTR:
* Q = V bitand (1^64 || 0^1 || 1^31 || 0^1 || 1^31)
*/
v[8] &= 0x7f;
v[12] &= 0x7f;
/* CTR */
tfm2 = crypto_alloc_skcipher("ctr(aes)", 0, 0);
if (IS_ERR(tfm2)) {
kfree(tmp);
return PTR_ERR(tfm2);
}
/* K2 for CTR */
res = crypto_skcipher_setkey(tfm2, key + key_len, key_len);
if (res)
goto fail;
req = skcipher_request_alloc(tfm2, GFP_KERNEL);
if (!req) {
res = -ENOMEM;
goto fail;
}
sg_init_one(src, tmp, plain_len);
sg_init_one(dst, out + AES_BLOCK_SIZE, plain_len);
skcipher_request_set_crypt(req, src, dst, plain_len, v);
res = crypto_skcipher_encrypt(req);
skcipher_request_free(req);
fail:
kfree(tmp);
crypto_free_skcipher(tfm2);
return res;
}
/* Note: addr[] and len[] needs to have one extra slot at the end. */
static int aes_siv_decrypt(const u8 *key, size_t key_len,
const u8 *iv_crypt, size_t iv_c_len,
size_t num_elem, const u8 *addr[], size_t len[],
u8 *out)
{
struct crypto_cipher *tfm;
struct crypto_skcipher *tfm2;
struct skcipher_request *req;
struct scatterlist src[1], dst[1];
size_t crypt_len;
int res;
u8 frame_iv[AES_BLOCK_SIZE], iv[AES_BLOCK_SIZE];
u8 check[AES_BLOCK_SIZE];
crypt_len = iv_c_len - AES_BLOCK_SIZE;
key_len /= 2; /* S2V key || CTR key */
addr[num_elem] = out;
len[num_elem] = crypt_len;
num_elem++;
memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
memcpy(frame_iv, iv_crypt, AES_BLOCK_SIZE);
/* Synthetic IV to be used as the initial counter in CTR:
* Q = V bitand (1^64 || 0^1 || 1^31 || 0^1 || 1^31)
*/
iv[8] &= 0x7f;
iv[12] &= 0x7f;
/* CTR */
tfm2 = crypto_alloc_skcipher("ctr(aes)", 0, 0);
if (IS_ERR(tfm2))
return PTR_ERR(tfm2);
/* K2 for CTR */
res = crypto_skcipher_setkey(tfm2, key + key_len, key_len);
if (res) {
crypto_free_skcipher(tfm2);
return res;
}
req = skcipher_request_alloc(tfm2, GFP_KERNEL);
if (!req) {
crypto_free_skcipher(tfm2);
return -ENOMEM;
}
sg_init_one(src, iv_crypt + AES_BLOCK_SIZE, crypt_len);
sg_init_one(dst, out, crypt_len);
skcipher_request_set_crypt(req, src, dst, crypt_len, iv);
res = crypto_skcipher_decrypt(req);
skcipher_request_free(req);
crypto_free_skcipher(tfm2);
if (res)
return res;
/* S2V */
tfm = crypto_alloc_cipher("aes", 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
/* K1 for S2V */
res = crypto_cipher_setkey(tfm, key, key_len);
if (!res)
res = aes_s2v(tfm, num_elem, addr, len, check);
crypto_free_cipher(tfm);
if (res)
return res;
if (memcmp(check, frame_iv, AES_BLOCK_SIZE) != 0)
return -EINVAL;
return 0;
}
int fils_encrypt_assoc_req(struct sk_buff *skb,
struct ieee80211_mgd_assoc_data *assoc_data)
{
struct ieee80211_mgmt *mgmt = (void *)skb->data;
u8 *capab, *ies, *encr;
const u8 *addr[5 + 1], *session;
size_t len[5 + 1];
size_t crypt_len;
if (ieee80211_is_reassoc_req(mgmt->frame_control)) {
capab = (u8 *)&mgmt->u.reassoc_req.capab_info;
ies = mgmt->u.reassoc_req.variable;
} else {
capab = (u8 *)&mgmt->u.assoc_req.capab_info;
ies = mgmt->u.assoc_req.variable;
}
session = cfg80211_find_ext_ie(WLAN_EID_EXT_FILS_SESSION,
ies, skb->data + skb->len - ies);
if (!session || session[1] != 1 + 8)
return -EINVAL;
/* encrypt after FILS Session element */
encr = (u8 *)session + 2 + 1 + 8;
/* AES-SIV AAD vectors */
/* The STA's MAC address */
addr[0] = mgmt->sa;
len[0] = ETH_ALEN;
/* The AP's BSSID */
addr[1] = mgmt->da;
len[1] = ETH_ALEN;
/* The STA's nonce */
addr[2] = assoc_data->fils_nonces;
len[2] = FILS_NONCE_LEN;
/* The AP's nonce */
addr[3] = &assoc_data->fils_nonces[FILS_NONCE_LEN];
len[3] = FILS_NONCE_LEN;
/* The (Re)Association Request frame from the Capability Information
* field to the FILS Session element (both inclusive).
*/
addr[4] = capab;
len[4] = encr - capab;
crypt_len = skb->data + skb->len - encr;
skb_put(skb, AES_BLOCK_SIZE);
return aes_siv_encrypt(assoc_data->fils_kek, assoc_data->fils_kek_len,
encr, crypt_len, 1, addr, len, encr);
}
int fils_decrypt_assoc_resp(struct ieee80211_sub_if_data *sdata,
u8 *frame, size_t *frame_len,
struct ieee80211_mgd_assoc_data *assoc_data)
{
struct ieee80211_mgmt *mgmt = (void *)frame;
u8 *capab, *ies, *encr;
const u8 *addr[5 + 1], *session;
size_t len[5 + 1];
int res;
size_t crypt_len;
if (*frame_len < 24 + 6)
return -EINVAL;
capab = (u8 *)&mgmt->u.assoc_resp.capab_info;
ies = mgmt->u.assoc_resp.variable;
session = cfg80211_find_ext_ie(WLAN_EID_EXT_FILS_SESSION,
ies, frame + *frame_len - ies);
if (!session || session[1] != 1 + 8) {
mlme_dbg(sdata,
"No (valid) FILS Session element in (Re)Association Response frame from %pM",
mgmt->sa);
return -EINVAL;
}
/* decrypt after FILS Session element */
encr = (u8 *)session + 2 + 1 + 8;
/* AES-SIV AAD vectors */
/* The AP's BSSID */
addr[0] = mgmt->sa;
len[0] = ETH_ALEN;
/* The STA's MAC address */
addr[1] = mgmt->da;
len[1] = ETH_ALEN;
/* The AP's nonce */
addr[2] = &assoc_data->fils_nonces[FILS_NONCE_LEN];
len[2] = FILS_NONCE_LEN;
/* The STA's nonce */
addr[3] = assoc_data->fils_nonces;
len[3] = FILS_NONCE_LEN;
/* The (Re)Association Response frame from the Capability Information
* field to the FILS Session element (both inclusive).
*/
addr[4] = capab;
len[4] = encr - capab;
crypt_len = frame + *frame_len - encr;
if (crypt_len < AES_BLOCK_SIZE) {
mlme_dbg(sdata,
"Not enough room for AES-SIV data after FILS Session element in (Re)Association Response frame from %pM",
mgmt->sa);
return -EINVAL;
}
res = aes_siv_decrypt(assoc_data->fils_kek, assoc_data->fils_kek_len,
encr, crypt_len, 5, addr, len, encr);
if (res != 0) {
mlme_dbg(sdata,
"AES-SIV decryption of (Re)Association Response frame from %pM failed",
mgmt->sa);
return res;
}
*frame_len -= AES_BLOCK_SIZE;
return 0;
}

19
net/mac80211/fils_aead.h Normal file
View File

@ -0,0 +1,19 @@
/*
* FILS AEAD for (Re)Association Request/Response frames
* Copyright 2016, Qualcomm Atheros, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef FILS_AEAD_H
#define FILS_AEAD_H
int fils_encrypt_assoc_req(struct sk_buff *skb,
struct ieee80211_mgd_assoc_data *assoc_data);
int fils_decrypt_assoc_resp(struct ieee80211_sub_if_data *sdata,
u8 *frame, size_t *frame_len,
struct ieee80211_mgd_assoc_data *assoc_data);
#endif /* FILS_AEAD_H */

View File

@ -84,6 +84,8 @@ struct ieee80211_local;
#define IEEE80211_DEFAULT_MAX_SP_LEN \ #define IEEE80211_DEFAULT_MAX_SP_LEN \
IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS];
#define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */)
#define IEEE80211_MAX_NAN_INSTANCE_ID 255 #define IEEE80211_MAX_NAN_INSTANCE_ID 255
@ -307,6 +309,7 @@ struct ieee80211_if_vlan {
/* used for all tx if the VLAN is configured to 4-addr mode */ /* used for all tx if the VLAN is configured to 4-addr mode */
struct sta_info __rcu *sta; struct sta_info __rcu *sta;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
}; };
struct mesh_stats { struct mesh_stats {
@ -398,6 +401,10 @@ struct ieee80211_mgd_assoc_data {
struct ieee80211_vht_cap ap_vht_cap; struct ieee80211_vht_cap ap_vht_cap;
u8 fils_nonces[2 * FILS_NONCE_LEN];
u8 fils_kek[FILS_MAX_KEK_LEN];
size_t fils_kek_len;
size_t ie_len; size_t ie_len;
u8 ie[]; u8 ie[];
}; };
@ -442,7 +449,7 @@ struct ieee80211_if_managed {
struct ieee80211_mgd_auth_data *auth_data; struct ieee80211_mgd_auth_data *auth_data;
struct ieee80211_mgd_assoc_data *assoc_data; struct ieee80211_mgd_assoc_data *assoc_data;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN] __aligned(2);
u16 aid; u16 aid;
@ -1527,6 +1534,23 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
return false; return false;
} }
void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata);
void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata);
/* This function returns the number of multicast stations connected to this
* interface. It returns -1 if that number is not tracked, that is for netdevs
* not in AP or AP_VLAN mode or when using 4addr.
*/
static inline int
ieee80211_vif_get_num_mcast_if(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP)
return atomic_read(&sdata->u.ap.num_mcast_sta);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
return atomic_read(&sdata->u.vlan.num_mcast_sta);
return -1;
}
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local, u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
struct ieee80211_rx_status *status, struct ieee80211_rx_status *status,
unsigned int mpdu_len, unsigned int mpdu_len,

View File

@ -1998,3 +1998,19 @@ void ieee80211_iface_exit(void)
{ {
unregister_netdevice_notifier(&mac80211_netdev_notifier); unregister_netdevice_notifier(&mac80211_netdev_notifier);
} }
void ieee80211_vif_inc_num_mcast(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP)
atomic_inc(&sdata->u.ap.num_mcast_sta);
else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
atomic_inc(&sdata->u.vlan.num_mcast_sta);
}
void ieee80211_vif_dec_num_mcast(struct ieee80211_sub_if_data *sdata)
{
if (sdata->vif.type == NL80211_IFTYPE_AP)
atomic_dec(&sdata->u.ap.num_mcast_sta);
else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
atomic_dec(&sdata->u.vlan.num_mcast_sta);
}

View File

@ -549,6 +549,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
NL80211_FEATURE_MAC_ON_CREATE | NL80211_FEATURE_MAC_ON_CREATE |
NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_USERSPACE_MPM |
NL80211_FEATURE_FULL_AP_CLIENT_STATE; NL80211_FEATURE_FULL_AP_CLIENT_STATE;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA);
if (!ops->hw_scan) if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN | wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@ -821,6 +822,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
!local->ops->tdls_recv_channel_switch)) !local->ops->tdls_recv_channel_switch))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (WARN_ON(ieee80211_hw_check(hw, SUPPORTS_TX_FRAG) &&
!local->ops->set_frag_threshold))
return -EINVAL;
if (WARN_ON(local->hw.wiphy->interface_modes & if (WARN_ON(local->hw.wiphy->interface_modes &
BIT(NL80211_IFTYPE_NAN) && BIT(NL80211_IFTYPE_NAN) &&
(!local->ops->start_nan || !local->ops->stop_nan))) (!local->ops->start_nan || !local->ops->stop_nan)))

View File

@ -30,6 +30,7 @@
#include "driver-ops.h" #include "driver-ops.h"
#include "rate.h" #include "rate.h"
#include "led.h" #include "led.h"
#include "fils_aead.h"
#define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2) #define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2)
@ -652,6 +653,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
2 + sizeof(struct ieee80211_ht_cap) + /* HT */ 2 + sizeof(struct ieee80211_ht_cap) + /* HT */
2 + sizeof(struct ieee80211_vht_cap) + /* VHT */ 2 + sizeof(struct ieee80211_vht_cap) + /* VHT */
assoc_data->ie_len + /* extra IEs */ assoc_data->ie_len + /* extra IEs */
(assoc_data->fils_kek_len ? 16 /* AES-SIV */ : 0) +
9, /* WMM */ 9, /* WMM */
GFP_KERNEL); GFP_KERNEL);
if (!skb) if (!skb)
@ -875,6 +877,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
memcpy(pos, assoc_data->ie + offset, noffset - offset); memcpy(pos, assoc_data->ie + offset, noffset - offset);
} }
if (assoc_data->fils_kek_len &&
fils_encrypt_assoc_req(skb, assoc_data) < 0) {
dev_kfree_skb(skb);
return;
}
drv_mgd_prepare_tx(local, sdata); drv_mgd_prepare_tx(local, sdata);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
@ -2618,6 +2626,9 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
case WLAN_AUTH_LEAP: case WLAN_AUTH_LEAP:
case WLAN_AUTH_FT: case WLAN_AUTH_FT:
case WLAN_AUTH_SAE: case WLAN_AUTH_SAE:
case WLAN_AUTH_FILS_SK:
case WLAN_AUTH_FILS_SK_PFS:
case WLAN_AUTH_FILS_PK:
break; break;
case WLAN_AUTH_SHARED_KEY: case WLAN_AUTH_SHARED_KEY:
if (ifmgd->auth_data->expected_transaction != 4) { if (ifmgd->auth_data->expected_transaction != 4) {
@ -3143,6 +3154,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
reassoc ? "Rea" : "A", mgmt->sa, reassoc ? "Rea" : "A", mgmt->sa,
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
if (assoc_data->fils_kek_len &&
fils_decrypt_assoc_resp(sdata, (u8 *)mgmt, &len, assoc_data) < 0)
return;
pos = mgmt->u.assoc_resp.variable; pos = mgmt->u.assoc_resp.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems); ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
@ -3193,7 +3208,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
uapsd_queues = 0; uapsd_queues = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
if (sdata->tx_conf[ac].uapsd) if (sdata->tx_conf[ac].uapsd)
uapsd_queues |= BIT(ac); uapsd_queues |= ieee80211_ac_to_qos_mask[ac];
} }
cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues); cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues);
@ -4479,24 +4494,36 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
case NL80211_AUTHTYPE_SAE: case NL80211_AUTHTYPE_SAE:
auth_alg = WLAN_AUTH_SAE; auth_alg = WLAN_AUTH_SAE;
break; break;
case NL80211_AUTHTYPE_FILS_SK:
auth_alg = WLAN_AUTH_FILS_SK;
break;
case NL80211_AUTHTYPE_FILS_SK_PFS:
auth_alg = WLAN_AUTH_FILS_SK_PFS;
break;
case NL80211_AUTHTYPE_FILS_PK:
auth_alg = WLAN_AUTH_FILS_PK;
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len + auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
req->ie_len, GFP_KERNEL); req->ie_len, GFP_KERNEL);
if (!auth_data) if (!auth_data)
return -ENOMEM; return -ENOMEM;
auth_data->bss = req->bss; auth_data->bss = req->bss;
if (req->sae_data_len >= 4) { if (req->auth_data_len >= 4) {
__le16 *pos = (__le16 *) req->sae_data; if (req->auth_type == NL80211_AUTHTYPE_SAE) {
auth_data->sae_trans = le16_to_cpu(pos[0]); __le16 *pos = (__le16 *) req->auth_data;
auth_data->sae_status = le16_to_cpu(pos[1]);
memcpy(auth_data->data, req->sae_data + 4, auth_data->sae_trans = le16_to_cpu(pos[0]);
req->sae_data_len - 4); auth_data->sae_status = le16_to_cpu(pos[1]);
auth_data->data_len += req->sae_data_len - 4; }
memcpy(auth_data->data, req->auth_data + 4,
req->auth_data_len - 4);
auth_data->data_len += req->auth_data_len - 4;
} }
if (req->ie && req->ie_len) { if (req->ie && req->ie_len) {
@ -4692,6 +4719,21 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
assoc_data->ie_len = req->ie_len; assoc_data->ie_len = req->ie_len;
} }
if (req->fils_kek) {
/* should already be checked in cfg80211 - so warn */
if (WARN_ON(req->fils_kek_len > FILS_MAX_KEK_LEN)) {
err = -EINVAL;
goto err_free;
}
memcpy(assoc_data->fils_kek, req->fils_kek,
req->fils_kek_len);
assoc_data->fils_kek_len = req->fils_kek_len;
}
if (req->fils_nonces)
memcpy(assoc_data->fils_nonces, req->fils_nonces,
2 * FILS_NONCE_LEN);
assoc_data->bss = req->bss; assoc_data->bss = req->bss;
if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) {

View File

@ -1394,13 +1394,15 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
u8 ac = ieee802_1d_to_ac[tid & 7]; u8 ac = ieee802_1d_to_ac[tid & 7];
/* /*
* If this AC is not trigger-enabled do nothing. * If this AC is not trigger-enabled do nothing unless the
* driver is calling us after it already checked.
* *
* NB: This could/should check a separate bitmap of trigger- * NB: This could/should check a separate bitmap of trigger-
* enabled queues, but for now we only implement uAPSD w/o * enabled queues, but for now we only implement uAPSD w/o
* TSPEC changes to the ACs, so they're always the same. * TSPEC changes to the ACs, so they're always the same.
*/ */
if (!(sta->sta.uapsd_queues & BIT(ac))) if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) &&
tid != IEEE80211_NUM_TIDS)
return; return;
/* if we are in a service period, do nothing */ /* if we are in a service period, do nothing */
@ -2215,7 +2217,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
!(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) { (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
if (is_multicast_ether_addr(ehdr->h_dest)) { if (is_multicast_ether_addr(ehdr->h_dest) &&
ieee80211_vif_get_num_mcast_if(sdata) != 0) {
/* /*
* send multicast frames both to higher layers in * send multicast frames both to higher layers in
* local net stack and back to the wireless medium * local net stack and back to the wireless medium
@ -2224,7 +2227,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
if (!xmit_skb) if (!xmit_skb)
net_info_ratelimited("%s: failed to clone multicast frame\n", net_info_ratelimited("%s: failed to clone multicast frame\n",
dev->name); dev->name);
} else { } else if (!is_multicast_ether_addr(ehdr->h_dest)) {
dsta = sta_info_get(sdata, skb->data); dsta = sta_info_get(sdata, skb->data);
if (dsta) { if (dsta) {
/* /*

View File

@ -709,7 +709,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
unsigned long tids; unsigned long tids;
if (ignore_for_tim & BIT(ac)) if (ignore_for_tim & ieee80211_ac_to_qos_mask[ac])
continue; continue;
indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) || indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) ||
@ -1389,7 +1389,7 @@ ieee80211_sta_ps_more_data(struct sta_info *sta, u8 ignored_acs,
return true; return true;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
if (ignored_acs & BIT(ac)) if (ignored_acs & ieee80211_ac_to_qos_mask[ac])
continue; continue;
if (!skb_queue_empty(&sta->tx_filtered[ac]) || if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
@ -1414,7 +1414,7 @@ ieee80211_sta_ps_get_frames(struct sta_info *sta, int n_frames, u8 ignored_acs,
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
unsigned long tids; unsigned long tids;
if (ignored_acs & BIT(ac)) if (ignored_acs & ieee80211_ac_to_qos_mask[ac])
continue; continue;
tids = ieee80211_tids_for_ac(ac); tids = ieee80211_tids_for_ac(ac);
@ -1482,7 +1482,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
BIT(find_highest_prio_tid(driver_release_tids)); BIT(find_highest_prio_tid(driver_release_tids));
if (skb_queue_empty(&frames) && !driver_release_tids) { if (skb_queue_empty(&frames) && !driver_release_tids) {
int tid; int tid, ac;
/* /*
* For PS-Poll, this can only happen due to a race condition * For PS-Poll, this can only happen due to a race condition
@ -1500,7 +1500,10 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
*/ */
/* This will evaluate to 1, 3, 5 or 7. */ /* This will evaluate to 1, 3, 5 or 7. */
tid = 7 - ((ffs(~ignored_acs) - 1) << 1); for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++)
if (ignored_acs & BIT(ac))
continue;
tid = 7 - 2 * ac;
ieee80211_send_null_response(sta, tid, reason, true, false); ieee80211_send_null_response(sta, tid, reason, true, false);
} else if (!driver_release_tids) { } else if (!driver_release_tids) {
@ -1871,10 +1874,7 @@ int sta_info_move_state(struct sta_info *sta,
if (!sta->sta.support_p2p_ps) if (!sta->sta.support_p2p_ps)
ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP || ieee80211_vif_dec_num_mcast(sta->sdata);
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
!sta->sdata->u.vlan.sta))
atomic_dec(&sta->sdata->bss->num_mcast_sta);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_clear_fast_xmit(sta); ieee80211_clear_fast_xmit(sta);
ieee80211_clear_fast_rx(sta); ieee80211_clear_fast_rx(sta);
@ -1882,10 +1882,7 @@ int sta_info_move_state(struct sta_info *sta,
break; break;
case IEEE80211_STA_AUTHORIZED: case IEEE80211_STA_AUTHORIZED:
if (sta->sta_state == IEEE80211_STA_ASSOC) { if (sta->sta_state == IEEE80211_STA_ASSOC) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP || ieee80211_vif_inc_num_mcast(sta->sdata);
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
!sta->sdata->u.vlan.sta))
atomic_inc(&sta->sdata->bss->num_mcast_sta);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta); ieee80211_check_fast_xmit(sta);
ieee80211_check_fast_rx(sta); ieee80211_check_fast_rx(sta);

View File

@ -184,7 +184,6 @@ struct tid_ampdu_tx {
* @ssn: Starting Sequence Number expected to be aggregated. * @ssn: Starting Sequence Number expected to be aggregated.
* @buf_size: buffer size for incoming A-MPDUs * @buf_size: buffer size for incoming A-MPDUs
* @timeout: reset timer value (in TUs). * @timeout: reset timer value (in TUs).
* @dialog_token: dialog token for aggregation session
* @rcu_head: RCU head used for freeing this struct * @rcu_head: RCU head used for freeing this struct
* @reorder_lock: serializes access to reorder buffer, see below. * @reorder_lock: serializes access to reorder buffer, see below.
* @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
@ -213,7 +212,6 @@ struct tid_ampdu_rx {
u16 ssn; u16 ssn;
u16 buf_size; u16 buf_size;
u16 timeout; u16 timeout;
u8 dialog_token;
bool auto_seq; bool auto_seq;
bool removed; bool removed;
}; };
@ -225,6 +223,7 @@ struct tid_ampdu_rx {
* to tid_tx[idx], which are protected by the sta spinlock) * to tid_tx[idx], which are protected by the sta spinlock)
* tid_start_tx is also protected by sta->lock. * tid_start_tx is also protected by sta->lock.
* @tid_rx: aggregation info for Rx per TID -- RCU protected * @tid_rx: aggregation info for Rx per TID -- RCU protected
* @tid_rx_token: dialog tokens for valid aggregation sessions
* @tid_rx_timer_expired: bitmap indicating on which TIDs the * @tid_rx_timer_expired: bitmap indicating on which TIDs the
* RX timer expired until the work for it runs * RX timer expired until the work for it runs
* @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the
@ -243,6 +242,7 @@ struct sta_ampdu_mlme {
struct mutex mtx; struct mutex mtx;
/* rx */ /* rx */
struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
u8 tid_rx_token[IEEE80211_NUM_TIDS];
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];

View File

@ -331,9 +331,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
return TX_DROP; return TX_DROP;
} }
} else if (unlikely(tx->sdata->vif.type == NL80211_IFTYPE_AP && } else if (unlikely(ieee80211_is_data(hdr->frame_control) &&
ieee80211_is_data(hdr->frame_control) && ieee80211_vif_get_num_mcast_if(tx->sdata) == 0)) {
!atomic_read(&tx->sdata->u.ap.num_mcast_sta))) {
/* /*
* No associated STAs - no need to send multicast * No associated STAs - no need to send multicast
* frames. * frames.
@ -935,7 +934,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
if (info->flags & IEEE80211_TX_CTL_DONTFRAG) if (info->flags & IEEE80211_TX_CTL_DONTFRAG)
return TX_CONTINUE; return TX_CONTINUE;
if (tx->local->ops->set_frag_threshold) if (ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG))
return TX_CONTINUE; return TX_CONTINUE;
/* /*
@ -2801,7 +2800,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
/* fast-xmit doesn't handle fragmentation at all */ /* fast-xmit doesn't handle fragmentation at all */
if (local->hw.wiphy->frag_threshold != (u32)-1 && if (local->hw.wiphy->frag_threshold != (u32)-1 &&
!local->ops->set_frag_threshold) !ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG))
goto out; goto out;
rcu_read_lock(); rcu_read_lock();
@ -3060,11 +3059,12 @@ static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ethhdr amsdu_hdr; struct ethhdr *amsdu_hdr;
int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header); int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header);
int subframe_len = skb->len - hdr_len; int subframe_len = skb->len - hdr_len;
void *data; void *data;
u8 *qc; u8 *qc, *h_80211_src, *h_80211_dst;
const u8 *bssid;
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
return false; return false;
@ -3072,19 +3072,44 @@ static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata,
if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) if (info->control.flags & IEEE80211_TX_CTRL_AMSDU)
return true; return true;
if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr), if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(*amsdu_hdr),
&subframe_len)) &subframe_len))
return false; return false;
amsdu_hdr.h_proto = cpu_to_be16(subframe_len); data = skb_push(skb, sizeof(*amsdu_hdr));
memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN); memmove(data, data + sizeof(*amsdu_hdr), hdr_len);
memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN);
data = skb_push(skb, sizeof(amsdu_hdr));
memmove(data, data + sizeof(amsdu_hdr), hdr_len);
memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr));
hdr = data; hdr = data;
amsdu_hdr = data + hdr_len;
/* h_80211_src/dst is addr* field within hdr */
h_80211_src = data + fast_tx->sa_offs;
h_80211_dst = data + fast_tx->da_offs;
amsdu_hdr->h_proto = cpu_to_be16(subframe_len);
ether_addr_copy(amsdu_hdr->h_source, h_80211_src);
ether_addr_copy(amsdu_hdr->h_dest, h_80211_dst);
/* according to IEEE 802.11-2012 8.3.2 table 8-19, the outer SA/DA
* fields needs to be changed to BSSID for A-MSDU frames depending
* on FromDS/ToDS values.
*/
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
bssid = sdata->u.mgd.bssid;
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
bssid = sdata->vif.addr;
break;
default:
bssid = NULL;
}
if (bssid && ieee80211_has_fromds(hdr->frame_control))
ether_addr_copy(h_80211_src, bssid);
if (bssid && ieee80211_has_tods(hdr->frame_control))
ether_addr_copy(h_80211_dst, bssid);
qc = ieee80211_get_qos_ctl(hdr); qc = ieee80211_get_qos_ctl(hdr);
*qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;

View File

@ -3308,10 +3308,11 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *sdata_iter; struct ieee80211_sub_if_data *sdata_iter;
enum nl80211_iftype iftype = sdata->wdev.iftype; enum nl80211_iftype iftype = sdata->wdev.iftype;
int num[NUM_NL80211_IFTYPES];
struct ieee80211_chanctx *ctx; struct ieee80211_chanctx *ctx;
int num_different_channels = 0;
int total = 1; int total = 1;
struct iface_combination_params params = {
.radar_detect = radar_detect,
};
lockdep_assert_held(&local->chanctx_mtx); lockdep_assert_held(&local->chanctx_mtx);
@ -3322,12 +3323,19 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
!chandef->chan)) !chandef->chan))
return -EINVAL; return -EINVAL;
if (chandef)
num_different_channels = 1;
if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
return -EINVAL; return -EINVAL;
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_MESH_POINT) {
/*
* always passing this is harmless, since it'll be the
* same value that cfg80211 finds if it finds the same
* interface ... and that's always allowed
*/
params.new_beacon_int = sdata->vif.bss_conf.beacon_int;
}
/* Always allow software iftypes */ /* Always allow software iftypes */
if (local->hw.wiphy->software_iftypes & BIT(iftype)) { if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
if (radar_detect) if (radar_detect)
@ -3335,24 +3343,26 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
return 0; return 0;
} }
memset(num, 0, sizeof(num)); if (chandef)
params.num_different_channels = 1;
if (iftype != NL80211_IFTYPE_UNSPECIFIED) if (iftype != NL80211_IFTYPE_UNSPECIFIED)
num[iftype] = 1; params.iftype_num[iftype] = 1;
list_for_each_entry(ctx, &local->chanctx_list, list) { list_for_each_entry(ctx, &local->chanctx_list, list) {
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue; continue;
radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); params.radar_detect |=
ieee80211_chanctx_radar_detect(local, ctx);
if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) { if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) {
num_different_channels++; params.num_different_channels++;
continue; continue;
} }
if (chandef && chanmode == IEEE80211_CHANCTX_SHARED && if (chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
cfg80211_chandef_compatible(chandef, cfg80211_chandef_compatible(chandef,
&ctx->conf.def)) &ctx->conf.def))
continue; continue;
num_different_channels++; params.num_different_channels++;
} }
list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) { list_for_each_entry_rcu(sdata_iter, &local->interfaces, list) {
@ -3365,16 +3375,14 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype)) local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
continue; continue;
num[wdev_iter->iftype]++; params.iftype_num[wdev_iter->iftype]++;
total++; total++;
} }
if (total == 1 && !radar_detect) if (total == 1 && !params.radar_detect)
return 0; return 0;
return cfg80211_check_combinations(local->hw.wiphy, return cfg80211_check_combinations(local->hw.wiphy, &params);
num_different_channels,
radar_detect, num);
} }
static void static void
@ -3390,12 +3398,10 @@ ieee80211_iter_max_chans(const struct ieee80211_iface_combination *c,
int ieee80211_max_num_channels(struct ieee80211_local *local) int ieee80211_max_num_channels(struct ieee80211_local *local)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int num[NUM_NL80211_IFTYPES] = {};
struct ieee80211_chanctx *ctx; struct ieee80211_chanctx *ctx;
int num_different_channels = 0;
u8 radar_detect = 0;
u32 max_num_different_channels = 1; u32 max_num_different_channels = 1;
int err; int err;
struct iface_combination_params params = {0};
lockdep_assert_held(&local->chanctx_mtx); lockdep_assert_held(&local->chanctx_mtx);
@ -3403,17 +3409,17 @@ int ieee80211_max_num_channels(struct ieee80211_local *local)
if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED) if (ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED)
continue; continue;
num_different_channels++; params.num_different_channels++;
radar_detect |= ieee80211_chanctx_radar_detect(local, ctx); params.radar_detect |=
ieee80211_chanctx_radar_detect(local, ctx);
} }
list_for_each_entry_rcu(sdata, &local->interfaces, list) list_for_each_entry_rcu(sdata, &local->interfaces, list)
num[sdata->wdev.iftype]++; params.iftype_num[sdata->wdev.iftype]++;
err = cfg80211_iter_combinations(local->hw.wiphy, err = cfg80211_iter_combinations(local->hw.wiphy, &params,
num_different_channels, radar_detect, ieee80211_iter_max_chans,
num, ieee80211_iter_max_chans,
&max_num_different_channels); &max_num_different_channels);
if (err < 0) if (err < 0)
return err; return err;
@ -3456,3 +3462,10 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
*byte_cnt = txqi->tin.backlog_bytes + frag_bytes; *byte_cnt = txqi->tin.backlog_bytes + frag_bytes;
} }
EXPORT_SYMBOL(ieee80211_txq_get_depth); EXPORT_SYMBOL(ieee80211_txq_get_depth);
const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS] = {
IEEE80211_WMM_IE_STA_QOSINFO_AC_VO,
IEEE80211_WMM_IE_STA_QOSINFO_AC_VI,
IEEE80211_WMM_IE_STA_QOSINFO_AC_BE,
IEEE80211_WMM_IE_STA_QOSINFO_AC_BK
};

View File

@ -236,26 +236,35 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
{ {
struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_hdr *hdr = (void *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
u8 flags;
u8 *p; u8 *p;
u8 ack_policy, tid;
if (!ieee80211_is_data_qos(hdr->frame_control)) if (!ieee80211_is_data_qos(hdr->frame_control))
return; return;
p = ieee80211_get_qos_ctl(hdr); p = ieee80211_get_qos_ctl(hdr);
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
/* preserve EOSP bit */ /* set up the first byte */
ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
/*
* preserve everything but the TID and ACK policy
* (which we both write here)
*/
flags = *p & ~(IEEE80211_QOS_CTL_TID_MASK |
IEEE80211_QOS_CTL_ACK_POLICY_MASK);
if (is_multicast_ether_addr(hdr->addr1) || if (is_multicast_ether_addr(hdr->addr1) ||
sdata->noack_map & BIT(tid)) { sdata->noack_map & BIT(tid)) {
ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK; flags |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
info->flags |= IEEE80211_TX_CTL_NO_ACK; info->flags |= IEEE80211_TX_CTL_NO_ACK;
} }
/* qos header is 2 bytes */ *p = flags | tid;
*p++ = ack_policy | tid;
/* set up the second byte */
p++;
if (ieee80211_vif_is_mesh(&sdata->vif)) { if (ieee80211_vif_is_mesh(&sdata->vif)) {
/* preserve RSPI and Mesh PS Level bit */ /* preserve RSPI and Mesh PS Level bit */
*p &= ((IEEE80211_QOS_CTL_RSPI | *p &= ((IEEE80211_QOS_CTL_RSPI |

View File

@ -57,7 +57,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
if (info->control.hw_key && if (info->control.hw_key &&
(info->flags & IEEE80211_TX_CTL_DONTFRAG || (info->flags & IEEE80211_TX_CTL_DONTFRAG ||
tx->local->ops->set_frag_threshold) && ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG)) &&
!(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
/* hwaccel - with no need for SW-generated MMIC */ /* hwaccel - with no need for SW-generated MMIC */
return TX_CONTINUE; return TX_CONTINUE;

View File

@ -210,11 +210,11 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
return; return;
if (!wdev->p2p_started) if (!wdev_running(wdev))
return; return;
rdev_stop_p2p_device(rdev, wdev); rdev_stop_p2p_device(rdev, wdev);
wdev->p2p_started = false; wdev->is_running = false;
rdev->opencount--; rdev->opencount--;
@ -233,11 +233,11 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN)) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
return; return;
if (!wdev->nan_started) if (!wdev_running(wdev))
return; return;
rdev_stop_nan(rdev, wdev); rdev_stop_nan(rdev, wdev);
wdev->nan_started = false; wdev->is_running = false;
rdev->opencount--; rdev->opencount--;
} }
@ -562,6 +562,21 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
c->limits[j].max > 1)) c->limits[j].max > 1))
return -EINVAL; return -EINVAL;
/*
* This isn't well-defined right now. If you have an
* IBSS interface, then its beacon interval may change
* by joining other networks, and nothing prevents it
* from doing that.
* So technically we probably shouldn't even allow AP
* and IBSS in the same interface, but it seems that
* some drivers support that, possibly only with fixed
* beacon intervals for IBSS.
*/
if (WARN_ON(types & BIT(NL80211_IFTYPE_ADHOC) &&
c->beacon_int_min_gcd)) {
return -EINVAL;
}
cnt += c->limits[j].max; cnt += c->limits[j].max;
/* /*
* Don't advertise an unsupported type * Don't advertise an unsupported type
@ -571,6 +586,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
return -EINVAL; return -EINVAL;
} }
#ifndef CONFIG_WIRELESS_WDS
if (WARN_ON(all_iftypes & BIT(NL80211_IFTYPE_WDS)))
return -EINVAL;
#endif
/* You can't even choose that many! */ /* You can't even choose that many! */
if (WARN_ON(cnt < c->max_interfaces)) if (WARN_ON(cnt < c->max_interfaces))
return -EINVAL; return -EINVAL;
@ -609,6 +629,11 @@ int wiphy_register(struct wiphy *wiphy)
!rdev->ops->add_nan_func || !rdev->ops->del_nan_func))) !rdev->ops->add_nan_func || !rdev->ops->del_nan_func)))
return -EINVAL; return -EINVAL;
#ifndef CONFIG_WIRELESS_WDS
if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)))
return -EINVAL;
#endif
/* /*
* if a wiphy has unsupported modes for regulatory channel enforcement, * if a wiphy has unsupported modes for regulatory channel enforcement,
* opt-out of enforcement checking * opt-out of enforcement checking

View File

@ -345,7 +345,7 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len, const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len, const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx, const u8 *key, int key_len, int key_idx,
const u8 *sae_data, int sae_data_len); const u8 *auth_data, int auth_data_len);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct net_device *dev,
struct ieee80211_channel *chan, struct ieee80211_channel *chan,
@ -475,7 +475,7 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
u32 *mask); u32 *mask);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int); enum nl80211_iftype iftype, u32 beacon_int);
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num); enum nl80211_iftype iftype, int num);

View File

@ -183,6 +183,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
wdev->mesh_id_len = setup->mesh_id_len; wdev->mesh_id_len = setup->mesh_id_len;
wdev->chandef = setup->chandef; wdev->chandef = setup->chandef;
wdev->beacon_interval = setup->beacon_interval;
} }
return err; return err;
@ -258,6 +259,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
err = rdev_leave_mesh(rdev, dev); err = rdev_leave_mesh(rdev, dev);
if (!err) { if (!err) {
wdev->mesh_id_len = 0; wdev->mesh_id_len = 0;
wdev->beacon_interval = 0;
memset(&wdev->chandef, 0, sizeof(wdev->chandef)); memset(&wdev->chandef, 0, sizeof(wdev->chandef));
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
} }

View File

@ -204,14 +204,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len, const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len, const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx, const u8 *key, int key_len, int key_idx,
const u8 *sae_data, int sae_data_len) const u8 *auth_data, int auth_data_len)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req = { struct cfg80211_auth_request req = {
.ie = ie, .ie = ie,
.ie_len = ie_len, .ie_len = ie_len,
.sae_data = sae_data, .auth_data = auth_data,
.sae_data_len = sae_data_len, .auth_data_len = auth_data_len,
.auth_type = auth_type, .auth_type = auth_type,
.key = key, .key = key,
.key_len = key_len, .key_len = key_len,

View File

@ -343,7 +343,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 }, [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
[NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, }, [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN }, [NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 }, [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 }, [NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
@ -400,6 +400,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 }, [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
[NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 }, [NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED }, [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
[NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
.len = FILS_MAX_KEK_LEN },
[NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
}; };
/* policy for the key attributes */ /* policy for the key attributes */
@ -421,6 +425,7 @@ nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
[NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
}; };
#ifdef CONFIG_PM
/* policy for WoWLAN attributes */ /* policy for WoWLAN attributes */
static const struct nla_policy static const struct nla_policy
nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
@ -454,6 +459,7 @@ nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 }, [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 },
[NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 },
}; };
#endif /* CONFIG_PM */
/* policy for coalesce rule attributes */ /* policy for coalesce rule attributes */
static const struct nla_policy static const struct nla_policy
@ -1062,6 +1068,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
c->radar_detect_regions))) c->radar_detect_regions)))
goto nla_put_failure; goto nla_put_failure;
if (c->beacon_int_min_gcd &&
nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
c->beacon_int_min_gcd))
goto nla_put_failure;
nla_nest_end(msg, nl_combi); nla_nest_end(msg, nl_combi);
} }
@ -1309,6 +1319,95 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg,
return 0; return 0;
} }
#define CMD(op, n) \
do { \
if (rdev->ops->op) { \
i++; \
if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
goto nla_put_failure; \
} \
} while (0)
static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
struct sk_buff *msg)
{
int i = 0;
/*
* do *NOT* add anything into this function, new things need to be
* advertised only to new versions of userspace that can deal with
* the split (and they can't possibly care about new features...
*/
CMD(add_virtual_intf, NEW_INTERFACE);
CMD(change_virtual_intf, SET_INTERFACE);
CMD(add_key, NEW_KEY);
CMD(start_ap, START_AP);
CMD(add_station, NEW_STATION);
CMD(add_mpath, NEW_MPATH);
CMD(update_mesh_config, SET_MESH_CONFIG);
CMD(change_bss, SET_BSS);
CMD(auth, AUTHENTICATE);
CMD(assoc, ASSOCIATE);
CMD(deauth, DEAUTHENTICATE);
CMD(disassoc, DISASSOCIATE);
CMD(join_ibss, JOIN_IBSS);
CMD(join_mesh, JOIN_MESH);
CMD(set_pmksa, SET_PMKSA);
CMD(del_pmksa, DEL_PMKSA);
CMD(flush_pmksa, FLUSH_PMKSA);
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
CMD(mgmt_tx, FRAME);
CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
rdev->ops->join_mesh) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
goto nla_put_failure;
}
CMD(set_wds_peer, SET_WDS_PEER);
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
CMD(tdls_oper, TDLS_OPER);
}
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
CMD(sched_scan_start, START_SCHED_SCAN);
CMD(probe_client, PROBE_CLIENT);
CMD(set_noack_map, SET_NOACK_MAP);
if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
goto nla_put_failure;
}
CMD(start_p2p_device, START_P2P_DEVICE);
CMD(set_mcast_rate, SET_MCAST_RATE);
#ifdef CONFIG_NL80211_TESTMODE
CMD(testmode_cmd, TESTMODE);
#endif
if (rdev->ops->connect || rdev->ops->auth) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
goto nla_put_failure;
}
if (rdev->ops->disconnect || rdev->ops->deauth) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
goto nla_put_failure;
}
return i;
nla_put_failure:
return -ENOBUFS;
}
struct nl80211_dump_wiphy_state { struct nl80211_dump_wiphy_state {
s64 filter_wiphy; s64 filter_wiphy;
long start; long start;
@ -1536,68 +1635,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (!nl_cmds) if (!nl_cmds)
goto nla_put_failure; goto nla_put_failure;
i = 0; i = nl80211_add_commands_unsplit(rdev, msg);
#define CMD(op, n) \ if (i < 0)
do { \ goto nla_put_failure;
if (rdev->ops->op) { \
i++; \
if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
goto nla_put_failure; \
} \
} while (0)
CMD(add_virtual_intf, NEW_INTERFACE);
CMD(change_virtual_intf, SET_INTERFACE);
CMD(add_key, NEW_KEY);
CMD(start_ap, START_AP);
CMD(add_station, NEW_STATION);
CMD(add_mpath, NEW_MPATH);
CMD(update_mesh_config, SET_MESH_CONFIG);
CMD(change_bss, SET_BSS);
CMD(auth, AUTHENTICATE);
CMD(assoc, ASSOCIATE);
CMD(deauth, DEAUTHENTICATE);
CMD(disassoc, DISASSOCIATE);
CMD(join_ibss, JOIN_IBSS);
CMD(join_mesh, JOIN_MESH);
CMD(set_pmksa, SET_PMKSA);
CMD(del_pmksa, DEL_PMKSA);
CMD(flush_pmksa, FLUSH_PMKSA);
if (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
CMD(remain_on_channel, REMAIN_ON_CHANNEL);
CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
CMD(mgmt_tx, FRAME);
CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
if (rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
if (rdev->ops->set_monitor_channel || rdev->ops->start_ap ||
rdev->ops->join_mesh) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
goto nla_put_failure;
}
CMD(set_wds_peer, SET_WDS_PEER);
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
CMD(tdls_oper, TDLS_OPER);
}
if (rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
CMD(sched_scan_start, START_SCHED_SCAN);
CMD(probe_client, PROBE_CLIENT);
CMD(set_noack_map, SET_NOACK_MAP);
if (rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
goto nla_put_failure;
}
CMD(start_p2p_device, START_P2P_DEVICE);
CMD(set_mcast_rate, SET_MCAST_RATE);
#ifdef CONFIG_NL80211_TESTMODE
CMD(testmode_cmd, TESTMODE);
#endif
if (state->split) { if (state->split) {
CMD(crit_proto_start, CRIT_PROTOCOL_START); CMD(crit_proto_start, CRIT_PROTOCOL_START);
CMD(crit_proto_stop, CRIT_PROTOCOL_STOP); CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
@ -1607,22 +1647,11 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.features & if (rdev->wiphy.features &
NL80211_FEATURE_SUPPORTS_WMM_ADMISSION) NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
CMD(add_tx_ts, ADD_TX_TS); CMD(add_tx_ts, ADD_TX_TS);
CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST);
CMD(update_connect_params, UPDATE_CONNECT_PARAMS);
} }
/* add into the if now */
#undef CMD #undef CMD
if (rdev->ops->connect || rdev->ops->auth) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
goto nla_put_failure;
}
if (rdev->ops->disconnect || rdev->ops->deauth) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
goto nla_put_failure;
}
nla_nest_end(msg, nl_cmds); nla_nest_end(msg, nl_cmds);
state->split_start++; state->split_start++;
if (state->split) if (state->split)
@ -2283,10 +2312,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(nl_txq_params, nla_for_each_nested(nl_txq_params,
info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
rem_txq_params) { rem_txq_params) {
result = nla_parse(tb, NL80211_TXQ_ATTR_MAX, result = nla_parse_nested(tb, NL80211_TXQ_ATTR_MAX,
nla_data(nl_txq_params), nl_txq_params,
nla_len(nl_txq_params), txq_params_policy);
txq_params_policy);
if (result) if (result)
return result; return result;
result = parse_txq_params(tb, &txq_params); result = parse_txq_params(tb, &txq_params);
@ -3536,8 +3564,8 @@ static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
sband = rdev->wiphy.bands[band]; sband = rdev->wiphy.bands[band];
if (sband == NULL) if (sband == NULL)
return -EINVAL; return -EINVAL;
err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates), err = nla_parse_nested(tb, NL80211_TXRATE_MAX, tx_rates,
nla_len(tx_rates), nl80211_txattr_policy); nl80211_txattr_policy);
if (err) if (err)
return err; return err;
if (tb[NL80211_TXRATE_LEGACY]) { if (tb[NL80211_TXRATE_LEGACY]) {
@ -3743,12 +3771,23 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) && if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
auth_type == NL80211_AUTHTYPE_SAE) auth_type == NL80211_AUTHTYPE_SAE)
return false; return false;
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_FILS_STA) &&
(auth_type == NL80211_AUTHTYPE_FILS_SK ||
auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
auth_type == NL80211_AUTHTYPE_FILS_PK))
return false;
return true; return true;
case NL80211_CMD_CONNECT: case NL80211_CMD_CONNECT:
case NL80211_CMD_START_AP: case NL80211_CMD_START_AP:
/* SAE not supported yet */ /* SAE not supported yet */
if (auth_type == NL80211_AUTHTYPE_SAE) if (auth_type == NL80211_AUTHTYPE_SAE)
return false; return false;
/* FILS not supported yet */
if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
auth_type == NL80211_AUTHTYPE_FILS_PK)
return false;
return true; return true;
default: default:
return false; return false;
@ -3790,7 +3829,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.dtim_period = params.dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
err = cfg80211_validate_beacon_int(rdev, params.beacon_interval); err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
params.beacon_interval);
if (err) if (err)
return err; return err;
@ -6292,9 +6332,8 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES],
rem_reg_rules) { rem_reg_rules) {
r = nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, r = nla_parse_nested(tb, NL80211_REG_RULE_ATTR_MAX,
nla_data(nl_reg_rule), nla_len(nl_reg_rule), nl_reg_rule, reg_rule_policy);
reg_rule_policy);
if (r) if (r)
goto bad_reg; goto bad_reg;
r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]); r = parse_reg_rule(tb, &rd->reg_rules[rule_idx]);
@ -6361,8 +6400,8 @@ static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
if (!nla_ok(nest, nla_len(nest))) if (!nla_ok(nest, nla_len(nest)))
return -EINVAL; return -EINVAL;
err = nla_parse(attr, NL80211_BSS_SELECT_ATTR_MAX, nla_data(nest), err = nla_parse_nested(attr, NL80211_BSS_SELECT_ATTR_MAX, nest,
nla_len(nest), nl80211_bss_select_policy); nl80211_bss_select_policy);
if (err) if (err)
return err; return err;
@ -6752,9 +6791,8 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
if (WARN_ON(i >= n_plans)) if (WARN_ON(i >= n_plans))
return -EINVAL; return -EINVAL;
err = nla_parse(plan, NL80211_SCHED_SCAN_PLAN_MAX, err = nla_parse_nested(plan, NL80211_SCHED_SCAN_PLAN_MAX,
nla_data(attr), nla_len(attr), attr, nl80211_plan_policy);
nl80211_plan_policy);
if (err) if (err)
return err; return err;
@ -6843,9 +6881,9 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
tmp) { tmp) {
struct nlattr *rssi; struct nlattr *rssi;
err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, err = nla_parse_nested(tb,
nla_data(attr), nla_len(attr), NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
nl80211_match_policy); attr, nl80211_match_policy);
if (err) if (err)
return ERR_PTR(err); return ERR_PTR(err);
/* add other standalone attributes here */ /* add other standalone attributes here */
@ -7016,9 +7054,9 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
tmp) { tmp) {
struct nlattr *ssid, *rssi; struct nlattr *ssid, *rssi;
err = nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, err = nla_parse_nested(tb,
nla_data(attr), nla_len(attr), NL80211_SCHED_SCAN_MATCH_ATTR_MAX,
nl80211_match_policy); attr, nl80211_match_policy);
if (err) if (err)
goto out_free; goto out_free;
ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
@ -7696,8 +7734,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL; const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
int err, ssid_len, ie_len = 0, sae_data_len = 0; int err, ssid_len, ie_len = 0, auth_data_len = 0;
enum nl80211_auth_type auth_type; enum nl80211_auth_type auth_type;
struct key_parse key; struct key_parse key;
bool local_state_change; bool local_state_change;
@ -7777,17 +7815,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE)) if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
return -EINVAL; return -EINVAL;
if (auth_type == NL80211_AUTHTYPE_SAE && if ((auth_type == NL80211_AUTHTYPE_SAE ||
!info->attrs[NL80211_ATTR_SAE_DATA]) auth_type == NL80211_AUTHTYPE_FILS_SK ||
auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
auth_type == NL80211_AUTHTYPE_FILS_PK) &&
!info->attrs[NL80211_ATTR_AUTH_DATA])
return -EINVAL; return -EINVAL;
if (info->attrs[NL80211_ATTR_SAE_DATA]) { if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
if (auth_type != NL80211_AUTHTYPE_SAE) if (auth_type != NL80211_AUTHTYPE_SAE &&
auth_type != NL80211_AUTHTYPE_FILS_SK &&
auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
auth_type != NL80211_AUTHTYPE_FILS_PK)
return -EINVAL; return -EINVAL;
sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]); auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]); auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
/* need to include at least Auth Transaction and Status Code */ /* need to include at least Auth Transaction and Status Code */
if (sae_data_len < 4) if (auth_data_len < 4)
return -EINVAL; return -EINVAL;
} }
@ -7804,7 +7848,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len, ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx, key.p.key, key.p.key_len, key.idx,
sae_data, sae_data_len); auth_data, auth_data_len);
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
return err; return err;
} }
@ -7983,6 +8027,15 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
req.flags |= ASSOC_REQ_USE_RRM; req.flags |= ASSOC_REQ_USE_RRM;
} }
if (info->attrs[NL80211_ATTR_FILS_KEK]) {
req.fils_kek = nla_data(info->attrs[NL80211_ATTR_FILS_KEK]);
req.fils_kek_len = nla_len(info->attrs[NL80211_ATTR_FILS_KEK]);
if (!info->attrs[NL80211_ATTR_FILS_NONCES])
return -EINVAL;
req.fils_nonces =
nla_data(info->attrs[NL80211_ATTR_FILS_NONCES]);
}
err = nl80211_crypto_settings(rdev, info, &req.crypto, 1); err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
if (!err) { if (!err) {
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
@ -8140,7 +8193,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.beacon_interval = ibss.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
err = cfg80211_validate_beacon_int(rdev, ibss.beacon_interval); err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
ibss.beacon_interval);
if (err) if (err)
return err; return err;
@ -8713,6 +8767,37 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
return err; return err;
} }
static int nl80211_update_connect_params(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_connect_params connect = {};
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
u32 changed = 0;
int ret;
if (!rdev->ops->update_connect_params)
return -EOPNOTSUPP;
if (info->attrs[NL80211_ATTR_IE]) {
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
changed |= UPDATE_ASSOC_IES;
}
wdev_lock(dev->ieee80211_ptr);
if (!wdev->current_bss)
ret = -ENOLINK;
else
ret = rdev_update_connect_params(rdev, dev, &connect, changed);
wdev_unlock(dev->ieee80211_ptr);
return ret;
}
static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
@ -9404,7 +9489,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
setup.beacon_interval = setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
err = cfg80211_validate_beacon_int(rdev, setup.beacon_interval); err = cfg80211_validate_beacon_int(rdev,
NL80211_IFTYPE_MESH_POINT,
setup.beacon_interval);
if (err) if (err)
return err; return err;
} }
@ -9715,9 +9802,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
if (!rdev->wiphy.wowlan->tcp) if (!rdev->wiphy.wowlan->tcp)
return -EINVAL; return -EINVAL;
err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TCP, attr,
nla_data(attr), nla_len(attr), nl80211_wowlan_tcp_policy);
nl80211_wowlan_tcp_policy);
if (err) if (err)
return err; return err;
@ -9862,9 +9948,7 @@ static int nl80211_parse_wowlan_nd(struct cfg80211_registered_device *rdev,
goto out; goto out;
} }
err = nla_parse(tb, NL80211_ATTR_MAX, err = nla_parse_nested(tb, NL80211_ATTR_MAX, attr, nl80211_policy);
nla_data(attr), nla_len(attr),
nl80211_policy);
if (err) if (err)
goto out; goto out;
@ -9898,10 +9982,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
goto set_wakeup; goto set_wakeup;
} }
err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, err = nla_parse_nested(tb, MAX_NL80211_WOWLAN_TRIG,
nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS],
nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), nl80211_wowlan_policy);
nl80211_wowlan_policy);
if (err) if (err)
return err; return err;
@ -9983,8 +10066,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
rem) { rem) {
u8 *mask_pat; u8 *mask_pat;
nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat,
nla_len(pat), NULL); NULL);
err = -EINVAL; err = -EINVAL;
if (!pat_tb[NL80211_PKTPAT_MASK] || if (!pat_tb[NL80211_PKTPAT_MASK] ||
!pat_tb[NL80211_PKTPAT_PATTERN]) !pat_tb[NL80211_PKTPAT_PATTERN])
@ -10194,8 +10277,8 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
int rem, pat_len, mask_len, pkt_offset, n_patterns = 0; int rem, pat_len, mask_len, pkt_offset, n_patterns = 0;
struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
err = nla_parse(tb, NL80211_ATTR_COALESCE_RULE_MAX, nla_data(rule), err = nla_parse_nested(tb, NL80211_ATTR_COALESCE_RULE_MAX, rule,
nla_len(rule), nl80211_coalesce_policy); nl80211_coalesce_policy);
if (err) if (err)
return err; return err;
@ -10233,8 +10316,7 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev,
rem) { rem) {
u8 *mask_pat; u8 *mask_pat;
nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), nla_parse_nested(pat_tb, MAX_NL80211_PKTPAT, pat, NULL);
nla_len(pat), NULL);
if (!pat_tb[NL80211_PKTPAT_MASK] || if (!pat_tb[NL80211_PKTPAT_MASK] ||
!pat_tb[NL80211_PKTPAT_PATTERN]) !pat_tb[NL80211_PKTPAT_PATTERN])
return -EINVAL; return -EINVAL;
@ -10353,10 +10435,9 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
if (!info->attrs[NL80211_ATTR_REKEY_DATA]) if (!info->attrs[NL80211_ATTR_REKEY_DATA])
return -EINVAL; return -EINVAL;
err = nla_parse(tb, MAX_NL80211_REKEY_DATA, err = nla_parse_nested(tb, MAX_NL80211_REKEY_DATA,
nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]), info->attrs[NL80211_ATTR_REKEY_DATA],
nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]), nl80211_rekey_policy);
nl80211_rekey_policy);
if (err) if (err)
return err; return err;
@ -10505,7 +10586,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE) if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (wdev->p2p_started) if (wdev_running(wdev))
return 0; return 0;
if (rfkill_blocked(rdev->rfkill)) if (rfkill_blocked(rdev->rfkill))
@ -10515,7 +10596,7 @@ static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
return err; return err;
wdev->p2p_started = true; wdev->is_running = true;
rdev->opencount++; rdev->opencount++;
return 0; return 0;
@ -10547,7 +10628,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
if (wdev->iftype != NL80211_IFTYPE_NAN) if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (wdev->nan_started) if (!wdev_running(wdev))
return -EEXIST; return -EEXIST;
if (rfkill_blocked(rdev->rfkill)) if (rfkill_blocked(rdev->rfkill))
@ -10570,7 +10651,7 @@ static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
return err; return err;
wdev->nan_started = true; wdev->is_running = true;
rdev->opencount++; rdev->opencount++;
return 0; return 0;
@ -10654,7 +10735,7 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
if (wdev->iftype != NL80211_IFTYPE_NAN) if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!wdev->nan_started) if (!wdev_running(wdev))
return -ENOTCONN; return -ENOTCONN;
if (!info->attrs[NL80211_ATTR_NAN_FUNC]) if (!info->attrs[NL80211_ATTR_NAN_FUNC])
@ -10664,10 +10745,9 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
wdev->owner_nlportid != info->snd_portid) wdev->owner_nlportid != info->snd_portid)
return -ENOTCONN; return -ENOTCONN;
err = nla_parse(tb, NL80211_NAN_FUNC_ATTR_MAX, err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,
nla_data(info->attrs[NL80211_ATTR_NAN_FUNC]), info->attrs[NL80211_ATTR_NAN_FUNC],
nla_len(info->attrs[NL80211_ATTR_NAN_FUNC]), nl80211_nan_func_policy);
nl80211_nan_func_policy);
if (err) if (err)
return err; return err;
@ -10762,9 +10842,9 @@ static int nl80211_nan_add_func(struct sk_buff *skb,
if (tb[NL80211_NAN_FUNC_SRF]) { if (tb[NL80211_NAN_FUNC_SRF]) {
struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR]; struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
err = nla_parse(srf_tb, NL80211_NAN_SRF_ATTR_MAX, err = nla_parse_nested(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
nla_data(tb[NL80211_NAN_FUNC_SRF]), tb[NL80211_NAN_FUNC_SRF],
nla_len(tb[NL80211_NAN_FUNC_SRF]), NULL); nl80211_nan_srf_policy);
if (err) if (err)
goto out; goto out;
@ -10890,7 +10970,7 @@ static int nl80211_nan_del_func(struct sk_buff *skb,
if (wdev->iftype != NL80211_IFTYPE_NAN) if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!wdev->nan_started) if (!wdev_running(wdev))
return -ENOTCONN; return -ENOTCONN;
if (!info->attrs[NL80211_ATTR_COOKIE]) if (!info->attrs[NL80211_ATTR_COOKIE])
@ -10918,7 +10998,7 @@ static int nl80211_nan_change_config(struct sk_buff *skb,
if (wdev->iftype != NL80211_IFTYPE_NAN) if (wdev->iftype != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!wdev->nan_started) if (!wdev_running(wdev))
return -ENOTCONN; return -ENOTCONN;
if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) { if (info->attrs[NL80211_ATTR_NAN_MASTER_PREF]) {
@ -11230,10 +11310,7 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) { if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
if (wdev->netdev && if (!wdev_running(wdev))
!netif_running(wdev->netdev))
return -ENETDOWN;
if (!wdev->netdev && !wdev->p2p_started)
return -ENETDOWN; return -ENETDOWN;
} }
@ -11394,10 +11471,7 @@ static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
return -EINVAL; return -EINVAL;
if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) { if (vcmd->flags & WIPHY_VENDOR_CMD_NEED_RUNNING) {
if (wdev->netdev && if (!wdev_running(wdev))
!netif_running(wdev->netdev))
return -ENETDOWN;
if (!wdev->netdev && !wdev->p2p_started)
return -ENETDOWN; return -ENETDOWN;
} }
} }
@ -11710,6 +11784,31 @@ static int nl80211_tdls_cancel_channel_switch(struct sk_buff *skb,
return 0; return 0;
} }
static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
const struct nlattr *nla;
bool enabled;
if (netif_running(dev))
return -EBUSY;
if (!rdev->ops->set_multicast_to_unicast)
return -EOPNOTSUPP;
if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
nla = info->attrs[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED];
enabled = nla_get_flag(nla);
return rdev_set_multicast_to_unicast(rdev, dev, enabled);
}
#define NL80211_FLAG_NEED_WIPHY 0x01 #define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02 #define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04 #define NL80211_FLAG_NEED_RTNL 0x04
@ -11768,30 +11867,16 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
info->user_ptr[1] = wdev; info->user_ptr[1] = wdev;
} }
if (dev) { if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && !wdev_running(wdev)) {
!netif_running(dev)) { if (rtnl)
if (rtnl) rtnl_unlock();
rtnl_unlock(); return -ENETDOWN;
return -ENETDOWN;
}
dev_hold(dev);
} else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
!wdev->p2p_started) {
if (rtnl)
rtnl_unlock();
return -ENETDOWN;
}
if (wdev->iftype == NL80211_IFTYPE_NAN &&
!wdev->nan_started) {
if (rtnl)
rtnl_unlock();
return -ENETDOWN;
}
} }
if (dev)
dev_hold(dev);
info->user_ptr[0] = rdev; info->user_ptr[0] = rdev;
} }
@ -12162,6 +12247,14 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{
.cmd = NL80211_CMD_UPDATE_CONNECT_PARAMS,
.doit = nl80211_update_connect_params,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{ {
.cmd = NL80211_CMD_DISCONNECT, .cmd = NL80211_CMD_DISCONNECT,
.doit = nl80211_disconnect, .doit = nl80211_disconnect,
@ -12583,6 +12676,14 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL, NL80211_FLAG_NEED_RTNL,
}, },
{
.cmd = NL80211_CMD_SET_MULTICAST_TO_UNICAST,
.doit = nl80211_set_multicast_to_unicast,
.policy = nl80211_policy,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
}; };
static struct genl_family nl80211_fam __ro_after_init = { static struct genl_family nl80211_fam __ro_after_init = {

View File

@ -490,6 +490,18 @@ static inline int rdev_connect(struct cfg80211_registered_device *rdev,
return ret; return ret;
} }
static inline int
rdev_update_connect_params(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_connect_params *sme, u32 changed)
{
int ret;
trace_rdev_update_connect_params(&rdev->wiphy, dev, sme, changed);
ret = rdev->ops->update_connect_params(&rdev->wiphy, dev, sme, changed);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int rdev_disconnect(struct cfg80211_registered_device *rdev, static inline int rdev_disconnect(struct cfg80211_registered_device *rdev,
struct net_device *dev, u16 reason_code) struct net_device *dev, u16 reason_code)
{ {
@ -562,6 +574,18 @@ static inline int rdev_set_wds_peer(struct cfg80211_registered_device *rdev,
return ret; return ret;
} }
static inline int
rdev_set_multicast_to_unicast(struct cfg80211_registered_device *rdev,
struct net_device *dev,
const bool enabled)
{
int ret;
trace_rdev_set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
ret = rdev->ops->set_multicast_to_unicast(&rdev->wiphy, dev, enabled);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev) static inline void rdev_rfkill_poll(struct cfg80211_registered_device *rdev)
{ {
trace_rdev_rfkill_poll(&rdev->wiphy); trace_rdev_rfkill_poll(&rdev->wiphy);

View File

@ -1088,7 +1088,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
err = cfg80211_sme_disconnect(wdev, reason); err = cfg80211_sme_disconnect(wdev, reason);
else if (!rdev->ops->disconnect) else if (!rdev->ops->disconnect)
cfg80211_mlme_down(rdev, dev); cfg80211_mlme_down(rdev, dev);
else if (wdev->current_bss) else if (wdev->ssid_len)
err = rdev_disconnect(rdev, dev, reason); err = rdev_disconnect(rdev, dev, reason);
return err; return err;

View File

@ -1281,6 +1281,24 @@ TRACE_EVENT(rdev_connect,
__entry->wpa_versions, __entry->flags, MAC_PR_ARG(prev_bssid)) __entry->wpa_versions, __entry->flags, MAC_PR_ARG(prev_bssid))
); );
TRACE_EVENT(rdev_update_connect_params,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_connect_params *sme, u32 changed),
TP_ARGS(wiphy, netdev, sme, changed),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
__field(u32, changed)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
__entry->changed = changed;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", parameters changed: %u",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->changed)
);
TRACE_EVENT(rdev_set_cqm_rssi_config, TRACE_EVENT(rdev_set_cqm_rssi_config,
TP_PROTO(struct wiphy *wiphy, TP_PROTO(struct wiphy *wiphy,
struct net_device *netdev, s32 rssi_thold, struct net_device *netdev, s32 rssi_thold,
@ -3030,6 +3048,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_abort_scan,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
TP_ARGS(wiphy, wdev) TP_ARGS(wiphy, wdev)
); );
TRACE_EVENT(rdev_set_multicast_to_unicast,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const bool enabled),
TP_ARGS(wiphy, netdev, enabled),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
__field(bool, enabled)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
__entry->enabled = enabled;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", unicast: %s",
WIPHY_PR_ARG, NETDEV_PR_ARG,
BOOL_TO_STR(__entry->enabled))
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH

View File

@ -13,6 +13,7 @@
#include <net/dsfield.h> #include <net/dsfield.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/mpls.h> #include <linux/mpls.h>
#include <linux/gcd.h>
#include "core.h" #include "core.h"
#include "rdev-ops.h" #include "rdev-ops.h"
@ -1381,6 +1382,25 @@ static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
return false; return false;
} }
static size_t skip_ie(const u8 *ies, size_t ielen, size_t pos)
{
/* we assume a validly formed IEs buffer */
u8 len = ies[pos + 1];
pos += 2 + len;
/* the IE itself must have 255 bytes for fragments to follow */
if (len < 255)
return pos;
while (pos < ielen && ies[pos] == WLAN_EID_FRAGMENT) {
len = ies[pos + 1];
pos += 2 + len;
}
return pos;
}
size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
const u8 *ids, int n_ids, const u8 *ids, int n_ids,
const u8 *after_ric, int n_after_ric, const u8 *after_ric, int n_after_ric,
@ -1390,14 +1410,14 @@ size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) { while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
pos += 2 + ies[pos + 1]; pos = skip_ie(ies, ielen, pos);
while (pos < ielen && while (pos < ielen &&
!ieee80211_id_in_list(after_ric, n_after_ric, !ieee80211_id_in_list(after_ric, n_after_ric,
ies[pos])) ies[pos]))
pos += 2 + ies[pos + 1]; pos = skip_ie(ies, ielen, pos);
} else { } else {
pos += 2 + ies[pos + 1]; pos = skip_ie(ies, ielen, pos);
} }
} }
@ -1558,31 +1578,57 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
} }
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
u32 beacon_int) u32 *beacon_int_gcd,
bool *beacon_int_different)
{ {
struct wireless_dev *wdev; struct wireless_dev *wdev;
int res = 0;
*beacon_int_gcd = 0;
*beacon_int_different = false;
list_for_each_entry(wdev, &wiphy->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
if (!*beacon_int_gcd) {
*beacon_int_gcd = wdev->beacon_interval;
continue;
}
if (wdev->beacon_interval == *beacon_int_gcd)
continue;
*beacon_int_different = true;
*beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
}
if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
if (*beacon_int_gcd)
*beacon_int_different = true;
*beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
}
}
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, u32 beacon_int)
{
/*
* This is just a basic pre-condition check; if interface combinations
* are possible the driver must already be checking those with a call
* to cfg80211_check_combinations(), in which case we'll validate more
* through the cfg80211_calculate_bi_data() call and code in
* cfg80211_iter_combinations().
*/
if (beacon_int < 10 || beacon_int > 10000) if (beacon_int < 10 || beacon_int > 10000)
return -EINVAL; return -EINVAL;
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { return 0;
if (!wdev->beacon_interval)
continue;
if (wdev->beacon_interval != beacon_int) {
res = -EINVAL;
break;
}
}
return res;
} }
int cfg80211_iter_combinations(struct wiphy *wiphy, int cfg80211_iter_combinations(struct wiphy *wiphy,
const int num_different_channels, struct iface_combination_params *params,
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES],
void (*iter)(const struct ieee80211_iface_combination *c, void (*iter)(const struct ieee80211_iface_combination *c,
void *data), void *data),
void *data) void *data)
@ -1592,8 +1638,23 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int i, j, iftype; int i, j, iftype;
int num_interfaces = 0; int num_interfaces = 0;
u32 used_iftypes = 0; u32 used_iftypes = 0;
u32 beacon_int_gcd;
bool beacon_int_different;
if (radar_detect) { /*
* This is a bit strange, since the iteration used to rely only on
* the data given by the driver, but here it now relies on context,
* in form of the currently operating interfaces.
* This is OK for all current users, and saves us from having to
* push the GCD calculations into all the drivers.
* In the future, this should probably rely more on data that's in
* cfg80211 already - the only thing not would appear to be any new
* interfaces (while being brought up) and channel/radar data.
*/
cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
&beacon_int_gcd, &beacon_int_different);
if (params->radar_detect) {
rcu_read_lock(); rcu_read_lock();
regdom = rcu_dereference(cfg80211_regdomain); regdom = rcu_dereference(cfg80211_regdomain);
if (regdom) if (regdom)
@ -1602,8 +1663,8 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
} }
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
num_interfaces += iftype_num[iftype]; num_interfaces += params->iftype_num[iftype];
if (iftype_num[iftype] > 0 && if (params->iftype_num[iftype] > 0 &&
!(wiphy->software_iftypes & BIT(iftype))) !(wiphy->software_iftypes & BIT(iftype)))
used_iftypes |= BIT(iftype); used_iftypes |= BIT(iftype);
} }
@ -1617,7 +1678,7 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if (num_interfaces > c->max_interfaces) if (num_interfaces > c->max_interfaces)
continue; continue;
if (num_different_channels > c->num_different_channels) if (params->num_different_channels > c->num_different_channels)
continue; continue;
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
@ -1632,16 +1693,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
all_iftypes |= limits[j].types; all_iftypes |= limits[j].types;
if (!(limits[j].types & BIT(iftype))) if (!(limits[j].types & BIT(iftype)))
continue; continue;
if (limits[j].max < iftype_num[iftype]) if (limits[j].max < params->iftype_num[iftype])
goto cont; goto cont;
limits[j].max -= iftype_num[iftype]; limits[j].max -= params->iftype_num[iftype];
} }
} }
if (radar_detect != (c->radar_detect_widths & radar_detect)) if (params->radar_detect !=
(c->radar_detect_widths & params->radar_detect))
goto cont; goto cont;
if (radar_detect && c->radar_detect_regions && if (params->radar_detect && c->radar_detect_regions &&
!(c->radar_detect_regions & BIT(region))) !(c->radar_detect_regions & BIT(region)))
goto cont; goto cont;
@ -1653,6 +1715,14 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes) if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont; goto cont;
if (beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
beacon_int_gcd < c->beacon_int_min_gcd)
goto cont;
if (!c->beacon_int_min_gcd && beacon_int_different)
goto cont;
}
/* This combination covered all interface types and /* This combination covered all interface types and
* supported the requested numbers, so we're good. * supported the requested numbers, so we're good.
*/ */
@ -1675,14 +1745,11 @@ cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
} }
int cfg80211_check_combinations(struct wiphy *wiphy, int cfg80211_check_combinations(struct wiphy *wiphy,
const int num_different_channels, struct iface_combination_params *params)
const u8 radar_detect,
const int iftype_num[NUM_NL80211_IFTYPES])
{ {
int err, num = 0; int err, num = 0;
err = cfg80211_iter_combinations(wiphy, num_different_channels, err = cfg80211_iter_combinations(wiphy, params,
radar_detect, iftype_num,
cfg80211_iter_sum_ifcombs, &num); cfg80211_iter_sum_ifcombs, &num);
if (err) if (err)
return err; return err;