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