WPS: Fix multi-interface WPS operations in hostapd
authorJouni Malinen <j@w1.fi>
Sun, 16 Aug 2015 19:38:31 +0000 (22:38 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 16 Aug 2015 20:14:44 +0000 (23:14 +0300)
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>
src/ap/wps_hostapd.c

index 1c21b23..cde31e6 100644 (file)
@@ -1304,30 +1304,53 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
 }
 
 
+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 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx)
 
 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 @@ struct wps_ap_pin_data {
 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