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