diff options
author | Luis Carlos Cobo <luisca@cozybit.com> | 2008-02-23 09:17:10 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:41 -0500 |
commit | 33b64eb2b1b1759cbdafbe5c59df652f1e7c746e (patch) | |
tree | 10b314d244e4a44229a6b0da85c3ac76cce2c895 /net/mac80211/tx.c | |
parent | 2e3c8736820bf72a8ad10721c7e31d36d4fa7790 (diff) |
mac80211: support for mesh interfaces in mac80211 data path
This changes the TX/RX paths in mac80211 to support mesh interfaces.
This code will be cleaned up later again before being enabled.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 158 |
1 files changed, 129 insertions, 29 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1cd58e01f1ee..fc1ffb55ed5c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -26,6 +26,9 @@ | |||
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "ieee80211_led.h" | 28 | #include "ieee80211_led.h" |
29 | #ifdef CONFIG_MAC80211_MESH | ||
30 | #include "mesh.h" | ||
31 | #endif | ||
29 | #include "wep.h" | 32 | #include "wep.h" |
30 | #include "wpa.h" | 33 | #include "wpa.h" |
31 | #include "wme.h" | 34 | #include "wme.h" |
@@ -249,6 +252,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | |||
249 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) | 252 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) |
250 | return TX_DROP; | 253 | return TX_DROP; |
251 | 254 | ||
255 | if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
256 | return TX_CONTINUE; | ||
257 | |||
252 | if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) | 258 | if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) |
253 | return TX_CONTINUE; | 259 | return TX_CONTINUE; |
254 | 260 | ||
@@ -1384,8 +1390,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1384 | struct ieee80211_tx_packet_data *pkt_data; | 1390 | struct ieee80211_tx_packet_data *pkt_data; |
1385 | struct ieee80211_sub_if_data *sdata; | 1391 | struct ieee80211_sub_if_data *sdata; |
1386 | int ret = 1, head_need; | 1392 | int ret = 1, head_need; |
1387 | u16 ethertype, hdrlen, fc; | 1393 | u16 ethertype, hdrlen, meshhdrlen = 0, fc; |
1388 | struct ieee80211_hdr hdr; | 1394 | struct ieee80211_hdr hdr; |
1395 | struct ieee80211s_hdr mesh_hdr; | ||
1389 | const u8 *encaps_data; | 1396 | const u8 *encaps_data; |
1390 | int encaps_len, skip_header_bytes; | 1397 | int encaps_len, skip_header_bytes; |
1391 | int nh_pos, h_pos; | 1398 | int nh_pos, h_pos; |
@@ -1427,6 +1434,37 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1427 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1434 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
1428 | hdrlen = 30; | 1435 | hdrlen = 30; |
1429 | break; | 1436 | break; |
1437 | #ifdef CONFIG_MAC80211_MESH | ||
1438 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
1439 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | ||
1440 | /* RA TA DA SA */ | ||
1441 | if (is_multicast_ether_addr(skb->data)) | ||
1442 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
1443 | else if (mesh_nexthop_lookup(hdr.addr1, skb, dev)) | ||
1444 | return 0; | ||
1445 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1446 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1447 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1448 | if (skb->pkt_type == PACKET_OTHERHOST) { | ||
1449 | /* Forwarded frame, keep mesh ttl and seqnum */ | ||
1450 | struct ieee80211s_hdr *prev_meshhdr; | ||
1451 | prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); | ||
1452 | meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); | ||
1453 | memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen); | ||
1454 | sdata->u.sta.mshstats.fwded_frames++; | ||
1455 | } else { | ||
1456 | if (!sdata->u.sta.mshcfg.dot11MeshTTL) { | ||
1457 | /* Do not send frames with mesh_ttl == 0 */ | ||
1458 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
1459 | ret = 0; | ||
1460 | goto fail; | ||
1461 | } | ||
1462 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | ||
1463 | sdata); | ||
1464 | } | ||
1465 | hdrlen = 30; | ||
1466 | break; | ||
1467 | #endif | ||
1430 | case IEEE80211_IF_TYPE_STA: | 1468 | case IEEE80211_IF_TYPE_STA: |
1431 | fc |= IEEE80211_FCTL_TODS; | 1469 | fc |= IEEE80211_FCTL_TODS; |
1432 | /* BSSID SA DA */ | 1470 | /* BSSID SA DA */ |
@@ -1471,8 +1509,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1471 | * EAPOL frames from the local station. | 1509 | * EAPOL frames from the local station. |
1472 | */ | 1510 | */ |
1473 | if (unlikely(!is_multicast_ether_addr(hdr.addr1) && | 1511 | if (unlikely(!is_multicast_ether_addr(hdr.addr1) && |
1474 | !(sta_flags & WLAN_STA_AUTHORIZED) && | 1512 | !(sta_flags & WLAN_STA_AUTHORIZED) && |
1475 | !(ethertype == ETH_P_PAE && | 1513 | !(ethertype == ETH_P_PAE && |
1476 | compare_ether_addr(dev->dev_addr, | 1514 | compare_ether_addr(dev->dev_addr, |
1477 | skb->data + ETH_ALEN) == 0))) { | 1515 | skb->data + ETH_ALEN) == 0))) { |
1478 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1516 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -1525,7 +1563,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1525 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and | 1563 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and |
1526 | * alloc_skb() (net/core/skbuff.c) | 1564 | * alloc_skb() (net/core/skbuff.c) |
1527 | */ | 1565 | */ |
1528 | head_need = hdrlen + encaps_len + local->tx_headroom; | 1566 | head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; |
1529 | head_need -= skb_headroom(skb); | 1567 | head_need -= skb_headroom(skb); |
1530 | 1568 | ||
1531 | /* We are going to modify skb data, so make a copy of it if happens to | 1569 | /* We are going to modify skb data, so make a copy of it if happens to |
@@ -1559,6 +1597,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1559 | h_pos += encaps_len; | 1597 | h_pos += encaps_len; |
1560 | } | 1598 | } |
1561 | 1599 | ||
1600 | if (meshhdrlen > 0) { | ||
1601 | memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen); | ||
1602 | nh_pos += meshhdrlen; | ||
1603 | h_pos += meshhdrlen; | ||
1604 | } | ||
1605 | |||
1562 | if (fc & IEEE80211_STYPE_QOS_DATA) { | 1606 | if (fc & IEEE80211_STYPE_QOS_DATA) { |
1563 | __le16 *qos_control; | 1607 | __le16 *qos_control; |
1564 | 1608 | ||
@@ -1734,6 +1778,40 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1734 | read_unlock_bh(&local->sta_lock); | 1778 | read_unlock_bh(&local->sta_lock); |
1735 | } | 1779 | } |
1736 | 1780 | ||
1781 | #ifdef CONFIG_MAC80211_MESH | ||
1782 | static struct sk_buff *ieee80211_mesh_beacon_get(struct net_device *dev) | ||
1783 | { | ||
1784 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1785 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
1786 | struct ieee80211_mgmt *mgmt; | ||
1787 | u8 *pos; | ||
1788 | |||
1789 | if (!skb) | ||
1790 | return NULL; | ||
1791 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1792 | mgmt = (struct ieee80211_mgmt *) | ||
1793 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
1794 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
1795 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
1796 | IEEE80211_STYPE_BEACON); | ||
1797 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1798 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
1799 | /* BSSID is left zeroed, wildcard value */ | ||
1800 | mgmt->u.beacon.beacon_int = | ||
1801 | cpu_to_le16(local->hw.conf.beacon_int); | ||
1802 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ | ||
1803 | |||
1804 | pos = skb_put(skb, 2); | ||
1805 | *pos++ = WLAN_EID_SSID; | ||
1806 | *pos++ = 0x0; | ||
1807 | |||
1808 | mesh_mgmt_ies_add(skb, dev); | ||
1809 | |||
1810 | return skb; | ||
1811 | } | ||
1812 | #endif | ||
1813 | |||
1814 | |||
1737 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | 1815 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, |
1738 | struct ieee80211_vif *vif, | 1816 | struct ieee80211_vif *vif, |
1739 | struct ieee80211_tx_control *control) | 1817 | struct ieee80211_tx_control *control) |
@@ -1746,6 +1824,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1746 | struct rate_selection rsel; | 1824 | struct rate_selection rsel; |
1747 | struct beacon_data *beacon; | 1825 | struct beacon_data *beacon; |
1748 | struct ieee80211_supported_band *sband; | 1826 | struct ieee80211_supported_band *sband; |
1827 | int *num_beacons; | ||
1828 | int err = 0; | ||
1749 | 1829 | ||
1750 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1830 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1751 | 1831 | ||
@@ -1753,11 +1833,51 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1753 | 1833 | ||
1754 | sdata = vif_to_sdata(vif); | 1834 | sdata = vif_to_sdata(vif); |
1755 | bdev = sdata->dev; | 1835 | bdev = sdata->dev; |
1756 | ap = &sdata->u.ap; | ||
1757 | 1836 | ||
1758 | beacon = rcu_dereference(ap->beacon); | 1837 | switch (sdata->vif.type) { |
1838 | case IEEE80211_IF_TYPE_AP: | ||
1839 | ap = &sdata->u.ap; | ||
1840 | beacon = rcu_dereference(ap->beacon); | ||
1841 | if (!ap || !beacon) { | ||
1842 | err = -1; | ||
1843 | break; | ||
1844 | } | ||
1845 | |||
1846 | /* headroom, head length, tail length and maximum TIM length */ | ||
1847 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + | ||
1848 | beacon->tail_len + 256); | ||
1849 | if (!skb) | ||
1850 | goto out; | ||
1851 | |||
1852 | skb_reserve(skb, local->tx_headroom); | ||
1853 | memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||
1854 | beacon->head_len); | ||
1759 | 1855 | ||
1760 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { | 1856 | ieee80211_include_sequence(sdata, |
1857 | (struct ieee80211_hdr *)skb->data); | ||
1858 | |||
1859 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1860 | |||
1861 | if (beacon->tail) | ||
1862 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, | ||
1863 | beacon->tail_len); | ||
1864 | |||
1865 | num_beacons = &ap->num_beacons; | ||
1866 | break; | ||
1867 | |||
1868 | #ifdef CONFIG_MAC80211_MESH | ||
1869 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
1870 | skb = ieee80211_mesh_beacon_get(bdev); | ||
1871 | num_beacons = &sdata->u.sta.num_beacons; | ||
1872 | break; | ||
1873 | #endif | ||
1874 | |||
1875 | default: | ||
1876 | err = -1; | ||
1877 | break; | ||
1878 | } | ||
1879 | |||
1880 | if (err) { | ||
1761 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1881 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1762 | if (net_ratelimit()) | 1882 | if (net_ratelimit()) |
1763 | printk(KERN_DEBUG "no beacon data avail for %s\n", | 1883 | printk(KERN_DEBUG "no beacon data avail for %s\n", |
@@ -1767,24 +1887,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1767 | goto out; | 1887 | goto out; |
1768 | } | 1888 | } |
1769 | 1889 | ||
1770 | /* headroom, head length, tail length and maximum TIM length */ | ||
1771 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + | ||
1772 | beacon->tail_len + 256); | ||
1773 | if (!skb) | ||
1774 | goto out; | ||
1775 | |||
1776 | skb_reserve(skb, local->tx_headroom); | ||
1777 | memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||
1778 | beacon->head_len); | ||
1779 | |||
1780 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); | ||
1781 | |||
1782 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1783 | |||
1784 | if (beacon->tail) | ||
1785 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, | ||
1786 | beacon->tail_len); | ||
1787 | |||
1788 | if (control) { | 1890 | if (control) { |
1789 | rate_control_get_rate(local->mdev, sband, skb, &rsel); | 1891 | rate_control_get_rate(local->mdev, sband, skb, &rsel); |
1790 | if (!rsel.rate) { | 1892 | if (!rsel.rate) { |
@@ -1808,10 +1910,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1808 | control->retry_limit = 1; | 1910 | control->retry_limit = 1; |
1809 | control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; | 1911 | control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; |
1810 | } | 1912 | } |
1811 | 1913 | (*num_beacons)++; | |
1812 | ap->num_beacons++; | 1914 | out: |
1813 | |||
1814 | out: | ||
1815 | rcu_read_unlock(); | 1915 | rcu_read_unlock(); |
1816 | return skb; | 1916 | return skb; |
1817 | } | 1917 | } |