P2P: Send AP mode WPS-FAIL event to parent interface
[libeap.git] / src / ap / wps_hostapd.c
index 7963d60..b2f6a78 100644 (file)
@@ -45,6 +45,45 @@ static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
 static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 
 
+struct wps_for_each_data {
+       int (*func)(struct hostapd_data *h, void *ctx);
+       void *ctx;
+};
+
+
+static int wps_for_each(struct hostapd_iface *iface, void *ctx)
+{
+       struct wps_for_each_data *data = ctx;
+       size_t j;
+
+       if (iface == NULL)
+               return 0;
+       for (j = 0; j < iface->num_bss; j++) {
+               struct hostapd_data *hapd = iface->bss[j];
+               int ret = data->func(hapd, data->ctx);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+
+static int hostapd_wps_for_each(struct hostapd_data *hapd,
+                               int (*func)(struct hostapd_data *h, void *ctx),
+                               void *ctx)
+{
+       struct hostapd_iface *iface = hapd->iface;
+       struct wps_for_each_data data;
+       data.func = func;
+       data.ctx = ctx;
+       if (iface->for_each_interface == NULL)
+               return wps_for_each(iface, &data);
+       return iface->for_each_interface(iface->interfaces, wps_for_each,
+                                        &data);
+}
+
+
 static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
                                  size_t psk_len)
 {
@@ -200,9 +239,9 @@ static void wps_reload_config(void *eloop_data, void *user_ctx)
 }
 
 
-static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 {
-       struct hostapd_data *hapd = ctx;
+       const struct wps_credential *cred = ctx;
        FILE *oconf, *nconf;
        size_t len, i;
        char *tmp_fname;
@@ -210,6 +249,9 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
        int multi_bss;
        int wpa;
 
+       if (hapd->wps == NULL)
+               return 0;
+
        wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
                        cred->cred_attr, cred->cred_attr_len);
 
@@ -414,14 +456,19 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
        eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
                               NULL);
 
-       /* TODO: dualband AP may need to update multiple configuration files */
-
        wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
 
        return 0;
 }
 
 
+static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+{
+       struct hostapd_data *hapd = ctx;
+       return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred);
+}
+
+
 static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
 {
        struct hostapd_data *hapd = eloop_data;
@@ -436,11 +483,12 @@ static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
 }
 
 
-static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
-                                 struct wps_event_pwd_auth_fail *data)
+static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
 {
-       if (!data->enrollee || hapd->conf->ap_pin == NULL)
-               return;
+       struct wps_event_pwd_auth_fail *data = ctx;
+
+       if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL)
+               return 0;
 
        /*
         * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
@@ -451,7 +499,7 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
        wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u",
                   hapd->ap_pin_failures);
        if (hapd->ap_pin_failures < 3)
-               return;
+               return 0;
 
        wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
        hapd->wps->ap_setup_locked = 1;
@@ -473,7 +521,23 @@ static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
                                       NULL);
        }
 
-       /* TODO: dualband AP may need to update other interfaces */
+       return 0;
+}
+
+
+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
+                                 struct wps_event_pwd_auth_fail *data)
+{
+       hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
+}
+
+
+static void hostapd_wps_event_fail(struct hostapd_data *hapd,
+                                  struct wps_event_fail *fail)
+{
+       wpa_msg(hapd->msg_ctx, MSG_INFO,
+               WPS_EVENT_FAIL "msg=%d config_error=%d",
+               fail->msg, fail->config_error);
 }
 
 
@@ -482,8 +546,34 @@ static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
 {
        struct hostapd_data *hapd = ctx;
 
-       if (event == WPS_EV_PWD_AUTH_FAIL)
+       switch (event) {
+       case WPS_EV_M2D:
+               break;
+       case WPS_EV_FAIL:
+               hostapd_wps_event_fail(hapd, &data->fail);
+               break;
+       case WPS_EV_SUCCESS:
+               break;
+       case WPS_EV_PWD_AUTH_FAIL:
                hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
+               break;
+       case WPS_EV_PBC_OVERLAP:
+               break;
+       case WPS_EV_PBC_TIMEOUT:
+               break;
+       case WPS_EV_ER_AP_ADD:
+               break;
+       case WPS_EV_ER_AP_REMOVE:
+               break;
+       case WPS_EV_ER_ENROLLEE_ADD:
+               break;
+       case WPS_EV_ER_ENROLLEE_REMOVE:
+               break;
+       case WPS_EV_ER_AP_SETTINGS:
+               break;
+       }
+       if (hapd->wps_event_cb)
+               hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
 }
 
 
@@ -540,6 +630,8 @@ static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
 static int interface_count(struct hostapd_iface *iface)
 {
        int count = 0;
+       if (iface->for_each_interface == NULL)
+               return 0;
        iface->for_each_interface(iface->interfaces, count_interface_cb,
                                  &count);
        return count;
@@ -800,33 +892,72 @@ void hostapd_update_wps(struct hostapd_data *hapd)
 }
 
 
+struct wps_add_pin_data {
+       const u8 *addr;
+       const u8 *uuid;
+       const u8 *pin;
+       size_t pin_len;
+       int timeout;
+       int added;
+};
+
+
+static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
+{
+       struct wps_add_pin_data *data = ctx;
+       int ret;
+
+       if (hapd->wps == NULL)
+               return 0;
+       ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
+                                   data->uuid, data->pin, data->pin_len,
+                                   data->timeout);
+       if (ret == 0)
+               data->added++;
+       return ret;
+}
+
+
 int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
                        const char *uuid, const char *pin, int timeout)
 {
        u8 u[UUID_LEN];
-       int any = 0;
+       struct wps_add_pin_data data;
+
+       data.addr = addr;
+       data.uuid = u;
+       data.pin = (const u8 *) pin;
+       data.pin_len = os_strlen(pin);
+       data.timeout = timeout;
+       data.added = 0;
 
-       if (hapd->wps == NULL)
-               return -1;
        if (os_strcmp(uuid, "any") == 0)
-               any = 1;
-       else if (uuid_str2bin(uuid, u))
+               data.uuid = NULL;
+       else {
+               if (uuid_str2bin(uuid, u))
+                       return -1;
+               data.uuid = u;
+       }
+       if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
                return -1;
-       return wps_registrar_add_pin(hapd->wps->registrar, addr,
-                                    any ? NULL : u,
-                                    (const u8 *) pin, os_strlen(pin),
-                                    timeout);
+       return data.added ? 0 : -1;
 }
 
 
-int hostapd_wps_button_pushed(struct hostapd_data *hapd)
+static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
 {
        if (hapd->wps == NULL)
-               return -1;
+               return 0;
        return wps_registrar_button_pushed(hapd->wps->registrar);
 }
 
 
+int hostapd_wps_button_pushed(struct hostapd_data *hapd)
+{
+       return hostapd_wps_for_each(hapd, wps_button_pushed, NULL);
+}
+
+
 #ifdef CONFIG_WPS_OOB
 int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
                          char *path, char *method, char *name)
@@ -1072,31 +1203,53 @@ static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
 }
 
 
-void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
+static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
 {
-       wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
        os_free(hapd->conf->ap_pin);
        hapd->conf->ap_pin = NULL;
 #ifdef CONFIG_WPS_UPNP
        upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
 #endif /* CONFIG_WPS_UPNP */
        eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+       return 0;
 }
 
 
-const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
 {
-       unsigned int pin;
+       wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+       hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
+}
+
+
+struct wps_ap_pin_data {
        char pin_txt[9];
+       int timeout;
+};
 
-       pin = wps_generate_pin();
-       os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
+
+static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
+{
+       struct wps_ap_pin_data *data = ctx;
        os_free(hapd->conf->ap_pin);
-       hapd->conf->ap_pin = os_strdup(pin_txt);
+       hapd->conf->ap_pin = os_strdup(data->pin_txt);
 #ifdef CONFIG_WPS_UPNP
-       upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt);
+       upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
 #endif /* CONFIG_WPS_UPNP */
-       hostapd_wps_ap_pin_enable(hapd, timeout);
+       hostapd_wps_ap_pin_enable(hapd, data->timeout);
+       return 0;
+}
+
+
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+{
+       unsigned int pin;
+       struct wps_ap_pin_data data;
+
+       pin = wps_generate_pin();
+       os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin);
+       data.timeout = timeout;
+       hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
        return hapd->conf->ap_pin;
 }
 
@@ -1110,13 +1263,12 @@ const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
 int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
                           int timeout)
 {
-       os_free(hapd->conf->ap_pin);
-       hapd->conf->ap_pin = os_strdup(pin);
-       if (hapd->conf->ap_pin == NULL)
+       struct wps_ap_pin_data data;
+       int ret;
+
+       ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
+       if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
                return -1;
-#ifdef CONFIG_WPS_UPNP
-       upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin);
-#endif /* CONFIG_WPS_UPNP */
-       hostapd_wps_ap_pin_enable(hapd, timeout);
-       return 0;
+       data.timeout = timeout;
+       return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
 }