diff options
Diffstat (limited to 'drivers/net/wireless/libertas/scan.c')
-rw-r--r-- | drivers/net/wireless/libertas/scan.c | 250 |
1 files changed, 200 insertions, 50 deletions
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 6c95af3023cc..c6a6c042b82f 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c | |||
@@ -12,18 +12,19 @@ | |||
12 | #include <net/lib80211.h> | 12 | #include <net/lib80211.h> |
13 | 13 | ||
14 | #include "host.h" | 14 | #include "host.h" |
15 | #include "decl.h" | ||
16 | #include "dev.h" | 15 | #include "dev.h" |
17 | #include "scan.h" | 16 | #include "scan.h" |
17 | #include "assoc.h" | ||
18 | #include "wext.h" | ||
18 | #include "cmd.h" | 19 | #include "cmd.h" |
19 | 20 | ||
20 | //! Approximate amount of data needed to pass a scan result back to iwlist | 21 | //! Approximate amount of data needed to pass a scan result back to iwlist |
21 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ | 22 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ |
22 | + IW_ESSID_MAX_SIZE \ | 23 | + IEEE80211_MAX_SSID_LEN \ |
23 | + IW_EV_UINT_LEN \ | 24 | + IW_EV_UINT_LEN \ |
24 | + IW_EV_FREQ_LEN \ | 25 | + IW_EV_FREQ_LEN \ |
25 | + IW_EV_QUAL_LEN \ | 26 | + IW_EV_QUAL_LEN \ |
26 | + IW_ESSID_MAX_SIZE \ | 27 | + IEEE80211_MAX_SSID_LEN \ |
27 | + IW_EV_PARAM_LEN \ | 28 | + IW_EV_PARAM_LEN \ |
28 | + 40) /* 40 for WPAIE */ | 29 | + 40) /* 40 for WPAIE */ |
29 | 30 | ||
@@ -121,6 +122,189 @@ static inline int is_same_network(struct bss_descriptor *src, | |||
121 | 122 | ||
122 | 123 | ||
123 | 124 | ||
125 | /*********************************************************************/ | ||
126 | /* */ | ||
127 | /* Region channel support */ | ||
128 | /* */ | ||
129 | /*********************************************************************/ | ||
130 | |||
131 | #define LBS_TX_PWR_DEFAULT 20 /*100mW */ | ||
132 | #define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ | ||
133 | #define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ | ||
134 | #define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ | ||
135 | #define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */ | ||
136 | |||
137 | /* Format { channel, frequency (MHz), maxtxpower } */ | ||
138 | /* band: 'B/G', region: USA FCC/Canada IC */ | ||
139 | static struct chan_freq_power channel_freq_power_US_BG[] = { | ||
140 | {1, 2412, LBS_TX_PWR_US_DEFAULT}, | ||
141 | {2, 2417, LBS_TX_PWR_US_DEFAULT}, | ||
142 | {3, 2422, LBS_TX_PWR_US_DEFAULT}, | ||
143 | {4, 2427, LBS_TX_PWR_US_DEFAULT}, | ||
144 | {5, 2432, LBS_TX_PWR_US_DEFAULT}, | ||
145 | {6, 2437, LBS_TX_PWR_US_DEFAULT}, | ||
146 | {7, 2442, LBS_TX_PWR_US_DEFAULT}, | ||
147 | {8, 2447, LBS_TX_PWR_US_DEFAULT}, | ||
148 | {9, 2452, LBS_TX_PWR_US_DEFAULT}, | ||
149 | {10, 2457, LBS_TX_PWR_US_DEFAULT}, | ||
150 | {11, 2462, LBS_TX_PWR_US_DEFAULT} | ||
151 | }; | ||
152 | |||
153 | /* band: 'B/G', region: Europe ETSI */ | ||
154 | static struct chan_freq_power channel_freq_power_EU_BG[] = { | ||
155 | {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, | ||
156 | {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, | ||
157 | {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, | ||
158 | {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, | ||
159 | {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, | ||
160 | {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, | ||
161 | {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, | ||
162 | {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, | ||
163 | {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, | ||
164 | {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, | ||
165 | {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, | ||
166 | {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, | ||
167 | {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} | ||
168 | }; | ||
169 | |||
170 | /* band: 'B/G', region: Spain */ | ||
171 | static struct chan_freq_power channel_freq_power_SPN_BG[] = { | ||
172 | {10, 2457, LBS_TX_PWR_DEFAULT}, | ||
173 | {11, 2462, LBS_TX_PWR_DEFAULT} | ||
174 | }; | ||
175 | |||
176 | /* band: 'B/G', region: France */ | ||
177 | static struct chan_freq_power channel_freq_power_FR_BG[] = { | ||
178 | {10, 2457, LBS_TX_PWR_FR_DEFAULT}, | ||
179 | {11, 2462, LBS_TX_PWR_FR_DEFAULT}, | ||
180 | {12, 2467, LBS_TX_PWR_FR_DEFAULT}, | ||
181 | {13, 2472, LBS_TX_PWR_FR_DEFAULT} | ||
182 | }; | ||
183 | |||
184 | /* band: 'B/G', region: Japan */ | ||
185 | static struct chan_freq_power channel_freq_power_JPN_BG[] = { | ||
186 | {1, 2412, LBS_TX_PWR_JP_DEFAULT}, | ||
187 | {2, 2417, LBS_TX_PWR_JP_DEFAULT}, | ||
188 | {3, 2422, LBS_TX_PWR_JP_DEFAULT}, | ||
189 | {4, 2427, LBS_TX_PWR_JP_DEFAULT}, | ||
190 | {5, 2432, LBS_TX_PWR_JP_DEFAULT}, | ||
191 | {6, 2437, LBS_TX_PWR_JP_DEFAULT}, | ||
192 | {7, 2442, LBS_TX_PWR_JP_DEFAULT}, | ||
193 | {8, 2447, LBS_TX_PWR_JP_DEFAULT}, | ||
194 | {9, 2452, LBS_TX_PWR_JP_DEFAULT}, | ||
195 | {10, 2457, LBS_TX_PWR_JP_DEFAULT}, | ||
196 | {11, 2462, LBS_TX_PWR_JP_DEFAULT}, | ||
197 | {12, 2467, LBS_TX_PWR_JP_DEFAULT}, | ||
198 | {13, 2472, LBS_TX_PWR_JP_DEFAULT}, | ||
199 | {14, 2484, LBS_TX_PWR_JP_DEFAULT} | ||
200 | }; | ||
201 | |||
202 | /** | ||
203 | * the structure for channel, frequency and power | ||
204 | */ | ||
205 | struct region_cfp_table { | ||
206 | u8 region; | ||
207 | struct chan_freq_power *cfp_BG; | ||
208 | int cfp_no_BG; | ||
209 | }; | ||
210 | |||
211 | /** | ||
212 | * the structure for the mapping between region and CFP | ||
213 | */ | ||
214 | static struct region_cfp_table region_cfp_table[] = { | ||
215 | {0x10, /*US FCC */ | ||
216 | channel_freq_power_US_BG, | ||
217 | ARRAY_SIZE(channel_freq_power_US_BG), | ||
218 | } | ||
219 | , | ||
220 | {0x20, /*CANADA IC */ | ||
221 | channel_freq_power_US_BG, | ||
222 | ARRAY_SIZE(channel_freq_power_US_BG), | ||
223 | } | ||
224 | , | ||
225 | {0x30, /*EU*/ channel_freq_power_EU_BG, | ||
226 | ARRAY_SIZE(channel_freq_power_EU_BG), | ||
227 | } | ||
228 | , | ||
229 | {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, | ||
230 | ARRAY_SIZE(channel_freq_power_SPN_BG), | ||
231 | } | ||
232 | , | ||
233 | {0x32, /*FRANCE*/ channel_freq_power_FR_BG, | ||
234 | ARRAY_SIZE(channel_freq_power_FR_BG), | ||
235 | } | ||
236 | , | ||
237 | {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, | ||
238 | ARRAY_SIZE(channel_freq_power_JPN_BG), | ||
239 | } | ||
240 | , | ||
241 | /*Add new region here */ | ||
242 | }; | ||
243 | |||
244 | /** | ||
245 | * @brief This function finds the CFP in | ||
246 | * region_cfp_table based on region and band parameter. | ||
247 | * | ||
248 | * @param region The region code | ||
249 | * @param band The band | ||
250 | * @param cfp_no A pointer to CFP number | ||
251 | * @return A pointer to CFP | ||
252 | */ | ||
253 | static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no) | ||
254 | { | ||
255 | int i, end; | ||
256 | |||
257 | lbs_deb_enter(LBS_DEB_MAIN); | ||
258 | |||
259 | end = ARRAY_SIZE(region_cfp_table); | ||
260 | |||
261 | for (i = 0; i < end ; i++) { | ||
262 | lbs_deb_main("region_cfp_table[i].region=%d\n", | ||
263 | region_cfp_table[i].region); | ||
264 | if (region_cfp_table[i].region == region) { | ||
265 | *cfp_no = region_cfp_table[i].cfp_no_BG; | ||
266 | lbs_deb_leave(LBS_DEB_MAIN); | ||
267 | return region_cfp_table[i].cfp_BG; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL"); | ||
272 | return NULL; | ||
273 | } | ||
274 | |||
275 | int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) | ||
276 | { | ||
277 | int ret = 0; | ||
278 | int i = 0; | ||
279 | |||
280 | struct chan_freq_power *cfp; | ||
281 | int cfp_no; | ||
282 | |||
283 | lbs_deb_enter(LBS_DEB_MAIN); | ||
284 | |||
285 | memset(priv->region_channel, 0, sizeof(priv->region_channel)); | ||
286 | |||
287 | cfp = lbs_get_region_cfp_table(region, &cfp_no); | ||
288 | if (cfp != NULL) { | ||
289 | priv->region_channel[i].nrcfp = cfp_no; | ||
290 | priv->region_channel[i].CFP = cfp; | ||
291 | } else { | ||
292 | lbs_deb_main("wrong region code %#x in band B/G\n", | ||
293 | region); | ||
294 | ret = -1; | ||
295 | goto out; | ||
296 | } | ||
297 | priv->region_channel[i].valid = 1; | ||
298 | priv->region_channel[i].region = region; | ||
299 | priv->region_channel[i].band = band; | ||
300 | i++; | ||
301 | out: | ||
302 | lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | |||
307 | |||
124 | 308 | ||
125 | /*********************************************************************/ | 309 | /*********************************************************************/ |
126 | /* */ | 310 | /* */ |
@@ -161,31 +345,15 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
161 | scantype = CMD_SCAN_TYPE_ACTIVE; | 345 | scantype = CMD_SCAN_TYPE_ACTIVE; |
162 | 346 | ||
163 | for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { | 347 | for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { |
164 | if (priv->enable11d && (priv->connect_status != LBS_CONNECTED) | 348 | if (!priv->region_channel[rgnidx].valid) |
165 | && (priv->mesh_connect_status != LBS_CONNECTED)) { | 349 | continue; |
166 | /* Scan all the supported chan for the first scan */ | 350 | scanregion = &priv->region_channel[rgnidx]; |
167 | if (!priv->universal_channel[rgnidx].valid) | ||
168 | continue; | ||
169 | scanregion = &priv->universal_channel[rgnidx]; | ||
170 | |||
171 | /* clear the parsed_region_chan for the first scan */ | ||
172 | memset(&priv->parsed_region_chan, 0x00, | ||
173 | sizeof(priv->parsed_region_chan)); | ||
174 | } else { | ||
175 | if (!priv->region_channel[rgnidx].valid) | ||
176 | continue; | ||
177 | scanregion = &priv->region_channel[rgnidx]; | ||
178 | } | ||
179 | 351 | ||
180 | for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { | 352 | for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) { |
181 | struct chanscanparamset *chan = &scanchanlist[chanidx]; | 353 | struct chanscanparamset *chan = &scanchanlist[chanidx]; |
182 | 354 | ||
183 | cfp = scanregion->CFP + nextchan; | 355 | cfp = scanregion->CFP + nextchan; |
184 | 356 | ||
185 | if (priv->enable11d) | ||
186 | scantype = lbs_get_scan_type_11d(cfp->channel, | ||
187 | &priv->parsed_region_chan); | ||
188 | |||
189 | if (scanregion->band == BAND_B || scanregion->band == BAND_G) | 357 | if (scanregion->band == BAND_B || scanregion->band == BAND_G) |
190 | chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; | 358 | chan->radiotype = CMD_SCAN_RADIO_TYPE_BG; |
191 | 359 | ||
@@ -519,7 +687,6 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
519 | struct ieee_ie_cf_param_set *cf; | 687 | struct ieee_ie_cf_param_set *cf; |
520 | struct ieee_ie_ibss_param_set *ibss; | 688 | struct ieee_ie_ibss_param_set *ibss; |
521 | DECLARE_SSID_BUF(ssid); | 689 | DECLARE_SSID_BUF(ssid); |
522 | struct ieee_ie_country_info_set *pcountryinfo; | ||
523 | uint8_t *pos, *end, *p; | 690 | uint8_t *pos, *end, *p; |
524 | uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; | 691 | uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; |
525 | uint16_t beaconsize = 0; | 692 | uint16_t beaconsize = 0; |
@@ -642,26 +809,6 @@ static int lbs_process_bss(struct bss_descriptor *bss, | |||
642 | lbs_deb_scan("got IBSS IE\n"); | 809 | lbs_deb_scan("got IBSS IE\n"); |
643 | break; | 810 | break; |
644 | 811 | ||
645 | case WLAN_EID_COUNTRY: | ||
646 | pcountryinfo = (struct ieee_ie_country_info_set *) pos; | ||
647 | lbs_deb_scan("got COUNTRY IE\n"); | ||
648 | if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode) | ||
649 | || pcountryinfo->header.len > 254) { | ||
650 | lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n", | ||
651 | __func__, | ||
652 | pcountryinfo->header.len, | ||
653 | sizeof(pcountryinfo->countrycode)); | ||
654 | ret = -1; | ||
655 | goto done; | ||
656 | } | ||
657 | |||
658 | memcpy(&bss->countryinfo, pcountryinfo, | ||
659 | pcountryinfo->header.len + 2); | ||
660 | lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo", | ||
661 | (uint8_t *) pcountryinfo, | ||
662 | (int) (pcountryinfo->header.len + 2)); | ||
663 | break; | ||
664 | |||
665 | case WLAN_EID_EXT_SUPP_RATES: | 812 | case WLAN_EID_EXT_SUPP_RATES: |
666 | /* only process extended supported rate if data rate is | 813 | /* only process extended supported rate if data rate is |
667 | * already found. Data rate IE should come before | 814 | * already found. Data rate IE should come before |
@@ -812,7 +959,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv, | |||
812 | /* SSID */ | 959 | /* SSID */ |
813 | iwe.cmd = SIOCGIWESSID; | 960 | iwe.cmd = SIOCGIWESSID; |
814 | iwe.u.data.flags = 1; | 961 | iwe.u.data.flags = 1; |
815 | iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IW_ESSID_MAX_SIZE); | 962 | iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN); |
816 | start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); | 963 | start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); |
817 | 964 | ||
818 | /* Mode */ | 965 | /* Mode */ |
@@ -1022,9 +1169,12 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1022 | return -EAGAIN; | 1169 | return -EAGAIN; |
1023 | 1170 | ||
1024 | /* Update RSSI if current BSS is a locally created ad-hoc BSS */ | 1171 | /* Update RSSI if current BSS is a locally created ad-hoc BSS */ |
1025 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) | 1172 | if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { |
1026 | lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, | 1173 | err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, |
1027 | CMD_OPTION_WAITFORRSP, 0, NULL); | 1174 | CMD_OPTION_WAITFORRSP, 0, NULL); |
1175 | if (err) | ||
1176 | goto out; | ||
1177 | } | ||
1028 | 1178 | ||
1029 | mutex_lock(&priv->lock); | 1179 | mutex_lock(&priv->lock); |
1030 | list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { | 1180 | list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { |
@@ -1058,7 +1208,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1058 | 1208 | ||
1059 | dwrq->length = (ev - extra); | 1209 | dwrq->length = (ev - extra); |
1060 | dwrq->flags = 0; | 1210 | dwrq->flags = 0; |
1061 | 1211 | out: | |
1062 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); | 1212 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); |
1063 | return err; | 1213 | return err; |
1064 | } | 1214 | } |
@@ -1141,11 +1291,11 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, | |||
1141 | /* The size of the TLV buffer is equal to the entire command response | 1291 | /* The size of the TLV buffer is equal to the entire command response |
1142 | * size (scanrespsize) minus the fixed fields (sizeof()'s), the | 1292 | * size (scanrespsize) minus the fixed fields (sizeof()'s), the |
1143 | * BSS Descriptions (bssdescriptsize as bytesLef) and the command | 1293 | * BSS Descriptions (bssdescriptsize as bytesLef) and the command |
1144 | * response header (S_DS_GEN) | 1294 | * response header (sizeof(struct cmd_header)) |
1145 | */ | 1295 | */ |
1146 | tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) | 1296 | tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize) |
1147 | + sizeof(scanresp->nr_sets) | 1297 | + sizeof(scanresp->nr_sets) |
1148 | + S_DS_GEN); | 1298 | + sizeof(struct cmd_header)); |
1149 | 1299 | ||
1150 | /* | 1300 | /* |
1151 | * Process each scan response returned (scanresp->nr_sets). Save | 1301 | * Process each scan response returned (scanresp->nr_sets). Save |