]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Handle Selected Registrar as a union of info from all Registrars
authorJouni Malinen <j@w1.fi>
Sat, 12 Dec 2009 14:54:59 +0000 (16:54 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 12 Dec 2009 14:54:59 +0000 (16:54 +0200)
Instead of using the latest selected registrar change, collect selected
registrar information separately from all registrars and use the union
of this information when building the WPS IE for Beacon and Probe
Response frames.

Note: SetSelectedRegistrar UPnP action does not include a unique
identifier, so the ER matching routine is based only on the IP address
of the ER. In theory, there could be multiple ERs using the same IP
address (but different port or URL), so there may be some corner cases
that would not always match the correct ER entry at the AP. Anyway, this
is not really expected to occur in normal use cases and even if it did
happen, the selected registrar information is not any worse than it was
before when only the last change from any registrar for being
advertized.

hostapd/Makefile
src/wps/wps.h
src/wps/wps_i.h
src/wps/wps_registrar.c
src/wps/wps_upnp.c
src/wps/wps_upnp_ap.c [new file with mode: 0644]
src/wps/wps_upnp_i.h
src/wps/wps_upnp_web.c
wpa_supplicant/Makefile

index 9d9ec3390306ba188d28459ad6fe144f7dda03b6..4155a3465330d3acaf88ef76bea15aa94d2f7431 100644 (file)
@@ -314,6 +314,7 @@ OBJS += ../src/wps/wps_upnp.o
 OBJS += ../src/wps/wps_upnp_ssdp.o
 OBJS += ../src/wps/wps_upnp_web.o
 OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
 OBJS += ../src/wps/upnp_xml.o
 OBJS += ../src/wps/httpread.o
 OBJS += ../src/wps/http_client.o
index e6464a6443fdf0d30146c412907122ec73de0320..8d6c1a615e81ba995eab7e8897841e5de99dfed2 100644 (file)
@@ -657,8 +657,6 @@ int wps_registrar_button_pushed(struct wps_registrar *reg);
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
                                const struct wpabuf *wps_data);
 int wps_registrar_update_ie(struct wps_registrar *reg);
-int wps_registrar_set_selected_registrar(struct wps_registrar *reg,
-                                        const struct wpabuf *msg);
 int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
                           char *buf, size_t buflen);
 
index 70037b1df6e3d121c322db28d9108bf5f629fa67..07d3029702b82ecbffeac73f6f51c18d7464de5e 100644 (file)
@@ -259,6 +259,7 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
 int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
 int wps_device_store(struct wps_registrar *reg,
                     struct wps_device_data *dev, const u8 *uuid);
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
 
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
index 2da674bf115b6a35857e851419b176b97fa4720d..8a25c9292768efbb227a133a59fb026bcaf4824d 100644 (file)
 #include "common.h"
 #include "base64.h"
 #include "eloop.h"
+#include "uuid.h"
 #include "crypto/crypto.h"
 #include "crypto/sha256.h"
 #include "common/ieee802_11_defs.h"
 #include "wps_i.h"
 #include "wps_dev_attr.h"
 #include "wps_upnp.h"
-#include "uuid.h"
+#include "wps_upnp_i.h"
 
 #define WPS_WORKAROUNDS
 
@@ -111,6 +112,7 @@ struct wps_registrar {
        int skip_cred_build;
        struct wpabuf *extra_cred;
        int disable_auto_conf;
+       int sel_reg_union;
        int sel_reg_dev_password_id_override;
        int sel_reg_config_methods_override;
        int static_wep_only;
@@ -122,7 +124,6 @@ struct wps_registrar {
 
 
 static int wps_set_ie(struct wps_registrar *reg);
-static void wps_cb_set_sel_reg(struct wps_registrar *reg);
 static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wps_registrar_set_selected_timeout(void *eloop_ctx,
                                               void *timeout_ctx);
@@ -344,7 +345,7 @@ static int wps_build_ap_setup_locked(struct wps_context *wps,
 static int wps_build_selected_registrar(struct wps_registrar *reg,
                                        struct wpabuf *msg)
 {
-       if (!reg->selected_registrar)
+       if (!reg->sel_reg_union)
                return 0;
        wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar");
        wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
@@ -358,7 +359,7 @@ static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
                                             struct wpabuf *msg)
 {
        u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
-       if (!reg->selected_registrar)
+       if (!reg->sel_reg_union)
                return 0;
        if (reg->sel_reg_dev_password_id_override >= 0)
                id = reg->sel_reg_dev_password_id_override;
@@ -374,7 +375,7 @@ static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
                                            struct wpabuf *msg)
 {
        u16 methods;
-       if (!reg->selected_registrar)
+       if (!reg->sel_reg_union)
                return 0;
        methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
        if (reg->pbc)
@@ -537,8 +538,7 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
        wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
        reg->selected_registrar = 1;
        reg->pbc = 0;
-       wps_set_ie(reg);
-       wps_cb_set_sel_reg(reg);
+       wps_registrar_selected_registrar_changed(reg);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
                               wps_registrar_set_selected_timeout,
@@ -692,8 +692,7 @@ static void wps_registrar_stop_pbc(struct wps_registrar *reg)
 {
        reg->selected_registrar = 0;
        reg->pbc = 0;
-       wps_set_ie(reg);
-       wps_cb_set_sel_reg(reg);
+       wps_registrar_selected_registrar_changed(reg);
 }
 
 
@@ -728,8 +727,7 @@ int wps_registrar_button_pushed(struct wps_registrar *reg)
        reg->force_pbc_overlap = 0;
        reg->selected_registrar = 1;
        reg->pbc = 1;
-       wps_set_ie(reg);
-       wps_cb_set_sel_reg(reg);
+       wps_registrar_selected_registrar_changed(reg);
 
        eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
@@ -745,13 +743,13 @@ static void wps_registrar_pbc_completed(struct wps_registrar *reg)
        wps_registrar_stop_pbc(reg);
 }
 
+
 static void wps_registrar_pin_completed(struct wps_registrar *reg)
 {
        wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        reg->selected_registrar = 0;
-       wps_set_ie(reg);
-       wps_cb_set_sel_reg(reg);
+       wps_registrar_selected_registrar_changed(reg);
 }
 
 
@@ -2731,64 +2729,91 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
 {
        struct wps_registrar *reg = eloop_ctx;
 
-       wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar timed out - "
-                  "unselect Registrar");
+       wpa_printf(MSG_DEBUG, "WPS: Selected Registrar timeout - "
+                  "unselect internal Registrar");
        reg->selected_registrar = 0;
        reg->pbc = 0;
-       reg->sel_reg_dev_password_id_override = -1;
-       reg->sel_reg_config_methods_override = -1;
-       wps_set_ie(reg);
-       wps_cb_set_sel_reg(reg);
+       wps_registrar_selected_registrar_changed(reg);
+}
+
+
+#ifdef CONFIG_WPS_UPNP
+static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
+                                     struct subscription *s)
+{
+       wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
+                  "config_methods=0x%x)",
+                  s->dev_password_id, s->config_methods);
+       reg->sel_reg_union = 1;
+       if (reg->sel_reg_dev_password_id_override != DEV_PW_PUSHBUTTON)
+               reg->sel_reg_dev_password_id_override = s->dev_password_id;
+       if (reg->sel_reg_config_methods_override == -1)
+               reg->sel_reg_config_methods_override = 0;
+       reg->sel_reg_config_methods_override |= s->config_methods;
+}
+#endif /* CONFIG_WPS_UPNP */
+
+
+static void wps_registrar_sel_reg_union(struct wps_registrar *reg)
+{
+#ifdef CONFIG_WPS_UPNP
+       struct subscription *s;
+
+       if (reg->wps->wps_upnp == NULL)
+               return;
+
+       s = reg->wps->wps_upnp->subscriptions;
+       while (s) {
+               if (s->addr_list)
+                       wpa_printf(MSG_DEBUG, "WPS: External Registrar %s:%d",
+                                  inet_ntoa(s->addr_list->saddr.sin_addr),
+                                  ntohs(s->addr_list->saddr.sin_port));
+               if (s->selected_registrar)
+                       wps_registrar_sel_reg_add(reg, s);
+               else
+                       wpa_printf(MSG_DEBUG, "WPS: External Registrar not "
+                                  "selected");
+
+               s = s->next;
+               if (s == reg->wps->wps_upnp->subscriptions)
+                       break;
+       }
+#endif /* CONFIG_WPS_UPNP */
 }
 
 
 /**
- * wps_registrar_set_selected_registrar - Notification of SetSelectedRegistrar
+ * wps_registrar_selected_registrar_changed - SetSelectedRegistrar change
  * @reg: Registrar data from wps_registrar_init()
- * @msg: Received message from SetSelectedRegistrar
- * Returns: 0 on success, -1 on failure
  *
- * This function is called when an AP receives a SetSelectedRegistrar UPnP
- * message.
+ * This function is called when selected registrar state changes, e.g., when an
+ * AP receives a SetSelectedRegistrar UPnP message.
  */
-int wps_registrar_set_selected_registrar(struct wps_registrar *reg,
-                                        const struct wpabuf *msg)
+void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
 {
-       struct wps_parse_attr attr;
+       wpa_printf(MSG_DEBUG, "WPS: Selected registrar information changed");
 
-       wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes",
-                       msg);
-
-       if (wps_parse_msg(msg, &attr) < 0)
-               return -1;
-       if (!wps_version_supported(attr.version)) {
-               wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar "
-                          "version 0x%x", attr.version ? *attr.version : 0);
-               return -1;
-       }
+       reg->sel_reg_union = reg->selected_registrar;
+       reg->sel_reg_dev_password_id_override = -1;
+       reg->sel_reg_config_methods_override = -1;
+       if (reg->selected_registrar) {
+               reg->sel_reg_config_methods_override =
+                       reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+               if (reg->pbc) {
+                       reg->sel_reg_dev_password_id_override =
+                               DEV_PW_PUSHBUTTON;
+                       reg->sel_reg_config_methods_override |=
+                               WPS_CONFIG_PUSHBUTTON;
+               }
+               wpa_printf(MSG_DEBUG, "WPS: Internal Registrar selected "
+                          "(pbc=%d)", reg->pbc);
+       } else
+               wpa_printf(MSG_DEBUG, "WPS: Internal Registrar not selected");
 
-       if (attr.selected_registrar == NULL ||
-           *attr.selected_registrar == 0) {
-               wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
-                          "Selected Registrar");
-               eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg,
-                                    NULL);
-               wps_registrar_set_selected_timeout(reg, NULL);
-               return 0;
-       }
+       wps_registrar_sel_reg_union(reg);
 
-       reg->selected_registrar = 1;
-       reg->sel_reg_dev_password_id_override = attr.dev_password_id ?
-               WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
-       reg->sel_reg_config_methods_override = attr.sel_reg_config_methods ?
-               WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
        wps_set_ie(reg);
-
-       eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
-       eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
-                              wps_registrar_set_selected_timeout,
-                              reg, NULL);
-       return 0;
+       wps_cb_set_sel_reg(reg);
 }
 
 
index 0b66ea29fd13f753f3502911759dfff1840b17eb..7d6fb29de4fb4645914cea7ef17fe9992e7f1fe2 100644 (file)
@@ -601,6 +601,7 @@ void subscription_destroy(struct subscription *s)
        if (s->addr_list)
                subscr_addr_free_all(s);
        event_delete_all(s);
+       upnp_er_remove_notification(s);
        os_free(s);
 }
 
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
new file mode 100644 (file)
index 0000000..93746da
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Wi-Fi Protected Setup - UPnP AP functionality
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "wps_i.h"
+#include "wps_upnp.h"
+#include "wps_upnp_i.h"
+
+
+static void upnp_er_set_selected_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct subscription *s = eloop_ctx;
+       wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar from ER timed out");
+       s->selected_registrar = 0;
+       wps_registrar_selected_registrar_changed(s->reg);
+}
+
+
+int upnp_er_set_selected_registrar(struct wps_registrar *reg,
+                                  struct subscription *s,
+                                  const struct wpabuf *msg)
+{
+       struct wps_parse_attr attr;
+
+       wpa_hexdump_buf(MSG_MSGDUMP, "WPS: SetSelectedRegistrar attributes",
+                       msg);
+
+       if (wps_parse_msg(msg, &attr) < 0)
+               return -1;
+       if (!wps_version_supported(attr.version)) {
+               wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar "
+                          "version 0x%x", attr.version ? *attr.version : 0);
+               return -1;
+       }
+
+       s->reg = reg;
+       eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
+
+       if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) {
+               wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
+                          "Selected Registrar");
+               s->selected_registrar = 0;
+       } else {
+               s->selected_registrar = 1;
+               s->dev_password_id = attr.dev_password_id ?
+                       WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
+               s->config_methods = attr.sel_reg_config_methods ?
+                       WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
+               eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+                                      upnp_er_set_selected_timeout, s, NULL);
+       }
+
+       wps_registrar_selected_registrar_changed(reg);
+
+       return 0;
+}
+
+
+void upnp_er_remove_notification(struct subscription *s)
+{
+       s->selected_registrar = 0;
+       eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
+       if (s->reg)
+               wps_registrar_selected_registrar_changed(s->reg);
+}
index cfa30cffe38af7e6f3d3306d79372e0f81ae3721..d05956137ad822d124d916d7d221521130f59088 100644 (file)
@@ -32,6 +32,7 @@
 
 struct subscription;
 struct upnp_wps_device_sm;
+struct wps_registrar;
 
 
 enum advertisement_type_enum {
@@ -100,6 +101,12 @@ struct subscription {
        int n_queue; /* How many events are queued */
        struct wps_event_ *current_event; /* non-NULL if being sent (not in q)
                                           */
+
+       /* Information from SetSelectedRegistrar action */
+       u8 selected_registrar;
+       u16 dev_password_id;
+       u16 config_methods;
+       struct wps_registrar *reg;
 };
 
 
@@ -178,4 +185,10 @@ void event_delete_all(struct subscription *s);
 void event_send_all_later(struct upnp_wps_device_sm *sm);
 void event_send_stop_all(struct upnp_wps_device_sm *sm);
 
+/* wps_upnp_ap.c */
+int upnp_er_set_selected_registrar(struct wps_registrar *reg,
+                                  struct subscription *s,
+                                  const struct wpabuf *msg);
+void upnp_er_remove_notification(struct subscription *s);
+
 #endif /* WPS_UPNP_I_H */
index 1ba9118d161fd1f46f219976da3d2c9ecf6389f5..4b20d5ba72ad9d4b4a928d7763f7621f525ec842 100644 (file)
@@ -537,19 +537,61 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
 }
 
 
+static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
+{
+       struct subscr_addr *a;
+
+       a = s->addr_list;
+       while (a) {
+               if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
+                       return 1;
+               a = a->next;
+               if (a == s->addr_list)
+                       break;
+       }
+       return 0;
+}
+
+
+static struct subscription * find_er(struct upnp_wps_device_sm *sm,
+                                    struct sockaddr_in *cli)
+{
+       struct subscription *s;
+
+       s = sm->subscriptions;
+       while (s) {
+               if (find_er_addr(s, cli))
+                       return s;
+               s = s->next;
+               if (s == sm->subscriptions)
+                       break;
+       }
+
+       return NULL;
+}
+
+
 static enum http_reply_code
-web_process_set_selected_registrar(struct upnp_wps_device_sm *sm, char *data,
+web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
+                                  struct sockaddr_in *cli, char *data,
                                   struct wpabuf **reply,
                                   const char **replyname)
 {
        struct wpabuf *msg;
        enum http_reply_code ret;
+       struct subscription *s;
 
        wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
+       s = find_er(sm, cli);
+       if (s == NULL) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
+                          "from unknown ER");
+               return UPNP_ACTION_FAILED;
+       }
        msg = xml_get_base64_item(data, "NewMessage", &ret);
        if (msg == NULL)
                return ret;
-       if (wps_registrar_set_selected_registrar(sm->wps->registrar, msg)) {
+       if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) {
                wpabuf_free(msg);
                return HTTP_INTERNAL_SERVER_ERROR;
        }
@@ -744,6 +786,7 @@ static const char * web_get_action(struct http_request *req,
  * would appear to be required (given that we will be closing it!).
  */
 static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
+                                     struct sockaddr_in *cli,
                                      struct http_request *req,
                                      const char *filename)
 {
@@ -774,7 +817,7 @@ static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
                ret = web_process_put_wlan_response(sm, data, &reply,
                                                    &replyname);
        else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
-               ret = web_process_set_selected_registrar(sm, data, &reply,
+               ret = web_process_set_selected_registrar(sm, cli, data, &reply,
                                                         &replyname);
        else
                wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
@@ -1160,7 +1203,7 @@ static void web_connection_check_data(void *ctx, struct http_request *req)
                web_connection_parse_get(sm, req, filename);
                break;
        case HTTPREAD_HDR_TYPE_POST:
-               web_connection_parse_post(sm, req, filename);
+               web_connection_parse_post(sm, cli, req, filename);
                break;
        case HTTPREAD_HDR_TYPE_SUBSCRIBE:
                web_connection_parse_subscribe(sm, req, filename);
index d111c38e2741d77e27b3c3b9b0029a5ff3506dcb..1eb5b3bf217255a6227690b69a2fd05614ac050b 100644 (file)
@@ -498,6 +498,7 @@ OBJS += ../src/wps/wps_upnp.o
 OBJS += ../src/wps/wps_upnp_ssdp.o
 OBJS += ../src/wps/wps_upnp_web.o
 OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
 OBJS += ../src/wps/upnp_xml.o
 OBJS += ../src/wps/httpread.o
 OBJS += ../src/wps/http_client.o