LCOV - code coverage report
Current view: top level - net/mac80211 - agg-rx.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 251 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 12 0.0 %
Branches: 0 90 0.0 %

           Branch data     Line data    Source code
       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                 :          0 : static void ieee80211_free_tid_rx(struct rcu_head *h)
      46                 :            : {
      47                 :          0 :         struct tid_ampdu_rx *tid_rx =
      48                 :          0 :                 container_of(h, struct tid_ampdu_rx, rcu_head);
      49                 :          0 :         int i;
      50                 :            : 
      51         [ #  # ]:          0 :         for (i = 0; i < tid_rx->buf_size; i++)
      52                 :          0 :                 __skb_queue_purge(&tid_rx->reorder_buf[i]);
      53                 :          0 :         kfree(tid_rx->reorder_buf);
      54                 :          0 :         kfree(tid_rx->reorder_time);
      55                 :          0 :         kfree(tid_rx);
      56                 :          0 : }
      57                 :            : 
      58                 :          0 : void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
      59                 :            :                                      u16 initiator, u16 reason, bool tx)
      60                 :            : {
      61                 :          0 :         struct ieee80211_local *local = sta->local;
      62                 :          0 :         struct tid_ampdu_rx *tid_rx;
      63                 :          0 :         struct ieee80211_ampdu_params params = {
      64                 :          0 :                 .sta = &sta->sta,
      65                 :            :                 .action = IEEE80211_AMPDU_RX_STOP,
      66                 :            :                 .tid = tid,
      67                 :            :                 .amsdu = false,
      68                 :            :                 .timeout = 0,
      69                 :            :                 .ssn = 0,
      70                 :            :         };
      71                 :            : 
      72                 :          0 :         lockdep_assert_held(&sta->ampdu_mlme.mtx);
      73                 :            : 
      74                 :          0 :         tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
      75                 :            :                                         lockdep_is_held(&sta->ampdu_mlme.mtx));
      76                 :            : 
      77         [ #  # ]:          0 :         if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
      78                 :          0 :                 return;
      79                 :            : 
      80                 :          0 :         RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
      81                 :          0 :         __clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
      82                 :            : 
      83                 :          0 :         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         [ #  # ]:          0 :         if (drv_ampdu_action(local, sta->sdata, &params))
      90                 :          0 :                 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         [ #  # ]:          0 :         if (initiator == WLAN_BACK_RECIPIENT && tx)
      96                 :          0 :                 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         [ #  # ]:          0 :         if (!tid_rx)
     104                 :            :                 return;
     105                 :            : 
     106                 :          0 :         del_timer_sync(&tid_rx->session_timer);
     107                 :            : 
     108                 :            :         /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
     109                 :          0 :         spin_lock_bh(&tid_rx->reorder_lock);
     110                 :          0 :         tid_rx->removed = true;
     111                 :          0 :         spin_unlock_bh(&tid_rx->reorder_lock);
     112                 :          0 :         del_timer_sync(&tid_rx->reorder_timer);
     113                 :            : 
     114                 :          0 :         call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
     115                 :            : }
     116                 :            : 
     117                 :          0 : void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
     118                 :            :                                     u16 initiator, u16 reason, bool tx)
     119                 :            : {
     120                 :          0 :         mutex_lock(&sta->ampdu_mlme.mtx);
     121                 :          0 :         ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
     122                 :          0 :         mutex_unlock(&sta->ampdu_mlme.mtx);
     123                 :          0 : }
     124                 :            : 
     125                 :          0 : void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
     126                 :            :                                   const u8 *addr)
     127                 :            : {
     128                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
     129                 :          0 :         struct sta_info *sta;
     130                 :          0 :         int i;
     131                 :            : 
     132                 :          0 :         rcu_read_lock();
     133                 :          0 :         sta = sta_info_get_bss(sdata, addr);
     134         [ #  # ]:          0 :         if (!sta) {
     135                 :          0 :                 rcu_read_unlock();
     136                 :          0 :                 return;
     137                 :            :         }
     138                 :            : 
     139         [ #  # ]:          0 :         for (i = 0; i < IEEE80211_NUM_TIDS; i++)
     140         [ #  # ]:          0 :                 if (ba_rx_bitmap & BIT(i))
     141                 :          0 :                         set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested);
     142                 :            : 
     143                 :          0 :         ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
     144                 :          0 :         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                 :          0 : static void sta_rx_agg_session_timer_expired(struct timer_list *t)
     153                 :            : {
     154                 :          0 :         struct tid_ampdu_rx *tid_rx = from_timer(tid_rx, t, session_timer);
     155                 :          0 :         struct sta_info *sta = tid_rx->sta;
     156                 :          0 :         u8 tid = tid_rx->tid;
     157                 :          0 :         unsigned long timeout;
     158                 :            : 
     159         [ #  # ]:          0 :         timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
     160         [ #  # ]:          0 :         if (time_is_after_jiffies(timeout)) {
     161                 :          0 :                 mod_timer(&tid_rx->session_timer, timeout);
     162                 :          0 :                 return;
     163                 :            :         }
     164                 :            : 
     165                 :          0 :         ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n",
     166                 :            :                sta->sta.addr, tid);
     167                 :            : 
     168                 :          0 :         set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
     169                 :          0 :         ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
     170                 :            : }
     171                 :            : 
     172                 :          0 : static void sta_rx_agg_reorder_timer_expired(struct timer_list *t)
     173                 :            : {
     174                 :          0 :         struct tid_ampdu_rx *tid_rx = from_timer(tid_rx, t, reorder_timer);
     175                 :            : 
     176                 :          0 :         rcu_read_lock();
     177                 :          0 :         ieee80211_release_reorder_timeout(tid_rx->sta, tid_rx->tid);
     178                 :          0 :         rcu_read_unlock();
     179                 :          0 : }
     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                 :          0 : 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                 :          0 :         struct ieee80211_sub_if_data *sdata = sta->sdata;
     220                 :          0 :         struct ieee80211_local *local = sdata->local;
     221                 :          0 :         struct sk_buff *skb;
     222                 :          0 :         struct ieee80211_mgmt *mgmt;
     223                 :          0 :         bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
     224                 :          0 :         u16 capab;
     225                 :            : 
     226                 :          0 :         skb = dev_alloc_skb(sizeof(*mgmt) +
     227                 :            :                     2 + sizeof(struct ieee80211_addba_ext_ie) +
     228                 :          0 :                     local->hw.extra_tx_headroom);
     229         [ #  # ]:          0 :         if (!skb)
     230                 :            :                 return;
     231                 :            : 
     232                 :          0 :         skb_reserve(skb, local->hw.extra_tx_headroom);
     233                 :          0 :         mgmt = skb_put_zero(skb, 24);
     234                 :          0 :         memcpy(mgmt->da, da, ETH_ALEN);
     235                 :          0 :         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
     236                 :          0 :         if (sdata->vif.type == NL80211_IFTYPE_AP ||
     237         [ #  # ]:          0 :             sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
     238                 :            :             sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
     239                 :          0 :                 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
     240         [ #  # ]:          0 :         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
     241                 :          0 :                 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
     242         [ #  # ]:          0 :         else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
     243                 :          0 :                 memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
     244                 :            : 
     245                 :          0 :         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
     246                 :            :                                           IEEE80211_STYPE_ACTION);
     247                 :            : 
     248                 :          0 :         skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
     249                 :          0 :         mgmt->u.action.category = WLAN_CATEGORY_BACK;
     250                 :          0 :         mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
     251                 :          0 :         mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
     252                 :            : 
     253                 :          0 :         capab = (u16)(amsdu << 0);        /* bit 0 A-MSDU support */
     254                 :          0 :         capab |= (u16)(policy << 1);      /* bit 1 aggregation policy */
     255                 :          0 :         capab |= (u16)(tid << 2);         /* bit 5:2 TID number */
     256                 :          0 :         capab |= (u16)(buf_size << 6);    /* bit 15:6 max size of aggregation */
     257                 :            : 
     258                 :          0 :         mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
     259                 :          0 :         mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
     260                 :          0 :         mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
     261                 :            : 
     262   [ #  #  #  # ]:          0 :         if (sta->sta.he_cap.has_he && addbaext)
     263                 :          0 :                 ieee80211_add_addbaext(sdata, skb, addbaext);
     264                 :            : 
     265                 :          0 :         ieee80211_tx_skb(sdata, skb);
     266                 :            : }
     267                 :            : 
     268                 :          0 : 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                 :          0 :         struct ieee80211_local *local = sta->sdata->local;
     275                 :          0 :         struct tid_ampdu_rx *tid_agg_rx;
     276                 :          0 :         struct ieee80211_ampdu_params params = {
     277                 :          0 :                 .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                 :          0 :         int i, ret = -EOPNOTSUPP;
     285                 :          0 :         u16 status = WLAN_STATUS_REQUEST_DECLINED;
     286                 :          0 :         u16 max_buf_size;
     287                 :            : 
     288         [ #  # ]:          0 :         if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
     289                 :          0 :                 ht_dbg(sta->sdata,
     290                 :            :                        "STA %pM requests BA session on unsupported tid %d\n",
     291                 :            :                        sta->sta.addr, tid);
     292                 :          0 :                 goto end;
     293                 :            :         }
     294                 :            : 
     295         [ #  # ]:          0 :         if (!sta->sta.ht_cap.ht_supported) {
     296                 :          0 :                 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                 :          0 :                 goto end;
     301                 :            :         }
     302                 :            : 
     303         [ #  # ]:          0 :         if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
     304                 :          0 :                 ht_dbg(sta->sdata,
     305                 :            :                        "Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
     306                 :            :                        sta->sta.addr, tid);
     307                 :          0 :                 goto end;
     308                 :            :         }
     309                 :            : 
     310         [ #  # ]:          0 :         if (sta->sta.he_cap.has_he)
     311                 :            :                 max_buf_size = IEEE80211_MAX_AMPDU_BUF;
     312                 :            :         else
     313                 :          0 :                 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         [ #  # ]:          0 :         if (((ba_policy != 1) &&
     320   [ #  #  #  # ]:          0 :              (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
     321                 :            :             (buf_size > max_buf_size)) {
     322                 :          0 :                 status = WLAN_STATUS_INVALID_QOS_PARAM;
     323                 :          0 :                 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                 :          0 :                 goto end;
     327                 :            :         }
     328                 :            :         /* determine default buffer size */
     329         [ #  # ]:          0 :         if (buf_size == 0)
     330                 :          0 :                 buf_size = max_buf_size;
     331                 :            : 
     332                 :            :         /* make sure the size doesn't exceed the maximum supported by the hw */
     333                 :          0 :         if (buf_size > sta->sta.max_rx_aggregation_subframes)
     334                 :            :                 buf_size = sta->sta.max_rx_aggregation_subframes;
     335                 :          0 :         params.buf_size = buf_size;
     336                 :            : 
     337                 :          0 :         ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n",
     338                 :            :                buf_size, sta->sta.addr);
     339                 :            : 
     340                 :            :         /* examine state machine */
     341                 :          0 :         lockdep_assert_held(&sta->ampdu_mlme.mtx);
     342                 :            : 
     343         [ #  # ]:          0 :         if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
     344         [ #  # ]:          0 :                 if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
     345                 :          0 :                         struct tid_ampdu_rx *tid_rx;
     346                 :            : 
     347                 :          0 :                         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                 :          0 :                         rcu_read_lock();
     356         [ #  # ]:          0 :                         tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
     357   [ #  #  #  # ]:          0 :                         if (tid_rx && tid_rx->timeout == timeout)
     358                 :            :                                 status = WLAN_STATUS_SUCCESS;
     359                 :            :                         else
     360                 :          0 :                                 status = WLAN_STATUS_REQUEST_DECLINED;
     361                 :          0 :                         rcu_read_unlock();
     362                 :          0 :                         goto end;
     363                 :            :                 }
     364                 :            : 
     365                 :          0 :                 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                 :          0 :                 ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
     371                 :            :                                                 WLAN_STATUS_UNSPECIFIED_QOS,
     372                 :            :                                                 false);
     373                 :            :         }
     374                 :            : 
     375         [ #  # ]:          0 :         if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
     376                 :          0 :                 ret = drv_ampdu_action(local, sta->sdata, &params);
     377                 :          0 :                 ht_dbg(sta->sdata,
     378                 :            :                        "Rx A-MPDU request on %pM tid %d result %d\n",
     379                 :            :                        sta->sta.addr, tid, ret);
     380         [ #  # ]:          0 :                 if (!ret)
     381                 :          0 :                         status = WLAN_STATUS_SUCCESS;
     382                 :          0 :                 goto end;
     383                 :            :         }
     384                 :            : 
     385                 :            :         /* prepare A-MPDU MLME for Rx aggregation */
     386                 :          0 :         tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
     387         [ #  # ]:          0 :         if (!tid_agg_rx)
     388                 :          0 :                 goto end;
     389                 :            : 
     390                 :          0 :         spin_lock_init(&tid_agg_rx->reorder_lock);
     391                 :            : 
     392                 :            :         /* rx timer */
     393                 :          0 :         timer_setup(&tid_agg_rx->session_timer,
     394                 :            :                     sta_rx_agg_session_timer_expired, TIMER_DEFERRABLE);
     395                 :            : 
     396                 :            :         /* rx reorder timer */
     397                 :          0 :         timer_setup(&tid_agg_rx->reorder_timer,
     398                 :            :                     sta_rx_agg_reorder_timer_expired, 0);
     399                 :            : 
     400                 :            :         /* prepare reordering buffer */
     401                 :          0 :         tid_agg_rx->reorder_buf =
     402                 :          0 :                 kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL);
     403                 :          0 :         tid_agg_rx->reorder_time =
     404                 :            :                 kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
     405   [ #  #  #  # ]:          0 :         if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
     406                 :          0 :                 kfree(tid_agg_rx->reorder_buf);
     407                 :          0 :                 kfree(tid_agg_rx->reorder_time);
     408                 :          0 :                 kfree(tid_agg_rx);
     409                 :          0 :                 goto end;
     410                 :            :         }
     411                 :            : 
     412         [ #  # ]:          0 :         for (i = 0; i < buf_size; i++)
     413                 :          0 :                 __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
     414                 :            : 
     415                 :          0 :         ret = drv_ampdu_action(local, sta->sdata, &params);
     416                 :          0 :         ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
     417                 :            :                sta->sta.addr, tid, ret);
     418         [ #  # ]:          0 :         if (ret) {
     419                 :          0 :                 kfree(tid_agg_rx->reorder_buf);
     420                 :          0 :                 kfree(tid_agg_rx->reorder_time);
     421                 :          0 :                 kfree(tid_agg_rx);
     422                 :          0 :                 goto end;
     423                 :            :         }
     424                 :            : 
     425                 :            :         /* update data */
     426                 :          0 :         tid_agg_rx->ssn = start_seq_num;
     427                 :          0 :         tid_agg_rx->head_seq_num = start_seq_num;
     428                 :          0 :         tid_agg_rx->buf_size = buf_size;
     429                 :          0 :         tid_agg_rx->timeout = timeout;
     430                 :          0 :         tid_agg_rx->stored_mpdu_num = 0;
     431                 :          0 :         tid_agg_rx->auto_seq = auto_seq;
     432                 :          0 :         tid_agg_rx->started = false;
     433                 :          0 :         tid_agg_rx->reorder_buf_filtered = 0;
     434                 :          0 :         tid_agg_rx->tid = tid;
     435                 :          0 :         tid_agg_rx->sta = sta;
     436                 :          0 :         status = WLAN_STATUS_SUCCESS;
     437                 :            : 
     438                 :            :         /* activate it for RX */
     439         [ #  # ]:          0 :         rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
     440                 :            : 
     441         [ #  # ]:          0 :         if (timeout) {
     442         [ #  # ]:          0 :                 mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
     443                 :          0 :                 tid_agg_rx->last_rx = jiffies;
     444                 :            :         }
     445                 :            : 
     446                 :          0 : end:
     447         [ #  # ]:          0 :         if (status == WLAN_STATUS_SUCCESS) {
     448                 :          0 :                 __set_bit(tid, sta->ampdu_mlme.agg_session_valid);
     449                 :          0 :                 __clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
     450                 :          0 :                 sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
     451                 :            :         }
     452                 :            : 
     453         [ #  # ]:          0 :         if (tx)
     454                 :          0 :                 ieee80211_send_addba_resp(sta, sta->sta.addr, tid,
     455                 :            :                                           dialog_token, status, 1, buf_size,
     456                 :            :                                           timeout, addbaext);
     457                 :          0 : }
     458                 :            : 
     459                 :          0 : 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                 :          0 :         mutex_lock(&sta->ampdu_mlme.mtx);
     467                 :          0 :         ___ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
     468                 :            :                                          start_seq_num, ba_policy, tid,
     469                 :            :                                          buf_size, tx, auto_seq, addbaext);
     470                 :          0 :         mutex_unlock(&sta->ampdu_mlme.mtx);
     471                 :          0 : }
     472                 :            : 
     473                 :          0 : 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                 :          0 :         u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
     479                 :          0 :         struct ieee802_11_elems elems = { 0 };
     480                 :          0 :         u8 dialog_token;
     481                 :          0 :         int ies_len;
     482                 :            : 
     483                 :            :         /* extract session parameters from addba request frame */
     484                 :          0 :         dialog_token = mgmt->u.action.u.addba_req.dialog_token;
     485                 :          0 :         timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
     486                 :          0 :         start_seq_num =
     487                 :          0 :                 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
     488                 :            : 
     489                 :          0 :         capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
     490                 :          0 :         ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
     491                 :          0 :         tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
     492                 :          0 :         buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
     493                 :            : 
     494                 :          0 :         ies_len = len - offsetof(struct ieee80211_mgmt,
     495                 :            :                                  u.action.u.addba_req.variable);
     496         [ #  # ]:          0 :         if (ies_len) {
     497                 :          0 :                 ieee802_11_parse_elems(mgmt->u.action.u.addba_req.variable,
     498                 :          0 :                                 ies_len, true, &elems, mgmt->bssid, NULL);
     499         [ #  # ]:          0 :                 if (elems.parse_error)
     500                 :          0 :                         return;
     501                 :            :         }
     502                 :            : 
     503                 :          0 :         __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                 :          0 : void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
     510                 :            :                                  const u8 *addr, unsigned int tid)
     511                 :            : {
     512                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
     513                 :          0 :         struct ieee80211_local *local = sdata->local;
     514                 :          0 :         struct sta_info *sta;
     515                 :            : 
     516                 :          0 :         rcu_read_lock();
     517                 :          0 :         sta = sta_info_get_bss(sdata, addr);
     518         [ #  # ]:          0 :         if (!sta)
     519                 :          0 :                 goto unlock;
     520                 :            : 
     521                 :          0 :         set_bit(tid, sta->ampdu_mlme.tid_rx_manage_offl);
     522                 :          0 :         ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
     523                 :          0 :  unlock:
     524                 :          0 :         rcu_read_unlock();
     525                 :          0 : }
     526                 :            : EXPORT_SYMBOL(ieee80211_manage_rx_ba_offl);
     527                 :            : 
     528                 :          0 : void ieee80211_rx_ba_timer_expired(struct ieee80211_vif *vif,
     529                 :            :                                    const u8 *addr, unsigned int tid)
     530                 :            : {
     531                 :          0 :         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
     532                 :          0 :         struct ieee80211_local *local = sdata->local;
     533                 :          0 :         struct sta_info *sta;
     534                 :            : 
     535                 :          0 :         rcu_read_lock();
     536                 :          0 :         sta = sta_info_get_bss(sdata, addr);
     537         [ #  # ]:          0 :         if (!sta)
     538                 :          0 :                 goto unlock;
     539                 :            : 
     540                 :          0 :         set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
     541                 :          0 :         ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
     542                 :            : 
     543                 :          0 :  unlock:
     544                 :          0 :         rcu_read_unlock();
     545                 :          0 : }
     546                 :            : EXPORT_SYMBOL(ieee80211_rx_ba_timer_expired);

Generated by: LCOV version 1.14