diff options
author | David S. Miller <davem@davemloft.net> | 2019-04-26 16:05:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-04-26 16:05:52 -0400 |
commit | 30e5a9a5ba853b896250f0665a2e10bbafa2f6bc (patch) | |
tree | 31f4be512bc417c03f7479d6c69d24f50ecfb00b | |
parent | 148f025d41a8bf8fe7e72d1a86024b5e4d25f224 (diff) | |
parent | 8828f81ad4a2f4e89ebe6e7793c06ed767c31d53 (diff) |
Merge tag 'mac80211-next-for-davem-2019-04-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Johannes Berg says:
====================
Various updates, notably:
* extended key ID support (from 802.11-2016)
* per-STA TX power control support
* mac80211 TX performance improvements
* HE (802.11ax) updates
* mesh link probing support
* enhancements of multi-BSSID support (also related to HE)
* OWE userspace processing support
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
36 files changed, 1465 insertions, 360 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7437faae7cf2..4c2145ba87a0 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -2810,6 +2810,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, | |||
2810 | ieee80211_hw_set(hw, SIGNAL_DBM); | 2810 | ieee80211_hw_set(hw, SIGNAL_DBM); |
2811 | ieee80211_hw_set(hw, SUPPORTS_PS); | 2811 | ieee80211_hw_set(hw, SUPPORTS_PS); |
2812 | ieee80211_hw_set(hw, TDLS_WIDER_BW); | 2812 | ieee80211_hw_set(hw, TDLS_WIDER_BW); |
2813 | |||
2814 | /* We only have SW crypto and only implement the A-MPDU API | ||
2815 | * (but don't really build A-MPDUs) so can have extended key | ||
2816 | * support | ||
2817 | */ | ||
2818 | ieee80211_hw_set(hw, EXT_KEY_ID_NATIVE); | ||
2813 | if (rctbl) | 2819 | if (rctbl) |
2814 | ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); | 2820 | ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); |
2815 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); | 2821 | ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); |
@@ -3900,6 +3906,8 @@ static int __init init_mac80211_hwsim(void) | |||
3900 | param.p2p_device = support_p2p_device; | 3906 | param.p2p_device = support_p2p_device; |
3901 | param.use_chanctx = channels > 1; | 3907 | param.use_chanctx = channels > 1; |
3902 | param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; | 3908 | param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; |
3909 | if (param.p2p_device) | ||
3910 | param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
3903 | 3911 | ||
3904 | err = mac80211_hwsim_new_radio(NULL, ¶m); | 3912 | err = mac80211_hwsim_new_radio(NULL, ¶m); |
3905 | if (err < 0) | 3913 | if (err < 0) |
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 48703ec60d06..61f0a316c6ac 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1557,7 +1557,7 @@ struct ieee80211_vht_operation { | |||
1557 | * struct ieee80211_he_cap_elem - HE capabilities element | 1557 | * struct ieee80211_he_cap_elem - HE capabilities element |
1558 | * | 1558 | * |
1559 | * This structure is the "HE capabilities element" fixed fields as | 1559 | * This structure is the "HE capabilities element" fixed fields as |
1560 | * described in P802.11ax_D3.0 section 9.4.2.237.2 and 9.4.2.237.3 | 1560 | * described in P802.11ax_D4.0 section 9.4.2.242.2 and 9.4.2.242.3 |
1561 | */ | 1561 | */ |
1562 | struct ieee80211_he_cap_elem { | 1562 | struct ieee80211_he_cap_elem { |
1563 | u8 mac_cap_info[6]; | 1563 | u8 mac_cap_info[6]; |
@@ -1619,12 +1619,12 @@ struct ieee80211_he_mcs_nss_supp { | |||
1619 | * struct ieee80211_he_operation - HE capabilities element | 1619 | * struct ieee80211_he_operation - HE capabilities element |
1620 | * | 1620 | * |
1621 | * This structure is the "HE operation element" fields as | 1621 | * This structure is the "HE operation element" fields as |
1622 | * described in P802.11ax_D3.0 section 9.4.2.238 | 1622 | * described in P802.11ax_D4.0 section 9.4.2.243 |
1623 | */ | 1623 | */ |
1624 | struct ieee80211_he_operation { | 1624 | struct ieee80211_he_operation { |
1625 | __le32 he_oper_params; | 1625 | __le32 he_oper_params; |
1626 | __le16 he_mcs_nss_set; | 1626 | __le16 he_mcs_nss_set; |
1627 | /* Optional 0,1,3 or 4 bytes: depends on @he_oper_params */ | 1627 | /* Optional 0,1,3,4,5,7 or 8 bytes: depends on @he_oper_params */ |
1628 | u8 optional[0]; | 1628 | u8 optional[0]; |
1629 | } __packed; | 1629 | } __packed; |
1630 | 1630 | ||
@@ -1632,7 +1632,7 @@ struct ieee80211_he_operation { | |||
1632 | * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field | 1632 | * struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field |
1633 | * | 1633 | * |
1634 | * This structure is the "MU AC Parameter Record" fields as | 1634 | * This structure is the "MU AC Parameter Record" fields as |
1635 | * described in P802.11ax_D2.0 section 9.4.2.240 | 1635 | * described in P802.11ax_D4.0 section 9.4.2.245 |
1636 | */ | 1636 | */ |
1637 | struct ieee80211_he_mu_edca_param_ac_rec { | 1637 | struct ieee80211_he_mu_edca_param_ac_rec { |
1638 | u8 aifsn; | 1638 | u8 aifsn; |
@@ -1644,7 +1644,7 @@ struct ieee80211_he_mu_edca_param_ac_rec { | |||
1644 | * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element | 1644 | * struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element |
1645 | * | 1645 | * |
1646 | * This structure is the "MU EDCA Parameter Set element" fields as | 1646 | * This structure is the "MU EDCA Parameter Set element" fields as |
1647 | * described in P802.11ax_D2.0 section 9.4.2.240 | 1647 | * described in P802.11ax_D4.0 section 9.4.2.245 |
1648 | */ | 1648 | */ |
1649 | struct ieee80211_mu_edca_param_set { | 1649 | struct ieee80211_mu_edca_param_set { |
1650 | u8 mu_qos_info; | 1650 | u8 mu_qos_info; |
@@ -2026,6 +2026,7 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) | |||
2026 | #define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000 | 2026 | #define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000 |
2027 | #define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000 | 2027 | #define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000 |
2028 | #define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000 | 2028 | #define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000 |
2029 | #define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000 | ||
2029 | #define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000 | 2030 | #define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000 |
2030 | #define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24 | 2031 | #define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24 |
2031 | #define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000 | 2032 | #define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000 |
@@ -2056,6 +2057,8 @@ ieee80211_he_oper_size(const u8 *he_oper_ie) | |||
2056 | oper_len += 3; | 2057 | oper_len += 3; |
2057 | if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) | 2058 | if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS) |
2058 | oper_len++; | 2059 | oper_len++; |
2060 | if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO) | ||
2061 | oper_len += 4; | ||
2059 | 2062 | ||
2060 | /* Add the first byte (extension ID) to the total length */ | 2063 | /* Add the first byte (extension ID) to the total length */ |
2061 | oper_len++; | 2064 | oper_len++; |
@@ -2487,6 +2490,7 @@ enum ieee80211_eid_ext { | |||
2487 | WLAN_EID_EXT_HE_MU_EDCA = 38, | 2490 | WLAN_EID_EXT_HE_MU_EDCA = 38, |
2488 | WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME = 52, | 2491 | WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME = 52, |
2489 | WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55, | 2492 | WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55, |
2493 | WLAN_EID_EXT_NON_INHERITANCE = 56, | ||
2490 | }; | 2494 | }; |
2491 | 2495 | ||
2492 | /* Action category code */ | 2496 | /* Action category code */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 13bfeb712d36..87dae868707e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -485,6 +485,7 @@ struct vif_params { | |||
485 | * with the get_key() callback, must be in little endian, | 485 | * with the get_key() callback, must be in little endian, |
486 | * length given by @seq_len. | 486 | * length given by @seq_len. |
487 | * @seq_len: length of @seq. | 487 | * @seq_len: length of @seq. |
488 | * @mode: key install mode (RX_TX, NO_TX or SET_TX) | ||
488 | */ | 489 | */ |
489 | struct key_params { | 490 | struct key_params { |
490 | const u8 *key; | 491 | const u8 *key; |
@@ -492,6 +493,7 @@ struct key_params { | |||
492 | int key_len; | 493 | int key_len; |
493 | int seq_len; | 494 | int seq_len; |
494 | u32 cipher; | 495 | u32 cipher; |
496 | enum nl80211_key_mode mode; | ||
495 | }; | 497 | }; |
496 | 498 | ||
497 | /** | 499 | /** |
@@ -973,6 +975,27 @@ enum station_parameters_apply_mask { | |||
973 | STATION_PARAM_APPLY_UAPSD = BIT(0), | 975 | STATION_PARAM_APPLY_UAPSD = BIT(0), |
974 | STATION_PARAM_APPLY_CAPABILITY = BIT(1), | 976 | STATION_PARAM_APPLY_CAPABILITY = BIT(1), |
975 | STATION_PARAM_APPLY_PLINK_STATE = BIT(2), | 977 | STATION_PARAM_APPLY_PLINK_STATE = BIT(2), |
978 | STATION_PARAM_APPLY_STA_TXPOWER = BIT(3), | ||
979 | }; | ||
980 | |||
981 | /** | ||
982 | * struct sta_txpwr - station txpower configuration | ||
983 | * | ||
984 | * Used to configure txpower for station. | ||
985 | * | ||
986 | * @power: tx power (in dBm) to be used for sending data traffic. If tx power | ||
987 | * is not provided, the default per-interface tx power setting will be | ||
988 | * overriding. Driver should be picking up the lowest tx power, either tx | ||
989 | * power per-interface or per-station. | ||
990 | * @type: In particular if TPC %type is NL80211_TX_POWER_LIMITED then tx power | ||
991 | * will be less than or equal to specified from userspace, whereas if TPC | ||
992 | * %type is NL80211_TX_POWER_AUTOMATIC then it indicates default tx power. | ||
993 | * NL80211_TX_POWER_FIXED is not a valid configuration option for | ||
994 | * per peer TPC. | ||
995 | */ | ||
996 | struct sta_txpwr { | ||
997 | s16 power; | ||
998 | enum nl80211_tx_power_setting type; | ||
976 | }; | 999 | }; |
977 | 1000 | ||
978 | /** | 1001 | /** |
@@ -1047,6 +1070,7 @@ struct station_parameters { | |||
1047 | const struct ieee80211_he_cap_elem *he_capa; | 1070 | const struct ieee80211_he_cap_elem *he_capa; |
1048 | u8 he_capa_len; | 1071 | u8 he_capa_len; |
1049 | u16 airtime_weight; | 1072 | u16 airtime_weight; |
1073 | struct sta_txpwr txpwr; | ||
1050 | }; | 1074 | }; |
1051 | 1075 | ||
1052 | /** | 1076 | /** |
@@ -1327,6 +1351,7 @@ struct cfg80211_tid_stats { | |||
1327 | * @fcs_err_count: number of packets (MPDUs) received from this station with | 1351 | * @fcs_err_count: number of packets (MPDUs) received from this station with |
1328 | * an FCS error. This counter should be incremented only when TA of the | 1352 | * an FCS error. This counter should be incremented only when TA of the |
1329 | * received packet with an FCS error matches the peer MAC address. | 1353 | * received packet with an FCS error matches the peer MAC address. |
1354 | * @airtime_link_metric: mesh airtime link metric. | ||
1330 | */ | 1355 | */ |
1331 | struct station_info { | 1356 | struct station_info { |
1332 | u64 filled; | 1357 | u64 filled; |
@@ -1381,6 +1406,8 @@ struct station_info { | |||
1381 | 1406 | ||
1382 | u32 rx_mpdu_count; | 1407 | u32 rx_mpdu_count; |
1383 | u32 fcs_err_count; | 1408 | u32 fcs_err_count; |
1409 | |||
1410 | u32 airtime_link_metric; | ||
1384 | }; | 1411 | }; |
1385 | 1412 | ||
1386 | #if IS_ENABLED(CONFIG_CFG80211) | 1413 | #if IS_ENABLED(CONFIG_CFG80211) |
@@ -1832,11 +1859,19 @@ static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask) | |||
1832 | * @bssid: BSSID to be matched; may be all-zero BSSID in case of SSID match | 1859 | * @bssid: BSSID to be matched; may be all-zero BSSID in case of SSID match |
1833 | * or no match (RSSI only) | 1860 | * or no match (RSSI only) |
1834 | * @rssi_thold: don't report scan results below this threshold (in s32 dBm) | 1861 | * @rssi_thold: don't report scan results below this threshold (in s32 dBm) |
1862 | * @per_band_rssi_thold: Minimum rssi threshold for each band to be applied | ||
1863 | * for filtering out scan results received. Drivers advertize this support | ||
1864 | * of band specific rssi based filtering through the feature capability | ||
1865 | * %NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD. These band | ||
1866 | * specific rssi thresholds take precedence over rssi_thold, if specified. | ||
1867 | * If not specified for any band, it will be assigned with rssi_thold of | ||
1868 | * corresponding matchset. | ||
1835 | */ | 1869 | */ |
1836 | struct cfg80211_match_set { | 1870 | struct cfg80211_match_set { |
1837 | struct cfg80211_ssid ssid; | 1871 | struct cfg80211_ssid ssid; |
1838 | u8 bssid[ETH_ALEN]; | 1872 | u8 bssid[ETH_ALEN]; |
1839 | s32 rssi_thold; | 1873 | s32 rssi_thold; |
1874 | s32 per_band_rssi_thold[NUM_NL80211_BANDS]; | ||
1840 | }; | 1875 | }; |
1841 | 1876 | ||
1842 | /** | 1877 | /** |
@@ -3100,6 +3135,32 @@ struct cfg80211_pmsr_request { | |||
3100 | }; | 3135 | }; |
3101 | 3136 | ||
3102 | /** | 3137 | /** |
3138 | * struct cfg80211_update_owe_info - OWE Information | ||
3139 | * | ||
3140 | * This structure provides information needed for the drivers to offload OWE | ||
3141 | * (Opportunistic Wireless Encryption) processing to the user space. | ||
3142 | * | ||
3143 | * Commonly used across update_owe_info request and event interfaces. | ||
3144 | * | ||
3145 | * @peer: MAC address of the peer device for which the OWE processing | ||
3146 | * has to be done. | ||
3147 | * @status: status code, %WLAN_STATUS_SUCCESS for successful OWE info | ||
3148 | * processing, use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space | ||
3149 | * cannot give you the real status code for failures. Used only for | ||
3150 | * OWE update request command interface (user space to driver). | ||
3151 | * @ie: IEs obtained from the peer or constructed by the user space. These are | ||
3152 | * the IEs of the remote peer in the event from the host driver and | ||
3153 | * the constructed IEs by the user space in the request interface. | ||
3154 | * @ie_len: Length of IEs in octets. | ||
3155 | */ | ||
3156 | struct cfg80211_update_owe_info { | ||
3157 | u8 peer[ETH_ALEN] __aligned(2); | ||
3158 | u16 status; | ||
3159 | const u8 *ie; | ||
3160 | size_t ie_len; | ||
3161 | }; | ||
3162 | |||
3163 | /** | ||
3103 | * struct cfg80211_ops - backend description for wireless configuration | 3164 | * struct cfg80211_ops - backend description for wireless configuration |
3104 | * | 3165 | * |
3105 | * This struct is registered by fullmac card drivers and/or wireless stacks | 3166 | * This struct is registered by fullmac card drivers and/or wireless stacks |
@@ -3436,6 +3497,13 @@ struct cfg80211_pmsr_request { | |||
3436 | * Statistics should be cumulative, currently no way to reset is provided. | 3497 | * Statistics should be cumulative, currently no way to reset is provided. |
3437 | * @start_pmsr: start peer measurement (e.g. FTM) | 3498 | * @start_pmsr: start peer measurement (e.g. FTM) |
3438 | * @abort_pmsr: abort peer measurement | 3499 | * @abort_pmsr: abort peer measurement |
3500 | * | ||
3501 | * @update_owe_info: Provide updated OWE info to driver. Driver implementing SME | ||
3502 | * but offloading OWE processing to the user space will get the updated | ||
3503 | * DH IE through this interface. | ||
3504 | * | ||
3505 | * @probe_mesh_link: Probe direct Mesh peer's link quality by sending data frame | ||
3506 | * and overrule HWMP path selection algorithm. | ||
3439 | */ | 3507 | */ |
3440 | struct cfg80211_ops { | 3508 | struct cfg80211_ops { |
3441 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); | 3509 | int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); |
@@ -3750,6 +3818,10 @@ struct cfg80211_ops { | |||
3750 | struct cfg80211_pmsr_request *request); | 3818 | struct cfg80211_pmsr_request *request); |
3751 | void (*abort_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev, | 3819 | void (*abort_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev, |
3752 | struct cfg80211_pmsr_request *request); | 3820 | struct cfg80211_pmsr_request *request); |
3821 | int (*update_owe_info)(struct wiphy *wiphy, struct net_device *dev, | ||
3822 | struct cfg80211_update_owe_info *owe_info); | ||
3823 | int (*probe_mesh_link)(struct wiphy *wiphy, struct net_device *dev, | ||
3824 | const u8 *buf, size_t len); | ||
3753 | }; | 3825 | }; |
3754 | 3826 | ||
3755 | /* | 3827 | /* |
@@ -5492,6 +5564,28 @@ static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid, | |||
5492 | } | 5564 | } |
5493 | 5565 | ||
5494 | /** | 5566 | /** |
5567 | * cfg80211_is_element_inherited - returns if element ID should be inherited | ||
5568 | * @element: element to check | ||
5569 | * @non_inherit_element: non inheritance element | ||
5570 | */ | ||
5571 | bool cfg80211_is_element_inherited(const struct element *element, | ||
5572 | const struct element *non_inherit_element); | ||
5573 | |||
5574 | /** | ||
5575 | * cfg80211_merge_profile - merges a MBSSID profile if it is split between IEs | ||
5576 | * @ie: ies | ||
5577 | * @ielen: length of IEs | ||
5578 | * @mbssid_elem: current MBSSID element | ||
5579 | * @sub_elem: current MBSSID subelement (profile) | ||
5580 | * @merged_ie: location of the merged profile | ||
5581 | * @max_copy_len: max merged profile length | ||
5582 | */ | ||
5583 | size_t cfg80211_merge_profile(const u8 *ie, size_t ielen, | ||
5584 | const struct element *mbssid_elem, | ||
5585 | const struct element *sub_elem, | ||
5586 | u8 *merged_ie, size_t max_copy_len); | ||
5587 | |||
5588 | /** | ||
5495 | * enum cfg80211_bss_frame_type - frame type that the BSS data came from | 5589 | * enum cfg80211_bss_frame_type - frame type that the BSS data came from |
5496 | * @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is | 5590 | * @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is |
5497 | * from a beacon or probe response | 5591 | * from a beacon or probe response |
@@ -7213,4 +7307,14 @@ void cfg80211_pmsr_complete(struct wireless_dev *wdev, | |||
7213 | #define wiphy_WARN(wiphy, format, args...) \ | 7307 | #define wiphy_WARN(wiphy, format, args...) \ |
7214 | WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args); | 7308 | WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args); |
7215 | 7309 | ||
7310 | /** | ||
7311 | * cfg80211_update_owe_info_event - Notify the peer's OWE info to user space | ||
7312 | * @netdev: network device | ||
7313 | * @owe_info: peer's owe info | ||
7314 | * @gfp: allocation flags | ||
7315 | */ | ||
7316 | void cfg80211_update_owe_info_event(struct net_device *netdev, | ||
7317 | struct cfg80211_update_owe_info *owe_info, | ||
7318 | gfp_t gfp); | ||
7319 | |||
7216 | #endif /* __NET_CFG80211_H */ | 7320 | #endif /* __NET_CFG80211_H */ |
diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h index be7c0fab3478..2caa86660ab0 100644 --- a/include/net/fq_impl.h +++ b/include/net/fq_impl.h | |||
@@ -107,21 +107,23 @@ begin: | |||
107 | return skb; | 107 | return skb; |
108 | } | 108 | } |
109 | 109 | ||
110 | static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) | ||
111 | { | ||
112 | u32 hash = skb_get_hash_perturb(skb, fq->perturbation); | ||
113 | |||
114 | return reciprocal_scale(hash, fq->flows_cnt); | ||
115 | } | ||
116 | |||
110 | static struct fq_flow *fq_flow_classify(struct fq *fq, | 117 | static struct fq_flow *fq_flow_classify(struct fq *fq, |
111 | struct fq_tin *tin, | 118 | struct fq_tin *tin, u32 idx, |
112 | struct sk_buff *skb, | 119 | struct sk_buff *skb, |
113 | fq_flow_get_default_t get_default_func) | 120 | fq_flow_get_default_t get_default_func) |
114 | { | 121 | { |
115 | struct fq_flow *flow; | 122 | struct fq_flow *flow; |
116 | u32 hash; | ||
117 | u32 idx; | ||
118 | 123 | ||
119 | lockdep_assert_held(&fq->lock); | 124 | lockdep_assert_held(&fq->lock); |
120 | 125 | ||
121 | hash = skb_get_hash_perturb(skb, fq->perturbation); | ||
122 | idx = reciprocal_scale(hash, fq->flows_cnt); | ||
123 | flow = &fq->flows[idx]; | 126 | flow = &fq->flows[idx]; |
124 | |||
125 | if (flow->tin && flow->tin != tin) { | 127 | if (flow->tin && flow->tin != tin) { |
126 | flow = get_default_func(fq, tin, idx, skb); | 128 | flow = get_default_func(fq, tin, idx, skb); |
127 | tin->collisions++; | 129 | tin->collisions++; |
@@ -153,7 +155,7 @@ static void fq_recalc_backlog(struct fq *fq, | |||
153 | } | 155 | } |
154 | 156 | ||
155 | static void fq_tin_enqueue(struct fq *fq, | 157 | static void fq_tin_enqueue(struct fq *fq, |
156 | struct fq_tin *tin, | 158 | struct fq_tin *tin, u32 idx, |
157 | struct sk_buff *skb, | 159 | struct sk_buff *skb, |
158 | fq_skb_free_t free_func, | 160 | fq_skb_free_t free_func, |
159 | fq_flow_get_default_t get_default_func) | 161 | fq_flow_get_default_t get_default_func) |
@@ -163,7 +165,7 @@ static void fq_tin_enqueue(struct fq *fq, | |||
163 | 165 | ||
164 | lockdep_assert_held(&fq->lock); | 166 | lockdep_assert_held(&fq->lock); |
165 | 167 | ||
166 | flow = fq_flow_classify(fq, tin, skb, get_default_func); | 168 | flow = fq_flow_classify(fq, tin, idx, skb, get_default_func); |
167 | 169 | ||
168 | flow->tin = tin; | 170 | flow->tin = tin; |
169 | flow->backlog += skb->len; | 171 | flow->backlog += skb->len; |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 112dc18c658f..72080d9d617e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -807,6 +807,7 @@ enum mac80211_tx_info_flags { | |||
807 | * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information | 807 | * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information |
808 | * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame | 808 | * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame |
809 | * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path | 809 | * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path |
810 | * @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup | ||
810 | * | 811 | * |
811 | * These flags are used in tx_info->control.flags. | 812 | * These flags are used in tx_info->control.flags. |
812 | */ | 813 | */ |
@@ -816,6 +817,7 @@ enum mac80211_tx_control_flags { | |||
816 | IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), | 817 | IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), |
817 | IEEE80211_TX_CTRL_AMSDU = BIT(3), | 818 | IEEE80211_TX_CTRL_AMSDU = BIT(3), |
818 | IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), | 819 | IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), |
820 | IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5), | ||
819 | }; | 821 | }; |
820 | 822 | ||
821 | /* | 823 | /* |
@@ -1697,6 +1699,7 @@ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif); | |||
1697 | * @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for | 1699 | * @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for |
1698 | * a TKIP key if it only requires MIC space. Do not set together with | 1700 | * a TKIP key if it only requires MIC space. Do not set together with |
1699 | * @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key. | 1701 | * @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key. |
1702 | * @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation. | ||
1700 | */ | 1703 | */ |
1701 | enum ieee80211_key_flags { | 1704 | enum ieee80211_key_flags { |
1702 | IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0), | 1705 | IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0), |
@@ -1708,6 +1711,7 @@ enum ieee80211_key_flags { | |||
1708 | IEEE80211_KEY_FLAG_RX_MGMT = BIT(6), | 1711 | IEEE80211_KEY_FLAG_RX_MGMT = BIT(6), |
1709 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7), | 1712 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7), |
1710 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8), | 1713 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8), |
1714 | IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9), | ||
1711 | }; | 1715 | }; |
1712 | 1716 | ||
1713 | /** | 1717 | /** |
@@ -1888,6 +1892,24 @@ struct ieee80211_sta_rates { | |||
1888 | }; | 1892 | }; |
1889 | 1893 | ||
1890 | /** | 1894 | /** |
1895 | * struct ieee80211_sta_txpwr - station txpower configuration | ||
1896 | * | ||
1897 | * Used to configure txpower for station. | ||
1898 | * | ||
1899 | * @power: indicates the tx power, in dBm, to be used when sending data frames | ||
1900 | * to the STA. | ||
1901 | * @type: In particular if TPC %type is NL80211_TX_POWER_LIMITED then tx power | ||
1902 | * will be less than or equal to specified from userspace, whereas if TPC | ||
1903 | * %type is NL80211_TX_POWER_AUTOMATIC then it indicates default tx power. | ||
1904 | * NL80211_TX_POWER_FIXED is not a valid configuration option for | ||
1905 | * per peer TPC. | ||
1906 | */ | ||
1907 | struct ieee80211_sta_txpwr { | ||
1908 | s16 power; | ||
1909 | enum nl80211_tx_power_setting type; | ||
1910 | }; | ||
1911 | |||
1912 | /** | ||
1891 | * struct ieee80211_sta - station table entry | 1913 | * struct ieee80211_sta - station table entry |
1892 | * | 1914 | * |
1893 | * A station table entry represents a station we are possibly | 1915 | * A station table entry represents a station we are possibly |
@@ -1973,6 +1995,7 @@ struct ieee80211_sta { | |||
1973 | bool support_p2p_ps; | 1995 | bool support_p2p_ps; |
1974 | u16 max_rc_amsdu_len; | 1996 | u16 max_rc_amsdu_len; |
1975 | u16 max_tid_amsdu_len[IEEE80211_NUM_TIDS]; | 1997 | u16 max_tid_amsdu_len[IEEE80211_NUM_TIDS]; |
1998 | struct ieee80211_sta_txpwr txpwr; | ||
1976 | 1999 | ||
1977 | struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; | 2000 | struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; |
1978 | 2001 | ||
@@ -2243,6 +2266,9 @@ struct ieee80211_txq { | |||
2243 | * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID | 2266 | * @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID |
2244 | * only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set. | 2267 | * only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set. |
2245 | * | 2268 | * |
2269 | * @IEEE80211_HW_EXT_KEY_ID_NATIVE: Driver and hardware are supporting Extended | ||
2270 | * Key ID and can handle two unicast keys per station for Rx and Tx. | ||
2271 | * | ||
2246 | * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays | 2272 | * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays |
2247 | */ | 2273 | */ |
2248 | enum ieee80211_hw_flags { | 2274 | enum ieee80211_hw_flags { |
@@ -2294,6 +2320,7 @@ enum ieee80211_hw_flags { | |||
2294 | IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN, | 2320 | IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN, |
2295 | IEEE80211_HW_SUPPORTS_MULTI_BSSID, | 2321 | IEEE80211_HW_SUPPORTS_MULTI_BSSID, |
2296 | IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, | 2322 | IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, |
2323 | IEEE80211_HW_EXT_KEY_ID_NATIVE, | ||
2297 | 2324 | ||
2298 | /* keep last, obviously */ | 2325 | /* keep last, obviously */ |
2299 | NUM_IEEE80211_HW_FLAGS | 2326 | NUM_IEEE80211_HW_FLAGS |
@@ -3794,6 +3821,9 @@ struct ieee80211_ops { | |||
3794 | #endif | 3821 | #endif |
3795 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 3822 | void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
3796 | enum sta_notify_cmd, struct ieee80211_sta *sta); | 3823 | enum sta_notify_cmd, struct ieee80211_sta *sta); |
3824 | int (*sta_set_txpwr)(struct ieee80211_hw *hw, | ||
3825 | struct ieee80211_vif *vif, | ||
3826 | struct ieee80211_sta *sta); | ||
3797 | int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | 3827 | int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
3798 | struct ieee80211_sta *sta, | 3828 | struct ieee80211_sta *sta, |
3799 | enum ieee80211_sta_state old_state, | 3829 | enum ieee80211_sta_state old_state, |
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index dd4f86ee286e..6f09d1500960 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h | |||
@@ -11,7 +11,7 @@ | |||
11 | * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> | 11 | * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> |
12 | * Copyright 2008 Colin McCabe <colin@cozybit.com> | 12 | * Copyright 2008 Colin McCabe <colin@cozybit.com> |
13 | * Copyright 2015-2017 Intel Deutschland GmbH | 13 | * Copyright 2015-2017 Intel Deutschland GmbH |
14 | * Copyright (C) 2018 Intel Corporation | 14 | * Copyright (C) 2018-2019 Intel Corporation |
15 | * | 15 | * |
16 | * Permission to use, copy, modify, and/or distribute this software for any | 16 | * Permission to use, copy, modify, and/or distribute this software for any |
17 | * purpose with or without fee is hereby granted, provided that the above | 17 | * purpose with or without fee is hereby granted, provided that the above |
@@ -1065,6 +1065,26 @@ | |||
1065 | * indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes | 1065 | * indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes |
1066 | * determining the width and type. | 1066 | * determining the width and type. |
1067 | * | 1067 | * |
1068 | * @NL80211_CMD_UPDATE_OWE_INFO: This interface allows the host driver to | ||
1069 | * offload OWE processing to user space. This intends to support | ||
1070 | * OWE AKM by the host drivers that implement SME but rely | ||
1071 | * on the user space for the cryptographic/DH IE processing in AP mode. | ||
1072 | * | ||
1073 | * @NL80211_CMD_PROBE_MESH_LINK: The requirement for mesh link metric | ||
1074 | * refreshing, is that from one mesh point we be able to send some data | ||
1075 | * frames to other mesh points which are not currently selected as a | ||
1076 | * primary traffic path, but which are only 1 hop away. The absence of | ||
1077 | * the primary path to the chosen node makes it necessary to apply some | ||
1078 | * form of marking on a chosen packet stream so that the packets can be | ||
1079 | * properly steered to the selected node for testing, and not by the | ||
1080 | * regular mesh path lookup. Further, the packets must be of type data | ||
1081 | * so that the rate control (often embedded in firmware) is used for | ||
1082 | * rate selection. | ||
1083 | * | ||
1084 | * Here attribute %NL80211_ATTR_MAC is used to specify connected mesh | ||
1085 | * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame | ||
1086 | * content. The frame is ethernet data. | ||
1087 | * | ||
1068 | * @NL80211_CMD_MAX: highest used command number | 1088 | * @NL80211_CMD_MAX: highest used command number |
1069 | * @__NL80211_CMD_AFTER_LAST: internal use | 1089 | * @__NL80211_CMD_AFTER_LAST: internal use |
1070 | */ | 1090 | */ |
@@ -1285,6 +1305,10 @@ enum nl80211_commands { | |||
1285 | 1305 | ||
1286 | NL80211_CMD_NOTIFY_RADAR, | 1306 | NL80211_CMD_NOTIFY_RADAR, |
1287 | 1307 | ||
1308 | NL80211_CMD_UPDATE_OWE_INFO, | ||
1309 | |||
1310 | NL80211_CMD_PROBE_MESH_LINK, | ||
1311 | |||
1288 | /* add new commands above here */ | 1312 | /* add new commands above here */ |
1289 | 1313 | ||
1290 | /* used to define NL80211_CMD_MAX below */ | 1314 | /* used to define NL80211_CMD_MAX below */ |
@@ -2308,6 +2332,15 @@ enum nl80211_commands { | |||
2308 | * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime | 2332 | * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime |
2309 | * scheduler. | 2333 | * scheduler. |
2310 | * | 2334 | * |
2335 | * @NL80211_ATTR_STA_TX_POWER_SETTING: Transmit power setting type (u8) for | ||
2336 | * station associated with the AP. See &enum nl80211_tx_power_setting for | ||
2337 | * possible values. | ||
2338 | * @NL80211_ATTR_STA_TX_POWER: Transmit power level (s16) in dBm units. This | ||
2339 | * allows to set Tx power for a station. If this attribute is not included, | ||
2340 | * the default per-interface tx power setting will be overriding. Driver | ||
2341 | * should be picking up the lowest tx power, either tx power per-interface | ||
2342 | * or per-station. | ||
2343 | * | ||
2311 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available | 2344 | * @NUM_NL80211_ATTR: total number of nl80211_attrs available |
2312 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 2345 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
2313 | * @__NL80211_ATTR_AFTER_LAST: internal use | 2346 | * @__NL80211_ATTR_AFTER_LAST: internal use |
@@ -2758,6 +2791,8 @@ enum nl80211_attrs { | |||
2758 | NL80211_ATTR_PEER_MEASUREMENTS, | 2791 | NL80211_ATTR_PEER_MEASUREMENTS, |
2759 | 2792 | ||
2760 | NL80211_ATTR_AIRTIME_WEIGHT, | 2793 | NL80211_ATTR_AIRTIME_WEIGHT, |
2794 | NL80211_ATTR_STA_TX_POWER_SETTING, | ||
2795 | NL80211_ATTR_STA_TX_POWER, | ||
2761 | 2796 | ||
2762 | /* add attributes here, update the policy in nl80211.c */ | 2797 | /* add attributes here, update the policy in nl80211.c */ |
2763 | 2798 | ||
@@ -2802,7 +2837,7 @@ enum nl80211_attrs { | |||
2802 | 2837 | ||
2803 | #define NL80211_MAX_SUPP_RATES 32 | 2838 | #define NL80211_MAX_SUPP_RATES 32 |
2804 | #define NL80211_MAX_SUPP_HT_RATES 77 | 2839 | #define NL80211_MAX_SUPP_HT_RATES 77 |
2805 | #define NL80211_MAX_SUPP_REG_RULES 64 | 2840 | #define NL80211_MAX_SUPP_REG_RULES 128 |
2806 | #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 | 2841 | #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 |
2807 | #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 | 2842 | #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 |
2808 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 | 2843 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 |
@@ -3139,6 +3174,7 @@ enum nl80211_sta_bss_param { | |||
3139 | * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames | 3174 | * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames |
3140 | * sent to the station (u64, usec) | 3175 | * sent to the station (u64, usec) |
3141 | * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16) | 3176 | * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16) |
3177 | * @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station | ||
3142 | * @__NL80211_STA_INFO_AFTER_LAST: internal | 3178 | * @__NL80211_STA_INFO_AFTER_LAST: internal |
3143 | * @NL80211_STA_INFO_MAX: highest possible station info attribute | 3179 | * @NL80211_STA_INFO_MAX: highest possible station info attribute |
3144 | */ | 3180 | */ |
@@ -3184,6 +3220,7 @@ enum nl80211_sta_info { | |||
3184 | NL80211_STA_INFO_CONNECTED_TO_GATE, | 3220 | NL80211_STA_INFO_CONNECTED_TO_GATE, |
3185 | NL80211_STA_INFO_TX_DURATION, | 3221 | NL80211_STA_INFO_TX_DURATION, |
3186 | NL80211_STA_INFO_AIRTIME_WEIGHT, | 3222 | NL80211_STA_INFO_AIRTIME_WEIGHT, |
3223 | NL80211_STA_INFO_AIRTIME_LINK_METRIC, | ||
3187 | 3224 | ||
3188 | /* keep last */ | 3225 | /* keep last */ |
3189 | __NL80211_STA_INFO_AFTER_LAST, | 3226 | __NL80211_STA_INFO_AFTER_LAST, |
@@ -3638,6 +3675,14 @@ enum nl80211_reg_rule_attr { | |||
3638 | * value as specified by &struct nl80211_bss_select_rssi_adjust. | 3675 | * value as specified by &struct nl80211_bss_select_rssi_adjust. |
3639 | * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching | 3676 | * @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching |
3640 | * (this cannot be used together with SSID). | 3677 | * (this cannot be used together with SSID). |
3678 | * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Nested attribute that carries the | ||
3679 | * band specific minimum rssi thresholds for the bands defined in | ||
3680 | * enum nl80211_band. The minimum rssi threshold value(s32) specific to a | ||
3681 | * band shall be encapsulated in attribute with type value equals to one | ||
3682 | * of the NL80211_BAND_* defined in enum nl80211_band. For example, the | ||
3683 | * minimum rssi threshold value for 2.4GHZ band shall be encapsulated | ||
3684 | * within an attribute of type NL80211_BAND_2GHZ. And one or more of such | ||
3685 | * attributes will be nested within this attribute. | ||
3641 | * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter | 3686 | * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter |
3642 | * attribute number currently defined | 3687 | * attribute number currently defined |
3643 | * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use | 3688 | * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use |
@@ -3650,6 +3695,7 @@ enum nl80211_sched_scan_match_attr { | |||
3650 | NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI, | 3695 | NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI, |
3651 | NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST, | 3696 | NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST, |
3652 | NL80211_SCHED_SCAN_MATCH_ATTR_BSSID, | 3697 | NL80211_SCHED_SCAN_MATCH_ATTR_BSSID, |
3698 | NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI, | ||
3653 | 3699 | ||
3654 | /* keep last */ | 3700 | /* keep last */ |
3655 | __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, | 3701 | __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, |
@@ -4135,6 +4181,27 @@ enum nl80211_channel_type { | |||
4135 | }; | 4181 | }; |
4136 | 4182 | ||
4137 | /** | 4183 | /** |
4184 | * enum nl80211_key_mode - Key mode | ||
4185 | * | ||
4186 | * @NL80211_KEY_RX_TX: (Default) | ||
4187 | * Key can be used for Rx and Tx immediately | ||
4188 | * | ||
4189 | * The following modes can only be selected for unicast keys and when the | ||
4190 | * driver supports @NL80211_EXT_FEATURE_EXT_KEY_ID: | ||
4191 | * | ||
4192 | * @NL80211_KEY_NO_TX: Only allowed in combination with @NL80211_CMD_NEW_KEY: | ||
4193 | * Unicast key can only be used for Rx, Tx not allowed, yet | ||
4194 | * @NL80211_KEY_SET_TX: Only allowed in combination with @NL80211_CMD_SET_KEY: | ||
4195 | * The unicast key identified by idx and mac is cleared for Tx and becomes | ||
4196 | * the preferred Tx key for the station. | ||
4197 | */ | ||
4198 | enum nl80211_key_mode { | ||
4199 | NL80211_KEY_RX_TX, | ||
4200 | NL80211_KEY_NO_TX, | ||
4201 | NL80211_KEY_SET_TX | ||
4202 | }; | ||
4203 | |||
4204 | /** | ||
4138 | * enum nl80211_chan_width - channel width definitions | 4205 | * enum nl80211_chan_width - channel width definitions |
4139 | * | 4206 | * |
4140 | * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH | 4207 | * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH |
@@ -4377,6 +4444,9 @@ enum nl80211_key_default_types { | |||
4377 | * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags | 4444 | * @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags |
4378 | * attributes, specifying what a key should be set as default as. | 4445 | * attributes, specifying what a key should be set as default as. |
4379 | * See &enum nl80211_key_default_types. | 4446 | * See &enum nl80211_key_default_types. |
4447 | * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode. | ||
4448 | * Defaults to @NL80211_KEY_RX_TX. | ||
4449 | * | ||
4380 | * @__NL80211_KEY_AFTER_LAST: internal | 4450 | * @__NL80211_KEY_AFTER_LAST: internal |
4381 | * @NL80211_KEY_MAX: highest key attribute | 4451 | * @NL80211_KEY_MAX: highest key attribute |
4382 | */ | 4452 | */ |
@@ -4390,6 +4460,7 @@ enum nl80211_key_attributes { | |||
4390 | NL80211_KEY_DEFAULT_MGMT, | 4460 | NL80211_KEY_DEFAULT_MGMT, |
4391 | NL80211_KEY_TYPE, | 4461 | NL80211_KEY_TYPE, |
4392 | NL80211_KEY_DEFAULT_TYPES, | 4462 | NL80211_KEY_DEFAULT_TYPES, |
4463 | NL80211_KEY_MODE, | ||
4393 | 4464 | ||
4394 | /* keep last */ | 4465 | /* keep last */ |
4395 | __NL80211_KEY_AFTER_LAST, | 4466 | __NL80211_KEY_AFTER_LAST, |
@@ -5335,6 +5406,8 @@ enum nl80211_feature_flags { | |||
5335 | * able to rekey an in-use key correctly. Userspace must not rekey PTK keys | 5406 | * able to rekey an in-use key correctly. Userspace must not rekey PTK keys |
5336 | * if this flag is not set. Ignoring this can leak clear text packets and/or | 5407 | * if this flag is not set. Ignoring this can leak clear text packets and/or |
5337 | * freeze the connection. | 5408 | * freeze the connection. |
5409 | * @NL80211_EXT_FEATURE_EXT_KEY_ID: Driver supports "Extended Key ID for | ||
5410 | * Individually Addressed Frames" from IEEE802.11-2016. | ||
5338 | * | 5411 | * |
5339 | * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime | 5412 | * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime |
5340 | * fairness for transmitted packets and has enabled airtime fairness | 5413 | * fairness for transmitted packets and has enabled airtime fairness |
@@ -5343,6 +5416,12 @@ enum nl80211_feature_flags { | |||
5343 | * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching | 5416 | * @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching |
5344 | * (set/del PMKSA operations) in AP mode. | 5417 | * (set/del PMKSA operations) in AP mode. |
5345 | * | 5418 | * |
5419 | * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports | ||
5420 | * filtering of sched scan results using band specific RSSI thresholds. | ||
5421 | * | ||
5422 | * @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power | ||
5423 | * to a station. | ||
5424 | * | ||
5346 | * @NUM_NL80211_EXT_FEATURES: number of extended features. | 5425 | * @NUM_NL80211_EXT_FEATURES: number of extended features. |
5347 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. | 5426 | * @MAX_NL80211_EXT_FEATURES: highest extended feature index. |
5348 | */ | 5427 | */ |
@@ -5384,6 +5463,9 @@ enum nl80211_ext_feature_index { | |||
5384 | NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, | 5463 | NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER, |
5385 | NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, | 5464 | NL80211_EXT_FEATURE_AIRTIME_FAIRNESS, |
5386 | NL80211_EXT_FEATURE_AP_PMKSA_CACHING, | 5465 | NL80211_EXT_FEATURE_AP_PMKSA_CACHING, |
5466 | NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, | ||
5467 | NL80211_EXT_FEATURE_EXT_KEY_ID, | ||
5468 | NL80211_EXT_FEATURE_STA_TX_PWR, | ||
5387 | 5469 | ||
5388 | /* add new features before the definition below */ | 5470 | /* add new features before the definition below */ |
5389 | NUM_NL80211_EXT_FEATURES, | 5471 | NUM_NL80211_EXT_FEATURES, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 09dd1c2860fc..52e6a091b7e4 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -351,6 +351,36 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy, | |||
351 | return 0; | 351 | return 0; |
352 | } | 352 | } |
353 | 353 | ||
354 | static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata, | ||
355 | const u8 *mac_addr, u8 key_idx) | ||
356 | { | ||
357 | struct ieee80211_local *local = sdata->local; | ||
358 | struct ieee80211_key *key; | ||
359 | struct sta_info *sta; | ||
360 | int ret = -EINVAL; | ||
361 | |||
362 | if (!wiphy_ext_feature_isset(local->hw.wiphy, | ||
363 | NL80211_EXT_FEATURE_EXT_KEY_ID)) | ||
364 | return -EINVAL; | ||
365 | |||
366 | sta = sta_info_get_bss(sdata, mac_addr); | ||
367 | |||
368 | if (!sta) | ||
369 | return -EINVAL; | ||
370 | |||
371 | if (sta->ptk_idx == key_idx) | ||
372 | return 0; | ||
373 | |||
374 | mutex_lock(&local->key_mtx); | ||
375 | key = key_mtx_dereference(local, sta->ptk[key_idx]); | ||
376 | |||
377 | if (key && key->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX) | ||
378 | ret = ieee80211_set_tx_key(key); | ||
379 | |||
380 | mutex_unlock(&local->key_mtx); | ||
381 | return ret; | ||
382 | } | ||
383 | |||
354 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 384 | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, |
355 | u8 key_idx, bool pairwise, const u8 *mac_addr, | 385 | u8 key_idx, bool pairwise, const u8 *mac_addr, |
356 | struct key_params *params) | 386 | struct key_params *params) |
@@ -365,6 +395,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
365 | if (!ieee80211_sdata_running(sdata)) | 395 | if (!ieee80211_sdata_running(sdata)) |
366 | return -ENETDOWN; | 396 | return -ENETDOWN; |
367 | 397 | ||
398 | if (pairwise && params->mode == NL80211_KEY_SET_TX) | ||
399 | return ieee80211_set_tx(sdata, mac_addr, key_idx); | ||
400 | |||
368 | /* reject WEP and TKIP keys if WEP failed to initialize */ | 401 | /* reject WEP and TKIP keys if WEP failed to initialize */ |
369 | switch (params->cipher) { | 402 | switch (params->cipher) { |
370 | case WLAN_CIPHER_SUITE_WEP40: | 403 | case WLAN_CIPHER_SUITE_WEP40: |
@@ -396,6 +429,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
396 | if (pairwise) | 429 | if (pairwise) |
397 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; | 430 | key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE; |
398 | 431 | ||
432 | if (params->mode == NL80211_KEY_NO_TX) | ||
433 | key->conf.flags |= IEEE80211_KEY_FLAG_NO_AUTO_TX; | ||
434 | |||
399 | mutex_lock(&local->sta_mtx); | 435 | mutex_lock(&local->sta_mtx); |
400 | 436 | ||
401 | if (mac_addr) { | 437 | if (mac_addr) { |
@@ -1421,6 +1457,15 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1421 | if (params->listen_interval >= 0) | 1457 | if (params->listen_interval >= 0) |
1422 | sta->listen_interval = params->listen_interval; | 1458 | sta->listen_interval = params->listen_interval; |
1423 | 1459 | ||
1460 | if (params->sta_modify_mask & STATION_PARAM_APPLY_STA_TXPOWER) { | ||
1461 | sta->sta.txpwr.type = params->txpwr.type; | ||
1462 | if (params->txpwr.type == NL80211_TX_POWER_LIMITED) | ||
1463 | sta->sta.txpwr.power = params->txpwr.power; | ||
1464 | ret = drv_sta_set_txpwr(local, sdata, sta); | ||
1465 | if (ret) | ||
1466 | return ret; | ||
1467 | } | ||
1468 | |||
1424 | if (params->supported_rates) { | 1469 | if (params->supported_rates) { |
1425 | ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, | 1470 | ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, |
1426 | sband, params->supported_rates, | 1471 | sband, params->supported_rates, |
@@ -3990,4 +4035,5 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3990 | .get_ftm_responder_stats = ieee80211_get_ftm_responder_stats, | 4035 | .get_ftm_responder_stats = ieee80211_get_ftm_responder_stats, |
3991 | .start_pmsr = ieee80211_start_pmsr, | 4036 | .start_pmsr = ieee80211_start_pmsr, |
3992 | .abort_pmsr = ieee80211_abort_pmsr, | 4037 | .abort_pmsr = ieee80211_abort_pmsr, |
4038 | .probe_mesh_link = ieee80211_probe_mesh_link, | ||
3993 | }; | 4039 | }; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 2d43bc127043..0d462206eef6 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -150,6 +150,58 @@ static const struct file_operations aqm_ops = { | |||
150 | .llseek = default_llseek, | 150 | .llseek = default_llseek, |
151 | }; | 151 | }; |
152 | 152 | ||
153 | static ssize_t force_tx_status_read(struct file *file, | ||
154 | char __user *user_buf, | ||
155 | size_t count, | ||
156 | loff_t *ppos) | ||
157 | { | ||
158 | struct ieee80211_local *local = file->private_data; | ||
159 | char buf[3]; | ||
160 | int len = 0; | ||
161 | |||
162 | len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status); | ||
163 | |||
164 | return simple_read_from_buffer(user_buf, count, ppos, | ||
165 | buf, len); | ||
166 | } | ||
167 | |||
168 | static ssize_t force_tx_status_write(struct file *file, | ||
169 | const char __user *user_buf, | ||
170 | size_t count, | ||
171 | loff_t *ppos) | ||
172 | { | ||
173 | struct ieee80211_local *local = file->private_data; | ||
174 | char buf[3]; | ||
175 | size_t len; | ||
176 | |||
177 | if (count > sizeof(buf)) | ||
178 | return -EINVAL; | ||
179 | |||
180 | if (copy_from_user(buf, user_buf, count)) | ||
181 | return -EFAULT; | ||
182 | |||
183 | buf[sizeof(buf) - 1] = '\0'; | ||
184 | len = strlen(buf); | ||
185 | if (len > 0 && buf[len - 1] == '\n') | ||
186 | buf[len - 1] = 0; | ||
187 | |||
188 | if (buf[0] == '0' && buf[1] == '\0') | ||
189 | local->force_tx_status = 0; | ||
190 | else if (buf[0] == '1' && buf[1] == '\0') | ||
191 | local->force_tx_status = 1; | ||
192 | else | ||
193 | return -EINVAL; | ||
194 | |||
195 | return count; | ||
196 | } | ||
197 | |||
198 | static const struct file_operations force_tx_status_ops = { | ||
199 | .write = force_tx_status_write, | ||
200 | .read = force_tx_status_read, | ||
201 | .open = simple_open, | ||
202 | .llseek = default_llseek, | ||
203 | }; | ||
204 | |||
153 | #ifdef CONFIG_PM | 205 | #ifdef CONFIG_PM |
154 | static ssize_t reset_write(struct file *file, const char __user *user_buf, | 206 | static ssize_t reset_write(struct file *file, const char __user *user_buf, |
155 | size_t count, loff_t *ppos) | 207 | size_t count, loff_t *ppos) |
@@ -221,6 +273,7 @@ static const char *hw_flag_names[] = { | |||
221 | FLAG(TX_STATUS_NO_AMPDU_LEN), | 273 | FLAG(TX_STATUS_NO_AMPDU_LEN), |
222 | FLAG(SUPPORTS_MULTI_BSSID), | 274 | FLAG(SUPPORTS_MULTI_BSSID), |
223 | FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), | 275 | FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), |
276 | FLAG(EXT_KEY_ID_NATIVE), | ||
224 | #undef FLAG | 277 | #undef FLAG |
225 | }; | 278 | }; |
226 | 279 | ||
@@ -382,6 +435,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
382 | DEBUGFS_ADD(hwflags); | 435 | DEBUGFS_ADD(hwflags); |
383 | DEBUGFS_ADD(user_power); | 436 | DEBUGFS_ADD(user_power); |
384 | DEBUGFS_ADD(power); | 437 | DEBUGFS_ADD(power); |
438 | DEBUGFS_ADD_MODE(force_tx_status, 0600); | ||
385 | 439 | ||
386 | if (local->ops->wake_tx_queue) | 440 | if (local->ops->wake_tx_queue) |
387 | DEBUGFS_ADD_MODE(aqm, 0600); | 441 | DEBUGFS_ADD_MODE(aqm, 0600); |
diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c index bb886e7db47f..839c0022a29c 100644 --- a/net/mac80211/driver-ops.c +++ b/net/mac80211/driver-ops.c | |||
@@ -138,6 +138,27 @@ int drv_sta_state(struct ieee80211_local *local, | |||
138 | return ret; | 138 | return ret; |
139 | } | 139 | } |
140 | 140 | ||
141 | __must_check | ||
142 | int drv_sta_set_txpwr(struct ieee80211_local *local, | ||
143 | struct ieee80211_sub_if_data *sdata, | ||
144 | struct sta_info *sta) | ||
145 | { | ||
146 | int ret = -EOPNOTSUPP; | ||
147 | |||
148 | might_sleep(); | ||
149 | |||
150 | sdata = get_bss_sdata(sdata); | ||
151 | if (!check_sdata_in_driver(sdata)) | ||
152 | return -EIO; | ||
153 | |||
154 | trace_drv_sta_set_txpwr(local, sdata, &sta->sta); | ||
155 | if (local->ops->sta_set_txpwr) | ||
156 | ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif, | ||
157 | &sta->sta); | ||
158 | trace_drv_return_int(local, ret); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
141 | void drv_sta_rc_update(struct ieee80211_local *local, | 162 | void drv_sta_rc_update(struct ieee80211_local *local, |
142 | struct ieee80211_sub_if_data *sdata, | 163 | struct ieee80211_sub_if_data *sdata, |
143 | struct ieee80211_sta *sta, u32 changed) | 164 | struct ieee80211_sta *sta, u32 changed) |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index ae4f0be3b393..c2d8b5451a5e 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -529,6 +529,11 @@ int drv_sta_state(struct ieee80211_local *local, | |||
529 | enum ieee80211_sta_state old_state, | 529 | enum ieee80211_sta_state old_state, |
530 | enum ieee80211_sta_state new_state); | 530 | enum ieee80211_sta_state new_state); |
531 | 531 | ||
532 | __must_check | ||
533 | int drv_sta_set_txpwr(struct ieee80211_local *local, | ||
534 | struct ieee80211_sub_if_data *sdata, | ||
535 | struct sta_info *sta); | ||
536 | |||
532 | void drv_sta_rc_update(struct ieee80211_local *local, | 537 | void drv_sta_rc_update(struct ieee80211_local *local, |
533 | struct ieee80211_sub_if_data *sdata, | 538 | struct ieee80211_sub_if_data *sdata, |
534 | struct ieee80211_sta *sta, u32 changed); | 539 | struct ieee80211_sta *sta, u32 changed); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e170f986d226..073a8235ae1b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1269,7 +1269,7 @@ struct ieee80211_local { | |||
1269 | 1269 | ||
1270 | /* | 1270 | /* |
1271 | * Key mutex, protects sdata's key_list and sta_info's | 1271 | * Key mutex, protects sdata's key_list and sta_info's |
1272 | * key pointers (write access, they're RCU.) | 1272 | * key pointers and ptk_idx (write access, they're RCU.) |
1273 | */ | 1273 | */ |
1274 | struct mutex key_mtx; | 1274 | struct mutex key_mtx; |
1275 | 1275 | ||
@@ -1384,6 +1384,7 @@ struct ieee80211_local { | |||
1384 | struct dentry *rcdir; | 1384 | struct dentry *rcdir; |
1385 | struct dentry *keys; | 1385 | struct dentry *keys; |
1386 | } debugfs; | 1386 | } debugfs; |
1387 | bool force_tx_status; | ||
1387 | #endif | 1388 | #endif |
1388 | 1389 | ||
1389 | /* | 1390 | /* |
@@ -1505,7 +1506,6 @@ struct ieee802_11_elems { | |||
1505 | const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie; | 1506 | const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie; |
1506 | const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie; | 1507 | const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie; |
1507 | const struct ieee80211_bssid_index *bssid_index; | 1508 | const struct ieee80211_bssid_index *bssid_index; |
1508 | const u8 *nontransmitted_bssid_profile; | ||
1509 | u8 max_bssid_indicator; | 1509 | u8 max_bssid_indicator; |
1510 | u8 dtim_count; | 1510 | u8 dtim_count; |
1511 | u8 dtim_period; | 1511 | u8 dtim_period; |
@@ -1761,7 +1761,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1761 | struct net_device *dev); | 1761 | struct net_device *dev); |
1762 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | 1762 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
1763 | struct net_device *dev, | 1763 | struct net_device *dev, |
1764 | u32 info_flags); | 1764 | u32 info_flags, |
1765 | u32 ctrl_flags); | ||
1765 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | 1766 | void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, |
1766 | struct sk_buff_head *skbs); | 1767 | struct sk_buff_head *skbs); |
1767 | struct sk_buff * | 1768 | struct sk_buff * |
@@ -1778,6 +1779,8 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta); | |||
1778 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, | 1779 | int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, |
1779 | const u8 *buf, size_t len, | 1780 | const u8 *buf, size_t len, |
1780 | const u8 *dest, __be16 proto, bool unencrypted); | 1781 | const u8 *dest, __be16 proto, bool unencrypted); |
1782 | int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, | ||
1783 | const u8 *buf, size_t len); | ||
1781 | 1784 | ||
1782 | /* HT */ | 1785 | /* HT */ |
1783 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1786 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f0d97eba250b..94459b2b3d2a 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1225,6 +1225,7 @@ static void ieee80211_if_setup(struct net_device *dev) | |||
1225 | static void ieee80211_if_setup_no_queue(struct net_device *dev) | 1225 | static void ieee80211_if_setup_no_queue(struct net_device *dev) |
1226 | { | 1226 | { |
1227 | ieee80211_if_setup(dev); | 1227 | ieee80211_if_setup(dev); |
1228 | dev->features |= NETIF_F_LLTX; | ||
1228 | dev->priv_flags |= IFF_NO_QUEUE; | 1229 | dev->priv_flags |= IFF_NO_QUEUE; |
1229 | } | 1230 | } |
1230 | 1231 | ||
@@ -1762,13 +1763,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1762 | txq_size += sizeof(struct txq_info) + | 1763 | txq_size += sizeof(struct txq_info) + |
1763 | local->hw.txq_data_size; | 1764 | local->hw.txq_data_size; |
1764 | 1765 | ||
1765 | if (local->ops->wake_tx_queue) | 1766 | if (local->ops->wake_tx_queue) { |
1766 | if_setup = ieee80211_if_setup_no_queue; | 1767 | if_setup = ieee80211_if_setup_no_queue; |
1767 | else | 1768 | } else { |
1768 | if_setup = ieee80211_if_setup; | 1769 | if_setup = ieee80211_if_setup; |
1769 | 1770 | if (local->hw.queues >= IEEE80211_NUM_ACS) | |
1770 | if (local->hw.queues >= IEEE80211_NUM_ACS) | 1771 | txqs = IEEE80211_NUM_ACS; |
1771 | txqs = IEEE80211_NUM_ACS; | 1772 | } |
1772 | 1773 | ||
1773 | ndev = alloc_netdev_mqs(size + txq_size, | 1774 | ndev = alloc_netdev_mqs(size + txq_size, |
1774 | name, name_assign_type, | 1775 | name, name_assign_type, |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 37e372896230..20bf9db7a388 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -140,6 +140,12 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
140 | * so clear that flag now to avoid trying to remove | 140 | * so clear that flag now to avoid trying to remove |
141 | * it again later. | 141 | * it again later. |
142 | */ | 142 | */ |
143 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | ||
144 | !(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | | ||
145 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE | | ||
146 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | ||
147 | increment_tailroom_need_count(sdata); | ||
148 | |||
143 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 149 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
144 | return -EINVAL; | 150 | return -EINVAL; |
145 | } | 151 | } |
@@ -179,9 +185,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
179 | if (!ret) { | 185 | if (!ret) { |
180 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 186 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
181 | 187 | ||
182 | if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | | 188 | if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
183 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) || | 189 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
184 | (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | 190 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
185 | decrease_tailroom_need_count(sdata, 1); | 191 | decrease_tailroom_need_count(sdata, 1); |
186 | 192 | ||
187 | WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && | 193 | WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && |
@@ -242,9 +248,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
242 | sta = key->sta; | 248 | sta = key->sta; |
243 | sdata = key->sdata; | 249 | sdata = key->sdata; |
244 | 250 | ||
245 | if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | | 251 | if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
246 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) || | 252 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
247 | (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | 253 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
248 | increment_tailroom_need_count(sdata); | 254 | increment_tailroom_need_count(sdata); |
249 | 255 | ||
250 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 256 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
@@ -258,9 +264,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
258 | sta ? sta->sta.addr : bcast_addr, ret); | 264 | sta ? sta->sta.addr : bcast_addr, ret); |
259 | } | 265 | } |
260 | 266 | ||
267 | int ieee80211_set_tx_key(struct ieee80211_key *key) | ||
268 | { | ||
269 | struct sta_info *sta = key->sta; | ||
270 | struct ieee80211_local *local = key->local; | ||
271 | struct ieee80211_key *old; | ||
272 | |||
273 | assert_key_lock(local); | ||
274 | |||
275 | old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]); | ||
276 | sta->ptk_idx = key->conf.keyidx; | ||
277 | ieee80211_check_fast_xmit(sta); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
261 | static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, | 282 | static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, |
262 | struct ieee80211_key *new_key, | 283 | struct ieee80211_key *new_key, |
263 | bool ptk0rekey) | 284 | bool pairwise) |
264 | { | 285 | { |
265 | struct ieee80211_sub_if_data *sdata; | 286 | struct ieee80211_sub_if_data *sdata; |
266 | struct ieee80211_local *local; | 287 | struct ieee80211_local *local; |
@@ -277,8 +298,9 @@ static int ieee80211_hw_key_replace(struct ieee80211_key *old_key, | |||
277 | assert_key_lock(old_key->local); | 298 | assert_key_lock(old_key->local); |
278 | sta = old_key->sta; | 299 | sta = old_key->sta; |
279 | 300 | ||
280 | /* PTK only using key ID 0 needs special handling on rekey */ | 301 | /* Unicast rekey without Extended Key ID needs special handling */ |
281 | if (new_key && sta && ptk0rekey) { | 302 | if (new_key && sta && pairwise && |
303 | rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) { | ||
282 | local = old_key->local; | 304 | local = old_key->local; |
283 | sdata = old_key->sdata; | 305 | sdata = old_key->sdata; |
284 | 306 | ||
@@ -394,10 +416,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
394 | 416 | ||
395 | if (old) { | 417 | if (old) { |
396 | idx = old->conf.keyidx; | 418 | idx = old->conf.keyidx; |
397 | /* TODO: proper implement and test "Extended Key ID for | ||
398 | * Individually Addressed Frames" from IEEE 802.11-2016. | ||
399 | * Till then always assume only key ID 0 is used for | ||
400 | * pairwise keys.*/ | ||
401 | ret = ieee80211_hw_key_replace(old, new, pairwise); | 419 | ret = ieee80211_hw_key_replace(old, new, pairwise); |
402 | } else { | 420 | } else { |
403 | /* new must be provided in case old is not */ | 421 | /* new must be provided in case old is not */ |
@@ -414,15 +432,20 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | |||
414 | if (sta) { | 432 | if (sta) { |
415 | if (pairwise) { | 433 | if (pairwise) { |
416 | rcu_assign_pointer(sta->ptk[idx], new); | 434 | rcu_assign_pointer(sta->ptk[idx], new); |
417 | sta->ptk_idx = idx; | 435 | if (new && |
418 | if (new) { | 436 | !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) { |
437 | sta->ptk_idx = idx; | ||
419 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | 438 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); |
420 | ieee80211_check_fast_xmit(sta); | 439 | ieee80211_check_fast_xmit(sta); |
421 | } | 440 | } |
422 | } else { | 441 | } else { |
423 | rcu_assign_pointer(sta->gtk[idx], new); | 442 | rcu_assign_pointer(sta->gtk[idx], new); |
424 | } | 443 | } |
425 | if (new) | 444 | /* Only needed for transition from no key -> key. |
445 | * Still triggers unnecessary when using Extended Key ID | ||
446 | * and installing the second key ID the first time. | ||
447 | */ | ||
448 | if (new && !old) | ||
426 | ieee80211_check_fast_rx(sta); | 449 | ieee80211_check_fast_rx(sta); |
427 | } else { | 450 | } else { |
428 | defunikey = old && | 451 | defunikey = old && |
@@ -738,16 +761,34 @@ int ieee80211_key_link(struct ieee80211_key *key, | |||
738 | * can cause warnings to appear. | 761 | * can cause warnings to appear. |
739 | */ | 762 | */ |
740 | bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; | 763 | bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; |
741 | int ret; | 764 | int ret = -EOPNOTSUPP; |
742 | 765 | ||
743 | mutex_lock(&sdata->local->key_mtx); | 766 | mutex_lock(&sdata->local->key_mtx); |
744 | 767 | ||
745 | if (sta && pairwise) | 768 | if (sta && pairwise) { |
769 | struct ieee80211_key *alt_key; | ||
770 | |||
746 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); | 771 | old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]); |
747 | else if (sta) | 772 | alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]); |
773 | |||
774 | /* The rekey code assumes that the old and new key are using | ||
775 | * the same cipher. Enforce the assumption for pairwise keys. | ||
776 | */ | ||
777 | if (key && | ||
778 | ((alt_key && alt_key->conf.cipher != key->conf.cipher) || | ||
779 | (old_key && old_key->conf.cipher != key->conf.cipher))) | ||
780 | goto out; | ||
781 | } else if (sta) { | ||
748 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); | 782 | old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]); |
749 | else | 783 | } else { |
750 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); | 784 | old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); |
785 | } | ||
786 | |||
787 | /* Non-pairwise keys must also not switch the cipher on rekey */ | ||
788 | if (!pairwise) { | ||
789 | if (key && old_key && old_key->conf.cipher != key->conf.cipher) | ||
790 | goto out; | ||
791 | } | ||
751 | 792 | ||
752 | /* | 793 | /* |
753 | * Silently accept key re-installation without really installing the | 794 | * Silently accept key re-installation without really installing the |
@@ -1187,9 +1228,9 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf) | |||
1187 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 1228 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { |
1188 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | 1229 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
1189 | 1230 | ||
1190 | if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | | 1231 | if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC | |
1191 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) || | 1232 | IEEE80211_KEY_FLAG_PUT_MIC_SPACE | |
1192 | (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) | 1233 | IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) |
1193 | increment_tailroom_need_count(key->sdata); | 1234 | increment_tailroom_need_count(key->sdata); |
1194 | } | 1235 | } |
1195 | 1236 | ||
diff --git a/net/mac80211/key.h b/net/mac80211/key.h index ebdb80b85dc3..f06fbd03d235 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #define NUM_DEFAULT_KEYS 4 | 19 | #define NUM_DEFAULT_KEYS 4 |
20 | #define NUM_DEFAULT_MGMT_KEYS 2 | 20 | #define NUM_DEFAULT_MGMT_KEYS 2 |
21 | #define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */ | ||
21 | 22 | ||
22 | struct ieee80211_local; | 23 | struct ieee80211_local; |
23 | struct ieee80211_sub_if_data; | 24 | struct ieee80211_sub_if_data; |
@@ -146,6 +147,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len, | |||
146 | int ieee80211_key_link(struct ieee80211_key *key, | 147 | int ieee80211_key_link(struct ieee80211_key *key, |
147 | struct ieee80211_sub_if_data *sdata, | 148 | struct ieee80211_sub_if_data *sdata, |
148 | struct sta_info *sta); | 149 | struct sta_info *sta); |
150 | int ieee80211_set_tx_key(struct ieee80211_key *key); | ||
149 | void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); | 151 | void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom); |
150 | void ieee80211_key_free_unused(struct ieee80211_key *key); | 152 | void ieee80211_key_free_unused(struct ieee80211_key *key); |
151 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, | 153 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 800e67615e2a..2b608044ae23 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -1051,6 +1051,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1051 | } | 1051 | } |
1052 | } | 1052 | } |
1053 | 1053 | ||
1054 | /* Enable Extended Key IDs when driver allowed it, or when it | ||
1055 | * supports neither HW crypto nor A-MPDUs | ||
1056 | */ | ||
1057 | if ((!local->ops->set_key && | ||
1058 | !ieee80211_hw_check(hw, AMPDU_AGGREGATION)) || | ||
1059 | ieee80211_hw_check(&local->hw, EXT_KEY_ID_NATIVE)) | ||
1060 | wiphy_ext_feature_set(local->hw.wiphy, | ||
1061 | NL80211_EXT_FEATURE_EXT_KEY_ID); | ||
1062 | |||
1063 | /* Mac80211 and therefore all cards only using SW crypto are able to | ||
1064 | * handle PTK rekeys correctly | ||
1065 | */ | ||
1066 | if (!local->ops->set_key) | ||
1067 | wiphy_ext_feature_set(local->hw.wiphy, | ||
1068 | NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); | ||
1069 | |||
1054 | /* | 1070 | /* |
1055 | * Calculate scan IE length -- we need this to alloc | 1071 | * Calculate scan IE length -- we need this to alloc |
1056 | * memory and to subtract from the driver limit. It | 1072 | * memory and to subtract from the driver limit. It |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 574c3891c4b2..88535a2e62bc 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -278,6 +278,8 @@ mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst); | |||
278 | int mesh_path_add_gate(struct mesh_path *mpath); | 278 | int mesh_path_add_gate(struct mesh_path *mpath); |
279 | int mesh_path_send_to_gates(struct mesh_path *mpath); | 279 | int mesh_path_send_to_gates(struct mesh_path *mpath); |
280 | int mesh_gate_num(struct ieee80211_sub_if_data *sdata); | 280 | int mesh_gate_num(struct ieee80211_sub_if_data *sdata); |
281 | u32 airtime_link_metric_get(struct ieee80211_local *local, | ||
282 | struct sta_info *sta); | ||
281 | 283 | ||
282 | /* Mesh plinks */ | 284 | /* Mesh plinks */ |
283 | void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, | 285 | void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f7517668e77a..bf8e13cd5fd1 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -318,8 +318,8 @@ void ieee80211s_update_metric(struct ieee80211_local *local, | |||
318 | cfg80211_calculate_bitrate(&rinfo)); | 318 | cfg80211_calculate_bitrate(&rinfo)); |
319 | } | 319 | } |
320 | 320 | ||
321 | static u32 airtime_link_metric_get(struct ieee80211_local *local, | 321 | u32 airtime_link_metric_get(struct ieee80211_local *local, |
322 | struct sta_info *sta) | 322 | struct sta_info *sta) |
323 | { | 323 | { |
324 | /* This should be adjusted for each device */ | 324 | /* This should be adjusted for each device */ |
325 | int device_constant = 1 << ARITH_SHIFT; | 325 | int device_constant = 1 << ARITH_SHIFT; |
@@ -1130,16 +1130,17 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata, | |||
1130 | struct mesh_path *mpath; | 1130 | struct mesh_path *mpath; |
1131 | struct sk_buff *skb_to_free = NULL; | 1131 | struct sk_buff *skb_to_free = NULL; |
1132 | u8 *target_addr = hdr->addr3; | 1132 | u8 *target_addr = hdr->addr3; |
1133 | int err = 0; | ||
1134 | 1133 | ||
1135 | /* Nulls are only sent to peers for PS and should be pre-addressed */ | 1134 | /* Nulls are only sent to peers for PS and should be pre-addressed */ |
1136 | if (ieee80211_is_qos_nullfunc(hdr->frame_control)) | 1135 | if (ieee80211_is_qos_nullfunc(hdr->frame_control)) |
1137 | return 0; | 1136 | return 0; |
1138 | 1137 | ||
1139 | rcu_read_lock(); | 1138 | /* Allow injected packets to bypass mesh routing */ |
1140 | err = mesh_nexthop_lookup(sdata, skb); | 1139 | if (info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) |
1141 | if (!err) | 1140 | return 0; |
1142 | goto endlookup; | 1141 | |
1142 | if (!mesh_nexthop_lookup(sdata, skb)) | ||
1143 | return 0; | ||
1143 | 1144 | ||
1144 | /* no nexthop found, start resolving */ | 1145 | /* no nexthop found, start resolving */ |
1145 | mpath = mesh_path_lookup(sdata, target_addr); | 1146 | mpath = mesh_path_lookup(sdata, target_addr); |
@@ -1147,8 +1148,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata, | |||
1147 | mpath = mesh_path_add(sdata, target_addr); | 1148 | mpath = mesh_path_add(sdata, target_addr); |
1148 | if (IS_ERR(mpath)) { | 1149 | if (IS_ERR(mpath)) { |
1149 | mesh_path_discard_frame(sdata, skb); | 1150 | mesh_path_discard_frame(sdata, skb); |
1150 | err = PTR_ERR(mpath); | 1151 | return PTR_ERR(mpath); |
1151 | goto endlookup; | ||
1152 | } | 1152 | } |
1153 | } | 1153 | } |
1154 | 1154 | ||
@@ -1161,13 +1161,10 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata, | |||
1161 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 1161 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1162 | ieee80211_set_qos_hdr(sdata, skb); | 1162 | ieee80211_set_qos_hdr(sdata, skb); |
1163 | skb_queue_tail(&mpath->frame_queue, skb); | 1163 | skb_queue_tail(&mpath->frame_queue, skb); |
1164 | err = -ENOENT; | ||
1165 | if (skb_to_free) | 1164 | if (skb_to_free) |
1166 | mesh_path_discard_frame(sdata, skb_to_free); | 1165 | mesh_path_discard_frame(sdata, skb_to_free); |
1167 | 1166 | ||
1168 | endlookup: | 1167 | return -ENOENT; |
1169 | rcu_read_unlock(); | ||
1170 | return err; | ||
1171 | } | 1168 | } |
1172 | 1169 | ||
1173 | /** | 1170 | /** |
@@ -1187,13 +1184,10 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata, | |||
1187 | struct sta_info *next_hop; | 1184 | struct sta_info *next_hop; |
1188 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 1185 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1189 | u8 *target_addr = hdr->addr3; | 1186 | u8 *target_addr = hdr->addr3; |
1190 | int err = -ENOENT; | ||
1191 | 1187 | ||
1192 | rcu_read_lock(); | ||
1193 | mpath = mesh_path_lookup(sdata, target_addr); | 1188 | mpath = mesh_path_lookup(sdata, target_addr); |
1194 | |||
1195 | if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE)) | 1189 | if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE)) |
1196 | goto endlookup; | 1190 | return -ENOENT; |
1197 | 1191 | ||
1198 | if (time_after(jiffies, | 1192 | if (time_after(jiffies, |
1199 | mpath->exp_time - | 1193 | mpath->exp_time - |
@@ -1208,12 +1202,10 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata, | |||
1208 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); | 1202 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); |
1209 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | 1203 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
1210 | ieee80211_mps_set_frame_flags(sdata, next_hop, hdr); | 1204 | ieee80211_mps_set_frame_flags(sdata, next_hop, hdr); |
1211 | err = 0; | 1205 | return 0; |
1212 | } | 1206 | } |
1213 | 1207 | ||
1214 | endlookup: | 1208 | return -ENOENT; |
1215 | rcu_read_unlock(); | ||
1216 | return err; | ||
1217 | } | 1209 | } |
1218 | 1210 | ||
1219 | void mesh_path_timer(struct timer_list *t) | 1211 | void mesh_path_timer(struct timer_list *t) |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index b76a2aefa9ec..796b069ad251 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -217,7 +217,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst, | |||
217 | { | 217 | { |
218 | struct mesh_path *mpath; | 218 | struct mesh_path *mpath; |
219 | 219 | ||
220 | mpath = rhashtable_lookup_fast(&tbl->rhead, dst, mesh_rht_params); | 220 | mpath = rhashtable_lookup(&tbl->rhead, dst, mesh_rht_params); |
221 | 221 | ||
222 | if (mpath && mpath_expired(mpath)) { | 222 | if (mpath && mpath_expired(mpath)) { |
223 | spin_lock_bh(&mpath->state_lock); | 223 | spin_lock_bh(&mpath->state_lock); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2dbcf5d5512e..b7a9fe3d5fcb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1188,9 +1188,6 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1188 | goto out; | 1188 | goto out; |
1189 | } | 1189 | } |
1190 | 1190 | ||
1191 | /* XXX: shouldn't really modify cfg80211-owned data! */ | ||
1192 | ifmgd->associated->channel = sdata->csa_chandef.chan; | ||
1193 | |||
1194 | ifmgd->csa_waiting_bcn = true; | 1191 | ifmgd->csa_waiting_bcn = true; |
1195 | 1192 | ||
1196 | ieee80211_sta_reset_beacon_monitor(sdata); | 1193 | ieee80211_sta_reset_beacon_monitor(sdata); |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index ccaf951e4e31..8b168724c5e7 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -51,8 +51,13 @@ | |||
51 | MINSTREL_MAX_STREAMS * _sgi + \ | 51 | MINSTREL_MAX_STREAMS * _sgi + \ |
52 | _streams - 1 | 52 | _streams - 1 |
53 | 53 | ||
54 | #define _MAX(a, b) (((a)>(b))?(a):(b)) | ||
55 | |||
56 | #define GROUP_SHIFT(duration) \ | ||
57 | _MAX(0, 16 - __builtin_clz(duration)) | ||
58 | |||
54 | /* MCS rate information for an MCS group */ | 59 | /* MCS rate information for an MCS group */ |
55 | #define MCS_GROUP(_streams, _sgi, _ht40, _s) \ | 60 | #define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ |
56 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ | 61 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ |
57 | .streams = _streams, \ | 62 | .streams = _streams, \ |
58 | .shift = _s, \ | 63 | .shift = _s, \ |
@@ -72,6 +77,13 @@ | |||
72 | } \ | 77 | } \ |
73 | } | 78 | } |
74 | 79 | ||
80 | #define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ | ||
81 | GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) | ||
82 | |||
83 | #define MCS_GROUP(_streams, _sgi, _ht40) \ | ||
84 | __MCS_GROUP(_streams, _sgi, _ht40, \ | ||
85 | MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) | ||
86 | |||
75 | #define VHT_GROUP_IDX(_streams, _sgi, _bw) \ | 87 | #define VHT_GROUP_IDX(_streams, _sgi, _bw) \ |
76 | (MINSTREL_VHT_GROUP_0 + \ | 88 | (MINSTREL_VHT_GROUP_0 + \ |
77 | MINSTREL_MAX_STREAMS * 2 * (_bw) + \ | 89 | MINSTREL_MAX_STREAMS * 2 * (_bw) + \ |
@@ -81,7 +93,7 @@ | |||
81 | #define BW2VBPS(_bw, r3, r2, r1) \ | 93 | #define BW2VBPS(_bw, r3, r2, r1) \ |
82 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) | 94 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) |
83 | 95 | ||
84 | #define VHT_GROUP(_streams, _sgi, _bw, _s) \ | 96 | #define __VHT_GROUP(_streams, _sgi, _bw, _s) \ |
85 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ | 97 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ |
86 | .streams = _streams, \ | 98 | .streams = _streams, \ |
87 | .shift = _s, \ | 99 | .shift = _s, \ |
@@ -114,6 +126,14 @@ | |||
114 | } \ | 126 | } \ |
115 | } | 127 | } |
116 | 128 | ||
129 | #define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ | ||
130 | GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ | ||
131 | BW2VBPS(_bw, 117, 54, 26))) | ||
132 | |||
133 | #define VHT_GROUP(_streams, _sgi, _bw) \ | ||
134 | __VHT_GROUP(_streams, _sgi, _bw, \ | ||
135 | VHT_GROUP_SHIFT(_streams, _sgi, _bw)) | ||
136 | |||
117 | #define CCK_DURATION(_bitrate, _short, _len) \ | 137 | #define CCK_DURATION(_bitrate, _short, _len) \ |
118 | (1000 * (10 /* SIFS */ + \ | 138 | (1000 * (10 /* SIFS */ + \ |
119 | (_short ? 72 + 24 : 144 + 48) + \ | 139 | (_short ? 72 + 24 : 144 + 48) + \ |
@@ -129,7 +149,7 @@ | |||
129 | CCK_ACK_DURATION(55, _short) >> _s, \ | 149 | CCK_ACK_DURATION(55, _short) >> _s, \ |
130 | CCK_ACK_DURATION(110, _short) >> _s | 150 | CCK_ACK_DURATION(110, _short) >> _s |
131 | 151 | ||
132 | #define CCK_GROUP(_s) \ | 152 | #define __CCK_GROUP(_s) \ |
133 | [MINSTREL_CCK_GROUP] = { \ | 153 | [MINSTREL_CCK_GROUP] = { \ |
134 | .streams = 1, \ | 154 | .streams = 1, \ |
135 | .flags = 0, \ | 155 | .flags = 0, \ |
@@ -140,6 +160,12 @@ | |||
140 | } \ | 160 | } \ |
141 | } | 161 | } |
142 | 162 | ||
163 | #define CCK_GROUP_SHIFT \ | ||
164 | GROUP_SHIFT(CCK_ACK_DURATION(10, false)) | ||
165 | |||
166 | #define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT) | ||
167 | |||
168 | |||
143 | static bool minstrel_vht_only = true; | 169 | static bool minstrel_vht_only = true; |
144 | module_param(minstrel_vht_only, bool, 0644); | 170 | module_param(minstrel_vht_only, bool, 0644); |
145 | MODULE_PARM_DESC(minstrel_vht_only, | 171 | MODULE_PARM_DESC(minstrel_vht_only, |
@@ -154,47 +180,57 @@ MODULE_PARM_DESC(minstrel_vht_only, | |||
154 | * BW -> SGI -> #streams | 180 | * BW -> SGI -> #streams |
155 | */ | 181 | */ |
156 | const struct mcs_group minstrel_mcs_groups[] = { | 182 | const struct mcs_group minstrel_mcs_groups[] = { |
157 | MCS_GROUP(1, 0, BW_20, 5), | 183 | MCS_GROUP(1, 0, BW_20), |
158 | MCS_GROUP(2, 0, BW_20, 4), | 184 | MCS_GROUP(2, 0, BW_20), |
159 | MCS_GROUP(3, 0, BW_20, 4), | 185 | MCS_GROUP(3, 0, BW_20), |
160 | 186 | MCS_GROUP(4, 0, BW_20), | |
161 | MCS_GROUP(1, 1, BW_20, 5), | 187 | |
162 | MCS_GROUP(2, 1, BW_20, 4), | 188 | MCS_GROUP(1, 1, BW_20), |
163 | MCS_GROUP(3, 1, BW_20, 4), | 189 | MCS_GROUP(2, 1, BW_20), |
164 | 190 | MCS_GROUP(3, 1, BW_20), | |
165 | MCS_GROUP(1, 0, BW_40, 4), | 191 | MCS_GROUP(4, 1, BW_20), |
166 | MCS_GROUP(2, 0, BW_40, 4), | 192 | |
167 | MCS_GROUP(3, 0, BW_40, 4), | 193 | MCS_GROUP(1, 0, BW_40), |
168 | 194 | MCS_GROUP(2, 0, BW_40), | |
169 | MCS_GROUP(1, 1, BW_40, 4), | 195 | MCS_GROUP(3, 0, BW_40), |
170 | MCS_GROUP(2, 1, BW_40, 4), | 196 | MCS_GROUP(4, 0, BW_40), |
171 | MCS_GROUP(3, 1, BW_40, 4), | 197 | |
172 | 198 | MCS_GROUP(1, 1, BW_40), | |
173 | CCK_GROUP(8), | 199 | MCS_GROUP(2, 1, BW_40), |
174 | 200 | MCS_GROUP(3, 1, BW_40), | |
175 | VHT_GROUP(1, 0, BW_20, 5), | 201 | MCS_GROUP(4, 1, BW_40), |
176 | VHT_GROUP(2, 0, BW_20, 4), | 202 | |
177 | VHT_GROUP(3, 0, BW_20, 4), | 203 | CCK_GROUP, |
178 | 204 | ||
179 | VHT_GROUP(1, 1, BW_20, 5), | 205 | VHT_GROUP(1, 0, BW_20), |
180 | VHT_GROUP(2, 1, BW_20, 4), | 206 | VHT_GROUP(2, 0, BW_20), |
181 | VHT_GROUP(3, 1, BW_20, 4), | 207 | VHT_GROUP(3, 0, BW_20), |
182 | 208 | VHT_GROUP(4, 0, BW_20), | |
183 | VHT_GROUP(1, 0, BW_40, 4), | 209 | |
184 | VHT_GROUP(2, 0, BW_40, 4), | 210 | VHT_GROUP(1, 1, BW_20), |
185 | VHT_GROUP(3, 0, BW_40, 4), | 211 | VHT_GROUP(2, 1, BW_20), |
186 | 212 | VHT_GROUP(3, 1, BW_20), | |
187 | VHT_GROUP(1, 1, BW_40, 4), | 213 | VHT_GROUP(4, 1, BW_20), |
188 | VHT_GROUP(2, 1, BW_40, 4), | 214 | |
189 | VHT_GROUP(3, 1, BW_40, 4), | 215 | VHT_GROUP(1, 0, BW_40), |
190 | 216 | VHT_GROUP(2, 0, BW_40), | |
191 | VHT_GROUP(1, 0, BW_80, 4), | 217 | VHT_GROUP(3, 0, BW_40), |
192 | VHT_GROUP(2, 0, BW_80, 4), | 218 | VHT_GROUP(4, 0, BW_40), |
193 | VHT_GROUP(3, 0, BW_80, 4), | 219 | |
194 | 220 | VHT_GROUP(1, 1, BW_40), | |
195 | VHT_GROUP(1, 1, BW_80, 4), | 221 | VHT_GROUP(2, 1, BW_40), |
196 | VHT_GROUP(2, 1, BW_80, 4), | 222 | VHT_GROUP(3, 1, BW_40), |
197 | VHT_GROUP(3, 1, BW_80, 4), | 223 | VHT_GROUP(4, 1, BW_40), |
224 | |||
225 | VHT_GROUP(1, 0, BW_80), | ||
226 | VHT_GROUP(2, 0, BW_80), | ||
227 | VHT_GROUP(3, 0, BW_80), | ||
228 | VHT_GROUP(4, 0, BW_80), | ||
229 | |||
230 | VHT_GROUP(1, 1, BW_80), | ||
231 | VHT_GROUP(2, 1, BW_80), | ||
232 | VHT_GROUP(3, 1, BW_80), | ||
233 | VHT_GROUP(4, 1, BW_80), | ||
198 | }; | 234 | }; |
199 | 235 | ||
200 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; | 236 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 26b7a3244b47..f762e5ba7c2e 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -13,7 +13,7 @@ | |||
13 | * The number of streams can be changed to 2 to reduce code | 13 | * The number of streams can be changed to 2 to reduce code |
14 | * size and memory footprint. | 14 | * size and memory footprint. |
15 | */ | 15 | */ |
16 | #define MINSTREL_MAX_STREAMS 3 | 16 | #define MINSTREL_MAX_STREAMS 4 |
17 | #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ | 17 | #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ |
18 | #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ | 18 | #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ |
19 | 19 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index bf0b187f994e..25577ede2986 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1005,23 +1005,43 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb) | |||
1005 | return -1; | 1005 | return -1; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs, | 1008 | static int ieee80211_get_keyid(struct sk_buff *skb, |
1009 | struct sk_buff *skb) | 1009 | const struct ieee80211_cipher_scheme *cs) |
1010 | { | 1010 | { |
1011 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1011 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1012 | __le16 fc; | 1012 | __le16 fc; |
1013 | int hdrlen; | 1013 | int hdrlen; |
1014 | int minlen; | ||
1015 | u8 key_idx_off; | ||
1016 | u8 key_idx_shift; | ||
1014 | u8 keyid; | 1017 | u8 keyid; |
1015 | 1018 | ||
1016 | fc = hdr->frame_control; | 1019 | fc = hdr->frame_control; |
1017 | hdrlen = ieee80211_hdrlen(fc); | 1020 | hdrlen = ieee80211_hdrlen(fc); |
1018 | 1021 | ||
1019 | if (skb->len < hdrlen + cs->hdr_len) | 1022 | if (cs) { |
1023 | minlen = hdrlen + cs->hdr_len; | ||
1024 | key_idx_off = hdrlen + cs->key_idx_off; | ||
1025 | key_idx_shift = cs->key_idx_shift; | ||
1026 | } else { | ||
1027 | /* WEP, TKIP, CCMP and GCMP */ | ||
1028 | minlen = hdrlen + IEEE80211_WEP_IV_LEN; | ||
1029 | key_idx_off = hdrlen + 3; | ||
1030 | key_idx_shift = 6; | ||
1031 | } | ||
1032 | |||
1033 | if (unlikely(skb->len < minlen)) | ||
1020 | return -EINVAL; | 1034 | return -EINVAL; |
1021 | 1035 | ||
1022 | skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1); | 1036 | skb_copy_bits(skb, key_idx_off, &keyid, 1); |
1023 | keyid &= cs->key_idx_mask; | 1037 | |
1024 | keyid >>= cs->key_idx_shift; | 1038 | if (cs) |
1039 | keyid &= cs->key_idx_mask; | ||
1040 | keyid >>= key_idx_shift; | ||
1041 | |||
1042 | /* cs could use more than the usual two bits for the keyid */ | ||
1043 | if (unlikely(keyid >= NUM_DEFAULT_KEYS)) | ||
1044 | return -EINVAL; | ||
1025 | 1045 | ||
1026 | return keyid; | 1046 | return keyid; |
1027 | } | 1047 | } |
@@ -1860,9 +1880,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1860 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 1880 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
1861 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1881 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
1862 | int keyidx; | 1882 | int keyidx; |
1863 | int hdrlen; | ||
1864 | ieee80211_rx_result result = RX_DROP_UNUSABLE; | 1883 | ieee80211_rx_result result = RX_DROP_UNUSABLE; |
1865 | struct ieee80211_key *sta_ptk = NULL; | 1884 | struct ieee80211_key *sta_ptk = NULL; |
1885 | struct ieee80211_key *ptk_idx = NULL; | ||
1866 | int mmie_keyidx = -1; | 1886 | int mmie_keyidx = -1; |
1867 | __le16 fc; | 1887 | __le16 fc; |
1868 | const struct ieee80211_cipher_scheme *cs = NULL; | 1888 | const struct ieee80211_cipher_scheme *cs = NULL; |
@@ -1900,21 +1920,24 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1900 | 1920 | ||
1901 | if (rx->sta) { | 1921 | if (rx->sta) { |
1902 | int keyid = rx->sta->ptk_idx; | 1922 | int keyid = rx->sta->ptk_idx; |
1923 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
1903 | 1924 | ||
1904 | if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) { | 1925 | if (ieee80211_has_protected(fc)) { |
1905 | cs = rx->sta->cipher_scheme; | 1926 | cs = rx->sta->cipher_scheme; |
1906 | keyid = ieee80211_get_cs_keyid(cs, rx->skb); | 1927 | keyid = ieee80211_get_keyid(rx->skb, cs); |
1928 | |||
1907 | if (unlikely(keyid < 0)) | 1929 | if (unlikely(keyid < 0)) |
1908 | return RX_DROP_UNUSABLE; | 1930 | return RX_DROP_UNUSABLE; |
1931 | |||
1932 | ptk_idx = rcu_dereference(rx->sta->ptk[keyid]); | ||
1909 | } | 1933 | } |
1910 | sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); | ||
1911 | } | 1934 | } |
1912 | 1935 | ||
1913 | if (!ieee80211_has_protected(fc)) | 1936 | if (!ieee80211_has_protected(fc)) |
1914 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); | 1937 | mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb); |
1915 | 1938 | ||
1916 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { | 1939 | if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) { |
1917 | rx->key = sta_ptk; | 1940 | rx->key = ptk_idx ? ptk_idx : sta_ptk; |
1918 | if ((status->flag & RX_FLAG_DECRYPTED) && | 1941 | if ((status->flag & RX_FLAG_DECRYPTED) && |
1919 | (status->flag & RX_FLAG_IV_STRIPPED)) | 1942 | (status->flag & RX_FLAG_IV_STRIPPED)) |
1920 | return RX_CONTINUE; | 1943 | return RX_CONTINUE; |
@@ -1974,8 +1997,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1974 | } | 1997 | } |
1975 | return RX_CONTINUE; | 1998 | return RX_CONTINUE; |
1976 | } else { | 1999 | } else { |
1977 | u8 keyid; | ||
1978 | |||
1979 | /* | 2000 | /* |
1980 | * The device doesn't give us the IV so we won't be | 2001 | * The device doesn't give us the IV so we won't be |
1981 | * able to look up the key. That's ok though, we | 2002 | * able to look up the key. That's ok though, we |
@@ -1989,23 +2010,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) | |||
1989 | (status->flag & RX_FLAG_IV_STRIPPED)) | 2010 | (status->flag & RX_FLAG_IV_STRIPPED)) |
1990 | return RX_CONTINUE; | 2011 | return RX_CONTINUE; |
1991 | 2012 | ||
1992 | hdrlen = ieee80211_hdrlen(fc); | 2013 | keyidx = ieee80211_get_keyid(rx->skb, cs); |
1993 | |||
1994 | if (cs) { | ||
1995 | keyidx = ieee80211_get_cs_keyid(cs, rx->skb); | ||
1996 | 2014 | ||
1997 | if (unlikely(keyidx < 0)) | 2015 | if (unlikely(keyidx < 0)) |
1998 | return RX_DROP_UNUSABLE; | 2016 | return RX_DROP_UNUSABLE; |
1999 | } else { | ||
2000 | if (rx->skb->len < 8 + hdrlen) | ||
2001 | return RX_DROP_UNUSABLE; /* TODO: count this? */ | ||
2002 | /* | ||
2003 | * no need to call ieee80211_wep_get_keyidx, | ||
2004 | * it verifies a bunch of things we've done already | ||
2005 | */ | ||
2006 | skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1); | ||
2007 | keyidx = keyid >> 6; | ||
2008 | } | ||
2009 | 2017 | ||
2010 | /* check per-station GTK first, if multicast packet */ | 2018 | /* check per-station GTK first, if multicast packet */ |
2011 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) | 2019 | if (is_multicast_ether_addr(hdr->addr1) && rx->sta) |
@@ -4050,12 +4058,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta) | |||
4050 | case WLAN_CIPHER_SUITE_GCMP_256: | 4058 | case WLAN_CIPHER_SUITE_GCMP_256: |
4051 | break; | 4059 | break; |
4052 | default: | 4060 | default: |
4053 | /* we also don't want to deal with WEP or cipher scheme | 4061 | /* We also don't want to deal with |
4054 | * since those require looking up the key idx in the | 4062 | * WEP or cipher scheme. |
4055 | * frame, rather than assuming the PTK is used | ||
4056 | * (we need to revisit this once we implement the real | ||
4057 | * PTK index, which is now valid in the spec, but we | ||
4058 | * haven't implemented that part yet) | ||
4059 | */ | 4063 | */ |
4060 | goto clear_rcu; | 4064 | goto clear_rcu; |
4061 | } | 4065 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 11f058987a54..a4932ee3595c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -347,6 +347,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
347 | sta->sta.max_rx_aggregation_subframes = | 347 | sta->sta.max_rx_aggregation_subframes = |
348 | local->hw.max_rx_aggregation_subframes; | 348 | local->hw.max_rx_aggregation_subframes; |
349 | 349 | ||
350 | /* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only. | ||
351 | * The Tx path starts to use a key as soon as the key slot ptk_idx | ||
352 | * references to is not NULL. To not use the initial Rx-only key | ||
353 | * prematurely for Tx initialize ptk_idx to an impossible PTK keyid | ||
354 | * which always will refer to a NULL key. | ||
355 | */ | ||
356 | BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX); | ||
357 | sta->ptk_idx = INVALID_PTK_KEYIDX; | ||
358 | |||
350 | sta->local = local; | 359 | sta->local = local; |
351 | sta->sdata = sdata; | 360 | sta->sdata = sdata; |
352 | sta->rx_stats.last_rx = jiffies; | 361 | sta->rx_stats.last_rx = jiffies; |
@@ -2373,6 +2382,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, | |||
2373 | sinfo->filled |= | 2382 | sinfo->filled |= |
2374 | BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); | 2383 | BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); |
2375 | } | 2384 | } |
2385 | |||
2386 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2387 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC); | ||
2388 | sinfo->airtime_link_metric = | ||
2389 | airtime_link_metric_get(local, sta); | ||
2390 | } | ||
2376 | } | 2391 | } |
2377 | 2392 | ||
2378 | u32 sta_get_expected_throughput(struct sta_info *sta) | 2393 | u32 sta_get_expected_throughput(struct sta_info *sta) |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index d30690d79a58..24c37f91ca46 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -1056,7 +1056,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
1056 | 1056 | ||
1057 | /* disable bottom halves when entering the Tx path */ | 1057 | /* disable bottom halves when entering the Tx path */ |
1058 | local_bh_disable(); | 1058 | local_bh_disable(); |
1059 | __ieee80211_subif_start_xmit(skb, dev, flags); | 1059 | __ieee80211_subif_start_xmit(skb, dev, flags, 0); |
1060 | local_bh_enable(); | 1060 | local_bh_enable(); |
1061 | 1061 | ||
1062 | return ret; | 1062 | return ret; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 8ba70d26b82e..3bb4459b52c7 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -828,6 +828,36 @@ TRACE_EVENT(drv_sta_state, | |||
828 | ) | 828 | ) |
829 | ); | 829 | ); |
830 | 830 | ||
831 | TRACE_EVENT(drv_sta_set_txpwr, | ||
832 | TP_PROTO(struct ieee80211_local *local, | ||
833 | struct ieee80211_sub_if_data *sdata, | ||
834 | struct ieee80211_sta *sta), | ||
835 | |||
836 | TP_ARGS(local, sdata, sta), | ||
837 | |||
838 | TP_STRUCT__entry( | ||
839 | LOCAL_ENTRY | ||
840 | VIF_ENTRY | ||
841 | STA_ENTRY | ||
842 | __field(s16, txpwr) | ||
843 | __field(u8, type) | ||
844 | ), | ||
845 | |||
846 | TP_fast_assign( | ||
847 | LOCAL_ASSIGN; | ||
848 | VIF_ASSIGN; | ||
849 | STA_ASSIGN; | ||
850 | __entry->txpwr = sta->txpwr.power; | ||
851 | __entry->type = sta->txpwr.type; | ||
852 | ), | ||
853 | |||
854 | TP_printk( | ||
855 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " txpwr: %d type %d", | ||
856 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, | ||
857 | __entry->txpwr, __entry->type | ||
858 | ) | ||
859 | ); | ||
860 | |||
831 | TRACE_EVENT(drv_sta_rc_update, | 861 | TRACE_EVENT(drv_sta_rc_update, |
832 | TP_PROTO(struct ieee80211_local *local, | 862 | TP_PROTO(struct ieee80211_local *local, |
833 | struct ieee80211_sub_if_data *sdata, | 863 | struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2e816dd67be7..dd220b977025 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1399,11 +1399,15 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local, | |||
1399 | { | 1399 | { |
1400 | struct fq *fq = &local->fq; | 1400 | struct fq *fq = &local->fq; |
1401 | struct fq_tin *tin = &txqi->tin; | 1401 | struct fq_tin *tin = &txqi->tin; |
1402 | u32 flow_idx = fq_flow_idx(fq, skb); | ||
1402 | 1403 | ||
1403 | ieee80211_set_skb_enqueue_time(skb); | 1404 | ieee80211_set_skb_enqueue_time(skb); |
1404 | fq_tin_enqueue(fq, tin, skb, | 1405 | |
1406 | spin_lock_bh(&fq->lock); | ||
1407 | fq_tin_enqueue(fq, tin, flow_idx, skb, | ||
1405 | fq_skb_free_func, | 1408 | fq_skb_free_func, |
1406 | fq_flow_get_default_func); | 1409 | fq_flow_get_default_func); |
1410 | spin_unlock_bh(&fq->lock); | ||
1407 | } | 1411 | } |
1408 | 1412 | ||
1409 | static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin, | 1413 | static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin, |
@@ -1590,7 +1594,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local, | |||
1590 | struct sta_info *sta, | 1594 | struct sta_info *sta, |
1591 | struct sk_buff *skb) | 1595 | struct sk_buff *skb) |
1592 | { | 1596 | { |
1593 | struct fq *fq = &local->fq; | ||
1594 | struct ieee80211_vif *vif; | 1597 | struct ieee80211_vif *vif; |
1595 | struct txq_info *txqi; | 1598 | struct txq_info *txqi; |
1596 | 1599 | ||
@@ -1608,9 +1611,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local, | |||
1608 | if (!txqi) | 1611 | if (!txqi) |
1609 | return false; | 1612 | return false; |
1610 | 1613 | ||
1611 | spin_lock_bh(&fq->lock); | ||
1612 | ieee80211_txq_enqueue(local, txqi, skb); | 1614 | ieee80211_txq_enqueue(local, txqi, skb); |
1613 | spin_unlock_bh(&fq->lock); | ||
1614 | 1615 | ||
1615 | schedule_and_wake_txq(local, txqi); | 1616 | schedule_and_wake_txq(local, txqi); |
1616 | 1617 | ||
@@ -2431,6 +2432,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, | |||
2431 | * @sdata: virtual interface to build the header for | 2432 | * @sdata: virtual interface to build the header for |
2432 | * @skb: the skb to build the header in | 2433 | * @skb: the skb to build the header in |
2433 | * @info_flags: skb flags to set | 2434 | * @info_flags: skb flags to set |
2435 | * @ctrl_flags: info control flags to set | ||
2434 | * | 2436 | * |
2435 | * This function takes the skb with 802.3 header and reformats the header to | 2437 | * This function takes the skb with 802.3 header and reformats the header to |
2436 | * the appropriate IEEE 802.11 header based on which interface the packet is | 2438 | * the appropriate IEEE 802.11 header based on which interface the packet is |
@@ -2446,7 +2448,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, | |||
2446 | */ | 2448 | */ |
2447 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | 2449 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, |
2448 | struct sk_buff *skb, u32 info_flags, | 2450 | struct sk_buff *skb, u32 info_flags, |
2449 | struct sta_info *sta) | 2451 | struct sta_info *sta, u32 ctrl_flags) |
2450 | { | 2452 | { |
2451 | struct ieee80211_local *local = sdata->local; | 2453 | struct ieee80211_local *local = sdata->local; |
2452 | struct ieee80211_tx_info *info; | 2454 | struct ieee80211_tx_info *info; |
@@ -2470,6 +2472,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
2470 | if (IS_ERR(sta)) | 2472 | if (IS_ERR(sta)) |
2471 | sta = NULL; | 2473 | sta = NULL; |
2472 | 2474 | ||
2475 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
2476 | if (local->force_tx_status) | ||
2477 | info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
2478 | #endif | ||
2479 | |||
2473 | /* convert Ethernet header to proper 802.11 header (based on | 2480 | /* convert Ethernet header to proper 802.11 header (based on |
2474 | * operation mode) */ | 2481 | * operation mode) */ |
2475 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 2482 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
@@ -2600,6 +2607,13 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
2600 | goto free; | 2607 | goto free; |
2601 | } | 2608 | } |
2602 | band = chanctx_conf->def.chan->band; | 2609 | band = chanctx_conf->def.chan->band; |
2610 | |||
2611 | /* For injected frames, fill RA right away as nexthop lookup | ||
2612 | * will be skipped. | ||
2613 | */ | ||
2614 | if ((ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) && | ||
2615 | is_zero_ether_addr(hdr.addr1)) | ||
2616 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
2603 | break; | 2617 | break; |
2604 | #endif | 2618 | #endif |
2605 | case NL80211_IFTYPE_STATION: | 2619 | case NL80211_IFTYPE_STATION: |
@@ -2818,6 +2832,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
2818 | info->flags = info_flags; | 2832 | info->flags = info_flags; |
2819 | info->ack_frame_id = info_id; | 2833 | info->ack_frame_id = info_id; |
2820 | info->band = band; | 2834 | info->band = band; |
2835 | info->control.flags = ctrl_flags; | ||
2821 | 2836 | ||
2822 | return skb; | 2837 | return skb; |
2823 | free: | 2838 | free: |
@@ -3000,23 +3015,15 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) | |||
3000 | switch (build.key->conf.cipher) { | 3015 | switch (build.key->conf.cipher) { |
3001 | case WLAN_CIPHER_SUITE_CCMP: | 3016 | case WLAN_CIPHER_SUITE_CCMP: |
3002 | case WLAN_CIPHER_SUITE_CCMP_256: | 3017 | case WLAN_CIPHER_SUITE_CCMP_256: |
3003 | /* add fixed key ID */ | 3018 | if (gen_iv) |
3004 | if (gen_iv) { | ||
3005 | (build.hdr + build.hdr_len)[3] = | ||
3006 | 0x20 | (build.key->conf.keyidx << 6); | ||
3007 | build.pn_offs = build.hdr_len; | 3019 | build.pn_offs = build.hdr_len; |
3008 | } | ||
3009 | if (gen_iv || iv_spc) | 3020 | if (gen_iv || iv_spc) |
3010 | build.hdr_len += IEEE80211_CCMP_HDR_LEN; | 3021 | build.hdr_len += IEEE80211_CCMP_HDR_LEN; |
3011 | break; | 3022 | break; |
3012 | case WLAN_CIPHER_SUITE_GCMP: | 3023 | case WLAN_CIPHER_SUITE_GCMP: |
3013 | case WLAN_CIPHER_SUITE_GCMP_256: | 3024 | case WLAN_CIPHER_SUITE_GCMP_256: |
3014 | /* add fixed key ID */ | 3025 | if (gen_iv) |
3015 | if (gen_iv) { | ||
3016 | (build.hdr + build.hdr_len)[3] = | ||
3017 | 0x20 | (build.key->conf.keyidx << 6); | ||
3018 | build.pn_offs = build.hdr_len; | 3026 | build.pn_offs = build.hdr_len; |
3019 | } | ||
3020 | if (gen_iv || iv_spc) | 3027 | if (gen_iv || iv_spc) |
3021 | build.hdr_len += IEEE80211_GCMP_HDR_LEN; | 3028 | build.hdr_len += IEEE80211_GCMP_HDR_LEN; |
3022 | break; | 3029 | break; |
@@ -3222,6 +3229,7 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3222 | int max_frags = local->hw.max_tx_fragments; | 3229 | int max_frags = local->hw.max_tx_fragments; |
3223 | int max_amsdu_len = sta->sta.max_amsdu_len; | 3230 | int max_amsdu_len = sta->sta.max_amsdu_len; |
3224 | int orig_truesize; | 3231 | int orig_truesize; |
3232 | u32 flow_idx; | ||
3225 | __be16 len; | 3233 | __be16 len; |
3226 | void *data; | 3234 | void *data; |
3227 | bool ret = false; | 3235 | bool ret = false; |
@@ -3250,6 +3258,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3250 | max_amsdu_len = min_t(int, max_amsdu_len, | 3258 | max_amsdu_len = min_t(int, max_amsdu_len, |
3251 | sta->sta.max_tid_amsdu_len[tid]); | 3259 | sta->sta.max_tid_amsdu_len[tid]); |
3252 | 3260 | ||
3261 | flow_idx = fq_flow_idx(fq, skb); | ||
3262 | |||
3253 | spin_lock_bh(&fq->lock); | 3263 | spin_lock_bh(&fq->lock); |
3254 | 3264 | ||
3255 | /* TODO: Ideally aggregation should be done on dequeue to remain | 3265 | /* TODO: Ideally aggregation should be done on dequeue to remain |
@@ -3257,7 +3267,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | |||
3257 | */ | 3267 | */ |
3258 | 3268 | ||
3259 | tin = &txqi->tin; | 3269 | tin = &txqi->tin; |
3260 | flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func); | 3270 | flow = fq_flow_classify(fq, tin, flow_idx, skb, |
3271 | fq_flow_get_default_func); | ||
3261 | head = skb_peek_tail(&flow->queue); | 3272 | head = skb_peek_tail(&flow->queue); |
3262 | if (!head || skb_is_gso(head)) | 3273 | if (!head || skb_is_gso(head)) |
3263 | goto out; | 3274 | goto out; |
@@ -3386,6 +3397,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, | |||
3386 | pn = atomic64_inc_return(&key->conf.tx_pn); | 3397 | pn = atomic64_inc_return(&key->conf.tx_pn); |
3387 | crypto_hdr[0] = pn; | 3398 | crypto_hdr[0] = pn; |
3388 | crypto_hdr[1] = pn >> 8; | 3399 | crypto_hdr[1] = pn >> 8; |
3400 | crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6); | ||
3389 | crypto_hdr[4] = pn >> 16; | 3401 | crypto_hdr[4] = pn >> 16; |
3390 | crypto_hdr[5] = pn >> 24; | 3402 | crypto_hdr[5] = pn >> 24; |
3391 | crypto_hdr[6] = pn >> 32; | 3403 | crypto_hdr[6] = pn >> 32; |
@@ -3478,6 +3490,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | |||
3478 | (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); | 3490 | (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); |
3479 | info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; | 3491 | info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; |
3480 | 3492 | ||
3493 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
3494 | if (local->force_tx_status) | ||
3495 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
3496 | #endif | ||
3497 | |||
3481 | if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { | 3498 | if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { |
3482 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | 3499 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
3483 | *ieee80211_get_qos_ctl(hdr) = tid; | 3500 | *ieee80211_get_qos_ctl(hdr) = tid; |
@@ -3533,6 +3550,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | |||
3533 | ieee80211_tx_result r; | 3550 | ieee80211_tx_result r; |
3534 | struct ieee80211_vif *vif = txq->vif; | 3551 | struct ieee80211_vif *vif = txq->vif; |
3535 | 3552 | ||
3553 | begin: | ||
3536 | spin_lock_bh(&fq->lock); | 3554 | spin_lock_bh(&fq->lock); |
3537 | 3555 | ||
3538 | if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) || | 3556 | if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) || |
@@ -3549,11 +3567,12 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, | |||
3549 | if (skb) | 3567 | if (skb) |
3550 | goto out; | 3568 | goto out; |
3551 | 3569 | ||
3552 | begin: | ||
3553 | skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); | 3570 | skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); |
3554 | if (!skb) | 3571 | if (!skb) |
3555 | goto out; | 3572 | goto out; |
3556 | 3573 | ||
3574 | spin_unlock_bh(&fq->lock); | ||
3575 | |||
3557 | hdr = (struct ieee80211_hdr *)skb->data; | 3576 | hdr = (struct ieee80211_hdr *)skb->data; |
3558 | info = IEEE80211_SKB_CB(skb); | 3577 | info = IEEE80211_SKB_CB(skb); |
3559 | 3578 | ||
@@ -3598,8 +3617,11 @@ begin: | |||
3598 | 3617 | ||
3599 | skb = __skb_dequeue(&tx.skbs); | 3618 | skb = __skb_dequeue(&tx.skbs); |
3600 | 3619 | ||
3601 | if (!skb_queue_empty(&tx.skbs)) | 3620 | if (!skb_queue_empty(&tx.skbs)) { |
3621 | spin_lock_bh(&fq->lock); | ||
3602 | skb_queue_splice_tail(&tx.skbs, &txqi->frags); | 3622 | skb_queue_splice_tail(&tx.skbs, &txqi->frags); |
3623 | spin_unlock_bh(&fq->lock); | ||
3624 | } | ||
3603 | } | 3625 | } |
3604 | 3626 | ||
3605 | if (skb_has_frag_list(skb) && | 3627 | if (skb_has_frag_list(skb) && |
@@ -3638,6 +3660,7 @@ begin: | |||
3638 | } | 3660 | } |
3639 | 3661 | ||
3640 | IEEE80211_SKB_CB(skb)->control.vif = vif; | 3662 | IEEE80211_SKB_CB(skb)->control.vif = vif; |
3663 | return skb; | ||
3641 | 3664 | ||
3642 | out: | 3665 | out: |
3643 | spin_unlock_bh(&fq->lock); | 3666 | spin_unlock_bh(&fq->lock); |
@@ -3783,9 +3806,11 @@ EXPORT_SYMBOL(ieee80211_txq_schedule_start); | |||
3783 | 3806 | ||
3784 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, | 3807 | void __ieee80211_subif_start_xmit(struct sk_buff *skb, |
3785 | struct net_device *dev, | 3808 | struct net_device *dev, |
3786 | u32 info_flags) | 3809 | u32 info_flags, |
3810 | u32 ctrl_flags) | ||
3787 | { | 3811 | { |
3788 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3812 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3813 | struct ieee80211_local *local = sdata->local; | ||
3789 | struct sta_info *sta; | 3814 | struct sta_info *sta; |
3790 | struct sk_buff *next; | 3815 | struct sk_buff *next; |
3791 | 3816 | ||
@@ -3799,7 +3824,15 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
3799 | if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) | 3824 | if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) |
3800 | goto out_free; | 3825 | goto out_free; |
3801 | 3826 | ||
3802 | if (!IS_ERR_OR_NULL(sta)) { | 3827 | if (IS_ERR(sta)) |
3828 | sta = NULL; | ||
3829 | |||
3830 | if (local->ops->wake_tx_queue) { | ||
3831 | u16 queue = __ieee80211_select_queue(sdata, sta, skb); | ||
3832 | skb_set_queue_mapping(skb, queue); | ||
3833 | } | ||
3834 | |||
3835 | if (sta) { | ||
3803 | struct ieee80211_fast_tx *fast_tx; | 3836 | struct ieee80211_fast_tx *fast_tx; |
3804 | 3837 | ||
3805 | sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift); | 3838 | sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift); |
@@ -3848,7 +3881,8 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
3848 | skb->prev = NULL; | 3881 | skb->prev = NULL; |
3849 | skb->next = NULL; | 3882 | skb->next = NULL; |
3850 | 3883 | ||
3851 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); | 3884 | skb = ieee80211_build_hdr(sdata, skb, info_flags, |
3885 | sta, ctrl_flags); | ||
3852 | if (IS_ERR(skb)) | 3886 | if (IS_ERR(skb)) |
3853 | goto out; | 3887 | goto out; |
3854 | 3888 | ||
@@ -3988,9 +4022,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
3988 | __skb_queue_head_init(&queue); | 4022 | __skb_queue_head_init(&queue); |
3989 | ieee80211_convert_to_unicast(skb, dev, &queue); | 4023 | ieee80211_convert_to_unicast(skb, dev, &queue); |
3990 | while ((skb = __skb_dequeue(&queue))) | 4024 | while ((skb = __skb_dequeue(&queue))) |
3991 | __ieee80211_subif_start_xmit(skb, dev, 0); | 4025 | __ieee80211_subif_start_xmit(skb, dev, 0, 0); |
3992 | } else { | 4026 | } else { |
3993 | __ieee80211_subif_start_xmit(skb, dev, 0); | 4027 | __ieee80211_subif_start_xmit(skb, dev, 0, 0); |
3994 | } | 4028 | } |
3995 | 4029 | ||
3996 | return NETDEV_TX_OK; | 4030 | return NETDEV_TX_OK; |
@@ -4015,7 +4049,7 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | |||
4015 | goto out; | 4049 | goto out; |
4016 | } | 4050 | } |
4017 | 4051 | ||
4018 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); | 4052 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, 0); |
4019 | if (IS_ERR(skb)) | 4053 | if (IS_ERR(skb)) |
4020 | goto out; | 4054 | goto out; |
4021 | 4055 | ||
@@ -5052,7 +5086,36 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, | |||
5052 | skb_reset_mac_header(skb); | 5086 | skb_reset_mac_header(skb); |
5053 | 5087 | ||
5054 | local_bh_disable(); | 5088 | local_bh_disable(); |
5055 | __ieee80211_subif_start_xmit(skb, skb->dev, flags); | 5089 | __ieee80211_subif_start_xmit(skb, skb->dev, flags, 0); |
5090 | local_bh_enable(); | ||
5091 | |||
5092 | return 0; | ||
5093 | } | ||
5094 | |||
5095 | int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, | ||
5096 | const u8 *buf, size_t len) | ||
5097 | { | ||
5098 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
5099 | struct ieee80211_local *local = sdata->local; | ||
5100 | struct sk_buff *skb; | ||
5101 | |||
5102 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len + | ||
5103 | 30 + /* header size */ | ||
5104 | 18); /* 11s header size */ | ||
5105 | if (!skb) | ||
5106 | return -ENOMEM; | ||
5107 | |||
5108 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
5109 | skb_put_data(skb, buf, len); | ||
5110 | |||
5111 | skb->dev = dev; | ||
5112 | skb->protocol = htons(ETH_P_802_3); | ||
5113 | skb_reset_network_header(skb); | ||
5114 | skb_reset_mac_header(skb); | ||
5115 | |||
5116 | local_bh_disable(); | ||
5117 | __ieee80211_subif_start_xmit(skb, skb->dev, 0, | ||
5118 | IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP); | ||
5056 | local_bh_enable(); | 5119 | local_bh_enable(); |
5057 | 5120 | ||
5058 | return 0; | 5121 | return 0; |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4c1655972565..cba4633cd6cf 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -894,10 +894,10 @@ EXPORT_SYMBOL(ieee80211_queue_delayed_work); | |||
894 | static u32 | 894 | static u32 |
895 | _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | 895 | _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, |
896 | struct ieee802_11_elems *elems, | 896 | struct ieee802_11_elems *elems, |
897 | u64 filter, u32 crc, u8 *transmitter_bssid, | 897 | u64 filter, u32 crc, |
898 | u8 *bss_bssid) | 898 | const struct element *check_inherit) |
899 | { | 899 | { |
900 | const struct element *elem, *sub; | 900 | const struct element *elem; |
901 | bool calc_crc = filter != 0; | 901 | bool calc_crc = filter != 0; |
902 | DECLARE_BITMAP(seen_elems, 256); | 902 | DECLARE_BITMAP(seen_elems, 256); |
903 | const u8 *ie; | 903 | const u8 *ie; |
@@ -910,6 +910,11 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
910 | u8 elen = elem->datalen; | 910 | u8 elen = elem->datalen; |
911 | const u8 *pos = elem->data; | 911 | const u8 *pos = elem->data; |
912 | 912 | ||
913 | if (check_inherit && | ||
914 | !cfg80211_is_element_inherited(elem, | ||
915 | check_inherit)) | ||
916 | continue; | ||
917 | |||
913 | switch (id) { | 918 | switch (id) { |
914 | case WLAN_EID_SSID: | 919 | case WLAN_EID_SSID: |
915 | case WLAN_EID_SUPP_RATES: | 920 | case WLAN_EID_SUPP_RATES: |
@@ -1208,57 +1213,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
1208 | if (elen >= sizeof(*elems->max_idle_period_ie)) | 1213 | if (elen >= sizeof(*elems->max_idle_period_ie)) |
1209 | elems->max_idle_period_ie = (void *)pos; | 1214 | elems->max_idle_period_ie = (void *)pos; |
1210 | break; | 1215 | break; |
1211 | case WLAN_EID_MULTIPLE_BSSID: | ||
1212 | if (!bss_bssid || !transmitter_bssid || elen < 4) | ||
1213 | break; | ||
1214 | |||
1215 | elems->max_bssid_indicator = pos[0]; | ||
1216 | |||
1217 | for_each_element(sub, pos + 1, elen - 1) { | ||
1218 | u8 sub_len = sub->datalen; | ||
1219 | u8 new_bssid[ETH_ALEN]; | ||
1220 | const u8 *index; | ||
1221 | |||
1222 | /* | ||
1223 | * we only expect the "non-transmitted BSSID | ||
1224 | * profile" subelement (subelement id 0) | ||
1225 | */ | ||
1226 | if (sub->id != 0 || sub->datalen < 4) { | ||
1227 | /* not a valid BSS profile */ | ||
1228 | continue; | ||
1229 | } | ||
1230 | |||
1231 | if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP || | ||
1232 | sub->data[1] != 2) { | ||
1233 | /* The first element of the | ||
1234 | * Nontransmitted BSSID Profile is not | ||
1235 | * the Nontransmitted BSSID Capability | ||
1236 | * element. | ||
1237 | */ | ||
1238 | continue; | ||
1239 | } | ||
1240 | |||
1241 | /* found a Nontransmitted BSSID Profile */ | ||
1242 | index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, | ||
1243 | sub->data, sub_len); | ||
1244 | if (!index || index[1] < 1 || index[2] == 0) { | ||
1245 | /* Invalid MBSSID Index element */ | ||
1246 | continue; | ||
1247 | } | ||
1248 | |||
1249 | cfg80211_gen_new_bssid(transmitter_bssid, | ||
1250 | pos[0], | ||
1251 | index[2], | ||
1252 | new_bssid); | ||
1253 | if (ether_addr_equal(new_bssid, bss_bssid)) { | ||
1254 | elems->nontransmitted_bssid_profile = | ||
1255 | (void *)sub; | ||
1256 | elems->bssid_index_len = index[1]; | ||
1257 | elems->bssid_index = (void *)&index[2]; | ||
1258 | break; | ||
1259 | } | ||
1260 | } | ||
1261 | break; | ||
1262 | case WLAN_EID_EXTENSION: | 1216 | case WLAN_EID_EXTENSION: |
1263 | if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA && | 1217 | if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA && |
1264 | elen >= (sizeof(*elems->mu_edca_param_set) + 1)) { | 1218 | elen >= (sizeof(*elems->mu_edca_param_set) + 1)) { |
@@ -1300,26 +1254,108 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
1300 | return crc; | 1254 | return crc; |
1301 | } | 1255 | } |
1302 | 1256 | ||
1257 | static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, | ||
1258 | struct ieee802_11_elems *elems, | ||
1259 | u8 *transmitter_bssid, | ||
1260 | u8 *bss_bssid, | ||
1261 | u8 *nontransmitted_profile) | ||
1262 | { | ||
1263 | const struct element *elem, *sub; | ||
1264 | size_t profile_len = 0; | ||
1265 | bool found = false; | ||
1266 | |||
1267 | if (!bss_bssid || !transmitter_bssid) | ||
1268 | return profile_len; | ||
1269 | |||
1270 | for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) { | ||
1271 | if (elem->datalen < 2) | ||
1272 | continue; | ||
1273 | |||
1274 | for_each_element(sub, elem->data + 1, elem->datalen - 1) { | ||
1275 | u8 new_bssid[ETH_ALEN]; | ||
1276 | const u8 *index; | ||
1277 | |||
1278 | if (sub->id != 0 || sub->datalen < 4) { | ||
1279 | /* not a valid BSS profile */ | ||
1280 | continue; | ||
1281 | } | ||
1282 | |||
1283 | if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP || | ||
1284 | sub->data[1] != 2) { | ||
1285 | /* The first element of the | ||
1286 | * Nontransmitted BSSID Profile is not | ||
1287 | * the Nontransmitted BSSID Capability | ||
1288 | * element. | ||
1289 | */ | ||
1290 | continue; | ||
1291 | } | ||
1292 | |||
1293 | memset(nontransmitted_profile, 0, len); | ||
1294 | profile_len = cfg80211_merge_profile(start, len, | ||
1295 | elem, | ||
1296 | sub, | ||
1297 | nontransmitted_profile, | ||
1298 | len); | ||
1299 | |||
1300 | /* found a Nontransmitted BSSID Profile */ | ||
1301 | index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX, | ||
1302 | nontransmitted_profile, | ||
1303 | profile_len); | ||
1304 | if (!index || index[1] < 1 || index[2] == 0) { | ||
1305 | /* Invalid MBSSID Index element */ | ||
1306 | continue; | ||
1307 | } | ||
1308 | |||
1309 | cfg80211_gen_new_bssid(transmitter_bssid, | ||
1310 | elem->data[0], | ||
1311 | index[2], | ||
1312 | new_bssid); | ||
1313 | if (ether_addr_equal(new_bssid, bss_bssid)) { | ||
1314 | found = true; | ||
1315 | elems->bssid_index_len = index[1]; | ||
1316 | elems->bssid_index = (void *)&index[2]; | ||
1317 | break; | ||
1318 | } | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | return found ? profile_len : 0; | ||
1323 | } | ||
1324 | |||
1303 | u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | 1325 | u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, |
1304 | struct ieee802_11_elems *elems, | 1326 | struct ieee802_11_elems *elems, |
1305 | u64 filter, u32 crc, u8 *transmitter_bssid, | 1327 | u64 filter, u32 crc, u8 *transmitter_bssid, |
1306 | u8 *bss_bssid) | 1328 | u8 *bss_bssid) |
1307 | { | 1329 | { |
1330 | const struct element *non_inherit = NULL; | ||
1331 | u8 *nontransmitted_profile; | ||
1332 | int nontransmitted_profile_len = 0; | ||
1333 | |||
1308 | memset(elems, 0, sizeof(*elems)); | 1334 | memset(elems, 0, sizeof(*elems)); |
1309 | elems->ie_start = start; | 1335 | elems->ie_start = start; |
1310 | elems->total_len = len; | 1336 | elems->total_len = len; |
1311 | 1337 | ||
1338 | nontransmitted_profile = kmalloc(len, GFP_ATOMIC); | ||
1339 | if (nontransmitted_profile) { | ||
1340 | nontransmitted_profile_len = | ||
1341 | ieee802_11_find_bssid_profile(start, len, elems, | ||
1342 | transmitter_bssid, | ||
1343 | bss_bssid, | ||
1344 | nontransmitted_profile); | ||
1345 | non_inherit = | ||
1346 | cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, | ||
1347 | nontransmitted_profile, | ||
1348 | nontransmitted_profile_len); | ||
1349 | } | ||
1350 | |||
1312 | crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter, | 1351 | crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter, |
1313 | crc, transmitter_bssid, bss_bssid); | 1352 | crc, non_inherit); |
1314 | 1353 | ||
1315 | /* Override with nontransmitted profile, if found */ | 1354 | /* Override with nontransmitted profile, if found */ |
1316 | if (transmitter_bssid && elems->nontransmitted_bssid_profile) { | 1355 | if (nontransmitted_profile_len) |
1317 | const u8 *profile = elems->nontransmitted_bssid_profile; | 1356 | _ieee802_11_parse_elems_crc(nontransmitted_profile, |
1318 | 1357 | nontransmitted_profile_len, | |
1319 | _ieee802_11_parse_elems_crc(&profile[2], profile[1], | 1358 | action, elems, 0, 0, NULL); |
1320 | action, elems, 0, 0, | ||
1321 | transmitter_bssid, bss_bssid); | ||
1322 | } | ||
1323 | 1359 | ||
1324 | if (elems->tim && !elems->parse_error) { | 1360 | if (elems->tim && !elems->parse_error) { |
1325 | const struct ieee80211_tim_ie *tim_ie = elems->tim; | 1361 | const struct ieee80211_tim_ie *tim_ie = elems->tim; |
@@ -1339,6 +1375,8 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
1339 | offsetofend(struct ieee80211_bssid_index, dtim_count)) | 1375 | offsetofend(struct ieee80211_bssid_index, dtim_count)) |
1340 | elems->dtim_count = elems->bssid_index->dtim_count; | 1376 | elems->dtim_count = elems->bssid_index->dtim_count; |
1341 | 1377 | ||
1378 | kfree(nontransmitted_profile); | ||
1379 | |||
1342 | return crc; | 1380 | return crc; |
1343 | } | 1381 | } |
1344 | 1382 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 5f7c96368b11..6a3187883c4b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -141,6 +141,42 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | |||
141 | return ieee80211_downgrade_queue(sdata, NULL, skb); | 141 | return ieee80211_downgrade_queue(sdata, NULL, skb); |
142 | } | 142 | } |
143 | 143 | ||
144 | u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | ||
145 | struct sta_info *sta, struct sk_buff *skb) | ||
146 | { | ||
147 | struct mac80211_qos_map *qos_map; | ||
148 | bool qos; | ||
149 | |||
150 | /* all mesh/ocb stations are required to support WME */ | ||
151 | if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT || | ||
152 | sdata->vif.type == NL80211_IFTYPE_OCB) | ||
153 | qos = true; | ||
154 | else if (sta) | ||
155 | qos = sta->sta.wme; | ||
156 | else | ||
157 | qos = false; | ||
158 | |||
159 | if (!qos) { | ||
160 | skb->priority = 0; /* required for correct WPA/11i MIC */ | ||
161 | return IEEE80211_AC_BE; | ||
162 | } | ||
163 | |||
164 | if (skb->protocol == sdata->control_port_protocol) { | ||
165 | skb->priority = 7; | ||
166 | goto downgrade; | ||
167 | } | ||
168 | |||
169 | /* use the data classifier to determine what 802.1d tag the | ||
170 | * data frame has */ | ||
171 | qos_map = rcu_dereference(sdata->qos_map); | ||
172 | skb->priority = cfg80211_classify8021d(skb, qos_map ? | ||
173 | &qos_map->qos_map : NULL); | ||
174 | |||
175 | downgrade: | ||
176 | return ieee80211_downgrade_queue(sdata, sta, skb); | ||
177 | } | ||
178 | |||
179 | |||
144 | /* Indicate which queue to use. */ | 180 | /* Indicate which queue to use. */ |
145 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | 181 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
146 | struct sk_buff *skb) | 182 | struct sk_buff *skb) |
@@ -148,10 +184,12 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
148 | struct ieee80211_local *local = sdata->local; | 184 | struct ieee80211_local *local = sdata->local; |
149 | struct sta_info *sta = NULL; | 185 | struct sta_info *sta = NULL; |
150 | const u8 *ra = NULL; | 186 | const u8 *ra = NULL; |
151 | bool qos = false; | ||
152 | struct mac80211_qos_map *qos_map; | ||
153 | u16 ret; | 187 | u16 ret; |
154 | 188 | ||
189 | /* when using iTXQ, we can do this later */ | ||
190 | if (local->ops->wake_tx_queue) | ||
191 | return 0; | ||
192 | |||
155 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { | 193 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
156 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 194 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
157 | return 0; | 195 | return 0; |
@@ -161,10 +199,8 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
161 | switch (sdata->vif.type) { | 199 | switch (sdata->vif.type) { |
162 | case NL80211_IFTYPE_AP_VLAN: | 200 | case NL80211_IFTYPE_AP_VLAN: |
163 | sta = rcu_dereference(sdata->u.vlan.sta); | 201 | sta = rcu_dereference(sdata->u.vlan.sta); |
164 | if (sta) { | 202 | if (sta) |
165 | qos = sta->sta.wme; | ||
166 | break; | 203 | break; |
167 | } | ||
168 | /* fall through */ | 204 | /* fall through */ |
169 | case NL80211_IFTYPE_AP: | 205 | case NL80211_IFTYPE_AP: |
170 | ra = skb->data; | 206 | ra = skb->data; |
@@ -172,56 +208,26 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
172 | case NL80211_IFTYPE_WDS: | 208 | case NL80211_IFTYPE_WDS: |
173 | ra = sdata->u.wds.remote_addr; | 209 | ra = sdata->u.wds.remote_addr; |
174 | break; | 210 | break; |
175 | #ifdef CONFIG_MAC80211_MESH | ||
176 | case NL80211_IFTYPE_MESH_POINT: | ||
177 | qos = true; | ||
178 | break; | ||
179 | #endif | ||
180 | case NL80211_IFTYPE_STATION: | 211 | case NL80211_IFTYPE_STATION: |
181 | /* might be a TDLS station */ | 212 | /* might be a TDLS station */ |
182 | sta = sta_info_get(sdata, skb->data); | 213 | sta = sta_info_get(sdata, skb->data); |
183 | if (sta) | 214 | if (sta) |
184 | qos = sta->sta.wme; | 215 | break; |
185 | 216 | ||
186 | ra = sdata->u.mgd.bssid; | 217 | ra = sdata->u.mgd.bssid; |
187 | break; | 218 | break; |
188 | case NL80211_IFTYPE_ADHOC: | 219 | case NL80211_IFTYPE_ADHOC: |
189 | ra = skb->data; | 220 | ra = skb->data; |
190 | break; | 221 | break; |
191 | case NL80211_IFTYPE_OCB: | ||
192 | /* all stations are required to support WME */ | ||
193 | qos = true; | ||
194 | break; | ||
195 | default: | 222 | default: |
196 | break; | 223 | break; |
197 | } | 224 | } |
198 | 225 | ||
199 | if (!sta && ra && !is_multicast_ether_addr(ra)) { | 226 | if (!sta && ra && !is_multicast_ether_addr(ra)) |
200 | sta = sta_info_get(sdata, ra); | 227 | sta = sta_info_get(sdata, ra); |
201 | if (sta) | ||
202 | qos = sta->sta.wme; | ||
203 | } | ||
204 | 228 | ||
205 | if (!qos) { | 229 | ret = __ieee80211_select_queue(sdata, sta, skb); |
206 | skb->priority = 0; /* required for correct WPA/11i MIC */ | ||
207 | ret = IEEE80211_AC_BE; | ||
208 | goto out; | ||
209 | } | ||
210 | 230 | ||
211 | if (skb->protocol == sdata->control_port_protocol) { | ||
212 | skb->priority = 7; | ||
213 | goto downgrade; | ||
214 | } | ||
215 | |||
216 | /* use the data classifier to determine what 802.1d tag the | ||
217 | * data frame has */ | ||
218 | qos_map = rcu_dereference(sdata->qos_map); | ||
219 | skb->priority = cfg80211_classify8021d(skb, qos_map ? | ||
220 | &qos_map->qos_map : NULL); | ||
221 | |||
222 | downgrade: | ||
223 | ret = ieee80211_downgrade_queue(sdata, sta, skb); | ||
224 | out: | ||
225 | rcu_read_unlock(); | 231 | rcu_read_unlock(); |
226 | return ret; | 232 | return ret; |
227 | } | 233 | } |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 80151edc5195..b1b1439cb91b 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -16,6 +16,8 @@ | |||
16 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | 16 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, |
17 | struct sk_buff *skb, | 17 | struct sk_buff *skb, |
18 | struct ieee80211_hdr *hdr); | 18 | struct ieee80211_hdr *hdr); |
19 | u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | ||
20 | struct sta_info *sta, struct sk_buff *skb); | ||
19 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | 21 | u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, |
20 | struct sk_buff *skb); | 22 | struct sk_buff *skb); |
21 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, | 23 | void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e7ee18ab6cb7..e74d21f4108a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -331,6 +331,11 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { | |||
331 | .len = NL80211_MAX_SUPP_RATES }, | 331 | .len = NL80211_MAX_SUPP_RATES }, |
332 | [NL80211_ATTR_STA_PLINK_ACTION] = | 332 | [NL80211_ATTR_STA_PLINK_ACTION] = |
333 | NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1), | 333 | NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1), |
334 | [NL80211_ATTR_STA_TX_POWER_SETTING] = | ||
335 | NLA_POLICY_RANGE(NLA_U8, | ||
336 | NL80211_TX_POWER_AUTOMATIC, | ||
337 | NL80211_TX_POWER_FIXED), | ||
338 | [NL80211_ATTR_STA_TX_POWER] = { .type = NLA_S16 }, | ||
334 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 339 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
335 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, | 340 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, |
336 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | 341 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, |
@@ -553,6 +558,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = { | |||
553 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 558 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
554 | [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1), | 559 | [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1), |
555 | [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | 560 | [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, |
561 | [NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX), | ||
556 | }; | 562 | }; |
557 | 563 | ||
558 | /* policy for the key default flags */ | 564 | /* policy for the key default flags */ |
@@ -618,11 +624,20 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | |||
618 | }; | 624 | }; |
619 | 625 | ||
620 | static const struct nla_policy | 626 | static const struct nla_policy |
627 | nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = { | ||
628 | [NL80211_BAND_2GHZ] = { .type = NLA_S32 }, | ||
629 | [NL80211_BAND_5GHZ] = { .type = NLA_S32 }, | ||
630 | [NL80211_BAND_60GHZ] = { .type = NLA_S32 }, | ||
631 | }; | ||
632 | |||
633 | static const struct nla_policy | ||
621 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { | 634 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { |
622 | [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, | 635 | [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, |
623 | .len = IEEE80211_MAX_SSID_LEN }, | 636 | .len = IEEE80211_MAX_SSID_LEN }, |
624 | [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN }, | 637 | [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN }, |
625 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, | 638 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, |
639 | [NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] = | ||
640 | NLA_POLICY_NESTED(nl80211_match_band_rssi_policy), | ||
626 | }; | 641 | }; |
627 | 642 | ||
628 | static const struct nla_policy | 643 | static const struct nla_policy |
@@ -958,6 +973,9 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key, | |||
958 | k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; | 973 | k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST]; |
959 | } | 974 | } |
960 | 975 | ||
976 | if (tb[NL80211_KEY_MODE]) | ||
977 | k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]); | ||
978 | |||
961 | return 0; | 979 | return 0; |
962 | } | 980 | } |
963 | 981 | ||
@@ -3634,8 +3652,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
3634 | if (key.idx < 0) | 3652 | if (key.idx < 0) |
3635 | return -EINVAL; | 3653 | return -EINVAL; |
3636 | 3654 | ||
3637 | /* only support setting default key */ | 3655 | /* Only support setting default key and |
3638 | if (!key.def && !key.defmgmt) | 3656 | * Extended Key ID action NL80211_KEY_SET_TX. |
3657 | */ | ||
3658 | if (!key.def && !key.defmgmt && | ||
3659 | !(key.p.mode == NL80211_KEY_SET_TX)) | ||
3639 | return -EINVAL; | 3660 | return -EINVAL; |
3640 | 3661 | ||
3641 | wdev_lock(dev->ieee80211_ptr); | 3662 | wdev_lock(dev->ieee80211_ptr); |
@@ -3659,7 +3680,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
3659 | #ifdef CONFIG_CFG80211_WEXT | 3680 | #ifdef CONFIG_CFG80211_WEXT |
3660 | dev->ieee80211_ptr->wext.default_key = key.idx; | 3681 | dev->ieee80211_ptr->wext.default_key = key.idx; |
3661 | #endif | 3682 | #endif |
3662 | } else { | 3683 | } else if (key.defmgmt) { |
3663 | if (key.def_uni || !key.def_multi) { | 3684 | if (key.def_uni || !key.def_multi) { |
3664 | err = -EINVAL; | 3685 | err = -EINVAL; |
3665 | goto out; | 3686 | goto out; |
@@ -3681,8 +3702,25 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
3681 | #ifdef CONFIG_CFG80211_WEXT | 3702 | #ifdef CONFIG_CFG80211_WEXT |
3682 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; | 3703 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; |
3683 | #endif | 3704 | #endif |
3684 | } | 3705 | } else if (key.p.mode == NL80211_KEY_SET_TX && |
3706 | wiphy_ext_feature_isset(&rdev->wiphy, | ||
3707 | NL80211_EXT_FEATURE_EXT_KEY_ID)) { | ||
3708 | u8 *mac_addr = NULL; | ||
3709 | |||
3710 | if (info->attrs[NL80211_ATTR_MAC]) | ||
3711 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3712 | |||
3713 | if (!mac_addr || key.idx < 0 || key.idx > 1) { | ||
3714 | err = -EINVAL; | ||
3715 | goto out; | ||
3716 | } | ||
3685 | 3717 | ||
3718 | err = rdev_add_key(rdev, dev, key.idx, | ||
3719 | NL80211_KEYTYPE_PAIRWISE, | ||
3720 | mac_addr, &key.p); | ||
3721 | } else { | ||
3722 | err = -EINVAL; | ||
3723 | } | ||
3686 | out: | 3724 | out: |
3687 | wdev_unlock(dev->ieee80211_ptr); | 3725 | wdev_unlock(dev->ieee80211_ptr); |
3688 | 3726 | ||
@@ -3843,8 +3881,7 @@ static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy, | |||
3843 | if (n_entries > wiphy->max_acl_mac_addrs) | 3881 | if (n_entries > wiphy->max_acl_mac_addrs) |
3844 | return ERR_PTR(-ENOTSUPP); | 3882 | return ERR_PTR(-ENOTSUPP); |
3845 | 3883 | ||
3846 | acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries), | 3884 | acl = kzalloc(struct_size(acl, mac_addrs, n_entries), GFP_KERNEL); |
3847 | GFP_KERNEL); | ||
3848 | if (!acl) | 3885 | if (!acl) |
3849 | return ERR_PTR(-ENOMEM); | 3886 | return ERR_PTR(-ENOMEM); |
3850 | 3887 | ||
@@ -4889,6 +4926,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid, | |||
4889 | PUT_SINFO(TX_RETRIES, tx_retries, u32); | 4926 | PUT_SINFO(TX_RETRIES, tx_retries, u32); |
4890 | PUT_SINFO(TX_FAILED, tx_failed, u32); | 4927 | PUT_SINFO(TX_FAILED, tx_failed, u32); |
4891 | PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32); | 4928 | PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32); |
4929 | PUT_SINFO(AIRTIME_LINK_METRIC, airtime_link_metric, u32); | ||
4892 | PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32); | 4930 | PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32); |
4893 | PUT_SINFO(LOCAL_PM, local_pm, u32); | 4931 | PUT_SINFO(LOCAL_PM, local_pm, u32); |
4894 | PUT_SINFO(PEER_PM, peer_pm, u32); | 4932 | PUT_SINFO(PEER_PM, peer_pm, u32); |
@@ -5387,6 +5425,36 @@ static int nl80211_set_station_tdls(struct genl_info *info, | |||
5387 | return nl80211_parse_sta_wme(info, params); | 5425 | return nl80211_parse_sta_wme(info, params); |
5388 | } | 5426 | } |
5389 | 5427 | ||
5428 | static int nl80211_parse_sta_txpower_setting(struct genl_info *info, | ||
5429 | struct station_parameters *params) | ||
5430 | { | ||
5431 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5432 | int idx; | ||
5433 | |||
5434 | if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) { | ||
5435 | if (!rdev->ops->set_tx_power || | ||
5436 | !wiphy_ext_feature_isset(&rdev->wiphy, | ||
5437 | NL80211_EXT_FEATURE_STA_TX_PWR)) | ||
5438 | return -EOPNOTSUPP; | ||
5439 | |||
5440 | idx = NL80211_ATTR_STA_TX_POWER_SETTING; | ||
5441 | params->txpwr.type = nla_get_u8(info->attrs[idx]); | ||
5442 | |||
5443 | if (params->txpwr.type == NL80211_TX_POWER_LIMITED) { | ||
5444 | idx = NL80211_ATTR_STA_TX_POWER; | ||
5445 | |||
5446 | if (info->attrs[idx]) | ||
5447 | params->txpwr.power = | ||
5448 | nla_get_s16(info->attrs[idx]); | ||
5449 | else | ||
5450 | return -EINVAL; | ||
5451 | } | ||
5452 | params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER; | ||
5453 | } | ||
5454 | |||
5455 | return 0; | ||
5456 | } | ||
5457 | |||
5390 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 5458 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
5391 | { | 5459 | { |
5392 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5460 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -5480,6 +5548,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
5480 | NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) | 5548 | NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) |
5481 | return -EOPNOTSUPP; | 5549 | return -EOPNOTSUPP; |
5482 | 5550 | ||
5551 | err = nl80211_parse_sta_txpower_setting(info, ¶ms); | ||
5552 | if (err) | ||
5553 | return err; | ||
5554 | |||
5483 | /* Include parameters for TDLS peer (will check later) */ | 5555 | /* Include parameters for TDLS peer (will check later) */ |
5484 | err = nl80211_set_station_tdls(info, ¶ms); | 5556 | err = nl80211_set_station_tdls(info, ¶ms); |
5485 | if (err) | 5557 | if (err) |
@@ -5617,6 +5689,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
5617 | NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) | 5689 | NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) |
5618 | return -EOPNOTSUPP; | 5690 | return -EOPNOTSUPP; |
5619 | 5691 | ||
5692 | err = nl80211_parse_sta_txpower_setting(info, ¶ms); | ||
5693 | if (err) | ||
5694 | return err; | ||
5695 | |||
5620 | err = nl80211_parse_sta_channel_info(info, ¶ms); | 5696 | err = nl80211_parse_sta_channel_info(info, ¶ms); |
5621 | if (err) | 5697 | if (err) |
5622 | return err; | 5698 | return err; |
@@ -6882,7 +6958,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
6882 | struct nlattr *nl_reg_rule; | 6958 | struct nlattr *nl_reg_rule; |
6883 | char *alpha2; | 6959 | char *alpha2; |
6884 | int rem_reg_rules, r; | 6960 | int rem_reg_rules, r; |
6885 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 6961 | u32 num_rules = 0, rule_idx = 0; |
6886 | enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; | 6962 | enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET; |
6887 | struct ieee80211_regdomain *rd; | 6963 | struct ieee80211_regdomain *rd; |
6888 | 6964 | ||
@@ -6907,10 +6983,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
6907 | if (!reg_is_valid_request(alpha2)) | 6983 | if (!reg_is_valid_request(alpha2)) |
6908 | return -EINVAL; | 6984 | return -EINVAL; |
6909 | 6985 | ||
6910 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 6986 | rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL); |
6911 | num_rules * sizeof(struct ieee80211_reg_rule); | ||
6912 | |||
6913 | rd = kzalloc(size_of_regd, GFP_KERNEL); | ||
6914 | if (!rd) | 6987 | if (!rd) |
6915 | return -ENOMEM; | 6988 | return -ENOMEM; |
6916 | 6989 | ||
@@ -7537,6 +7610,41 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans, | |||
7537 | return 0; | 7610 | return 0; |
7538 | } | 7611 | } |
7539 | 7612 | ||
7613 | static int | ||
7614 | nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy, | ||
7615 | struct cfg80211_match_set *match_sets, | ||
7616 | struct nlattr *tb_band_rssi, | ||
7617 | s32 rssi_thold) | ||
7618 | { | ||
7619 | struct nlattr *attr; | ||
7620 | int i, tmp, ret = 0; | ||
7621 | |||
7622 | if (!wiphy_ext_feature_isset(wiphy, | ||
7623 | NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) { | ||
7624 | if (tb_band_rssi) | ||
7625 | ret = -EOPNOTSUPP; | ||
7626 | else | ||
7627 | for (i = 0; i < NUM_NL80211_BANDS; i++) | ||
7628 | match_sets->per_band_rssi_thold[i] = | ||
7629 | NL80211_SCAN_RSSI_THOLD_OFF; | ||
7630 | return ret; | ||
7631 | } | ||
7632 | |||
7633 | for (i = 0; i < NUM_NL80211_BANDS; i++) | ||
7634 | match_sets->per_band_rssi_thold[i] = rssi_thold; | ||
7635 | |||
7636 | nla_for_each_nested(attr, tb_band_rssi, tmp) { | ||
7637 | enum nl80211_band band = nla_type(attr); | ||
7638 | |||
7639 | if (band < 0 || band >= NUM_NL80211_BANDS) | ||
7640 | return -EINVAL; | ||
7641 | |||
7642 | match_sets->per_band_rssi_thold[band] = nla_get_s32(attr); | ||
7643 | } | ||
7644 | |||
7645 | return 0; | ||
7646 | } | ||
7647 | |||
7540 | static struct cfg80211_sched_scan_request * | 7648 | static struct cfg80211_sched_scan_request * |
7541 | nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, | 7649 | nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, |
7542 | struct nlattr **attrs, int max_match_sets) | 7650 | struct nlattr **attrs, int max_match_sets) |
@@ -7776,43 +7884,55 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev, | |||
7776 | goto out_free; | 7884 | goto out_free; |
7777 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; | 7885 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; |
7778 | bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]; | 7886 | bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID]; |
7779 | if (ssid || bssid) { | 7887 | |
7780 | if (WARN_ON(i >= n_match_sets)) { | 7888 | if (!ssid && !bssid) { |
7781 | /* this indicates a programming error, | 7889 | i++; |
7782 | * the loop above should have verified | 7890 | continue; |
7783 | * things properly | 7891 | } |
7784 | */ | 7892 | |
7893 | if (WARN_ON(i >= n_match_sets)) { | ||
7894 | /* this indicates a programming error, | ||
7895 | * the loop above should have verified | ||
7896 | * things properly | ||
7897 | */ | ||
7898 | err = -EINVAL; | ||
7899 | goto out_free; | ||
7900 | } | ||
7901 | |||
7902 | if (ssid) { | ||
7903 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | ||
7785 | err = -EINVAL; | 7904 | err = -EINVAL; |
7786 | goto out_free; | 7905 | goto out_free; |
7787 | } | 7906 | } |
7788 | 7907 | memcpy(request->match_sets[i].ssid.ssid, | |
7789 | if (ssid) { | 7908 | nla_data(ssid), nla_len(ssid)); |
7790 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | 7909 | request->match_sets[i].ssid.ssid_len = |
7791 | err = -EINVAL; | 7910 | nla_len(ssid); |
7792 | goto out_free; | 7911 | } |
7793 | } | 7912 | if (bssid) { |
7794 | memcpy(request->match_sets[i].ssid.ssid, | 7913 | if (nla_len(bssid) != ETH_ALEN) { |
7795 | nla_data(ssid), nla_len(ssid)); | 7914 | err = -EINVAL; |
7796 | request->match_sets[i].ssid.ssid_len = | 7915 | goto out_free; |
7797 | nla_len(ssid); | ||
7798 | } | ||
7799 | if (bssid) { | ||
7800 | if (nla_len(bssid) != ETH_ALEN) { | ||
7801 | err = -EINVAL; | ||
7802 | goto out_free; | ||
7803 | } | ||
7804 | memcpy(request->match_sets[i].bssid, | ||
7805 | nla_data(bssid), ETH_ALEN); | ||
7806 | } | 7916 | } |
7917 | memcpy(request->match_sets[i].bssid, | ||
7918 | nla_data(bssid), ETH_ALEN); | ||
7919 | } | ||
7807 | 7920 | ||
7808 | /* special attribute - old implementation w/a */ | 7921 | /* special attribute - old implementation w/a */ |
7922 | request->match_sets[i].rssi_thold = default_match_rssi; | ||
7923 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
7924 | if (rssi) | ||
7809 | request->match_sets[i].rssi_thold = | 7925 | request->match_sets[i].rssi_thold = |
7810 | default_match_rssi; | 7926 | nla_get_s32(rssi); |
7811 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | 7927 | |
7812 | if (rssi) | 7928 | /* Parse per band RSSI attribute */ |
7813 | request->match_sets[i].rssi_thold = | 7929 | err = nl80211_parse_sched_scan_per_band_rssi(wiphy, |
7814 | nla_get_s32(rssi); | 7930 | &request->match_sets[i], |
7815 | } | 7931 | tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI], |
7932 | request->match_sets[i].rssi_thold); | ||
7933 | if (err) | ||
7934 | goto out_free; | ||
7935 | |||
7816 | i++; | 7936 | i++; |
7817 | } | 7937 | } |
7818 | 7938 | ||
@@ -8061,7 +8181,7 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb, | |||
8061 | 8181 | ||
8062 | cfg80211_sched_dfs_chan_update(rdev); | 8182 | cfg80211_sched_dfs_chan_update(rdev); |
8063 | 8183 | ||
8064 | memcpy(&rdev->radar_chandef, &chandef, sizeof(chandef)); | 8184 | rdev->radar_chandef = chandef; |
8065 | 8185 | ||
8066 | /* Propagate this notification to other radios as well */ | 8186 | /* Propagate this notification to other radios as well */ |
8067 | queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); | 8187 | queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); |
@@ -13259,6 +13379,72 @@ nla_put_failure: | |||
13259 | return -ENOBUFS; | 13379 | return -ENOBUFS; |
13260 | } | 13380 | } |
13261 | 13381 | ||
13382 | static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info) | ||
13383 | { | ||
13384 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
13385 | struct cfg80211_update_owe_info owe_info; | ||
13386 | struct net_device *dev = info->user_ptr[1]; | ||
13387 | |||
13388 | if (!rdev->ops->update_owe_info) | ||
13389 | return -EOPNOTSUPP; | ||
13390 | |||
13391 | if (!info->attrs[NL80211_ATTR_STATUS_CODE] || | ||
13392 | !info->attrs[NL80211_ATTR_MAC]) | ||
13393 | return -EINVAL; | ||
13394 | |||
13395 | memset(&owe_info, 0, sizeof(owe_info)); | ||
13396 | owe_info.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]); | ||
13397 | nla_memcpy(owe_info.peer, info->attrs[NL80211_ATTR_MAC], ETH_ALEN); | ||
13398 | |||
13399 | if (info->attrs[NL80211_ATTR_IE]) { | ||
13400 | owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
13401 | owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
13402 | } | ||
13403 | |||
13404 | return rdev_update_owe_info(rdev, dev, &owe_info); | ||
13405 | } | ||
13406 | |||
13407 | static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info) | ||
13408 | { | ||
13409 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
13410 | struct net_device *dev = info->user_ptr[1]; | ||
13411 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
13412 | struct station_info sinfo = {}; | ||
13413 | const u8 *buf; | ||
13414 | size_t len; | ||
13415 | u8 *dest; | ||
13416 | int err; | ||
13417 | |||
13418 | if (!rdev->ops->probe_mesh_link || !rdev->ops->get_station) | ||
13419 | return -EOPNOTSUPP; | ||
13420 | |||
13421 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
13422 | !info->attrs[NL80211_ATTR_FRAME]) { | ||
13423 | GENL_SET_ERR_MSG(info, "Frame or MAC missing"); | ||
13424 | return -EINVAL; | ||
13425 | } | ||
13426 | |||
13427 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) | ||
13428 | return -EOPNOTSUPP; | ||
13429 | |||
13430 | dest = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
13431 | buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); | ||
13432 | len = nla_len(info->attrs[NL80211_ATTR_FRAME]); | ||
13433 | |||
13434 | if (len < sizeof(struct ethhdr)) | ||
13435 | return -EINVAL; | ||
13436 | |||
13437 | if (!ether_addr_equal(buf, dest) || is_multicast_ether_addr(buf) || | ||
13438 | !ether_addr_equal(buf + ETH_ALEN, dev->dev_addr)) | ||
13439 | return -EINVAL; | ||
13440 | |||
13441 | err = rdev_get_station(rdev, dev, dest, &sinfo); | ||
13442 | if (err) | ||
13443 | return err; | ||
13444 | |||
13445 | return rdev_probe_mesh_link(rdev, dev, dest, buf, len); | ||
13446 | } | ||
13447 | |||
13262 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 13448 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
13263 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 13449 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
13264 | #define NL80211_FLAG_NEED_RTNL 0x04 | 13450 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -14095,6 +14281,20 @@ static const struct genl_ops nl80211_ops[] = { | |||
14095 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 14281 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
14096 | NL80211_FLAG_NEED_RTNL, | 14282 | NL80211_FLAG_NEED_RTNL, |
14097 | }, | 14283 | }, |
14284 | { | ||
14285 | .cmd = NL80211_CMD_UPDATE_OWE_INFO, | ||
14286 | .doit = nl80211_update_owe_info, | ||
14287 | .flags = GENL_ADMIN_PERM, | ||
14288 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
14289 | NL80211_FLAG_NEED_RTNL, | ||
14290 | }, | ||
14291 | { | ||
14292 | .cmd = NL80211_CMD_PROBE_MESH_LINK, | ||
14293 | .doit = nl80211_probe_mesh_link, | ||
14294 | .flags = GENL_UNS_ADMIN_PERM, | ||
14295 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
14296 | NL80211_FLAG_NEED_RTNL, | ||
14297 | }, | ||
14098 | }; | 14298 | }; |
14099 | 14299 | ||
14100 | static struct genl_family nl80211_fam __ro_after_init = { | 14300 | static struct genl_family nl80211_fam __ro_after_init = { |
@@ -15624,6 +15824,11 @@ void cfg80211_ch_switch_notify(struct net_device *dev, | |||
15624 | 15824 | ||
15625 | wdev->chandef = *chandef; | 15825 | wdev->chandef = *chandef; |
15626 | wdev->preset_chandef = *chandef; | 15826 | wdev->preset_chandef = *chandef; |
15827 | |||
15828 | if (wdev->iftype == NL80211_IFTYPE_STATION && | ||
15829 | !WARN_ON(!wdev->current_bss)) | ||
15830 | wdev->current_bss->pub.channel = chandef->chan; | ||
15831 | |||
15627 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, | 15832 | nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL, |
15628 | NL80211_CMD_CH_SWITCH_NOTIFY, 0); | 15833 | NL80211_CMD_CH_SWITCH_NOTIFY, 0); |
15629 | } | 15834 | } |
@@ -16267,6 +16472,46 @@ int cfg80211_external_auth_request(struct net_device *dev, | |||
16267 | } | 16472 | } |
16268 | EXPORT_SYMBOL(cfg80211_external_auth_request); | 16473 | EXPORT_SYMBOL(cfg80211_external_auth_request); |
16269 | 16474 | ||
16475 | void cfg80211_update_owe_info_event(struct net_device *netdev, | ||
16476 | struct cfg80211_update_owe_info *owe_info, | ||
16477 | gfp_t gfp) | ||
16478 | { | ||
16479 | struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy; | ||
16480 | struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); | ||
16481 | struct sk_buff *msg; | ||
16482 | void *hdr; | ||
16483 | |||
16484 | trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info); | ||
16485 | |||
16486 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
16487 | if (!msg) | ||
16488 | return; | ||
16489 | |||
16490 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO); | ||
16491 | if (!hdr) | ||
16492 | goto nla_put_failure; | ||
16493 | |||
16494 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
16495 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
16496 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer)) | ||
16497 | goto nla_put_failure; | ||
16498 | |||
16499 | if (!owe_info->ie_len || | ||
16500 | nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie)) | ||
16501 | goto nla_put_failure; | ||
16502 | |||
16503 | genlmsg_end(msg, hdr); | ||
16504 | |||
16505 | genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, | ||
16506 | NL80211_MCGRP_MLME, gfp); | ||
16507 | return; | ||
16508 | |||
16509 | nla_put_failure: | ||
16510 | genlmsg_cancel(msg, hdr); | ||
16511 | nlmsg_free(msg); | ||
16512 | } | ||
16513 | EXPORT_SYMBOL(cfg80211_update_owe_info_event); | ||
16514 | |||
16270 | /* initialisation/exit functions */ | 16515 | /* initialisation/exit functions */ |
16271 | 16516 | ||
16272 | int __init nl80211_init(void) | 16517 | int __init nl80211_init(void) |
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 5cb48d135fab..e853a4fe6f97 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -77,7 +77,8 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev, | |||
77 | struct key_params *params) | 77 | struct key_params *params) |
78 | { | 78 | { |
79 | int ret; | 79 | int ret; |
80 | trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr); | 80 | trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, |
81 | mac_addr, params->mode); | ||
81 | ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise, | 82 | ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise, |
82 | mac_addr, params); | 83 | mac_addr, params); |
83 | trace_rdev_return_int(&rdev->wiphy, ret); | 84 | trace_rdev_return_int(&rdev->wiphy, ret); |
@@ -1272,4 +1273,30 @@ rdev_abort_pmsr(struct cfg80211_registered_device *rdev, | |||
1272 | trace_rdev_return_void(&rdev->wiphy); | 1273 | trace_rdev_return_void(&rdev->wiphy); |
1273 | } | 1274 | } |
1274 | 1275 | ||
1276 | static inline int rdev_update_owe_info(struct cfg80211_registered_device *rdev, | ||
1277 | struct net_device *dev, | ||
1278 | struct cfg80211_update_owe_info *oweinfo) | ||
1279 | { | ||
1280 | int ret = -EOPNOTSUPP; | ||
1281 | |||
1282 | trace_rdev_update_owe_info(&rdev->wiphy, dev, oweinfo); | ||
1283 | if (rdev->ops->update_owe_info) | ||
1284 | ret = rdev->ops->update_owe_info(&rdev->wiphy, dev, oweinfo); | ||
1285 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | static inline int | ||
1290 | rdev_probe_mesh_link(struct cfg80211_registered_device *rdev, | ||
1291 | struct net_device *dev, const u8 *dest, | ||
1292 | const void *buf, size_t len) | ||
1293 | { | ||
1294 | int ret; | ||
1295 | |||
1296 | trace_rdev_probe_mesh_link(&rdev->wiphy, dev, dest, buf, len); | ||
1297 | ret = rdev->ops->probe_mesh_link(&rdev->wiphy, dev, buf, len); | ||
1298 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
1299 | return ret; | ||
1300 | } | ||
1301 | |||
1275 | #endif /* __CFG80211_RDEV_OPS */ | 1302 | #endif /* __CFG80211_RDEV_OPS */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0ba778f371cb..816425ffe05a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -427,14 +427,10 @@ static const struct ieee80211_regdomain * | |||
427 | reg_copy_regd(const struct ieee80211_regdomain *src_regd) | 427 | reg_copy_regd(const struct ieee80211_regdomain *src_regd) |
428 | { | 428 | { |
429 | struct ieee80211_regdomain *regd; | 429 | struct ieee80211_regdomain *regd; |
430 | int size_of_regd; | ||
431 | unsigned int i; | 430 | unsigned int i; |
432 | 431 | ||
433 | size_of_regd = | 432 | regd = kzalloc(struct_size(regd, reg_rules, src_regd->n_reg_rules), |
434 | sizeof(struct ieee80211_regdomain) + | 433 | GFP_KERNEL); |
435 | src_regd->n_reg_rules * sizeof(struct ieee80211_reg_rule); | ||
436 | |||
437 | regd = kzalloc(size_of_regd, GFP_KERNEL); | ||
438 | if (!regd) | 434 | if (!regd) |
439 | return ERR_PTR(-ENOMEM); | 435 | return ERR_PTR(-ENOMEM); |
440 | 436 | ||
@@ -948,12 +944,10 @@ static int regdb_query_country(const struct fwdb_header *db, | |||
948 | unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; | 944 | unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; |
949 | struct fwdb_collection *coll = (void *)((u8 *)db + ptr); | 945 | struct fwdb_collection *coll = (void *)((u8 *)db + ptr); |
950 | struct ieee80211_regdomain *regdom; | 946 | struct ieee80211_regdomain *regdom; |
951 | unsigned int size_of_regd, i; | 947 | unsigned int i; |
952 | |||
953 | size_of_regd = sizeof(struct ieee80211_regdomain) + | ||
954 | coll->n_rules * sizeof(struct ieee80211_reg_rule); | ||
955 | 948 | ||
956 | regdom = kzalloc(size_of_regd, GFP_KERNEL); | 949 | regdom = kzalloc(struct_size(regdom, reg_rules, coll->n_rules), |
950 | GFP_KERNEL); | ||
957 | if (!regdom) | 951 | if (!regdom) |
958 | return -ENOMEM; | 952 | return -ENOMEM; |
959 | 953 | ||
@@ -1489,7 +1483,7 @@ static struct ieee80211_regdomain * | |||
1489 | regdom_intersect(const struct ieee80211_regdomain *rd1, | 1483 | regdom_intersect(const struct ieee80211_regdomain *rd1, |
1490 | const struct ieee80211_regdomain *rd2) | 1484 | const struct ieee80211_regdomain *rd2) |
1491 | { | 1485 | { |
1492 | int r, size_of_regd; | 1486 | int r; |
1493 | unsigned int x, y; | 1487 | unsigned int x, y; |
1494 | unsigned int num_rules = 0; | 1488 | unsigned int num_rules = 0; |
1495 | const struct ieee80211_reg_rule *rule1, *rule2; | 1489 | const struct ieee80211_reg_rule *rule1, *rule2; |
@@ -1520,10 +1514,7 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, | |||
1520 | if (!num_rules) | 1514 | if (!num_rules) |
1521 | return NULL; | 1515 | return NULL; |
1522 | 1516 | ||
1523 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 1517 | rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL); |
1524 | num_rules * sizeof(struct ieee80211_reg_rule); | ||
1525 | |||
1526 | rd = kzalloc(size_of_regd, GFP_KERNEL); | ||
1527 | if (!rd) | 1518 | if (!rd) |
1528 | return NULL; | 1519 | return NULL; |
1529 | 1520 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 04d888628f29..c04f5451f89b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -179,12 +179,63 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev, | |||
179 | return true; | 179 | return true; |
180 | } | 180 | } |
181 | 181 | ||
182 | bool cfg80211_is_element_inherited(const struct element *elem, | ||
183 | const struct element *non_inherit_elem) | ||
184 | { | ||
185 | u8 id_len, ext_id_len, i, loop_len, id; | ||
186 | const u8 *list; | ||
187 | |||
188 | if (elem->id == WLAN_EID_MULTIPLE_BSSID) | ||
189 | return false; | ||
190 | |||
191 | if (!non_inherit_elem || non_inherit_elem->datalen < 2) | ||
192 | return true; | ||
193 | |||
194 | /* | ||
195 | * non inheritance element format is: | ||
196 | * ext ID (56) | IDs list len | list | extension IDs list len | list | ||
197 | * Both lists are optional. Both lengths are mandatory. | ||
198 | * This means valid length is: | ||
199 | * elem_len = 1 (extension ID) + 2 (list len fields) + list lengths | ||
200 | */ | ||
201 | id_len = non_inherit_elem->data[1]; | ||
202 | if (non_inherit_elem->datalen < 3 + id_len) | ||
203 | return true; | ||
204 | |||
205 | ext_id_len = non_inherit_elem->data[2 + id_len]; | ||
206 | if (non_inherit_elem->datalen < 3 + id_len + ext_id_len) | ||
207 | return true; | ||
208 | |||
209 | if (elem->id == WLAN_EID_EXTENSION) { | ||
210 | if (!ext_id_len) | ||
211 | return true; | ||
212 | loop_len = ext_id_len; | ||
213 | list = &non_inherit_elem->data[3 + id_len]; | ||
214 | id = elem->data[0]; | ||
215 | } else { | ||
216 | if (!id_len) | ||
217 | return true; | ||
218 | loop_len = id_len; | ||
219 | list = &non_inherit_elem->data[2]; | ||
220 | id = elem->id; | ||
221 | } | ||
222 | |||
223 | for (i = 0; i < loop_len; i++) { | ||
224 | if (list[i] == id) | ||
225 | return false; | ||
226 | } | ||
227 | |||
228 | return true; | ||
229 | } | ||
230 | EXPORT_SYMBOL(cfg80211_is_element_inherited); | ||
231 | |||
182 | static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, | 232 | static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, |
183 | const u8 *subelement, size_t subie_len, | 233 | const u8 *subelement, size_t subie_len, |
184 | u8 *new_ie, gfp_t gfp) | 234 | u8 *new_ie, gfp_t gfp) |
185 | { | 235 | { |
186 | u8 *pos, *tmp; | 236 | u8 *pos, *tmp; |
187 | const u8 *tmp_old, *tmp_new; | 237 | const u8 *tmp_old, *tmp_new; |
238 | const struct element *non_inherit_elem; | ||
188 | u8 *sub_copy; | 239 | u8 *sub_copy; |
189 | 240 | ||
190 | /* copy subelement as we need to change its content to | 241 | /* copy subelement as we need to change its content to |
@@ -203,6 +254,11 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, | |||
203 | pos += (tmp_new[1] + 2); | 254 | pos += (tmp_new[1] + 2); |
204 | } | 255 | } |
205 | 256 | ||
257 | /* get non inheritance list if exists */ | ||
258 | non_inherit_elem = | ||
259 | cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, | ||
260 | sub_copy, subie_len); | ||
261 | |||
206 | /* go through IEs in ie (skip SSID) and subelement, | 262 | /* go through IEs in ie (skip SSID) and subelement, |
207 | * merge them into new_ie | 263 | * merge them into new_ie |
208 | */ | 264 | */ |
@@ -223,8 +279,11 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, | |||
223 | subie_len); | 279 | subie_len); |
224 | 280 | ||
225 | if (!tmp) { | 281 | if (!tmp) { |
282 | const struct element *old_elem = (void *)tmp_old; | ||
283 | |||
226 | /* ie in old ie but not in subelement */ | 284 | /* ie in old ie but not in subelement */ |
227 | if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) { | 285 | if (cfg80211_is_element_inherited(old_elem, |
286 | non_inherit_elem)) { | ||
228 | memcpy(pos, tmp_old, tmp_old[1] + 2); | 287 | memcpy(pos, tmp_old, tmp_old[1] + 2); |
229 | pos += tmp_old[1] + 2; | 288 | pos += tmp_old[1] + 2; |
230 | } | 289 | } |
@@ -268,8 +327,7 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, | |||
268 | tmp_new = sub_copy; | 327 | tmp_new = sub_copy; |
269 | while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { | 328 | while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { |
270 | if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP || | 329 | if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP || |
271 | tmp_new[0] == WLAN_EID_SSID || | 330 | tmp_new[0] == WLAN_EID_SSID)) { |
272 | tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX)) { | ||
273 | memcpy(pos, tmp_new, tmp_new[1] + 2); | 331 | memcpy(pos, tmp_new, tmp_new[1] + 2); |
274 | pos += tmp_new[1] + 2; | 332 | pos += tmp_new[1] + 2; |
275 | } | 333 | } |
@@ -1397,6 +1455,78 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, | |||
1397 | return &res->pub; | 1455 | return &res->pub; |
1398 | } | 1456 | } |
1399 | 1457 | ||
1458 | static const struct element | ||
1459 | *cfg80211_get_profile_continuation(const u8 *ie, size_t ielen, | ||
1460 | const struct element *mbssid_elem, | ||
1461 | const struct element *sub_elem) | ||
1462 | { | ||
1463 | const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen; | ||
1464 | const struct element *next_mbssid; | ||
1465 | const struct element *next_sub; | ||
1466 | |||
1467 | next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, | ||
1468 | mbssid_end, | ||
1469 | ielen - (mbssid_end - ie)); | ||
1470 | |||
1471 | /* | ||
1472 | * If is is not the last subelement in current MBSSID IE or there isn't | ||
1473 | * a next MBSSID IE - profile is complete. | ||
1474 | */ | ||
1475 | if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) || | ||
1476 | !next_mbssid) | ||
1477 | return NULL; | ||
1478 | |||
1479 | /* For any length error, just return NULL */ | ||
1480 | |||
1481 | if (next_mbssid->datalen < 4) | ||
1482 | return NULL; | ||
1483 | |||
1484 | next_sub = (void *)&next_mbssid->data[1]; | ||
1485 | |||
1486 | if (next_mbssid->data + next_mbssid->datalen < | ||
1487 | next_sub->data + next_sub->datalen) | ||
1488 | return NULL; | ||
1489 | |||
1490 | if (next_sub->id != 0 || next_sub->datalen < 2) | ||
1491 | return NULL; | ||
1492 | |||
1493 | /* | ||
1494 | * Check if the first element in the next sub element is a start | ||
1495 | * of a new profile | ||
1496 | */ | ||
1497 | return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ? | ||
1498 | NULL : next_mbssid; | ||
1499 | } | ||
1500 | |||
1501 | size_t cfg80211_merge_profile(const u8 *ie, size_t ielen, | ||
1502 | const struct element *mbssid_elem, | ||
1503 | const struct element *sub_elem, | ||
1504 | u8 *merged_ie, size_t max_copy_len) | ||
1505 | { | ||
1506 | size_t copied_len = sub_elem->datalen; | ||
1507 | const struct element *next_mbssid; | ||
1508 | |||
1509 | if (sub_elem->datalen > max_copy_len) | ||
1510 | return 0; | ||
1511 | |||
1512 | memcpy(merged_ie, sub_elem->data, sub_elem->datalen); | ||
1513 | |||
1514 | while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen, | ||
1515 | mbssid_elem, | ||
1516 | sub_elem))) { | ||
1517 | const struct element *next_sub = (void *)&next_mbssid->data[1]; | ||
1518 | |||
1519 | if (copied_len + next_sub->datalen > max_copy_len) | ||
1520 | break; | ||
1521 | memcpy(merged_ie + copied_len, next_sub->data, | ||
1522 | next_sub->datalen); | ||
1523 | copied_len += next_sub->datalen; | ||
1524 | } | ||
1525 | |||
1526 | return copied_len; | ||
1527 | } | ||
1528 | EXPORT_SYMBOL(cfg80211_merge_profile); | ||
1529 | |||
1400 | static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | 1530 | static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, |
1401 | struct cfg80211_inform_bss *data, | 1531 | struct cfg80211_inform_bss *data, |
1402 | enum cfg80211_bss_frame_type ftype, | 1532 | enum cfg80211_bss_frame_type ftype, |
@@ -1410,7 +1540,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | |||
1410 | const struct element *elem, *sub; | 1540 | const struct element *elem, *sub; |
1411 | size_t new_ie_len; | 1541 | size_t new_ie_len; |
1412 | u8 new_bssid[ETH_ALEN]; | 1542 | u8 new_bssid[ETH_ALEN]; |
1413 | u8 *new_ie; | 1543 | u8 *new_ie, *profile; |
1544 | u64 seen_indices = 0; | ||
1414 | u16 capability; | 1545 | u16 capability; |
1415 | struct cfg80211_bss *bss; | 1546 | struct cfg80211_bss *bss; |
1416 | 1547 | ||
@@ -1428,10 +1559,16 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | |||
1428 | if (!new_ie) | 1559 | if (!new_ie) |
1429 | return; | 1560 | return; |
1430 | 1561 | ||
1562 | profile = kmalloc(ielen, gfp); | ||
1563 | if (!profile) | ||
1564 | goto out; | ||
1565 | |||
1431 | for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) { | 1566 | for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) { |
1432 | if (elem->datalen < 4) | 1567 | if (elem->datalen < 4) |
1433 | continue; | 1568 | continue; |
1434 | for_each_element(sub, elem->data + 1, elem->datalen - 1) { | 1569 | for_each_element(sub, elem->data + 1, elem->datalen - 1) { |
1570 | u8 profile_len; | ||
1571 | |||
1435 | if (sub->id != 0 || sub->datalen < 4) { | 1572 | if (sub->id != 0 || sub->datalen < 4) { |
1436 | /* not a valid BSS profile */ | 1573 | /* not a valid BSS profile */ |
1437 | continue; | 1574 | continue; |
@@ -1446,16 +1583,31 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | |||
1446 | continue; | 1583 | continue; |
1447 | } | 1584 | } |
1448 | 1585 | ||
1586 | memset(profile, 0, ielen); | ||
1587 | profile_len = cfg80211_merge_profile(ie, ielen, | ||
1588 | elem, | ||
1589 | sub, | ||
1590 | profile, | ||
1591 | ielen); | ||
1592 | |||
1449 | /* found a Nontransmitted BSSID Profile */ | 1593 | /* found a Nontransmitted BSSID Profile */ |
1450 | mbssid_index_ie = cfg80211_find_ie | 1594 | mbssid_index_ie = cfg80211_find_ie |
1451 | (WLAN_EID_MULTI_BSSID_IDX, | 1595 | (WLAN_EID_MULTI_BSSID_IDX, |
1452 | sub->data, sub->datalen); | 1596 | profile, profile_len); |
1453 | if (!mbssid_index_ie || mbssid_index_ie[1] < 1 || | 1597 | if (!mbssid_index_ie || mbssid_index_ie[1] < 1 || |
1454 | mbssid_index_ie[2] == 0) { | 1598 | mbssid_index_ie[2] == 0 || |
1599 | mbssid_index_ie[2] > 46) { | ||
1455 | /* No valid Multiple BSSID-Index element */ | 1600 | /* No valid Multiple BSSID-Index element */ |
1456 | continue; | 1601 | continue; |
1457 | } | 1602 | } |
1458 | 1603 | ||
1604 | if (seen_indices & BIT(mbssid_index_ie[2])) | ||
1605 | /* We don't support legacy split of a profile */ | ||
1606 | net_dbg_ratelimited("Partial info for BSSID index %d\n", | ||
1607 | mbssid_index_ie[2]); | ||
1608 | |||
1609 | seen_indices |= BIT(mbssid_index_ie[2]); | ||
1610 | |||
1459 | non_tx_data->bssid_index = mbssid_index_ie[2]; | 1611 | non_tx_data->bssid_index = mbssid_index_ie[2]; |
1460 | non_tx_data->max_bssid_indicator = elem->data[0]; | 1612 | non_tx_data->max_bssid_indicator = elem->data[0]; |
1461 | 1613 | ||
@@ -1464,13 +1616,14 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | |||
1464 | non_tx_data->bssid_index, | 1616 | non_tx_data->bssid_index, |
1465 | new_bssid); | 1617 | new_bssid); |
1466 | memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); | 1618 | memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); |
1467 | new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data, | 1619 | new_ie_len = cfg80211_gen_new_ie(ie, ielen, |
1468 | sub->datalen, new_ie, | 1620 | profile, |
1621 | profile_len, new_ie, | ||
1469 | gfp); | 1622 | gfp); |
1470 | if (!new_ie_len) | 1623 | if (!new_ie_len) |
1471 | continue; | 1624 | continue; |
1472 | 1625 | ||
1473 | capability = get_unaligned_le16(sub->data + 2); | 1626 | capability = get_unaligned_le16(profile + 2); |
1474 | bss = cfg80211_inform_single_bss_data(wiphy, data, | 1627 | bss = cfg80211_inform_single_bss_data(wiphy, data, |
1475 | ftype, | 1628 | ftype, |
1476 | new_bssid, tsf, | 1629 | new_bssid, tsf, |
@@ -1486,7 +1639,9 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | |||
1486 | } | 1639 | } |
1487 | } | 1640 | } |
1488 | 1641 | ||
1642 | out: | ||
1489 | kfree(new_ie); | 1643 | kfree(new_ie); |
1644 | kfree(profile); | ||
1490 | } | 1645 | } |
1491 | 1646 | ||
1492 | struct cfg80211_bss * | 1647 | struct cfg80211_bss * |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 44b2ce1bb13a..2abfff925aac 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -430,22 +430,43 @@ DECLARE_EVENT_CLASS(key_handle, | |||
430 | BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) | 430 | BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr)) |
431 | ); | 431 | ); |
432 | 432 | ||
433 | DEFINE_EVENT(key_handle, rdev_add_key, | 433 | DEFINE_EVENT(key_handle, rdev_get_key, |
434 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, | 434 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, |
435 | bool pairwise, const u8 *mac_addr), | 435 | bool pairwise, const u8 *mac_addr), |
436 | TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) | 436 | TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) |
437 | ); | 437 | ); |
438 | 438 | ||
439 | DEFINE_EVENT(key_handle, rdev_get_key, | 439 | DEFINE_EVENT(key_handle, rdev_del_key, |
440 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, | 440 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, |
441 | bool pairwise, const u8 *mac_addr), | 441 | bool pairwise, const u8 *mac_addr), |
442 | TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) | 442 | TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) |
443 | ); | 443 | ); |
444 | 444 | ||
445 | DEFINE_EVENT(key_handle, rdev_del_key, | 445 | TRACE_EVENT(rdev_add_key, |
446 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, | 446 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, |
447 | bool pairwise, const u8 *mac_addr), | 447 | bool pairwise, const u8 *mac_addr, u8 mode), |
448 | TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr) | 448 | TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr, mode), |
449 | TP_STRUCT__entry( | ||
450 | WIPHY_ENTRY | ||
451 | NETDEV_ENTRY | ||
452 | MAC_ENTRY(mac_addr) | ||
453 | __field(u8, key_index) | ||
454 | __field(bool, pairwise) | ||
455 | __field(u8, mode) | ||
456 | ), | ||
457 | TP_fast_assign( | ||
458 | WIPHY_ASSIGN; | ||
459 | NETDEV_ASSIGN; | ||
460 | MAC_ASSIGN(mac_addr, mac_addr); | ||
461 | __entry->key_index = key_index; | ||
462 | __entry->pairwise = pairwise; | ||
463 | __entry->mode = mode; | ||
464 | ), | ||
465 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, " | ||
466 | "mode: %u, pairwise: %s, mac addr: " MAC_PR_FMT, | ||
467 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index, | ||
468 | __entry->mode, BOOL_TO_STR(__entry->pairwise), | ||
469 | MAC_PR_ARG(mac_addr)) | ||
449 | ); | 470 | ); |
450 | 471 | ||
451 | TRACE_EVENT(rdev_set_default_key, | 472 | TRACE_EVENT(rdev_set_default_key, |
@@ -3362,6 +3383,62 @@ TRACE_EVENT(cfg80211_pmsr_complete, | |||
3362 | WIPHY_PR_ARG, WDEV_PR_ARG, | 3383 | WIPHY_PR_ARG, WDEV_PR_ARG, |
3363 | (unsigned long long)__entry->cookie) | 3384 | (unsigned long long)__entry->cookie) |
3364 | ); | 3385 | ); |
3386 | |||
3387 | TRACE_EVENT(rdev_update_owe_info, | ||
3388 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
3389 | struct cfg80211_update_owe_info *owe_info), | ||
3390 | TP_ARGS(wiphy, netdev, owe_info), | ||
3391 | TP_STRUCT__entry(WIPHY_ENTRY | ||
3392 | NETDEV_ENTRY | ||
3393 | MAC_ENTRY(peer) | ||
3394 | __field(u16, status) | ||
3395 | __dynamic_array(u8, ie, owe_info->ie_len)), | ||
3396 | TP_fast_assign(WIPHY_ASSIGN; | ||
3397 | NETDEV_ASSIGN; | ||
3398 | MAC_ASSIGN(peer, owe_info->peer); | ||
3399 | __entry->status = owe_info->status; | ||
3400 | memcpy(__get_dynamic_array(ie), | ||
3401 | owe_info->ie, owe_info->ie_len);), | ||
3402 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT | ||
3403 | " status %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), | ||
3404 | __entry->status) | ||
3405 | ); | ||
3406 | |||
3407 | TRACE_EVENT(cfg80211_update_owe_info_event, | ||
3408 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
3409 | struct cfg80211_update_owe_info *owe_info), | ||
3410 | TP_ARGS(wiphy, netdev, owe_info), | ||
3411 | TP_STRUCT__entry(WIPHY_ENTRY | ||
3412 | NETDEV_ENTRY | ||
3413 | MAC_ENTRY(peer) | ||
3414 | __dynamic_array(u8, ie, owe_info->ie_len)), | ||
3415 | TP_fast_assign(WIPHY_ASSIGN; | ||
3416 | NETDEV_ASSIGN; | ||
3417 | MAC_ASSIGN(peer, owe_info->peer); | ||
3418 | memcpy(__get_dynamic_array(ie), owe_info->ie, | ||
3419 | owe_info->ie_len);), | ||
3420 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, | ||
3421 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) | ||
3422 | ); | ||
3423 | |||
3424 | TRACE_EVENT(rdev_probe_mesh_link, | ||
3425 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
3426 | const u8 *dest, const u8 *buf, size_t len), | ||
3427 | TP_ARGS(wiphy, netdev, dest, buf, len), | ||
3428 | TP_STRUCT__entry( | ||
3429 | WIPHY_ENTRY | ||
3430 | NETDEV_ENTRY | ||
3431 | MAC_ENTRY(dest) | ||
3432 | ), | ||
3433 | TP_fast_assign( | ||
3434 | WIPHY_ASSIGN; | ||
3435 | NETDEV_ASSIGN; | ||
3436 | MAC_ASSIGN(dest, dest); | ||
3437 | ), | ||
3438 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT, | ||
3439 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest)) | ||
3440 | ); | ||
3441 | |||
3365 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ | 3442 | #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ |
3366 | 3443 | ||
3367 | #undef TRACE_INCLUDE_PATH | 3444 | #undef TRACE_INCLUDE_PATH |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 75899b62bdc9..cf63b635afc0 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -237,14 +237,23 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
237 | case WLAN_CIPHER_SUITE_CCMP_256: | 237 | case WLAN_CIPHER_SUITE_CCMP_256: |
238 | case WLAN_CIPHER_SUITE_GCMP: | 238 | case WLAN_CIPHER_SUITE_GCMP: |
239 | case WLAN_CIPHER_SUITE_GCMP_256: | 239 | case WLAN_CIPHER_SUITE_GCMP_256: |
240 | /* Disallow pairwise keys with non-zero index unless it's WEP | 240 | /* IEEE802.11-2016 allows only 0 and - when using Extended Key |
241 | * or a vendor specific cipher (because current deployments use | 241 | * ID - 1 as index for pairwise keys. |
242 | * pairwise WEP keys with non-zero indices and for vendor | 242 | * @NL80211_KEY_NO_TX is only allowed for pairwise keys when |
243 | * specific ciphers this should be validated in the driver or | 243 | * the driver supports Extended Key ID. |
244 | * hardware level - but 802.11i clearly specifies to use zero) | 244 | * @NL80211_KEY_SET_TX can't be set when installing and |
245 | * validating a key. | ||
245 | */ | 246 | */ |
246 | if (pairwise && key_idx) | 247 | if (params->mode == NL80211_KEY_NO_TX) { |
248 | if (!wiphy_ext_feature_isset(&rdev->wiphy, | ||
249 | NL80211_EXT_FEATURE_EXT_KEY_ID)) | ||
250 | return -EINVAL; | ||
251 | else if (!pairwise || key_idx < 0 || key_idx > 1) | ||
252 | return -EINVAL; | ||
253 | } else if ((pairwise && key_idx) || | ||
254 | params->mode == NL80211_KEY_SET_TX) { | ||
247 | return -EINVAL; | 255 | return -EINVAL; |
256 | } | ||
248 | break; | 257 | break; |
249 | case WLAN_CIPHER_SUITE_AES_CMAC: | 258 | case WLAN_CIPHER_SUITE_AES_CMAC: |
250 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: | 259 | case WLAN_CIPHER_SUITE_BIP_CMAC_256: |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index d522787c7354..46e4d69db845 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -353,9 +353,6 @@ static int cfg80211_wext_siwretry(struct net_device *dev, | |||
353 | changed |= WIPHY_PARAM_RETRY_SHORT; | 353 | changed |= WIPHY_PARAM_RETRY_SHORT; |
354 | } | 354 | } |
355 | 355 | ||
356 | if (!changed) | ||
357 | return 0; | ||
358 | |||
359 | err = rdev_set_wiphy_params(rdev, changed); | 356 | err = rdev_set_wiphy_params(rdev, changed); |
360 | if (err) { | 357 | if (err) { |
361 | wdev->wiphy->retry_short = oshort; | 358 | wdev->wiphy->retry_short = oshort; |