aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2005-06-18 19:27:56 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-06-27 00:23:55 -0400
commit95dd91fbd8d3c788ef93bc94b4b600889e04dba1 (patch)
treef9d1e9bb31856bc49d5853187b32c80f6ee79076 /drivers
parent16739b065f4b0965d975f5c756204c7aa911cd61 (diff)
[PATCH] orinoco: scanning support
Patch from Pavel Roskin
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/orinoco.c543
-rw-r--r--drivers/net/wireless/orinoco.h22
2 files changed, 544 insertions, 21 deletions
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index c057b7f9a02a..38fd8623a444 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -514,6 +514,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
514/* Internal constants */ 514/* Internal constants */
515/********************************************************************/ 515/********************************************************************/
516 516
517/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
518static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
519#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
520
517#define ORINOCO_MIN_MTU 256 521#define ORINOCO_MIN_MTU 256
518#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD) 522#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
519 523
@@ -579,25 +583,42 @@ static struct {
579/* Data types */ 583/* Data types */
580/********************************************************************/ 584/********************************************************************/
581 585
582struct header_struct { 586/* Used in Event handling.
583 /* 802.3 */ 587 * We avoid nested structres as they break on ARM -- Moustafa */
584 u8 dest[ETH_ALEN]; 588struct hermes_tx_descriptor_802_11 {
585 u8 src[ETH_ALEN]; 589 /* hermes_tx_descriptor */
586 u16 len; 590 u16 status;
587 /* 802.2 */ 591 u16 reserved1;
592 u16 reserved2;
593 u32 sw_support;
594 u8 retry_count;
595 u8 tx_rate;
596 u16 tx_control;
597
598 /* ieee802_11_hdr */
599 u16 frame_ctl;
600 u16 duration_id;
601 u8 addr1[ETH_ALEN];
602 u8 addr2[ETH_ALEN];
603 u8 addr3[ETH_ALEN];
604 u16 seq_ctl;
605 u8 addr4[ETH_ALEN];
606 u16 data_len;
607
608 /* ethhdr */
609 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
610 unsigned char h_source[ETH_ALEN]; /* source ether addr */
611 unsigned short h_proto; /* packet type ID field */
612
613 /* p8022_hdr */
588 u8 dsap; 614 u8 dsap;
589 u8 ssap; 615 u8 ssap;
590 u8 ctrl; 616 u8 ctrl;
591 /* SNAP */
592 u8 oui[3]; 617 u8 oui[3];
618
593 u16 ethertype; 619 u16 ethertype;
594} __attribute__ ((packed)); 620} __attribute__ ((packed));
595 621
596/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
597u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
598
599#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
600
601struct hermes_rx_descriptor { 622struct hermes_rx_descriptor {
602 u16 status; 623 u16 status;
603 u32 time; 624 u32 time;
@@ -958,26 +979,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
958 struct orinoco_private *priv = netdev_priv(dev); 979 struct orinoco_private *priv = netdev_priv(dev);
959 struct net_device_stats *stats = &priv->stats; 980 struct net_device_stats *stats = &priv->stats;
960 u16 fid = hermes_read_regn(hw, TXCOMPLFID); 981 u16 fid = hermes_read_regn(hw, TXCOMPLFID);
961 struct hermes_tx_descriptor desc; 982 struct hermes_tx_descriptor_802_11 hdr;
962 int err = 0; 983 int err = 0;
963 984
964 if (fid == DUMMY_FID) 985 if (fid == DUMMY_FID)
965 return; /* Nothing's really happened */ 986 return; /* Nothing's really happened */
966 987
967 err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); 988 /* Read the frame header */
989 err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
990 sizeof(struct hermes_tx_descriptor) +
991 sizeof(struct ieee80211_hdr),
992 fid, 0);
993
994 hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
995 stats->tx_errors++;
996
968 if (err) { 997 if (err) {
969 printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " 998 printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
970 "(FID=%04X error %d)\n", 999 "(FID=%04X error %d)\n",
971 dev->name, fid, err); 1000 dev->name, fid, err);
972 } else { 1001 return;
973 DEBUG(1, "%s: Tx error, status %d\n",
974 dev->name, le16_to_cpu(desc.status));
975 } 1002 }
976 1003
977 stats->tx_errors++; 1004 DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
1005 err, fid);
1006
1007 /* We produce a TXDROP event only for retry or lifetime
1008 * exceeded, because that's the only status that really mean
1009 * that this particular node went away.
1010 * Other errors means that *we* screwed up. - Jean II */
1011 hdr.status = le16_to_cpu(hdr.status);
1012 if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
1013 union iwreq_data wrqu;
1014
1015 /* Copy 802.11 dest address.
1016 * We use the 802.11 header because the frame may
1017 * not be 802.3 or may be mangled...
1018 * In Ad-Hoc mode, it will be the node address.
1019 * In managed mode, it will be most likely the AP addr
1020 * User space will figure out how to convert it to
1021 * whatever it needs (IP address or else).
1022 * - Jean II */
1023 memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
1024 wrqu.addr.sa_family = ARPHRD_ETHER;
1025
1026 /* Send event to user space */
1027 wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
1028 }
978 1029
979 netif_wake_queue(dev); 1030 netif_wake_queue(dev);
980 hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
981} 1031}
982 1032
983static void orinoco_tx_timeout(struct net_device *dev) 1033static void orinoco_tx_timeout(struct net_device *dev)
@@ -1316,6 +1366,30 @@ static void orinoco_join_ap(struct net_device *dev)
1316 orinoco_unlock(priv, &flags); 1366 orinoco_unlock(priv, &flags);
1317} 1367}
1318 1368
1369/* Send new BSSID to userspace */
1370static void orinoco_send_wevents(struct net_device *dev)
1371{
1372 struct orinoco_private *priv = netdev_priv(dev);
1373 struct hermes *hw = &priv->hw;
1374 union iwreq_data wrqu;
1375 int err;
1376 unsigned long flags;
1377
1378 if (orinoco_lock(priv, &flags) != 0)
1379 return;
1380
1381 err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
1382 ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
1383 if (err != 0)
1384 return;
1385
1386 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1387
1388 /* Send event to user space */
1389 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
1390 orinoco_unlock(priv, &flags);
1391}
1392
1319static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) 1393static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
1320{ 1394{
1321 struct orinoco_private *priv = netdev_priv(dev); 1395 struct orinoco_private *priv = netdev_priv(dev);
@@ -1395,6 +1469,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
1395 break; 1469 break;
1396 newstatus = le16_to_cpu(linkstatus.linkstatus); 1470 newstatus = le16_to_cpu(linkstatus.linkstatus);
1397 1471
1472 /* Symbol firmware uses "out of range" to signal that
1473 * the hostscan frame can be requested. */
1474 if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
1475 priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
1476 priv->has_hostscan && priv->scan_inprogress) {
1477 hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
1478 break;
1479 }
1480
1398 connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) 1481 connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
1399 || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) 1482 || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
1400 || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); 1483 || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1404,12 +1487,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
1404 else if (!ignore_disconnect) 1487 else if (!ignore_disconnect)
1405 netif_carrier_off(dev); 1488 netif_carrier_off(dev);
1406 1489
1407 if (newstatus != priv->last_linkstatus) 1490 if (newstatus != priv->last_linkstatus) {
1491 priv->last_linkstatus = newstatus;
1408 print_linkstatus(dev, newstatus); 1492 print_linkstatus(dev, newstatus);
1493 /* The info frame contains only one word which is the
1494 * status (see hermes.h). The status is pretty boring
1495 * in itself, that's why we export the new BSSID...
1496 * Jean II */
1497 schedule_work(&priv->wevent_work);
1498 }
1499 }
1500 break;
1501 case HERMES_INQ_SCAN:
1502 if (!priv->scan_inprogress && priv->bssid_fixed &&
1503 priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
1504 schedule_work(&priv->join_work);
1505 break;
1506 }
1507 /* fall through */
1508 case HERMES_INQ_HOSTSCAN:
1509 case HERMES_INQ_HOSTSCAN_SYMBOL: {
1510 /* Result of a scanning. Contains information about
1511 * cells in the vicinity - Jean II */
1512 union iwreq_data wrqu;
1513 unsigned char *buf;
1514
1515 /* Sanity check */
1516 if (len > 4096) {
1517 printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
1518 dev->name, len);
1519 break;
1520 }
1521
1522 /* We are a strict producer. If the previous scan results
1523 * have not been consumed, we just have to drop this
1524 * frame. We can't remove the previous results ourselves,
1525 * that would be *very* racy... Jean II */
1526 if (priv->scan_result != NULL) {
1527 printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
1528 break;
1529 }
1409 1530
1410 priv->last_linkstatus = newstatus; 1531 /* Allocate buffer for results */
1532 buf = kmalloc(len, GFP_ATOMIC);
1533 if (buf == NULL)
1534 /* No memory, so can't printk()... */
1535 break;
1536
1537 /* Read scan data */
1538 err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
1539 infofid, sizeof(info));
1540 if (err)
1541 break;
1542
1543#ifdef ORINOCO_DEBUG
1544 {
1545 int i;
1546 printk(KERN_DEBUG "Scan result [%02X", buf[0]);
1547 for(i = 1; i < (len * 2); i++)
1548 printk(":%02X", buf[i]);
1549 printk("]\n");
1550 }
1551#endif /* ORINOCO_DEBUG */
1552
1553 /* Allow the clients to access the results */
1554 priv->scan_len = len;
1555 priv->scan_result = buf;
1556
1557 /* Send an empty event to user space.
1558 * We don't send the received data on the event because
1559 * it would require us to do complex transcoding, and
1560 * we want to minimise the work done in the irq handler
1561 * Use a request to extract the data - Jean II */
1562 wrqu.data.length = 0;
1563 wrqu.data.flags = 0;
1564 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
1411 } 1565 }
1412 break; 1566 break;
1567 case HERMES_INQ_SEC_STAT_AGERE:
1568 /* Security status (Agere specific) */
1569 /* Ignore this frame for now */
1570 if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
1571 break;
1572 /* fall through */
1413 default: 1573 default:
1414 printk(KERN_DEBUG "%s: Unknown information frame received: " 1574 printk(KERN_DEBUG "%s: Unknown information frame received: "
1415 "type 0x%04x, length %d\n", dev->name, type, len); 1575 "type 0x%04x, length %d\n", dev->name, type, len);
@@ -2010,6 +2170,11 @@ static void orinoco_reset(struct net_device *dev)
2010 2170
2011 orinoco_unlock(priv, &flags); 2171 orinoco_unlock(priv, &flags);
2012 2172
2173 /* Scanning support: Cleanup of driver struct */
2174 kfree(priv->scan_result);
2175 priv->scan_result = NULL;
2176 priv->scan_inprogress = 0;
2177
2013 if (priv->hard_reset) { 2178 if (priv->hard_reset) {
2014 err = (*priv->hard_reset)(priv); 2179 err = (*priv->hard_reset)(priv);
2015 if (err) { 2180 if (err) {
@@ -2248,6 +2413,7 @@ static int determine_firmware(struct net_device *dev)
2248 priv->has_mwo = (firmver >= 0x60000); 2413 priv->has_mwo = (firmver >= 0x60000);
2249 priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ 2414 priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
2250 priv->ibss_port = 1; 2415 priv->ibss_port = 1;
2416 priv->has_hostscan = (firmver >= 0x8000a);
2251 2417
2252 /* Tested with Agere firmware : 2418 /* Tested with Agere firmware :
2253 * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II 2419 * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2293,6 +2459,8 @@ static int determine_firmware(struct net_device *dev)
2293 priv->ibss_port = 4; 2459 priv->ibss_port = 4;
2294 priv->broken_disableport = (firmver == 0x25013) || 2460 priv->broken_disableport = (firmver == 0x25013) ||
2295 (firmver >= 0x30000 && firmver <= 0x31000); 2461 (firmver >= 0x30000 && firmver <= 0x31000);
2462 priv->has_hostscan = (firmver >= 0x31001) ||
2463 (firmver >= 0x29057 && firmver < 0x30000);
2296 /* Tested with Intel firmware : 0x20015 => Jean II */ 2464 /* Tested with Intel firmware : 0x20015 => Jean II */
2297 /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ 2465 /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
2298 break; 2466 break;
@@ -2312,6 +2480,7 @@ static int determine_firmware(struct net_device *dev)
2312 priv->has_ibss = (firmver >= 0x000700); /* FIXME */ 2480 priv->has_ibss = (firmver >= 0x000700); /* FIXME */
2313 priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); 2481 priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
2314 priv->has_pm = (firmver >= 0x000700); 2482 priv->has_pm = (firmver >= 0x000700);
2483 priv->has_hostscan = (firmver >= 0x010301);
2315 2484
2316 if (firmver >= 0x000800) 2485 if (firmver >= 0x000800)
2317 priv->ibss_port = 0; 2486 priv->ibss_port = 0;
@@ -2539,6 +2708,7 @@ struct net_device *alloc_orinocodev(int sizeof_card,
2539 * hardware */ 2708 * hardware */
2540 INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); 2709 INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
2541 INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev); 2710 INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
2711 INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
2542 2712
2543 netif_carrier_off(dev); 2713 netif_carrier_off(dev);
2544 priv->last_linkstatus = 0xffff; 2714 priv->last_linkstatus = 0xffff;
@@ -2549,6 +2719,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
2549 2719
2550void free_orinocodev(struct net_device *dev) 2720void free_orinocodev(struct net_device *dev)
2551{ 2721{
2722 struct orinoco_private *priv = netdev_priv(dev);
2723
2724 kfree(priv->scan_result);
2552 free_netdev(dev); 2725 free_netdev(dev);
2553} 2726}
2554 2727
@@ -3967,6 +4140,332 @@ static int orinoco_ioctl_getspy(struct net_device *dev,
3967 return 0; 4140 return 0;
3968} 4141}
3969 4142
4143/* Trigger a scan (look for other cells in the vicinity */
4144static int orinoco_ioctl_setscan(struct net_device *dev,
4145 struct iw_request_info *info,
4146 struct iw_param *srq,
4147 char *extra)
4148{
4149 struct orinoco_private *priv = netdev_priv(dev);
4150 hermes_t *hw = &priv->hw;
4151 int err = 0;
4152 unsigned long flags;
4153
4154 /* Note : you may have realised that, as this is a SET operation,
4155 * this is priviledged and therefore a normal user can't
4156 * perform scanning.
4157 * This is not an error, while the device perform scanning,
4158 * traffic doesn't flow, so it's a perfect DoS...
4159 * Jean II */
4160
4161 if (orinoco_lock(priv, &flags) != 0)
4162 return -EBUSY;
4163
4164 /* Scanning with port 0 disabled would fail */
4165 if (!netif_running(dev)) {
4166 err = -ENETDOWN;
4167 goto out;
4168 }
4169
4170 /* In monitor mode, the scan results are always empty.
4171 * Probe responses are passed to the driver as received
4172 * frames and could be processed in software. */
4173 if (priv->iw_mode == IW_MODE_MONITOR) {
4174 err = -EOPNOTSUPP;
4175 goto out;
4176 }
4177
4178 /* Note : because we don't lock out the irq handler, the way
4179 * we access scan variables in priv is critical.
4180 * o scan_inprogress : not touched by irq handler
4181 * o scan_mode : not touched by irq handler
4182 * o scan_result : irq is strict producer, non-irq is strict
4183 * consumer.
4184 * o scan_len : synchronised with scan_result
4185 * Before modifying anything on those variables, please think hard !
4186 * Jean II */
4187
4188 /* If there is still some left-over scan results, get rid of it */
4189 if (priv->scan_result != NULL) {
4190 /* What's likely is that a client did crash or was killed
4191 * between triggering the scan request and reading the
4192 * results, so we need to reset everything.
4193 * Some clients that are too slow may suffer from that...
4194 * Jean II */
4195 kfree(priv->scan_result);
4196 priv->scan_result = NULL;
4197 }
4198
4199 /* Save flags */
4200 priv->scan_mode = srq->flags;
4201
4202 /* Always trigger scanning, even if it's in progress.
4203 * This way, if the info frame get lost, we will recover somewhat
4204 * gracefully - Jean II */
4205
4206 if (priv->has_hostscan) {
4207 switch (priv->firmware_type) {
4208 case FIRMWARE_TYPE_SYMBOL:
4209 err = hermes_write_wordrec(hw, USER_BAP,
4210 HERMES_RID_CNFHOSTSCAN_SYMBOL,
4211 HERMES_HOSTSCAN_SYMBOL_ONCE |
4212 HERMES_HOSTSCAN_SYMBOL_BCAST);
4213 break;
4214 case FIRMWARE_TYPE_INTERSIL: {
4215 u16 req[3];
4216
4217 req[0] = cpu_to_le16(0x3fff); /* All channels */
4218 req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
4219 req[2] = 0; /* Any ESSID */
4220 err = HERMES_WRITE_RECORD(hw, USER_BAP,
4221 HERMES_RID_CNFHOSTSCAN, &req);
4222 }
4223 break;
4224 case FIRMWARE_TYPE_AGERE:
4225 err = hermes_write_wordrec(hw, USER_BAP,
4226 HERMES_RID_CNFSCANSSID_AGERE,
4227 0); /* Any ESSID */
4228 if (err)
4229 break;
4230
4231 err = hermes_inquire(hw, HERMES_INQ_SCAN);
4232 break;
4233 }
4234 } else
4235 err = hermes_inquire(hw, HERMES_INQ_SCAN);
4236
4237 /* One more client */
4238 if (! err)
4239 priv->scan_inprogress = 1;
4240
4241 out:
4242 orinoco_unlock(priv, &flags);
4243 return err;
4244}
4245
4246/* Translate scan data returned from the card to a card independant
4247 * format that the Wireless Tools will understand - Jean II */
4248static inline int orinoco_translate_scan(struct net_device *dev,
4249 char *buffer,
4250 char *scan,
4251 int scan_len)
4252{
4253 struct orinoco_private *priv = netdev_priv(dev);
4254 int offset; /* In the scan data */
4255 union hermes_scan_info *atom;
4256 int atom_len;
4257 u16 capabilities;
4258 u16 channel;
4259 struct iw_event iwe; /* Temporary buffer */
4260 char * current_ev = buffer;
4261 char * end_buf = buffer + IW_SCAN_MAX_DATA;
4262
4263 switch (priv->firmware_type) {
4264 case FIRMWARE_TYPE_AGERE:
4265 atom_len = sizeof(struct agere_scan_apinfo);
4266 offset = 0;
4267 break;
4268 case FIRMWARE_TYPE_SYMBOL:
4269 /* Lack of documentation necessitates this hack.
4270 * Different firmwares have 68 or 76 byte long atoms.
4271 * We try modulo first. If the length divides by both,
4272 * we check what would be the channel in the second
4273 * frame for a 68-byte atom. 76-byte atoms have 0 there.
4274 * Valid channel cannot be 0. */
4275 if (scan_len % 76)
4276 atom_len = 68;
4277 else if (scan_len % 68)
4278 atom_len = 76;
4279 else if (scan_len >= 1292 && scan[68] == 0)
4280 atom_len = 76;
4281 else
4282 atom_len = 68;
4283 offset = 0;
4284 break;
4285 case FIRMWARE_TYPE_INTERSIL:
4286 offset = 4;
4287 if (priv->has_hostscan)
4288 atom_len = scan[0] + (scan[1] << 8);
4289 else
4290 atom_len = offsetof(struct prism2_scan_apinfo, atim);
4291 break;
4292 default:
4293 return 0;
4294 }
4295
4296 /* Check that we got an whole number of atoms */
4297 if ((scan_len - offset) % atom_len) {
4298 printk(KERN_ERR "%s: Unexpected scan data length %d, "
4299 "atom_len %d, offset %d\n", dev->name, scan_len,
4300 atom_len, offset);
4301 return 0;
4302 }
4303
4304 /* Read the entries one by one */
4305 for (; offset + atom_len <= scan_len; offset += atom_len) {
4306 /* Get next atom */
4307 atom = (union hermes_scan_info *) (scan + offset);
4308
4309 /* First entry *MUST* be the AP MAC address */
4310 iwe.cmd = SIOCGIWAP;
4311 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
4312 memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
4313 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
4314
4315 /* Other entries will be displayed in the order we give them */
4316
4317 /* Add the ESSID */
4318 iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
4319 if (iwe.u.data.length > 32)
4320 iwe.u.data.length = 32;
4321 iwe.cmd = SIOCGIWESSID;
4322 iwe.u.data.flags = 1;
4323 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
4324
4325 /* Add mode */
4326 iwe.cmd = SIOCGIWMODE;
4327 capabilities = le16_to_cpu(atom->a.capabilities);
4328 if (capabilities & 0x3) {
4329 if (capabilities & 0x1)
4330 iwe.u.mode = IW_MODE_MASTER;
4331 else
4332 iwe.u.mode = IW_MODE_ADHOC;
4333 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
4334 }
4335
4336 channel = atom->s.channel;
4337 if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
4338 /* Add frequency */
4339 iwe.cmd = SIOCGIWFREQ;
4340 iwe.u.freq.m = channel_frequency[channel-1] * 100000;
4341 iwe.u.freq.e = 1;
4342 current_ev = iwe_stream_add_event(current_ev, end_buf,
4343 &iwe, IW_EV_FREQ_LEN);
4344 }
4345
4346 /* Add quality statistics */
4347 iwe.cmd = IWEVQUAL;
4348 iwe.u.qual.updated = 0x10; /* no link quality */
4349 iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
4350 iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
4351 /* Wireless tools prior to 27.pre22 will show link quality
4352 * anyway, so we provide a reasonable value. */
4353 if (iwe.u.qual.level > iwe.u.qual.noise)
4354 iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
4355 else
4356 iwe.u.qual.qual = 0;
4357 current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
4358
4359 /* Add encryption capability */
4360 iwe.cmd = SIOCGIWENCODE;
4361 if (capabilities & 0x10)
4362 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4363 else
4364 iwe.u.data.flags = IW_ENCODE_DISABLED;
4365 iwe.u.data.length = 0;
4366 current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
4367
4368 /* Bit rate is not available in Lucent/Agere firmwares */
4369 if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
4370 char * current_val = current_ev + IW_EV_LCP_LEN;
4371 int i;
4372 int step;
4373
4374 if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
4375 step = 2;
4376 else
4377 step = 1;
4378
4379 iwe.cmd = SIOCGIWRATE;
4380 /* Those two flags are ignored... */
4381 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4382 /* Max 10 values */
4383 for (i = 0; i < 10; i += step) {
4384 /* NULL terminated */
4385 if (atom->p.rates[i] == 0x0)
4386 break;
4387 /* Bit rate given in 500 kb/s units (+ 0x80) */
4388 iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
4389 current_val = iwe_stream_add_value(current_ev, current_val,
4390 end_buf, &iwe,
4391 IW_EV_PARAM_LEN);
4392 }
4393 /* Check if we added any event */
4394 if ((current_val - current_ev) > IW_EV_LCP_LEN)
4395 current_ev = current_val;
4396 }
4397
4398 /* The other data in the scan result are not really
4399 * interesting, so for now drop it - Jean II */
4400 }
4401 return current_ev - buffer;
4402}
4403
4404/* Return results of a scan */
4405static int orinoco_ioctl_getscan(struct net_device *dev,
4406 struct iw_request_info *info,
4407 struct iw_point *srq,
4408 char *extra)
4409{
4410 struct orinoco_private *priv = netdev_priv(dev);
4411 int err = 0;
4412 unsigned long flags;
4413
4414 if (orinoco_lock(priv, &flags) != 0)
4415 return -EBUSY;
4416
4417 /* If no results yet, ask to try again later */
4418 if (priv->scan_result == NULL) {
4419 if (priv->scan_inprogress)
4420 /* Important note : we don't want to block the caller
4421 * until results are ready for various reasons.
4422 * First, managing wait queues is complex and racy.
4423 * Second, we grab some rtnetlink lock before comming
4424 * here (in dev_ioctl()).
4425 * Third, we generate an Wireless Event, so the
4426 * caller can wait itself on that - Jean II */
4427 err = -EAGAIN;
4428 else
4429 /* Client error, no scan results...
4430 * The caller need to restart the scan. */
4431 err = -ENODATA;
4432 } else {
4433 /* We have some results to push back to user space */
4434
4435 /* Translate to WE format */
4436 srq->length = orinoco_translate_scan(dev, extra,
4437 priv->scan_result,
4438 priv->scan_len);
4439
4440 /* Return flags */
4441 srq->flags = (__u16) priv->scan_mode;
4442
4443 /* Results are here, so scan no longer in progress */
4444 priv->scan_inprogress = 0;
4445
4446 /* In any case, Scan results will be cleaned up in the
4447 * reset function and when exiting the driver.
4448 * The person triggering the scanning may never come to
4449 * pick the results, so we need to do it in those places.
4450 * Jean II */
4451
4452#ifdef SCAN_SINGLE_READ
4453 /* If you enable this option, only one client (the first
4454 * one) will be able to read the result (and only one
4455 * time). If there is multiple concurent clients that
4456 * want to read scan results, this behavior is not
4457 * advisable - Jean II */
4458 kfree(priv->scan_result);
4459 priv->scan_result = NULL;
4460#endif /* SCAN_SINGLE_READ */
4461 /* Here, if too much time has elapsed since last scan,
4462 * we may want to clean up scan results... - Jean II */
4463 }
4464
4465 orinoco_unlock(priv, &flags);
4466 return err;
4467}
4468
3970/* Commit handler, called after set operations */ 4469/* Commit handler, called after set operations */
3971static int orinoco_ioctl_commit(struct net_device *dev, 4470static int orinoco_ioctl_commit(struct net_device *dev,
3972 struct iw_request_info *info, 4471 struct iw_request_info *info,
@@ -4060,6 +4559,8 @@ static const iw_handler orinoco_handler[] = {
4060 [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy, 4559 [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
4061 [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap, 4560 [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
4062 [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap, 4561 [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
4562 [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
4563 [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
4063 [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid, 4564 [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
4064 [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid, 4565 [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
4065 [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick, 4566 [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 329e79f6d7b1..2a6b1c09b26d 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -32,6 +32,20 @@ struct orinoco_key {
32 char data[ORINOCO_MAX_KEY_SIZE]; 32 char data[ORINOCO_MAX_KEY_SIZE];
33} __attribute__ ((packed)); 33} __attribute__ ((packed));
34 34
35struct header_struct {
36 /* 802.3 */
37 u8 dest[ETH_ALEN];
38 u8 src[ETH_ALEN];
39 u16 len;
40 /* 802.2 */
41 u8 dsap;
42 u8 ssap;
43 u8 ctrl;
44 /* SNAP */
45 u8 oui[3];
46 u16 ethertype;
47} __attribute__ ((packed));
48
35typedef enum { 49typedef enum {
36 FIRMWARE_TYPE_AGERE, 50 FIRMWARE_TYPE_AGERE,
37 FIRMWARE_TYPE_INTERSIL, 51 FIRMWARE_TYPE_INTERSIL,
@@ -51,6 +65,7 @@ struct orinoco_private {
51 int open; 65 int open;
52 u16 last_linkstatus; 66 u16 last_linkstatus;
53 struct work_struct join_work; 67 struct work_struct join_work;
68 struct work_struct wevent_work;
54 69
55 /* Net device stuff */ 70 /* Net device stuff */
56 struct net_device *ndev; 71 struct net_device *ndev;
@@ -77,6 +92,7 @@ struct orinoco_private {
77 unsigned int has_pm:1; 92 unsigned int has_pm:1;
78 unsigned int has_preamble:1; 93 unsigned int has_preamble:1;
79 unsigned int has_sensitivity:1; 94 unsigned int has_sensitivity:1;
95 unsigned int has_hostscan:1;
80 unsigned int broken_disableport:1; 96 unsigned int broken_disableport:1;
81 97
82 /* Configuration paramaters */ 98 /* Configuration paramaters */
@@ -103,6 +119,12 @@ struct orinoco_private {
103 /* Configuration dependent variables */ 119 /* Configuration dependent variables */
104 int port_type, createibss; 120 int port_type, createibss;
105 int promiscuous, mc_count; 121 int promiscuous, mc_count;
122
123 /* Scanning support */
124 int scan_inprogress; /* Scan pending... */
125 u32 scan_mode; /* Type of scan done */
126 char * scan_result; /* Result of previous scan */
127 int scan_len; /* Lenght of result */
106}; 128};
107 129
108#ifdef ORINOCO_DEBUG 130#ifdef ORINOCO_DEBUG