diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c index 73aa93dfb..408c4f151 100644 --- a/hostapd/dump_state.c +++ b/hostapd/dump_state.c @@ -106,7 +106,8 @@ static void hostapd_dump_state(struct hostapd_data *hapd) fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr)); fprintf(f, - " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n" + " AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" + "\n" " capability=0x%x listen_interval=%d\n", sta->aid, sta->flags, @@ -127,6 +128,7 @@ static void hostapd_dump_state(struct hostapd_data *hapd) (sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""), (sta->flags & WLAN_STA_WDS ? "[WDS]" : ""), (sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""), + (sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""), sta->capability, sta->listen_interval); diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index db2d5f226..443c1fa6a 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -93,7 +93,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (sta == NULL) return -1; } - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); #ifdef CONFIG_P2P if (elems.p2p) { @@ -118,7 +118,18 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { + struct wpabuf *wps; sta->flags |= WLAN_STA_WPS; + wps = ieee802_11_vendor_ie_concat(ie, ielen, + WPS_IE_VENDOR_TYPE); + if (wps) { + if (wps_is_20(wps)) { + wpa_printf(MSG_DEBUG, "WPS: STA " + "supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } + wpabuf_free(wps); + } goto skip_wpa_check; } @@ -156,11 +167,11 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, return -1; } } else if (hapd->conf->wps_state) { + struct wpabuf *wps; + wps = ieee802_11_vendor_ie_concat(ie, ielen, + WPS_IE_VENDOR_TYPE); #ifdef CONFIG_WPS_STRICT if (ie) { - struct wpabuf *wps; - wps = ieee802_11_vendor_ie_concat(ie, ielen, - WPS_IE_VENDOR_TYPE); if (wps && wps_validate_assoc_req(wps) < 0) { hostapd_drv_sta_disassoc( hapd, sta->addr, @@ -175,8 +186,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 && os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) { sta->flags |= WLAN_STA_WPS; + if (wps && wps_is_20(wps)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports " + "WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } } else sta->flags |= WLAN_STA_MAYBE_WPS; + wpabuf_free(wps); } skip_wpa_check: diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 227a0a52f..c1c4314ac 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -701,7 +701,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #ifdef CONFIG_WPS - sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); if (hapd->conf->wps_state && elems.wps_ie) { wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " "Request - assume WPS is used"); @@ -709,6 +709,10 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, wpabuf_free(sta->wps_ie); sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, WPS_IE_VENDOR_TYPE); + if (sta->wps_ie && wps_is_20(sta->wps_ie)) { + wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0"); + sta->flags |= WLAN_STA_WPS2; + } wpa_ie = NULL; wpa_ie_len = 0; if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) { diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 6b6fd4bdf..ea8ca1147 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -752,14 +752,24 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; #ifdef CONFIG_WPS - if (!hapd->conf->ieee802_1x && - ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == - WLAN_STA_MAYBE_WPS)) { - /* - * Delay EAPOL frame transmission until a possible WPS - * STA initiates the handshake with EAPOL-Start. - */ - sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + if (!hapd->conf->ieee802_1x) { + u32 wflags = sta->flags & (WLAN_STA_WPS | + WLAN_STA_WPS2 | + WLAN_STA_MAYBE_WPS); + if (wflags == WLAN_STA_MAYBE_WPS || + wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { + /* + * Delay EAPOL frame transmission until a + * possible WPS STA initiates the handshake + * with EAPOL-Start. Only allow the wait to be + * skipped if the STA is known to support WPS + * 2.0. + */ + wpa_printf(MSG_DEBUG, "WPS: Do not start " + "EAPOL until EAPOL-Start is " + "received"); + sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; + } } #endif /* CONFIG_WPS */ @@ -888,11 +898,14 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) #ifdef CONFIG_WPS sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; - if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) { + if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) { /* - * Delay EAPOL frame transmission until a possible WPS - * initiates the handshake with EAPOL-Start. + * Delay EAPOL frame transmission until a possible WPS STA + * initiates the handshake with EAPOL-Start. Only allow the + * wait to be skipped if the STA is known to support WPS 2.0. */ + wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " + "EAPOL-Start is received"); sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; } #endif /* CONFIG_WPS */ diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 9ec4fe33e..318481f27 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -32,6 +32,7 @@ #define WLAN_STA_MAYBE_WPS BIT(13) #define WLAN_STA_WDS BIT(14) #define WLAN_STA_ASSOC_REQ_OK BIT(15) +#define WLAN_STA_WPS2 BIT(16) #define WLAN_STA_NONERP BIT(31) /* Maximum number of supported rates (from both Supported Rates and Extended diff --git a/src/wps/wps.c b/src/wps/wps.c index 5c8c25fea..101ae1d0b 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -354,6 +354,19 @@ const u8 * wps_get_uuid_e(const struct wpabuf *msg) } +/** + * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0 + */ +int wps_is_20(const struct wpabuf *msg) +{ + struct wps_parse_attr attr; + + if (msg == NULL || wps_parse_msg(msg, &attr) < 0) + return 0; + return attr.version2 != NULL; +} + + /** * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request * @req_type: Value for Request Type attribute diff --git a/src/wps/wps.h b/src/wps/wps.h index 3e4c2185b..2cbbc1855 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -239,6 +239,7 @@ int wps_ap_priority_compar(const struct wpabuf *wps_a, 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); +int wps_is_20(const struct wpabuf *msg); struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type); struct wpabuf * wps_build_assoc_resp_ie(void);