Browse Source

WPS UPnP: Added support for multiple external Registrars

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.
Jouni Malinen 16 years ago
parent
commit
915c1ba3c5
8 changed files with 121 additions and 35 deletions
  1. 19 14
      hostapd/wps_hostapd.c
  2. 0 1
      src/eap_server/eap_wsc.c
  3. 13 0
      src/wps/wps.c
  4. 17 4
      src/wps/wps.h
  5. 65 12
      src/wps/wps_registrar.c
  6. 2 1
      src/wps/wps_upnp.h
  7. 1 0
      src/wps/wps_upnp_event.c
  8. 4 3
      src/wps/wps_upnp_web.c

+ 19 - 14
hostapd/wps_hostapd.c

@@ -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);
 }
 
 

+ 0 - 1
src/eap_server/eap_wsc.c

@@ -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);

+ 13 - 0
src/wps/wps.c

@@ -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);
+	}
+}

+ 17 - 4
src/wps/wps.h

@@ -332,6 +332,20 @@ union wps_event_data {
 	} pwd_auth_fail;
 };
 
+/**
+ * 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
  *
@@ -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 */

+ 65 - 12
src/wps/wps_registrar.c

@@ -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;

+ 2 - 1
src/wps/wps_upnp.h

@@ -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);

+ 1 - 0
src/wps/wps_upnp_event.c

@@ -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"
 

+ 4 - 3
src/wps/wps_upnp_web.c

@@ -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);