diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wps.c b/components/wpa_supplicant/esp_supplicant/src/esp_wps.c index 3d31912df4..7a07b4afaa 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wps.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wps.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -376,53 +376,54 @@ static int wps_send_frag_ack(u8 id) return ret; } -static int wps_enrollee_process_msg_frag(struct wpabuf **buf, int tot_len, u8 *frag_data, int frag_len, u8 flag) +static int wps_eap_wsc_process_cont(struct wps_eap_wsc_frag_data *frag, + const u8 *buf, size_t len, u8 op_code) { - struct wps_sm *sm = wps_sm_get(); - u8 identifier; - - if (!sm || !buf || !frag_data) { - wpa_printf(MSG_ERROR, "WPS: %s: Invalid arguments", __func__); - return ESP_FAIL; + if (op_code != frag->in_op_code) { + wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in fragment " + "(expected %d)", op_code, frag->in_op_code); + return -1; } - identifier = sm->current_identifier; + if (len > wpabuf_tailroom(frag->in_buf)) { + wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow"); + return -1; + } - if (*buf == NULL) { - if (frag_len < 0 || tot_len < frag_len) { - wpa_printf(MSG_ERROR, "WPS: Invalid first fragment length"); - return ESP_FAIL; + wpabuf_put_data(frag->in_buf, buf, len); + wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu " + "bytes more", (unsigned long) len, + (unsigned long) wpabuf_tailroom(frag->in_buf)); + + return 0; +} + +static int wps_eap_wsc_process_fragment(struct wps_eap_wsc_frag_data *frag, + u8 flags, u8 op_code, + u16 message_length, + const u8 *buf, size_t len) +{ + if (frag->in_buf == NULL && !(flags & WSC_FLAGS_LF)) { + wpa_printf(MSG_DEBUG, "EAP-WSC: No Message Length field in a " + "fragmented packet"); + return -1; + } + + if (frag->in_buf == NULL) { + frag->in_buf = wpabuf_alloc(message_length); + if (frag->in_buf == NULL) { + wpa_printf(MSG_DEBUG, "EAP-WSC: No memory for message"); + return -1; } - - *buf = wpabuf_alloc(tot_len); - if (*buf == NULL) { - return ESP_ERR_NO_MEM; - } - - wpabuf_put_data(*buf, frag_data, frag_len); - return wps_send_frag_ack(identifier); + frag->in_op_code = op_code; + wpabuf_put_data(frag->in_buf, buf, len); + wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first " + "fragment, waiting for %lu bytes more", + (unsigned long) len, + (unsigned long) wpabuf_tailroom(frag->in_buf)); } - if (flag & WPS_MSG_FLAG_LEN) { - wpa_printf(MSG_ERROR, "WPS: %s: Invalid fragment flag: 0x%02x", __func__, flag); - wpabuf_free(*buf); - *buf = NULL; - return ESP_FAIL; - } - - if (frag_len < 0 || wpabuf_len(*buf) + frag_len > tot_len) { - wpa_printf(MSG_ERROR, "WPS: Invalid subsequent fragment length"); - wpabuf_free(*buf); - *buf = NULL; - return ESP_FAIL; - } - wpabuf_put_data(*buf, frag_data, frag_len); - - if (flag & WPS_MSG_FLAG_MORE) { - return wps_send_frag_ack(identifier); - } - - return ESP_OK; + return 0; } static void wifi_station_wps_post_m8_timeout(void *data, void *user_ctx) @@ -436,29 +437,31 @@ static void wifi_station_wps_post_m8_timeout(void *data, void *user_ctx) sm->post_m8_recv = false; wps_finish(); } -}; +} static int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res) { struct wps_sm *sm = wps_sm_get(); - static struct wpabuf *wps_buf = NULL; + struct wps_eap_wsc_frag_data *frag; struct eap_expand *expd; - int tlen = 0; - u8 *tbuf; - u8 flag; - int frag_len; - u16 be_tot_len = 0; + const u8 *pos, *end; + u8 flags; + u16 message_length = 0; + struct wpabuf tmpbuf; if (!sm || !res) { return ESP_FAIL; } + frag = &sm->wsc_frag; + if (len < (int)(sizeof(struct eap_expand) + 1)) { wpa_printf(MSG_ERROR, "WPS: Truncated EAP-Expanded header"); return ESP_FAIL; } expd = (struct eap_expand *) ubuf; - wpa_printf(MSG_DEBUG, "WPS: Processing WSC message (len=%d, total_len=%d)", len, tlen); + pos = ubuf + sizeof(struct eap_expand); + end = ubuf + len; if (sm->state == WAIT_START) { if (expd->opcode != WSC_Start) { @@ -473,64 +476,56 @@ static int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res) return ESP_ERR_INVALID_STATE; } - flag = *(u8 *)(ubuf + sizeof(struct eap_expand)); - if (flag & WPS_MSG_FLAG_LEN) { - if (len < (int)(sizeof(struct eap_expand) + 1 + 2)) { - wpa_printf(MSG_ERROR, "WPS: Missing total length field"); + flags = *pos++; + if (flags & WSC_FLAGS_LF) { + if (end - pos < 2) { + wpa_printf(MSG_ERROR, "WPS: Message underflow"); return ESP_FAIL; } - tbuf = ubuf + sizeof(struct eap_expand) + 1 + 2; // includes 2-byte total length - frag_len = len - (sizeof(struct eap_expand) + 1 + 2); - be_tot_len = *(u16 *)(ubuf + sizeof(struct eap_expand) + 1); - tlen = ((be_tot_len & 0xff) << 8) | ((be_tot_len >> 8) & 0xff); - } else { - tbuf = ubuf + sizeof(struct eap_expand) + 1; - frag_len = len - (sizeof(struct eap_expand) + 1); - tlen = frag_len; - } + message_length = WPA_GET_BE16(pos); + pos += 2; - if (frag_len < 0 || tlen < 0 || ((flag & WPS_MSG_FLAG_LEN) && tlen < frag_len)) { - wpa_printf(MSG_ERROR, "WPS: Invalid fragment sizes"); - if (wps_buf) { - wpabuf_free(wps_buf); - wps_buf = NULL; - } - return ESP_FAIL; - } - - if (tlen > 50000) { - wpa_printf(MSG_ERROR, "WPS: Invalid EAP-WSC message length"); - return ESP_FAIL; - } - if ((flag & WPS_MSG_FLAG_MORE) || wps_buf != NULL) {//frag msg - wpa_printf(MSG_DEBUG, "WPS: Received fragment (id=%d, flag=0x%x, frag_len=%d, total_len=%d)", sm->current_identifier, flag, frag_len, tlen); - if (ESP_OK != wps_enrollee_process_msg_frag(&wps_buf, tlen, tbuf, frag_len, flag)) { - if (wps_buf) { - wpabuf_free(wps_buf); - wps_buf = NULL; - } + if (message_length < (u16)(end - pos) || message_length > 50000) { + wpa_printf(MSG_ERROR, "WPS: Invalid Message Length"); return ESP_FAIL; } - if (flag & WPS_MSG_FLAG_MORE) { - *res = WPS_FRAGMENT; - return ESP_OK; - } - } else { //not frag msg - if (wps_buf) {//if something wrong, frag msg buf is not freed, free first - wpa_printf(MSG_ERROR, "WPS: Fragment buffer not freed before receiving new message"); - wpabuf_free(wps_buf); - wps_buf = NULL; - } - wps_buf = wpabuf_alloc_copy(tbuf, tlen); } - if (!wps_buf) { + wpa_printf(MSG_DEBUG, "WPS: Received packet: Op-Code %d Flags 0x%x " + "Message Length %d", expd->opcode, flags, message_length); + + if (frag->in_buf && + wps_eap_wsc_process_cont(frag, pos, end - pos, expd->opcode) < 0) { + wpabuf_free(frag->in_buf); + frag->in_buf = NULL; return ESP_FAIL; } + if (flags & WSC_FLAGS_MF) { + if (wps_eap_wsc_process_fragment(frag, flags, expd->opcode, + message_length, pos, + end - pos) < 0) { + wpabuf_free(frag->in_buf); + frag->in_buf = NULL; + return ESP_FAIL; + } + if (wps_send_frag_ack(sm->current_identifier) != ESP_OK) { + wpabuf_free(frag->in_buf); + frag->in_buf = NULL; + return ESP_FAIL; + } + *res = WPS_FRAGMENT; + return ESP_OK; + } + + if (frag->in_buf == NULL) { + wpabuf_set(&tmpbuf, pos, end - pos); + frag->in_buf = &tmpbuf; + } + eloop_cancel_timeout(wifi_station_wps_msg_timeout, NULL, NULL); - *res = wps_enrollee_process_msg(sm->wps, expd->opcode, wps_buf); + *res = wps_enrollee_process_msg(sm->wps, expd->opcode, frag->in_buf); if (*res == WPS_CONTINUE && sm->wps->state == WPS_MSG_DONE) { wpa_printf(MSG_DEBUG, "WPS: M8 processed, starting workaround timer"); @@ -543,10 +538,10 @@ static int wps_process_wps_mX_req(u8 *ubuf, int len, enum wps_process_res *res) sm->state = WPA_FAIL; } - if (wps_buf) { - wpabuf_free(wps_buf); - wps_buf = NULL; + if (frag->in_buf != &tmpbuf) { + wpabuf_free(frag->in_buf); } + frag->in_buf = NULL; return ESP_OK; } @@ -1343,6 +1338,10 @@ static int wifi_station_wps_deinit(void) wps_deinit(sm->wps); sm->wps = NULL; } + if (sm->wsc_frag.in_buf) { + wpabuf_free(sm->wsc_frag.in_buf); + sm->wsc_frag.in_buf = NULL; + } if (s_wps_sm_cb) { s_wps_sm_cb->wps_sm_notify_deauth = NULL; os_free(s_wps_sm_cb); diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h index 2ff0fd73e1..2d78081ca3 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,11 +9,7 @@ #include "wps/wps.h" #include "wps/wps_attr_parse.h" -/* WPS message flag */ -enum wps_msg_flag { - WPS_MSG_FLAG_MORE = 0x01, - WPS_MSG_FLAG_LEN = 0x02 -}; +struct wpabuf; enum wps_reg_sig_type { SIG_WPS_REG_ENABLE = 1, //1 @@ -41,6 +37,11 @@ struct discard_ap_list_t { u8 bssid[6]; }; +struct wps_eap_wsc_frag_data { + struct wpabuf *in_buf; + enum wsc_op_code in_op_code; +}; + struct wps_sm { u8 state; struct wps_config *wps_cfg; @@ -61,6 +62,7 @@ struct wps_sm { u8 discover_ssid_cnt; bool wps_pbc_overlap; bool post_m8_recv; + struct wps_eap_wsc_frag_data wsc_frag; }; #define API_MUTEX_TAKE() do {\