diff options
-rw-r--r-- | include/linux/ieee80211.h | 85 | ||||
-rw-r--r-- | include/linux/if_ether.h | 1 | ||||
-rw-r--r-- | net/mac80211/Kconfig | 12 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 310 | ||||
-rw-r--r-- | net/mac80211/main.c | 4 |
5 files changed, 412 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b5e0a5c344fd..48363c3c40f8 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -759,6 +759,12 @@ struct ieee80211_mgmt { | |||
759 | u8 action; | 759 | u8 action; |
760 | u8 smps_control; | 760 | u8 smps_control; |
761 | } __attribute__ ((packed)) ht_smps; | 761 | } __attribute__ ((packed)) ht_smps; |
762 | struct { | ||
763 | u8 action_code; | ||
764 | u8 dialog_token; | ||
765 | __le16 capability; | ||
766 | u8 variable[0]; | ||
767 | } __packed tdls_discover_resp; | ||
762 | } u; | 768 | } u; |
763 | } __attribute__ ((packed)) action; | 769 | } __attribute__ ((packed)) action; |
764 | } u; | 770 | } u; |
@@ -805,6 +811,52 @@ struct ieee80211_pspoll { | |||
805 | u8 ta[6]; | 811 | u8 ta[6]; |
806 | } __attribute__ ((packed)); | 812 | } __attribute__ ((packed)); |
807 | 813 | ||
814 | /* TDLS */ | ||
815 | |||
816 | /* Link-id information element */ | ||
817 | struct ieee80211_tdls_lnkie { | ||
818 | u8 ie_type; /* Link Identifier IE */ | ||
819 | u8 ie_len; | ||
820 | u8 bssid[6]; | ||
821 | u8 init_sta[6]; | ||
822 | u8 resp_sta[6]; | ||
823 | } __packed; | ||
824 | |||
825 | struct ieee80211_tdls_data { | ||
826 | u8 da[6]; | ||
827 | u8 sa[6]; | ||
828 | __be16 ether_type; | ||
829 | u8 payload_type; | ||
830 | u8 category; | ||
831 | u8 action_code; | ||
832 | union { | ||
833 | struct { | ||
834 | u8 dialog_token; | ||
835 | __le16 capability; | ||
836 | u8 variable[0]; | ||
837 | } __packed setup_req; | ||
838 | struct { | ||
839 | __le16 status_code; | ||
840 | u8 dialog_token; | ||
841 | __le16 capability; | ||
842 | u8 variable[0]; | ||
843 | } __packed setup_resp; | ||
844 | struct { | ||
845 | __le16 status_code; | ||
846 | u8 dialog_token; | ||
847 | u8 variable[0]; | ||
848 | } __packed setup_cfm; | ||
849 | struct { | ||
850 | __le16 reason_code; | ||
851 | u8 variable[0]; | ||
852 | } __packed teardown; | ||
853 | struct { | ||
854 | u8 dialog_token; | ||
855 | u8 variable[0]; | ||
856 | } __packed discover_req; | ||
857 | } u; | ||
858 | } __packed; | ||
859 | |||
808 | /** | 860 | /** |
809 | * struct ieee80211_bar - HT Block Ack Request | 861 | * struct ieee80211_bar - HT Block Ack Request |
810 | * | 862 | * |
@@ -1196,6 +1248,8 @@ enum ieee80211_eid { | |||
1196 | WLAN_EID_TS_DELAY = 43, | 1248 | WLAN_EID_TS_DELAY = 43, |
1197 | WLAN_EID_TCLAS_PROCESSING = 44, | 1249 | WLAN_EID_TCLAS_PROCESSING = 44, |
1198 | WLAN_EID_QOS_CAPA = 46, | 1250 | WLAN_EID_QOS_CAPA = 46, |
1251 | /* 802.11z */ | ||
1252 | WLAN_EID_LINK_ID = 101, | ||
1199 | /* 802.11s */ | 1253 | /* 802.11s */ |
1200 | WLAN_EID_MESH_CONFIG = 113, | 1254 | WLAN_EID_MESH_CONFIG = 113, |
1201 | WLAN_EID_MESH_ID = 114, | 1255 | WLAN_EID_MESH_ID = 114, |
@@ -1279,6 +1333,7 @@ enum ieee80211_category { | |||
1279 | WLAN_CATEGORY_HT = 7, | 1333 | WLAN_CATEGORY_HT = 7, |
1280 | WLAN_CATEGORY_SA_QUERY = 8, | 1334 | WLAN_CATEGORY_SA_QUERY = 8, |
1281 | WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, | 1335 | WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9, |
1336 | WLAN_CATEGORY_TDLS = 12, | ||
1282 | WLAN_CATEGORY_MESH_ACTION = 13, | 1337 | WLAN_CATEGORY_MESH_ACTION = 13, |
1283 | WLAN_CATEGORY_MULTIHOP_ACTION = 14, | 1338 | WLAN_CATEGORY_MULTIHOP_ACTION = 14, |
1284 | WLAN_CATEGORY_SELF_PROTECTED = 15, | 1339 | WLAN_CATEGORY_SELF_PROTECTED = 15, |
@@ -1342,6 +1397,36 @@ enum ieee80211_key_len { | |||
1342 | WLAN_KEY_LEN_AES_CMAC = 16, | 1397 | WLAN_KEY_LEN_AES_CMAC = 16, |
1343 | }; | 1398 | }; |
1344 | 1399 | ||
1400 | /* Public action codes */ | ||
1401 | enum ieee80211_pub_actioncode { | ||
1402 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14, | ||
1403 | }; | ||
1404 | |||
1405 | /* TDLS action codes */ | ||
1406 | enum ieee80211_tdls_actioncode { | ||
1407 | WLAN_TDLS_SETUP_REQUEST = 0, | ||
1408 | WLAN_TDLS_SETUP_RESPONSE = 1, | ||
1409 | WLAN_TDLS_SETUP_CONFIRM = 2, | ||
1410 | WLAN_TDLS_TEARDOWN = 3, | ||
1411 | WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4, | ||
1412 | WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5, | ||
1413 | WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6, | ||
1414 | WLAN_TDLS_PEER_PSM_REQUEST = 7, | ||
1415 | WLAN_TDLS_PEER_PSM_RESPONSE = 8, | ||
1416 | WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9, | ||
1417 | WLAN_TDLS_DISCOVERY_REQUEST = 10, | ||
1418 | }; | ||
1419 | |||
1420 | /* | ||
1421 | * TDLS capabililites to be enabled in the 5th byte of the | ||
1422 | * @WLAN_EID_EXT_CAPABILITY information element | ||
1423 | */ | ||
1424 | #define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5) | ||
1425 | #define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6) | ||
1426 | |||
1427 | /* TDLS specific payload type in the LLC/SNAP header */ | ||
1428 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | ||
1429 | |||
1345 | /** | 1430 | /** |
1346 | * enum - mesh path selection protocol identifier | 1431 | * enum - mesh path selection protocol identifier |
1347 | * | 1432 | * |
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index a3d99ff6e3b5..49c38fc8dbc3 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h | |||
@@ -83,6 +83,7 @@ | |||
83 | #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ | 83 | #define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ |
84 | #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ | 84 | #define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ |
85 | #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ | 85 | #define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ |
86 | #define ETH_P_TDLS 0x890D /* TDLS */ | ||
86 | #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ | 87 | #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ |
87 | #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ | 88 | #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ |
88 | #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ | 89 | #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index d1886b59bec4..7d3b438755f0 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -225,6 +225,18 @@ config MAC80211_VERBOSE_MHWMP_DEBUG | |||
225 | 225 | ||
226 | Do not select this option. | 226 | Do not select this option. |
227 | 227 | ||
228 | config MAC80211_VERBOSE_TDLS_DEBUG | ||
229 | bool "Verbose TDLS debugging" | ||
230 | depends on MAC80211_DEBUG_MENU | ||
231 | ---help--- | ||
232 | Selecting this option causes mac80211 to print out very | ||
233 | verbose TDLS selection debugging messages (when mac80211 | ||
234 | is a TDLS STA). | ||
235 | It should not be selected on production systems as those | ||
236 | messages are remotely triggerable. | ||
237 | |||
238 | Do not select this option. | ||
239 | |||
228 | config MAC80211_DEBUG_COUNTERS | 240 | config MAC80211_DEBUG_COUNTERS |
229 | bool "Extra statistics for TX/RX debugging" | 241 | bool "Extra statistics for TX/RX debugging" |
230 | depends on MAC80211_DEBUG_MENU | 242 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 13061ebc93ef..1d17677a0ec1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <net/net_namespace.h> | 13 | #include <net/net_namespace.h> |
14 | #include <linux/rcupdate.h> | 14 | #include <linux/rcupdate.h> |
15 | #include <linux/if_ether.h> | ||
15 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
16 | #include "ieee80211_i.h" | 17 | #include "ieee80211_i.h" |
17 | #include "driver-ops.h" | 18 | #include "driver-ops.h" |
@@ -2128,6 +2129,313 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy, | |||
2128 | return 0; | 2129 | return 0; |
2129 | } | 2130 | } |
2130 | 2131 | ||
2132 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | ||
2133 | { | ||
2134 | u8 *pos = (void *)skb_put(skb, 7); | ||
2135 | |||
2136 | *pos++ = WLAN_EID_EXT_CAPABILITY; | ||
2137 | *pos++ = 5; /* len */ | ||
2138 | *pos++ = 0x0; | ||
2139 | *pos++ = 0x0; | ||
2140 | *pos++ = 0x0; | ||
2141 | *pos++ = 0x0; | ||
2142 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | ||
2143 | } | ||
2144 | |||
2145 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | ||
2146 | { | ||
2147 | struct ieee80211_local *local = sdata->local; | ||
2148 | u16 capab; | ||
2149 | |||
2150 | capab = 0; | ||
2151 | if (local->oper_channel->band != IEEE80211_BAND_2GHZ) | ||
2152 | return capab; | ||
2153 | |||
2154 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
2155 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
2156 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
2157 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
2158 | |||
2159 | return capab; | ||
2160 | } | ||
2161 | |||
2162 | static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, | ||
2163 | u8 *peer, u8 *bssid) | ||
2164 | { | ||
2165 | struct ieee80211_tdls_lnkie *lnkid; | ||
2166 | |||
2167 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); | ||
2168 | |||
2169 | lnkid->ie_type = WLAN_EID_LINK_ID; | ||
2170 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; | ||
2171 | |||
2172 | memcpy(lnkid->bssid, bssid, ETH_ALEN); | ||
2173 | memcpy(lnkid->init_sta, src_addr, ETH_ALEN); | ||
2174 | memcpy(lnkid->resp_sta, peer, ETH_ALEN); | ||
2175 | } | ||
2176 | |||
2177 | static int | ||
2178 | ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | ||
2179 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2180 | u16 status_code, struct sk_buff *skb) | ||
2181 | { | ||
2182 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2183 | struct ieee80211_tdls_data *tf; | ||
2184 | |||
2185 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | ||
2186 | |||
2187 | memcpy(tf->da, peer, ETH_ALEN); | ||
2188 | memcpy(tf->sa, sdata->vif.addr, ETH_ALEN); | ||
2189 | tf->ether_type = cpu_to_be16(ETH_P_TDLS); | ||
2190 | tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; | ||
2191 | |||
2192 | switch (action_code) { | ||
2193 | case WLAN_TDLS_SETUP_REQUEST: | ||
2194 | tf->category = WLAN_CATEGORY_TDLS; | ||
2195 | tf->action_code = WLAN_TDLS_SETUP_REQUEST; | ||
2196 | |||
2197 | skb_put(skb, sizeof(tf->u.setup_req)); | ||
2198 | tf->u.setup_req.dialog_token = dialog_token; | ||
2199 | tf->u.setup_req.capability = | ||
2200 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2201 | |||
2202 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2203 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2204 | ieee80211_tdls_add_ext_capab(skb); | ||
2205 | break; | ||
2206 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2207 | tf->category = WLAN_CATEGORY_TDLS; | ||
2208 | tf->action_code = WLAN_TDLS_SETUP_RESPONSE; | ||
2209 | |||
2210 | skb_put(skb, sizeof(tf->u.setup_resp)); | ||
2211 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); | ||
2212 | tf->u.setup_resp.dialog_token = dialog_token; | ||
2213 | tf->u.setup_resp.capability = | ||
2214 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2215 | |||
2216 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2217 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2218 | ieee80211_tdls_add_ext_capab(skb); | ||
2219 | break; | ||
2220 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2221 | tf->category = WLAN_CATEGORY_TDLS; | ||
2222 | tf->action_code = WLAN_TDLS_SETUP_CONFIRM; | ||
2223 | |||
2224 | skb_put(skb, sizeof(tf->u.setup_cfm)); | ||
2225 | tf->u.setup_cfm.status_code = cpu_to_le16(status_code); | ||
2226 | tf->u.setup_cfm.dialog_token = dialog_token; | ||
2227 | break; | ||
2228 | case WLAN_TDLS_TEARDOWN: | ||
2229 | tf->category = WLAN_CATEGORY_TDLS; | ||
2230 | tf->action_code = WLAN_TDLS_TEARDOWN; | ||
2231 | |||
2232 | skb_put(skb, sizeof(tf->u.teardown)); | ||
2233 | tf->u.teardown.reason_code = cpu_to_le16(status_code); | ||
2234 | break; | ||
2235 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2236 | tf->category = WLAN_CATEGORY_TDLS; | ||
2237 | tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST; | ||
2238 | |||
2239 | skb_put(skb, sizeof(tf->u.discover_req)); | ||
2240 | tf->u.discover_req.dialog_token = dialog_token; | ||
2241 | break; | ||
2242 | default: | ||
2243 | return -EINVAL; | ||
2244 | } | ||
2245 | |||
2246 | return 0; | ||
2247 | } | ||
2248 | |||
2249 | static int | ||
2250 | ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | ||
2251 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2252 | u16 status_code, struct sk_buff *skb) | ||
2253 | { | ||
2254 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2255 | struct ieee80211_mgmt *mgmt; | ||
2256 | |||
2257 | mgmt = (void *)skb_put(skb, 24); | ||
2258 | memset(mgmt, 0, 24); | ||
2259 | memcpy(mgmt->da, peer, ETH_ALEN); | ||
2260 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
2261 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | ||
2262 | |||
2263 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2264 | IEEE80211_STYPE_ACTION); | ||
2265 | |||
2266 | switch (action_code) { | ||
2267 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2268 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp)); | ||
2269 | mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; | ||
2270 | mgmt->u.action.u.tdls_discover_resp.action_code = | ||
2271 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES; | ||
2272 | mgmt->u.action.u.tdls_discover_resp.dialog_token = | ||
2273 | dialog_token; | ||
2274 | mgmt->u.action.u.tdls_discover_resp.capability = | ||
2275 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2276 | |||
2277 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2278 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2279 | ieee80211_tdls_add_ext_capab(skb); | ||
2280 | break; | ||
2281 | default: | ||
2282 | return -EINVAL; | ||
2283 | } | ||
2284 | |||
2285 | return 0; | ||
2286 | } | ||
2287 | |||
2288 | static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
2289 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2290 | u16 status_code, const u8 *extra_ies, | ||
2291 | size_t extra_ies_len) | ||
2292 | { | ||
2293 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2294 | struct ieee80211_local *local = sdata->local; | ||
2295 | struct ieee80211_tx_info *info; | ||
2296 | struct sk_buff *skb = NULL; | ||
2297 | bool send_direct; | ||
2298 | int ret; | ||
2299 | |||
2300 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2301 | return -ENOTSUPP; | ||
2302 | |||
2303 | /* make sure we are in managed mode, and associated */ | ||
2304 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
2305 | !sdata->u.mgd.associated) | ||
2306 | return -EINVAL; | ||
2307 | |||
2308 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | ||
2309 | printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer); | ||
2310 | #endif | ||
2311 | |||
2312 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
2313 | max(sizeof(struct ieee80211_mgmt), | ||
2314 | sizeof(struct ieee80211_tdls_data)) + | ||
2315 | 50 + /* supported rates */ | ||
2316 | 7 + /* ext capab */ | ||
2317 | extra_ies_len + | ||
2318 | sizeof(struct ieee80211_tdls_lnkie)); | ||
2319 | if (!skb) | ||
2320 | return -ENOMEM; | ||
2321 | |||
2322 | info = IEEE80211_SKB_CB(skb); | ||
2323 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2324 | |||
2325 | switch (action_code) { | ||
2326 | case WLAN_TDLS_SETUP_REQUEST: | ||
2327 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2328 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2329 | case WLAN_TDLS_TEARDOWN: | ||
2330 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2331 | ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer, | ||
2332 | action_code, dialog_token, | ||
2333 | status_code, skb); | ||
2334 | send_direct = false; | ||
2335 | break; | ||
2336 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2337 | ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code, | ||
2338 | dialog_token, status_code, | ||
2339 | skb); | ||
2340 | send_direct = true; | ||
2341 | break; | ||
2342 | default: | ||
2343 | ret = -ENOTSUPP; | ||
2344 | break; | ||
2345 | } | ||
2346 | |||
2347 | if (ret < 0) | ||
2348 | goto fail; | ||
2349 | |||
2350 | if (extra_ies_len) | ||
2351 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | ||
2352 | |||
2353 | /* the TDLS link IE is always added last */ | ||
2354 | switch (action_code) { | ||
2355 | case WLAN_TDLS_SETUP_REQUEST: | ||
2356 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2357 | case WLAN_TDLS_TEARDOWN: | ||
2358 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2359 | /* we are the initiator */ | ||
2360 | ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer, | ||
2361 | sdata->u.mgd.bssid); | ||
2362 | break; | ||
2363 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2364 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2365 | /* we are the responder */ | ||
2366 | ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr, | ||
2367 | sdata->u.mgd.bssid); | ||
2368 | break; | ||
2369 | default: | ||
2370 | ret = -ENOTSUPP; | ||
2371 | goto fail; | ||
2372 | } | ||
2373 | |||
2374 | if (send_direct) { | ||
2375 | ieee80211_tx_skb(sdata, skb); | ||
2376 | return 0; | ||
2377 | } | ||
2378 | |||
2379 | /* | ||
2380 | * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise | ||
2381 | * we should default to AC_VI. | ||
2382 | */ | ||
2383 | switch (action_code) { | ||
2384 | case WLAN_TDLS_SETUP_REQUEST: | ||
2385 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2386 | skb_set_queue_mapping(skb, IEEE80211_AC_BK); | ||
2387 | skb->priority = 2; | ||
2388 | break; | ||
2389 | default: | ||
2390 | skb_set_queue_mapping(skb, IEEE80211_AC_VI); | ||
2391 | skb->priority = 5; | ||
2392 | break; | ||
2393 | } | ||
2394 | |||
2395 | /* disable bottom halves when entering the Tx path */ | ||
2396 | local_bh_disable(); | ||
2397 | ret = ieee80211_subif_start_xmit(skb, dev); | ||
2398 | local_bh_enable(); | ||
2399 | |||
2400 | return ret; | ||
2401 | |||
2402 | fail: | ||
2403 | dev_kfree_skb(skb); | ||
2404 | return ret; | ||
2405 | } | ||
2406 | |||
2407 | static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | ||
2408 | u8 *peer, enum nl80211_tdls_operation oper) | ||
2409 | { | ||
2410 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2411 | |||
2412 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2413 | return -ENOTSUPP; | ||
2414 | |||
2415 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2416 | return -EINVAL; | ||
2417 | |||
2418 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | ||
2419 | printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer); | ||
2420 | #endif | ||
2421 | |||
2422 | switch (oper) { | ||
2423 | case NL80211_TDLS_ENABLE_LINK: | ||
2424 | break; | ||
2425 | case NL80211_TDLS_DISABLE_LINK: | ||
2426 | return sta_info_destroy_addr(sdata, peer); | ||
2427 | case NL80211_TDLS_TEARDOWN: | ||
2428 | case NL80211_TDLS_SETUP: | ||
2429 | case NL80211_TDLS_DISCOVERY_REQ: | ||
2430 | /* We don't support in-driver setup/teardown/discovery */ | ||
2431 | return -ENOTSUPP; | ||
2432 | default: | ||
2433 | return -ENOTSUPP; | ||
2434 | } | ||
2435 | |||
2436 | return 0; | ||
2437 | } | ||
2438 | |||
2131 | struct cfg80211_ops mac80211_config_ops = { | 2439 | struct cfg80211_ops mac80211_config_ops = { |
2132 | .add_virtual_intf = ieee80211_add_iface, | 2440 | .add_virtual_intf = ieee80211_add_iface, |
2133 | .del_virtual_intf = ieee80211_del_iface, | 2441 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2191,4 +2499,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2191 | .set_ringparam = ieee80211_set_ringparam, | 2499 | .set_ringparam = ieee80211_set_ringparam, |
2192 | .get_ringparam = ieee80211_get_ringparam, | 2500 | .get_ringparam = ieee80211_get_ringparam, |
2193 | .set_rekey_data = ieee80211_set_rekey_data, | 2501 | .set_rekey_data = ieee80211_set_rekey_data, |
2502 | .tdls_oper = ieee80211_tdls_oper, | ||
2503 | .tdls_mgmt = ieee80211_tdls_mgmt, | ||
2194 | }; | 2504 | }; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index a5809a1a6239..336ceb9d2462 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -863,6 +863,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
863 | if (local->ops->sched_scan_start) | 863 | if (local->ops->sched_scan_start) |
864 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 864 | local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
865 | 865 | ||
866 | /* mac80211 based drivers don't support internal TDLS setup */ | ||
867 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) | ||
868 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; | ||
869 | |||
866 | result = wiphy_register(local->hw.wiphy); | 870 | result = wiphy_register(local->hw.wiphy); |
867 | if (result < 0) | 871 | if (result < 0) |
868 | goto fail_wiphy_register; | 872 | goto fail_wiphy_register; |