Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

YanBo and committed by
John W. Linville
79617dee 31e9ab2b

+201 -11
+5
include/linux/ieee80211.h
··· 471 471 u8 eaddr3[6]; 472 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 480 * struct ieee80211_quiet_ie 476 481 *
+4
net/mac80211/mesh.h
··· 71 71 */ 72 72 struct mesh_path { 73 73 u8 dst[ETH_ALEN]; 74 + u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ 74 75 struct ieee80211_sub_if_data *sdata; 75 76 struct sta_info *next_hop; 76 77 struct timer_list timer; ··· 227 226 void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); 228 227 struct mesh_path *mesh_path_lookup(u8 *dst, 229 228 struct ieee80211_sub_if_data *sdata); 229 + struct mesh_path *mpp_path_lookup(u8 *dst, 230 + struct ieee80211_sub_if_data *sdata); 231 + int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); 230 232 struct mesh_path *mesh_path_lookup_by_idx(int idx, 231 233 struct ieee80211_sub_if_data *sdata); 232 234 void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
+126 -1
net/mac80211/mesh_pathtbl.c
··· 36 36 }; 37 37 38 38 static struct mesh_table *mesh_paths; 39 + static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */ 39 40 40 41 /* This lock will have the grow table function as writer and add / delete nodes 41 42 * as readers. When reading the table (i.e. doing lookups) we are well protected ··· 94 93 } 95 94 return NULL; 96 95 } 96 + 97 + struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata) 98 + { 99 + struct mesh_path *mpath; 100 + struct hlist_node *n; 101 + struct hlist_head *bucket; 102 + struct mesh_table *tbl; 103 + struct mpath_node *node; 104 + 105 + tbl = rcu_dereference(mpp_paths); 106 + 107 + bucket = &tbl->hash_buckets[mesh_table_hash(dst, sdata, tbl)]; 108 + hlist_for_each_entry_rcu(node, n, bucket, list) { 109 + mpath = node->mpath; 110 + if (mpath->sdata == sdata && 111 + memcmp(dst, mpath->dst, ETH_ALEN) == 0) { 112 + if (MPATH_EXPIRED(mpath)) { 113 + spin_lock_bh(&mpath->state_lock); 114 + if (MPATH_EXPIRED(mpath)) 115 + mpath->flags &= ~MESH_PATH_ACTIVE; 116 + spin_unlock_bh(&mpath->state_lock); 117 + } 118 + return mpath; 119 + } 120 + } 121 + return NULL; 122 + } 123 + 97 124 98 125 /** 99 126 * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index ··· 251 222 kfree(new_mpath); 252 223 err_path_alloc: 253 224 atomic_dec(&sdata->u.mesh.mpaths); 225 + return err; 226 + } 227 + 228 + 229 + int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata) 230 + { 231 + struct mesh_path *mpath, *new_mpath; 232 + struct mpath_node *node, *new_node; 233 + struct hlist_head *bucket; 234 + struct hlist_node *n; 235 + int grow = 0; 236 + int err = 0; 237 + u32 hash_idx; 238 + 239 + 240 + if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0) 241 + /* never add ourselves as neighbours */ 242 + return -ENOTSUPP; 243 + 244 + if (is_multicast_ether_addr(dst)) 245 + return -ENOTSUPP; 246 + 247 + err = -ENOMEM; 248 + new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); 249 + if (!new_mpath) 250 + goto err_path_alloc; 251 + 252 + new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); 253 + if (!new_node) 254 + goto err_node_alloc; 255 + 256 + read_lock(&pathtbl_resize_lock); 257 + memcpy(new_mpath->dst, dst, ETH_ALEN); 258 + memcpy(new_mpath->mpp, mpp, ETH_ALEN); 259 + new_mpath->sdata = sdata; 260 + new_mpath->flags = 0; 261 + skb_queue_head_init(&new_mpath->frame_queue); 262 + new_node->mpath = new_mpath; 263 + new_mpath->exp_time = jiffies; 264 + spin_lock_init(&new_mpath->state_lock); 265 + 266 + hash_idx = mesh_table_hash(dst, sdata, mpp_paths); 267 + bucket = &mpp_paths->hash_buckets[hash_idx]; 268 + 269 + spin_lock(&mpp_paths->hashwlock[hash_idx]); 270 + 271 + err = -EEXIST; 272 + hlist_for_each_entry(node, n, bucket, list) { 273 + mpath = node->mpath; 274 + if (mpath->sdata == sdata && memcmp(dst, mpath->dst, ETH_ALEN) == 0) 275 + goto err_exists; 276 + } 277 + 278 + hlist_add_head_rcu(&new_node->list, bucket); 279 + if (atomic_inc_return(&mpp_paths->entries) >= 280 + mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1)) 281 + grow = 1; 282 + 283 + spin_unlock(&mpp_paths->hashwlock[hash_idx]); 284 + read_unlock(&pathtbl_resize_lock); 285 + if (grow) { 286 + struct mesh_table *oldtbl, *newtbl; 287 + 288 + write_lock(&pathtbl_resize_lock); 289 + oldtbl = mpp_paths; 290 + newtbl = mesh_table_grow(mpp_paths); 291 + if (!newtbl) { 292 + write_unlock(&pathtbl_resize_lock); 293 + return 0; 294 + } 295 + rcu_assign_pointer(mpp_paths, newtbl); 296 + write_unlock(&pathtbl_resize_lock); 297 + 298 + synchronize_rcu(); 299 + mesh_table_free(oldtbl, false); 300 + } 301 + return 0; 302 + 303 + err_exists: 304 + spin_unlock(&mpp_paths->hashwlock[hash_idx]); 305 + read_unlock(&pathtbl_resize_lock); 306 + kfree(new_node); 307 + err_node_alloc: 308 + kfree(new_mpath); 309 + err_path_alloc: 254 310 return err; 255 311 } 256 312 ··· 589 475 int mesh_pathtbl_init(void) 590 476 { 591 477 mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); 478 + if (!mesh_paths) 479 + return -ENOMEM; 592 480 mesh_paths->free_node = &mesh_path_node_free; 593 481 mesh_paths->copy_node = &mesh_path_node_copy; 594 482 mesh_paths->mean_chain_len = MEAN_CHAIN_LEN; 595 - if (!mesh_paths) 483 + 484 + mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); 485 + if (!mpp_paths) { 486 + mesh_table_free(mesh_paths, true); 596 487 return -ENOMEM; 488 + } 489 + mpp_paths->free_node = &mesh_path_node_free; 490 + mpp_paths->copy_node = &mesh_path_node_copy; 491 + mpp_paths->mean_chain_len = MEAN_CHAIN_LEN; 492 + 597 493 return 0; 598 494 } 599 495 ··· 635 511 void mesh_pathtbl_unregister(void) 636 512 { 637 513 mesh_table_free(mesh_paths, true); 514 + mesh_table_free(mpp_paths, true); 638 515 }
+28 -4
net/mac80211/rx.c
··· 1107 1107 1108 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 1110 /* convert IEEE 802.11 header + possible LLC headers into Ethernet 1115 1111 * header 1116 1112 * IEEE 802.11 address fields: ··· 1130 1134 if (unlikely(sdata->vif.type != NL80211_IFTYPE_WDS && 1131 1135 sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) 1132 1136 return -1; 1137 + if (ieee80211_vif_is_mesh(&sdata->vif)) { 1138 + struct ieee80211s_hdr *meshdr = (struct ieee80211s_hdr *) 1139 + (skb->data + hdrlen); 1140 + hdrlen += ieee80211_get_mesh_hdrlen(meshdr); 1141 + if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { 1142 + memcpy(dst, meshdr->eaddr1, ETH_ALEN); 1143 + memcpy(src, meshdr->eaddr2, ETH_ALEN); 1144 + } 1145 + } 1133 1146 break; 1134 1147 case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS): 1135 1148 if (sdata->vif.type != NL80211_IFTYPE_STATION || ··· 1397 1392 if (!mesh_hdr->ttl) 1398 1393 /* illegal frame */ 1399 1394 return RX_DROP_MONITOR; 1395 + 1396 + if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ 1397 + struct ieee80211_sub_if_data *sdata; 1398 + struct mesh_path *mppath; 1399 + 1400 + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); 1401 + rcu_read_lock(); 1402 + mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata); 1403 + if (!mppath) { 1404 + mpp_path_add(mesh_hdr->eaddr2, hdr->addr4, sdata); 1405 + } else { 1406 + spin_lock_bh(&mppath->state_lock); 1407 + mppath->exp_time = jiffies; 1408 + if (compare_ether_addr(mppath->mpp, hdr->addr4) != 0) 1409 + memcpy(mppath->mpp, hdr->addr4, ETH_ALEN); 1410 + spin_unlock_bh(&mppath->state_lock); 1411 + } 1412 + rcu_read_unlock(); 1413 + } 1400 1414 1401 1415 if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) 1402 1416 return RX_CONTINUE;
+38 -6
net/mac80211/tx.c
··· 1498 1498 #ifdef CONFIG_MAC80211_MESH 1499 1499 case NL80211_IFTYPE_MESH_POINT: 1500 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 1501 if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { 1507 1502 /* Do not send frames with mesh_ttl == 0 */ 1508 1503 sdata->u.mesh.mshstats.dropped_frames_ttl++; 1509 1504 ret = 0; 1510 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 1545 hdrlen = 30; 1514 1546 break; 1515 1547 #endif