ieee80211_regdomain.c revision 170530
10SN/A/*- 2477SN/A * Copyright (c) 2005-2007 Sam Leffler, Errno Consulting 30SN/A * All rights reserved. 40SN/A * 50SN/A * Redistribution and use in source and binary forms, with or without 60SN/A * modification, are permitted provided that the following conditions 7157SN/A * are met: 80SN/A * 1. Redistributions of source code must retain the above copyright 9157SN/A * notice, this list of conditions and the following disclaimer. 100SN/A * 2. Redistributions in binary form must reproduce the above copyright 110SN/A * notice, this list of conditions and the following disclaimer in the 120SN/A * documentation and/or other materials provided with the distribution. 130SN/A * 140SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 150SN/A * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 160SN/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 170SN/A * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 180SN/A * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 190SN/A * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 200SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21157SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22157SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23157SN/A * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 240SN/A */ 250SN/A 260SN/A#include <sys/cdefs.h> 270SN/A__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_regdomain.c 170530 2007-06-11 03:36:55Z sam $"); 280SN/A 290SN/A/* 300SN/A * IEEE 802.11 regdomain support. 310SN/A */ 320SN/A 330SN/A#include <sys/param.h> 340SN/A#include <sys/systm.h> 350SN/A#include <sys/kernel.h> 360SN/A 370SN/A#include <sys/socket.h> 380SN/A 390SN/A#include <net/if.h> 400SN/A#include <net/if_arp.h> 410SN/A#include <net/if_dl.h> 420SN/A#include <net/if_media.h> 430SN/A#include <net/if_types.h> 440SN/A#include <net/ethernet.h> 450SN/A 460SN/A#include <net80211/ieee80211_var.h> 470SN/A#include <net80211/ieee80211_regdomain.h> 480SN/A 490SN/Avoid 500SN/Aieee80211_regdomain_attach(struct ieee80211com *ic) 510SN/A{ 520SN/A ic->ic_regdomain = 0; /* XXX */ 530SN/A ic->ic_countrycode = CTRY_UNITED_STATES;/* XXX */ 540SN/A ic->ic_location = 1+2; /* both */ 550SN/A} 560SN/A 570SN/Avoid 580SN/Aieee80211_regdomain_detach(struct ieee80211com *ic) 590SN/A{ 600SN/A} 610SN/A 620SN/Astatic void 630SN/Aaddchan(struct ieee80211com *ic, int ieee, int flags) 640SN/A{ 650SN/A struct ieee80211_channel *c; 660SN/A 670SN/A c = &ic->ic_channels[ic->ic_nchans++]; 680SN/A c->ic_freq = ieee80211_ieee2mhz(ieee, flags); 690SN/A c->ic_ieee = ieee; 700SN/A c->ic_flags = flags; 710SN/A} 720SN/A 730SN/A/* 740SN/A * Setup the channel list for the specified regulatory domain, 750SN/A * country code, and operating modes. This interface is used 760SN/A * when a driver does not obtain the channel list from another 770SN/A * source (such as firmware). 780SN/A */ 790SN/Avoid 800SN/Aieee80211_init_channels(struct ieee80211com *ic, 810SN/A int rd, enum ISOCountryCode cc, int bands, int outdoor, int ecm) 820SN/A{ 830SN/A int i; 840SN/A 850SN/A /* XXX just do something for now */ 860SN/A ic->ic_nchans = 0; 870SN/A if (isset(&bands, IEEE80211_MODE_11B) || 880SN/A isset(&bands, IEEE80211_MODE_11G)) { 890SN/A for (i = 1; i <= (ecm ? 14 : 11); i++) { 900SN/A if (isset(&bands, IEEE80211_MODE_11B)) 910SN/A addchan(ic, i, IEEE80211_CHAN_B); 920SN/A if (isset(&bands, IEEE80211_MODE_11G)) 930SN/A addchan(ic, i, IEEE80211_CHAN_G); 940SN/A } 950SN/A } 960SN/A if (isset(&bands, IEEE80211_MODE_11A)) { 970SN/A for (i = 36; i <= 64; i += 4) 980SN/A addchan(ic, i, IEEE80211_CHAN_A); 990SN/A for (i = 100; i <= 140; i += 4) 1000SN/A addchan(ic, i, IEEE80211_CHAN_A); 1010SN/A for (i = 149; i <= 161; i += 4) 1020SN/A addchan(ic, i, IEEE80211_CHAN_A); 1030SN/A } 1040SN/A ic->ic_regdomain = rd; 1050SN/A ic->ic_countrycode = cc; 1060SN/A ic->ic_location = outdoor; 1070SN/A} 1080SN/A 1090SN/A/* 1100SN/A * Add Country Information IE. 1110SN/A */ 1120SN/Auint8_t * 1130SN/Aieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic, 1140SN/A enum ISOCountryCode cc, int location) 1150SN/A{ 1160SN/A#define CHAN_UNINTERESTING \ 1170SN/A (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO | \ 1180SN/A IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER) 1190SN/A /* XXX what about auto? */ 1200SN/A /* flag set of channels to be excluded */ 1210SN/A static const int skipflags[IEEE80211_MODE_MAX] = { 1220SN/A CHAN_UNINTERESTING, /* MODE_AUTO */ 1230SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_11A */ 1240SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11B */ 1250SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11G */ 1260SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_OFDM | /* MODE_FH */ 1270SN/A IEEE80211_CHAN_CCK | IEEE80211_CHAN_DYN, 1280SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_TURBO_A */ 1290SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_TURBO_G */ 1300SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_STURBO_A */ 1310SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_2GHZ, /* MODE_11NA */ 1320SN/A CHAN_UNINTERESTING | IEEE80211_CHAN_5GHZ, /* MODE_11NG */ 1330SN/A }; 1340SN/A struct ieee80211_country_ie *ie = (struct ieee80211_country_ie *)frm; 1350SN/A const char *iso_name; 1360SN/A uint8_t nextchan, chans[IEEE80211_CHAN_BYTES]; 1370SN/A int i, skip; 1380SN/A 1390SN/A ie->ie = IEEE80211_ELEMID_COUNTRY; 1400SN/A iso_name = ieee80211_cctoiso(cc); 1410SN/A if (iso_name == NULL) { 1420SN/A if_printf(ic->ic_ifp, "bad country code %d ignored\n", cc); 1430SN/A iso_name = " "; 1440SN/A } 1450SN/A ie->cc[0] = iso_name[0]; 1460SN/A ie->cc[1] = iso_name[1]; 1470SN/A /* 1480SN/A * Indoor/Outdoor portion of country string. 1490SN/A * NB: this is not quite right, since we should have one of: 1500SN/A * 'I' indoor only 1510SN/A * 'O' outdoor only 1520SN/A * ' ' all enviroments 1530SN/A */ 1540SN/A ie->cc[2] = ((location & 3) == 3 ? ' ' : location & 1 ? 'I' : 'O'); 1550SN/A 1560SN/A /* 1570SN/A * Run-length encoded channel+max tx power info. 1580SN/A */ 1590SN/A frm = (uint8_t *)&ie->band[0]; 1600SN/A nextchan = 0; /* NB: impossible channel # */ 1610SN/A memset(chans, 0, sizeof(chans)); 1620SN/A skip = skipflags[ic->ic_curmode]; 1630SN/A for (i = 0; i < ic->ic_nchans; i++) { 1640SN/A const struct ieee80211_channel *c = &ic->ic_channels[i]; 1650SN/A 1660SN/A if (isset(chans, c->ic_ieee)) /* suppress dup's */ 1670SN/A continue; 1680SN/A if ((c->ic_flags & skip) == 0) /* skip band, etc. */ 1690SN/A continue; 1700SN/A setbit(chans, c->ic_ieee); 1710SN/A if (c->ic_ieee != nextchan || 1720SN/A c->ic_maxregpower != frm[-1]) { /* new run */ 1730SN/A /* XXX max of 83 runs */ 1740SN/A frm[0] = c->ic_ieee; /* starting channel # */ 1750SN/A frm[1] = 1; /* # channels in run */ 1760SN/A frm[2] = c->ic_maxregpower; /* tx power cap */ 1770SN/A frm += 3; 1780SN/A nextchan = c->ic_ieee + 1; /* overflow? */ 1790SN/A } else { /* extend run */ 1800SN/A frm[-2]++; 1810SN/A nextchan++; 1820SN/A } 1830SN/A } 1840SN/A ie->len = frm - ie->cc; 1850SN/A if (ie->len & 1) /* pad to multiple of 2 */ 1860SN/A ie->len++; 1870SN/A return frm; 1880SN/A#undef CHAN_UNINTERESTING 1890SN/A} 1900SN/A 1910SN/A/* 1920SN/A * Country Code Table for code-to-string conversion. 1930SN/A */ 1940SN/Astatic const struct { 1950SN/A enum ISOCountryCode iso_code; 1960SN/A const char* iso_name; 1970SN/A} country_strings[] = { 1980SN/A { CTRY_DEBUG, "DB" }, /* NB: nonstandard */ 1990SN/A { CTRY_DEFAULT, "NA" }, /* NB: nonstandard */ 2000SN/A { CTRY_ALBANIA, "AL" }, 2010SN/A { CTRY_ALGERIA, "DZ" }, 2020SN/A { CTRY_ARGENTINA, "AR" }, 2030SN/A { CTRY_ARMENIA, "AM" }, 2040SN/A { CTRY_AUSTRALIA, "AU" }, 2050SN/A { CTRY_AUSTRIA, "AT" }, 2060SN/A { CTRY_AZERBAIJAN, "AZ" }, 2070SN/A { CTRY_BAHRAIN, "BH" }, 2080SN/A { CTRY_BELARUS, "BY" }, 2090SN/A { CTRY_BELGIUM, "BE" }, 2100SN/A { CTRY_BELIZE, "BZ" }, 2110SN/A { CTRY_BOLIVIA, "BO" }, 2120SN/A { CTRY_BRAZIL, "BR" }, 2130SN/A { CTRY_BRUNEI_DARUSSALAM, "BN" }, 2140SN/A { CTRY_BULGARIA, "BG" }, 2150SN/A { CTRY_CANADA, "CA" }, 2160SN/A { CTRY_CHILE, "CL" }, 2170SN/A { CTRY_CHINA, "CN" }, 2180SN/A { CTRY_COLOMBIA, "CO" }, 2190SN/A { CTRY_COSTA_RICA, "CR" }, 2200SN/A { CTRY_CROATIA, "HR" }, 2210SN/A { CTRY_CYPRUS, "CY" }, 2220SN/A { CTRY_CZECH, "CZ" }, 2230SN/A { CTRY_DENMARK, "DK" }, 2240SN/A { CTRY_DOMINICAN_REPUBLIC, "DO" }, 2250SN/A { CTRY_ECUADOR, "EC" }, 2260SN/A { CTRY_EGYPT, "EG" }, 2270SN/A { CTRY_EL_SALVADOR, "SV" }, 2280SN/A { CTRY_ESTONIA, "EE" }, 2290SN/A { CTRY_FINLAND, "FI" }, 2300SN/A { CTRY_FRANCE, "FR" }, 2310SN/A { CTRY_FRANCE2, "F2" }, 2320SN/A { CTRY_GEORGIA, "GE" }, 2330SN/A { CTRY_GERMANY, "DE" }, 2340SN/A { CTRY_GREECE, "GR" }, 2350SN/A { CTRY_GUATEMALA, "GT" }, 2360SN/A { CTRY_HONDURAS, "HN" }, 2370SN/A { CTRY_HONG_KONG, "HK" }, 2380SN/A { CTRY_HUNGARY, "HU" }, 2390SN/A { CTRY_ICELAND, "IS" }, 2400SN/A { CTRY_INDIA, "IN" }, 2410SN/A { CTRY_INDONESIA, "ID" }, 2420SN/A { CTRY_IRAN, "IR" }, 2430SN/A { CTRY_IRELAND, "IE" }, 2440SN/A { CTRY_ISRAEL, "IL" }, 2450SN/A { CTRY_ITALY, "IT" }, 2460SN/A { CTRY_JAMAICA, "JM" }, 2470SN/A { CTRY_JAPAN, "JP" }, 2480SN/A { CTRY_JAPAN1, "J1" }, 2490SN/A { CTRY_JAPAN2, "J2" }, 2500SN/A { CTRY_JAPAN3, "J3" }, 2510SN/A { CTRY_JAPAN4, "J4" }, 2520SN/A { CTRY_JAPAN5, "J5" }, 2530SN/A { CTRY_JORDAN, "JO" }, 2540SN/A { CTRY_KAZAKHSTAN, "KZ" }, 2550SN/A { CTRY_KOREA_NORTH, "KP" }, 2560SN/A { CTRY_KOREA_ROC, "KR" }, 2570SN/A { CTRY_KOREA_ROC2, "K2" }, 2580SN/A { CTRY_KUWAIT, "KW" }, 2590SN/A { CTRY_LATVIA, "LV" }, 2600SN/A { CTRY_LEBANON, "LB" }, 2610SN/A { CTRY_LIECHTENSTEIN, "LI" }, 2620SN/A { CTRY_LITHUANIA, "LT" }, 2630SN/A { CTRY_LUXEMBOURG, "LU" }, 2640SN/A { CTRY_MACAU, "MO" }, 2650SN/A { CTRY_MACEDONIA, "MK" }, 2660SN/A { CTRY_MALAYSIA, "MY" }, 2670SN/A { CTRY_MEXICO, "MX" }, 2680SN/A { CTRY_MONACO, "MC" }, 2690SN/A { CTRY_MOROCCO, "MA" }, 2700SN/A { CTRY_NETHERLANDS, "NL" }, 2710SN/A { CTRY_NEW_ZEALAND, "NZ" }, 2720SN/A { CTRY_NORWAY, "NO" }, 2730SN/A { CTRY_OMAN, "OM" }, 2740SN/A { CTRY_PAKISTAN, "PK" }, 2750SN/A { CTRY_PANAMA, "PA" }, 2760SN/A { CTRY_PERU, "PE" }, 2770SN/A { CTRY_PHILIPPINES, "PH" }, 2780SN/A { CTRY_POLAND, "PL" }, 2790SN/A { CTRY_PORTUGAL, "PT" }, 2800SN/A { CTRY_PUERTO_RICO, "PR" }, 2810SN/A { CTRY_QATAR, "QA" }, 2820SN/A { CTRY_ROMANIA, "RO" }, 2830SN/A { CTRY_RUSSIA, "RU" }, 2840SN/A { CTRY_SAUDI_ARABIA, "SA" }, 2850SN/A { CTRY_SINGAPORE, "SG" }, 2860SN/A { CTRY_SLOVAKIA, "SK" }, 2870SN/A { CTRY_SLOVENIA, "SI" }, 2880SN/A { CTRY_SOUTH_AFRICA, "ZA" }, 2890SN/A { CTRY_SPAIN, "ES" }, 2900SN/A { CTRY_SWEDEN, "SE" }, 2910SN/A { CTRY_SWITZERLAND, "CH" }, 2920SN/A { CTRY_SYRIA, "SY" }, 2930SN/A { CTRY_TAIWAN, "TW" }, 2940SN/A { CTRY_THAILAND, "TH" }, 2950SN/A { CTRY_TRINIDAD_Y_TOBAGO, "TT" }, 2960SN/A { CTRY_TUNISIA, "TN" }, 2970SN/A { CTRY_TURKEY, "TR" }, 2980SN/A { CTRY_UKRAINE, "UA" }, 2990SN/A { CTRY_UAE, "AE" }, 3000SN/A { CTRY_UNITED_KINGDOM, "GB" }, 3010SN/A { CTRY_UNITED_STATES, "US" }, 3020SN/A { CTRY_URUGUAY, "UY" }, 3030SN/A { CTRY_UZBEKISTAN, "UZ" }, 3040SN/A { CTRY_VENEZUELA, "VE" }, 3050SN/A { CTRY_VIET_NAM, "VN" }, 3060SN/A { CTRY_YEMEN, "YE" }, 3070SN/A { CTRY_ZIMBABWE, "ZW" } 3080SN/A}; 3090SN/A 3100SN/Aconst char * 3110SN/Aieee80211_cctoiso(enum ISOCountryCode cc) 3120SN/A{ 3130SN/A#define N(a) (sizeof(a) / sizeof(a[0])) 3140SN/A int i; 3150SN/A 3160SN/A for (i = 0; i < N(country_strings); i++) { 3170SN/A if (country_strings[i].iso_code == cc) 3180SN/A return country_strings[i].iso_name; 3190SN/A } 3200SN/A return NULL; 3210SN/A#undef N 3220SN/A} 3230SN/A 3240SN/Aint 3250SN/Aieee80211_isotocc(const char iso[2]) 3260SN/A{ 3270SN/A#define N(a) (sizeof(a) / sizeof(a[0])) 3280SN/A int i; 3290SN/A 3300SN/A for (i = 0; i < N(country_strings); i++) { 3310SN/A if (country_strings[i].iso_name[0] == iso[0] && 3320SN/A country_strings[i].iso_name[1] == iso[1]) 3330SN/A return country_strings[i].iso_code; 3340SN/A } 3350SN/A return -1; 3360SN/A#undef N 3370SN/A} 3380SN/A