root/net/mac80211/ocb.c

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

DEFINITIONS

This source file includes following definitions.
  1. ieee80211_ocb_rx_no_sta
  2. ieee80211_ocb_finish_sta
  3. ieee80211_ocb_housekeeping
  4. ieee80211_ocb_work
  5. ieee80211_ocb_housekeeping_timer
  6. ieee80211_ocb_setup_sdata
  7. ieee80211_ocb_join
  8. ieee80211_ocb_leave

   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 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         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
  43         struct ieee80211_local *local = sdata->local;
  44         struct ieee80211_chanctx_conf *chanctx_conf;
  45         struct ieee80211_supported_band *sband;
  46         enum nl80211_bss_scan_width scan_width;
  47         struct sta_info *sta;
  48         int band;
  49 
  50         /* XXX: Consider removing the least recently used entry and
  51          *      allow new one to be added.
  52          */
  53         if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) {
  54                 net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n",
  55                                      sdata->name, addr);
  56                 return;
  57         }
  58 
  59         ocb_dbg(sdata, "Adding new OCB station %pM\n", addr);
  60 
  61         rcu_read_lock();
  62         chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  63         if (WARN_ON_ONCE(!chanctx_conf)) {
  64                 rcu_read_unlock();
  65                 return;
  66         }
  67         band = chanctx_conf->def.chan->band;
  68         scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
  69         rcu_read_unlock();
  70 
  71         sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
  72         if (!sta)
  73                 return;
  74 
  75         /* Add only mandatory rates for now */
  76         sband = local->hw.wiphy->bands[band];
  77         sta->sta.supp_rates[band] =
  78                 ieee80211_mandatory_rates(sband, scan_width);
  79 
  80         spin_lock(&ifocb->incomplete_lock);
  81         list_add(&sta->list, &ifocb->incomplete_stations);
  82         spin_unlock(&ifocb->incomplete_lock);
  83         ieee80211_queue_work(&local->hw, &sdata->work);
  84 }
  85 
  86 static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
  87         __acquires(RCU)
  88 {
  89         struct ieee80211_sub_if_data *sdata = sta->sdata;
  90         u8 addr[ETH_ALEN];
  91 
  92         memcpy(addr, sta->sta.addr, ETH_ALEN);
  93 
  94         ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n",
  95                 addr, sdata->name);
  96 
  97         sta_info_move_state(sta, IEEE80211_STA_AUTH);
  98         sta_info_move_state(sta, IEEE80211_STA_ASSOC);
  99         sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
 100 
 101         rate_control_rate_init(sta);
 102 
 103         /* If it fails, maybe we raced another insertion? */
 104         if (sta_info_insert_rcu(sta))
 105                 return sta_info_get(sdata, addr);
 106         return sta;
 107 }
 108 
 109 static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata)
 110 {
 111         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 112 
 113         ocb_dbg(sdata, "Running ocb housekeeping\n");
 114 
 115         ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT);
 116 
 117         mod_timer(&ifocb->housekeeping_timer,
 118                   round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL));
 119 }
 120 
 121 void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata)
 122 {
 123         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 124         struct sta_info *sta;
 125 
 126         if (ifocb->joined != true)
 127                 return;
 128 
 129         sdata_lock(sdata);
 130 
 131         spin_lock_bh(&ifocb->incomplete_lock);
 132         while (!list_empty(&ifocb->incomplete_stations)) {
 133                 sta = list_first_entry(&ifocb->incomplete_stations,
 134                                        struct sta_info, list);
 135                 list_del(&sta->list);
 136                 spin_unlock_bh(&ifocb->incomplete_lock);
 137 
 138                 ieee80211_ocb_finish_sta(sta);
 139                 rcu_read_unlock();
 140                 spin_lock_bh(&ifocb->incomplete_lock);
 141         }
 142         spin_unlock_bh(&ifocb->incomplete_lock);
 143 
 144         if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags))
 145                 ieee80211_ocb_housekeeping(sdata);
 146 
 147         sdata_unlock(sdata);
 148 }
 149 
 150 static void ieee80211_ocb_housekeeping_timer(struct timer_list *t)
 151 {
 152         struct ieee80211_sub_if_data *sdata =
 153                 from_timer(sdata, t, u.ocb.housekeeping_timer);
 154         struct ieee80211_local *local = sdata->local;
 155         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 156 
 157         set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
 158 
 159         ieee80211_queue_work(&local->hw, &sdata->work);
 160 }
 161 
 162 void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
 163 {
 164         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 165 
 166         timer_setup(&ifocb->housekeeping_timer,
 167                     ieee80211_ocb_housekeeping_timer, 0);
 168         INIT_LIST_HEAD(&ifocb->incomplete_stations);
 169         spin_lock_init(&ifocb->incomplete_lock);
 170 }
 171 
 172 int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
 173                        struct ocb_setup *setup)
 174 {
 175         struct ieee80211_local *local = sdata->local;
 176         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 177         u32 changed = BSS_CHANGED_OCB | BSS_CHANGED_BSSID;
 178         int err;
 179 
 180         if (ifocb->joined == true)
 181                 return -EINVAL;
 182 
 183         sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
 184         sdata->smps_mode = IEEE80211_SMPS_OFF;
 185         sdata->needed_rx_chains = sdata->local->rx_chains;
 186 
 187         mutex_lock(&sdata->local->mtx);
 188         err = ieee80211_vif_use_channel(sdata, &setup->chandef,
 189                                         IEEE80211_CHANCTX_SHARED);
 190         mutex_unlock(&sdata->local->mtx);
 191         if (err)
 192                 return err;
 193 
 194         ieee80211_bss_info_change_notify(sdata, changed);
 195 
 196         ifocb->joined = true;
 197 
 198         set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
 199         ieee80211_queue_work(&local->hw, &sdata->work);
 200 
 201         netif_carrier_on(sdata->dev);
 202         return 0;
 203 }
 204 
 205 int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata)
 206 {
 207         struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
 208         struct ieee80211_local *local = sdata->local;
 209         struct sta_info *sta;
 210 
 211         ifocb->joined = false;
 212         sta_info_flush(sdata);
 213 
 214         spin_lock_bh(&ifocb->incomplete_lock);
 215         while (!list_empty(&ifocb->incomplete_stations)) {
 216                 sta = list_first_entry(&ifocb->incomplete_stations,
 217                                        struct sta_info, list);
 218                 list_del(&sta->list);
 219                 spin_unlock_bh(&ifocb->incomplete_lock);
 220 
 221                 sta_info_free(local, sta);
 222                 spin_lock_bh(&ifocb->incomplete_lock);
 223         }
 224         spin_unlock_bh(&ifocb->incomplete_lock);
 225 
 226         netif_carrier_off(sdata->dev);
 227         clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
 228         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB);
 229 
 230         mutex_lock(&sdata->local->mtx);
 231         ieee80211_vif_release_channel(sdata);
 232         mutex_unlock(&sdata->local->mtx);
 233 
 234         skb_queue_purge(&sdata->skb_queue);
 235 
 236         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         return 0;
 245 }

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