Loading drivers/net/wireless/orinoco.c +522 −21 Original line number Diff line number Diff line Loading @@ -514,6 +514,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer /* Internal constants */ /********************************************************************/ /* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) #define ORINOCO_MIN_MTU 256 #define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD) Loading Loading @@ -579,25 +583,42 @@ static struct { /* Data types */ /********************************************************************/ struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ /* Used in Event handling. * We avoid nested structres as they break on ARM -- Moustafa */ struct hermes_tx_descriptor_802_11 { /* hermes_tx_descriptor */ u16 status; u16 reserved1; u16 reserved2; u32 sw_support; u8 retry_count; u8 tx_rate; u16 tx_control; /* ieee802_11_hdr */ u16 frame_ctl; u16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; u16 seq_ctl; u8 addr4[ETH_ALEN]; u16 data_len; /* ethhdr */ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ unsigned short h_proto; /* packet type ID field */ /* p8022_hdr */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype; } __attribute__ ((packed)); /* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) struct hermes_rx_descriptor { u16 status; u32 time; Loading Loading @@ -958,26 +979,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; struct hermes_tx_descriptor_802_11 hdr; int err = 0; if (fid == DUMMY_FID) return; /* Nothing's really happened */ err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); /* Read the frame header */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(struct hermes_tx_descriptor) + sizeof(struct ieee80211_hdr), fid, 0); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); stats->tx_errors++; if (err) { printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " "(FID=%04X error %d)\n", dev->name, fid, err); } else { DEBUG(1, "%s: Tx error, status %d\n", dev->name, le16_to_cpu(desc.status)); return; } stats->tx_errors++; DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, err, fid); /* We produce a TXDROP event only for retry or lifetime * exceeded, because that's the only status that really mean * that this particular node went away. * Other errors means that *we* screwed up. - Jean II */ hdr.status = le16_to_cpu(hdr.status); if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { union iwreq_data wrqu; /* Copy 802.11 dest address. * We use the 802.11 header because the frame may * not be 802.3 or may be mangled... * In Ad-Hoc mode, it will be the node address. * In managed mode, it will be most likely the AP addr * User space will figure out how to convert it to * whatever it needs (IP address or else). * - Jean II */ memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); wrqu.addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); } netif_wake_queue(dev); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } static void orinoco_tx_timeout(struct net_device *dev) Loading Loading @@ -1316,6 +1366,30 @@ static void orinoco_join_ap(struct net_device *dev) orinoco_unlock(priv, &flags); } /* Send new BSSID to userspace */ static void orinoco_send_wevents(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; union iwreq_data wrqu; int err; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) return; err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) return; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); orinoco_unlock(priv, &flags); } static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = netdev_priv(dev); Loading Loading @@ -1395,6 +1469,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) break; newstatus = le16_to_cpu(linkstatus.linkstatus); /* Symbol firmware uses "out of range" to signal that * the hostscan frame can be requested. */ if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && priv->firmware_type == FIRMWARE_TYPE_SYMBOL && priv->has_hostscan && priv->scan_inprogress) { hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); break; } connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); Loading @@ -1404,12 +1487,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) else if (!ignore_disconnect) netif_carrier_off(dev); if (newstatus != priv->last_linkstatus) if (newstatus != priv->last_linkstatus) { priv->last_linkstatus = newstatus; print_linkstatus(dev, newstatus); /* The info frame contains only one word which is the * status (see hermes.h). The status is pretty boring * in itself, that's why we export the new BSSID... * Jean II */ schedule_work(&priv->wevent_work); } } break; case HERMES_INQ_SCAN: if (!priv->scan_inprogress && priv->bssid_fixed && priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { schedule_work(&priv->join_work); break; } /* fall through */ case HERMES_INQ_HOSTSCAN: case HERMES_INQ_HOSTSCAN_SYMBOL: { /* Result of a scanning. Contains information about * cells in the vicinity - Jean II */ union iwreq_data wrqu; unsigned char *buf; /* Sanity check */ if (len > 4096) { printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", dev->name, len); break; } priv->last_linkstatus = newstatus; /* We are a strict producer. If the previous scan results * have not been consumed, we just have to drop this * frame. We can't remove the previous results ourselves, * that would be *very* racy... Jean II */ if (priv->scan_result != NULL) { printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name); break; } /* Allocate buffer for results */ buf = kmalloc(len, GFP_ATOMIC); if (buf == NULL) /* No memory, so can't printk()... */ break; /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, infofid, sizeof(info)); if (err) break; #ifdef ORINOCO_DEBUG { int i; printk(KERN_DEBUG "Scan result [%02X", buf[0]); for(i = 1; i < (len * 2); i++) printk(":%02X", buf[i]); printk("]\n"); } #endif /* ORINOCO_DEBUG */ /* Allow the clients to access the results */ priv->scan_len = len; priv->scan_result = buf; /* Send an empty event to user space. * We don't send the received data on the event because * it would require us to do complex transcoding, and * we want to minimise the work done in the irq handler * Use a request to extract the data - Jean II */ wrqu.data.length = 0; wrqu.data.flags = 0; wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); } break; case HERMES_INQ_SEC_STAT_AGERE: /* Security status (Agere specific) */ /* Ignore this frame for now */ if (priv->firmware_type == FIRMWARE_TYPE_AGERE) break; /* fall through */ default: printk(KERN_DEBUG "%s: Unknown information frame received: " "type 0x%04x, length %d\n", dev->name, type, len); Loading Loading @@ -2010,6 +2170,11 @@ static void orinoco_reset(struct net_device *dev) orinoco_unlock(priv, &flags); /* Scanning support: Cleanup of driver struct */ kfree(priv->scan_result); priv->scan_result = NULL; priv->scan_inprogress = 0; if (priv->hard_reset) { err = (*priv->hard_reset)(priv); if (err) { Loading Loading @@ -2248,6 +2413,7 @@ static int determine_firmware(struct net_device *dev) priv->has_mwo = (firmver >= 0x60000); priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->ibss_port = 1; priv->has_hostscan = (firmver >= 0x8000a); /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II Loading Loading @@ -2293,6 +2459,8 @@ static int determine_firmware(struct net_device *dev) priv->ibss_port = 4; priv->broken_disableport = (firmver == 0x25013) || (firmver >= 0x30000 && firmver <= 0x31000); priv->has_hostscan = (firmver >= 0x31001) || (firmver >= 0x29057 && firmver < 0x30000); /* Tested with Intel firmware : 0x20015 => Jean II */ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ break; Loading @@ -2312,6 +2480,7 @@ static int determine_firmware(struct net_device *dev) priv->has_ibss = (firmver >= 0x000700); /* FIXME */ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); priv->has_pm = (firmver >= 0x000700); priv->has_hostscan = (firmver >= 0x010301); if (firmver >= 0x000800) priv->ibss_port = 0; Loading Loading @@ -2539,6 +2708,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, * hardware */ INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev); INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev); netif_carrier_off(dev); priv->last_linkstatus = 0xffff; Loading @@ -2549,6 +2719,9 @@ struct net_device *alloc_orinocodev(int sizeof_card, void free_orinocodev(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); kfree(priv->scan_result); free_netdev(dev); } Loading Loading @@ -3967,6 +4140,332 @@ static int orinoco_ioctl_getspy(struct net_device *dev, return 0; } /* Trigger a scan (look for other cells in the vicinity */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, struct iw_param *srq, char *extra) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; unsigned long flags; /* Note : you may have realised that, as this is a SET operation, * this is priviledged and therefore a normal user can't * perform scanning. * This is not an error, while the device perform scanning, * traffic doesn't flow, so it's a perfect DoS... * Jean II */ if (orinoco_lock(priv, &flags) != 0) return -EBUSY; /* Scanning with port 0 disabled would fail */ if (!netif_running(dev)) { err = -ENETDOWN; goto out; } /* In monitor mode, the scan results are always empty. * Probe responses are passed to the driver as received * frames and could be processed in software. */ if (priv->iw_mode == IW_MODE_MONITOR) { err = -EOPNOTSUPP; goto out; } /* Note : because we don't lock out the irq handler, the way * we access scan variables in priv is critical. * o scan_inprogress : not touched by irq handler * o scan_mode : not touched by irq handler * o scan_result : irq is strict producer, non-irq is strict * consumer. * o scan_len : synchronised with scan_result * Before modifying anything on those variables, please think hard ! * Jean II */ /* If there is still some left-over scan results, get rid of it */ if (priv->scan_result != NULL) { /* What's likely is that a client did crash or was killed * between triggering the scan request and reading the * results, so we need to reset everything. * Some clients that are too slow may suffer from that... * Jean II */ kfree(priv->scan_result); priv->scan_result = NULL; } /* Save flags */ priv->scan_mode = srq->flags; /* Always trigger scanning, even if it's in progress. * This way, if the info frame get lost, we will recover somewhat * gracefully - Jean II */ if (priv->has_hostscan) { switch (priv->firmware_type) { case FIRMWARE_TYPE_SYMBOL: err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFHOSTSCAN_SYMBOL, HERMES_HOSTSCAN_SYMBOL_ONCE | HERMES_HOSTSCAN_SYMBOL_BCAST); break; case FIRMWARE_TYPE_INTERSIL: { u16 req[3]; req[0] = cpu_to_le16(0x3fff); /* All channels */ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ req[2] = 0; /* Any ESSID */ err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFHOSTSCAN, &req); } break; case FIRMWARE_TYPE_AGERE: err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSCANSSID_AGERE, 0); /* Any ESSID */ if (err) break; err = hermes_inquire(hw, HERMES_INQ_SCAN); break; } } else err = hermes_inquire(hw, HERMES_INQ_SCAN); /* One more client */ if (! err) priv->scan_inprogress = 1; out: orinoco_unlock(priv, &flags); return err; } /* Translate scan data returned from the card to a card independant * format that the Wireless Tools will understand - Jean II */ static inline int orinoco_translate_scan(struct net_device *dev, char *buffer, char *scan, int scan_len) { struct orinoco_private *priv = netdev_priv(dev); int offset; /* In the scan data */ union hermes_scan_info *atom; int atom_len; u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ char * current_ev = buffer; char * end_buf = buffer + IW_SCAN_MAX_DATA; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: atom_len = sizeof(struct agere_scan_apinfo); offset = 0; break; case FIRMWARE_TYPE_SYMBOL: /* Lack of documentation necessitates this hack. * Different firmwares have 68 or 76 byte long atoms. * We try modulo first. If the length divides by both, * we check what would be the channel in the second * frame for a 68-byte atom. 76-byte atoms have 0 there. * Valid channel cannot be 0. */ if (scan_len % 76) atom_len = 68; else if (scan_len % 68) atom_len = 76; else if (scan_len >= 1292 && scan[68] == 0) atom_len = 76; else atom_len = 68; offset = 0; break; case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) atom_len = scan[0] + (scan[1] << 8); else atom_len = offsetof(struct prism2_scan_apinfo, atim); break; default: return 0; } /* Check that we got an whole number of atoms */ if ((scan_len - offset) % atom_len) { printk(KERN_ERR "%s: Unexpected scan data length %d, " "atom_len %d, offset %d\n", dev->name, scan_len, atom_len, offset); return 0; } /* Read the entries one by one */ for (; offset + atom_len <= scan_len; offset += atom_len) { /* Get next atom */ atom = (union hermes_scan_info *) (scan + offset); /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ /* Add the ESSID */ iwe.u.data.length = le16_to_cpu(atom->a.essid_len); if (iwe.u.data.length > 32) iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); /* Add mode */ iwe.cmd = SIOCGIWMODE; capabilities = le16_to_cpu(atom->a.capabilities); if (capabilities & 0x3) { if (capabilities & 0x1) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } channel = atom->s.channel; if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) { /* Add frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = channel_frequency[channel-1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.updated = 0x10; /* no link quality */ iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95; iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95; /* Wireless tools prior to 27.pre22 will show link quality * anyway, so we provide a reasonable value. */ if (iwe.u.qual.level > iwe.u.qual.noise) iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; else iwe.u.qual.qual = 0; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; if (capabilities & 0x10) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); /* Bit rate is not available in Lucent/Agere firmwares */ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { char * current_val = current_ev + IW_EV_LCP_LEN; int i; int step; if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) step = 2; else step = 1; iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; /* Max 10 values */ for (i = 0; i < 10; i += step) { /* NULL terminated */ if (atom->p.rates[i] == 0x0) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000); current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ if ((current_val - current_ev) > IW_EV_LCP_LEN) current_ev = current_val; } /* The other data in the scan result are not really * interesting, so for now drop it - Jean II */ } return current_ev - buffer; } /* Return results of a scan */ static int orinoco_ioctl_getscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { struct orinoco_private *priv = netdev_priv(dev); int err = 0; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; /* If no results yet, ask to try again later */ if (priv->scan_result == NULL) { if (priv->scan_inprogress) /* Important note : we don't want to block the caller * until results are ready for various reasons. * First, managing wait queues is complex and racy. * Second, we grab some rtnetlink lock before comming * here (in dev_ioctl()). * Third, we generate an Wireless Event, so the * caller can wait itself on that - Jean II */ err = -EAGAIN; else /* Client error, no scan results... * The caller need to restart the scan. */ err = -ENODATA; } else { /* We have some results to push back to user space */ /* Translate to WE format */ srq->length = orinoco_translate_scan(dev, extra, priv->scan_result, priv->scan_len); /* Return flags */ srq->flags = (__u16) priv->scan_mode; /* Results are here, so scan no longer in progress */ priv->scan_inprogress = 0; /* In any case, Scan results will be cleaned up in the * reset function and when exiting the driver. * The person triggering the scanning may never come to * pick the results, so we need to do it in those places. * Jean II */ #ifdef SCAN_SINGLE_READ /* If you enable this option, only one client (the first * one) will be able to read the result (and only one * time). If there is multiple concurent clients that * want to read scan results, this behavior is not * advisable - Jean II */ kfree(priv->scan_result); priv->scan_result = NULL; #endif /* SCAN_SINGLE_READ */ /* Here, if too much time has elapsed since last scan, * we may want to clean up scan results... - Jean II */ } orinoco_unlock(priv, &flags); return err; } /* Commit handler, called after set operations */ static int orinoco_ioctl_commit(struct net_device *dev, struct iw_request_info *info, Loading Loading @@ -4060,6 +4559,8 @@ static const iw_handler orinoco_handler[] = { [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy, [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap, [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap, [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan, [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan, [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid, [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid, [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick, Loading drivers/net/wireless/orinoco.h +22 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,20 @@ struct orinoco_key { char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype; } __attribute__ ((packed)); typedef enum { FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_INTERSIL, Loading @@ -51,6 +65,7 @@ struct orinoco_private { int open; u16 last_linkstatus; struct work_struct join_work; struct work_struct wevent_work; /* Net device stuff */ struct net_device *ndev; Loading @@ -77,6 +92,7 @@ struct orinoco_private { unsigned int has_pm:1; unsigned int has_preamble:1; unsigned int has_sensitivity:1; unsigned int has_hostscan:1; unsigned int broken_disableport:1; /* Configuration paramaters */ Loading @@ -103,6 +119,12 @@ struct orinoco_private { /* Configuration dependent variables */ int port_type, createibss; int promiscuous, mc_count; /* Scanning support */ int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ char * scan_result; /* Result of previous scan */ int scan_len; /* Lenght of result */ }; #ifdef ORINOCO_DEBUG Loading Loading
drivers/net/wireless/orinoco.c +522 −21 Original line number Diff line number Diff line Loading @@ -514,6 +514,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer /* Internal constants */ /********************************************************************/ /* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) #define ORINOCO_MIN_MTU 256 #define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD) Loading Loading @@ -579,25 +583,42 @@ static struct { /* Data types */ /********************************************************************/ struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ /* Used in Event handling. * We avoid nested structres as they break on ARM -- Moustafa */ struct hermes_tx_descriptor_802_11 { /* hermes_tx_descriptor */ u16 status; u16 reserved1; u16 reserved2; u32 sw_support; u8 retry_count; u8 tx_rate; u16 tx_control; /* ieee802_11_hdr */ u16 frame_ctl; u16 duration_id; u8 addr1[ETH_ALEN]; u8 addr2[ETH_ALEN]; u8 addr3[ETH_ALEN]; u16 seq_ctl; u8 addr4[ETH_ALEN]; u16 data_len; /* ethhdr */ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ unsigned short h_proto; /* packet type ID field */ /* p8022_hdr */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype; } __attribute__ ((packed)); /* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */ u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) struct hermes_rx_descriptor { u16 status; u32 time; Loading Loading @@ -958,26 +979,55 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; struct hermes_tx_descriptor_802_11 hdr; int err = 0; if (fid == DUMMY_FID) return; /* Nothing's really happened */ err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); /* Read the frame header */ err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(struct hermes_tx_descriptor) + sizeof(struct ieee80211_hdr), fid, 0); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); stats->tx_errors++; if (err) { printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " "(FID=%04X error %d)\n", dev->name, fid, err); } else { DEBUG(1, "%s: Tx error, status %d\n", dev->name, le16_to_cpu(desc.status)); return; } stats->tx_errors++; DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name, err, fid); /* We produce a TXDROP event only for retry or lifetime * exceeded, because that's the only status that really mean * that this particular node went away. * Other errors means that *we* screwed up. - Jean II */ hdr.status = le16_to_cpu(hdr.status); if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) { union iwreq_data wrqu; /* Copy 802.11 dest address. * We use the 802.11 header because the frame may * not be 802.3 or may be mangled... * In Ad-Hoc mode, it will be the node address. * In managed mode, it will be most likely the AP addr * User space will figure out how to convert it to * whatever it needs (IP address or else). * - Jean II */ memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN); wrqu.addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL); } netif_wake_queue(dev); hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } static void orinoco_tx_timeout(struct net_device *dev) Loading Loading @@ -1316,6 +1366,30 @@ static void orinoco_join_ap(struct net_device *dev) orinoco_unlock(priv, &flags); } /* Send new BSSID to userspace */ static void orinoco_send_wevents(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; union iwreq_data wrqu; int err; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) return; err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) return; wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); orinoco_unlock(priv, &flags); } static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = netdev_priv(dev); Loading Loading @@ -1395,6 +1469,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) break; newstatus = le16_to_cpu(linkstatus.linkstatus); /* Symbol firmware uses "out of range" to signal that * the hostscan frame can be requested. */ if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE && priv->firmware_type == FIRMWARE_TYPE_SYMBOL && priv->has_hostscan && priv->scan_inprogress) { hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL); break; } connected = (newstatus == HERMES_LINKSTATUS_CONNECTED) || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE); Loading @@ -1404,12 +1487,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) else if (!ignore_disconnect) netif_carrier_off(dev); if (newstatus != priv->last_linkstatus) if (newstatus != priv->last_linkstatus) { priv->last_linkstatus = newstatus; print_linkstatus(dev, newstatus); /* The info frame contains only one word which is the * status (see hermes.h). The status is pretty boring * in itself, that's why we export the new BSSID... * Jean II */ schedule_work(&priv->wevent_work); } } break; case HERMES_INQ_SCAN: if (!priv->scan_inprogress && priv->bssid_fixed && priv->firmware_type == FIRMWARE_TYPE_INTERSIL) { schedule_work(&priv->join_work); break; } /* fall through */ case HERMES_INQ_HOSTSCAN: case HERMES_INQ_HOSTSCAN_SYMBOL: { /* Result of a scanning. Contains information about * cells in the vicinity - Jean II */ union iwreq_data wrqu; unsigned char *buf; /* Sanity check */ if (len > 4096) { printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", dev->name, len); break; } priv->last_linkstatus = newstatus; /* We are a strict producer. If the previous scan results * have not been consumed, we just have to drop this * frame. We can't remove the previous results ourselves, * that would be *very* racy... Jean II */ if (priv->scan_result != NULL) { printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name); break; } /* Allocate buffer for results */ buf = kmalloc(len, GFP_ATOMIC); if (buf == NULL) /* No memory, so can't printk()... */ break; /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, infofid, sizeof(info)); if (err) break; #ifdef ORINOCO_DEBUG { int i; printk(KERN_DEBUG "Scan result [%02X", buf[0]); for(i = 1; i < (len * 2); i++) printk(":%02X", buf[i]); printk("]\n"); } #endif /* ORINOCO_DEBUG */ /* Allow the clients to access the results */ priv->scan_len = len; priv->scan_result = buf; /* Send an empty event to user space. * We don't send the received data on the event because * it would require us to do complex transcoding, and * we want to minimise the work done in the irq handler * Use a request to extract the data - Jean II */ wrqu.data.length = 0; wrqu.data.flags = 0; wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); } break; case HERMES_INQ_SEC_STAT_AGERE: /* Security status (Agere specific) */ /* Ignore this frame for now */ if (priv->firmware_type == FIRMWARE_TYPE_AGERE) break; /* fall through */ default: printk(KERN_DEBUG "%s: Unknown information frame received: " "type 0x%04x, length %d\n", dev->name, type, len); Loading Loading @@ -2010,6 +2170,11 @@ static void orinoco_reset(struct net_device *dev) orinoco_unlock(priv, &flags); /* Scanning support: Cleanup of driver struct */ kfree(priv->scan_result); priv->scan_result = NULL; priv->scan_inprogress = 0; if (priv->hard_reset) { err = (*priv->hard_reset)(priv); if (err) { Loading Loading @@ -2248,6 +2413,7 @@ static int determine_firmware(struct net_device *dev) priv->has_mwo = (firmver >= 0x60000); priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ priv->ibss_port = 1; priv->has_hostscan = (firmver >= 0x8000a); /* Tested with Agere firmware : * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II Loading Loading @@ -2293,6 +2459,8 @@ static int determine_firmware(struct net_device *dev) priv->ibss_port = 4; priv->broken_disableport = (firmver == 0x25013) || (firmver >= 0x30000 && firmver <= 0x31000); priv->has_hostscan = (firmver >= 0x31001) || (firmver >= 0x29057 && firmver < 0x30000); /* Tested with Intel firmware : 0x20015 => Jean II */ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */ break; Loading @@ -2312,6 +2480,7 @@ static int determine_firmware(struct net_device *dev) priv->has_ibss = (firmver >= 0x000700); /* FIXME */ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800); priv->has_pm = (firmver >= 0x000700); priv->has_hostscan = (firmver >= 0x010301); if (firmver >= 0x000800) priv->ibss_port = 0; Loading Loading @@ -2539,6 +2708,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, * hardware */ INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev); INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev); netif_carrier_off(dev); priv->last_linkstatus = 0xffff; Loading @@ -2549,6 +2719,9 @@ struct net_device *alloc_orinocodev(int sizeof_card, void free_orinocodev(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); kfree(priv->scan_result); free_netdev(dev); } Loading Loading @@ -3967,6 +4140,332 @@ static int orinoco_ioctl_getspy(struct net_device *dev, return 0; } /* Trigger a scan (look for other cells in the vicinity */ static int orinoco_ioctl_setscan(struct net_device *dev, struct iw_request_info *info, struct iw_param *srq, char *extra) { struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; unsigned long flags; /* Note : you may have realised that, as this is a SET operation, * this is priviledged and therefore a normal user can't * perform scanning. * This is not an error, while the device perform scanning, * traffic doesn't flow, so it's a perfect DoS... * Jean II */ if (orinoco_lock(priv, &flags) != 0) return -EBUSY; /* Scanning with port 0 disabled would fail */ if (!netif_running(dev)) { err = -ENETDOWN; goto out; } /* In monitor mode, the scan results are always empty. * Probe responses are passed to the driver as received * frames and could be processed in software. */ if (priv->iw_mode == IW_MODE_MONITOR) { err = -EOPNOTSUPP; goto out; } /* Note : because we don't lock out the irq handler, the way * we access scan variables in priv is critical. * o scan_inprogress : not touched by irq handler * o scan_mode : not touched by irq handler * o scan_result : irq is strict producer, non-irq is strict * consumer. * o scan_len : synchronised with scan_result * Before modifying anything on those variables, please think hard ! * Jean II */ /* If there is still some left-over scan results, get rid of it */ if (priv->scan_result != NULL) { /* What's likely is that a client did crash or was killed * between triggering the scan request and reading the * results, so we need to reset everything. * Some clients that are too slow may suffer from that... * Jean II */ kfree(priv->scan_result); priv->scan_result = NULL; } /* Save flags */ priv->scan_mode = srq->flags; /* Always trigger scanning, even if it's in progress. * This way, if the info frame get lost, we will recover somewhat * gracefully - Jean II */ if (priv->has_hostscan) { switch (priv->firmware_type) { case FIRMWARE_TYPE_SYMBOL: err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFHOSTSCAN_SYMBOL, HERMES_HOSTSCAN_SYMBOL_ONCE | HERMES_HOSTSCAN_SYMBOL_BCAST); break; case FIRMWARE_TYPE_INTERSIL: { u16 req[3]; req[0] = cpu_to_le16(0x3fff); /* All channels */ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */ req[2] = 0; /* Any ESSID */ err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFHOSTSCAN, &req); } break; case FIRMWARE_TYPE_AGERE: err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSCANSSID_AGERE, 0); /* Any ESSID */ if (err) break; err = hermes_inquire(hw, HERMES_INQ_SCAN); break; } } else err = hermes_inquire(hw, HERMES_INQ_SCAN); /* One more client */ if (! err) priv->scan_inprogress = 1; out: orinoco_unlock(priv, &flags); return err; } /* Translate scan data returned from the card to a card independant * format that the Wireless Tools will understand - Jean II */ static inline int orinoco_translate_scan(struct net_device *dev, char *buffer, char *scan, int scan_len) { struct orinoco_private *priv = netdev_priv(dev); int offset; /* In the scan data */ union hermes_scan_info *atom; int atom_len; u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ char * current_ev = buffer; char * end_buf = buffer + IW_SCAN_MAX_DATA; switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: atom_len = sizeof(struct agere_scan_apinfo); offset = 0; break; case FIRMWARE_TYPE_SYMBOL: /* Lack of documentation necessitates this hack. * Different firmwares have 68 or 76 byte long atoms. * We try modulo first. If the length divides by both, * we check what would be the channel in the second * frame for a 68-byte atom. 76-byte atoms have 0 there. * Valid channel cannot be 0. */ if (scan_len % 76) atom_len = 68; else if (scan_len % 68) atom_len = 76; else if (scan_len >= 1292 && scan[68] == 0) atom_len = 76; else atom_len = 68; offset = 0; break; case FIRMWARE_TYPE_INTERSIL: offset = 4; if (priv->has_hostscan) atom_len = scan[0] + (scan[1] << 8); else atom_len = offsetof(struct prism2_scan_apinfo, atim); break; default: return 0; } /* Check that we got an whole number of atoms */ if ((scan_len - offset) % atom_len) { printk(KERN_ERR "%s: Unexpected scan data length %d, " "atom_len %d, offset %d\n", dev->name, scan_len, atom_len, offset); return 0; } /* Read the entries one by one */ for (; offset + atom_len <= scan_len; offset += atom_len) { /* Get next atom */ atom = (union hermes_scan_info *) (scan + offset); /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ /* Add the ESSID */ iwe.u.data.length = le16_to_cpu(atom->a.essid_len); if (iwe.u.data.length > 32) iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); /* Add mode */ iwe.cmd = SIOCGIWMODE; capabilities = le16_to_cpu(atom->a.capabilities); if (capabilities & 0x3) { if (capabilities & 0x1) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } channel = atom->s.channel; if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) { /* Add frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = channel_frequency[channel-1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); } /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.updated = 0x10; /* no link quality */ iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95; iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95; /* Wireless tools prior to 27.pre22 will show link quality * anyway, so we provide a reasonable value. */ if (iwe.u.qual.level > iwe.u.qual.noise) iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; else iwe.u.qual.qual = 0; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; if (capabilities & 0x10) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); /* Bit rate is not available in Lucent/Agere firmwares */ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { char * current_val = current_ev + IW_EV_LCP_LEN; int i; int step; if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) step = 2; else step = 1; iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; /* Max 10 values */ for (i = 0; i < 10; i += step) { /* NULL terminated */ if (atom->p.rates[i] == 0x0) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000); current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any event */ if ((current_val - current_ev) > IW_EV_LCP_LEN) current_ev = current_val; } /* The other data in the scan result are not really * interesting, so for now drop it - Jean II */ } return current_ev - buffer; } /* Return results of a scan */ static int orinoco_ioctl_getscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { struct orinoco_private *priv = netdev_priv(dev); int err = 0; unsigned long flags; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; /* If no results yet, ask to try again later */ if (priv->scan_result == NULL) { if (priv->scan_inprogress) /* Important note : we don't want to block the caller * until results are ready for various reasons. * First, managing wait queues is complex and racy. * Second, we grab some rtnetlink lock before comming * here (in dev_ioctl()). * Third, we generate an Wireless Event, so the * caller can wait itself on that - Jean II */ err = -EAGAIN; else /* Client error, no scan results... * The caller need to restart the scan. */ err = -ENODATA; } else { /* We have some results to push back to user space */ /* Translate to WE format */ srq->length = orinoco_translate_scan(dev, extra, priv->scan_result, priv->scan_len); /* Return flags */ srq->flags = (__u16) priv->scan_mode; /* Results are here, so scan no longer in progress */ priv->scan_inprogress = 0; /* In any case, Scan results will be cleaned up in the * reset function and when exiting the driver. * The person triggering the scanning may never come to * pick the results, so we need to do it in those places. * Jean II */ #ifdef SCAN_SINGLE_READ /* If you enable this option, only one client (the first * one) will be able to read the result (and only one * time). If there is multiple concurent clients that * want to read scan results, this behavior is not * advisable - Jean II */ kfree(priv->scan_result); priv->scan_result = NULL; #endif /* SCAN_SINGLE_READ */ /* Here, if too much time has elapsed since last scan, * we may want to clean up scan results... - Jean II */ } orinoco_unlock(priv, &flags); return err; } /* Commit handler, called after set operations */ static int orinoco_ioctl_commit(struct net_device *dev, struct iw_request_info *info, Loading Loading @@ -4060,6 +4559,8 @@ static const iw_handler orinoco_handler[] = { [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy, [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap, [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap, [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan, [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan, [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid, [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid, [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick, Loading
drivers/net/wireless/orinoco.h +22 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,20 @@ struct orinoco_key { char data[ORINOCO_MAX_KEY_SIZE]; } __attribute__ ((packed)); struct header_struct { /* 802.3 */ u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype; } __attribute__ ((packed)); typedef enum { FIRMWARE_TYPE_AGERE, FIRMWARE_TYPE_INTERSIL, Loading @@ -51,6 +65,7 @@ struct orinoco_private { int open; u16 last_linkstatus; struct work_struct join_work; struct work_struct wevent_work; /* Net device stuff */ struct net_device *ndev; Loading @@ -77,6 +92,7 @@ struct orinoco_private { unsigned int has_pm:1; unsigned int has_preamble:1; unsigned int has_sensitivity:1; unsigned int has_hostscan:1; unsigned int broken_disableport:1; /* Configuration paramaters */ Loading @@ -103,6 +119,12 @@ struct orinoco_private { /* Configuration dependent variables */ int port_type, createibss; int promiscuous, mc_count; /* Scanning support */ int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ char * scan_result; /* Result of previous scan */ int scan_len; /* Lenght of result */ }; #ifdef ORINOCO_DEBUG Loading