1 /** @file mlan_action.c
2 *
3 * @brief This file provides functions for action management frame
4 *
5 * Copyright 2022-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 /********************************************************
12 Change log:
13 08/11/2022: initial version
14 ********************************************************/
15
16 #include <mlan_api.h>
17 #include "wifi.h"
18 #ifdef RW610
19 #include "wifi-imu.h"
20 #else
21 #include "wifi-sdio.h"
22 #endif
23
24 /********************************************************
25 Local Variables
26 ********************************************************/
27
28 /********************************************************
29 Global Variables
30 ********************************************************/
31
32 /********************************************************
33 Local Functions
34 ********************************************************/
35 /**
36 * @brief This function process rx radio measurement action frame
37 *
38 * @param payload rx frame including 802.11 header
39 * @param payload_len length of action frame
40 * @param src_addr source address
41 *
42 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
43 */
wlan_process_mgmt_radio_measurement_action(t_u8 * payload,t_u32 payload_len,t_u8 * dest_addr,t_u8 * src_addr,RxPD * rxpd)44 static mlan_status wlan_process_mgmt_radio_measurement_action(
45 t_u8 *payload, t_u32 payload_len, t_u8 *dest_addr, t_u8 *src_addr, RxPD *rxpd)
46 {
47 t_u8 action_code = 0;
48 t_u8 *pos;
49 mlan_status ret = MLAN_STATUS_FAILURE;
50
51 pos = payload + sizeof(wlan_802_11_header) + 1;
52 action_code = *pos++;
53 #if CONFIG_11K
54 IEEEtypes_FrameCtl_t *mgmt_fc_p =
55 (IEEEtypes_FrameCtl_t *)(void *)&(((wlan_802_11_header *)(void *)payload)->frm_ctl);
56 payload_len -= (sizeof(wlan_802_11_header) + 2U);
57 #endif
58
59 switch (action_code)
60 {
61 #if CONFIG_11K
62 case (t_u8)IEEE_MGMT_RRM_RADIO_MEASUREMENT_REQUEST:
63 {
64 wlan_process_radio_measurement_request(pos, payload_len, dest_addr, src_addr, (bool)mgmt_fc_p->wep);
65 ret = MLAN_STATUS_SUCCESS;
66 break;
67 }
68 case (t_u8)IEEE_MGMT_RRM_LINK_MEASUREMENT_REQUEST:
69 {
70 wlan_process_link_measurement_request(pos, payload_len, dest_addr, src_addr, (bool)mgmt_fc_p->wep, rxpd);
71 ret = MLAN_STATUS_SUCCESS;
72 break;
73 }
74 case (t_u8)IEEE_MGMT_RRM_NEIGHBOR_REPORT_RESPONSE:
75 {
76 wlan_process_neighbor_report_response(pos, payload_len, dest_addr, src_addr, (bool)mgmt_fc_p->wep);
77 ret = MLAN_STATUS_SUCCESS;
78 break;
79 }
80 #else
81 case 0:
82 break;
83 #endif
84 default:
85 wifi_d("RRM: Unknown request: %u", action_code);
86 break;
87 }
88 return ret;
89 }
90
91 /**
92 * @brief This function process rx action frame
93 *
94 * @param payload rx frame including 802.11 header
95 * @param payload_len length of action frame
96 * @param src_addr source address
97 *
98 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
99 */
wlan_process_mgmt_wnm_action(t_u8 * payload,t_u32 payload_len,t_u8 * src_addr,t_u8 * dest_addr)100 static mlan_status wlan_process_mgmt_wnm_action(t_u8 *payload, t_u32 payload_len, t_u8 *src_addr, t_u8 *dest_addr)
101 {
102 IEEEtypes_WNM_ActionFieldType_e action_code = (IEEEtypes_WNM_ActionFieldType_e)0;
103 t_u8 *pos;
104 mlan_status ret = MLAN_STATUS_FAILURE;
105
106 pos = payload + sizeof(wlan_802_11_header) + 1;
107 action_code = (IEEEtypes_WNM_ActionFieldType_e)(*pos++);
108
109 switch (action_code)
110 {
111 #if CONFIG_11V
112 case IEEE_MGMT_WNM_BTM_REQUEST:
113 {
114 IEEEtypes_FrameCtl_t *mgmt_fc_p =
115 (IEEEtypes_FrameCtl_t *)(void *)&(((wlan_802_11_header *)(void *)payload)->frm_ctl);
116
117 wlan_process_mgmt_wnm_btm_req(pos, (payload + payload_len), src_addr, dest_addr, (bool)mgmt_fc_p->wep);
118 ret = MLAN_STATUS_SUCCESS;
119 break;
120 }
121 #endif
122 default:
123 wifi_d("WNM: Unknown request: %u", action_code);
124 break;
125 }
126 return ret;
127 }
128
wlan_process_mgmt_unprotect_wnm_action(t_u8 * payload,t_u32 payload_len,RxPD * rxpd)129 static mlan_status wlan_process_mgmt_unprotect_wnm_action(t_u8 *payload, t_u32 payload_len, RxPD *rxpd)
130 {
131 t_u8 action_code = 0;
132 t_u8 *pos;
133 mlan_status ret = MLAN_STATUS_FAILURE;
134
135 pos = payload + sizeof(wlan_802_11_header) + 1;
136 action_code = *(pos++);
137
138 switch (action_code)
139 {
140 case 1:
141 #if CONFIG_1AS
142 wlan_process_timing_measurement_frame(payload, payload_len, rxpd);
143 ret = MLAN_STATUS_SUCCESS;
144 #endif
145 break;
146 default:
147 wifi_d("unprotect WNM: Unknown request: %u", action_code);
148 break;
149 }
150 return ret;
151 }
152
153 #if CONFIG_1AS
154 /* imu_header + mgmt_txpd_len + sizeof(t_u16 frame_len) */
155 #define WLAN_MGMT_PKT_START_OFFSET (INTF_HEADER_LEN + 0x14U)
156
wlan_outbuf_lock(void)157 static inline void wlan_outbuf_lock(void)
158 {
159 #ifdef RW610
160 wifi_imu_lock();
161 #else
162 (void)wifi_sdio_lock();
163 #endif
164 }
165
wlan_outbuf_unlock(void)166 static inline void wlan_outbuf_unlock(void)
167 {
168 #ifdef RW610
169 wifi_imu_unlock();
170 #else
171 wifi_sdio_unlock();
172 #endif
173 }
174
wlan_fill_mgmt_mac_header(mlan_private * pmpriv,wlan_mgmt_pkt * pkt_hdr,t_u16 subtype,t_u8 * da,t_u8 * sa)175 static void wlan_fill_mgmt_mac_header(mlan_private *pmpriv, wlan_mgmt_pkt *pkt_hdr, t_u16 subtype, t_u8 *da, t_u8 *sa)
176 {
177 IEEEtypes_FrameCtl_t *frame_ctrl = (IEEEtypes_FrameCtl_t *)(void *)&pkt_hdr->wlan_header.frm_ctl;
178
179 frame_ctrl->sub_type = (t_u8)subtype;
180 frame_ctrl->type = (t_u8)IEEE_TYPE_MANAGEMENT;
181 (void)memcpy(pkt_hdr->wlan_header.addr1, da, MLAN_MAC_ADDR_LENGTH);
182 (void)memcpy(pkt_hdr->wlan_header.addr2, sa, MLAN_MAC_ADDR_LENGTH);
183 if (pmpriv->bss_index == 0U)
184 {
185 (void)memcpy(pkt_hdr->wlan_header.addr3, da, MLAN_MAC_ADDR_LENGTH);
186 }
187 else
188 {
189 (void)memcpy(pkt_hdr->wlan_header.addr3, sa, MLAN_MAC_ADDR_LENGTH);
190 }
191 pkt_hdr->wlan_header.seq_ctl = 0;
192 (void)memset(pkt_hdr->wlan_header.addr4, 0x00, MLAN_MAC_ADDR_LENGTH);
193 }
194
wlan_process_timing_measurement_frame(t_u8 * payload,t_u32 payload_len,RxPD * rxpd)195 void wlan_process_timing_measurement_frame(t_u8 *payload, t_u32 payload_len, RxPD *rxpd)
196 {
197 mlan_private *pmpriv = mlan_adap->priv[rxpd->bss_type];
198 t_u64 tsf;
199 wlan_802_11_header *hdr = (wlan_802_11_header *)(void *)payload;
200 wifi_wnm_timing_msmt_t *tm_ind = MNULL;
201 wifi_dot1as_info_t *info = &pmpriv->dot1as_info;
202
203 if (payload_len < sizeof(wlan_802_11_header) + sizeof(wifi_wnm_timing_msmt_t) + 1U)
204 {
205 wifi_e("wlan_recv_tm_frame invalid packet length %d", payload_len);
206 return;
207 }
208
209 info->role = 1;
210 (void)memcpy(info->peer_addr, hdr->addr2, MLAN_MAC_ADDR_LENGTH);
211
212 /* get t2,t3 timestamp in rxpd */
213 tsf = rxpd->reserved1;
214 tsf = wlan_le64_to_cpu(tsf);
215 info->t3 = (t_u32)(tsf >> 32);
216 info->t2 = (t_u32)tsf;
217
218 /* t1 == tod, t4 == toa */
219 /* skip category */
220 tm_ind = (wifi_wnm_timing_msmt_t *)(void *)(payload + sizeof(wlan_802_11_header) + 1);
221 /* 1 byte dialog_token + 1 byte prev_dialog_token + 4 bytes t1 + 4 bytes t4 */
222 (void)memcpy(&info->dialog_token, &tm_ind->dialog_token, 10);
223
224 /* TODO: Vendor Specific */
225 wifi_d("Recv timing measurement frame peer " MACSTR ", t1[%u] t2[%u] t3[%u] t4[%u]\r\n", MAC2STR(info->peer_addr),
226 info->t1, info->t2, info->t3, info->t4);
227 wlan_report_timing_measurement((wlan_dot1as_info_t *)info);
228 }
229
wlan_send_timing_measurement_req_frame(mlan_private * pmpriv,t_u8 * ta,t_u8 trigger)230 void wlan_send_timing_measurement_req_frame(mlan_private *pmpriv, t_u8 *ta, t_u8 trigger)
231 {
232 t_u32 len;
233 uint32_t max_len;
234 t_u32 offset = WLAN_MGMT_PKT_START_OFFSET;
235 t_u8 *buf = wifi_get_outbuf(&max_len);
236 wlan_mgmt_pkt *pkt_hdr = MNULL;
237 TxPD *txpd = MNULL;
238 t_u32 meas_frm_len = 0;
239
240 assert(ta != MNULL);
241 assert(buf != MNULL);
242 wlan_outbuf_lock();
243
244 pkt_hdr = (wlan_mgmt_pkt *)(void *)(buf + offset);
245 wlan_fill_mgmt_mac_header(pmpriv, pkt_hdr, SUBTYPE_ACTION, ta, &pmpriv->curr_addr[0]);
246 offset += sizeof(wlan_mgmt_pkt);
247
248 /* WNM, Timimg Meaeurement Request action, Trigger */
249 buf[offset] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_WNM;
250 buf[offset + 1U] = IEEE_MGMT_WNM_TIMING_MEASUREMENT_REQUEST;
251 buf[offset + 2U] = trigger;
252 len = offset + 3U;
253
254 meas_frm_len = len - WLAN_MGMT_PKT_START_OFFSET - sizeof(pkt_hdr->frm_len);
255 pkt_hdr->frm_len = (t_u16)meas_frm_len;
256
257 (void)raw_process_pkt_hdrs(buf, len, pmpriv->bss_index);
258 /* set tx_token_id to 1 to get tx_status_event from FW */
259 txpd = (TxPD *)(void *)(buf + INTF_HEADER_LEN);
260 txpd->tx_token_id = 1;
261 (void)raw_wlan_xmit_pkt(buf, len, pmpriv->bss_index, 0);
262 wlan_outbuf_unlock();
263 }
264
wlan_send_timing_measurement_frame(mlan_private * pmpriv)265 mlan_status wlan_send_timing_measurement_frame(mlan_private *pmpriv)
266 {
267 mlan_status ret;
268 t_u32 len;
269 uint32_t max_len;
270 t_u32 offset = WLAN_MGMT_PKT_START_OFFSET;
271 t_u8 *buf = wifi_get_outbuf(&max_len);
272 wlan_mgmt_pkt *pkt_hdr = MNULL;
273 wifi_wnm_timing_msmt_t *tm = MNULL;
274 TxPD *txpd = MNULL;
275 t_u32 meas_frm_len = 0;
276
277 assert(buf != MNULL);
278 wlan_outbuf_lock();
279
280 /* fill mac80211 header */
281 pkt_hdr = (wlan_mgmt_pkt *)(void *)(buf + offset);
282 wlan_fill_mgmt_mac_header(pmpriv, pkt_hdr, SUBTYPE_ACTION, &pmpriv->dot1as_info.peer_addr[0],
283 &pmpriv->curr_addr[0]);
284 offset += sizeof(wlan_mgmt_pkt);
285
286 /* Unprotected WNM */
287 buf[offset] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM;
288 offset += 1U;
289
290 /* fill tm body */
291 tm = (wifi_wnm_timing_msmt_t *)(void *)&buf[offset];
292 /* Timimg Measurement */
293 tm->action = 1;
294 /* 1 byte dialog_token + 1 byte prev_dialog_token + 4 bytes t1 + 4 bytes t4 */
295 (void)memcpy(&tm->dialog_token, &pmpriv->dot1as_info.dialog_token, 10);
296 tm->max_tod_err = 0;
297 tm->max_toa_err = 0;
298
299 len = offset + sizeof(wifi_wnm_timing_msmt_t);
300 meas_frm_len = len - WLAN_MGMT_PKT_START_OFFSET - sizeof(pkt_hdr->frm_len);
301 pkt_hdr->frm_len = (t_u16)meas_frm_len;
302 /* TODO: Vendor Specific */
303
304 (void)raw_process_pkt_hdrs(buf, len, pmpriv->bss_index);
305 /* set tx_token_id to 1 to get tx_status_event from FW */
306 txpd = (TxPD *)(void *)(buf + INTF_HEADER_LEN);
307 txpd->tx_token_id = 1;
308 ret = raw_wlan_xmit_pkt(buf, len, pmpriv->bss_index, 0);
309 wlan_outbuf_unlock();
310 return ret;
311 }
312 #endif
313
314 /********************************************************
315 Global functions
316 ********************************************************/
317 /**
318 * @brief This function process rx action frame
319 *
320 * @param payload rx frame including 802.11 header
321 * @param payload_len length of action frame
322 *
323 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
324 */
wlan_process_mgmt_action(t_u8 * payload,t_u32 payload_len,RxPD * rxpd)325 mlan_status wlan_process_mgmt_action(t_u8 *payload, t_u32 payload_len, RxPD *rxpd)
326 {
327 wlan_802_11_header *pieee_pkt_hdr = MNULL;
328 IEEEtypes_ActionCategory_e category = (IEEEtypes_ActionCategory_e)0;
329 mlan_status ret = MLAN_STATUS_FAILURE;
330
331 pieee_pkt_hdr = (wlan_802_11_header *)(void *)payload;
332 category = (IEEEtypes_ActionCategory_e)(*(payload + sizeof(wlan_802_11_header)));
333
334 switch (category)
335 {
336 case IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC:
337 ret = wlan_process_mgmt_radio_measurement_action(payload, payload_len, pieee_pkt_hdr->addr1,
338 pieee_pkt_hdr->addr2, rxpd);
339 break;
340 case IEEE_MGMT_ACTION_CATEGORY_WNM:
341 ret = wlan_process_mgmt_wnm_action(payload, payload_len, pieee_pkt_hdr->addr1, pieee_pkt_hdr->addr2);
342 break;
343 case IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM:
344 ret = wlan_process_mgmt_unprotect_wnm_action(payload, payload_len, rxpd);
345 break;
346 default:
347 wifi_d("Action: Unknown request: %u", category);
348 break;
349 }
350 return ret;
351 }
352