1 /*
2  * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "utils/includes.h"
8 #include "utils/common.h"
9 #include "utils/eloop.h"
10 #include "common/defs.h"
11 
12 #include "esp_dpp_i.h"
13 #include "esp_dpp.h"
14 #include "esp_wpa.h"
15 #include "esp_event.h"
16 #include "esp_wifi.h"
17 #include "common/ieee802_11_defs.h"
18 #include "esp_wps_i.h"
19 
20 #ifdef CONFIG_DPP
21 static void *s_dpp_task_hdl = NULL;
22 static void *s_dpp_evt_queue = NULL;
23 static void *s_dpp_api_lock = NULL;
24 
25 static bool s_dpp_listen_in_progress;
26 static struct esp_dpp_context_t s_dpp_ctx;
27 static wifi_action_rx_cb_t s_action_rx_cb = esp_supp_rx_action;
28 
29 #define DPP_API_LOCK() os_mutex_lock(s_dpp_api_lock)
30 #define DPP_API_UNLOCK() os_mutex_unlock(s_dpp_api_lock)
31 
32 struct action_rx_param {
33     u8 sa[ETH_ALEN];
34     u32 channel;
35     u32 frm_len;
36     u32 vendor_data_len;
37     struct ieee80211_action *action_frm;
38 };
39 
40 
esp_dpp_post_evt(uint32_t evt_id,uint32_t data)41 static int esp_dpp_post_evt(uint32_t evt_id, uint32_t data)
42 {
43     dpp_event_t *evt = os_zalloc(sizeof(dpp_event_t));
44     int ret = ESP_OK;
45 
46     if (evt == NULL) {
47         ret = ESP_ERR_NO_MEM;
48         goto end;
49     }
50     evt->id = evt_id;
51     evt->data = data;
52     if (s_dpp_api_lock) {
53         DPP_API_LOCK();
54     } else {
55         ret = ESP_ERR_DPP_FAILURE;
56         goto end;
57     }
58     if (os_queue_send(s_dpp_evt_queue, &evt, os_task_ms_to_tick(10)) != TRUE) {
59         DPP_API_UNLOCK();
60         ret = ESP_ERR_DPP_FAILURE;
61         goto end;
62     }
63     if (evt_id != SIG_DPP_DEL_TASK) {
64         DPP_API_UNLOCK();
65     }
66     wpa_printf(MSG_DEBUG,"DPP: Sent event %d to DPP task", evt_id);
67 
68     return ret;
69 end:
70     if (evt) {
71         os_free(evt);
72     }
73     wpa_printf(MSG_ERROR,"DPP: Failed to send event %d to DPP task", evt_id);
74     return ret;
75 }
76 
esp_dpp_deinit_auth(void)77 static uint8_t esp_dpp_deinit_auth(void)
78 {
79     esp_err_t ret = esp_dpp_post_evt(SIG_DPP_DEINIT_AUTH, 0);
80     if (ESP_OK != ret) {
81             wpa_printf(MSG_ERROR, "Failed to post DPP auth deinit to DPP Task(status=%d)", ret);
82             return ret;
83    }
84    return ESP_OK;
85 }
86 
esp_dpp_call_cb(esp_supp_dpp_event_t evt,void * data)87 static void esp_dpp_call_cb(esp_supp_dpp_event_t evt, void *data)
88 {
89     if (s_dpp_ctx.dpp_auth) {
90         esp_dpp_deinit_auth();
91     }
92     s_dpp_ctx.dpp_event_cb(evt, data);
93 }
94 
esp_dpp_auth_conf_wait_timeout(void * eloop_ctx,void * timeout_ctx)95 static void esp_dpp_auth_conf_wait_timeout(void *eloop_ctx, void *timeout_ctx)
96 {
97     if (!s_dpp_ctx.dpp_auth || !s_dpp_ctx.dpp_auth->waiting_auth_conf)
98         return;
99 
100     wpa_printf(MSG_DEBUG,
101            "DPP: Terminate authentication exchange due to Auth Confirm timeout");
102     esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_AUTH_TIMEOUT);
103 }
104 
esp_dpp_send_action_frame(uint8_t * dest_mac,const uint8_t * buf,uint32_t len,uint8_t channel,uint32_t wait_time_ms)105 static esp_err_t esp_dpp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len,
106                                            uint8_t channel, uint32_t wait_time_ms)
107 {
108     wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + len);;
109     if (!req) {
110         return ESP_FAIL;;
111     }
112 
113     req->ifx = WIFI_IF_STA;
114     memcpy(req->dest_mac, dest_mac, ETH_ALEN);
115     req->no_ack = false;
116     req->data_len = len;
117     req->rx_cb = s_action_rx_cb;
118     memcpy(req->data, buf, req->data_len);
119 
120     wpa_printf(MSG_DEBUG, "DPP: Mgmt Tx - MAC:" MACSTR ", Channel-%d, WaitT-%d",
121                MAC2STR(dest_mac), channel, wait_time_ms);
122 
123     if (ESP_OK != esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_REQ, channel,
124                                          wait_time_ms, req)) {
125         wpa_printf(MSG_ERROR, "DPP: Failed to perform offchannel operation");
126         esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE);
127         os_free(req);
128         return ESP_FAIL;;
129     }
130 
131     os_free(req);
132 
133     return ESP_OK;
134 }
135 
esp_dpp_rx_auth_req(struct action_rx_param * rx_param,uint8_t * dpp_data)136 static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_data)
137 {
138     size_t len = rx_param->vendor_data_len - 2;
139     const u8 *r_bootstrap, *i_bootstrap;
140     u16 r_bootstrap_len, i_bootstrap_len;
141     struct dpp_bootstrap_info *own_bi;
142     int rc;
143 
144     wpa_printf(MSG_INFO, "DPP: Authentication Request from " MACSTR, MAC2STR(rx_param->sa));
145 
146     r_bootstrap = dpp_get_attr(dpp_data, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
147                                &r_bootstrap_len);
148     if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
149         wpa_printf(MSG_INFO, "DPP: Missing or invalid Responder Bootstrapping Key Hash attribute");
150         rc = ESP_ERR_DPP_INVALID_ATTR;
151         goto fail;
152     }
153     wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", r_bootstrap, r_bootstrap_len);
154 
155     i_bootstrap = dpp_get_attr(dpp_data, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH,
156                                &i_bootstrap_len);
157     if (!i_bootstrap || i_bootstrap_len != SHA256_MAC_LEN) {
158         wpa_printf(MSG_INFO, "DPP: Missing or invalid Initiator Bootstrapping Key Hash attribute");
159         rc = ESP_ERR_DPP_INVALID_ATTR;
160         goto fail;
161     }
162     wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", i_bootstrap, i_bootstrap_len);
163 
164     own_bi = dpp_bootstrap_get_id(s_dpp_ctx.dpp_global, s_dpp_ctx.id);
165     /* Try to find own and peer bootstrapping key matches based on the
166      * received hash values */
167     if (os_memcmp(own_bi->pubkey_hash, r_bootstrap, SHA256_MAC_LEN)) {
168         wpa_printf(MSG_INFO, "DPP: No matching own bootstrapping key found as responder - ignore message");
169         rc = ESP_ERR_DPP_INVALID_ATTR;
170         goto fail;
171     }
172     if (s_dpp_ctx.dpp_auth) {
173         wpa_printf(MSG_DEBUG, "DPP: Already in DPP authentication exchange - ignore new one");
174         return;
175     }
176     s_dpp_ctx.dpp_auth = dpp_auth_req_rx(NULL, DPP_CAPAB_ENROLLEE, 0, NULL,
177                                          own_bi, rx_param->channel,
178                                          (const u8 *)&rx_param->action_frm->u.public_action.v, dpp_data, len);
179     os_memcpy(s_dpp_ctx.dpp_auth->peer_mac_addr, rx_param->sa, ETH_ALEN);
180     wpa_printf(MSG_DEBUG, "DPP: Sending authentication response.");
181     esp_dpp_send_action_frame(rx_param->sa, wpabuf_head(s_dpp_ctx.dpp_auth->resp_msg),
182                           wpabuf_len(s_dpp_ctx.dpp_auth->resp_msg),
183                           rx_param->channel, OFFCHAN_TX_WAIT_TIME);
184     eloop_cancel_timeout(esp_dpp_auth_conf_wait_timeout, NULL,NULL);
185     eloop_register_timeout(ESP_DPP_AUTH_TIMEOUT_SECS, 0, esp_dpp_auth_conf_wait_timeout,NULL, NULL);
186 
187     return;
188 fail:
189     esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)rc);
190 }
191 
gas_query_req_tx(struct dpp_authentication * auth)192 static void gas_query_req_tx(struct dpp_authentication *auth)
193 {
194     struct wpabuf *buf;
195     int supp_op_classes[] = {81, 0};
196 
197     buf = dpp_build_conf_req_helper(auth, NULL, 0, NULL,
198                                     supp_op_classes);
199     if (!buf) {
200         wpa_printf(MSG_DEBUG, "DPP: No configuration request data available");
201         esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE);
202         return;
203     }
204 
205     wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR " (chan %u)",
206                MAC2STR(auth->peer_mac_addr), auth->curr_chan);
207 
208     esp_dpp_send_action_frame(auth->peer_mac_addr, wpabuf_head(buf), wpabuf_len(buf),
209                           auth->curr_chan, OFFCHAN_TX_WAIT_TIME);
210 }
211 
esp_dpp_handle_config_obj(struct dpp_authentication * auth,struct dpp_config_obj * conf)212 static int esp_dpp_handle_config_obj(struct dpp_authentication *auth,
213                                      struct dpp_config_obj *conf)
214 {
215     wifi_config_t *wifi_cfg = &s_dpp_ctx.wifi_cfg;
216 
217     os_memset(wifi_cfg, 0, sizeof(wifi_config_t));
218     if (conf->ssid_len) {
219         os_memcpy(wifi_cfg->sta.ssid, conf->ssid, conf->ssid_len);
220     }
221 
222     if (dpp_akm_legacy(conf->akm)) {
223         if (conf->passphrase[0])
224             os_memcpy(wifi_cfg->sta.password, conf->passphrase,
225                       sizeof(wifi_cfg->sta.password));
226         if (conf->akm == DPP_AKM_PSK_SAE) {
227             wifi_cfg->sta.pmf_cfg.required = true;
228         }
229     }
230 
231     if (conf->connector) {
232         /* TODO: Save the Connector and consider using a command
233          * to fetch the value instead of sending an event with
234          * it. The Connector could end up being larger than what
235          * most clients are ready to receive as an event
236          * message. */
237         wpa_printf(MSG_INFO, DPP_EVENT_CONNECTOR "%s",
238                    conf->connector);
239     }
240     if (s_dpp_listen_in_progress) {
241         esp_supp_dpp_stop_listen();
242     }
243     esp_dpp_call_cb(ESP_SUPP_DPP_CFG_RECVD, wifi_cfg);
244 
245     return 0;
246 }
247 
esp_dpp_rx_auth_conf(struct action_rx_param * rx_param,uint8_t * dpp_data)248 static void esp_dpp_rx_auth_conf(struct action_rx_param *rx_param, uint8_t *dpp_data)
249 {
250     struct dpp_authentication *auth = s_dpp_ctx.dpp_auth;
251     struct ieee80211_public_action *public_action =
252             &rx_param->action_frm->u.public_action;
253     size_t len = rx_param->vendor_data_len - 2;
254     int rc;
255 
256     wpa_printf(MSG_DEBUG, "DPP: Authentication Confirmation from " MACSTR,
257                MAC2STR(rx_param->sa));
258 
259     if (!auth) {
260         wpa_printf(MSG_DEBUG, "DPP: No DPP Authentication in progress - drop");
261         rc = ESP_ERR_DPP_FAILURE;
262         goto fail;
263     }
264 
265     if (os_memcmp(rx_param->sa, auth->peer_mac_addr, ETH_ALEN) != 0) {
266         wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
267                    MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
268         rc = ESP_ERR_DPP_FAILURE;
269         goto fail;
270     }
271 
272     eloop_cancel_timeout(esp_dpp_auth_conf_wait_timeout, NULL, NULL);
273 
274     if (dpp_auth_conf_rx(auth, (const u8 *)&public_action->v,
275                          dpp_data, len) < 0) {
276         wpa_printf(MSG_DEBUG, "DPP: Authentication failed");
277         rc = ESP_ERR_DPP_FAILURE;
278         goto fail;
279     }
280 
281     /* Send GAS Query Req */
282     gas_query_req_tx(auth);
283 
284     return;
285 
286 fail:
287     esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)rc);
288 }
289 
esp_dpp_rx_auth(struct action_rx_param * rx_param)290 static void esp_dpp_rx_auth(struct action_rx_param *rx_param)
291 {
292     uint8_t crypto_suit, type;
293     uint8_t *tmp;
294 
295     tmp = rx_param->action_frm->u.public_action.v.pa_vendor_spec.vendor_data;
296     crypto_suit = tmp[0];
297     type = tmp[1];
298 
299     if (crypto_suit != 1) {
300         wpa_printf(MSG_ERROR, "DPP: Unsupported crypto suit");
301         esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_NOT_SUPPORTED);
302         return;
303     }
304 
305     switch (type) {
306     case DPP_PA_AUTHENTICATION_REQ:
307         esp_dpp_rx_auth_req(rx_param, &tmp[2]);
308         break;
309     case DPP_PA_AUTHENTICATION_CONF:
310         esp_dpp_rx_auth_conf(rx_param, &tmp[2]);
311         break;
312     }
313 }
314 
gas_query_resp_rx(struct action_rx_param * rx_param)315 static void gas_query_resp_rx(struct action_rx_param *rx_param)
316 {
317     struct dpp_authentication *auth = s_dpp_ctx.dpp_auth;
318     uint8_t *pos = rx_param->action_frm->u.public_action.v.pa_gas_resp.data;
319     uint8_t *resp = &pos[10];
320     int i, res;
321 
322     if (pos[1] == WLAN_EID_VENDOR_SPECIFIC && pos[2] == 5 &&
323             WPA_GET_BE24(&pos[3]) == OUI_WFA && pos[6] == 0x1a && pos[7] == 1 && auth) {
324         if (dpp_conf_resp_rx(auth, resp, rx_param->vendor_data_len - 2) < 0) {
325             wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
326             goto fail;
327         }
328 
329         for (i = 0; i < auth->num_conf_obj; i++) {
330             res = esp_dpp_handle_config_obj(auth, &auth->conf_obj[i]);
331             if (res < 0) {
332                 goto fail;
333             }
334         }
335     }
336 
337     return;
338 fail:
339     esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_FAILURE);
340 }
341 
esp_dpp_rx_action(struct action_rx_param * rx_param)342 static void esp_dpp_rx_action(struct action_rx_param *rx_param)
343 {
344     if (rx_param->action_frm->category == WLAN_ACTION_PUBLIC) {
345         struct ieee80211_public_action *public_action =
346                 &rx_param->action_frm->u.public_action;
347 
348         wpa_printf(MSG_DEBUG, "DPP: Rx Public Action frame: action - %d",
349                    public_action->action);
350 
351         if (public_action->action == WLAN_PA_VENDOR_SPECIFIC &&
352                 WPA_GET_BE24(public_action->v.pa_vendor_spec.oui) == OUI_WFA &&
353                 public_action->v.pa_vendor_spec.wfa_stype == DPP_OUI_TYPE) {
354 
355             rx_param->vendor_data_len = rx_param->frm_len -
356                                         (size_t)(public_action->v.pa_vendor_spec.vendor_data -
357                                                  (u8 *)rx_param->action_frm);
358 
359             if (s_dpp_listen_in_progress) {
360                 esp_supp_dpp_stop_listen();
361             }
362 
363             esp_dpp_rx_auth(rx_param);
364         } else if (public_action->action == WLAN_PA_GAS_INITIAL_RESP &&
365                    public_action->v.pa_gas_resp.type == WLAN_EID_ADV_PROTO &&
366                    public_action->v.pa_gas_resp.length == 8 &&
367                    public_action->v.pa_gas_resp.status_code == 0) {
368 
369             rx_param->vendor_data_len = rx_param->frm_len -
370                                         (size_t)(public_action->v.pa_gas_resp.data +
371                                                  public_action->v.pa_gas_resp.length -
372                                                  (u8 *)rx_param->action_frm);
373 
374             gas_query_resp_rx(rx_param);
375         }
376     }
377 
378     os_free(rx_param->action_frm);
379     os_free(rx_param);
380 }
381 
esp_dpp_task(void * pvParameters)382 static void esp_dpp_task(void *pvParameters )
383 {
384     dpp_event_t *evt;
385     bool task_del = false;
386 
387     for (;;) {
388         if (os_queue_recv(s_dpp_evt_queue, &evt, OS_BLOCK) == TRUE) {
389             if (evt->id >= SIG_DPP_MAX) {
390                 os_free(evt);
391                 continue;
392             }
393 
394             switch (evt->id) {
395             case SIG_DPP_DEL_TASK:
396                 struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params;
397                 eloop_cancel_timeout(esp_dpp_auth_conf_wait_timeout, NULL, NULL);
398                 if (params->info) {
399                     os_free(params->info);
400                     params->info = NULL;
401                 }
402 
403                 if (s_dpp_ctx.dpp_global) {
404                     dpp_global_deinit(s_dpp_ctx.dpp_global);
405                     s_dpp_ctx.dpp_global = NULL;
406                 }
407                 if (s_dpp_ctx.dpp_auth) {
408                     dpp_auth_deinit(s_dpp_ctx.dpp_auth);
409                     s_dpp_ctx.dpp_auth = NULL;
410                 }
411                 task_del = true;
412                 break;
413 
414             case SIG_DPP_BOOTSTRAP_GEN: {
415                 char *command = (char *)evt->data;
416                 const char *uri;
417 
418                 s_dpp_ctx.id = dpp_bootstrap_gen(s_dpp_ctx.dpp_global, command);
419                 uri = dpp_bootstrap_get_uri(s_dpp_ctx.dpp_global, s_dpp_ctx.id);
420 
421                 esp_dpp_call_cb(ESP_SUPP_DPP_URI_READY, (void *)uri);
422                 os_free(command);
423             }
424             break;
425 
426             case SIG_DPP_RX_ACTION: {
427                 esp_dpp_rx_action((struct action_rx_param *)evt->data);
428             }
429             break;
430 
431             case SIG_DPP_LISTEN_NEXT_CHANNEL: {
432                 struct dpp_bootstrap_params_t *p = &s_dpp_ctx.bootstrap_params;
433                 static int counter;
434                 int channel;
435                 esp_err_t ret = 0;
436 
437                 if (p->num_chan <= 0) {
438                     wpa_printf(MSG_ERROR, "Listen channel not set");
439                     break;
440                 }
441                 channel = p->chan_list[counter++ % p->num_chan];
442                 ret = esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_REQ, channel,
443                                            BOOTSTRAP_ROC_WAIT_TIME, s_action_rx_cb);
444                 if (ret != ESP_OK) {
445                     wpa_printf(MSG_ERROR, "Failed ROC. error : 0x%x", ret);
446                     break;
447                 }
448                 s_dpp_listen_in_progress = true;
449             }
450             break;
451 
452             case SIG_DPP_DEINIT_AUTH: {
453                 if (s_dpp_ctx.dpp_auth) {
454                     dpp_auth_deinit(s_dpp_ctx.dpp_auth);
455                     s_dpp_ctx.dpp_auth = NULL;
456                 }
457                 wpa_printf(MSG_DEBUG, "DPP auth deinintialized");
458             }
459             break;
460 
461             default:
462                 break;
463             }
464 
465             os_free(evt);
466 
467             if (task_del) {
468                 break;
469             }
470         }
471     }
472 
473     os_queue_delete(s_dpp_evt_queue);
474     s_dpp_evt_queue = NULL;
475 
476     if (s_dpp_api_lock) {
477         os_mutex_delete(s_dpp_api_lock);
478         s_dpp_api_lock = NULL;
479     }
480 
481     /* At this point, we completed */
482     os_task_delete(NULL);
483 }
484 
esp_supp_rx_action(uint8_t * hdr,uint8_t * payload,size_t len,uint8_t channel)485 int esp_supp_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel)
486 {
487     struct ieee80211_hdr *rx_hdr = (struct ieee80211_hdr *)hdr;
488     struct action_rx_param *rx_param;
489     int ret = ESP_ERR_NOT_SUPPORTED;
490 
491     if (WLAN_FC_GET_STYPE(rx_hdr->frame_control) == WLAN_FC_STYPE_ACTION) {
492         rx_param = os_zalloc(sizeof(struct action_rx_param));
493         if (!rx_param) {
494             wpa_printf(MSG_ERROR, "Failed to allocate memory for Rx Action");
495             return ESP_ERR_NO_MEM;
496         }
497         os_memcpy(rx_param->sa, rx_hdr->addr2, ETH_ALEN);
498         rx_param->channel = channel;
499         rx_param->action_frm = os_zalloc(len);
500         if (!rx_param->action_frm) {
501             wpa_printf(MSG_ERROR, "Failed to allocate memory for Rx Action");
502             os_free(rx_param);
503             return ESP_ERR_NO_MEM;
504         }
505         rx_param->frm_len = len;
506         os_memcpy(rx_param->action_frm, payload, len);
507 
508         ret = esp_dpp_post_evt(SIG_DPP_RX_ACTION, (u32)rx_param);
509         if (ESP_OK != ret) {
510             wpa_printf(MSG_ERROR, "Failed to post event to DPP Task(status=%d)", ret);
511             os_free(rx_param->action_frm);
512             os_free(rx_param);
513             return ret;
514         }
515     }
516 
517     return ret;
518 }
519 
offchan_event_handler(void * arg,esp_event_base_t event_base,int32_t event_id,void * event_data)520 static void offchan_event_handler(void *arg, esp_event_base_t event_base,
521                                   int32_t event_id, void *event_data)
522 {
523     if (event_id == WIFI_EVENT_ACTION_TX_STATUS) {
524         wifi_event_action_tx_status_t *evt =
525             (wifi_event_action_tx_status_t *)event_data;
526         wpa_printf(MSG_DEBUG, "Mgmt Tx Status - %d, Cookie - 0x%x",
527                    evt->status, (uint32_t)evt->context);
528 
529         if (evt->status) {
530             eloop_cancel_timeout(esp_dpp_auth_conf_wait_timeout, NULL, NULL);
531             if (s_dpp_listen_in_progress) {
532                 esp_supp_dpp_stop_listen();
533             }
534             esp_dpp_call_cb(ESP_SUPP_DPP_FAIL, (void *)ESP_ERR_DPP_TX_FAILURE);
535         }
536 
537     } else if (event_id == WIFI_EVENT_ROC_DONE) {
538         wifi_event_roc_done_t *evt = (wifi_event_roc_done_t *)event_data;
539 
540         if (s_dpp_listen_in_progress && evt->context == (uint32_t)s_action_rx_cb) {
541             esp_dpp_post_evt(SIG_DPP_LISTEN_NEXT_CHANNEL, 0);
542         }
543     }
544 }
545 
esp_dpp_parse_chan_list(const char * chan_list)546 static char *esp_dpp_parse_chan_list(const char *chan_list)
547 {
548     struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params;
549     char *uri_channels = os_zalloc(14 * 6 + 1);
550     const char *pos = chan_list;
551     const char *pos2;
552     char *pos3 = uri_channels;
553     params->num_chan = 0;
554 
555     os_memcpy(pos3, " chan=", strlen(" chan="));
556     pos3 += strlen(" chan=");
557 
558     while (pos && *pos) {
559         int channel;
560         int len = strlen(chan_list);
561 
562         pos2 = pos;
563         while (*pos2 >= '0' && *pos2 <= '9') {
564             pos2++;
565         }
566         if (*pos2 == ',' || *pos2 == ' ' || *pos2 == '\0') {
567             channel = atoi(pos);
568             if (channel < 1 || channel > 14) {
569                 os_free(uri_channels);
570                 return NULL;
571             }
572             params->chan_list[params->num_chan++] = channel;
573             os_memcpy(pos3, "81/", strlen("81/"));
574             pos3 += strlen("81/");
575             os_memcpy(pos3, pos, (pos2 - pos));
576             pos3 += (pos2 - pos);
577             *pos3++ = ',';
578 
579             pos = pos2 + 1;
580         }
581         while (*pos == ',' || *pos == ' ' || *pos == '\0') {
582             pos++;
583         }
584 
585         if (((int)(pos - chan_list) >= len)) {
586             break;
587         }
588     }
589     *(pos3 - 1) = ' ';
590 
591     return uri_channels;
592 }
593 
594 esp_err_t
esp_supp_dpp_bootstrap_gen(const char * chan_list,enum dpp_bootstrap_type type,const char * key,const char * uri_info)595 esp_supp_dpp_bootstrap_gen(const char *chan_list, enum dpp_bootstrap_type type,
596                            const char *key, const char *uri_info)
597 {
598     if (!s_dpp_ctx.dpp_global) {
599         wpa_printf(MSG_ERROR, "DPP: failed to bootstrap as dpp not initialized.");
600         return ESP_FAIL;
601     }
602     struct dpp_bootstrap_params_t *params = &s_dpp_ctx.bootstrap_params;
603     char *uri_chan_list = esp_dpp_parse_chan_list(chan_list);
604     char *command = os_zalloc(1200);
605     int ret;
606 
607     if (!uri_chan_list || !command || params->num_chan >= 14 || params->num_chan == 0) {
608         wpa_printf(MSG_ERROR, "Invalid Channel list - %s", chan_list);
609         if (command) {
610             os_free(command);
611         }
612         ret = ESP_ERR_DPP_FAILURE;
613         goto fail;
614     }
615 
616     if (type != DPP_BOOTSTRAP_QR_CODE) {
617         wpa_printf(MSG_INFO, "Bootstrap type %d not supported", type);
618         os_free(command);
619         ret = ESP_ERR_NOT_SUPPORTED;
620         goto fail;
621     }
622     params->type = type;
623     esp_wifi_get_mac(WIFI_IF_STA, params->mac);
624 
625     if (uri_info) {
626         params->info_len = strlen(uri_info);
627         if (params->info_len) {
628             params->info = os_zalloc(params->info_len + 1);
629             if (!params->info) {
630                 os_free(command);
631                 ret = ESP_ERR_NO_MEM;
632                 goto fail;
633             }
634             os_memcpy(params->info, uri_info, params->info_len);
635         }
636     }
637 
638     os_snprintf(command, 1200, "type=qrcode mac=" MACSTR "%s%s%s%s%s",
639             MAC2STR(params->mac), uri_chan_list,
640             key ? "key=" : "", key ? key : "",
641             params->info_len ? " info=" : "",
642             params->info_len ? params->info : "");
643 
644     ret = esp_dpp_post_evt(SIG_DPP_BOOTSTRAP_GEN, (u32)command);
645     if (ret != ESP_OK) {
646         os_free(command);
647         if (params->info) {
648             os_free(params->info);
649             params->info = NULL;
650         }
651         goto fail;
652     }
653 
654     ret = ESP_OK;
655 fail:
656     if (uri_chan_list) {
657         os_free(uri_chan_list);
658     }
659 
660     return ret;
661 }
662 
esp_supp_dpp_start_listen(void)663 esp_err_t esp_supp_dpp_start_listen(void)
664 {
665     if (s_dpp_listen_in_progress) {
666         wpa_printf(MSG_ERROR, "DPP: Failed to start listen as listen is already in progress.");
667         return ESP_FAIL;
668     }
669 
670     if (!s_dpp_ctx.dpp_global || s_dpp_ctx.id < 1) {
671         wpa_printf(MSG_ERROR, "DPP: failed to start listen as dpp not initialized or bootstrapped.");
672         return ESP_FAIL;
673     }
674 
675     if (esp_wifi_get_user_init_flag_internal() == 0) {
676         wpa_printf(MSG_ERROR, "DPP: ROC not possible before wifi is started");
677         return ESP_ERR_INVALID_STATE;
678     }
679 
680     return esp_dpp_post_evt(SIG_DPP_LISTEN_NEXT_CHANNEL, 0);
681 }
682 
esp_supp_dpp_stop_listen(void)683 void esp_supp_dpp_stop_listen(void)
684 {
685     s_dpp_listen_in_progress = false;
686     esp_wifi_remain_on_channel(WIFI_IF_STA, WIFI_ROC_CANCEL, 0, 0, NULL);
687 }
688 
is_dpp_enabled(void)689 bool is_dpp_enabled(void)
690 {
691     return (s_dpp_ctx.dpp_global ? true : false);
692 }
693 
esp_supp_dpp_init(esp_supp_dpp_event_cb_t cb)694 esp_err_t esp_supp_dpp_init(esp_supp_dpp_event_cb_t cb)
695 {
696     esp_err_t ret = ESP_OK;
697     wifi_mode_t mode = 0;
698     if (esp_wifi_get_mode(&mode) || ((mode != ESP32_WIFI_MODE_STA) && (mode != ESP32_WIFI_MODE_APSTA))) {
699         wpa_printf(MSG_ERROR, "DPP: failed to init as not in station mode.");
700         return ESP_FAIL;
701     }
702 
703     if (is_wps_enabled()) {
704         wpa_printf(MSG_ERROR, "DPP: failed to init since WPS is enabled");
705         return ESP_FAIL;
706     }
707     if (s_dpp_ctx.dpp_global) {
708         wpa_printf(MSG_ERROR, "DPP: failed to init as init already done. Please deinit first and retry.");
709         return ESP_FAIL;
710     }
711 
712     os_bzero(&s_dpp_ctx, sizeof(s_dpp_ctx));
713     struct dpp_global_config cfg = {0};
714     cfg.cb_ctx = &s_dpp_ctx;
715     cfg.msg_ctx = &s_dpp_ctx;
716     s_dpp_ctx.dpp_global = dpp_global_init(&cfg);
717     if (!s_dpp_ctx.dpp_global) {
718         wpa_printf(MSG_ERROR, "DPP: failed to allocate memory for dpp_global");
719         ret = ESP_ERR_NO_MEM;
720         goto init_fail;
721     }
722 
723     s_dpp_api_lock = os_recursive_mutex_create();
724     if (!s_dpp_api_lock) {
725         wpa_printf(MSG_ERROR, "DPP: dpp_init: failed to create DPP API lock");
726         ret = ESP_ERR_NO_MEM;
727         goto init_fail;
728     }
729 
730     s_dpp_evt_queue = os_queue_create(3, sizeof(dpp_event_t));
731     if (!s_dpp_evt_queue) {
732         wpa_printf(MSG_ERROR, "DPP: dpp_init: failed to create DPP API queue");
733         ret = ESP_ERR_NO_MEM;
734         goto init_fail;
735     }
736 
737     ret = os_task_create(esp_dpp_task, "dppT", DPP_TASK_STACK_SIZE, NULL, 2, &s_dpp_task_hdl);
738     if (ret != TRUE) {
739         wpa_printf(MSG_ERROR, "DPP: failed to create task");
740         ret = ESP_ERR_NO_MEM;
741         goto init_fail;
742     }
743 
744     s_dpp_listen_in_progress = false;
745     s_dpp_ctx.dpp_event_cb = cb;
746 
747     esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ACTION_TX_STATUS,
748                                &offchan_event_handler, NULL);
749     esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_ROC_DONE,
750                                &offchan_event_handler, NULL);
751 
752     wpa_printf(MSG_INFO, "esp_dpp_task prio:%d, stack:%d", 2, DPP_TASK_STACK_SIZE);
753 
754     return ESP_OK;
755 init_fail:
756     if (s_dpp_ctx.dpp_global) {
757         dpp_global_deinit(s_dpp_ctx.dpp_global);
758         s_dpp_ctx.dpp_global = NULL;
759     }
760     if (s_dpp_api_lock) {
761         os_mutex_delete(s_dpp_api_lock);
762         s_dpp_api_lock = NULL;
763     }
764     if (s_dpp_evt_queue) {
765         os_queue_delete(s_dpp_evt_queue);
766         s_dpp_evt_queue = NULL;
767     }
768     return ret;
769 }
esp_supp_dpp_deinit(void)770 void esp_supp_dpp_deinit(void)
771 {
772 
773     esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_ACTION_TX_STATUS,
774                                &offchan_event_handler);
775     esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_ROC_DONE,
776                                &offchan_event_handler);
777     if (s_dpp_ctx.dpp_global) {
778         if (esp_dpp_post_evt(SIG_DPP_DEL_TASK, 0)) {
779             wpa_printf(MSG_ERROR, "DPP Deinit Failed");
780         }
781     }
782 }
783 #endif
784