]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
hostapd: extend DPP ucode API with WPS M7/M8 encrypted settings handling
authorFelix Fietkau <nbd@nbd.name>
Sun, 8 Feb 2026 11:03:18 +0000 (11:03 +0000)
committerFelix Fietkau <nbd@nbd.name>
Sun, 8 Feb 2026 11:25:20 +0000 (12:25 +0100)
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 <nbd@nbd.name>
package/network/services/hostapd/files/hostapd.uc
package/network/services/hostapd/files/wpa_supplicant.uc
package/network/services/hostapd/patches/601-ucode_support.patch
package/network/services/hostapd/src/src/ap/ucode.c
package/network/services/hostapd/src/src/ap/ucode.h
package/network/services/hostapd/src/wpa_supplicant/ucode.c
package/network/services/hostapd/src/wpa_supplicant/ucode.h

index 6290b139e7566fac52c5ddba7c75bb7d6b4f6da2..6558b55b0a918b4e1867272112936bc8af01aea7 100644 (file)
@@ -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;
+       },
 };
index ea60794245fbdb0e993c390ff5a2c1144679c2bf..a0ecdde5cd0ffc2eab5c7f94d2da04050e8f96dd 100644 (file)
@@ -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;
+       },
 };
index 02b7404254c87648511b0247de5612eab55ed7c2..aa1becb996134356e91dd682d21abea12cecd3f1 100644 (file)
@@ -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,
index adaf20d19e5a4bb3cdf1ff9e7115dc213ef009a0..5c5cf299990acfdc29ef354cbac985a01f3ec7d8 100644 (file)
@@ -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[] = {
index c287ab566549f6139015bfb5070c005082eda8af..64dc8f1ef535c73acda8b456a129ab4b74e18f7d 100644 (file)
@@ -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,
index 4de2e0453213f3d1bc104d69e9bc6298ce506afd..b315c19aaad9c8702120c960871ff7f9e5fb8d58 100644 (file)
@@ -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 },
index 61d6c1f4d980af3cc5205e7c046b08f1e8e4baed..fc84c6731d201ddc640f40c5af4738990fc1a123 100644 (file)
@@ -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,