2 * Copyright (c) 2005-2007 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 * IEEE 802.11 regdomain support.
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
37 #include <sys/socket.h>
40 #include <net/if_arp.h>
41 #include <net/if_dl.h>
42 #include <net/if_media.h>
43 #include <net/if_types.h>
44 #include <net/ethernet.h>
46 #include <net80211/ieee80211_var.h>
47 #include <net80211/ieee80211_regdomain.h>
50 ieee80211_regdomain_attach(struct ieee80211com *ic)
52 ic->ic_regdomain = 0; /* XXX */
53 ic->ic_countrycode = CTRY_UNITED_STATES;/* XXX */
54 ic->ic_location = 1+2; /* both */
58 ieee80211_regdomain_detach(struct ieee80211com *ic)
63 addchan(struct ieee80211com *ic, int ieee, int flags)
65 struct ieee80211_channel *c;
67 c = &ic->ic_channels[ic->ic_nchans++];
68 c->ic_freq = ieee80211_ieee2mhz(ieee, flags);
74 * Setup the channel list for the specified regulatory domain,
75 * country code, and operating modes. This interface is used
76 * when a driver does not obtain the channel list from another
77 * source (such as firmware).
80 ieee80211_init_channels(struct ieee80211com *ic,
81 int rd, enum ISOCountryCode cc, int bands, int outdoor, int ecm)
85 /* XXX just do something for now */
87 if (isset(&bands, IEEE80211_MODE_11B) ||
88 isset(&bands, IEEE80211_MODE_11G)) {
89 for (i = 1; i <= (ecm ? 14 : 11); i++) {
90 if (isset(&bands, IEEE80211_MODE_11B))
91 addchan(ic, i, IEEE80211_CHAN_B);
92 if (isset(&bands, IEEE80211_MODE_11G))
93 addchan(ic, i, IEEE80211_CHAN_G);
96 if (isset(&bands, IEEE80211_MODE_11A)) {
97 for (i = 36; i <= 64; i += 4)
98 addchan(ic, i, IEEE80211_CHAN_A);
99 for (i = 100; i <= 140; i += 4)
100 addchan(ic, i, IEEE80211_CHAN_A);
101 for (i = 149; i <= 161; i += 4)
102 addchan(ic, i, IEEE80211_CHAN_A);
104 ic->ic_regdomain = rd;
105 ic->ic_countrycode = cc;
106 ic->ic_location = outdoor;
110 * Add Country Information IE.
113 ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic,
114 enum ISOCountryCode cc, int location)
116 #define CHAN_UNINTERESTING \
117 (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO | \
118 IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)
119 /* XXX what about auto? */
120 /* flag set of channels to be excluded */
121 static const int skipflags[IEEE80211_MODE_MAX] = {
122 CHAN_UNINTERESTING, /* MODE_AUTO */
123 CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_11A */
124 CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11B */
125 CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11G */
126 CHAN_UNINTERESTING | IEEE80211_CHAN_OFDM | /* MODE_FH */
127 IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN,
128 CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_TURBO_A */
129 CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_TURBO_G */
130 CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_STURBO_A */
131 CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_11NA */
132 CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11NG */
134 struct ieee80211_country_ie *ie = (struct ieee80211_country_ie *)frm;
135 const char *iso_name;
136 uint8_t nextchan, chans[IEEE80211_CHAN_BYTES];
139 ie->ie = IEEE80211_ELEMID_COUNTRY;
140 iso_name = ieee80211_cctoiso(cc);
141 if (iso_name == NULL) {
142 if_printf(ic->ic_ifp, "bad country code %d ignored\n", cc);
145 ie->cc[0] = iso_name[0];
146 ie->cc[1] = iso_name[1];
148 * Indoor/Outdoor portion of country string.
149 * NB: this is not quite right, since we should have one of:
152 * ' ' all enviroments
154 ie->cc[2] = ((location & 3) == 3 ? ' ' : location & 1 ? 'I' : 'O');
157 * Run-length encoded channel+max tx power info.
159 frm = (uint8_t *)&ie->band[0];
160 nextchan = 0; /* NB: impossible channel # */
161 memset(chans, 0, sizeof(chans));
162 skip = skipflags[ic->ic_curmode];
163 for (i = 0; i < ic->ic_nchans; i++) {
164 const struct ieee80211_channel *c = &ic->ic_channels[i];
166 if (isset(chans, c->ic_ieee)) /* suppress dup's */
168 if (c->ic_flags & skip) /* skip band, etc. */
170 setbit(chans, c->ic_ieee);
171 if (c->ic_ieee != nextchan ||
172 c->ic_maxregpower != frm[-1]) { /* new run */
173 /* XXX max of 83 runs */
174 frm[0] = c->ic_ieee; /* starting channel # */
175 frm[1] = 1; /* # channels in run */
176 frm[2] = c->ic_maxregpower; /* tx power cap */
178 nextchan = c->ic_ieee + 1; /* overflow? */
179 } else { /* extend run */
184 ie->len = frm - ie->cc;
185 if (ie->len & 1) { /* Zero pad to multiple of 2 */
190 #undef CHAN_UNINTERESTING
194 * Country Code Table for code-to-string conversion.
196 static const struct {
197 enum ISOCountryCode iso_code;
198 const char* iso_name;
199 } country_strings[] = {
200 { CTRY_DEBUG, "DB" }, /* NB: nonstandard */
201 { CTRY_DEFAULT, "NA" }, /* NB: nonstandard */
202 { CTRY_ALBANIA, "AL" },
203 { CTRY_ALGERIA, "DZ" },
204 { CTRY_ARGENTINA, "AR" },
205 { CTRY_ARMENIA, "AM" },
206 { CTRY_AUSTRALIA, "AU" },
207 { CTRY_AUSTRIA, "AT" },
208 { CTRY_AZERBAIJAN, "AZ" },
209 { CTRY_BAHRAIN, "BH" },
210 { CTRY_BELARUS, "BY" },
211 { CTRY_BELGIUM, "BE" },
212 { CTRY_BELIZE, "BZ" },
213 { CTRY_BOLIVIA, "BO" },
214 { CTRY_BRAZIL, "BR" },
215 { CTRY_BRUNEI_DARUSSALAM, "BN" },
216 { CTRY_BULGARIA, "BG" },
217 { CTRY_CANADA, "CA" },
218 { CTRY_CHILE, "CL" },
219 { CTRY_CHINA, "CN" },
220 { CTRY_COLOMBIA, "CO" },
221 { CTRY_COSTA_RICA, "CR" },
222 { CTRY_CROATIA, "HR" },
223 { CTRY_CYPRUS, "CY" },
224 { CTRY_CZECH, "CZ" },
225 { CTRY_DENMARK, "DK" },
226 { CTRY_DOMINICAN_REPUBLIC, "DO" },
227 { CTRY_ECUADOR, "EC" },
228 { CTRY_EGYPT, "EG" },
229 { CTRY_EL_SALVADOR, "SV" },
230 { CTRY_ESTONIA, "EE" },
231 { CTRY_FINLAND, "FI" },
232 { CTRY_FRANCE, "FR" },
233 { CTRY_FRANCE2, "F2" },
234 { CTRY_GEORGIA, "GE" },
235 { CTRY_GERMANY, "DE" },
236 { CTRY_GREECE, "GR" },
237 { CTRY_GUATEMALA, "GT" },
238 { CTRY_HONDURAS, "HN" },
239 { CTRY_HONG_KONG, "HK" },
240 { CTRY_HUNGARY, "HU" },
241 { CTRY_ICELAND, "IS" },
242 { CTRY_INDIA, "IN" },
243 { CTRY_INDONESIA, "ID" },
245 { CTRY_IRELAND, "IE" },
246 { CTRY_ISRAEL, "IL" },
247 { CTRY_ITALY, "IT" },
248 { CTRY_JAMAICA, "JM" },
249 { CTRY_JAPAN, "JP" },
250 { CTRY_JAPAN1, "J1" },
251 { CTRY_JAPAN2, "J2" },
252 { CTRY_JAPAN3, "J3" },
253 { CTRY_JAPAN4, "J4" },
254 { CTRY_JAPAN5, "J5" },
255 { CTRY_JORDAN, "JO" },
256 { CTRY_KAZAKHSTAN, "KZ" },
257 { CTRY_KOREA_NORTH, "KP" },
258 { CTRY_KOREA_ROC, "KR" },
259 { CTRY_KOREA_ROC2, "K2" },
260 { CTRY_KUWAIT, "KW" },
261 { CTRY_LATVIA, "LV" },
262 { CTRY_LEBANON, "LB" },
263 { CTRY_LIECHTENSTEIN, "LI" },
264 { CTRY_LITHUANIA, "LT" },
265 { CTRY_LUXEMBOURG, "LU" },
266 { CTRY_MACAU, "MO" },
267 { CTRY_MACEDONIA, "MK" },
268 { CTRY_MALAYSIA, "MY" },
269 { CTRY_MEXICO, "MX" },
270 { CTRY_MONACO, "MC" },
271 { CTRY_MOROCCO, "MA" },
272 { CTRY_NETHERLANDS, "NL" },
273 { CTRY_NEW_ZEALAND, "NZ" },
274 { CTRY_NORWAY, "NO" },
276 { CTRY_PAKISTAN, "PK" },
277 { CTRY_PANAMA, "PA" },
279 { CTRY_PHILIPPINES, "PH" },
280 { CTRY_POLAND, "PL" },
281 { CTRY_PORTUGAL, "PT" },
282 { CTRY_PUERTO_RICO, "PR" },
283 { CTRY_QATAR, "QA" },
284 { CTRY_ROMANIA, "RO" },
285 { CTRY_RUSSIA, "RU" },
286 { CTRY_SAUDI_ARABIA, "SA" },
287 { CTRY_SINGAPORE, "SG" },
288 { CTRY_SLOVAKIA, "SK" },
289 { CTRY_SLOVENIA, "SI" },
290 { CTRY_SOUTH_AFRICA, "ZA" },
291 { CTRY_SPAIN, "ES" },
292 { CTRY_SWEDEN, "SE" },
293 { CTRY_SWITZERLAND, "CH" },
294 { CTRY_SYRIA, "SY" },
295 { CTRY_TAIWAN, "TW" },
296 { CTRY_THAILAND, "TH" },
297 { CTRY_TRINIDAD_Y_TOBAGO, "TT" },
298 { CTRY_TUNISIA, "TN" },
299 { CTRY_TURKEY, "TR" },
300 { CTRY_UKRAINE, "UA" },
302 { CTRY_UNITED_KINGDOM, "GB" },
303 { CTRY_UNITED_STATES, "US" },
304 { CTRY_URUGUAY, "UY" },
305 { CTRY_UZBEKISTAN, "UZ" },
306 { CTRY_VENEZUELA, "VE" },
307 { CTRY_VIET_NAM, "VN" },
308 { CTRY_YEMEN, "YE" },
309 { CTRY_ZIMBABWE, "ZW" }
313 ieee80211_cctoiso(enum ISOCountryCode cc)
315 #define N(a) (sizeof(a) / sizeof(a[0]))
318 for (i = 0; i < N(country_strings); i++) {
319 if (country_strings[i].iso_code == cc)
320 return country_strings[i].iso_name;
327 ieee80211_isotocc(const char iso[2])
329 #define N(a) (sizeof(a) / sizeof(a[0]))
332 for (i = 0; i < N(country_strings); i++) {
333 if (country_strings[i].iso_name[0] == iso[0] &&
334 country_strings[i].iso_name[1] == iso[1])
335 return country_strings[i].iso_code;