1 /*
2  * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifdef CONFIG_WPA3_SAE
7 
8 #include "common/sae.h"
9 #include "common/ieee802_11_defs.h"
10 #include "esp_wifi_driver.h"
11 #include "rsn_supp/wpa.h"
12 #include "ap/hostapd.h"
13 #include "ap/ieee802_11.h"
14 #include "ap/sta_info.h"
15 #include "esp_wpa3_i.h"
16 #include "endian.h"
17 #include "esp_hostap.h"
18 #include <inttypes.h>
19 #include <zephyr/kernel.h>
20 static struct sae_pt *g_sae_pt;
21 static struct sae_data g_sae_data;
22 static struct wpabuf *g_sae_token = NULL;
23 static struct wpabuf *g_sae_commit = NULL;
24 static struct wpabuf *g_sae_confirm = NULL;
25 int g_allowed_groups[] = { IANA_SECP256R1, 0 };
26 
wpa3_build_sae_commit(u8 * bssid,size_t * sae_msg_len)27 static esp_err_t wpa3_build_sae_commit(u8 *bssid, size_t *sae_msg_len)
28 {
29     int default_group = IANA_SECP256R1;
30     u32 len = 0;
31     uint8_t use_pt = 0;
32     u8 own_addr[ETH_ALEN];
33     const u8 *pw = (const u8 *)esp_wifi_sta_get_prof_password_internal();
34     struct wifi_ssid *ssid = esp_wifi_sta_get_prof_ssid_internal();
35     uint8_t sae_pwe = esp_wifi_get_config_sae_pwe_h2e_internal(WIFI_IF_STA);
36     char sae_pwd_id[SAE_H2E_IDENTIFIER_LEN+1] = {0};
37     bool valid_pwd_id = false;
38     const u8 *rsnxe;
39     u8 rsnxe_capa = 0;
40 
41    rsnxe = esp_wifi_sta_get_rsnxe(bssid);
42    if (rsnxe && rsnxe[1] >= 1) {
43        rsnxe_capa = rsnxe[2];
44    }
45 
46 #ifdef CONFIG_SAE_PK
47     bool use_pk = false;
48     uint8_t sae_pk_mode = esp_wifi_sta_get_config_sae_pk_internal();
49 
50     if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
51          sae_pk_mode != WPA3_SAE_PK_MODE_DISABLED &&
52          ((pw && sae_pk_valid_password((const char*)pw)))) {
53         use_pt = 1;
54         use_pk = true;
55     }
56 
57     if (sae_pk_mode == WPA3_SAE_PK_MODE_ONLY && !use_pk) {
58         wpa_printf(MSG_DEBUG,
59            "SAE: Cannot use PK with the selected AP");
60         return ESP_FAIL;
61     }
62 #endif /* CONFIG_SAE_PK */
63     if (use_pt || sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
64         sae_pwe == SAE_PWE_BOTH) {
65         use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
66 
67         if ((sae_pwe == SAE_PWE_HASH_TO_ELEMENT
68 #ifdef CONFIG_SAE_PK
69             || (use_pk && sae_pk_mode == WPA3_SAE_PK_MODE_ONLY)
70 #endif /* CONFIG_SAE_PK */
71             ) && !use_pt) {
72             wpa_printf(MSG_DEBUG,
73               "SAE: Cannot use H2E with the selected AP");
74             return ESP_FAIL;
75         }
76     }
77 
78 
79     if (use_pt != 0) {
80         memcpy(sae_pwd_id, esp_wifi_sta_get_sae_identifier_internal(), SAE_H2E_IDENTIFIER_LEN);
81         if (os_strlen(sae_pwd_id) > 0) {
82             valid_pwd_id = true;
83         }
84     }
85 
86     if (use_pt && !g_sae_pt) {
87         g_sae_pt = sae_derive_pt(g_allowed_groups, ssid->ssid, ssid->len, pw, strlen((const char *)pw), valid_pwd_id ? sae_pwd_id : NULL);
88     }
89 
90     if (wpa_sta_cur_pmksa_matches_akm()) {
91         wpa_printf(MSG_INFO, "wpa3: Skip SAE and use cached PMK instead");
92         *sae_msg_len = 0;
93         return ESP_FAIL;
94     }
95 
96     if (g_sae_commit) {
97         wpabuf_free(g_sae_commit);
98         g_sae_commit = NULL;
99     }
100 
101     if (g_sae_token) {
102         len = wpabuf_len(g_sae_token);
103         goto reuse_data;
104     }
105 
106     memset(&g_sae_data, 0, sizeof(g_sae_data));
107     if (sae_set_group(&g_sae_data, default_group)) {
108         wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group);
109         return ESP_FAIL;
110     }
111 
112     esp_wifi_get_macaddr_internal(WIFI_IF_STA, own_addr);
113     if (!bssid) {
114         wpa_printf(MSG_ERROR, "wpa3: cannot prepare SAE commit with no BSSID!");
115         return ESP_FAIL;
116     }
117 
118     if (use_pt &&
119             sae_prepare_commit_pt(&g_sae_data, g_sae_pt,
120                     own_addr, bssid, NULL, NULL) < 0) {
121         wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!");
122         return ESP_FAIL;
123     }
124     if (!use_pt &&
125             sae_prepare_commit(own_addr, bssid, pw,
126                     strlen((const char *)pw),
127                     &g_sae_data) < 0) {
128         wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!");
129         return ESP_FAIL;
130     }
131 
132 #ifdef CONFIG_SAE_PK
133     if (g_sae_data.tmp && use_pt && use_pk) {
134         g_sae_data.pk = 1;
135         os_memcpy(g_sae_data.tmp->own_addr,own_addr, ETH_ALEN );
136         os_memcpy(g_sae_data.tmp->peer_addr, bssid, ETH_ALEN);
137         sae_pk_set_password(&g_sae_data,(const char*) pw);
138     }
139 #endif
140 
141 reuse_data:
142     len += SAE_COMMIT_MAX_LEN;
143     g_sae_commit = wpabuf_alloc(len);
144     if (!g_sae_commit) {
145         wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg");
146         return ESP_FAIL;
147     }
148 
149     if (sae_write_commit(&g_sae_data, g_sae_commit, g_sae_token, valid_pwd_id ? sae_pwd_id : NULL) != ESP_OK) {
150         wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg");
151         wpabuf_free(g_sae_commit);
152         g_sae_commit = NULL;
153         return ESP_FAIL;
154     }
155 
156     if (g_sae_token) {
157         wpabuf_free(g_sae_token);
158         g_sae_token = NULL;
159     }
160     g_sae_data.state = SAE_COMMITTED;
161 
162     return ESP_OK;
163 }
164 
wpa3_build_sae_confirm(void)165 static esp_err_t wpa3_build_sae_confirm(void)
166 {
167     if (g_sae_data.state != SAE_COMMITTED)
168         return ESP_FAIL;
169 
170     if (g_sae_confirm) {
171         wpabuf_free(g_sae_confirm);
172         g_sae_confirm = NULL;
173     }
174 
175     g_sae_confirm = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
176     if (!g_sae_confirm) {
177         wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for confirm msg");
178         return ESP_FAIL;
179     }
180 
181     if (sae_write_confirm(&g_sae_data, g_sae_confirm) != ESP_OK) {
182         wpa_printf(MSG_ERROR, "wpa3: failed to write SAE confirm msg");
183         wpabuf_free(g_sae_confirm);
184         g_sae_confirm = NULL;
185         return ESP_FAIL;
186     }
187     g_sae_data.state = SAE_CONFIRMED;
188 
189     return ESP_OK;
190 }
191 
esp_wpa3_free_sae_data(void)192 void esp_wpa3_free_sae_data(void)
193 {
194     if (g_sae_commit) {
195         wpabuf_free(g_sae_commit);
196         g_sae_commit = NULL;
197     }
198 
199     if (g_sae_confirm) {
200         wpabuf_free(g_sae_confirm);
201         g_sae_confirm = NULL;
202     }
203     sae_clear_data(&g_sae_data);
204     if (g_sae_pt) {
205         sae_deinit_pt(g_sae_pt);
206         g_sae_pt = NULL;
207     }
208 }
209 
wpa3_build_sae_msg(u8 * bssid,u32 sae_msg_type,size_t * sae_msg_len)210 static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, size_t *sae_msg_len)
211 {
212     u8 *buf = NULL;
213 
214     switch (sae_msg_type) {
215         case SAE_MSG_COMMIT:
216             /* Do not go for SAE when WPS is ongoing */
217             if (esp_wifi_get_wps_status_internal() != WPS_STATUS_DISABLE) {
218                 *sae_msg_len = 0;
219                 return NULL;
220             }
221             if (ESP_OK != wpa3_build_sae_commit(bssid, sae_msg_len))
222                 return NULL;
223             *sae_msg_len = wpabuf_len(g_sae_commit);
224             buf = wpabuf_mhead_u8(g_sae_commit);
225             break;
226         case SAE_MSG_CONFIRM:
227             if (ESP_OK != wpa3_build_sae_confirm())
228                 return NULL;
229             *sae_msg_len = wpabuf_len(g_sae_confirm);
230             buf = wpabuf_mhead_u8(g_sae_confirm);
231             break;
232         default:
233             break;
234     }
235 
236     return buf;
237 }
238 
wpa3_sae_is_group_enabled(int group)239 static int wpa3_sae_is_group_enabled(int group)
240 {
241     int *groups = NULL;
242     int default_groups[] = { 19, 0 };
243     int i;
244 
245     if (!groups) {
246         groups = default_groups;
247     }
248 
249     for (i = 0; groups[i] > 0; i++) {
250         if (groups[i] == group) {
251             return 1;
252         }
253     }
254 
255     return 0;
256 }
257 
wpa3_check_sae_rejected_groups(const struct wpabuf * groups)258 static int wpa3_check_sae_rejected_groups(const struct wpabuf *groups)
259 {
260     size_t i, count, len;
261     const u8 *pos;
262 
263     if (!groups) {
264         return 0;
265     }
266 
267     pos = wpabuf_head(groups);
268     len = wpabuf_len(groups);
269     if (len & 1) {
270         wpa_printf(MSG_DEBUG,
271                    "SAE: Invalid length of the Rejected Groups element payload: %zu",
272                    len);
273         return 1;
274     }
275     count = len / 2;
276     for (i = 0; i < count; i++) {
277         int enabled;
278         u16 group;
279 
280         group = WPA_GET_LE16(pos);
281         pos += 2;
282         enabled = wpa3_sae_is_group_enabled(group);
283         wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
284                    group, enabled ? "enabled" : "disabled");
285         if (enabled) {
286             return 1;
287         }
288     }
289 
290     return 0;
291 }
292 
wpa3_parse_sae_commit(u8 * buf,u32 len,u16 status)293 static int wpa3_parse_sae_commit(u8 *buf, u32 len, u16 status)
294 {
295     int ret;
296 
297     if (g_sae_data.state != SAE_COMMITTED) {
298         wpa_printf(MSG_DEBUG, "wpa3: Discarding commit frame received in state %d", g_sae_data.state);
299         return ESP_ERR_WIFI_DISCARD;
300     }
301 
302     if (status == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ) {
303         if (g_sae_token)
304             wpabuf_free(g_sae_token);
305         if (g_sae_data.h2e) {
306             if ((buf[2] != WLAN_EID_EXTENSION) ||
307                 (buf[3] == 0) ||
308                 (buf[3] > len - 4) ||
309                 (buf[4] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN)) {
310                 wpa_printf(MSG_ERROR, "Invalid SAE anti-clogging token container header");
311                 return ESP_FAIL;
312             }
313             g_sae_token = wpabuf_alloc_copy(buf + 5, len - 5);
314         } else {
315             g_sae_token = wpabuf_alloc_copy(buf + 2, len - 2);
316         }
317         return ESP_OK;
318     }
319 
320     ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups,
321                            (status == WLAN_STATUS_SAE_HASH_TO_ELEMENT || status == WLAN_STATUS_SAE_PK));
322     if (ret == SAE_SILENTLY_DISCARD) {
323         wpa_printf(MSG_DEBUG, "wpa3: Discarding commit frame due to reflection attack");
324         return ESP_ERR_WIFI_DISCARD;
325     } else if (ret) {
326         wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret);
327         return ret;
328     }
329     if (g_sae_data.tmp && wpa3_check_sae_rejected_groups(g_sae_data.tmp->peer_rejected_groups)) {
330         return -1;
331     }
332 
333     ret = sae_process_commit(&g_sae_data);
334     if (ret) {
335         wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret);
336         return ret;
337     }
338 
339     return ESP_OK;
340 }
341 
wpa3_parse_sae_confirm(u8 * buf,u32 len)342 static int wpa3_parse_sae_confirm(u8 *buf, u32 len)
343 {
344     if (g_sae_data.state != SAE_CONFIRMED) {
345         wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
346                    g_sae_data.state);
347         return ESP_FAIL;
348     }
349 
350     if (sae_check_confirm(&g_sae_data, buf, len) != ESP_OK) {
351         wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE confirm");
352         return ESP_FAIL;
353     }
354     g_sae_data.state = SAE_ACCEPTED;
355 
356     wpa_set_pmk(g_sae_data.pmk, g_sae_data.pmk_len, g_sae_data.pmkid, true);
357 
358     return ESP_OK;
359 }
360 
wpa3_parse_sae_msg(u8 * buf,size_t len,u32 sae_msg_type,u16 status)361 static int wpa3_parse_sae_msg(u8 *buf, size_t len, u32 sae_msg_type, u16 status)
362 {
363     int ret = ESP_OK;
364 
365     switch (sae_msg_type) {
366         case SAE_MSG_COMMIT:
367             ret = wpa3_parse_sae_commit(buf, len, status);
368             break;
369         case SAE_MSG_CONFIRM:
370             ret = wpa3_parse_sae_confirm(buf, len);
371             esp_wpa3_free_sae_data();
372             break;
373         default:
374             wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%" PRId32 ")!", sae_msg_type);
375             ret = ESP_FAIL;
376             break;
377     }
378 
379     return ret;
380 }
381 
esp_wifi_register_wpa3_cb(struct wpa_funcs * wpa_cb)382 void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb)
383 {
384     wpa_cb->wpa3_build_sae_msg = wpa3_build_sae_msg;
385     wpa_cb->wpa3_parse_sae_msg = wpa3_parse_sae_msg;
386 }
387 
esp_wifi_unregister_wpa3_cb(void)388 void esp_wifi_unregister_wpa3_cb(void)
389 {
390     extern struct wpa_funcs *wpa_cb;
391 
392     wpa_cb->wpa3_build_sae_msg = NULL;
393     wpa_cb->wpa3_parse_sae_msg = NULL;
394 
395 }
396 #endif /* CONFIG_WPA3_SAE */
397 
398 #ifdef CONFIG_SAE
399 
400 static void *g_wpa3_hostap_task_hdl = NULL;
401 static void *g_wpa3_hostap_evt_queue = NULL;
402 struct k_sem * g_wpa3_hostap_auth_api_lock = NULL;
403 
wpa3_hostap_post_evt(uint32_t evt_id,uint32_t data)404 int wpa3_hostap_post_evt(uint32_t evt_id, uint32_t data)
405 {
406     wpa3_hostap_auth_event_t *evt = os_zalloc(sizeof(wpa3_hostap_auth_event_t));
407     if (evt == NULL) {
408         return ESP_FAIL;
409     }
410     evt->id = evt_id;
411     evt->data = data;
412 
413     if (g_wpa3_hostap_auth_api_lock) {
414         WPA3_HOSTAP_AUTH_API_LOCK();
415         if (g_wpa3_hostap_evt_queue == NULL) {
416             WPA3_HOSTAP_AUTH_API_UNLOCK();
417             os_free(evt);
418             wpa_printf(MSG_DEBUG, "hostap evt queue NULL");
419             return ESP_FAIL;
420         }
421     } else {
422         os_free(evt);
423         wpa_printf(MSG_DEBUG, "g_wpa3_hostap_auth_api_lock not found");
424         return ESP_FAIL;
425     }
426     if (evt->id == SIG_WPA3_RX_CONFIRM || evt->id == SIG_TASK_DEL) {
427         /* prioritising confirm for completing handshake for committed sta */
428         if (os_queue_send_to_front(g_wpa3_hostap_evt_queue, &evt, 0) != pdPASS) {
429             WPA3_HOSTAP_AUTH_API_UNLOCK();
430             wpa_printf(MSG_DEBUG, "failed to add msg to queue front");
431             os_free(evt);
432             return ESP_FAIL;
433         }
434     } else {
435         if (os_queue_send(g_wpa3_hostap_evt_queue, &evt, 0) != pdPASS) {
436             WPA3_HOSTAP_AUTH_API_UNLOCK();
437             os_free(evt);
438             wpa_printf(MSG_DEBUG, "failed to send msg to queue");
439             return ESP_FAIL;
440         }
441     }
442     if (evt_id != SIG_TASK_DEL) {
443         /* For SIG_TASK_DEL, WPA3_HOSTAP_AUTH_API_UNLOCK will be after clean up of hostapd_data */
444         WPA3_HOSTAP_AUTH_API_UNLOCK();
445     }
446     return ESP_OK;
447 }
448 
wpa3_process_rx_commit(wpa3_hostap_auth_event_t * evt)449 static void wpa3_process_rx_commit(wpa3_hostap_auth_event_t *evt)
450 {
451     struct hostapd_sae_commit_queue *frm;
452     struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal();
453     struct sta_info *sta = NULL;
454     int ret;
455     frm = dl_list_first(&hapd->sae_commit_queue,
456                         struct hostapd_sae_commit_queue, list);
457     if (!frm) {
458         return;
459     }
460 
461     dl_list_del(&frm->list);
462     wpa_printf(MSG_DEBUG, "SAE: Process next available message from queue");
463 
464     sta = ap_get_sta(hapd, frm->bssid);
465     if (!sta) {
466         sta = ap_sta_add(hapd, frm->bssid);
467         if (!sta) {
468             wpa_printf(MSG_DEBUG, "ap_sta_add() failed");
469             ret = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
470             if (esp_send_sae_auth_reply(hapd, frm->bssid, frm->bssid, WLAN_AUTH_SAE,
471                                         frm->auth_transaction, ret, NULL,
472                                         0) != 0) {
473                 wpa_printf(MSG_INFO, "esp_send_sae_auth_reply: send failed");
474             }
475             goto free;
476         }
477     }
478 
479     if (sta->lock && os_semphr_take(sta->lock, 0)) {
480         sta->sae_commit_processing = true;
481         ret = handle_auth_sae(hapd, sta, frm->msg, frm->len, frm->bssid, frm->auth_transaction, frm->status);
482 
483         if (sta->remove_pending) {
484             ap_free_sta(hapd, sta);
485             goto free;
486         }
487         sta->sae_commit_processing = false;
488         os_semphr_give(sta->lock);
489         uint16_t aid = 0;
490         if (ret != WLAN_STATUS_SUCCESS &&
491             ret != WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ) {
492             esp_wifi_ap_get_sta_aid(frm->bssid, &aid);
493             if (aid == 0) {
494                 esp_wifi_ap_deauth_internal(frm->bssid, ret);
495             }
496         }
497     }
498 
499 free:
500     os_free(frm);
501 }
502 
wpa3_process_rx_confirm(wpa3_hostap_auth_event_t * evt)503 static void wpa3_process_rx_confirm(wpa3_hostap_auth_event_t *evt)
504 {
505     struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal();
506     struct sta_info *sta = NULL;
507     int ret = WLAN_STATUS_SUCCESS;
508     struct sae_hostap_confirm_data *frm = (struct sae_hostap_confirm_data *)evt->data;
509     if (!frm) {
510         return;
511     }
512     sta = ap_get_sta(hapd, frm->bssid);
513     if (!sta) {
514         os_free(frm);
515         return;
516     }
517 
518     if (sta->lock && os_semphr_take(sta->lock, 0)) {
519         ret = handle_auth_sae(hapd, sta, frm->msg, frm->len, frm->bssid, frm->auth_transaction, frm->status);
520 
521         if (sta->remove_pending) {
522             ap_free_sta(hapd, sta);
523             goto done;
524         }
525         if (ret == WLAN_STATUS_SUCCESS) {
526             if (esp_wifi_ap_notify_node_sae_auth_done(frm->bssid) != true) {
527                 ap_free_sta(hapd, sta);
528                 goto done;
529             }
530         }
531         os_semphr_give(sta->lock);
532         if (ret != WLAN_STATUS_SUCCESS) {
533             uint16_t aid = 0;
534             esp_wifi_ap_get_sta_aid(frm->bssid, &aid);
535             if (aid == 0) {
536                 esp_wifi_ap_deauth_internal(frm->bssid, ret);
537             }
538         }
539     }
540 done:
541     os_free(frm);
542 }
543 
esp_wpa3_hostap_task(void * pvParameters)544 static void esp_wpa3_hostap_task(void *pvParameters)
545 {
546     wpa3_hostap_auth_event_t *evt;
547     bool task_del = false;
548 
549     while (1) {
550         if (os_queue_recv(g_wpa3_hostap_evt_queue, &evt, portMAX_DELAY) == 1) {
551             switch (evt->id) {
552             case SIG_WPA3_RX_COMMIT: {
553                 wpa3_process_rx_commit(evt);
554                 break;
555             }
556             case SIG_WPA3_RX_CONFIRM: {
557                 wpa3_process_rx_confirm(evt);
558                 break;
559             }
560             case SIG_TASK_DEL:
561                 task_del = true;
562                 break;
563             default:
564                 break;
565             }
566             os_free(evt);
567 
568             if (task_del) {
569                 break;
570             }
571         }
572     }
573     uint32_t items_in_queue = os_queue_msg_waiting(g_wpa3_hostap_evt_queue);
574     while(items_in_queue--) {
575         /* Free events posted to queue */
576         os_queue_recv(g_wpa3_hostap_evt_queue, &evt, portMAX_DELAY);
577         if (evt->id == SIG_WPA3_RX_CONFIRM) {
578             os_free((void *)evt->data);
579         }
580         os_free(evt);
581     }
582     os_queue_delete(g_wpa3_hostap_evt_queue);
583     g_wpa3_hostap_evt_queue = NULL;
584 
585     if (g_wpa3_hostap_auth_api_lock) {
586         WPA3_HOSTAP_AUTH_API_UNLOCK();
587     }
588     /* At this point, task is deleted*/
589     os_task_delete(NULL);
590 }
591 
wpa3_hostap_auth_init(void * data)592 int wpa3_hostap_auth_init(void *data)
593 {
594     if (g_wpa3_hostap_evt_queue) {
595         wpa_printf(MSG_ERROR, "esp_wpa3_hostap_task has already been initialised");
596         return ESP_OK;
597     }
598 
599     if (g_wpa3_hostap_auth_api_lock == NULL) {
600         g_wpa3_hostap_auth_api_lock = os_semphr_create(1, 1);
601         if (!g_wpa3_hostap_auth_api_lock) {
602             wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create WPA3 hostap auth API lock");
603             return ESP_FAIL;
604         }
605     }
606 
607     g_wpa3_hostap_evt_queue =  os_queue_create(10, sizeof(wpa3_hostap_auth_event_t));
608     if (!g_wpa3_hostap_evt_queue) {
609         wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create queue");
610         return ESP_FAIL;
611     }
612 
613     if (os_task_create(esp_wpa3_hostap_task, "esp_wpa3_hostap_task",
614                     WPA3_HOSTAP_HANDLE_AUTH_TASK_STACK_SIZE, NULL,
615                     WPA3_HOSTAP_HANDLE_AUTH_TASK_PRIORITY,
616                     &g_wpa3_hostap_task_hdl) != pdPASS) {
617         wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create task");
618         os_queue_delete(g_wpa3_hostap_evt_queue);
619         g_wpa3_hostap_evt_queue = NULL;
620         return ESP_FAIL;
621     }
622 
623     struct hostapd_data *hapd = (struct hostapd_data *)data;
624     dl_list_init(&hapd->sae_commit_queue);
625     return ESP_OK;
626 }
627 
wpa3_hostap_auth_deinit(void)628 bool wpa3_hostap_auth_deinit(void)
629 {
630     if (wpa3_hostap_post_evt(SIG_TASK_DEL, 0) != 0) {
631         wpa_printf(MSG_DEBUG, "failed to send task delete event");
632         return false;
633     } else {
634         return true;
635     }
636 }
637 
wpa3_hostap_handle_auth(u8 * buf,size_t len,u32 auth_transaction,u16 status,u8 * bssid)638 static int wpa3_hostap_handle_auth(u8 *buf, size_t len, u32 auth_transaction, u16 status, u8 *bssid)
639 {
640     struct hostapd_data *hapd = (struct hostapd_data *)esp_wifi_get_hostap_private_internal();
641     if (!hapd) {
642         return ESP_FAIL;
643     }
644     struct sta_info *sta = ap_get_sta(hapd, bssid);
645     if (auth_transaction == SAE_MSG_COMMIT) {
646         if (sta && sta->sae_commit_processing) {
647             /* Ignore commit msg as we are already processing commit msg for this station */
648             return ESP_OK;
649         }
650         return auth_sae_queue(hapd, buf, len, bssid, status, auth_transaction);
651     }
652 
653     if (sta && auth_transaction == SAE_MSG_CONFIRM) {
654         struct sae_hostap_confirm_data *frm = os_malloc(sizeof(struct sae_hostap_confirm_data) + len);
655         if (!frm) {
656             wpa_printf(MSG_ERROR, "failed to allocate memory for confirm event");
657             return ESP_FAIL;
658         }
659         frm->len = len;
660         os_memcpy(frm->bssid, bssid, ETH_ALEN);
661         frm->auth_transaction = auth_transaction;
662         frm->status = status;
663         os_memcpy(frm->msg, buf, len);
664         if (wpa3_hostap_post_evt(SIG_WPA3_RX_CONFIRM, (u32)frm) != 0) {
665             wpa_printf(MSG_ERROR, "failed to queue confirm build event");
666             os_free(frm);
667             return ESP_FAIL;
668         }
669     }
670     return ESP_OK;
671 }
672 
esp_send_sae_auth_reply(struct hostapd_data * hapd,const u8 * dst,const u8 * bssid,u16 auth_alg,u16 auth_transaction,u16 resp,const u8 * ies,size_t ies_len)673 int esp_send_sae_auth_reply(struct hostapd_data *hapd,
674                             const u8 *dst, const u8 *bssid,
675                             u16 auth_alg, u16 auth_transaction, u16 resp,
676                             const u8 *ies, size_t ies_len)
677 {
678     int reply_res = ESP_FAIL;
679     ies_len += 3 * sizeof(uint16_t);
680 
681     wifi_mgmt_frm_req_t *req = os_zalloc(sizeof(*req) + ies_len);
682     if (!req) {
683         wpa_printf(MSG_ERROR, "failed to send sae auth reply");
684         return reply_res;
685     }
686     ((uint16_t *)req->data)[0] = htole16(auth_alg);
687     ((uint16_t *)req->data)[1] = htole16(auth_transaction);
688     ((uint16_t *)req->data)[2] = htole16(resp);
689     os_memcpy(&((uint16_t *)req->data)[3], ies, ies_len - 3 * sizeof(uint16_t));
690 
691     req->ifx = WIFI_IF_AP;
692     req->subtype = (WLAN_FC_STYPE_AUTH << 4);
693     req->data_len = ies_len;
694     os_memcpy(req->da, bssid, ETH_ALEN);
695 
696     if (esp_wifi_send_mgmt_frm_internal(req) != 0) {
697         wpa_printf(MSG_INFO, "%s: send failed", __func__);
698     } else {
699         reply_res = ESP_OK;
700     }
701 
702     os_free(req);
703     return reply_res;
704 }
705 
esp_wifi_register_wpa3_ap_cb(struct wpa_funcs * wpa_cb)706 void esp_wifi_register_wpa3_ap_cb(struct wpa_funcs *wpa_cb)
707 {
708     wpa_cb->wpa3_hostap_handle_auth = wpa3_hostap_handle_auth;
709 }
710 
711 #endif /* CONFIG_SAE */
712