]> err.no Git - linux-2.6/blobdiff - net/mac80211/mesh.c
mac80211: revamp virtual interface handling
[linux-2.6] / net / mac80211 / mesh.c
index 8ff533005d929288a4b38d969756d9e9b599c8d3..b5933b271491551bc10edacdfda4416be6b8125d 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <asm/unaligned.h>
 #include "ieee80211_i.h"
 #include "mesh.h"
 
@@ -48,11 +49,6 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev)
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *sta = &sdata->u.sta;
 
-       if (sta->mesh_id_len == ie->mesh_id_len &&
-               memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-               memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
-               memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
-               memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
        /*
         * As support for each feature is added, check for matching
         * - On mesh config capabilities
@@ -63,6 +59,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev)
         *   - MDA enabled
         * - Power management control on fc
         */
+       if (sta->mesh_id_len == ie->mesh_id_len &&
+               memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+               memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
+               memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
+               memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
                return true;
 
        return false;
@@ -83,18 +84,17 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
 /**
  * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
  *
- * @dev: mesh interface in which mesh beacons are going to be updated
+ * @sdata: mesh interface in which mesh beacons are going to be updated
  */
-void mesh_accept_plinks_update(struct net_device *dev)
+void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        bool free_plinks;
 
        /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
         * the mesh interface might be able to establish plinks with peers that
-        * are already on the table but are not on ESTAB state. However, in
-        * general the mesh interface is not accepting peer link requests from
-        * new peers, and that must be reflected in the beacon
+        * are already on the table but are not on PLINK_ESTAB state. However,
+        * in general the mesh interface is not accepting peer link requests
+        * from new peers, and that must be reflected in the beacon
         */
        free_plinks = mesh_plink_availables(sdata);
 
@@ -168,8 +168,8 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
        struct rmc_entry *p, *n;
 
        /* Don't care about endianness since only match matters */
-       memcpy(&seqnum, mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
-       idx = mesh_hdr->seqnum[0] & rmc->idx_mask;
+       memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
+       idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
        list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
                ++entries;
                if (time_after(jiffies, p->exp_time) ||
@@ -315,6 +315,13 @@ struct mesh_table *mesh_table_alloc(int size_order)
        return newtbl;
 }
 
+static void __mesh_table_free(struct mesh_table *tbl)
+{
+       kfree(tbl->hash_buckets);
+       kfree(tbl->hashwlock);
+       kfree(tbl);
+}
+
 void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
 {
        struct hlist_head *mesh_hash;
@@ -330,9 +337,7 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
                }
                spin_unlock(&tbl->hashwlock[i]);
        }
-       kfree(tbl->hash_buckets);
-       kfree(tbl->hashwlock);
-       kfree(tbl);
+       __mesh_table_free(tbl);
 }
 
 static void ieee80211_mesh_path_timer(unsigned long data)
@@ -349,21 +354,16 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
 {
        struct mesh_table *newtbl;
        struct hlist_head *oldhash;
-       struct hlist_node *p;
-       int err = 0;
+       struct hlist_node *p, *q;
        int i;
 
        if (atomic_read(&tbl->entries)
-                       < tbl->mean_chain_len * (tbl->hash_mask + 1)) {
-               err = -EPERM;
+                       < tbl->mean_chain_len * (tbl->hash_mask + 1))
                goto endgrow;
-       }
 
        newtbl = mesh_table_alloc(tbl->size_order + 1);
-       if (!newtbl) {
-               err = -ENOMEM;
+       if (!newtbl)
                goto endgrow;
-       }
 
        newtbl->free_node = tbl->free_node;
        newtbl->mean_chain_len = tbl->mean_chain_len;
@@ -373,11 +373,76 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
        oldhash = tbl->hash_buckets;
        for (i = 0; i <= tbl->hash_mask; i++)
                hlist_for_each(p, &oldhash[i])
-                       tbl->copy_node(p, newtbl);
+                       if (tbl->copy_node(p, newtbl) < 0)
+                               goto errcopy;
+
+       return newtbl;
 
+errcopy:
+       for (i = 0; i <= newtbl->hash_mask; i++) {
+               hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
+                       tbl->free_node(p, 0);
+       }
+       __mesh_table_free(tbl);
 endgrow:
-       if (err)
-               return NULL;
-       else
-               return newtbl;
+       return NULL;
+}
+
+/**
+ * ieee80211_new_mesh_header - create a new mesh header
+ * @meshhdr:    uninitialized mesh header
+ * @sdata:     mesh interface to be used
+ *
+ * Return the header length.
+ */
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+               struct ieee80211_sub_if_data *sdata)
+{
+       meshhdr->flags = 0;
+       meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+       put_unaligned(cpu_to_le32(sdata->u.sta.mesh_seqnum), &meshhdr->seqnum);
+       sdata->u.sta.mesh_seqnum++;
+
+       return 6;
+}
+
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+       ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+       ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+       ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+       ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+       ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
+       ifsta->mshcfg.auto_open_plinks = true;
+       ifsta->mshcfg.dot11MeshMaxPeerLinks =
+               MESH_MAX_ESTAB_PLINKS;
+       ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+               MESH_PATH_TIMEOUT;
+       ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+               MESH_PREQ_MIN_INT;
+       ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+               MESH_DIAM_TRAVERSAL_TIME;
+       ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+               MESH_MAX_PREQ_RETRIES;
+       ifsta->mshcfg.path_refresh_time =
+               MESH_PATH_REFRESH_TIME;
+       ifsta->mshcfg.min_discovery_timeout =
+               MESH_MIN_DISCOVERY_TIMEOUT;
+       ifsta->accepting_plinks = true;
+       ifsta->preq_id = 0;
+       ifsta->dsn = 0;
+       atomic_set(&ifsta->mpaths, 0);
+       mesh_rmc_init(sdata->dev);
+       ifsta->last_preq = jiffies;
+       /* Allocate all mesh structures when creating the first mesh interface. */
+       if (!mesh_allocated)
+               ieee80211s_init();
+       mesh_ids_set_default(ifsta);
+       setup_timer(&ifsta->mesh_path_timer,
+                   ieee80211_mesh_path_timer,
+                   (unsigned long) sdata);
+       INIT_LIST_HEAD(&ifsta->preq_queue.list);
+       spin_lock_init(&ifsta->mesh_preq_queue_lock);
 }