WPS ER: Fetch AP's M1 to learn device type and WPS state
authorJouni Malinen <j@w1.fi>
Sat, 21 Nov 2009 11:13:02 +0000 (13:13 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 21 Nov 2009 11:13:02 +0000 (13:13 +0200)
src/wps/wps_er.c

index 699315b..7e3a14c 100644 (file)
@@ -66,6 +66,8 @@ struct wps_er_ap {
        struct wps_data *wps;
 
        u8 uuid[WPS_UUID_LEN];
+       u8 pri_dev_type[8];
+       u8 wps_state;
        char *friendly_name;
        char *manufacturer;
        char *manufacturer_url;
@@ -85,6 +87,8 @@ struct wps_er_ap {
        unsigned int id;
 
        struct wps_credential *ap_settings;
+
+       void (*m1_handler)(struct wps_er_ap *ap, struct wpabuf *m1);
 };
 
 struct wps_er {
@@ -104,6 +108,9 @@ struct wps_er {
 
 
 static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
+static int wps_er_send_get_device_info(struct wps_er_ap *ap,
+                                      void (*m1_handler)(struct wps_er_ap *ap,
+                                                         struct wpabuf *m1));
 
 
 static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
@@ -377,6 +384,29 @@ static void wps_er_subscribe(struct wps_er_ap *ap)
 }
 
 
+static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
+{
+       struct wps_parse_attr attr;
+
+       if (wps_parse_msg(m1, &attr) < 0) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
+               return;
+       }
+       if (attr.primary_dev_type)
+               os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
+       if (attr.wps_state)
+               ap->wps_state = *attr.wps_state;
+
+       wps_er_subscribe(ap);
+}
+
+
+static void wps_er_get_device_info(struct wps_er_ap *ap)
+{
+       wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
+}
+
+
 static void wps_er_parse_device_description(struct wps_er_ap *ap,
                                            struct wpabuf *reply)
 {
@@ -443,7 +473,7 @@ static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
 {
        struct wps_er_ap *ap = ctx;
        struct wpabuf *reply;
-       int subscribe = 0;
+       int ok = 0;
 
        switch (event) {
        case HTTP_CLIENT_OK:
@@ -451,7 +481,7 @@ static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
                if (reply == NULL)
                        break;
                wps_er_parse_device_description(ap, reply);
-               subscribe = 1;
+               ok = 1;
                break;
        case HTTP_CLIENT_FAILED:
        case HTTP_CLIENT_INVALID_REPLY:
@@ -461,8 +491,8 @@ static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
        }
        http_client_free(ap->http);
        ap->http = NULL;
-       if (subscribe)
-               wps_er_subscribe(ap);
+       if (ok)
+               wps_er_get_device_info(ap);
 }
 
 
@@ -1560,25 +1590,13 @@ static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
 }
 
 
-static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
+static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
 {
-       struct wpabuf *info;
-       enum http_reply_code ret;
        struct wps_config cfg;
 
-       wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
-                  "from the AP");
-       info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
-       if (info == NULL) {
-               wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
-                          "NewDeviceInfo from GetDeviceInfo response");
-               return;
-       }
-
        if (ap->wps) {
                wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
                           "progress with this AP");
-               wpabuf_free(info);
                return;
        }
 
@@ -1586,14 +1604,30 @@ static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
        cfg.wps = ap->er->wps;
        cfg.registrar = 1;
        ap->wps = wps_init(&cfg);
-       if (ap->wps == NULL) {
-               wpabuf_free(info);
+       if (ap->wps == NULL)
                return;
-       }
        ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
        ap->wps->ap_settings_cb_ctx = ap;
 
-       wps_er_ap_process(ap, info);
+       wps_er_ap_process(ap, m1);
+}
+
+
+static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
+{
+       struct wpabuf *info;
+       enum http_reply_code ret;
+
+       wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
+                  "from the AP");
+       info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
+       if (info == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
+                          "NewDeviceInfo from GetDeviceInfo response");
+               return;
+       }
+
+       ap->m1_handler(ap, info);
        wpabuf_free(info);
 }
 
@@ -1632,27 +1666,18 @@ static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
 }
 
 
-int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
-                size_t pin_len)
+static int wps_er_send_get_device_info(struct wps_er_ap *ap,
+                                      void (*m1_handler)(struct wps_er_ap *ap,
+                                                         struct wpabuf *m1))
 {
-       struct wps_er_ap *ap;
        struct wpabuf *buf;
        char *len_ptr, *body_ptr;
        struct sockaddr_in dst;
        char *url, *path;
 
-       if (er == NULL)
-               return -1;
-
-       ap = wps_er_ap_get(er, NULL, uuid);
-       if (ap == NULL) {
-               wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
-                          "request");
-               return -1;
-       }
-       if (ap->wps || ap->http) {
-               wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
-                          "with the AP - cannot start learn");
+       if (ap->http) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
+                          "with the AP - cannot get device info");
                return -1;
        }
 
@@ -1682,6 +1707,35 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
                return -1;
        }
 
+       ap->m1_handler = m1_handler;
+
+       return 0;
+}
+
+
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
+                size_t pin_len)
+{
+       struct wps_er_ap *ap;
+
+       if (er == NULL)
+               return -1;
+
+       ap = wps_er_ap_get(er, NULL, uuid);
+       if (ap == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
+                          "request");
+               return -1;
+       }
+       if (ap->wps) {
+               wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
+                          "with the AP - cannot start learn");
+               return -1;
+       }
+
+       if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
+               return -1;
+
        /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
        wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);