1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright(c) 2020 Adapt-IP
5 * Copyright (C) 2023 Intel Corporation
7 #include <linux/ieee80211.h>
8 #include <net/mac80211.h>
9 #include "ieee80211_i.h"
10 #include "driver-ops.h"
12 void ieee80211_s1g_sta_rate_init(struct sta_info
*sta
)
14 /* avoid indicating legacy bitrates for S1G STAs */
15 sta
->deflink
.tx_stats
.last_rate
.flags
|= IEEE80211_TX_RC_S1G_MCS
;
16 sta
->deflink
.rx_stats
.last_rate
=
17 STA_STATS_FIELD(TYPE
, STA_STATS_RATE_TYPE_S1G
);
20 bool ieee80211_s1g_is_twt_setup(struct sk_buff
*skb
)
22 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)skb
->data
;
24 if (likely(!ieee80211_is_action(mgmt
->frame_control
)))
27 if (likely(mgmt
->u
.action
.category
!= WLAN_CATEGORY_S1G
))
30 return mgmt
->u
.action
.u
.s1g
.action_code
== WLAN_S1G_TWT_SETUP
;
34 ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data
*sdata
, const u8
*da
,
35 const u8
*bssid
, struct ieee80211_twt_setup
*twt
)
37 int len
= IEEE80211_MIN_ACTION_SIZE
+ 4 + twt
->length
;
38 struct ieee80211_local
*local
= sdata
->local
;
39 struct ieee80211_mgmt
*mgmt
;
42 skb
= dev_alloc_skb(local
->hw
.extra_tx_headroom
+ len
);
46 skb_reserve(skb
, local
->hw
.extra_tx_headroom
);
47 mgmt
= skb_put_zero(skb
, len
);
48 mgmt
->frame_control
= cpu_to_le16(IEEE80211_FTYPE_MGMT
|
49 IEEE80211_STYPE_ACTION
);
50 memcpy(mgmt
->da
, da
, ETH_ALEN
);
51 memcpy(mgmt
->sa
, sdata
->vif
.addr
, ETH_ALEN
);
52 memcpy(mgmt
->bssid
, bssid
, ETH_ALEN
);
54 mgmt
->u
.action
.category
= WLAN_CATEGORY_S1G
;
55 mgmt
->u
.action
.u
.s1g
.action_code
= WLAN_S1G_TWT_SETUP
;
56 memcpy(mgmt
->u
.action
.u
.s1g
.variable
, twt
, 3 + twt
->length
);
58 IEEE80211_SKB_CB(skb
)->flags
|= IEEE80211_TX_INTFL_DONT_ENCRYPT
|
59 IEEE80211_TX_INTFL_MLME_CONN_TX
|
60 IEEE80211_TX_CTL_REQ_TX_STATUS
;
61 ieee80211_tx_skb(sdata
, skb
);
65 ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data
*sdata
,
66 const u8
*da
, const u8
*bssid
, u8 flowid
)
68 struct ieee80211_local
*local
= sdata
->local
;
69 struct ieee80211_mgmt
*mgmt
;
73 skb
= dev_alloc_skb(local
->hw
.extra_tx_headroom
+
74 IEEE80211_MIN_ACTION_SIZE
+ 2);
78 skb_reserve(skb
, local
->hw
.extra_tx_headroom
);
79 mgmt
= skb_put_zero(skb
, IEEE80211_MIN_ACTION_SIZE
+ 2);
80 mgmt
->frame_control
= cpu_to_le16(IEEE80211_FTYPE_MGMT
|
81 IEEE80211_STYPE_ACTION
);
82 memcpy(mgmt
->da
, da
, ETH_ALEN
);
83 memcpy(mgmt
->sa
, sdata
->vif
.addr
, ETH_ALEN
);
84 memcpy(mgmt
->bssid
, bssid
, ETH_ALEN
);
86 mgmt
->u
.action
.category
= WLAN_CATEGORY_S1G
;
87 mgmt
->u
.action
.u
.s1g
.action_code
= WLAN_S1G_TWT_TEARDOWN
;
88 id
= (u8
*)mgmt
->u
.action
.u
.s1g
.variable
;
91 IEEE80211_SKB_CB(skb
)->flags
|= IEEE80211_TX_INTFL_DONT_ENCRYPT
|
92 IEEE80211_TX_CTL_REQ_TX_STATUS
;
93 ieee80211_tx_skb(sdata
, skb
);
97 ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data
*sdata
,
98 struct sta_info
*sta
, struct sk_buff
*skb
)
100 struct ieee80211_mgmt
*mgmt
= (void *)skb
->data
;
101 struct ieee80211_twt_setup
*twt
= (void *)mgmt
->u
.action
.u
.s1g
.variable
;
102 struct ieee80211_twt_params
*twt_agrt
= (void *)twt
->params
;
104 twt_agrt
->req_type
&= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST
);
106 /* broadcast TWT not supported yet */
107 if (twt
->control
& IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST
) {
108 twt_agrt
->req_type
&=
109 ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD
);
110 twt_agrt
->req_type
|=
111 le16_encode_bits(TWT_SETUP_CMD_REJECT
,
112 IEEE80211_TWT_REQTYPE_SETUP_CMD
);
116 /* TWT Information not supported yet */
117 twt
->control
|= IEEE80211_TWT_CONTROL_RX_DISABLED
;
119 drv_add_twt_setup(sdata
->local
, sdata
, &sta
->sta
, twt
);
121 ieee80211_s1g_send_twt_setup(sdata
, mgmt
->sa
, sdata
->vif
.addr
, twt
);
125 ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data
*sdata
,
126 struct sta_info
*sta
, struct sk_buff
*skb
)
128 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)skb
->data
;
130 drv_twt_teardown_request(sdata
->local
, sdata
, &sta
->sta
,
131 mgmt
->u
.action
.u
.s1g
.variable
[0]);
135 ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data
*sdata
,
136 struct sta_info
*sta
, struct sk_buff
*skb
)
138 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)skb
->data
;
139 struct ieee80211_twt_setup
*twt
= (void *)mgmt
->u
.action
.u
.s1g
.variable
;
140 struct ieee80211_twt_params
*twt_agrt
= (void *)twt
->params
;
141 u8 flowid
= le16_get_bits(twt_agrt
->req_type
,
142 IEEE80211_TWT_REQTYPE_FLOWID
);
144 drv_twt_teardown_request(sdata
->local
, sdata
, &sta
->sta
, flowid
);
146 ieee80211_s1g_send_twt_teardown(sdata
, mgmt
->sa
, sdata
->vif
.addr
,
150 void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data
*sdata
,
153 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)skb
->data
;
154 struct ieee80211_local
*local
= sdata
->local
;
155 struct sta_info
*sta
;
157 lockdep_assert_wiphy(local
->hw
.wiphy
);
159 sta
= sta_info_get_bss(sdata
, mgmt
->sa
);
163 switch (mgmt
->u
.action
.u
.s1g
.action_code
) {
164 case WLAN_S1G_TWT_SETUP
:
165 ieee80211_s1g_rx_twt_setup(sdata
, sta
, skb
);
167 case WLAN_S1G_TWT_TEARDOWN
:
168 ieee80211_s1g_rx_twt_teardown(sdata
, sta
, skb
);
175 void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data
*sdata
,
178 struct ieee80211_mgmt
*mgmt
= (struct ieee80211_mgmt
*)skb
->data
;
179 struct ieee80211_local
*local
= sdata
->local
;
180 struct sta_info
*sta
;
182 lockdep_assert_wiphy(local
->hw
.wiphy
);
184 sta
= sta_info_get_bss(sdata
, mgmt
->da
);
188 switch (mgmt
->u
.action
.u
.s1g
.action_code
) {
189 case WLAN_S1G_TWT_SETUP
:
190 /* process failed twt setup frames */
191 ieee80211_s1g_tx_twt_setup_fail(sdata
, sta
, skb
);