@@ -438,7 +438,9 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
int size;
int err = -EINVAL;
- old = sdata->u.ap.beacon;
+
+ old = ieee80211_vif_is_mesh(&sdata->vif) ?
+ sdata->u.mesh.beacon : sdata->u.ap.beacon;
/* head must not be zero-length */
if (params->head && !params->head_len)
@@ -514,7 +516,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();
@@ -533,7 +538,8 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- old = sdata->u.ap.beacon;
+ old = ieee80211_vif_is_mesh(&sdata->vif) ?
+ sdata->u.mesh.beacon : sdata->u.ap.beacon;
if (old)
return -EALREADY;
@@ -549,7 +555,8 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- old = sdata->u.ap.beacon;
+ old = ieee80211_vif_is_mesh(&sdata->vif) ?
+ sdata->u.mesh.beacon : sdata->u.ap.beacon;
if (!old)
return -ENOENT;
@@ -564,12 +571,16 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- old = sdata->u.ap.beacon;
+ old = ieee80211_vif_is_mesh(&sdata->vif) ?
+ sdata->u.mesh.beacon : 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);
@@ -454,6 +454,7 @@ struct ieee80211_if_mesh {
unsigned long wrkq_flags;
+ struct beacon_data *beacon;
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
size_t mesh_id_len;
/* Active Path Selection Protocol Identifier */
@@ -208,6 +208,13 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.bssid = NULL;
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
sdata->vif.bss_conf.bssid = zero;
+ if (sdata->u.mesh.beacon && sdata->u.mesh.beacon->tail_len) {
+ sdata->u.mesh.mesh_pp_id = MESH_PATH_PROTOCOL_VENDOR;
+ sdata->u.mesh.mesh_pm_id = MESH_PATH_METRIC_VENDOR;
+ } else {
+ sdata->u.mesh.mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
+ sdata->u.mesh.mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
+ }
} else {
WARN_ON(1);
return;
@@ -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)
@@ -126,8 +127,8 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
void mesh_ids_set_default(struct ieee80211_if_mesh *sta)
{
- sta->mesh_pp_id = 0; /* HWMP */
- sta->mesh_pm_id = 0; /* Airtime */
+ sta->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
+ sta->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
sta->mesh_cc_id = 0; /* Disabled */
sta->mesh_sp_id = 0; /* Neighbor Offset */
sta->mesh_auth_id = 0; /* Disabled */
@@ -512,11 +513,51 @@ 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;
+ char *pos;
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
ieee80211_mesh_root_setup(ifmsh);
ieee80211_queue_work(&local->hw, &sdata->work);
+
+ /* Configure here the fixed part of the 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);
@@ -524,6 +565,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
{
+ sdata->vif.bss_conf.enable_beacon = 0;
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
del_timer_sync(&sdata->u.mesh.housekeeping_timer);
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
/*
@@ -534,6 +577,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);
}
static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
@@ -44,6 +44,30 @@ enum mesh_path_flags {
};
/**
+ * enum - mesh path selection protocol identifier
+ *
+ * @MESH_PATH_PROTOCOL_HWMP: the default path selection protocol
+ * @MESH_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will be
+ * specified in a vendor specific information element
+ */
+enum {
+ MESH_PATH_PROTOCOL_HWMP = 0,
+ MESH_PATH_PROTOCOL_VENDOR = 255,
+};
+
+/**
+ * enum - mesh path selection metric identifier
+ *
+ * @MESH_PATH_METRIC_AIRTIME: the default path selection metric
+ * @MESH_PATH_METRIC_VENDOR: a vendor specific metric that will be
+ * specified in a vendor specific information element
+ */
+enum {
+ MESH_PATH_METRIC_AIRTIME = 0,
+ MESH_PATH_METRIC_VENDOR = 255,
+};
+
+/**
* enum mesh_deferred_task_flags - mac80211 mesh deferred tasks
*
*
@@ -2266,32 +2266,23 @@ 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;
- /* headroom, head length, tail length and maximum TIM length */
- skb = dev_alloc_skb(local->tx_headroom + 400);
- if (!skb)
- goto out;
+ beacon = rcu_dereference(ifmsh->beacon);
+ if (ifmsh && beacon) {
+ /* headroom, head length, mesh_ies and tail length */
+ skb = dev_alloc_skb(local->tx_headroom + 400);
+ if (!skb)
+ goto out;
- 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);
+ 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);
+ if (beacon->tail && beacon->tail_len)
+ memcpy(skb_put(skb, beacon->tail_len),
+ beacon->tail, beacon->tail_len);
+ }
} else {
WARN_ON(1);
goto out;
@@ -1709,6 +1709,7 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
@@ -1776,6 +1777,7 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;