Skip to content

Commit

Permalink
mac80211: adding 802.11n essential A-MPDU addBA capability
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ron Rindjunsky authored and David S. Miller committed Jan 28, 2008
1 parent c715350 commit 9f985b0
Showing 1 changed file with 124 additions and 0 deletions.
124 changes: 124 additions & 0 deletions net/mac80211/ieee80211_sta.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@

#define ERP_INFO_USE_PROTECTION BIT(1)

/* mgmt header + 1 byte action code */
#define IEEE80211_MIN_ACTION_SIZE (24 + 1)

#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0

static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
u8 *ssid, size_t ssid_len);
static struct ieee80211_sta_bss *
Expand Down Expand Up @@ -987,6 +994,91 @@ static void ieee80211_auth_challenge(struct net_device *dev,
elems.challenge_len + 2, 1);
}

static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
u8 dialog_token, u16 status, u16 policy,
u16 buf_size, u16 timeout)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u16 capab;

skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_DEBUG "%s: failed to allocate buffer "
"for addba resp frame\n", dev->name);
return;
}

skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
memset(mgmt, 0, 24);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
if (sdata->type == IEEE80211_IF_TYPE_AP)
memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
else
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
IEEE80211_STYPE_ACTION);

skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
mgmt->u.action.category = WLAN_CATEGORY_BACK;
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;

capab = (u16)(policy << 1); /* bit 1 aggregation policy */
capab |= (u16)(tid << 2); /* bit 5:2 TID number */
capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */

mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);

ieee80211_sta_tx(dev, skb, 0);

return;
}

static void ieee80211_sta_process_addba_request(struct net_device *dev,
struct ieee80211_mgmt *mgmt,
size_t len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
u16 capab, tid, timeout, ba_policy, buf_size, status;
u8 dialog_token;

sta = sta_info_get(local, mgmt->sa);
if (!sta)
return;

/* extract session parameters from addba request frame */
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);

capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;

/* TODO - currently aggregation is declined (A-MPDU add BA request
* acceptance is not obligatory by 802.11n draft), but here is
* the entry point for dealing with it */
#ifdef MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "Add Block Ack request arrived,"
" currently denying it\n");
#endif /* MAC80211_HT_DEBUG */

status = WLAN_STATUS_REQUEST_DECLINED;

ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
status, 1, buf_size, timeout);
sta_info_put(sta);
}

static void ieee80211_rx_mgmt_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
Expand Down Expand Up @@ -1870,6 +1962,34 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
ieee80211_sta_tx(dev, skb, 0);
}

void ieee80211_rx_mgmt_action(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
size_t len)
{
if (len < IEEE80211_MIN_ACTION_SIZE)
return;

switch (mgmt->u.action.category) {
case WLAN_CATEGORY_BACK:
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
sizeof(mgmt->u.action.u.addba_req)))
break;
ieee80211_sta_process_addba_request(dev, mgmt, len);
break;
default:
if (net_ratelimit())
printk(KERN_DEBUG "%s: received unsupported BACK\n",
dev->name);
break;
}
break;
default:
break;
}
}

void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
Expand Down Expand Up @@ -1899,6 +2019,7 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
case IEEE80211_STYPE_REASSOC_RESP:
case IEEE80211_STYPE_DEAUTH:
case IEEE80211_STYPE_DISASSOC:
case IEEE80211_STYPE_ACTION:
skb_queue_tail(&ifsta->skb_queue, skb);
queue_work(local->hw.workqueue, &ifsta->work);
return;
Expand Down Expand Up @@ -1956,6 +2077,9 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
case IEEE80211_STYPE_DISASSOC:
ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
break;
case IEEE80211_STYPE_ACTION:
ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
break;
}

kfree_skb(skb);
Expand Down

0 comments on commit 9f985b0

Please sign in to comment.