Patchwork [01/18] AP: add explicit EAPOL TX status event

login
register
mail settings
Submitter Johannes Berg
Date Nov. 4, 2011, 10:37 a.m.
Message ID <20111104103808.254968760@sipsolutions.net>
Download mbox | patch
Permalink /patch/123586/
State Accepted
Commit dd840f793c69a12027601aacf770a5b33f33440e
Headers show

Comments

Johannes Berg - Nov. 4, 2011, 10:37 a.m.
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(-)
Johannes Berg - Nov. 14, 2011, 2:48 p.m.
On Fri, 2011-11-04 at 11:37 +0100, Johannes Berg wrote:
> plain text document attachment
> (0001-AP-add-explicit-EAPOL-TX-status-event.patch)
> 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().

This needs an update for driver_common.c now, I have a fixed version at
http://git.sipsolutions.net/?p=hostap.git;a=commitdiff;h=ba765f14de07be27c6a05a5b458d99a6ad57972f

johannes
Jouni Malinen - Nov. 19, 2011, 11:02 a.m.
On Fri, Nov 04, 2011 at 11:37:50AM +0100, Johannes Berg wrote:
> 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().

Thanks, applied.

> diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c

> -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)

I reordered these functions to make the diff more readable.

Patch

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 2b4e656..283262d 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -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;
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 f6e9f08..71f272e 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -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;
 }
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 06f2db3..bb29300 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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;
 };
 
 /**
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index d08fc7c..44c5fa4 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -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
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 9a0663b..7246170 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -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;