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