xref: /linux/net/mac80211/nan.c (revision e9e25a957842ba2667b75df40f5a73bfda934d7b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * NAN mode implementation
4  * Copyright(c) 2025-2026 Intel Corporation
5  */
6 #include <net/mac80211.h>
7 
8 #include "ieee80211_i.h"
9 #include "driver-ops.h"
10 #include "sta_info.h"
11 
12 static void
13 ieee80211_nan_init_channel(struct ieee80211_nan_channel *nan_channel,
14 			   struct cfg80211_nan_channel *cfg_nan_channel)
15 {
16 	memset(nan_channel, 0, sizeof(*nan_channel));
17 
18 	nan_channel->chanreq.oper = cfg_nan_channel->chandef;
19 	memcpy(nan_channel->channel_entry, cfg_nan_channel->channel_entry,
20 	       sizeof(nan_channel->channel_entry));
21 	nan_channel->needed_rx_chains = cfg_nan_channel->rx_nss;
22 }
23 
24 static void
25 ieee80211_nan_update_channel(struct ieee80211_local *local,
26 			     struct ieee80211_nan_channel *nan_channel,
27 			     struct cfg80211_nan_channel *cfg_nan_channel,
28 			     bool deferred)
29 {
30 	struct ieee80211_chanctx_conf *conf;
31 	bool reducing_nss;
32 
33 	if (WARN_ON(!cfg80211_chandef_identical(&nan_channel->chanreq.oper,
34 						&cfg_nan_channel->chandef)))
35 		return;
36 
37 	if (WARN_ON(memcmp(nan_channel->channel_entry,
38 			   cfg_nan_channel->channel_entry,
39 			   sizeof(nan_channel->channel_entry))))
40 		return;
41 
42 	if (nan_channel->needed_rx_chains == cfg_nan_channel->rx_nss)
43 		return;
44 
45 	reducing_nss = nan_channel->needed_rx_chains > cfg_nan_channel->rx_nss;
46 	nan_channel->needed_rx_chains = cfg_nan_channel->rx_nss;
47 
48 	conf = nan_channel->chanctx_conf;
49 
50 	/*
51 	 * If we are adding NSSs, we need to be ready before notifying the peer,
52 	 * if we are reducing NSSs, we need to wait until the peer is notified.
53 	 */
54 	if (!conf || (deferred && reducing_nss))
55 		return;
56 
57 	ieee80211_recalc_smps_chanctx(local, container_of(conf,
58 							  struct ieee80211_chanctx,
59 							  conf));
60 }
61 
62 static int
63 ieee80211_nan_use_chanctx(struct ieee80211_sub_if_data *sdata,
64 			  struct ieee80211_nan_channel *nan_channel,
65 			  bool assign_on_failure)
66 {
67 	struct ieee80211_chanctx *ctx;
68 	bool reused_ctx;
69 
70 	if (!nan_channel->chanreq.oper.chan)
71 		return -EINVAL;
72 
73 	if (ieee80211_check_combinations(sdata, &nan_channel->chanreq.oper,
74 					 IEEE80211_CHANCTX_SHARED, 0, -1))
75 		return -EBUSY;
76 
77 	ctx = ieee80211_find_or_create_chanctx(sdata, &nan_channel->chanreq,
78 					       IEEE80211_CHANCTX_SHARED,
79 					       assign_on_failure,
80 					       &reused_ctx);
81 	if (IS_ERR(ctx))
82 		return PTR_ERR(ctx);
83 
84 	nan_channel->chanctx_conf = &ctx->conf;
85 
86 	/*
87 	 * In case an existing channel context is being used, we marked it as
88 	 * will_be_used, now that it is assigned - clear this indication
89 	 */
90 	if (reused_ctx) {
91 		WARN_ON(!ctx->will_be_used);
92 		ctx->will_be_used = false;
93 	}
94 	ieee80211_recalc_chanctx_min_def(sdata->local, ctx);
95 	ieee80211_recalc_smps_chanctx(sdata->local, ctx);
96 
97 	return 0;
98 }
99 
100 static void
101 ieee80211_nan_update_peer_channels(struct ieee80211_sub_if_data *sdata,
102 				   struct ieee80211_chanctx_conf *removed_conf)
103 {
104 	struct ieee80211_local *local = sdata->local;
105 	struct sta_info *sta;
106 
107 	lockdep_assert_wiphy(local->hw.wiphy);
108 
109 	list_for_each_entry(sta, &local->sta_list, list) {
110 		struct ieee80211_nan_peer_sched *peer_sched;
111 		int write_idx = 0;
112 		bool updated = false;
113 
114 		if (sta->sdata != sdata)
115 			continue;
116 
117 		peer_sched = sta->sta.nan_sched;
118 		if (!peer_sched)
119 			continue;
120 
121 		/* NULL out map slots for channels being removed */
122 		for (int i = 0; i < peer_sched->n_channels; i++) {
123 			if (peer_sched->channels[i].chanctx_conf != removed_conf)
124 				continue;
125 
126 			for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) {
127 				struct ieee80211_nan_peer_map *map =
128 					&peer_sched->maps[m];
129 
130 				if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
131 					continue;
132 
133 				for (int s = 0; s < ARRAY_SIZE(map->slots); s++)
134 					if (map->slots[s] == &peer_sched->channels[i])
135 						map->slots[s] = NULL;
136 			}
137 		}
138 
139 		/* Compact channels array, removing those with removed_conf */
140 		for (int i = 0; i < peer_sched->n_channels; i++) {
141 			if (peer_sched->channels[i].chanctx_conf == removed_conf) {
142 				updated = true;
143 				continue;
144 			}
145 
146 			if (write_idx != i) {
147 				/* Update map pointers before moving */
148 				for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) {
149 					struct ieee80211_nan_peer_map *map =
150 						&peer_sched->maps[m];
151 
152 					if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
153 						continue;
154 
155 					for (int s = 0; s < ARRAY_SIZE(map->slots); s++)
156 						if (map->slots[s] == &peer_sched->channels[i])
157 							map->slots[s] = &peer_sched->channels[write_idx];
158 				}
159 
160 				peer_sched->channels[write_idx] = peer_sched->channels[i];
161 			}
162 			write_idx++;
163 		}
164 
165 		/* Clear any remaining entries at the end */
166 		for (int i = write_idx; i < peer_sched->n_channels; i++)
167 			memset(&peer_sched->channels[i], 0, sizeof(peer_sched->channels[i]));
168 
169 		peer_sched->n_channels = write_idx;
170 
171 		if (updated)
172 			drv_nan_peer_sched_changed(local, sdata, sta);
173 	}
174 }
175 
176 static void
177 ieee80211_nan_remove_channel(struct ieee80211_sub_if_data *sdata,
178 			     struct ieee80211_nan_channel *nan_channel)
179 {
180 	struct ieee80211_chanctx_conf *conf;
181 	struct ieee80211_chanctx *ctx;
182 	struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
183 
184 	if (WARN_ON(!nan_channel))
185 		return;
186 
187 	lockdep_assert_wiphy(sdata->local->hw.wiphy);
188 
189 	if (!nan_channel->chanreq.oper.chan)
190 		return;
191 
192 	for (int slot = 0; slot < ARRAY_SIZE(sched_cfg->schedule); slot++)
193 		if (sched_cfg->schedule[slot] == nan_channel)
194 			sched_cfg->schedule[slot] = NULL;
195 
196 	conf = nan_channel->chanctx_conf;
197 
198 	/* If any peer nan schedule uses this chanctx, update them */
199 	if (conf)
200 		ieee80211_nan_update_peer_channels(sdata, conf);
201 
202 	memset(nan_channel, 0, sizeof(*nan_channel));
203 
204 	/* Update the driver before (possibly) releasing the channel context */
205 	drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
206 
207 	/* Channel might not have a chanctx if it was ULWed */
208 	if (!conf)
209 		return;
210 
211 	ctx = container_of(conf, struct ieee80211_chanctx, conf);
212 
213 	if (ieee80211_chanctx_num_assigned(sdata->local, ctx) > 0) {
214 		ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
215 		ieee80211_recalc_smps_chanctx(sdata->local, ctx);
216 		ieee80211_recalc_chanctx_min_def(sdata->local, ctx);
217 	}
218 
219 	if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
220 		ieee80211_free_chanctx(sdata->local, ctx, false);
221 }
222 
223 static void
224 ieee80211_nan_update_all_ndi_carriers(struct ieee80211_local *local)
225 {
226 	struct ieee80211_sub_if_data *sdata;
227 
228 	lockdep_assert_wiphy(local->hw.wiphy);
229 
230 	/* Iterate all interfaces and update carrier for NDI interfaces */
231 	list_for_each_entry(sdata, &local->interfaces, list) {
232 		if (!ieee80211_sdata_running(sdata) ||
233 		    sdata->vif.type != NL80211_IFTYPE_NAN_DATA)
234 			continue;
235 
236 		ieee80211_nan_update_ndi_carrier(sdata);
237 	}
238 }
239 
240 static struct ieee80211_nan_channel *
241 ieee80211_nan_find_free_channel(struct ieee80211_nan_sched_cfg *sched_cfg)
242 {
243 	for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
244 		if (!sched_cfg->channels[i].chanreq.oper.chan)
245 			return &sched_cfg->channels[i];
246 	}
247 
248 	return NULL;
249 }
250 
251 int
252 ieee80211_nan_set_non_evac_channels(struct ieee80211_sub_if_data *sdata,
253 				    struct cfg80211_nan_non_evac_channels *channels)
254 {
255 	struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
256 
257 	/*
258 	 * cfg80211 already validated that all provided channels belong to the
259 	 * current schedule, so just clear all non-evacuable flags and set the
260 	 * ones in the list.
261 	 */
262 	for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++)
263 		sched_cfg->channels[j].no_evacuate = false;
264 
265 	for (int i = 0; i < channels->n_channels; i++) {
266 		for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) {
267 			if (!sched_cfg->channels[j].chanreq.oper.chan)
268 				continue;
269 			if (cfg80211_chandef_identical(&sched_cfg->channels[j].chanreq.oper,
270 						       &channels->chandefs[i])) {
271 				sched_cfg->channels[j].no_evacuate = true;
272 				break;
273 			}
274 		}
275 	}
276 
277 	return 0;
278 }
279 
280 int ieee80211_nan_set_local_sched(struct ieee80211_sub_if_data *sdata,
281 				  struct cfg80211_nan_local_sched *sched)
282 {
283 	struct ieee80211_nan_channel *sched_idx_to_chan[IEEE80211_NAN_MAX_CHANNELS] = {};
284 	struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
285 	struct ieee80211_nan_sched_cfg *backup_sched __free(kfree) = kmalloc_obj(*backup_sched);
286 	int ret;
287 
288 	if (!backup_sched)
289 		return -ENOMEM;
290 
291 	if (sched->n_channels > IEEE80211_NAN_MAX_CHANNELS)
292 		return -EOPNOTSUPP;
293 
294 	if (sched->nan_avail_blob_len > IEEE80211_NAN_AVAIL_BLOB_MAX_LEN)
295 		return -EINVAL;
296 
297 	/*
298 	 * If a deferred schedule update is pending completion, new updates are
299 	 * not allowed. Only allow to configure an empty schedule so NAN can be
300 	 * stopped in the middle of a deferred update. This is fine because
301 	 * empty schedule means the local NAN device will not be available for
302 	 * peers anymore so there is no need to update peers about a new
303 	 * schedule.
304 	 */
305 	if (WARN_ON(sched_cfg->deferred && sched->n_channels))
306 		return -EBUSY;
307 
308 	bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
309 
310 	memcpy(backup_sched->schedule, sched_cfg->schedule,
311 	       sizeof(backup_sched->schedule));
312 	memcpy(backup_sched->channels, sched_cfg->channels,
313 	       sizeof(backup_sched->channels));
314 	memcpy(backup_sched->avail_blob, sched_cfg->avail_blob,
315 	       sizeof(backup_sched->avail_blob));
316 	backup_sched->avail_blob_len = sched_cfg->avail_blob_len;
317 
318 	memcpy(sched_cfg->avail_blob, sched->nan_avail_blob,
319 	       sched->nan_avail_blob_len);
320 	sched_cfg->avail_blob_len = sched->nan_avail_blob_len;
321 
322 	/*
323 	 * Remove channels that are no longer in the new schedule to free up
324 	 * resources before adding new channels. For deferred schedule, channels
325 	 * will be removed when the schedule is applied.
326 	 * Create a mapping from sched index to sched_cfg channel
327 	 */
328 	for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
329 		bool still_needed = false;
330 
331 		if (!sched_cfg->channels[i].chanreq.oper.chan)
332 			continue;
333 
334 		for (int j = 0; j < sched->n_channels; j++) {
335 			if (cfg80211_chandef_identical(&sched_cfg->channels[i].chanreq.oper,
336 						       &sched->nan_channels[j].chandef)) {
337 				sched_idx_to_chan[j] =
338 					&sched_cfg->channels[i];
339 				still_needed = true;
340 				break;
341 			}
342 		}
343 
344 		if (!still_needed) {
345 			__set_bit(i, sdata->u.nan.removed_channels);
346 			if (!sched->deferred)
347 				ieee80211_nan_remove_channel(sdata,
348 							     &sched_cfg->channels[i]);
349 		}
350 	}
351 
352 	for (int i = 0; i < sched->n_channels; i++) {
353 		struct ieee80211_nan_channel *chan = sched_idx_to_chan[i];
354 
355 		if (chan) {
356 			ieee80211_nan_update_channel(sdata->local, chan,
357 						     &sched->nan_channels[i],
358 						     sched->deferred);
359 		} else {
360 			chan = ieee80211_nan_find_free_channel(sched_cfg);
361 			if (WARN_ON(!chan)) {
362 				ret = -EINVAL;
363 				goto err;
364 			}
365 
366 			sched_idx_to_chan[i] = chan;
367 			ieee80211_nan_init_channel(chan,
368 						   &sched->nan_channels[i]);
369 		}
370 
371 		/* Also a pre-existing channel might have been ULWed, so no chanctx */
372 		if (!chan->chanctx_conf) {
373 			ret = ieee80211_nan_use_chanctx(sdata, chan, false);
374 			if (ret) {
375 				memset(chan, 0, sizeof(*chan));
376 				goto err;
377 			}
378 		}
379 	}
380 
381 	for (int s = 0; s < ARRAY_SIZE(sched_cfg->schedule); s++) {
382 		if (sched->schedule[s] < ARRAY_SIZE(sched_idx_to_chan))
383 			sched_cfg->schedule[s] =
384 				sched_idx_to_chan[sched->schedule[s]];
385 		else
386 			sched_cfg->schedule[s] = NULL;
387 	}
388 
389 	sched_cfg->deferred = sched->deferred;
390 
391 	drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
392 
393 	/*
394 	 * For deferred update, don't update NDI carriers yet as the new
395 	 * schedule is not yet applied so common slots don't change. The NDI
396 	 * carrier will be updated once the driver notifies the new schedule is
397 	 * applied.
398 	 */
399 	if (sched_cfg->deferred)
400 		return 0;
401 
402 	ieee80211_nan_update_all_ndi_carriers(sdata->local);
403 	bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
404 
405 	return 0;
406 err:
407 	/* Remove newly added channels */
408 	for (int i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
409 		struct cfg80211_chan_def *chan_def =
410 			&sched_cfg->channels[i].chanreq.oper;
411 
412 		if (!chan_def->chan)
413 			continue;
414 
415 		if (!cfg80211_chandef_identical(&backup_sched->channels[i].chanreq.oper,
416 						chan_def))
417 			ieee80211_nan_remove_channel(sdata,
418 						     &sched_cfg->channels[i]);
419 	}
420 
421 	/* Re-add all backed up channels */
422 	for (int i = 0; i < ARRAY_SIZE(backup_sched->channels); i++) {
423 		struct ieee80211_nan_channel *chan = &sched_cfg->channels[i];
424 
425 		*chan = backup_sched->channels[i];
426 
427 		/*
428 		 * For deferred update, no channels were removed and the channel
429 		 * context didn't change, so nothing else to do.
430 		 */
431 		if (!chan->chanctx_conf || sched->deferred)
432 			continue;
433 
434 		if (test_bit(i, sdata->u.nan.removed_channels)) {
435 			/* Clear the stale chanctx pointer */
436 			chan->chanctx_conf = NULL;
437 			/*
438 			 * We removed the newly added channels so we don't lack
439 			 * resources. So the only reason that this would fail
440 			 * is a FW error which we ignore. Therefore, this
441 			 * should never fail.
442 			 */
443 			WARN_ON(ieee80211_nan_use_chanctx(sdata, chan, true));
444 		} else {
445 			struct ieee80211_chanctx_conf *conf = chan->chanctx_conf;
446 
447 			/* FIXME: detect no-op? */
448 			/* Channel was not removed but may have been updated */
449 			ieee80211_recalc_smps_chanctx(sdata->local,
450 						     container_of(conf,
451 								  struct ieee80211_chanctx,
452 								  conf));
453 		}
454 	}
455 
456 	memcpy(sched_cfg->schedule, backup_sched->schedule,
457 	       sizeof(backup_sched->schedule));
458 	memcpy(sched_cfg->avail_blob, backup_sched->avail_blob,
459 	       sizeof(backup_sched->avail_blob));
460 	sched_cfg->avail_blob_len = backup_sched->avail_blob_len;
461 	sched_cfg->deferred = false;
462 	bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
463 
464 	drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
465 	ieee80211_nan_update_all_ndi_carriers(sdata->local);
466 	return ret;
467 }
468 
469 void ieee80211_nan_sched_update_done(struct ieee80211_vif *vif)
470 {
471 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
472 	struct ieee80211_nan_sched_cfg *sched_cfg = &vif->cfg.nan_sched;
473 	unsigned int i;
474 
475 	lockdep_assert_wiphy(sdata->local->hw.wiphy);
476 
477 	if (WARN_ON(!sched_cfg->deferred))
478 		return;
479 
480 	ieee80211_nan_update_all_ndi_carriers(sdata->local);
481 
482 	/*
483 	 * Clear the deferred flag before removing channels. Removing channels
484 	 * will trigger another schedule update to the driver, and there is no
485 	 * need for this update to be deferred since removed channels are not
486 	 * part of the schedule anymore, so no need to notify peers about
487 	 * removing them.
488 	 */
489 	sched_cfg->deferred = false;
490 
491 	for (i = 0; i < ARRAY_SIZE(sched_cfg->channels); i++) {
492 		struct ieee80211_nan_channel *chan = &sched_cfg->channels[i];
493 		struct ieee80211_chanctx_conf *conf = chan->chanctx_conf;
494 
495 		if (!chan->chanreq.oper.chan)
496 			continue;
497 
498 		if (test_bit(i, sdata->u.nan.removed_channels))
499 			ieee80211_nan_remove_channel(sdata, chan);
500 		else if (conf)
501 			/*
502 			 * We might have called this already for some channels,
503 			 * but this knows to handle a no-op.
504 			 */
505 			ieee80211_recalc_smps_chanctx(sdata->local,
506 						      container_of(conf,
507 								   struct ieee80211_chanctx,
508 								   conf));
509 	}
510 
511 	bitmap_zero(sdata->u.nan.removed_channels, IEEE80211_NAN_MAX_CHANNELS);
512 	cfg80211_nan_sched_update_done(ieee80211_vif_to_wdev(vif), true,
513 				       GFP_KERNEL);
514 }
515 EXPORT_SYMBOL(ieee80211_nan_sched_update_done);
516 
517 void ieee80211_nan_free_peer_sched(struct ieee80211_nan_peer_sched *sched)
518 {
519 	if (!sched)
520 		return;
521 
522 	kfree(sched->init_ulw);
523 	kfree(sched);
524 }
525 
526 static int
527 ieee80211_nan_init_peer_channel(struct ieee80211_sub_if_data *sdata,
528 				const struct sta_info *sta,
529 				const struct cfg80211_nan_channel *cfg_chan,
530 				struct ieee80211_nan_channel *new_chan)
531 {
532 	struct ieee80211_nan_sched_cfg *sched_cfg = &sdata->vif.cfg.nan_sched;
533 
534 	/* Find compatible local channel */
535 	for (int j = 0; j < ARRAY_SIZE(sched_cfg->channels); j++) {
536 		struct ieee80211_nan_channel *local_chan =
537 			&sched_cfg->channels[j];
538 		const struct cfg80211_chan_def *compat;
539 
540 		if (!local_chan->chanreq.oper.chan)
541 			continue;
542 
543 		compat = cfg80211_chandef_compatible(&local_chan->chanreq.oper,
544 						     &cfg_chan->chandef);
545 		if (!compat)
546 			continue;
547 
548 		/* compat is the wider chandef, and we want the narrower one */
549 		new_chan->chanreq.oper = compat == &local_chan->chanreq.oper ?
550 					 cfg_chan->chandef : local_chan->chanreq.oper;
551 		new_chan->needed_rx_chains = min(local_chan->needed_rx_chains,
552 						 cfg_chan->rx_nss);
553 		new_chan->chanctx_conf = local_chan->chanctx_conf;
554 
555 		break;
556 	}
557 
558 	/*
559 	 * nl80211 already validated that each peer channel is compatible
560 	 * with at least one local channel, so this should never happen.
561 	 */
562 	if (WARN_ON(!new_chan->chanreq.oper.chan))
563 		return -EINVAL;
564 
565 	memcpy(new_chan->channel_entry, cfg_chan->channel_entry,
566 	       sizeof(new_chan->channel_entry));
567 
568 	return 0;
569 }
570 
571 static void
572 ieee80211_nan_init_peer_map(struct ieee80211_nan_peer_sched *peer_sched,
573 			    const struct cfg80211_nan_peer_map *cfg_map,
574 			    struct ieee80211_nan_peer_map *new_map)
575 {
576 	new_map->map_id = cfg_map->map_id;
577 
578 	if (new_map->map_id == CFG80211_NAN_INVALID_MAP_ID)
579 		return;
580 
581 	/* Set up the slots array */
582 	for (int slot = 0; slot < ARRAY_SIZE(new_map->slots); slot++) {
583 		u8 chan_idx = cfg_map->schedule[slot];
584 
585 		if (chan_idx < peer_sched->n_channels)
586 			new_map->slots[slot] = &peer_sched->channels[chan_idx];
587 	}
588 }
589 
590 /*
591  * Check if the local schedule and a peer schedule have at least one common
592  * slot - a slot where both schedules are active on compatible channels.
593  */
594 static bool
595 ieee80211_nan_has_common_slots(struct ieee80211_sub_if_data *sdata,
596 			       struct ieee80211_nan_peer_sched *peer_sched)
597 {
598 	for (int slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; slot++) {
599 		struct ieee80211_nan_channel *local_chan =
600 			sdata->vif.cfg.nan_sched.schedule[slot];
601 
602 		if (!local_chan || !local_chan->chanctx_conf)
603 			continue;
604 
605 		/* Check all peer maps for this slot */
606 		for (int m = 0; m < CFG80211_NAN_MAX_PEER_MAPS; m++) {
607 			struct ieee80211_nan_peer_map *map = &peer_sched->maps[m];
608 			struct ieee80211_nan_channel *peer_chan;
609 
610 			if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
611 				continue;
612 
613 			peer_chan = map->slots[slot];
614 			if (!peer_chan)
615 				continue;
616 
617 			if (local_chan->chanctx_conf == peer_chan->chanctx_conf)
618 				return true;
619 		}
620 	}
621 
622 	return false;
623 }
624 
625 void ieee80211_nan_update_ndi_carrier(struct ieee80211_sub_if_data *ndi_sdata)
626 {
627 	struct ieee80211_local *local = ndi_sdata->local;
628 	struct ieee80211_sub_if_data *nmi_sdata;
629 	struct sta_info *sta;
630 
631 	lockdep_assert_wiphy(local->hw.wiphy);
632 
633 	if (WARN_ON(ndi_sdata->vif.type != NL80211_IFTYPE_NAN_DATA ||
634 		    !ndi_sdata->dev) || !ieee80211_sdata_running(ndi_sdata))
635 		return;
636 
637 	nmi_sdata = wiphy_dereference(local->hw.wiphy, ndi_sdata->u.nan_data.nmi);
638 	if (WARN_ON(!nmi_sdata))
639 		return;
640 
641 	list_for_each_entry(sta, &local->sta_list, list) {
642 		struct ieee80211_sta *nmi_sta;
643 
644 		if (sta->sdata != ndi_sdata ||
645 		    !test_sta_flag(sta, WLAN_STA_AUTHORIZED))
646 			continue;
647 
648 		nmi_sta = wiphy_dereference(local->hw.wiphy, sta->sta.nmi);
649 		if (WARN_ON(!nmi_sta) || !nmi_sta->nan_sched)
650 			continue;
651 
652 		if (ieee80211_nan_has_common_slots(nmi_sdata, nmi_sta->nan_sched)) {
653 			netif_carrier_on(ndi_sdata->dev);
654 			return;
655 		}
656 	}
657 
658 	netif_carrier_off(ndi_sdata->dev);
659 }
660 
661 static void
662 ieee80211_nan_update_peer_ndis_carrier(struct ieee80211_local *local,
663 				       struct sta_info *nmi_sta)
664 {
665 	struct sta_info *sta;
666 
667 	lockdep_assert_wiphy(local->hw.wiphy);
668 
669 	list_for_each_entry(sta, &local->sta_list, list) {
670 		if (rcu_access_pointer(sta->sta.nmi) == &nmi_sta->sta)
671 			ieee80211_nan_update_ndi_carrier(sta->sdata);
672 	}
673 }
674 
675 int ieee80211_nan_set_peer_sched(struct ieee80211_sub_if_data *sdata,
676 				 struct cfg80211_nan_peer_sched *sched)
677 {
678 	struct ieee80211_nan_peer_sched *new_sched, *old_sched, *to_free;
679 	struct sta_info *sta;
680 	int ret;
681 
682 	lockdep_assert_wiphy(sdata->local->hw.wiphy);
683 
684 	if (!sdata->u.nan.started)
685 		return -EINVAL;
686 
687 	sta = sta_info_get(sdata, sched->peer_addr);
688 	if (!sta)
689 		return -ENOENT;
690 
691 	new_sched = kzalloc_flex(*new_sched, channels, sched->n_channels);
692 	if (!new_sched)
693 		return -ENOMEM;
694 
695 	to_free = new_sched;
696 
697 	new_sched->seq_id = sched->seq_id;
698 	new_sched->committed_dw = sched->committed_dw;
699 	new_sched->max_chan_switch = sched->max_chan_switch;
700 	new_sched->n_channels = sched->n_channels;
701 
702 	if (sched->ulw_size && sched->init_ulw) {
703 		new_sched->init_ulw = kmemdup(sched->init_ulw, sched->ulw_size,
704 					      GFP_KERNEL);
705 		if (!new_sched->init_ulw) {
706 			ret = -ENOMEM;
707 			goto out;
708 		}
709 		new_sched->ulw_size = sched->ulw_size;
710 	}
711 
712 	for (int i = 0; i < sched->n_channels; i++) {
713 		ret = ieee80211_nan_init_peer_channel(sdata, sta,
714 						      &sched->nan_channels[i],
715 						      &new_sched->channels[i]);
716 		if (ret)
717 			goto out;
718 	}
719 
720 	for (int m = 0; m < ARRAY_SIZE(sched->maps); m++)
721 		ieee80211_nan_init_peer_map(new_sched, &sched->maps[m],
722 					    &new_sched->maps[m]);
723 
724 	/* Install the new schedule before calling the driver */
725 	old_sched = sta->sta.nan_sched;
726 	sta->sta.nan_sched = new_sched;
727 
728 	ret = drv_nan_peer_sched_changed(sdata->local, sdata, sta);
729 	if (ret) {
730 		/* Revert to old schedule */
731 		sta->sta.nan_sched = old_sched;
732 		goto out;
733 	}
734 
735 	ieee80211_nan_update_peer_ndis_carrier(sdata->local, sta);
736 
737 	/* Success - free old schedule */
738 	to_free = old_sched;
739 	ret = 0;
740 
741 out:
742 	ieee80211_nan_free_peer_sched(to_free);
743 	return ret;
744 }
745 
746 void
747 ieee80211_nan_evacuate_channel(struct ieee80211_sub_if_data *sdata,
748 			       struct ieee80211_nan_channel *nan_channel)
749 {
750 	struct ieee80211_chanctx_conf *conf;
751 	struct ieee80211_chanctx *ctx;
752 
753 	lockdep_assert_wiphy(sdata->local->hw.wiphy);
754 
755 	if (WARN_ON(!nan_channel || !nan_channel->chanreq.oper.chan))
756 		return;
757 
758 	conf = nan_channel->chanctx_conf;
759 	if (WARN_ON(!conf))
760 		return;
761 
762 	nan_channel->chanctx_conf = NULL;
763 
764 	/* Update all peer channels that reference this chanctx */
765 	ieee80211_nan_update_peer_channels(sdata, conf);
766 
767 	drv_vif_cfg_changed(sdata->local, sdata, BSS_CHANGED_NAN_LOCAL_SCHED);
768 
769 	cfg80211_nan_channel_evac(&sdata->wdev, &nan_channel->chanreq.oper,
770 				  GFP_KERNEL);
771 
772 	/* Update NDI carrier states */
773 	ieee80211_nan_update_all_ndi_carriers(sdata->local);
774 
775 	/* Clean up the channel context if no longer used */
776 	ctx = container_of(conf, struct ieee80211_chanctx, conf);
777 
778 	if (ieee80211_chanctx_num_assigned(sdata->local, ctx) > 0) {
779 		ieee80211_recalc_chanctx_chantype(sdata->local, ctx);
780 		ieee80211_recalc_smps_chanctx(sdata->local, ctx);
781 		ieee80211_recalc_chanctx_min_def(sdata->local, ctx);
782 	}
783 
784 	if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
785 		ieee80211_free_chanctx(sdata->local, ctx, false);
786 }
787 
788 struct ieee80211_nan_channel *
789 ieee80211_nan_find_evac_chan(struct ieee80211_local *local,
790 			     struct ieee80211_sub_if_data *sdata,
791 			     struct ieee80211_chanctx *ctx)
792 {
793 	struct ieee80211_nan_sched_cfg *sched_cfg;
794 	struct ieee80211_nan_channel *evac_chan = NULL;
795 	int min_slot_count = INT_MAX;
796 	int usable_channels = 0;
797 
798 	lockdep_assert_wiphy(local->hw.wiphy);
799 
800 	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_NAN))
801 		return NULL;
802 
803 	sched_cfg = &sdata->vif.cfg.nan_sched;
804 
805 	/* Find the channel to evacuate and count usable channels */
806 	for (int i = 0; i < IEEE80211_NAN_MAX_CHANNELS; i++) {
807 		struct ieee80211_nan_channel *chan =
808 			&sched_cfg->channels[i];
809 		struct ieee80211_chanctx *chan_ctx;
810 		int slot_count = 0;
811 
812 		if (!chan->chanreq.oper.chan || !chan->chanctx_conf)
813 			continue;
814 
815 		usable_channels++;
816 
817 		/* No-evacuate channel is usable but cannot be evacuated */
818 		if (chan->no_evacuate)
819 			continue;
820 
821 		chan_ctx = container_of(chan->chanctx_conf,
822 					struct ieee80211_chanctx, conf);
823 
824 		/* If ctx specified, only consider that specific chanctx */
825 		if (ctx) {
826 			if (chan_ctx == ctx)
827 				evac_chan = chan;
828 			continue;
829 		}
830 
831 		/* Can only evacuate channels whose chanctx is NAN-only */
832 		if (ieee80211_chanctx_refcount(local, chan_ctx) > 1)
833 			continue;
834 
835 		/* Count how many time slots use this channel */
836 		for (int s = 0; s < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; s++)
837 			if (sched_cfg->schedule[s] == chan)
838 				slot_count++;
839 
840 		if (slot_count < min_slot_count) {
841 			min_slot_count = slot_count;
842 			evac_chan = chan;
843 		}
844 	}
845 
846 	/* No suitable NAN channel found */
847 	if (!evac_chan)
848 		return NULL;
849 
850 	/* NAN needs at least one remaining usable channel after evacuation */
851 	if (usable_channels < 2)
852 		return NULL;
853 
854 	return evac_chan;
855 }
856 
857 bool ieee80211_nan_try_evacuate(struct ieee80211_hw *hw,
858 				struct ieee80211_chanctx_conf *conf)
859 {
860 	struct ieee80211_local *local = hw_to_local(hw);
861 	struct ieee80211_sub_if_data *sdata =
862 		ieee80211_find_nan_sdata(local);
863 	struct ieee80211_nan_channel *evac_chan;
864 	struct ieee80211_chanctx *ctx = NULL;
865 
866 	lockdep_assert_wiphy(local->hw.wiphy);
867 
868 	if (!sdata)
869 		return false;
870 
871 	if (conf)
872 		ctx = container_of(conf, struct ieee80211_chanctx, conf);
873 
874 	evac_chan = ieee80211_nan_find_evac_chan(local, sdata, ctx);
875 	if (!evac_chan)
876 		return false;
877 
878 	ieee80211_nan_evacuate_channel(sdata, evac_chan);
879 
880 	return true;
881 }
882 EXPORT_SYMBOL(ieee80211_nan_try_evacuate);
883