diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/mesh.c | 62 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 5 | ||||
-rw-r--r-- | net/mac80211/rx.c | 45 | ||||
-rw-r--r-- | net/mac80211/tx.c | 64 | ||||
-rw-r--r-- | net/wireless/util.c | 16 |
5 files changed, 136 insertions, 56 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8c068e215fb8..10d93386042a 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 | */ | ||
411 | int 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 | */ |
408 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 445 | int 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 | ||
419 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | 473 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 6aaf1ecbcb63..2ebd74cb0380 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 */ |
196 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | ||
197 | char *da, char *sa); | ||
196 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 198 | int 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); | ||
198 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 201 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
199 | struct ieee80211_sub_if_data *sdata); | 202 | struct ieee80211_sub_if_data *sdata); |
200 | bool mesh_matches_local(struct ieee802_11_elems *ie, | 203 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 25a669c86e14..4cd9e45b1443 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 32442980cc24..ee8aa76f071a 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 ba387d85dcfd..693275a16a26 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) |