This time we have:

* some AP-side infrastructure for FILS discovery and
    unsolicited probe resonses
  * a major rework of the encapsulation/header conversion
    offload from Felix, to fit better with e.g. AP_VLAN
    interfaces
  * performance fix for VHT A-MPDU size, don't limit to HT
  * some initial patches for S1G (sub 1 GHz) support, more
    will come in this area
  * minor cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAl9oqc0ACgkQB8qZga/f
 l8TdMxAAnGTS7p6n//5RrdNmbT/UgMPBPhdHJTXZy7q1z3hDI5xrWRrx26fQeB31
 exslnHd6q28bNGKscExcLRsP63SKn+P3PdUWJzbusya46OZnMgajNQYiQkL3ISfS
 MkF0Uyv7GmkkRn8nBg1ZbLMtzONxqn9uT6o3qyNODHwYgf/QjlEWstL7Q0fEy5UU
 gftBz4WOhMOsEQQu3XvLu2hMd6EI14ZWkChdwboYJ29GgJrCYnhO/0B4QpVJxBpp
 ROYQgF3c3Fis2tJpyZ0FNqG7T16MhjOD2+hyNAcX2+ZkkbSzn6B89jOd/qeowJOT
 FwYbJNQTUxBYH8+IYZeGVWRMyPuZdazrfccbTd9Lfrk3y/Hi+cuuneFFXykST6Zd
 EqRkumAOJY9b6HgcGTkfRFdY4SU4v3lcAOcAgg1fJVFvmLKcHfhD3xKyGz3Q1JLv
 v9x/9S+G69YWyxl09rMY9c78S6enxKmhJdV1wnv3zbALvqNTa2OpaZnCBx+hmkEy
 NoSowwYeb0PANk9PfA1N0+uQPVKu8SGT0FhxLj6NEAhCbbVBTqZ3z4TkdYByy/a0
 L80zk1ziyC4uS24+TcILHyCzRHkdLdsD8lEeVTDZIusU6nXX9imZ+yWGwIkbi35Y
 v+6fUns/1UMJqBc3J/wtr9pamoIBJT3Qe0lHC4Uy7CxuO5S1UVM=
 =Bnsm
 -----END PGP SIGNATURE-----

Merge tag 'mac80211-next-for-net-next-2020-09-21' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
This time we have:
 * some AP-side infrastructure for FILS discovery and
   unsolicited probe resonses
 * a major rework of the encapsulation/header conversion
   offload from Felix, to fit better with e.g. AP_VLAN
   interfaces
 * performance fix for VHT A-MPDU size, don't limit to HT
 * some initial patches for S1G (sub 1 GHz) support, more
   will come in this area
 * minor cleanups
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-09-21 14:55:09 -07:00
commit ae4dd9a8c2
26 changed files with 1567 additions and 927 deletions

View file

@ -18,7 +18,7 @@ ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
return HAL_TCL_ENCAP_TYPE_RAW;
if (tx_info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
return HAL_TCL_ENCAP_TYPE_ETHERNET;
return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
@ -98,7 +98,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN;
if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data(hdr->frame_control))
return -ENOTSUPP;

View file

@ -3936,7 +3936,7 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
return -ENOSPC;
info = IEEE80211_SKB_CB(skb);
if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) {
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) {
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
ieee80211_is_disassoc(hdr->frame_control)) &&
@ -4063,7 +4063,7 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
bool is_prb_rsp;
int ret;
if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
} else if (ieee80211_is_mgmt(hdr->frame_control)) {
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
@ -4349,6 +4349,37 @@ static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
return ret;
}
static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
u32 param_id, param_value;
int ret;
param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET ||
(vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_AP))
vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
param_value = ATH11K_HW_TXRX_ETHERNET;
else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
param_value = ATH11K_HW_TXRX_RAW;
else
param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
if (ret) {
ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
arvif->vdev_id, ret);
vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
}
}
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@ -4358,7 +4389,6 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
struct vdev_create_params vdev_param = {0};
struct peer_create_params peer_param;
u32 param_id, param_value;
int hw_encap = 0;
u16 nss;
int i;
int ret;
@ -4452,32 +4482,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
list_add(&arvif->list, &ar->arvifs);
spin_unlock_bh(&ar->data_lock);
param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET)
switch (vif->type) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_AP:
hw_encap = 1;
break;
default:
break;
}
if (ieee80211_set_hw_80211_encap(vif, hw_encap))
param_value = ATH11K_HW_TXRX_ETHERNET;
else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
param_value = ATH11K_HW_TXRX_RAW;
else
param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
if (ret) {
ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
arvif->vdev_id, ret);
goto err_vdev_del;
}
ath11k_mac_op_update_vif_offload(hw, vif);
nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
@ -5840,6 +5845,7 @@ static const struct ieee80211_ops ath11k_ops = {
.reconfig_complete = ath11k_mac_op_reconfig_complete,
.add_interface = ath11k_mac_op_add_interface,
.remove_interface = ath11k_mac_op_remove_interface,
.update_vif_offload = ath11k_mac_op_update_vif_offload,
.config = ath11k_mac_op_config,
.bss_info_changed = ath11k_mac_op_bss_info_changed,
.configure_filter = ath11k_mac_op_configure_filter,
@ -6148,6 +6154,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
if (ht_cap & WMI_HT_CAP_ENABLED) {
ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);

View file

@ -2330,84 +2330,84 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
}
/* S1G Capabilities Information field */
#define S1G_CAPAB_B0_S1G_LONG BIT(0)
#define S1G_CAPAB_B0_SGI_1MHZ BIT(1)
#define S1G_CAPAB_B0_SGI_2MHZ BIT(2)
#define S1G_CAPAB_B0_SGI_4MHZ BIT(3)
#define S1G_CAPAB_B0_SGI_8MHZ BIT(4)
#define S1G_CAPAB_B0_SGI_16MHZ BIT(5)
#define S1G_CAPAB_B0_SUPP_CH_WIDTH_MASK (BIT(6) | BIT(7))
#define S1G_CAPAB_B0_SUPP_CH_WIDTH_SHIFT 6
#define S1G_CAP0_S1G_LONG BIT(0)
#define S1G_CAP0_SGI_1MHZ BIT(1)
#define S1G_CAP0_SGI_2MHZ BIT(2)
#define S1G_CAP0_SGI_4MHZ BIT(3)
#define S1G_CAP0_SGI_8MHZ BIT(4)
#define S1G_CAP0_SGI_16MHZ BIT(5)
#define S1G_CAP0_SUPP_CH_WIDTH GENMASK(7, 6)
#define S1G_CAPAB_B1_RX_LDPC BIT(0)
#define S1G_CAPAB_B1_TX_STBC BIT(1)
#define S1G_CAPAB_B1_RX_STBC BIT(2)
#define S1G_CAPAB_B1_SU_BFER BIT(3)
#define S1G_CAPAB_B1_SU_BFEE BIT(4)
#define S1G_CAPAB_B1_BFEE_STS_MASK (BIT(5) | BIT(6) | BIT(7))
#define S1G_CAPAB_B1_BFEE_STS_SHIFT 5
#define S1G_SUPP_CH_WIDTH_2 0
#define S1G_SUPP_CH_WIDTH_4 1
#define S1G_SUPP_CH_WIDTH_8 2
#define S1G_SUPP_CH_WIDTH_16 3
#define S1G_SUPP_CH_WIDTH_MAX(cap) ((1 << FIELD_GET(S1G_CAP0_SUPP_CH_WIDTH, \
cap[0])) << 1)
#define S1G_CAPAB_B2_SOUNDING_DIMENSIONS_MASK (BIT(0) | BIT(1) | BIT(2))
#define S1G_CAPAB_B2_SOUNDING_DIMENSIONS_SHIFT 0
#define S1G_CAPAB_B2_MU_BFER BIT(3)
#define S1G_CAPAB_B2_MU_BFEE BIT(4)
#define S1G_CAPAB_B2_PLUS_HTC_VHT BIT(5)
#define S1G_CAPAB_B2_TRAVELING_PILOT_MASK (BIT(6) | BIT(7))
#define S1G_CAPAB_B2_TRAVELING_PILOT_SHIFT 6
#define S1G_CAP1_RX_LDPC BIT(0)
#define S1G_CAP1_TX_STBC BIT(1)
#define S1G_CAP1_RX_STBC BIT(2)
#define S1G_CAP1_SU_BFER BIT(3)
#define S1G_CAP1_SU_BFEE BIT(4)
#define S1G_CAP1_BFEE_STS GENMASK(7, 5)
#define S1G_CAPAB_B3_RD_RESPONDER BIT(0)
#define S1G_CAPAB_B3_HT_DELAYED_BA BIT(1)
#define S1G_CAPAB_B3_MAX_MPDU_LEN BIT(2)
#define S1G_CAPAB_B3_MAX_AMPDU_LEN_EXP_MASK (BIT(3) | BIT(4))
#define S1G_CAPAB_B3_MAX_AMPDU_LEN_EXP_SHIFT 3
#define S1G_CAPAB_B3_MIN_MPDU_START_MASK (BIT(5) | BIT(6) | BIT(7))
#define S1G_CAPAB_B3_MIN_MPDU_START_SHIFT 5
#define S1G_CAP2_SOUNDING_DIMENSIONS GENMASK(2, 0)
#define S1G_CAP2_MU_BFER BIT(3)
#define S1G_CAP2_MU_BFEE BIT(4)
#define S1G_CAP2_PLUS_HTC_VHT BIT(5)
#define S1G_CAP2_TRAVELING_PILOT GENMASK(7, 6)
#define S1G_CAPAB_B4_UPLINK_SYNC BIT(0)
#define S1G_CAPAB_B4_DYNAMIC_AID BIT(1)
#define S1G_CAPAB_B4_BAT BIT(2)
#define S1G_CAPAB_B4_TIME_ADE BIT(3)
#define S1G_CAPAB_B4_NON_TIM BIT(4)
#define S1G_CAPAB_B4_GROUP_AID BIT(5)
#define S1G_CAPAB_B4_STA_TYPE_MASK (BIT(6) | BIT(7))
#define S1G_CAPAB_B4_STA_TYPE_SHIFT 6
#define S1G_CAP3_RD_RESPONDER BIT(0)
#define S1G_CAP3_HT_DELAYED_BA BIT(1)
#define S1G_CAP3_MAX_MPDU_LEN BIT(2)
#define S1G_CAP3_MAX_AMPDU_LEN_EXP GENMASK(4, 3)
#define S1G_CAP3_MIN_MPDU_START GENMASK(7, 5)
#define S1G_CAPAB_B5_CENT_AUTH_CONTROL BIT(0)
#define S1G_CAPAB_B5_DIST_AUTH_CONTROL BIT(1)
#define S1G_CAPAB_B5_AMSDU BIT(2)
#define S1G_CAPAB_B5_AMPDU BIT(3)
#define S1G_CAPAB_B5_ASYMMETRIC_BA BIT(4)
#define S1G_CAPAB_B5_FLOW_CONTROL BIT(5)
#define S1G_CAPAB_B5_SECTORIZED_BEAM_MASK (BIT(6) | BIT(7))
#define S1G_CAPAB_B5_SECTORIZED_BEAM_SHIFT 6
#define S1G_CAP4_UPLINK_SYNC BIT(0)
#define S1G_CAP4_DYNAMIC_AID BIT(1)
#define S1G_CAP4_BAT BIT(2)
#define S1G_CAP4_TIME_ADE BIT(3)
#define S1G_CAP4_NON_TIM BIT(4)
#define S1G_CAP4_GROUP_AID BIT(5)
#define S1G_CAP4_STA_TYPE GENMASK(7, 6)
#define S1G_CAPAB_B6_OBSS_MITIGATION BIT(0)
#define S1G_CAPAB_B6_FRAGMENT_BA BIT(1)
#define S1G_CAPAB_B6_NDP_PS_POLL BIT(2)
#define S1G_CAPAB_B6_RAW_OPERATION BIT(3)
#define S1G_CAPAB_B6_PAGE_SLICING BIT(4)
#define S1G_CAPAB_B6_TXOP_SHARING_IMP_ACK BIT(5)
#define S1G_CAPAB_B6_VHT_LINK_ADAPT_MASK (BIT(6) | BIT(7))
#define S1G_CAPAB_B6_VHT_LINK_ADAPT_SHIFT 6
#define S1G_CAP5_CENT_AUTH_CONTROL BIT(0)
#define S1G_CAP5_DIST_AUTH_CONTROL BIT(1)
#define S1G_CAP5_AMSDU BIT(2)
#define S1G_CAP5_AMPDU BIT(3)
#define S1G_CAP5_ASYMMETRIC_BA BIT(4)
#define S1G_CAP5_FLOW_CONTROL BIT(5)
#define S1G_CAP5_SECTORIZED_BEAM GENMASK(7, 6)
#define S1G_CAPAB_B7_TACK_AS_PS_POLL BIT(0)
#define S1G_CAPAB_B7_DUP_1MHZ BIT(1)
#define S1G_CAPAB_B7_MCS_NEGOTIATION BIT(2)
#define S1G_CAPAB_B7_1MHZ_CTL_RESPONSE_PREAMBLE BIT(3)
#define S1G_CAPAB_B7_NDP_BFING_REPORT_POLL BIT(4)
#define S1G_CAPAB_B7_UNSOLICITED_DYN_AID BIT(5)
#define S1G_CAPAB_B7_SECTOR_TRAINING_OPERATION BIT(6)
#define S1G_CAPAB_B7_TEMP_PS_MODE_SWITCH BIT(7)
#define S1G_CAP6_OBSS_MITIGATION BIT(0)
#define S1G_CAP6_FRAGMENT_BA BIT(1)
#define S1G_CAP6_NDP_PS_POLL BIT(2)
#define S1G_CAP6_RAW_OPERATION BIT(3)
#define S1G_CAP6_PAGE_SLICING BIT(4)
#define S1G_CAP6_TXOP_SHARING_IMP_ACK BIT(5)
#define S1G_CAP6_VHT_LINK_ADAPT GENMASK(7, 6)
#define S1G_CAPAB_B8_TWT_GROUPING BIT(0)
#define S1G_CAPAB_B8_BDT BIT(1)
#define S1G_CAPAB_B8_COLOR_MASK (BIT(2) | BIT(3) | BIT(4))
#define S1G_CAPAB_B8_COLOR_SHIFT 2
#define S1G_CAPAB_B8_TWT_REQUEST BIT(5)
#define S1G_CAPAB_B8_TWT_RESPOND BIT(6)
#define S1G_CAPAB_B8_PV1_FRAME BIT(7)
#define S1G_CAP7_TACK_AS_PS_POLL BIT(0)
#define S1G_CAP7_DUP_1MHZ BIT(1)
#define S1G_CAP7_MCS_NEGOTIATION BIT(2)
#define S1G_CAP7_1MHZ_CTL_RESPONSE_PREAMBLE BIT(3)
#define S1G_CAP7_NDP_BFING_REPORT_POLL BIT(4)
#define S1G_CAP7_UNSOLICITED_DYN_AID BIT(5)
#define S1G_CAP7_SECTOR_TRAINING_OPERATION BIT(6)
#define S1G_CAP7_TEMP_PS_MODE_SWITCH BIT(7)
#define S1G_CAPAB_B9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0)
#define S1G_CAP8_TWT_GROUPING BIT(0)
#define S1G_CAP8_BDT BIT(1)
#define S1G_CAP8_COLOR GENMASK(4, 2)
#define S1G_CAP8_TWT_REQUEST BIT(5)
#define S1G_CAP8_TWT_RESPOND BIT(6)
#define S1G_CAP8_PV1_FRAME BIT(7)
#define S1G_CAP9_LINK_ADAPT_PER_CONTROL_RESPONSE BIT(0)
#define S1G_OPER_CH_WIDTH_PRIMARY_1MHZ BIT(0)
#define S1G_OPER_CH_WIDTH_OPER GENMASK(4, 1)
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0

View file

@ -96,6 +96,16 @@ struct wiphy;
* @IEEE80211_CHAN_NO_10MHZ: 10 MHz bandwidth is not permitted
* on this channel.
* @IEEE80211_CHAN_NO_HE: HE operation is not permitted on this channel.
* @IEEE80211_CHAN_1MHZ: 1 MHz bandwidth is permitted
* on this channel.
* @IEEE80211_CHAN_2MHZ: 2 MHz bandwidth is permitted
* on this channel.
* @IEEE80211_CHAN_4MHZ: 4 MHz bandwidth is permitted
* on this channel.
* @IEEE80211_CHAN_8MHZ: 8 MHz bandwidth is permitted
* on this channel.
* @IEEE80211_CHAN_16MHZ: 16 MHz bandwidth is permitted
* on this channel.
*
*/
enum ieee80211_channel_flags {
@ -113,6 +123,11 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_NO_20MHZ = 1<<11,
IEEE80211_CHAN_NO_10MHZ = 1<<12,
IEEE80211_CHAN_NO_HE = 1<<13,
IEEE80211_CHAN_1MHZ = 1<<14,
IEEE80211_CHAN_2MHZ = 1<<15,
IEEE80211_CHAN_4MHZ = 1<<16,
IEEE80211_CHAN_8MHZ = 1<<17,
IEEE80211_CHAN_16MHZ = 1<<18,
};
#define IEEE80211_CHAN_NO_HT40 \
@ -450,6 +465,7 @@ struct ieee80211_sta_s1g_cap {
* @ht_cap: HT capabilities in this band
* @vht_cap: VHT capabilities in this band
* @edmg_cap: EDMG capabilities in this band
* @s1g_cap: S1G capabilities in this band (S1B band only, of course)
* @n_iftype_data: number of iftype data entries
* @iftype_data: interface type data entries. Note that the bits in
* @types_mask inside this structure cannot overlap (i.e. only
@ -1067,6 +1083,39 @@ struct cfg80211_acl_data {
struct mac_address mac_addrs[];
};
/**
* struct cfg80211_fils_discovery - FILS discovery parameters from
* IEEE Std 802.11ai-2016, Annex C.3 MIB detail.
*
* @min_interval: Minimum packet interval in TUs (0 - 10000)
* @max_interval: Maximum packet interval in TUs (0 - 10000)
* @tmpl_len: Template length
* @tmpl: Template data for FILS discovery frame including the action
* frame headers.
*/
struct cfg80211_fils_discovery {
u32 min_interval;
u32 max_interval;
size_t tmpl_len;
const u8 *tmpl;
};
/**
* struct cfg80211_unsol_bcast_probe_resp - Unsolicited broadcast probe
* response parameters in 6GHz.
*
* @interval: Packet interval in TUs. Maximum allowed is 20 TU, as mentioned
* in IEEE P802.11ax/D6.0 26.17.2.3.2 - AP behavior for fast passive
* scanning
* @tmpl_len: Template length
* @tmpl: Template data for probe response
*/
struct cfg80211_unsol_bcast_probe_resp {
u32 interval;
size_t tmpl_len;
const u8 *tmpl;
};
/**
* enum cfg80211_ap_settings_flags - AP settings flags
*
@ -1114,6 +1163,8 @@ enum cfg80211_ap_settings_flags {
* @he_obss_pd: OBSS Packet Detection settings
* @he_bss_color: BSS Color settings
* @he_oper: HE operation IE (or %NULL if HE isn't enabled)
* @fils_discovery: FILS discovery transmission parameters
* @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters
*/
struct cfg80211_ap_settings {
struct cfg80211_chan_def chandef;
@ -1144,6 +1195,8 @@ struct cfg80211_ap_settings {
u32 flags;
struct ieee80211_he_obss_pd he_obss_pd;
struct cfg80211_he_bss_color he_bss_color;
struct cfg80211_fils_discovery fils_discovery;
struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp;
};
/**
@ -1787,6 +1840,7 @@ struct mpath_info {
* (or NULL for no change)
* @basic_rates_len: number of basic rates
* @ap_isolate: do not forward packets between connected stations
* (0 = no, 1 = yes, -1 = do not change)
* @ht_opmode: HT Operation mode
* (u16 = opmode, -1 = do not change)
* @p2p_ctwindow: P2P CT Window (-1 = no change)
@ -5278,6 +5332,16 @@ ieee80211_channel_to_khz(const struct ieee80211_channel *chan)
return MHZ_TO_KHZ(chan->center_freq) + chan->freq_offset;
}
/**
* ieee80211_s1g_channel_width - get allowed channel width from @chan
*
* Only allowed for band NL80211_BAND_S1GHZ
* @chan: channel
* Return: The allowed channel width for this center_freq
*/
enum nl80211_chan_width
ieee80211_s1g_channel_width(const struct ieee80211_channel *chan);
/**
* ieee80211_channel_to_freq_khz - convert channel number to frequency
* @chan: channel number

View file

@ -317,6 +317,9 @@ struct ieee80211_vif_chanctx_switch {
* @BSS_CHANGED_TWT: TWT status changed
* @BSS_CHANGED_HE_OBSS_PD: OBSS Packet Detection status changed.
* @BSS_CHANGED_HE_BSS_COLOR: BSS Color has changed
* @BSS_CHANGED_FILS_DISCOVERY: FILS discovery status changed.
* @BSS_CHANGED_UNSOL_BCAST_PROBE_RESP: Unsolicited broadcast probe response
* status changed.
*
*/
enum ieee80211_bss_change {
@ -350,6 +353,8 @@ enum ieee80211_bss_change {
BSS_CHANGED_TWT = 1<<27,
BSS_CHANGED_HE_OBSS_PD = 1<<28,
BSS_CHANGED_HE_BSS_COLOR = 1<<29,
BSS_CHANGED_FILS_DISCOVERY = 1<<30,
BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = 1<<31,
/* when adding here, make sure to change ieee80211_reconfig */
};
@ -490,6 +495,18 @@ struct ieee80211_ftm_responder_params {
size_t civicloc_len;
};
/**
* struct ieee80211_fils_discovery - FILS discovery parameters from
* IEEE Std 802.11ai-2016, Annex C.3 MIB detail.
*
* @min_interval: Minimum packet interval in TUs (0 - 10000)
* @max_interval: Maximum packet interval in TUs (0 - 10000)
*/
struct ieee80211_fils_discovery {
u32 min_interval;
u32 max_interval;
};
/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
@ -607,6 +624,9 @@ struct ieee80211_ftm_responder_params {
* @he_oper: HE operation information of the AP we are connected to
* @he_obss_pd: OBSS Packet Detection parameters.
* @he_bss_color: BSS coloring settings, if BSS supports HE
* @fils_discovery: FILS discovery configuration
* @unsol_bcast_probe_resp_interval: Unsolicited broadcast probe response
* interval.
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@ -674,6 +694,8 @@ struct ieee80211_bss_conf {
} he_oper;
struct ieee80211_he_obss_pd he_obss_pd;
struct cfg80211_he_bss_color he_bss_color;
struct ieee80211_fils_discovery fils_discovery;
u32 unsol_bcast_probe_resp_interval;
};
/**
@ -720,9 +742,8 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate
* that a frame can be transmitted while the queues are stopped for
* off-channel operation.
* @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
* used to indicate that a pending frame requires TX processing before
* it can be sent out.
* @IEEE80211_TX_CTL_HW_80211_ENCAP: This frame uses hardware encapsulation
* (header conversion)
* @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
* used to indicate that a frame was already retried due to PS
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
@ -791,7 +812,7 @@ enum mac80211_tx_info_flags {
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13),
IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17),
@ -823,8 +844,9 @@ enum mac80211_tx_info_flags {
* @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
* @IEEE80211_TX_CTRL_HW_80211_ENCAP: This frame uses hardware encapsulation
* (header conversion)
* @IEEE80211_TX_INTCFL_NEED_TXPROCESSING: completely internal to mac80211,
* used to indicate that a pending frame requires TX processing before
* it can be sent out.
* @IEEE80211_TX_CTRL_NO_SEQNO: Do not overwrite the sequence number that
* has already been assigned to this frame.
*
@ -837,7 +859,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_AMSDU = BIT(3),
IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5),
IEEE80211_TX_CTRL_HW_80211_ENCAP = BIT(6),
IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6),
IEEE80211_TX_CTRL_NO_SEQNO = BIT(7),
};
@ -1002,7 +1024,8 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
* @status.ampdu_ack_len: AMPDU ack length
* @status.ampdu_len: AMPDU length
* @status.antenna: (legacy, kept only for iwlegacy)
* @status.tx_time: airtime consumed for transmission
* @status.tx_time: airtime consumed for transmission; note this is only
* used for WMM AC, not for airtime fairness
* @status.is_valid_ack_signal: ACK signal is valid
* @status.status_driver_data: driver use area
* @ack: union part for pure ACK data
@ -1095,12 +1118,14 @@ ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
* @info: Basic tx status information
* @skb: Packet skb (can be NULL if not provided by the driver)
* @rate: The TX rate that was used when sending the packet
* @free_list: list where processed skbs are stored to be free'd by the driver
*/
struct ieee80211_tx_status {
struct ieee80211_sta *sta;
struct ieee80211_tx_info *info;
struct sk_buff *skb;
struct rate_info *rate;
struct list_head *free_list;
};
/**
@ -1606,6 +1631,21 @@ enum ieee80211_vif_flags {
IEEE80211_VIF_GET_NOA_UPDATE = BIT(3),
};
/**
* enum ieee80211_offload_flags - virtual interface offload flags
*
* @IEEE80211_OFFLOAD_ENCAP_ENABLED: tx encapsulation offload is enabled
* The driver supports sending frames passed as 802.3 frames by mac80211.
* It must also support sending 802.11 packets for the same interface.
* @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload
*/
enum ieee80211_offload_flags {
IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0),
IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1),
};
/**
* struct ieee80211_vif - per-interface data
*
@ -1626,6 +1666,11 @@ enum ieee80211_vif_flags {
* these need to be set (or cleared) when the interface is added
* or, if supported by the driver, the interface type is changed
* at runtime, mac80211 will never touch this field
* @offloaad_flags: hardware offload capabilities/flags for this interface.
* These are initialized by mac80211 before calling .add_interface,
* .change_interface or .update_vif_offload and updated by the driver
* within these ops, based on supported features or runtime change
* restrictions.
* @hw_queue: hardware queue for each AC
* @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
* @chanctx_conf: The channel context this interface is assigned to, or %NULL
@ -1645,6 +1690,8 @@ enum ieee80211_vif_flags {
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
* @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
* protected by fq->lock.
* @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
* &enum ieee80211_offload_flags.
*/
struct ieee80211_vif {
enum nl80211_iftype type;
@ -1662,6 +1709,7 @@ struct ieee80211_vif {
struct ieee80211_chanctx_conf __rcu *chanctx_conf;
u32 driver_flags;
u32 offload_flags;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfs_dir;
@ -2328,6 +2376,9 @@ struct ieee80211_txq {
* aggregating MPDUs with the same keyid, allowing mac80211 to keep Tx
* A-MPDU sessions active while rekeying with Extended Key ID.
*
* @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
* offload
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@ -2380,6 +2431,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
@ -3814,6 +3866,10 @@ enum ieee80211_reconfig_type {
* @set_tid_config: Apply TID specific configurations. This callback may sleep.
* @reset_tid_config: Reset TID specific configuration for the peer.
* This callback may sleep.
* @update_vif_offload: Update virtual interface offload flags
* This callback may sleep.
* @sta_set_4addr: Called to notify the driver when a station starts/stops using
* 4-address mode
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@ -4125,6 +4181,10 @@ struct ieee80211_ops {
int (*reset_tid_config)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u8 tids);
void (*update_vif_offload)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled);
};
/**
@ -5647,7 +5707,7 @@ void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid);
/**
* ieee80211_sta_register_airtime - register airtime usage for a sta/tid
*
* Register airtime usage for a given sta on a given tid. The driver can call
* Register airtime usage for a given sta on a given tid. The driver must call
* this function to notify mac80211 that a station used a certain amount of
* airtime. This information will be used by the TXQ scheduler to schedule
* stations in a way that ensures airtime fairness.
@ -6593,4 +6653,29 @@ u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
*/
bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable);
/**
* ieee80211_get_fils_discovery_tmpl - Get FILS discovery template.
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* The driver is responsible for freeing the returned skb.
*
* Return: FILS discovery template. %NULL on error.
*/
struct sk_buff *ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
/**
* ieee80211_get_unsol_bcast_probe_resp_tmpl - Get unsolicited broadcast
* probe response template.
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
*
* The driver is responsible for freeing the returned skb.
*
* Return: Unsolicited broadcast probe response template. %NULL on error.
*/
struct sk_buff *
ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
#endif /* MAC80211_H */

View file

@ -2513,6 +2513,14 @@ enum nl80211_commands {
* @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from
* association request when used with NL80211_CMD_NEW_STATION).
*
* @NL80211_ATTR_FILS_DISCOVERY: Optional parameter to configure FILS
* discovery. It is a nested attribute, see
* &enum nl80211_fils_discovery_attributes.
*
* @NL80211_ATTR_UNSOL_BCAST_PROBE_RESP: Optional parameter to configure
* unsolicited broadcast probe response. It is a nested attribute, see
* &enum nl80211_unsol_bcast_probe_resp_attributes.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -2995,6 +3003,10 @@ enum nl80211_attrs {
NL80211_ATTR_HE_6GHZ_CAPABILITY,
NL80211_ATTR_FILS_DISCOVERY,
NL80211_ATTR_UNSOL_BCAST_PROBE_RESP,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -3737,6 +3749,16 @@ enum nl80211_wmm_rule {
* @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel
* in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz
* @NL80211_FREQUENCY_ATTR_1MHZ: 1 MHz operation is allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_2MHZ: 2 MHz operation is allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_4MHZ: 4 MHz operation is allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_8MHZ: 8 MHz operation is allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@ -3768,6 +3790,11 @@ enum nl80211_frequency_attr {
NL80211_FREQUENCY_ATTR_WMM,
NL80211_FREQUENCY_ATTR_NO_HE,
NL80211_FREQUENCY_ATTR_OFFSET,
NL80211_FREQUENCY_ATTR_1MHZ,
NL80211_FREQUENCY_ATTR_2MHZ,
NL80211_FREQUENCY_ATTR_4MHZ,
NL80211_FREQUENCY_ATTR_8MHZ,
NL80211_FREQUENCY_ATTR_16MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@ -5852,6 +5879,12 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP: Device wants to do SAE authentication
* in AP mode (SAE password is passed as part of the start AP command).
*
* @NL80211_EXT_FEATURE_FILS_DISCOVERY: Driver/device supports FILS discovery
* frames transmission
*
* @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports
* unsolicited broadcast probe response transmission
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@ -5910,6 +5943,8 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION,
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK,
NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
NL80211_EXT_FEATURE_FILS_DISCOVERY,
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@ -7004,4 +7039,64 @@ enum nl80211_iftype_akm_attributes {
NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1,
};
/**
* enum nl80211_fils_discovery_attributes - FILS discovery configuration
* from IEEE Std 802.11ai-2016, Annex C.3 MIB detail.
*
* @__NL80211_FILS_DISCOVERY_ATTR_INVALID: Invalid
*
* @NL80211_FILS_DISCOVERY_ATTR_INT_MIN: Minimum packet interval (u32, TU).
* Allowed range: 0..10000 (TU = Time Unit)
* @NL80211_FILS_DISCOVERY_ATTR_INT_MAX: Maximum packet interval (u32, TU).
* Allowed range: 0..10000 (TU = Time Unit)
* @NL80211_FILS_DISCOVERY_ATTR_TMPL: Template data for FILS discovery action
* frame including the headers.
*
* @__NL80211_FILS_DISCOVERY_ATTR_LAST: Internal
* @NL80211_FILS_DISCOVERY_ATTR_MAX: highest attribute
*/
enum nl80211_fils_discovery_attributes {
__NL80211_FILS_DISCOVERY_ATTR_INVALID,
NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
NL80211_FILS_DISCOVERY_ATTR_TMPL,
/* keep last */
__NL80211_FILS_DISCOVERY_ATTR_LAST,
NL80211_FILS_DISCOVERY_ATTR_MAX = __NL80211_FILS_DISCOVERY_ATTR_LAST - 1
};
/*
* FILS discovery template minimum length with action frame headers and
* mandatory fields.
*/
#define NL80211_FILS_DISCOVERY_TMPL_MIN_LEN 42
/**
* enum nl80211_unsol_bcast_probe_resp_attributes - Unsolicited broadcast probe
* response configuration. Applicable only in 6GHz.
*
* @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID: Invalid
*
* @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT: Maximum packet interval (u32, TU).
* Allowed range: 0..20 (TU = Time Unit). IEEE P802.11ax/D6.0
* 26.17.2.3.2 (AP behavior for fast passive scanning).
* @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL: Unsolicited broadcast probe response
* frame template (binary).
*
* @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST: Internal
* @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX: highest attribute
*/
enum nl80211_unsol_bcast_probe_resp_attributes {
__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID,
NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
/* keep last */
__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST,
NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX =
__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1
};
#endif /* __LINUX_NL80211_H */

View file

@ -837,6 +837,59 @@ static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
return 0;
}
static int ieee80211_set_fils_discovery(struct ieee80211_sub_if_data *sdata,
struct cfg80211_fils_discovery *params)
{
struct fils_discovery_data *new, *old = NULL;
struct ieee80211_fils_discovery *fd;
if (!params->tmpl || !params->tmpl_len)
return -EINVAL;
fd = &sdata->vif.bss_conf.fils_discovery;
fd->min_interval = params->min_interval;
fd->max_interval = params->max_interval;
old = sdata_dereference(sdata->u.ap.fils_discovery, sdata);
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
if (!new)
return -ENOMEM;
new->len = params->tmpl_len;
memcpy(new->data, params->tmpl, params->tmpl_len);
rcu_assign_pointer(sdata->u.ap.fils_discovery, new);
if (old)
kfree_rcu(old, rcu_head);
return 0;
}
static int
ieee80211_set_unsol_bcast_probe_resp(struct ieee80211_sub_if_data *sdata,
struct cfg80211_unsol_bcast_probe_resp *params)
{
struct unsol_bcast_probe_resp_data *new, *old = NULL;
if (!params->tmpl || !params->tmpl_len)
return -EINVAL;
old = sdata_dereference(sdata->u.ap.unsol_bcast_probe_resp, sdata);
new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
if (!new)
return -ENOMEM;
new->len = params->tmpl_len;
memcpy(new->data, params->tmpl, params->tmpl_len);
rcu_assign_pointer(sdata->u.ap.unsol_bcast_probe_resp, new);
if (old)
kfree_rcu(old, rcu_head);
sdata->vif.bss_conf.unsol_bcast_probe_resp_interval =
params->interval;
return 0;
}
static int ieee80211_set_ftm_responder_params(
struct ieee80211_sub_if_data *sdata,
const u8 *lci, size_t lci_len,
@ -1099,12 +1152,26 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
}
err = ieee80211_assign_beacon(sdata, &params->beacon, NULL);
if (err < 0) {
ieee80211_vif_release_channel(sdata);
return err;
}
if (err < 0)
goto error;
changed |= err;
if (params->fils_discovery.max_interval) {
err = ieee80211_set_fils_discovery(sdata,
&params->fils_discovery);
if (err < 0)
goto error;
changed |= BSS_CHANGED_FILS_DISCOVERY;
}
if (params->unsol_bcast_probe_resp.interval) {
err = ieee80211_set_unsol_bcast_probe_resp(sdata,
&params->unsol_bcast_probe_resp);
if (err < 0)
goto error;
changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
}
err = drv_start_ap(sdata->local, sdata);
if (err) {
old = sdata_dereference(sdata->u.ap.beacon, sdata);
@ -1112,8 +1179,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (old)
kfree_rcu(old, rcu_head);
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
ieee80211_vif_release_channel(sdata);
return err;
goto error;
}
ieee80211_recalc_dtim(local, sdata);
@ -1124,6 +1190,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
netif_carrier_on(vlan->dev);
return 0;
error:
ieee80211_vif_release_channel(sdata);
return err;
}
static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
@ -1160,6 +1230,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
struct ieee80211_local *local = sdata->local;
struct beacon_data *old_beacon;
struct probe_resp *old_probe_resp;
struct fils_discovery_data *old_fils_discovery;
struct unsol_bcast_probe_resp_data *old_unsol_bcast_probe_resp;
struct cfg80211_chan_def chandef;
sdata_assert_lock(sdata);
@ -1168,6 +1240,11 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
if (!old_beacon)
return -ENOENT;
old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);
old_fils_discovery = sdata_dereference(sdata->u.ap.fils_discovery,
sdata);
old_unsol_bcast_probe_resp =
sdata_dereference(sdata->u.ap.unsol_bcast_probe_resp,
sdata);
/* abort any running channel switch */
mutex_lock(&local->mtx);
@ -1191,9 +1268,15 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
/* remove beacon and probe response */
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
RCU_INIT_POINTER(sdata->u.ap.fils_discovery, NULL);
RCU_INIT_POINTER(sdata->u.ap.unsol_bcast_probe_resp, NULL);
kfree_rcu(old_beacon, rcu_head);
if (old_probe_resp)
kfree_rcu(old_probe_resp, rcu_head);
if (old_fils_discovery)
kfree_rcu(old_fils_discovery, rcu_head);
if (old_unsol_bcast_probe_resp)
kfree_rcu(old_unsol_bcast_probe_resp, rcu_head);
kfree(sdata->vif.bss_conf.ftmr_params);
sdata->vif.bss_conf.ftmr_params = NULL;
@ -1696,6 +1779,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
__ieee80211_check_fast_rx_iface(vlansdata);
drv_sta_set_4addr(local, sta->sdata, &sta->sta, true);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&

View file

@ -408,6 +408,7 @@ static const char *hw_flag_names[] = {
FLAG(SUPPORTS_MULTI_BSSID),
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
FLAG(AMPDU_KEYBORDER_SUPPORT),
FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
#undef FLAG
};

View file

@ -1384,4 +1384,33 @@ static inline int drv_reset_tid_config(struct ieee80211_local *local,
return ret;
}
static inline void drv_update_vif_offload(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
might_sleep();
check_sdata_in_driver(sdata);
if (!local->ops->update_vif_offload)
return;
trace_drv_update_vif_offload(local, sdata);
local->ops->update_vif_offload(&local->hw, &sdata->vif);
trace_drv_return_void(local);
}
static inline void drv_sta_set_4addr(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta, bool enabled)
{
sdata = get_bss_sdata(sdata);
if (!check_sdata_in_driver(sdata))
return;
trace_drv_sta_set_4addr(local, sdata, sta, enabled);
if (local->ops->sta_set_4addr)
local->ops->sta_set_4addr(&local->hw, &sdata->vif, sta, enabled);
trace_drv_return_void(local);
}
#endif /* __MAC80211_DRIVER_OPS */

View file

@ -271,6 +271,18 @@ struct probe_resp {
u8 data[];
};
struct fils_discovery_data {
struct rcu_head rcu_head;
int len;
u8 data[];
};
struct unsol_bcast_probe_resp_data {
struct rcu_head rcu_head;
int len;
u8 data[];
};
struct ps_data {
/* yes, this looks ugly, but guarantees that we can later use
* bitmap_empty :)
@ -286,6 +298,8 @@ struct ps_data {
struct ieee80211_if_ap {
struct beacon_data __rcu *beacon;
struct probe_resp __rcu *probe_resp;
struct fils_discovery_data __rcu *fils_discovery;
struct unsol_bcast_probe_resp_data __rcu *unsol_bcast_probe_resp;
/* to be used after channel switch. */
struct cfg80211_beacon_data *next_beacon;
@ -989,8 +1003,6 @@ struct ieee80211_sub_if_data {
} debugfs;
#endif
bool hw_80211_encap;
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
};
@ -1767,6 +1779,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
bool update_bss);
void ieee80211_recalc_offload(struct ieee80211_local *local);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
{
@ -2040,8 +2053,6 @@ void ieee80211_dynamic_ps_timer(struct timer_list *t);
void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
bool powersave);
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr);
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr, bool ack, u16 tx_time);

File diff suppressed because it is too large Load diff

View file

@ -177,13 +177,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
}
}
/* TKIP countermeasures don't work in encap offload mode */
if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
sdata->hw_80211_encap) {
sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n");
return -EINVAL;
}
ret = drv_set_key(key->local, SET_KEY, sdata,
sta ? &sta->sta : NULL, &key->conf);
@ -219,14 +212,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
/* We cannot do software crypto of data frames with
* encapsulation offload enabled. However for 802.11w to
* function properly we need cmac/gmac keys.
*/
if (sdata->hw_80211_encap)
return -EINVAL;
fallthrough;
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:

View file

@ -212,7 +212,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
skb->priority = 7;
info->control.vif = &sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
ieee80211_set_qos_hdr(sdata, skb);
ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
}
@ -1163,7 +1163,7 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
skb_to_free = skb_dequeue(&mpath->frame_queue);
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
ieee80211_set_qos_hdr(sdata, skb);
skb_queue_tail(&mpath->frame_queue, skb);
if (skb_to_free)

View file

@ -432,7 +432,7 @@ static void mpsp_qos_null_append(struct sta_info *sta,
info = IEEE80211_SKB_CB(new_skb);
info->control.vif = &sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
__skb_queue_tail(frames, new_skb);
}

View file

@ -2432,23 +2432,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
}
void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr)
{
/*
* We can postpone the mgd.timer whenever receiving unicast frames
* from AP because we know that the connection is working both ways
* at that time. But multicast frames (and hence also beacons) must
* be ignored here, because we need to trigger the timer during
* data idle periods for sending the periodic probe request to the
* AP we're connected to.
*/
if (is_multicast_ether_addr(hdr->addr1))
return;
ieee80211_sta_reset_conn_monitor(sdata);
}
static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@ -2521,21 +2504,13 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
{
ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
if (!ieee80211_is_data(hdr->frame_control))
return;
if (ieee80211_is_any_nullfunc(hdr->frame_control) &&
sdata->u.mgd.probe_send_count > 0) {
if (ack)
ieee80211_sta_reset_conn_monitor(sdata);
else
sdata->u.mgd.nullfunc_failed = true;
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
if (!ieee80211_is_any_nullfunc(hdr->frame_control) ||
!sdata->u.mgd.probe_send_count)
return;
}
if (ack)
ieee80211_sta_reset_conn_monitor(sdata);
if (!ack)
sdata->u.mgd.nullfunc_failed = true;
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
@ -3548,6 +3523,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
goto out;
}
if (sdata->wdev.use_4addr)
drv_sta_set_4addr(local, sdata, &sta->sta, true);
mutex_unlock(&sdata->local->sta_mtx);
/*
@ -3605,8 +3583,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
* Start timer to probe the connection to the AP now.
* Also start the timer that will detect beacon loss.
*/
ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
ieee80211_sta_reset_beacon_monitor(sdata);
ieee80211_sta_reset_conn_monitor(sdata);
ret = true;
out:
@ -4577,10 +4555,26 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
from_timer(sdata, t, u.mgd.conn_mon_timer);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
unsigned long timeout;
if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return;
sta = sta_info_get(sdata, ifmgd->bssid);
if (!sta)
return;
timeout = sta->status_stats.last_ack;
if (time_before(sta->status_stats.last_ack, sta->rx_stats.last_rx))
timeout = sta->rx_stats.last_rx;
timeout += IEEE80211_CONNECTION_IDLE_TIME;
if (time_is_before_jiffies(timeout)) {
mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
return;
}
ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
}

View file

@ -1811,9 +1811,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->rx_stats.last_rate = sta_stats_encode_rate(status);
}
if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_sta_rx_notify(rx->sdata, hdr);
sta->rx_stats.fragments++;
u64_stats_update_begin(&rx->sta->rx_stats.syncp);
@ -2899,7 +2896,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->control.vif = &rx->sdata->vif;
info->control.jiffies = jiffies;
if (is_multicast_ether_addr(fwd_hdr->addr1)) {
@ -4148,7 +4145,6 @@ void ieee80211_check_fast_rx(struct sta_info *sta)
fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
fastrx.expected_ds_bits = 0;
} else {
fastrx.sta_notify = sdata->u.mgd.probe_send_count > 0;
fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
fastrx.expected_ds_bits =
@ -4378,11 +4374,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
pskb_trim(skb, skb->len - fast_rx->icv_len))
goto drop;
if (unlikely(fast_rx->sta_notify)) {
ieee80211_sta_rx_notify(rx->sdata, hdr);
fast_rx->sta_notify = false;
}
/* statistics part of ieee80211_rx_h_sta_process() */
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
stats->last_signal = status->signal;

View file

@ -336,7 +336,6 @@ struct ieee80211_fast_tx {
* @expected_ds_bits: from/to DS bits expected
* @icv_len: length of the MIC if present
* @key: bool indicating encryption is expected (key is set)
* @sta_notify: notify the MLME code (once)
* @internal_forward: forward froms internally on AP/VLAN type interfaces
* @uses_rss: copy of USES_RSS hw flag
* @da_offs: offset of the DA in the header (for header conversion)
@ -352,7 +351,6 @@ struct ieee80211_fast_rx {
__le16 expected_ds_bits;
u8 icv_len;
u8 key:1,
sta_notify:1,
internal_forward:1,
uses_rss:1;
u8 da_offs, sa_offs;

View file

@ -66,8 +66,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
info->control.jiffies = jiffies;
info->control.vif = &sta->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
IEEE80211_TX_INTFL_RETRANSMISSION;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->flags |= IEEE80211_TX_INTFL_RETRANSMISSION;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
sta->status_stats.filtered++;
@ -184,18 +184,6 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
struct ieee80211_mgmt *mgmt = (void *) skb->data;
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
sta->status_stats.last_ack = jiffies;
if (txinfo->status.is_valid_ack_signal) {
sta->status_stats.last_ack_signal =
(s8)txinfo->status.ack_signal;
sta->status_stats.ack_signal_filled = true;
ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
-txinfo->status.ack_signal);
}
}
if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *) skb->data;
@ -890,7 +878,8 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
}
static void __ieee80211_tx_status(struct ieee80211_hw *hw,
struct ieee80211_tx_status *status)
struct ieee80211_tx_status *status,
int rates_idx, int retry_count)
{
struct sk_buff *skb = status->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@ -899,17 +888,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
struct sta_info *sta;
__le16 fc;
struct ieee80211_supported_band *sband;
int retry_count;
int rates_idx;
bool send_to_cooked;
bool acked;
bool noack_success;
struct ieee80211_bar *bar;
int shift = 0;
int tid = IEEE80211_NUM_TIDS;
u16 tx_time_est;
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
sband = local->hw.wiphy->bands[info->band];
fc = hdr->frame_control;
@ -987,24 +971,14 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
ieee80211_handle_filtered_frame(local, sta, skb);
return;
} else {
} else if (ieee80211_is_data_present(fc)) {
if (!acked && !noack_success)
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
sta->status_stats.msdu_failed[tid]++;
if (ieee80211_is_data_present(fc)) {
if (!acked && !noack_success)
sta->status_stats.msdu_failed[tid]++;
sta->status_stats.msdu_retries[tid] +=
retry_count;
}
sta->status_stats.msdu_retries[tid] +=
retry_count;
}
rate_control_tx_status(local, sband, status);
if (ieee80211_vif_is_mesh(&sta->sdata->vif))
ieee80211s_update_metric(local, sta, status);
if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
ieee80211_frame_acked(sta, skb);
@ -1012,37 +986,6 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
acked, info->status.tx_time);
if (info->status.tx_time &&
wiphy_ext_feature_isset(local->hw.wiphy,
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
ieee80211_sta_register_airtime(&sta->sta, tid,
info->status.tx_time, 0);
if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
/* Do this here to avoid the expensive lookup of the sta
* in ieee80211_report_used_skb().
*/
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est,
true);
ieee80211_info_set_tx_time_est(info, 0);
}
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
if (acked) {
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
/* Track when last TDLS packet was ACKed */
sta->status_stats.last_pkt_time = jiffies;
} else if (noack_success) {
/* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}
}
}
/* SNMP counters
@ -1101,7 +1044,10 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
* with this test...
*/
if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
dev_kfree_skb(skb);
if (status->free_list)
list_add_tail(&skb->list, status->free_list);
else
dev_kfree_skb(skb);
return;
}
@ -1126,7 +1072,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
if (sta)
status.sta = &sta->sta;
__ieee80211_tx_status(hw, &status);
ieee80211_tx_status_ext(hw, &status);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_tx_status);
@ -1137,10 +1083,12 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_tx_info *info = status->info;
struct ieee80211_sta *pubsta = status->sta;
struct sk_buff *skb = status->skb;
struct ieee80211_supported_band *sband;
struct sta_info *sta;
int retry_count;
struct sta_info *sta = NULL;
int rates_idx, retry_count;
bool acked, noack_success;
u16 tx_time_est;
if (pubsta) {
sta = container_of(pubsta, struct sta_info, sta);
@ -1149,13 +1097,22 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
sta->tx_stats.last_rate_info = *status->rate;
}
if (status->skb)
return __ieee80211_tx_status(hw, status);
if (skb && (tx_time_est =
ieee80211_info_get_tx_time_est(IEEE80211_SKB_CB(skb))) > 0) {
/* Do this here to avoid the expensive lookup of the sta
* in ieee80211_report_used_skb().
*/
ieee80211_sta_update_pending_airtime(local, sta,
skb_get_queue_mapping(skb),
tx_time_est,
true);
ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0);
}
if (!status->sta)
return;
if (!status->info)
goto free;
ieee80211_tx_get_rates(hw, info, &retry_count);
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
sband = hw->wiphy->bands[info->band];
@ -1167,20 +1124,30 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
if (acked) {
sta->status_stats.last_ack = jiffies;
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
if (acked) {
sta->status_stats.last_ack = jiffies;
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
/* Track when last packet was ACKed */
sta->status_stats.last_pkt_time = jiffies;
} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
return;
} else if (noack_success) {
/* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
/* Track when last packet was ACKed */
sta->status_stats.last_pkt_time = jiffies;
if (info->status.is_valid_ack_signal) {
sta->status_stats.last_ack_signal =
(s8)info->status.ack_signal;
sta->status_stats.ack_signal_filled = true;
ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
-info->status.ack_signal);
}
} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
return;
} else if (noack_success) {
/* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}
}
rate_control_tx_status(local, sband, status);
@ -1188,6 +1155,10 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
ieee80211s_update_metric(local, sta, status);
}
if (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
return __ieee80211_tx_status(hw, status, rates_idx,
retry_count);
if (acked || noack_success) {
I802_DEBUG_INC(local->dot11TransmittedFrameCount);
if (!pubsta)
@ -1199,6 +1170,16 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
} else {
I802_DEBUG_INC(local->dot11FailedCount);
}
free:
if (!skb)
return;
ieee80211_report_used_skb(local, skb, false);
if (status->free_list)
list_add_tail(&skb->list, status->free_list);
else
dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status_ext);
@ -1225,69 +1206,23 @@ void ieee80211_tx_status_8023(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_status status = {
.skb = skb,
.info = IEEE80211_SKB_CB(skb),
};
struct sta_info *sta;
int retry_count;
int rates_idx;
bool acked;
sdata = vif_to_sdata(vif);
acked = info->flags & IEEE80211_TX_STAT_ACK;
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
rcu_read_lock();
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
goto counters_update;
if (!ieee80211_lookup_ra_sta(sdata, skb, &sta) && !IS_ERR(sta))
status.sta = &sta->sta;
if (IS_ERR(sta))
goto counters_update;
ieee80211_tx_status_ext(hw, &status);
if (!acked)
sta->status_stats.retry_failed++;
if (rates_idx != -1)
sta->tx_stats.last_rate = info->status.rates[rates_idx];
sta->status_stats.retry_count += retry_count;
if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
if (acked && vif->type == NL80211_IFTYPE_STATION)
ieee80211_sta_reset_conn_monitor(sdata);
sta->status_stats.last_ack = jiffies;
if (info->flags & IEEE80211_TX_STAT_ACK) {
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
sta->status_stats.last_pkt_time = jiffies;
} else {
ieee80211_lost_packet(sta, info);
}
}
counters_update:
rcu_read_unlock();
ieee80211_led_tx(local);
if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
goto skip_stats_update;
I802_DEBUG_INC(local->dot11TransmittedFrameCount);
if (is_multicast_ether_addr(skb->data))
I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
if (retry_count > 0)
I802_DEBUG_INC(local->dot11RetryCount);
if (retry_count > 1)
I802_DEBUG_INC(local->dot11MultipleRetryCount);
skip_stats_update:
ieee80211_report_used_skb(local, skb, false);
dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status_8023);

View file

@ -2734,6 +2734,39 @@ TRACE_EVENT(drv_get_ftm_responder_stats,
)
);
DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata),
TP_ARGS(local, sdata)
);
TRACE_EVENT(drv_sta_set_4addr,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *sta, bool enabled),
TP_ARGS(local, sdata, sta, enabled),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
STA_ENTRY
__field(bool, enabled)
),
TP_fast_assign(
LOCAL_ASSIGN;
VIF_ASSIGN;
STA_ASSIGN;
__entry->enabled = enabled;
),
TP_printk(
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " enabled:%d",
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->enabled
)
);
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH

View file

@ -531,7 +531,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->control.jiffies = jiffies;
info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
spin_unlock(&sta->ps_lock);
@ -1134,7 +1134,7 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
tx->sta->sta.addr, tx->sta->sta.aid);
}
info->control.vif = &tx->sdata->vif;
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
__skb_queue_tail(&tid_tx->pending, skb);
if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
@ -1179,7 +1179,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
* we are doing the needed processing, so remove the flag
* now.
*/
info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->control.flags &= ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
hdr = (struct ieee80211_hdr *) skb->data;
@ -1258,7 +1258,7 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
return NULL;
if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
if ((!ieee80211_is_mgmt(hdr->frame_control) ||
ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
@ -3649,7 +3649,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
else
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
goto encap_out;
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
@ -4190,38 +4190,18 @@ static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
struct net_device *dev, struct sta_info *sta,
struct sk_buff *skb)
struct ieee80211_key *key, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ethhdr *ehdr = (struct ethhdr *)skb->data;
struct ieee80211_local *local = sdata->local;
bool authorized = false;
bool multicast;
unsigned char *ra = ehdr->h_dest;
struct tid_ampdu_tx *tid_tx;
u8 tid;
if (IS_ERR(sta) || (sta && !sta->uploaded))
sta = NULL;
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
(!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER)))
ra = sdata->u.mgd.bssid;
if (is_zero_ether_addr(ra))
goto out_free;
multicast = is_multicast_ether_addr(ra);
if (sta)
authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
if (!multicast && !authorized &&
(ehdr->h_proto != sdata->control_port_protocol ||
!ether_addr_equal(sdata->vif.addr, ehdr->h_source)))
goto out_free;
if (multicast && sdata->vif.type == NL80211_IFTYPE_AP &&
!atomic_read(&sdata->u.ap.num_mcast_sta))
goto out_free;
if (local->ops->wake_tx_queue) {
u16 queue = __ieee80211_select_queue(sdata, sta, skb);
skb_set_queue_mapping(skb, queue);
skb_get_hash(skb);
}
if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
@ -4229,36 +4209,42 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
memset(info, 0, sizeof(*info));
if (unlikely(!multicast && skb->sk &&
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
if (tid_tx) {
if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
/* fall back to non-offload slow path */
__ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL);
return;
}
info->flags |= IEEE80211_TX_CTL_AMPDU;
if (tid_tx->timeout)
tid_tx->last_tx = jiffies;
}
if (unlikely(skb->sk &&
skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
&info->flags, NULL);
if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) {
if (sdata->control_port_no_encrypt)
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
}
if (multicast)
info->flags |= IEEE80211_TX_CTL_NO_ACK;
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
ieee80211_tx_stats(dev, skb->len);
if (sta) {
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
}
sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
info->control.vif = &sdata->vif;
if (key)
info->control.hw_key = &key->conf;
ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
return;
@ -4271,12 +4257,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ethhdr *ehdr = (struct ethhdr *)skb->data;
struct ieee80211_key *key;
struct sta_info *sta;
if (WARN_ON(!sdata->hw_80211_encap)) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
bool offload = true;
if (unlikely(skb->len < ETH_HLEN)) {
kfree_skb(skb);
@ -4285,11 +4269,26 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
rcu_read_lock();
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
kfree_skb(skb);
else
ieee80211_8023_xmit(sdata, dev, sta, skb);
goto out;
}
if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
!test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
sdata->control_port_protocol == ehdr->h_proto))
offload = false;
else if ((key = rcu_dereference(sta->ptk[sta->ptk_idx])) &&
(!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
offload = false;
if (offload)
ieee80211_8023_xmit(sdata, dev, sta, key, skb);
else
ieee80211_subif_start_xmit(skb, dev);
out:
rcu_read_unlock();
return NETDEV_TX_OK;
@ -4365,7 +4364,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
sdata = vif_to_sdata(info->control.vif);
if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) {
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (unlikely(!chanctx_conf)) {
dev_kfree_skb(skb);
@ -4373,7 +4372,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
}
info->band = chanctx_conf->def.chan->band;
result = ieee80211_tx(sdata, NULL, skb, true);
} else if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
} else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
dev_kfree_skb(skb);
return true;
@ -5000,6 +4999,63 @@ struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_proberesp_get);
struct sk_buff *ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct sk_buff *skb = NULL;
struct fils_discovery_data *tmpl = NULL;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
if (sdata->vif.type != NL80211_IFTYPE_AP)
return NULL;
rcu_read_lock();
tmpl = rcu_dereference(sdata->u.ap.fils_discovery);
if (!tmpl) {
rcu_read_unlock();
return NULL;
}
skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + tmpl->len);
if (skb) {
skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
skb_put_data(skb, tmpl->data, tmpl->len);
}
rcu_read_unlock();
return skb;
}
EXPORT_SYMBOL(ieee80211_get_fils_discovery_tmpl);
struct sk_buff *
ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct sk_buff *skb = NULL;
struct unsol_bcast_probe_resp_data *tmpl = NULL;
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
if (sdata->vif.type != NL80211_IFTYPE_AP)
return NULL;
rcu_read_lock();
tmpl = rcu_dereference(sdata->u.ap.unsol_bcast_probe_resp);
if (!tmpl) {
rcu_read_unlock();
return NULL;
}
skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + tmpl->len);
if (skb) {
skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
skb_put_data(skb, tmpl->data, tmpl->len);
}
rcu_read_unlock();
return skb;
}
EXPORT_SYMBOL(ieee80211_get_unsol_bcast_probe_resp_tmpl);
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{

View file

@ -315,10 +315,6 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
/* If HT IE reported 3839 bytes only, stay with that size. */
if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839)
return;
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;

View file

@ -141,9 +141,62 @@ static bool cfg80211_edmg_chandef_valid(const struct cfg80211_chan_def *chandef)
return true;
}
static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
{
int mhz;
switch (chan_width) {
case NL80211_CHAN_WIDTH_1:
mhz = 1;
break;
case NL80211_CHAN_WIDTH_2:
mhz = 2;
break;
case NL80211_CHAN_WIDTH_4:
mhz = 4;
break;
case NL80211_CHAN_WIDTH_8:
mhz = 8;
break;
case NL80211_CHAN_WIDTH_16:
mhz = 16;
break;
case NL80211_CHAN_WIDTH_5:
mhz = 5;
break;
case NL80211_CHAN_WIDTH_10:
mhz = 10;
break;
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
mhz = 20;
break;
case NL80211_CHAN_WIDTH_40:
mhz = 40;
break;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
mhz = 80;
break;
case NL80211_CHAN_WIDTH_160:
mhz = 160;
break;
default:
WARN_ON_ONCE(1);
return -1;
}
return mhz;
}
static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
{
return nl80211_chan_width_to_mhz(c->width);
}
bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
{
u32 control_freq;
u32 control_freq, oper_freq;
int oper_width, control_width;
if (!chandef->chan)
return false;
@ -155,10 +208,6 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
switch (chandef->width) {
case NL80211_CHAN_WIDTH_1:
case NL80211_CHAN_WIDTH_2:
case NL80211_CHAN_WIDTH_4:
case NL80211_CHAN_WIDTH_8:
case NL80211_CHAN_WIDTH_16:
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
@ -169,6 +218,30 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
if (chandef->center_freq2)
return false;
break;
case NL80211_CHAN_WIDTH_2:
case NL80211_CHAN_WIDTH_4:
case NL80211_CHAN_WIDTH_8:
case NL80211_CHAN_WIDTH_16:
control_freq = ieee80211_channel_to_khz(chandef->chan);
oper_freq = ieee80211_chandef_to_khz(chandef);
control_width = nl80211_chan_width_to_mhz(
ieee80211_s1g_channel_width(
chandef->chan));
oper_width = cfg80211_chandef_get_width(chandef);
if (oper_width < 0 || control_width < 0)
return false;
if (chandef->center_freq2)
return false;
if (control_freq + MHZ_TO_KHZ(control_width) / 2 >
oper_freq + MHZ_TO_KHZ(oper_width) / 2)
return false;
if (control_freq - MHZ_TO_KHZ(control_width) / 2 <
oper_freq - MHZ_TO_KHZ(oper_width) / 2)
return false;
break;
case NL80211_CHAN_WIDTH_40:
if (chandef->center_freq1 != control_freq + 10 &&
chandef->center_freq1 != control_freq - 10)
@ -264,53 +337,6 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
}
}
static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
{
int width;
switch (c->width) {
case NL80211_CHAN_WIDTH_1:
width = 1;
break;
case NL80211_CHAN_WIDTH_2:
width = 2;
break;
case NL80211_CHAN_WIDTH_4:
width = 4;
break;
case NL80211_CHAN_WIDTH_8:
width = 8;
break;
case NL80211_CHAN_WIDTH_16:
width = 16;
break;
case NL80211_CHAN_WIDTH_5:
width = 5;
break;
case NL80211_CHAN_WIDTH_10:
width = 10;
break;
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
width = 20;
break;
case NL80211_CHAN_WIDTH_40:
width = 40;
break;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
width = 80;
break;
case NL80211_CHAN_WIDTH_160:
width = 160;
break;
default:
WARN_ON_ONCE(1);
return -1;
}
return width;
}
const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
const struct cfg80211_chan_def *c2)

View file

@ -26,8 +26,6 @@
#include <net/lib80211.h>
#define DRV_NAME "lib80211"
#define DRV_DESCRIPTION "common routines for IEEE802.11 drivers"
MODULE_DESCRIPTION(DRV_DESCRIPTION);

View file

@ -209,14 +209,23 @@ static int validate_beacon_head(const struct nlattr *attr,
unsigned int len = nla_len(attr);
const struct element *elem;
const struct ieee80211_mgmt *mgmt = (void *)data;
unsigned int fixedlen = offsetof(struct ieee80211_mgmt,
u.beacon.variable);
bool s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
unsigned int fixedlen, hdrlen;
if (s1g_bcn) {
fixedlen = offsetof(struct ieee80211_ext,
u.s1g_beacon.variable);
hdrlen = offsetof(struct ieee80211_ext, u.s1g_beacon);
} else {
fixedlen = offsetof(struct ieee80211_mgmt,
u.beacon.variable);
hdrlen = offsetof(struct ieee80211_mgmt, u.beacon);
}
if (len < fixedlen)
goto err;
if (ieee80211_hdrlen(mgmt->frame_control) !=
offsetof(struct ieee80211_mgmt, u.beacon))
if (ieee80211_hdrlen(mgmt->frame_control) != hdrlen)
goto err;
data += fixedlen;
@ -367,6 +376,22 @@ nl80211_tid_config_attr_policy[NL80211_TID_CONFIG_ATTR_MAX + 1] = {
NLA_POLICY_NESTED(nl80211_txattr_policy),
};
static const struct nla_policy
nl80211_fils_discovery_policy[NL80211_FILS_DISCOVERY_ATTR_MAX + 1] = {
[NL80211_FILS_DISCOVERY_ATTR_INT_MIN] = NLA_POLICY_MAX(NLA_U32, 10000),
[NL80211_FILS_DISCOVERY_ATTR_INT_MAX] = NLA_POLICY_MAX(NLA_U32, 10000),
NLA_POLICY_RANGE(NLA_BINARY,
NL80211_FILS_DISCOVERY_TMPL_MIN_LEN,
IEEE80211_MAX_DATA_LEN),
};
static const struct nla_policy
nl80211_unsol_bcast_probe_resp_policy[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX + 1] = {
[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] = NLA_POLICY_MAX(NLA_U32, 20),
[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN }
};
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
@ -675,6 +700,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_SCAN_FREQ_KHZ] = { .type = NLA_NESTED },
[NL80211_ATTR_HE_6GHZ_CAPABILITY] =
NLA_POLICY_EXACT_LEN(sizeof(struct ieee80211_he_6ghz_capa)),
[NL80211_ATTR_FILS_DISCOVERY] =
NLA_POLICY_NESTED(nl80211_fils_discovery_policy),
[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP] =
NLA_POLICY_NESTED(nl80211_unsol_bcast_probe_resp_policy),
};
/* policy for the key attributes */
@ -1010,6 +1039,21 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
if ((chan->flags & IEEE80211_CHAN_NO_HE) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HE))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_1MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_1MHZ))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_2MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_2MHZ))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_4MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_4MHZ))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_8MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_8MHZ))
goto nla_put_failure;
if ((chan->flags & IEEE80211_CHAN_16MHZ) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_16MHZ))
goto nla_put_failure;
}
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
@ -4850,6 +4894,65 @@ static int nl80211_parse_he_bss_color(struct nlattr *attrs,
return 0;
}
static int nl80211_parse_fils_discovery(struct cfg80211_registered_device *rdev,
struct nlattr *attrs,
struct cfg80211_ap_settings *params)
{
struct nlattr *tb[NL80211_FILS_DISCOVERY_ATTR_MAX + 1];
int ret;
struct cfg80211_fils_discovery *fd = &params->fils_discovery;
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_FILS_DISCOVERY))
return -EINVAL;
ret = nla_parse_nested(tb, NL80211_FILS_DISCOVERY_ATTR_MAX, attrs,
NULL, NULL);
if (ret)
return ret;
if (!tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN] ||
!tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX] ||
!tb[NL80211_FILS_DISCOVERY_ATTR_TMPL])
return -EINVAL;
fd->tmpl_len = nla_len(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
fd->tmpl = nla_data(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
fd->min_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN]);
fd->max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]);
return 0;
}
static int
nl80211_parse_unsol_bcast_probe_resp(struct cfg80211_registered_device *rdev,
struct nlattr *attrs,
struct cfg80211_ap_settings *params)
{
struct nlattr *tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX + 1];
int ret;
struct cfg80211_unsol_bcast_probe_resp *presp =
&params->unsol_bcast_probe_resp;
if (!wiphy_ext_feature_isset(&rdev->wiphy,
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP))
return -EINVAL;
ret = nla_parse_nested(tb, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX,
attrs, NULL, NULL);
if (ret)
return ret;
if (!tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] ||
!tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL])
return -EINVAL;
presp->tmpl = nla_data(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]);
presp->tmpl_len = nla_len(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL]);
presp->interval = nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT]);
return 0;
}
static void nl80211_check_ap_rate_selectors(struct cfg80211_ap_settings *params,
const u8 *rates)
{
@ -5158,6 +5261,22 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
goto out;
}
if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
err = nl80211_parse_fils_discovery(rdev,
info->attrs[NL80211_ATTR_FILS_DISCOVERY],
&params);
if (err)
goto out;
}
if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
err = nl80211_parse_unsol_bcast_probe_resp(
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
&params);
if (err)
return err;
}
nl80211_calculate_ap_params(&params);
if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])

View file

@ -1617,9 +1617,11 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
{
const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
const struct ieee80211_reg_rule *reg_rule = NULL;
const u32 bws[] = {0, 1, 2, 4, 5, 8, 10, 16, 20};
int i = ARRAY_SIZE(bws) - 1;
u32 bw;
for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) {
for (bw = MHZ_TO_KHZ(bws[i]); bw >= min_bw; bw = MHZ_TO_KHZ(bws[i--])) {
reg_rule = freq_reg_info_regd(center_freq, regd, bw);
if (!IS_ERR(reg_rule))
return reg_rule;
@ -1631,7 +1633,9 @@ __freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy,
u32 center_freq)
{
return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(20));
u32 min_bw = center_freq < MHZ_TO_KHZ(1000) ? 1 : 20;
return __freq_reg_info(wiphy, center_freq, MHZ_TO_KHZ(min_bw));
}
EXPORT_SYMBOL(freq_reg_info);
@ -1659,6 +1663,7 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
{
const struct ieee80211_freq_range *freq_range = NULL;
u32 max_bandwidth_khz, center_freq_khz, bw_flags = 0;
bool is_s1g = chan->band == NL80211_BAND_S1GHZ;
freq_range = &reg_rule->freq_range;
@ -1678,16 +1683,57 @@ static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd
MHZ_TO_KHZ(20)))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags |= IEEE80211_CHAN_NO_HT40;
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
bw_flags |= IEEE80211_CHAN_NO_160MHZ;
if (is_s1g) {
/* S1G is strict about non overlapping channels. We can
* calculate which bandwidth is allowed per channel by finding
* the largest bandwidth which cleanly divides the freq_range.
*/
int edge_offset;
int ch_bw = max_bandwidth_khz;
while (ch_bw) {
edge_offset = (center_freq_khz - ch_bw / 2) -
freq_range->start_freq_khz;
if (edge_offset % ch_bw == 0) {
switch (KHZ_TO_MHZ(ch_bw)) {
case 1:
bw_flags |= IEEE80211_CHAN_1MHZ;
break;
case 2:
bw_flags |= IEEE80211_CHAN_2MHZ;
break;
case 4:
bw_flags |= IEEE80211_CHAN_4MHZ;
break;
case 8:
bw_flags |= IEEE80211_CHAN_8MHZ;
break;
case 16:
bw_flags |= IEEE80211_CHAN_16MHZ;
break;
default:
/* If we got here, no bandwidths fit on
* this frequency, ie. band edge.
*/
bw_flags |= IEEE80211_CHAN_DISABLED;
break;
}
break;
}
ch_bw /= 2;
}
} else {
if (max_bandwidth_khz < MHZ_TO_KHZ(10))
bw_flags |= IEEE80211_CHAN_NO_10MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(20))
bw_flags |= IEEE80211_CHAN_NO_20MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(40))
bw_flags |= IEEE80211_CHAN_NO_HT40;
if (max_bandwidth_khz < MHZ_TO_KHZ(80))
bw_flags |= IEEE80211_CHAN_NO_80MHZ;
if (max_bandwidth_khz < MHZ_TO_KHZ(160))
bw_flags |= IEEE80211_CHAN_NO_160MHZ;
}
return bw_flags;
}

View file

@ -111,6 +111,33 @@ u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
}
EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
enum nl80211_chan_width
ieee80211_s1g_channel_width(const struct ieee80211_channel *chan)
{
if (WARN_ON(!chan || chan->band != NL80211_BAND_S1GHZ))
return NL80211_CHAN_WIDTH_20_NOHT;
/*S1G defines a single allowed channel width per channel.
* Extract that width here.
*/
if (chan->flags & IEEE80211_CHAN_1MHZ)
return NL80211_CHAN_WIDTH_1;
else if (chan->flags & IEEE80211_CHAN_2MHZ)
return NL80211_CHAN_WIDTH_2;
else if (chan->flags & IEEE80211_CHAN_4MHZ)
return NL80211_CHAN_WIDTH_4;
else if (chan->flags & IEEE80211_CHAN_8MHZ)
return NL80211_CHAN_WIDTH_8;
else if (chan->flags & IEEE80211_CHAN_16MHZ)
return NL80211_CHAN_WIDTH_16;
pr_err("unknown channel width for channel at %dKHz?\n",
ieee80211_channel_to_khz(chan));
return NL80211_CHAN_WIDTH_1;
}
EXPORT_SYMBOL(ieee80211_s1g_channel_width);
int ieee80211_freq_khz_to_channel(u32 freq)
{
/* TODO: just handle MHz for now */
@ -399,6 +426,11 @@ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
{
unsigned int hdrlen = 24;
if (ieee80211_is_ext(fc)) {
hdrlen = 4;
goto out;
}
if (ieee80211_is_data(fc)) {
if (ieee80211_has_a4(fc))
hdrlen = 30;