Parcourir la source

Move more multi-BSSID processing into drv_callbacks.c

This simplifies driver wrapper operations and removes last direct
struct hostapd_data dereferences from driver_nl80211.c. In addition,
some of the TX callbacks are now fixed for secondary BSSes.
Jouni Malinen il y a 16 ans
Parent
commit
4b9841d34c
4 fichiers modifiés avec 153 ajouts et 150 suppressions
  1. 120 5
      hostapd/drv_callbacks.c
  2. 3 1
      src/drivers/driver.h
  3. 1 1
      src/drivers/driver_hostap.c
  4. 29 143
      src/drivers/driver_nl80211.c

+ 120 - 5
hostapd/drv_callbacks.c

@@ -120,24 +120,104 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 		       const u8 *buf, size_t len, int ack)
 {
 	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
 
 	sta = ap_get_sta(hapd, addr);
-	if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
+	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, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+	if (sta->flags & WLAN_STA_PENDING_POLL) {
 		wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
 			   "activity poll", MAC2STR(sta->addr),
 			   ack ? "ACKed" : "did not ACK");
 		if (ack)
 			sta->flags &= ~WLAN_STA_PENDING_POLL;
 	}
-	if (sta)
-		ieee802_1x_tx_status(hapd, sta, buf, len, ack);
+
+	ieee802_1x_tx_status(hapd, sta, buf, len, ack);
+}
+
+
+static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc, type, stype;
+
+	/*
+	 * PS-Poll frames are 16 bytes. All other frames are
+	 * 24 bytes or longer.
+	 */
+	if (len < 16)
+		return NULL;
+
+	fc = le_to_host16(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(fc);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	switch (type) {
+	case WLAN_FC_TYPE_DATA:
+		if (len < 24)
+			return NULL;
+		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+		case WLAN_FC_TODS:
+			return hdr->addr1;
+		case WLAN_FC_FROMDS:
+			return hdr->addr2;
+		default:
+			return NULL;
+		}
+	case WLAN_FC_TYPE_CTRL:
+		if (stype != WLAN_FC_STYPE_PSPOLL)
+			return NULL;
+		return hdr->addr1;
+	case WLAN_FC_TYPE_MGMT:
+		return hdr->addr3;
+	default:
+		return NULL;
+	}
+}
+
+
+#define HAPD_BROADCAST ((struct hostapd_data *) -1)
+
+static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
+					    const u8 *bssid)
+{
+	size_t i;
+
+	if (bssid == NULL)
+		return NULL;
+	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
+	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
+		return HAPD_BROADCAST;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
+			return iface->bss[i];
+	}
+
+	return NULL;
 }
 
 
-void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, const u8 *addr)
+void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
+				 const struct ieee80211_hdr *hdr, size_t len)
 {
 	struct sta_info *sta;
+	const u8 *addr;
+
+	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+	if (hapd == NULL || hapd == HAPD_BROADCAST)
+		return;
 
+	addr = hdr->addr2;
 	sta = ap_get_sta(hapd, addr);
 	if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
 		wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated "
@@ -262,13 +342,48 @@ void hostapd_eapol_receive(struct hostapd_data *hapd, const u8 *sa,
 void hostapd_mgmt_rx(struct hostapd_data *hapd, u8 *buf, size_t len,
 		     u16 stype, struct hostapd_frame_info *fi)
 {
-	ieee802_11_mgmt(hapd, buf, len, stype, fi);
+	struct hostapd_iface *iface = hapd->iface;
+	struct ieee80211_hdr *hdr;
+	const u8 *bssid;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	bssid = get_hdr_bssid(hdr, len);
+	if (bssid == NULL)
+		return;
+
+	hapd = get_hapd_bssid(iface, bssid);
+	if (hapd == NULL) {
+		u16 fc;
+		fc = le_to_host16(hdr->frame_control);
+
+		/*
+		 * Drop frames to unknown BSSIDs except for Beacon frames which
+		 * could be used to update neighbor information.
+		 */
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			hapd = iface->bss[0];
+		else
+			return;
+	}
+
+	if (hapd == HAPD_BROADCAST) {
+		size_t i;
+		for (i = 0; i < iface->num_bss; i++)
+			ieee802_11_mgmt(iface->bss[i], buf, len, stype, fi);
+	} else
+		ieee802_11_mgmt(hapd, buf, len, stype, fi);
 }
 
 
 void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
 			u16 stype, int ok)
 {
+	struct ieee80211_hdr *hdr;
+	hdr = (struct ieee80211_hdr *) buf;
+	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+	if (hapd == NULL || hapd == HAPD_BROADCAST)
+		return;
 	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
 }
 #endif /* NEED_MLME */

+ 3 - 1
src/drivers/driver.h

@@ -1728,12 +1728,14 @@ void wpa_scan_sort_results(struct wpa_scan_results *res);
 /* hostapd functions for driver wrappers */
 
 struct sta_info;
+struct ieee80211_hdr;
 
 void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   int reassoc);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 		       const u8 *buf, size_t len, int ack);
-void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
+				 const struct ieee80211_hdr *hdr, size_t len);
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 			const u8 *ie, size_t ielen);
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);

+ 1 - 1
src/drivers/driver_hostap.c

@@ -78,7 +78,7 @@ static void handle_data(struct hostap_driver_data *drv, u8 *buf, size_t len,
 	}
 
 	sa = hdr->addr2;
-	hostapd_rx_from_unknown_sta(drv->hapd, sa);
+	hostapd_rx_from_unknown_sta(drv->hapd, hdr, len);
 
 	pos = (u8 *) (hdr + 1);
 	left = len - sizeof(*hdr);

+ 29 - 143
src/drivers/driver_nl80211.c

@@ -38,20 +38,11 @@
 #include <linux/filter.h>
 #include "radiotap.h"
 #include "radiotap_iter.h"
-#endif /* CONFIG_AP || HOSTAPD */
-
-#ifdef CONFIG_AP
 
-#include "../hostapd/hostapd_defs.h"
-
-#ifndef ETH_P_ALL
-#define ETH_P_ALL 0x0003
-#endif
-
-#endif /* CONFIG_AP */
+#include "../../hostapd/hostapd_defs.h"
+#endif /* CONFIG_AP || HOSTAPD */
 
 #ifdef HOSTAPD
-#include "../../hostapd/hostapd.h"
 #include "../../hostapd/sta_flags.h"
 #include "ieee802_11_common.h"
 
@@ -78,12 +69,6 @@
 #define IF_OPER_UP 6
 #endif
 
-enum ieee80211_msg_type {
-	ieee80211_msg_normal = 0,
-	ieee80211_msg_tx_callback_ack = 1,
-	ieee80211_msg_tx_callback_fail = 2,
-};
-
 struct i802_bss {
 	struct i802_bss *next;
 	int ifindex;
@@ -125,8 +110,6 @@ struct wpa_driver_nl80211_data {
 #endif /* CONFIG_AP */
 
 #ifdef HOSTAPD
-	struct hostapd_data *hapd;
-
 	int eapol_sock; /* socket for EAPOL frames */
 
 	int default_if_indices[16];
@@ -2472,139 +2455,46 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
 }
 
 
-static void handle_frame(struct wpa_driver_nl80211_data *drv,
-			 u8 *buf, size_t len,
-			 struct hostapd_frame_info *hfi,
-			 enum ieee80211_msg_type msg_type)
+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
+			     struct ieee80211_hdr *hdr, size_t len)
 {
-	struct ieee80211_hdr *hdr;
-	u16 fc, type, stype;
-	size_t data_len = len;
-	u8 *bssid;
-	void *ctx = drv->ctx;
 #ifdef HOSTAPD
-	struct hostapd_iface *iface = drv->hapd->iface;
-	struct hostapd_data *hapd = NULL;
-	int broadcast_bssid = 0;
-	size_t i;
+	hostapd_rx_from_unknown_sta(drv->ctx, hdr, len);
+#else /* HOSTAPD */
+	ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
 #endif /* HOSTAPD */
+}
 
-	/*
-	 * PS-Poll frames are 16 bytes. All other frames are
-	 * 24 bytes or longer.
-	 */
-	if (len < 16)
-		return;
+
+static void handle_frame(struct wpa_driver_nl80211_data *drv,
+			 u8 *buf, size_t len,
+			 struct hostapd_frame_info *hfi)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc, stype;
 
 	hdr = (struct ieee80211_hdr *) buf;
 	fc = le_to_host16(hdr->frame_control);
-
-	type = WLAN_FC_GET_TYPE(fc);
 	stype = WLAN_FC_GET_STYPE(fc);
 
-	switch (type) {
-	case WLAN_FC_TYPE_DATA:
-		if (len < 24)
-			return;
-		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
-		case WLAN_FC_TODS:
-			bssid = hdr->addr1;
-			break;
-		case WLAN_FC_FROMDS:
-			bssid = hdr->addr2;
-			break;
-		default:
-			/* discard */
-			return;
-		}
-		break;
-	case WLAN_FC_TYPE_CTRL:
-		/* discard non-ps-poll frames */
-		if (stype != WLAN_FC_STYPE_PSPOLL)
-			return;
-		bssid = hdr->addr1;
-		break;
-	case WLAN_FC_TYPE_MGMT:
-		bssid = hdr->addr3;
-		break;
-	default:
-		/* discard */
-		return;
-	}
-
-#ifdef HOSTAPD
-	/* find interface frame belongs to */
-	for (i = 0; i < iface->num_bss; i++) {
-		if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) {
-			hapd = iface->bss[i];
-			break;
-		}
-	}
-
-	if (hapd == NULL) {
-		hapd = iface->bss[0];
-
-		if (bssid[0] != 0xff || bssid[1] != 0xff ||
-		    bssid[2] != 0xff || bssid[3] != 0xff ||
-		    bssid[4] != 0xff || bssid[5] != 0xff) {
-			/*
-			 * Unknown BSSID - drop frame if this is not from
-			 * passive scanning or a beacon (at least ProbeReq
-			 * frames to other APs may be allowed through RX
-			 * filtering in the wlan hw/driver)
-			 */
-			if ((type != WLAN_FC_TYPE_MGMT ||
-			     stype != WLAN_FC_STYPE_BEACON))
-				return;
-		} else
-			broadcast_bssid = 1;
-	}
-	ctx = hapd;
-#endif /* HOSTAPD */
-
-	switch (msg_type) {
-	case ieee80211_msg_normal:
-		/* continue processing */
-		break;
-	case ieee80211_msg_tx_callback_ack:
-		handle_tx_callback(ctx, buf, data_len, 1);
-		return;
-	case ieee80211_msg_tx_callback_fail:
-		handle_tx_callback(ctx, buf, data_len, 0);
-		return;
-	}
-
-	switch (type) {
+	switch (WLAN_FC_GET_TYPE(fc)) {
 	case WLAN_FC_TYPE_MGMT:
 		if (stype != WLAN_FC_STYPE_BEACON &&
 		    stype != WLAN_FC_STYPE_PROBE_REQ)
 			wpa_printf(MSG_MSGDUMP, "MGMT");
 #ifdef HOSTAPD
-		if (broadcast_bssid) {
-			for (i = 0; i < iface->num_bss; i++)
-				hostapd_mgmt_rx(iface->bss[i], buf, data_len,
-						stype, hfi);
-		} else
-			hostapd_mgmt_rx(hapd, buf, data_len, stype, hfi);
+		hostapd_mgmt_rx(drv->ctx, buf, len, stype, hfi);
 #else /* HOSTAPD */
-		ap_mgmt_rx(drv->ctx, buf, data_len, stype, hfi);
+		ap_mgmt_rx(drv->ctx, buf, len, stype, hfi);
 #endif /* HOSTAPD */
 		break;
 	case WLAN_FC_TYPE_CTRL:
 		/* can only get here with PS-Poll frames */
 		wpa_printf(MSG_DEBUG, "CTRL");
-#ifdef HOSTAPD
-		hostapd_rx_from_unknown_sta(drv->hapd, hdr->addr2);
-#else /* HOSTAPD */
-		ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
-#endif /* HOSTAPD */
+		from_unknown_sta(drv, hdr, len);
 		break;
 	case WLAN_FC_TYPE_DATA:
-#ifdef HOSTAPD
-		hostapd_rx_from_unknown_sta(drv->hapd, hdr->addr2);
-#else /* HOSTAPD */
-		ap_rx_from_unknown_sta(drv->ctx, hdr->addr2);
-#endif /* HOSTAPD */
+		from_unknown_sta(drv, hdr, len);
 		break;
 	}
 }
@@ -2618,7 +2508,7 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
 	struct ieee80211_radiotap_iterator iter;
 	int ret;
 	struct hostapd_frame_info hfi;
-	int injected = 0, failed = 0, msg_type, rxflags = 0;
+	int injected = 0, failed = 0, rxflags = 0;
 
 	len = recv(sock, buf, sizeof(buf), 0);
 	if (len < 0) {
@@ -2675,14 +2565,11 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
 		return;
 
 	if (!injected)
-		msg_type = ieee80211_msg_normal;
-	else if (failed)
-		msg_type = ieee80211_msg_tx_callback_fail;
+		handle_frame(drv, buf + iter.max_length,
+			     len - iter.max_length, &hfi);
 	else
-		msg_type = ieee80211_msg_tx_callback_ack;
-
-	handle_frame(drv, buf + iter.max_length,
-		     len - iter.max_length, &hfi, msg_type);
+		handle_tx_callback(drv->ctx, buf + iter.max_length,
+				   len - iter.max_length, !failed);
 }
 
 
@@ -3864,11 +3751,11 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
 	}
 
 	if (have_ifidx(drv, lladdr.sll_ifindex)) {
-		struct hostapd_data *hapd;
-		hapd = hostapd_sta_get_bss(drv->hapd, lladdr.sll_addr);
-		if (!hapd)
+		void *ctx;
+		ctx = hostapd_sta_get_bss(drv->ctx, lladdr.sll_addr);
+		if (!ctx)
 			return;
-		hostapd_eapol_receive(hapd, lladdr.sll_addr, buf, len);
+		hostapd_eapol_receive(ctx, lladdr.sll_addr, buf, len);
 	}
 }
 
@@ -3943,7 +3830,6 @@ static void *i802_init(struct hostapd_data *hapd,
 	if (drv == NULL)
 		return NULL;
 
-	drv->hapd = hapd;
 	drv->bss.ifindex = drv->ifindex;
 
 	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);