]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS 2.0: Add support for AuthorizedMACs attribute
authorJouni Malinen <j@w1.fi>
Sat, 12 Dec 2009 14:40:10 +0000 (16:40 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 9 Sep 2010 13:07:47 +0000 (06:07 -0700)
Advertize list of authorized enrollee MAC addresses in Beacon and
Probe Response frames and use these when selecting the AP. In order
to provide the list, the enrollee MAC address should be specified
whenever adding a new PIN. In addition, add UUID-R into
SetSelectedRegistrar action to make it potentially easier for an AP
to figure out which ER sent the action should there be multiple ERs
using the same IP address.

22 files changed:
hostapd/README-WPS
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/wpa_ctrl.h
src/eap_peer/eap_wsc.c
src/wps/wps.c
src/wps/wps.h
src/wps/wps_defs.h
src/wps/wps_er.c
src/wps/wps_i.h
src/wps/wps_registrar.c
src/wps/wps_upnp_ap.c
src/wps/wps_upnp_i.h
wpa_supplicant/ap.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_cli.c
wpa_supplicant/wpa_gui-qt4/peers.cpp
wpa_supplicant/wpa_gui-qt4/wpagui.cpp
wpa_supplicant/wps_supplicant.c
wpa_supplicant/wps_supplicant.h

index 74f211348edebbbb7679804de7e111f247060799..3bfde616a44bc92a67997f16559ca742a48e2616 100644 (file)
@@ -171,10 +171,17 @@ hostapd_cli wps_pin any 12345670
 
 To reduce likelihood of PIN being used with other devices or of
 forgetting an active PIN available for potential attackers, expiration
-time can be set for the new PIN:
+time in seconds can be set for the new PIN (value 0 indicates no
+expiration):
 
 hostapd_cli wps_pin any 12345670 300
 
+If the MAC address of the enrollee is known, it should be configured
+to allow the AP to advertise list of authorized enrollees:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \
+       12345670 300 00:11:22:33:44:55
+
 
 After this, the Enrollee can connect to the AP again and complete WPS
 negotiation. At that point, a new, random WPA PSK is generated for the
index 9c47ba8bb76da7f6f2163fc3ca8d7a3c920af241..e03e66fa11410a1adb63ce0fa4133a3f09027c2c 100644 (file)
@@ -275,6 +275,8 @@ static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
        char *pin = os_strchr(txt, ' ');
        char *timeout_txt;
        int timeout;
+       u8 addr_buf[ETH_ALEN], *addr = NULL;
+       char *pos;
 
        if (pin == NULL)
                return -1;
@@ -284,10 +286,16 @@ static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
        if (timeout_txt) {
                *timeout_txt++ = '\0';
                timeout = atoi(timeout_txt);
+               pos = os_strchr(timeout_txt, ' ');
+               if (pos) {
+                       *pos++ = '\0';
+                       if (hwaddr_aton(pos, addr_buf) == 0)
+                               addr = addr_buf;
+               }
        } else
                timeout = 0;
 
-       return hostapd_wps_add_pin(hapd, txt, pin, timeout);
+       return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
 }
 
 
index 589530e419fc60e74a8ab72ddcf705cad28d3ecf..4f22e853cc3f0488470b98b6ab1e5c0676be6a1c 100644 (file)
@@ -89,7 +89,7 @@ static const char *commands_help =
 "   sa_query <addr>      send SA Query to a station\n"
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
-"   wps_pin <uuid> <pin> [timeout]  add WPS Enrollee PIN (Device Password)\n"
+"   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
 "   wps_pbc              indicate button pushed to initiate PBC\n"
 #ifdef CONFIG_WPS_OOB
 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
@@ -352,13 +352,16 @@ static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
 static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
-       char buf[64];
+       char buf[256];
        if (argc < 2) {
                printf("Invalid 'wps_pin' command - at least two arguments, "
                       "UUID and PIN, are required.\n");
                return -1;
        }
-       if (argc > 2)
+       if (argc > 3)
+               snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
+                        argv[0], argv[1], argv[2], argv[3]);
+       else if (argc > 2)
                snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
                         argv[0], argv[1], argv[2]);
        else
index a6ffd4d0db0bf3974b2f0288fa91b66ccda44f7a..008a88a7443c0de3acd28b6f9be0c1ea005e61f6 100644 (file)
@@ -714,8 +714,8 @@ void hostapd_update_wps(struct hostapd_data *hapd)
 }
 
 
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
-                       const char *pin, int timeout)
+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;
@@ -726,7 +726,8 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
                any = 1;
        else if (uuid_str2bin(uuid, u))
                return -1;
-       return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
+       return wps_registrar_add_pin(hapd->wps->registrar, addr,
+                                    any ? NULL : u,
                                     (const u8 *) pin, os_strlen(pin),
                                     timeout);
 }
@@ -777,7 +778,7 @@ int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
 
        if ((wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ||
             wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_R) &&
-           hostapd_wps_add_pin(hapd, "any",
+           hostapd_wps_add_pin(hapd, NULL, "any",
                                wpabuf_head(wps->oob_conf.dev_password), 0) <
            0)
                goto error;
index e978a1cf668d5ede663917b09ab2f5a6c0f53ec9..b9d525aa3151f272b8cb6d68b7f1668f245ef4b0 100644 (file)
@@ -21,8 +21,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                     struct hostapd_bss_config *conf);
 void hostapd_deinit_wps(struct hostapd_data *hapd);
 void hostapd_update_wps(struct hostapd_data *hapd);
-int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
-                       const char *pin, int timeout);
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+                       const char *uuid, const char *pin, int timeout);
 int hostapd_wps_button_pushed(struct hostapd_data *hapd);
 int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
                          char *path, char *method, char *name);
index 54aa988f4071f07953b25c1b8313ca87413f1863..5780484cf3536c593075366a51ab1887341fbabb 100644 (file)
@@ -63,6 +63,8 @@ extern "C" {
 #define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
 /** Available WPS AP with active PBC found in scan results */
 #define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
+/** Available WPS AP with our address as authorized in scan results */
+#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
 /** Available WPS AP with recently selected PIN registrar found in scan results
  */
 #define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
index f65d982161f6649cee82008567f57923fb9e8445..a38e2ad993373568654df2c638550aa977f6c7a2 100644 (file)
@@ -226,7 +226,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
                data->fragment_size = WSC_FRAGMENT_SIZE;
 
        if (registrar && cfg.pin) {
-               wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
+               wps_registrar_add_pin(data->wps_ctx->registrar, NULL, NULL,
                                      cfg.pin, cfg.pin_len, 0);
        }
 
index 533cbaf677ae428a949099095240ea542b4377f2..6d4b1cbc64474ec905049a7ea695989687101319 100644 (file)
@@ -205,15 +205,8 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
 }
 
 
-/**
- * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
- * @msg: WPS IE contents from Beacon or Probe Response frame
- * Returns: 1 if PIN Registrar is active, 0 if not
- */
-int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+static int is_selected_pin_registrar(struct wps_parse_attr *attr)
 {
-       struct wps_parse_attr attr;
-
        /*
         * In theory, this could also verify that attr.sel_reg_config_methods
         * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
@@ -222,17 +215,69 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
         * Device Password ID here.
         */
 
+       if (!attr->selected_registrar || *attr->selected_registrar == 0)
+               return 0;
+
+       if (attr->dev_password_id != NULL &&
+           WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON)
+               return 0;
+
+       return 1;
+}
+
+
+/**
+ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PIN Registrar is active, 0 if not
+ */
+int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+{
+       struct wps_parse_attr attr;
+
        if (wps_parse_msg(msg, &attr) < 0)
                return 0;
 
-       if (!attr.selected_registrar || *attr.selected_registrar == 0)
+       return is_selected_pin_registrar(&attr);
+}
+
+
+/**
+ * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * @addr: MAC address to search for
+ * @ver1_compat: Whether to use version 1 compatibility mode
+ * Returns: 1 if address is authorized, 0 if not
+ */
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+                          int ver1_compat)
+{
+       struct wps_parse_attr attr;
+       unsigned int i;
+       const u8 *pos;
+
+       if (wps_parse_msg(msg, &attr) < 0)
                return 0;
 
-       if (attr.dev_password_id != NULL &&
-           WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
+       if (!attr.version2 && ver1_compat) {
+               /*
+                * Version 1.0 AP - AuthorizedMACs not used, so revert back to
+                * old mechanism of using SelectedRegistrar.
+                */
+               return is_selected_pin_registrar(&attr);
+       }
+
+       if (!attr.authorized_macs)
                return 0;
 
-       return 1;
+       pos = attr.authorized_macs;
+       for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
+               if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+                       return 1;
+               pos += ETH_ALEN;
+       }
+
+       return 0;
 }
 
 
index 8536499d7b4c9bcc0cb745ca79cd617aeabec60f..31be0b57386411dc25042ee2944c143e5006d109 100644 (file)
@@ -197,6 +197,8 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
 int wps_is_selected_pin_registrar(const struct wpabuf *msg);
 int wps_ap_priority_compar(const struct wpabuf *wps_a,
                           const struct wpabuf *wps_b);
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+                          int ver1_compat);
 const u8 * wps_get_uuid_e(const struct wpabuf *msg);
 
 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
@@ -707,8 +709,9 @@ struct wps_registrar *
 wps_registrar_init(struct wps_context *wps,
                   const struct wps_registrar_config *cfg);
 void wps_registrar_deinit(struct wps_registrar *reg);
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
-                         const u8 *pin, size_t pin_len, int timeout);
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+                         const u8 *uuid, const u8 *pin, size_t pin_len,
+                         int timeout);
 int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_button_pushed(struct wps_registrar *reg);
index 9f3f15241cbd226fee444ac5c59c9708ac3c2e86..835eb4c83f366bbf7857584f0e5d690e29868f27 100644 (file)
@@ -296,4 +296,6 @@ enum wps_response_type {
 /* Walk Time for push button configuration (in seconds) */
 #define WPS_PBC_WALK_TIME 120
 
+#define WPS_MAX_AUTHORIZED_MACS 5
+
 #endif /* WPS_DEFS_H */
index fdcc1cbbe16833111892f5efccd7654b2cc4f705..9f5074af4984b26c290176c9a389c93f587e8e78 100644 (file)
@@ -1349,6 +1349,15 @@ static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
 }
 
 
+static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
+{
+       wpabuf_put_be16(msg, ATTR_UUID_R);
+       wpabuf_put_be16(msg, WPS_UUID_LEN);
+       wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
+       return 0;
+}
+
+
 void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
                        u16 sel_reg_config_methods)
 {
@@ -1363,7 +1372,9 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
            wps_er_build_selected_registrar(msg, sel_reg) ||
            wps_er_build_dev_password_id(msg, dev_passwd_id) ||
            wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
-           wps_build_version2(msg)) {
+           wps_build_version2(msg) ||
+           wps_build_authorized_macs(er->wps->registrar, msg) ||
+           wps_er_build_uuid_r(msg, er->wps->uuid)) {
                wpabuf_free(msg);
                return;
        }
@@ -1690,7 +1701,7 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
                return -1;
 
        /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
-       wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
+       wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
 
        return 0;
 }
@@ -1751,7 +1762,7 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
                return -1;
 
        /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
-       wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
+       wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
 
        return 0;
 }
index 4456ca7f7fa7f9cb476c5d11ed926bf80f8bb223..d4378c3d651c025055fafebc5d31591dd11d7e07 100644 (file)
@@ -275,6 +275,7 @@ 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);
+int wps_build_authorized_macs(struct wps_registrar *reg, struct wpabuf *msg);
 
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
index dff875373a1ee53c76a9140d6e536d63e4f44caa..cbe8a72b76c39026332d5f3818f5b9a27e267835 100644 (file)
@@ -39,6 +39,7 @@ struct wps_uuid_pin {
 #define PIN_EXPIRES BIT(1)
        int flags;
        struct os_time expiration;
+       u8 enrollee_addr[ETH_ALEN];
 };
 
 
@@ -127,6 +128,9 @@ struct wps_registrar {
        struct wps_registrar_device *devices;
 
        int force_pbc_overlap;
+
+       u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+       u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
 };
 
 
@@ -136,6 +140,38 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
                                               void *timeout_ctx);
 
 
+static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
+                                            const u8 *addr)
+{
+       int i;
+       for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+               if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0)
+                       return; /* already in list */
+       for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--)
+               os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1],
+                         ETH_ALEN);
+       os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN);
+}
+
+
+static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,
+                                               const u8 *addr)
+{
+       int i;
+       for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) {
+               if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0)
+                       break;
+       }
+       if (i == WPS_MAX_AUTHORIZED_MACS)
+               return; /* not in the list */
+       for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++)
+               os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1],
+                         ETH_ALEN);
+       os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0,
+                 ETH_ALEN);
+}
+
+
 static void wps_free_devices(struct wps_registrar_device *dev)
 {
        struct wps_registrar_device *prev;
@@ -426,6 +462,28 @@ static int wps_build_config_methods_r(struct wps_registrar *reg,
 }
 
 
+int wps_build_authorized_macs(struct wps_registrar *reg, struct wpabuf *msg)
+{
+       int count = 0;
+
+       while (count < WPS_MAX_AUTHORIZED_MACS) {
+               if (is_zero_ether_addr(reg->authorized_macs_union[count]))
+                       break;
+               count++;
+       }
+
+       if (count == 0)
+               return 0;
+
+       wpa_printf(MSG_DEBUG, "WPS:  * AuthorizedMACs (count=%d)", count);
+       wpabuf_put_be16(msg, ATTR_AUTHORIZED_MACS);
+       wpabuf_put_be16(msg, count * ETH_ALEN);
+       wpabuf_put_data(msg, reg->authorized_macs_union, count * ETH_ALEN);
+
+       return 0;
+}
+
+
 /**
  * wps_registrar_init - Initialize WPS Registrar data
  * @wps: Pointer to longterm WPS context
@@ -499,20 +557,24 @@ void wps_registrar_deinit(struct wps_registrar *reg)
 /**
  * wps_registrar_add_pin - Configure a new PIN for Registrar
  * @reg: Registrar data from wps_registrar_init()
+ * @addr: Enrollee MAC address or %NULL if not known
  * @uuid: UUID-E or %NULL for wildcard (any UUID)
  * @pin: PIN (Device Password)
  * @pin_len: Length of pin in octets
  * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
  * Returns: 0 on success, -1 on failure
  */
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
-                         const u8 *pin, size_t pin_len, int timeout)
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+                         const u8 *uuid, const u8 *pin, size_t pin_len,
+                         int timeout)
 {
        struct wps_uuid_pin *p;
 
        p = os_zalloc(sizeof(*p));
        if (p == NULL)
                return -1;
+       if (addr)
+               os_memcpy(p->enrollee_addr, addr, ETH_ALEN);
        if (uuid == NULL)
                p->wildcard_uuid = 1;
        else
@@ -539,6 +601,8 @@ 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;
+       if (addr)
+               wps_registrar_add_authorized_mac(reg, addr);
        wps_registrar_selected_registrar_changed(reg);
        eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
        eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
@@ -561,7 +625,10 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg)
                    os_time_before(&pin->expiration, &now)) {
                        wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
+                       wps_registrar_remove_authorized_mac(
+                               reg, pin->enrollee_addr);
                        wps_remove_pin(pin);
+                       wps_registrar_selected_registrar_changed(reg);
                }
        }
 }
@@ -582,7 +649,10 @@ int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
                if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
                        wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
                                    pin->uuid, WPS_UUID_LEN);
+                       wps_registrar_remove_authorized_mac(
+                               reg, pin->enrollee_addr);
                        wps_remove_pin(pin);
+                       wps_registrar_selected_registrar_changed(reg);
                        return 0;
                }
        }
@@ -901,17 +971,17 @@ static int wps_set_ie(struct wps_registrar *reg)
        if (reg->set_ie_cb == NULL)
                return 0;
 
-       wpa_printf(MSG_DEBUG, "WPS: Build Beacon and Probe Response IEs");
-
-       beacon = wpabuf_alloc(300);
+       beacon = wpabuf_alloc(400);
        if (beacon == NULL)
                return -1;
-       probe = wpabuf_alloc(400);
+       probe = wpabuf_alloc(500);
        if (probe == NULL) {
                wpabuf_free(beacon);
                return -1;
        }
 
+       wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
+
        if (wps_build_version(beacon) ||
            wps_build_wps_state(reg->wps, beacon) ||
            wps_build_ap_setup_locked(reg->wps, beacon) ||
@@ -919,7 +989,15 @@ static int wps_set_ie(struct wps_registrar *reg)
            wps_build_sel_reg_dev_password_id(reg, beacon) ||
            wps_build_sel_reg_config_methods(reg, beacon) ||
            wps_build_version2(beacon) ||
-           wps_build_version(probe) ||
+           wps_build_authorized_macs(reg, beacon)) {
+               wpabuf_free(beacon);
+               wpabuf_free(probe);
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
+
+       if (wps_build_version(probe) ||
            wps_build_wps_state(reg->wps, probe) ||
            wps_build_ap_setup_locked(reg->wps, probe) ||
            wps_build_selected_registrar(reg, probe) ||
@@ -931,7 +1009,8 @@ static int wps_set_ie(struct wps_registrar *reg)
            wps_build_device_attrs(&reg->wps->dev, probe) ||
            wps_build_probe_config_methods(reg, probe) ||
            wps_build_rf_bands(&reg->wps->dev, probe) ||
-           wps_build_version2(probe)) {
+           wps_build_version2(probe) ||
+           wps_build_authorized_macs(reg, probe)) {
                wpabuf_free(beacon);
                wpabuf_free(probe);
                return -1;
@@ -2672,6 +2751,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
        } else {
                wps_registrar_pin_completed(wps->wps->registrar);
        }
+       /* TODO: maintain AuthorizedMACs somewhere separately for each ER and
+        * merge them into APs own list.. */
 
        wps_success_event(wps->wps);
 
@@ -2767,6 +2848,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
 static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
                                      struct subscription *s)
 {
+       int i, j;
        wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
                   "config_methods=0x%x)",
                   s->dev_password_id, s->config_methods);
@@ -2776,6 +2858,17 @@ static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
        if (reg->sel_reg_config_methods_override == -1)
                reg->sel_reg_config_methods_override = 0;
        reg->sel_reg_config_methods_override |= s->config_methods;
+       for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+               if (is_zero_ether_addr(reg->authorized_macs_union[i]))
+                       break;
+       for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS;
+            j++) {
+               if (is_zero_ether_addr(s->authorized_macs[j]))
+                       break;
+               os_memcpy(reg->authorized_macs_union[i],
+                         s->authorized_macs[j], ETH_ALEN);
+               i++;
+       }
 }
 #endif /* CONFIG_WPS_UPNP */
 
@@ -2821,6 +2914,8 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
        reg->sel_reg_union = reg->selected_registrar;
        reg->sel_reg_dev_password_id_override = -1;
        reg->sel_reg_config_methods_override = -1;
+       os_memcpy(reg->authorized_macs_union, reg->authorized_macs,
+                 WPS_MAX_AUTHORIZED_MACS * ETH_ALEN);
        if (reg->selected_registrar) {
                reg->sel_reg_config_methods_override =
                        reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
index d0bcc2886911289b9241dab32fa2a160dece8e21..501dacb054a2b1091ceca3e075b4b9824362e6a7 100644 (file)
@@ -46,6 +46,7 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
        s->reg = reg;
        eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
 
+       os_memset(s->authorized_macs, 0, sizeof(s->authorized_macs));
        if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) {
                wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
                           "Selected Registrar");
@@ -56,6 +57,13 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
                        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;
+               if (attr.authorized_macs) {
+                       int count = attr.authorized_macs_len / ETH_ALEN;
+                       if (count > WPS_MAX_AUTHORIZED_MACS)
+                               count = WPS_MAX_AUTHORIZED_MACS;
+                       os_memcpy(s->authorized_macs, attr.authorized_macs,
+                                 count * ETH_ALEN);
+               }
                eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
                                       upnp_er_set_selected_timeout, s, NULL);
        }
index b31875ac9a0988c928999be32d9fbaaa6f976e0d..918a12acdd48f516e7d5f15152515013f205067b 100644 (file)
@@ -96,6 +96,7 @@ struct subscription {
        u8 selected_registrar;
        u16 dev_password_id;
        u16 config_methods;
+       u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
        struct wps_registrar *reg;
 };
 
index 2b939847541b07664959537bf12a3ee9816c49e8..e2be10cf13d76bfbc13bc92c2e6a3bf5f9a629e0 100644 (file)
@@ -368,7 +368,8 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                pin = buf;
        }
 
-       ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin, 0);
+       ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
+                                 0);
        if (ret)
                return -1;
        return ret_len;
index 464a226829d610a9e92a5e3cc8053d625f50829f..4a2412fcc119c4108d19b6e85330a546aff12cee 100644 (file)
@@ -311,12 +311,19 @@ static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
 static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
                                                char *cmd)
 {
-       char *uuid = cmd, *pin;
+       char *uuid = cmd, *pin, *pos;
+       u8 addr_buf[ETH_ALEN], *addr = NULL;
        pin = os_strchr(uuid, ' ');
        if (pin == NULL)
                return -1;
        *pin++ = '\0';
-       return wpas_wps_er_add_pin(wpa_s, uuid, pin);
+       pos = os_strchr(pin, ' ');
+       if (pos) {
+               *pos++ = '\0';
+               if (hwaddr_aton(pos, addr_buf) == 0)
+                       addr = addr_buf;
+       }
+       return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
 }
 
 
@@ -818,7 +825,8 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
 
 
 #ifdef CONFIG_WPS
-static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+                                           char *pos, char *end,
                                            struct wpabuf *wps_ie)
 {
        int ret;
@@ -828,6 +836,8 @@ static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
                return pos;
        if (wps_is_selected_pbc_registrar(wps_ie))
                txt = "[WPS-PBC]";
+       else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
+               txt = "[WPS-AUTH]";
        else if (wps_is_selected_pin_registrar(wps_ie))
                txt = "[WPS-PIN]";
        else
@@ -842,13 +852,14 @@ static char * wpa_supplicant_wps_ie_txt_buf(char *pos, char *end,
 #endif /* CONFIG_WPS */
 
 
-static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
+static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
+                                       char *pos, char *end,
                                        const struct wpa_bss *bss)
 {
 #ifdef CONFIG_WPS
        struct wpabuf *wps_ie;
        wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
-       return wpa_supplicant_wps_ie_txt_buf(pos, end, wps_ie);
+       return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
 #else /* CONFIG_WPS */
        return pos;
 #endif /* CONFIG_WPS */
@@ -857,6 +868,7 @@ static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
 
 /* Format one result on one text line into a buffer. */
 static int wpa_supplicant_ctrl_iface_scan_result(
+       struct wpa_supplicant *wpa_s,
        const struct wpa_bss *bss, char *buf, size_t buflen)
 {
        char *pos, *end;
@@ -877,7 +889,7 @@ static int wpa_supplicant_ctrl_iface_scan_result(
        ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        if (ie2)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-       pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
+       pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
        if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
                ret = os_snprintf(pos, end - pos, "[WEP]");
                if (ret < 0 || ret >= end - pos)
@@ -928,7 +940,7 @@ static int wpa_supplicant_ctrl_iface_scan_results(
        pos += ret;
 
        dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
-               ret = wpa_supplicant_ctrl_iface_scan_result(bss, pos,
+               ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
                                                            end - pos);
                if (ret < 0 || ret >= end - pos)
                        return pos - buf;
@@ -1616,7 +1628,7 @@ static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
        ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
        if (ie2)
                pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
-       pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
+       pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
        if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
                ret = os_snprintf(pos, end - pos, "[WEP]");
                if (ret < 0 || ret >= end - pos)
index 2a9261b09320c5b55008740ea6168fa8a236f263..b97f05d8900c9e40ced4cd84cab26147e82a032a 100644 (file)
@@ -731,15 +731,21 @@ static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
        char cmd[256];
        int res;
 
-       if (argc != 2) {
-               printf("Invalid WPS_ER_PIN command: need two arguments:\n"
+       if (argc < 2) {
+               printf("Invalid WPS_ER_PIN command: need at least two "
+                      "arguments:\n"
                       "- UUID: use 'any' to select any\n"
-                      "- PIN: Enrollee PIN\n");
+                      "- PIN: Enrollee PIN\n"
+                      "optional: - Enrollee MAC address\n");
                return -1;
        }
 
-       res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
-                         argv[0], argv[1]);
+       if (argc > 2)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
+                                 argv[0], argv[1], argv[2]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
+                                 argv[0], argv[1]);
        if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
                printf("Too long WPS_ER_PIN command.\n");
                return -1;
index 7a992993d81b235905402408ce789ac00dc2d606..f14cef4cbf9e11fad5f3c9bd3201366fcaa607d1 100644 (file)
@@ -197,10 +197,9 @@ void Peers::enter_pin()
        int peer_type = ctx_item->data(peer_role_type).toInt();
        QString uuid;
        QString addr;
+       addr = ctx_item->data(peer_role_address).toString();
        if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE)
                uuid = ctx_item->data(peer_role_uuid).toString();
-       else
-               addr = ctx_item->data(peer_role_address).toString();
 
        StringQuery input(tr("PIN:"));
        input.setWindowTitle(tr("PIN for ") + ctx_item->text());
@@ -212,9 +211,10 @@ void Peers::enter_pin()
        size_t reply_len;
 
        if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) {
-               snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
+               snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
                         uuid.toAscii().constData(),
-                        input.get_string().toAscii().constData());
+                        input.get_string().toAscii().constData(),
+                        addr.toAscii().constData());
        } else {
                snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s",
                         addr.toAscii().constData(),
index 2057d67234e1c2188c50f077d8a4db207e3352db..865b7b7c5fb0c0b565f3523b4e16a5e74136aae5 100644 (file)
@@ -899,6 +899,15 @@ void WpaGui::processMsg(char *msg)
                if (textStatus->text() == "INACTIVE" ||
                    textStatus->text() == "DISCONNECTED")
                        wpaguiTab->setCurrentWidget(wpsTab);
+       } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) {
+               showTrayMessage(QSystemTrayIcon::Information, 3,
+                               "Wi-Fi Protected Setup (WPS) AP\n"
+                               "indicating this client is authorized.");
+               wpsStatusText->setText("WPS AP indicating this client is "
+                                      "authorized");
+               if (textStatus->text() == "INACTIVE" ||
+                   textStatus->text() == "DISCONNECTED")
+                       wpaguiTab->setCurrentWidget(wpsTab);
        } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
                wpsStatusText->setText(tr("WPS AP detected"));
        } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
index 92296fc799b1c11d7d0c88070a03d4acef1110db..5a471f49257b1cb57b9e7df76d9f8f1ee7f3cfc5 100644 (file)
@@ -35,7 +35,9 @@
 #include "wps_supplicant.h"
 
 
+#ifndef WPS_PIN_SCAN_IGNORE_SEL_REG
 #define WPS_PIN_SCAN_IGNORE_SEL_REG 3
+#endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */
 
 static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
@@ -966,12 +968,13 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                }
 
                /*
-                * Start with WPS APs that advertise active PIN Registrar and
-                * allow any WPS AP after third scan since some APs do not set
-                * Selected Registrar attribute properly when using external
-                * Registrar.
+                * Start with WPS APs that advertise our address as an
+                * authorized MAC (v2.0) or active PIN Registrar (v1.0) and
+                * allow any WPS AP after couple of scans since some APs do not
+                * set Selected Registrar attribute properly when using
+                * external Registrar.
                 */
-               if (!wps_is_selected_pin_registrar(wps_ie)) {
+               if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
                        if (wpa_s->scan_runs < WPS_PIN_SCAN_IGNORE_SEL_REG) {
                                wpa_printf(MSG_DEBUG, "   skip - WPS AP "
                                           "without active PIN Registrar");
@@ -981,7 +984,7 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
                        wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
                } else {
                        wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
-                                  "(Active PIN)");
+                                  "(Authorized MAC or Active PIN)");
                }
                wpabuf_free(wps_ie);
                return 1;
@@ -1013,7 +1016,7 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
        } else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
                wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
                if (wps_ie &&
-                   (wps_is_selected_pin_registrar(wps_ie) ||
+                   (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
                     wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
                        /* allow wildcard SSID for WPS PIN */
                        ret = 1;
@@ -1095,6 +1098,9 @@ void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
                if (wps_is_selected_pbc_registrar(ie))
                        wpa_msg_ctrl(wpa_s, MSG_INFO,
                                     WPS_EVENT_AP_AVAILABLE_PBC);
+               else if (wps_is_addr_authorized(ie, wpa_s->own_addr, 0))
+                       wpa_msg_ctrl(wpa_s, MSG_INFO,
+                                    WPS_EVENT_AP_AVAILABLE_AUTH);
                else if (wps_is_selected_pin_registrar(ie))
                        wpa_msg_ctrl(wpa_s, MSG_INFO,
                                     WPS_EVENT_AP_AVAILABLE_PIN);
@@ -1164,8 +1170,8 @@ int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
 
 
 #ifdef CONFIG_WPS_ER
-int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
-                       const char *pin)
+int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
+                       const char *uuid, const char *pin)
 {
        u8 u[UUID_LEN];
        int any = 0;
@@ -1174,7 +1180,8 @@ int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
                any = 1;
        else if (uuid_str2bin(uuid, u))
                return -1;
-       return wps_registrar_add_pin(wpa_s->wps->registrar, any ? NULL : u,
+       return wps_registrar_add_pin(wpa_s->wps->registrar, addr,
+                                    any ? NULL : u,
                                     (const u8 *) pin, os_strlen(pin), 300);
 }
 
index 5417c501eeee84d531b75bf6a7dd0af76441c3ef..2bd6fa743be0f0b2db889b29c63c0eb3db982700 100644 (file)
@@ -54,8 +54,8 @@ int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
                              char *end);
 int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
 int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
-int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const char *uuid,
-                       const char *pin);
+int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
+                       const char *uuid, const char *pin);
 int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);
 int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
                      const char *pin);