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