aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Kilroy <kilroyd@googlemail.com>2009-06-18 18:21:33 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:46 -0400
commitc63cdbe8f80487c372fe0dfe460ed30467029f01 (patch)
treea981d5b052fc74b5f894775353a3e6e96591a1c7
parent5217c571c898371c540e49671600d54346b2e123 (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.c20
-rw-r--r--drivers/net/wireless/orinoco/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco/hw.c85
-rw-r--r--drivers/net/wireless/orinoco/hw.h3
-rw-r--r--drivers/net/wireless/orinoco/main.c167
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h22
-rw-r--r--drivers/net/wireless/orinoco/scan.c285
-rw-r--r--drivers/net/wireless/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/orinoco/wext.c517
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
140static 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
140const struct cfg80211_ops orinoco_cfg_ops = { 159const 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
1161int 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,
47int orinoco_hw_get_freq(struct orinoco_private *priv); 48int orinoco_hw_get_freq(struct orinoco_private *priv);
48int orinoco_hw_get_bitratelist(struct orinoco_private *priv, 49int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
49 int *numrates, s32 *rates, int max); 50 int *numrates, s32 *rates, int max);
51int 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
209struct 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
1275static 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
1293static 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
1308static 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
1268static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) 1347static 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
1511static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) 1566static 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}
2221EXPORT_SYMBOL(free_orinocodev); 2286EXPORT_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
51struct bss_element {
52 union hermes_scan_info bss;
53 unsigned long last_scanned;
54 struct list_head list;
55};
56
57struct xbss_element {
58 struct agere_ext_scan_info bss;
59 unsigned long last_scanned;
60 struct list_head list;
61};
62
63struct firmware; 51struct firmware;
64 52
65struct orinoco_private { 53struct 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
20int orinoco_bss_data_allocate(struct orinoco_private *priv) 26static 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
41void 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
47void orinoco_bss_data_init(struct orinoco_private *priv) 44static 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;
64void 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
100void orinoco_add_ext_scan_result(struct orinoco_private *priv, 73static 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
136int orinoco_process_scan_results(struct orinoco_private *priv, 123void 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
154void 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 @@
9struct orinoco_private; 9struct orinoco_private;
10struct agere_ext_scan_info; 10struct agere_ext_scan_info;
11 11
12/* Setup and free memory for scan results */
13int orinoco_bss_data_allocate(struct orinoco_private *priv);
14void orinoco_bss_data_free(struct orinoco_private *priv);
15void orinoco_bss_data_init(struct orinoco_private *priv);
16
17/* Add scan results */ 12/* Add scan results */
18void orinoco_add_ext_scan_result(struct orinoco_private *priv, 13void orinoco_add_extscan_result(struct orinoco_private *priv,
19 struct agere_ext_scan_info *atom); 14 struct agere_ext_scan_info *atom,
20int orinoco_process_scan_results(struct orinoco_private *dev, 15 size_t len);
21 unsigned char *buf, 16void orinoco_add_hostscan_results(struct orinoco_private *dev,
22 int len); 17 unsigned char *buf,
23 18 size_t len);
24/* Clear scan results */
25void 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) */
1587static 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 */
1710static 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
1857static 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 */
2023static 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
2095out:
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 */
2101static int orinoco_ioctl_commit(struct net_device *dev, 1588static 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),