diff options
Diffstat (limited to 'net/mac80211/regdomain.c')
-rw-r--r-- | net/mac80211/regdomain.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c new file mode 100644 index 000000000000..b697a2afbb4b --- /dev/null +++ b/net/mac80211/regdomain.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | ||
3 | * Copyright 2005-2006, Devicescape Software, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This regulatory domain control implementation is known to be incomplete | ||
12 | * and confusing. mac80211 regulatory domain control will be significantly | ||
13 | * reworked in the not-too-distant future. | ||
14 | * | ||
15 | * For now, drivers wishing to control which channels are and aren't available | ||
16 | * are advised as follows: | ||
17 | * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag | ||
18 | * - continue to include *ALL* possible channels in the modes registered | ||
19 | * through ieee80211_register_hwmode() | ||
20 | * - for each allowable ieee80211_channel structure registered in the above | ||
21 | * call, set the flag member to some meaningful value such as | ||
22 | * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | | ||
23 | * IEEE80211_CHAN_W_IBSS. | ||
24 | * - leave flag as 0 for non-allowable channels | ||
25 | * | ||
26 | * The usual implementation is for a driver to read a device EEPROM to | ||
27 | * determine which regulatory domain it should be operating under, then | ||
28 | * looking up the allowable channels in a driver-local table, then performing | ||
29 | * the above. | ||
30 | */ | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/netdevice.h> | ||
34 | #include <net/mac80211.h> | ||
35 | #include "ieee80211_i.h" | ||
36 | |||
37 | static int ieee80211_regdom = 0x10; /* FCC */ | ||
38 | module_param(ieee80211_regdom, int, 0444); | ||
39 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK"); | ||
40 | |||
41 | /* | ||
42 | * If firmware is upgraded by the vendor, additional channels can be used based | ||
43 | * on the new Japanese regulatory rules. This is indicated by setting | ||
44 | * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel | ||
45 | * module. | ||
46 | */ | ||
47 | static int ieee80211_japan_5ghz /* = 0 */; | ||
48 | module_param(ieee80211_japan_5ghz, int, 0444); | ||
49 | MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz"); | ||
50 | |||
51 | |||
52 | struct ieee80211_channel_range { | ||
53 | short start_freq; | ||
54 | short end_freq; | ||
55 | unsigned char power_level; | ||
56 | unsigned char antenna_max; | ||
57 | }; | ||
58 | |||
59 | static const struct ieee80211_channel_range ieee80211_fcc_channels[] = { | ||
60 | { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */, | ||
61 | { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */, | ||
62 | { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */, | ||
63 | { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */, | ||
64 | { 0 } | ||
65 | }; | ||
66 | |||
67 | static const struct ieee80211_channel_range ieee80211_mkk_channels[] = { | ||
68 | { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */, | ||
69 | { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */, | ||
70 | { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */, | ||
71 | { 0 } | ||
72 | }; | ||
73 | |||
74 | |||
75 | static const struct ieee80211_channel_range *channel_range = | ||
76 | ieee80211_fcc_channels; | ||
77 | |||
78 | |||
79 | static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | chan->flag = 0; | ||
84 | |||
85 | if (ieee80211_regdom == 64 && | ||
86 | (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) { | ||
87 | /* Do not allow Turbo modes in Japan. */ | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | for (i = 0; channel_range[i].start_freq; i++) { | ||
92 | const struct ieee80211_channel_range *r = &channel_range[i]; | ||
93 | if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { | ||
94 | if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz && | ||
95 | chan->freq >= 5260 && chan->freq <= 5320) { | ||
96 | /* | ||
97 | * Skip new channels in Japan since the | ||
98 | * firmware was not marked having been upgraded | ||
99 | * by the vendor. | ||
100 | */ | ||
101 | continue; | ||
102 | } | ||
103 | |||
104 | if (ieee80211_regdom == 0x10 && | ||
105 | (chan->freq == 5190 || chan->freq == 5210 || | ||
106 | chan->freq == 5230)) { | ||
107 | /* Skip MKK channels when in FCC domain. */ | ||
108 | continue; | ||
109 | } | ||
110 | |||
111 | chan->flag |= IEEE80211_CHAN_W_SCAN | | ||
112 | IEEE80211_CHAN_W_ACTIVE_SCAN | | ||
113 | IEEE80211_CHAN_W_IBSS; | ||
114 | chan->power_level = r->power_level; | ||
115 | chan->antenna_max = r->antenna_max; | ||
116 | |||
117 | if (ieee80211_regdom == 64 && | ||
118 | (chan->freq == 5170 || chan->freq == 5190 || | ||
119 | chan->freq == 5210 || chan->freq == 5230)) { | ||
120 | /* | ||
121 | * New regulatory rules in Japan have backwards | ||
122 | * compatibility with old channels in 5.15-5.25 | ||
123 | * GHz band, but the station is not allowed to | ||
124 | * use active scan on these old channels. | ||
125 | */ | ||
126 | chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN; | ||
127 | } | ||
128 | |||
129 | if (ieee80211_regdom == 64 && | ||
130 | (chan->freq == 5260 || chan->freq == 5280 || | ||
131 | chan->freq == 5300 || chan->freq == 5320)) { | ||
132 | /* | ||
133 | * IBSS is not allowed on 5.25-5.35 GHz band | ||
134 | * due to radar detection requirements. | ||
135 | */ | ||
136 | chan->flag &= ~IEEE80211_CHAN_W_IBSS; | ||
137 | } | ||
138 | |||
139 | break; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode) | ||
146 | { | ||
147 | int c; | ||
148 | for (c = 0; c < mode->num_channels; c++) | ||
149 | ieee80211_unmask_channel(mode->mode, &mode->channels[c]); | ||
150 | } | ||
151 | |||
152 | |||
153 | void ieee80211_regdomain_init(void) | ||
154 | { | ||
155 | if (ieee80211_regdom == 0x40) | ||
156 | channel_range = ieee80211_mkk_channels; | ||
157 | } | ||
158 | |||