diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index d3ab6242a..195b8a73c 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -865,7 +865,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len = hostapd_ctrl_iface_wps_check_pin( hapd, buf + 14, reply, reply_size); } else if (os_strcmp(buf, "WPS_PBC") == 0) { - if (hostapd_wps_button_pushed(hapd)) + if (hostapd_wps_button_pushed(hapd, NULL)) reply_len = -1; #ifdef CONFIG_WPS_OOB } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) { diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index a49248fde..c1fdba6b9 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -463,7 +463,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #endif /* CONFIG_IEEE80211R */ case EVENT_WPS_BUTTON_PUSHED: - hostapd_wps_button_pushed(hapd); + hostapd_wps_button_pushed(hapd, NULL); break; #ifdef NEED_AP_MLME case EVENT_TX_STATUS: diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index cfff55cdf..d5042c046 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -965,15 +965,18 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, static int wps_button_pushed(struct hostapd_data *hapd, void *ctx) { + const u8 *p2p_dev_addr = ctx; if (hapd->wps == NULL) return 0; - return wps_registrar_button_pushed(hapd->wps->registrar); + return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr); } -int hostapd_wps_button_pushed(struct hostapd_data *hapd) +int hostapd_wps_button_pushed(struct hostapd_data *hapd, + const u8 *p2p_dev_addr) { - return hostapd_wps_for_each(hapd, wps_button_pushed, NULL); + return hostapd_wps_for_each(hapd, wps_button_pushed, + (void *) p2p_dev_addr); } diff --git a/src/ap/wps_hostapd.h b/src/ap/wps_hostapd.h index 36401be38..338a22088 100644 --- a/src/ap/wps_hostapd.h +++ b/src/ap/wps_hostapd.h @@ -23,7 +23,8 @@ 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 u8 *addr, const char *uuid, const char *pin, int timeout); -int hostapd_wps_button_pushed(struct hostapd_data *hapd); +int hostapd_wps_button_pushed(struct hostapd_data *hapd, + const u8 *p2p_dev_addr); int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type, char *path, char *method, char *name); int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr, @@ -60,7 +61,8 @@ static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, return 0; } -static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd) +static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd, + const u8 *p2p_dev_addr) { return 0; } diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c index 83e55d9f1..e944a4d43 100644 --- a/src/eap_server/eap_server_wsc.c +++ b/src/eap_server/eap_server_wsc.c @@ -18,6 +18,7 @@ #include "eloop.h" #include "eap_i.h" #include "eap_common/eap_wsc_common.h" +#include "p2p/p2p.h" #include "wps/wps.h" @@ -135,11 +136,14 @@ static void * eap_wsc_init(struct eap_sm *sm) } cfg.assoc_wps_ie = sm->assoc_wps_ie; cfg.peer_addr = sm->peer_addr; +#ifdef CONFIG_P2P if (sm->assoc_p2p_ie) { wpa_printf(MSG_DEBUG, "EAP-WSC: Prefer PSK format for P2P " "client"); cfg.use_psk_key = 1; + cfg.p2p_dev_addr = p2p_get_go_dev_addr(sm->assoc_p2p_ie); } +#endif /* CONFIG_P2P */ data->wps = wps_init(&cfg); if (data->wps == NULL) { os_free(data); diff --git a/src/wps/wps.c b/src/wps/wps.c index 73dd58cba..a9d41d039 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -109,6 +109,8 @@ struct wps_data * wps_init(const struct wps_config *cfg) if (cfg->peer_addr) os_memcpy(data->peer_dev.mac_addr, cfg->peer_addr, ETH_ALEN); + if (cfg->p2p_dev_addr) + os_memcpy(data->p2p_dev_addr, cfg->p2p_dev_addr, ETH_ALEN); data->use_psk_key = cfg->use_psk_key; diff --git a/src/wps/wps.h b/src/wps/wps.h index 771551a85..47b3e760e 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -164,6 +164,16 @@ struct wps_config { * dev_pw_id - Device Password ID for Enrollee when PIN is used */ u16 dev_pw_id; + + /** + * p2p_dev_addr - P2P Device Address from (Re)Association Request + * + * On AP/GO, this is set to the P2P Device Address of the associating + * P2P client if a P2P IE is included in the (Re)Association Request + * frame and the P2P Device Address is included. Otherwise, this is set + * to %NULL to indicate the station does not have a P2P Device Address. + */ + const u8 *p2p_dev_addr; }; struct wps_data * wps_init(const struct wps_config *cfg); @@ -747,7 +757,8 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr, int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid); int wps_registrar_wps_cancel(struct wps_registrar *reg); int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid); -int wps_registrar_button_pushed(struct wps_registrar *reg); +int wps_registrar_button_pushed(struct wps_registrar *reg, + const u8 *p2p_dev_addr); void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, const struct wpabuf *wps_data, int p2p_wildcard); diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index d3aee2d95..a46183695 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -1550,7 +1550,7 @@ int wps_er_pbc(struct wps_er *er, const u8 *uuid) } er->set_sel_reg_uuid_filter = uuid; - res = wps_registrar_button_pushed(er->wps->registrar); + res = wps_registrar_button_pushed(er->wps->registrar, NULL); er->set_sel_reg_uuid_filter = NULL; if (res) return -1; diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index 316e1f69f..a9f8949e7 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -117,6 +117,8 @@ struct wps_data { struct wps_credential *use_cred; int use_psk_key; + u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or + * 00:00:00:00:00:00 if not a P2p client */ }; diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index ec429f831..a01066c77 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -135,6 +135,8 @@ struct wps_registrar { u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN]; u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN]; + + u8 p2p_dev_addr[ETH_ALEN]; }; @@ -842,6 +844,7 @@ static void wps_registrar_stop_pbc(struct wps_registrar *reg) { reg->selected_registrar = 0; reg->pbc = 0; + os_memset(reg->p2p_dev_addr, 0, ETH_ALEN); wps_registrar_remove_authorized_mac(reg, (u8 *) "\xff\xff\xff\xff\xff\xff"); wps_registrar_selected_registrar_changed(reg); @@ -861,13 +864,16 @@ static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx) /** * wps_registrar_button_pushed - Notify Registrar that AP button was pushed * @reg: Registrar data from wps_registrar_init() + * @p2p_dev_addr: Limit allowed PBC devices to the specified P2P device, %NULL + * indicates no such filtering * Returns: 0 on success, -1 on failure * * This function is called on an AP when a push button is pushed to activate * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout * or when a PBC registration is completed. */ -int wps_registrar_button_pushed(struct wps_registrar *reg) +int wps_registrar_button_pushed(struct wps_registrar *reg, + const u8 *p2p_dev_addr) { if (wps_registrar_pbc_overlap(reg, NULL, NULL)) { wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC " @@ -879,6 +885,10 @@ int wps_registrar_button_pushed(struct wps_registrar *reg) reg->force_pbc_overlap = 0; reg->selected_registrar = 1; reg->pbc = 1; + if (p2p_dev_addr) + os_memcpy(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); + else + os_memset(reg->p2p_dev_addr, 0, ETH_ALEN); wps_registrar_add_authorized_mac(reg, (u8 *) "\xff\xff\xff\xff\xff\xff"); wps_registrar_selected_registrar_changed(reg); @@ -2226,6 +2236,27 @@ static int wps_process_config_error(struct wps_data *wps, const u8 *err) } +static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps) +{ +#ifdef CONFIG_P2P + struct wps_registrar *reg = wps->wps->registrar; + + if (is_zero_ether_addr(reg->p2p_dev_addr)) + return 1; /* no filtering in use */ + + if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address " + "filtering for PBC: expected " MACSTR " was " + MACSTR " - indicate PBC session overlap", + MAC2STR(reg->p2p_dev_addr), + MAC2STR(wps->p2p_dev_addr)); + return 0; + } +#endif /* CONFIG_P2P */ + return 1; +} + + static enum wps_process_res wps_process_m1(struct wps_data *wps, struct wps_parse_attr *attr) { @@ -2280,12 +2311,16 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps, if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) { if (wps->wps->registrar->force_pbc_overlap || wps_registrar_pbc_overlap(wps->wps->registrar, - wps->mac_addr_e, wps->uuid_e)) { + wps->mac_addr_e, wps->uuid_e) || + !wps_registrar_p2p_dev_addr_match(wps)) { wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC " "negotiation"); wps->state = SEND_M2D; wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED; wps_pbc_overlap_event(wps->wps); + wps_fail_event(wps->wps, WPS_M1, + WPS_CFG_MULTIPLE_PBC_DETECTED, + WPS_EI_NO_ERROR); wps->wps->registrar->force_pbc_overlap = 1; return WPS_CONTINUE; } diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 26ccdeab2..2597816b4 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -517,11 +517,13 @@ void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WPS -int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid) +int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, + const u8 *p2p_dev_addr) { if (!wpa_s->ap_iface) return -1; - return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0]); + return hostapd_wps_button_pushed(wpa_s->ap_iface->bss[0], + p2p_dev_addr); } diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index d3bab2490..b913be3e2 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -21,7 +21,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s); void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, const u8 *src_addr, const u8 *buf, size_t len); -int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, + const u8 *p2p_dev_addr); int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, const char *pin, char *buf, size_t buflen); int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 7731895f4..31ec5d663 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -213,10 +213,21 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, char *cmd) { u8 bssid[ETH_ALEN], *_bssid = bssid; + u8 p2p_dev_addr[ETH_ALEN], *_p2p_dev_addr = NULL; - if (cmd == NULL || os_strcmp(cmd, "any") == 0) + if (cmd == NULL || os_strcmp(cmd, "any") == 0) { _bssid = NULL; - else if (hwaddr_aton(cmd, bssid)) { +#ifdef CONFIG_P2P + } else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) { + if (hwaddr_aton(cmd + 13, p2p_dev_addr)) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid " + "P2P Device Address '%s'", + cmd + 13); + return -1; + } + _p2p_dev_addr = p2p_dev_addr; +#endif /* CONFIG_P2P */ + } else if (hwaddr_aton(cmd, bssid)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'", cmd); return -1; @@ -224,7 +235,7 @@ static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s, #ifdef CONFIG_AP if (wpa_s->ap_iface) - return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid); + return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr); #endif /* CONFIG_AP */ return wpas_wps_start_pbc(wpa_s, _bssid, 0); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index dfc50c529..85c3fbe3e 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -857,7 +857,8 @@ static void p2p_go_configured(void *ctx, void *data) return; } if (params->wps_method == WPS_PBC) - wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr); + wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr, + NULL); else if (wpa_s->p2p_pin[0]) wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr, wpa_s->p2p_pin, NULL, 0);