xref: /freebsd/sys/net80211/ieee80211_regdomain.c (revision 5ef9cd6c92d8949958eed0dd72663b36cf22e23b)
168e8e04eSSam Leffler /*-
268e8e04eSSam Leffler  * Copyright (c) 2005-2007 Sam Leffler, Errno Consulting
368e8e04eSSam Leffler  * All rights reserved.
468e8e04eSSam Leffler  *
568e8e04eSSam Leffler  * Redistribution and use in source and binary forms, with or without
668e8e04eSSam Leffler  * modification, are permitted provided that the following conditions
768e8e04eSSam Leffler  * are met:
868e8e04eSSam Leffler  * 1. Redistributions of source code must retain the above copyright
968e8e04eSSam Leffler  *    notice, this list of conditions and the following disclaimer.
1068e8e04eSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
1168e8e04eSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
1268e8e04eSSam Leffler  *    documentation and/or other materials provided with the distribution.
1368e8e04eSSam Leffler  *
1468e8e04eSSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1568e8e04eSSam Leffler  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1668e8e04eSSam Leffler  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1768e8e04eSSam Leffler  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1868e8e04eSSam Leffler  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1968e8e04eSSam Leffler  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2068e8e04eSSam Leffler  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2168e8e04eSSam Leffler  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2268e8e04eSSam Leffler  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2368e8e04eSSam Leffler  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2468e8e04eSSam Leffler  */
2568e8e04eSSam Leffler 
2668e8e04eSSam Leffler #include <sys/cdefs.h>
2768e8e04eSSam Leffler __FBSDID("$FreeBSD$");
2868e8e04eSSam Leffler 
2968e8e04eSSam Leffler /*
3068e8e04eSSam Leffler  * IEEE 802.11 regdomain support.
3168e8e04eSSam Leffler  */
3268e8e04eSSam Leffler 
3368e8e04eSSam Leffler #include <sys/param.h>
3468e8e04eSSam Leffler #include <sys/systm.h>
3568e8e04eSSam Leffler #include <sys/kernel.h>
3668e8e04eSSam Leffler 
3768e8e04eSSam Leffler #include <sys/socket.h>
3868e8e04eSSam Leffler 
3968e8e04eSSam Leffler #include <net/if.h>
4068e8e04eSSam Leffler #include <net/if_arp.h>
4168e8e04eSSam Leffler #include <net/if_dl.h>
4268e8e04eSSam Leffler #include <net/if_media.h>
4368e8e04eSSam Leffler #include <net/if_types.h>
4468e8e04eSSam Leffler #include <net/ethernet.h>
4568e8e04eSSam Leffler 
4668e8e04eSSam Leffler #include <net80211/ieee80211_var.h>
4768e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h>
4868e8e04eSSam Leffler 
4968e8e04eSSam Leffler void
5068e8e04eSSam Leffler ieee80211_regdomain_attach(struct ieee80211com *ic)
5168e8e04eSSam Leffler {
5268e8e04eSSam Leffler 	ic->ic_regdomain = 0;			/* XXX */
5368e8e04eSSam Leffler 	ic->ic_countrycode = CTRY_UNITED_STATES;/* XXX */
5468e8e04eSSam Leffler 	ic->ic_location = 1+2;			/* both */
5568e8e04eSSam Leffler }
5668e8e04eSSam Leffler 
5768e8e04eSSam Leffler void
5868e8e04eSSam Leffler ieee80211_regdomain_detach(struct ieee80211com *ic)
5968e8e04eSSam Leffler {
6068e8e04eSSam Leffler }
6168e8e04eSSam Leffler 
6268e8e04eSSam Leffler static void
6368e8e04eSSam Leffler addchan(struct ieee80211com *ic, int ieee, int flags)
6468e8e04eSSam Leffler {
6568e8e04eSSam Leffler 	struct ieee80211_channel *c;
6668e8e04eSSam Leffler 
6768e8e04eSSam Leffler 	c = &ic->ic_channels[ic->ic_nchans++];
6868e8e04eSSam Leffler 	c->ic_freq = ieee80211_ieee2mhz(ieee, flags);
6968e8e04eSSam Leffler 	c->ic_ieee = ieee;
7068e8e04eSSam Leffler 	c->ic_flags = flags;
7168e8e04eSSam Leffler }
7268e8e04eSSam Leffler 
7368e8e04eSSam Leffler /*
7468e8e04eSSam Leffler  * Setup the channel list for the specified regulatory domain,
7568e8e04eSSam Leffler  * country code, and operating modes.  This interface is used
7668e8e04eSSam Leffler  * when a driver does not obtain the channel list from another
7768e8e04eSSam Leffler  * source (such as firmware).
7868e8e04eSSam Leffler  */
7968e8e04eSSam Leffler void
8068e8e04eSSam Leffler ieee80211_init_channels(struct ieee80211com *ic,
8168e8e04eSSam Leffler 	int rd, enum ISOCountryCode cc, int bands, int outdoor, int ecm)
8268e8e04eSSam Leffler {
8368e8e04eSSam Leffler 	int i;
8468e8e04eSSam Leffler 
8568e8e04eSSam Leffler 	/* XXX just do something for now */
8668e8e04eSSam Leffler 	ic->ic_nchans = 0;
8768e8e04eSSam Leffler 	if (isset(&bands, IEEE80211_MODE_11B) ||
8868e8e04eSSam Leffler 	    isset(&bands, IEEE80211_MODE_11G)) {
8968e8e04eSSam Leffler 		for (i = 1; i <= (ecm ? 14 : 11); i++) {
9068e8e04eSSam Leffler 			if (isset(&bands, IEEE80211_MODE_11B))
9168e8e04eSSam Leffler 				addchan(ic, i, IEEE80211_CHAN_B);
9268e8e04eSSam Leffler 			if (isset(&bands, IEEE80211_MODE_11G))
9368e8e04eSSam Leffler 				addchan(ic, i, IEEE80211_CHAN_G);
9468e8e04eSSam Leffler 		}
9568e8e04eSSam Leffler 	}
9668e8e04eSSam Leffler 	if (isset(&bands, IEEE80211_MODE_11A)) {
9768e8e04eSSam Leffler 		for (i = 36; i <= 64; i += 4)
9868e8e04eSSam Leffler 			addchan(ic, i, IEEE80211_CHAN_A);
9968e8e04eSSam Leffler 		for (i = 100; i <= 140; i += 4)
10068e8e04eSSam Leffler 			addchan(ic, i, IEEE80211_CHAN_A);
10168e8e04eSSam Leffler 		for (i = 149; i <= 161; i += 4)
10268e8e04eSSam Leffler 			addchan(ic, i, IEEE80211_CHAN_A);
10368e8e04eSSam Leffler 	}
10468e8e04eSSam Leffler 	ic->ic_regdomain = rd;
10568e8e04eSSam Leffler 	ic->ic_countrycode = cc;
10668e8e04eSSam Leffler 	ic->ic_location = outdoor;
10768e8e04eSSam Leffler }
10868e8e04eSSam Leffler 
10968e8e04eSSam Leffler /*
11068e8e04eSSam Leffler  * Add Country Information IE.
11168e8e04eSSam Leffler  */
11268e8e04eSSam Leffler uint8_t *
11368e8e04eSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic,
11468e8e04eSSam Leffler 	enum ISOCountryCode cc, int location)
11568e8e04eSSam Leffler {
11668e8e04eSSam Leffler #define	CHAN_UNINTERESTING \
11768e8e04eSSam Leffler     (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO | \
11868e8e04eSSam Leffler      IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)
11968e8e04eSSam Leffler 	/* XXX what about auto? */
12068e8e04eSSam Leffler 	/* flag set of channels to be excluded */
12168e8e04eSSam Leffler 	static const int skipflags[IEEE80211_MODE_MAX] = {
12268e8e04eSSam Leffler 	    CHAN_UNINTERESTING,				/* MODE_AUTO */
12368e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ,	/* MODE_11A */
12468e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ,	/* MODE_11B */
12568e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ,	/* MODE_11G */
12668e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_OFDM |	/* MODE_FH */
12768e8e04eSSam Leffler 	        IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN,
12868e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ,	/* MODE_TURBO_A */
12968e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ,	/* MODE_TURBO_G */
13068e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ,	/* MODE_STURBO_A */
13168e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ,	/* MODE_11NA */
13268e8e04eSSam Leffler 	    CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ,	/* MODE_11NG */
13368e8e04eSSam Leffler 	};
13468e8e04eSSam Leffler 	struct ieee80211_country_ie *ie = (struct ieee80211_country_ie *)frm;
13568e8e04eSSam Leffler 	const char *iso_name;
13668e8e04eSSam Leffler 	uint8_t nextchan, chans[IEEE80211_CHAN_BYTES];
13768e8e04eSSam Leffler 	int i, skip;
13868e8e04eSSam Leffler 
13968e8e04eSSam Leffler 	ie->ie = IEEE80211_ELEMID_COUNTRY;
14068e8e04eSSam Leffler 	iso_name = ieee80211_cctoiso(cc);
14168e8e04eSSam Leffler 	if (iso_name == NULL) {
14268e8e04eSSam Leffler 		if_printf(ic->ic_ifp, "bad country code %d ignored\n", cc);
14368e8e04eSSam Leffler 		iso_name = "  ";
14468e8e04eSSam Leffler 	}
14568e8e04eSSam Leffler 	ie->cc[0] = iso_name[0];
14668e8e04eSSam Leffler 	ie->cc[1] = iso_name[1];
14768e8e04eSSam Leffler 	/*
14868e8e04eSSam Leffler 	 * Indoor/Outdoor portion of country string.
14968e8e04eSSam Leffler 	 * NB: this is not quite right, since we should have one of:
15068e8e04eSSam Leffler 	 *     'I' indoor only
15168e8e04eSSam Leffler 	 *     'O' outdoor only
15268e8e04eSSam Leffler 	 *     ' ' all enviroments
15368e8e04eSSam Leffler 	 */
15468e8e04eSSam Leffler 	ie->cc[2] = ((location & 3) == 3 ? ' ' : location & 1 ? 'I' : 'O');
15568e8e04eSSam Leffler 
15668e8e04eSSam Leffler 	/*
15768e8e04eSSam Leffler 	 * Run-length encoded channel+max tx power info.
15868e8e04eSSam Leffler 	 */
15968e8e04eSSam Leffler 	frm = (uint8_t *)&ie->band[0];
16068e8e04eSSam Leffler 	nextchan = 0;			/* NB: impossible channel # */
16168e8e04eSSam Leffler 	memset(chans, 0, sizeof(chans));
16268e8e04eSSam Leffler 	skip = skipflags[ic->ic_curmode];
16368e8e04eSSam Leffler 	for (i = 0; i < ic->ic_nchans; i++) {
16468e8e04eSSam Leffler 		const struct ieee80211_channel *c = &ic->ic_channels[i];
16568e8e04eSSam Leffler 
16668e8e04eSSam Leffler 		if (isset(chans, c->ic_ieee))		/* suppress dup's */
16768e8e04eSSam Leffler 			continue;
1685ef9cd6cSSam Leffler 		if (c->ic_flags & skip)			/* skip band, etc. */
16968e8e04eSSam Leffler 			continue;
17068e8e04eSSam Leffler 		setbit(chans, c->ic_ieee);
17168e8e04eSSam Leffler 		if (c->ic_ieee != nextchan ||
17268e8e04eSSam Leffler 		    c->ic_maxregpower != frm[-1]) {	/* new run */
17368e8e04eSSam Leffler 			/* XXX max of 83 runs */
17468e8e04eSSam Leffler 			frm[0] = c->ic_ieee;		/* starting channel # */
17568e8e04eSSam Leffler 			frm[1] = 1;			/* # channels in run */
17668e8e04eSSam Leffler 			frm[2] = c->ic_maxregpower;	/* tx power cap */
17768e8e04eSSam Leffler 			frm += 3;
17868e8e04eSSam Leffler 			nextchan = c->ic_ieee + 1;	/* overflow? */
17968e8e04eSSam Leffler 		} else {				/* extend run */
18068e8e04eSSam Leffler 			frm[-2]++;
18168e8e04eSSam Leffler 			nextchan++;
18268e8e04eSSam Leffler 		}
18368e8e04eSSam Leffler 	}
18468e8e04eSSam Leffler 	ie->len = frm - ie->cc;
185f05ba5eeSSepherosa Ziehau 	if (ie->len & 1) {		/* Zero pad to multiple of 2 */
18668e8e04eSSam Leffler 		ie->len++;
187f05ba5eeSSepherosa Ziehau 		*frm++ = 0;
188f05ba5eeSSepherosa Ziehau 	}
18968e8e04eSSam Leffler 	return frm;
19068e8e04eSSam Leffler #undef CHAN_UNINTERESTING
19168e8e04eSSam Leffler }
19268e8e04eSSam Leffler 
19368e8e04eSSam Leffler /*
19468e8e04eSSam Leffler  * Country Code Table for code-to-string conversion.
19568e8e04eSSam Leffler  */
19668e8e04eSSam Leffler static const struct {
19768e8e04eSSam Leffler 	enum ISOCountryCode iso_code;
19868e8e04eSSam Leffler 	const char*	iso_name;
19968e8e04eSSam Leffler } country_strings[] = {
20068e8e04eSSam Leffler     { CTRY_DEBUG,	 	"DB" },		/* NB: nonstandard */
20168e8e04eSSam Leffler     { CTRY_DEFAULT,	 	"NA" },		/* NB: nonstandard */
20268e8e04eSSam Leffler     { CTRY_ALBANIA,		"AL" },
20368e8e04eSSam Leffler     { CTRY_ALGERIA,		"DZ" },
20468e8e04eSSam Leffler     { CTRY_ARGENTINA,		"AR" },
20568e8e04eSSam Leffler     { CTRY_ARMENIA,		"AM" },
20668e8e04eSSam Leffler     { CTRY_AUSTRALIA,		"AU" },
20768e8e04eSSam Leffler     { CTRY_AUSTRIA,		"AT" },
20868e8e04eSSam Leffler     { CTRY_AZERBAIJAN,		"AZ" },
20968e8e04eSSam Leffler     { CTRY_BAHRAIN,		"BH" },
21068e8e04eSSam Leffler     { CTRY_BELARUS,		"BY" },
21168e8e04eSSam Leffler     { CTRY_BELGIUM,		"BE" },
21268e8e04eSSam Leffler     { CTRY_BELIZE,		"BZ" },
21368e8e04eSSam Leffler     { CTRY_BOLIVIA,		"BO" },
21468e8e04eSSam Leffler     { CTRY_BRAZIL,		"BR" },
21568e8e04eSSam Leffler     { CTRY_BRUNEI_DARUSSALAM,	"BN" },
21668e8e04eSSam Leffler     { CTRY_BULGARIA,		"BG" },
21768e8e04eSSam Leffler     { CTRY_CANADA,		"CA" },
21868e8e04eSSam Leffler     { CTRY_CHILE,		"CL" },
21968e8e04eSSam Leffler     { CTRY_CHINA,		"CN" },
22068e8e04eSSam Leffler     { CTRY_COLOMBIA,		"CO" },
22168e8e04eSSam Leffler     { CTRY_COSTA_RICA,		"CR" },
22268e8e04eSSam Leffler     { CTRY_CROATIA,		"HR" },
22368e8e04eSSam Leffler     { CTRY_CYPRUS,		"CY" },
22468e8e04eSSam Leffler     { CTRY_CZECH,		"CZ" },
22568e8e04eSSam Leffler     { CTRY_DENMARK,		"DK" },
22668e8e04eSSam Leffler     { CTRY_DOMINICAN_REPUBLIC,	"DO" },
22768e8e04eSSam Leffler     { CTRY_ECUADOR,		"EC" },
22868e8e04eSSam Leffler     { CTRY_EGYPT,		"EG" },
22968e8e04eSSam Leffler     { CTRY_EL_SALVADOR,		"SV" },
23068e8e04eSSam Leffler     { CTRY_ESTONIA,		"EE" },
23168e8e04eSSam Leffler     { CTRY_FINLAND,		"FI" },
23268e8e04eSSam Leffler     { CTRY_FRANCE,		"FR" },
23368e8e04eSSam Leffler     { CTRY_FRANCE2,		"F2" },
23468e8e04eSSam Leffler     { CTRY_GEORGIA,		"GE" },
23568e8e04eSSam Leffler     { CTRY_GERMANY,		"DE" },
23668e8e04eSSam Leffler     { CTRY_GREECE,		"GR" },
23768e8e04eSSam Leffler     { CTRY_GUATEMALA,		"GT" },
23868e8e04eSSam Leffler     { CTRY_HONDURAS,		"HN" },
23968e8e04eSSam Leffler     { CTRY_HONG_KONG,		"HK" },
24068e8e04eSSam Leffler     { CTRY_HUNGARY,		"HU" },
24168e8e04eSSam Leffler     { CTRY_ICELAND,		"IS" },
24268e8e04eSSam Leffler     { CTRY_INDIA,		"IN" },
24368e8e04eSSam Leffler     { CTRY_INDONESIA,		"ID" },
24468e8e04eSSam Leffler     { CTRY_IRAN,		"IR" },
24568e8e04eSSam Leffler     { CTRY_IRELAND,		"IE" },
24668e8e04eSSam Leffler     { CTRY_ISRAEL,		"IL" },
24768e8e04eSSam Leffler     { CTRY_ITALY,		"IT" },
24868e8e04eSSam Leffler     { CTRY_JAMAICA,		"JM" },
24968e8e04eSSam Leffler     { CTRY_JAPAN,		"JP" },
25068e8e04eSSam Leffler     { CTRY_JAPAN1,		"J1" },
25168e8e04eSSam Leffler     { CTRY_JAPAN2,		"J2" },
25268e8e04eSSam Leffler     { CTRY_JAPAN3,		"J3" },
25368e8e04eSSam Leffler     { CTRY_JAPAN4,		"J4" },
25468e8e04eSSam Leffler     { CTRY_JAPAN5,		"J5" },
25568e8e04eSSam Leffler     { CTRY_JORDAN,		"JO" },
25668e8e04eSSam Leffler     { CTRY_KAZAKHSTAN,		"KZ" },
25768e8e04eSSam Leffler     { CTRY_KOREA_NORTH,		"KP" },
25868e8e04eSSam Leffler     { CTRY_KOREA_ROC,		"KR" },
25968e8e04eSSam Leffler     { CTRY_KOREA_ROC2,		"K2" },
26068e8e04eSSam Leffler     { CTRY_KUWAIT,		"KW" },
26168e8e04eSSam Leffler     { CTRY_LATVIA,		"LV" },
26268e8e04eSSam Leffler     { CTRY_LEBANON,		"LB" },
26368e8e04eSSam Leffler     { CTRY_LIECHTENSTEIN,	"LI" },
26468e8e04eSSam Leffler     { CTRY_LITHUANIA,		"LT" },
26568e8e04eSSam Leffler     { CTRY_LUXEMBOURG,		"LU" },
26668e8e04eSSam Leffler     { CTRY_MACAU,		"MO" },
26768e8e04eSSam Leffler     { CTRY_MACEDONIA,		"MK" },
26868e8e04eSSam Leffler     { CTRY_MALAYSIA,		"MY" },
26968e8e04eSSam Leffler     { CTRY_MEXICO,		"MX" },
27068e8e04eSSam Leffler     { CTRY_MONACO,		"MC" },
27168e8e04eSSam Leffler     { CTRY_MOROCCO,		"MA" },
27268e8e04eSSam Leffler     { CTRY_NETHERLANDS,		"NL" },
27368e8e04eSSam Leffler     { CTRY_NEW_ZEALAND,		"NZ" },
27468e8e04eSSam Leffler     { CTRY_NORWAY,		"NO" },
27568e8e04eSSam Leffler     { CTRY_OMAN,		"OM" },
27668e8e04eSSam Leffler     { CTRY_PAKISTAN,		"PK" },
27768e8e04eSSam Leffler     { CTRY_PANAMA,		"PA" },
27868e8e04eSSam Leffler     { CTRY_PERU,		"PE" },
27968e8e04eSSam Leffler     { CTRY_PHILIPPINES,		"PH" },
28068e8e04eSSam Leffler     { CTRY_POLAND,		"PL" },
28168e8e04eSSam Leffler     { CTRY_PORTUGAL,		"PT" },
28268e8e04eSSam Leffler     { CTRY_PUERTO_RICO,		"PR" },
28368e8e04eSSam Leffler     { CTRY_QATAR,		"QA" },
28468e8e04eSSam Leffler     { CTRY_ROMANIA,		"RO" },
28568e8e04eSSam Leffler     { CTRY_RUSSIA,		"RU" },
28668e8e04eSSam Leffler     { CTRY_SAUDI_ARABIA,	"SA" },
28768e8e04eSSam Leffler     { CTRY_SINGAPORE,		"SG" },
28868e8e04eSSam Leffler     { CTRY_SLOVAKIA,		"SK" },
28968e8e04eSSam Leffler     { CTRY_SLOVENIA,		"SI" },
29068e8e04eSSam Leffler     { CTRY_SOUTH_AFRICA,	"ZA" },
29168e8e04eSSam Leffler     { CTRY_SPAIN,		"ES" },
29268e8e04eSSam Leffler     { CTRY_SWEDEN,		"SE" },
29368e8e04eSSam Leffler     { CTRY_SWITZERLAND,		"CH" },
29468e8e04eSSam Leffler     { CTRY_SYRIA,		"SY" },
29568e8e04eSSam Leffler     { CTRY_TAIWAN,		"TW" },
29668e8e04eSSam Leffler     { CTRY_THAILAND,		"TH" },
29768e8e04eSSam Leffler     { CTRY_TRINIDAD_Y_TOBAGO,	"TT" },
29868e8e04eSSam Leffler     { CTRY_TUNISIA,		"TN" },
29968e8e04eSSam Leffler     { CTRY_TURKEY,		"TR" },
30068e8e04eSSam Leffler     { CTRY_UKRAINE,		"UA" },
30168e8e04eSSam Leffler     { CTRY_UAE,			"AE" },
30268e8e04eSSam Leffler     { CTRY_UNITED_KINGDOM,	"GB" },
30368e8e04eSSam Leffler     { CTRY_UNITED_STATES,	"US" },
30468e8e04eSSam Leffler     { CTRY_URUGUAY,		"UY" },
30568e8e04eSSam Leffler     { CTRY_UZBEKISTAN,		"UZ" },
30668e8e04eSSam Leffler     { CTRY_VENEZUELA,		"VE" },
30768e8e04eSSam Leffler     { CTRY_VIET_NAM,		"VN" },
30868e8e04eSSam Leffler     { CTRY_YEMEN,		"YE" },
30968e8e04eSSam Leffler     { CTRY_ZIMBABWE,		"ZW" }
31068e8e04eSSam Leffler };
31168e8e04eSSam Leffler 
31268e8e04eSSam Leffler const char *
31368e8e04eSSam Leffler ieee80211_cctoiso(enum ISOCountryCode cc)
31468e8e04eSSam Leffler {
31568e8e04eSSam Leffler #define	N(a)	(sizeof(a) / sizeof(a[0]))
31668e8e04eSSam Leffler 	int i;
31768e8e04eSSam Leffler 
31868e8e04eSSam Leffler 	for (i = 0; i < N(country_strings); i++) {
31968e8e04eSSam Leffler 		if (country_strings[i].iso_code == cc)
32068e8e04eSSam Leffler 			return country_strings[i].iso_name;
32168e8e04eSSam Leffler 	}
32268e8e04eSSam Leffler 	return NULL;
32368e8e04eSSam Leffler #undef N
32468e8e04eSSam Leffler }
32568e8e04eSSam Leffler 
32668e8e04eSSam Leffler int
32768e8e04eSSam Leffler ieee80211_isotocc(const char iso[2])
32868e8e04eSSam Leffler {
32968e8e04eSSam Leffler #define	N(a)	(sizeof(a) / sizeof(a[0]))
33068e8e04eSSam Leffler 	int i;
33168e8e04eSSam Leffler 
33268e8e04eSSam Leffler 	for (i = 0; i < N(country_strings); i++) {
33368e8e04eSSam Leffler 		if (country_strings[i].iso_name[0] == iso[0] &&
33468e8e04eSSam Leffler 		    country_strings[i].iso_name[1] == iso[1])
33568e8e04eSSam Leffler 			return country_strings[i].iso_code;
33668e8e04eSSam Leffler 	}
33768e8e04eSSam Leffler 	return -1;
33868e8e04eSSam Leffler #undef N
33968e8e04eSSam Leffler }
340