diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-10-11 15:35:42 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-10-11 15:35:42 -0400 |
commit | 094daf7db7c47861009899ce23f9177d761e20b0 (patch) | |
tree | a107065393720b80664157a035b206576e834793 /net/mac80211/cfg.c | |
parent | 3ed6f6958c0ac21958285d8648f14d34da4bbcb3 (diff) | |
parent | 5f68a2b0a890d086e40fc7b55f4a0c32c28bc0d2 (diff) |
Merge branch 'master' of git://git.infradead.org/users/linville/wireless-next into for-davem
Conflicts:
Documentation/feature-removal-schedule.txt
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 380 |
1 files changed, 363 insertions, 17 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9b1a95e1f56a..55ee5a31756f 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" |
@@ -667,7 +668,6 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
667 | struct sta_info *sta, | 668 | struct sta_info *sta, |
668 | struct station_parameters *params) | 669 | struct station_parameters *params) |
669 | { | 670 | { |
670 | unsigned long flags; | ||
671 | u32 rates; | 671 | u32 rates; |
672 | int i, j; | 672 | int i, j; |
673 | struct ieee80211_supported_band *sband; | 673 | struct ieee80211_supported_band *sband; |
@@ -676,46 +676,58 @@ static void sta_apply_parameters(struct ieee80211_local *local, | |||
676 | 676 | ||
677 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 677 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
678 | 678 | ||
679 | spin_lock_irqsave(&sta->flaglock, flags); | ||
680 | mask = params->sta_flags_mask; | 679 | mask = params->sta_flags_mask; |
681 | set = params->sta_flags_set; | 680 | set = params->sta_flags_set; |
682 | 681 | ||
683 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { | 682 | if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) { |
684 | sta->flags &= ~WLAN_STA_AUTHORIZED; | ||
685 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) | 683 | if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) |
686 | sta->flags |= WLAN_STA_AUTHORIZED; | 684 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); |
685 | else | ||
686 | clear_sta_flag(sta, WLAN_STA_AUTHORIZED); | ||
687 | } | 687 | } |
688 | 688 | ||
689 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { | 689 | if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) { |
690 | sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; | ||
691 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) | 690 | if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) |
692 | sta->flags |= WLAN_STA_SHORT_PREAMBLE; | 691 | set_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); |
692 | else | ||
693 | clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE); | ||
693 | } | 694 | } |
694 | 695 | ||
695 | if (mask & BIT(NL80211_STA_FLAG_WME)) { | 696 | if (mask & BIT(NL80211_STA_FLAG_WME)) { |
696 | sta->flags &= ~WLAN_STA_WME; | ||
697 | sta->sta.wme = false; | ||
698 | if (set & BIT(NL80211_STA_FLAG_WME)) { | 697 | if (set & BIT(NL80211_STA_FLAG_WME)) { |
699 | sta->flags |= WLAN_STA_WME; | 698 | set_sta_flag(sta, WLAN_STA_WME); |
700 | sta->sta.wme = true; | 699 | sta->sta.wme = true; |
700 | } else { | ||
701 | clear_sta_flag(sta, WLAN_STA_WME); | ||
702 | sta->sta.wme = false; | ||
701 | } | 703 | } |
702 | } | 704 | } |
703 | 705 | ||
704 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { | 706 | if (mask & BIT(NL80211_STA_FLAG_MFP)) { |
705 | sta->flags &= ~WLAN_STA_MFP; | ||
706 | if (set & BIT(NL80211_STA_FLAG_MFP)) | 707 | if (set & BIT(NL80211_STA_FLAG_MFP)) |
707 | sta->flags |= WLAN_STA_MFP; | 708 | set_sta_flag(sta, WLAN_STA_MFP); |
709 | else | ||
710 | clear_sta_flag(sta, WLAN_STA_MFP); | ||
708 | } | 711 | } |
709 | 712 | ||
710 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { | 713 | if (mask & BIT(NL80211_STA_FLAG_AUTHENTICATED)) { |
711 | sta->flags &= ~WLAN_STA_AUTH; | ||
712 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) | 714 | if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) |
713 | sta->flags |= WLAN_STA_AUTH; | 715 | set_sta_flag(sta, WLAN_STA_AUTH); |
716 | else | ||
717 | clear_sta_flag(sta, WLAN_STA_AUTH); | ||
714 | } | 718 | } |
715 | spin_unlock_irqrestore(&sta->flaglock, flags); | ||
716 | 719 | ||
717 | sta->sta.uapsd_queues = params->uapsd_queues; | 720 | if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { |
718 | sta->sta.max_sp = params->max_sp; | 721 | if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) |
722 | set_sta_flag(sta, WLAN_STA_TDLS_PEER); | ||
723 | else | ||
724 | clear_sta_flag(sta, WLAN_STA_TDLS_PEER); | ||
725 | } | ||
726 | |||
727 | if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { | ||
728 | sta->sta.uapsd_queues = params->uapsd_queues; | ||
729 | sta->sta.max_sp = params->max_sp; | ||
730 | } | ||
719 | 731 | ||
720 | /* | 732 | /* |
721 | * cfg80211 validates this (1-2007) and allows setting the AID | 733 | * cfg80211 validates this (1-2007) and allows setting the AID |
@@ -806,10 +818,17 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
806 | if (!sta) | 818 | if (!sta) |
807 | return -ENOMEM; | 819 | return -ENOMEM; |
808 | 820 | ||
809 | sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 821 | set_sta_flag(sta, WLAN_STA_AUTH); |
822 | set_sta_flag(sta, WLAN_STA_ASSOC); | ||
810 | 823 | ||
811 | sta_apply_parameters(local, sta, params); | 824 | sta_apply_parameters(local, sta, params); |
812 | 825 | ||
826 | /* Only TDLS-supporting stations can add TDLS peers */ | ||
827 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && | ||
828 | !((wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) && | ||
829 | sdata->vif.type == NL80211_IFTYPE_STATION)) | ||
830 | return -ENOTSUPP; | ||
831 | |||
813 | rate_control_rate_init(sta); | 832 | rate_control_rate_init(sta); |
814 | 833 | ||
815 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 834 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
@@ -862,6 +881,14 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
862 | return -ENOENT; | 881 | return -ENOENT; |
863 | } | 882 | } |
864 | 883 | ||
884 | /* The TDLS bit cannot be toggled after the STA was added */ | ||
885 | if ((params->sta_flags_mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) && | ||
886 | !!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) != | ||
887 | !!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { | ||
888 | rcu_read_unlock(); | ||
889 | return -EINVAL; | ||
890 | } | ||
891 | |||
865 | if (params->vlan && params->vlan != sta->sdata->dev) { | 892 | if (params->vlan && params->vlan != sta->sdata->dev) { |
866 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 893 | vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
867 | 894 | ||
@@ -2126,6 +2153,323 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy, | |||
2126 | return 0; | 2153 | return 0; |
2127 | } | 2154 | } |
2128 | 2155 | ||
2156 | static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb) | ||
2157 | { | ||
2158 | u8 *pos = (void *)skb_put(skb, 7); | ||
2159 | |||
2160 | *pos++ = WLAN_EID_EXT_CAPABILITY; | ||
2161 | *pos++ = 5; /* len */ | ||
2162 | *pos++ = 0x0; | ||
2163 | *pos++ = 0x0; | ||
2164 | *pos++ = 0x0; | ||
2165 | *pos++ = 0x0; | ||
2166 | *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; | ||
2167 | } | ||
2168 | |||
2169 | static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata) | ||
2170 | { | ||
2171 | struct ieee80211_local *local = sdata->local; | ||
2172 | u16 capab; | ||
2173 | |||
2174 | capab = 0; | ||
2175 | if (local->oper_channel->band != IEEE80211_BAND_2GHZ) | ||
2176 | return capab; | ||
2177 | |||
2178 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
2179 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
2180 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
2181 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
2182 | |||
2183 | return capab; | ||
2184 | } | ||
2185 | |||
2186 | static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, | ||
2187 | u8 *peer, u8 *bssid) | ||
2188 | { | ||
2189 | struct ieee80211_tdls_lnkie *lnkid; | ||
2190 | |||
2191 | lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie)); | ||
2192 | |||
2193 | lnkid->ie_type = WLAN_EID_LINK_ID; | ||
2194 | lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; | ||
2195 | |||
2196 | memcpy(lnkid->bssid, bssid, ETH_ALEN); | ||
2197 | memcpy(lnkid->init_sta, src_addr, ETH_ALEN); | ||
2198 | memcpy(lnkid->resp_sta, peer, ETH_ALEN); | ||
2199 | } | ||
2200 | |||
2201 | static int | ||
2202 | ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | ||
2203 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2204 | u16 status_code, struct sk_buff *skb) | ||
2205 | { | ||
2206 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2207 | struct ieee80211_tdls_data *tf; | ||
2208 | |||
2209 | tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u)); | ||
2210 | |||
2211 | memcpy(tf->da, peer, ETH_ALEN); | ||
2212 | memcpy(tf->sa, sdata->vif.addr, ETH_ALEN); | ||
2213 | tf->ether_type = cpu_to_be16(ETH_P_TDLS); | ||
2214 | tf->payload_type = WLAN_TDLS_SNAP_RFTYPE; | ||
2215 | |||
2216 | switch (action_code) { | ||
2217 | case WLAN_TDLS_SETUP_REQUEST: | ||
2218 | tf->category = WLAN_CATEGORY_TDLS; | ||
2219 | tf->action_code = WLAN_TDLS_SETUP_REQUEST; | ||
2220 | |||
2221 | skb_put(skb, sizeof(tf->u.setup_req)); | ||
2222 | tf->u.setup_req.dialog_token = dialog_token; | ||
2223 | tf->u.setup_req.capability = | ||
2224 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2225 | |||
2226 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2227 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2228 | ieee80211_tdls_add_ext_capab(skb); | ||
2229 | break; | ||
2230 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2231 | tf->category = WLAN_CATEGORY_TDLS; | ||
2232 | tf->action_code = WLAN_TDLS_SETUP_RESPONSE; | ||
2233 | |||
2234 | skb_put(skb, sizeof(tf->u.setup_resp)); | ||
2235 | tf->u.setup_resp.status_code = cpu_to_le16(status_code); | ||
2236 | tf->u.setup_resp.dialog_token = dialog_token; | ||
2237 | tf->u.setup_resp.capability = | ||
2238 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2239 | |||
2240 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2241 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2242 | ieee80211_tdls_add_ext_capab(skb); | ||
2243 | break; | ||
2244 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2245 | tf->category = WLAN_CATEGORY_TDLS; | ||
2246 | tf->action_code = WLAN_TDLS_SETUP_CONFIRM; | ||
2247 | |||
2248 | skb_put(skb, sizeof(tf->u.setup_cfm)); | ||
2249 | tf->u.setup_cfm.status_code = cpu_to_le16(status_code); | ||
2250 | tf->u.setup_cfm.dialog_token = dialog_token; | ||
2251 | break; | ||
2252 | case WLAN_TDLS_TEARDOWN: | ||
2253 | tf->category = WLAN_CATEGORY_TDLS; | ||
2254 | tf->action_code = WLAN_TDLS_TEARDOWN; | ||
2255 | |||
2256 | skb_put(skb, sizeof(tf->u.teardown)); | ||
2257 | tf->u.teardown.reason_code = cpu_to_le16(status_code); | ||
2258 | break; | ||
2259 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2260 | tf->category = WLAN_CATEGORY_TDLS; | ||
2261 | tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST; | ||
2262 | |||
2263 | skb_put(skb, sizeof(tf->u.discover_req)); | ||
2264 | tf->u.discover_req.dialog_token = dialog_token; | ||
2265 | break; | ||
2266 | default: | ||
2267 | return -EINVAL; | ||
2268 | } | ||
2269 | |||
2270 | return 0; | ||
2271 | } | ||
2272 | |||
2273 | static int | ||
2274 | ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | ||
2275 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2276 | u16 status_code, struct sk_buff *skb) | ||
2277 | { | ||
2278 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2279 | struct ieee80211_mgmt *mgmt; | ||
2280 | |||
2281 | mgmt = (void *)skb_put(skb, 24); | ||
2282 | memset(mgmt, 0, 24); | ||
2283 | memcpy(mgmt->da, peer, ETH_ALEN); | ||
2284 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
2285 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); | ||
2286 | |||
2287 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
2288 | IEEE80211_STYPE_ACTION); | ||
2289 | |||
2290 | switch (action_code) { | ||
2291 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2292 | skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp)); | ||
2293 | mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; | ||
2294 | mgmt->u.action.u.tdls_discover_resp.action_code = | ||
2295 | WLAN_PUB_ACTION_TDLS_DISCOVER_RES; | ||
2296 | mgmt->u.action.u.tdls_discover_resp.dialog_token = | ||
2297 | dialog_token; | ||
2298 | mgmt->u.action.u.tdls_discover_resp.capability = | ||
2299 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | ||
2300 | |||
2301 | ieee80211_add_srates_ie(&sdata->vif, skb); | ||
2302 | ieee80211_add_ext_srates_ie(&sdata->vif, skb); | ||
2303 | ieee80211_tdls_add_ext_capab(skb); | ||
2304 | break; | ||
2305 | default: | ||
2306 | return -EINVAL; | ||
2307 | } | ||
2308 | |||
2309 | return 0; | ||
2310 | } | ||
2311 | |||
2312 | static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | ||
2313 | u8 *peer, u8 action_code, u8 dialog_token, | ||
2314 | u16 status_code, const u8 *extra_ies, | ||
2315 | size_t extra_ies_len) | ||
2316 | { | ||
2317 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2318 | struct ieee80211_local *local = sdata->local; | ||
2319 | struct ieee80211_tx_info *info; | ||
2320 | struct sk_buff *skb = NULL; | ||
2321 | bool send_direct; | ||
2322 | int ret; | ||
2323 | |||
2324 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2325 | return -ENOTSUPP; | ||
2326 | |||
2327 | /* make sure we are in managed mode, and associated */ | ||
2328 | if (sdata->vif.type != NL80211_IFTYPE_STATION || | ||
2329 | !sdata->u.mgd.associated) | ||
2330 | return -EINVAL; | ||
2331 | |||
2332 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | ||
2333 | printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer); | ||
2334 | #endif | ||
2335 | |||
2336 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
2337 | max(sizeof(struct ieee80211_mgmt), | ||
2338 | sizeof(struct ieee80211_tdls_data)) + | ||
2339 | 50 + /* supported rates */ | ||
2340 | 7 + /* ext capab */ | ||
2341 | extra_ies_len + | ||
2342 | sizeof(struct ieee80211_tdls_lnkie)); | ||
2343 | if (!skb) | ||
2344 | return -ENOMEM; | ||
2345 | |||
2346 | info = IEEE80211_SKB_CB(skb); | ||
2347 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2348 | |||
2349 | switch (action_code) { | ||
2350 | case WLAN_TDLS_SETUP_REQUEST: | ||
2351 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2352 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2353 | case WLAN_TDLS_TEARDOWN: | ||
2354 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2355 | ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer, | ||
2356 | action_code, dialog_token, | ||
2357 | status_code, skb); | ||
2358 | send_direct = false; | ||
2359 | break; | ||
2360 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2361 | ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code, | ||
2362 | dialog_token, status_code, | ||
2363 | skb); | ||
2364 | send_direct = true; | ||
2365 | break; | ||
2366 | default: | ||
2367 | ret = -ENOTSUPP; | ||
2368 | break; | ||
2369 | } | ||
2370 | |||
2371 | if (ret < 0) | ||
2372 | goto fail; | ||
2373 | |||
2374 | if (extra_ies_len) | ||
2375 | memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len); | ||
2376 | |||
2377 | /* the TDLS link IE is always added last */ | ||
2378 | switch (action_code) { | ||
2379 | case WLAN_TDLS_SETUP_REQUEST: | ||
2380 | case WLAN_TDLS_SETUP_CONFIRM: | ||
2381 | case WLAN_TDLS_TEARDOWN: | ||
2382 | case WLAN_TDLS_DISCOVERY_REQUEST: | ||
2383 | /* we are the initiator */ | ||
2384 | ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer, | ||
2385 | sdata->u.mgd.bssid); | ||
2386 | break; | ||
2387 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2388 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | ||
2389 | /* we are the responder */ | ||
2390 | ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr, | ||
2391 | sdata->u.mgd.bssid); | ||
2392 | break; | ||
2393 | default: | ||
2394 | ret = -ENOTSUPP; | ||
2395 | goto fail; | ||
2396 | } | ||
2397 | |||
2398 | if (send_direct) { | ||
2399 | ieee80211_tx_skb(sdata, skb); | ||
2400 | return 0; | ||
2401 | } | ||
2402 | |||
2403 | /* | ||
2404 | * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise | ||
2405 | * we should default to AC_VI. | ||
2406 | */ | ||
2407 | switch (action_code) { | ||
2408 | case WLAN_TDLS_SETUP_REQUEST: | ||
2409 | case WLAN_TDLS_SETUP_RESPONSE: | ||
2410 | skb_set_queue_mapping(skb, IEEE80211_AC_BK); | ||
2411 | skb->priority = 2; | ||
2412 | break; | ||
2413 | default: | ||
2414 | skb_set_queue_mapping(skb, IEEE80211_AC_VI); | ||
2415 | skb->priority = 5; | ||
2416 | break; | ||
2417 | } | ||
2418 | |||
2419 | /* disable bottom halves when entering the Tx path */ | ||
2420 | local_bh_disable(); | ||
2421 | ret = ieee80211_subif_start_xmit(skb, dev); | ||
2422 | local_bh_enable(); | ||
2423 | |||
2424 | return ret; | ||
2425 | |||
2426 | fail: | ||
2427 | dev_kfree_skb(skb); | ||
2428 | return ret; | ||
2429 | } | ||
2430 | |||
2431 | static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | ||
2432 | u8 *peer, enum nl80211_tdls_operation oper) | ||
2433 | { | ||
2434 | struct sta_info *sta; | ||
2435 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2436 | |||
2437 | if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
2438 | return -ENOTSUPP; | ||
2439 | |||
2440 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
2441 | return -EINVAL; | ||
2442 | |||
2443 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | ||
2444 | printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer); | ||
2445 | #endif | ||
2446 | |||
2447 | switch (oper) { | ||
2448 | case NL80211_TDLS_ENABLE_LINK: | ||
2449 | rcu_read_lock(); | ||
2450 | sta = sta_info_get(sdata, peer); | ||
2451 | if (!sta) { | ||
2452 | rcu_read_unlock(); | ||
2453 | return -ENOLINK; | ||
2454 | } | ||
2455 | |||
2456 | set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); | ||
2457 | rcu_read_unlock(); | ||
2458 | break; | ||
2459 | case NL80211_TDLS_DISABLE_LINK: | ||
2460 | return sta_info_destroy_addr(sdata, peer); | ||
2461 | case NL80211_TDLS_TEARDOWN: | ||
2462 | case NL80211_TDLS_SETUP: | ||
2463 | case NL80211_TDLS_DISCOVERY_REQ: | ||
2464 | /* We don't support in-driver setup/teardown/discovery */ | ||
2465 | return -ENOTSUPP; | ||
2466 | default: | ||
2467 | return -ENOTSUPP; | ||
2468 | } | ||
2469 | |||
2470 | return 0; | ||
2471 | } | ||
2472 | |||
2129 | struct cfg80211_ops mac80211_config_ops = { | 2473 | struct cfg80211_ops mac80211_config_ops = { |
2130 | .add_virtual_intf = ieee80211_add_iface, | 2474 | .add_virtual_intf = ieee80211_add_iface, |
2131 | .del_virtual_intf = ieee80211_del_iface, | 2475 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2189,4 +2533,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2189 | .set_ringparam = ieee80211_set_ringparam, | 2533 | .set_ringparam = ieee80211_set_ringparam, |
2190 | .get_ringparam = ieee80211_get_ringparam, | 2534 | .get_ringparam = ieee80211_get_ringparam, |
2191 | .set_rekey_data = ieee80211_set_rekey_data, | 2535 | .set_rekey_data = ieee80211_set_rekey_data, |
2536 | .tdls_oper = ieee80211_tdls_oper, | ||
2537 | .tdls_mgmt = ieee80211_tdls_mgmt, | ||
2192 | }; | 2538 | }; |