aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2011-09-28 07:12:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-30 15:57:07 -0400
commitdfe018bf99537e42c816d3f543620a7e09fcf3cd (patch)
tree9efb4a6d078bb1051ba9dae9342b7685943a3c48
parent768db3438b4b48a33d073093bb364e624409cab7 (diff)
mac80211: handle TDLS high-level commands and frames
Register and implement the TDLS cfg80211 callback functions. Internally prepare and send TDLS management frames. We incorporate local STA capabilities and supported rates with extra IEs given by usermode. The resulting packet is either encapsulated in a data frame, or assembled as an action frame. It is transmitted either directly or through the AP, as mandated by the TDLS specification. Declare support for the TDLS external setup wiphy capability. This tells usermode to handle link setup and discovery on its own, and use the kernel driver for sending TDLS mgmt packets. Signed-off-by: Arik Nemtsov <arik@wizery.com> Cc: Kalyan C Gaddam <chakkal@iit.edu> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/ieee80211.h85
-rw-r--r--include/linux/if_ether.h1
-rw-r--r--net/mac80211/Kconfig12
-rw-r--r--net/mac80211/cfg.c310
-rw-r--r--net/mac80211/main.c4
5 files changed, 412 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index b5e0a5c344f..48363c3c40f 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 */
817struct 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
825struct 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 */
1401enum ieee80211_pub_actioncode {
1402 WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
1403};
1404
1405/* TDLS action codes */
1406enum 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 a3d99ff6e3b..49c38fc8dbc 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 d1886b59bec..7d3b438755f 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
228config 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
228config MAC80211_DEBUG_COUNTERS 240config 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 13061ebc93e..1d17677a0ec 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
2132static 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
2145static 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
2162static 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
2177static int
2178ieee80211_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
2249static int
2250ieee80211_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
2288static 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
2402fail:
2403 dev_kfree_skb(skb);
2404 return ret;
2405}
2406
2407static 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
2131struct cfg80211_ops mac80211_config_ops = { 2439struct 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 a5809a1a623..336ceb9d246 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;