linux/net/mac80211/agg-rx.c
<<
>>
Prefs
   1/*
   2 * HT handling
   3 *
   4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
   5 * Copyright 2002-2005, Instant802 Networks, Inc.
   6 * Copyright 2005-2006, Devicescape Software, Inc.
   7 * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
   8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
   9 * Copyright 2007-2010, Intel Corporation
  10 * Copyright(c) 2015 Intel Deutschland GmbH
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 */
  16
  17/**
  18 * DOC: RX A-MPDU aggregation
  19 *
  20 * Aggregation on the RX side requires only implementing the
  21 * @ampdu_action callback that is invoked to start/stop any
  22 * block-ack sessions for RX aggregation.
  23 *
  24 * When RX aggregation is started by the peer, the driver is
  25 * notified via @ampdu_action function, with the
  26 * %IEEE80211_AMPDU_RX_START action, and may reject the request
  27 * in which case a negative response is sent to the peer, if it
  28 * accepts it a positive response is sent.
  29 *
  30 * While the session is active, the device/driver are required
  31 * to de-aggregate frames and pass them up one by one to mac80211,
  32 * which will handle the reorder buffer.
  33 *
  34 * When the aggregation session is stopped again by the peer or
  35 * ourselves, the driver's @ampdu_action function will be called
  36 * with the action %IEEE80211_AMPDU_RX_STOP. In this case, the
  37 * call must not fail.
  38 */
  39
  40#include <linux/ieee80211.h>
  41#include <linux/slab.h>
  42#include <linux/export.h>
  43#include <net/mac80211.h>
  44#include "ieee80211_i.h"
  45#include "driver-ops.h"
  46
  47static void ieee80211_free_tid_rx(struct rcu_head *h)
  48{
  49        struct tid_ampdu_rx *tid_rx =
  50                container_of(h, struct tid_ampdu_rx, rcu_head);
  51        int i;
  52
  53        for (i = 0; i < tid_rx->buf_size; i++)
  54                __skb_queue_purge(&tid_rx->reorder_buf[i]);
  55        kfree(tid_rx->reorder_buf);
  56        kfree(tid_rx->reorder_time);
  57        kfree(tid_rx);
  58}
  59
  60void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
  61                                     u16 initiator, u16 reason, bool tx)
  62{
  63        struct ieee80211_local *local = sta->local;
  64        struct tid_ampdu_rx *tid_rx;
  65        struct ieee80211_ampdu_params params = {
  66                .sta = &sta->sta,
  67                .action = IEEE80211_AMPDU_RX_STOP,
  68                .tid = tid,
  69                .amsdu = false,
  70                .timeout = 0,
  71                .ssn = 0,
  72        };
  73
  74        lockdep_assert_held(&sta->ampdu_mlme.mtx);
  75
  76        tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
  77                                        lockdep_is_held(&sta->ampdu_mlme.mtx));
  78
  79        if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
  80                return;
  81
  82        RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
  83        __clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
  84
  85        ht_dbg(sta->sdata,
  86               "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
  87               sta->sta.addr, tid,
  88               initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
  89               (int)reason);
  90
  91        if (drv_ampdu_action(local, sta->sdata, &params))
  92                sdata_info(sta->sdata,
  93                           "HW problem - can not stop rx aggregation for %pM tid %d\n",
  94                           sta->sta.addr, tid);
  95
  96        /* check if this is a self generated aggregation halt */
  97        if (initiator == WLAN_BACK_RECIPIENT && tx)
  98                ieee80211_send_delba(sta->sdata, sta->sta.addr,
  99                                     tid, WLAN_BACK_RECIPIENT, reason);
 100
 101        /*
 102         * return here in case tid_rx is not assigned - which will happen if
 103         * IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
 104         */
 105        if (!tid_rx)
 106                return;
 107
 108        del_timer_sync(&tid_rx->session_timer);
 109
 110        /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
 111        spin_lock_bh(&tid_rx->reorder_lock);
 112        tid_rx->removed = true;
 113        spin_unlock_bh(&tid_rx->reorder_lock);
 114        del_timer_sync(&tid_rx->reorder_timer);
 115
 116        call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
 117}
 118
 119void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 120                                    u16 initiator, u16 reason, bool tx)
 121{
 122        mutex_lock(&sta->ampdu_mlme.mtx);
 123        ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
 124        mutex_unlock(&sta->ampdu_mlme.mtx);
 125}
 126
 127void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
 128                                  const u8 *addr)
 129{
 130        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 131        struct sta_info *sta;
 132        int i;
 133
 134        rcu_read_lock();
 135        sta = sta_info_get_bss(sdata, addr);
 136        if (!sta) {
 137                rcu_read_unlock();
 138                return;
 139        }
 140
 141        for (i = 0; i < IEEE80211_NUM_TIDS; i++)
 142                if (ba_rx_bitmap & BIT(i))
 143                        set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested);
 144
 145        ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 146        rcu_read_unlock();
 147}
 148EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
 149
 150/*
 151 * After accepting the AddBA Request we activated a timer,
 152 * resetting it after each frame that arrives from the originator.
 153 */
 154static void sta_rx_agg_session_timer_expired(unsigned long data)
 155{
 156        /* not an elegant detour, but there is no choice as the timer passes
 157         * only one argument, and various sta_info are needed here, so init
 158         * flow in sta_info_create gives the TID as data, while the timer_to_id
 159         * array gives the sta through container_of */
 160        u8 *ptid = (u8 *)data;
 161        u8 *timer_to_id = ptid - *ptid;
 162        struct sta_info *sta = container_of(timer_to_id, struct sta_info,
 163                                         timer_to_tid[0]);
 164        struct tid_ampdu_rx *tid_rx;
 165        unsigned long timeout;
 166
 167        rcu_read_lock();
 168        tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[*ptid]);
 169        if (!tid_rx) {
 170                rcu_read_unlock();
 171                return;
 172        }
 173
 174        timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
 175        if (time_is_after_jiffies(timeout)) {
 176                mod_timer(&tid_rx->session_timer, timeout);
 177                rcu_read_unlock();
 178                return;
 179        }
 180        rcu_read_unlock();
 181
 182        ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n",
 183               sta->sta.addr, (u16)*ptid);
 184
 185        set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
 186        ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
 187}
 188
 189static void sta_rx_agg_reorder_timer_expired(unsigned long data)
 190{
 191        u8 *ptid = (u8 *)data;
 192        u8 *timer_to_id = ptid - *ptid;
 193        struct sta_info *sta = container_of(timer_to_id, struct sta_info,
 194                        timer_to_tid[0]);
 195
 196        rcu_read_lock();
 197        ieee80211_release_reorder_timeout(sta, *ptid);
 198        rcu_read_unlock();
 199}
 200
 201static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
 202                                      u8 dialog_token, u16 status, u16 policy,
 203                                      u16 buf_size, u16 timeout)
 204{
 205        struct ieee80211_local *local = sdata->local;
 206        struct sk_buff *skb;
 207        struct ieee80211_mgmt *mgmt;
 208        bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
 209        u16 capab;
 210
 211        skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
 212        if (!skb)
 213                return;
 214
 215        skb_reserve(skb, local->hw.extra_tx_headroom);
 216        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 217        memset(mgmt, 0, 24);
 218        memcpy(mgmt->da, da, ETH_ALEN);
 219        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
 220        if (sdata->vif.type == NL80211_IFTYPE_AP ||
 221            sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
 222            sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
 223                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
 224        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
 225                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 226        else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 227                memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
 228
 229        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 230                                          IEEE80211_STYPE_ACTION);
 231
 232        skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
 233        mgmt->u.action.category = WLAN_CATEGORY_BACK;
 234        mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
 235        mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
 236
 237        capab = (u16)(amsdu << 0);      /* bit 0 A-MSDU support */
 238        capab |= (u16)(policy << 1);    /* bit 1 aggregation policy */
 239        capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
 240        capab |= (u16)(buf_size << 6);  /* bit 15:6 max size of aggregation */
 241
 242        mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
 243        mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
 244        mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
 245
 246        ieee80211_tx_skb(sdata, skb);
 247}
 248
 249void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 250                                     u8 dialog_token, u16 timeout,
 251                                     u16 start_seq_num, u16 ba_policy, u16 tid,
 252                                     u16 buf_size, bool tx, bool auto_seq)
 253{
 254        struct ieee80211_local *local = sta->sdata->local;
 255        struct tid_ampdu_rx *tid_agg_rx;
 256        struct ieee80211_ampdu_params params = {
 257                .sta = &sta->sta,
 258                .action = IEEE80211_AMPDU_RX_START,
 259                .tid = tid,
 260                .amsdu = false,
 261                .timeout = timeout,
 262                .ssn = start_seq_num,
 263        };
 264        int i, ret = -EOPNOTSUPP;
 265        u16 status = WLAN_STATUS_REQUEST_DECLINED;
 266
 267        if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
 268                ht_dbg(sta->sdata,
 269                       "STA %pM requests BA session on unsupported tid %d\n",
 270                       sta->sta.addr, tid);
 271                goto end_no_lock;
 272        }
 273
 274        if (!sta->sta.ht_cap.ht_supported) {
 275                ht_dbg(sta->sdata,
 276                       "STA %pM erroneously requests BA session on tid %d w/o QoS\n",
 277                       sta->sta.addr, tid);
 278                /* send a response anyway, it's an error case if we get here */
 279                goto end_no_lock;
 280        }
 281
 282        if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
 283                ht_dbg(sta->sdata,
 284                       "Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
 285                       sta->sta.addr, tid);
 286                goto end_no_lock;
 287        }
 288
 289        /* sanity check for incoming parameters:
 290         * check if configuration can support the BA policy
 291         * and if buffer size does not exceeds max value */
 292        /* XXX: check own ht delayed BA capability?? */
 293        if (((ba_policy != 1) &&
 294             (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
 295            (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
 296                status = WLAN_STATUS_INVALID_QOS_PARAM;
 297                ht_dbg_ratelimited(sta->sdata,
 298                                   "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
 299                                   sta->sta.addr, tid, ba_policy, buf_size);
 300                goto end_no_lock;
 301        }
 302        /* determine default buffer size */
 303        if (buf_size == 0)
 304                buf_size = IEEE80211_MAX_AMPDU_BUF;
 305
 306        /* make sure the size doesn't exceed the maximum supported by the hw */
 307        if (buf_size > local->hw.max_rx_aggregation_subframes)
 308                buf_size = local->hw.max_rx_aggregation_subframes;
 309        params.buf_size = buf_size;
 310
 311        /* examine state machine */
 312        mutex_lock(&sta->ampdu_mlme.mtx);
 313
 314        if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
 315                tid_agg_rx = rcu_dereference_protected(
 316                                sta->ampdu_mlme.tid_rx[tid],
 317                                lockdep_is_held(&sta->ampdu_mlme.mtx));
 318
 319                if (tid_agg_rx->dialog_token == dialog_token) {
 320                        ht_dbg_ratelimited(sta->sdata,
 321                                           "updated AddBA Req from %pM on tid %u\n",
 322                                           sta->sta.addr, tid);
 323                        /* We have no API to update the timeout value in the
 324                         * driver so reject the timeout update.
 325                         */
 326                        status = WLAN_STATUS_REQUEST_DECLINED;
 327                        ieee80211_send_addba_resp(sta->sdata, sta->sta.addr,
 328                                                  tid, dialog_token, status,
 329                                                  1, buf_size, timeout);
 330                        goto end;
 331                }
 332
 333                ht_dbg_ratelimited(sta->sdata,
 334                                   "unexpected AddBA Req from %pM on tid %u\n",
 335                                   sta->sta.addr, tid);
 336
 337                /* delete existing Rx BA session on the same tid */
 338                ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
 339                                                WLAN_STATUS_UNSPECIFIED_QOS,
 340                                                false);
 341        }
 342
 343        if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
 344                ret = drv_ampdu_action(local, sta->sdata, &params);
 345                ht_dbg(sta->sdata,
 346                       "Rx A-MPDU request on %pM tid %d result %d\n",
 347                       sta->sta.addr, tid, ret);
 348                if (!ret)
 349                        status = WLAN_STATUS_SUCCESS;
 350                goto end;
 351        }
 352
 353        /* prepare A-MPDU MLME for Rx aggregation */
 354        tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
 355        if (!tid_agg_rx)
 356                goto end;
 357
 358        spin_lock_init(&tid_agg_rx->reorder_lock);
 359
 360        /* rx timer */
 361        tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
 362        tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
 363        init_timer_deferrable(&tid_agg_rx->session_timer);
 364
 365        /* rx reorder timer */
 366        tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
 367        tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
 368        init_timer(&tid_agg_rx->reorder_timer);
 369
 370        /* prepare reordering buffer */
 371        tid_agg_rx->reorder_buf =
 372                kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL);
 373        tid_agg_rx->reorder_time =
 374                kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
 375        if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
 376                kfree(tid_agg_rx->reorder_buf);
 377                kfree(tid_agg_rx->reorder_time);
 378                kfree(tid_agg_rx);
 379                goto end;
 380        }
 381
 382        for (i = 0; i < buf_size; i++)
 383                __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
 384
 385        ret = drv_ampdu_action(local, sta->sdata, &params);
 386        ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
 387               sta->sta.addr, tid, ret);
 388        if (ret) {
 389                kfree(tid_agg_rx->reorder_buf);
 390                kfree(tid_agg_rx->reorder_time);
 391                kfree(tid_agg_rx);
 392                goto end;
 393        }
 394
 395        /* update data */
 396        tid_agg_rx->dialog_token = dialog_token;
 397        tid_agg_rx->ssn = start_seq_num;
 398        tid_agg_rx->head_seq_num = start_seq_num;
 399        tid_agg_rx->buf_size = buf_size;
 400        tid_agg_rx->timeout = timeout;
 401        tid_agg_rx->stored_mpdu_num = 0;
 402        tid_agg_rx->auto_seq = auto_seq;
 403        tid_agg_rx->reorder_buf_filtered = 0;
 404        status = WLAN_STATUS_SUCCESS;
 405
 406        /* activate it for RX */
 407        rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
 408
 409        if (timeout) {
 410                mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
 411                tid_agg_rx->last_rx = jiffies;
 412        }
 413
 414end:
 415        if (status == WLAN_STATUS_SUCCESS)
 416                __set_bit(tid, sta->ampdu_mlme.agg_session_valid);
 417        mutex_unlock(&sta->ampdu_mlme.mtx);
 418
 419end_no_lock:
 420        if (tx)
 421                ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
 422                                          dialog_token, status, 1, buf_size,
 423                                          timeout);
 424}
 425
 426void ieee80211_process_addba_request(struct ieee80211_local *local,
 427                                     struct sta_info *sta,
 428                                     struct ieee80211_mgmt *mgmt,
 429                                     size_t len)
 430{
 431        u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
 432        u8 dialog_token;
 433
 434        /* extract session parameters from addba request frame */
 435        dialog_token = mgmt->u.action.u.addba_req.dialog_token;
 436        timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
 437        start_seq_num =
 438                le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
 439
 440        capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
 441        ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
 442        tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
 443        buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
 444
 445        __ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
 446                                        start_seq_num, ba_policy, tid,
 447                                        buf_size, true, false);
 448}
 449
 450void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif,
 451                                        const u8 *addr, u16 tid)
 452{
 453        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 454        struct ieee80211_local *local = sdata->local;
 455        struct ieee80211_rx_agg *rx_agg;
 456        struct sk_buff *skb = dev_alloc_skb(0);
 457
 458        if (unlikely(!skb))
 459                return;
 460
 461        rx_agg = (struct ieee80211_rx_agg *) &skb->cb;
 462        memcpy(&rx_agg->addr, addr, ETH_ALEN);
 463        rx_agg->tid = tid;
 464
 465        skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START;
 466        skb_queue_tail(&sdata->skb_queue, skb);
 467        ieee80211_queue_work(&local->hw, &sdata->work);
 468}
 469EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl);
 470
 471void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif,
 472                                       const u8 *addr, u16 tid)
 473{
 474        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 475        struct ieee80211_local *local = sdata->local;
 476        struct ieee80211_rx_agg *rx_agg;
 477        struct sk_buff *skb = dev_alloc_skb(0);
 478
 479        if (unlikely(!skb))
 480                return;
 481
 482        rx_agg = (struct ieee80211_rx_agg *) &skb->cb;
 483        memcpy(&rx_agg->addr, addr, ETH_ALEN);
 484        rx_agg->tid = tid;
 485
 486        skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP;
 487        skb_queue_tail(&sdata->skb_queue, skb);
 488        ieee80211_queue_work(&local->hw, &sdata->work);
 489}
 490EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl);
 491