diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 80205a4e6..8ce74c4a2 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1299,7 +1299,16 @@ typedef enum wpa_event_type { * to receiving deauthenticate frame from the AP or when sending that * frame to the current AP. */ - EVENT_DEAUTH + EVENT_DEAUTH, + + /** + * EVENT_ASSOC_REJECT - Association rejected + * + * This event should be called when (re)association attempt has been + * rejected by the AP. Information about authentication result is + * included in union wpa_event_data::assoc_reject. + */ + EVENT_ASSOC_REJECT } wpa_event_type; @@ -1448,6 +1457,34 @@ union wpa_event_data { const u8 *ies; size_t ies_len; } auth; + + /** + * struct assoc_reject - Data for EVENT_ASSOC_REJECT events + */ + struct assoc_reject { + /** + * resp_ies - (Re)Association Response IEs + * + * Optional association data from the driver. This data is not + * required WPA, but may be useful for some protocols and as + * such, should be reported if this is available to the driver + * interface. + * + * This should start with the first IE (fixed fields before IEs + * are not included). + */ + u8 *resp_ies; + + /** + * resp_ies_len - Length of resp_ies in bytes + */ + size_t resp_ies_len; + + /** + * status_code - Status Code from (Re)association Response + */ + u16 status_code; + } assoc_reject; }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 3e71159c9..b0f93089c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -586,10 +586,16 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, status = le_to_host16(mgmt->u.assoc_resp.status_code); if (status != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "nl80211: Association failed: status " - "code %d", status); - /* TODO: notify SME so that things like SA Query and comeback - * time can be implemented */ + os_memset(&event, 0, sizeof(event)); + if (len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_reject.resp_ies = + (u8 *) mgmt->u.assoc_resp.variable; + event.assoc_reject.resp_ies_len = + len - 24 - sizeof(mgmt->u.assoc_resp); + } + event.assoc_reject.status_code = status; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } @@ -600,7 +606,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, if (len > 24 + sizeof(mgmt->u.assoc_resp)) { event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; event.assoc_info.resp_ies_len = - len - 24 - sizeof(mgmt->u.assoc_req); + len - 24 - sizeof(mgmt->u.assoc_resp); } wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 5186d2a6e..1fb1d2d61 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1226,6 +1226,9 @@ void wpa_supplicant_event(void *ctx, wpa_event_type event, wpa_supplicant_event_ibss_rsn_start(wpa_s, data); break; #endif /* CONFIG_IBSS_RSN */ + case EVENT_ASSOC_REJECT: + sme_event_assoc_reject(wpa_s, data); + break; default: wpa_printf(MSG_INFO, "Unknown event %d", event); break; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 9b8844d9d..97a5f8056 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -335,3 +335,21 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, wpa_s->sme.ft_ies_len = ies_len; return 0; } + + +void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + wpa_printf(MSG_DEBUG, "SME: Association failed: status code %d", + data->assoc_reject.status_code); + + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + os_memset(wpa_s->bssid, 0, ETH_ALEN); + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + + /* + * TODO: if more than one possible AP is available in scan results, + * could try the other ones before requesting a new scan. + */ + wpa_supplicant_req_scan(wpa_s, 5, 0); +} diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h index ce1b2dcbb..566e417d1 100644 --- a/wpa_supplicant/sme.h +++ b/wpa_supplicant/sme.h @@ -22,6 +22,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data); int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, const u8 *ies, size_t ies_len); +void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, + union wpa_event_data *data); #else /* CONFIG_SME */ @@ -41,6 +43,13 @@ static inline int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, { return -1; } + + +static inline void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ +} + #endif /* CONFIG_SME */ #endif /* SME_H */