diff options
author | Ron Rindjunsky <ron.rindjunsky@intel.com> | 2007-11-26 09:14:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:55:31 -0500 |
commit | 9f985b0eee4070e494b9d62313da982cfef9b5e3 (patch) | |
tree | 95479ea5d92758f6449b6c06dee54d27a66cf0e5 /net/mac80211/ieee80211_sta.c | |
parent | c715350828b12ce3b29e655fec7a7d6b22245d00 (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.c | 124 |
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 | |||
60 | static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, | 67 | static 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); |
62 | static struct ieee80211_sta_bss * | 69 | static 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 | ||
997 | static 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 | |||
1045 | static 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 | ||
991 | static void ieee80211_rx_mgmt_auth(struct net_device *dev, | 1083 | static 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 | ||
1965 | void 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 | ||
1874 | void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, | 1994 | void 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); |