aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_sta.c
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2007-11-26 09:14:32 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:31 -0500
commit9f985b0eee4070e494b9d62313da982cfef9b5e3 (patch)
tree95479ea5d92758f6449b6c06dee54d27a66cf0e5 /net/mac80211/ieee80211_sta.c
parentc715350828b12ce3b29e655fec7a7d6b22245d00 (diff)
mac80211: adding 802.11n essential A-MPDU addBA capability
This patch adds the capability to identify and answer an add block ACK request. As this series of patches only adds HT handling with no aggregations, (A-MPDU aggregations acceptance is not obligatory according to 802.11n draft) we are currently sending back a refusal upon this request. Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r--net/mac80211/ieee80211_sta.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 1f47afeb925d..1d553d78b227 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -57,6 +57,13 @@
57 57
58#define ERP_INFO_USE_PROTECTION BIT(1) 58#define ERP_INFO_USE_PROTECTION BIT(1)
59 59
60/* mgmt header + 1 byte action code */
61#define IEEE80211_MIN_ACTION_SIZE (24 + 1)
62
63#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
64#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
65#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
66
60static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, 67static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
61 u8 *ssid, size_t ssid_len); 68 u8 *ssid, size_t ssid_len);
62static struct ieee80211_sta_bss * 69static struct ieee80211_sta_bss *
@@ -987,6 +994,91 @@ static void ieee80211_auth_challenge(struct net_device *dev,
987 elems.challenge_len + 2, 1); 994 elems.challenge_len + 2, 1);
988} 995}
989 996
997static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
998 u8 dialog_token, u16 status, u16 policy,
999 u16 buf_size, u16 timeout)
1000{
1001 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1002 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
1003 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1004 struct sk_buff *skb;
1005 struct ieee80211_mgmt *mgmt;
1006 u16 capab;
1007
1008 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
1009 if (!skb) {
1010 printk(KERN_DEBUG "%s: failed to allocate buffer "
1011 "for addba resp frame\n", dev->name);
1012 return;
1013 }
1014
1015 skb_reserve(skb, local->hw.extra_tx_headroom);
1016 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
1017 memset(mgmt, 0, 24);
1018 memcpy(mgmt->da, da, ETH_ALEN);
1019 memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
1020 if (sdata->type == IEEE80211_IF_TYPE_AP)
1021 memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
1022 else
1023 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
1024 mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
1025 IEEE80211_STYPE_ACTION);
1026
1027 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
1028 mgmt->u.action.category = WLAN_CATEGORY_BACK;
1029 mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
1030 mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
1031
1032 capab = (u16)(policy << 1); /* bit 1 aggregation policy */
1033 capab |= (u16)(tid << 2); /* bit 5:2 TID number */
1034 capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
1035
1036 mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
1037 mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
1038 mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
1039
1040 ieee80211_sta_tx(dev, skb, 0);
1041
1042 return;
1043}
1044
1045static void ieee80211_sta_process_addba_request(struct net_device *dev,
1046 struct ieee80211_mgmt *mgmt,
1047 size_t len)
1048{
1049 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1050 struct sta_info *sta;
1051 u16 capab, tid, timeout, ba_policy, buf_size, status;
1052 u8 dialog_token;
1053
1054 sta = sta_info_get(local, mgmt->sa);
1055 if (!sta)
1056 return;
1057
1058 /* extract session parameters from addba request frame */
1059 dialog_token = mgmt->u.action.u.addba_req.dialog_token;
1060 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
1061
1062 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
1063 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
1064 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
1065 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
1066
1067 /* TODO - currently aggregation is declined (A-MPDU add BA request
1068 * acceptance is not obligatory by 802.11n draft), but here is
1069 * the entry point for dealing with it */
1070#ifdef MAC80211_HT_DEBUG
1071 if (net_ratelimit())
1072 printk(KERN_DEBUG "Add Block Ack request arrived,"
1073 " currently denying it\n");
1074#endif /* MAC80211_HT_DEBUG */
1075
1076 status = WLAN_STATUS_REQUEST_DECLINED;
1077
1078 ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
1079 status, 1, buf_size, timeout);
1080 sta_info_put(sta);
1081}
990 1082
991static void ieee80211_rx_mgmt_auth(struct net_device *dev, 1083static void ieee80211_rx_mgmt_auth(struct net_device *dev,
992 struct ieee80211_if_sta *ifsta, 1084 struct ieee80211_if_sta *ifsta,
@@ -1870,6 +1962,34 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
1870 ieee80211_sta_tx(dev, skb, 0); 1962 ieee80211_sta_tx(dev, skb, 0);
1871} 1963}
1872 1964
1965void ieee80211_rx_mgmt_action(struct net_device *dev,
1966 struct ieee80211_if_sta *ifsta,
1967 struct ieee80211_mgmt *mgmt,
1968 size_t len)
1969{
1970 if (len < IEEE80211_MIN_ACTION_SIZE)
1971 return;
1972
1973 switch (mgmt->u.action.category) {
1974 case WLAN_CATEGORY_BACK:
1975 switch (mgmt->u.action.u.addba_req.action_code) {
1976 case WLAN_ACTION_ADDBA_REQ:
1977 if (len < (IEEE80211_MIN_ACTION_SIZE +
1978 sizeof(mgmt->u.action.u.addba_req)))
1979 break;
1980 ieee80211_sta_process_addba_request(dev, mgmt, len);
1981 break;
1982 default:
1983 if (net_ratelimit())
1984 printk(KERN_DEBUG "%s: received unsupported BACK\n",
1985 dev->name);
1986 break;
1987 }
1988 break;
1989 default:
1990 break;
1991 }
1992}
1873 1993
1874void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, 1994void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
1875 struct ieee80211_rx_status *rx_status) 1995 struct ieee80211_rx_status *rx_status)
@@ -1899,6 +2019,7 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
1899 case IEEE80211_STYPE_REASSOC_RESP: 2019 case IEEE80211_STYPE_REASSOC_RESP:
1900 case IEEE80211_STYPE_DEAUTH: 2020 case IEEE80211_STYPE_DEAUTH:
1901 case IEEE80211_STYPE_DISASSOC: 2021 case IEEE80211_STYPE_DISASSOC:
2022 case IEEE80211_STYPE_ACTION:
1902 skb_queue_tail(&ifsta->skb_queue, skb); 2023 skb_queue_tail(&ifsta->skb_queue, skb);
1903 queue_work(local->hw.workqueue, &ifsta->work); 2024 queue_work(local->hw.workqueue, &ifsta->work);
1904 return; 2025 return;
@@ -1956,6 +2077,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
1956 case IEEE80211_STYPE_DISASSOC: 2077 case IEEE80211_STYPE_DISASSOC:
1957 ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); 2078 ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
1958 break; 2079 break;
2080 case IEEE80211_STYPE_ACTION:
2081 ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
2082 break;
1959 } 2083 }
1960 2084
1961 kfree_skb(skb); 2085 kfree_skb(skb);