mirror of https://gitee.com/openkylin/linux.git
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:
commit
30e5a9a5ba
|
@ -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, ¶m);
|
||||
if (err < 0)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, ¶ms);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Include parameters for TDLS peer (will check later) */
|
||||
err = nl80211_set_station_tdls(info, ¶ms);
|
||||
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, ¶ms);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = nl80211_parse_sta_channel_info(info, ¶ms);
|
||||
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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue