aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYanBo <dreamfly281@gmail.com>2008-09-22 01:30:32 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-24 16:18:02 -0400
commit79617deeebb9cf089e2bc2aad19743b1209043f6 (patch)
tree52c93b45d07ce3cd5c78be743446068602e90234
parent31e9ab2b180bccb3977b9a82ff357ac4c6ee3c83 (diff)
mac80211: mesh portal functionality support
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@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/ieee80211.h5
-rw-r--r--net/mac80211/mesh.h4
-rw-r--r--net/mac80211/mesh_pathtbl.c127
-rw-r--r--net/mac80211/rx.c32
-rw-r--r--net/mac80211/tx.c44
5 files changed, 201 insertions, 11 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index abc1abc63bf0..14126bc36641 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -471,6 +471,11 @@ struct ieee80211s_hdr {
471 u8 eaddr3[6]; 471 u8 eaddr3[6];
472} __attribute__ ((packed)); 472} __attribute__ ((packed));
473 473
474/* Mesh flags */
475#define MESH_FLAGS_AE_A4 0x1
476#define MESH_FLAGS_AE_A5_A6 0x2
477#define MESH_FLAGS_PS_DEEP 0x4
478
474/** 479/**
475 * struct ieee80211_quiet_ie 480 * struct ieee80211_quiet_ie
476 * 481 *
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 8ee414a0447c..e10471c6ba42 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -71,6 +71,7 @@ enum mesh_path_flags {
71 */ 71 */
72struct mesh_path { 72struct mesh_path {
73 u8 dst[ETH_ALEN]; 73 u8 dst[ETH_ALEN];
74 u8 mpp[ETH_ALEN]; /* used for MPP or MAP */
74 struct ieee80211_sub_if_data *sdata; 75 struct ieee80211_sub_if_data *sdata;
75 struct sta_info *next_hop; 76 struct sta_info *next_hop;
76 struct timer_list timer; 77 struct timer_list timer;
@@ -226,6 +227,9 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
226void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); 227void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata);
227struct mesh_path *mesh_path_lookup(u8 *dst, 228struct mesh_path *mesh_path_lookup(u8 *dst,
228 struct ieee80211_sub_if_data *sdata); 229 struct ieee80211_sub_if_data *sdata);
230struct mesh_path *mpp_path_lookup(u8 *dst,
231 struct ieee80211_sub_if_data *sdata);
232int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata);
229struct mesh_path *mesh_path_lookup_by_idx(int idx, 233struct mesh_path *mesh_path_lookup_by_idx(int idx,
230 struct ieee80211_sub_if_data *sdata); 234 struct ieee80211_sub_if_data *sdata);
231void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); 235void 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 e4fa2905fadc..3c72557df45a 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -36,6 +36,7 @@ struct mpath_node {
36}; 36};
37 37
38static struct mesh_table *mesh_paths; 38static struct mesh_table *mesh_paths;
39static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
39 40
40/* This lock will have the grow table function as writer and add / delete nodes 41/* This lock will have the grow table function as writer and add / delete nodes
41 * as readers. When reading the table (i.e. doing lookups) we are well protected 42 * 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)
94 return NULL; 95 return NULL;
95} 96}
96 97
98struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
99{
100 struct mesh_path *mpath;
101 struct hlist_node *n;
102 struct hlist_head *bucket;
103 struct mesh_table *tbl;
104 struct mpath_node *node;
105
106 tbl = rcu_dereference(mpp_paths);
107
108 bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)];
109 hlist_for_each_entry_rcu(node, n, bucket, list) {
110 mpath = node->mpath;
111 if (mpath->sdata == sdata &&
112 memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
113 if (MPATH_EXPIRED(mpath)) {
114 spin_lock_bh(&mpath->state_lock);
115 if (MPATH_EXPIRED(mpath))
116 mpath->flags &= ~MESH_PATH_ACTIVE;
117 spin_unlock_bh(&mpath->state_lock);
118 }
119 return mpath;
120 }
121 }
122 return NULL;
123}
124
125
97/** 126/**
98 * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index 127 * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
99 * @idx: index 128 * @idx: index
@@ -226,6 +255,91 @@ err_path_alloc:
226} 255}
227 256
228 257
258int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
259{
260 struct mesh_path *mpath, *new_mpath;
261 struct mpath_node *node, *new_node;
262 struct hlist_head *bucket;
263 struct hlist_node *n;
264 int grow = 0;
265 int err = 0;
266 u32 hash_idx;
267
268
269 if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
270 /* never add ourselves as neighbours */
271 return -ENOTSUPP;
272
273 if (is_multicast_ether_addr(dst))
274 return -ENOTSUPP;
275
276 err = -ENOMEM;
277 new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
278 if (!new_mpath)
279 goto err_path_alloc;
280
281 new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
282 if (!new_node)
283 goto err_node_alloc;
284
285 read_lock(&pathtbl_resize_lock);
286 memcpy(new_mpath->dst, dst, ETH_ALEN);
287 memcpy(new_mpath->mpp, mpp, ETH_ALEN);
288 new_mpath->sdata = sdata;
289 new_mpath->flags = 0;
290 skb_queue_head_init(&new_mpath->frame_queue);
291 new_node->mpath = new_mpath;
292 new_mpath->exp_time = jiffies;
293 spin_lock_init(&new_mpath->state_lock);
294
295 hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
296 bucket = &mpp_paths->hash_buckets[hash_idx];
297
298 spin_lock(&mpp_paths->hashwlock[hash_idx]);
299
300 err = -EEXIST;
301 hlist_for_each_entry(node, n, bucket, list) {
302 mpath = node->mpath;
303 if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
304 goto err_exists;
305 }
306
307 hlist_add_head_rcu(&new_node->list, bucket);
308 if (atomic_inc_return(&mpp_paths->entries) >=
309 mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
310 grow = 1;
311
312 spin_unlock(&mpp_paths->hashwlock[hash_idx]);
313 read_unlock(&pathtbl_resize_lock);
314 if (grow) {
315 struct mesh_table *oldtbl, *newtbl;
316
317 write_lock(&pathtbl_resize_lock);
318 oldtbl = mpp_paths;
319 newtbl = mesh_table_grow(mpp_paths);
320 if (!newtbl) {
321 write_unlock(&pathtbl_resize_lock);
322 return 0;
323 }
324 rcu_assign_pointer(mpp_paths, newtbl);
325 write_unlock(&pathtbl_resize_lock);
326
327 synchronize_rcu();
328 mesh_table_free(oldtbl, false);
329 }
330 return 0;
331
332err_exists:
333 spin_unlock(&mpp_paths->hashwlock[hash_idx]);
334 read_unlock(&pathtbl_resize_lock);
335 kfree(new_node);
336err_node_alloc:
337 kfree(new_mpath);
338err_path_alloc:
339 return err;
340}
341
342
229/** 343/**
230 * mesh_plink_broken - deactivates paths and sends perr when a link breaks 344 * mesh_plink_broken - deactivates paths and sends perr when a link breaks
231 * 345 *
@@ -475,11 +589,21 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
475int mesh_pathtbl_init(void) 589int mesh_pathtbl_init(void)
476{ 590{
477 mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); 591 mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
592 if (!mesh_paths)
593 return -ENOMEM;
478 mesh_paths->free_node = &mesh_path_node_free; 594 mesh_paths->free_node = &mesh_path_node_free;
479 mesh_paths->copy_node = &mesh_path_node_copy; 595 mesh_paths->copy_node = &mesh_path_node_copy;
480 mesh_paths->mean_chain_len = MEAN_CHAIN_LEN; 596 mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
481 if (!mesh_paths) 597
598 mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
599 if (!mpp_paths) {
600 mesh_table_free(mesh_paths, true);
482 return -ENOMEM; 601 return -ENOMEM;
602 }
603 mpp_paths->free_node = &mesh_path_node_free;
604 mpp_paths->copy_node = &mesh_path_node_copy;
605 mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
606
483 return 0; 607 return 0;
484} 608}
485 609
@@ -511,4 +635,5 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
511void mesh_pathtbl_unregister(void) 635void mesh_pathtbl_unregister(void)
512{ 636{
513 mesh_table_free(mesh_paths, true); 637 mesh_table_free(mesh_paths, true);
638 mesh_table_free(mpp_paths, true);
514} 639}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 3ab9670f1809..2efa4dd47b5d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1107,10 +1107,6 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
1107 1107
1108 hdrlen = ieee80211_hdrlen(hdr->frame_control); 1108 hdrlen = ieee80211_hdrlen(hdr->frame_control);
1109 1109
1110 if (ieee80211_vif_is_mesh(&sdata->vif))
1111 hdrlen += ieee80211_get_mesh_hdrlen(
1112 (struct ieee80211s_hdr *) (skb->data + hdrlen));
1113
1114 /* convert IEEE 802.11 header + possible LLC headers into Ethernet 1110 /* convert IEEE 802.11 header + possible LLC headers into Ethernet
1115 * header 1111 * header
1116 * IEEE 802.11 address fields: 1112 * IEEE 802.11 address fields:
@@ -1134,6 +1130,15 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
1134 if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS && 1130 if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS &&
1135 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) 1131 sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
1136 return -1; 1132 return -1;
1133 if (ieee80211_vif_is_mesh(&sdata->vif)) {
1134 struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *)
1135 (skb->data + hdrlen);
1136 hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
1137 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
1138 memcpy(dst, meshdr->eaddr1, ETH_ALEN);
1139 memcpy(src, meshdr->eaddr2, ETH_ALEN);
1140 }
1141 }
1137 break; 1142 break;
1138 case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS): 1143 case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
1139 if (sdata->vif.type != NL80211_IFTYPE_STATION || 1144 if (sdata->vif.type != NL80211_IFTYPE_STATION ||
@@ -1393,6 +1398,25 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1393 /* illegal frame */ 1398 /* illegal frame */
1394 return RX_DROP_MONITOR; 1399 return RX_DROP_MONITOR;
1395 1400
1401 if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
1402 struct ieee80211_sub_if_data *sdata;
1403 struct mesh_path *mppath;
1404
1405 sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
1406 rcu_read_lock();
1407 mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
1408 if (!mppath) {
1409 mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata);
1410 } else {
1411 spin_lock_bh(&mppath->state_lock);
1412 mppath->exp_time = jiffies;
1413 if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0)
1414 memcpy(mppath->mpp, hdr->addr4, ETH_ALEN);
1415 spin_unlock_bh(&mppath->state_lock);
1416 }
1417 rcu_read_unlock();
1418 }
1419
1396 if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) 1420 if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
1397 return RX_CONTINUE; 1421 return RX_CONTINUE;
1398 1422
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 00d798cc9e04..00d96e63dce9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1498,18 +1498,50 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
1498#ifdef CONFIG_MAC80211_MESH 1498#ifdef CONFIG_MAC80211_MESH
1499 case NL80211_IFTYPE_MESH_POINT: 1499 case NL80211_IFTYPE_MESH_POINT:
1500 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); 1500 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
1501 /* RA TA DA SA */
1502 memset(hdr.addr1, 0, ETH_ALEN);
1503 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
1504 memcpy(hdr.addr3, skb->data, ETH_ALEN);
1505 memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
1506 if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { 1501 if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
1507 /* Do not send frames with mesh_ttl == 0 */ 1502 /* Do not send frames with mesh_ttl == 0 */
1508 sdata->u.mesh.mshstats.dropped_frames_ttl++; 1503 sdata->u.mesh.mshstats.dropped_frames_ttl++;
1509 ret = 0; 1504 ret = 0;
1510 goto fail; 1505 goto fail;
1511 } 1506 }
1512 meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata); 1507 memset(&mesh_hdr, 0, sizeof(mesh_hdr));
1508
1509 if (compare_ether_addr(dev->dev_addr,
1510 skb->data + ETH_ALEN) == 0) {
1511 /* RA TA DA SA */
1512 memset(hdr.addr1, 0, ETH_ALEN);
1513 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
1514 memcpy(hdr.addr3, skb->data, ETH_ALEN);
1515 memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
1516 meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
1517 } else {
1518 /* packet from other interface */
1519 struct mesh_path *mppath;
1520
1521 memset(hdr.addr1, 0, ETH_ALEN);
1522 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
1523 memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
1524
1525 if (is_multicast_ether_addr(skb->data))
1526 memcpy(hdr.addr3, skb->data, ETH_ALEN);
1527 else {
1528 rcu_read_lock();
1529 mppath = mpp_path_lookup(skb->data, sdata);
1530 if (mppath)
1531 memcpy(hdr.addr3, mppath->mpp, ETH_ALEN);
1532 else
1533 memset(hdr.addr3, 0xff, ETH_ALEN);
1534 rcu_read_unlock();
1535 }
1536
1537 mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6;
1538 mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
1539 put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
1540 memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
1541 memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
1542 sdata->u.mesh.mesh_seqnum++;
1543 meshhdrlen = 18;
1544 }
1513 hdrlen = 30; 1545 hdrlen = 30;
1514 break; 1546 break;
1515#endif 1547#endif