WPS: Fix multi-interface WPS operations in hostapd
Couple of the for-each-interface loops used incorrect return value when
skipping over non-WPS interfaces. This could result in skipping some WPS
interfaces in the loop and returning error. Setting AP PIN did not check
for WPS being enabled at all and trigger a NULL pointer dereference if
non-WPS interface was enabled.
Signed-off-by: Jouni Malinen <j@w1.fi>
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 1c21b23..cde31e6 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1304,30 +1304,53 @@
}
+struct wps_button_pushed_ctx {
+ const u8 *p2p_dev_addr;
+ unsigned int count;
+};
+
static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
{
- const u8 *p2p_dev_addr = ctx;
- if (hapd->wps == NULL)
- return -1;
- return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
+ struct wps_button_pushed_ctx *data = ctx;
+
+ if (hapd->wps) {
+ data->count++;
+ return wps_registrar_button_pushed(hapd->wps->registrar,
+ data->p2p_dev_addr);
+ }
+
+ return 0;
}
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr)
{
- return hostapd_wps_for_each(hapd, wps_button_pushed,
- (void *) p2p_dev_addr);
+ struct wps_button_pushed_ctx ctx;
+ int ret;
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ ctx.p2p_dev_addr = p2p_dev_addr;
+ ret = hostapd_wps_for_each(hapd, wps_button_pushed, &ctx);
+ if (ret == 0 && !ctx.count)
+ ret = -1;
+ return ret;
}
+struct wps_cancel_ctx {
+ unsigned int count;
+};
+
static int wps_cancel(struct hostapd_data *hapd, void *ctx)
{
- if (hapd->wps == NULL)
- return -1;
+ struct wps_cancel_ctx *data = ctx;
- wps_registrar_wps_cancel(hapd->wps->registrar);
- ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ if (hapd->wps) {
+ data->count++;
+ wps_registrar_wps_cancel(hapd->wps->registrar);
+ ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ }
return 0;
}
@@ -1335,7 +1358,14 @@
int hostapd_wps_cancel(struct hostapd_data *hapd)
{
- return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+ struct wps_cancel_ctx ctx;
+ int ret;
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ ret = hostapd_wps_for_each(hapd, wps_cancel, &ctx);
+ if (ret == 0 && !ctx.count)
+ ret = -1;
+ return ret;
}
@@ -1565,6 +1595,10 @@
static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
{
struct wps_ap_pin_data *data = ctx;
+
+ if (!hapd->wps)
+ return 0;
+
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(data->pin_txt);
#ifdef CONFIG_WPS_UPNP