forked from Minki/linux
A few more things:
* Use correct DFS domain for self-managed devices * some preparations for transmit power element handling and other 6 GHz regulatory handling * TWT support in AP mode in mac80211 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH1e1rEeCd0AIMq6MB8qZga/fl8QFAmEnWbwACgkQB8qZga/f l8QfOQ/+LwZsbYDxvbluoQPBviIPey1s5PqLyVpCDA1XZI0G8G9FmZ33J1Ao3b4A /MCFB05rL7Pv8h9Rpx5Nd6ZdMrq4+rF0qYHJrNQnYlfxeb/z0CJCZGDaTQOcSDLc HPTQRU2hd5+ZInxgnefbD84nJ8Bpdd6cRTKS06xPxY2+1k6dPSHQ/OjLdmur5IlN gLSfyiPY6ryVWbNanzbIlKcisw6RxuagFjqzbay/JVycKNx0x2hWnoF7Ad/AHdkK P7l60CiMyTyibU7VfQ1NnGm3WK55Df32fDVVKtflFRi3fY08p8zRNKZdD4XD+4KD ptqwd173qiV+WjZaEr6YoHFirCcheFibc8/Z3iYS6LwD+w1isMoZPa8rRFoXnPkS xMlJAvAgcMBHUBOfeS8Ymo0qZvIvo36933S81g64Bl5IPbhfin2Vybs8jT0xLEPP LMDqWv+jcQ5ONc+RAjQ23c8I3mTdDPTZ+F8lzXkzhTBdcfWkXQWxMbLN/CU5RX8t hGTtTTlHC1cqgSQLT42WrPPDgbxzAqAcLTTvRwnu0TLvJcTc6NDcfoBXkXjiLOij g+GiPOXG36qy+cKTwzvSASkKqP71nQOdO74VHyftzMGHqvaEz2NzSVPNWk/3Nwpo 7MuQvfE0cQAvTdmt9fTlelm61CyKLl16aKV1IjA6/Ob9Nr/haUw= =2Ucp -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-net-next-2021-08-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== A few more things: * Use correct DFS domain for self-managed devices * some preparations for transmit power element handling and other 6 GHz regulatory handling * TWT support in AP mode in mac80211 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
8b325d2a09
@ -1088,6 +1088,48 @@ struct ieee80211_ext {
|
||||
} u;
|
||||
} __packed __aligned(2);
|
||||
|
||||
#define IEEE80211_TWT_CONTROL_NDP BIT(0)
|
||||
#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1)
|
||||
#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3)
|
||||
#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4)
|
||||
#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5)
|
||||
|
||||
#define IEEE80211_TWT_REQTYPE_REQUEST BIT(0)
|
||||
#define IEEE80211_TWT_REQTYPE_SETUP_CMD GENMASK(3, 1)
|
||||
#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4)
|
||||
#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5)
|
||||
#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6)
|
||||
#define IEEE80211_TWT_REQTYPE_FLOWID GENMASK(9, 7)
|
||||
#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP GENMASK(14, 10)
|
||||
#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15)
|
||||
|
||||
enum ieee80211_twt_setup_cmd {
|
||||
TWT_SETUP_CMD_REQUEST,
|
||||
TWT_SETUP_CMD_SUGGEST,
|
||||
TWT_SETUP_CMD_DEMAND,
|
||||
TWT_SETUP_CMD_GROUPING,
|
||||
TWT_SETUP_CMD_ACCEPT,
|
||||
TWT_SETUP_CMD_ALTERNATE,
|
||||
TWT_SETUP_CMD_DICTATE,
|
||||
TWT_SETUP_CMD_REJECT,
|
||||
};
|
||||
|
||||
struct ieee80211_twt_params {
|
||||
__le16 req_type;
|
||||
__le64 twt;
|
||||
u8 min_twt_dur;
|
||||
__le16 mantissa;
|
||||
u8 channel;
|
||||
} __packed;
|
||||
|
||||
struct ieee80211_twt_setup {
|
||||
u8 dialog_token;
|
||||
u8 element_id;
|
||||
u8 length;
|
||||
u8 control;
|
||||
u8 params[];
|
||||
} __packed;
|
||||
|
||||
struct ieee80211_mgmt {
|
||||
__le16 frame_control;
|
||||
__le16 duration;
|
||||
@ -1252,6 +1294,10 @@ struct ieee80211_mgmt {
|
||||
__le16 toa_error;
|
||||
u8 variable[0];
|
||||
} __packed ftm;
|
||||
struct {
|
||||
u8 action_code;
|
||||
u8 variable[];
|
||||
} __packed s1g;
|
||||
} u;
|
||||
} __packed action;
|
||||
} u;
|
||||
@ -2266,6 +2312,9 @@ ieee80211_he_ppe_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
|
||||
#define IEEE80211_HE_OPERATION_PARTIAL_BSS_COLOR 0x40000000
|
||||
#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x80000000
|
||||
|
||||
#define IEEE80211_6GHZ_CTRL_REG_LPI_AP 0
|
||||
#define IEEE80211_6GHZ_CTRL_REG_SP_AP 1
|
||||
|
||||
/**
|
||||
* ieee80211_he_6ghz_oper - HE 6 GHz operation Information field
|
||||
* @primary: primary channel
|
||||
@ -2282,12 +2331,51 @@ struct ieee80211_he_6ghz_oper {
|
||||
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ 2
|
||||
#define IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ 3
|
||||
#define IEEE80211_HE_6GHZ_OPER_CTRL_DUP_BEACON 0x4
|
||||
#define IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO 0x38
|
||||
u8 control;
|
||||
u8 ccfs0;
|
||||
u8 ccfs1;
|
||||
u8 minrate;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* In "9.4.2.161 Transmit Power Envelope element" of "IEEE Std 802.11ax-2021",
|
||||
* it show four types in "Table 9-275a-Maximum Transmit Power Interpretation
|
||||
* subfield encoding", and two category for each type in "Table E-12-Regulatory
|
||||
* Info subfield encoding in the United States".
|
||||
* So it it totally max 8 Transmit Power Envelope element.
|
||||
*/
|
||||
#define IEEE80211_TPE_MAX_IE_COUNT 8
|
||||
/*
|
||||
* In "Table 9-277—Meaning of Maximum Transmit Power Count subfield"
|
||||
* of "IEEE Std 802.11ax™‐2021", the max power level is 8.
|
||||
*/
|
||||
#define IEEE80211_MAX_NUM_PWR_LEVEL 8
|
||||
|
||||
#define IEEE80211_TPE_MAX_POWER_COUNT 8
|
||||
|
||||
/* transmit power interpretation type of transmit power envelope element */
|
||||
enum ieee80211_tx_power_intrpt_type {
|
||||
IEEE80211_TPE_LOCAL_EIRP,
|
||||
IEEE80211_TPE_LOCAL_EIRP_PSD,
|
||||
IEEE80211_TPE_REG_CLIENT_EIRP,
|
||||
IEEE80211_TPE_REG_CLIENT_EIRP_PSD,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ieee80211_tx_pwr_env
|
||||
*
|
||||
* This structure represents the "Transmit Power Envelope element"
|
||||
*/
|
||||
struct ieee80211_tx_pwr_env {
|
||||
u8 tx_power_info;
|
||||
s8 tx_power[IEEE80211_TPE_MAX_POWER_COUNT];
|
||||
} __packed;
|
||||
|
||||
#define IEEE80211_TX_PWR_ENV_INFO_COUNT 0x7
|
||||
#define IEEE80211_TX_PWR_ENV_INFO_INTERPRET 0x38
|
||||
#define IEEE80211_TX_PWR_ENV_INFO_CATEGORY 0xC0
|
||||
|
||||
/*
|
||||
* ieee80211_he_oper_size - calculate 802.11ax HE Operations IE size
|
||||
* @he_oper_ie: byte data of the He Operations IE, stating from the byte
|
||||
@ -2869,7 +2957,7 @@ enum ieee80211_eid {
|
||||
WLAN_EID_VHT_OPERATION = 192,
|
||||
WLAN_EID_EXTENDED_BSS_LOAD = 193,
|
||||
WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194,
|
||||
WLAN_EID_VHT_TX_POWER_ENVELOPE = 195,
|
||||
WLAN_EID_TX_POWER_ENVELOPE = 195,
|
||||
WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196,
|
||||
WLAN_EID_AID = 197,
|
||||
WLAN_EID_QUIET_CHANNEL = 198,
|
||||
@ -2881,6 +2969,7 @@ enum ieee80211_eid {
|
||||
WLAN_EID_AID_RESPONSE = 211,
|
||||
WLAN_EID_S1G_BCN_COMPAT = 213,
|
||||
WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214,
|
||||
WLAN_EID_S1G_TWT = 216,
|
||||
WLAN_EID_S1G_CAPABILITIES = 217,
|
||||
WLAN_EID_VENDOR_SPECIFIC = 221,
|
||||
WLAN_EID_QOS_PARAMETER = 222,
|
||||
@ -2950,6 +3039,7 @@ enum ieee80211_category {
|
||||
WLAN_CATEGORY_FST = 18,
|
||||
WLAN_CATEGORY_UNPROT_DMG = 20,
|
||||
WLAN_CATEGORY_VHT = 21,
|
||||
WLAN_CATEGORY_S1G = 22,
|
||||
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
|
||||
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
|
||||
};
|
||||
@ -3023,6 +3113,20 @@ enum ieee80211_key_len {
|
||||
WLAN_KEY_LEN_BIP_GMAC_256 = 32,
|
||||
};
|
||||
|
||||
enum ieee80211_s1g_actioncode {
|
||||
WLAN_S1G_AID_SWITCH_REQUEST,
|
||||
WLAN_S1G_AID_SWITCH_RESPONSE,
|
||||
WLAN_S1G_SYNC_CONTROL,
|
||||
WLAN_S1G_STA_INFO_ANNOUNCE,
|
||||
WLAN_S1G_EDCA_PARAM_SET,
|
||||
WLAN_S1G_EL_OPERATION,
|
||||
WLAN_S1G_TWT_SETUP,
|
||||
WLAN_S1G_TWT_TEARDOWN,
|
||||
WLAN_S1G_SECT_GROUP_ID_LIST,
|
||||
WLAN_S1G_SECT_ID_FEEDBACK,
|
||||
WLAN_S1G_TWT_INFORMATION = 11,
|
||||
};
|
||||
|
||||
#define IEEE80211_WEP_IV_LEN 4
|
||||
#define IEEE80211_WEP_ICV_LEN 4
|
||||
#define IEEE80211_CCMP_HDR_LEN 8
|
||||
|
@ -3926,6 +3926,13 @@ struct ieee80211_prep_tx_info {
|
||||
* @set_sar_specs: Update the SAR (TX power) settings.
|
||||
* @sta_set_decap_offload: Called to notify the driver when a station is allowed
|
||||
* to use rx decapsulation offload
|
||||
* @add_twt_setup: Update hw with TWT agreement parameters received from the peer.
|
||||
* This callback allows the hw to check if requested parameters
|
||||
* are supported and if there is enough room for a new agreement.
|
||||
* The hw is expected to set agreement result in the req_type field of
|
||||
* twt structure.
|
||||
* @twt_teardown_request: Update the hw with TWT teardown request received
|
||||
* from the peer.
|
||||
*/
|
||||
struct ieee80211_ops {
|
||||
void (*tx)(struct ieee80211_hw *hw,
|
||||
@ -4249,6 +4256,11 @@ struct ieee80211_ops {
|
||||
void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, bool enabled);
|
||||
void (*add_twt_setup)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_twt_setup *twt);
|
||||
void (*twt_teardown_request)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta, u8 flowid);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1447,4 +1447,40 @@ static inline void drv_sta_set_decap_offload(struct ieee80211_local *local,
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline void drv_add_twt_setup(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_twt_setup *twt)
|
||||
{
|
||||
struct ieee80211_twt_params *twt_agrt;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
twt_agrt = (void *)twt->params;
|
||||
|
||||
trace_drv_add_twt_setup(local, sta, twt, twt_agrt);
|
||||
local->ops->add_twt_setup(&local->hw, sta, twt);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
static inline void drv_twt_teardown_request(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sta *sta,
|
||||
u8 flowid)
|
||||
{
|
||||
might_sleep();
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
||||
if (!local->ops->twt_teardown_request)
|
||||
return;
|
||||
|
||||
trace_drv_twt_teardown_request(local, sta, flowid);
|
||||
local->ops->twt_teardown_request(&local->hw, sta, flowid);
|
||||
trace_drv_return_void(local);
|
||||
}
|
||||
|
||||
#endif /* __MAC80211_DRIVER_OPS */
|
||||
|
@ -946,6 +946,7 @@ struct ieee80211_sub_if_data {
|
||||
|
||||
struct work_struct work;
|
||||
struct sk_buff_head skb_queue;
|
||||
struct sk_buff_head status_queue;
|
||||
|
||||
u8 needed_rx_chains;
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
@ -1533,6 +1534,7 @@ struct ieee802_11_elems {
|
||||
const struct ieee80211_he_spr *he_spr;
|
||||
const struct ieee80211_mu_edca_param_set *mu_edca_param_set;
|
||||
const struct ieee80211_he_6ghz_capa *he_6ghz_capa;
|
||||
const struct ieee80211_tx_pwr_env *tx_pwr_env[IEEE80211_TPE_MAX_IE_COUNT];
|
||||
const u8 *uora_element;
|
||||
const u8 *mesh_id;
|
||||
const u8 *peering;
|
||||
@ -1583,6 +1585,8 @@ struct ieee802_11_elems {
|
||||
u8 perr_len;
|
||||
u8 country_elem_len;
|
||||
u8 bssid_index_len;
|
||||
u8 tx_pwr_env_len[IEEE80211_TPE_MAX_IE_COUNT];
|
||||
u8 tx_pwr_env_num;
|
||||
|
||||
/* whether a parse error occurred while retrieving these elements */
|
||||
bool parse_error;
|
||||
@ -2080,6 +2084,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
|
||||
|
||||
/* S1G */
|
||||
void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
|
||||
bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb);
|
||||
void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb);
|
||||
|
||||
/* Spectrum management */
|
||||
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -552,6 +552,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
||||
*/
|
||||
ieee80211_free_keys(sdata, true);
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
skb_queue_purge(&sdata->status_queue);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
@ -984,6 +985,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
}
|
||||
|
||||
skb_queue_head_init(&sdata->skb_queue);
|
||||
skb_queue_head_init(&sdata->status_queue);
|
||||
INIT_WORK(&sdata->work, ieee80211_iface_work);
|
||||
|
||||
return 0;
|
||||
@ -1382,6 +1384,16 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
} else if (ieee80211_is_action(mgmt->frame_control) &&
|
||||
mgmt->u.action.category == WLAN_CATEGORY_S1G) {
|
||||
switch (mgmt->u.action.u.s1g.action_code) {
|
||||
case WLAN_S1G_TWT_TEARDOWN:
|
||||
case WLAN_S1G_TWT_SETUP:
|
||||
ieee80211_s1g_rx_twt_action(sdata, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ieee80211_is_ext(mgmt->frame_control)) {
|
||||
if (sdata->vif.type == NL80211_IFTYPE_STATION)
|
||||
ieee80211_sta_rx_queued_ext(sdata, skb);
|
||||
@ -1437,6 +1449,24 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||
|
||||
if (ieee80211_is_action(mgmt->frame_control) &&
|
||||
mgmt->u.action.category == WLAN_CATEGORY_S1G) {
|
||||
switch (mgmt->u.action.u.s1g.action_code) {
|
||||
case WLAN_S1G_TWT_TEARDOWN:
|
||||
case WLAN_S1G_TWT_SETUP:
|
||||
ieee80211_s1g_status_twt_action(sdata, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ieee80211_iface_work(struct work_struct *work)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
@ -1466,6 +1496,16 @@ static void ieee80211_iface_work(struct work_struct *work)
|
||||
kcov_remote_stop();
|
||||
}
|
||||
|
||||
/* process status queue */
|
||||
while ((skb = skb_dequeue(&sdata->status_queue))) {
|
||||
kcov_remote_start_common(skb_get_kcov_handle(skb));
|
||||
|
||||
ieee80211_iface_process_status(sdata, skb);
|
||||
kfree_skb(skb);
|
||||
|
||||
kcov_remote_stop();
|
||||
}
|
||||
|
||||
/* then other type-dependent work */
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@ -1529,6 +1569,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
skb_queue_head_init(&sdata->skb_queue);
|
||||
skb_queue_head_init(&sdata->status_queue);
|
||||
INIT_WORK(&sdata->work, ieee80211_iface_work);
|
||||
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
|
||||
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
|
||||
|
@ -3212,6 +3212,68 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
|
||||
return RX_CONTINUE;
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
|
||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
const struct ieee80211_sta_he_cap *hecap;
|
||||
struct ieee80211_supported_band *sband;
|
||||
|
||||
/* TWT actions are only supported in AP for the moment */
|
||||
if (sdata->vif.type != NL80211_IFTYPE_AP)
|
||||
return false;
|
||||
|
||||
if (!rx->local->ops->add_twt_setup)
|
||||
return false;
|
||||
|
||||
sband = rx->local->hw.wiphy->bands[status->band];
|
||||
hecap = ieee80211_get_he_iftype_cap(sband,
|
||||
ieee80211_vif_type_p2p(&sdata->vif));
|
||||
if (!hecap)
|
||||
return false;
|
||||
|
||||
if (!(hecap->he_cap_elem.mac_cap_info[0] &
|
||||
IEEE80211_HE_MAC_CAP0_TWT_RES))
|
||||
return false;
|
||||
|
||||
if (!rx->sta)
|
||||
return false;
|
||||
|
||||
switch (mgmt->u.action.u.s1g.action_code) {
|
||||
case WLAN_S1G_TWT_SETUP: {
|
||||
struct ieee80211_twt_setup *twt;
|
||||
|
||||
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
|
||||
1 + /* action code */
|
||||
sizeof(struct ieee80211_twt_setup) +
|
||||
2 /* TWT req_type agrt */)
|
||||
break;
|
||||
|
||||
twt = (void *)mgmt->u.action.u.s1g.variable;
|
||||
if (twt->element_id != WLAN_EID_S1G_TWT)
|
||||
break;
|
||||
|
||||
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
|
||||
4 + /* action code + token + tlv */
|
||||
twt->length)
|
||||
break;
|
||||
|
||||
return true; /* queue the frame */
|
||||
}
|
||||
case WLAN_S1G_TWT_TEARDOWN:
|
||||
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
|
||||
break;
|
||||
|
||||
return true; /* queue the frame */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static ieee80211_rx_result debug_noinline
|
||||
ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
{
|
||||
@ -3491,6 +3553,17 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
!mesh_path_sel_is_hwmp(sdata))
|
||||
break;
|
||||
goto queue;
|
||||
case WLAN_CATEGORY_S1G:
|
||||
switch (mgmt->u.action.u.s1g.action_code) {
|
||||
case WLAN_S1G_TWT_SETUP:
|
||||
case WLAN_S1G_TWT_TEARDOWN:
|
||||
if (ieee80211_process_rx_twt_action(rx))
|
||||
goto queue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return RX_CONTINUE;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include "ieee80211_i.h"
|
||||
#include "driver-ops.h"
|
||||
|
||||
void ieee80211_s1g_sta_rate_init(struct sta_info *sta)
|
||||
{
|
||||
@ -14,3 +15,182 @@ void ieee80211_s1g_sta_rate_init(struct sta_info *sta)
|
||||
sta->rx_stats.last_rate =
|
||||
STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G);
|
||||
}
|
||||
|
||||
bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
|
||||
if (likely(!ieee80211_is_action(mgmt->frame_control)))
|
||||
return false;
|
||||
|
||||
if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G))
|
||||
return false;
|
||||
|
||||
return mgmt->u.action.u.s1g.action_code == WLAN_S1G_TWT_SETUP;
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da,
|
||||
const u8 *bssid, struct ieee80211_twt_setup *twt)
|
||||
{
|
||||
int len = IEEE80211_MIN_ACTION_SIZE + 4 + twt->length;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = skb_put_zero(skb, len);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, bssid, ETH_ALEN);
|
||||
|
||||
mgmt->u.action.category = WLAN_CATEGORY_S1G;
|
||||
mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_SETUP;
|
||||
memcpy(mgmt->u.action.u.s1g.variable, twt, 3 + twt->length);
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_INTFL_MLME_CONN_TX |
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *da, const u8 *bssid, u8 flowid)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
struct sk_buff *skb;
|
||||
u8 *id;
|
||||
|
||||
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
|
||||
IEEE80211_MIN_ACTION_SIZE + 2);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
skb_reserve(skb, local->hw.extra_tx_headroom);
|
||||
mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE + 2);
|
||||
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
|
||||
IEEE80211_STYPE_ACTION);
|
||||
memcpy(mgmt->da, da, ETH_ALEN);
|
||||
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
|
||||
memcpy(mgmt->bssid, bssid, ETH_ALEN);
|
||||
|
||||
mgmt->u.action.category = WLAN_CATEGORY_S1G;
|
||||
mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_TEARDOWN;
|
||||
id = (u8 *)mgmt->u.action.u.s1g.variable;
|
||||
*id = flowid;
|
||||
|
||||
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||
IEEE80211_TX_CTL_REQ_TX_STATUS;
|
||||
ieee80211_tx_skb(sdata, skb);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||
struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
|
||||
struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
|
||||
|
||||
twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST);
|
||||
|
||||
/* broadcast TWT not supported yet */
|
||||
if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) {
|
||||
le16p_replace_bits(&twt_agrt->req_type,
|
||||
TWT_SETUP_CMD_REJECT,
|
||||
IEEE80211_TWT_REQTYPE_SETUP_CMD);
|
||||
goto out;
|
||||
}
|
||||
|
||||
drv_add_twt_setup(sdata->local, sdata, &sta->sta, twt);
|
||||
out:
|
||||
ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, twt);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
|
||||
drv_twt_teardown_request(sdata->local, sdata, &sta->sta,
|
||||
mgmt->u.action.u.s1g.variable[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata,
|
||||
struct sta_info *sta, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable;
|
||||
struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
|
||||
u8 flowid = le16_get_bits(twt_agrt->req_type,
|
||||
IEEE80211_TWT_REQTYPE_FLOWID);
|
||||
|
||||
drv_twt_teardown_request(sdata->local, sdata, &sta->sta, flowid);
|
||||
|
||||
ieee80211_s1g_send_twt_teardown(sdata, mgmt->sa, sdata->vif.addr,
|
||||
flowid);
|
||||
}
|
||||
|
||||
void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
sta = sta_info_get_bss(sdata, mgmt->sa);
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
switch (mgmt->u.action.u.s1g.action_code) {
|
||||
case WLAN_S1G_TWT_SETUP:
|
||||
ieee80211_s1g_rx_twt_setup(sdata, sta, skb);
|
||||
break;
|
||||
case WLAN_S1G_TWT_TEARDOWN:
|
||||
ieee80211_s1g_rx_twt_teardown(sdata, sta, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
||||
void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
mutex_lock(&local->sta_mtx);
|
||||
|
||||
sta = sta_info_get_bss(sdata, mgmt->da);
|
||||
if (!sta)
|
||||
goto out;
|
||||
|
||||
switch (mgmt->u.action.u.s1g.action_code) {
|
||||
case WLAN_S1G_TWT_SETUP:
|
||||
/* process failed twt setup frames */
|
||||
ieee80211_s1g_tx_twt_setup_fail(sdata, sta, skb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
}
|
||||
|
@ -705,13 +705,26 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
|
||||
/* Check to see if packet is a TDLS teardown packet */
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
(ieee80211_get_tdls_action(skb, hdr_size) ==
|
||||
WLAN_TDLS_TEARDOWN))
|
||||
WLAN_TDLS_TEARDOWN)) {
|
||||
ieee80211_tdls_td_tx_handle(local, sdata, skb,
|
||||
info->flags);
|
||||
else
|
||||
} else if (ieee80211_s1g_is_twt_setup(skb)) {
|
||||
if (!acked) {
|
||||
struct sk_buff *qskb;
|
||||
|
||||
qskb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (qskb) {
|
||||
skb_queue_tail(&sdata->status_queue,
|
||||
qskb);
|
||||
ieee80211_queue_work(&local->hw,
|
||||
&sdata->work);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ieee80211_mgd_conn_tx_status(sdata,
|
||||
hdr->frame_control,
|
||||
acked);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
@ -2825,6 +2825,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_decap_offload,
|
||||
TP_ARGS(local, sdata, sta, enabled)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_add_twt_setup,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_twt_setup *twt,
|
||||
struct ieee80211_twt_params *twt_agrt),
|
||||
|
||||
TP_ARGS(local, sta, twt, twt_agrt),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
STA_ENTRY
|
||||
__field(u8, dialog_token)
|
||||
__field(u8, control)
|
||||
__field(__le16, req_type)
|
||||
__field(__le64, twt)
|
||||
__field(u8, duration)
|
||||
__field(__le16, mantissa)
|
||||
__field(u8, channel)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->dialog_token = twt->dialog_token;
|
||||
__entry->control = twt->control;
|
||||
__entry->req_type = twt_agrt->req_type;
|
||||
__entry->twt = twt_agrt->twt;
|
||||
__entry->duration = twt_agrt->min_twt_dur;
|
||||
__entry->mantissa = twt_agrt->mantissa;
|
||||
__entry->channel = twt_agrt->channel;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT
|
||||
" token:%d control:0x%02x req_type:0x%04x"
|
||||
" twt:%llu duration:%d mantissa:%d channel:%d",
|
||||
LOCAL_PR_ARG, STA_PR_ARG, __entry->dialog_token,
|
||||
__entry->control, le16_to_cpu(__entry->req_type),
|
||||
le64_to_cpu(__entry->twt), __entry->duration,
|
||||
le16_to_cpu(__entry->mantissa), __entry->channel
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(drv_twt_teardown_request,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sta *sta, u8 flowid),
|
||||
|
||||
TP_ARGS(local, sta, flowid),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
STA_ENTRY
|
||||
__field(u8, flowid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->flowid = flowid;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT STA_PR_FMT " flowid:%d",
|
||||
LOCAL_PR_ARG, STA_PR_ARG, __entry->flowid
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
@ -1336,6 +1336,18 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
|
||||
elems->rsnx = pos;
|
||||
elems->rsnx_len = elen;
|
||||
break;
|
||||
case WLAN_EID_TX_POWER_ENVELOPE:
|
||||
if (elen < 1 ||
|
||||
elen > sizeof(struct ieee80211_tx_pwr_env))
|
||||
break;
|
||||
|
||||
if (elems->tx_pwr_env_num >= ARRAY_SIZE(elems->tx_pwr_env))
|
||||
break;
|
||||
|
||||
elems->tx_pwr_env[elems->tx_pwr_env_num] = (void *)pos;
|
||||
elems->tx_pwr_env_len[elems->tx_pwr_env_num] = elen;
|
||||
elems->tx_pwr_env_num++;
|
||||
break;
|
||||
case WLAN_EID_EXTENSION:
|
||||
ieee80211_parse_extension_element(calc_crc ?
|
||||
&crc : NULL,
|
||||
|
@ -171,9 +171,11 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
|
||||
{
|
||||
const struct ieee80211_regdomain *regd = NULL;
|
||||
const struct ieee80211_regdomain *wiphy_regd = NULL;
|
||||
enum nl80211_dfs_regions dfs_region;
|
||||
|
||||
rcu_read_lock();
|
||||
regd = get_cfg80211_regdom();
|
||||
dfs_region = regd->dfs_region;
|
||||
|
||||
if (!wiphy)
|
||||
goto out;
|
||||
@ -182,6 +184,11 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
|
||||
if (!wiphy_regd)
|
||||
goto out;
|
||||
|
||||
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
|
||||
dfs_region = wiphy_regd->dfs_region;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wiphy_regd->dfs_region == regd->dfs_region)
|
||||
goto out;
|
||||
|
||||
@ -193,7 +200,7 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return regd->dfs_region;
|
||||
return dfs_region;
|
||||
}
|
||||
|
||||
static void rcu_free_regdom(const struct ieee80211_regdomain *r)
|
||||
|
Loading…
Reference in New Issue
Block a user