root/net/mac80211/agg-rx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ieee80211_free_tid_rx
  2. ___ieee80211_stop_rx_ba_session
  3. __ieee80211_stop_rx_ba_session
  4. ieee80211_stop_rx_ba_session
  5. sta_rx_agg_session_timer_expired
  6. sta_rx_agg_reorder_timer_expired
  7. ieee80211_add_addbaext
  8. ieee80211_send_addba_resp
  9. ___ieee80211_start_rx_ba_session
  10. __ieee80211_start_rx_ba_session
  11. ieee80211_process_addba_request
  12. ieee80211_manage_rx_ba_offl
  13. ieee80211_rx_ba_timer_expired

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

/* [<][>][^][v][top][bottom][index][help] */