File Index
Files and directories
Sign in
FILE

ocb.c

File preview with syntax highlighting.

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