Search Linux Wireless

[PATCH 1/5] mac80211: give if_mesh a beacon

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Maintain a mesh beacon in the mesh interface like the AP interface does.
This will save us some work later when Probe Responses are implemented.

Based on Javier Cardona's "mac80211: Support beacon configuration via
nl80211 for mesh interfaces", which never made it upstream.

Signed-off-by: Thomas Pedersen <thomas@xxxxxxxxxxx>
---
 net/mac80211/cfg.c         |   31 +++++++++++++++++++++++------
 net/mac80211/ieee80211_i.h |    1 +
 net/mac80211/mesh.c        |   44 +++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/tx.c          |   45 ++++++++++++++++++-------------------------
 4 files changed, 88 insertions(+), 33 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bfc36e9..639c287 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -466,7 +466,10 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 	int size;
 	int err = -EINVAL;
 
-	old = rtnl_dereference(sdata->u.ap.beacon);
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		old = rtnl_dereference(sdata->u.mesh.beacon);
+	else
+		old = rtnl_dereference(sdata->u.ap.beacon);
 
 	/* head must not be zero-length */
 	if (params->head && !params->head_len)
@@ -542,8 +545,10 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
 	sdata->vif.bss_conf.dtim_period = new->dtim_period;
 
-	rcu_assign_pointer(sdata->u.ap.beacon, new);
-
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		rcu_assign_pointer(sdata->u.mesh.beacon, new);
+	else
+		rcu_assign_pointer(sdata->u.ap.beacon, new);
 	synchronize_rcu();
 
 	kfree(old);
@@ -561,7 +566,10 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	old = rtnl_dereference(sdata->u.ap.beacon);
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		old = rtnl_dereference(sdata->u.mesh.beacon);
+	else
+		old = rtnl_dereference(sdata->u.ap.beacon);
 	if (old)
 		return -EALREADY;
 
@@ -576,7 +584,10 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	old = rtnl_dereference(sdata->u.ap.beacon);
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		old = rtnl_dereference(sdata->u.mesh.beacon);
+	else
+		old = rtnl_dereference(sdata->u.ap.beacon);
 	if (!old)
 		return -ENOENT;
 
@@ -590,11 +601,17 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	old = rtnl_dereference(sdata->u.ap.beacon);
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		old = rtnl_dereference(sdata->u.mesh.beacon);
+	else
+		old = rtnl_dereference(sdata->u.ap.beacon);
 	if (!old)
 		return -ENOENT;
 
-	rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		rcu_assign_pointer(sdata->u.mesh.beacon, NULL);
+	else
+		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
 	synchronize_rcu();
 	kfree(old);
 
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index dda0d1a..2d726b7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -519,6 +519,7 @@ struct ieee80211_if_mesh {
 		IEEE80211_MESH_SEC_AUTHED = 0x1,
 		IEEE80211_MESH_SEC_SECURED = 0x2,
 	} security;
+	struct beacon_data *beacon;
 };
 
 #ifdef CONFIG_MAC80211_MESH
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29e9980..60fd958 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 #include "ieee80211_i.h"
+#include "cfg.h"
 #include "mesh.h"
 
 #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
@@ -461,6 +462,9 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_mgmt *bcn_head;
+	struct beacon_parameters bcn_params;
+	u8 *pos;
 
 	local->fif_other_bss++;
 	/* mesh ifaces must set allmulti to forward mcast traffic */
@@ -473,7 +477,44 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 	ieee80211_mesh_root_setup(ifmsh);
 	ieee80211_queue_work(&local->hw, &sdata->work);
+
+	/* Build fixed part of mesh beacon. */
+	memset(&bcn_params, 0, sizeof(struct beacon_parameters));
+
+	/* header + fixed fields + null ssid */
+	bcn_params.head_len = 24 + sizeof(bcn_head->u.beacon) + 2;
+	pos = kmalloc(bcn_params.head_len, GFP_KERNEL | __GFP_ZERO);
+	if (pos == NULL) {
+		printk(KERN_ERR "Unable to allocate mesh beacon\n");
+		return;
+	}
+
+	/* Header */
+	bcn_head = (struct ieee80211_mgmt *) pos;
+	bcn_head->frame_control =
+		cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
+	memset(bcn_head->da, 0xff, ETH_ALEN);
+	memcpy(bcn_head->sa, sdata->vif.addr, ETH_ALEN);
+	memcpy(bcn_head->bssid, sdata->vif.addr, ETH_ALEN);
+
+	/* Default beacon interval and capabilities */
+	bcn_head->u.beacon.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
+	bcn_head->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+
+	/* Mesh uses null SSID */
+	pos += 24 + sizeof(bcn_head->u.beacon);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = 0x0;
+
+	bcn_params.head = (char *) bcn_head;
+	bcn_params.dtim_period = 1;	/* unused for now */
+
+	if (mac80211_config_ops.add_beacon(sdata->wdev.wiphy, sdata->dev,
+				&bcn_params))
+		printk(KERN_ERR "Unable to configure mesh beacon\n");
+
 	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
+	sdata->vif.bss_conf.enable_beacon = 1;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
 						BSS_CHANGED_BEACON_ENABLED |
 						BSS_CHANGED_BEACON_INT);
@@ -485,6 +526,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
 	ifmsh->mesh_id_len = 0;
+	sdata->vif.bss_conf.enable_beacon = 0;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 	sta_info_flush(local, NULL);
 
@@ -498,6 +540,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 	 * it no longer is.
 	 */
 	cancel_work_sync(&sdata->work);
+	if (sdata->u.mesh.beacon)
+		mac80211_config_ops.del_beacon(sdata->wdev.wiphy, sdata->dev);
 
 	local->fif_other_bss--;
 	atomic_dec(&local->iff_allmultis);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8cb0d2d..c406b13 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2250,38 +2250,31 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 		hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 						 IEEE80211_STYPE_BEACON);
 	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
-		struct ieee80211_mgmt *mgmt;
-		u8 *pos;
-
+		struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 #ifdef CONFIG_MAC80211_MESH
 		if (!sdata->u.mesh.mesh_id_len)
 			goto out;
 #endif
+		beacon = rcu_dereference(ifmsh->beacon);
+		if (beacon) {
+			/* headroom, head length, tail length, mesh_ies and
+			 * maximum TIM length */
+			skb = dev_alloc_skb(local->tx_headroom +
+					    beacon->head_len +
+					    beacon->tail_len + 400);
+			if (!skb)
+				goto out;
 
-		/* headroom, head length, tail length and maximum TIM length */
-		skb = dev_alloc_skb(local->tx_headroom + 400 +
-				sdata->u.mesh.ie_len);
-		if (!skb)
-			goto out;
+			skb_reserve(skb, local->hw.extra_tx_headroom);
+			memcpy(skb_put(skb, beacon->head_len), beacon->head,
+			       beacon->head_len);
+
+			mesh_mgmt_ies_add(skb, sdata);
 
-		skb_reserve(skb, local->hw.extra_tx_headroom);
-		mgmt = (struct ieee80211_mgmt *)
-			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-		mgmt->frame_control =
-		    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
-		memset(mgmt->da, 0xff, ETH_ALEN);
-		memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
-		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
-		mgmt->u.beacon.beacon_int =
-			cpu_to_le16(sdata->vif.bss_conf.beacon_int);
-		mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
-
-		pos = skb_put(skb, 2);
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = 0x0;
-
-		mesh_mgmt_ies_add(skb, sdata);
+			if (beacon->tail && beacon->tail_len)
+				memcpy(skb_put(skb, beacon->tail_len),
+				       beacon->tail, beacon->tail_len);
+		}
 	} else {
 		WARN_ON(1);
 		goto out;
-- 
1.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux