The new event can be used when EAPOL TX status can't be reported as a complete 802.11 frame but is instead reported as just the EAPOL data as originally passed to hapd_send_eapol(). --- src/ap/drv_callbacks.c | 6 ++++ src/ap/ieee802_11.c | 23 +++++++++++++++ src/ap/ieee802_11.h | 2 + src/ap/ieee802_1x.c | 70 ++++++++++++++++++++++++++++------------------- src/ap/ieee802_1x.h | 2 + src/drivers/driver.h | 24 +++++++++++++++- wpa_supplicant/ap.c | 10 +++++++ wpa_supplicant/ap.h | 2 + wpa_supplicant/events.c | 6 ++++ 9 files changed, 116 insertions(+), 29 deletions(-) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index e6f13f8..a091531 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -506,6 +506,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } break; + case EVENT_EAPOL_TX_STATUS: + hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, + data->eapol_tx_status.data, + data->eapol_tx_status.data_len, + data->eapol_tx_status.ack); + break; case EVENT_DRIVER_CLIENT_POLL_OK: hostapd_client_poll_ok(hapd, data->client_poll.addr); break; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 2b24c3f..e689ba2 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1735,6 +1735,29 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, } +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack) +{ + struct sta_info *sta; + struct hostapd_iface *iface = hapd->iface; + + sta = ap_get_sta(hapd, dst); + if (sta == NULL && iface->num_bss > 1) { + size_t j; + for (j = 0; j < iface->num_bss; j++) { + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, dst); + if (sta) + break; + } + } + if (sta == NULL) + return; + + ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); +} + + void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta; diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index b358060..43042a5 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -62,6 +62,8 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len, int ack); +void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack); void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds); u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index d163ce6..bb81263 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -1772,40 +1772,23 @@ void ieee802_1x_deinit(struct hostapd_data *hapd) } -int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *buf, size_t len, int ack) +void ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, int len, int ack) { - struct ieee80211_hdr *hdr; - struct ieee802_1x_hdr *xhdr; + const struct ieee802_1x_hdr *xhdr = (void *)data; + const u8 *buf = data; + const u8 *pos = buf + sizeof(*xhdr); struct ieee802_1x_eapol_key *key; - u8 *pos; - const unsigned char rfc1042_hdr[ETH_ALEN] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - - if (sta == NULL) - return -1; - if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) - return 0; - - hdr = (struct ieee80211_hdr *) buf; - pos = (u8 *) (hdr + 1); - if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) - return 0; - pos += sizeof(rfc1042_hdr); - if (WPA_GET_BE16(pos) != ETH_P_PAE) - return 0; - pos += 2; - - xhdr = (struct ieee802_1x_hdr *) pos; - pos += sizeof(*xhdr); wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " "type=%d length=%d - ack=%d", MAC2STR(sta->addr), xhdr->version, xhdr->type, be_to_host16(xhdr->length), ack); - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && - pos + sizeof(struct wpa_eapol_key) <= buf + len) { + if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) + return; + + if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { const struct wpa_eapol_key *wpa; wpa = (const struct wpa_eapol_key *) pos; if (wpa->type == EAPOL_KEY_TYPE_RSN || @@ -1819,8 +1802,7 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, * retransmitted in case of failure. Try to re-sent failed EAPOL-Key * packets couple of times because otherwise STA keys become * unsynchronized with AP. */ - if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack && - pos + sizeof(*key) <= buf + len) { + if (!ack && pos + sizeof(*key) <= buf + len) { key = (struct ieee802_1x_eapol_key *) pos; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " @@ -1837,6 +1819,38 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, /* TODO: could move unicast key configuration from ieee802_1x_tx_key() * to here and change the key only if the EAPOL-Key packet was Acked. */ +} + + +int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *buf, size_t len, int ack) +{ + struct ieee80211_hdr *hdr; + struct ieee802_1x_hdr *xhdr; + u8 *pos; + const unsigned char rfc1042_hdr[ETH_ALEN] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + if (sta == NULL) + return -1; + if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr)) + return 0; + + hdr = (struct ieee80211_hdr *) buf; + pos = (u8 *) (hdr + 1); + len -= sizeof(*hdr); + + if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) + return 0; + pos += sizeof(rfc1042_hdr); + len -= sizeof(rfc1042_hdr); + + if (WPA_GET_BE16(pos) != ETH_P_PAE) + return 0; + pos += 2; + len -= 2; + + ieee802_1x_eapol_tx_status(hapd, sta, pos, len, ack); return 1; } diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h index 1a4d2eb..303eaf7 100644 --- a/src/ap/ieee802_1x.h +++ b/src/ap/ieee802_1x.h @@ -68,6 +68,8 @@ int ieee802_1x_init(struct hostapd_data *hapd); void ieee802_1x_deinit(struct hostapd_data *hapd); int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, const u8 *buf, size_t len, int ack); +void ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *data, int len, int ack); u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len); u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, int idx); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 2a926e5..36f7996 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -2948,7 +2948,12 @@ enum wpa_event_type { * This event indicates that the station responded to the poll * initiated with @poll_client. */ - EVENT_DRIVER_CLIENT_POLL_OK + EVENT_DRIVER_CLIENT_POLL_OK, + + /** + * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status + */ + EVENT_EAPOL_TX_STATUS }; @@ -3511,6 +3516,23 @@ union wpa_event_data { struct client_poll { u8 addr[ETH_ALEN]; } client_poll; + + /** + * struct eapol_tx_status + * @dst: original destination + * @data: data starting with 801.1X header (!) + * @data_len: length of data + * @ack: indicates ack or lost frame + * + * This corresponds to hapd_send_eapol if the frame sent + * there isn't just reported as EVENT_TX_STATUS. + */ + struct eapol_tx_status { + const u8 *dst; + const u8 *data; + int data_len; + int ack; + } eapol_tx_status; }; /** diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index c4959bf..0b1c80d 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -566,6 +566,16 @@ void ap_tx_status(void *ctx, const u8 *addr, } +void ap_eapol_tx_status(void *ctx, const u8 *dst, + const u8 *data, size_t len, int ack) +{ +#ifdef NEED_AP_MLME + struct wpa_supplicant *wpa_s = ctx; + hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack); +#endif /* NEED_AP_MLME */ +} + + void ap_client_poll_ok(void *ctx, const u8 *addr) { #ifdef NEED_AP_MLME diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h index 567e784..aa4c362 100644 --- a/wpa_supplicant/ap.h +++ b/wpa_supplicant/ap.h @@ -41,6 +41,8 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen, int verbose); void ap_tx_status(void *ctx, const u8 *addr, const u8 *buf, size_t len, int ack); +void ap_eapol_tx_status(void *ctx, const u8 *dst, + const u8 *data, size_t len, int ack); void ap_client_poll_ok(void *ctx, const u8 *addr); void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds); void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 4ec935e..2d5c328 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2027,6 +2027,12 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_AP */ break; #ifdef CONFIG_AP + case EVENT_EAPOL_TX_STATUS: + ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst, + data->eapol_tx_status.data, + data->eapol_tx_status.data_len, + data->eapol_tx_status.ack); + break; case EVENT_DRIVER_CLIENT_POLL_OK: ap_client_poll_ok(wpa_s, data->client_poll.addr); break; -- 1.7.6.3