WPS UPnP: Added support for multiple external Registrars
authorJouni Malinen <jouni.malinen@atheros.com>
Fri, 6 Feb 2009 19:39:32 +0000 (21:39 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 6 Feb 2009 19:39:32 +0000 (21:39 +0200)
Allow more than one pending PutWLANMessage data to be stored (M2/M2D
from multiple external Registrars) and drop pending M2/M2D messages when
the Enrollee replies with M3.

hostapd/wps_hostapd.c
src/eap_server/eap_wsc.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_registrar.c
src/wps/wps_upnp.h
src/wps/wps_upnp_event.c
src/wps/wps_upnp_web.c

index 1ad7bee..d32ee26 100644 (file)
@@ -661,7 +661,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
        wps_registrar_deinit(hapd->wps->registrar);
        os_free(hapd->wps->network_key);
        wps_device_data_free(&hapd->wps->dev);
-       wpabuf_free(hapd->wps->upnp_msg);
+       wps_free_pending_msgs(hapd->wps->upnp_msgs);
        os_free(hapd->wps);
        hapd->wps = NULL;
        hostapd_wps_clear_ies(hapd);
@@ -855,10 +855,12 @@ static int hostapd_rx_req_del_sta_settings(void *priv,
 
 static int hostapd_rx_req_put_wlan_event_response(
        void *priv, enum upnp_wps_wlanevent_type ev_type,
-       const u8 *mac_addr, const struct wpabuf *msg)
+       const u8 *mac_addr, const struct wpabuf *msg,
+       enum wps_msg_type msg_type)
 {
        struct hostapd_data *hapd = priv;
        struct sta_info *sta;
+       struct upnp_pending_message *p;
 
        wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
                   MACSTR, ev_type, MAC2STR(mac_addr));
@@ -875,11 +877,6 @@ static int hostapd_rx_req_put_wlan_event_response(
         * server implementation for delivery to the peer.
         */
 
-       /* TODO: support multiple pending UPnP messages */
-       os_memcpy(hapd->wps->upnp_msg_addr, mac_addr, ETH_ALEN);
-       wpabuf_free(hapd->wps->upnp_msg);
-       hapd->wps->upnp_msg = wpabuf_dup(msg);
-
        sta = ap_get_sta(hapd, mac_addr);
        if (!sta) {
                /*
@@ -890,18 +887,26 @@ static int hostapd_rx_req_put_wlan_event_response(
                wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
                           "on NewWLANEventMAC; try wildcard match");
                for (sta = hapd->sta_list; sta; sta = sta->next) {
-                       if (sta->eapol_sm &&
-                           sta->eapol_sm->eap == hapd->wps->pending_session)
+                       if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
                                break;
                }
        }
-       if (sta)
-               return eapol_auth_eap_pending_cb(sta->eapol_sm,
-                                                hapd->wps->pending_session);
 
-       wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
+       if (!sta) {
+               wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
+               return 0;
+       }
 
-       return 0;
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL)
+               return -1;
+       os_memcpy(p->addr, sta->addr, ETH_ALEN);
+       p->msg = wpabuf_dup(msg);
+       p->type = msg_type;
+       p->next = hapd->wps->upnp_msgs;
+       hapd->wps->upnp_msgs = p;
+
+       return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
 }
 
 
index 097e8c4..3c17577 100644 (file)
@@ -436,7 +436,6 @@ static void eap_wsc_process(struct eap_sm *sm, void *priv,
        case WPS_PENDING:
                eap_wsc_state(data, MSG);
                sm->method_pending = METHOD_PENDING_WAIT;
-               sm->wps->pending_session = sm;
                eloop_cancel_timeout(eap_wsc_ext_reg_timeout, sm, data);
                eloop_register_timeout(5, 0, eap_wsc_ext_reg_timeout,
                                       sm, data);
index 015eb07..395eba6 100644 (file)
@@ -320,3 +320,16 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
 
        return ie;
 }
+
+
+void wps_free_pending_msgs(struct upnp_pending_message *msgs)
+{
+       struct upnp_pending_message *p, *prev;
+       p = msgs;
+       while (p) {
+               prev = p;
+               p = p->next;
+               wpabuf_free(prev->msg);
+               os_free(prev);
+       }
+}
index c42ce1e..e0f2b2d 100644 (file)
@@ -333,6 +333,20 @@ union wps_event_data {
 };
 
 /**
+ * struct upnp_pending_message - Pending PutWLANResponse messages
+ * @next: Pointer to next pending message or %NULL
+ * @addr: NewWLANEventMAC
+ * @msg: NewMessage
+ * @type: Message Type
+ */
+struct upnp_pending_message {
+       struct upnp_pending_message *next;
+       u8 addr[ETH_ALEN];
+       struct wpabuf *msg;
+       enum wps_msg_type type;
+};
+
+/**
  * struct wps_context - Long term WPS context data
  *
  * This data is stored at the higher layer Authenticator or Supplicant data
@@ -476,10 +490,8 @@ struct wps_context {
 
        struct upnp_wps_device_sm *wps_upnp;
 
-       /* TODO: support multiple pending messages from UPnP PutWLANResponse */
-       u8 upnp_msg_addr[ETH_ALEN];
-       struct wpabuf *upnp_msg;
-       void *pending_session;
+       /* Pending messages from UPnP PutWLANResponse */
+       struct upnp_pending_message *upnp_msgs;
 };
 
 
@@ -501,5 +513,6 @@ int wps_registrar_set_selected_registrar(struct wps_registrar *reg,
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
 unsigned int wps_generate_pin(void);
+void wps_free_pending_msgs(struct upnp_pending_message *msgs);
 
 #endif /* WPS_H */
index de76a00..949f540 100644 (file)
@@ -216,6 +216,31 @@ static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)
 }
 
 
+#ifdef CONFIG_WPS_UPNP
+static void wps_registrar_free_pending_m2(struct wps_context *wps)
+{
+       struct upnp_pending_message *p, *p2, *prev = NULL;
+       p = wps->upnp_msgs;
+       while (p) {
+               if (p->type == WPS_M2 || p->type == WPS_M2D) {
+                       if (prev == NULL)
+                               wps->upnp_msgs = p->next;
+                       else
+                               prev->next = p->next;
+                       wpa_printf(MSG_DEBUG, "WPS UPnP: Drop pending M2/M2D");
+                       p2 = p;
+                       p = p->next;
+                       wpabuf_free(p2->msg);
+                       os_free(p2);
+                       continue;
+               }
+               prev = p;
+               p = p->next;
+       }
+}
+#endif /* CONFIG_WPS_UPNP */
+
+
 static int wps_build_ap_setup_locked(struct wps_context *wps,
                                     struct wpabuf *msg)
 {
@@ -1324,13 +1349,30 @@ struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
        struct wpabuf *msg;
 
 #ifdef CONFIG_WPS_UPNP
-       if (wps->wps->wps_upnp && wps->wps->upnp_msg) {
-               wpa_printf(MSG_DEBUG, "WPS: Use pending message from UPnP");
-               msg = wps->wps->upnp_msg;
-               wps->wps->upnp_msg = NULL;
-               *op_code = WSC_MSG; /* FIX: ack/nack */
-               wps->ext_reg = 1;
-               return msg;
+       if (wps->wps->wps_upnp) {
+               struct upnp_pending_message *p, *prev = NULL;
+               if (wps->ext_reg > 1)
+                       wps_registrar_free_pending_m2(wps->wps);
+               p = wps->wps->upnp_msgs;
+               /* TODO: check pending message MAC address */
+               while (p && p->next) {
+                       prev = p;
+                       p = p->next;
+               }
+               if (p) {
+                       wpa_printf(MSG_DEBUG, "WPS: Use pending message from "
+                                  "UPnP");
+                       if (prev)
+                               prev->next = NULL;
+                       else
+                               wps->wps->upnp_msgs = NULL;
+                       msg = p->msg;
+                       os_free(p);
+                       *op_code = WSC_MSG;
+                       if (wps->ext_reg == 0)
+                               wps->ext_reg = 1;
+                       return msg;
+               }
        }
        if (wps->ext_reg) {
                wpa_printf(MSG_DEBUG, "WPS: Using external Registrar, but no "
@@ -1958,8 +2000,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
 #ifdef CONFIG_WPS_UPNP
                if (wps->wps->wps_upnp && attr.mac_addr) {
                        /* Remove old pending messages when starting new run */
-                       wpabuf_free(wps->wps->upnp_msg);
-                       wps->wps->upnp_msg = NULL;
+                       wps_free_pending_msgs(wps->wps->upnp_msgs);
+                       wps->wps->upnp_msgs = NULL;
 
                        upnp_wps_device_send_wlan_event(
                                wps->wps->wps_upnp, attr.mac_addr,
@@ -2030,7 +2072,7 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
 #ifdef CONFIG_WPS_UPNP
        if (wps->wps->wps_upnp && wps->ext_reg && wps->state == RECV_M2D_ACK &&
            upnp_wps_subscribers(wps->wps->wps_upnp)) {
-               if (wps->wps->upnp_msg)
+               if (wps->wps->upnp_msgs)
                        return WPS_CONTINUE;
                wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
                           "external Registrar");
@@ -2055,8 +2097,10 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
 #ifdef CONFIG_WPS_UPNP
                if (wps->wps->wps_upnp &&
                    upnp_wps_subscribers(wps->wps->wps_upnp)) {
-                       if (wps->wps->upnp_msg)
+                       if (wps->wps->upnp_msgs)
                                return WPS_CONTINUE;
+                       if (wps->ext_reg == 0)
+                               wps->ext_reg = 1;
                        wpa_printf(MSG_DEBUG, "WPS: Wait for response from an "
                                   "external Registrar");
                        return WPS_PENDING;
@@ -2278,7 +2322,16 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
                   (unsigned long) wpabuf_len(msg), op_code);
 
 #ifdef CONFIG_WPS_UPNP
-       if (wps->wps->wps_upnp && wps->ext_reg && wps->wps->upnp_msg == NULL &&
+       if (wps->wps->wps_upnp && op_code == WSC_MSG && wps->ext_reg == 1) {
+               struct wps_parse_attr attr;
+               if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type &&
+                   *attr.msg_type == WPS_M3)
+                       wps->ext_reg = 2; /* past M2/M2D phase */
+       }
+       if (wps->ext_reg > 1)
+               wps_registrar_free_pending_m2(wps->wps);
+       if (wps->wps->wps_upnp && wps->ext_reg &&
+           wps->wps->upnp_msgs == NULL &&
            (op_code == WSC_MSG || op_code == WSC_Done)) {
                struct wps_parse_attr attr;
                int type;
index 995a7f2..eb3397e 100644 (file)
@@ -40,7 +40,8 @@ struct upnp_wps_device_ctx {
        int (*rx_req_del_sta_settings)(void *priv, const struct wpabuf *msg);
        int (*rx_req_put_wlan_event_response)(
                void *priv, enum upnp_wps_wlanevent_type ev_type,
-               const u8 *mac_addr, const struct wpabuf *msg);
+               const u8 *mac_addr, const struct wpabuf *msg,
+               enum wps_msg_type msg_type);
        int (*rx_req_set_selected_registrar)(void *priv,
                                             const struct wpabuf *msg);
        int (*rx_req_reboot_ap)(void *priv, const struct wpabuf *msg);
index 7470e61..f278f35 100644 (file)
@@ -16,6 +16,7 @@
 #include "eloop.h"
 #include "uuid.h"
 #include "httpread.h"
+#include "wps_defs.h"
 #include "wps_upnp.h"
 #include "wps_upnp_i.h"
 
index 3e68672..241afaa 100644 (file)
@@ -993,6 +993,7 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
        enum http_reply_code ret;
        u8 macaddr[ETH_ALEN];
        int ev_type;
+       int type;
        char *val;
 
        /*
@@ -1020,17 +1021,17 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
        os_free(val);
        if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
                struct wps_parse_attr attr;
-               int type;
                if (wps_parse_msg(msg, &attr) < 0 ||
                    attr.msg_type == NULL)
                        type = -1;
                else
                        type = *attr.msg_type;
                wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
-       }
+       } else
+               type = -1;
        if (!sm->ctx->rx_req_put_wlan_event_response ||
            sm->ctx->rx_req_put_wlan_event_response(sm->priv, ev_type,
-                                                   macaddr, msg)) {
+                                                   macaddr, msg, type)) {
                wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
                           "rx_req_put_wlan_event_response");
                wpabuf_free(msg);