diff options
author | Holger Schurig <hs4233@mail.mn-solutions.de> | 2008-03-05 01:05:32 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-13 16:02:32 -0400 |
commit | 52933d815bff78605a490582a2212a8131482e00 (patch) | |
tree | d30f7107a771b3ef2b5d1b187fc9baa3c733b0b2 /drivers/net/wireless/libertas/scan.c | |
parent | d9357136ac4729f589543afb6b1d17d443ae4f71 (diff) |
libertas: implement SSID scanning for SIOCSIWSCAN
After my bit scan re-writing the SIOCSIWSCAN wext ioctl no longer supported
scanning for a specific SSID. However, wpa_supplicant is a possible user of
this ioctl, so here is code that add's this.
While passing, removed even more of the debugfs-based scanning. You can (and
should) the SIOCSIWSCAN to ask for scans, so there is no need for
proprietary interfaces for scanning. And, besides, the scan result couldn't
be used further, e.g. not for associating.
Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>
Acked-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/scan.c')
-rw-r--r-- | drivers/net/wireless/libertas/scan.c | 145 |
1 files changed, 67 insertions, 78 deletions
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 99f11a56d84e..0598541451d8 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c | |||
@@ -260,24 +260,12 @@ done: | |||
260 | 260 | ||
261 | 261 | ||
262 | 262 | ||
263 | |||
264 | /*********************************************************************/ | 263 | /*********************************************************************/ |
265 | /* */ | 264 | /* */ |
266 | /* Main scanning support */ | 265 | /* Main scanning support */ |
267 | /* */ | 266 | /* */ |
268 | /*********************************************************************/ | 267 | /*********************************************************************/ |
269 | 268 | ||
270 | void lbs_scan_worker(struct work_struct *work) | ||
271 | { | ||
272 | struct lbs_private *priv = | ||
273 | container_of(work, struct lbs_private, scan_work.work); | ||
274 | |||
275 | lbs_deb_enter(LBS_DEB_SCAN); | ||
276 | lbs_scan_networks(priv, NULL, 0); | ||
277 | lbs_deb_leave(LBS_DEB_SCAN); | ||
278 | } | ||
279 | |||
280 | |||
281 | /** | 269 | /** |
282 | * @brief Create a channel list for the driver to scan based on region info | 270 | * @brief Create a channel list for the driver to scan based on region info |
283 | * | 271 | * |
@@ -289,17 +277,11 @@ void lbs_scan_worker(struct work_struct *work) | |||
289 | * | 277 | * |
290 | * @param priv A pointer to struct lbs_private structure | 278 | * @param priv A pointer to struct lbs_private structure |
291 | * @param scanchanlist Output parameter: resulting channel list to scan | 279 | * @param scanchanlist Output parameter: resulting channel list to scan |
292 | * @param filteredscan Flag indicating whether or not a BSSID or SSID filter | ||
293 | * is being sent in the command to firmware. Used to | ||
294 | * increase the number of channels sent in a scan | ||
295 | * command and to disable the firmware channel scan | ||
296 | * filter. | ||
297 | * | 280 | * |
298 | * @return void | 281 | * @return void |
299 | */ | 282 | */ |
300 | static int lbs_scan_create_channel_list(struct lbs_private *priv, | 283 | static int lbs_scan_create_channel_list(struct lbs_private *priv, |
301 | struct chanscanparamset *scanchanlist, | 284 | struct chanscanparamset *scanchanlist) |
302 | uint8_t filteredscan) | ||
303 | { | 285 | { |
304 | struct region_channel *scanregion; | 286 | struct region_channel *scanregion; |
305 | struct chan_freq_power *cfp; | 287 | struct chan_freq_power *cfp; |
@@ -354,9 +336,6 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
354 | } | 336 | } |
355 | 337 | ||
356 | chan->channumber = cfp->channel; | 338 | chan->channumber = cfp->channel; |
357 | |||
358 | if (filteredscan) | ||
359 | chan->chanscanmode.disablechanfilt = 1; | ||
360 | } | 339 | } |
361 | } | 340 | } |
362 | return chanidx; | 341 | return chanidx; |
@@ -370,15 +349,14 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv, | |||
370 | * length 06 00 | 349 | * length 06 00 |
371 | * ssid 4d 4e 54 45 53 54 | 350 | * ssid 4d 4e 54 45 53 54 |
372 | */ | 351 | */ |
373 | static int lbs_scan_add_ssid_tlv(uint8_t *tlv, | 352 | static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv) |
374 | const struct lbs_ioctl_user_scan_cfg *user_cfg) | ||
375 | { | 353 | { |
376 | struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; | 354 | struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv; |
377 | 355 | ||
378 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); | 356 | ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); |
379 | ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len); | 357 | ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len); |
380 | memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len); | 358 | memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len); |
381 | return sizeof(ssid_tlv->header) + user_cfg->ssid_len; | 359 | return sizeof(ssid_tlv->header) + priv->scan_ssid_len; |
382 | } | 360 | } |
383 | 361 | ||
384 | 362 | ||
@@ -461,8 +439,7 @@ static int lbs_scan_add_rates_tlv(uint8_t *tlv) | |||
461 | * for a bunch of channels. | 439 | * for a bunch of channels. |
462 | */ | 440 | */ |
463 | static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, | 441 | static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, |
464 | struct chanscanparamset *chan_list, int chan_count, | 442 | struct chanscanparamset *chan_list, int chan_count) |
465 | const struct lbs_ioctl_user_scan_cfg *user_cfg) | ||
466 | { | 443 | { |
467 | int ret = -ENOMEM; | 444 | int ret = -ENOMEM; |
468 | struct cmd_ds_802_11_scan *scan_cmd; | 445 | struct cmd_ds_802_11_scan *scan_cmd; |
@@ -477,13 +454,13 @@ static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype, | |||
477 | goto out; | 454 | goto out; |
478 | 455 | ||
479 | tlv = scan_cmd->tlvbuffer; | 456 | tlv = scan_cmd->tlvbuffer; |
480 | if (user_cfg) | 457 | /* TODO: do we need to scan for a specific BSSID? |
481 | memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN); | 458 | memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */ |
482 | scan_cmd->bsstype = bsstype; | 459 | scan_cmd->bsstype = bsstype; |
483 | 460 | ||
484 | /* add TLVs */ | 461 | /* add TLVs */ |
485 | if (user_cfg && user_cfg->ssid_len) | 462 | if (priv->scan_ssid_len) |
486 | tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg); | 463 | tlv += lbs_scan_add_ssid_tlv(priv, tlv); |
487 | if (chan_list && chan_count) | 464 | if (chan_list && chan_count) |
488 | tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count); | 465 | tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count); |
489 | tlv += lbs_scan_add_rates_tlv(tlv); | 466 | tlv += lbs_scan_add_rates_tlv(tlv); |
@@ -516,14 +493,11 @@ out: | |||
516 | * update the internal driver scan table | 493 | * update the internal driver scan table |
517 | * | 494 | * |
518 | * @param priv A pointer to struct lbs_private structure | 495 | * @param priv A pointer to struct lbs_private structure |
519 | * @param puserscanin Pointer to the input configuration for the requested | 496 | * @param full_scan Do a full-scan (blocking) |
520 | * scan. | ||
521 | * | 497 | * |
522 | * @return 0 or < 0 if error | 498 | * @return 0 or < 0 if error |
523 | */ | 499 | */ |
524 | int lbs_scan_networks(struct lbs_private *priv, | 500 | static int lbs_scan_networks(struct lbs_private *priv, int full_scan) |
525 | const struct lbs_ioctl_user_scan_cfg *user_cfg, | ||
526 | int full_scan) | ||
527 | { | 501 | { |
528 | int ret = -ENOMEM; | 502 | int ret = -ENOMEM; |
529 | struct chanscanparamset *chan_list; | 503 | struct chanscanparamset *chan_list; |
@@ -531,7 +505,6 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
531 | int chan_count; | 505 | int chan_count; |
532 | uint8_t bsstype = CMD_BSS_TYPE_ANY; | 506 | uint8_t bsstype = CMD_BSS_TYPE_ANY; |
533 | int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; | 507 | int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; |
534 | int filteredscan = 0; | ||
535 | union iwreq_data wrqu; | 508 | union iwreq_data wrqu; |
536 | #ifdef CONFIG_LIBERTAS_DEBUG | 509 | #ifdef CONFIG_LIBERTAS_DEBUG |
537 | struct bss_descriptor *iter; | 510 | struct bss_descriptor *iter; |
@@ -547,17 +520,16 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
547 | if (full_scan && delayed_work_pending(&priv->scan_work)) | 520 | if (full_scan && delayed_work_pending(&priv->scan_work)) |
548 | cancel_delayed_work(&priv->scan_work); | 521 | cancel_delayed_work(&priv->scan_work); |
549 | 522 | ||
550 | /* Determine same scan parameters */ | 523 | /* User-specified bsstype or channel list |
524 | TODO: this can be implemented if some user-space application | ||
525 | need the feature. Formerly, it was accessible from debugfs, | ||
526 | but then nowhere used. | ||
551 | if (user_cfg) { | 527 | if (user_cfg) { |
552 | if (user_cfg->bsstype) | 528 | if (user_cfg->bsstype) |
553 | bsstype = user_cfg->bsstype; | 529 | bsstype = user_cfg->bsstype; |
554 | if (!is_zero_ether_addr(user_cfg->bssid)) { | 530 | } */ |
555 | numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN; | 531 | |
556 | filteredscan = 1; | 532 | lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype); |
557 | } | ||
558 | } | ||
559 | lbs_deb_scan("numchannels %d, bsstype %d, filteredscan %d\n", | ||
560 | numchannels, bsstype, filteredscan); | ||
561 | 533 | ||
562 | /* Create list of channels to scan */ | 534 | /* Create list of channels to scan */ |
563 | chan_list = kzalloc(sizeof(struct chanscanparamset) * | 535 | chan_list = kzalloc(sizeof(struct chanscanparamset) * |
@@ -568,7 +540,7 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
568 | } | 540 | } |
569 | 541 | ||
570 | /* We want to scan all channels */ | 542 | /* We want to scan all channels */ |
571 | chan_count = lbs_scan_create_channel_list(priv, chan_list, filteredscan); | 543 | chan_count = lbs_scan_create_channel_list(priv, chan_list); |
572 | 544 | ||
573 | netif_stop_queue(priv->dev); | 545 | netif_stop_queue(priv->dev); |
574 | netif_carrier_off(priv->dev); | 546 | netif_carrier_off(priv->dev); |
@@ -597,7 +569,7 @@ int lbs_scan_networks(struct lbs_private *priv, | |||
597 | lbs_deb_scan("scanning %d of %d channels\n", | 569 | lbs_deb_scan("scanning %d of %d channels\n", |
598 | to_scan, chan_count); | 570 | to_scan, chan_count); |
599 | ret = lbs_do_scan(priv, bsstype, curr_chans, | 571 | ret = lbs_do_scan(priv, bsstype, curr_chans, |
600 | to_scan, user_cfg); | 572 | to_scan); |
601 | if (ret) { | 573 | if (ret) { |
602 | lbs_pr_err("SCAN_CMD failed\n"); | 574 | lbs_pr_err("SCAN_CMD failed\n"); |
603 | goto out2; | 575 | goto out2; |
@@ -658,6 +630,17 @@ out: | |||
658 | 630 | ||
659 | 631 | ||
660 | 632 | ||
633 | void lbs_scan_worker(struct work_struct *work) | ||
634 | { | ||
635 | struct lbs_private *priv = | ||
636 | container_of(work, struct lbs_private, scan_work.work); | ||
637 | |||
638 | lbs_deb_enter(LBS_DEB_SCAN); | ||
639 | lbs_scan_networks(priv, 0); | ||
640 | lbs_deb_leave(LBS_DEB_SCAN); | ||
641 | } | ||
642 | |||
643 | |||
661 | /*********************************************************************/ | 644 | /*********************************************************************/ |
662 | /* */ | 645 | /* */ |
663 | /* Result interpretation */ | 646 | /* Result interpretation */ |
@@ -1068,7 +1051,7 @@ static struct bss_descriptor *lbs_find_best_ssid_in_list(struct lbs_private *pri | |||
1068 | } | 1051 | } |
1069 | 1052 | ||
1070 | /** | 1053 | /** |
1071 | * @brief Find the AP with specific ssid in the scan list | 1054 | * @brief Find the best AP |
1072 | * | 1055 | * |
1073 | * Used from association worker. | 1056 | * Used from association worker. |
1074 | * | 1057 | * |
@@ -1086,7 +1069,8 @@ int lbs_find_best_network_ssid(struct lbs_private *priv, uint8_t *out_ssid, | |||
1086 | 1069 | ||
1087 | lbs_deb_enter(LBS_DEB_SCAN); | 1070 | lbs_deb_enter(LBS_DEB_SCAN); |
1088 | 1071 | ||
1089 | lbs_scan_networks(priv, NULL, 1); | 1072 | priv->scan_ssid_len = 0; |
1073 | lbs_scan_networks(priv, 1); | ||
1090 | if (priv->surpriseremoved) | 1074 | if (priv->surpriseremoved) |
1091 | goto out; | 1075 | goto out; |
1092 | 1076 | ||
@@ -1112,29 +1096,24 @@ out: | |||
1112 | * @param priv A pointer to struct lbs_private structure | 1096 | * @param priv A pointer to struct lbs_private structure |
1113 | * @param ssid A pointer to the SSID to scan for | 1097 | * @param ssid A pointer to the SSID to scan for |
1114 | * @param ssid_len Length of the SSID | 1098 | * @param ssid_len Length of the SSID |
1115 | * @param clear_ssid Should existing scan results with this SSID | ||
1116 | * be cleared? | ||
1117 | * | 1099 | * |
1118 | * @return 0-success, otherwise fail | 1100 | * @return 0-success, otherwise fail |
1119 | */ | 1101 | */ |
1120 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, | 1102 | int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, |
1121 | uint8_t ssid_len, uint8_t clear_ssid) | 1103 | uint8_t ssid_len) |
1122 | { | 1104 | { |
1123 | struct lbs_ioctl_user_scan_cfg scancfg; | ||
1124 | int ret = 0; | 1105 | int ret = 0; |
1125 | 1106 | ||
1126 | lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", | 1107 | lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", |
1127 | escape_essid(ssid, ssid_len), clear_ssid); | 1108 | escape_essid(ssid, ssid_len)); |
1128 | 1109 | ||
1129 | if (!ssid_len) | 1110 | if (!ssid_len) |
1130 | goto out; | 1111 | goto out; |
1131 | 1112 | ||
1132 | memset(&scancfg, 0x00, sizeof(scancfg)); | 1113 | memcpy(priv->scan_ssid, ssid, ssid_len); |
1133 | memcpy(scancfg.ssid, ssid, ssid_len); | 1114 | priv->scan_ssid_len = ssid_len; |
1134 | scancfg.ssid_len = ssid_len; | ||
1135 | scancfg.clear_ssid = clear_ssid; | ||
1136 | 1115 | ||
1137 | lbs_scan_networks(priv, &scancfg, 1); | 1116 | lbs_scan_networks(priv, 1); |
1138 | if (priv->surpriseremoved) { | 1117 | if (priv->surpriseremoved) { |
1139 | ret = -1; | 1118 | ret = -1; |
1140 | goto out; | 1119 | goto out; |
@@ -1317,27 +1296,36 @@ out: | |||
1317 | * @return 0 --success, otherwise fail | 1296 | * @return 0 --success, otherwise fail |
1318 | */ | 1297 | */ |
1319 | int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | 1298 | int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, |
1320 | struct iw_param *wrqu, char *extra) | 1299 | union iwreq_data *wrqu, char *extra) |
1321 | { | 1300 | { |
1322 | struct lbs_private *priv = dev->priv; | 1301 | struct lbs_private *priv = dev->priv; |
1302 | int ret = 0; | ||
1323 | 1303 | ||
1324 | lbs_deb_enter(LBS_DEB_SCAN); | 1304 | lbs_deb_enter(LBS_DEB_WEXT); |
1325 | 1305 | ||
1326 | if (!netif_running(dev)) | 1306 | if (!netif_running(dev)) { |
1327 | return -ENETDOWN; | 1307 | ret = -ENETDOWN; |
1308 | goto out; | ||
1309 | } | ||
1328 | 1310 | ||
1329 | /* mac80211 does this: | 1311 | /* mac80211 does this: |
1330 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1312 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1331 | if (sdata->type != IEEE80211_IF_TYPE_xxx) | 1313 | if (sdata->type != IEEE80211_IF_TYPE_xxx) { |
1332 | return -EOPNOTSUPP; | 1314 | ret = -EOPNOTSUPP; |
1315 | goto out; | ||
1316 | } | ||
1317 | */ | ||
1333 | 1318 | ||
1334 | if (wrqu->data.length == sizeof(struct iw_scan_req) && | 1319 | if (wrqu->data.length == sizeof(struct iw_scan_req) && |
1335 | wrqu->data.flags & IW_SCAN_THIS_ESSID) { | 1320 | wrqu->data.flags & IW_SCAN_THIS_ESSID) { |
1336 | req = (struct iw_scan_req *)extra; | 1321 | struct iw_scan_req *req = (struct iw_scan_req *)extra; |
1337 | ssid = req->essid; | 1322 | priv->scan_ssid_len = req->essid_len; |
1338 | ssid_len = req->essid_len; | 1323 | memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); |
1324 | lbs_deb_wext("set_scan, essid '%s'\n", | ||
1325 | escape_essid(priv->scan_ssid, priv->scan_ssid_len)); | ||
1326 | } else { | ||
1327 | priv->scan_ssid_len = 0; | ||
1339 | } | 1328 | } |
1340 | */ | ||
1341 | 1329 | ||
1342 | if (!delayed_work_pending(&priv->scan_work)) | 1330 | if (!delayed_work_pending(&priv->scan_work)) |
1343 | queue_delayed_work(priv->work_thread, &priv->scan_work, | 1331 | queue_delayed_work(priv->work_thread, &priv->scan_work, |
@@ -1346,10 +1334,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, | |||
1346 | priv->scan_channel = -1; | 1334 | priv->scan_channel = -1; |
1347 | 1335 | ||
1348 | if (priv->surpriseremoved) | 1336 | if (priv->surpriseremoved) |
1349 | return -EIO; | 1337 | ret = -EIO; |
1350 | 1338 | ||
1351 | lbs_deb_leave(LBS_DEB_SCAN); | 1339 | out: |
1352 | return 0; | 1340 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); |
1341 | return ret; | ||
1353 | } | 1342 | } |
1354 | 1343 | ||
1355 | 1344 | ||
@@ -1374,7 +1363,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1374 | struct bss_descriptor *iter_bss; | 1363 | struct bss_descriptor *iter_bss; |
1375 | struct bss_descriptor *safe; | 1364 | struct bss_descriptor *safe; |
1376 | 1365 | ||
1377 | lbs_deb_enter(LBS_DEB_SCAN); | 1366 | lbs_deb_enter(LBS_DEB_WEXT); |
1378 | 1367 | ||
1379 | /* iwlist should wait until the current scan is finished */ | 1368 | /* iwlist should wait until the current scan is finished */ |
1380 | if (priv->scan_channel) | 1369 | if (priv->scan_channel) |
@@ -1418,7 +1407,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, | |||
1418 | dwrq->length = (ev - extra); | 1407 | dwrq->length = (ev - extra); |
1419 | dwrq->flags = 0; | 1408 | dwrq->flags = 0; |
1420 | 1409 | ||
1421 | lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err); | 1410 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err); |
1422 | return err; | 1411 | return err; |
1423 | } | 1412 | } |
1424 | 1413 | ||