aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/README-WPS9
-rw-r--r--hostapd/ctrl_iface.c10
-rw-r--r--hostapd/hostapd_cli.c9
-rw-r--r--src/ap/wps_hostapd.c9
-rw-r--r--src/ap/wps_hostapd.h4
-rw-r--r--src/common/wpa_ctrl.h2
-rw-r--r--src/eap_peer/eap_wsc.c2
-rw-r--r--src/wps/wps.c69
-rw-r--r--src/wps/wps.h7
-rw-r--r--src/wps/wps_defs.h2
-rw-r--r--src/wps/wps_er.c17
-rw-r--r--src/wps/wps_i.h1
-rw-r--r--src/wps/wps_registrar.c111
-rw-r--r--src/wps/wps_upnp_ap.c8
-rw-r--r--src/wps/wps_upnp_i.h1
-rw-r--r--wpa_supplicant/ap.c3
-rw-r--r--wpa_supplicant/ctrl_iface.c28
-rw-r--r--wpa_supplicant/wpa_cli.c16
-rw-r--r--wpa_supplicant/wpa_gui-qt4/peers.cpp8
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.cpp9
-rw-r--r--wpa_supplicant/wps_supplicant.c27
-rw-r--r--wpa_supplicant/wps_supplicant.h4
22 files changed, 289 insertions, 67 deletions
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index 74f2113..3bfde61 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -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
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 9c47ba8..e03e66f 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -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);
}
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 589530e..4f22e85 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -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
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index a6ffd4d..008a88a 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -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;
diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h
index e978a1c..b9d525a 100644
--- a/src/ap/wps_hostapd.h
+++ b/src/ap/wps_hostapd.h
@@ -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);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 54aa988..5780484 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -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 "
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index f65d982..a38e2ad 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -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);
}
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 533cbaf..6d4b1cb 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -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;
}
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 8536499..31be0b5 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -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);
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 9f3f152..835eb4c 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -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 */
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index fdcc1cb..9f5074a 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -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;
}
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 4456ca7..d4378c3 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -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);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index dff8753..cbe8a72 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -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;
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index d0bcc28..501dacb 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -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);
}
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index b31875a..918a12a 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -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;
};
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 2b93984..e2be10c 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -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;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 464a226..4a2412f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -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)
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 2a9261b..b97f05d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -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;
diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp
index 7a99299..f14cef4 100644
--- a/wpa_supplicant/wpa_gui-qt4/peers.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp
@@ -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(),
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 2057d67..865b7b7 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -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)) {
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 92296fc..5a471f4 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -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);
}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 5417c50..2bd6fa7 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -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);