aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Cardona <javier@cozybit.com>2009-08-10 15:15:48 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:14:00 -0400
commit3c5772a5279de9eadfff7adb5ddea08106495fff (patch)
tree297772521c18283ccfa19aacb090f396fa2b399e
parenta9e3091bf08ddea35f172549a8a21d5bd6ee6129 (diff)
mac80211: Use 3-address format for mesh broadcast frames.
The 11s task group recently changed the frame mesh multicast/broadcast frame format to use 3-address. This was done to avoid interactions with widely deployed lazy-WDS access points. This patch changes the format of group addressed frames, both mesh-originated and proxied, to use the data format defined in draft D2.08 and forward. The address fields used for group addressed frames is: In 802.11 header ToDS:0 FromDS:1 addr1: DA (broadcast/multicast address) addr2: TA addr3: Mesh SA In address extension header: addr4: SA (only present if frame was proxied) Note that this change breaks backward compatibility with earlier mesh stack versions. Signed-off-by: Andrey Yurovsky <andrey@cozybit.com> Signed-off-by: Javier Cardona <javier@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/mesh.c62
-rw-r--r--net/mac80211/mesh.h5
-rw-r--r--net/mac80211/rx.c45
-rw-r--r--net/mac80211/tx.c64
-rw-r--r--net/wireless/util.c16
5 files changed, 136 insertions, 56 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8c068e215fb..10d93386042 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -399,21 +399,75 @@ endgrow:
399} 399}
400 400
401/** 401/**
402 * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
403 * @hdr: 802.11 frame header
404 * @fc: frame control field
405 * @meshda: destination address in the mesh
406 * @meshsa: source address address in the mesh. Same as TA, as frame is
407 * locally originated.
408 *
409 * Return the length of the 802.11 (does not include a mesh control header)
410 */
411int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
412 *meshda, char *meshsa) {
413 if (is_multicast_ether_addr(meshda)) {
414 *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
415 /* DA TA SA */
416 memcpy(hdr->addr1, meshda, ETH_ALEN);
417 memcpy(hdr->addr2, meshsa, ETH_ALEN);
418 memcpy(hdr->addr3, meshsa, ETH_ALEN);
419 return 24;
420 } else {
421 *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
422 IEEE80211_FCTL_TODS);
423 /* RA TA DA SA */
424 memset(hdr->addr1, 0, ETH_ALEN); /* RA is resolved later */
425 memcpy(hdr->addr2, meshsa, ETH_ALEN);
426 memcpy(hdr->addr3, meshda, ETH_ALEN);
427 memcpy(hdr->addr4, meshsa, ETH_ALEN);
428 return 30;
429 }
430}
431
432/**
402 * ieee80211_new_mesh_header - create a new mesh header 433 * ieee80211_new_mesh_header - create a new mesh header
403 * @meshhdr: uninitialized mesh header 434 * @meshhdr: uninitialized mesh header
404 * @sdata: mesh interface to be used 435 * @sdata: mesh interface to be used
436 * @addr4: addr4 of the mesh frame (1st in ae header)
437 * may be NULL
438 * @addr5: addr5 of the mesh frame (1st or 2nd in ae header)
439 * may be NULL unless addr6 is present
440 * @addr6: addr6 of the mesh frame (2nd or 3rd in ae header)
441 * may be NULL unless addr5 is present
405 * 442 *
406 * Return the header length. 443 * Return the header length.
407 */ 444 */
408int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, 445int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
409 struct ieee80211_sub_if_data *sdata) 446 struct ieee80211_sub_if_data *sdata, char *addr4,
447 char *addr5, char *addr6)
410{ 448{
411 meshhdr->flags = 0; 449 int aelen = 0;
450 memset(meshhdr, 0, sizeof(meshhdr));
412 meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; 451 meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
413 put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); 452 put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
414 sdata->u.mesh.mesh_seqnum++; 453 sdata->u.mesh.mesh_seqnum++;
415 454 if (addr4) {
416 return 6; 455 meshhdr->flags |= MESH_FLAGS_AE_A4;
456 aelen += ETH_ALEN;
457 memcpy(meshhdr->eaddr1, addr4, ETH_ALEN);
458 }
459 if (addr5 && addr6) {
460 meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
461 aelen += 2 * ETH_ALEN;
462 if (!addr4) {
463 memcpy(meshhdr->eaddr1, addr5, ETH_ALEN);
464 memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
465 } else {
466 memcpy(meshhdr->eaddr2, addr5, ETH_ALEN);
467 memcpy(meshhdr->eaddr3, addr6, ETH_ALEN);
468 }
469 }
470 return 6 + aelen;
417} 471}
418 472
419static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, 473static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 6aaf1ecbcb6..2ebd74cb038 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -193,8 +193,11 @@ struct mesh_rmc {
193 193
194/* Public interfaces */ 194/* Public interfaces */
195/* Various */ 195/* Various */
196int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
197 char *da, char *sa);
196int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, 198int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
197 struct ieee80211_sub_if_data *sdata); 199 struct ieee80211_sub_if_data *sdata, char *addr4,
200 char *addr5, char *addr6);
198int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, 201int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
199 struct ieee80211_sub_if_data *sdata); 202 struct ieee80211_sub_if_data *sdata);
200bool mesh_matches_local(struct ieee802_11_elems *ie, 203bool mesh_matches_local(struct ieee802_11_elems *ie,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 25a669c86e1..4cd9e45b144 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
489{ 489{
490 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; 490 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
491 unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); 491 unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
492 char *dev_addr = rx->dev->dev_addr;
492 493
493 if (ieee80211_is_data(hdr->frame_control)) { 494 if (ieee80211_is_data(hdr->frame_control)) {
494 if (!ieee80211_has_a4(hdr->frame_control)) 495 if (is_multicast_ether_addr(hdr->addr1)) {
495 return RX_DROP_MONITOR; 496 if (ieee80211_has_tods(hdr->frame_control) ||
496 if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) 497 !ieee80211_has_fromds(hdr->frame_control))
497 return RX_DROP_MONITOR; 498 return RX_DROP_MONITOR;
499 if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
500 return RX_DROP_MONITOR;
501 } else {
502 if (!ieee80211_has_a4(hdr->frame_control))
503 return RX_DROP_MONITOR;
504 if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
505 return RX_DROP_MONITOR;
506 }
498 } 507 }
499 508
500 /* If there is not an established peer link and this is not a peer link 509 /* If there is not an established peer link and this is not a peer link
@@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
527 536
528 if (ieee80211_is_data(hdr->frame_control) && 537 if (ieee80211_is_data(hdr->frame_control) &&
529 is_multicast_ether_addr(hdr->addr1) && 538 is_multicast_ether_addr(hdr->addr1) &&
530 mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata)) 539 mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
531 return RX_DROP_MONITOR; 540 return RX_DROP_MONITOR;
532#undef msh_h_get 541#undef msh_h_get
533 542
@@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1495 /* illegal frame */ 1504 /* illegal frame */
1496 return RX_DROP_MONITOR; 1505 return RX_DROP_MONITOR;
1497 1506
1498 if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){ 1507 if (!is_multicast_ether_addr(hdr->addr1) &&
1508 (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) {
1499 struct mesh_path *mppath; 1509 struct mesh_path *mppath;
1500 1510
1501 rcu_read_lock(); 1511 rcu_read_lock();
@@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1512 rcu_read_unlock(); 1522 rcu_read_unlock();
1513 } 1523 }
1514 1524
1515 if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0) 1525 /* Frame has reached destination. Don't forward */
1526 if (!is_multicast_ether_addr(hdr->addr1) &&
1527 compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
1516 return RX_CONTINUE; 1528 return RX_CONTINUE;
1517 1529
1518 mesh_hdr->ttl--; 1530 mesh_hdr->ttl--;
@@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1532 rx->dev->name); 1544 rx->dev->name);
1533 1545
1534 fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; 1546 fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
1535 /*
1536 * Save TA to addr1 to send TA a path error if a
1537 * suitable next hop is not found
1538 */
1539 memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
1540 memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN); 1547 memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
1541 info = IEEE80211_SKB_CB(fwd_skb); 1548 info = IEEE80211_SKB_CB(fwd_skb);
1542 memset(info, 0, sizeof(*info)); 1549 memset(info, 0, sizeof(*info));
1543 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; 1550 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
1544 info->control.vif = &rx->sdata->vif; 1551 info->control.vif = &rx->sdata->vif;
1545 ieee80211_select_queue(local, fwd_skb); 1552 ieee80211_select_queue(local, fwd_skb);
1546 if (is_multicast_ether_addr(fwd_hdr->addr3)) 1553 if (!is_multicast_ether_addr(fwd_hdr->addr1)) {
1547 memcpy(fwd_hdr->addr1, fwd_hdr->addr3, 1554 int err;
1555 /*
1556 * Save TA to addr1 to send TA a path error if a
1557 * suitable next hop is not found
1558 */
1559 memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
1548 ETH_ALEN); 1560 ETH_ALEN);
1549 else { 1561 err = mesh_nexthop_lookup(fwd_skb, sdata);
1550 int err = mesh_nexthop_lookup(fwd_skb, sdata);
1551 /* Failed to immediately resolve next hop: 1562 /* Failed to immediately resolve next hop:
1552 * fwded frame was dropped or will be added 1563 * fwded frame was dropped or will be added
1553 * later to the pending skb queue. */ 1564 * later to the pending skb queue. */
@@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1560 } 1571 }
1561 } 1572 }
1562 1573
1563 if (is_multicast_ether_addr(hdr->addr3) || 1574 if (is_multicast_ether_addr(hdr->addr1) ||
1564 rx->dev->flags & IFF_PROMISC) 1575 rx->dev->flags & IFF_PROMISC)
1565 return RX_CONTINUE; 1576 return RX_CONTINUE;
1566 else 1577 else
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 32442980cc2..ee8aa76f071 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1414,9 +1414,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
1414 1414
1415 if (ieee80211_vif_is_mesh(&sdata->vif) && 1415 if (ieee80211_vif_is_mesh(&sdata->vif) &&
1416 ieee80211_is_data(hdr->frame_control)) { 1416 ieee80211_is_data(hdr->frame_control)) {
1417 if (is_multicast_ether_addr(hdr->addr3)) 1417 if (!is_multicast_ether_addr(hdr->addr1))
1418 memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
1419 else
1420 if (mesh_nexthop_lookup(skb, sdata)) { 1418 if (mesh_nexthop_lookup(skb, sdata)) {
1421 dev_put(sdata->dev); 1419 dev_put(sdata->dev);
1422 return; 1420 return;
@@ -1619,52 +1617,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
1619 break; 1617 break;
1620#ifdef CONFIG_MAC80211_MESH 1618#ifdef CONFIG_MAC80211_MESH
1621 case NL80211_IFTYPE_MESH_POINT: 1619 case NL80211_IFTYPE_MESH_POINT:
1622 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
1623 if (!sdata->u.mesh.mshcfg.dot11MeshTTL) { 1620 if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
1624 /* Do not send frames with mesh_ttl == 0 */ 1621 /* Do not send frames with mesh_ttl == 0 */
1625 sdata->u.mesh.mshstats.dropped_frames_ttl++; 1622 sdata->u.mesh.mshstats.dropped_frames_ttl++;
1626 ret = NETDEV_TX_OK; 1623 ret = NETDEV_TX_OK;
1627 goto fail; 1624 goto fail;
1628 } 1625 }
1629 memset(&mesh_hdr, 0, sizeof(mesh_hdr));
1630 1626
1631 if (compare_ether_addr(dev->dev_addr, 1627 if (compare_ether_addr(dev->dev_addr,
1632 skb->data + ETH_ALEN) == 0) { 1628 skb->data + ETH_ALEN) == 0) {
1633 /* RA TA DA SA */ 1629 hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
1634 memset(hdr.addr1, 0, ETH_ALEN); 1630 skb->data, skb->data + ETH_ALEN);
1635 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); 1631 meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
1636 memcpy(hdr.addr3, skb->data, ETH_ALEN); 1632 sdata, NULL, NULL, NULL);
1637 memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
1638 meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
1639 } else { 1633 } else {
1640 /* packet from other interface */ 1634 /* packet from other interface */
1641 struct mesh_path *mppath; 1635 struct mesh_path *mppath;
1636 int is_mesh_mcast = 1;
1637 char *mesh_da;
1642 1638
1643 memset(hdr.addr1, 0, ETH_ALEN); 1639 rcu_read_lock();
1644 memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
1645 memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
1646
1647 if (is_multicast_ether_addr(skb->data)) 1640 if (is_multicast_ether_addr(skb->data))
1648 memcpy(hdr.addr3, skb->data, ETH_ALEN); 1641 /* DA TA mSA AE:SA */
1642 mesh_da = skb->data;
1649 else { 1643 else {
1650 rcu_read_lock();
1651 mppath = mpp_path_lookup(skb->data, sdata); 1644 mppath = mpp_path_lookup(skb->data, sdata);
1652 if (mppath) 1645 if (mppath) {
1653 memcpy(hdr.addr3, mppath->mpp, ETH_ALEN); 1646 /* RA TA mDA mSA AE:DA SA */
1654 else 1647 mesh_da = mppath->mpp;
1655 memset(hdr.addr3, 0xff, ETH_ALEN); 1648 is_mesh_mcast = 0;
1656 rcu_read_unlock(); 1649 } else
1650 /* DA TA mSA AE:SA */
1651 mesh_da = dev->broadcast;
1657 } 1652 }
1653 hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
1654 mesh_da, dev->dev_addr);
1655 rcu_read_unlock();
1656 if (is_mesh_mcast)
1657 meshhdrlen =
1658 ieee80211_new_mesh_header(&mesh_hdr,
1659 sdata,
1660 skb->data + ETH_ALEN,
1661 NULL,
1662 NULL);
1663 else
1664 meshhdrlen =
1665 ieee80211_new_mesh_header(&mesh_hdr,
1666 sdata,
1667 NULL,
1668 skb->data,
1669 skb->data + ETH_ALEN);
1658 1670
1659 mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6;
1660 mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
1661 put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
1662 memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
1663 memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
1664 sdata->u.mesh.mesh_seqnum++;
1665 meshhdrlen = 18;
1666 } 1671 }
1667 hdrlen = 30;
1668 break; 1672 break;
1669#endif 1673#endif
1670 case NL80211_IFTYPE_STATION: 1674 case NL80211_IFTYPE_STATION:
diff --git a/net/wireless/util.c b/net/wireless/util.c
index ba387d85dcf..693275a16a2 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
274 switch (ae) { 274 switch (ae) {
275 case 0: 275 case 0:
276 return 6; 276 return 6;
277 case 1: 277 case MESH_FLAGS_AE_A4:
278 return 12; 278 return 12;
279 case 2: 279 case MESH_FLAGS_AE_A5_A6:
280 return 18; 280 return 18;
281 case 3: 281 case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6):
282 return 24; 282 return 24;
283 default: 283 default:
284 return 6; 284 return 6;
@@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
333 } 333 }
334 break; 334 break;
335 case cpu_to_le16(IEEE80211_FCTL_FROMDS): 335 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
336 if (iftype != NL80211_IFTYPE_STATION || 336 if ((iftype != NL80211_IFTYPE_STATION &&
337 iftype != NL80211_IFTYPE_MESH_POINT) ||
337 (is_multicast_ether_addr(dst) && 338 (is_multicast_ether_addr(dst) &&
338 !compare_ether_addr(src, addr))) 339 !compare_ether_addr(src, addr)))
339 return -1; 340 return -1;
341 if (iftype == NL80211_IFTYPE_MESH_POINT) {
342 struct ieee80211s_hdr *meshdr =
343 (struct ieee80211s_hdr *) (skb->data + hdrlen);
344 hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
345 if (meshdr->flags & MESH_FLAGS_AE_A4)
346 memcpy(src, meshdr->eaddr1, ETH_ALEN);
347 }
340 break; 348 break;
341 case cpu_to_le16(0): 349 case cpu_to_le16(0):
342 if (iftype != NL80211_IFTYPE_ADHOC) 350 if (iftype != NL80211_IFTYPE_ADHOC)