diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index a906637e0..b39f40252 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2564,6 +2564,34 @@ static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd, return wpa_snprintf_hex(buf, buflen, pmk, pmk_len); } + +static int hostapd_ctrl_register_frame(struct hostapd_data *hapd, + const char *cmd) +{ + u16 type; + char *pos, *end; + u8 match[10]; + size_t match_len; + bool multicast = false; + + type = strtol(cmd, &pos, 16); + if (*pos != ' ') + return -1; + pos++; + end = os_strchr(pos, ' '); + if (end) { + match_len = end - pos; + multicast = os_strstr(end, "multicast") != NULL; + } else { + match_len = os_strlen(pos) / 2; + } + if (hexstr2bin(pos, match, match_len)) + return -1; + + return hostapd_drv_register_frame(hapd, type, match, match_len, + multicast); +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -3648,6 +3676,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) { reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply, reply_size); + } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) { + if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index a42070116..61c8f64eb 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -403,4 +403,17 @@ static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd, } #endif /* ANDROID */ +#ifdef CONFIG_TESTING_OPTIONS +static inline int +hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type, + const u8 *match, size_t match_len, + bool multicast) +{ + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->register_frame) + return -1; + return hapd->driver->register_frame(hapd->drv_priv, type, match, + match_len, multicast); +} +#endif /* CONFIG_TESTING_OPTIONS */ + #endif /* AP_DRV_OPS */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 5b2c71ca0..8ef9ea23a 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -4553,6 +4553,12 @@ struct wpa_driver_ops { * explicitly allow reception of broadcast Public Action frames. */ int (*dpp_listen)(void *priv, bool enable); + +#ifdef CONFIG_TESTING_OPTIONS + int (*register_frame)(void *priv, u16 type, + const u8 *match, size_t match_len, + bool multicast); +#endif /* CONFIG_TESTING_OPTIONS */ }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index e7a28cae2..5c56b0422 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -12035,6 +12035,23 @@ static int nl80211_dpp_listen(void *priv, bool enable) #endif /* CONFIG_DPP */ +#ifdef CONFIG_TESTING_OPTIONS +static int testing_nl80211_register_frame(void *priv, u16 type, + const u8 *match, size_t match_len, + bool multicast) +{ + struct i802_bss *bss = priv; + struct nl_sock *handle; + + if (!bss->nl_mgmt) + return -1; + handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID); + return nl80211_register_frame(bss, handle, type, match, match_len, + multicast); +} +#endif /* CONFIG_TESTING_OPTIONS */ + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -12173,4 +12190,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #ifdef CONFIG_DPP .dpp_listen = nl80211_dpp_listen, #endif /* CONFIG_DPP */ +#ifdef CONFIG_TESTING_OPTIONS + .register_frame = testing_nl80211_register_frame, +#endif /* CONFIG_TESTING_OPTIONS */ };