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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAlzC5YYACgkQB8qZga/f
 l8QDWg/+N7wm+l7bTMx4hjJzZZ60n9fBvyGJx0gsnPVH8wdOiPoh/epuI04I8I4m
 pGNbGvPB9Z4z2tD56XsIQnXf88ab3R27bRupSSW1vtzVSbDhg8wQ7jg0nABrdyDS
 PgoTmDMfVERLewXdntqRANzVYGfoWSOzo1u6A0Xhys8FqxxX/eD+Vdo4dKzmeN47
 +LDfuCpInVPn0TOpFp5IJ4+B4a0dhkz2/Q1BOE7NquXVvk4X77VJohV/BgQJ04Io
 yt7mn5rzYM6j4o1XLACxUEHkXvht6h34abG0yHRnuoAEp/sdPz2jAXT4OxYqs6x0
 XdLdr8gZgkMnnYaOQef74uJ2Ku+4A1ootjXSPazA7BWX0X5GqHnET/INk2S6cQPj
 C95LYfKC0ICD0qfioBmmHx8icDGoovcaswCju2ozfqWaD4Lwr3BcesnNDFtkHD9o
 aYaTTGGSxFyr2bZWTDpv4D4H5g3V4srRJsXs+SokL54nvlwd/smUJ4PVTLomP9y2
 XswRtLdoiUsCrJy967CXfhsxnE5SRhmBQE38Jq8/pzetlRk2spvJJC5MGYF0O/nT
 0UHbrjBCFUT2s8jv+gWWabOBUovsNJlgaxFwrZ/eNVIk0DK0ERoMV3V4MktU8uza
 Y339T14kxw4wlY2z5pOmEgkxmKZbPb55dBba04JEZzz9zDTawTk=
 =JQOx
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
David S. Miller 2019-04-26 16:05:52 -04:00
commit 30e5a9a5ba
36 changed files with 1480 additions and 375 deletions

View File

@ -2810,6 +2810,12 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
ieee80211_hw_set(hw, SIGNAL_DBM);
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, TDLS_WIDER_BW);
/* We only have SW crypto and only implement the A-MPDU API
* (but don't really build A-MPDUs) so can have extended key
* support
*/
ieee80211_hw_set(hw, EXT_KEY_ID_NATIVE);
if (rctbl)
ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
@ -3900,6 +3906,8 @@ static int __init init_mac80211_hwsim(void)
param.p2p_device = support_p2p_device;
param.use_chanctx = channels > 1;
param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK;
if (param.p2p_device)
param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
err = mac80211_hwsim_new_radio(NULL, &param);
if (err < 0)

View File

@ -1557,7 +1557,7 @@ struct ieee80211_vht_operation {
* struct ieee80211_he_cap_elem - HE capabilities element
*
* This structure is the "HE capabilities element" fixed fields as
* described in P802.11ax_D3.0 section 9.4.2.237.2 and 9.4.2.237.3
* described in P802.11ax_D4.0 section 9.4.2.242.2 and 9.4.2.242.3
*/
struct ieee80211_he_cap_elem {
u8 mac_cap_info[6];
@ -1619,12 +1619,12 @@ struct ieee80211_he_mcs_nss_supp {
* struct ieee80211_he_operation - HE capabilities element
*
* This structure is the "HE operation element" fields as
* described in P802.11ax_D3.0 section 9.4.2.238
* described in P802.11ax_D4.0 section 9.4.2.243
*/
struct ieee80211_he_operation {
__le32 he_oper_params;
__le16 he_mcs_nss_set;
/* Optional 0,1,3 or 4 bytes: depends on @he_oper_params */
/* Optional 0,1,3,4,5,7 or 8 bytes: depends on @he_oper_params */
u8 optional[0];
} __packed;
@ -1632,7 +1632,7 @@ struct ieee80211_he_operation {
* struct ieee80211_he_mu_edca_param_ac_rec - MU AC Parameter Record field
*
* This structure is the "MU AC Parameter Record" fields as
* described in P802.11ax_D2.0 section 9.4.2.240
* described in P802.11ax_D4.0 section 9.4.2.245
*/
struct ieee80211_he_mu_edca_param_ac_rec {
u8 aifsn;
@ -1644,7 +1644,7 @@ struct ieee80211_he_mu_edca_param_ac_rec {
* struct ieee80211_mu_edca_param_set - MU EDCA Parameter Set element
*
* This structure is the "MU EDCA Parameter Set element" fields as
* described in P802.11ax_D2.0 section 9.4.2.240
* described in P802.11ax_D4.0 section 9.4.2.245
*/
struct ieee80211_mu_edca_param_set {
u8 mu_qos_info;
@ -2026,6 +2026,7 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
#define IEEE80211_HE_OPERATION_VHT_OPER_INFO 0x00004000
#define IEEE80211_HE_OPERATION_CO_HOSTED_BSS 0x00008000
#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x00010000
#define IEEE80211_HE_OPERATION_6GHZ_OP_INFO 0x00020000
#define IEEE80211_HE_OPERATION_BSS_COLOR_MASK 0x3f000000
#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 24
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
@ -2056,6 +2057,8 @@ ieee80211_he_oper_size(const u8 *he_oper_ie)
oper_len += 3;
if (he_oper_params & IEEE80211_HE_OPERATION_CO_HOSTED_BSS)
oper_len++;
if (he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO)
oper_len += 4;
/* Add the first byte (extension ID) to the total length */
oper_len++;
@ -2487,6 +2490,7 @@ enum ieee80211_eid_ext {
WLAN_EID_EXT_HE_MU_EDCA = 38,
WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME = 52,
WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION = 55,
WLAN_EID_EXT_NON_INHERITANCE = 56,
};
/* Action category code */

View File

@ -485,6 +485,7 @@ struct vif_params {
* with the get_key() callback, must be in little endian,
* length given by @seq_len.
* @seq_len: length of @seq.
* @mode: key install mode (RX_TX, NO_TX or SET_TX)
*/
struct key_params {
const u8 *key;
@ -492,6 +493,7 @@ struct key_params {
int key_len;
int seq_len;
u32 cipher;
enum nl80211_key_mode mode;
};
/**
@ -973,6 +975,27 @@ enum station_parameters_apply_mask {
STATION_PARAM_APPLY_UAPSD = BIT(0),
STATION_PARAM_APPLY_CAPABILITY = BIT(1),
STATION_PARAM_APPLY_PLINK_STATE = BIT(2),
STATION_PARAM_APPLY_STA_TXPOWER = BIT(3),
};
/**
* struct sta_txpwr - station txpower configuration
*
* Used to configure txpower for station.
*
* @power: tx power (in dBm) to be used for sending data traffic. If tx power
* is not provided, the default per-interface tx power setting will be
* overriding. Driver should be picking up the lowest tx power, either tx
* power per-interface or per-station.
* @type: In particular if TPC %type is NL80211_TX_POWER_LIMITED then tx power
* will be less than or equal to specified from userspace, whereas if TPC
* %type is NL80211_TX_POWER_AUTOMATIC then it indicates default tx power.
* NL80211_TX_POWER_FIXED is not a valid configuration option for
* per peer TPC.
*/
struct sta_txpwr {
s16 power;
enum nl80211_tx_power_setting type;
};
/**
@ -1047,6 +1070,7 @@ struct station_parameters {
const struct ieee80211_he_cap_elem *he_capa;
u8 he_capa_len;
u16 airtime_weight;
struct sta_txpwr txpwr;
};
/**
@ -1327,6 +1351,7 @@ struct cfg80211_tid_stats {
* @fcs_err_count: number of packets (MPDUs) received from this station with
* an FCS error. This counter should be incremented only when TA of the
* received packet with an FCS error matches the peer MAC address.
* @airtime_link_metric: mesh airtime link metric.
*/
struct station_info {
u64 filled;
@ -1381,6 +1406,8 @@ struct station_info {
u32 rx_mpdu_count;
u32 fcs_err_count;
u32 airtime_link_metric;
};
#if IS_ENABLED(CONFIG_CFG80211)
@ -1832,11 +1859,19 @@ static inline void get_random_mask_addr(u8 *buf, const u8 *addr, const u8 *mask)
* @bssid: BSSID to be matched; may be all-zero BSSID in case of SSID match
* or no match (RSSI only)
* @rssi_thold: don't report scan results below this threshold (in s32 dBm)
* @per_band_rssi_thold: Minimum rssi threshold for each band to be applied
* for filtering out scan results received. Drivers advertize this support
* of band specific rssi based filtering through the feature capability
* %NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD. These band
* specific rssi thresholds take precedence over rssi_thold, if specified.
* If not specified for any band, it will be assigned with rssi_thold of
* corresponding matchset.
*/
struct cfg80211_match_set {
struct cfg80211_ssid ssid;
u8 bssid[ETH_ALEN];
s32 rssi_thold;
s32 per_band_rssi_thold[NUM_NL80211_BANDS];
};
/**
@ -3099,6 +3134,32 @@ struct cfg80211_pmsr_request {
struct cfg80211_pmsr_request_peer peers[];
};
/**
* struct cfg80211_update_owe_info - OWE Information
*
* This structure provides information needed for the drivers to offload OWE
* (Opportunistic Wireless Encryption) processing to the user space.
*
* Commonly used across update_owe_info request and event interfaces.
*
* @peer: MAC address of the peer device for which the OWE processing
* has to be done.
* @status: status code, %WLAN_STATUS_SUCCESS for successful OWE info
* processing, use %WLAN_STATUS_UNSPECIFIED_FAILURE if user space
* cannot give you the real status code for failures. Used only for
* OWE update request command interface (user space to driver).
* @ie: IEs obtained from the peer or constructed by the user space. These are
* the IEs of the remote peer in the event from the host driver and
* the constructed IEs by the user space in the request interface.
* @ie_len: Length of IEs in octets.
*/
struct cfg80211_update_owe_info {
u8 peer[ETH_ALEN] __aligned(2);
u16 status;
const u8 *ie;
size_t ie_len;
};
/**
* struct cfg80211_ops - backend description for wireless configuration
*
@ -3436,6 +3497,13 @@ struct cfg80211_pmsr_request {
* Statistics should be cumulative, currently no way to reset is provided.
* @start_pmsr: start peer measurement (e.g. FTM)
* @abort_pmsr: abort peer measurement
*
* @update_owe_info: Provide updated OWE info to driver. Driver implementing SME
* but offloading OWE processing to the user space will get the updated
* DH IE through this interface.
*
* @probe_mesh_link: Probe direct Mesh peer's link quality by sending data frame
* and overrule HWMP path selection algorithm.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@ -3750,6 +3818,10 @@ struct cfg80211_ops {
struct cfg80211_pmsr_request *request);
void (*abort_pmsr)(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_pmsr_request *request);
int (*update_owe_info)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_owe_info *owe_info);
int (*probe_mesh_link)(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);
};
/*
@ -5491,6 +5563,28 @@ static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,
u64_to_ether_addr(new_bssid_u64, new_bssid);
}
/**
* cfg80211_is_element_inherited - returns if element ID should be inherited
* @element: element to check
* @non_inherit_element: non inheritance element
*/
bool cfg80211_is_element_inherited(const struct element *element,
const struct element *non_inherit_element);
/**
* cfg80211_merge_profile - merges a MBSSID profile if it is split between IEs
* @ie: ies
* @ielen: length of IEs
* @mbssid_elem: current MBSSID element
* @sub_elem: current MBSSID subelement (profile)
* @merged_ie: location of the merged profile
* @max_copy_len: max merged profile length
*/
size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
const struct element *mbssid_elem,
const struct element *sub_elem,
u8 *merged_ie, size_t max_copy_len);
/**
* enum cfg80211_bss_frame_type - frame type that the BSS data came from
* @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is
@ -7213,4 +7307,14 @@ void cfg80211_pmsr_complete(struct wireless_dev *wdev,
#define wiphy_WARN(wiphy, format, args...) \
WARN(1, "wiphy: %s\n" format, wiphy_name(wiphy), ##args);
/**
* cfg80211_update_owe_info_event - Notify the peer's OWE info to user space
* @netdev: network device
* @owe_info: peer's owe info
* @gfp: allocation flags
*/
void cfg80211_update_owe_info_event(struct net_device *netdev,
struct cfg80211_update_owe_info *owe_info,
gfp_t gfp);
#endif /* __NET_CFG80211_H */

View File

@ -107,21 +107,23 @@ static struct sk_buff *fq_tin_dequeue(struct fq *fq,
return skb;
}
static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb)
{
u32 hash = skb_get_hash_perturb(skb, fq->perturbation);
return reciprocal_scale(hash, fq->flows_cnt);
}
static struct fq_flow *fq_flow_classify(struct fq *fq,
struct fq_tin *tin,
struct fq_tin *tin, u32 idx,
struct sk_buff *skb,
fq_flow_get_default_t get_default_func)
{
struct fq_flow *flow;
u32 hash;
u32 idx;
lockdep_assert_held(&fq->lock);
hash = skb_get_hash_perturb(skb, fq->perturbation);
idx = reciprocal_scale(hash, fq->flows_cnt);
flow = &fq->flows[idx];
if (flow->tin && flow->tin != tin) {
flow = get_default_func(fq, tin, idx, skb);
tin->collisions++;
@ -153,7 +155,7 @@ static void fq_recalc_backlog(struct fq *fq,
}
static void fq_tin_enqueue(struct fq *fq,
struct fq_tin *tin,
struct fq_tin *tin, u32 idx,
struct sk_buff *skb,
fq_skb_free_t free_func,
fq_flow_get_default_t get_default_func)
@ -163,7 +165,7 @@ static void fq_tin_enqueue(struct fq *fq,
lockdep_assert_held(&fq->lock);
flow = fq_flow_classify(fq, tin, skb, get_default_func);
flow = fq_flow_classify(fq, tin, idx, skb, get_default_func);
flow->tin = tin;
flow->backlog += skb->len;

View File

@ -807,6 +807,7 @@ enum mac80211_tx_info_flags {
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
* @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
* @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup
*
* These flags are used in tx_info->control.flags.
*/
@ -816,6 +817,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
IEEE80211_TX_CTRL_AMSDU = BIT(3),
IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5),
};
/*
@ -1697,6 +1699,7 @@ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif);
* @IEEE80211_KEY_FLAG_PUT_MIC_SPACE: This flag should be set by the driver for
* a TKIP key if it only requires MIC space. Do not set together with
* @IEEE80211_KEY_FLAG_GENERATE_MMIC on the same key.
* @IEEE80211_KEY_FLAG_NO_AUTO_TX: Key needs explicit Tx activation.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(0),
@ -1708,6 +1711,7 @@ enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_RX_MGMT = BIT(6),
IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(7),
IEEE80211_KEY_FLAG_PUT_MIC_SPACE = BIT(8),
IEEE80211_KEY_FLAG_NO_AUTO_TX = BIT(9),
};
/**
@ -1887,6 +1891,24 @@ struct ieee80211_sta_rates {
} rate[IEEE80211_TX_RATE_TABLE_SIZE];
};
/**
* struct ieee80211_sta_txpwr - station txpower configuration
*
* Used to configure txpower for station.
*
* @power: indicates the tx power, in dBm, to be used when sending data frames
* to the STA.
* @type: In particular if TPC %type is NL80211_TX_POWER_LIMITED then tx power
* will be less than or equal to specified from userspace, whereas if TPC
* %type is NL80211_TX_POWER_AUTOMATIC then it indicates default tx power.
* NL80211_TX_POWER_FIXED is not a valid configuration option for
* per peer TPC.
*/
struct ieee80211_sta_txpwr {
s16 power;
enum nl80211_tx_power_setting type;
};
/**
* struct ieee80211_sta - station table entry
*
@ -1973,6 +1995,7 @@ struct ieee80211_sta {
bool support_p2p_ps;
u16 max_rc_amsdu_len;
u16 max_tid_amsdu_len[IEEE80211_NUM_TIDS];
struct ieee80211_sta_txpwr txpwr;
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
@ -2243,6 +2266,9 @@ struct ieee80211_txq {
* @IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID: Hardware supports multi BSSID
* only for HE APs. Applies if @IEEE80211_HW_SUPPORTS_MULTI_BSSID is set.
*
* @IEEE80211_HW_EXT_KEY_ID_NATIVE: Driver and hardware are supporting Extended
* Key ID and can handle two unicast keys per station for Rx and Tx.
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@ -2294,6 +2320,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
IEEE80211_HW_EXT_KEY_ID_NATIVE,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
@ -3794,6 +3821,9 @@ struct ieee80211_ops {
#endif
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, struct ieee80211_sta *sta);
int (*sta_set_txpwr)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,

View File

@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018 Intel Corporation
* Copyright (C) 2018-2019 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -1065,6 +1065,26 @@
* indicated by %NL80211_ATTR_WIPHY_FREQ and other attributes
* determining the width and type.
*
* @NL80211_CMD_UPDATE_OWE_INFO: This interface allows the host driver to
* offload OWE processing to user space. This intends to support
* OWE AKM by the host drivers that implement SME but rely
* on the user space for the cryptographic/DH IE processing in AP mode.
*
* @NL80211_CMD_PROBE_MESH_LINK: The requirement for mesh link metric
* refreshing, is that from one mesh point we be able to send some data
* frames to other mesh points which are not currently selected as a
* primary traffic path, but which are only 1 hop away. The absence of
* the primary path to the chosen node makes it necessary to apply some
* form of marking on a chosen packet stream so that the packets can be
* properly steered to the selected node for testing, and not by the
* regular mesh path lookup. Further, the packets must be of type data
* so that the rate control (often embedded in firmware) is used for
* rate selection.
*
* Here attribute %NL80211_ATTR_MAC is used to specify connected mesh
* peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame
* content. The frame is ethernet data.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -1285,6 +1305,10 @@ enum nl80211_commands {
NL80211_CMD_NOTIFY_RADAR,
NL80211_CMD_UPDATE_OWE_INFO,
NL80211_CMD_PROBE_MESH_LINK,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -2308,6 +2332,15 @@ enum nl80211_commands {
* @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
* scheduler.
*
* @NL80211_ATTR_STA_TX_POWER_SETTING: Transmit power setting type (u8) for
* station associated with the AP. See &enum nl80211_tx_power_setting for
* possible values.
* @NL80211_ATTR_STA_TX_POWER: Transmit power level (s16) in dBm units. This
* allows to set Tx power for a station. If this attribute is not included,
* the default per-interface tx power setting will be overriding. Driver
* should be picking up the lowest tx power, either tx power per-interface
* or per-station.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -2758,6 +2791,8 @@ enum nl80211_attrs {
NL80211_ATTR_PEER_MEASUREMENTS,
NL80211_ATTR_AIRTIME_WEIGHT,
NL80211_ATTR_STA_TX_POWER_SETTING,
NL80211_ATTR_STA_TX_POWER,
/* add attributes here, update the policy in nl80211.c */
@ -2802,7 +2837,7 @@ enum nl80211_attrs {
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 64
#define NL80211_MAX_SUPP_REG_RULES 128
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
@ -3139,6 +3174,7 @@ enum nl80211_sta_bss_param {
* @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames
* sent to the station (u64, usec)
* @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
* @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@ -3184,6 +3220,7 @@ enum nl80211_sta_info {
NL80211_STA_INFO_CONNECTED_TO_GATE,
NL80211_STA_INFO_TX_DURATION,
NL80211_STA_INFO_AIRTIME_WEIGHT,
NL80211_STA_INFO_AIRTIME_LINK_METRIC,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@ -3638,6 +3675,14 @@ enum nl80211_reg_rule_attr {
* value as specified by &struct nl80211_bss_select_rssi_adjust.
* @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching
* (this cannot be used together with SSID).
* @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Nested attribute that carries the
* band specific minimum rssi thresholds for the bands defined in
* enum nl80211_band. The minimum rssi threshold value(s32) specific to a
* band shall be encapsulated in attribute with type value equals to one
* of the NL80211_BAND_* defined in enum nl80211_band. For example, the
* minimum rssi threshold value for 2.4GHZ band shall be encapsulated
* within an attribute of type NL80211_BAND_2GHZ. And one or more of such
* attributes will be nested within this attribute.
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@ -3650,6 +3695,7 @@ enum nl80211_sched_scan_match_attr {
NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@ -4134,6 +4180,27 @@ enum nl80211_channel_type {
NL80211_CHAN_HT40PLUS
};
/**
* enum nl80211_key_mode - Key mode
*
* @NL80211_KEY_RX_TX: (Default)
* Key can be used for Rx and Tx immediately
*
* The following modes can only be selected for unicast keys and when the
* driver supports @NL80211_EXT_FEATURE_EXT_KEY_ID:
*
* @NL80211_KEY_NO_TX: Only allowed in combination with @NL80211_CMD_NEW_KEY:
* Unicast key can only be used for Rx, Tx not allowed, yet
* @NL80211_KEY_SET_TX: Only allowed in combination with @NL80211_CMD_SET_KEY:
* The unicast key identified by idx and mac is cleared for Tx and becomes
* the preferred Tx key for the station.
*/
enum nl80211_key_mode {
NL80211_KEY_RX_TX,
NL80211_KEY_NO_TX,
NL80211_KEY_SET_TX
};
/**
* enum nl80211_chan_width - channel width definitions
*
@ -4377,6 +4444,9 @@ enum nl80211_key_default_types {
* @NL80211_KEY_DEFAULT_TYPES: A nested attribute containing flags
* attributes, specifying what a key should be set as default as.
* See &enum nl80211_key_default_types.
* @NL80211_KEY_MODE: the mode from enum nl80211_key_mode.
* Defaults to @NL80211_KEY_RX_TX.
*
* @__NL80211_KEY_AFTER_LAST: internal
* @NL80211_KEY_MAX: highest key attribute
*/
@ -4390,6 +4460,7 @@ enum nl80211_key_attributes {
NL80211_KEY_DEFAULT_MGMT,
NL80211_KEY_TYPE,
NL80211_KEY_DEFAULT_TYPES,
NL80211_KEY_MODE,
/* keep last */
__NL80211_KEY_AFTER_LAST,
@ -5335,6 +5406,8 @@ enum nl80211_feature_flags {
* able to rekey an in-use key correctly. Userspace must not rekey PTK keys
* if this flag is not set. Ignoring this can leak clear text packets and/or
* freeze the connection.
* @NL80211_EXT_FEATURE_EXT_KEY_ID: Driver supports "Extended Key ID for
* Individually Addressed Frames" from IEEE802.11-2016.
*
* @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
* fairness for transmitted packets and has enabled airtime fairness
@ -5343,6 +5416,12 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching
* (set/del PMKSA operations) in AP mode.
*
* @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports
* filtering of sched scan results using band specific RSSI thresholds.
*
* @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
* to a station.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@ -5384,6 +5463,9 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,

View File

@ -351,6 +351,36 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
return 0;
}
static int ieee80211_set_tx(struct ieee80211_sub_if_data *sdata,
const u8 *mac_addr, u8 key_idx)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_key *key;
struct sta_info *sta;
int ret = -EINVAL;
if (!wiphy_ext_feature_isset(local->hw.wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID))
return -EINVAL;
sta = sta_info_get_bss(sdata, mac_addr);
if (!sta)
return -EINVAL;
if (sta->ptk_idx == key_idx)
return 0;
mutex_lock(&local->key_mtx);
key = key_mtx_dereference(local, sta->ptk[key_idx]);
if (key && key->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)
ret = ieee80211_set_tx_key(key);
mutex_unlock(&local->key_mtx);
return ret;
}
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
@ -365,6 +395,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
if (pairwise && params->mode == NL80211_KEY_SET_TX)
return ieee80211_set_tx(sdata, mac_addr, key_idx);
/* reject WEP and TKIP keys if WEP failed to initialize */
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
@ -396,6 +429,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (pairwise)
key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
if (params->mode == NL80211_KEY_NO_TX)
key->conf.flags |= IEEE80211_KEY_FLAG_NO_AUTO_TX;
mutex_lock(&local->sta_mtx);
if (mac_addr) {
@ -1421,6 +1457,15 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (params->listen_interval >= 0)
sta->listen_interval = params->listen_interval;
if (params->sta_modify_mask & STATION_PARAM_APPLY_STA_TXPOWER) {
sta->sta.txpwr.type = params->txpwr.type;
if (params->txpwr.type == NL80211_TX_POWER_LIMITED)
sta->sta.txpwr.power = params->txpwr.power;
ret = drv_sta_set_txpwr(local, sdata, sta);
if (ret)
return ret;
}
if (params->supported_rates) {
ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
sband, params->supported_rates,
@ -3990,4 +4035,5 @@ const struct cfg80211_ops mac80211_config_ops = {
.get_ftm_responder_stats = ieee80211_get_ftm_responder_stats,
.start_pmsr = ieee80211_start_pmsr,
.abort_pmsr = ieee80211_abort_pmsr,
.probe_mesh_link = ieee80211_probe_mesh_link,
};

View File

@ -150,6 +150,58 @@ static const struct file_operations aqm_ops = {
.llseek = default_llseek,
};
static ssize_t force_tx_status_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
char buf[3];
int len = 0;
len = scnprintf(buf, sizeof(buf), "%d\n", (int)local->force_tx_status);
return simple_read_from_buffer(user_buf, count, ppos,
buf, len);
}
static ssize_t force_tx_status_write(struct file *file,
const char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct ieee80211_local *local = file->private_data;
char buf[3];
size_t len;
if (count > sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, user_buf, count))
return -EFAULT;
buf[sizeof(buf) - 1] = '\0';
len = strlen(buf);
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = 0;
if (buf[0] == '0' && buf[1] == '\0')
local->force_tx_status = 0;
else if (buf[0] == '1' && buf[1] == '\0')
local->force_tx_status = 1;
else
return -EINVAL;
return count;
}
static const struct file_operations force_tx_status_ops = {
.write = force_tx_status_write,
.read = force_tx_status_read,
.open = simple_open,
.llseek = default_llseek,
};
#ifdef CONFIG_PM
static ssize_t reset_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
@ -221,6 +273,7 @@ static const char *hw_flag_names[] = {
FLAG(TX_STATUS_NO_AMPDU_LEN),
FLAG(SUPPORTS_MULTI_BSSID),
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
FLAG(EXT_KEY_ID_NATIVE),
#undef FLAG
};
@ -382,6 +435,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
DEBUGFS_ADD_MODE(force_tx_status, 0600);
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);

View File

@ -138,6 +138,27 @@ int drv_sta_state(struct ieee80211_local *local,
return ret;
}
__must_check
int drv_sta_set_txpwr(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
{
int ret = -EOPNOTSUPP;
might_sleep();
sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
return -EIO;
trace_drv_sta_set_txpwr(local, sdata, &sta->sta);
if (local->ops->sta_set_txpwr)
ret = local->ops->sta_set_txpwr(&local->hw, &sdata->vif,
&sta->sta);
trace_drv_return_int(local, ret);
return ret;
}
void drv_sta_rc_update(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta, u32 changed)

View File

@ -529,6 +529,11 @@ int drv_sta_state(struct ieee80211_local *local,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state);
__must_check
int drv_sta_set_txpwr(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta);
void drv_sta_rc_update(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta, u32 changed);

View File

@ -1269,7 +1269,7 @@ struct ieee80211_local {
/*
* Key mutex, protects sdata's key_list and sta_info's
* key pointers (write access, they're RCU.)
* key pointers and ptk_idx (write access, they're RCU.)
*/
struct mutex key_mtx;
@ -1384,6 +1384,7 @@ struct ieee80211_local {
struct dentry *rcdir;
struct dentry *keys;
} debugfs;
bool force_tx_status;
#endif
/*
@ -1505,7 +1506,6 @@ struct ieee802_11_elems {
const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
const struct ieee80211_multiple_bssid_configuration *mbssid_config_ie;
const struct ieee80211_bssid_index *bssid_index;
const u8 *nontransmitted_bssid_profile;
u8 max_bssid_indicator;
u8 dtim_count;
u8 dtim_period;
@ -1761,7 +1761,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags);
u32 info_flags,
u32 ctrl_flags);
void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
struct sk_buff_head *skbs);
struct sk_buff *
@ -1778,6 +1779,8 @@ void ieee80211_clear_fast_xmit(struct sta_info *sta);
int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len,
const u8 *dest, __be16 proto, bool unencrypted);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);
/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,

View File

@ -1225,6 +1225,7 @@ static void ieee80211_if_setup(struct net_device *dev)
static void ieee80211_if_setup_no_queue(struct net_device *dev)
{
ieee80211_if_setup(dev);
dev->features |= NETIF_F_LLTX;
dev->priv_flags |= IFF_NO_QUEUE;
}
@ -1762,13 +1763,13 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
txq_size += sizeof(struct txq_info) +
local->hw.txq_data_size;
if (local->ops->wake_tx_queue)
if (local->ops->wake_tx_queue) {
if_setup = ieee80211_if_setup_no_queue;
else
} else {
if_setup = ieee80211_if_setup;
if (local->hw.queues >= IEEE80211_NUM_ACS)
txqs = IEEE80211_NUM_ACS;
if (local->hw.queues >= IEEE80211_NUM_ACS)
txqs = IEEE80211_NUM_ACS;
}
ndev = alloc_netdev_mqs(size + txq_size,
name, name_assign_type,

View File

@ -140,6 +140,12 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
* so clear that flag now to avoid trying to remove
* it again later.
*/
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
increment_tailroom_need_count(sdata);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
return -EINVAL;
}
@ -179,9 +185,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
decrease_tailroom_need_count(sdata, 1);
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)
sta = key->sta;
sdata = key->sdata;
if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
increment_tailroom_need_count(sdata);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
@ -258,9 +264,24 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
sta ? sta->sta.addr : bcast_addr, ret);
}
int ieee80211_set_tx_key(struct ieee80211_key *key)
{
struct sta_info *sta = key->sta;
struct ieee80211_local *local = key->local;
struct ieee80211_key *old;
assert_key_lock(local);
old = key_mtx_dereference(local, sta->ptk[sta->ptk_idx]);
sta->ptk_idx = key->conf.keyidx;
ieee80211_check_fast_xmit(sta);
return 0;
}
static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
struct ieee80211_key *new_key,
bool ptk0rekey)
bool pairwise)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_local *local;
@ -277,8 +298,9 @@ static int ieee80211_hw_key_replace(struct ieee80211_key *old_key,
assert_key_lock(old_key->local);
sta = old_key->sta;
/* PTK only using key ID 0 needs special handling on rekey */
if (new_key && sta && ptk0rekey) {
/* Unicast rekey without Extended Key ID needs special handling */
if (new_key && sta && pairwise &&
rcu_access_pointer(sta->ptk[sta->ptk_idx]) == old_key) {
local = old_key->local;
sdata = old_key->sdata;
@ -394,10 +416,6 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (old) {
idx = old->conf.keyidx;
/* TODO: proper implement and test "Extended Key ID for
* Individually Addressed Frames" from IEEE 802.11-2016.
* Till then always assume only key ID 0 is used for
* pairwise keys.*/
ret = ieee80211_hw_key_replace(old, new, pairwise);
} else {
/* new must be provided in case old is not */
@ -414,15 +432,20 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (sta) {
if (pairwise) {
rcu_assign_pointer(sta->ptk[idx], new);
sta->ptk_idx = idx;
if (new) {
if (new &&
!(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) {
sta->ptk_idx = idx;
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_check_fast_xmit(sta);
}
} else {
rcu_assign_pointer(sta->gtk[idx], new);
}
if (new)
/* Only needed for transition from no key -> key.
* Still triggers unnecessary when using Extended Key ID
* and installing the second key ID the first time.
*/
if (new && !old)
ieee80211_check_fast_rx(sta);
} else {
defunikey = old &&
@ -738,16 +761,34 @@ int ieee80211_key_link(struct ieee80211_key *key,
* can cause warnings to appear.
*/
bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
int ret;
int ret = -EOPNOTSUPP;
mutex_lock(&sdata->local->key_mtx);
if (sta && pairwise)
if (sta && pairwise) {
struct ieee80211_key *alt_key;
old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);
else if (sta)
alt_key = key_mtx_dereference(sdata->local, sta->ptk[idx ^ 1]);
/* The rekey code assumes that the old and new key are using
* the same cipher. Enforce the assumption for pairwise keys.
*/
if (key &&
((alt_key && alt_key->conf.cipher != key->conf.cipher) ||
(old_key && old_key->conf.cipher != key->conf.cipher)))
goto out;
} else if (sta) {
old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
else
} else {
old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
}
/* Non-pairwise keys must also not switch the cipher on rekey */
if (!pairwise) {
if (key && old_key && old_key->conf.cipher != key->conf.cipher)
goto out;
}
/*
* Silently accept key re-installation without really installing the
@ -1187,9 +1228,9 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
if (!((key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE)) ||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
if (!(key->conf.flags & (IEEE80211_KEY_FLAG_GENERATE_MMIC |
IEEE80211_KEY_FLAG_PUT_MIC_SPACE |
IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
increment_tailroom_need_count(key->sdata);
}

View File

@ -18,6 +18,7 @@
#define NUM_DEFAULT_KEYS 4
#define NUM_DEFAULT_MGMT_KEYS 2
#define INVALID_PTK_KEYIDX 2 /* Keyidx always pointing to a NULL key for PTK */
struct ieee80211_local;
struct ieee80211_sub_if_data;
@ -146,6 +147,7 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
int ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta);
int ieee80211_set_tx_key(struct ieee80211_key *key);
void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
void ieee80211_key_free_unused(struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,

View File

@ -1051,6 +1051,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
}
/* Enable Extended Key IDs when driver allowed it, or when it
* supports neither HW crypto nor A-MPDUs
*/
if ((!local->ops->set_key &&
!ieee80211_hw_check(hw, AMPDU_AGGREGATION)) ||
ieee80211_hw_check(&local->hw, EXT_KEY_ID_NATIVE))
wiphy_ext_feature_set(local->hw.wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID);
/* Mac80211 and therefore all cards only using SW crypto are able to
* handle PTK rekeys correctly
*/
if (!local->ops->set_key)
wiphy_ext_feature_set(local->hw.wiphy,
NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
/*
* Calculate scan IE length -- we need this to alloc
* memory and to subtract from the driver limit. It

View File

@ -278,6 +278,8 @@ mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst);
int mesh_path_add_gate(struct mesh_path *mpath);
int mesh_path_send_to_gates(struct mesh_path *mpath);
int mesh_gate_num(struct ieee80211_sub_if_data *sdata);
u32 airtime_link_metric_get(struct ieee80211_local *local,
struct sta_info *sta);
/* Mesh plinks */
void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,

View File

@ -318,8 +318,8 @@ void ieee80211s_update_metric(struct ieee80211_local *local,
cfg80211_calculate_bitrate(&rinfo));
}
static u32 airtime_link_metric_get(struct ieee80211_local *local,
struct sta_info *sta)
u32 airtime_link_metric_get(struct ieee80211_local *local,
struct sta_info *sta)
{
/* This should be adjusted for each device */
int device_constant = 1 << ARITH_SHIFT;
@ -1130,16 +1130,17 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
struct mesh_path *mpath;
struct sk_buff *skb_to_free = NULL;
u8 *target_addr = hdr->addr3;
int err = 0;
/* Nulls are only sent to peers for PS and should be pre-addressed */
if (ieee80211_is_qos_nullfunc(hdr->frame_control))
return 0;
rcu_read_lock();
err = mesh_nexthop_lookup(sdata, skb);
if (!err)
goto endlookup;
/* Allow injected packets to bypass mesh routing */
if (info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP)
return 0;
if (!mesh_nexthop_lookup(sdata, skb))
return 0;
/* no nexthop found, start resolving */
mpath = mesh_path_lookup(sdata, target_addr);
@ -1147,8 +1148,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
mpath = mesh_path_add(sdata, target_addr);
if (IS_ERR(mpath)) {
mesh_path_discard_frame(sdata, skb);
err = PTR_ERR(mpath);
goto endlookup;
return PTR_ERR(mpath);
}
}
@ -1161,13 +1161,10 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
ieee80211_set_qos_hdr(sdata, skb);
skb_queue_tail(&mpath->frame_queue, skb);
err = -ENOENT;
if (skb_to_free)
mesh_path_discard_frame(sdata, skb_to_free);
endlookup:
rcu_read_unlock();
return err;
return -ENOENT;
}
/**
@ -1187,13 +1184,10 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
struct sta_info *next_hop;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u8 *target_addr = hdr->addr3;
int err = -ENOENT;
rcu_read_lock();
mpath = mesh_path_lookup(sdata, target_addr);
if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
goto endlookup;
return -ENOENT;
if (time_after(jiffies,
mpath->exp_time -
@ -1208,12 +1202,10 @@ int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata,
memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
ieee80211_mps_set_frame_flags(sdata, next_hop, hdr);
err = 0;
return 0;
}
endlookup:
rcu_read_unlock();
return err;
return -ENOENT;
}
void mesh_path_timer(struct timer_list *t)

View File

@ -217,7 +217,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, const u8 *dst,
{
struct mesh_path *mpath;
mpath = rhashtable_lookup_fast(&tbl->rhead, dst, mesh_rht_params);
mpath = rhashtable_lookup(&tbl->rhead, dst, mesh_rht_params);
if (mpath && mpath_expired(mpath)) {
spin_lock_bh(&mpath->state_lock);

View File

@ -1188,9 +1188,6 @@ static void ieee80211_chswitch_work(struct work_struct *work)
goto out;
}
/* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = sdata->csa_chandef.chan;
ifmgd->csa_waiting_bcn = true;
ieee80211_sta_reset_beacon_monitor(sdata);

View File

@ -51,8 +51,13 @@
MINSTREL_MAX_STREAMS * _sgi + \
_streams - 1
#define _MAX(a, b) (((a)>(b))?(a):(b))
#define GROUP_SHIFT(duration) \
_MAX(0, 16 - __builtin_clz(duration))
/* MCS rate information for an MCS group */
#define MCS_GROUP(_streams, _sgi, _ht40, _s) \
#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
[GROUP_IDX(_streams, _sgi, _ht40)] = { \
.streams = _streams, \
.shift = _s, \
@ -72,6 +77,13 @@
} \
}
#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
#define MCS_GROUP(_streams, _sgi, _ht40) \
__MCS_GROUP(_streams, _sgi, _ht40, \
MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
(MINSTREL_VHT_GROUP_0 + \
MINSTREL_MAX_STREAMS * 2 * (_bw) + \
@ -81,7 +93,7 @@
#define BW2VBPS(_bw, r3, r2, r1) \
(_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
#define VHT_GROUP(_streams, _sgi, _bw, _s) \
#define __VHT_GROUP(_streams, _sgi, _bw, _s) \
[VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
.streams = _streams, \
.shift = _s, \
@ -114,6 +126,14 @@
} \
}
#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
BW2VBPS(_bw, 117, 54, 26)))
#define VHT_GROUP(_streams, _sgi, _bw) \
__VHT_GROUP(_streams, _sgi, _bw, \
VHT_GROUP_SHIFT(_streams, _sgi, _bw))
#define CCK_DURATION(_bitrate, _short, _len) \
(1000 * (10 /* SIFS */ + \
(_short ? 72 + 24 : 144 + 48) + \
@ -129,7 +149,7 @@
CCK_ACK_DURATION(55, _short) >> _s, \
CCK_ACK_DURATION(110, _short) >> _s
#define CCK_GROUP(_s) \
#define __CCK_GROUP(_s) \
[MINSTREL_CCK_GROUP] = { \
.streams = 1, \
.flags = 0, \
@ -140,6 +160,12 @@
} \
}
#define CCK_GROUP_SHIFT \
GROUP_SHIFT(CCK_ACK_DURATION(10, false))
#define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT)
static bool minstrel_vht_only = true;
module_param(minstrel_vht_only, bool, 0644);
MODULE_PARM_DESC(minstrel_vht_only,
@ -154,47 +180,57 @@ MODULE_PARM_DESC(minstrel_vht_only,
* BW -> SGI -> #streams
*/
const struct mcs_group minstrel_mcs_groups[] = {
MCS_GROUP(1, 0, BW_20, 5),
MCS_GROUP(2, 0, BW_20, 4),
MCS_GROUP(3, 0, BW_20, 4),
MCS_GROUP(1, 0, BW_20),
MCS_GROUP(2, 0, BW_20),
MCS_GROUP(3, 0, BW_20),
MCS_GROUP(4, 0, BW_20),
MCS_GROUP(1, 1, BW_20, 5),
MCS_GROUP(2, 1, BW_20, 4),
MCS_GROUP(3, 1, BW_20, 4),
MCS_GROUP(1, 1, BW_20),
MCS_GROUP(2, 1, BW_20),
MCS_GROUP(3, 1, BW_20),
MCS_GROUP(4, 1, BW_20),
MCS_GROUP(1, 0, BW_40, 4),
MCS_GROUP(2, 0, BW_40, 4),
MCS_GROUP(3, 0, BW_40, 4),
MCS_GROUP(1, 0, BW_40),
MCS_GROUP(2, 0, BW_40),
MCS_GROUP(3, 0, BW_40),
MCS_GROUP(4, 0, BW_40),
MCS_GROUP(1, 1, BW_40, 4),
MCS_GROUP(2, 1, BW_40, 4),
MCS_GROUP(3, 1, BW_40, 4),
MCS_GROUP(1, 1, BW_40),
MCS_GROUP(2, 1, BW_40),
MCS_GROUP(3, 1, BW_40),
MCS_GROUP(4, 1, BW_40),
CCK_GROUP(8),
CCK_GROUP,
VHT_GROUP(1, 0, BW_20, 5),
VHT_GROUP(2, 0, BW_20, 4),
VHT_GROUP(3, 0, BW_20, 4),
VHT_GROUP(1, 0, BW_20),
VHT_GROUP(2, 0, BW_20),
VHT_GROUP(3, 0, BW_20),
VHT_GROUP(4, 0, BW_20),
VHT_GROUP(1, 1, BW_20, 5),
VHT_GROUP(2, 1, BW_20, 4),
VHT_GROUP(3, 1, BW_20, 4),
VHT_GROUP(1, 1, BW_20),
VHT_GROUP(2, 1, BW_20),
VHT_GROUP(3, 1, BW_20),
VHT_GROUP(4, 1, BW_20),
VHT_GROUP(1, 0, BW_40, 4),
VHT_GROUP(2, 0, BW_40, 4),
VHT_GROUP(3, 0, BW_40, 4),
VHT_GROUP(1, 0, BW_40),
VHT_GROUP(2, 0, BW_40),
VHT_GROUP(3, 0, BW_40),
VHT_GROUP(4, 0, BW_40),
VHT_GROUP(1, 1, BW_40, 4),
VHT_GROUP(2, 1, BW_40, 4),
VHT_GROUP(3, 1, BW_40, 4),
VHT_GROUP(1, 1, BW_40),
VHT_GROUP(2, 1, BW_40),
VHT_GROUP(3, 1, BW_40),
VHT_GROUP(4, 1, BW_40),
VHT_GROUP(1, 0, BW_80, 4),
VHT_GROUP(2, 0, BW_80, 4),
VHT_GROUP(3, 0, BW_80, 4),
VHT_GROUP(1, 0, BW_80),
VHT_GROUP(2, 0, BW_80),
VHT_GROUP(3, 0, BW_80),
VHT_GROUP(4, 0, BW_80),
VHT_GROUP(1, 1, BW_80, 4),
VHT_GROUP(2, 1, BW_80, 4),
VHT_GROUP(3, 1, BW_80, 4),
VHT_GROUP(1, 1, BW_80),
VHT_GROUP(2, 1, BW_80),
VHT_GROUP(3, 1, BW_80),
VHT_GROUP(4, 1, BW_80),
};
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;

View File

@ -13,7 +13,7 @@
* The number of streams can be changed to 2 to reduce code
* size and memory footprint.
*/
#define MINSTREL_MAX_STREAMS 3
#define MINSTREL_MAX_STREAMS 4
#define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
#define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */

View File

@ -1005,23 +1005,43 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
return -1;
}
static int ieee80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,
struct sk_buff *skb)
static int ieee80211_get_keyid(struct sk_buff *skb,
const struct ieee80211_cipher_scheme *cs)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc;
int hdrlen;
int minlen;
u8 key_idx_off;
u8 key_idx_shift;
u8 keyid;
fc = hdr->frame_control;
hdrlen = ieee80211_hdrlen(fc);
if (skb->len < hdrlen + cs->hdr_len)
if (cs) {
minlen = hdrlen + cs->hdr_len;
key_idx_off = hdrlen + cs->key_idx_off;
key_idx_shift = cs->key_idx_shift;
} else {
/* WEP, TKIP, CCMP and GCMP */
minlen = hdrlen + IEEE80211_WEP_IV_LEN;
key_idx_off = hdrlen + 3;
key_idx_shift = 6;
}
if (unlikely(skb->len < minlen))
return -EINVAL;
skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);
keyid &= cs->key_idx_mask;
keyid >>= cs->key_idx_shift;
skb_copy_bits(skb, key_idx_off, &keyid, 1);
if (cs)
keyid &= cs->key_idx_mask;
keyid >>= key_idx_shift;
/* cs could use more than the usual two bits for the keyid */
if (unlikely(keyid >= NUM_DEFAULT_KEYS))
return -EINVAL;
return keyid;
}
@ -1860,9 +1880,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
int keyidx;
int hdrlen;
ieee80211_rx_result result = RX_DROP_UNUSABLE;
struct ieee80211_key *sta_ptk = NULL;
struct ieee80211_key *ptk_idx = NULL;
int mmie_keyidx = -1;
__le16 fc;
const struct ieee80211_cipher_scheme *cs = NULL;
@ -1900,21 +1920,24 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (rx->sta) {
int keyid = rx->sta->ptk_idx;
sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {
if (ieee80211_has_protected(fc)) {
cs = rx->sta->cipher_scheme;
keyid = ieee80211_get_cs_keyid(cs, rx->skb);
keyid = ieee80211_get_keyid(rx->skb, cs);
if (unlikely(keyid < 0))
return RX_DROP_UNUSABLE;
ptk_idx = rcu_dereference(rx->sta->ptk[keyid]);
}
sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);
}
if (!ieee80211_has_protected(fc))
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
if (!is_multicast_ether_addr(hdr->addr1) && sta_ptk) {
rx->key = sta_ptk;
rx->key = ptk_idx ? ptk_idx : sta_ptk;
if ((status->flag & RX_FLAG_DECRYPTED) &&
(status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
@ -1974,8 +1997,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
}
return RX_CONTINUE;
} else {
u8 keyid;
/*
* The device doesn't give us the IV so we won't be
* able to look up the key. That's ok though, we
@ -1989,23 +2010,10 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
(status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
hdrlen = ieee80211_hdrlen(fc);
keyidx = ieee80211_get_keyid(rx->skb, cs);
if (cs) {
keyidx = ieee80211_get_cs_keyid(cs, rx->skb);
if (unlikely(keyidx < 0))
return RX_DROP_UNUSABLE;
} else {
if (rx->skb->len < 8 + hdrlen)
return RX_DROP_UNUSABLE; /* TODO: count this? */
/*
* no need to call ieee80211_wep_get_keyidx,
* it verifies a bunch of things we've done already
*/
skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
keyidx = keyid >> 6;
}
if (unlikely(keyidx < 0))
return RX_DROP_UNUSABLE;
/* check per-station GTK first, if multicast packet */
if (is_multicast_ether_addr(hdr->addr1) && rx->sta)
@ -4050,12 +4058,8 @@ void ieee80211_check_fast_rx(struct sta_info *sta)
case WLAN_CIPHER_SUITE_GCMP_256:
break;
default:
/* we also don't want to deal with WEP or cipher scheme
* since those require looking up the key idx in the
* frame, rather than assuming the PTK is used
* (we need to revisit this once we implement the real
* PTK index, which is now valid in the spec, but we
* haven't implemented that part yet)
/* We also don't want to deal with
* WEP or cipher scheme.
*/
goto clear_rcu;
}

View File

@ -347,6 +347,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->sta.max_rx_aggregation_subframes =
local->hw.max_rx_aggregation_subframes;
/* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only.
* The Tx path starts to use a key as soon as the key slot ptk_idx
* references to is not NULL. To not use the initial Rx-only key
* prematurely for Tx initialize ptk_idx to an impossible PTK keyid
* which always will refer to a NULL key.
*/
BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX);
sta->ptk_idx = INVALID_PTK_KEYIDX;
sta->local = local;
sta->sdata = sdata;
sta->rx_stats.last_rx = jiffies;
@ -2373,6 +2382,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sinfo->filled |=
BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
}
if (ieee80211_vif_is_mesh(&sdata->vif)) {
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC);
sinfo->airtime_link_metric =
airtime_link_metric_get(local, sta);
}
}
u32 sta_get_expected_throughput(struct sta_info *sta)

View File

@ -1056,7 +1056,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
/* disable bottom halves when entering the Tx path */
local_bh_disable();
__ieee80211_subif_start_xmit(skb, dev, flags);
__ieee80211_subif_start_xmit(skb, dev, flags, 0);
local_bh_enable();
return ret;

View File

@ -828,6 +828,36 @@ TRACE_EVENT(drv_sta_state,
)
);
TRACE_EVENT(drv_sta_set_txpwr,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta),
TP_ARGS(local, sdata, sta),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
STA_ENTRY
__field(s16, txpwr)
__field(u8, type)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
STA_ASSIGN;
__entry->txpwr = sta->txpwr.power;
__entry->type = sta->txpwr.type;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " txpwr: %d type %d",
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
__entry->txpwr, __entry->type
)
);
TRACE_EVENT(drv_sta_rc_update,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,

View File

@ -1399,11 +1399,15 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
{
struct fq *fq = &local->fq;
struct fq_tin *tin = &txqi->tin;
u32 flow_idx = fq_flow_idx(fq, skb);
ieee80211_set_skb_enqueue_time(skb);
fq_tin_enqueue(fq, tin, skb,
spin_lock_bh(&fq->lock);
fq_tin_enqueue(fq, tin, flow_idx, skb,
fq_skb_free_func,
fq_flow_get_default_func);
spin_unlock_bh(&fq->lock);
}
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,
struct sta_info *sta,
struct sk_buff *skb)
{
struct fq *fq = &local->fq;
struct ieee80211_vif *vif;
struct txq_info *txqi;
@ -1608,9 +1611,7 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
if (!txqi)
return false;
spin_lock_bh(&fq->lock);
ieee80211_txq_enqueue(local, txqi, skb);
spin_unlock_bh(&fq->lock);
schedule_and_wake_txq(local, txqi);
@ -2431,6 +2432,7 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
* @sdata: virtual interface to build the header for
* @skb: the skb to build the header in
* @info_flags: skb flags to set
* @ctrl_flags: info control flags to set
*
* This function takes the skb with 802.3 header and reformats the header to
* 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,
*/
static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 info_flags,
struct sta_info *sta)
struct sta_info *sta, u32 ctrl_flags)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info;
@ -2470,6 +2472,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
if (IS_ERR(sta))
sta = NULL;
#ifdef CONFIG_MAC80211_DEBUGFS
if (local->force_tx_status)
info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
#endif
/* convert Ethernet header to proper 802.11 header (based on
* operation mode) */
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,
goto free;
}
band = chanctx_conf->def.chan->band;
/* For injected frames, fill RA right away as nexthop lookup
* will be skipped.
*/
if ((ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) &&
is_zero_ether_addr(hdr.addr1))
memcpy(hdr.addr1, skb->data, ETH_ALEN);
break;
#endif
case NL80211_IFTYPE_STATION:
@ -2818,6 +2832,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
info->flags = info_flags;
info->ack_frame_id = info_id;
info->band = band;
info->control.flags = ctrl_flags;
return skb;
free:
@ -3000,23 +3015,15 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
switch (build.key->conf.cipher) {
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
/* add fixed key ID */
if (gen_iv) {
(build.hdr + build.hdr_len)[3] =
0x20 | (build.key->conf.keyidx << 6);
if (gen_iv)
build.pn_offs = build.hdr_len;
}
if (gen_iv || iv_spc)
build.hdr_len += IEEE80211_CCMP_HDR_LEN;
break;
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* add fixed key ID */
if (gen_iv) {
(build.hdr + build.hdr_len)[3] =
0x20 | (build.key->conf.keyidx << 6);
if (gen_iv)
build.pn_offs = build.hdr_len;
}
if (gen_iv || iv_spc)
build.hdr_len += IEEE80211_GCMP_HDR_LEN;
break;
@ -3222,6 +3229,7 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
int max_frags = local->hw.max_tx_fragments;
int max_amsdu_len = sta->sta.max_amsdu_len;
int orig_truesize;
u32 flow_idx;
__be16 len;
void *data;
bool ret = false;
@ -3250,6 +3258,8 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata,
max_amsdu_len = min_t(int, max_amsdu_len,
sta->sta.max_tid_amsdu_len[tid]);
flow_idx = fq_flow_idx(fq, skb);
spin_lock_bh(&fq->lock);
/* 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,
*/
tin = &txqi->tin;
flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
flow = fq_flow_classify(fq, tin, flow_idx, skb,
fq_flow_get_default_func);
head = skb_peek_tail(&flow->queue);
if (!head || skb_is_gso(head))
goto out;
@ -3386,6 +3397,7 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
pn = atomic64_inc_return(&key->conf.tx_pn);
crypto_hdr[0] = pn;
crypto_hdr[1] = pn >> 8;
crypto_hdr[3] = 0x20 | (key->conf.keyidx << 6);
crypto_hdr[4] = pn >> 16;
crypto_hdr[5] = pn >> 24;
crypto_hdr[6] = pn >> 32;
@ -3478,6 +3490,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
#ifdef CONFIG_MAC80211_DEBUGFS
if (local->force_tx_status)
info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
#endif
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
*ieee80211_get_qos_ctl(hdr) = tid;
@ -3533,6 +3550,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
ieee80211_tx_result r;
struct ieee80211_vif *vif = txq->vif;
begin:
spin_lock_bh(&fq->lock);
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
@ -3549,11 +3567,12 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
if (skb)
goto out;
begin:
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
if (!skb)
goto out;
spin_unlock_bh(&fq->lock);
hdr = (struct ieee80211_hdr *)skb->data;
info = IEEE80211_SKB_CB(skb);
@ -3598,8 +3617,11 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
skb = __skb_dequeue(&tx.skbs);
if (!skb_queue_empty(&tx.skbs))
if (!skb_queue_empty(&tx.skbs)) {
spin_lock_bh(&fq->lock);
skb_queue_splice_tail(&tx.skbs, &txqi->frags);
spin_unlock_bh(&fq->lock);
}
}
if (skb_has_frag_list(skb) &&
@ -3638,6 +3660,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
}
IEEE80211_SKB_CB(skb)->control.vif = vif;
return skb;
out:
spin_unlock_bh(&fq->lock);
@ -3783,9 +3806,11 @@ EXPORT_SYMBOL(ieee80211_txq_schedule_start);
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev,
u32 info_flags)
u32 info_flags,
u32 ctrl_flags)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct sk_buff *next;
@ -3799,7 +3824,15 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto out_free;
if (!IS_ERR_OR_NULL(sta)) {
if (IS_ERR(sta))
sta = NULL;
if (local->ops->wake_tx_queue) {
u16 queue = __ieee80211_select_queue(sdata, sta, skb);
skb_set_queue_mapping(skb, queue);
}
if (sta) {
struct ieee80211_fast_tx *fast_tx;
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,
skb->prev = NULL;
skb->next = NULL;
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
skb = ieee80211_build_hdr(sdata, skb, info_flags,
sta, ctrl_flags);
if (IS_ERR(skb))
goto out;
@ -3988,9 +4022,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
__skb_queue_head_init(&queue);
ieee80211_convert_to_unicast(skb, dev, &queue);
while ((skb = __skb_dequeue(&queue)))
__ieee80211_subif_start_xmit(skb, dev, 0);
__ieee80211_subif_start_xmit(skb, dev, 0, 0);
} else {
__ieee80211_subif_start_xmit(skb, dev, 0);
__ieee80211_subif_start_xmit(skb, dev, 0, 0);
}
return NETDEV_TX_OK;
@ -4015,7 +4049,7 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
goto out;
}
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
skb = ieee80211_build_hdr(sdata, skb, info_flags, sta, 0);
if (IS_ERR(skb))
goto out;
@ -5052,7 +5086,36 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
skb_reset_mac_header(skb);
local_bh_disable();
__ieee80211_subif_start_xmit(skb, skb->dev, flags);
__ieee80211_subif_start_xmit(skb, skb->dev, flags, 0);
local_bh_enable();
return 0;
}
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len +
30 + /* header size */
18); /* 11s header size */
if (!skb)
return -ENOMEM;
skb_reserve(skb, local->hw.extra_tx_headroom);
skb_put_data(skb, buf, len);
skb->dev = dev;
skb->protocol = htons(ETH_P_802_3);
skb_reset_network_header(skb);
skb_reset_mac_header(skb);
local_bh_disable();
__ieee80211_subif_start_xmit(skb, skb->dev, 0,
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP);
local_bh_enable();
return 0;

View File

@ -894,10 +894,10 @@ EXPORT_SYMBOL(ieee80211_queue_delayed_work);
static u32
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
u64 filter, u32 crc, u8 *transmitter_bssid,
u8 *bss_bssid)
u64 filter, u32 crc,
const struct element *check_inherit)
{
const struct element *elem, *sub;
const struct element *elem;
bool calc_crc = filter != 0;
DECLARE_BITMAP(seen_elems, 256);
const u8 *ie;
@ -910,6 +910,11 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
u8 elen = elem->datalen;
const u8 *pos = elem->data;
if (check_inherit &&
!cfg80211_is_element_inherited(elem,
check_inherit))
continue;
switch (id) {
case WLAN_EID_SSID:
case WLAN_EID_SUPP_RATES:
@ -1208,57 +1213,6 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
if (elen >= sizeof(*elems->max_idle_period_ie))
elems->max_idle_period_ie = (void *)pos;
break;
case WLAN_EID_MULTIPLE_BSSID:
if (!bss_bssid || !transmitter_bssid || elen < 4)
break;
elems->max_bssid_indicator = pos[0];
for_each_element(sub, pos + 1, elen - 1) {
u8 sub_len = sub->datalen;
u8 new_bssid[ETH_ALEN];
const u8 *index;
/*
* we only expect the "non-transmitted BSSID
* profile" subelement (subelement id 0)
*/
if (sub->id != 0 || sub->datalen < 4) {
/* not a valid BSS profile */
continue;
}
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
sub->data[1] != 2) {
/* The first element of the
* Nontransmitted BSSID Profile is not
* the Nontransmitted BSSID Capability
* element.
*/
continue;
}
/* found a Nontransmitted BSSID Profile */
index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
sub->data, sub_len);
if (!index || index[1] < 1 || index[2] == 0) {
/* Invalid MBSSID Index element */
continue;
}
cfg80211_gen_new_bssid(transmitter_bssid,
pos[0],
index[2],
new_bssid);
if (ether_addr_equal(new_bssid, bss_bssid)) {
elems->nontransmitted_bssid_profile =
(void *)sub;
elems->bssid_index_len = index[1];
elems->bssid_index = (void *)&index[2];
break;
}
}
break;
case WLAN_EID_EXTENSION:
if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
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,
return crc;
}
static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
u8 *transmitter_bssid,
u8 *bss_bssid,
u8 *nontransmitted_profile)
{
const struct element *elem, *sub;
size_t profile_len = 0;
bool found = false;
if (!bss_bssid || !transmitter_bssid)
return profile_len;
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
if (elem->datalen < 2)
continue;
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
u8 new_bssid[ETH_ALEN];
const u8 *index;
if (sub->id != 0 || sub->datalen < 4) {
/* not a valid BSS profile */
continue;
}
if (sub->data[0] != WLAN_EID_NON_TX_BSSID_CAP ||
sub->data[1] != 2) {
/* The first element of the
* Nontransmitted BSSID Profile is not
* the Nontransmitted BSSID Capability
* element.
*/
continue;
}
memset(nontransmitted_profile, 0, len);
profile_len = cfg80211_merge_profile(start, len,
elem,
sub,
nontransmitted_profile,
len);
/* found a Nontransmitted BSSID Profile */
index = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
nontransmitted_profile,
profile_len);
if (!index || index[1] < 1 || index[2] == 0) {
/* Invalid MBSSID Index element */
continue;
}
cfg80211_gen_new_bssid(transmitter_bssid,
elem->data[0],
index[2],
new_bssid);
if (ether_addr_equal(new_bssid, bss_bssid)) {
found = true;
elems->bssid_index_len = index[1];
elems->bssid_index = (void *)&index[2];
break;
}
}
}
return found ? profile_len : 0;
}
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
u64 filter, u32 crc, u8 *transmitter_bssid,
u8 *bss_bssid)
{
const struct element *non_inherit = NULL;
u8 *nontransmitted_profile;
int nontransmitted_profile_len = 0;
memset(elems, 0, sizeof(*elems));
elems->ie_start = start;
elems->total_len = len;
nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
if (nontransmitted_profile) {
nontransmitted_profile_len =
ieee802_11_find_bssid_profile(start, len, elems,
transmitter_bssid,
bss_bssid,
nontransmitted_profile);
non_inherit =
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
nontransmitted_profile,
nontransmitted_profile_len);
}
crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
crc, transmitter_bssid, bss_bssid);
crc, non_inherit);
/* Override with nontransmitted profile, if found */
if (transmitter_bssid && elems->nontransmitted_bssid_profile) {
const u8 *profile = elems->nontransmitted_bssid_profile;
_ieee802_11_parse_elems_crc(&profile[2], profile[1],
action, elems, 0, 0,
transmitter_bssid, bss_bssid);
}
if (nontransmitted_profile_len)
_ieee802_11_parse_elems_crc(nontransmitted_profile,
nontransmitted_profile_len,
action, elems, 0, 0, NULL);
if (elems->tim && !elems->parse_error) {
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,
offsetofend(struct ieee80211_bssid_index, dtim_count))
elems->dtim_count = elems->bssid_index->dtim_count;
kfree(nontransmitted_profile);
return crc;
}

View File

@ -141,71 +141,24 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
return ieee80211_downgrade_queue(sdata, NULL, skb);
}
/* Indicate which queue to use. */
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL;
const u8 *ra = NULL;
bool qos = false;
struct mac80211_qos_map *qos_map;
u16 ret;
bool qos;
if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
skb->priority = 0; /* required for correct WPA/11i MIC */
return 0;
}
rcu_read_lock();
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta);
if (sta) {
qos = sta->sta.wme;
break;
}
/* fall through */
case NL80211_IFTYPE_AP:
ra = skb->data;
break;
case NL80211_IFTYPE_WDS:
ra = sdata->u.wds.remote_addr;
break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
/* all mesh/ocb stations are required to support WME */
if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
sdata->vif.type == NL80211_IFTYPE_OCB)
qos = true;
break;
#endif
case NL80211_IFTYPE_STATION:
/* might be a TDLS station */
sta = sta_info_get(sdata, skb->data);
if (sta)
qos = sta->sta.wme;
ra = sdata->u.mgd.bssid;
break;
case NL80211_IFTYPE_ADHOC:
ra = skb->data;
break;
case NL80211_IFTYPE_OCB:
/* all stations are required to support WME */
qos = true;
break;
default:
break;
}
if (!sta && ra && !is_multicast_ether_addr(ra)) {
sta = sta_info_get(sdata, ra);
if (sta)
qos = sta->sta.wme;
}
else if (sta)
qos = sta->sta.wme;
else
qos = false;
if (!qos) {
skb->priority = 0; /* required for correct WPA/11i MIC */
ret = IEEE80211_AC_BE;
goto out;
return IEEE80211_AC_BE;
}
if (skb->protocol == sdata->control_port_protocol) {
@ -220,8 +173,61 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
&qos_map->qos_map : NULL);
downgrade:
ret = ieee80211_downgrade_queue(sdata, sta, skb);
out:
return ieee80211_downgrade_queue(sdata, sta, skb);
}
/* Indicate which queue to use. */
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta = NULL;
const u8 *ra = NULL;
u16 ret;
/* when using iTXQ, we can do this later */
if (local->ops->wake_tx_queue)
return 0;
if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
skb->priority = 0; /* required for correct WPA/11i MIC */
return 0;
}
rcu_read_lock();
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP_VLAN:
sta = rcu_dereference(sdata->u.vlan.sta);
if (sta)
break;
/* fall through */
case NL80211_IFTYPE_AP:
ra = skb->data;
break;
case NL80211_IFTYPE_WDS:
ra = sdata->u.wds.remote_addr;
break;
case NL80211_IFTYPE_STATION:
/* might be a TDLS station */
sta = sta_info_get(sdata, skb->data);
if (sta)
break;
ra = sdata->u.mgd.bssid;
break;
case NL80211_IFTYPE_ADHOC:
ra = skb->data;
break;
default:
break;
}
if (!sta && ra && !is_multicast_ether_addr(ra))
sta = sta_info_get(sdata, ra);
ret = __ieee80211_select_queue(sdata, sta, skb);
rcu_read_unlock();
return ret;
}

View File

@ -16,6 +16,8 @@
u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
struct ieee80211_hdr *hdr);
u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb);
u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,

View File

@ -331,6 +331,11 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
.len = NL80211_MAX_SUPP_RATES },
[NL80211_ATTR_STA_PLINK_ACTION] =
NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1),
[NL80211_ATTR_STA_TX_POWER_SETTING] =
NLA_POLICY_RANGE(NLA_U8,
NL80211_TX_POWER_AUTOMATIC,
NL80211_TX_POWER_FIXED),
[NL80211_ATTR_STA_TX_POWER] = { .type = NLA_S16 },
[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
[NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
@ -553,6 +558,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
[NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
[NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
[NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
};
/* policy for the key default flags */
@ -617,12 +623,21 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
[NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN },
};
static const struct nla_policy
nl80211_match_band_rssi_policy[NUM_NL80211_BANDS] = {
[NL80211_BAND_2GHZ] = { .type = NLA_S32 },
[NL80211_BAND_5GHZ] = { .type = NLA_S32 },
[NL80211_BAND_60GHZ] = { .type = NLA_S32 },
};
static const struct nla_policy
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_SSID_LEN },
[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = { .len = ETH_ALEN },
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
};
static const struct nla_policy
@ -958,6 +973,9 @@ static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
}
if (tb[NL80211_KEY_MODE])
k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);
return 0;
}
@ -3634,8 +3652,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (key.idx < 0)
return -EINVAL;
/* only support setting default key */
if (!key.def && !key.defmgmt)
/* Only support setting default key and
* Extended Key ID action NL80211_KEY_SET_TX.
*/
if (!key.def && !key.defmgmt &&
!(key.p.mode == NL80211_KEY_SET_TX))
return -EINVAL;
wdev_lock(dev->ieee80211_ptr);
@ -3659,7 +3680,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_key = key.idx;
#endif
} else {
} else if (key.defmgmt) {
if (key.def_uni || !key.def_multi) {
err = -EINVAL;
goto out;
@ -3681,8 +3702,25 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
#ifdef CONFIG_CFG80211_WEXT
dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
#endif
}
} else if (key.p.mode == NL80211_KEY_SET_TX &&
wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID)) {
u8 *mac_addr = NULL;
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
if (!mac_addr || key.idx < 0 || key.idx > 1) {
err = -EINVAL;
goto out;
}
err = rdev_add_key(rdev, dev, key.idx,
NL80211_KEYTYPE_PAIRWISE,
mac_addr, &key.p);
} else {
err = -EINVAL;
}
out:
wdev_unlock(dev->ieee80211_ptr);
@ -3843,8 +3881,7 @@ static struct cfg80211_acl_data *parse_acl_data(struct wiphy *wiphy,
if (n_entries > wiphy->max_acl_mac_addrs)
return ERR_PTR(-ENOTSUPP);
acl = kzalloc(sizeof(*acl) + (sizeof(struct mac_address) * n_entries),
GFP_KERNEL);
acl = kzalloc(struct_size(acl, mac_addrs, n_entries), GFP_KERNEL);
if (!acl)
return ERR_PTR(-ENOMEM);
@ -4889,6 +4926,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
PUT_SINFO(TX_RETRIES, tx_retries, u32);
PUT_SINFO(TX_FAILED, tx_failed, u32);
PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
PUT_SINFO(AIRTIME_LINK_METRIC, airtime_link_metric, u32);
PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
PUT_SINFO(LOCAL_PM, local_pm, u32);
PUT_SINFO(PEER_PM, peer_pm, u32);
@ -5387,6 +5425,36 @@ static int nl80211_set_station_tdls(struct genl_info *info,
return nl80211_parse_sta_wme(info, params);
}
static int nl80211_parse_sta_txpower_setting(struct genl_info *info,
struct station_parameters *params)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
int idx;
if (info->attrs[NL80211_ATTR_STA_TX_POWER_SETTING]) {
if (!rdev->ops->set_tx_power ||
!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_STA_TX_PWR))
return -EOPNOTSUPP;
idx = NL80211_ATTR_STA_TX_POWER_SETTING;
params->txpwr.type = nla_get_u8(info->attrs[idx]);
if (params->txpwr.type == NL80211_TX_POWER_LIMITED) {
idx = NL80211_ATTR_STA_TX_POWER;
if (info->attrs[idx])
params->txpwr.power =
nla_get_s16(info->attrs[idx]);
else
return -EINVAL;
}
params->sta_modify_mask |= STATION_PARAM_APPLY_STA_TXPOWER;
}
return 0;
}
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
{
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)
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
return -EOPNOTSUPP;
err = nl80211_parse_sta_txpower_setting(info, &params);
if (err)
return err;
/* Include parameters for TDLS peer (will check later) */
err = nl80211_set_station_tdls(info, &params);
if (err)
@ -5617,6 +5689,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
return -EOPNOTSUPP;
err = nl80211_parse_sta_txpower_setting(info, &params);
if (err)
return err;
err = nl80211_parse_sta_channel_info(info, &params);
if (err)
return err;
@ -6882,7 +6958,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
struct nlattr *nl_reg_rule;
char *alpha2;
int rem_reg_rules, r;
u32 num_rules = 0, rule_idx = 0, size_of_regd;
u32 num_rules = 0, rule_idx = 0;
enum nl80211_dfs_regions dfs_region = NL80211_DFS_UNSET;
struct ieee80211_regdomain *rd;
@ -6907,10 +6983,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
if (!reg_is_valid_request(alpha2))
return -EINVAL;
size_of_regd = sizeof(struct ieee80211_regdomain) +
num_rules * sizeof(struct ieee80211_reg_rule);
rd = kzalloc(size_of_regd, GFP_KERNEL);
rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
if (!rd)
return -ENOMEM;
@ -7537,6 +7610,41 @@ nl80211_parse_sched_scan_plans(struct wiphy *wiphy, int n_plans,
return 0;
}
static int
nl80211_parse_sched_scan_per_band_rssi(struct wiphy *wiphy,
struct cfg80211_match_set *match_sets,
struct nlattr *tb_band_rssi,
s32 rssi_thold)
{
struct nlattr *attr;
int i, tmp, ret = 0;
if (!wiphy_ext_feature_isset(wiphy,
NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD)) {
if (tb_band_rssi)
ret = -EOPNOTSUPP;
else
for (i = 0; i < NUM_NL80211_BANDS; i++)
match_sets->per_band_rssi_thold[i] =
NL80211_SCAN_RSSI_THOLD_OFF;
return ret;
}
for (i = 0; i < NUM_NL80211_BANDS; i++)
match_sets->per_band_rssi_thold[i] = rssi_thold;
nla_for_each_nested(attr, tb_band_rssi, tmp) {
enum nl80211_band band = nla_type(attr);
if (band < 0 || band >= NUM_NL80211_BANDS)
return -EINVAL;
match_sets->per_band_rssi_thold[band] = nla_get_s32(attr);
}
return 0;
}
static struct cfg80211_sched_scan_request *
nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
struct nlattr **attrs, int max_match_sets)
@ -7776,43 +7884,55 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
goto out_free;
ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID];
bssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID];
if (ssid || bssid) {
if (WARN_ON(i >= n_match_sets)) {
/* this indicates a programming error,
* the loop above should have verified
* things properly
*/
if (!ssid && !bssid) {
i++;
continue;
}
if (WARN_ON(i >= n_match_sets)) {
/* this indicates a programming error,
* the loop above should have verified
* things properly
*/
err = -EINVAL;
goto out_free;
}
if (ssid) {
if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
err = -EINVAL;
goto out_free;
}
if (ssid) {
if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) {
err = -EINVAL;
goto out_free;
}
memcpy(request->match_sets[i].ssid.ssid,
nla_data(ssid), nla_len(ssid));
request->match_sets[i].ssid.ssid_len =
nla_len(ssid);
}
if (bssid) {
if (nla_len(bssid) != ETH_ALEN) {
err = -EINVAL;
goto out_free;
}
memcpy(request->match_sets[i].bssid,
nla_data(bssid), ETH_ALEN);
}
/* special attribute - old implementation w/a */
request->match_sets[i].rssi_thold =
default_match_rssi;
rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
if (rssi)
request->match_sets[i].rssi_thold =
nla_get_s32(rssi);
memcpy(request->match_sets[i].ssid.ssid,
nla_data(ssid), nla_len(ssid));
request->match_sets[i].ssid.ssid_len =
nla_len(ssid);
}
if (bssid) {
if (nla_len(bssid) != ETH_ALEN) {
err = -EINVAL;
goto out_free;
}
memcpy(request->match_sets[i].bssid,
nla_data(bssid), ETH_ALEN);
}
/* special attribute - old implementation w/a */
request->match_sets[i].rssi_thold = default_match_rssi;
rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI];
if (rssi)
request->match_sets[i].rssi_thold =
nla_get_s32(rssi);
/* Parse per band RSSI attribute */
err = nl80211_parse_sched_scan_per_band_rssi(wiphy,
&request->match_sets[i],
tb[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI],
request->match_sets[i].rssi_thold);
if (err)
goto out_free;
i++;
}
@ -8061,7 +8181,7 @@ static int nl80211_notify_radar_detection(struct sk_buff *skb,
cfg80211_sched_dfs_chan_update(rdev);
memcpy(&rdev->radar_chandef, &chandef, sizeof(chandef));
rdev->radar_chandef = chandef;
/* Propagate this notification to other radios as well */
queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
@ -13259,6 +13379,72 @@ static int nl80211_get_ftm_responder_stats(struct sk_buff *skb,
return -ENOBUFS;
}
static int nl80211_update_owe_info(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct cfg80211_update_owe_info owe_info;
struct net_device *dev = info->user_ptr[1];
if (!rdev->ops->update_owe_info)
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_STATUS_CODE] ||
!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
memset(&owe_info, 0, sizeof(owe_info));
owe_info.status = nla_get_u16(info->attrs[NL80211_ATTR_STATUS_CODE]);
nla_memcpy(owe_info.peer, info->attrs[NL80211_ATTR_MAC], ETH_ALEN);
if (info->attrs[NL80211_ATTR_IE]) {
owe_info.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
owe_info.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
return rdev_update_owe_info(rdev, dev, &owe_info);
}
static int nl80211_probe_mesh_link(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct station_info sinfo = {};
const u8 *buf;
size_t len;
u8 *dest;
int err;
if (!rdev->ops->probe_mesh_link || !rdev->ops->get_station)
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_MAC] ||
!info->attrs[NL80211_ATTR_FRAME]) {
GENL_SET_ERR_MSG(info, "Frame or MAC missing");
return -EINVAL;
}
if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
return -EOPNOTSUPP;
dest = nla_data(info->attrs[NL80211_ATTR_MAC]);
buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
if (len < sizeof(struct ethhdr))
return -EINVAL;
if (!ether_addr_equal(buf, dest) || is_multicast_ether_addr(buf) ||
!ether_addr_equal(buf + ETH_ALEN, dev->dev_addr))
return -EINVAL;
err = rdev_get_station(rdev, dev, dest, &sinfo);
if (err)
return err;
return rdev_probe_mesh_link(rdev, dev, dest, buf, len);
}
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@ -14095,6 +14281,20 @@ static const struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_UPDATE_OWE_INFO,
.doit = nl80211_update_owe_info,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
.cmd = NL80211_CMD_PROBE_MESH_LINK,
.doit = nl80211_probe_mesh_link,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
};
static struct genl_family nl80211_fam __ro_after_init = {
@ -15624,6 +15824,11 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
wdev->chandef = *chandef;
wdev->preset_chandef = *chandef;
if (wdev->iftype == NL80211_IFTYPE_STATION &&
!WARN_ON(!wdev->current_bss))
wdev->current_bss->pub.channel = chandef->chan;
nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
NL80211_CMD_CH_SWITCH_NOTIFY, 0);
}
@ -16267,6 +16472,46 @@ int cfg80211_external_auth_request(struct net_device *dev,
}
EXPORT_SYMBOL(cfg80211_external_auth_request);
void cfg80211_update_owe_info_event(struct net_device *netdev,
struct cfg80211_update_owe_info *owe_info,
gfp_t gfp)
{
struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct sk_buff *msg;
void *hdr;
trace_cfg80211_update_owe_info_event(wiphy, netdev, owe_info);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UPDATE_OWE_INFO);
if (!hdr)
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, owe_info->peer))
goto nla_put_failure;
if (!owe_info->ie_len ||
nla_put(msg, NL80211_ATTR_IE, owe_info->ie_len, owe_info->ie))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, gfp);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_update_owe_info_event);
/* initialisation/exit functions */
int __init nl80211_init(void)

View File

@ -77,7 +77,8 @@ static inline int rdev_add_key(struct cfg80211_registered_device *rdev,
struct key_params *params)
{
int ret;
trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise, mac_addr);
trace_rdev_add_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr, params->mode);
ret = rdev->ops->add_key(&rdev->wiphy, netdev, key_index, pairwise,
mac_addr, params);
trace_rdev_return_int(&rdev->wiphy, ret);
@ -1272,4 +1273,30 @@ rdev_abort_pmsr(struct cfg80211_registered_device *rdev,
trace_rdev_return_void(&rdev->wiphy);
}
static inline int rdev_update_owe_info(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct cfg80211_update_owe_info *oweinfo)
{
int ret = -EOPNOTSUPP;
trace_rdev_update_owe_info(&rdev->wiphy, dev, oweinfo);
if (rdev->ops->update_owe_info)
ret = rdev->ops->update_owe_info(&rdev->wiphy, dev, oweinfo);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
static inline int
rdev_probe_mesh_link(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *dest,
const void *buf, size_t len)
{
int ret;
trace_rdev_probe_mesh_link(&rdev->wiphy, dev, dest, buf, len);
ret = rdev->ops->probe_mesh_link(&rdev->wiphy, dev, buf, len);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View File

@ -427,14 +427,10 @@ static const struct ieee80211_regdomain *
reg_copy_regd(const struct ieee80211_regdomain *src_regd)
{
struct ieee80211_regdomain *regd;
int size_of_regd;
unsigned int i;
size_of_regd =
sizeof(struct ieee80211_regdomain) +
src_regd->n_reg_rules * sizeof(struct ieee80211_reg_rule);
regd = kzalloc(size_of_regd, GFP_KERNEL);
regd = kzalloc(struct_size(regd, reg_rules, src_regd->n_reg_rules),
GFP_KERNEL);
if (!regd)
return ERR_PTR(-ENOMEM);
@ -948,12 +944,10 @@ static int regdb_query_country(const struct fwdb_header *db,
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
struct fwdb_collection *coll = (void *)((u8 *)db + ptr);
struct ieee80211_regdomain *regdom;
unsigned int size_of_regd, i;
unsigned int i;
size_of_regd = sizeof(struct ieee80211_regdomain) +
coll->n_rules * sizeof(struct ieee80211_reg_rule);
regdom = kzalloc(size_of_regd, GFP_KERNEL);
regdom = kzalloc(struct_size(regdom, reg_rules, coll->n_rules),
GFP_KERNEL);
if (!regdom)
return -ENOMEM;
@ -1489,7 +1483,7 @@ static struct ieee80211_regdomain *
regdom_intersect(const struct ieee80211_regdomain *rd1,
const struct ieee80211_regdomain *rd2)
{
int r, size_of_regd;
int r;
unsigned int x, y;
unsigned int num_rules = 0;
const struct ieee80211_reg_rule *rule1, *rule2;
@ -1520,10 +1514,7 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
if (!num_rules)
return NULL;
size_of_regd = sizeof(struct ieee80211_regdomain) +
num_rules * sizeof(struct ieee80211_reg_rule);
rd = kzalloc(size_of_regd, GFP_KERNEL);
rd = kzalloc(struct_size(rd, reg_rules, num_rules), GFP_KERNEL);
if (!rd)
return NULL;

View File

@ -179,12 +179,63 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
return true;
}
bool cfg80211_is_element_inherited(const struct element *elem,
const struct element *non_inherit_elem)
{
u8 id_len, ext_id_len, i, loop_len, id;
const u8 *list;
if (elem->id == WLAN_EID_MULTIPLE_BSSID)
return false;
if (!non_inherit_elem || non_inherit_elem->datalen < 2)
return true;
/*
* non inheritance element format is:
* ext ID (56) | IDs list len | list | extension IDs list len | list
* Both lists are optional. Both lengths are mandatory.
* This means valid length is:
* elem_len = 1 (extension ID) + 2 (list len fields) + list lengths
*/
id_len = non_inherit_elem->data[1];
if (non_inherit_elem->datalen < 3 + id_len)
return true;
ext_id_len = non_inherit_elem->data[2 + id_len];
if (non_inherit_elem->datalen < 3 + id_len + ext_id_len)
return true;
if (elem->id == WLAN_EID_EXTENSION) {
if (!ext_id_len)
return true;
loop_len = ext_id_len;
list = &non_inherit_elem->data[3 + id_len];
id = elem->data[0];
} else {
if (!id_len)
return true;
loop_len = id_len;
list = &non_inherit_elem->data[2];
id = elem->id;
}
for (i = 0; i < loop_len; i++) {
if (list[i] == id)
return false;
}
return true;
}
EXPORT_SYMBOL(cfg80211_is_element_inherited);
static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
const u8 *subelement, size_t subie_len,
u8 *new_ie, gfp_t gfp)
{
u8 *pos, *tmp;
const u8 *tmp_old, *tmp_new;
const struct element *non_inherit_elem;
u8 *sub_copy;
/* 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,
pos += (tmp_new[1] + 2);
}
/* get non inheritance list if exists */
non_inherit_elem =
cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
sub_copy, subie_len);
/* go through IEs in ie (skip SSID) and subelement,
* merge them into new_ie
*/
@ -223,8 +279,11 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
subie_len);
if (!tmp) {
const struct element *old_elem = (void *)tmp_old;
/* ie in old ie but not in subelement */
if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
if (cfg80211_is_element_inherited(old_elem,
non_inherit_elem)) {
memcpy(pos, tmp_old, tmp_old[1] + 2);
pos += tmp_old[1] + 2;
}
@ -268,8 +327,7 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
tmp_new = sub_copy;
while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
tmp_new[0] == WLAN_EID_SSID ||
tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX)) {
tmp_new[0] == WLAN_EID_SSID)) {
memcpy(pos, tmp_new, tmp_new[1] + 2);
pos += tmp_new[1] + 2;
}
@ -1397,6 +1455,78 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
return &res->pub;
}
static const struct element
*cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
const struct element *mbssid_elem,
const struct element *sub_elem)
{
const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
const struct element *next_mbssid;
const struct element *next_sub;
next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
mbssid_end,
ielen - (mbssid_end - ie));
/*
* If is is not the last subelement in current MBSSID IE or there isn't
* a next MBSSID IE - profile is complete.
*/
if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
!next_mbssid)
return NULL;
/* For any length error, just return NULL */
if (next_mbssid->datalen < 4)
return NULL;
next_sub = (void *)&next_mbssid->data[1];
if (next_mbssid->data + next_mbssid->datalen <
next_sub->data + next_sub->datalen)
return NULL;
if (next_sub->id != 0 || next_sub->datalen < 2)
return NULL;
/*
* Check if the first element in the next sub element is a start
* of a new profile
*/
return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
NULL : next_mbssid;
}
size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
const struct element *mbssid_elem,
const struct element *sub_elem,
u8 *merged_ie, size_t max_copy_len)
{
size_t copied_len = sub_elem->datalen;
const struct element *next_mbssid;
if (sub_elem->datalen > max_copy_len)
return 0;
memcpy(merged_ie, sub_elem->data, sub_elem->datalen);
while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
mbssid_elem,
sub_elem))) {
const struct element *next_sub = (void *)&next_mbssid->data[1];
if (copied_len + next_sub->datalen > max_copy_len)
break;
memcpy(merged_ie + copied_len, next_sub->data,
next_sub->datalen);
copied_len += next_sub->datalen;
}
return copied_len;
}
EXPORT_SYMBOL(cfg80211_merge_profile);
static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
struct cfg80211_inform_bss *data,
enum cfg80211_bss_frame_type ftype,
@ -1410,7 +1540,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
const struct element *elem, *sub;
size_t new_ie_len;
u8 new_bssid[ETH_ALEN];
u8 *new_ie;
u8 *new_ie, *profile;
u64 seen_indices = 0;
u16 capability;
struct cfg80211_bss *bss;
@ -1428,10 +1559,16 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
if (!new_ie)
return;
profile = kmalloc(ielen, gfp);
if (!profile)
goto out;
for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
if (elem->datalen < 4)
continue;
for_each_element(sub, elem->data + 1, elem->datalen - 1) {
u8 profile_len;
if (sub->id != 0 || sub->datalen < 4) {
/* not a valid BSS profile */
continue;
@ -1446,16 +1583,31 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
continue;
}
memset(profile, 0, ielen);
profile_len = cfg80211_merge_profile(ie, ielen,
elem,
sub,
profile,
ielen);
/* found a Nontransmitted BSSID Profile */
mbssid_index_ie = cfg80211_find_ie
(WLAN_EID_MULTI_BSSID_IDX,
sub->data, sub->datalen);
profile, profile_len);
if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
mbssid_index_ie[2] == 0) {
mbssid_index_ie[2] == 0 ||
mbssid_index_ie[2] > 46) {
/* No valid Multiple BSSID-Index element */
continue;
}
if (seen_indices & BIT(mbssid_index_ie[2]))
/* We don't support legacy split of a profile */
net_dbg_ratelimited("Partial info for BSSID index %d\n",
mbssid_index_ie[2]);
seen_indices |= BIT(mbssid_index_ie[2]);
non_tx_data->bssid_index = mbssid_index_ie[2];
non_tx_data->max_bssid_indicator = elem->data[0];
@ -1464,13 +1616,14 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
non_tx_data->bssid_index,
new_bssid);
memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data,
sub->datalen, new_ie,
new_ie_len = cfg80211_gen_new_ie(ie, ielen,
profile,
profile_len, new_ie,
gfp);
if (!new_ie_len)
continue;
capability = get_unaligned_le16(sub->data + 2);
capability = get_unaligned_le16(profile + 2);
bss = cfg80211_inform_single_bss_data(wiphy, data,
ftype,
new_bssid, tsf,
@ -1486,7 +1639,9 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
}
}
out:
kfree(new_ie);
kfree(profile);
}
struct cfg80211_bss *

View File

@ -430,12 +430,6 @@ DECLARE_EVENT_CLASS(key_handle,
BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr))
);
DEFINE_EVENT(key_handle, rdev_add_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr),
TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
);
DEFINE_EVENT(key_handle, rdev_get_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr),
@ -448,6 +442,33 @@ DEFINE_EVENT(key_handle, rdev_del_key,
TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr)
);
TRACE_EVENT(rdev_add_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool pairwise, const u8 *mac_addr, u8 mode),
TP_ARGS(wiphy, netdev, key_index, pairwise, mac_addr, mode),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(mac_addr)
__field(u8, key_index)
__field(bool, pairwise)
__field(u8, mode)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(mac_addr, mac_addr);
__entry->key_index = key_index;
__entry->pairwise = pairwise;
__entry->mode = mode;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, "
"mode: %u, pairwise: %s, mac addr: " MAC_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
__entry->mode, BOOL_TO_STR(__entry->pairwise),
MAC_PR_ARG(mac_addr))
);
TRACE_EVENT(rdev_set_default_key,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
bool unicast, bool multicast),
@ -3362,6 +3383,62 @@ TRACE_EVENT(cfg80211_pmsr_complete,
WIPHY_PR_ARG, WDEV_PR_ARG,
(unsigned long long)__entry->cookie)
);
TRACE_EVENT(rdev_update_owe_info,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_update_owe_info *owe_info),
TP_ARGS(wiphy, netdev, owe_info),
TP_STRUCT__entry(WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(peer)
__field(u16, status)
__dynamic_array(u8, ie, owe_info->ie_len)),
TP_fast_assign(WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(peer, owe_info->peer);
__entry->status = owe_info->status;
memcpy(__get_dynamic_array(ie),
owe_info->ie, owe_info->ie_len);),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT
" status %d", WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
__entry->status)
);
TRACE_EVENT(cfg80211_update_owe_info_event,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
struct cfg80211_update_owe_info *owe_info),
TP_ARGS(wiphy, netdev, owe_info),
TP_STRUCT__entry(WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(peer)
__dynamic_array(u8, ie, owe_info->ie_len)),
TP_fast_assign(WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(peer, owe_info->peer);
memcpy(__get_dynamic_array(ie), owe_info->ie,
owe_info->ie_len);),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
);
TRACE_EVENT(rdev_probe_mesh_link,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
const u8 *dest, const u8 *buf, size_t len),
TP_ARGS(wiphy, netdev, dest, buf, len),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
MAC_ENTRY(dest)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
MAC_ASSIGN(dest, dest);
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dest))
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH

View File

@ -237,14 +237,23 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* Disallow pairwise keys with non-zero index unless it's WEP
* or a vendor specific cipher (because current deployments use
* pairwise WEP keys with non-zero indices and for vendor
* specific ciphers this should be validated in the driver or
* hardware level - but 802.11i clearly specifies to use zero)
/* IEEE802.11-2016 allows only 0 and - when using Extended Key
* ID - 1 as index for pairwise keys.
* @NL80211_KEY_NO_TX is only allowed for pairwise keys when
* the driver supports Extended Key ID.
* @NL80211_KEY_SET_TX can't be set when installing and
* validating a key.
*/
if (pairwise && key_idx)
if (params->mode == NL80211_KEY_NO_TX) {
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_EXT_KEY_ID))
return -EINVAL;
else if (!pairwise || key_idx < 0 || key_idx > 1)
return -EINVAL;
} else if ((pairwise && key_idx) ||
params->mode == NL80211_KEY_SET_TX) {
return -EINVAL;
}
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:

View File

@ -353,9 +353,6 @@ static int cfg80211_wext_siwretry(struct net_device *dev,
changed |= WIPHY_PARAM_RETRY_SHORT;
}
if (!changed)
return 0;
err = rdev_set_wiphy_params(rdev, changed);
if (err) {
wdev->wiphy->retry_short = oshort;