diff options
author | jal2 <jal2> | 2004-03-18 20:54:57 +0000 |
---|---|---|
committer | jal2 <jal2> | 2004-03-18 20:54:57 +0000 |
commit | ba37e510d2fb6ad1df2ba2300919cf7d5fa59b4f (patch) | |
tree | e322416d1c017793a0a7fbfb15744a4a3807713f | |
parent | fff811f8d3ae212aee457fbb74e0f78277fa11d5 (diff) |
- version 0.12beta9
- Nick's new iw_handler implementation, supports "iwlist ..." and more
- authentication method is now choosen by encr XXX restr, not by iwpriv anymore
- removed "iwpriv wlan0 list_bss" command
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 25 | ||||
-rw-r--r-- | at76c503-fw_skel.c | 7 | ||||
-rw-r--r-- | at76c503.c | 2504 | ||||
-rw-r--r-- | at76c503.h | 25 |
5 files changed, 1875 insertions, 690 deletions
@@ -1,6 +1,6 @@ -#$Id: Makefile,v 1.25 2004/03/02 20:38:52 jal2 Exp $ +#$Id: Makefile,v 1.26 2004/03/18 20:54:57 jal2 Exp $ -VERSION = 0.12beta8 +VERSION = 0.12beta9 CC=gcc @@ -1,4 +1,4 @@ -(* $Id: README,v 1.12 2003/11/27 22:23:46 jal2 Exp $ *) +(* $Id: README,v 1.13 2004/03/18 20:54:57 jal2 Exp $ *) at76c503 - linux driver for Atmel at76c503 based usb wlan adapters ------------------------------------------------------------------ @@ -9,7 +9,9 @@ any corporation that builds devices with this chip. My only information source is the driver from http://atmelwlandriver.sourceforge.net. -Look at http://at76c503a.berlios.de/ for more information, mailing lists and links. +Look at http://at76c503a.berlios.de/ for more accurate information, +mailing lists and links. This README is probably outdated. + Known devices with this chip are: - Belkin F5D6050 @@ -21,9 +23,10 @@ and many more. Reqirements: ------------ -- Kernel 2.4.x. I am developing the driver on 2.4.20, but it - reportedly also works on 2.4.19, 2.4.18 and 2.4.16. I am not sure - about 2.5.x. +- Kernel 2.4.x. I am developing the driver on 2.4.23, but it + reportedly also works on 2.4.20, 2.4.19, 2.4.18 and 2.4.16. +- kernel 2.6.x: 2.6.1-4 were reported to work fine. + Installation: ------------- @@ -31,6 +34,9 @@ Installation: make make install +(with kernel 2.6 you must be run for both steps). + + Running: -------- @@ -105,8 +111,6 @@ Private Parameters In addition to the parameters of iwconfig, some can be set by iwpriv: - long preamble: iwpriv wlanX short_preamble 0 - short preamble: iwpriv wlanX short_preamble 1 -- open system authentication: iwpriv wlanX auth_mode 0 -- shared key authentication: iwpriv wlanX auth_mode 1 - amount of debug messages: iwpriv wlanX set_debug N with N a combination of bits, see DBG_* in at76c503.c - power save mode: iwpriv wlanX powersave_mode N (* N = 1,2,3 @@ -170,8 +174,8 @@ Known Problems -Thanks to: -- the authors of the usbvnet driver (atmelwlandriver.sourceforge.net) +Thanks to (in no particular order): +- the authors (Stavros et.al.) of the usbvnet driver (atmelwlandriver.sourceforge.net) - Joerg Albert for lots of patches - Brad Hards and Bas Vermeulen for the firmware code, which I ported to kernel space - David Gibson, I used his orinoco driver for learning @@ -179,8 +183,9 @@ Thanks to: - the author(s) of the rtl8150 driver - lots of other authors of usb and wlan drivers, where I stole code from - Pavel Roskin for testing, debugging and his patches +- Nick Jones for rewriting the iw_handler interface -Oliver Kurth <oku@masqmail.cx>, Mon, 6 Jan 2003 22:39:47 +0100 +Oliver Kurth, Mon, 6 Jan 2003 22:39:47 +0100 updated by Joerg Albert, Thu, 1 May 2003 and later diff --git a/at76c503-fw_skel.c b/at76c503-fw_skel.c index 92f2a34..2511c55 100644 --- a/at76c503-fw_skel.c +++ b/at76c503-fw_skel.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- */ /* - * $Id: at76c503-fw_skel.c,v 1.5 2004/02/20 22:14:42 jal2 Exp $ + * $Id: at76c503-fw_skel.c,v 1.6 2004/03/18 20:54:57 jal2 Exp $ * * Driver for at76c503-based devices based on the Atmel "Fast-Vnet" reference * @@ -26,8 +26,13 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) extern inline char *fw_dev_param(struct usb_device *udev, char *buf) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 20) snprintf(buf, FIRMWARE_NAME_MAX, "usb-%s-%s", udev->bus->bus_name, udev->devpath); +#else + snprintf(buf, FIRMWARE_NAME_MAX, "usb-%d-%d", + udev->bus->busnum, udev->devnum); +#endif return buf; } #else @@ -1,5 +1,5 @@ /* -*- linux-c -*- */ -/* $Id: at76c503.c,v 1.45 2004/03/17 22:35:07 jal2 Exp $ +/* $Id: at76c503.c,v 1.46 2004/03/18 20:54:57 jal2 Exp $ * * USB at76c503/at76c505 driver * @@ -10,6 +10,7 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * + * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed * * History: * @@ -95,6 +96,19 @@ #include <linux/ethtool.h> #include <asm/uaccess.h> #include <linux/wireless.h> + +#if WIRELESS_EXT > 12 + +#include <net/iw_handler.h> +#define IW_REQUEST_INFO struct iw_request_info + +#else + +#define EIWCOMMIT EINPROGRESS +#define IW_REQUEST_INFO void + +#endif // #if WIRELESS_EXT > 12 + #include <linux/rtnetlink.h> /* for rtnl_lock() */ #include "at76c503.h" @@ -142,6 +156,8 @@ static inline void usb_set_intfdata(struct usb_interface *intf, void *data) {} #endif //#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) +/* wireless extension level this source currently supports */ +#define WIRELESS_EXT_SUPPORTED 16 #ifndef USB_ST_URB_PENDING #define USB_ST_URB_PENDING (-EINPROGRESS) @@ -289,6 +305,8 @@ struct header_struct { #define DEF_RTS_THRESHOLD 1536 #define DEF_FRAG_THRESHOLD 1536 +#define DEF_SHORT_RETRY_LIMIT 8 +//#define DEF_LONG_RETRY_LIMIT 4 #define DEF_ESSID "okuwlan" #define DEF_ESSID_LEN 7 #define DEF_CHANNEL 10 @@ -430,10 +448,8 @@ static u8 rfc1042sig[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #endif /* COLLAPSE_RFC1042 */ /* local function prototypes */ - -#if IW_MAX_SPY > 0 static void iwspy_update(struct at76c503 *dev, struct at76c503_rx_buffer *buf); -#endif + static void at76c503_read_bulk_callback (struct urb *urb); static void at76c503_write_bulk_callback(struct urb *urb); static void defer_kevent (struct at76c503 *dev, int flag); @@ -2115,6 +2131,54 @@ int reassoc_req(struct at76c503 *dev, struct bss_info *curr_bss, } /* reassoc_req */ +static +int handle_scan(struct at76c503 *dev) +{ + int ret; + + if (dev->istate == INIT) { + ret = -EPERM; + goto end_scan; + } + assert(dev->istate == SCANNING); + + /* empty the driver's bss list */ + free_bss_list(dev); + + /* scan twice: first run with ProbeReq containing the + empty SSID, the second run with the real SSID. + APs in cloaked mode (e.g. Agere) will answer + in the second run with their real SSID. */ + + if ((ret = start_scan(dev, 0)) < 0) { + err("%s: start_scan failed with %d", dev->netdev->name, ret); + goto end_scan; + } + if ((ret = wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) { + err("%s start_scan completed with %d", + dev->netdev->name, ret); + goto end_scan; + } + + /* dump the results of the scan with ANY ssid */ + dump_bss_table(dev, 0); + + if ((ret = start_scan(dev, 1)) < 0) { + err("%s: 2.start_scan failed with %d", dev->netdev->name, ret); + goto end_scan; + } + if ((ret = wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) { + err("%s 2.start_scan completed with %d", + dev->netdev->name, ret); + goto end_scan; + } + + /* dump the results of the scan with real ssid */ + dump_bss_table(dev, 0); +end_scan: + return (ret < 0); +} + #if 0 /* == PROC re_register_intf == re-register the interfaces with the driver core. Taken from @@ -2358,46 +2422,11 @@ end_join: if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) { clear_bit(KEVENT_SCAN, &dev->kevent_flags); - if (dev->istate == INIT) - goto end_scan; - assert(dev->istate == SCANNING); - - /* empty the driver's bss list */ - free_bss_list(dev); - - /* scan twice: first run with ProbeReq containing the - empty SSID, the second run with the real SSID. - APs in cloaked mode (e.g. Agere) will answer - in the second run with their real SSID. */ - - if ((ret=start_scan(dev, 0)) < 0) { - err("%s: start_scan failed with %d", - dev->netdev->name, ret); - goto end_scan; - } - if ((ret=wait_completion(dev,CMD_SCAN)) != - CMD_STATUS_COMPLETE) { - err("%s start_scan completed with %d", - dev->netdev->name, ret); - goto end_scan; - } - - /* dump the results of the scan with ANY ssid */ - dump_bss_table(dev, 0); - if ((ret=start_scan(dev, 1)) < 0) { - err("%s: 2.start_scan failed with %d", - dev->netdev->name, ret); - goto end_scan; - } - if ((ret=wait_completion(dev,CMD_SCAN)) != - CMD_STATUS_COMPLETE) { - err("%s 2.start_scan completed with %d", - dev->netdev->name, ret); + + if (handle_scan(dev)) { goto end_scan; } - - /* dump the results of the scan with real ssid */ - dump_bss_table(dev, 0); + NEW_STATE(dev,JOINING); assert(dev->curr_bss == NULL); /* done in free_bss_list, find_bss will start with first bss */ @@ -2953,9 +2982,9 @@ static void rx_mgmt_beacon(struct at76c503 *dev, int new_entry = 0; int len; unsigned long flags; - + spin_lock_irqsave(&dev->bss_list_spinlock, flags); - + if (dev->istate == CONNECTED) { /* in state CONNECTED we use the mgmt_timer to control the beacon of the BSS */ @@ -2995,24 +3024,26 @@ static void rx_mgmt_beacon(struct at76c503 *dev, /* append new struct into list */ list_add_tail(&match->list, &dev->bss_list); } - + /* we either overwrite an existing entry or append a new one match points to the entry in both cases */ - + match->capa = le16_to_cpu(bdata->capability_information); - + /* while beacon_interval is not (!) */ match->beacon_interval = le16_to_cpu(bdata->beacon_interval); - + match->rssi = buf->rssi; match->link_qual = buf->link_quality; match->noise_level = buf->noise_level; - + memcpy(match->mac,mgmt->addr2,ETH_ALEN); //just for info memcpy(match->bssid,mgmt->addr3,ETH_ALEN); - + dbg(DBG_RX_BEACON, "%s: bssid %s", dev->netdev->name, + mac2str(match->bssid)); + tlv_ptr = bdata->data; - + assert(*tlv_ptr == IE_ID_SSID); len = min(IW_ESSID_MAX_SIZE,(int)*(tlv_ptr+1)); if ((new_entry) || !is_cloaked_ssid(tlv_ptr+2, len)) { @@ -3033,6 +3064,7 @@ static void rx_mgmt_beacon(struct at76c503 *dev, assert(*tlv_ptr == IE_ID_DS_PARAM_SET); match->channel = *(tlv_ptr+2); + dbg(DBG_RX_BEACON, "%s: channel %d", dev->netdev->name, match->channel); match->last_rx = jiffies; /* record last rx of beacon */ @@ -3060,7 +3092,7 @@ static void rx_mgmt(struct at76c503 *dev, struct at76c503_rx_buffer *buf) values, we just present the raw value at the moment - TJS */ if (buf->rssi > 1) { - lev_dbm = (buf->rssi * 10 / 4); + lev_dbm = (buf->rssi * 5 / 2); if (lev_dbm > 255) lev_dbm = 255; wstats->qual.qual = buf->link_quality; @@ -3570,7 +3602,7 @@ static int submit_rx_urb(struct at76c503 *dev) } size = skb_tailroom(skb); - usb_fill_bulk_urb(dev->read_urb, dev->udev, + FILL_BULK_URB(dev->read_urb, dev->udev, usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), skb_put(skb, size), size, (usb_complete_t)at76c503_read_bulk_callback, dev); @@ -3686,9 +3718,9 @@ static void rx_tasklet(unsigned long param) /* jal: TODO: find out if we can update iwspy also on other frames than management (might depend on the radio chip / firmware version !) */ -#if IW_MAX_SPY > 0 + iwspy_update(dev, buf); -#endif + rx_mgmt(dev, buf); break; @@ -3883,7 +3915,7 @@ int startup_device(struct at76c503 *dev) dev->channel, dev->wep_enabled ? "enabled" : "disabled", dev->wep_key_id, dev->wep_keys_len[dev->wep_key_id]); - dbg_uc("%s param: preamble %s rts %d frag %d txrate %s excl %d", + dbg_uc("%s param: preamble %s rts %d frag %d txrate %s auth_mode %d", dev->netdev->name, dev->preamble_type == PREAMBLE_TYPE_SHORT ? "short" : "long", dev->rts_threshold, dev->frag_threshold, @@ -3892,7 +3924,7 @@ int startup_device(struct at76c503 *dev) dev->txrate == TX_RATE_5_5MBIT ? "5.5MBit" : dev->txrate == TX_RATE_11MBIT ? "11MBit" : dev->txrate == TX_RATE_AUTO ? "auto" : "<invalid>", - dev->wep_excl_unencr); + dev->auth_mode); dbg_uc("%s param: pm_mode %d pm_period %d auth_mode %s " "scan_times %d %d scan_mode %s", dev->netdev->name, @@ -3904,11 +3936,12 @@ int startup_device(struct at76c503 *dev) } memset(ccfg, 0, sizeof(struct at76c503_card_config)); - ccfg->exclude_unencrypted = dev->wep_excl_unencr; + ccfg->exclude_unencrypted = 1; /* jal: always exclude unencrypted + if WEP is active */ ccfg->promiscuous_mode = 0; - ccfg->promiscuous_mode = 1; - ccfg->short_retry_limit = 8; - + ccfg->short_retry_limit = dev->short_retry_limit; + //ccfg->long_retry_limit = dev->long_retry_limit; + if (dev->wep_enabled && dev->wep_keys_len[dev->wep_key_id] > WEP_SMALL_KEY_LEN) ccfg->encryption_type = 2; @@ -4100,96 +4133,42 @@ int at76c503_set_mac_address(struct net_device *netdev, void *addr) return 1; } -#if IW_MAX_SPY > 0 /* == PROC iwspy_update == check if we spy on the sender address of buf and update statistics */ static void iwspy_update(struct at76c503 *dev, struct at76c503_rx_buffer *buf) { - int i; - u16 lev_dbm; +#if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) struct ieee802_11_hdr *hdr = (struct ieee802_11_hdr *)buf->packet; - - for(i=0; i < dev->iwspy_nr; i++) { - if (!memcmp(hdr->addr2, dev->iwspy_addr[i].sa_data, - ETH_ALEN)) { - dev->iwspy_stats[i].qual = buf->link_quality; - lev_dbm = buf->rssi * 5 / 2; - dev->iwspy_stats[i].level = - (lev_dbm > 255 ? 255 : lev_dbm); - dev->iwspy_stats[i].noise = buf->noise_level; - dev->iwspy_stats[i].updated = 1; + u16 lev_dbm = buf->rssi * 5 / 2; + struct iw_quality wstats = { + .qual = buf->link_quality, + .level = (lev_dbm > 255) ? 255 : lev_dbm, + .noise = buf->noise_level, + .updated = 1, + }; +#if WIRELESS_EXT <= 15 + int i = 0; +#endif + + spin_lock_bh(&(dev->spy_spinlock)); + +#if WIRELESS_EXT > 15 + if (dev->spy_data.spy_number > 0) { + wireless_spy_update(dev->netdev, hdr->addr2, &wstats); + } +#else + for (i; i < dev->iwspy_nr; i++) { + if (!memcmp(hdr->addr2, dev->iwspy_addr[i].sa_data, ETH_ALEN)) { + memcpy(&(dev->iwspy_stats[i]), &wstats, sizeof(wstats)); break; } } +#endif // #if WIRELESS_EXT > 15 + spin_unlock_bh(&(dev->spy_spinlock)); +#endif // #if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) } /* iwspy_update */ -/* == PROC ioctl_setspy == */ -static int ioctl_setspy(struct at76c503 *dev, struct iw_point *srq) -{ - int i; - - if (srq == NULL) - return -EFAULT; - - dbg(DBG_IOCTL, "%s: ioctl(SIOCSIWSPY, number %d)", - dev->netdev->name, srq->length); - - if (srq->length > IW_MAX_SPY) - return -E2BIG; - - dev->iwspy_nr = srq->length; - - if (dev->iwspy_nr > 0) { - if (copy_from_user(dev->iwspy_addr, srq->pointer, - sizeof(struct sockaddr) * dev->iwspy_nr)) { - dev->iwspy_nr = 0; - return -EFAULT; - } - memset(dev->iwspy_stats, 0, sizeof(dev->iwspy_stats)); - } - - /* Time to show what we have done... */ - if (debug & DBG_IOCTL) { - dbg_uc("%s: New spy list:", dev->netdev->name); - for (i = 0; i < dev->iwspy_nr; i++) { - dbg_uc("%s: %s", dev->netdev->name, - mac2str(dev->iwspy_addr[i].sa_data)); - } - } - - return 0; -} /* ioctl_setspy */ - - -/* == PROC ioctl_getspy == */ -static int ioctl_getspy(struct at76c503 *dev, struct iw_point *srq) -{ - int i; - - dbg(DBG_IOCTL, "%s: ioctl(SIOCGIWSPY, number %d)", dev->netdev->name, - dev->iwspy_nr); - - srq->length = dev->iwspy_nr; - - if (srq->length > 0 && (srq->pointer)) { - /* Push stuff to user space */ - if(copy_to_user(srq->pointer, dev->iwspy_addr, - sizeof(struct sockaddr) * srq->length)) - return -EFAULT; - if(copy_to_user(srq->pointer + - sizeof(struct sockaddr)*srq->length, - dev->iwspy_stats, - sizeof(struct iw_quality)*srq->length )) - return -EFAULT; - - for(i=0; i < dev->iwspy_nr; i++) - dev->iwspy_stats[i].updated = 0; - } - return 0; -} /* ioctl_getspy */ -#endif /* #if IW_MAX_SPY > 0 */ - static int ethtool_ioctl(struct at76c503 *dev, void *useraddr) { u32 ethcmd; @@ -4247,616 +4226,1799 @@ static int ethtool_ioctl(struct at76c503 *dev, void *useraddr) return -EOPNOTSUPP; } + +/******************************************************************************* + * structure that describes the private ioctls/iw handlers of this driver + */ +static const struct iw_priv_args at76c503_priv_args[] = { + { PRIV_IOCTL_SET_SHORT_PREAMBLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "short_preamble" }, // 0 - long, 1 -short + + { PRIV_IOCTL_SET_DEBUG, + // we must pass the new debug mask as a string, + // 'cause iwpriv cannot parse hex numbers + // starting with 0x :-( + IW_PRIV_TYPE_CHAR | 10, 0, + "set_debug"}, // set debug value + + { PRIV_IOCTL_SET_POWERSAVE_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "powersave_mode"}, // 1 - active, 2 - power save, + // 3 - smart power save + { PRIV_IOCTL_SET_SCAN_TIMES, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "scan_times"}, // min_channel_time, + // max_channel_time + { PRIV_IOCTL_SET_SCAN_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "scan_mode"}, // 0 - active, 1 - passive scan +}; + + +/******************************************************************************* + * at76c503 implementations of iw_handler functions: + */ static -int at76c503_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +int at76c503_iw_handler_commit(struct net_device *netdev, + IW_REQUEST_INFO *info, + void *null, + char *extra) { - struct at76c503 *dev = netdev->priv; - struct iwreq *wrq = (struct iwreq *)rq; - int ret = 0; - int changed = 0; /* set to 1 if we must re-start the device */ - - if (! netif_device_present(netdev)) - return -ENODEV; - - if (down_interruptible(&dev->sem)) - return -EINTR; + struct at76c503 *dev = (struct at76c503*)netdev->priv; + unsigned long flags; + + dbg(DBG_IOCTL, "%s %s: restarting the device", netdev->name, + __FUNCTION__); + + // stop any pending tx bulk urb + //TODO + + // jal: TODO: protect access to dev->istate by a spinlock + // (ISR's on other processors may read/write it) + if (dev->istate != INIT) { + dev->istate = INIT; + // stop pending management stuff + del_timer_sync(&dev->mgmt_timer); - switch (cmd) { + spin_lock_irqsave(&dev->mgmt_spinlock,flags); + if (dev->next_mgmt_bulk) { + kfree(dev->next_mgmt_bulk); + dev->next_mgmt_bulk = NULL; + } + spin_unlock_irqrestore(&dev->mgmt_spinlock,flags); - /* rudimentary ethtool support for hotplug of SuSE 8.3 */ - case SIOCETHTOOL: - ret = ethtool_ioctl(dev,rq->ifr_data); - break; + netif_carrier_off(dev->netdev); + netif_stop_queue(dev->netdev); + } - case SIOCGIWNAME: - dbg(DBG_IOCTL, "%s: SIOCGIWNAME", netdev->name); - strcpy(wrq->u.name, "IEEE 802.11-DS"); - break; - - case SIOCGIWAP: - dbg(DBG_IOCTL, "%s: SIOCGIWAP", netdev->name); - wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + // do the restart after two seconds to catch + // following ioctl's (from more params of iwconfig) + // in _one_ restart + mod_timer(&dev->restart_timer, jiffies+2*HZ); + + return 0; +} - memcpy(wrq->u.ap_addr.sa_data, dev->bssid, ETH_ALEN); +static +int at76c503_iw_handler_get_name(struct net_device *netdev, + IW_REQUEST_INFO *info, + char *name, + char *extra) +{ + strcpy(name, "IEEE 802.11-DS"); + + dbg(DBG_IOCTL, "%s: SIOCGIWNAME - name %s", netdev->name, name); + + return 0; +} - break; +static +int at76c503_iw_handler_set_freq(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_freq *freq, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int chan = -1; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - freq.m %d freq.e %d", netdev->name, + freq->m, freq->e); + + // modelled on orinoco.c + if ((freq->e == 0) && (freq->m <= 1000)) + { + // Setting by channel number + chan = freq->m; + } + else + { + // Setting by frequency - search the table + int mult = 1; + int i; + + for (i = 0; i < (6 - freq->e); i++) { + mult *= 10; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + if (freq->m == (channel_frequency[i] * mult)) + chan = i + 1; + } + } + + if (chan < 1 || !dev->domain ) { + // non-positive channels are invalid + // we need a domain info to set the channel + // either that or an invalid frequency was + // provided by the user + ret = -EINVAL; + } else { + if (!(dev->domain->channel_map & (1 << (chan-1)))) { + info("%s: channel %d not allowed for domain %s", + dev->netdev->name, chan, dev->domain->name); + ret = -EINVAL; + } + } + + if (ret == -EIWCOMMIT) { + dev->channel = chan; + dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - ch %d", netdev->name, chan); + } + + return ret; +} - case SIOCSIWNICKN: +static +int at76c503_iw_handler_get_freq(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_freq *freq, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + freq->m = dev->channel; + freq->e = 0; + + if (dev->channel) { - struct iw_point *erq = &wrq->u.data; - char nickn[IW_ESSID_MAX_SIZE+1]; + dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - freq %ld x 10e%d", netdev->name, + channel_frequency[dev->channel - 1], 6); + } + dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - ch %d", netdev->name, dev->channel); + + return 0; +} - memset(nickn, 0, sizeof(nickn)); +static +int at76c503_iw_handler_set_mode(struct net_device *netdev, + IW_REQUEST_INFO *info, + __u32 *mode, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode); + + if ((*mode != IW_MODE_ADHOC) && + (*mode != IW_MODE_INFRA)) { + ret = -EINVAL; + } else { + dev->iw_mode = *mode; + } + + return ret; +} - if (erq->flags) { - if (erq->length > IW_ESSID_MAX_SIZE){ - ret = -E2BIG; - goto csiwnickn_error; - } - - if (copy_from_user(nickn, erq->pointer, erq->length)){ - ret = -EFAULT; - goto csiwessid_error; - } +static +int at76c503_iw_handler_get_mode(struct net_device *netdev, + IW_REQUEST_INFO *info, + __u32 *mode, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + *mode = dev->iw_mode; + + dbg(DBG_IOCTL, "%s: SIOCGIWMODE - %d", netdev->name, *mode); + + return 0; +} + +static +int at76c503_iw_handler_get_range(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + // inspired by atmel.c + struct at76c503 *dev = (struct at76c503*)netdev->priv; + struct iw_range *range = (struct iw_range*)extra; + int i; + + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + + //TODO: range->throughput = xxxxxx; + + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + + + // this driver doesn't maintain sensitivity information + range->sensitivity = 0; + + + range->max_qual.qual = + ((dev->board_type == BOARDTYPE_503_INTERSIL_3861) || + (dev->board_type == BOARDTYPE_503_INTERSIL_3863)) ? 100 : 0; + range->max_qual.level = 100; + range->max_qual.noise = 0; + + range->avg_qual.qual = + ((dev->board_type == BOARDTYPE_503_INTERSIL_3861) || + (dev->board_type == BOARDTYPE_503_INTERSIL_3863)) ? 30 : 0; + range->avg_qual.level = 30; + range->avg_qual.noise = 0; + + + range->bitrate[0] = 1000000; + range->bitrate[1] = 2000000; + range->bitrate[2] = 5500000; + range->bitrate[3] = 11000000; + range->num_bitrates = 4; + + + range->min_rts = 0; + range->max_rts = MAX_RTS_THRESHOLD; + + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + + //range->min_pmp = 0; + //range->max_pmp = 5000000; + //range->min_pmt = 0; + //range->max_pnt = 0; + //range->pmp_flags = IW_POWER_PERIOD; + //range->pmt_flags = 0; + //range->pm_capa = IW_POWER_PERIOD; + //TODO: find out what values we can use to describe PM capabilities + range->pmp_flags = IW_POWER_ON; + range->pmt_flags = IW_POWER_ON; + range->pm_capa = 0; + + + range->encoding_size[0] = WEP_SMALL_KEY_LEN; + range->encoding_size[1] = WEP_LARGE_KEY_LEN; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = NR_WEP_KEYS; + //TODO: do we need this? what is a valid value if we don't support? + //range->encoding_login_index = -1; + + /* both WL-240U and Linksys WUSB11 v2.6 specify 15 dBm as output power + - take this for all (ignore antenna gains) */ + range->txpower[0] = 15; + range->num_txpower = 1; + range->txpower_capa = IW_TXPOW_DBM; + + // at time of writing (22/Feb/2004), version we intend to support + // is v16, + range->we_version_source = WIRELESS_EXT_SUPPORTED; + range->we_version_compiled = WIRELESS_EXT; + + // same as the values used in atmel.c + range->retry_capa = IW_RETRY_LIMIT ; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = 0; + range->min_retry = 1; + range->max_retry = 65535; + + + range->num_channels = NUM_CHANNELS; + range->num_frequency = 0; + + for (i = 0; + i < 32; //number of bits in reg_domain.channel_map + i++) + { + // test if channel map bit is raised + if (dev->domain->channel_map & (0x1 << i)) + { + range->num_frequency += 1; - dbg(DBG_IOCTL, "%s: SIOCSIWNICKN %s", netdev->name, - nickn); - strcpy(dev->nickn, nickn); + range->freq[i].i = i + 1; + range->freq[i].m = channel_frequency[i] * 100000; + range->freq[i].e = 1; // channel frequency*100000 * 10^1 } } - csiwnickn_error: - break; + + dbg(DBG_IOCTL, "%s: SIOCGIWRANGE", netdev->name); + + return 0; +} - case SIOCGIWNICKN: +static +int at76c503_iw_handler_get_priv(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + dbg(DBG_IOCTL, "%s: SIOCGIWPRIV", netdev->name); + + memcpy(extra, at76c503_priv_args, sizeof(at76c503_priv_args)); + data->length = sizeof(at76c503_priv_args) / + sizeof(at76c503_priv_args[0]); + + return 0; +} + + +#if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) +static +int at76c503_iw_handler_set_spy(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; +#if WIRELESS_EXT <= 15 + int i = 0; +#endif + int ret = 0; + + dbg(DBG_IOCTL, "%s: SIOCSIWSPY - number of addresses %d", + netdev->name, data->length); + + spin_lock_bh(&(dev->spy_spinlock)); +#if WIRELESS_EXT > 15 + ret = iw_handler_set_spy(dev->netdev, info, (union iwreq_data *)data, + extra); +#else + if (&data == NULL) { + return -EFAULT; + } + + if (data->length > IW_MAX_SPY) { - struct iw_point *erq = &wrq->u.data; + return -E2BIG; + } + + dev->iwspy_nr = data->length; + + if (dev->iwspy_nr > 0) { + memcpy(dev->iwspy_addr, extra, + sizeof(struct sockaddr) * dev->iwspy_nr); + + memset(dev->iwspy_stats, 0, sizeof(dev->iwspy_stats)); + } + + // Time to show what we have done... + dbg(DBG_IOCTL, "%s: New spy list:", netdev->name); + for (i = 0; i < dev->iwspy_nr; i++) { + dbg(DBG_IOCTL, "%s: SIOCSIWSPY - entry %d: %s", netdev->name, + i + 1, mac2str(dev->iwspy_addr[i].sa_data)); + } +#endif // #if WIRELESS_EXT > 15 + spin_unlock_bh(&(dev->spy_spinlock)); + + return ret; +} - erq->length = strlen(dev->nickn); - if(copy_to_user(erq->pointer, dev->nickn, - erq->length)){ - ret = -EFAULT; +static +int at76c503_iw_handler_get_spy(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + + struct at76c503 *dev = (struct at76c503*)netdev->priv; +#if WIRELESS_EXT <= 15 + int i = 0; +#endif + int ret = 0; + + spin_lock_bh(&(dev->spy_spinlock)); +#if WIRELESS_EXT > 15 + ret = iw_handler_get_spy(dev->netdev, info, + (union iwreq_data *)data, extra); +#else + data->length = dev->iwspy_nr; + + if ((data->length > 0) && extra) { + // Push stuff to user space + memcpy(extra, dev->iwspy_addr, + sizeof(struct sockaddr) * data->length); + + memcpy(extra + sizeof(struct sockaddr) * data->length, + dev->iwspy_stats, + sizeof(struct iw_quality) * data->length); + + for (i = 0; i < dev->iwspy_nr; i++) { + dev->iwspy_stats[i].updated = 0; } } - break; +#endif // #if WIRELESS_EXT > 15 + spin_unlock_bh(&(dev->spy_spinlock)); + + dbg(DBG_IOCTL, "%s: SIOCGIWSPY - number of addresses %d", + netdev->name, data->length); + + return ret; +} +#endif // #if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) + +#if WIRELESS_EXT > 15 +static +int at76c503_iw_handler_set_thrspy(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret; + + dbg(DBG_IOCTL, "%s: SIOCSIWTHRSPY - number of addresses %d)", + netdev->name, data->length); + + spin_lock_bh(&(dev->spy_spinlock)); + ret = iw_handler_set_thrspy(netdev, info, (union iwreq_data *)data, + extra); + spin_unlock_bh(&(dev->spy_spinlock)); + + return ret; +} - case SIOCSIWRTS: - { - int rthr = wrq->u.rts.value; - dbg(DBG_IOCTL, "%s: SIOCSIWRTS: value %d disabled %d", - netdev->name, wrq->u.rts.value, wrq->u.rts.disabled); - - if(wrq->u.rts.disabled) - rthr = MAX_RTS_THRESHOLD; - if((rthr < 0) || (rthr > MAX_RTS_THRESHOLD)) { - ret = -EINVAL; - } else { - dev->rts_threshold = rthr; - changed = 1; - } - } - break; +static +int at76c503_iw_handler_get_thrspy(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret; + + spin_lock_bh(&(dev->spy_spinlock)); + ret = iw_handler_get_thrspy(netdev, info, (union iwreq_data *)data, + extra); + spin_unlock_bh(&(dev->spy_spinlock)); + + dbg(DBG_IOCTL, "%s: SIOCGIWTHRSPY - number of addresses %d)", + netdev->name, data->length); + + return ret; +} +#endif //#if WIRELESS_EXT > 15 - // Get the current RTS threshold - case SIOCGIWRTS: - dbg(DBG_IOCTL, "%s: SIOCGIWRTS", netdev->name); +/*static +int at76c503_iw_handler_set_wap(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct sockaddr *ap_addr, + char *extra) +{ + return -EOPNOTSUPP; +}*/ - wrq->u.rts.value = dev->rts_threshold; - wrq->u.rts.disabled = (wrq->u.rts.value == MAX_RTS_THRESHOLD); - wrq->u.rts.fixed = 1; - break; +static +int at76c503_iw_handler_get_wap(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct sockaddr *ap_addr, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(ap_addr->sa_data, dev->bssid, ETH_ALEN); + + dbg(DBG_IOCTL, "%s: SIOCGIWAP - wap/bssid %s", netdev->name, + mac2str(ap_addr->sa_data)); + + return 0; +} + +/*static +int at76c503_iw_handler_get_waplist(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + return -EOPNOTSUPP; +}*/ + +#if WIRELESS_EXT > 13 +static +int at76c503_iw_handler_set_scan(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *param, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = 0; + unsigned long flags; + + dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name); + + // stop pending management stuff + del_timer_sync(&(dev->mgmt_timer)); + + spin_lock_irqsave(&(dev->mgmt_spinlock), flags); + if (dev->next_mgmt_bulk) { + kfree(dev->next_mgmt_bulk); + dev->next_mgmt_bulk = NULL; + } + spin_unlock_irqrestore(&(dev->mgmt_spinlock), flags); + + if (netif_running(dev->netdev)) { + // pause network activity + netif_carrier_off(dev->netdev); + netif_stop_queue(dev->netdev); + } + + // change to scanning state + NEW_STATE(dev, SCANNING); + + ret = handle_scan(dev); + + if (!ret) { + NEW_STATE(dev,JOINING); + assert(dev->curr_bss == NULL); + defer_kevent(dev, KEVENT_JOIN); + } + + return (ret < 0) ? ret : 0; +} - // Set the desired fragmentation threshold +static +int at76c503_iw_handler_get_scan(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + unsigned long flags; + struct list_head *lptr, *nptr; + struct bss_info *curr_bss; + struct iw_event iwe; + char *curr_val, *curr_pos = extra; + int i; - case SIOCSIWFRAG: - { - int fthr = wrq->u.frag.value; - dbg(DBG_IOCTL, "%s: SIOCSIWFRAG, value %d, disabled %d", - netdev->name, wrq->u.frag.value, wrq->u.frag.disabled); - - if(wrq->u.frag.disabled) - fthr = MAX_FRAG_THRESHOLD; - if((fthr < MIN_FRAG_THRESHOLD) || (fthr > MAX_FRAG_THRESHOLD)){ - ret = -EINVAL; - }else{ - dev->frag_threshold = fthr & ~0x1; // get an even value - changed = 1; - } + dbg(DBG_IOCTL, "%s: SIOCGIWSCAN", netdev->name); + + spin_lock_irqsave(&(dev->bss_list_spinlock), flags); + + list_for_each_safe(lptr, nptr, &(dev->bss_list)) { + curr_bss = list_entry(lptr, struct bss_info, list); + + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, curr_bss->bssid, 6); + curr_pos = iwe_stream_add_event(curr_pos, + extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); + + iwe.u.data.length = curr_bss->ssid_len; + iwe.cmd = SIOCGIWESSID; + // 1: SSID on , 0: SSID off/any + iwe.u.data.flags = (dev->essid_size > 0) ? 1 : 0; + + curr_pos = iwe_stream_add_point(curr_pos, + extra + IW_SCAN_MAX_DATA, &iwe, curr_bss->ssid); + + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = (curr_bss->capa & IEEE802_11_CAPA_IBSS) ? + IW_MODE_ADHOC : + (curr_bss->capa & IEEE802_11_CAPA_ESS) ? + IW_MODE_INFRA : + IW_MODE_AUTO; + // IW_MODE_AUTO = 0 which I thought is + // the most logical value to return in this case + curr_pos = iwe_stream_add_event(curr_pos, + extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); + + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = curr_bss->channel; + iwe.u.freq.e = 0; + curr_pos = iwe_stream_add_event(curr_pos, + extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); + + iwe.cmd = SIOCGIWENCODE; + if (curr_bss->capa & IEEE802_11_CAPA_PRIVACY) { + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + iwe.u.data.length = 0; + curr_pos = iwe_stream_add_point(curr_pos, + extra + IW_SCAN_MAX_DATA, &iwe, NULL); + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.level = curr_bss->rssi; /* do some calibration here ? */ + iwe.u.qual.noise = 0; + iwe.u.qual.qual = curr_bss->link_qual; /* good old Intersil radios report this, too */ + /* Add new value to event */ + curr_pos = iwe_stream_add_event(curr_pos, + extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_QUAL_LEN); + + /* Rate : stuffing multiple values in a single event require a bit + * more of magic - Jean II */ + curr_val = curr_pos + IW_EV_LCP_LEN; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + /* Max 8 values */ + for(i=0; i < curr_bss->rates_len; i++) { + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = + ((curr_bss->rates[i] & 0x7f) * 500000); + /* Add new value to event */ + curr_val = iwe_stream_add_value(curr_pos, curr_val, + extra + IW_SCAN_MAX_DATA, + &iwe, IW_EV_PARAM_LEN); } - break; - // Get the current fragmentation threshold - case SIOCGIWFRAG: - dbg(DBG_IOCTL, "%s: SIOCGIWFRAG", netdev->name); + /* Check if we added any event */ + if ((curr_val - curr_pos) > IW_EV_LCP_LEN) + curr_pos = curr_val; - wrq->u.frag.value = dev->frag_threshold; - wrq->u.frag.disabled = (wrq->u.frag.value >= MAX_FRAG_THRESHOLD); - wrq->u.frag.fixed = 1; - break; - case SIOCGIWFREQ: - dbg(DBG_IOCTL, "%s: SIOCGIWFREQ", netdev->name); - wrq->u.freq.m = dev->channel; - wrq->u.freq.e = 0; - wrq->u.freq.i = 0; - break; + // more information may be sent back using IWECUSTOM - case SIOCSIWFREQ: - /* copied from orinoco.c */ - { - struct iw_freq *frq = &wrq->u.freq; - int chan = -1; - - if((frq->e == 0) && (frq->m <= 1000)){ - /* Setting by channel number */ - chan = frq->m; - }else{ - /* Setting by frequency - search the table */ - int mult = 1; - int i; - - for(i = 0; i < (6 - frq->e); i++) - mult *= 10; - - for(i = 0; i < NUM_CHANNELS; i++) - if(frq->m == (channel_frequency[i] * mult)) - chan = i+1; - } - - if (chan < 1 || !dev->domain ) - /* non-positive channels are invalid - we need a domain info to set the channel */ - ret = -EINVAL; - else - if (!(dev->domain->channel_map & (1 << (chan-1)))) { - info("%s: channel %d not allowed for domain %s", - dev->netdev->name, chan, dev->domain->name); - ret = -EINVAL; - } + } + + spin_unlock_irqrestore(&(dev->bss_list_spinlock), flags); + + data->length = (curr_pos - extra); + data->flags = 0; + + return 0; +} +#endif // #if WIRELESS_EXT > 13 - if (ret == 0) { - dev->channel = chan; - dbg(DBG_IOCTL, "%s: SIOCSIWFREQ ch %d", - netdev->name, chan); - changed = 1; - } - } - break; - case SIOCGIWMODE: - dbg(DBG_IOCTL, "%s: SIOCGIWMODE", netdev->name); - wrq->u.mode = dev->iw_mode; - break; +static +int at76c503_iw_handler_set_essid(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWESSID - %s", netdev->name, extra); + + if (data->flags) + { + memcpy(dev->essid, extra, data->length); + // iwconfig gives len including 0 byte - + // 3 hours debugging... grrrr (oku) + dev->essid_size = data->length - 1; + } + else + { + dev->essid_size = 0; + } + + return -EIWCOMMIT; +} - case SIOCSIWMODE: - dbg(DBG_IOCTL, "%s: SIOCSIWMODE %d", netdev->name, wrq->u.mode); - if ((wrq->u.mode != IW_MODE_ADHOC) && - (wrq->u.mode != IW_MODE_INFRA)) - ret = -EINVAL; - else { - dev->iw_mode = wrq->u.mode; - changed = 1; +static +int at76c503_iw_handler_get_essid(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + if (dev->essid_size) { + // not the ANY ssid in dev->essid + data->flags = 1; + data->length = dev->essid_size; + memcpy(extra, dev->essid, data->length); + extra[data->length] = '\0'; + data->length += 1; + } else { + // the ANY ssid was specified + if (dev->istate == CONNECTED && + dev->curr_bss != NULL) { + // report the SSID we have found + data->flags = 1; + data->length = dev->curr_bss->ssid_len; + memcpy(extra, dev->curr_bss->ssid, data->length); + extra[dev->curr_bss->ssid_len] = '\0'; + data->length += 1; + } else { + // report ANY back + data->flags=0; + data->length=0; } - break; + } + + dbg(DBG_IOCTL, "%s: SIOCGIWESSID - %s", netdev->name, extra); + + return 0; +} - case SIOCGIWESSID: - dbg(DBG_IOCTL, "%s: SIOCGIWESSID", netdev->name); - { - char *essid = NULL; - struct iw_point *erq = &wrq->u.essid; - - if (dev->essid_size) { - /* not the ANY ssid in dev->essid */ - erq->flags = 1; - erq->length = dev->essid_size; - essid = dev->essid; - } else { - /* the ANY ssid was specified */ - if (dev->istate == CONNECTED && - dev->curr_bss != NULL) { - /* report the SSID we have found */ - erq->flags=1; - erq->length = dev->curr_bss->ssid_len; - essid = dev->curr_bss->ssid; - } else { - /* report ANY back */ - erq->flags=0; - erq->length=0; - } - } +static +int at76c503_iw_handler_set_nickname(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWNICKN - %s", netdev->name, extra); + + // iwconfig gives length including 0 byte like in the case of essid + memcpy(dev->nickn, extra, data->length); + + return 0; +} - if(erq->pointer){ - if(copy_to_user(erq->pointer, essid, - erq->length)){ - ret = -EFAULT; - } - } +static +int at76c503_iw_handler_get_nickname(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *data, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + data->length = strlen(dev->nickn); + memcpy(extra, dev->nickn, data->length); + extra[data->length] = '\0'; + data->length += 1; + + dbg(DBG_IOCTL, "%s: SIOCGIWNICKN - %s", netdev->name, extra); + + return 0; +} - } - break; +static +int at76c503_iw_handler_set_rate(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *bitrate, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: SIOCSIWRATE - %d", netdev->name, + bitrate->value); + + switch (bitrate->value) + { + case -1: dev->txrate = TX_RATE_AUTO; break; // auto rate + case 1000000: dev->txrate = TX_RATE_1MBIT; break; + case 2000000: dev->txrate = TX_RATE_2MBIT; break; + case 5500000: dev->txrate = TX_RATE_5_5MBIT; break; + case 11000000: dev->txrate = TX_RATE_11MBIT; break; + default: ret = -EINVAL; + } + + return ret; +} - case SIOCSIWESSID: - { - char essidbuf[IW_ESSID_MAX_SIZE+1]; - struct iw_point *erq = &wrq->u.essid; +static +int at76c503_iw_handler_get_rate(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *bitrate, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = 0; + + switch (dev->txrate) + { + // return max rate if RATE_AUTO + case TX_RATE_AUTO: bitrate->value = 11000000; break; + case TX_RATE_1MBIT: bitrate->value = 1000000; break; + case TX_RATE_2MBIT: bitrate->value = 2000000; break; + case TX_RATE_5_5MBIT: bitrate->value = 5500000; break; + case TX_RATE_11MBIT: bitrate->value = 11000000; break; + default: ret = -EINVAL; + } + + bitrate->fixed = (dev->txrate != TX_RATE_AUTO); + bitrate->disabled = 0; + + dbg(DBG_IOCTL, "%s: SIOCGIWRATE - %d", netdev->name, + bitrate->value); + + return ret; +} - memset(&essidbuf, 0, sizeof(essidbuf)); +static +int at76c503_iw_handler_set_rts(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *rts, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + int rthr = rts->value; + + dbg(DBG_IOCTL, "%s: SIOCSIWRTS - value %d disabled %s", + netdev->name, rts->value, + (rts->disabled) ? "true" : "false"); + + if (rts->disabled) + rthr = MAX_RTS_THRESHOLD; + + if ((rthr < 0) || (rthr > MAX_RTS_THRESHOLD)) { + ret = -EINVAL; + } else { + dev->rts_threshold = rthr; + } + + return ret; +} - if (erq->flags) { - if (erq->length > IW_ESSID_MAX_SIZE){ - ret = -E2BIG; - goto csiwessid_error; - } +static +int at76c503_iw_handler_get_rts(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *rts, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; - if (copy_from_user(essidbuf, erq->pointer, erq->length)){ - ret = -EFAULT; - goto csiwessid_error; - } + rts->value = dev->rts_threshold; + rts->disabled = (rts->value >= MAX_RTS_THRESHOLD); + rts->fixed = 1; - assert(erq->length > 0); - /* iwconfig gives len including 0 byte - - 3 hours debugging... grrrr (oku) */ - dev->essid_size = erq->length - 1; - dbg(DBG_IOCTL, "%s: SIOCSIWESSID %d %s", netdev->name, - dev->essid_size, essidbuf); - memcpy(dev->essid, essidbuf, IW_ESSID_MAX_SIZE); - } else - dev->essid_size = 0; /* ANY ssid */ - changed = 1; - } - csiwessid_error: - break; + dbg(DBG_IOCTL, "%s: SIOCGIWRTS - value %d disabled %s", + netdev->name, rts->value, + (rts->disabled) ? "true" : "false"); + + return 0; +} - case SIOCGIWRATE: - wrq->u.bitrate.value = dev->txrate == TX_RATE_1MBIT ? 1000000 : - dev->txrate == TX_RATE_2MBIT ? 2000000 : - dev->txrate == TX_RATE_5_5MBIT ? 5500000 : - dev->txrate == TX_RATE_11MBIT ? 11000000 : 11000000; - wrq->u.bitrate.fixed = (dev->txrate != TX_RATE_AUTO); - wrq->u.bitrate.disabled = 0; - break; +static +int at76c503_iw_handler_set_frag(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *frag, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EIWCOMMIT; + int fthr = frag->value; + + dbg(DBG_IOCTL, "%s: SIOCSIWFRAG - value %d, disabled %s", + netdev->name, frag->value, + (frag->disabled) ? "true" : "false"); + + if(frag->disabled) + fthr = MAX_FRAG_THRESHOLD; + + if ((fthr < MIN_FRAG_THRESHOLD) || (fthr > MAX_FRAG_THRESHOLD)) { + ret = -EINVAL; + } else { + dev->frag_threshold = fthr & ~0x1; // get an even value + } + + return ret; +} - case SIOCSIWRATE: - dbg(DBG_IOCTL, "%s: SIOCSIWRATE %d", netdev->name, - wrq->u.bitrate.value); - changed = 1; - switch (wrq->u.bitrate.value){ - case -1: dev->txrate = 4; break; /* auto rate */ - case 1000000: dev->txrate = 0; break; - case 2000000: dev->txrate = 1; break; - case 5500000: dev->txrate = 2; break; - case 11000000: dev->txrate = 3; break; - default: - ret = -EINVAL; - changed = 0; +static +int at76c503_iw_handler_get_frag(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *frag, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + frag->value = dev->frag_threshold; + frag->disabled = (frag->value >= MAX_FRAG_THRESHOLD); + frag->fixed = 1; + + dbg(DBG_IOCTL, "%s: SIOCGIWFRAG - value %d, disabled %s", + netdev->name, frag->value, + (frag->disabled) ? "true" : "false"); + + return 0; +} + +static +int at76c503_iw_handler_get_txpow(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *power, + char *extra) +{ + power->value = 15; + power->fixed = 1; /* No power control */ + power->disabled = 0; + power->flags = IW_TXPOW_DBM; + + dbg(DBG_IOCTL, "%s: SIOCGIWTXPOW - txpow %d dBm", netdev->name, + power->value); + + return 0; +} + +// disabled as setting the retry value seems to not be possible with +// at76c50x devices +// adapted (ripped) from atmel.c +/*static +int at76c503_iw_handler_set_retry(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *retry, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int ret = -EINPROGRESS; + + if(!retry->disabled && (retry->flags & IW_RETRY_LIMIT)) { + //if(retry->flags & IW_RETRY_MAX) { + // priv->long_retry_limit = retry->value; + //} else + if (retry->flags & IW_RETRY_MIN) { + dev->short_retry_limit = retry->value; + } else { + // No modifier : set both + //priv->long_retry = retry->value; + dev->short_retry_limit = retry->value; } - break; + } else { + ret = -EINVAL; + } + + return ret; +}*/ + +// adapted (ripped) from atmel.c +static +int at76c503_iw_handler_get_retry(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *retry, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + retry->disabled = 0; // Can't be disabled + + // Note : by default, display the min retry number + //if((retry->flags & IW_RETRY_MAX)) { + // retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + // retry->value = dev->long_retry_limit; + //} else { + retry->flags = IW_RETRY_LIMIT; + retry->value = dev->short_retry_limit; + + //if(dev->long_retry_limit != dev->short_retry_limit) { + // dev->retry.flags |= IW_RETRY_MIN; + //} + //} - case SIOCSIWENCODE: - dbg(DBG_IOCTL, "%s: SIOCSIWENCODE enc.flags %08x " - "pointer %p len %d", netdev->name, wrq->u.encoding.flags, - wrq->u.encoding.pointer, wrq->u.encoding.length); - dbg(DBG_IOCTL, "%s: old wepstate: enabled %d key_id %d " - "excl_unencr %d\n", - dev->netdev->name, dev->wep_enabled, dev->wep_key_id, - dev->wep_excl_unencr); - changed = 1; - { - int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; - /* take the old default key if index is invalid */ - if((index < 0) || (index >= NR_WEP_KEYS)) - index = dev->wep_key_id; - if(wrq->u.encoding.pointer){ - int len = wrq->u.encoding.length; - - if(len > WEP_LARGE_KEY_LEN){ - len = WEP_LARGE_KEY_LEN; - } + return 0; +} - memset(dev->wep_keys[index], 0, WEP_KEY_SIZE); - if(copy_from_user(dev->wep_keys[index], - wrq->u.encoding.pointer, len)) { - dev->wep_keys_len[index] = 0; - changed = 0; - ret = -EFAULT; - }else{ - dev->wep_keys_len[index] = - len <= WEP_SMALL_KEY_LEN ? - WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; - dev->wep_enabled = 1; - } - } - - dev->wep_key_id = index; - dev->wep_enabled = ((wrq->u.encoding.flags & IW_ENCODE_DISABLED) == 0); - if (wrq->u.encoding.flags & IW_ENCODE_RESTRICTED) - dev->wep_excl_unencr = 1; - if (wrq->u.encoding.flags & IW_ENCODE_OPEN) - dev->wep_excl_unencr = 0; - - dbg(DBG_IOCTL, "%s: new wepstate: enabled %d key_id %d key_len %d " - "excl_unencr %d\n", - dev->netdev->name, dev->wep_enabled, dev->wep_key_id, - dev->wep_keys_len[dev->wep_key_id], - dev->wep_excl_unencr); +static +int at76c503_iw_handler_set_encode(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *encoding, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int index = (encoding->flags & IW_ENCODE_INDEX) - 1; + int len = encoding->length; + + dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - enc.flags %08x " + "pointer %p len %d", netdev->name, encoding->flags, + encoding->pointer, encoding->length); + dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - old wepstate: enabled %s key_id %d " + "auth_mode %s", + netdev->name, (dev->wep_enabled) ? "true" : "false", + dev->wep_key_id, + (dev->auth_mode == IEEE802_11_AUTH_ALG_SHARED_SECRET) ? + "restricted" : "open"); + + // take the old default key if index is invalid + if ((index < 0) || (index >= NR_WEP_KEYS)) + index = dev->wep_key_id; + + if (len > 0) + { + if (len > WEP_LARGE_KEY_LEN) + len = WEP_LARGE_KEY_LEN; + + memset(dev->wep_keys[index], 0, WEP_KEY_SIZE); + memcpy(dev->wep_keys[index], extra, len); + dev->wep_keys_len[index] = (len <= WEP_SMALL_KEY_LEN) ? + WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; + dev->wep_enabled = 1; + } + + dev->wep_key_id = index; + dev->wep_enabled = ((encoding->flags & IW_ENCODE_DISABLED) == 0); + + if (encoding->flags & IW_ENCODE_RESTRICTED) + dev->auth_mode = IEEE802_11_AUTH_ALG_SHARED_SECRET; + if (encoding->flags & IW_ENCODE_OPEN) + dev->auth_mode = IEEE802_11_AUTH_ALG_OPEN_SYSTEM; + + dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - new wepstate: enabled %s key_id %d " + "key_len %d auth_mode %s", + netdev->name, (dev->wep_enabled) ? "true" : "false", + dev->wep_key_id + 1, dev->wep_keys_len[dev->wep_key_id], + (dev->auth_mode == IEEE802_11_AUTH_ALG_SHARED_SECRET) ? + "restricted" : "open"); + + return 0; +} + +static +int at76c503_iw_handler_get_encode(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_point *encoding, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int index = (encoding->flags & IW_ENCODE_INDEX) - 1; + + if ((index < 0) || (index >= NR_WEP_KEYS)) + index = dev->wep_key_id; + + encoding->flags = + (dev->auth_mode == IEEE802_11_AUTH_ALG_SHARED_SECRET) ? + IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN; + + if (!dev->wep_enabled) + encoding->flags |= IW_ENCODE_DISABLED; + + if (encoding->pointer) + { + encoding->length = dev->wep_keys_len[index]; + + memcpy(extra, dev->wep_keys[index], dev->wep_keys_len[index]); + + encoding->flags |= (index + 1); + } + + dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - enc.flags %08x " + "pointer %p len %d", netdev->name, encoding->flags, + encoding->pointer, encoding->length); + dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - wepstate: enabled %s key_id %d " + "key_len %d auth_mode %s", + netdev->name, (dev->wep_enabled) ? "true" : "false", + dev->wep_key_id + 1, dev->wep_keys_len[dev->wep_key_id], + (dev->auth_mode == IEEE802_11_AUTH_ALG_SHARED_SECRET) ? + "restricted" : "open"); + + return 0; +} + +static +int at76c503_iw_handler_set_power(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *power, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + dbg(DBG_IOCTL, "%s: SIOCSIWPOWER - disabled %s flags x%x value x%x", + netdev->name, (power->disabled) ? "true" : "false", + power->flags, power->value); + + if (power->disabled) + { + dev->pm_mode = PM_ACTIVE; + } + else + { + // we set the listen_interval based on the period given + // no idea how to handle the timeout of iwconfig ??? + if (power->flags & IW_POWER_PERIOD) + { + dev->pm_period_us = power->value; } - break; + + dev->pm_mode = PM_SAVE; // use iw_priv to select SMART_SAVE + } + + return -EIWCOMMIT; +} - // Get the WEP keys and mode - case SIOCGIWENCODE: - dbg(DBG_IOCTL, "%s: SIOCGIWENCODE", netdev->name); +static +int at76c503_iw_handler_get_power(struct net_device *netdev, + IW_REQUEST_INFO *info, + struct iw_param *power, + char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + + power->disabled = dev->pm_mode == PM_ACTIVE; + + if ((power->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) + { + power->flags = IW_POWER_TIMEOUT; + power->value = 0; + } + else + { + unsigned long flags; + u16 beacon_int; // of the current bss + + power->flags = IW_POWER_PERIOD; + + spin_lock_irqsave(&dev->bss_list_spinlock, flags); + beacon_int = dev->curr_bss != NULL ? + dev->curr_bss->beacon_interval : 0; + spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); + + if (beacon_int != 0) { - int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; - if ((index < 0) || (index >= NR_WEP_KEYS)) - index = dev->wep_key_id; - - wrq->u.encoding.flags = - (dev->wep_excl_unencr) ? IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN; - if(!dev->wep_enabled) - wrq->u.encoding.flags |= IW_ENCODE_DISABLED; - if(wrq->u.encoding.pointer){ - wrq->u.encoding.length = dev->wep_keys_len[index]; - if (copy_to_user(wrq->u.encoding.pointer, - dev->wep_keys[index], - dev->wep_keys_len[index])) - ret = -EFAULT; - wrq->u.encoding.flags |= (index + 1); - } + power->value = + (beacon_int * dev->pm_period_beacon) << 10; } - break; + else + { + power->value = dev->pm_period_us; + } + } + + power->flags |= IW_POWER_ALL_R; + + dbg(DBG_IOCTL, "%s: SIOCGIWPOWER - disabled %s flags x%x value x%x", + netdev->name, (power->disabled) ? "true" : "false", + power->flags, power->value); + + return 0; +} -#if IW_MAX_SPY > 0 - // Set the spy list - case SIOCSIWSPY: - /* never needs a device restart */ - ret = ioctl_setspy(dev, &wrq->u.data); - break; - // Get the spy list - case SIOCGIWSPY: - ret = ioctl_getspy(dev, &wrq->u.data); - break; -#endif /* #if IW_MAX_SPY > 0 */ +/******************************************************************************* + * Private IOCTLS + */ +static +int at76c503_iw_handler_PRIV_IOCTL_SET_SHORT_PREAMBLE + (struct net_device *netdev, IW_REQUEST_INFO *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SHORT_PREAMBLE, %d", + netdev->name, val); + + if (val < 0 || val > 2) { + //allow value of 2 - in the win98 driver it stands + //for "auto preamble" ...? + ret = -EINVAL; + } else { + dev->preamble_type = val; + } + + return ret; +} - case SIOCSIWPOWER: - dbg(DBG_IOCTL, "%s: SIOCSIWPOWER disabled %d flags x%x value x%x", netdev->name, - wrq->u.power.disabled, wrq->u.power.flags, wrq->u.power.value); - if (wrq->u.power.disabled) - dev->pm_mode = PM_ACTIVE; - else { - /* we set the listen_interval based on the period given */ - /* no idea how to handle the timeout of iwconfig ??? */ - if (wrq->u.power.flags & IW_POWER_PERIOD) { - dev->pm_period_us = wrq->u.power.value; - } - dev->pm_mode = PM_SAVE; /* use iw_priv to select SMART_SAVE */ +static +int at76c503_iw_handler_PRIV_IOCTL_SET_DEBUG + (struct net_device *netdev, IW_REQUEST_INFO *info, + struct iw_point *data, char *extra) +{ + char *ptr; + u32 val; + + if (data->length > 0) { + val = simple_strtol(extra, &ptr, 0); + + if (ptr == extra) { + val = DBG_DEFAULTS; } - changed = 1; - break; + + dbg_uc("%s: PRIV_IOCTL_SET_DEBUG input %d: %s -> x%x", + netdev->name, data->length, extra, val); + } else { + val = DBG_DEFAULTS; + } + + dbg_uc("%s: PRIV_IOCTL_SET_DEBUG, old 0x%x new 0x%x", + netdev->name, debug, val); + + /* jal: some more output to pin down lockups */ + dbg_uc("%s: netif running %d queue_stopped %d carrier_ok %d", + netdev->name, + netif_running(netdev), + netif_queue_stopped(netdev), + netif_carrier_ok(netdev)); + + debug = val; + + return 0; +} - case SIOCGIWPOWER: - dbg(DBG_IOCTL, "%s: SIOCGIWPOWER", netdev->name); - wrq->u.power.disabled = dev->pm_mode == PM_ACTIVE; - if ((wrq->u.power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - wrq->u.power.flags = IW_POWER_TIMEOUT; - wrq->u.power.value = 0; - } else { - unsigned long flags; - u16 beacon_int; /* of the current bss */ - wrq->u.power.flags = IW_POWER_PERIOD; +static +int at76c503_iw_handler_PRIV_IOCTL_SET_POWERSAVE_MODE + (struct net_device *netdev, IW_REQUEST_INFO *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_POWERSAVE_MODE, %d (%s)", + netdev->name, val, + val == PM_ACTIVE ? "active" : val == PM_SAVE ? "save" : + val == PM_SMART_SAVE ? "smart save" : "<invalid>"); + if (val < PM_ACTIVE || val > PM_SMART_SAVE) { + ret = -EINVAL; + } else { + dev->pm_mode = val; + } + + return ret; +} - spin_lock_irqsave(&dev->bss_list_spinlock, flags); - beacon_int = dev->curr_bss != NULL ? - dev->curr_bss->beacon_interval : 0; - spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); - - if (beacon_int != 0) { - wrq->u.power.value = - (beacon_int * dev->pm_period_beacon) << 10; - } else - wrq->u.power.value = dev->pm_period_us; - } - wrq->u.power.flags |= IW_POWER_ALL_R; /* ??? */ - break; +static +int at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_TIMES + (struct net_device *netdev, IW_REQUEST_INFO *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int mint = *((int *)name); + int maxt = *((int *)name + 1); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SCAN_TIMES - min %d max %d", + netdev->name, mint, maxt); + if (mint <= 0 || maxt <= 0 || mint > maxt) { + ret = -EINVAL; + } else { + dev->scan_min_time = mint; + dev->scan_max_time = maxt; + } + + return ret; +} +static +int at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE + (struct net_device *netdev, IW_REQUEST_INFO *info, + char *name, char *extra) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + int val = *((int *)name); + int ret = -EIWCOMMIT; + + dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SCAN_MODE - mode %s", + netdev->name, (val = SCAN_TYPE_ACTIVE) ? "active" : + (val = SCAN_TYPE_PASSIVE) ? "passive" : "<invalid>"); + + if (val != SCAN_TYPE_ACTIVE && val != SCAN_TYPE_PASSIVE) { + ret = -EINVAL; + } else { + dev->scan_mode = val; + } + + return ret; +} + + + +#if WIRELESS_EXT > 12 +/******************************************************************************* + * structure that advertises the iw handlers of this driver + */ +static const iw_handler at76c503_handlers[] = +{ + (iw_handler) at76c503_iw_handler_commit, // SIOCSIWCOMMIT + (iw_handler) at76c503_iw_handler_get_name, // SIOCGIWNAME + (iw_handler) NULL, // SIOCSIWNWID + (iw_handler) NULL, // SIOCGIWNWID + (iw_handler) at76c503_iw_handler_set_freq, // SIOCSIWFREQ + (iw_handler) at76c503_iw_handler_get_freq, // SIOCGIWFREQ + (iw_handler) at76c503_iw_handler_set_mode, // SIOCSIWMODE + (iw_handler) at76c503_iw_handler_get_mode, // SIOCGIWMODE + (iw_handler) NULL, // SIOCSIWSENS + (iw_handler) NULL, // SIOCGIWSENS + (iw_handler) NULL, // -- hole -- + (iw_handler) at76c503_iw_handler_get_range, // SIOCGIWRANGE + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // SIOCGIWPRIV + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + +#if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) + (iw_handler) at76c503_iw_handler_set_spy, // SIOCSIWSPY + (iw_handler) at76c503_iw_handler_get_spy, // SIOCGIWSPY +#else + (iw_handler) NULL, // SIOCSIWSPY + (iw_handler) NULL, // SIOCGIWSPY +#endif + +#if WIRELESS_EXT > 15 + (iw_handler) at76c503_iw_handler_set_thrspy, // SIOCSIWTHRSPY + (iw_handler) at76c503_iw_handler_get_thrspy, // SIOCGIWTHRSPY +#else + (iw_handler) NULL, // SIOCSIWTHRSPY + (iw_handler) NULL, // SIOCGIWTHRSPY +#endif + + (iw_handler) NULL, // SIOCSIWAP + (iw_handler) at76c503_iw_handler_get_wap, // SIOCGIWAP + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // SIOCGIWAPLIST + (iw_handler) at76c503_iw_handler_set_scan, // SIOCSIWSCAN + (iw_handler) at76c503_iw_handler_get_scan, // SIOCGIWSCAN + (iw_handler) at76c503_iw_handler_set_essid, // SIOCSIWESSID + (iw_handler) at76c503_iw_handler_get_essid, // SIOCGIWESSID + (iw_handler) at76c503_iw_handler_set_nickname, // SIOCSIWNICKN + (iw_handler) at76c503_iw_handler_get_nickname, // SIOCGIWNICKN + (iw_handler) NULL, // -- hole -- + (iw_handler) NULL, // -- hole -- + (iw_handler) at76c503_iw_handler_set_rate, // SIOCSIWRATE + (iw_handler) at76c503_iw_handler_get_rate, // SIOCGIWRATE + (iw_handler) at76c503_iw_handler_set_rts, // SIOCSIWRTS + (iw_handler) at76c503_iw_handler_get_rts, // SIOCGIWRTS + (iw_handler) at76c503_iw_handler_set_frag, // SIOCSIWFRAG + (iw_handler) at76c503_iw_handler_get_frag, // SIOCGIWFRAG + (iw_handler) NULL, // SIOCSIWTXPOW + (iw_handler) at76c503_iw_handler_get_txpow, // SIOCGIWTXPOW + /*(iw_handler) at76c503_iw_handler_set_retry, // SIOCSIWRETRY*/ + (iw_handler) NULL, // SIOCSIWRETRY + (iw_handler) at76c503_iw_handler_get_retry, // SIOCGIWRETRY + (iw_handler) at76c503_iw_handler_set_encode, // SIOCSIWENCODE + (iw_handler) at76c503_iw_handler_get_encode, // SIOCGIWENCODE + (iw_handler) at76c503_iw_handler_set_power, // SIOCSIWPOWER + (iw_handler) at76c503_iw_handler_get_power, // SIOCGIWPOWER +}; + +/******************************************************************************* + * structure that advertises the private iw handlers of this driver + */ +static const iw_handler at76c503_priv_handlers[] = +{ + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SHORT_PREAMBLE, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_DEBUG, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_POWERSAVE_MODE, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_TIMES, + (iw_handler) NULL, + (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE, + (iw_handler) NULL, +}; + +static const struct iw_handler_def at76c503_handler_def = +{ + .num_standard = sizeof(at76c503_handlers)/sizeof(iw_handler), + .num_private = sizeof(at76c503_priv_handlers)/sizeof(iw_handler), + .num_private_args = sizeof(at76c503_priv_args)/ + sizeof(struct iw_priv_args), + .standard = (iw_handler *) at76c503_handlers, + .private = (iw_handler *) at76c503_priv_handlers, + .private_args = (struct iw_priv_args *) at76c503_priv_args, +#if WIRELESS_EXT > 15 + .spy_offset = offsetof(struct at76c503, spy_data), +#endif // #if WIRELESS_EXT > 15 + +}; + +#endif // #if WIRELESS_EXT > 12 + + + +static +int at76c503_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct at76c503 *dev = (struct at76c503*)netdev->priv; + struct iwreq *wrq = (struct iwreq *)rq; + int ret = 0; + + if (! netif_device_present(netdev)) + return -ENODEV; + + if (down_interruptible(&dev->sem)) + return -EINTR; + + switch (cmd) { + + // rudimentary ethtool support for hotplug of SuSE 8.3 + case SIOCETHTOOL: + { + ret = ethtool_ioctl(dev,rq->ifr_data); + } + break; + + case SIOCGIWNAME: + { + at76c503_iw_handler_get_name(netdev, NULL, + wrq->u.name, NULL); + } + break; + + case SIOCSIWFREQ: + { + ret = at76c503_iw_handler_set_freq(netdev, NULL, + &(wrq->u.freq), NULL); + } + break; + + case SIOCGIWFREQ: + { + at76c503_iw_handler_get_freq(netdev, NULL, + &(wrq->u.freq), NULL); + } + break; + + case SIOCSIWMODE: + { + ret = at76c503_iw_handler_set_mode(netdev, NULL, + &(wrq->u.mode), NULL); + } + break; + + case SIOCGIWMODE: + { + at76c503_iw_handler_get_mode(netdev, NULL, + &(wrq->u.mode), NULL); + } + break; + + case SIOCGIWRANGE: + { + char extra[sizeof(struct iw_range)]; + + at76c503_iw_handler_get_range(netdev, NULL, + &(wrq->u.data), extra); + + if (copy_to_user(wrq->u.data.pointer, extra, + sizeof(struct iw_range))) { + ret = -EFAULT; + } + } + break; + case SIOCGIWPRIV: - if (wrq->u.data.pointer) { - const struct iw_priv_args priv[] = { - { PRIV_IOCTL_SET_SHORT_PREAMBLE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "short_preamble" }, /* 0 - long, 1 -short */ - - { PRIV_IOCTL_SET_DEBUG, - /* we must pass the new debug mask as a string, - 'cause iwpriv cannot parse hex numbers - starting with 0x :-( */ - IW_PRIV_TYPE_CHAR | 10, 0, - "set_debug"}, /* set debug value */ - - { PRIV_IOCTL_SET_AUTH_MODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "auth_mode"}, /* 0 - open , 1 - shared secret */ - - { PRIV_IOCTL_LIST_BSS, - 0, 0, "list_bss"}, /* dump current bss table */ - - { PRIV_IOCTL_SET_POWERSAVE_MODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "powersave_mode"}, /* 1 - active, 2 - power save, - 3 - smart power save */ - { PRIV_IOCTL_SET_SCAN_TIMES, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, - "scan_times"}, /* min_channel_time, - max_channel_time */ - { PRIV_IOCTL_SET_SCAN_MODE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, - "scan_mode"}, /* 0 - active, 1 - passive scan */ - }; - - wrq->u.data.length = sizeof(priv) / sizeof(priv[0]); - if (copy_to_user(wrq->u.data.pointer, priv, - sizeof(priv))) - ret = -EFAULT; + { + char extra[sizeof(at76c503_priv_args)]; + + at76c503_iw_handler_get_priv(netdev, NULL, + &(wrq->u.data), extra); + + if (copy_to_user(wrq->u.data.pointer, extra, + sizeof(at76c503_priv_args))) { + ret = -EFAULT; } - break; - - case PRIV_IOCTL_SET_SHORT_PREAMBLE: + } + break; + +#if (WIRELESS_EXT <= 15) && (IW_MAX_SPY > 0) + // Set the spy list + case SIOCSIWSPY: { - int val = *((int *)wrq->u.name); - dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SHORT_PREAMBLE, %d", - dev->netdev->name, val); - if (val < 0 || val > 2) - //allow value of 2 - in the win98 driver it stands - //for "auto preamble" ...? - ret = -EINVAL; - else { - dev->preamble_type = val; - changed = 1; + char extra[sizeof(struct sockaddr) * IW_MAX_SPY]; + + if (wrq->u.data.length > IW_MAX_SPY) { + ret = -E2BIG; + goto sspyerror; } + + if (copy_from_user(extra, wrq->u.data.pointer, + sizeof(struct sockaddr) * dev->iwspy_nr)) { + dev->iwspy_nr = 0; + ret = -EFAULT; + goto sspyerror; + } + + // never needs a device restart + at76c503_iw_handler_set_spy(netdev, NULL, + &(wrq->u.data), extra); } +sspyerror: break; - - case PRIV_IOCTL_SET_DEBUG: + + // Get the spy list + case SIOCGIWSPY: { - char *ptr, nbuf[10+1]; - struct iw_point *erq = &wrq->u.data; - u32 val; + // one sockaddr and iw_quality struct for each station we spy on + char extra[(sizeof(struct sockaddr) + sizeof(struct iw_quality)) + * wrq->u.data.length]; - if (erq->length > 0) { - if (copy_from_user(nbuf, erq->pointer, - min((int)sizeof(nbuf),(int)erq->length))) { - ret = -EFAULT; - goto set_debug_end; - } - val = simple_strtol(nbuf, &ptr, 0); - if (ptr == nbuf) - val = DBG_DEFAULTS; - dbg_uc("%s: PRIV_IOCTL_SET_DEBUG input %d: %s -> x%x", - dev->netdev->name, erq->length, nbuf, val); - } else - val = DBG_DEFAULTS; - dbg_uc("%s: PRIV_IOCTL_SET_DEBUG, old 0x%x new 0x%x", - dev->netdev->name, debug, val); - /* jal: some more output to pin down lockups */ - dbg_uc("%s: netif running %d queue_stopped %d carrier_ok %d", - dev->netdev->name, - netif_running(dev->netdev), - netif_queue_stopped(dev->netdev), - netif_carrier_ok(dev->netdev)); - debug = val; - } - set_debug_end: + at76c503_iw_handler_get_spy(netdev, NULL, + &(wrq->u.data), extra); + + if (copy_to_user(wrq->u.data.pointer, dev->iwspy_addr, + (sizeof(struct sockaddr) + + sizeof(struct iw_quality)) * + wrq->u.data.length)) { + ret = -EFAULT; + } + } break; - - case PRIV_IOCTL_SET_AUTH_MODE: +#endif // #if (WIRELESS_EXT <= 15) && (IW_MAX_SPY > 0) + + /*case SIOCSIWAP: { - int val = *((int *)wrq->u.name); - dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_AUTH_MODE, %d (%s)", - dev->netdev->name, val, - val == 0 ? "open system" : val == 1 ? "shared secret" : - "<invalid>"); - if (val < 0 || val > 1) - ret = -EINVAL; - else { - dev->auth_mode = (val ? IEEE802_11_AUTH_ALG_SHARED_SECRET : - IEEE802_11_AUTH_ALG_OPEN_SYSTEM); - changed = 1; + } + break;*/ + + case SIOCGIWAP: + { + at76c503_iw_handler_get_wap(netdev, NULL, + &(wrq->u.ap_addr), NULL); + } + break; + + /*case SIOCGIWAPLIST: + { + } + break;*/ + +#if WIRELESS_EXT > 13 + case SIOCSIWSCAN: + { + ret = at76c503_iw_handler_set_scan(netdev, NULL, NULL, NULL); + } + break; + + case SIOCGIWSCAN: + { + char extra[IW_SCAN_MAX_DATA]; + + at76c503_iw_handler_get_scan(netdev, NULL, + &(wrq->u.data), extra); + + if (copy_to_user(wrq->u.data.pointer, extra, + wrq->u.data.length)) { + ret = -EFAULT; } } break; - - case PRIV_IOCTL_LIST_BSS: - dump_bss_table(dev, 1); - break; - - case PRIV_IOCTL_SET_POWERSAVE_MODE: +#endif // #if WIRELESS_EXT > 13 + + case SIOCSIWESSID: { - int val = *((int *)wrq->u.name); - dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_POWERSAVE_MODE, %d (%s)", - dev->netdev->name, val, - val == PM_ACTIVE ? "active" : val == PM_SAVE ? "save" : - val == PM_SMART_SAVE ? "smart save" : "<invalid>"); - if (val < PM_ACTIVE || val > PM_SMART_SAVE) - ret = -EINVAL; - else { - dev->pm_mode = val; - changed = 1; + char extra[IW_ESSID_MAX_SIZE + 1]; + + if (wrq->u.data.length > IW_ESSID_MAX_SIZE) { + return -E2BIG; + goto sessiderror; } + + if (copy_from_user(extra, wrq->u.data.pointer, + wrq->u.data.length)) { + ret = -EFAULT; + goto sessiderror; + } + + ret = at76c503_iw_handler_set_essid(netdev, NULL, + &(wrq->u.data), extra); } +sessiderror: break; - - case PRIV_IOCTL_SET_SCAN_TIMES: + + case SIOCGIWESSID: { - int mint = *((int *)wrq->u.name); - int maxt = *((int *)wrq->u.name + 1); - dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SCAN_TIMES, %d %d", - dev->netdev->name, mint, maxt); - if (mint <= 0 || maxt <= 0 || mint > maxt) - ret = -EINVAL; - else { - dev->scan_min_time = mint; - dev->scan_max_time = maxt; - changed = 1; + char extra[IW_ESSID_MAX_SIZE + 1]; + + at76c503_iw_handler_get_essid(netdev, NULL, + &(wrq->u.data), extra); + + if (copy_to_user(wrq->u.data.pointer, extra, + wrq->u.data.length)) { + ret = -EFAULT; } } break; - - case PRIV_IOCTL_SET_SCAN_MODE: + + case SIOCSIWNICKN: { - int val = *((int *)wrq->u.name); - dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_SCAN_MODE, %d", - dev->netdev->name, val); - if (val != SCAN_TYPE_ACTIVE && val != SCAN_TYPE_PASSIVE) - ret = -EINVAL; - else { - dev->scan_mode = val; - changed = 1; + char extra[IW_ESSID_MAX_SIZE + 1]; + + if (wrq->u.data.length > IW_ESSID_MAX_SIZE) { + return -E2BIG; + goto snickerror; } + + if (copy_from_user(extra, wrq->u.data.pointer, + wrq->u.data.length)) { + ret = -EFAULT; + goto snickerror; + } + + ret = at76c503_iw_handler_set_nickname(netdev, NULL, + &(wrq->u.data), extra); + } +snickerror: + break; + + case SIOCGIWNICKN: + { + char extra[IW_ESSID_MAX_SIZE + 1]; + + at76c503_iw_handler_get_nickname(netdev, NULL, + &(wrq->u.data), extra); + + if (copy_to_user(wrq->u.data.pointer, extra, + wrq->u.data.length)) { + ret = -EFAULT; + } + } + break; + + case SIOCSIWRATE: + { + ret = at76c503_iw_handler_set_rate(netdev, NULL, + &(wrq->u.bitrate), NULL); + } + break; + + case SIOCGIWRATE: + { + at76c503_iw_handler_get_rate(netdev, NULL, + &(wrq->u.bitrate), NULL); + } + break; + + case SIOCSIWRTS: + { + ret = at76c503_iw_handler_set_rts(netdev, NULL, + &(wrq->u.rts), NULL); + } + break; + + case SIOCGIWRTS: + { + at76c503_iw_handler_get_rts(netdev, NULL, + &(wrq->u.rts), NULL); + } + break; + + case SIOCSIWFRAG: + { + ret = at76c503_iw_handler_set_frag(netdev, NULL, + &(wrq->u.frag), NULL); + } + break; + + case SIOCGIWFRAG: + { + at76c503_iw_handler_get_frag(netdev, NULL, + &(wrq->u.frag), NULL); + } + break; + + /*case SIOCSIWTXPOW: + { + + } + break;*/ + + case SIOCGIWTXPOW: + { + at76c503_iw_handler_get_txpow(netdev, NULL, + &(wrq->u.power), NULL); + } + break; + + /*case SIOCSIWRETRY: + { + ret = at76c503_iw_handler_set_retry(netdev, NULL, + &(wrq->u.retry), NULL); + } + break;*/ + + case SIOCGIWRETRY: + { + at76c503_iw_handler_get_retry(netdev, NULL, + &(wrq->u.retry), NULL); + } + break; + + case SIOCSIWENCODE: + { + char extra[WEP_KEY_SIZE + 1]; + + if (wrq->u.data.length > WEP_KEY_SIZE) { + return -E2BIG; + goto sencodeerror; + } + + if (copy_from_user(extra, wrq->u.data.pointer, + wrq->u.data.length)) { + ret = -EFAULT; + goto sencodeerror; + } + + ret = at76c503_iw_handler_set_encode(netdev, NULL, + &(wrq->u.encoding), extra); + } +sencodeerror: + break; + + case SIOCGIWENCODE: + { + char extra[WEP_KEY_SIZE + 1]; + + at76c503_iw_handler_get_encode(netdev, NULL, + &(wrq->u.encoding), extra); + + if (copy_to_user(wrq->u.data.pointer, extra, + wrq->u.data.length)) { + ret = -EFAULT; + } + } + break; + + case SIOCSIWPOWER: + { + ret = at76c503_iw_handler_set_power(netdev, NULL, + &(wrq->u.power), NULL); + } + break; + + case SIOCGIWPOWER: + { + at76c503_iw_handler_get_power(netdev, NULL, + &(wrq->u.power), NULL); + } + break; + + case PRIV_IOCTL_SET_SHORT_PREAMBLE: + { + ret = at76c503_iw_handler_PRIV_IOCTL_SET_SHORT_PREAMBLE + (netdev, NULL, wrq->u.name, NULL); } break; + case PRIV_IOCTL_SET_DEBUG: + { + char extra[wrq->u.data.length]; + + if (copy_from_user(extra, wrq->u.data.pointer, + wrq->u.data.length)) { + ret = -EFAULT; + goto set_debug_end; + } + + at76c503_iw_handler_PRIV_IOCTL_SET_DEBUG + (netdev, NULL, &(wrq->u.data), extra); + } +set_debug_end: + break; + + case PRIV_IOCTL_SET_POWERSAVE_MODE: + { + ret = at76c503_iw_handler_PRIV_IOCTL_SET_POWERSAVE_MODE + (netdev, NULL, wrq->u.name, NULL); + } + break; + + case PRIV_IOCTL_SET_SCAN_TIMES: + { + ret = at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_TIMES + (netdev, NULL, wrq->u.name, NULL); + } + break; + + case PRIV_IOCTL_SET_SCAN_MODE: + { + ret = at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE + (netdev, NULL, wrq->u.name, NULL); + } + break; + default: - dbg(DBG_IOCTL, "%s: ioctl not supported (0x%x)", netdev->name, cmd); + dbg(DBG_IOCTL, "%s: ioctl not supported (0x%x)", netdev->name, + cmd); ret = -EOPNOTSUPP; } - -#if 1 - - /* we only startup the device if it was already opened before. */ - if ((changed) && (dev->open_count > 0)) { - - unsigned long flags; - - assert(ret >= 0); - - dbg(DBG_IOCTL, "%s %s: restarting the device", dev->netdev->name, - __FUNCTION__); - - /* stop any pending tx bulk urb */ - - /* jal: TODO: protect access to dev->istate by a spinlock - (ISR's on other processors may read/write it) */ - if (dev->istate != INIT) { - dev->istate = INIT; - /* stop pending management stuff */ - del_timer_sync(&dev->mgmt_timer); - - spin_lock_irqsave(&dev->mgmt_spinlock,flags); - if (dev->next_mgmt_bulk) { - kfree(dev->next_mgmt_bulk); - dev->next_mgmt_bulk = NULL; - } - spin_unlock_irqrestore(&dev->mgmt_spinlock,flags); - - netif_carrier_off(dev->netdev); - netif_stop_queue(dev->netdev); + + // we only restart the device if it was changed and already opened + // before + if (ret == -EIWCOMMIT) { + if (dev->open_count > 0) { + at76c503_iw_handler_commit(netdev, NULL, NULL, NULL); } - - /* do the restart after two seconds to catch - following ioctl's (from more params of iwconfig) - in _one_ restart */ - mod_timer(&dev->restart_timer, jiffies+2*HZ); -} -#endif + + // reset ret so that this ioctl can return success + ret = 0; + } + up(&dev->sem); return ret; } @@ -4869,7 +6031,6 @@ void at76c503_delete_device(struct at76c503 *dev) if (!dev) return; - /* signal to _stop() that the device is gone */ dev->flags |= AT76C503A_UNPLUG; @@ -4879,7 +6040,7 @@ void at76c503_delete_device(struct at76c503 *dev) if ((sem_taken=down_trylock(&rtnl_sem)) != 0) info("%s: rtnl_sem already down'ed", __FUNCTION__); - /* synchronously calls at76c503a_stop() */ + /* synchronously calls at76c503_stop() */ unregister_netdevice(dev->netdev); if (!sem_taken) @@ -5053,9 +6214,12 @@ struct at76c503 *alloc_new_device(struct usb_device *udev, int board_type, dev->bss_list_timer.data = (unsigned long)dev; dev->bss_list_timer.function = bss_list_timeout; -#if IW_MAX_SPY > 0 +#if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) + dev->spy_spinlock = SPIN_LOCK_UNLOCKED; +#if WIRELESS_EXT <= 15 dev->iwspy_nr = 0; #endif +#endif /* mark all rx data entries as unused */ for(i=0; i < NR_RX_DATA_BUF; i++) @@ -5119,7 +6283,7 @@ int init_new_device(struct at76c503 *dev) else dev->rx_data_fcs_len = 4; - info("$Id: at76c503.c,v 1.45 2004/03/17 22:35:07 jal2 Exp $ compiled %s %s", __DATE__, __TIME__); + info("$Id: at76c503.c,v 1.46 2004/03/18 20:54:57 jal2 Exp $ compiled %s %s", __DATE__, __TIME__); info("firmware version %d.%d.%d #%d (fcs_len %d)", dev->fw_version.major, dev->fw_version.minor, dev->fw_version.patch, dev->fw_version.build, @@ -5148,6 +6312,8 @@ int init_new_device(struct at76c503 *dev) strncpy(dev->nickn, DEF_ESSID, sizeof(dev->nickn)); dev->rts_threshold = DEF_RTS_THRESHOLD; dev->frag_threshold = DEF_FRAG_THRESHOLD; + dev->short_retry_limit = DEF_SHORT_RETRY_LIMIT; + //dev->long_retr_limit = DEF_LONG_RETRY_LIMIT; dev->txrate = TX_RATE_AUTO; dev->preamble_type = preamble_type; dev->auth_mode = auth_mode ? IEEE802_11_AUTH_ALG_SHARED_SECRET : @@ -5163,6 +6329,10 @@ int init_new_device(struct at76c503 *dev) netdev->get_wireless_stats = at76c503_get_wireless_stats; netdev->hard_start_xmit = at76c503_tx; netdev->tx_timeout = at76c503_tx_timeout; +#if WIRELESS_EXT > 12 + netdev->wireless_handlers = + (struct iw_handler_def*)&at76c503_handler_def; +#endif netdev->do_ioctl = at76c503_ioctl; netdev->set_multicast_list = at76c503_set_multicast; netdev->set_mac_address = at76c503_set_mac_address; @@ -1,5 +1,5 @@ /* -*- linux-c -*- */ -/* $Id: at76c503.h,v 1.20 2004/03/17 22:35:07 jal2 Exp $ +/* $Id: at76c503.h,v 1.21 2004/03/18 20:54:57 jal2 Exp $ * * USB at76c503 driver * @@ -18,6 +18,9 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/wireless.h> +#if WIRELESS_EXT > 12 +#include <net/iw_handler.h> +#endif #include <linux/version.h> #include "ieee802_11.h" /* we need some constants here */ @@ -56,17 +59,13 @@ /* set preamble length*/ #define PRIV_IOCTL_SET_SHORT_PREAMBLE (SIOCIWFIRSTPRIV + 0x0) /* set debug parameter */ -#define PRIV_IOCTL_SET_DEBUG (SIOCIWFIRSTPRIV + 0x1) -/* set authentication mode: 0 - open, 1 - shared key */ -#define PRIV_IOCTL_SET_AUTH_MODE (SIOCIWFIRSTPRIV + 0x2) -/* dump bss table */ -#define PRIV_IOCTL_LIST_BSS (SIOCIWFIRSTPRIV + 0x3) +#define PRIV_IOCTL_SET_DEBUG (SIOCIWFIRSTPRIV + 0x2) /* set power save mode (incl. the Atmel proprietary smart save mode */ #define PRIV_IOCTL_SET_POWERSAVE_MODE (SIOCIWFIRSTPRIV + 0x4) /* set min and max channel times for scan */ -#define PRIV_IOCTL_SET_SCAN_TIMES (SIOCIWFIRSTPRIV + 0x5) +#define PRIV_IOCTL_SET_SCAN_TIMES (SIOCIWFIRSTPRIV + 0x6) /* set scan mode */ -#define PRIV_IOCTL_SET_SCAN_MODE (SIOCIWFIRSTPRIV + 0x6) +#define PRIV_IOCTL_SET_SCAN_MODE (SIOCIWFIRSTPRIV + 0x8) #define DEVICE_VENDOR_REQUEST_OUT 0x40 #define DEVICE_VENDOR_REQUEST_IN 0xc0 @@ -498,7 +497,6 @@ struct at76c503 { u8 op_mode; /* the WEP stuff */ - int wep_excl_unencr; /* 1 if unencrypted packets shall be discarded */ int wep_enabled; /* 1 if WEP is enabled */ int wep_key_id; /* key id to be used */ u8 wep_keys[NR_WEP_KEYS][WEP_KEY_SIZE]; /* the four WEP keys, @@ -520,6 +518,8 @@ struct at76c503 { int txrate; /* 0,1,2,3 = 1,2,5.5,11 MBit, 4 is auto-fallback */ int frag_threshold; /* threshold for fragmentation of tx packets */ int rts_threshold; /* threshold for RTS mechanism */ + int short_retry_limit; + //int long_retry_limit; int scan_min_time; /* scan min channel time */ int scan_max_time; /* scan max channel time */ @@ -560,11 +560,16 @@ struct at76c503 { struct reg_domain const *domain; /* the description of the regulatory domain */ /* iwspy support */ -#if IW_MAX_SPY > 0 +#if (WIRELESS_EXT > 15) || (IW_MAX_SPY > 0) + spinlock_t spy_spinlock; +#if WIRELESS_EXT > 15 + struct iw_spy_data spy_data; +#else int iwspy_nr; /* nr of valid entries below */ struct sockaddr iwspy_addr[IW_MAX_SPY]; struct iw_quality iwspy_stats[IW_MAX_SPY]; #endif +#endif /* These fields contain HW config provided by the device (not all of * these fields are used by all board types) */ |