On 02/01/2013 05:56 AM, Thomas Pedersen wrote:
Previously, the entire mesh beacon would be generated each
time the beacon timer fired. Instead generate a beacon
head and tail
(so the TIM can easily be inserted when mesh
power save is on)
Got the hint =)
Btw, the TIM IE will always be present in mesh beacons (just 6 bytes
when no data has been buffered).
when starting a mesh or the MBSS
parameters change.
Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/cfg.c | 2 +
net/mac80211/ieee80211_i.h | 2 +
net/mac80211/mesh.c | 121 +++++++++++++++++++++++++++++++++++++++++++-
net/mac80211/mesh.h | 3 ++
net/mac80211/mesh_plink.c | 6 +--
net/mac80211/tx.c | 59 ++++-----------------
6 files changed, 139 insertions(+), 54 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 661b878..f3ca170 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1777,6 +1777,8 @@ static int ieee80211_update_mesh_config(struct wiphy
*wiphy,
if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask))
conf->dot11MeshHWMPconfirmationInterval =
nconf->dot11MeshHWMPconfirmationInterval;
+ /* need to update the IEs as well */
+ ieee80211_mbss_info_change_notify(sdata, BSS_CHANGED_BEACON);
return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5fba867..2370599 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -611,6 +611,8 @@ struct ieee80211_if_mesh {
u32 mesh_seqnum;
bool accepting_plinks;
int num_gates;
+ struct sk_buff __rcu *bcn_head;
+ struct sk_buff __rcu *bcn_tail;
const u8 *ie;
u8 ie_len;
enum {
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 694e273..17fa6b6 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -547,7 +547,7 @@ static void ieee80211_mesh_housekeeping(struct
ieee80211_sub_if_data *sdata,
mesh_path_expire(sdata);
changed = mesh_accept_plinks_update(sdata);
- ieee80211_bss_info_change_notify(sdata, changed);
+ ieee80211_mbss_info_change_notify(sdata, changed);
mod_timer(&ifmsh->housekeeping_timer,
round_jiffies(jiffies +
IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
@@ -598,6 +598,120 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data
*sdata)
}
#endif
+static int
+ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
+{
+ struct sk_buff *bcn_head, *bcn_tail;
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ enum ieee80211_band band;
+ u8 *pos;
+ struct ieee80211_sub_if_data *sdata;
+ int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
+ sizeof(mgmt->u.beacon);
+
+ sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+ band = chanctx_conf->def.chan->band;
+ rcu_read_unlock();
+
+ RCU_INIT_POINTER(ifmsh->bcn_head, NULL);
+ RCU_INIT_POINTER(ifmsh->bcn_tail, NULL);
+ synchronize_rcu();
+
+ bcn_head = dev_alloc_skb(hdr_len +
+ 2 + /* NULL SSID */
+ 2 + 8 + /* supported rates */
+ 2 + 3); /* DS params */
+ bcn_tail = dev_alloc_skb(2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+ 2 + sizeof(struct ieee80211_ht_cap) +
+ 2 + sizeof(struct ieee80211_ht_operation) +
+ 2 + ifmsh->mesh_id_len +
+ 2 + sizeof(struct ieee80211_meshconf_ie) +
+ ifmsh->ie_len);
+
+ if (!bcn_head || !bcn_tail)
+ goto out_free;
+
+ /* fill in the head */
+ mgmt = (struct ieee80211_mgmt *) skb_put(bcn_head, hdr_len);
+ memset(mgmt, 0, hdr_len);
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_BEACON);
+ eth_broadcast_addr(mgmt->da);
+ 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 |= cpu_to_le16(
+ sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
+
+ pos = skb_put(bcn_head, 2);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0x0;
+
+ if (ieee80211_add_srates_ie(sdata, bcn_head, true, band) ||
+ mesh_add_ds_params_ie(bcn_head, sdata)) {
+ mpl_dbg(sdata, "couldn't add beacon head IEs\n");
+ goto out_free;
+ }
+
+ /* now the tail */
+ if (ieee80211_add_ext_srates_ie(sdata, bcn_tail, true, band) ||
+ mesh_add_rsn_ie(bcn_tail, sdata) ||
+ mesh_add_ht_cap_ie(bcn_tail, sdata) ||
+ mesh_add_ht_oper_ie(bcn_tail, sdata) ||
+ mesh_add_meshid_ie(bcn_tail, sdata) ||
+ mesh_add_meshconf_ie(bcn_tail, sdata) ||
+ mesh_add_vendor_ies(bcn_tail, sdata)) {
+ mpl_dbg(sdata, "couldn't add beacon tail IEs!\n");
+ goto out_free;
+ }
+
+ rcu_assign_pointer(ifmsh->bcn_head, bcn_head);
+ rcu_assign_pointer(ifmsh->bcn_tail, bcn_tail);
+ return 0;
+out_free:
+ if (bcn_head)
+ kfree_skb(bcn_head);
+ if (bcn_tail)
+ kfree_skb(bcn_tail);
+ return -ENOMEM;
+}
+
+static int
+ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh)
+{
+ struct ieee80211_sub_if_data *sdata;
+ sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
+
+ rcu_read_lock();
+ dev_kfree_skb(rcu_dereference(ifmsh->bcn_head));
+ dev_kfree_skb(rcu_dereference(ifmsh->bcn_tail));
+ rcu_read_unlock();
+
+ if (WARN_ON(ieee80211_mesh_build_beacon(ifmsh))) {
+ mpl_dbg(sdata, "couldn't rebuild mesh beacon, stopping!\n");
+ ieee80211_stop_mesh(sdata);
+ return -1;
+ }
+ return 0;
+}
+
+int ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+ u32 changed)
+{
+ if (changed & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_HT |
+ BSS_CHANGED_BASIC_RATES |
+ BSS_CHANGED_BEACON_INT))
+ if (ieee80211_mesh_rebuild_beacon(&sdata->u.mesh))
+ return -1;
+ ieee80211_bss_info_change_notify(sdata, changed);
+ return 0;
+}
+
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
@@ -634,7 +748,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data
*sdata)
changed |= BSS_CHANGED_ERP_SLOT;
}
- ieee80211_bss_info_change_notify(sdata, changed);
+ if (ieee80211_mbss_info_change_notify(sdata, changed))
+ return;
netif_carrier_on(sdata->dev);
}
@@ -651,6 +766,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data
*sdata)
sdata->vif.bss_conf.enable_beacon = false;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+ dev_kfree_skb(ifmsh->bcn_head);
+ dev_kfree_skb(ifmsh->bcn_tail);
/* flush STAs and mpaths on this iface */
sta_info_flush(sdata);
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index aff3015..e6377ec 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -241,6 +241,9 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data
*sdata);
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
+/* wrapper for ieee80211_bss_info_change_notify() */
+int ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
+ u32 changed);
/* Mesh paths */
int mesh_nexthop_lookup(struct sk_buff *skb,
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 81e6126..de733e9 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -164,7 +164,7 @@ void mesh_plink_deactivate(struct sta_info *sta)
sta->reason);
spin_unlock_bh(&sta->lock);
- ieee80211_bss_info_change_notify(sdata, changed);
+ ieee80211_mbss_info_change_notify(sdata, changed);
}
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -587,7 +587,7 @@ void mesh_plink_block(struct sta_info *sta)
sta->plink_state = NL80211_PLINK_BLOCKED;
spin_unlock_bh(&sta->lock);
- ieee80211_bss_info_change_notify(sdata, changed);
+ ieee80211_mbss_info_change_notify(sdata, changed);
}
@@ -1002,5 +1002,5 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data
*sdata, struct ieee80211_m
rcu_read_unlock();
if (changed)
- ieee80211_bss_info_change_notify(sdata, changed);
+ ieee80211_mbss_info_change_notify(sdata, changed);
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a2cb6a3..cb311e1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2424,66 +2424,27 @@ 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;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- u8 *pos;
- int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
- sizeof(mgmt->u.beacon);
+ struct sk_buff *head = rcu_dereference(ifmsh->bcn_head);
+ struct sk_buff *tail = rcu_dereference(ifmsh->bcn_tail);
-#ifdef CONFIG_MAC80211_MESH
- if (!sdata->u.mesh.mesh_id_len)
+ if (!head || !tail)
goto out;
-#endif
if (ifmsh->sync_ops)
ifmsh->sync_ops->adjust_tbtt(
sdata);
skb = dev_alloc_skb(local->tx_headroom +
- hdr_len +
- 2 + /* NULL SSID */
- 2 + 8 + /* supported rates */
- 2 + 3 + /* DS params */
- 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
- 2 + sizeof(struct ieee80211_ht_cap) +
- 2 + sizeof(struct ieee80211_ht_operation) +
- 2 + sdata->u.mesh.mesh_id_len +
- 2 + sizeof(struct ieee80211_meshconf_ie) +
- sdata->u.mesh.ie_len);
+ head->len +
+ 256 + /* TIM IE */
Any reason to already allocate the space? May as well add that with the
TIM IE commit.
+ tail->len);
if (!skb)
goto out;
-
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
- memset(mgmt, 0, hdr_len);
- mgmt->frame_control =
- cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
- eth_broadcast_addr(mgmt->da);
- 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 |= cpu_to_le16(
- sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
-
- pos = skb_put(skb, 2);
- *pos++ = WLAN_EID_SSID;
- *pos++ = 0x0;
-
- band = chanctx_conf->def.chan->band;
-
- if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
- mesh_add_ds_params_ie(skb, sdata) ||
- ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
- mesh_add_rsn_ie(skb, sdata) ||
- mesh_add_ht_cap_ie(skb, sdata) ||
- mesh_add_ht_oper_ie(skb, sdata) ||
- mesh_add_meshid_ie(skb, sdata) ||
- mesh_add_meshconf_ie(skb, sdata) ||
- mesh_add_vendor_ies(skb, sdata)) {
- pr_err("o11s: couldn't add ies!\n");
- goto out;
- }
+ skb_reserve(skb, local->tx_headroom);
+ memcpy(skb_put(skb, head->len), head->data, head->len);
+ /* TODO: add TIM */
+ memcpy(skb_put(skb, tail->len), tail->data, tail->len);
} else {
WARN_ON(1);
goto out;
_______________________________________________
Devel mailing list
[email protected]
http://lists.open80211s.org/cgi-bin/mailman/listinfo/devel