LCOV - code coverage report
Current view: top level - net/mac80211 - ocb.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 119 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 8 0.0 %
Branches: 0 29 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * OCB mode implementation
       4                 :            :  *
       5                 :            :  * Copyright: (c) 2014 Czech Technical University in Prague
       6                 :            :  *            (c) 2014 Volkswagen Group Research
       7                 :            :  * Author:    Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
       8                 :            :  * Funded by: Volkswagen Group Research
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/delay.h>
      12                 :            : #include <linux/if_ether.h>
      13                 :            : #include <linux/skbuff.h>
      14                 :            : #include <linux/if_arp.h>
      15                 :            : #include <linux/etherdevice.h>
      16                 :            : #include <linux/rtnetlink.h>
      17                 :            : #include <net/mac80211.h>
      18                 :            : #include <asm/unaligned.h>
      19                 :            : 
      20                 :            : #include "ieee80211_i.h"
      21                 :            : #include "driver-ops.h"
      22                 :            : #include "rate.h"
      23                 :            : 
      24                 :            : #define IEEE80211_OCB_HOUSEKEEPING_INTERVAL             (60 * HZ)
      25                 :            : #define IEEE80211_OCB_PEER_INACTIVITY_LIMIT             (240 * HZ)
      26                 :            : #define IEEE80211_OCB_MAX_STA_ENTRIES                   128
      27                 :            : 
      28                 :            : /**
      29                 :            :  * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks
      30                 :            :  * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks
      31                 :            :  *
      32                 :            :  * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb
      33                 :            :  */
      34                 :            : enum ocb_deferred_task_flags {
      35                 :            :         OCB_WORK_HOUSEKEEPING,
      36                 :            : };
      37                 :            : 
      38                 :          0 : void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
      39                 :            :                              const u8 *bssid, const u8 *addr,
      40                 :            :                              u32 supp_rates)
      41                 :            : {
      42                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
      43                 :          0 :         struct ieee80211_local *local = sdata->local;
      44                 :          0 :         struct ieee80211_chanctx_conf *chanctx_conf;
      45                 :          0 :         struct ieee80211_supported_band *sband;
      46                 :          0 :         enum nl80211_bss_scan_width scan_width;
      47                 :          0 :         struct sta_info *sta;
      48                 :          0 :         int band;
      49                 :            : 
      50                 :            :         /* XXX: Consider removing the least recently used entry and
      51                 :            :          *      allow new one to be added.
      52                 :            :          */
      53         [ #  # ]:          0 :         if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) {
      54         [ #  # ]:          0 :                 net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n",
      55                 :            :                                      sdata->name, addr);
      56                 :          0 :                 return;
      57                 :            :         }
      58                 :            : 
      59                 :          0 :         ocb_dbg(sdata, "Adding new OCB station %pM\n", addr);
      60                 :            : 
      61                 :          0 :         rcu_read_lock();
      62         [ #  # ]:          0 :         chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
      63   [ #  #  #  # ]:          0 :         if (WARN_ON_ONCE(!chanctx_conf)) {
      64                 :          0 :                 rcu_read_unlock();
      65                 :          0 :                 return;
      66                 :            :         }
      67                 :          0 :         band = chanctx_conf->def.chan->band;
      68      [ #  #  # ]:          0 :         scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
      69                 :          0 :         rcu_read_unlock();
      70                 :            : 
      71                 :          0 :         sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
      72         [ #  # ]:          0 :         if (!sta)
      73                 :            :                 return;
      74                 :            : 
      75                 :            :         /* Add only mandatory rates for now */
      76                 :          0 :         sband = local->hw.wiphy->bands[band];
      77                 :          0 :         sta->sta.supp_rates[band] =
      78                 :          0 :                 ieee80211_mandatory_rates(sband, scan_width);
      79                 :            : 
      80                 :          0 :         spin_lock(&ifocb->incomplete_lock);
      81                 :          0 :         list_add(&sta->list, &ifocb->incomplete_stations);
      82                 :          0 :         spin_unlock(&ifocb->incomplete_lock);
      83                 :          0 :         ieee80211_queue_work(&local->hw, &sdata->work);
      84                 :            : }
      85                 :            : 
      86                 :          0 : static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
      87                 :            :         __acquires(RCU)
      88                 :            : {
      89                 :          0 :         struct ieee80211_sub_if_data *sdata = sta->sdata;
      90                 :          0 :         u8 addr[ETH_ALEN];
      91                 :            : 
      92                 :          0 :         memcpy(addr, sta->sta.addr, ETH_ALEN);
      93                 :            : 
      94                 :          0 :         ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n",
      95                 :            :                 addr, sdata->name);
      96                 :            : 
      97                 :          0 :         sta_info_move_state(sta, IEEE80211_STA_AUTH);
      98                 :          0 :         sta_info_move_state(sta, IEEE80211_STA_ASSOC);
      99                 :          0 :         sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
     100                 :            : 
     101                 :          0 :         rate_control_rate_init(sta);
     102                 :            : 
     103                 :            :         /* If it fails, maybe we raced another insertion? */
     104         [ #  # ]:          0 :         if (sta_info_insert_rcu(sta))
     105                 :          0 :                 return sta_info_get(sdata, addr);
     106                 :            :         return sta;
     107                 :            : }
     108                 :            : 
     109                 :          0 : static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata)
     110                 :            : {
     111                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
     112                 :            : 
     113                 :          0 :         ocb_dbg(sdata, "Running ocb housekeeping\n");
     114                 :            : 
     115                 :          0 :         ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT);
     116                 :            : 
     117                 :          0 :         mod_timer(&ifocb->housekeeping_timer,
     118                 :            :                   round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL));
     119                 :          0 : }
     120                 :            : 
     121                 :          0 : void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata)
     122                 :            : {
     123                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
     124                 :          0 :         struct sta_info *sta;
     125                 :            : 
     126         [ #  # ]:          0 :         if (ifocb->joined != true)
     127                 :            :                 return;
     128                 :            : 
     129                 :          0 :         sdata_lock(sdata);
     130                 :            : 
     131                 :          0 :         spin_lock_bh(&ifocb->incomplete_lock);
     132         [ #  # ]:          0 :         while (!list_empty(&ifocb->incomplete_stations)) {
     133                 :          0 :                 sta = list_first_entry(&ifocb->incomplete_stations,
     134                 :            :                                        struct sta_info, list);
     135                 :          0 :                 list_del(&sta->list);
     136                 :          0 :                 spin_unlock_bh(&ifocb->incomplete_lock);
     137                 :            : 
     138                 :          0 :                 ieee80211_ocb_finish_sta(sta);
     139                 :          0 :                 rcu_read_unlock();
     140                 :          0 :                 spin_lock_bh(&ifocb->incomplete_lock);
     141                 :            :         }
     142                 :          0 :         spin_unlock_bh(&ifocb->incomplete_lock);
     143                 :            : 
     144         [ #  # ]:          0 :         if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags))
     145                 :          0 :                 ieee80211_ocb_housekeeping(sdata);
     146                 :            : 
     147                 :          0 :         sdata_unlock(sdata);
     148                 :            : }
     149                 :            : 
     150                 :          0 : static void ieee80211_ocb_housekeeping_timer(struct timer_list *t)
     151                 :            : {
     152                 :          0 :         struct ieee80211_sub_if_data *sdata =
     153                 :          0 :                 from_timer(sdata, t, u.ocb.housekeeping_timer);
     154                 :          0 :         struct ieee80211_local *local = sdata->local;
     155                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
     156                 :            : 
     157                 :          0 :         set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
     158                 :            : 
     159                 :          0 :         ieee80211_queue_work(&local->hw, &sdata->work);
     160                 :          0 : }
     161                 :            : 
     162                 :          0 : void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
     163                 :            : {
     164                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
     165                 :            : 
     166                 :          0 :         timer_setup(&ifocb->housekeeping_timer,
     167                 :            :                     ieee80211_ocb_housekeeping_timer, 0);
     168                 :          0 :         INIT_LIST_HEAD(&ifocb->incomplete_stations);
     169                 :          0 :         spin_lock_init(&ifocb->incomplete_lock);
     170                 :          0 : }
     171                 :            : 
     172                 :          0 : int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
     173                 :            :                        struct ocb_setup *setup)
     174                 :            : {
     175                 :          0 :         struct ieee80211_local *local = sdata->local;
     176                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
     177                 :          0 :         u32 changed = BSS_CHANGED_OCB | BSS_CHANGED_BSSID;
     178                 :          0 :         int err;
     179                 :            : 
     180         [ #  # ]:          0 :         if (ifocb->joined == true)
     181                 :            :                 return -EINVAL;
     182                 :            : 
     183                 :          0 :         sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
     184                 :          0 :         sdata->smps_mode = IEEE80211_SMPS_OFF;
     185                 :          0 :         sdata->needed_rx_chains = sdata->local->rx_chains;
     186                 :            : 
     187                 :          0 :         mutex_lock(&sdata->local->mtx);
     188                 :          0 :         err = ieee80211_vif_use_channel(sdata, &setup->chandef,
     189                 :            :                                         IEEE80211_CHANCTX_SHARED);
     190                 :          0 :         mutex_unlock(&sdata->local->mtx);
     191         [ #  # ]:          0 :         if (err)
     192                 :            :                 return err;
     193                 :            : 
     194                 :          0 :         ieee80211_bss_info_change_notify(sdata, changed);
     195                 :            : 
     196                 :          0 :         ifocb->joined = true;
     197                 :            : 
     198                 :          0 :         set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
     199                 :          0 :         ieee80211_queue_work(&local->hw, &sdata->work);
     200                 :            : 
     201                 :          0 :         netif_carrier_on(sdata->dev);
     202                 :          0 :         return 0;
     203                 :            : }
     204                 :            : 
     205                 :          0 : int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata)
     206                 :            : {
     207                 :          0 :         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
     208                 :          0 :         struct ieee80211_local *local = sdata->local;
     209                 :          0 :         struct sta_info *sta;
     210                 :            : 
     211                 :          0 :         ifocb->joined = false;
     212                 :          0 :         sta_info_flush(sdata);
     213                 :            : 
     214                 :          0 :         spin_lock_bh(&ifocb->incomplete_lock);
     215         [ #  # ]:          0 :         while (!list_empty(&ifocb->incomplete_stations)) {
     216                 :          0 :                 sta = list_first_entry(&ifocb->incomplete_stations,
     217                 :            :                                        struct sta_info, list);
     218                 :          0 :                 list_del(&sta->list);
     219                 :          0 :                 spin_unlock_bh(&ifocb->incomplete_lock);
     220                 :            : 
     221                 :          0 :                 sta_info_free(local, sta);
     222                 :          0 :                 spin_lock_bh(&ifocb->incomplete_lock);
     223                 :            :         }
     224                 :          0 :         spin_unlock_bh(&ifocb->incomplete_lock);
     225                 :            : 
     226                 :          0 :         netif_carrier_off(sdata->dev);
     227                 :          0 :         clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
     228                 :          0 :         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB);
     229                 :            : 
     230                 :          0 :         mutex_lock(&sdata->local->mtx);
     231                 :          0 :         ieee80211_vif_release_channel(sdata);
     232                 :          0 :         mutex_unlock(&sdata->local->mtx);
     233                 :            : 
     234                 :          0 :         skb_queue_purge(&sdata->skb_queue);
     235                 :            : 
     236                 :          0 :         del_timer_sync(&sdata->u.ocb.housekeeping_timer);
     237                 :            :         /* If the timer fired while we waited for it, it will have
     238                 :            :          * requeued the work. Now the work will be running again
     239                 :            :          * but will not rearm the timer again because it checks
     240                 :            :          * whether we are connected to the network or not -- at this
     241                 :            :          * point we shouldn't be anymore.
     242                 :            :          */
     243                 :            : 
     244                 :          0 :         return 0;
     245                 :            : }

Generated by: LCOV version 1.14