diff options
author | David Kilroy <kilroyd@googlemail.com> | 2009-06-18 18:21:33 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:01:46 -0400 |
commit | c63cdbe8f80487c372fe0dfe460ed30467029f01 (patch) | |
tree | a981d5b052fc74b5f894775353a3e6e96591a1c7 | |
parent | 5217c571c898371c540e49671600d54346b2e123 (diff) |
orinoco: convert scanning to cfg80211
This removes the custom scan cache used by orinoco.
We also have to avoid calling cfg80211_scan_done from the hard
interrupt, so we offload the entirety of scan processing to a workqueue.
This may behave strangely if you start scanning just prior to
suspending...
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/orinoco/cfg.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hermes.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hw.c | 85 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hw.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 167 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/orinoco.h | 22 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/scan.c | 285 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/scan.h | 21 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/wext.c | 517 |
9 files changed, 378 insertions, 744 deletions
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 9e59d90b32e4..1a87d3a0967c 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c | |||
@@ -137,6 +137,26 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, | |||
137 | return err; | 137 | return err; |
138 | } | 138 | } |
139 | 139 | ||
140 | static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, | ||
141 | struct cfg80211_scan_request *request) | ||
142 | { | ||
143 | struct orinoco_private *priv = wiphy_priv(wiphy); | ||
144 | int err; | ||
145 | |||
146 | if (!request) | ||
147 | return -EINVAL; | ||
148 | |||
149 | if (priv->scan_request && priv->scan_request != request) | ||
150 | return -EBUSY; | ||
151 | |||
152 | priv->scan_request = request; | ||
153 | |||
154 | err = orinoco_hw_trigger_scan(priv, request->ssids); | ||
155 | |||
156 | return err; | ||
157 | } | ||
158 | |||
140 | const struct cfg80211_ops orinoco_cfg_ops = { | 159 | const struct cfg80211_ops orinoco_cfg_ops = { |
141 | .change_virtual_intf = orinoco_change_vif, | 160 | .change_virtual_intf = orinoco_change_vif, |
161 | .scan = orinoco_scan, | ||
142 | }; | 162 | }; |
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h index c78c442a02c8..2dddbb597c4d 100644 --- a/drivers/net/wireless/orinoco/hermes.h +++ b/drivers/net/wireless/orinoco/hermes.h | |||
@@ -342,7 +342,7 @@ struct agere_ext_scan_info { | |||
342 | __le64 timestamp; | 342 | __le64 timestamp; |
343 | __le16 beacon_interval; | 343 | __le16 beacon_interval; |
344 | __le16 capabilities; | 344 | __le16 capabilities; |
345 | u8 data[316]; | 345 | u8 data[0]; |
346 | } __attribute__ ((packed)); | 346 | } __attribute__ ((packed)); |
347 | 347 | ||
348 | #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) | 348 | #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) |
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index 4600fe4a7e1c..fa508af1a351 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c | |||
@@ -1157,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | |||
1157 | 1157 | ||
1158 | return 0; | 1158 | return 0; |
1159 | } | 1159 | } |
1160 | |||
1161 | int orinoco_hw_trigger_scan(struct orinoco_private *priv, | ||
1162 | const struct cfg80211_ssid *ssid) | ||
1163 | { | ||
1164 | struct net_device *dev = priv->ndev; | ||
1165 | hermes_t *hw = &priv->hw; | ||
1166 | unsigned long flags; | ||
1167 | int err = 0; | ||
1168 | |||
1169 | if (orinoco_lock(priv, &flags) != 0) | ||
1170 | return -EBUSY; | ||
1171 | |||
1172 | /* Scanning with port 0 disabled would fail */ | ||
1173 | if (!netif_running(dev)) { | ||
1174 | err = -ENETDOWN; | ||
1175 | goto out; | ||
1176 | } | ||
1177 | |||
1178 | /* In monitor mode, the scan results are always empty. | ||
1179 | * Probe responses are passed to the driver as received | ||
1180 | * frames and could be processed in software. */ | ||
1181 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { | ||
1182 | err = -EOPNOTSUPP; | ||
1183 | goto out; | ||
1184 | } | ||
1185 | |||
1186 | if (priv->has_hostscan) { | ||
1187 | switch (priv->firmware_type) { | ||
1188 | case FIRMWARE_TYPE_SYMBOL: | ||
1189 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1190 | HERMES_RID_CNFHOSTSCAN_SYMBOL, | ||
1191 | HERMES_HOSTSCAN_SYMBOL_ONCE | | ||
1192 | HERMES_HOSTSCAN_SYMBOL_BCAST); | ||
1193 | break; | ||
1194 | case FIRMWARE_TYPE_INTERSIL: { | ||
1195 | __le16 req[3]; | ||
1196 | |||
1197 | req[0] = cpu_to_le16(0x3fff); /* All channels */ | ||
1198 | req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ | ||
1199 | req[2] = 0; /* Any ESSID */ | ||
1200 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1201 | HERMES_RID_CNFHOSTSCAN, &req); | ||
1202 | break; | ||
1203 | } | ||
1204 | case FIRMWARE_TYPE_AGERE: | ||
1205 | if (ssid->ssid_len > 0) { | ||
1206 | struct hermes_idstring idbuf; | ||
1207 | size_t len = ssid->ssid_len; | ||
1208 | |||
1209 | idbuf.len = cpu_to_le16(len); | ||
1210 | memcpy(idbuf.val, ssid->ssid, len); | ||
1211 | |||
1212 | err = hermes_write_ltv(hw, USER_BAP, | ||
1213 | HERMES_RID_CNFSCANSSID_AGERE, | ||
1214 | HERMES_BYTES_TO_RECLEN(len + 2), | ||
1215 | &idbuf); | ||
1216 | } else | ||
1217 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1218 | HERMES_RID_CNFSCANSSID_AGERE, | ||
1219 | 0); /* Any ESSID */ | ||
1220 | if (err) | ||
1221 | break; | ||
1222 | |||
1223 | if (priv->has_ext_scan) { | ||
1224 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1225 | HERMES_RID_CNFSCANCHANNELS2GHZ, | ||
1226 | 0x7FFF); | ||
1227 | if (err) | ||
1228 | goto out; | ||
1229 | |||
1230 | err = hermes_inquire(hw, | ||
1231 | HERMES_INQ_CHANNELINFO); | ||
1232 | } else | ||
1233 | err = hermes_inquire(hw, HERMES_INQ_SCAN); | ||
1234 | |||
1235 | break; | ||
1236 | } | ||
1237 | } else | ||
1238 | err = hermes_inquire(hw, HERMES_INQ_SCAN); | ||
1239 | |||
1240 | out: | ||
1241 | orinoco_unlock(priv, &flags); | ||
1242 | |||
1243 | return err; | ||
1244 | } | ||
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h index 210c2b1b7f97..27b427649d1b 100644 --- a/drivers/net/wireless/orinoco/hw.h +++ b/drivers/net/wireless/orinoco/hw.h | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <linux/types.h> | 8 | #include <linux/types.h> |
9 | #include <linux/wireless.h> | 9 | #include <linux/wireless.h> |
10 | #include <net/cfg80211.h> | ||
10 | 11 | ||
11 | /* Hardware BAPs */ | 12 | /* Hardware BAPs */ |
12 | #define USER_BAP 0 | 13 | #define USER_BAP 0 |
@@ -47,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, | |||
47 | int orinoco_hw_get_freq(struct orinoco_private *priv); | 48 | int orinoco_hw_get_freq(struct orinoco_private *priv); |
48 | int orinoco_hw_get_bitratelist(struct orinoco_private *priv, | 49 | int orinoco_hw_get_bitratelist(struct orinoco_private *priv, |
49 | int *numrates, s32 *rates, int max); | 50 | int *numrates, s32 *rates, int max); |
51 | int orinoco_hw_trigger_scan(struct orinoco_private *priv, | ||
52 | const struct cfg80211_ssid *ssid); | ||
50 | 53 | ||
51 | #endif /* _ORINOCO_HW_H_ */ | 54 | #endif /* _ORINOCO_HW_H_ */ |
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ebf92ae6e365..cd1c04d42b6a 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -206,6 +206,13 @@ struct orinoco_rx_data { | |||
206 | struct list_head list; | 206 | struct list_head list; |
207 | }; | 207 | }; |
208 | 208 | ||
209 | struct orinoco_scan_data { | ||
210 | void *buf; | ||
211 | size_t len; | ||
212 | int type; | ||
213 | struct list_head list; | ||
214 | }; | ||
215 | |||
209 | /********************************************************************/ | 216 | /********************************************************************/ |
210 | /* Function prototypes */ | 217 | /* Function prototypes */ |
211 | /********************************************************************/ | 218 | /********************************************************************/ |
@@ -1265,6 +1272,78 @@ static void orinoco_send_wevents(struct work_struct *work) | |||
1265 | orinoco_unlock(priv, &flags); | 1272 | orinoco_unlock(priv, &flags); |
1266 | } | 1273 | } |
1267 | 1274 | ||
1275 | static void qbuf_scan(struct orinoco_private *priv, void *buf, | ||
1276 | int len, int type) | ||
1277 | { | ||
1278 | struct orinoco_scan_data *sd; | ||
1279 | unsigned long flags; | ||
1280 | |||
1281 | sd = kmalloc(sizeof(*sd), GFP_ATOMIC); | ||
1282 | sd->buf = buf; | ||
1283 | sd->len = len; | ||
1284 | sd->type = type; | ||
1285 | |||
1286 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1287 | list_add_tail(&sd->list, &priv->scan_list); | ||
1288 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1289 | |||
1290 | schedule_work(&priv->process_scan); | ||
1291 | } | ||
1292 | |||
1293 | static void qabort_scan(struct orinoco_private *priv) | ||
1294 | { | ||
1295 | struct orinoco_scan_data *sd; | ||
1296 | unsigned long flags; | ||
1297 | |||
1298 | sd = kmalloc(sizeof(*sd), GFP_ATOMIC); | ||
1299 | sd->len = -1; /* Abort */ | ||
1300 | |||
1301 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1302 | list_add_tail(&sd->list, &priv->scan_list); | ||
1303 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1304 | |||
1305 | schedule_work(&priv->process_scan); | ||
1306 | } | ||
1307 | |||
1308 | static void orinoco_process_scan_results(struct work_struct *work) | ||
1309 | { | ||
1310 | struct orinoco_private *priv = | ||
1311 | container_of(work, struct orinoco_private, process_scan); | ||
1312 | struct orinoco_scan_data *sd, *temp; | ||
1313 | unsigned long flags; | ||
1314 | void *buf; | ||
1315 | int len; | ||
1316 | int type; | ||
1317 | |||
1318 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1319 | list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { | ||
1320 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1321 | |||
1322 | buf = sd->buf; | ||
1323 | len = sd->len; | ||
1324 | type = sd->type; | ||
1325 | |||
1326 | list_del(&sd->list); | ||
1327 | kfree(sd); | ||
1328 | |||
1329 | if (len > 0) { | ||
1330 | if (type == HERMES_INQ_CHANNELINFO) | ||
1331 | orinoco_add_extscan_result(priv, buf, len); | ||
1332 | else | ||
1333 | orinoco_add_hostscan_results(priv, buf, len); | ||
1334 | |||
1335 | kfree(buf); | ||
1336 | } else if (priv->scan_request) { | ||
1337 | /* Either abort or complete the scan */ | ||
1338 | cfg80211_scan_done(priv->scan_request, (len < 0)); | ||
1339 | priv->scan_request = NULL; | ||
1340 | } | ||
1341 | |||
1342 | spin_lock_irqsave(&priv->scan_lock, flags); | ||
1343 | } | ||
1344 | spin_unlock_irqrestore(&priv->scan_lock, flags); | ||
1345 | } | ||
1346 | |||
1268 | static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | 1347 | static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) |
1269 | { | 1348 | { |
1270 | struct orinoco_private *priv = ndev_priv(dev); | 1349 | struct orinoco_private *priv = ndev_priv(dev); |
@@ -1351,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1351 | * the hostscan frame can be requested. */ | 1430 | * the hostscan frame can be requested. */ |
1352 | if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && | 1431 | if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && |
1353 | priv->firmware_type == FIRMWARE_TYPE_SYMBOL && | 1432 | priv->firmware_type == FIRMWARE_TYPE_SYMBOL && |
1354 | priv->has_hostscan && priv->scan_inprogress) { | 1433 | priv->has_hostscan && priv->scan_request) { |
1355 | hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); | 1434 | hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); |
1356 | break; | 1435 | break; |
1357 | } | 1436 | } |
@@ -1377,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1377 | } | 1456 | } |
1378 | break; | 1457 | break; |
1379 | case HERMES_INQ_SCAN: | 1458 | case HERMES_INQ_SCAN: |
1380 | if (!priv->scan_inprogress && priv->bssid_fixed && | 1459 | if (!priv->scan_request && priv->bssid_fixed && |
1381 | priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { | 1460 | priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { |
1382 | schedule_work(&priv->join_work); | 1461 | schedule_work(&priv->join_work); |
1383 | break; | 1462 | break; |
@@ -1387,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1387 | case HERMES_INQ_HOSTSCAN_SYMBOL: { | 1466 | case HERMES_INQ_HOSTSCAN_SYMBOL: { |
1388 | /* Result of a scanning. Contains information about | 1467 | /* Result of a scanning. Contains information about |
1389 | * cells in the vicinity - Jean II */ | 1468 | * cells in the vicinity - Jean II */ |
1390 | union iwreq_data wrqu; | ||
1391 | unsigned char *buf; | 1469 | unsigned char *buf; |
1392 | 1470 | ||
1393 | /* Scan is no longer in progress */ | ||
1394 | priv->scan_inprogress = 0; | ||
1395 | |||
1396 | /* Sanity check */ | 1471 | /* Sanity check */ |
1397 | if (len > 4096) { | 1472 | if (len > 4096) { |
1398 | printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", | 1473 | printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", |
1399 | dev->name, len); | 1474 | dev->name, len); |
1475 | qabort_scan(priv); | ||
1400 | break; | 1476 | break; |
1401 | } | 1477 | } |
1402 | 1478 | ||
1403 | /* Allocate buffer for results */ | 1479 | /* Allocate buffer for results */ |
1404 | buf = kmalloc(len, GFP_ATOMIC); | 1480 | buf = kmalloc(len, GFP_ATOMIC); |
1405 | if (buf == NULL) | 1481 | if (buf == NULL) { |
1406 | /* No memory, so can't printk()... */ | 1482 | /* No memory, so can't printk()... */ |
1483 | qabort_scan(priv); | ||
1407 | break; | 1484 | break; |
1485 | } | ||
1408 | 1486 | ||
1409 | /* Read scan data */ | 1487 | /* Read scan data */ |
1410 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, | 1488 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, |
1411 | infofid, sizeof(info)); | 1489 | infofid, sizeof(info)); |
1412 | if (err) { | 1490 | if (err) { |
1413 | kfree(buf); | 1491 | kfree(buf); |
1492 | qabort_scan(priv); | ||
1414 | break; | 1493 | break; |
1415 | } | 1494 | } |
1416 | 1495 | ||
@@ -1424,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1424 | } | 1503 | } |
1425 | #endif /* ORINOCO_DEBUG */ | 1504 | #endif /* ORINOCO_DEBUG */ |
1426 | 1505 | ||
1427 | if (orinoco_process_scan_results(priv, buf, len) == 0) { | 1506 | qbuf_scan(priv, buf, len, type); |
1428 | /* Send an empty event to user space. | ||
1429 | * We don't send the received data on the event because | ||
1430 | * it would require us to do complex transcoding, and | ||
1431 | * we want to minimise the work done in the irq handler | ||
1432 | * Use a request to extract the data - Jean II */ | ||
1433 | wrqu.data.length = 0; | ||
1434 | wrqu.data.flags = 0; | ||
1435 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
1436 | } | ||
1437 | kfree(buf); | ||
1438 | } | 1507 | } |
1439 | break; | 1508 | break; |
1440 | case HERMES_INQ_CHANNELINFO: | 1509 | case HERMES_INQ_CHANNELINFO: |
1441 | { | 1510 | { |
1442 | struct agere_ext_scan_info *bss; | 1511 | struct agere_ext_scan_info *bss; |
1443 | 1512 | ||
1444 | if (!priv->scan_inprogress) { | 1513 | if (!priv->scan_request) { |
1445 | printk(KERN_DEBUG "%s: Got chaninfo without scan, " | 1514 | printk(KERN_DEBUG "%s: Got chaninfo without scan, " |
1446 | "len=%d\n", dev->name, len); | 1515 | "len=%d\n", dev->name, len); |
1447 | break; | 1516 | break; |
@@ -1449,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1449 | 1518 | ||
1450 | /* An empty result indicates that the scan is complete */ | 1519 | /* An empty result indicates that the scan is complete */ |
1451 | if (len == 0) { | 1520 | if (len == 0) { |
1452 | union iwreq_data wrqu; | 1521 | qbuf_scan(priv, NULL, len, type); |
1453 | |||
1454 | /* Scan is no longer in progress */ | ||
1455 | priv->scan_inprogress = 0; | ||
1456 | |||
1457 | wrqu.data.length = 0; | ||
1458 | wrqu.data.flags = 0; | ||
1459 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
1460 | break; | 1522 | break; |
1461 | } | 1523 | } |
1462 | 1524 | ||
1463 | /* Sanity check */ | 1525 | /* Sanity check */ |
1464 | else if (len > sizeof(*bss)) { | 1526 | else if (len < (offsetof(struct agere_ext_scan_info, |
1465 | printk(KERN_WARNING | ||
1466 | "%s: Ext scan results too large (%d bytes). " | ||
1467 | "Truncating results to %zd bytes.\n", | ||
1468 | dev->name, len, sizeof(*bss)); | ||
1469 | len = sizeof(*bss); | ||
1470 | } else if (len < (offsetof(struct agere_ext_scan_info, | ||
1471 | data) + 2)) { | 1527 | data) + 2)) { |
1472 | /* Drop this result now so we don't have to | 1528 | /* Drop this result now so we don't have to |
1473 | * keep checking later */ | 1529 | * keep checking later */ |
@@ -1477,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1477 | break; | 1533 | break; |
1478 | } | 1534 | } |
1479 | 1535 | ||
1480 | bss = kmalloc(sizeof(*bss), GFP_ATOMIC); | 1536 | bss = kmalloc(len, GFP_ATOMIC); |
1481 | if (bss == NULL) | 1537 | if (bss == NULL) |
1482 | break; | 1538 | break; |
1483 | 1539 | ||
1484 | /* Read scan data */ | 1540 | /* Read scan data */ |
1485 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, | 1541 | err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len, |
1486 | infofid, sizeof(info)); | 1542 | infofid, sizeof(info)); |
1487 | if (err) { | 1543 | if (err) |
1488 | kfree(bss); | 1544 | kfree(bss); |
1489 | break; | 1545 | else |
1490 | } | 1546 | qbuf_scan(priv, bss, len, type); |
1491 | |||
1492 | orinoco_add_ext_scan_result(priv, bss); | ||
1493 | 1547 | ||
1494 | kfree(bss); | ||
1495 | break; | 1548 | break; |
1496 | } | 1549 | } |
1497 | case HERMES_INQ_SEC_STAT_AGERE: | 1550 | case HERMES_INQ_SEC_STAT_AGERE: |
@@ -1506,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) | |||
1506 | /* We don't actually do anything about it */ | 1559 | /* We don't actually do anything about it */ |
1507 | break; | 1560 | break; |
1508 | } | 1561 | } |
1562 | |||
1563 | return; | ||
1509 | } | 1564 | } |
1510 | 1565 | ||
1511 | static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) | 1566 | static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) |
@@ -1649,9 +1704,11 @@ void orinoco_reset(struct work_struct *work) | |||
1649 | 1704 | ||
1650 | orinoco_unlock(priv, &flags); | 1705 | orinoco_unlock(priv, &flags); |
1651 | 1706 | ||
1652 | /* Scanning support: Cleanup of driver struct */ | 1707 | /* Scanning support: Notify scan cancellation */ |
1653 | orinoco_clear_scan_results(priv, 0); | 1708 | if (priv->scan_request) { |
1654 | priv->scan_inprogress = 0; | 1709 | cfg80211_scan_done(priv->scan_request, 1); |
1710 | priv->scan_request = NULL; | ||
1711 | } | ||
1655 | 1712 | ||
1656 | if (priv->hard_reset) { | 1713 | if (priv->hard_reset) { |
1657 | err = (*priv->hard_reset)(priv); | 1714 | err = (*priv->hard_reset)(priv); |
@@ -1965,12 +2022,6 @@ int orinoco_init(struct orinoco_private *priv) | |||
1965 | } | 2022 | } |
1966 | } | 2023 | } |
1967 | 2024 | ||
1968 | /* Now we have the firmware capabilities, allocate appropiate | ||
1969 | * sized scan buffers */ | ||
1970 | if (orinoco_bss_data_allocate(priv)) | ||
1971 | goto out; | ||
1972 | orinoco_bss_data_init(priv); | ||
1973 | |||
1974 | err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); | 2025 | err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr); |
1975 | if (err) | 2026 | if (err) |
1976 | goto out; | 2027 | goto out; |
@@ -2100,6 +2151,10 @@ struct orinoco_private | |||
2100 | tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, | 2151 | tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet, |
2101 | (unsigned long) priv); | 2152 | (unsigned long) priv); |
2102 | 2153 | ||
2154 | spin_lock_init(&priv->scan_lock); | ||
2155 | INIT_LIST_HEAD(&priv->scan_list); | ||
2156 | INIT_WORK(&priv->process_scan, orinoco_process_scan_results); | ||
2157 | |||
2103 | priv->last_linkstatus = 0xffff; | 2158 | priv->last_linkstatus = 0xffff; |
2104 | 2159 | ||
2105 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) | 2160 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) |
@@ -2192,6 +2247,7 @@ void free_orinocodev(struct orinoco_private *priv) | |||
2192 | { | 2247 | { |
2193 | struct wiphy *wiphy = priv_to_wiphy(priv); | 2248 | struct wiphy *wiphy = priv_to_wiphy(priv); |
2194 | struct orinoco_rx_data *rx_data, *temp; | 2249 | struct orinoco_rx_data *rx_data, *temp; |
2250 | struct orinoco_scan_data *sd, *sdtemp; | ||
2195 | 2251 | ||
2196 | wiphy_unregister(wiphy); | 2252 | wiphy_unregister(wiphy); |
2197 | 2253 | ||
@@ -2209,13 +2265,22 @@ void free_orinocodev(struct orinoco_private *priv) | |||
2209 | kfree(rx_data); | 2265 | kfree(rx_data); |
2210 | } | 2266 | } |
2211 | 2267 | ||
2268 | cancel_work_sync(&priv->process_scan); | ||
2269 | /* Explicitly drain priv->scan_list */ | ||
2270 | list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) { | ||
2271 | list_del(&sd->list); | ||
2272 | |||
2273 | if ((sd->len > 0) && sd->buf) | ||
2274 | kfree(sd->buf); | ||
2275 | kfree(sd); | ||
2276 | } | ||
2277 | |||
2212 | orinoco_unregister_pm_notifier(priv); | 2278 | orinoco_unregister_pm_notifier(priv); |
2213 | orinoco_uncache_fw(priv); | 2279 | orinoco_uncache_fw(priv); |
2214 | 2280 | ||
2215 | priv->wpa_ie_len = 0; | 2281 | priv->wpa_ie_len = 0; |
2216 | kfree(priv->wpa_ie); | 2282 | kfree(priv->wpa_ie); |
2217 | orinoco_mic_free(priv); | 2283 | orinoco_mic_free(priv); |
2218 | orinoco_bss_data_free(priv); | ||
2219 | wiphy_free(wiphy); | 2284 | wiphy_free(wiphy); |
2220 | } | 2285 | } |
2221 | EXPORT_SYMBOL(free_orinocodev); | 2286 | EXPORT_SYMBOL(free_orinocodev); |
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h index 0c89c281e3e2..5f4f5c9eef79 100644 --- a/drivers/net/wireless/orinoco/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h | |||
@@ -48,18 +48,6 @@ typedef enum { | |||
48 | FIRMWARE_TYPE_SYMBOL | 48 | FIRMWARE_TYPE_SYMBOL |
49 | } fwtype_t; | 49 | } fwtype_t; |
50 | 50 | ||
51 | struct bss_element { | ||
52 | union hermes_scan_info bss; | ||
53 | unsigned long last_scanned; | ||
54 | struct list_head list; | ||
55 | }; | ||
56 | |||
57 | struct xbss_element { | ||
58 | struct agere_ext_scan_info bss; | ||
59 | unsigned long last_scanned; | ||
60 | struct list_head list; | ||
61 | }; | ||
62 | |||
63 | struct firmware; | 51 | struct firmware; |
64 | 52 | ||
65 | struct orinoco_private { | 53 | struct orinoco_private { |
@@ -145,12 +133,10 @@ struct orinoco_private { | |||
145 | int promiscuous, mc_count; | 133 | int promiscuous, mc_count; |
146 | 134 | ||
147 | /* Scanning support */ | 135 | /* Scanning support */ |
148 | struct list_head bss_list; | 136 | struct cfg80211_scan_request *scan_request; |
149 | struct list_head bss_free_list; | 137 | struct work_struct process_scan; |
150 | void *bss_xbss_data; | 138 | struct list_head scan_list; |
151 | 139 | spinlock_t scan_lock; /* protects the scan list */ | |
152 | int scan_inprogress; /* Scan pending... */ | ||
153 | u32 scan_mode; /* Type of scan done */ | ||
154 | 140 | ||
155 | /* WPA support */ | 141 | /* WPA support */ |
156 | u8 *wpa_ie; | 142 | u8 *wpa_ie; |
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c index 89d699d4dfe6..522eb98ec6f2 100644 --- a/drivers/net/wireless/orinoco/scan.c +++ b/drivers/net/wireless/orinoco/scan.c | |||
@@ -5,147 +5,166 @@ | |||
5 | 5 | ||
6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
7 | #include <linux/string.h> | 7 | #include <linux/string.h> |
8 | #include <linux/etherdevice.h> | 8 | #include <linux/ieee80211.h> |
9 | #include <net/cfg80211.h> | ||
9 | 10 | ||
10 | #include "hermes.h" | 11 | #include "hermes.h" |
11 | #include "orinoco.h" | 12 | #include "orinoco.h" |
13 | #include "main.h" | ||
12 | 14 | ||
13 | #include "scan.h" | 15 | #include "scan.h" |
14 | 16 | ||
15 | #define ORINOCO_MAX_BSS_COUNT 64 | 17 | #define ZERO_DBM_OFFSET 0x95 |
18 | #define MAX_SIGNAL_LEVEL 0x8A | ||
19 | #define MIN_SIGNAL_LEVEL 0x2F | ||
16 | 20 | ||
17 | #define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data) | 21 | #define SIGNAL_TO_DBM(x) \ |
18 | #define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data) | 22 | (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \ |
23 | - ZERO_DBM_OFFSET) | ||
24 | #define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100) | ||
19 | 25 | ||
20 | int orinoco_bss_data_allocate(struct orinoco_private *priv) | 26 | static int symbol_build_supp_rates(u8 *buf, const __le16 *rates) |
21 | { | 27 | { |
22 | if (priv->bss_xbss_data) | 28 | int i; |
23 | return 0; | 29 | u8 rate; |
24 | 30 | ||
25 | if (priv->has_ext_scan) | 31 | buf[0] = WLAN_EID_SUPP_RATES; |
26 | priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * | 32 | for (i = 0; i < 5; i++) { |
27 | sizeof(struct xbss_element), | 33 | rate = le16_to_cpu(rates[i]); |
28 | GFP_KERNEL); | 34 | /* NULL terminated */ |
29 | else | 35 | if (rate == 0x0) |
30 | priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT * | 36 | break; |
31 | sizeof(struct bss_element), | 37 | buf[i + 2] = rate; |
32 | GFP_KERNEL); | ||
33 | |||
34 | if (!priv->bss_xbss_data) { | ||
35 | printk(KERN_WARNING "Out of memory allocating beacons"); | ||
36 | return -ENOMEM; | ||
37 | } | 38 | } |
38 | return 0; | 39 | buf[1] = i; |
39 | } | ||
40 | 40 | ||
41 | void orinoco_bss_data_free(struct orinoco_private *priv) | 41 | return i + 2; |
42 | { | ||
43 | kfree(priv->bss_xbss_data); | ||
44 | priv->bss_xbss_data = NULL; | ||
45 | } | 42 | } |
46 | 43 | ||
47 | void orinoco_bss_data_init(struct orinoco_private *priv) | 44 | static int prism_build_supp_rates(u8 *buf, const u8 *rates) |
48 | { | 45 | { |
49 | int i; | 46 | int i; |
50 | 47 | ||
51 | INIT_LIST_HEAD(&priv->bss_free_list); | 48 | buf[0] = WLAN_EID_SUPP_RATES; |
52 | INIT_LIST_HEAD(&priv->bss_list); | 49 | for (i = 0; i < 8; i++) { |
53 | if (priv->has_ext_scan) | 50 | /* NULL terminated */ |
54 | for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) | 51 | if (rates[i] == 0x0) |
55 | list_add_tail(&(PRIV_XBSS[i].list), | 52 | break; |
56 | &priv->bss_free_list); | 53 | buf[i + 2] = rates[i]; |
57 | else | 54 | } |
58 | for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) | 55 | buf[1] = i; |
59 | list_add_tail(&(PRIV_BSS[i].list), | 56 | |
60 | &priv->bss_free_list); | 57 | /* We might still have another 2 rates, which need to go in |
61 | 58 | * extended supported rates */ | |
62 | } | 59 | if (i == 8 && rates[i] > 0) { |
63 | 60 | buf[10] = WLAN_EID_EXT_SUPP_RATES; | |
64 | void orinoco_clear_scan_results(struct orinoco_private *priv, | 61 | for (; i < 10; i++) { |
65 | unsigned long scan_age) | 62 | /* NULL terminated */ |
66 | { | 63 | if (rates[i] == 0x0) |
67 | if (priv->has_ext_scan) { | 64 | break; |
68 | struct xbss_element *bss; | 65 | buf[i + 2] = rates[i]; |
69 | struct xbss_element *tmp_bss; | ||
70 | |||
71 | /* Blow away current list of scan results */ | ||
72 | list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { | ||
73 | if (!scan_age || | ||
74 | time_after(jiffies, bss->last_scanned + scan_age)) { | ||
75 | list_move_tail(&bss->list, | ||
76 | &priv->bss_free_list); | ||
77 | /* Don't blow away ->list, just BSS data */ | ||
78 | memset(&bss->bss, 0, sizeof(bss->bss)); | ||
79 | bss->last_scanned = 0; | ||
80 | } | ||
81 | } | ||
82 | } else { | ||
83 | struct bss_element *bss; | ||
84 | struct bss_element *tmp_bss; | ||
85 | |||
86 | /* Blow away current list of scan results */ | ||
87 | list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { | ||
88 | if (!scan_age || | ||
89 | time_after(jiffies, bss->last_scanned + scan_age)) { | ||
90 | list_move_tail(&bss->list, | ||
91 | &priv->bss_free_list); | ||
92 | /* Don't blow away ->list, just BSS data */ | ||
93 | memset(&bss->bss, 0, sizeof(bss->bss)); | ||
94 | bss->last_scanned = 0; | ||
95 | } | ||
96 | } | 66 | } |
67 | buf[11] = i - 8; | ||
97 | } | 68 | } |
69 | |||
70 | return (i < 8) ? i + 2 : i + 4; | ||
98 | } | 71 | } |
99 | 72 | ||
100 | void orinoco_add_ext_scan_result(struct orinoco_private *priv, | 73 | static void orinoco_add_hostscan_result(struct orinoco_private *priv, |
101 | struct agere_ext_scan_info *atom) | 74 | const union hermes_scan_info *bss) |
102 | { | 75 | { |
103 | struct xbss_element *bss = NULL; | 76 | struct wiphy *wiphy = priv_to_wiphy(priv); |
104 | int found = 0; | 77 | struct ieee80211_channel *channel; |
105 | 78 | u8 *ie; | |
106 | /* Try to update an existing bss first */ | 79 | u8 ie_buf[46]; |
107 | list_for_each_entry(bss, &priv->bss_list, list) { | 80 | u64 timestamp; |
108 | if (compare_ether_addr(bss->bss.bssid, atom->bssid)) | 81 | s32 signal; |
109 | continue; | 82 | u16 capability; |
110 | /* ESSID lengths */ | 83 | u16 beacon_interval; |
111 | if (bss->bss.data[1] != atom->data[1]) | 84 | int ie_len; |
112 | continue; | 85 | int freq; |
113 | if (memcmp(&bss->bss.data[2], &atom->data[2], | 86 | int len; |
114 | atom->data[1])) | 87 | |
115 | continue; | 88 | len = le16_to_cpu(bss->a.essid_len); |
116 | found = 1; | 89 | |
90 | /* Reconstruct SSID and bitrate IEs to pass up */ | ||
91 | ie_buf[0] = WLAN_EID_SSID; | ||
92 | ie_buf[1] = len; | ||
93 | memcpy(&ie_buf[2], bss->a.essid, len); | ||
94 | |||
95 | ie = ie_buf + len + 2; | ||
96 | ie_len = ie_buf[1] + 2; | ||
97 | switch (priv->firmware_type) { | ||
98 | case FIRMWARE_TYPE_SYMBOL: | ||
99 | ie_len += symbol_build_supp_rates(ie, bss->s.rates); | ||
117 | break; | 100 | break; |
118 | } | ||
119 | 101 | ||
120 | /* Grab a bss off the free list */ | 102 | case FIRMWARE_TYPE_INTERSIL: |
121 | if (!found && !list_empty(&priv->bss_free_list)) { | 103 | ie_len += prism_build_supp_rates(ie, bss->p.rates); |
122 | bss = list_entry(priv->bss_free_list.next, | 104 | break; |
123 | struct xbss_element, list); | ||
124 | list_del(priv->bss_free_list.next); | ||
125 | 105 | ||
126 | list_add_tail(&bss->list, &priv->bss_list); | 106 | case FIRMWARE_TYPE_AGERE: |
107 | default: | ||
108 | break; | ||
127 | } | 109 | } |
128 | 110 | ||
129 | if (bss) { | 111 | freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel)); |
130 | /* Always update the BSS to get latest beacon info */ | 112 | channel = ieee80211_get_channel(wiphy, freq); |
131 | memcpy(&bss->bss, atom, sizeof(bss->bss)); | 113 | timestamp = 0; |
132 | bss->last_scanned = jiffies; | 114 | capability = le16_to_cpu(bss->a.capabilities); |
133 | } | 115 | beacon_interval = le16_to_cpu(bss->a.beacon_interv); |
116 | signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level)); | ||
117 | |||
118 | cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp, | ||
119 | capability, beacon_interval, ie_buf, ie_len, | ||
120 | signal, GFP_KERNEL); | ||
134 | } | 121 | } |
135 | 122 | ||
136 | int orinoco_process_scan_results(struct orinoco_private *priv, | 123 | void orinoco_add_extscan_result(struct orinoco_private *priv, |
137 | unsigned char *buf, | 124 | struct agere_ext_scan_info *bss, |
138 | int len) | 125 | size_t len) |
139 | { | 126 | { |
140 | int offset; /* In the scan data */ | 127 | struct wiphy *wiphy = priv_to_wiphy(priv); |
141 | union hermes_scan_info *atom; | 128 | struct ieee80211_channel *channel; |
142 | int atom_len; | 129 | u8 *ie; |
130 | u64 timestamp; | ||
131 | s32 signal; | ||
132 | u16 capability; | ||
133 | u16 beacon_interval; | ||
134 | size_t ie_len; | ||
135 | int chan, freq; | ||
136 | |||
137 | ie_len = len - sizeof(*bss); | ||
138 | ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS); | ||
139 | chan = ie ? ie[2] : 0; | ||
140 | freq = ieee80211_dsss_chan_to_freq(chan); | ||
141 | channel = ieee80211_get_channel(wiphy, freq); | ||
142 | |||
143 | timestamp = le64_to_cpu(bss->timestamp); | ||
144 | capability = le16_to_cpu(bss->capabilities); | ||
145 | beacon_interval = le16_to_cpu(bss->beacon_interval); | ||
146 | ie = bss->data; | ||
147 | signal = SIGNAL_TO_MBM(bss->level); | ||
148 | |||
149 | cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp, | ||
150 | capability, beacon_interval, ie, ie_len, | ||
151 | signal, GFP_KERNEL); | ||
152 | } | ||
153 | |||
154 | void orinoco_add_hostscan_results(struct orinoco_private *priv, | ||
155 | unsigned char *buf, | ||
156 | size_t len) | ||
157 | { | ||
158 | int offset; /* In the scan data */ | ||
159 | size_t atom_len; | ||
160 | bool abort = false; | ||
143 | 161 | ||
144 | switch (priv->firmware_type) { | 162 | switch (priv->firmware_type) { |
145 | case FIRMWARE_TYPE_AGERE: | 163 | case FIRMWARE_TYPE_AGERE: |
146 | atom_len = sizeof(struct agere_scan_apinfo); | 164 | atom_len = sizeof(struct agere_scan_apinfo); |
147 | offset = 0; | 165 | offset = 0; |
148 | break; | 166 | break; |
167 | |||
149 | case FIRMWARE_TYPE_SYMBOL: | 168 | case FIRMWARE_TYPE_SYMBOL: |
150 | /* Lack of documentation necessitates this hack. | 169 | /* Lack of documentation necessitates this hack. |
151 | * Different firmwares have 68 or 76 byte long atoms. | 170 | * Different firmwares have 68 or 76 byte long atoms. |
@@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv, | |||
163 | atom_len = 68; | 182 | atom_len = 68; |
164 | offset = 0; | 183 | offset = 0; |
165 | break; | 184 | break; |
185 | |||
166 | case FIRMWARE_TYPE_INTERSIL: | 186 | case FIRMWARE_TYPE_INTERSIL: |
167 | offset = 4; | 187 | offset = 4; |
168 | if (priv->has_hostscan) { | 188 | if (priv->has_hostscan) { |
@@ -172,13 +192,16 @@ int orinoco_process_scan_results(struct orinoco_private *priv, | |||
172 | printk(KERN_ERR "%s: Invalid atom_len in scan " | 192 | printk(KERN_ERR "%s: Invalid atom_len in scan " |
173 | "data: %d\n", priv->ndev->name, | 193 | "data: %d\n", priv->ndev->name, |
174 | atom_len); | 194 | atom_len); |
175 | return -EIO; | 195 | abort = true; |
196 | goto scan_abort; | ||
176 | } | 197 | } |
177 | } else | 198 | } else |
178 | atom_len = offsetof(struct prism2_scan_apinfo, atim); | 199 | atom_len = offsetof(struct prism2_scan_apinfo, atim); |
179 | break; | 200 | break; |
201 | |||
180 | default: | 202 | default: |
181 | return -EOPNOTSUPP; | 203 | abort = true; |
204 | goto scan_abort; | ||
182 | } | 205 | } |
183 | 206 | ||
184 | /* Check that we got an whole number of atoms */ | 207 | /* Check that we got an whole number of atoms */ |
@@ -186,48 +209,22 @@ int orinoco_process_scan_results(struct orinoco_private *priv, | |||
186 | printk(KERN_ERR "%s: Unexpected scan data length %d, " | 209 | printk(KERN_ERR "%s: Unexpected scan data length %d, " |
187 | "atom_len %d, offset %d\n", priv->ndev->name, len, | 210 | "atom_len %d, offset %d\n", priv->ndev->name, len, |
188 | atom_len, offset); | 211 | atom_len, offset); |
189 | return -EIO; | 212 | abort = true; |
213 | goto scan_abort; | ||
190 | } | 214 | } |
191 | 215 | ||
192 | orinoco_clear_scan_results(priv, msecs_to_jiffies(15000)); | 216 | /* Process the entries one by one */ |
193 | |||
194 | /* Read the entries one by one */ | ||
195 | for (; offset + atom_len <= len; offset += atom_len) { | 217 | for (; offset + atom_len <= len; offset += atom_len) { |
196 | int found = 0; | 218 | union hermes_scan_info *atom; |
197 | struct bss_element *bss = NULL; | ||
198 | 219 | ||
199 | /* Get next atom */ | ||
200 | atom = (union hermes_scan_info *) (buf + offset); | 220 | atom = (union hermes_scan_info *) (buf + offset); |
201 | 221 | ||
202 | /* Try to update an existing bss first */ | 222 | orinoco_add_hostscan_result(priv, atom); |
203 | list_for_each_entry(bss, &priv->bss_list, list) { | ||
204 | if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid)) | ||
205 | continue; | ||
206 | if (le16_to_cpu(bss->bss.a.essid_len) != | ||
207 | le16_to_cpu(atom->a.essid_len)) | ||
208 | continue; | ||
209 | if (memcmp(bss->bss.a.essid, atom->a.essid, | ||
210 | le16_to_cpu(atom->a.essid_len))) | ||
211 | continue; | ||
212 | found = 1; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | /* Grab a bss off the free list */ | ||
217 | if (!found && !list_empty(&priv->bss_free_list)) { | ||
218 | bss = list_entry(priv->bss_free_list.next, | ||
219 | struct bss_element, list); | ||
220 | list_del(priv->bss_free_list.next); | ||
221 | |||
222 | list_add_tail(&bss->list, &priv->bss_list); | ||
223 | } | ||
224 | |||
225 | if (bss) { | ||
226 | /* Always update the BSS to get latest beacon info */ | ||
227 | memcpy(&bss->bss, atom, sizeof(bss->bss)); | ||
228 | bss->last_scanned = jiffies; | ||
229 | } | ||
230 | } | 223 | } |
231 | 224 | ||
232 | return 0; | 225 | scan_abort: |
226 | if (priv->scan_request) { | ||
227 | cfg80211_scan_done(priv->scan_request, abort); | ||
228 | priv->scan_request = NULL; | ||
229 | } | ||
233 | } | 230 | } |
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h index f319f7466af1..2dc4e046dbdb 100644 --- a/drivers/net/wireless/orinoco/scan.h +++ b/drivers/net/wireless/orinoco/scan.h | |||
@@ -9,21 +9,12 @@ | |||
9 | struct orinoco_private; | 9 | struct orinoco_private; |
10 | struct agere_ext_scan_info; | 10 | struct agere_ext_scan_info; |
11 | 11 | ||
12 | /* Setup and free memory for scan results */ | ||
13 | int orinoco_bss_data_allocate(struct orinoco_private *priv); | ||
14 | void orinoco_bss_data_free(struct orinoco_private *priv); | ||
15 | void orinoco_bss_data_init(struct orinoco_private *priv); | ||
16 | |||
17 | /* Add scan results */ | 12 | /* Add scan results */ |
18 | void orinoco_add_ext_scan_result(struct orinoco_private *priv, | 13 | void orinoco_add_extscan_result(struct orinoco_private *priv, |
19 | struct agere_ext_scan_info *atom); | 14 | struct agere_ext_scan_info *atom, |
20 | int orinoco_process_scan_results(struct orinoco_private *dev, | 15 | size_t len); |
21 | unsigned char *buf, | 16 | void orinoco_add_hostscan_results(struct orinoco_private *dev, |
22 | int len); | 17 | unsigned char *buf, |
23 | 18 | size_t len); | |
24 | /* Clear scan results */ | ||
25 | void orinoco_clear_scan_results(struct orinoco_private *priv, | ||
26 | unsigned long scan_age); | ||
27 | |||
28 | 19 | ||
29 | #endif /* _ORINOCO_SCAN_H_ */ | 20 | #endif /* _ORINOCO_SCAN_H_ */ |
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index 9cd991a41ad4..082ea0a0cc98 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c | |||
@@ -1583,519 +1583,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev, | |||
1583 | return err; | 1583 | return err; |
1584 | } | 1584 | } |
1585 | 1585 | ||
1586 | /* Trigger a scan (look for other cells in the vicinity) */ | ||
1587 | static int orinoco_ioctl_setscan(struct net_device *dev, | ||
1588 | struct iw_request_info *info, | ||
1589 | struct iw_point *srq, | ||
1590 | char *extra) | ||
1591 | { | ||
1592 | struct orinoco_private *priv = ndev_priv(dev); | ||
1593 | hermes_t *hw = &priv->hw; | ||
1594 | struct iw_scan_req *si = (struct iw_scan_req *) extra; | ||
1595 | int err = 0; | ||
1596 | unsigned long flags; | ||
1597 | |||
1598 | /* Note : you may have realised that, as this is a SET operation, | ||
1599 | * this is privileged and therefore a normal user can't | ||
1600 | * perform scanning. | ||
1601 | * This is not an error, while the device perform scanning, | ||
1602 | * traffic doesn't flow, so it's a perfect DoS... | ||
1603 | * Jean II */ | ||
1604 | |||
1605 | if (orinoco_lock(priv, &flags) != 0) | ||
1606 | return -EBUSY; | ||
1607 | |||
1608 | /* Scanning with port 0 disabled would fail */ | ||
1609 | if (!netif_running(dev)) { | ||
1610 | err = -ENETDOWN; | ||
1611 | goto out; | ||
1612 | } | ||
1613 | |||
1614 | /* In monitor mode, the scan results are always empty. | ||
1615 | * Probe responses are passed to the driver as received | ||
1616 | * frames and could be processed in software. */ | ||
1617 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { | ||
1618 | err = -EOPNOTSUPP; | ||
1619 | goto out; | ||
1620 | } | ||
1621 | |||
1622 | /* Note : because we don't lock out the irq handler, the way | ||
1623 | * we access scan variables in priv is critical. | ||
1624 | * o scan_inprogress : not touched by irq handler | ||
1625 | * o scan_mode : not touched by irq handler | ||
1626 | * Before modifying anything on those variables, please think hard ! | ||
1627 | * Jean II */ | ||
1628 | |||
1629 | /* Save flags */ | ||
1630 | priv->scan_mode = srq->flags; | ||
1631 | |||
1632 | /* Always trigger scanning, even if it's in progress. | ||
1633 | * This way, if the info frame get lost, we will recover somewhat | ||
1634 | * gracefully - Jean II */ | ||
1635 | |||
1636 | if (priv->has_hostscan) { | ||
1637 | switch (priv->firmware_type) { | ||
1638 | case FIRMWARE_TYPE_SYMBOL: | ||
1639 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1640 | HERMES_RID_CNFHOSTSCAN_SYMBOL, | ||
1641 | HERMES_HOSTSCAN_SYMBOL_ONCE | | ||
1642 | HERMES_HOSTSCAN_SYMBOL_BCAST); | ||
1643 | break; | ||
1644 | case FIRMWARE_TYPE_INTERSIL: { | ||
1645 | __le16 req[3]; | ||
1646 | |||
1647 | req[0] = cpu_to_le16(0x3fff); /* All channels */ | ||
1648 | req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ | ||
1649 | req[2] = 0; /* Any ESSID */ | ||
1650 | err = HERMES_WRITE_RECORD(hw, USER_BAP, | ||
1651 | HERMES_RID_CNFHOSTSCAN, &req); | ||
1652 | } | ||
1653 | break; | ||
1654 | case FIRMWARE_TYPE_AGERE: | ||
1655 | if (priv->scan_mode & IW_SCAN_THIS_ESSID) { | ||
1656 | struct hermes_idstring idbuf; | ||
1657 | size_t len = min(sizeof(idbuf.val), | ||
1658 | (size_t) si->essid_len); | ||
1659 | idbuf.len = cpu_to_le16(len); | ||
1660 | memcpy(idbuf.val, si->essid, len); | ||
1661 | |||
1662 | err = hermes_write_ltv(hw, USER_BAP, | ||
1663 | HERMES_RID_CNFSCANSSID_AGERE, | ||
1664 | HERMES_BYTES_TO_RECLEN(len + 2), | ||
1665 | &idbuf); | ||
1666 | } else | ||
1667 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1668 | HERMES_RID_CNFSCANSSID_AGERE, | ||
1669 | 0); /* Any ESSID */ | ||
1670 | if (err) | ||
1671 | break; | ||
1672 | |||
1673 | if (priv->has_ext_scan) { | ||
1674 | /* Clear scan results at the start of | ||
1675 | * an extended scan */ | ||
1676 | orinoco_clear_scan_results(priv, | ||
1677 | msecs_to_jiffies(15000)); | ||
1678 | |||
1679 | /* TODO: Is this available on older firmware? | ||
1680 | * Can we use it to scan specific channels | ||
1681 | * for IW_SCAN_THIS_FREQ? */ | ||
1682 | err = hermes_write_wordrec(hw, USER_BAP, | ||
1683 | HERMES_RID_CNFSCANCHANNELS2GHZ, | ||
1684 | 0x7FFF); | ||
1685 | if (err) | ||
1686 | goto out; | ||
1687 | |||
1688 | err = hermes_inquire(hw, | ||
1689 | HERMES_INQ_CHANNELINFO); | ||
1690 | } else | ||
1691 | err = hermes_inquire(hw, HERMES_INQ_SCAN); | ||
1692 | break; | ||
1693 | } | ||
1694 | } else | ||
1695 | err = hermes_inquire(hw, HERMES_INQ_SCAN); | ||
1696 | |||
1697 | /* One more client */ | ||
1698 | if (!err) | ||
1699 | priv->scan_inprogress = 1; | ||
1700 | |||
1701 | out: | ||
1702 | orinoco_unlock(priv, &flags); | ||
1703 | return err; | ||
1704 | } | ||
1705 | |||
1706 | #define MAX_CUSTOM_LEN 64 | ||
1707 | |||
1708 | /* Translate scan data returned from the card to a card independant | ||
1709 | * format that the Wireless Tools will understand - Jean II */ | ||
1710 | static inline char *orinoco_translate_scan(struct net_device *dev, | ||
1711 | struct iw_request_info *info, | ||
1712 | char *current_ev, | ||
1713 | char *end_buf, | ||
1714 | union hermes_scan_info *bss, | ||
1715 | unsigned long last_scanned) | ||
1716 | { | ||
1717 | struct orinoco_private *priv = ndev_priv(dev); | ||
1718 | u16 capabilities; | ||
1719 | u16 channel; | ||
1720 | struct iw_event iwe; /* Temporary buffer */ | ||
1721 | char custom[MAX_CUSTOM_LEN]; | ||
1722 | |||
1723 | memset(&iwe, 0, sizeof(iwe)); | ||
1724 | |||
1725 | /* First entry *MUST* be the AP MAC address */ | ||
1726 | iwe.cmd = SIOCGIWAP; | ||
1727 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1728 | memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); | ||
1729 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1730 | &iwe, IW_EV_ADDR_LEN); | ||
1731 | |||
1732 | /* Other entries will be displayed in the order we give them */ | ||
1733 | |||
1734 | /* Add the ESSID */ | ||
1735 | iwe.u.data.length = le16_to_cpu(bss->a.essid_len); | ||
1736 | if (iwe.u.data.length > 32) | ||
1737 | iwe.u.data.length = 32; | ||
1738 | iwe.cmd = SIOCGIWESSID; | ||
1739 | iwe.u.data.flags = 1; | ||
1740 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1741 | &iwe, bss->a.essid); | ||
1742 | |||
1743 | /* Add mode */ | ||
1744 | iwe.cmd = SIOCGIWMODE; | ||
1745 | capabilities = le16_to_cpu(bss->a.capabilities); | ||
1746 | if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | ||
1747 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
1748 | iwe.u.mode = IW_MODE_MASTER; | ||
1749 | else | ||
1750 | iwe.u.mode = IW_MODE_ADHOC; | ||
1751 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1752 | &iwe, IW_EV_UINT_LEN); | ||
1753 | } | ||
1754 | |||
1755 | channel = bss->s.channel; | ||
1756 | if ((channel >= 1) && (channel <= NUM_CHANNELS)) { | ||
1757 | /* Add channel and frequency */ | ||
1758 | iwe.cmd = SIOCGIWFREQ; | ||
1759 | iwe.u.freq.m = channel; | ||
1760 | iwe.u.freq.e = 0; | ||
1761 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1762 | &iwe, IW_EV_FREQ_LEN); | ||
1763 | |||
1764 | iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; | ||
1765 | iwe.u.freq.e = 1; | ||
1766 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1767 | &iwe, IW_EV_FREQ_LEN); | ||
1768 | } | ||
1769 | |||
1770 | /* Add quality statistics. level and noise in dB. No link quality */ | ||
1771 | iwe.cmd = IWEVQUAL; | ||
1772 | iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; | ||
1773 | iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; | ||
1774 | iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; | ||
1775 | /* Wireless tools prior to 27.pre22 will show link quality | ||
1776 | * anyway, so we provide a reasonable value. */ | ||
1777 | if (iwe.u.qual.level > iwe.u.qual.noise) | ||
1778 | iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; | ||
1779 | else | ||
1780 | iwe.u.qual.qual = 0; | ||
1781 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1782 | &iwe, IW_EV_QUAL_LEN); | ||
1783 | |||
1784 | /* Add encryption capability */ | ||
1785 | iwe.cmd = SIOCGIWENCODE; | ||
1786 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
1787 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1788 | else | ||
1789 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1790 | iwe.u.data.length = 0; | ||
1791 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1792 | &iwe, NULL); | ||
1793 | |||
1794 | /* Bit rate is not available in Lucent/Agere firmwares */ | ||
1795 | if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { | ||
1796 | char *current_val = current_ev + iwe_stream_lcp_len(info); | ||
1797 | int i; | ||
1798 | int step; | ||
1799 | |||
1800 | if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) | ||
1801 | step = 2; | ||
1802 | else | ||
1803 | step = 1; | ||
1804 | |||
1805 | iwe.cmd = SIOCGIWRATE; | ||
1806 | /* Those two flags are ignored... */ | ||
1807 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
1808 | /* Max 10 values */ | ||
1809 | for (i = 0; i < 10; i += step) { | ||
1810 | /* NULL terminated */ | ||
1811 | if (bss->p.rates[i] == 0x0) | ||
1812 | break; | ||
1813 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
1814 | iwe.u.bitrate.value = | ||
1815 | ((bss->p.rates[i] & 0x7f) * 500000); | ||
1816 | current_val = iwe_stream_add_value(info, current_ev, | ||
1817 | current_val, | ||
1818 | end_buf, &iwe, | ||
1819 | IW_EV_PARAM_LEN); | ||
1820 | } | ||
1821 | /* Check if we added any event */ | ||
1822 | if ((current_val - current_ev) > iwe_stream_lcp_len(info)) | ||
1823 | current_ev = current_val; | ||
1824 | } | ||
1825 | |||
1826 | /* Beacon interval */ | ||
1827 | iwe.cmd = IWEVCUSTOM; | ||
1828 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
1829 | "bcn_int=%d", | ||
1830 | le16_to_cpu(bss->a.beacon_interv)); | ||
1831 | if (iwe.u.data.length) | ||
1832 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1833 | &iwe, custom); | ||
1834 | |||
1835 | /* Capabilites */ | ||
1836 | iwe.cmd = IWEVCUSTOM; | ||
1837 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
1838 | "capab=0x%04x", | ||
1839 | capabilities); | ||
1840 | if (iwe.u.data.length) | ||
1841 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1842 | &iwe, custom); | ||
1843 | |||
1844 | /* Add EXTRA: Age to display seconds since last beacon/probe response | ||
1845 | * for given network. */ | ||
1846 | iwe.cmd = IWEVCUSTOM; | ||
1847 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
1848 | " Last beacon: %dms ago", | ||
1849 | jiffies_to_msecs(jiffies - last_scanned)); | ||
1850 | if (iwe.u.data.length) | ||
1851 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1852 | &iwe, custom); | ||
1853 | |||
1854 | return current_ev; | ||
1855 | } | ||
1856 | |||
1857 | static inline char *orinoco_translate_ext_scan(struct net_device *dev, | ||
1858 | struct iw_request_info *info, | ||
1859 | char *current_ev, | ||
1860 | char *end_buf, | ||
1861 | struct agere_ext_scan_info *bss, | ||
1862 | unsigned long last_scanned) | ||
1863 | { | ||
1864 | u16 capabilities; | ||
1865 | u16 channel; | ||
1866 | struct iw_event iwe; /* Temporary buffer */ | ||
1867 | char custom[MAX_CUSTOM_LEN]; | ||
1868 | u8 *ie; | ||
1869 | |||
1870 | memset(&iwe, 0, sizeof(iwe)); | ||
1871 | |||
1872 | /* First entry *MUST* be the AP MAC address */ | ||
1873 | iwe.cmd = SIOCGIWAP; | ||
1874 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1875 | memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); | ||
1876 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1877 | &iwe, IW_EV_ADDR_LEN); | ||
1878 | |||
1879 | /* Other entries will be displayed in the order we give them */ | ||
1880 | |||
1881 | /* Add the ESSID */ | ||
1882 | ie = bss->data; | ||
1883 | iwe.u.data.length = ie[1]; | ||
1884 | if (iwe.u.data.length) { | ||
1885 | if (iwe.u.data.length > 32) | ||
1886 | iwe.u.data.length = 32; | ||
1887 | iwe.cmd = SIOCGIWESSID; | ||
1888 | iwe.u.data.flags = 1; | ||
1889 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1890 | &iwe, &ie[2]); | ||
1891 | } | ||
1892 | |||
1893 | /* Add mode */ | ||
1894 | capabilities = le16_to_cpu(bss->capabilities); | ||
1895 | if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | ||
1896 | iwe.cmd = SIOCGIWMODE; | ||
1897 | if (capabilities & WLAN_CAPABILITY_ESS) | ||
1898 | iwe.u.mode = IW_MODE_MASTER; | ||
1899 | else | ||
1900 | iwe.u.mode = IW_MODE_ADHOC; | ||
1901 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1902 | &iwe, IW_EV_UINT_LEN); | ||
1903 | } | ||
1904 | |||
1905 | ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); | ||
1906 | channel = ie ? ie[2] : 0; | ||
1907 | if ((channel >= 1) && (channel <= NUM_CHANNELS)) { | ||
1908 | /* Add channel and frequency */ | ||
1909 | iwe.cmd = SIOCGIWFREQ; | ||
1910 | iwe.u.freq.m = channel; | ||
1911 | iwe.u.freq.e = 0; | ||
1912 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1913 | &iwe, IW_EV_FREQ_LEN); | ||
1914 | |||
1915 | iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000; | ||
1916 | iwe.u.freq.e = 1; | ||
1917 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1918 | &iwe, IW_EV_FREQ_LEN); | ||
1919 | } | ||
1920 | |||
1921 | /* Add quality statistics. level and noise in dB. No link quality */ | ||
1922 | iwe.cmd = IWEVQUAL; | ||
1923 | iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID; | ||
1924 | iwe.u.qual.level = bss->level - 0x95; | ||
1925 | iwe.u.qual.noise = bss->noise - 0x95; | ||
1926 | /* Wireless tools prior to 27.pre22 will show link quality | ||
1927 | * anyway, so we provide a reasonable value. */ | ||
1928 | if (iwe.u.qual.level > iwe.u.qual.noise) | ||
1929 | iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; | ||
1930 | else | ||
1931 | iwe.u.qual.qual = 0; | ||
1932 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, | ||
1933 | &iwe, IW_EV_QUAL_LEN); | ||
1934 | |||
1935 | /* Add encryption capability */ | ||
1936 | iwe.cmd = SIOCGIWENCODE; | ||
1937 | if (capabilities & WLAN_CAPABILITY_PRIVACY) | ||
1938 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1939 | else | ||
1940 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1941 | iwe.u.data.length = 0; | ||
1942 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1943 | &iwe, NULL); | ||
1944 | |||
1945 | /* WPA IE */ | ||
1946 | ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data)); | ||
1947 | if (ie) { | ||
1948 | iwe.cmd = IWEVGENIE; | ||
1949 | iwe.u.data.length = ie[1] + 2; | ||
1950 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1951 | &iwe, ie); | ||
1952 | } | ||
1953 | |||
1954 | /* RSN IE */ | ||
1955 | ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); | ||
1956 | if (ie) { | ||
1957 | iwe.cmd = IWEVGENIE; | ||
1958 | iwe.u.data.length = ie[1] + 2; | ||
1959 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1960 | &iwe, ie); | ||
1961 | } | ||
1962 | |||
1963 | ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); | ||
1964 | if (ie) { | ||
1965 | char *p = current_ev + iwe_stream_lcp_len(info); | ||
1966 | int i; | ||
1967 | |||
1968 | iwe.cmd = SIOCGIWRATE; | ||
1969 | /* Those two flags are ignored... */ | ||
1970 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
1971 | |||
1972 | for (i = 2; i < (ie[1] + 2); i++) { | ||
1973 | iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000); | ||
1974 | p = iwe_stream_add_value(info, current_ev, p, end_buf, | ||
1975 | &iwe, IW_EV_PARAM_LEN); | ||
1976 | } | ||
1977 | /* Check if we added any event */ | ||
1978 | if (p > (current_ev + iwe_stream_lcp_len(info))) | ||
1979 | current_ev = p; | ||
1980 | } | ||
1981 | |||
1982 | /* Timestamp */ | ||
1983 | iwe.cmd = IWEVCUSTOM; | ||
1984 | iwe.u.data.length = | ||
1985 | snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx", | ||
1986 | (unsigned long long) le64_to_cpu(bss->timestamp)); | ||
1987 | if (iwe.u.data.length) | ||
1988 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1989 | &iwe, custom); | ||
1990 | |||
1991 | /* Beacon interval */ | ||
1992 | iwe.cmd = IWEVCUSTOM; | ||
1993 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
1994 | "bcn_int=%d", | ||
1995 | le16_to_cpu(bss->beacon_interval)); | ||
1996 | if (iwe.u.data.length) | ||
1997 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
1998 | &iwe, custom); | ||
1999 | |||
2000 | /* Capabilites */ | ||
2001 | iwe.cmd = IWEVCUSTOM; | ||
2002 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
2003 | "capab=0x%04x", | ||
2004 | capabilities); | ||
2005 | if (iwe.u.data.length) | ||
2006 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
2007 | &iwe, custom); | ||
2008 | |||
2009 | /* Add EXTRA: Age to display seconds since last beacon/probe response | ||
2010 | * for given network. */ | ||
2011 | iwe.cmd = IWEVCUSTOM; | ||
2012 | iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN, | ||
2013 | " Last beacon: %dms ago", | ||
2014 | jiffies_to_msecs(jiffies - last_scanned)); | ||
2015 | if (iwe.u.data.length) | ||
2016 | current_ev = iwe_stream_add_point(info, current_ev, end_buf, | ||
2017 | &iwe, custom); | ||
2018 | |||
2019 | return current_ev; | ||
2020 | } | ||
2021 | |||
2022 | /* Return results of a scan */ | ||
2023 | static int orinoco_ioctl_getscan(struct net_device *dev, | ||
2024 | struct iw_request_info *info, | ||
2025 | struct iw_point *srq, | ||
2026 | char *extra) | ||
2027 | { | ||
2028 | struct orinoco_private *priv = ndev_priv(dev); | ||
2029 | int err = 0; | ||
2030 | unsigned long flags; | ||
2031 | char *current_ev = extra; | ||
2032 | |||
2033 | if (orinoco_lock(priv, &flags) != 0) | ||
2034 | return -EBUSY; | ||
2035 | |||
2036 | if (priv->scan_inprogress) { | ||
2037 | /* Important note : we don't want to block the caller | ||
2038 | * until results are ready for various reasons. | ||
2039 | * First, managing wait queues is complex and racy. | ||
2040 | * Second, we grab some rtnetlink lock before comming | ||
2041 | * here (in dev_ioctl()). | ||
2042 | * Third, we generate an Wireless Event, so the | ||
2043 | * caller can wait itself on that - Jean II */ | ||
2044 | err = -EAGAIN; | ||
2045 | goto out; | ||
2046 | } | ||
2047 | |||
2048 | if (priv->has_ext_scan) { | ||
2049 | struct xbss_element *bss; | ||
2050 | |||
2051 | list_for_each_entry(bss, &priv->bss_list, list) { | ||
2052 | /* Translate this entry to WE format */ | ||
2053 | current_ev = | ||
2054 | orinoco_translate_ext_scan(dev, info, | ||
2055 | current_ev, | ||
2056 | extra + srq->length, | ||
2057 | &bss->bss, | ||
2058 | bss->last_scanned); | ||
2059 | |||
2060 | /* Check if there is space for one more entry */ | ||
2061 | if ((extra + srq->length - current_ev) | ||
2062 | <= IW_EV_ADDR_LEN) { | ||
2063 | /* Ask user space to try again with a | ||
2064 | * bigger buffer */ | ||
2065 | err = -E2BIG; | ||
2066 | goto out; | ||
2067 | } | ||
2068 | } | ||
2069 | |||
2070 | } else { | ||
2071 | struct bss_element *bss; | ||
2072 | |||
2073 | list_for_each_entry(bss, &priv->bss_list, list) { | ||
2074 | /* Translate this entry to WE format */ | ||
2075 | current_ev = orinoco_translate_scan(dev, info, | ||
2076 | current_ev, | ||
2077 | extra + srq->length, | ||
2078 | &bss->bss, | ||
2079 | bss->last_scanned); | ||
2080 | |||
2081 | /* Check if there is space for one more entry */ | ||
2082 | if ((extra + srq->length - current_ev) | ||
2083 | <= IW_EV_ADDR_LEN) { | ||
2084 | /* Ask user space to try again with a | ||
2085 | * bigger buffer */ | ||
2086 | err = -E2BIG; | ||
2087 | goto out; | ||
2088 | } | ||
2089 | } | ||
2090 | } | ||
2091 | |||
2092 | srq->length = (current_ev - extra); | ||
2093 | srq->flags = (__u16) priv->scan_mode; | ||
2094 | |||
2095 | out: | ||
2096 | orinoco_unlock(priv, &flags); | ||
2097 | return err; | ||
2098 | } | ||
2099 | 1586 | ||
2100 | /* Commit handler, called after set operations */ | 1587 | /* Commit handler, called after set operations */ |
2101 | static int orinoco_ioctl_commit(struct net_device *dev, | 1588 | static int orinoco_ioctl_commit(struct net_device *dev, |
@@ -2161,8 +1648,8 @@ static const iw_handler orinoco_handler[] = { | |||
2161 | STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), | 1648 | STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), |
2162 | STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), | 1649 | STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap), |
2163 | STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), | 1650 | STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap), |
2164 | STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan), | 1651 | STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan), |
2165 | STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan), | 1652 | STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan), |
2166 | STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), | 1653 | STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid), |
2167 | STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), | 1654 | STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid), |
2168 | STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), | 1655 | STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick), |