mac80211: update adjusting TBTT bit in beacon
authorThomas Pedersen <thomas@cozybit.com>
Sun, 15 Dec 2013 21:14:16 +0000 (13:14 -0800)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 16 Dec 2013 13:21:22 +0000 (14:21 +0100)
This regression was introduced in "mac80211: cache mesh
beacon".

mesh_sync_offset_adjust_tbtt()  was assuming that the
beacon would be rebuilt in every single pre-tbtt
interrupt, but now the beacon update happens on the
workqueue, and it must be ready for immediate delivery to
the driver.

Save a pointer to the meshconf IE in the beacon_data (this
works because both the IE pointer and beacon buffer are
protected by the same rcu_{dereference,assign_pointer}())
for quick updates during pre-tbtt. This is faster and a
little prettier than iterating over the elements to find
the meshconf IE every time.

Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ieee80211_i.h
net/mac80211/mesh.c
net/mac80211/mesh_sync.c
net/mac80211/tx.c

index ee13c65..adbff71 100644 (file)
@@ -232,6 +232,7 @@ struct ieee80211_rx_data {
 struct beacon_data {
        u8 *head, *tail;
        int head_len, tail_len;
+       struct ieee80211_meshconf_ie *meshconf;
        struct rcu_head rcu_head;
 };
 
@@ -540,7 +541,10 @@ struct ieee80211_mesh_sync_ops {
                             struct ieee80211_mgmt *mgmt,
                             struct ieee802_11_elems *elems,
                             struct ieee80211_rx_status *rx_status);
-       void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata);
+
+       /* should be called with beacon_data under RCU read lock */
+       void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata,
+                           struct beacon_data *beacon);
        /* add other framework functions here */
 };
 
@@ -614,6 +618,9 @@ struct ieee80211_if_mesh {
        bool chsw_init;
        u8 chsw_ttl;
        u16 pre_value;
+
+       /* offset from skb->data while building IE */
+       int meshconf_offset;
 };
 
 #ifdef CONFIG_MAC80211_MESH
index 89df62b..5a74b24 100644 (file)
@@ -259,6 +259,9 @@ int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
        *pos++ = WLAN_EID_MESH_CONFIG;
        *pos++ = meshconf_len;
 
+       /* save a pointer for quick updates in pre-tbtt */
+       ifmsh->meshconf_offset = pos - skb->data;
+
        /* Active path selection protocol ID */
        *pos++ = ifmsh->mesh_pp_id;
        /* Active path selection metric ID   */
@@ -723,6 +726,8 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
 
        bcn->tail_len = skb->len;
        memcpy(bcn->tail, skb->data, bcn->tail_len);
+       bcn->meshconf = (struct ieee80211_meshconf_ie *)
+                                       (bcn->tail + ifmsh->meshconf_offset);
 
        dev_kfree_skb(skb);
        rcu_assign_pointer(ifmsh->beacon, bcn);
index d1cf2d5..2bc5dc2 100644 (file)
@@ -164,12 +164,15 @@ no_sync:
        rcu_read_unlock();
 }
 
-static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
+static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata,
+                                        struct beacon_data *beacon)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       u8 cap;
 
        WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
        BUG_ON(!rcu_read_lock_held());
+       cap = beacon->meshconf->meshconf_cap;
 
        spin_lock_bh(&ifmsh->sync_offset_lock);
 
@@ -194,6 +197,10 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
                ifmsh->adjusting_tbtt = false;
        }
        spin_unlock_bh(&ifmsh->sync_offset_lock);
+
+       beacon->meshconf->meshconf_cap = ifmsh->adjusting_tbtt ?
+                       IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING | cap :
+                       ~IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING & cap;
 }
 
 static const struct sync_method sync_methods[] = {
index 002ded2..2f0e176 100644 (file)
@@ -2604,8 +2604,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                        ieee80211_update_csa(sdata, bcn);
 
                if (ifmsh->sync_ops)
-                       ifmsh->sync_ops->adjust_tbtt(
-                                               sdata);
+                       ifmsh->sync_ops->adjust_tbtt(sdata, bcn);
 
                skb = dev_alloc_skb(local->tx_headroom +
                                    bcn->head_len +