@@ -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;
@@ -1737,6 +1737,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;
@@ -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,
@@ -1787,40 +1787,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 ||
@@ -1834,8 +1817,7 @@ int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
* retransmitted in case of failure. Try to re-send 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 "
@@ -1852,6 +1834,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;
}
@@ -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);
@@ -2877,7 +2877,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
};
@@ -3440,6 +3445,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;
};
/**
@@ -559,6 +559,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
@@ -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);
@@ -2145,6 +2145,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;
From: Johannes Berg <johannes.berg@intel.com> 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(). Signed-hostap: Johannes Berg <johannes.berg@intel.com> --- 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(-)