1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005-2008 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: releng/12.0/sys/net80211/ieee80211_regdomain.c 326272 2017-11-27 15:23:17Z pfg $");
30
31/*
32 * IEEE 802.11 regdomain support.
33 */
34#include "opt_wlan.h"
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/malloc.h>
40#include <sys/socket.h>
41
42#include <net/if.h>
43#include <net/if_var.h>
44#include <net/if_media.h>
45#include <net/ethernet.h>
46
47#include <net80211/ieee80211_var.h>
48#include <net80211/ieee80211_regdomain.h>
49
50static void
51null_getradiocaps(struct ieee80211com *ic, int maxchan,
52	int *n, struct ieee80211_channel *c)
53{
54	/* just feed back the current channel list */
55	if (maxchan > ic->ic_nchans)
56		maxchan = ic->ic_nchans;
57	memcpy(c, ic->ic_channels, maxchan*sizeof(struct ieee80211_channel));
58	*n = maxchan;
59}
60
61static int
62null_setregdomain(struct ieee80211com *ic,
63	struct ieee80211_regdomain *rd,
64	int nchans, struct ieee80211_channel chans[])
65{
66	return 0;		/* accept anything */
67}
68
69void
70ieee80211_regdomain_attach(struct ieee80211com *ic)
71{
72	if (ic->ic_regdomain.regdomain == 0 &&
73	    ic->ic_regdomain.country == CTRY_DEFAULT) {
74		ic->ic_regdomain.location = ' ';		/* both */
75		/* NB: driver calls ieee80211_init_channels or similar */
76	}
77	ic->ic_getradiocaps = null_getradiocaps;
78	ic->ic_setregdomain = null_setregdomain;
79}
80
81void
82ieee80211_regdomain_detach(struct ieee80211com *ic)
83{
84	if (ic->ic_countryie != NULL) {
85		IEEE80211_FREE(ic->ic_countryie, M_80211_NODE_IE);
86		ic->ic_countryie = NULL;
87	}
88}
89
90void
91ieee80211_regdomain_vattach(struct ieee80211vap *vap)
92{
93}
94
95void
96ieee80211_regdomain_vdetach(struct ieee80211vap *vap)
97{
98}
99
100static const uint8_t def_chan_2ghz[] =
101    { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
102static const uint8_t def_chan_5ghz_band1[] =
103    { 36, 40, 44, 48, 52, 56, 60, 64 };
104static const uint8_t def_chan_5ghz_band2[] =
105    { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 };
106static const uint8_t def_chan_5ghz_band3[] =
107    { 149, 153, 157, 161 };
108
109/*
110 * Setup the channel list for the specified regulatory domain,
111 * country code, and operating modes.  This interface is used
112 * when a driver does not obtain the channel list from another
113 * source (such as firmware).
114 */
115int
116ieee80211_init_channels(struct ieee80211com *ic,
117	const struct ieee80211_regdomain *rd, const uint8_t bands[])
118{
119	struct ieee80211_channel *chans = ic->ic_channels;
120	int *nchans = &ic->ic_nchans;
121	int cbw_flags;
122
123	/* XXX just do something for now */
124	cbw_flags = (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) ?
125	    NET80211_CBW_FLAG_HT40 : 0;
126	*nchans = 0;
127	if (isset(bands, IEEE80211_MODE_11B) ||
128	    isset(bands, IEEE80211_MODE_11G) ||
129	    isset(bands, IEEE80211_MODE_11NG)) {
130		int nchan = nitems(def_chan_2ghz);
131		if (!(rd != NULL && rd->ecm))
132			nchan -= 3;
133
134		ieee80211_add_channel_list_2ghz(chans, IEEE80211_CHAN_MAX,
135		    nchans, def_chan_2ghz, nchan, bands, cbw_flags);
136	}
137	/* XXX IEEE80211_MODE_VHT_2GHZ if we really want to. */
138
139	if (isset(bands, IEEE80211_MODE_11A) ||
140	    isset(bands, IEEE80211_MODE_11NA)) {
141		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
142		    nchans, def_chan_5ghz_band1, nitems(def_chan_5ghz_band1),
143		    bands, cbw_flags);
144		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
145		    nchans, def_chan_5ghz_band2, nitems(def_chan_5ghz_band2),
146		    bands, cbw_flags);
147		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
148		    nchans, def_chan_5ghz_band3, nitems(def_chan_5ghz_band3),
149		    bands, cbw_flags);
150	}
151	if (isset(bands, IEEE80211_MODE_VHT_5GHZ)) {
152		cbw_flags |= NET80211_CBW_FLAG_HT40;  /* Make sure this is set; or assert?  */
153		cbw_flags |= NET80211_CBW_FLAG_VHT80;
154		if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(ic->ic_vhtcaps))
155			cbw_flags |= NET80211_CBW_FLAG_VHT160;
156		if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(
157		    ic->ic_vhtcaps))
158			cbw_flags |= NET80211_CBW_FLAG_VHT80P80;
159		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
160		    nchans, def_chan_5ghz_band1, nitems(def_chan_5ghz_band1),
161		    bands, cbw_flags);
162		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
163		    nchans, def_chan_5ghz_band2, nitems(def_chan_5ghz_band2),
164		    bands, cbw_flags);
165		ieee80211_add_channel_list_5ghz(chans, IEEE80211_CHAN_MAX,
166		    nchans, def_chan_5ghz_band3, nitems(def_chan_5ghz_band3),
167		    bands, cbw_flags);
168	}
169	if (rd != NULL)
170		ic->ic_regdomain = *rd;
171
172	return 0;
173}
174
175static __inline int
176chancompar(const void *a, const void *b)
177{
178	const struct ieee80211_channel *ca = a;
179	const struct ieee80211_channel *cb = b;
180
181	return (ca->ic_freq == cb->ic_freq) ?
182		(ca->ic_flags & IEEE80211_CHAN_ALL) -
183		    (cb->ic_flags & IEEE80211_CHAN_ALL) :
184		ca->ic_freq - cb->ic_freq;
185}
186
187/*
188 * Insertion sort.
189 */
190#define swap(_a, _b, _size) {			\
191	uint8_t *s = _b;			\
192	int i = _size;				\
193	do {					\
194		uint8_t tmp = *_a;		\
195		*_a++ = *s;			\
196		*s++ = tmp;			\
197	} while (--i);				\
198	_a -= _size;				\
199}
200
201static void
202sort_channels(void *a, size_t n, size_t size)
203{
204	uint8_t *aa = a;
205	uint8_t *ai, *t;
206
207	KASSERT(n > 0, ("no channels"));
208	for (ai = aa+size; --n >= 1; ai += size)
209		for (t = ai; t > aa; t -= size) {
210			uint8_t *u = t - size;
211			if (chancompar(u, t) <= 0)
212				break;
213			swap(u, t, size);
214		}
215}
216#undef swap
217
218/*
219 * Order channels w/ the same frequency so that
220 * b < g < htg and a < hta.  This is used to optimize
221 * channel table lookups and some user applications
222 * may also depend on it (though they should not).
223 */
224void
225ieee80211_sort_channels(struct ieee80211_channel chans[], int nchans)
226{
227	if (nchans > 0)
228		sort_channels(chans, nchans, sizeof(struct ieee80211_channel));
229}
230
231/*
232 * Allocate and construct a Country Information IE.
233 */
234struct ieee80211_appie *
235ieee80211_alloc_countryie(struct ieee80211com *ic)
236{
237#define	CHAN_UNINTERESTING \
238    (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO | \
239     IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)
240	/* XXX what about auto? */
241	/* flag set of channels to be excluded (band added below) */
242	static const int skipflags[IEEE80211_MODE_MAX] = {
243	    [IEEE80211_MODE_AUTO]	= CHAN_UNINTERESTING,
244	    [IEEE80211_MODE_11A]	= CHAN_UNINTERESTING,
245	    [IEEE80211_MODE_11B]	= CHAN_UNINTERESTING,
246	    [IEEE80211_MODE_11G]	= CHAN_UNINTERESTING,
247	    [IEEE80211_MODE_FH]		= CHAN_UNINTERESTING
248					| IEEE80211_CHAN_OFDM
249					| IEEE80211_CHAN_CCK
250					| IEEE80211_CHAN_DYN,
251	    [IEEE80211_MODE_TURBO_A]	= CHAN_UNINTERESTING,
252	    [IEEE80211_MODE_TURBO_G]	= CHAN_UNINTERESTING,
253	    [IEEE80211_MODE_STURBO_A]	= CHAN_UNINTERESTING,
254	    [IEEE80211_MODE_HALF]	= IEEE80211_CHAN_TURBO
255					| IEEE80211_CHAN_STURBO,
256	    [IEEE80211_MODE_QUARTER]	= IEEE80211_CHAN_TURBO
257					| IEEE80211_CHAN_STURBO,
258	    [IEEE80211_MODE_11NA]	= CHAN_UNINTERESTING,
259	    [IEEE80211_MODE_11NG]	= CHAN_UNINTERESTING,
260	};
261	const struct ieee80211_regdomain *rd = &ic->ic_regdomain;
262	uint8_t nextchan, chans[IEEE80211_CHAN_BYTES], *frm;
263	struct ieee80211_appie *aie;
264	struct ieee80211_country_ie *ie;
265	int i, skip, nruns;
266
267	aie = IEEE80211_MALLOC(IEEE80211_COUNTRY_MAX_SIZE, M_80211_NODE_IE,
268	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
269	if (aie == NULL) {
270		ic_printf(ic, "%s: unable to allocate memory for country ie\n",
271		    __func__);
272		/* XXX stat */
273		return NULL;
274	}
275	ie = (struct ieee80211_country_ie *) aie->ie_data;
276	ie->ie = IEEE80211_ELEMID_COUNTRY;
277	if (rd->isocc[0] == '\0') {
278		ic_printf(ic, "no ISO country string for cc %d; using blanks\n",
279		    rd->country);
280		ie->cc[0] = ie->cc[1] = ' ';
281	} else {
282		ie->cc[0] = rd->isocc[0];
283		ie->cc[1] = rd->isocc[1];
284	}
285	/*
286	 * Indoor/Outdoor portion of country string:
287	 *     'I' indoor only
288	 *     'O' outdoor only
289	 *     ' ' all environments
290	 */
291	ie->cc[2] = (rd->location == 'I' ? 'I' :
292		     rd->location == 'O' ? 'O' : ' ');
293	/*
294	 * Run-length encoded channel+max tx power info.
295	 */
296	frm = (uint8_t *)&ie->band[0];
297	nextchan = 0;			/* NB: impossible channel # */
298	nruns = 0;
299	memset(chans, 0, sizeof(chans));
300	skip = skipflags[ieee80211_chan2mode(ic->ic_bsschan)];
301	if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan))
302		skip |= IEEE80211_CHAN_2GHZ;
303	else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan))
304		skip |= IEEE80211_CHAN_5GHZ;
305	for (i = 0; i < ic->ic_nchans; i++) {
306		const struct ieee80211_channel *c = &ic->ic_channels[i];
307
308		if (isset(chans, c->ic_ieee))		/* suppress dup's */
309			continue;
310		if (c->ic_flags & skip)			/* skip band, etc. */
311			continue;
312		setbit(chans, c->ic_ieee);
313		if (c->ic_ieee != nextchan ||
314		    c->ic_maxregpower != frm[-1]) {	/* new run */
315			if (nruns == IEEE80211_COUNTRY_MAX_BANDS) {
316				ic_printf(ic, "%s: country ie too big, "
317				    "runs > max %d, truncating\n",
318				    __func__, IEEE80211_COUNTRY_MAX_BANDS);
319				/* XXX stat? fail? */
320				break;
321			}
322			frm[0] = c->ic_ieee;		/* starting channel # */
323			frm[1] = 1;			/* # channels in run */
324			frm[2] = c->ic_maxregpower;	/* tx power cap */
325			frm += 3;
326			nextchan = c->ic_ieee + 1;	/* overflow? */
327			nruns++;
328		} else {				/* extend run */
329			frm[-2]++;
330			nextchan++;
331		}
332	}
333	ie->len = frm - ie->cc;
334	if (ie->len & 1) {		/* Zero pad to multiple of 2 */
335		ie->len++;
336		*frm++ = 0;
337	}
338	aie->ie_len = frm - aie->ie_data;
339
340	return aie;
341#undef CHAN_UNINTERESTING
342}
343
344static int
345allvapsdown(struct ieee80211com *ic)
346{
347	struct ieee80211vap *vap;
348
349	IEEE80211_LOCK_ASSERT(ic);
350	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
351		if (vap->iv_state != IEEE80211_S_INIT)
352			return 0;
353	return 1;
354}
355
356int
357ieee80211_setregdomain(struct ieee80211vap *vap,
358    struct ieee80211_regdomain_req *reg)
359{
360	struct ieee80211com *ic = vap->iv_ic;
361	struct ieee80211_channel *c;
362	int desfreq = 0, desflags = 0;		/* XXX silence gcc complaint */
363	int error, i;
364
365	if (reg->rd.location != 'I' && reg->rd.location != 'O' &&
366	    reg->rd.location != ' ') {
367		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
368		    "%s: invalid location 0x%x\n", __func__, reg->rd.location);
369		return EINVAL;
370	}
371	if (reg->rd.isocc[0] == '\0' || reg->rd.isocc[1] == '\0') {
372		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
373		    "%s: invalid iso cc 0x%x:0x%x\n", __func__,
374		    reg->rd.isocc[0], reg->rd.isocc[1]);
375		return EINVAL;
376	}
377	if (reg->chaninfo.ic_nchans > IEEE80211_CHAN_MAX) {
378		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
379		    "%s: too many channels %u, max %u\n", __func__,
380		    reg->chaninfo.ic_nchans, IEEE80211_CHAN_MAX);
381		return EINVAL;
382	}
383	/*
384	 * Calculate freq<->IEEE mapping and default max tx power
385	 * for channels not setup.  The driver can override these
386	 * setting to reflect device properties/requirements.
387	 */
388	for (i = 0; i < reg->chaninfo.ic_nchans; i++) {
389		c = &reg->chaninfo.ic_chans[i];
390		if (c->ic_freq == 0 || c->ic_flags == 0) {
391			IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
392			    "%s: invalid channel spec at [%u]\n", __func__, i);
393			return EINVAL;
394		}
395		if (c->ic_maxregpower == 0) {
396			IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
397			    "%s: invalid channel spec, zero maxregpower, "
398			    "freq %u flags 0x%x\n", __func__,
399			    c->ic_freq, c->ic_flags);
400			return EINVAL;
401		}
402		if (c->ic_ieee == 0)
403			c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags);
404		if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0)
405			c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq +
406			    (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20),
407			    c->ic_flags);
408		if (c->ic_maxpower == 0)
409			c->ic_maxpower = 2*c->ic_maxregpower;
410	}
411	IEEE80211_LOCK(ic);
412	/* XXX bandaid; a running vap will likely crash */
413	if (!allvapsdown(ic)) {
414		IEEE80211_UNLOCK(ic);
415		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
416		    "%s: reject: vaps are running\n", __func__);
417		return EBUSY;
418	}
419	error = ic->ic_setregdomain(ic, &reg->rd,
420	    reg->chaninfo.ic_nchans, reg->chaninfo.ic_chans);
421	if (error != 0) {
422		IEEE80211_UNLOCK(ic);
423		IEEE80211_DPRINTF(vap, IEEE80211_MSG_IOCTL,
424		    "%s: driver rejected request, error %u\n", __func__, error);
425		return error;
426	}
427	/*
428	 * Commit: copy in new channel table and reset media state.
429	 * On return the state machines will be clocked so all vaps
430	 * will reset their state.
431	 *
432	 * XXX ic_bsschan is marked undefined, must have vap's in
433	 *     INIT state or we blow up forcing stations off
434	 */
435	/*
436	 * Save any desired channel for restore below.  Note this
437	 * needs to be done for all vaps but for now we only do
438	 * the one where the ioctl is issued.
439	 */
440	if (vap->iv_des_chan != IEEE80211_CHAN_ANYC) {
441		desfreq = vap->iv_des_chan->ic_freq;
442		desflags = vap->iv_des_chan->ic_flags;
443	}
444	/* regdomain parameters */
445	memcpy(&ic->ic_regdomain, &reg->rd, sizeof(reg->rd));
446	/* channel table */
447	memcpy(ic->ic_channels, reg->chaninfo.ic_chans,
448	    reg->chaninfo.ic_nchans * sizeof(struct ieee80211_channel));
449	ic->ic_nchans = reg->chaninfo.ic_nchans;
450	memset(&ic->ic_channels[ic->ic_nchans], 0,
451	    (IEEE80211_CHAN_MAX - ic->ic_nchans) *
452	       sizeof(struct ieee80211_channel));
453	ieee80211_chan_init(ic);
454
455	/*
456	 * Invalidate channel-related state.
457	 */
458	if (ic->ic_countryie != NULL) {
459		IEEE80211_FREE(ic->ic_countryie, M_80211_NODE_IE);
460		ic->ic_countryie = NULL;
461	}
462	ieee80211_scan_flush(vap);
463	ieee80211_dfs_reset(ic);
464	if (vap->iv_des_chan != IEEE80211_CHAN_ANYC) {
465		c = ieee80211_find_channel(ic, desfreq, desflags);
466		/* NB: may be NULL if not present in new channel list */
467		vap->iv_des_chan = (c != NULL) ? c : IEEE80211_CHAN_ANYC;
468	}
469	IEEE80211_UNLOCK(ic);
470
471	return 0;
472}
473