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