Search Linux Wireless

Re: [PATCH v3] mac80211: mesh portal functionality support

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

 



Yanbo,

This is a great contribution!  We'll try it out in our testbed next
week.  But until we complete a full review, a couple of comments
follow:

On Sun, Sep 21, 2008 at 6:30 AM, Johannes Berg
<johannes@xxxxxxxxxxxxxxxx> wrote:
> From: Li YanBo <dreamfly281@xxxxxxxxx>
>
> Currently the mesh code doesn't support bridging mesh point interfaces
> with wired ethernet or AP to construct an MPP or MAP. This patch adds
> code to support the "6 address frame format packet" functionality to
> mesh point interfaces. Now the mesh network can be used as backhaul
> for end to end communication.
>
> Signed-off-by: Li YanBo <dreamfly281@xxxxxxxxx>
> Signed-off-by: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
> ---
>  include/linux/ieee80211.h   |    5 ++
>  net/mac80211/mesh.h         |    3 +
>  net/mac80211/mesh_pathtbl.c |  129 ++++++++++++++++++++++++++++++++++++++++++-
>  net/mac80211/rx.c           |   32 +++++++++-
>  net/mac80211/tx.c           |   45 +++++++++++++--
>  5 files changed, 202 insertions(+), 12 deletions(-)
>
> diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
> index abc1abc..db1bb0c 100644
> --- a/include/linux/ieee80211.h
> +++ b/include/linux/ieee80211.h
> @@ -471,6 +471,11 @@ struct ieee80211s_hdr {
>        u8 eaddr3[6];
>  } __attribute__ ((packed));
>
> +/* Mesh extent address flags */
> +#define MESH_DATA_NO_EADDR     0x0
> +#define MESH_DATA_EADD1_EADD2  0x2

Just for consistency with the draft I suggest adding/renaming:

#define MESH_AE_ADD4                         0x1
#define MESH_AE_ADD5_ADD6              0x2
#define MESH_AE_ADD4_ADD5_ADD6  0x3

> +
> +
>  /**
>  * struct ieee80211_quiet_ie
>  *
> diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
> index 8ee414a..5b18d2b 100644
> --- a/net/mac80211/mesh.h
> +++ b/net/mac80211/mesh.h
> @@ -71,6 +71,7 @@ enum mesh_path_flags {
>  */
>  struct mesh_path {
>        u8 dst[ETH_ALEN];
> +       u8 mpp[ETH_ALEN];       /* used for MPP or MAP */
>        struct ieee80211_sub_if_data *sdata;
>        struct sta_info *next_hop;
>        struct timer_list timer;
> @@ -226,6 +227,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
>  void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
>  struct mesh_path *mesh_path_lookup(u8 *dst,
>                struct ieee80211_sub_if_data *sdata);
> +struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata);
> +int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata);
>  struct mesh_path *mesh_path_lookup_by_idx(int idx,
>                struct ieee80211_sub_if_data *sdata);
>  void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
> diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
> index e4fa290..f202eac 100644
> --- a/net/mac80211/mesh_pathtbl.c
> +++ b/net/mac80211/mesh_pathtbl.c
> @@ -36,6 +36,7 @@ struct mpath_node {
>  };
>
>  static struct mesh_table *mesh_paths;
> +static struct mesh_table *mpp_paths; /* Store pathes for MPP&MAP */
>
>  /* This lock will have the grow table function as writer and add / delete nodes
>  * as readers. When reading the table (i.e. doing lookups) we are well protected
> @@ -94,6 +95,34 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
>        return NULL;
>  }
>
> +struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
> +{
> +       struct mesh_path *mpath;
> +       struct hlist_node *n;
> +       struct hlist_head *bucket;
> +       struct mesh_table *tbl;
> +       struct mpath_node *node;
> +
> +       tbl = rcu_dereference(mpp_paths);
> +
> +       bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
> +       hlist_for_each_entry_rcu(node, n, bucket, list) {
> +               mpath = node->mpath;
> +               if (mpath->sdata == sdata &&
> +                   memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
> +                       if (MPATH_EXPIRED(mpath)) {
> +                               spin_lock_bh(&mpath->state_lock);
> +                               if (MPATH_EXPIRED(mpath))
> +                                       mpath->flags &= ~MESH_PATH_ACTIVE;
> +                               spin_unlock_bh(&mpath->state_lock);
> +                       }
> +                       return mpath;
> +               }
> +       }
> +       return NULL;
> +}
> +
> +
>  /**
>  * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
>  * @idx: index
> @@ -226,6 +255,91 @@ err_path_alloc:
>  }
>
>
> +int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
> +{
> +       struct mesh_path *mpath, *new_mpath;
> +       struct mpath_node *node, *new_node;
> +       struct hlist_head *bucket;
> +       struct hlist_node *n;
> +       int grow = 0;
> +       int err = 0;
> +       u32 hash_idx;
> +
> +
> +       if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
> +               /* never add ourselves as neighbours */
> +               return -ENOTSUPP;
> +
> +       if (is_multicast_ether_addr(dst))
> +               return -ENOTSUPP;
> +
> +       err = -ENOMEM;
> +       new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
> +       if (!new_mpath)
> +               goto err_path_alloc;
> +
> +       new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
> +       if (!new_node)
> +               goto err_node_alloc;
> +
> +       read_lock(&pathtbl_resize_lock);
> +       memcpy(new_mpath->dst, dst, ETH_ALEN);
> +       memcpy(new_mpath->mpp, mpp, ETH_ALEN);
> +       new_mpath->sdata = sdata;
> +       new_mpath->flags = 0;
> +       skb_queue_head_init(&new_mpath->frame_queue);
> +       new_node->mpath = new_mpath;
> +       new_mpath->exp_time = jiffies;
> +       spin_lock_init(&new_mpath->state_lock);
> +
> +       hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
> +       bucket = &mpp_paths->hash_buckets[hash_idx];
> +
> +       spin_lock(&mpp_paths->hashwlock[hash_idx]);
> +
> +       err = -EEXIST;
> +       hlist_for_each_entry(node, n, bucket, list) {
> +               mpath = node->mpath;
> +               if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
> +                       goto err_exists;
> +       }
> +
> +       hlist_add_head_rcu(&new_node->list, bucket);
> +       if (atomic_inc_return(&mpp_paths->entries) >=
> +               mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
> +               grow = 1;
> +
> +       spin_unlock(&mpp_paths->hashwlock[hash_idx]);
> +       read_unlock(&pathtbl_resize_lock);
> +       if (grow) {
> +               struct mesh_table *oldtbl, *newtbl;
> +
> +               write_lock(&pathtbl_resize_lock);
> +               oldtbl = mpp_paths;
> +               newtbl = mesh_table_grow(mpp_paths);
> +               if (!newtbl) {
> +                       write_unlock(&pathtbl_resize_lock);
> +                       return 0;
> +               }
> +               rcu_assign_pointer(mpp_paths, newtbl);
> +               write_unlock(&pathtbl_resize_lock);
> +
> +               synchronize_rcu();
> +               mesh_table_free(oldtbl, false);
> +       }
> +       return 0;
> +
> +err_exists:
> +       spin_unlock(&mpp_paths->hashwlock[hash_idx]);
> +       read_unlock(&pathtbl_resize_lock);
> +       kfree(new_node);
> +err_node_alloc:
> +       kfree(new_mpath);
> +err_path_alloc:
> +       return err;
> +}
> +
> +
>  /**
>  * mesh_plink_broken - deactivates paths and sends perr when a link breaks
>  *
> @@ -475,11 +589,21 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
>  int mesh_pathtbl_init(void)
>  {
>        mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
> +       if (!mesh_paths)
> +               return -ENOMEM;
>        mesh_paths->free_node = &mesh_path_node_free;
>        mesh_paths->copy_node = &mesh_path_node_copy;
>        mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
> -       if (!mesh_paths)
> -               return -ENOMEM;
> +
> +       mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
> +       if (!mpp_paths) {
> +               mesh_table_free(mesh_paths, true);
> +               return -ENOMEM;
> +       }
> +       mpp_paths->free_node = &mesh_path_node_free;
> +       mpp_paths->copy_node = &mesh_path_node_copy;
> +       mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
> +
>        return 0;
>  }
>
> @@ -511,4 +635,5 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
>  void mesh_pathtbl_unregister(void)
>  {
>        mesh_table_free(mesh_paths, true);
> +       mesh_table_free(mpp_paths, true);
>  }
> diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
> index 763c7ea..ff7e813 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1112,10 +1112,6 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
>
>        hdrlen = ieee80211_hdrlen(hdr->frame_control);
>
> -       if (ieee80211_vif_is_mesh(&sdata->vif))
> -               hdrlen += ieee80211_get_mesh_hdrlen(
> -                               (struct ieee80211s_hdr *) (skb->data + hdrlen));
> -
>        /* convert IEEE 802.11 header + possible LLC headers into Ethernet
>         * header
>         * IEEE 802.11 address fields:
> @@ -1139,6 +1135,15 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
>                if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
>                             sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
>                        return -1;
> +               if (ieee80211_vif_is_mesh(&sdata->vif)) {
> +                       struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
> +                               (skb->data + hdrlen);
> +                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
> +                       if (meshdr->flags == MESH_DATA_EADD1_EADD2) {
> +                               memcpy(dst, meshdr->eaddr1, ETH_ALEN);
> +                               memcpy(src, meshdr->eaddr2, ETH_ALEN);
> +                       }
> +               }
>                break;
>        case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
>                if (sdata->vif.type != NL80211_IFTYPE_STATION ||
> @@ -1398,6 +1403,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
>                /* illegal frame */
>                return RX_DROP_MONITOR;
>
> +       if (mesh_hdr->flags == MESH_DATA_EADD1_EADD2){

There are other assigned and reserved bits in the flags field.  It's
probably better to do...

 +       if ((mesh_hdr->flags & IEEE80211S_FLAGS_AE) == MESH_DATA_EADD1_EADD2){

> +               struct ieee80211_sub_if_data *sdata;
> +               struct mesh_path *mppath;
> +
> +               sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
> +               rcu_read_lock();
> +               mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
> +               if (!mppath) {
> +                       mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
> +               } else {
> +                       spin_lock_bh(&mppath->state_lock);
> +                       mppath->exp_time = jiffies;
> +                       if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
> +                               memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
> +                       spin_unlock_bh(&mppath->state_lock);
> +               }
> +               rcu_read_unlock();
> +       }
> +
>        if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
>                return RX_CONTINUE;
>
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index 20d6836..e1e11dc 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -1498,18 +1498,51 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
>  #ifdef CONFIG_MAC80211_MESH
>        case NL80211_IFTYPE_MESH_POINT:
>                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
> -               /* RA TA DA SA */
> -               memset(hdr.addr1, 0, ETH_ALEN);
> -               memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
> -               memcpy(hdr.addr3, skb->data, ETH_ALEN);
> -               memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
> +
>                if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
>                        /* Do not send frames with mesh_ttl == 0 */
>                        sdata->u.mesh.mshstats.dropped_frames_ttl++;
>                        ret = 0;
>                        goto fail;
>                }
> -               meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
> +               if (compare_ether_addr(dev->dev_addr,
> +                                         skb->data + ETH_ALEN) == 0) {
> +                       /* RA TA DA SA */
> +                       memset(hdr.addr1, 0, ETH_ALEN);
> +                       memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
> +                       memcpy(hdr.addr3, skb->data, ETH_ALEN);
> +                       memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
> +                       meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
> +               } else {
> +                       /* packet from other interface */
> +                       struct mesh_path *mppath;
> +                       u8 broadcast[ETH_ALEN] = {0xFF, 0xFF, 0xFF,
> +                                                 0xFF, 0xFF, 0xFF};
> +
> +                       memset(hdr.addr1, 0, ETH_ALEN);
> +                       memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
> +                       memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
> +
> +                       if (is_multicast_ether_addr(skb->data))
> +                               memcpy(hdr.addr3, skb->data, ETH_ALEN);
> +                       else {
> +                               rcu_read_lock();
> +                               mppath = mpp_path_lookup(skb->data, sdata);
> +                               if (mppath)
> +                                       memcpy(hdr.addr3, mppath->mpp, ETH_ALEN);
> +                               else
> +                                       memcpy(hdr.addr3, broadcast, ETH_ALEN);
> +                               rcu_read_unlock();
> +                       }
> +
> +                       mesh_hdr.flags = MESH_DATA_EADD1_EADD2;
> +                       mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
> +                       put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
> +                       memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
> +                       memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
> +                       sdata->u.mesh.mesh_seqnum++;
> +                       meshhdrlen = 18;
> +               }
>                hdrlen = 30;
>                break;
>  #endif
>
>
>

Cheers,

Javier
--
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