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

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>

+118 -70
+118 -70
net/mac80211/tx.c
··· 1789 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 1878 * ieee80211_build_hdr - build 802.11 header in the given frame 1794 1879 * @sdata: virtual interface to build the header for ··· 1894 1809 */ 1895 1810 static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, 1896 1811 struct sk_buff *skb, u32 info_flags, 1897 - struct sta_info **sta_out) 1812 + struct sta_info *sta) 1898 1813 { 1899 1814 struct ieee80211_local *local = sdata->local; 1900 1815 struct ieee80211_tx_info *info; ··· 1907 1822 const u8 *encaps_data; 1908 1823 int encaps_len, skip_header_bytes; 1909 1824 int nh_pos, h_pos; 1910 - struct sta_info *sta = NULL; 1911 - bool wme_sta = false, authorized = false, tdls_auth = false; 1912 - bool tdls_peer = false, tdls_setup_frame = false; 1825 + bool wme_sta = false, authorized = false; 1826 + bool tdls_peer; 1913 1827 bool multicast; 1914 - bool have_station = false; 1915 1828 u16 info_id = 0; 1916 1829 struct ieee80211_chanctx_conf *chanctx_conf; 1917 1830 struct ieee80211_sub_if_data *ap_sdata; 1918 1831 enum ieee80211_band band; 1919 1832 int ret; 1833 + 1834 + if (IS_ERR(sta)) 1835 + sta = NULL; 1920 1836 1921 1837 /* convert Ethernet header to proper 802.11 header (based on 1922 1838 * operation mode) */ ··· 1926 1840 1927 1841 switch (sdata->vif.type) { 1928 1842 case NL80211_IFTYPE_AP_VLAN: 1929 - sta = rcu_dereference(sdata->u.vlan.sta); 1930 - if (sta) { 1843 + if (sdata->wdev.use_4addr) { 1931 1844 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); 1932 1845 /* RA TA DA SA */ 1933 1846 memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); ··· 1936 1851 hdrlen = 30; 1937 1852 authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); 1938 1853 wme_sta = sta->sta.wme; 1939 - have_station = true; 1940 - *sta_out = sta; 1941 - } else if (sdata->wdev.use_4addr) { 1942 - ret = -ENOLINK; 1943 - goto free; 1944 1854 } 1945 1855 ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, 1946 1856 u.ap); ··· 1945 1865 goto free; 1946 1866 } 1947 1867 band = chanctx_conf->def.chan->band; 1948 - if (sta) 1868 + if (sdata->wdev.use_4addr) 1949 1869 break; 1950 1870 /* fall through */ 1951 1871 case NL80211_IFTYPE_AP: ··· 2049 1969 break; 2050 1970 #endif 2051 1971 case NL80211_IFTYPE_STATION: 2052 - if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { 2053 - sta = sta_info_get(sdata, skb->data); 2054 - if (sta) { 2055 - tdls_peer = test_sta_flag(sta, 2056 - WLAN_STA_TDLS_PEER); 2057 - tdls_auth = test_sta_flag(sta, 2058 - WLAN_STA_TDLS_PEER_AUTH); 2059 - } 1972 + /* we already did checks when looking up the RA STA */ 1973 + tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER); 2060 1974 2061 - if (tdls_peer) 2062 - tdls_setup_frame = 2063 - ethertype == ETH_P_TDLS && 2064 - skb->len > 14 && 2065 - skb->data[14] == WLAN_TDLS_SNAP_RFTYPE; 2066 - } 2067 - 2068 - /* 2069 - * TDLS link during setup - throw out frames to peer. We allow 2070 - * TDLS-setup frames to unauthorized peers for the special case 2071 - * of a link teardown after a TDLS sta is removed due to being 2072 - * unreachable. 2073 - */ 2074 - if (tdls_peer && !tdls_auth && !tdls_setup_frame) { 2075 - ret = -EINVAL; 2076 - goto free; 2077 - } 2078 - 2079 - /* send direct packets to authorized TDLS peers */ 2080 - if (tdls_peer && tdls_auth) { 1975 + if (tdls_peer) { 2081 1976 /* DA SA BSSID */ 2082 1977 memcpy(hdr.addr1, skb->data, ETH_ALEN); 2083 1978 memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); 2084 1979 memcpy(hdr.addr3, sdata->u.mgd.bssid, ETH_ALEN); 2085 1980 hdrlen = 24; 2086 - have_station = true; 2087 - authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); 2088 - wme_sta = sta->sta.wme; 2089 - *sta_out = sta; 2090 1981 } else if (sdata->u.mgd.use_4addr && 2091 1982 cpu_to_be16(ethertype) != sdata->control_port_protocol) { 2092 1983 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | ··· 2114 2063 goto free; 2115 2064 } 2116 2065 2117 - /* 2118 - * There's no need to try to look up the destination station 2119 - * if it is a multicast address. In mesh, there's no need to 2120 - * look up the station at all as it always must be QoS capable 2121 - * and mesh mode checks authorization later. 2122 - */ 2123 2066 multicast = is_multicast_ether_addr(hdr.addr1); 2124 - if (multicast) { 2125 - *sta_out = ERR_PTR(-ENOENT); 2126 - } else if (!have_station && !ieee80211_vif_is_mesh(&sdata->vif)) { 2127 - if (sdata->control_port_protocol == skb->protocol) 2128 - sta = sta_info_get_bss(sdata, hdr.addr1); 2129 - else 2130 - sta = sta_info_get(sdata, hdr.addr1); 2131 - if (sta) { 2132 - authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); 2133 - wme_sta = sta->sta.wme; 2134 - } 2135 - *sta_out = sta ?: ERR_PTR(-ENOENT); 2136 - } 2137 2067 2138 - /* For mesh, the use of the QoS header is mandatory */ 2139 - if (ieee80211_vif_is_mesh(&sdata->vif)) 2068 + /* sta is always NULL for mesh */ 2069 + if (sta) { 2070 + authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); 2071 + wme_sta = sta->sta.wme; 2072 + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { 2073 + /* For mesh, the use of the QoS header is mandatory */ 2140 2074 wme_sta = true; 2075 + } 2141 2076 2142 2077 /* receiver does QoS (which also means we do) use it */ 2143 2078 if (wme_sta) { ··· 2296 2259 u32 info_flags) 2297 2260 { 2298 2261 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 2299 - struct sta_info *sta = NULL; 2262 + struct sta_info *sta; 2300 2263 2301 2264 if (unlikely(skb->len < ETH_HLEN)) { 2302 2265 kfree_skb(skb); ··· 2305 2268 2306 2269 rcu_read_lock(); 2307 2270 2308 - skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta); 2271 + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { 2272 + kfree_skb(skb); 2273 + goto out; 2274 + } 2275 + 2276 + skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); 2309 2277 if (IS_ERR(skb)) 2310 2278 goto out; 2311 2279 ··· 2346 2304 .local = sdata->local, 2347 2305 .sdata = sdata, 2348 2306 }; 2349 - struct sta_info *sta_ignore; 2307 + struct sta_info *sta; 2350 2308 2351 2309 rcu_read_lock(); 2352 2310 2353 - skb = ieee80211_build_hdr(sdata, skb, info_flags, &sta_ignore); 2311 + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { 2312 + kfree_skb(skb); 2313 + skb = ERR_PTR(-EINVAL); 2314 + goto out; 2315 + } 2316 + 2317 + skb = ieee80211_build_hdr(sdata, skb, info_flags, sta); 2354 2318 if (IS_ERR(skb)) 2355 2319 goto out; 2356 2320