Skip to content

Commit f5a4c24

Browse files
LorenzoBianconijmberg-intel
authored andcommitted
mac80211: introduce individual TWT support in AP mode
Introduce TWT action frames parsing support to mac80211. Currently just individual TWT agreement are support in AP mode. Whenever the AP receives a TWT action frame from an associated client, after performing sanity checks, it will notify the underlay driver with requested parameters in order to check if they are supported and if there is enough room for a new agreement. The driver is expected to set the agreement result and report it to mac80211. Drivers supporting this have two new callbacks: - add_twt_setup (mandatory) - twt_teardown_request (optional) mac80211 will send an action frame reply according to the result reported by the driver. Tested-by: Peter Chiu <[email protected]> Signed-off-by: Lorenzo Bianconi <[email protected]> Link: https://lore.kernel.org/r/257512f2e22ba42b9f2624942a128dd8f141de4b.1629741512.git.lorenzo@kernel.org [use le16p_replace_bits(), minor cleanups, use (void *) casts, fix to use ieee80211_get_he_iftype_cap() correctly] Signed-off-by: Johannes Berg <[email protected]>
1 parent dab2ea6 commit f5a4c24

File tree

8 files changed

+430
-2
lines changed

8 files changed

+430
-2
lines changed

include/net/mac80211.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3926,6 +3926,13 @@ struct ieee80211_prep_tx_info {
39263926
* @set_sar_specs: Update the SAR (TX power) settings.
39273927
* @sta_set_decap_offload: Called to notify the driver when a station is allowed
39283928
* to use rx decapsulation offload
3929+
* @add_twt_setup: Update hw with TWT agreement parameters received from the peer.
3930+
* This callback allows the hw to check if requested parameters
3931+
* are supported and if there is enough room for a new agreement.
3932+
* The hw is expected to set agreement result in the req_type field of
3933+
* twt structure.
3934+
* @twt_teardown_request: Update the hw with TWT teardown request received
3935+
* from the peer.
39293936
*/
39303937
struct ieee80211_ops {
39313938
void (*tx)(struct ieee80211_hw *hw,
@@ -4249,6 +4256,11 @@ struct ieee80211_ops {
42494256
void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
42504257
struct ieee80211_vif *vif,
42514258
struct ieee80211_sta *sta, bool enabled);
4259+
void (*add_twt_setup)(struct ieee80211_hw *hw,
4260+
struct ieee80211_sta *sta,
4261+
struct ieee80211_twt_setup *twt);
4262+
void (*twt_teardown_request)(struct ieee80211_hw *hw,
4263+
struct ieee80211_sta *sta, u8 flowid);
42524264
};
42534265

42544266
/**

net/mac80211/driver-ops.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,4 +1447,40 @@ static inline void drv_sta_set_decap_offload(struct ieee80211_local *local,
14471447
trace_drv_return_void(local);
14481448
}
14491449

1450+
static inline void drv_add_twt_setup(struct ieee80211_local *local,
1451+
struct ieee80211_sub_if_data *sdata,
1452+
struct ieee80211_sta *sta,
1453+
struct ieee80211_twt_setup *twt)
1454+
{
1455+
struct ieee80211_twt_params *twt_agrt;
1456+
1457+
might_sleep();
1458+
1459+
if (!check_sdata_in_driver(sdata))
1460+
return;
1461+
1462+
twt_agrt = (void *)twt->params;
1463+
1464+
trace_drv_add_twt_setup(local, sta, twt, twt_agrt);
1465+
local->ops->add_twt_setup(&local->hw, sta, twt);
1466+
trace_drv_return_void(local);
1467+
}
1468+
1469+
static inline void drv_twt_teardown_request(struct ieee80211_local *local,
1470+
struct ieee80211_sub_if_data *sdata,
1471+
struct ieee80211_sta *sta,
1472+
u8 flowid)
1473+
{
1474+
might_sleep();
1475+
if (!check_sdata_in_driver(sdata))
1476+
return;
1477+
1478+
if (!local->ops->twt_teardown_request)
1479+
return;
1480+
1481+
trace_drv_twt_teardown_request(local, sta, flowid);
1482+
local->ops->twt_teardown_request(&local->hw, sta, flowid);
1483+
trace_drv_return_void(local);
1484+
}
1485+
14501486
#endif /* __MAC80211_DRIVER_OPS */

net/mac80211/ieee80211_i.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ struct ieee80211_sub_if_data {
946946

947947
struct work_struct work;
948948
struct sk_buff_head skb_queue;
949+
struct sk_buff_head status_queue;
949950

950951
u8 needed_rx_chains;
951952
enum ieee80211_smps_mode smps_mode;
@@ -2080,6 +2081,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
20802081

20812082
/* S1G */
20822083
void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
2084+
bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb);
2085+
void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata,
2086+
struct sk_buff *skb);
2087+
void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata,
2088+
struct sk_buff *skb);
20832089

20842090
/* Spectrum management */
20852091
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,

net/mac80211/iface.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
552552
*/
553553
ieee80211_free_keys(sdata, true);
554554
skb_queue_purge(&sdata->skb_queue);
555+
skb_queue_purge(&sdata->status_queue);
555556
}
556557

557558
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
@@ -984,6 +985,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
984985
}
985986

986987
skb_queue_head_init(&sdata->skb_queue);
988+
skb_queue_head_init(&sdata->status_queue);
987989
INIT_WORK(&sdata->work, ieee80211_iface_work);
988990

989991
return 0;
@@ -1382,6 +1384,16 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
13821384
WARN_ON(1);
13831385
break;
13841386
}
1387+
} else if (ieee80211_is_action(mgmt->frame_control) &&
1388+
mgmt->u.action.category == WLAN_CATEGORY_S1G) {
1389+
switch (mgmt->u.action.u.s1g.action_code) {
1390+
case WLAN_S1G_TWT_TEARDOWN:
1391+
case WLAN_S1G_TWT_SETUP:
1392+
ieee80211_s1g_rx_twt_action(sdata, skb);
1393+
break;
1394+
default:
1395+
break;
1396+
}
13851397
} else if (ieee80211_is_ext(mgmt->frame_control)) {
13861398
if (sdata->vif.type == NL80211_IFTYPE_STATION)
13871399
ieee80211_sta_rx_queued_ext(sdata, skb);
@@ -1437,6 +1449,24 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
14371449
}
14381450
}
14391451

1452+
static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
1453+
struct sk_buff *skb)
1454+
{
1455+
struct ieee80211_mgmt *mgmt = (void *)skb->data;
1456+
1457+
if (ieee80211_is_action(mgmt->frame_control) &&
1458+
mgmt->u.action.category == WLAN_CATEGORY_S1G) {
1459+
switch (mgmt->u.action.u.s1g.action_code) {
1460+
case WLAN_S1G_TWT_TEARDOWN:
1461+
case WLAN_S1G_TWT_SETUP:
1462+
ieee80211_s1g_status_twt_action(sdata, skb);
1463+
break;
1464+
default:
1465+
break;
1466+
}
1467+
}
1468+
}
1469+
14401470
static void ieee80211_iface_work(struct work_struct *work)
14411471
{
14421472
struct ieee80211_sub_if_data *sdata =
@@ -1466,6 +1496,16 @@ static void ieee80211_iface_work(struct work_struct *work)
14661496
kcov_remote_stop();
14671497
}
14681498

1499+
/* process status queue */
1500+
while ((skb = skb_dequeue(&sdata->status_queue))) {
1501+
kcov_remote_start_common(skb_get_kcov_handle(skb));
1502+
1503+
ieee80211_iface_process_status(sdata, skb);
1504+
kfree_skb(skb);
1505+
1506+
kcov_remote_stop();
1507+
}
1508+
14691509
/* then other type-dependent work */
14701510
switch (sdata->vif.type) {
14711511
case NL80211_IFTYPE_STATION:
@@ -1529,6 +1569,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
15291569
}
15301570

15311571
skb_queue_head_init(&sdata->skb_queue);
1572+
skb_queue_head_init(&sdata->status_queue);
15321573
INIT_WORK(&sdata->work, ieee80211_iface_work);
15331574
INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
15341575
INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);

net/mac80211/rx.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3212,6 +3212,68 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
32123212
return RX_CONTINUE;
32133213
}
32143214

3215+
static bool
3216+
ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx)
3217+
{
3218+
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data;
3219+
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
3220+
struct ieee80211_sub_if_data *sdata = rx->sdata;
3221+
const struct ieee80211_sta_he_cap *hecap;
3222+
struct ieee80211_supported_band *sband;
3223+
3224+
/* TWT actions are only supported in AP for the moment */
3225+
if (sdata->vif.type != NL80211_IFTYPE_AP)
3226+
return false;
3227+
3228+
if (!rx->local->ops->add_twt_setup)
3229+
return false;
3230+
3231+
sband = rx->local->hw.wiphy->bands[status->band];
3232+
hecap = ieee80211_get_he_iftype_cap(sband,
3233+
ieee80211_vif_type_p2p(&sdata->vif));
3234+
if (!hecap)
3235+
return false;
3236+
3237+
if (!(hecap->he_cap_elem.mac_cap_info[0] &
3238+
IEEE80211_HE_MAC_CAP0_TWT_RES))
3239+
return false;
3240+
3241+
if (!rx->sta)
3242+
return false;
3243+
3244+
switch (mgmt->u.action.u.s1g.action_code) {
3245+
case WLAN_S1G_TWT_SETUP: {
3246+
struct ieee80211_twt_setup *twt;
3247+
3248+
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
3249+
1 + /* action code */
3250+
sizeof(struct ieee80211_twt_setup) +
3251+
2 /* TWT req_type agrt */)
3252+
break;
3253+
3254+
twt = (void *)mgmt->u.action.u.s1g.variable;
3255+
if (twt->element_id != WLAN_EID_S1G_TWT)
3256+
break;
3257+
3258+
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE +
3259+
4 + /* action code + token + tlv */
3260+
twt->length)
3261+
break;
3262+
3263+
return true; /* queue the frame */
3264+
}
3265+
case WLAN_S1G_TWT_TEARDOWN:
3266+
if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2)
3267+
break;
3268+
3269+
return true; /* queue the frame */
3270+
default:
3271+
break;
3272+
}
3273+
3274+
return false;
3275+
}
3276+
32153277
static ieee80211_rx_result debug_noinline
32163278
ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
32173279
{
@@ -3491,6 +3553,17 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
34913553
!mesh_path_sel_is_hwmp(sdata))
34923554
break;
34933555
goto queue;
3556+
case WLAN_CATEGORY_S1G:
3557+
switch (mgmt->u.action.u.s1g.action_code) {
3558+
case WLAN_S1G_TWT_SETUP:
3559+
case WLAN_S1G_TWT_TEARDOWN:
3560+
if (ieee80211_process_rx_twt_action(rx))
3561+
goto queue;
3562+
break;
3563+
default:
3564+
break;
3565+
}
3566+
break;
34943567
}
34953568

34963569
return RX_CONTINUE;

0 commit comments

Comments
 (0)