diff mbox

[v2,32/33] nl80211: fix CMD_FRAME used with VLANs

Message ID 1474750454-6626-33-git-send-email-michael-dev@fami-braun.de
State Deferred
Headers show

Commit Message

michael-dev Sept. 24, 2016, 8:54 p.m. UTC
This is required for 802.11r with VLANs used in combination with over_ds,
or the action reply frame won't get out on WiFi.

This is because kernel mac80211 CMD_FRAME uses sta_info_get instead of
sta_info_get_bss, so the ifidx given needs to be the of the AP_VLAN iface.

This could or should be fixed in kernel as well, but in order to be able to
run the hwsim tests right now without rebuilding the kernel or in order to
use FT with VLAN on older kernel, this change is needed.

I'm happy to drop this and only use this as a local workaround until the
kernel change is done.

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
---
 src/ap/ap_config.c           | 27 ++++++++++++++++++++++
 src/ap/ap_config.h           |  4 ++++
 src/ap/ap_drv_ops.c          | 15 +++++++++++--
 src/ap/ap_drv_ops.h          |  3 +++
 src/ap/wpa_auth_glue.c       |  5 ++++-
 src/drivers/driver.h         |  3 ++-
 src/drivers/driver_atheros.c |  3 ++-
 src/drivers/driver_hostap.c  | 10 ++++-----
 src/drivers/driver_nl80211.c | 53 ++++++++++++++++++++++++++------------------
 wpa_supplicant/driver_i.h    |  2 +-
 10 files changed, 93 insertions(+), 32 deletions(-)
diff mbox

Patch

diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 63d56f5..f019da9 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -18,6 +18,8 @@ 
 #include "wpa_auth.h"
 #include "sta_info.h"
 #include "ap_config.h"
+#include "hostapd.h"
+#include <net/if.h>
 
 
 static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
@@ -709,6 +711,31 @@  const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
 }
 
 
+int hostapd_get_vlan_id_ifidx(struct hostapd_vlan *vlan, int vlan_id)
+{
+	const char *ifname = hostapd_get_vlan_id_ifname(vlan, vlan_id);
+
+	if (!ifname)
+		return 0;
+	return if_nametoindex(ifname);
+}
+
+
+int hostapd_get_sta_ifidx(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+
+	if (!hapd)
+		return 0;
+	sta = ap_get_sta(hapd, addr);
+	if (!sta)
+		return 0;
+	if (!sta->vlan_id_bound)
+		return 0;
+	return hostapd_get_vlan_id_ifidx(hapd->conf->vlan, sta->vlan_id_bound);
+}
+
+
 const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
 			   const u8 *addr, const u8 *p2p_dev_addr,
 			   const u8 *prev_psk)
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 5195b3d..aaed2ce 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -727,6 +727,8 @@  struct hostapd_config {
 	struct wpabuf *civic;
 };
 
+struct hostapd_data;
+
 
 int hostapd_mac_comp(const void *a, const void *b);
 struct hostapd_config * hostapd_config_defaults(void);
@@ -746,6 +748,8 @@  int hostapd_vlan_valid(struct hostapd_vlan *vlan,
 		       struct vlan_description *vlan_desc);
 const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
 					int vlan_id);
+int hostapd_get_vlan_id_ifidx(struct hostapd_vlan *vlan, int vlan_id);
+int hostapd_get_sta_ifidx(struct hostapd_data *hapd, const u8 *addr);
 struct hostapd_radius_attr *
 hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
 int hostapd_config_check(struct hostapd_config *conf, int full_config);
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f139465..73e2f36 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -626,7 +626,7 @@  int hostapd_drv_send_mlme(struct hostapd_data *hapd,
 	if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv)
 		return 0;
 	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
-				       NULL, 0);
+				       NULL, 0, 0);
 }
 
 
@@ -637,7 +637,18 @@  int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
 	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
 		return 0;
 	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
-				       csa_offs, csa_offs_len);
+				       csa_offs, csa_offs_len, 0);
+}
+
+
+int hostapd_drv_send_mlme_ifidx(struct hostapd_data *hapd,
+				const void *msg, size_t len, int noack,
+				int ifidx)
+{
+	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+		return 0;
+	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0,
+				       NULL, 0, ifidx);
 }
 
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 0bb7954..c981530 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -92,6 +92,9 @@  int hostapd_drv_send_mlme(struct hostapd_data *hapd,
 int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd,
 			      const void *msg, size_t len, int noack,
 			      const u16 *csa_offs, size_t csa_offs_len);
+int hostapd_drv_send_mlme_ifidx(struct hostapd_data *hapd,
+				const void *msg, size_t len, int noack,
+				int ifidx);
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
 			   const u8 *addr, int reason);
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index bd5f627..fbd5f6d 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -532,6 +532,7 @@  static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
 	struct ieee80211_mgmt *m;
 	size_t mlen;
 	struct sta_info *sta;
+	int ifidx;
 
 	sta = ap_get_sta(hapd, dst);
 	if (sta == NULL || sta->wpa_sm == NULL)
@@ -548,7 +549,9 @@  static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
 	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
 	os_memcpy(&m->u, data, data_len);
 
-	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+	ifidx = hostapd_get_sta_ifidx(hapd, dst);
+
+	res = hostapd_drv_send_mlme_ifidx(hapd, (u8 *) m, mlen, 0, ifidx);
 	os_free(m);
 	return res;
 }
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a449cc9..b0182c4 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2068,11 +2068,12 @@  struct wpa_driver_ops {
 	 * driver decide
 	 * @csa_offs: Array of CSA offsets or %NULL
 	 * @csa_offs_len: Number of elements in csa_offs
+	 * @ifidx: Interface index to send this out (AP_VLAN)
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
 			 int noack, unsigned int freq, const u16 *csa_offs,
-			 size_t csa_offs_len);
+			 size_t csa_offs_len, int ifidx);
 
 	/**
 	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index a88345f..ad5e1c1 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1852,7 +1852,8 @@  static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
 
 static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
 			     int noack, unsigned int freq,
-			     const u16 *csa_offs, size_t csa_offs_len)
+			     const u16 *csa_offs, size_t csa_offs_len,
+			     int ifidx)
 {
 	struct atheros_driver_data *drv = priv;
 	u8 buf[1510];
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 517a3bb..b5026c5 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -259,7 +259,7 @@  static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
 
 static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
 			    unsigned int freq,
-			    const u16 *csa_offs, size_t csa_offs_len)
+			    const u16 *csa_offs, size_t csa_offs_len, int ifidx)
 {
 	struct hostap_driver_data *drv = priv;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -308,7 +308,7 @@  static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0);
+	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -1046,7 +1046,7 @@  static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				sizeof(mgmt.u.deauth), 0, 0, NULL, 0);
+				sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0);
 }
 
 
@@ -1084,7 +1084,7 @@  static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				 sizeof(mgmt.u.disassoc), 0, 0, NULL, 0);
+				 sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0);
 }
 
 
@@ -1162,7 +1162,7 @@  static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
 	os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
 	os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
-	hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0);
+	hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0);
 }
 
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 1210d43..8af840b 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -177,7 +177,8 @@  static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len, u64 *cookie,
 				  int no_cck, int no_ack, int offchanok,
-				  const u16 *csa_offs, size_t csa_offs_len);
+				  const u16 *csa_offs, size_t csa_offs_len,
+				  int ifidx);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
 					       int report);
 
@@ -456,15 +457,19 @@  void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
 }
 
 
-static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss,
+				int ifidx)
 {
+	if (ifidx)
+		return nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifidx);
 	if (bss->wdev_id_set)
 		return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
 	return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 }
 
 
-struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+struct nl_msg * nl80211_cmd_msg_ifidx(struct i802_bss *bss, int flags,
+				      uint8_t cmd, int ifidx)
 {
 	struct nl_msg *msg;
 
@@ -473,7 +478,7 @@  struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
 		return NULL;
 
 	if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
-	    nl80211_set_iface_id(msg, bss) < 0) {
+	    nl80211_set_iface_id(msg, bss, ifidx) < 0) {
 		nlmsg_free(msg);
 		return NULL;
 	}
@@ -482,6 +487,11 @@  struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
 }
 
 
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+	return nl80211_cmd_msg_ifidx(bss, flags, cmd, 0);
+}
+
 static struct nl_msg *
 nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
 		    int flags, uint8_t cmd)
@@ -3243,7 +3253,7 @@  static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
 					 unsigned int freq, int no_cck,
 					 int offchanok, unsigned int wait_time,
 					 const u16 *csa_offs,
-					 size_t csa_offs_len)
+					 size_t csa_offs_len, int ifidx)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	u64 cookie;
@@ -3270,7 +3280,7 @@  static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
 	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
 	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
 				     &cookie, no_cck, noack, offchanok,
-				     csa_offs, csa_offs_len);
+				     csa_offs, csa_offs_len, ifidx);
 	if (res == 0 && !noack) {
 		const struct ieee80211_mgmt *mgmt;
 		u16 fc;
@@ -3298,7 +3308,7 @@  static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 					int offchanok,
 					unsigned int wait_time,
 					const u16 *csa_offs,
-					size_t csa_offs_len)
+					size_t csa_offs_len, int ifidx)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct ieee80211_mgmt *mgmt;
@@ -3328,7 +3338,7 @@  static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 		}
 		return nl80211_send_frame_cmd(bss, freq, 0,
 					      data, data_len, NULL, 1, noack,
-					      1, csa_offs, csa_offs_len);
+					      1, csa_offs, csa_offs_len, ifidx);
 	}
 
 	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
@@ -3343,7 +3353,7 @@  static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 					      data, data_len,
 					      &drv->send_action_cookie,
 					      no_cck, noack, offchanok,
-					      csa_offs, csa_offs_len);
+					      csa_offs, csa_offs_len, ifidx);
 	}
 
 	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3364,7 +3374,7 @@  static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
 	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
 					     noack, freq, no_cck, offchanok,
 					     wait_time, csa_offs,
-					     csa_offs_len);
+					     csa_offs_len, ifidx);
 }
 
 
@@ -4551,7 +4561,7 @@  static int wpa_driver_nl80211_hapd_send_eapol(
 	memcpy(pos, data, data_len);
 
 	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
-					    0, 0, 0, 0, NULL, 0);
+					    0, 0, 0, 0, NULL, 0, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -5778,7 +5788,7 @@  static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
 					    sizeof(mgmt.u.deauth), 0, 0, 0, 0,
-					    0, NULL, 0);
+					    0, NULL, 0, 0);
 }
 
 
@@ -5805,7 +5815,7 @@  static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
 					    sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
-					    0, NULL, 0);
+					    0, NULL, 0, 0);
 }
 
 
@@ -6509,7 +6519,7 @@  static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  const u8 *buf, size_t buf_len,
 				  u64 *cookie_out, int no_cck, int no_ack,
 				  int offchanok, const u16 *csa_offs,
-				  size_t csa_offs_len)
+				  size_t csa_offs_len, int ifidx)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
@@ -6521,7 +6531,7 @@  static int nl80211_send_frame_cmd(struct i802_bss *bss,
 		   freq, wait, no_cck, no_ack, offchanok);
 	wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
 
-	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
+	if (!(msg = nl80211_cmd_msg_ifidx(bss, 0, NL80211_CMD_FRAME, ifidx)) ||
 	    (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
 	    (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
 	    (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
@@ -6604,12 +6614,12 @@  static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
 	     !drv->use_monitor))
 		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
 						   0, freq, no_cck, 1,
-						   wait_time, NULL, 0);
+						   wait_time, NULL, 0, 0);
 	else
 		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
 					     24 + data_len,
 					     &drv->send_action_cookie,
-					     no_cck, 0, 1, NULL, 0);
+					     no_cck, 0, 1, NULL, 0, 0);
 
 	os_free(buf);
 	return ret;
@@ -6982,7 +6992,7 @@  static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
 {
 	struct i802_bss *bss = priv;
 	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
-					     0, 0, 0, 0, NULL, 0);
+					     0, 0, 0, 0, NULL, 0, 0);
 }
 
 
@@ -7388,7 +7398,7 @@  static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
 	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
 
 	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
-					 0, 0, NULL, 0) < 0)
+					 0, 0, NULL, 0, 0) < 0)
 		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
 			   "send poll frame");
 }
@@ -7709,12 +7719,13 @@  static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
 static int driver_nl80211_send_mlme(void *priv, const u8 *data,
 				    size_t data_len, int noack,
 				    unsigned int freq,
-				    const u16 *csa_offs, size_t csa_offs_len)
+				    const u16 *csa_offs, size_t csa_offs_len,
+				    int ifidx)
 {
 	struct i802_bss *bss = priv;
 	return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
 					    freq, 0, 0, 0, csa_offs,
-					    csa_offs_len);
+					    csa_offs_len, ifidx);
 }
 
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 220b7ba..f1d4d58 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -299,7 +299,7 @@  static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
 	if (wpa_s->driver->send_mlme)
 		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
 						data, data_len, noack,
-						freq, NULL, 0);
+						freq, NULL, 0, 0);
 	return -1;
 }