aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2014-05-01 03:17:28 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-05-05 09:56:15 -0400
commit95224fe83e5e78e042c96f2c43fa9092a3bc10ef (patch)
treec42b846315dfc54d893655984d6066c58c4bdbdb /net
parent0c4972ccaa27620fe4281ac5c8c536978a563345 (diff)
mac80211: move TDLS code to another file
With new additions planned, this code is getting too big for cfg.c. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/cfg.c314
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/tdls.c325
4 files changed, 336 insertions, 315 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 9d7d840aac6d..1e46ffa69167 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -25,7 +25,8 @@ mac80211-y := \
25 wme.o \ 25 wme.o \
26 event.o \ 26 event.o \
27 chan.o \ 27 chan.o \
28 trace.o mlme.o 28 trace.o mlme.o \
29 tdls.o
29 30
30mac80211-$(CONFIG_MAC80211_LEDS) += led.o 31mac80211-$(CONFIG_MAC80211_LEDS) += led.o
31mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ 32mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d8b236633ca3..19a7e6ff45d3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3508,320 +3508,6 @@ static int ieee80211_set_rekey_data(struct wiphy *wiphy,
3508 return 0; 3508 return 0;
3509} 3509}
3510 3510
3511static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
3512{
3513 u8 *pos = (void *)skb_put(skb, 7);
3514
3515 *pos++ = WLAN_EID_EXT_CAPABILITY;
3516 *pos++ = 5; /* len */
3517 *pos++ = 0x0;
3518 *pos++ = 0x0;
3519 *pos++ = 0x0;
3520 *pos++ = 0x0;
3521 *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
3522}
3523
3524static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
3525{
3526 struct ieee80211_local *local = sdata->local;
3527 u16 capab;
3528
3529 capab = 0;
3530 if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
3531 return capab;
3532
3533 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
3534 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
3535 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
3536 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
3537
3538 return capab;
3539}
3540
3541static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
3542 u8 *peer, u8 *bssid)
3543{
3544 struct ieee80211_tdls_lnkie *lnkid;
3545
3546 lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
3547
3548 lnkid->ie_type = WLAN_EID_LINK_ID;
3549 lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
3550
3551 memcpy(lnkid->bssid, bssid, ETH_ALEN);
3552 memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
3553 memcpy(lnkid->resp_sta, peer, ETH_ALEN);
3554}
3555
3556static int
3557ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
3558 u8 *peer, u8 action_code, u8 dialog_token,
3559 u16 status_code, struct sk_buff *skb)
3560{
3561 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3562 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
3563 struct ieee80211_tdls_data *tf;
3564
3565 tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
3566
3567 memcpy(tf->da, peer, ETH_ALEN);
3568 memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
3569 tf->ether_type = cpu_to_be16(ETH_P_TDLS);
3570 tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
3571
3572 switch (action_code) {
3573 case WLAN_TDLS_SETUP_REQUEST:
3574 tf->category = WLAN_CATEGORY_TDLS;
3575 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
3576
3577 skb_put(skb, sizeof(tf->u.setup_req));
3578 tf->u.setup_req.dialog_token = dialog_token;
3579 tf->u.setup_req.capability =
3580 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
3581
3582 ieee80211_add_srates_ie(sdata, skb, false, band);
3583 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
3584 ieee80211_tdls_add_ext_capab(skb);
3585 break;
3586 case WLAN_TDLS_SETUP_RESPONSE:
3587 tf->category = WLAN_CATEGORY_TDLS;
3588 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
3589
3590 skb_put(skb, sizeof(tf->u.setup_resp));
3591 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
3592 tf->u.setup_resp.dialog_token = dialog_token;
3593 tf->u.setup_resp.capability =
3594 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
3595
3596 ieee80211_add_srates_ie(sdata, skb, false, band);
3597 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
3598 ieee80211_tdls_add_ext_capab(skb);
3599 break;
3600 case WLAN_TDLS_SETUP_CONFIRM:
3601 tf->category = WLAN_CATEGORY_TDLS;
3602 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
3603
3604 skb_put(skb, sizeof(tf->u.setup_cfm));
3605 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
3606 tf->u.setup_cfm.dialog_token = dialog_token;
3607 break;
3608 case WLAN_TDLS_TEARDOWN:
3609 tf->category = WLAN_CATEGORY_TDLS;
3610 tf->action_code = WLAN_TDLS_TEARDOWN;
3611
3612 skb_put(skb, sizeof(tf->u.teardown));
3613 tf->u.teardown.reason_code = cpu_to_le16(status_code);
3614 break;
3615 case WLAN_TDLS_DISCOVERY_REQUEST:
3616 tf->category = WLAN_CATEGORY_TDLS;
3617 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
3618
3619 skb_put(skb, sizeof(tf->u.discover_req));
3620 tf->u.discover_req.dialog_token = dialog_token;
3621 break;
3622 default:
3623 return -EINVAL;
3624 }
3625
3626 return 0;
3627}
3628
3629static int
3630ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
3631 u8 *peer, u8 action_code, u8 dialog_token,
3632 u16 status_code, struct sk_buff *skb)
3633{
3634 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3635 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
3636 struct ieee80211_mgmt *mgmt;
3637
3638 mgmt = (void *)skb_put(skb, 24);
3639 memset(mgmt, 0, 24);
3640 memcpy(mgmt->da, peer, ETH_ALEN);
3641 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
3642 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
3643
3644 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3645 IEEE80211_STYPE_ACTION);
3646
3647 switch (action_code) {
3648 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
3649 skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
3650 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
3651 mgmt->u.action.u.tdls_discover_resp.action_code =
3652 WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
3653 mgmt->u.action.u.tdls_discover_resp.dialog_token =
3654 dialog_token;
3655 mgmt->u.action.u.tdls_discover_resp.capability =
3656 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
3657
3658 ieee80211_add_srates_ie(sdata, skb, false, band);
3659 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
3660 ieee80211_tdls_add_ext_capab(skb);
3661 break;
3662 default:
3663 return -EINVAL;
3664 }
3665
3666 return 0;
3667}
3668
3669static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
3670 u8 *peer, u8 action_code, u8 dialog_token,
3671 u16 status_code, u32 peer_capability,
3672 const u8 *extra_ies, size_t extra_ies_len)
3673{
3674 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3675 struct ieee80211_local *local = sdata->local;
3676 struct sk_buff *skb = NULL;
3677 bool send_direct;
3678 int ret;
3679
3680 if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
3681 return -ENOTSUPP;
3682
3683 /* make sure we are in managed mode, and associated */
3684 if (sdata->vif.type != NL80211_IFTYPE_STATION ||
3685 !sdata->u.mgd.associated)
3686 return -EINVAL;
3687
3688 tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
3689 action_code, peer);
3690
3691 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
3692 max(sizeof(struct ieee80211_mgmt),
3693 sizeof(struct ieee80211_tdls_data)) +
3694 50 + /* supported rates */
3695 7 + /* ext capab */
3696 extra_ies_len +
3697 sizeof(struct ieee80211_tdls_lnkie));
3698 if (!skb)
3699 return -ENOMEM;
3700
3701 skb_reserve(skb, local->hw.extra_tx_headroom);
3702
3703 switch (action_code) {
3704 case WLAN_TDLS_SETUP_REQUEST:
3705 case WLAN_TDLS_SETUP_RESPONSE:
3706 case WLAN_TDLS_SETUP_CONFIRM:
3707 case WLAN_TDLS_TEARDOWN:
3708 case WLAN_TDLS_DISCOVERY_REQUEST:
3709 ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
3710 action_code, dialog_token,
3711 status_code, skb);
3712 send_direct = false;
3713 break;
3714 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
3715 ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
3716 dialog_token, status_code,
3717 skb);
3718 send_direct = true;
3719 break;
3720 default:
3721 ret = -ENOTSUPP;
3722 break;
3723 }
3724
3725 if (ret < 0)
3726 goto fail;
3727
3728 if (extra_ies_len)
3729 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
3730
3731 /* the TDLS link IE is always added last */
3732 switch (action_code) {
3733 case WLAN_TDLS_SETUP_REQUEST:
3734 case WLAN_TDLS_SETUP_CONFIRM:
3735 case WLAN_TDLS_TEARDOWN:
3736 case WLAN_TDLS_DISCOVERY_REQUEST:
3737 /* we are the initiator */
3738 ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
3739 sdata->u.mgd.bssid);
3740 break;
3741 case WLAN_TDLS_SETUP_RESPONSE:
3742 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
3743 /* we are the responder */
3744 ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
3745 sdata->u.mgd.bssid);
3746 break;
3747 default:
3748 ret = -ENOTSUPP;
3749 goto fail;
3750 }
3751
3752 if (send_direct) {
3753 ieee80211_tx_skb(sdata, skb);
3754 return 0;
3755 }
3756
3757 /*
3758 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
3759 * we should default to AC_VI.
3760 */
3761 switch (action_code) {
3762 case WLAN_TDLS_SETUP_REQUEST:
3763 case WLAN_TDLS_SETUP_RESPONSE:
3764 skb_set_queue_mapping(skb, IEEE80211_AC_BK);
3765 skb->priority = 2;
3766 break;
3767 default:
3768 skb_set_queue_mapping(skb, IEEE80211_AC_VI);
3769 skb->priority = 5;
3770 break;
3771 }
3772
3773 /* disable bottom halves when entering the Tx path */
3774 local_bh_disable();
3775 ret = ieee80211_subif_start_xmit(skb, dev);
3776 local_bh_enable();
3777
3778 return ret;
3779
3780fail:
3781 dev_kfree_skb(skb);
3782 return ret;
3783}
3784
3785static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
3786 u8 *peer, enum nl80211_tdls_operation oper)
3787{
3788 struct sta_info *sta;
3789 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3790
3791 if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
3792 return -ENOTSUPP;
3793
3794 if (sdata->vif.type != NL80211_IFTYPE_STATION)
3795 return -EINVAL;
3796
3797 tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
3798
3799 switch (oper) {
3800 case NL80211_TDLS_ENABLE_LINK:
3801 rcu_read_lock();
3802 sta = sta_info_get(sdata, peer);
3803 if (!sta) {
3804 rcu_read_unlock();
3805 return -ENOLINK;
3806 }
3807
3808 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
3809 rcu_read_unlock();
3810 break;
3811 case NL80211_TDLS_DISABLE_LINK:
3812 return sta_info_destroy_addr(sdata, peer);
3813 case NL80211_TDLS_TEARDOWN:
3814 case NL80211_TDLS_SETUP:
3815 case NL80211_TDLS_DISCOVERY_REQ:
3816 /* We don't support in-driver setup/teardown/discovery */
3817 return -ENOTSUPP;
3818 default:
3819 return -ENOTSUPP;
3820 }
3821
3822 return 0;
3823}
3824
3825static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, 3511static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
3826 const u8 *peer, u64 *cookie) 3512 const u8 *peer, u64 *cookie)
3827{ 3513{
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b455f62d357a..f86d06aaf54b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1833,6 +1833,15 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
1833 u8 radar_detect); 1833 u8 radar_detect);
1834int ieee80211_max_num_channels(struct ieee80211_local *local); 1834int ieee80211_max_num_channels(struct ieee80211_local *local);
1835 1835
1836/* TDLS */
1837int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
1838 u8 *peer, u8 action_code, u8 dialog_token,
1839 u16 status_code, u32 peer_capability,
1840 const u8 *extra_ies, size_t extra_ies_len);
1841int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1842 u8 *peer, enum nl80211_tdls_operation oper);
1843
1844
1836#ifdef CONFIG_MAC80211_NOINLINE 1845#ifdef CONFIG_MAC80211_NOINLINE
1837#define debug_noinline noinline 1846#define debug_noinline noinline
1838#else 1847#else
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
new file mode 100644
index 000000000000..8e14e2aaea11
--- /dev/null
+++ b/net/mac80211/tdls.c
@@ -0,0 +1,325 @@
1/*
2 * mac80211 TDLS handling code
3 *
4 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright 2014, Intel Corporation
6 *
7 * This file is GPLv2 as found in COPYING.
8 */
9
10#include <linux/ieee80211.h>
11#include "ieee80211_i.h"
12
13static void ieee80211_tdls_add_ext_capab(struct sk_buff *skb)
14{
15 u8 *pos = (void *)skb_put(skb, 7);
16
17 *pos++ = WLAN_EID_EXT_CAPABILITY;
18 *pos++ = 5; /* len */
19 *pos++ = 0x0;
20 *pos++ = 0x0;
21 *pos++ = 0x0;
22 *pos++ = 0x0;
23 *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
24}
25
26static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata)
27{
28 struct ieee80211_local *local = sdata->local;
29 u16 capab;
30
31 capab = 0;
32 if (ieee80211_get_sdata_band(sdata) != IEEE80211_BAND_2GHZ)
33 return capab;
34
35 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
36 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
37 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
38 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
39
40 return capab;
41}
42
43static void ieee80211_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr,
44 u8 *peer, u8 *bssid)
45{
46 struct ieee80211_tdls_lnkie *lnkid;
47
48 lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
49
50 lnkid->ie_type = WLAN_EID_LINK_ID;
51 lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
52
53 memcpy(lnkid->bssid, bssid, ETH_ALEN);
54 memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
55 memcpy(lnkid->resp_sta, peer, ETH_ALEN);
56}
57
58static int
59ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev,
60 u8 *peer, u8 action_code, u8 dialog_token,
61 u16 status_code, struct sk_buff *skb)
62{
63 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
64 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
65 struct ieee80211_tdls_data *tf;
66
67 tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
68
69 memcpy(tf->da, peer, ETH_ALEN);
70 memcpy(tf->sa, sdata->vif.addr, ETH_ALEN);
71 tf->ether_type = cpu_to_be16(ETH_P_TDLS);
72 tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
73
74 switch (action_code) {
75 case WLAN_TDLS_SETUP_REQUEST:
76 tf->category = WLAN_CATEGORY_TDLS;
77 tf->action_code = WLAN_TDLS_SETUP_REQUEST;
78
79 skb_put(skb, sizeof(tf->u.setup_req));
80 tf->u.setup_req.dialog_token = dialog_token;
81 tf->u.setup_req.capability =
82 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
83
84 ieee80211_add_srates_ie(sdata, skb, false, band);
85 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
86 ieee80211_tdls_add_ext_capab(skb);
87 break;
88 case WLAN_TDLS_SETUP_RESPONSE:
89 tf->category = WLAN_CATEGORY_TDLS;
90 tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
91
92 skb_put(skb, sizeof(tf->u.setup_resp));
93 tf->u.setup_resp.status_code = cpu_to_le16(status_code);
94 tf->u.setup_resp.dialog_token = dialog_token;
95 tf->u.setup_resp.capability =
96 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
97
98 ieee80211_add_srates_ie(sdata, skb, false, band);
99 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
100 ieee80211_tdls_add_ext_capab(skb);
101 break;
102 case WLAN_TDLS_SETUP_CONFIRM:
103 tf->category = WLAN_CATEGORY_TDLS;
104 tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
105
106 skb_put(skb, sizeof(tf->u.setup_cfm));
107 tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
108 tf->u.setup_cfm.dialog_token = dialog_token;
109 break;
110 case WLAN_TDLS_TEARDOWN:
111 tf->category = WLAN_CATEGORY_TDLS;
112 tf->action_code = WLAN_TDLS_TEARDOWN;
113
114 skb_put(skb, sizeof(tf->u.teardown));
115 tf->u.teardown.reason_code = cpu_to_le16(status_code);
116 break;
117 case WLAN_TDLS_DISCOVERY_REQUEST:
118 tf->category = WLAN_CATEGORY_TDLS;
119 tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
120
121 skb_put(skb, sizeof(tf->u.discover_req));
122 tf->u.discover_req.dialog_token = dialog_token;
123 break;
124 default:
125 return -EINVAL;
126 }
127
128 return 0;
129}
130
131static int
132ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev,
133 u8 *peer, u8 action_code, u8 dialog_token,
134 u16 status_code, struct sk_buff *skb)
135{
136 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
137 enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
138 struct ieee80211_mgmt *mgmt;
139
140 mgmt = (void *)skb_put(skb, 24);
141 memset(mgmt, 0, 24);
142 memcpy(mgmt->da, peer, ETH_ALEN);
143 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
144 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
145
146 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
147 IEEE80211_STYPE_ACTION);
148
149 switch (action_code) {
150 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
151 skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
152 mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
153 mgmt->u.action.u.tdls_discover_resp.action_code =
154 WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
155 mgmt->u.action.u.tdls_discover_resp.dialog_token =
156 dialog_token;
157 mgmt->u.action.u.tdls_discover_resp.capability =
158 cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata));
159
160 ieee80211_add_srates_ie(sdata, skb, false, band);
161 ieee80211_add_ext_srates_ie(sdata, skb, false, band);
162 ieee80211_tdls_add_ext_capab(skb);
163 break;
164 default:
165 return -EINVAL;
166 }
167
168 return 0;
169}
170
171int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
172 u8 *peer, u8 action_code, u8 dialog_token,
173 u16 status_code, u32 peer_capability,
174 const u8 *extra_ies, size_t extra_ies_len)
175{
176 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
177 struct ieee80211_local *local = sdata->local;
178 struct sk_buff *skb = NULL;
179 bool send_direct;
180 int ret;
181
182 if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
183 return -ENOTSUPP;
184
185 /* make sure we are in managed mode, and associated */
186 if (sdata->vif.type != NL80211_IFTYPE_STATION ||
187 !sdata->u.mgd.associated)
188 return -EINVAL;
189
190 tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n",
191 action_code, peer);
192
193 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
194 max(sizeof(struct ieee80211_mgmt),
195 sizeof(struct ieee80211_tdls_data)) +
196 50 + /* supported rates */
197 7 + /* ext capab */
198 extra_ies_len +
199 sizeof(struct ieee80211_tdls_lnkie));
200 if (!skb)
201 return -ENOMEM;
202
203 skb_reserve(skb, local->hw.extra_tx_headroom);
204
205 switch (action_code) {
206 case WLAN_TDLS_SETUP_REQUEST:
207 case WLAN_TDLS_SETUP_RESPONSE:
208 case WLAN_TDLS_SETUP_CONFIRM:
209 case WLAN_TDLS_TEARDOWN:
210 case WLAN_TDLS_DISCOVERY_REQUEST:
211 ret = ieee80211_prep_tdls_encap_data(wiphy, dev, peer,
212 action_code, dialog_token,
213 status_code, skb);
214 send_direct = false;
215 break;
216 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
217 ret = ieee80211_prep_tdls_direct(wiphy, dev, peer, action_code,
218 dialog_token, status_code,
219 skb);
220 send_direct = true;
221 break;
222 default:
223 ret = -ENOTSUPP;
224 break;
225 }
226
227 if (ret < 0)
228 goto fail;
229
230 if (extra_ies_len)
231 memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
232
233 /* the TDLS link IE is always added last */
234 switch (action_code) {
235 case WLAN_TDLS_SETUP_REQUEST:
236 case WLAN_TDLS_SETUP_CONFIRM:
237 case WLAN_TDLS_TEARDOWN:
238 case WLAN_TDLS_DISCOVERY_REQUEST:
239 /* we are the initiator */
240 ieee80211_tdls_add_link_ie(skb, sdata->vif.addr, peer,
241 sdata->u.mgd.bssid);
242 break;
243 case WLAN_TDLS_SETUP_RESPONSE:
244 case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
245 /* we are the responder */
246 ieee80211_tdls_add_link_ie(skb, peer, sdata->vif.addr,
247 sdata->u.mgd.bssid);
248 break;
249 default:
250 ret = -ENOTSUPP;
251 goto fail;
252 }
253
254 if (send_direct) {
255 ieee80211_tx_skb(sdata, skb);
256 return 0;
257 }
258
259 /*
260 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
261 * we should default to AC_VI.
262 */
263 switch (action_code) {
264 case WLAN_TDLS_SETUP_REQUEST:
265 case WLAN_TDLS_SETUP_RESPONSE:
266 skb_set_queue_mapping(skb, IEEE80211_AC_BK);
267 skb->priority = 2;
268 break;
269 default:
270 skb_set_queue_mapping(skb, IEEE80211_AC_VI);
271 skb->priority = 5;
272 break;
273 }
274
275 /* disable bottom halves when entering the Tx path */
276 local_bh_disable();
277 ret = ieee80211_subif_start_xmit(skb, dev);
278 local_bh_enable();
279
280 return ret;
281
282fail:
283 dev_kfree_skb(skb);
284 return ret;
285}
286
287int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
288 u8 *peer, enum nl80211_tdls_operation oper)
289{
290 struct sta_info *sta;
291 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
292
293 if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
294 return -ENOTSUPP;
295
296 if (sdata->vif.type != NL80211_IFTYPE_STATION)
297 return -EINVAL;
298
299 tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
300
301 switch (oper) {
302 case NL80211_TDLS_ENABLE_LINK:
303 rcu_read_lock();
304 sta = sta_info_get(sdata, peer);
305 if (!sta) {
306 rcu_read_unlock();
307 return -ENOLINK;
308 }
309
310 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
311 rcu_read_unlock();
312 break;
313 case NL80211_TDLS_DISABLE_LINK:
314 return sta_info_destroy_addr(sdata, peer);
315 case NL80211_TDLS_TEARDOWN:
316 case NL80211_TDLS_SETUP:
317 case NL80211_TDLS_DISCOVERY_REQ:
318 /* We don't support in-driver setup/teardown/discovery */
319 return -ENOTSUPP;
320 default:
321 return -ENOTSUPP;
322 }
323
324 return 0;
325}