diff options
author | Johannes Berg <johannes.berg@intel.com> | 2015-03-21 04:13:45 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-03-30 04:47:19 -0400 |
commit | 97ffe75791b3e9c0797d5891070e41321c3beccb (patch) | |
tree | fd80b39d90a80c1b6f83d748fc512dab5f15e5b5 /net/mac80211/tx.c | |
parent | 527871d7206dac2733d0bae52f5a328811d299ee (diff) |
mac80211: factor out station lookup from ieee80211_build_hdr()
In order to look up the RA station earlier to implement a TX
fastpath, factor out the lookup from ieee80211_build_hdr().
To always have a valid station pointer, also move some of the
checks into the new function.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 188 |
1 files changed, 118 insertions, 70 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 018f029d0c95..e5d679f38cc1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1789,6 +1789,91 @@ fail: | |||
1789 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ | 1789 | return NETDEV_TX_OK; /* meaning, we dealt with the skb */ |
1790 | } | 1790 | } |
1791 | 1791 | ||
1792 | static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb) | ||
1793 | { | ||
1794 | u16 ethertype = (skb->data[12] << 8) | skb->data[13]; | ||
1795 | |||
1796 | return ethertype == ETH_P_TDLS && | ||
1797 | skb->len > 14 && | ||
1798 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; | ||
1799 | } | ||
1800 | |||
1801 | static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, | ||
1802 | struct sk_buff *skb, | ||
1803 | struct sta_info **sta_out) | ||
1804 | { | ||
1805 | struct sta_info *sta; | ||
1806 | |||
1807 | switch (sdata->vif.type) { | ||
1808 | case NL80211_IFTYPE_AP_VLAN: | ||
1809 | sta = rcu_dereference(sdata->u.vlan.sta); | ||
1810 | if (sta) { | ||
1811 | *sta_out = sta; | ||
1812 | return 0; | ||
1813 | } else if (sdata->wdev.use_4addr) { | ||
1814 | return -ENOLINK; | ||
1815 | } | ||
1816 | /* fall through */ | ||
1817 | case NL80211_IFTYPE_AP: | ||
1818 | case NL80211_IFTYPE_OCB: | ||
1819 | case NL80211_IFTYPE_ADHOC: | ||
1820 | if (is_multicast_ether_addr(skb->data)) { | ||
1821 | *sta_out = ERR_PTR(-ENOENT); | ||
1822 | return 0; | ||
1823 | } | ||
1824 | sta = sta_info_get_bss(sdata, skb->data); | ||
1825 | break; | ||
1826 | case NL80211_IFTYPE_WDS: | ||
1827 | sta = sta_info_get(sdata, sdata->u.wds.remote_addr); | ||
1828 | break; | ||
1829 | #ifdef CONFIG_MAC80211_MESH | ||
1830 | case NL80211_IFTYPE_MESH_POINT: | ||
1831 | /* determined much later */ | ||
1832 | *sta_out = NULL; | ||
1833 | return 0; | ||
1834 | #endif | ||
1835 | case NL80211_IFTYPE_STATION: | ||
1836 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | ||
1837 | sta = sta_info_get(sdata, skb->data); | ||
1838 | if (sta) { | ||
1839 | bool tdls_peer, tdls_auth; | ||
1840 | |||
1841 | tdls_peer = test_sta_flag(sta, | ||
1842 | WLAN_STA_TDLS_PEER); | ||
1843 | tdls_auth = test_sta_flag(sta, | ||
1844 | WLAN_STA_TDLS_PEER_AUTH); | ||
1845 | |||
1846 | if (tdls_peer && tdls_auth) { | ||
1847 | *sta_out = sta; | ||
1848 | return 0; | ||
1849 | } | ||
1850 | |||
1851 | /* | ||
1852 | * TDLS link during setup - throw out frames to | ||
1853 | * peer. Allow TDLS-setup frames to unauthorized | ||
1854 | * peers for the special case of a link teardown | ||
1855 | * after a TDLS sta is removed due to being | ||
1856 | * unreachable. | ||
1857 | */ | ||
1858 | if (tdls_peer && !tdls_auth && | ||
1859 | !ieee80211_is_tdls_setup(skb)) | ||
1860 | return -EINVAL; | ||
1861 | } | ||
1862 | |||
1863 | } | ||
1864 | |||
1865 | sta = sta_info_get(sdata, sdata->u.mgd.bssid); | ||
1866 | if (!sta) | ||
1867 | return -ENOLINK; | ||
1868 | break; | ||
1869 | default: | ||
1870 | return -EINVAL; | ||
1871 | } | ||
1872 | |||
1873 | *sta_out = sta ?: ERR_PTR(-ENOENT); | ||
1874 | return 0; | ||
1875 | } | ||
1876 | |||
1792 | /** | 1877 | /** |
1793 | * ieee80211_build_hdr - build 802.11 header in the given frame | 1878 | * ieee80211_build_hdr - build 802.11 header in the given frame |
1794 | * @sdata: virtual interface to build the header for | 1879 | * @sdata: virtual interface to build the header for |
@@ -1809,7 +1894,7 @@ fail: | |||
1809 | */ | 1894 | */ |
1810 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | 1895 | static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, |
1811 | struct sk_buff *skb, u32 info_flags, | 1896 | struct sk_buff *skb, u32 info_flags, |
1812 | struct sta_info **sta_out) | 1897 | struct sta_info *sta) |
1813 | { | 1898 | { |
1814 | struct ieee80211_local *local = sdata->local; | 1899 | struct ieee80211_local *local = sdata->local; |
1815 | struct ieee80211_tx_info *info; | 1900 | struct ieee80211_tx_info *info; |
@@ -1822,17 +1907,18 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1822 | const u8 *encaps_data; | 1907 | const u8 *encaps_data; |
1823 | int encaps_len, skip_header_bytes; | 1908 | int encaps_len, skip_header_bytes; |
1824 | int nh_pos, h_pos; | 1909 | int nh_pos, h_pos; |
1825 | struct sta_info *sta = NULL; | 1910 | bool wme_sta = false, authorized = false; |
1826 | bool wme_sta = false, authorized = false, tdls_auth = false; | 1911 | bool tdls_peer; |
1827 | bool tdls_peer = false, tdls_setup_frame = false; | ||
1828 | bool multicast; | 1912 | bool multicast; |
1829 | bool have_station = false; | ||
1830 | u16 info_id = 0; | 1913 | u16 info_id = 0; |
1831 | struct ieee80211_chanctx_conf *chanctx_conf; | 1914 | struct ieee80211_chanctx_conf *chanctx_conf; |
1832 | struct ieee80211_sub_if_data *ap_sdata; | 1915 | struct ieee80211_sub_if_data *ap_sdata; |
1833 | enum ieee80211_band band; | 1916 | enum ieee80211_band band; |
1834 | int ret; | 1917 | int ret; |
1835 | 1918 | ||
1919 | if (IS_ERR(sta)) | ||
1920 | sta = NULL; | ||
1921 | |||
1836 | /* convert Ethernet header to proper 802.11 header (based on | 1922 | /* convert Ethernet header to proper 802.11 header (based on |
1837 | * operation mode) */ | 1923 | * operation mode) */ |
1838 | ethertype = (skb->data[12] << 8) | skb->data[13]; | 1924 | ethertype = (skb->data[12] << 8) | skb->data[13]; |
@@ -1840,8 +1926,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1840 | 1926 | ||
1841 | switch (sdata->vif.type) { | 1927 | switch (sdata->vif.type) { |
1842 | case NL80211_IFTYPE_AP_VLAN: | 1928 | case NL80211_IFTYPE_AP_VLAN: |
1843 | sta = rcu_dereference(sdata->u.vlan.sta); | 1929 | if (sdata->wdev.use_4addr) { |
1844 | if (sta) { | ||
1845 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | 1930 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1846 | /* RA TA DA SA */ | 1931 | /* RA TA DA SA */ |
1847 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); | 1932 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); |
@@ -1851,11 +1936,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1851 | hdrlen = 30; | 1936 | hdrlen = 30; |
1852 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | 1937 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); |
1853 | wme_sta = sta->sta.wme; | 1938 | wme_sta = sta->sta.wme; |
1854 | have_station = true; | ||
1855 | *sta_out = sta; | ||
1856 | } else if (sdata->wdev.use_4addr) { | ||
1857 | ret = -ENOLINK; | ||
1858 | goto free; | ||
1859 | } | 1939 | } |
1860 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, | 1940 | ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
1861 | u.ap); | 1941 | u.ap); |
@@ -1865,7 +1945,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1865 | goto free; | 1945 | goto free; |
1866 | } | 1946 | } |
1867 | band = chanctx_conf->def.chan->band; | 1947 | band = chanctx_conf->def.chan->band; |
1868 | if (sta) | 1948 | if (sdata->wdev.use_4addr) |
1869 | break; | 1949 | break; |
1870 | /* fall through */ | 1950 | /* fall through */ |
1871 | case NL80211_IFTYPE_AP: | 1951 | case NL80211_IFTYPE_AP: |
@@ -1969,44 +2049,15 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
1969 | break; | 2049 | break; |
1970 | #endif | 2050 | #endif |
1971 | case NL80211_IFTYPE_STATION: | 2051 | case NL80211_IFTYPE_STATION: |
1972 | if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 2052 | /* we already did checks when looking up the RA STA */ |
1973 | sta = sta_info_get(sdata, skb->data); | 2053 | tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER); |
1974 | if (sta) { | ||
1975 | tdls_peer = test_sta_flag(sta, | ||
1976 | WLAN_STA_TDLS_PEER); | ||
1977 | tdls_auth = test_sta_flag(sta, | ||
1978 | WLAN_STA_TDLS_PEER_AUTH); | ||
1979 | } | ||
1980 | |||
1981 | if (tdls_peer) | ||
1982 | tdls_setup_frame = | ||
1983 | ethertype == ETH_P_TDLS && | ||
1984 | skb->len > 14 && | ||
1985 | skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; | ||
1986 | } | ||
1987 | |||
1988 | /* | ||
1989 | * TDLS link during setup - throw out frames to peer. We allow | ||
1990 | * TDLS-setup frames to unauthorized peers for the special case | ||
1991 | * of a link teardown after a TDLS sta is removed due to being | ||
1992 | * unreachable. | ||
1993 | */ | ||
1994 | if (tdls_peer && !tdls_auth && !tdls_setup_frame) { | ||
1995 | ret = -EINVAL; | ||
1996 | goto free; | ||
1997 | } | ||
1998 | 2054 | ||
1999 | /* send direct packets to authorized TDLS peers */ | 2055 | if (tdls_peer) { |
2000 | if (tdls_peer && tdls_auth) { | ||
2001 | /* DA SA BSSID */ | 2056 | /* DA SA BSSID */ |
2002 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 2057 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
2003 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 2058 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
2004 | memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN); | 2059 | memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN); |
2005 | hdrlen = 24; | 2060 | hdrlen = 24; |
2006 | have_station = true; | ||
2007 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
2008 | wme_sta = sta->sta.wme; | ||
2009 | *sta_out = sta; | ||
2010 | } else if (sdata->u.mgd.use_4addr && | 2061 | } else if (sdata->u.mgd.use_4addr && |
2011 | cpu_to_be16(ethertype) != sdata->control_port_protocol) { | 2062 | cpu_to_be16(ethertype) != sdata->control_port_protocol) { |
2012 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | | 2063 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | |
@@ -2063,30 +2114,16 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, | |||
2063 | goto free; | 2114 | goto free; |
2064 | } | 2115 | } |
2065 | 2116 | ||
2066 | /* | ||
2067 | * There's no need to try to look up the destination station | ||
2068 | * if it is a multicast address. In mesh, there's no need to | ||
2069 | * look up the station at all as it always must be QoS capable | ||
2070 | * and mesh mode checks authorization later. | ||
2071 | */ | ||
2072 | multicast = is_multicast_ether_addr(hdr.addr1); | 2117 | multicast = is_multicast_ether_addr(hdr.addr1); |
2073 | if (multicast) { | ||
2074 | *sta_out = ERR_PTR(-ENOENT); | ||
2075 | } else if (!have_station && !ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2076 | if (sdata->control_port_protocol == skb->protocol) | ||
2077 | sta = sta_info_get_bss(sdata, hdr.addr1); | ||
2078 | else | ||
2079 | sta = sta_info_get(sdata, hdr.addr1); | ||
2080 | if (sta) { | ||
2081 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
2082 | wme_sta = sta->sta.wme; | ||
2083 | } | ||
2084 | *sta_out = sta ?: ERR_PTR(-ENOENT); | ||
2085 | } | ||
2086 | 2118 | ||
2087 | /* For mesh, the use of the QoS header is mandatory */ | 2119 | /* sta is always NULL for mesh */ |
2088 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 2120 | if (sta) { |
2121 | authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
2122 | wme_sta = sta->sta.wme; | ||
2123 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
2124 | /* For mesh, the use of the QoS header is mandatory */ | ||
2089 | wme_sta = true; | 2125 | wme_sta = true; |
2126 | } | ||
2090 | 2127 | ||
2091 | /* receiver does QoS (which also means we do) use it */ | 2128 | /* receiver does QoS (which also means we do) use it */ |
2092 | if (wme_sta) { | 2129 | if (wme_sta) { |
@@ -2259,7 +2296,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2259 | u32 info_flags) | 2296 | u32 info_flags) |
2260 | { | 2297 | { |
2261 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2298 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
2262 | struct sta_info *sta = NULL; | 2299 | struct sta_info *sta; |
2263 | 2300 | ||
2264 | if (unlikely(skb->len < ETH_HLEN)) { | 2301 | if (unlikely(skb->len < ETH_HLEN)) { |
2265 | kfree_skb(skb); | 2302 | kfree_skb(skb); |
@@ -2268,7 +2305,12 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2268 | 2305 | ||
2269 | rcu_read_lock(); | 2306 | rcu_read_lock(); |
2270 | 2307 | ||
2271 | skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta); | 2308 | if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { |
2309 | kfree_skb(skb); | ||
2310 | goto out; | ||
2311 | } | ||
2312 | |||
2313 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); | ||
2272 | if (IS_ERR(skb)) | 2314 | if (IS_ERR(skb)) |
2273 | goto out; | 2315 | goto out; |
2274 | 2316 | ||
@@ -2304,11 +2346,17 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, | |||
2304 | .local = sdata->local, | 2346 | .local = sdata->local, |
2305 | .sdata = sdata, | 2347 | .sdata = sdata, |
2306 | }; | 2348 | }; |
2307 | struct sta_info *sta_ignore; | 2349 | struct sta_info *sta; |
2308 | 2350 | ||
2309 | rcu_read_lock(); | 2351 | rcu_read_lock(); |
2310 | 2352 | ||
2311 | skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta_ignore); | 2353 | if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { |
2354 | kfree_skb(skb); | ||
2355 | skb = ERR_PTR(-EINVAL); | ||
2356 | goto out; | ||
2357 | } | ||
2358 | |||
2359 | skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); | ||
2312 | if (IS_ERR(skb)) | 2360 | if (IS_ERR(skb)) |
2313 | goto out; | 2361 | goto out; |
2314 | 2362 | ||