From: Felix Fietkau Date: Sun, 8 Feb 2026 11:03:18 +0000 (+0000) Subject: hostapd: extend DPP ucode API with WPS M7/M8 encrypted settings handling X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a7756346c7307ce84082cf0754bf4b6654850cf3;p=thirdparty%2Fopenwrt.git hostapd: extend DPP ucode API with WPS M7/M8 encrypted settings handling Add callbacks to intercept WPS M7 reception (registrar side) and M8 reception (enrollee side), allowing external code to inject extra encrypted attributes and optionally skip credential building. On the registrar side, the m7_rx callback receives the decrypted M7 content and can return extra data to include in M8's encrypted settings as well as a flag to skip credential generation. On the enrollee side, add a wps_set_m7 method to set extra encrypted data for M7, and a m8_rx callback to handle the decrypted M8 content externally. Signed-off-by: Felix Fietkau --- diff --git a/package/network/services/hostapd/files/hostapd.uc b/package/network/services/hostapd/files/hostapd.uc index 6290b139e75..6558b55b0a9 100644 --- a/package/network/services/hostapd/files/hostapd.uc +++ b/package/network/services/hostapd/files/hostapd.uc @@ -1603,4 +1603,12 @@ return { return response.response; return null; }, + wps_m7_rx: function(ifname, addr, data) { + let response = dpp_rx_via_channel(ifname, "wps_m7_rx", { + ifname, addr, data, + }); + if (!response) + return null; + return response; + }, }; diff --git a/package/network/services/hostapd/files/wpa_supplicant.uc b/package/network/services/hostapd/files/wpa_supplicant.uc index ea60794245f..a0ecdde5cd0 100644 --- a/package/network/services/hostapd/files/wpa_supplicant.uc +++ b/package/network/services/hostapd/files/wpa_supplicant.uc @@ -478,6 +478,14 @@ function dpp_channel_handle_request(channel, req) iface.ctrl("DPP_STOP_CHIRP"); return 0; + case "wps_set_m7": + iface = dpp_find_iface(data.ifname); + if (!iface) + return libubus.STATUS_NOT_FOUND; + if (!iface.wps_set_m7(data.data)) + return libubus.STATUS_UNKNOWN_ERROR; + return 0; + default: return libubus.STATUS_METHOD_NOT_FOUND; } @@ -1078,4 +1086,12 @@ return { return true; return false; }, + wps_m8_rx: function(ifname, iface, data) { + let response = dpp_rx_via_channel(ifname, "wps_m8_rx", { + ifname, data, + }); + if (response && response.handled) + return true; + return false; + }, }; diff --git a/package/network/services/hostapd/patches/601-ucode_support.patch b/package/network/services/hostapd/patches/601-ucode_support.patch index 02b7404254c..aa1becb9961 100644 --- a/package/network/services/hostapd/patches/601-ucode_support.patch +++ b/package/network/services/hostapd/patches/601-ucode_support.patch @@ -95,7 +95,22 @@ as adding/removing interfaces. #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG -@@ -401,6 +402,8 @@ static int wpa_supplicant_wps_cred(void +@@ -371,6 +372,14 @@ static void wpas_wps_remove_dup_network( + } + + ++static int wpa_supplicant_wps_m8_rx(void *ctx, const u8 *data, ++ size_t data_len) ++{ ++ struct wpa_supplicant *wpa_s = ctx; ++ return wpas_ucode_wps_m8_rx(wpa_s, data, data_len); ++} ++ ++ + static int wpa_supplicant_wps_cred(void *ctx, + const struct wps_credential *cred) + { +@@ -401,6 +410,8 @@ static int wpa_supplicant_wps_cred(void wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", cred->cred_attr, cred->cred_attr_len); @@ -104,6 +119,22 @@ as adding/removing interfaces. if (wpa_s->conf->wps_cred_processing == 1) return 0; +@@ -1596,6 +1607,7 @@ int wpas_wps_init(struct wpa_supplicant + wps->cred_cb = wpa_supplicant_wps_cred; + wps->event_cb = wpa_supplicant_wps_event; + wps->rf_band_cb = wpa_supplicant_wps_rf_band; ++ wps->m8_rx_cb = wpa_supplicant_wps_m8_rx; + wps->cb_ctx = wpa_s; + + wps->dev.device_name = wpa_s->conf->device_name; +@@ -1713,6 +1725,7 @@ void wpas_wps_deinit(struct wpa_supplica + wpabuf_free(wpa_s->wps->dh_pubkey); + wpabuf_free(wpa_s->wps->dh_privkey); + wpabuf_free(wpa_s->wps->dev.vendor_ext_m1); ++ wpabuf_free(wpa_s->wps->m7_encr_extra); + os_free(wpa_s->wps->network_key); + os_free(wpa_s->wps); + wpa_s->wps = NULL; --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -169,9 +169,22 @@ OBJS += ../src/eapol_auth/eapol_auth_sm. @@ -1113,3 +1144,389 @@ as adding/removing interfaces. if (dpp_check_attrs(buf, len) < 0) { wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_RX "src=" MACSTR " freq=%u type=%d ignore=invalid-attributes", +--- a/src/ap/ucode.c ++++ b/src/ap/ucode.c +@@ -1132,6 +1132,56 @@ struct wpabuf *hostapd_ucode_dpp_gas_req + } + #endif /* CONFIG_DPP */ + ++void hostapd_ucode_wps_m7_rx(struct hostapd_data *hapd, const u8 *addr, ++ const u8 *data, size_t data_len, ++ struct wpabuf **m8_encr_extra, int *skip_cred) ++{ ++ uc_value_t *val, *obj; ++ char addr_str[18]; ++ char *data_b64; ++ size_t data_b64_len; ++ ++ if (wpa_ucode_call_prepare("wps_m7_rx")) ++ return; ++ ++ os_snprintf(addr_str, sizeof(addr_str), MACSTR, MAC2STR(addr)); ++ data_b64 = base64_encode_no_lf(data, data_len, &data_b64_len); ++ if (!data_b64) { ++ ucv_put(wpa_ucode_call(0)); ++ return; ++ } ++ ++ uc_value_push(ucv_string_new(hapd->conf->iface)); ++ uc_value_push(ucv_string_new(addr_str)); ++ uc_value_push(ucv_string_new(data_b64)); ++ os_free(data_b64); ++ ++ val = wpa_ucode_call(3); ++ if (ucv_type(val) != UC_OBJECT) ++ goto out; ++ ++ obj = ucv_object_get(val, "skip_cred", NULL); ++ if (ucv_is_truish(obj)) ++ *skip_cred = 1; ++ ++ obj = ucv_object_get(val, "data", NULL); ++ if (ucv_type(obj) == UC_STRING) { ++ const char *extra_b64 = ucv_string_get(obj); ++ unsigned char *extra; ++ size_t extra_len; ++ ++ extra = base64_decode(extra_b64, os_strlen(extra_b64), ++ &extra_len); ++ if (extra) { ++ *m8_encr_extra = wpabuf_alloc_copy(extra, extra_len); ++ os_free(extra); ++ } ++ } ++ ++out: ++ ucv_put(val); ++} ++ + int hostapd_ucode_init(struct hapd_interfaces *ifaces) + { + static const uc_function_list_t global_fns[] = { +--- a/src/ap/ucode.h ++++ b/src/ap/ucode.h +@@ -32,6 +32,10 @@ void hostapd_ucode_sta_connected(struct + void hostapd_ucode_apup_newpeer(struct hostapd_data *hapd, const char *ifname); + #endif // def CONFIG_APUP + ++void hostapd_ucode_wps_m7_rx(struct hostapd_data *hapd, const u8 *addr, ++ const u8 *data, size_t data_len, ++ struct wpabuf **m8_encr_extra, int *skip_cred); ++ + #ifdef CONFIG_DPP + int hostapd_ucode_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, + u8 frame_type, unsigned int freq, +@@ -66,6 +70,13 @@ static inline void hostapd_ucode_sta_con + static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd) + { + } ++static inline void hostapd_ucode_wps_m7_rx(struct hostapd_data *hapd, ++ const u8 *addr, ++ const u8 *data, size_t data_len, ++ struct wpabuf **m8_encr_extra, ++ int *skip_cred) ++{ ++} + + #ifdef CONFIG_DPP + static inline int hostapd_ucode_dpp_rx_action(struct hostapd_data *hapd, +--- a/src/ap/wps_hostapd.c ++++ b/src/ap/wps_hostapd.c +@@ -27,6 +27,7 @@ + #include "beacon.h" + #include "sta_info.h" + #include "wps_hostapd.h" ++#include "ucode.h" + + + #ifdef CONFIG_WPS_UPNP +@@ -719,6 +720,17 @@ static int hostapd_wps_cred_cb(void *ctx + } + + ++static void hostapd_wps_m7_rx_cb(void *ctx, const u8 *addr, ++ const u8 *data, size_t data_len, ++ struct wpabuf **m8_encr_extra, ++ int *skip_cred) ++{ ++ struct hostapd_data *hapd = ctx; ++ hostapd_ucode_wps_m7_rx(hapd, addr, data, data_len, ++ m8_encr_extra, skip_cred); ++} ++ ++ + static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx) + { + struct hostapd_data *hapd = eloop_data; +@@ -1096,6 +1108,7 @@ int hostapd_init_wps(struct hostapd_data + return -1; + + wps->cred_cb = hostapd_wps_cred_cb; ++ wps->m7_rx_cb = hostapd_wps_m7_rx_cb; + wps->event_cb = hostapd_wps_event_cb; + wps->rf_band_cb = hostapd_wps_rf_band_cb; + wps->cb_ctx = hapd; +--- a/src/wps/wps.c ++++ b/src/wps/wps.c +@@ -182,6 +182,7 @@ void wps_deinit(struct wps_data *data) + bin_clear_free(data->new_psk, data->new_psk_len); + wps_device_data_free(&data->peer_dev); + bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings)); ++ wpabuf_free(data->m8_encr_extra); + dh5_free(data->dh_ctx); + os_free(data); + } +--- a/src/wps/wps.h ++++ b/src/wps/wps.h +@@ -850,6 +850,14 @@ struct wps_context { + /* Whether to send WPA2-PSK passphrase as a passphrase instead of PSK + * for WPA3-Personal transition mode needs. */ + bool use_passphrase; ++ ++ struct wpabuf *m7_encr_extra; ++ ++ void (*m7_rx_cb)(void *ctx, const u8 *addr, ++ const u8 *data, size_t data_len, ++ struct wpabuf **m8_encr_extra, int *skip_cred); ++ ++ int (*m8_rx_cb)(void *ctx, const u8 *data, size_t data_len); + }; + + struct wps_registrar * +--- a/src/wps/wps_enrollee.c ++++ b/src/wps/wps_enrollee.c +@@ -377,14 +377,17 @@ static int wps_build_ap_settings(struct + static struct wpabuf * wps_build_m7(struct wps_data *wps) + { + struct wpabuf *msg, *plain; ++ size_t extra_len; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M7"); + +- plain = wpabuf_alloc(500 + wps->wps->ap_settings_len); ++ extra_len = wps->wps->m7_encr_extra ? ++ wpabuf_len(wps->wps->m7_encr_extra) : 0; ++ plain = wpabuf_alloc(500 + wps->wps->ap_settings_len + extra_len); + if (plain == NULL) + return NULL; + +- msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len); ++ msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len + extra_len); + if (msg == NULL) { + wpabuf_free(plain); + return NULL; +@@ -394,8 +397,16 @@ static struct wpabuf * wps_build_m7(stru + wps_build_msg_type(msg, WPS_M7) || + wps_build_registrar_nonce(wps, msg) || + wps_build_e_snonce2(wps, plain) || +- (wps->wps->ap && wps_build_ap_settings(wps, plain)) || +- wps_build_key_wrap_auth(wps, plain) || ++ (wps->wps->ap && wps_build_ap_settings(wps, plain))) { ++ wpabuf_clear_free(plain); ++ wpabuf_free(msg); ++ return NULL; ++ } ++ ++ if (wps->wps->m7_encr_extra) ++ wpabuf_put_buf(plain, wps->wps->m7_encr_extra); ++ ++ if (wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || + wps_build_authenticator(wps, msg)) { +@@ -1258,8 +1269,22 @@ static enum wps_process_res wps_process_ + wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings " + "attribute"); + if (wps_parse_msg(decrypted, &eattr) < 0 || +- wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) || +- wps_process_creds(wps, eattr.cred, eattr.cred_len, ++ wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth)) { ++ wpabuf_clear_free(decrypted); ++ wps->state = SEND_WSC_NACK; ++ return WPS_CONTINUE; ++ } ++ ++ if (wps->wps->m8_rx_cb && ++ wps->wps->m8_rx_cb(wps->wps->cb_ctx, ++ wpabuf_head(decrypted), ++ wpabuf_len(decrypted))) { ++ wpabuf_clear_free(decrypted); ++ wps->state = WPS_MSG_DONE; ++ return WPS_CONTINUE; ++ } ++ ++ if (wps_process_creds(wps, eattr.cred, eattr.cred_len, + eattr.num_cred, attr->version2 != NULL) || + wps_process_ap_settings_e(wps, &eattr, decrypted, + attr->version2 != NULL)) { +--- a/src/wps/wps_i.h ++++ b/src/wps/wps_i.h +@@ -128,6 +128,9 @@ struct wps_data { + + int multi_ap_backhaul_sta; + int multi_ap_profile; ++ ++ struct wpabuf *m8_encr_extra; ++ int skip_cred; + }; + + +--- a/src/wps/wps_registrar.c ++++ b/src/wps/wps_registrar.c +@@ -2064,14 +2064,17 @@ static struct wpabuf * wps_build_m6(stru + static struct wpabuf * wps_build_m8(struct wps_data *wps) + { + struct wpabuf *msg, *plain; ++ size_t extra_len; + + wpa_printf(MSG_DEBUG, "WPS: Building Message M8"); + +- plain = wpabuf_alloc(500); ++ extra_len = wps->m8_encr_extra ? ++ wpabuf_len(wps->m8_encr_extra) : 0; ++ plain = wpabuf_alloc(500 + extra_len); + if (plain == NULL) + return NULL; + +- msg = wpabuf_alloc(1000); ++ msg = wpabuf_alloc(1000 + extra_len); + if (msg == NULL) { + wpabuf_free(plain); + return NULL; +@@ -2080,9 +2083,19 @@ static struct wpabuf * wps_build_m8(stru + if (wps_build_version(msg) || + wps_build_msg_type(msg, WPS_M8) || + wps_build_enrollee_nonce(wps, msg) || +- ((wps->wps->ap || wps->er) && wps_build_cred(wps, plain)) || +- (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) || +- wps_build_key_wrap_auth(wps, plain) || ++ (!wps->skip_cred && (wps->wps->ap || wps->er) && ++ wps_build_cred(wps, plain)) || ++ (!wps->skip_cred && !wps->wps->ap && !wps->er && ++ wps_build_ap_settings(wps, plain))) { ++ wpabuf_clear_free(plain); ++ wpabuf_clear_free(msg); ++ return NULL; ++ } ++ ++ if (wps->m8_encr_extra) ++ wpabuf_put_buf(plain, wps->m8_encr_extra); ++ ++ if (wps_build_key_wrap_auth(wps, plain) || + wps_build_encr_settings(wps, msg, plain) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || + wps_build_authenticator(wps, msg)) { +@@ -3019,6 +3032,13 @@ static enum wps_process_res wps_process_ + return WPS_CONTINUE; + } + ++ if (wps->wps->m7_rx_cb) ++ wps->wps->m7_rx_cb(wps->wps->cb_ctx, wps->mac_addr_e, ++ wpabuf_head(decrypted), ++ wpabuf_len(decrypted), ++ &wps->m8_encr_extra, ++ &wps->skip_cred); ++ + wpabuf_clear_free(decrypted); + + wps->state = SEND_M8; +--- a/wpa_supplicant/ucode.c ++++ b/wpa_supplicant/ucode.c +@@ -243,6 +243,65 @@ void wpas_ucode_wps_complete(struct wpa_ + #endif /* CONFIG_WPS */ + } + ++static uc_value_t * ++uc_wpas_iface_wps_set_m7(uc_vm_t *vm, size_t nargs) ++{ ++ struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface"); ++ uc_value_t *data_arg = uc_fn_arg(0); ++ const char *data_b64; ++ unsigned char *data; ++ size_t data_len; ++ ++ if (!wpa_s || !wpa_s->wps) ++ return NULL; ++ ++ wpabuf_free(wpa_s->wps->m7_encr_extra); ++ wpa_s->wps->m7_encr_extra = NULL; ++ ++ if (ucv_type(data_arg) != UC_STRING) ++ return ucv_boolean_new(true); ++ ++ data_b64 = ucv_string_get(data_arg); ++ data = base64_decode(data_b64, os_strlen(data_b64), &data_len); ++ if (!data) ++ return NULL; ++ ++ wpa_s->wps->m7_encr_extra = wpabuf_alloc_copy(data, data_len); ++ os_free(data); ++ ++ return ucv_boolean_new(wpa_s->wps->m7_encr_extra != NULL); ++} ++ ++int wpas_ucode_wps_m8_rx(struct wpa_supplicant *wpa_s, ++ const u8 *data, size_t data_len) ++{ ++ uc_value_t *val; ++ char *data_b64; ++ size_t data_b64_len; ++ int ret = 0; ++ ++ if (wpa_ucode_call_prepare("wps_m8_rx")) ++ return 0; ++ ++ data_b64 = base64_encode_no_lf(data, data_len, &data_b64_len); ++ if (!data_b64) { ++ ucv_put(wpa_ucode_call(0)); ++ return 0; ++ } ++ ++ uc_value_push(ucv_string_new(wpa_s->ifname)); ++ val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx); ++ uc_value_push(ucv_get(val)); ++ uc_value_push(ucv_string_new(data_b64)); ++ os_free(data_b64); ++ ++ val = wpa_ucode_call(3); ++ ret = ucv_is_truish(val); ++ ucv_put(val); ++ ++ return ret; ++} ++ + #ifdef CONFIG_DPP + int wpas_ucode_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, + u8 frame_type, unsigned int freq, +@@ -692,6 +751,7 @@ int wpas_ucode_init(struct wpa_global *g + { "status", uc_wpas_iface_status }, + { "ctrl", uc_wpas_iface_ctrl }, + { "config", uc_wpas_iface_config }, ++ { "wps_set_m7", uc_wpas_iface_wps_set_m7 }, + #ifdef CONFIG_DPP + { "dpp_send_action", uc_wpas_iface_dpp_send_action }, + { "dpp_send_gas_req", uc_wpas_iface_dpp_send_gas_req }, +--- a/wpa_supplicant/ucode.h ++++ b/wpa_supplicant/ucode.h +@@ -26,6 +26,8 @@ void wpas_ucode_ctrl_event(struct wpa_su + bool wpas_ucode_bss_allowed(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); + void wpas_ucode_wps_complete(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred); ++int wpas_ucode_wps_m8_rx(struct wpa_supplicant *wpa_s, ++ const u8 *data, size_t data_len); + #ifdef CONFIG_DPP + int wpas_ucode_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, + u8 frame_type, unsigned int freq, +@@ -85,6 +87,12 @@ static inline void wpas_ucode_wps_comple + { + } + ++static inline int wpas_ucode_wps_m8_rx(struct wpa_supplicant *wpa_s, ++ const u8 *data, size_t data_len) ++{ ++ return 0; ++} ++ + static inline int wpas_ucode_dpp_rx_action(struct wpa_supplicant *wpa_s, + const u8 *src, u8 frame_type, + unsigned int freq, const u8 *data, diff --git a/package/network/services/hostapd/src/src/ap/ucode.c b/package/network/services/hostapd/src/src/ap/ucode.c index adaf20d19e5..5c5cf299990 100644 --- a/package/network/services/hostapd/src/src/ap/ucode.c +++ b/package/network/services/hostapd/src/src/ap/ucode.c @@ -1132,6 +1132,56 @@ struct wpabuf *hostapd_ucode_dpp_gas_req(struct hostapd_data *hapd, } #endif /* CONFIG_DPP */ +void hostapd_ucode_wps_m7_rx(struct hostapd_data *hapd, const u8 *addr, + const u8 *data, size_t data_len, + struct wpabuf **m8_encr_extra, int *skip_cred) +{ + uc_value_t *val, *obj; + char addr_str[18]; + char *data_b64; + size_t data_b64_len; + + if (wpa_ucode_call_prepare("wps_m7_rx")) + return; + + os_snprintf(addr_str, sizeof(addr_str), MACSTR, MAC2STR(addr)); + data_b64 = base64_encode_no_lf(data, data_len, &data_b64_len); + if (!data_b64) { + ucv_put(wpa_ucode_call(0)); + return; + } + + uc_value_push(ucv_string_new(hapd->conf->iface)); + uc_value_push(ucv_string_new(addr_str)); + uc_value_push(ucv_string_new(data_b64)); + os_free(data_b64); + + val = wpa_ucode_call(3); + if (ucv_type(val) != UC_OBJECT) + goto out; + + obj = ucv_object_get(val, "skip_cred", NULL); + if (ucv_is_truish(obj)) + *skip_cred = 1; + + obj = ucv_object_get(val, "data", NULL); + if (ucv_type(obj) == UC_STRING) { + const char *extra_b64 = ucv_string_get(obj); + unsigned char *extra; + size_t extra_len; + + extra = base64_decode(extra_b64, os_strlen(extra_b64), + &extra_len); + if (extra) { + *m8_encr_extra = wpabuf_alloc_copy(extra, extra_len); + os_free(extra); + } + } + +out: + ucv_put(val); +} + int hostapd_ucode_init(struct hapd_interfaces *ifaces) { static const uc_function_list_t global_fns[] = { diff --git a/package/network/services/hostapd/src/src/ap/ucode.h b/package/network/services/hostapd/src/src/ap/ucode.h index c287ab56654..64dc8f1ef53 100644 --- a/package/network/services/hostapd/src/src/ap/ucode.h +++ b/package/network/services/hostapd/src/src/ap/ucode.h @@ -32,6 +32,10 @@ void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct sta_info *sta void hostapd_ucode_apup_newpeer(struct hostapd_data *hapd, const char *ifname); #endif // def CONFIG_APUP +void hostapd_ucode_wps_m7_rx(struct hostapd_data *hapd, const u8 *addr, + const u8 *data, size_t data_len, + struct wpabuf **m8_encr_extra, int *skip_cred); + #ifdef CONFIG_DPP int hostapd_ucode_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, u8 frame_type, unsigned int freq, @@ -66,6 +70,13 @@ static inline void hostapd_ucode_sta_connected(struct hostapd_data *hapd, struct static inline void hostapd_ucode_free_bss(struct hostapd_data *hapd) { } +static inline void hostapd_ucode_wps_m7_rx(struct hostapd_data *hapd, + const u8 *addr, + const u8 *data, size_t data_len, + struct wpabuf **m8_encr_extra, + int *skip_cred) +{ +} #ifdef CONFIG_DPP static inline int hostapd_ucode_dpp_rx_action(struct hostapd_data *hapd, diff --git a/package/network/services/hostapd/src/wpa_supplicant/ucode.c b/package/network/services/hostapd/src/wpa_supplicant/ucode.c index 4de2e045321..b315c19aaad 100644 --- a/package/network/services/hostapd/src/wpa_supplicant/ucode.c +++ b/package/network/services/hostapd/src/wpa_supplicant/ucode.c @@ -243,6 +243,65 @@ void wpas_ucode_wps_complete(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WPS */ } +static uc_value_t * +uc_wpas_iface_wps_set_m7(uc_vm_t *vm, size_t nargs) +{ + struct wpa_supplicant *wpa_s = uc_fn_thisval("wpas.iface"); + uc_value_t *data_arg = uc_fn_arg(0); + const char *data_b64; + unsigned char *data; + size_t data_len; + + if (!wpa_s || !wpa_s->wps) + return NULL; + + wpabuf_free(wpa_s->wps->m7_encr_extra); + wpa_s->wps->m7_encr_extra = NULL; + + if (ucv_type(data_arg) != UC_STRING) + return ucv_boolean_new(true); + + data_b64 = ucv_string_get(data_arg); + data = base64_decode(data_b64, os_strlen(data_b64), &data_len); + if (!data) + return NULL; + + wpa_s->wps->m7_encr_extra = wpabuf_alloc_copy(data, data_len); + os_free(data); + + return ucv_boolean_new(wpa_s->wps->m7_encr_extra != NULL); +} + +int wpas_ucode_wps_m8_rx(struct wpa_supplicant *wpa_s, + const u8 *data, size_t data_len) +{ + uc_value_t *val; + char *data_b64; + size_t data_b64_len; + int ret = 0; + + if (wpa_ucode_call_prepare("wps_m8_rx")) + return 0; + + data_b64 = base64_encode_no_lf(data, data_len, &data_b64_len); + if (!data_b64) { + ucv_put(wpa_ucode_call(0)); + return 0; + } + + uc_value_push(ucv_string_new(wpa_s->ifname)); + val = wpa_ucode_registry_get(iface_registry, wpa_s->ucode.idx); + uc_value_push(ucv_get(val)); + uc_value_push(ucv_string_new(data_b64)); + os_free(data_b64); + + val = wpa_ucode_call(3); + ret = ucv_is_truish(val); + ucv_put(val); + + return ret; +} + #ifdef CONFIG_DPP int wpas_ucode_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, u8 frame_type, unsigned int freq, @@ -692,6 +751,7 @@ int wpas_ucode_init(struct wpa_global *gl) { "status", uc_wpas_iface_status }, { "ctrl", uc_wpas_iface_ctrl }, { "config", uc_wpas_iface_config }, + { "wps_set_m7", uc_wpas_iface_wps_set_m7 }, #ifdef CONFIG_DPP { "dpp_send_action", uc_wpas_iface_dpp_send_action }, { "dpp_send_gas_req", uc_wpas_iface_dpp_send_gas_req }, diff --git a/package/network/services/hostapd/src/wpa_supplicant/ucode.h b/package/network/services/hostapd/src/wpa_supplicant/ucode.h index 61d6c1f4d98..fc84c6731d2 100644 --- a/package/network/services/hostapd/src/wpa_supplicant/ucode.h +++ b/package/network/services/hostapd/src/wpa_supplicant/ucode.h @@ -26,6 +26,8 @@ void wpas_ucode_ctrl_event(struct wpa_supplicant *wpa_s, const char *str, size_t bool wpas_ucode_bss_allowed(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); void wpas_ucode_wps_complete(struct wpa_supplicant *wpa_s, const struct wps_credential *cred); +int wpas_ucode_wps_m8_rx(struct wpa_supplicant *wpa_s, + const u8 *data, size_t data_len); #ifdef CONFIG_DPP int wpas_ucode_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, u8 frame_type, unsigned int freq, @@ -85,6 +87,12 @@ static inline void wpas_ucode_wps_complete(struct wpa_supplicant *wpa_s, const s { } +static inline int wpas_ucode_wps_m8_rx(struct wpa_supplicant *wpa_s, + const u8 *data, size_t data_len) +{ + return 0; +} + static inline int wpas_ucode_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, u8 frame_type, unsigned int freq, const u8 *data,