aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Roskin <proski@gnu.org>2007-05-01 20:00:52 -0400
committerGuido Guenther <agx@bogon.sigxcpu.org>2007-05-02 11:22:17 +0200
commita3181906b9d8cfa79f304a832b3bc26ad2d1d173 (patch)
tree9391bcb79a6f349c4d2faaa7b9f703be13087998
parent422e7aba187883c60075b2ef914e56d505862939 (diff)
[PATCH] Reorder the functions to avoid most forward declarations
Always use two newlines between functions. Re-format some function declatrations. Signed-off-by: Pavel Roskin <proski@gnu.org>
-rw-r--r--at76_usb.c5317
1 files changed, 2724 insertions, 2593 deletions
diff --git a/at76_usb.c b/at76_usb.c
index 59d9129..45d52d8 100644
--- a/at76_usb.c
+++ b/at76_usb.c
@@ -186,25 +186,6 @@ static int default_iw_mode = IW_MODE_INFRA;
static int monitor_scan_min_time = 50;
static int monitor_scan_max_time = 600;
-/* Function prototypes */
-static void at76_iwspy_update(struct at76_priv *dev, struct at76_rx_buffer *buf);
-static void at76_read_bulk_callback(struct urb *urb);
-static void at76_write_bulk_callback(struct urb *urb);
-static struct bss_info *at76_match_bss(struct at76_priv *dev,
- struct bss_info *curr);
-static int at76_auth_req(struct at76_priv *dev, struct bss_info *bss, int seq_nr,
- struct ieee80211_info_element *challenge);
-static int at76_disassoc_req(struct at76_priv *dev, struct bss_info *bss);
-static int at76_assoc_req(struct at76_priv *dev, struct bss_info *bss);
-static int at76_reassoc_req(struct at76_priv *dev, struct bss_info *curr,
- struct bss_info *new);
-static void at76_dump_bss_table(struct at76_priv *dev);
-static int at76_submit_rx_urb(struct at76_priv *dev);
-static int at76_startup_device(struct at76_priv *dev);
-static int at76_set_iroaming(struct at76_priv *dev, int onoff);
-static void at76_set_monitor_mode(struct at76_priv *dev);
-static int at76_init_new_device(struct at76_priv *dev);
-
/* the supported rates of this hardware, bit7 marks a basic rate */
static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 };
/* The frequency of each channel in MHz */
@@ -255,6 +236,7 @@ struct dfu_ctx {
void *buf;
};
+
static int at76_dfu_download_block(struct dfu_ctx *ctx, u8 *buffer, int bytes,
int block)
{
@@ -281,6 +263,7 @@ static int at76_dfu_download_block(struct dfu_ctx *ctx, u8 *buffer, int bytes,
return result;
}
+
static int at76_dfu_get_status(struct dfu_ctx *ctx, struct dfu_status *status)
{
int result;
@@ -297,6 +280,7 @@ static int at76_dfu_get_status(struct dfu_ctx *ctx, struct dfu_status *status)
return result;
}
+
static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
{
int result;
@@ -312,6 +296,7 @@ static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
return result;
}
+
static inline u32 at76_get_timeout(struct dfu_status *s)
{
u32 ret = (s->poll_timeout[2] << 16) | (s->poll_timeout[1] << 8) |
@@ -320,6 +305,7 @@ static inline u32 at76_get_timeout(struct dfu_status *s)
return ret;
}
+
static struct dfu_ctx *at76_dfu_alloc_ctx(struct usb_device *udev)
{
struct dfu_ctx *ctx;
@@ -332,6 +318,7 @@ static struct dfu_ctx *at76_dfu_alloc_ctx(struct usb_device *udev)
return ctx;
}
+
/* if manifest_sync_timeout > 0 use this timeout (in msec) instead of the
one reported by the device in state MANIFEST_SYNC */
static int at76_usbdfu_download(struct usb_device *udev, u8 *dfu_buffer,
@@ -473,6 +460,7 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *dfu_buffer,
return 0;
}
+
/* some abbrev. for wireless events */
static inline void at76_iwevent_scan_complete(struct net_device *dev)
{
@@ -483,6 +471,7 @@ static inline void at76_iwevent_scan_complete(struct net_device *dev)
at76_dbg(DBG_WE_EVENTS, "%s: SIOCGIWSCAN sent", dev->name);
}
+
static inline void at76_iwevent_bss_connect(struct net_device *dev, u8 *bssid)
{
union iwreq_data wrqu;
@@ -494,6 +483,7 @@ static inline void at76_iwevent_bss_connect(struct net_device *dev, u8 *bssid)
at76_dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", dev->name, __FUNCTION__);
}
+
static inline void at76_iwevent_bss_disconnect(struct net_device *dev)
{
union iwreq_data wrqu;
@@ -529,6 +519,7 @@ static char *hex2str(char *obuf, void *buf, int len, char delim)
return ret;
}
+
/* check if the given ssid is cloaked */
static inline int at76_is_cloaked_ssid(u8 *ssid, int length)
{
@@ -539,6 +530,7 @@ static inline int at76_is_cloaked_ssid(u8 *ssid, int length)
(length > 0 && !memcmp(ssid, zeros, length));
}
+
static inline void at76_free_bss_list(struct at76_priv *dev)
{
struct list_head *next, *ptr;
@@ -556,6 +548,7 @@ static inline void at76_free_bss_list(struct at76_priv *dev)
spin_unlock_irqrestore(&dev->bss_list_spinlock, flags);
}
+
static inline char *mac2str(u8 *mac)
{
static char str[6 * 3];
@@ -565,22 +558,18 @@ static inline char *mac2str(u8 *mac)
return str;
}
+
/* led trigger */
+static int tx_activity;
static void at76_ledtrig_tx_timerfunc(unsigned long data);
-DEFINE_LED_TRIGGER(ledtrig_tx);
static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0);
-static int tx_activity;
-static int tx_lastactivity;
+DEFINE_LED_TRIGGER(ledtrig_tx);
-static void at76_ledtrig_tx_activity(void)
-{
- tx_activity++;
- if (!timer_pending(&ledtrig_tx_timer))
- mod_timer(&ledtrig_tx_timer, jiffies + msecs_to_jiffies(250));
-}
static void at76_ledtrig_tx_timerfunc(unsigned long data)
{
+ static int tx_lastactivity;
+
if (tx_lastactivity != tx_activity) {
tx_lastactivity = tx_activity;
led_trigger_event(ledtrig_tx, LED_FULL);
@@ -591,6 +580,14 @@ static void at76_ledtrig_tx_timerfunc(unsigned long data)
}
+static void at76_ledtrig_tx_activity(void)
+{
+ tx_activity++;
+ if (!timer_pending(&ledtrig_tx_timer))
+ mod_timer(&ledtrig_tx_timer, jiffies + msecs_to_jiffies(250));
+}
+
+
static int at76_remap(struct usb_device *udev)
{
int ret;
@@ -616,15 +613,17 @@ static int at76_get_op_mode(struct usb_device *udev)
return op_mode;
}
+
/* this loads a block of the second part of the firmware */
-static inline int at76_load_ext_fw_block(struct usb_device *udev,
- int i, void *buf, int bsize)
+static inline int at76_load_ext_fw_block(struct usb_device *udev, int i,
+ void *buf, int bsize)
{
return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x0e, DEVICE_VENDOR_REQUEST_OUT,
0x0802, i, buf, bsize, USB_CTRL_GET_TIMEOUT);
}
+
static inline int at76_get_hw_cfg_rfmd(struct usb_device *udev,
union at76_hwcfg *buf, int buf_size)
{
@@ -634,6 +633,7 @@ static inline int at76_get_hw_cfg_rfmd(struct usb_device *udev,
buf, buf_size, USB_CTRL_GET_TIMEOUT);
}
+
/* Intersil boards use a different "value" for GetHWConfig requests */
static inline int get_hw_cfg_intersil(struct usb_device *udev,
union at76_hwcfg *buf, int buf_size)
@@ -644,6 +644,7 @@ static inline int get_hw_cfg_intersil(struct usb_device *udev,
buf, buf_size, USB_CTRL_GET_TIMEOUT);
}
+
/* Get the hardware configuration for the adapter and place the appropriate
* data in the appropriate fields of 'dev' (the GetHWConfig request and
* interpretation of the result depends on the type of board we're dealing
@@ -700,6 +701,7 @@ static int at76_get_hw_config(struct at76_priv *dev)
return ret;
}
+
static struct reg_domain const *at76_get_reg_domain(u16 code)
{
static struct reg_domain const fd_tab[] = {
@@ -726,6 +728,7 @@ static struct reg_domain const *at76_get_reg_domain(u16 code)
return (i >= tab_len) ? &unknown : &fd_tab[i];
}
+
static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf,
int buf_size)
{
@@ -735,6 +738,7 @@ static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf,
buf, buf_size, USB_CTRL_GET_TIMEOUT);
}
+
/* Return positive number for status, negative for an error */
static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd)
{
@@ -750,6 +754,7 @@ static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd)
return stat_buf[5];
}
+
#define EXT_FW_BLOCK_SIZE 1024
static int at76_download_external_fw(struct usb_device *udev, u8 *buf, int size)
{
@@ -795,8 +800,9 @@ static int at76_download_external_fw(struct usb_device *udev, u8 *buf, int size)
return ret;
}
-static int at76_set_card_command(struct usb_device *udev, int cmd,
- void *buf, int buf_size)
+
+static int at76_set_card_command(struct usb_device *udev, int cmd, void *buf,
+ int buf_size)
{
int ret;
struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) +
@@ -821,8 +827,8 @@ static int at76_set_card_command(struct usb_device *udev, int cmd,
return -ENOMEM;
}
-#define MAKE_CMD_STATUS_CASE(c) case (c): return #c
+#define MAKE_CMD_STATUS_CASE(c) case (c): return #c
static const char *at76_get_cmd_status_string(u8 cmd_status)
{
switch (cmd_status) {
@@ -840,6 +846,7 @@ static const char *at76_get_cmd_status_string(u8 cmd_status)
return "UNKNOWN";
}
+
/* TODO: should timeout */
static int at76_wait_completion(struct at76_priv *dev, int cmd)
{
@@ -869,6 +876,7 @@ static int at76_wait_completion(struct at76_priv *dev, int cmd)
return status;
}
+
static int at76_set_mib(struct at76_priv *dev, struct set_mib_buffer *buf)
{
struct usb_device *udev = dev->udev;
@@ -901,6 +909,7 @@ static int at76_set_mib(struct at76_priv *dev, struct set_mib_buffer *buf)
return ret;
}
+
/* return < 0 on error, == 0 if no command sent, == 1 if cmd sent */
static int at76_set_radio(struct at76_priv *dev, int on_off)
{
@@ -918,6 +927,7 @@ static int at76_set_radio(struct at76_priv *dev, int on_off)
return ret;
}
+
/**
* set_pm_mode - set current power save mode
* (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART)
@@ -940,6 +950,7 @@ static int at76_set_pm_mode(struct at76_priv *dev)
return ret;
}
+
/* sets the assoc id for power save mode */
static int at76_set_associd(struct at76_priv *dev, u16 id)
{
@@ -960,6 +971,7 @@ static int at76_set_associd(struct at76_priv *dev, u16 id)
return ret;
}
+
/* sets the listen interval for power save mode.
really needed, as we have a similar parameter in the assocreq ??? */
static int at76_set_listen_interval(struct at76_priv *dev, u16 interval)
@@ -982,6 +994,7 @@ static int at76_set_listen_interval(struct at76_priv *dev, u16 interval)
return ret;
}
+
static int at76_set_preamble(struct at76_priv *dev, u8 type)
{
int ret = 0;
@@ -998,6 +1011,7 @@ static int at76_set_preamble(struct at76_priv *dev, u8 type)
return ret;
}
+
static int at76_set_frag(struct at76_priv *dev, u16 size)
{
int ret = 0;
@@ -1014,6 +1028,7 @@ static int at76_set_frag(struct at76_priv *dev, u16 size)
return ret;
}
+
static int at76_set_rts(struct at76_priv *dev, u16 size)
{
int ret = 0;
@@ -1030,6 +1045,7 @@ static int at76_set_rts(struct at76_priv *dev, u16 size)
return ret;
}
+
static int at76_set_autorate_fallback(struct at76_priv *dev, int onoff)
{
int ret = 0;
@@ -1046,6 +1062,7 @@ static int at76_set_autorate_fallback(struct at76_priv *dev, int onoff)
return ret;
}
+
static int at76_add_mac_address(struct at76_priv *dev, void *addr)
{
int ret = 0;
@@ -1063,6 +1080,7 @@ static int at76_add_mac_address(struct at76_priv *dev, void *addr)
return ret;
}
+
#if 0
/* implemented to get promisc. mode working, but does not help.
May still be useful for multicast eventually. */
@@ -1099,6 +1117,7 @@ static int set_group_address(struct at76_priv *dev, u8 *addr, int n)
}
#endif
+
static int at76_dump_mib_mac_addr(struct at76_priv *dev)
{
int ret = 0;
@@ -1132,6 +1151,7 @@ static int at76_dump_mib_mac_addr(struct at76_priv *dev)
return ret;
}
+
static int at76_dump_mib_mac_wep(struct at76_priv *dev)
{
int ret = 0;
@@ -1177,6 +1197,7 @@ static int at76_dump_mib_mac_wep(struct at76_priv *dev)
return ret;
}
+
static int at76_dump_mib_mac_mgmt(struct at76_priv *dev)
{
int ret = 0;
@@ -1232,6 +1253,7 @@ static int at76_dump_mib_mac_mgmt(struct at76_priv *dev)
return ret;
}
+
static int at76_dump_mib_mac(struct at76_priv *dev)
{
int ret = 0;
@@ -1279,6 +1301,7 @@ static int at76_dump_mib_mac(struct at76_priv *dev)
return ret;
}
+
static int at76_dump_mib_phy(struct at76_priv *dev)
{
int ret = 0;
@@ -1318,6 +1341,7 @@ static int at76_dump_mib_phy(struct at76_priv *dev)
return ret;
}
+
static int at76_dump_mib_local(struct at76_priv *dev)
{
int ret = 0;
@@ -1347,6 +1371,7 @@ static int at76_dump_mib_local(struct at76_priv *dev)
return ret;
}
+
static int at76_get_mib_mdomain(struct at76_priv *dev, struct mib_mdomain *val)
{
int ret = 0;
@@ -1373,6 +1398,7 @@ static int at76_get_mib_mdomain(struct at76_priv *dev, struct mib_mdomain *val)
return ret;
}
+
static void at76_dump_mib_mdomain(struct at76_priv *dev)
{
char obuf1[2*14+1], obuf2[2*14+1]; /* to hexdump tx_powerlevel,
@@ -1393,8 +1419,8 @@ static void at76_dump_mib_mdomain(struct at76_priv *dev)
(sizeof(obuf2) - 1) / 2, '\0'));
}
-static
-int at76_get_current_bssid(struct at76_priv *dev)
+
+static int at76_get_current_bssid(struct at76_priv *dev)
{
int ret = 0;
struct mib_mac_mgmt *mac_mgmt =
@@ -1419,6 +1445,7 @@ int at76_get_current_bssid(struct at76_priv *dev)
return ret;
}
+
static int at76_get_current_channel(struct at76_priv *dev)
{
int ret = 0;
@@ -1440,6 +1467,7 @@ static int at76_get_current_channel(struct at76_priv *dev)
return ret;
}
+
/**
* start_scan - start a scan
*
@@ -1502,6 +1530,7 @@ static int at76_start_scan(struct at76_priv *dev, int use_essid, int ir_step)
return at76_set_card_command(dev->udev, CMD_SCAN, &scan, sizeof(scan));
}
+
static int at76_start_ibss(struct at76_priv *dev)
{
struct at76_start_bss bss;
@@ -1517,6 +1546,7 @@ static int at76_start_ibss(struct at76_priv *dev)
sizeof(struct at76_start_bss));
}
+
/* idx points into dev->bss */
static int at76_join_bss(struct at76_priv *dev, struct bss_info *ptr)
{
@@ -1539,6 +1569,428 @@ static int at76_join_bss(struct at76_priv *dev, struct bss_info *ptr)
sizeof(struct at76_join));
}
+
+/* calc. the padding from txbuf->wlength (which excludes the USB TX header)
+ guess this is needed to compensate a flaw in the AT76C503A USB part ... */
+static inline int at76_calc_padding(int wlen)
+{
+ /* add the USB TX header */
+ wlen += AT76_TX_HDRLEN;
+
+ wlen = wlen % 64;
+
+ if (wlen < 50)
+ return 50 - wlen;
+
+ if (wlen >= 61)
+ return 64 + 50 - wlen;
+
+ return 0;
+}
+
+
+/* we are doing a lot of things here in an interrupt. Need
+ a bh handler (Watching TV with a TV card is probably
+ a good test: if you see flickers, we are doing too much.
+ Currently I do see flickers... even with our tasklet :-( )
+ Maybe because the bttv driver and usb-uhci use the same interrupt
+*/
+/* Or maybe because our BH handler is preempting bttv's BH handler.. BHs don't
+ * solve everything.. (alex) */
+static void at76_read_bulk_callback(struct urb *urb)
+{
+ struct at76_priv *priv = urb->context;
+
+ priv->rx_urb = urb;
+ tasklet_schedule(&priv->tasklet);
+ return;
+}
+
+
+static void at76_write_bulk_callback(struct urb *urb)
+{
+ struct at76_priv *dev = urb->context;
+ struct net_device_stats *stats = &dev->stats;
+ unsigned long flags;
+ struct at76_tx_buffer *mgmt_buf;
+ int ret;
+
+ if (urb->status != 0) {
+ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+ at76_dbg(DBG_URB,
+ "%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ } else
+ return; /* urb has been unlinked */
+ stats->tx_errors++;
+ } else
+ stats->tx_packets++;
+
+ spin_lock_irqsave(&dev->mgmt_spinlock, flags);
+ mgmt_buf = dev->next_mgmt_bulk;
+ dev->next_mgmt_bulk = NULL;
+ spin_unlock_irqrestore(&dev->mgmt_spinlock, flags);
+
+ if (mgmt_buf) {
+ /* we don't copy the padding bytes, but add them
+ to the length */
+ memcpy(dev->bulk_out_buffer, mgmt_buf,
+ le16_to_cpu(mgmt_buf->wlength) +
+ offsetof(struct at76_tx_buffer, packet));
+ usb_fill_bulk_urb(dev->write_urb, dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out_endpointAddr),
+ dev->bulk_out_buffer,
+ le16_to_cpu(mgmt_buf->wlength) +
+ mgmt_buf->padding + AT76_TX_HDRLEN,
+ at76_write_bulk_callback,
+ dev);
+ ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC);
+ if (ret) {
+ err("%s: %s error in tx submit urb: %d",
+ dev->netdev->name, __FUNCTION__, ret);
+ }
+ kfree(mgmt_buf);
+ } else
+ netif_wake_queue(dev->netdev);
+}
+
+
+/* send a management frame on bulk-out.
+ txbuf->wlength must be set (in LE format !) */
+static int at76_send_mgmt_bulk(struct at76_priv *dev,
+ struct at76_tx_buffer *txbuf)
+{
+ unsigned long flags;
+ int ret = 0;
+ int urb_status;
+ void *oldbuf = NULL;
+
+ netif_carrier_off(dev->netdev); /* disable running netdev watchdog */
+ netif_stop_queue(dev->netdev); /* stop tx data packets */
+
+ spin_lock_irqsave(&dev->mgmt_spinlock, flags);
+
+ if ((urb_status = dev->write_urb->status) == -EINPROGRESS) {
+ oldbuf = dev->next_mgmt_bulk; /* to kfree below */
+ dev->next_mgmt_bulk = txbuf;
+ txbuf = NULL;
+ }
+ spin_unlock_irqrestore(&dev->mgmt_spinlock, flags);
+
+ if (oldbuf) {
+ /* a data/mgmt tx is already pending in the URB -
+ if this is no error in some situations we must
+ implement a queue or silently modify the old msg */
+ err("%s: %s removed pending mgmt buffer %s",
+ dev->netdev->name, __FUNCTION__,
+ hex2str(dev->obuf, dev->next_mgmt_bulk,
+ min((int)(sizeof(dev->obuf)) / 3, 64), ' '));
+ kfree(dev->next_mgmt_bulk);
+ }
+
+ if (txbuf) {
+
+ txbuf->tx_rate = 0;
+ txbuf->padding = at76_calc_padding(le16_to_cpu(txbuf->wlength));
+
+ if (dev->next_mgmt_bulk) {
+ err("%s: %s URB status %d, but mgmt is pending",
+ dev->netdev->name, __FUNCTION__, urb_status);
+ }
+
+ at76_dbg(DBG_TX_MGMT, "%s: tx mgmt: wlen %d tx_rate %d pad %d %s",
+ dev->netdev->name, le16_to_cpu(txbuf->wlength),
+ txbuf->tx_rate, txbuf->padding,
+ hex2str(dev->obuf, txbuf->packet,
+ min((sizeof(dev->obuf) - 1) / 2,
+ (size_t) le16_to_cpu(txbuf->wlength)), '\0'));
+
+ /* txbuf was not consumed above -> send mgmt msg immediately */
+ memcpy(dev->bulk_out_buffer, txbuf,
+ le16_to_cpu(txbuf->wlength) + AT76_TX_HDRLEN);
+ usb_fill_bulk_urb(dev->write_urb, dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ dev->bulk_out_endpointAddr),
+ dev->bulk_out_buffer,
+ le16_to_cpu(txbuf->wlength) +
+ txbuf->padding +
+ AT76_TX_HDRLEN,
+ at76_write_bulk_callback,
+ dev);
+ ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC);
+ if (ret) {
+ err("%s: %s error in tx submit urb: %d",
+ dev->netdev->name, __FUNCTION__, ret);
+ }
+ kfree(txbuf);
+ }
+ /* if (txbuf) */
+ return ret;
+}
+
+
+/* Go to the next information element */
+static inline void next_ie(struct ieee80211_info_element **ie)
+{
+ *ie = (struct ieee80211_info_element *)(&(*ie)->data[(*ie)->len]);
+}
+
+
+/* challenge is the challenge string (in TLV format)
+ we got with seq_nr 2 for shared secret authentication only and
+ send in seq_nr 3 WEP encrypted to prove we have the correct WEP key;
+ otherwise it is NULL */
+static int at76_auth_req(struct at76_priv *dev, struct bss_info *bss,
+ int seq_nr, struct ieee80211_info_element *challenge)
+{
+ struct at76_tx_buffer *tx_buffer;
+ struct ieee80211_hdr_3addr *mgmt;
+ struct ieee80211_auth *req;
+ int buf_len = (seq_nr != 3 ? AUTH_FRAME_SIZE :
+ AUTH_FRAME_SIZE + 1 + 1 + challenge->len);
+
+ at76_assert(bss != NULL);
+ at76_assert(seq_nr != 3 || challenge != NULL);
+ tx_buffer = kmalloc(buf_len + MAX_PADDING_SIZE, GFP_ATOMIC);
+ if (!tx_buffer)
+ return -ENOMEM;
+
+ req = (struct ieee80211_auth *)(&tx_buffer->packet);
+ mgmt = &req->header;
+
+ /* make wireless header */
+ /* first auth msg is not encrypted, only the second (seq_nr == 3) */
+ mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH |
+ (seq_nr == 3 ? IEEE80211_FCTL_PROTECTED : 0));
+
+ mgmt->duration_id = cpu_to_le16(0x8000);
+ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
+ memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
+ mgmt->seq_ctl = cpu_to_le16(0);
+
+ req->algorithm = cpu_to_le16(dev->auth_mode);
+ req->transaction = cpu_to_le16(seq_nr);
+ req->status = cpu_to_le16(0);
+
+ if (seq_nr == 3)
+ memcpy(req->info_element, challenge, 1 + 1 + challenge->len);
+
+ /* init. at76_priv tx header */
+ tx_buffer->wlength = cpu_to_le16(buf_len - AT76_TX_HDRLEN);
+ at76_dbg(DBG_TX_MGMT, "%s: AuthReq bssid %s alg %d seq_nr %d",
+ dev->netdev->name, mac2str(mgmt->addr3),
+ le16_to_cpu(req->algorithm), le16_to_cpu(req->transaction));
+ if (seq_nr == 3) {
+ at76_dbg(DBG_TX_MGMT, "%s: AuthReq challenge: %s ...",
+ dev->netdev->name,
+ hex2str(dev->obuf, req->info_element,
+ min((int)sizeof(dev->obuf) / 3, 18), ' '));
+ }
+
+ /* either send immediately (if no data tx is pending
+ or put it in pending list */
+ return at76_send_mgmt_bulk(dev, tx_buffer);
+}
+
+
+static int at76_assoc_req(struct at76_priv *dev, struct bss_info *bss)
+{
+ struct at76_tx_buffer *tx_buffer;
+ struct ieee80211_hdr_3addr *mgmt;
+ struct ieee80211_assoc_request *req;
+ struct ieee80211_info_element *tlv;
+
+ at76_assert(bss != NULL);
+
+ tx_buffer = kmalloc(ASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
+ if (!tx_buffer)
+ return -ENOMEM;
+
+ req = (struct ieee80211_assoc_request *)(&tx_buffer->packet);
+ mgmt = &req->header;
+ tlv = req->info_element;
+
+ /* make wireless header */
+ mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ASSOC_REQ);
+
+ mgmt->duration_id = cpu_to_le16(0x8000);
+ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
+ memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
+ mgmt->seq_ctl = cpu_to_le16(0);
+
+ /* we must set the Privacy bit in the capabilities to assure an
+ Agere-based AP with optional WEP transmits encrypted frames
+ to us. AP only set the Privacy bit in their capabilities
+ if WEP is mandatory in the BSS! */
+ req->capability = cpu_to_le16(bss->capa |
+ (dev->wep_enabled ? WLAN_CAPABILITY_PRIVACY : 0) |
+ (dev->preamble_type == PREAMBLE_TYPE_SHORT ?
+ WLAN_CAPABILITY_SHORT_PREAMBLE : 0));
+
+ req->listen_interval = cpu_to_le16(2 * bss->beacon_interval);
+
+ /* write TLV data elements */
+
+ tlv->id = MFIE_TYPE_SSID;
+ tlv->len = bss->ssid_len;
+ memcpy(tlv->data, bss->ssid, bss->ssid_len);
+ next_ie(&tlv);
+
+ tlv->id = MFIE_TYPE_RATES;
+ tlv->len = sizeof(hw_rates);
+ memcpy(tlv->data, hw_rates, sizeof(hw_rates));
+ next_ie(&tlv); /* tlv points behind the supp_rates field */
+
+ /* init. at76_priv tx header */
+ tx_buffer->wlength = cpu_to_le16((u8 *) tlv - (u8 *) mgmt);
+
+ {
+ /* output buffer for ssid and rates */
+ char orates[4 * 2 + 1];
+ int len;
+
+ tlv = req->info_element;
+ len = min_t(int, IW_ESSID_MAX_SIZE, tlv->len);
+ memcpy(dev->obuf, tlv->data, len);
+ dev->obuf[len] = '\0';
+ next_ie(&tlv); /* points to IE of rates now */
+ at76_dbg(DBG_TX_MGMT, "%s: AssocReq bssid %s capa x%04x ssid %s rates %s",
+ dev->netdev->name, mac2str(mgmt->addr3),
+ le16_to_cpu(req->capability), dev->obuf,
+ hex2str(orates,tlv->data,min((sizeof(orates)-1)/2,(size_t)tlv->len),
+ '\0'));
+ }
+
+ /* either send immediately (if no data tx is pending
+ or put it in pending list */
+ return at76_send_mgmt_bulk(dev, tx_buffer);
+}
+
+
+/* we are currently associated to curr_bss and
+ want to reassoc to new_bss */
+static int at76_reassoc_req(struct at76_priv *dev, struct bss_info *curr_bss,
+ struct bss_info *new_bss)
+{
+ struct at76_tx_buffer *tx_buffer;
+ struct ieee80211_hdr_3addr *mgmt;
+ struct ieee80211_reassoc_request *req;
+ struct ieee80211_info_element *tlv;
+
+ at76_assert(curr_bss != NULL);
+ at76_assert(new_bss != NULL);
+ if (curr_bss == NULL || new_bss == NULL)
+ return -EFAULT;
+
+ tx_buffer = kmalloc(REASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
+ if (!tx_buffer)
+ return -ENOMEM;
+
+ req = (struct ieee80211_reassoc_request *)(&tx_buffer->packet);
+ mgmt = &req->header;
+ tlv = req->info_element;
+
+ /* make wireless header */
+ /* jal: encrypt this packet if wep_enabled is TRUE ??? */
+ mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_REASSOC_REQ);
+ mgmt->duration_id = cpu_to_le16(0x8000);
+ memcpy(mgmt->addr1, new_bss->bssid, ETH_ALEN);
+ memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->addr3, new_bss->bssid, ETH_ALEN);
+ mgmt->seq_ctl = cpu_to_le16(0);
+
+ /* we must set the Privacy bit in the capabilities to assure an
+ Agere-based AP with optional WEP transmits encrypted frames
+ to us. AP only set the Privacy bit in their capabilities
+ if WEP is mandatory in the BSS! */
+ req->capability = cpu_to_le16(new_bss->capa |
+ (dev->wep_enabled ? WLAN_CAPABILITY_PRIVACY : 0) |
+ (dev->preamble_type == PREAMBLE_TYPE_SHORT ?
+ WLAN_CAPABILITY_SHORT_PREAMBLE : 0));
+
+ req->listen_interval = cpu_to_le16(2 * new_bss->beacon_interval);
+
+ memcpy(req->current_ap, curr_bss->bssid, ETH_ALEN);
+
+ /* write TLV data elements */
+ tlv->id = MFIE_TYPE_SSID;
+ tlv->len = new_bss->ssid_len;
+ memcpy(tlv->data, new_bss->ssid, new_bss->ssid_len);
+ next_ie(&tlv);
+
+ tlv->id = MFIE_TYPE_RATES;
+ tlv->len = sizeof(hw_rates);
+ memcpy(tlv->data, hw_rates, sizeof(hw_rates));
+ /* tlv points behind the supp_rates field */
+ next_ie(&tlv);
+
+ /* init. at76_priv tx header */
+ tx_buffer->wlength = cpu_to_le16((u8 *)tlv-(u8 *)mgmt);
+
+ {
+ /* output buffer for rates and bssid */
+ char orates[4*2+1];
+ char ocurr[6*3+1];
+ tlv = req->info_element;
+ memcpy(dev->obuf, tlv->data, min(sizeof(dev->obuf),(size_t)tlv->len));
+ dev->obuf[IW_ESSID_MAX_SIZE] = '\0';
+ next_ie(&tlv); /* points to IE of rates now */
+ at76_dbg(DBG_TX_MGMT, "%s: ReAssocReq curr %s new %s capa x%04x ssid %s rates %s",
+ dev->netdev->name,
+ hex2str(ocurr, req->current_ap, ETH_ALEN, ':'),
+ mac2str(mgmt->addr3), le16_to_cpu(req->capability), dev->obuf,
+ hex2str(orates,tlv->data,min((sizeof(orates)-1)/2,(size_t)tlv->len),
+ '\0'));
+ }
+
+ /* either send immediately (if no data tx is pending
+ or put it in pending list */
+ return at76_send_mgmt_bulk(dev, tx_buffer);
+}
+
+
+static int at76_disassoc_req(struct at76_priv *dev, struct bss_info *bss)
+{
+ struct at76_tx_buffer *tx_buffer;
+ struct ieee80211_hdr_3addr *mgmt;
+ struct ieee80211_disassoc *req;
+
+ at76_assert(bss != NULL);
+ if (bss == NULL)
+ return -EFAULT;
+
+ tx_buffer = kmalloc(DISASSOC_FRAME_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
+ if (!tx_buffer)
+ return -ENOMEM;
+
+ req = (struct ieee80211_disassoc *)(&tx_buffer->packet);
+ mgmt = &req->header;
+
+ /* make wireless header */
+ mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_AUTH);
+ mgmt->duration_id = cpu_to_le16(0x8000);
+ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
+ memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
+ mgmt->seq_ctl = cpu_to_le16(0);
+
+ req->reason = 0;
+
+ /* init. at76_priv tx header */
+ tx_buffer->wlength = cpu_to_le16(DISASSOC_FRAME_SIZE - AT76_TX_HDRLEN);
+
+ at76_dbg(DBG_TX_MGMT, "%s: DisAssocReq bssid %s",
+ dev->netdev->name, mac2str(mgmt->addr3));
+
+ /* either send immediately (if no data tx is pending
+ or put it in pending list */
+ return at76_send_mgmt_bulk(dev, tx_buffer);
+}
+
+
/* the firmware download timeout (after remap) */
static void at76_fw_dl_timeout(unsigned long par)
{
@@ -1546,6 +1998,7 @@ static void at76_fw_dl_timeout(unsigned long par)
schedule_work(&dev->work_reset_device);
}
+
/* the restart timer timed out */
static void at76_restart_timeout(unsigned long par)
{
@@ -1553,6 +2006,7 @@ static void at76_restart_timeout(unsigned long par)
schedule_work(&dev->work_restart);
}
+
/* we got to check the bss_list for old entries */
static void at76_bss_list_timeout(unsigned long par)
{
@@ -1580,9 +2034,41 @@ static void at76_bss_list_timeout(unsigned long par)
spin_unlock_irqrestore(&dev->bss_list_spinlock, flags);
/* restart the timer */
mod_timer(&dev->bss_list_timer, jiffies + BSS_LIST_TIMEOUT);
+}
+
+
+static void at76_dump_bss_table(struct at76_priv *dev)
+{
+ struct bss_info *ptr;
+ unsigned long flags;
+ struct list_head *lptr;
+ char obuf_s[3*32];
+
+ spin_lock_irqsave(&dev->bss_list_spinlock, flags);
+ pr_debug("%s BSS table (curr=%p, new=%p):", dev->netdev->name,
+ dev->curr_bss, dev->new_bss);
+
+ list_for_each(lptr, &dev->bss_list) {
+ ptr = list_entry(lptr, struct bss_info, list);
+ pr_debug("0x%p: bssid %s channel %d ssid %s (%s)"
+ " capa x%04x rates %s rssi %d link %d noise %d",
+ ptr, mac2str(ptr->bssid),
+ ptr->channel,
+ ptr->ssid,
+ hex2str(dev->obuf, ptr->ssid,
+ min((sizeof(dev->obuf) - 1) / 2,
+ (size_t) ptr->ssid_len), '\0'),
+ ptr->capa,
+ hex2str(obuf_s, ptr->rates,
+ min(sizeof(obuf_s) / 3,
+ (size_t) ptr->rates_len), ' '),
+ ptr->rssi, ptr->link_qual, ptr->noise_level);
+ }
+ spin_unlock_irqrestore(&dev->bss_list_spinlock, flags);
}
+
/* we got a timeout for a infrastructure mgmt packet */
static void at76_mgmt_timeout(unsigned long par)
{
@@ -1590,6 +2076,7 @@ static void at76_mgmt_timeout(unsigned long par)
schedule_work(&dev->work_mgmt_timeout);
}
+
/*
* at76_work_mgmt_timeout_scan - expiry of management timer in istate SCANNING
*/
@@ -1689,6 +2176,7 @@ static void at76_handle_mgmt_timeout_scan(struct at76_priv *dev)
}
}
+
/* the deferred procedure called from at76_devent() */
static void at76_handle_mgmt_timeout(struct at76_priv *dev)
{
@@ -1790,402 +2278,1988 @@ static void at76_handle_mgmt_timeout(struct at76_priv *dev)
}
}
-/* calc. the padding from txbuf->wlength (which excludes the USB TX header)
- guess this is needed to compensate a flaw in the AT76C503A USB part ... */
-static inline int at76_calc_padding(int wlen)
+
+/* Called after successful association */
+static void at76_work_assoc_done(struct work_struct *work)
{
- /* add the USB TX header */
- wlen += AT76_TX_HDRLEN;
+ struct at76_priv *dev = container_of(work, struct at76_priv,
+ work_assoc_done);
- wlen = wlen % 64;
+ down(&dev->sem);
- if (wlen < 50)
- return 50 - wlen;
+ at76_assert(dev->istate == ASSOCIATING || dev->istate == REASSOCIATING);
+ if (dev->iw_mode == IW_MODE_INFRA) {
+ at76_assert(dev->curr_bss != NULL);
+ if (dev->curr_bss != NULL && dev->pm_mode != AT76_PM_OFF) {
+ /* calculate the listen interval in units of
+ beacon intervals of the curr_bss */
+ u32 pm_period_beacon = (dev->pm_period >> 10) /
+ dev->curr_bss->beacon_interval;
- if (wlen >= 61)
- return 64 + 50 - wlen;
+ pm_period_beacon = max(pm_period_beacon, 2u);
+ pm_period_beacon = min(pm_period_beacon, 0xffffu);
+
+ at76_dbg(DBG_PM, "%s: pm_mode %d assoc id x%x listen int %d",
+ dev->netdev->name, dev->pm_mode,
+ dev->curr_bss->assoc_id, pm_period_beacon);
+
+ at76_set_associd(dev, dev->curr_bss->assoc_id);
+ at76_set_listen_interval(dev, (u16)pm_period_beacon);
+#ifdef DEBUG
+ at76_dump_mib_mac(dev);
+ at76_dump_mib_mac_mgmt(dev);
+#endif
+ }
+ }
+ at76_set_pm_mode(dev);
+
+ netif_carrier_on(dev->netdev);
+ netif_wake_queue(dev->netdev);
+ dev->istate = CONNECTED;
+ at76_iwevent_bss_connect(dev->netdev, dev->curr_bss->bssid);
+ at76_dbg(DBG_PROGRESS, "%s: connected to BSSID %s",
+ dev->netdev->name, mac2str(dev->curr_bss->bssid));
+
+ up(&dev->sem);
+}
+
+
+static void at76_delete_device(struct at76_priv *dev)
+{
+ int i;
+
+ if (!dev)
+ return;
+
+ /* signal to _stop() that the device is gone */
+ dev->device_unplugged = 1;
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER",__FUNCTION__);
+
+ if (dev->netdev_registered) {
+ unregister_netdev(dev->netdev);
+ }
+
+ usb_put_dev(dev->udev);
+
+ /* assuming we used keventd, it must quiesce too */
+ flush_scheduled_work();
+
+ if (dev->bulk_out_buffer != NULL)
+ kfree(dev->bulk_out_buffer);
+
+ kfree(dev->ctrl_buffer);
+
+ if (dev->write_urb != NULL) {
+ usb_kill_urb(dev->write_urb);
+ usb_free_urb(dev->write_urb);
+ }
+ if (dev->read_urb != NULL) {
+ usb_kill_urb(dev->read_urb);
+ usb_free_urb(dev->read_urb);
+ }
+ if (dev->ctrl_buffer != NULL) {
+ usb_kill_urb(dev->ctrl_urb);
+ usb_free_urb(dev->ctrl_urb);
+ }
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __FUNCTION__);
+
+ if (dev->rx_skb != NULL)
+ kfree_skb(dev->rx_skb);
+
+ at76_free_bss_list(dev);
+ del_timer_sync(&dev->bss_list_timer);
+
+ if (dev->istate == CONNECTED) {
+ at76_iwevent_bss_disconnect(dev->netdev);
+ }
+
+ for (i = 0; i < NR_RX_DATA_BUF; i++)
+ if (dev->rx_data[i].skb != NULL) {
+ dev_kfree_skb(dev->rx_data[i].skb);
+ dev->rx_data[i].skb = NULL;
+ }
+ at76_dbg(DBG_PROC_ENTRY, "%s: before freeing dev/netdev", __FUNCTION__);
+ free_netdev(dev->netdev); /* dev is in netdev */
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __FUNCTION__);
+}
+
+
+static int at76_alloc_urbs(struct at76_priv *dev)
+{
+ struct usb_interface *interface = dev->interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = dev->udev;
+ int i, buffer_size;
+ struct usb_host_interface *iface_desc;
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __FUNCTION__);
+
+ at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __FUNCTION__,
+ interface->altsetting[0].desc.bNumEndpoints);
+
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ at76_dbg(DBG_URB, "%s: %d. endpoint: addr x%x attr x%x",
+ __FUNCTION__,
+ i, endpoint->bEndpointAddress, endpoint->bmAttributes);
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk in endpoint */
+
+ dev->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->read_urb) {
+ err("No free urbs available");
+ return -ENOMEM;
+ }
+ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ }
+
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk out endpoint */
+ dev->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->write_urb) {
+ err("no free urbs available");
+ return -ENOMEM;
+ }
+ buffer_size = sizeof(struct at76_tx_buffer) +
+ MAX_PADDING_SIZE;
+ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ dev->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!dev->bulk_out_buffer) {
+ err("couldn't allocate bulk_out_buffer");
+ return -ENOMEM;
+ }
+ usb_fill_bulk_urb(dev->write_urb, udev,
+ usb_sndbulkpipe(udev,
+ endpoint->bEndpointAddress),
+ dev->bulk_out_buffer, buffer_size,
+ at76_write_bulk_callback, dev);
+ }
+ }
+
+ dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->ctrl_urb) {
+ err("no free urbs available");
+ return -ENOMEM;
+ }
+ dev->ctrl_buffer = kmalloc(1024, GFP_KERNEL);
+ if (!dev->ctrl_buffer) {
+ err("couldn't allocate ctrl_buffer");
+ return -ENOMEM;
+ }
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __FUNCTION__);
return 0;
}
-/* send a management frame on bulk-out.
- txbuf->wlength must be set (in LE format !) */
-static int at76_send_mgmt_bulk(struct at76_priv *dev,
- struct at76_tx_buffer *txbuf)
+
+/* we only store the new mac address in netdev struct,
+ it gets set when the netdev is opened. */
+static int at76_set_mac_address(struct net_device *netdev, void *addr)
{
+ struct sockaddr *mac = addr;
+ memcpy(netdev->dev_addr, mac->sa_data, ETH_ALEN);
+ return 1;
+}
+
+
+static struct net_device_stats *at76_get_stats(struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ return &dev->stats;
+}
+
+
+static struct iw_statistics *at76_get_wireless_stats(struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "RETURN qual %d level %d noise %d updated %d",
+ dev->wstats.qual.qual, dev->wstats.qual.level,
+ dev->wstats.qual.noise, dev->wstats.qual.updated);
+
+ return &dev->wstats;
+}
+
+
+static void at76_set_multicast(struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int promisc;
+
+ promisc = ((netdev->flags & IFF_PROMISC) != 0);
+ if (promisc != dev->promisc) {
+ /* grmbl. This gets called in interrupt. */
+ dev->promisc = promisc;
+ schedule_work(&dev->work_set_promisc);
+ }
+}
+
+
+/*******************************************************************************
+ * at76_priv implementations of iw_handler functions:
+ */
+static int at76_iw_handler_commit(struct net_device *netdev,
+ struct iw_request_info *info,
+ void *null, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
unsigned long flags;
+ at76_dbg(DBG_IOCTL, "%s %s: restarting the device", netdev->name,
+ __FUNCTION__);
+
+ /* TODO: stop any pending tx bulk urb */
+ 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);
+ }
+
+ /* 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;
+}
+
+
+static int at76_iw_handler_get_name(struct net_device *netdev,
+ struct iw_request_info *info,
+ char *name, char *extra)
+{
+ strcpy(name, "IEEE 802.11b");
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWNAME - name %s", netdev->name, name);
+ return 0;
+}
+
+
+static int at76_iw_handler_set_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int chan = -1;
+ int ret = -EIWCOMMIT;
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - freq.m %d freq.e %d", netdev->name,
+ freq->m, freq->e);
+
+ 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->international_roaming) {
+ if (!(dev->domain->channel_map & (1 << (chan - 1)))) {
+ info("%s: channel %d not allowed for domain %s "
+ "(and international_roaming is OFF)",
+ dev->netdev->name, chan, dev->domain->name);
+ ret = -EINVAL;
+ }
+ }
+
+ if (ret == -EIWCOMMIT) {
+ dev->channel = chan;
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - ch %d", netdev->name, chan);
+ }
+
+ return ret;
+}
+
+
+static int at76_iw_handler_get_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ freq->m = dev->channel;
+ freq->e = 0;
+
+ if (dev->channel) {
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - freq %ld x 10e%d",
+ netdev->name, channel_frequency[dev->channel - 1], 6);
+ }
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - ch %d", netdev->name, dev->channel);
+
+ return 0;
+}
+
+
+static int at76_iw_handler_set_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode);
+
+ if ((*mode != IW_MODE_ADHOC) && (*mode != IW_MODE_INFRA) &&
+ (*mode != IW_MODE_MONITOR)) {
+ ret = -EINVAL;
+ } else {
+ dev->iw_mode = *mode;
+ if( dev->iw_mode != IW_MODE_INFRA)
+ dev->pm_mode = AT76_PM_OFF;
+ }
+ return ret;
+}
+
+
+static int at76_iw_handler_get_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ __u32 * mode, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ *mode = dev->iw_mode;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWMODE - %d", netdev->name, *mode);
+
+ return 0;
+}
+
+
+static int at76_iw_handler_get_range(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ /* inspired by atmel.c */
+ struct at76_priv *dev = netdev_priv(netdev);
+ 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 = 100;
+ range->max_qual.level = 100;
+ range->max_qual.noise = 0;
+ range->max_qual.updated = IW_QUAL_NOISE_INVALID;
+
+ range->avg_qual.qual = 50;
+ range->avg_qual.level = 50;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_NOISE_INVALID;
+
+ 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->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_ON;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_ALL_R;
+
+ 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 = WEP_KEYS;
+
+ /* 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;
+
+ range->we_version_source = WIRELESS_EXT;
+ 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 = 255;
+
+
+ range->num_channels = NUM_CHANNELS;
+ range->num_frequency = 0;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ /* test if channel map bit is raised */
+ if (dev->domain->channel_map & (0x1 << i)) {
+ range->num_frequency += 1;
+
+ range->freq[i].i = i + 1;
+ range->freq[i].m = channel_frequency[i] * 100000;
+ range->freq[i].e = 1; /* channel frequency*100000 * 10^1 */
+ }
+ }
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRANGE", netdev->name);
+
+ return 0;
+}
+
+
+static int at76_iw_handler_set_spy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
int ret = 0;
- int urb_status;
- void *oldbuf = NULL;
- netif_carrier_off(dev->netdev); /* disable running netdev watchdog */
- netif_stop_queue(dev->netdev); /* stop tx data packets */
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWSPY - number of addresses %d",
+ netdev->name, data->length);
- spin_lock_irqsave(&dev->mgmt_spinlock, flags);
+ spin_lock_bh(&(dev->spy_spinlock));
+ ret = iw_handler_set_spy(dev->netdev, info, (union iwreq_data *)data,
+ extra);
+ spin_unlock_bh(&(dev->spy_spinlock));
- if ((urb_status = dev->write_urb->status) == -EINPROGRESS) {
- oldbuf = dev->next_mgmt_bulk; /* to kfree below */
- dev->next_mgmt_bulk = txbuf;
- txbuf = NULL;
+ return ret;
+}
+
+
+static int at76_iw_handler_get_spy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = 0;
+
+ spin_lock_bh(&(dev->spy_spinlock));
+ ret = iw_handler_get_spy(dev->netdev, info,
+ (union iwreq_data *)data, extra);
+ spin_unlock_bh(&(dev->spy_spinlock));
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWSPY - number of addresses %d",
+ netdev->name, data->length);
+
+ return ret;
+}
+
+
+static int at76_iw_handler_set_thrspy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret;
+
+ at76_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;
+}
+
+
+static int at76_iw_handler_get_thrspy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ 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));
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWTHRSPY - number of addresses %d)",
+ netdev->name, data->length);
+
+ return ret;
+}
+
+
+static int at76_iw_handler_set_wap(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWAP - wap/bssid %s", netdev->name,
+ mac2str(ap_addr->sa_data));
+
+ /* if the incoming address == ff:ff:ff:ff:ff:ff, the user has
+ chosen any or auto AP preference */
+ if (is_broadcast_ether_addr(ap_addr->sa_data)
+ || is_zero_ether_addr(ap_addr->sa_data)) {
+ dev->wanted_bssid_valid = 0;
+ } else {
+ /* user wants to set a preferred AP address */
+ dev->wanted_bssid_valid = 1;
+ memcpy(dev->wanted_bssid, ap_addr->sa_data, ETH_ALEN);
}
- spin_unlock_irqrestore(&dev->mgmt_spinlock, flags);
- if (oldbuf) {
- /* a data/mgmt tx is already pending in the URB -
- if this is no error in some situations we must
- implement a queue or silently modify the old msg */
- err("%s: %s removed pending mgmt buffer %s",
- dev->netdev->name, __FUNCTION__,
- hex2str(dev->obuf, dev->next_mgmt_bulk,
- min((int)(sizeof(dev->obuf)) / 3, 64), ' '));
+ return -EIWCOMMIT;
+}
+
+
+static int at76_iw_handler_get_wap(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+ memcpy(ap_addr->sa_data, dev->bssid, ETH_ALEN);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWAP - wap/bssid %s", netdev->name,
+ mac2str(ap_addr->sa_data));
+
+ return 0;
+}
+
+
+static int at76_iw_handler_set_scan(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ unsigned long flags;
+ int ret = 0;
+ struct iw_scan_req *req = NULL;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name);
+
+ if (!netif_running(netdev))
+ return -ENETDOWN;
+
+ /* jal: we don't allow "iwlist ethX scan" while we are
+ in monitor mode */
+ if (dev->iw_mode == IW_MODE_MONITOR)
+ return -EBUSY;
+
+ /* Discard old scan results */
+ if ((jiffies - dev->last_scan) > (20 * HZ))
+ dev->scan_state = SCAN_IDLE;
+ dev->last_scan = jiffies;
+
+ /* Initiate a scan command */
+ if (dev->scan_state == SCAN_IN_PROGRESS)
+ return -EBUSY;
+
+ dev->scan_state = SCAN_IN_PROGRESS;
+
+ /* 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 (txbuf) {
+ if (netif_running(dev->netdev)) {
+ /* pause network activity */
+ netif_carrier_off(dev->netdev);
+ netif_stop_queue(dev->netdev);
+ }
+ /* Try to do passive or active scan if WE asks as. */
+ if (wrqu->data.length
+ && wrqu->data.length == sizeof(struct iw_scan_req)) {
+ req = (struct iw_scan_req *)extra;
- txbuf->tx_rate = 0;
- txbuf->padding = at76_calc_padding(le16_to_cpu(txbuf->wlength));
+ if (req->scan_type == IW_SCAN_TYPE_PASSIVE)
+ dev->scan_mode = SCAN_TYPE_PASSIVE;
+ else if (req->scan_type == IW_SCAN_TYPE_ACTIVE)
+ dev->scan_mode = SCAN_TYPE_ACTIVE;
- if (dev->next_mgmt_bulk) {
- err("%s: %s URB status %d, but mgmt is pending",
- dev->netdev->name, __FUNCTION__, urb_status);
+ /* Sanity check values? */
+ if (req->min_channel_time > 0) {
+ if (dev->istate == MONITORING)
+ dev->monitor_scan_min_time =
+ req->min_channel_time;
+ else
+ dev->scan_min_time = req->min_channel_time;
+ }
+ if (req->max_channel_time > 0) {
+ if (dev->istate == MONITORING)
+ dev->monitor_scan_max_time =
+ req->max_channel_time;
+ else
+ dev->scan_max_time = req->max_channel_time;
}
+ }
- at76_dbg(DBG_TX_MGMT, "%s: tx mgmt: wlen %d tx_rate %d pad %d %s",
- dev->netdev->name, le16_to_cpu(txbuf->wlength),
- txbuf->tx_rate, txbuf->padding,
- hex2str(dev->obuf, txbuf->packet,
- min((sizeof(dev->obuf) - 1) / 2,
- (size_t) le16_to_cpu(txbuf->wlength)), '\0'));
+ /* change to scanning state */
+ dev->istate = SCANNING;
+ schedule_work(&dev->work_scan);
- /* txbuf was not consumed above -> send mgmt msg immediately */
- memcpy(dev->bulk_out_buffer, txbuf,
- le16_to_cpu(txbuf->wlength) + AT76_TX_HDRLEN);
- usb_fill_bulk_urb(dev->write_urb, dev->udev,
- usb_sndbulkpipe(dev->udev,
- dev->bulk_out_endpointAddr),
- dev->bulk_out_buffer,
- le16_to_cpu(txbuf->wlength) +
- txbuf->padding +
- AT76_TX_HDRLEN,
- at76_write_bulk_callback,
- dev);
- ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC);
- if (ret) {
- err("%s: %s error in tx submit urb: %d",
- dev->netdev->name, __FUNCTION__, ret);
+ return ret;
+}
+
+
+static int at76_iw_handler_get_scan(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ unsigned long flags;
+ struct list_head *lptr, *nptr;
+ struct bss_info *curr_bss;
+ struct iw_event *iwe = kmalloc(sizeof(struct iw_event), GFP_KERNEL);
+ char *curr_val, *curr_pos = extra;
+ int i;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWSCAN", netdev->name);
+
+ if (!iwe)
+ return -ENOMEM;
+
+ if (dev->scan_state != SCAN_COMPLETED)
+ /* scan not yet finished */
+ return -EAGAIN;
+
+ 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;
+ iwe->u.data.flags = 1;
+
+ 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 & WLAN_CAPABILITY_IBSS) ?
+ IW_MODE_ADHOC :
+ (curr_bss->capa & WLAN_CAPABILITY_ESS) ?
+ IW_MODE_MASTER : 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 & WLAN_CAPABILITY_PRIVACY) {
+ iwe->u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe->u.data.flags = IW_ENCODE_DISABLED;
}
- kfree(txbuf);
+ 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.noise = 0;
+ iwe->u.qual.updated =
+ IW_QUAL_NOISE_INVALID | IW_QUAL_LEVEL_UPDATED;
+ iwe->u.qual.level = (curr_bss->rssi * 100 / 42);
+ if (iwe->u.qual.level > 100)
+ iwe->u.qual.level = 100;
+ if ((dev->board_type == BOARDTYPE_503_INTERSIL_3861) ||
+ (dev->board_type == BOARDTYPE_503_INTERSIL_3863)) {
+ iwe->u.qual.qual = curr_bss->link_qual;
+ } else {
+ iwe->u.qual.qual = 0;
+ iwe->u.qual.updated |= IW_QUAL_QUAL_INVALID;
+ }
+ /* 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);
+ }
+
+ /* Check if we added any event */
+ if ((curr_val - curr_pos) > IW_EV_LCP_LEN)
+ curr_pos = curr_val;
+
+ /* more information may be sent back using IWECUSTOM */
+
}
- /* if (txbuf) */
+
+ spin_unlock_irqrestore(&(dev->bss_list_spinlock), flags);
+
+ data->length = (curr_pos - extra);
+ data->flags = 0;
+
+ kfree(iwe);
+ return 0;
+}
+
+
+static int at76_iw_handler_set_essid(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWESSID - %s", netdev->name, extra);
+
+ if (data->flags) {
+ memcpy(dev->essid, extra, data->length);
+ dev->essid_size = data->length;
+ } else {
+ /* Use any SSID */
+ dev->essid_size = 0;
+ }
+
+ return -EIWCOMMIT;
+}
+
+
+static int at76_iw_handler_get_essid(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ 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;
+ }
+ }
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWESSID - %s", netdev->name, extra);
+
+ return 0;
+}
+
+
+static int at76_iw_handler_set_rate(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *bitrate, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+
+ at76_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;
+}
+
+
+static int at76_iw_handler_get_rate(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *bitrate, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ 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;
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRATE - %d", netdev->name,
+ bitrate->value);
+
+ return ret;
}
-/* Go to the next information element */
-static inline void next_ie(struct ieee80211_info_element **ie)
+
+static int at76_iw_handler_set_rts(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
{
- *ie = (struct ieee80211_info_element *)(&(*ie)->data[(*ie)->len]);
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+ int rthr = rts->value;
+
+ at76_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;
}
-static int at76_disassoc_req(struct at76_priv *dev, struct bss_info *bss)
+
+static int at76_iw_handler_get_rts(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
{
- struct at76_tx_buffer *tx_buffer;
- struct ieee80211_hdr_3addr *mgmt;
- struct ieee80211_disassoc *req;
+ struct at76_priv *dev = netdev_priv(netdev);
- at76_assert(bss != NULL);
- if (bss == NULL)
- return -EFAULT;
+ rts->value = dev->rts_threshold;
+ rts->disabled = (rts->value >= MAX_RTS_THRESHOLD);
+ rts->fixed = 1;
- tx_buffer = kmalloc(DISASSOC_FRAME_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
- if (!tx_buffer)
- return -ENOMEM;
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRTS - value %d disabled %s",
+ netdev->name, rts->value, (rts->disabled) ? "true" : "false");
- req = (struct ieee80211_disassoc *)(&tx_buffer->packet);
- mgmt = &req->header;
+ return 0;
+}
- /* make wireless header */
- mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_AUTH);
- mgmt->duration_id = cpu_to_le16(0x8000);
- memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
- memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
- memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
- mgmt->seq_ctl = cpu_to_le16(0);
- req->reason = 0;
+static int at76_iw_handler_set_frag(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+ int fthr = frag->value;
- /* init. at76_priv tx header */
- tx_buffer->wlength = cpu_to_le16(DISASSOC_FRAME_SIZE - AT76_TX_HDRLEN);
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFRAG - value %d, disabled %s",
+ netdev->name, frag->value, (frag->disabled) ? "true" : "false");
- at76_dbg(DBG_TX_MGMT, "%s: DisAssocReq bssid %s",
- dev->netdev->name, mac2str(mgmt->addr3));
+ if (frag->disabled)
+ fthr = MAX_FRAG_THRESHOLD;
- /* either send immediately (if no data tx is pending
- or put it in pending list */
- return at76_send_mgmt_bulk(dev, tx_buffer);
+ if ((fthr < MIN_FRAG_THRESHOLD) || (fthr > MAX_FRAG_THRESHOLD)) {
+ ret = -EINVAL;
+ } else {
+ dev->frag_threshold = fthr & ~0x1; /* get an even value */
+ }
+ return ret;
}
-/* challenge is the challenge string (in TLV format)
- we got with seq_nr 2 for shared secret authentication only and
- send in seq_nr 3 WEP encrypted to prove we have the correct WEP key;
- otherwise it is NULL */
-static int at76_auth_req(struct at76_priv *dev, struct bss_info *bss, int seq_nr,
- struct ieee80211_info_element *challenge)
+
+static int at76_iw_handler_get_frag(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
{
- struct at76_tx_buffer *tx_buffer;
- struct ieee80211_hdr_3addr *mgmt;
- struct ieee80211_auth *req;
- int buf_len = (seq_nr != 3 ? AUTH_FRAME_SIZE :
- AUTH_FRAME_SIZE + 1 + 1 + challenge->len);
+ struct at76_priv *dev = netdev_priv(netdev);
- at76_assert(bss != NULL);
- at76_assert(seq_nr != 3 || challenge != NULL);
- tx_buffer = kmalloc(buf_len + MAX_PADDING_SIZE, GFP_ATOMIC);
- if (!tx_buffer)
- return -ENOMEM;
+ frag->value = dev->frag_threshold;
+ frag->disabled = (frag->value >= MAX_FRAG_THRESHOLD);
+ frag->fixed = 1;
- req = (struct ieee80211_auth *)(&tx_buffer->packet);
- mgmt = &req->header;
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFRAG - value %d, disabled %s",
+ netdev->name, frag->value, (frag->disabled) ? "true" : "false");
- /* make wireless header */
- /* first auth msg is not encrypted, only the second (seq_nr == 3) */
- mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH |
- (seq_nr == 3 ? IEEE80211_FCTL_PROTECTED : 0));
+ return 0;
+}
- mgmt->duration_id = cpu_to_le16(0x8000);
- memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
- memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
- memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
- mgmt->seq_ctl = cpu_to_le16(0);
- req->algorithm = cpu_to_le16(dev->auth_mode);
- req->transaction = cpu_to_le16(seq_nr);
- req->status = cpu_to_le16(0);
+static int at76_iw_handler_get_txpow(struct net_device *netdev,
+ struct 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;
- if (seq_nr == 3)
- memcpy(req->info_element, challenge, 1 + 1 + challenge->len);
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWTXPOW - txpow %d dBm", netdev->name,
+ power->value);
- /* init. at76_priv tx header */
- tx_buffer->wlength = cpu_to_le16(buf_len - AT76_TX_HDRLEN);
- at76_dbg(DBG_TX_MGMT, "%s: AuthReq bssid %s alg %d seq_nr %d",
- dev->netdev->name, mac2str(mgmt->addr3),
- le16_to_cpu(req->algorithm), le16_to_cpu(req->transaction));
- if (seq_nr == 3) {
- at76_dbg(DBG_TX_MGMT, "%s: AuthReq challenge: %s ...",
- dev->netdev->name,
- hex2str(dev->obuf, req->info_element,
- min((int)sizeof(dev->obuf) / 3, 18), ' '));
+ return 0;
+}
+
+
+/* jal: short retry is handled by the firmware (at least 0.90.x),
+ while long retry is not (?) */
+static int at76_iw_handler_set_retry(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRETRY disabled %d flags x%x val %d",
+ netdev->name, retry->disabled, retry->flags, retry->value);
+
+ if (!retry->disabled && (retry->flags & IW_RETRY_LIMIT)) {
+ if ((retry->flags & IW_RETRY_MIN) ||
+ !(retry->flags & IW_RETRY_MAX)) {
+ dev->short_retry_limit = retry->value;
+ } else
+ ret = -EINVAL;
+ } else {
+ ret = -EINVAL;
}
- /* either send immediately (if no data tx is pending
- or put it in pending list */
- return at76_send_mgmt_bulk(dev, tx_buffer);
+ return ret;
+}
+
+
+/* adapted (ripped) from atmel.c */
+static int at76_iw_handler_get_retry(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRETRY", netdev->name);
+
+ retry->disabled = 0; /* Can't be disabled */
+
+ retry->flags = IW_RETRY_LIMIT;
+ retry->value = dev->short_retry_limit;
+
+ return 0;
}
-static int at76_assoc_req(struct at76_priv *dev, struct bss_info *bss)
+
+static int at76_iw_handler_set_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *encoding,
+ char *extra)
{
- struct at76_tx_buffer *tx_buffer;
- struct ieee80211_hdr_3addr *mgmt;
- struct ieee80211_assoc_request *req;
- struct ieee80211_info_element *tlv;
+ struct at76_priv *dev = netdev_priv(netdev);
+ int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
+ int len = encoding->length;
- at76_assert(bss != NULL);
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - enc.flags %08x "
+ "pointer %p len %d", netdev->name, encoding->flags,
+ encoding->pointer, encoding->length);
+ at76_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 == WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
- tx_buffer = kmalloc(ASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
- if (!tx_buffer)
- return -ENOMEM;
+ /* take the old default key if index is invalid */
+ if ((index < 0) || (index >= WEP_KEYS))
+ index = dev->wep_key_id;
- req = (struct ieee80211_assoc_request *)(&tx_buffer->packet);
- mgmt = &req->header;
- tlv = req->info_element;
+ if (len > 0) {
+ if (len > WEP_LARGE_KEY_LEN)
+ len = WEP_LARGE_KEY_LEN;
- /* make wireless header */
- mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ASSOC_REQ);
+ memset(dev->wep_keys[index], 0, WEP_KEY_LEN);
+ 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;
+ }
- mgmt->duration_id = cpu_to_le16(0x8000);
- memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
- memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
- memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
- mgmt->seq_ctl = cpu_to_le16(0);
+ dev->wep_key_id = index;
+ dev->wep_enabled = ((encoding->flags & IW_ENCODE_DISABLED) == 0);
- /* we must set the Privacy bit in the capabilities to assure an
- Agere-based AP with optional WEP transmits encrypted frames
- to us. AP only set the Privacy bit in their capabilities
- if WEP is mandatory in the BSS! */
- req->capability = cpu_to_le16(bss->capa |
- (dev->wep_enabled ? WLAN_CAPABILITY_PRIVACY : 0) |
- (dev->preamble_type == PREAMBLE_TYPE_SHORT ?
- WLAN_CAPABILITY_SHORT_PREAMBLE : 0));
+ if (encoding->flags & IW_ENCODE_RESTRICTED)
+ dev->auth_mode = WLAN_AUTH_SHARED_KEY;
+ if (encoding->flags & IW_ENCODE_OPEN)
+ dev->auth_mode = WLAN_AUTH_OPEN;
- req->listen_interval = cpu_to_le16(2 * bss->beacon_interval);
+ at76_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 == WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
- /* write TLV data elements */
+ return -EIWCOMMIT;
+}
- tlv->id = MFIE_TYPE_SSID;
- tlv->len = bss->ssid_len;
- memcpy(tlv->data, bss->ssid, bss->ssid_len);
- next_ie(&tlv);
- tlv->id = MFIE_TYPE_RATES;
- tlv->len = sizeof(hw_rates);
- memcpy(tlv->data, hw_rates, sizeof(hw_rates));
- next_ie(&tlv); /* tlv points behind the supp_rates field */
+static int at76_iw_handler_get_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *encoding,
+ char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
- /* init. at76_priv tx header */
- tx_buffer->wlength = cpu_to_le16((u8 *) tlv - (u8 *) mgmt);
+ if ((index < 0) || (index >= WEP_KEYS))
+ index = dev->wep_key_id;
- {
- /* output buffer for ssid and rates */
- char orates[4 * 2 + 1];
- int len;
+ encoding->flags =
+ (dev->auth_mode == WLAN_AUTH_SHARED_KEY) ?
+ IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN;
- tlv = req->info_element;
- len = min_t(int, IW_ESSID_MAX_SIZE, tlv->len);
- memcpy(dev->obuf, tlv->data, len);
- dev->obuf[len] = '\0';
- next_ie(&tlv); /* points to IE of rates now */
- at76_dbg(DBG_TX_MGMT, "%s: AssocReq bssid %s capa x%04x ssid %s rates %s",
- dev->netdev->name, mac2str(mgmt->addr3),
- le16_to_cpu(req->capability), dev->obuf,
- hex2str(orates,tlv->data,min((sizeof(orates)-1)/2,(size_t)tlv->len),
- '\0'));
+ 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);
}
- /* either send immediately (if no data tx is pending
- or put it in pending list */
- return at76_send_mgmt_bulk(dev, tx_buffer);
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - enc.flags %08x "
+ "pointer %p len %d", netdev->name, encoding->flags,
+ encoding->pointer, encoding->length);
+ at76_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 == WLAN_AUTH_SHARED_KEY) ?
+ "restricted" : "open");
+ return 0;
}
-/* we are currently associated to curr_bss and
- want to reassoc to new_bss */
-static int at76_reassoc_req(struct at76_priv *dev, struct bss_info *curr_bss,
- struct bss_info *new_bss)
+
+static int at76_iw_handler_set_power(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *prq, char *extra)
{
- struct at76_tx_buffer *tx_buffer;
- struct ieee80211_hdr_3addr *mgmt;
- struct ieee80211_reassoc_request *req;
- struct ieee80211_info_element *tlv;
+ int err = -EIWCOMMIT;
+ struct at76_priv *dev = netdev_priv(netdev);
- at76_assert(curr_bss != NULL);
- at76_assert(new_bss != NULL);
- if (curr_bss == NULL || new_bss == NULL)
- return -EFAULT;
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWPOWER - disabled %s flags x%x value x%x",
+ netdev->name, (prq->disabled) ? "true" : "false",
+ prq->flags, prq->value);
- tx_buffer = kmalloc(REASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
- if (!tx_buffer)
- return -ENOMEM;
+ if (prq->disabled) {
+ dev->pm_mode = AT76_PM_OFF;
+ } else {
+ switch (prq->flags & IW_POWER_MODE) {
+ case IW_POWER_ALL_R:
+ case IW_POWER_ON:
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ if (prq->flags & IW_POWER_PERIOD) {
+ dev->pm_period = prq->value;
+ }
+ if (prq->flags & IW_POWER_TIMEOUT) {
+ err = -EINVAL;
+ goto out;
+ }
+ dev->pm_mode = AT76_PM_ON;
+ }
+out:
+ return err;
+}
- req = (struct ieee80211_reassoc_request *)(&tx_buffer->packet);
- mgmt = &req->header;
- tlv = req->info_element;
- /* make wireless header */
- /* jal: encrypt this packet if wep_enabled is TRUE ??? */
- mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_REASSOC_REQ);
- mgmt->duration_id = cpu_to_le16(0x8000);
- memcpy(mgmt->addr1, new_bss->bssid, ETH_ALEN);
- memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN);
- memcpy(mgmt->addr3, new_bss->bssid, ETH_ALEN);
- mgmt->seq_ctl = cpu_to_le16(0);
+static int at76_iw_handler_get_power(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *power, char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
- /* we must set the Privacy bit in the capabilities to assure an
- Agere-based AP with optional WEP transmits encrypted frames
- to us. AP only set the Privacy bit in their capabilities
- if WEP is mandatory in the BSS! */
- req->capability = cpu_to_le16(new_bss->capa |
- (dev->wep_enabled ? WLAN_CAPABILITY_PRIVACY : 0) |
- (dev->preamble_type == PREAMBLE_TYPE_SHORT ?
- WLAN_CAPABILITY_SHORT_PREAMBLE : 0));
+ if ((power->disabled = (dev->pm_mode == AT76_PM_OFF)))
+ return 0;
+ else {
+ power->flags = IW_POWER_PERIOD;
+ power->value = dev->pm_period;
+ }
+ power->flags |= IW_POWER_ALL_R;
- req->listen_interval = cpu_to_le16(2 * new_bss->beacon_interval);
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWPOWER - disabled %s flags x%x value x%x",
+ netdev->name, (power->disabled) ? "true" : "false",
+ power->flags, power->value);
- memcpy(req->current_ap, curr_bss->bssid, ETH_ALEN);
+ return 0;
+}
- /* write TLV data elements */
- tlv->id = MFIE_TYPE_SSID;
- tlv->len = new_bss->ssid_len;
- memcpy(tlv->data, new_bss->ssid, new_bss->ssid_len);
- next_ie(&tlv);
- tlv->id = MFIE_TYPE_RATES;
- tlv->len = sizeof(hw_rates);
- memcpy(tlv->data, hw_rates, sizeof(hw_rates));
- /* tlv points behind the supp_rates field */
- next_ie(&tlv);
+/*******************************************************************************
+ * Private IOCTLS
+ */
+static int at76_iw_set_short_preamble(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
- /* init. at76_priv tx header */
- tx_buffer->wlength = cpu_to_le16((u8 *)tlv-(u8 *)mgmt);
+ at76_dbg(DBG_IOCTL, "%s: AT76_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;
+}
+
+
+static int at76_iw_set_debug(struct net_device *netdev,
+ struct 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;
+ }
+
+ dbg("%s: AT76_SET_DEBUG input %d: %s -> x%x",
+ netdev->name, data->length, extra, val);
+ } else {
+ val = DBG_DEFAULTS;
+ }
+
+ dbg("%s: AT76_SET_DEBUG, old 0x%x new 0x%x",
+ netdev->name, at76_debug, val);
+
+ /* jal: some more output to pin down lockups */
+ dbg("%s: netif running %d queue_stopped %d carrier_ok %d",
+ netdev->name,
+ netif_running(netdev),
+ netif_queue_stopped(netdev), netif_carrier_ok(netdev));
+
+ at76_debug = val;
+
+ return 0;
+}
+
+
+static int at76_iw_set_powersave_mode(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_POWERSAVE_MODE, %d (%s)",
+ netdev->name, val,
+ val == AT76_PM_OFF ? "active" : val == AT76_PM_ON ? "save" :
+ val == AT76_PM_SMART ? "smart save" : "<invalid>");
+ if (val < AT76_PM_OFF || val > AT76_PM_SMART) {
+ ret = -EINVAL;
+ } else {
+ dev->pm_mode = val;
+ }
+
+ return ret;
+}
+
+
+static int at76_iw_set_scan_times(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int mint = *((int *)name);
+ int maxt = *((int *)name + 1);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SCAN_TIMES - min %d max %d",
+ netdev->name, mint, maxt);
+ if (mint <= 0 || maxt <= 0 || mint > maxt) {
+ ret = -EINVAL;
+ } else {
+ if (dev->istate == MONITORING) {
+ dev->monitor_scan_min_time = mint;
+ dev->monitor_scan_max_time = maxt;
+ ret = 0;
+ } else {
+ dev->scan_min_time = mint;
+ dev->scan_max_time = maxt;
+ }
+ }
+
+ return ret;
+}
+
+
+static int at76_iw_set_scan_mode(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_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;
+}
+
+
+static int at76_set_iroaming(struct at76_priv *dev, int onoff)
+{
+ int ret = 0;
+
+ memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer));
+ dev->mib_buf.type = MIB_MAC_MGMT;
+ dev->mib_buf.size = 1;
+ dev->mib_buf.index = IROAMING_OFFSET;
+ dev->mib_buf.data[0] = (dev->international_roaming ? 1 : 0);
+ ret = at76_set_mib(dev, &dev->mib_buf);
+ if (ret < 0) {
+ err("%s: set_mib (intl_roaming_enable) failed: %d", dev->netdev->name, ret);
+ }
+
+ return ret;
+}
+
+
+static int at76_iw_set_intl_roaming(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_INTL_ROAMING - mode %s",
+ netdev->name, (val == IR_OFF) ? "off" :
+ (val == IR_ON) ? "on" : "<invalid>");
+
+ if (val != IR_OFF && val != IR_ON) {
+ ret = -EINVAL;
+ } else {
+ if (dev->international_roaming != val) {
+ dev->international_roaming = val;
+ at76_set_iroaming(dev, val);
+ }
+ }
+
+ return ret;
+}
+
+
+/*******************************************************************************
+ * structure that advertises the iw handlers of this driver
+ */
+static const iw_handler at76_handlers[] =
+{
+ [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) at76_iw_handler_commit,
+ [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_name,
+ [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_freq,
+ [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_freq,
+ [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_mode,
+ [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_mode,
+ [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_range,
+ [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_spy,
+ [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_spy,
+ [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_thrspy,
+ [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_thrspy,
+ [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_wap,
+ [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_wap,
+ [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_scan,
+ [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_scan,
+ [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_essid,
+ [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_essid,
+ [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_rate,
+ [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_rate,
+ [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_rts,
+ [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_rts,
+ [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_frag,
+ [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_frag,
+ [SIOCGIWTXPOW -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_txpow,
+ [SIOCSIWRETRY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_retry,
+ [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_retry,
+ [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_encode,
+ [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_encode,
+ [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_power,
+ [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_power,
+};
+
+#define AT76_SET_PRIV(h, f) [h - SIOCIWFIRSTPRIV] = (iw_handler) f
+
+/*structure that advertises the private iw handlers of this driver */
+static const iw_handler at76_priv_handlers[] = {
+ AT76_SET_PRIV(AT76_SET_SHORT_PREAMBLE, at76_iw_set_short_preamble),
+ AT76_SET_PRIV(AT76_SET_DEBUG, at76_iw_set_debug),
+ AT76_SET_PRIV(AT76_SET_POWERSAVE_MODE, at76_iw_set_powersave_mode),
+ AT76_SET_PRIV(AT76_SET_SCAN_TIMES, at76_iw_set_scan_times),
+ AT76_SET_PRIV(AT76_SET_SCAN_MODE, at76_iw_set_scan_mode),
+ AT76_SET_PRIV(AT76_SET_INTL_ROAMING, at76_iw_set_intl_roaming),
+};
+
+
+/*******************************************************************************
+ * structure that describes the private ioctls/iw handlers of this driver
+ */
+static const struct iw_priv_args at76_priv_args[] = {
+ {AT76_SET_SHORT_PREAMBLE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "short_preamble"}, /* 0 - long, 1 -short */
+
+ {AT76_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 */
+
+ {AT76_SET_POWERSAVE_MODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "powersave_mode"}, /* 1 - active, 2 - power save,
+ 3 - smart power save */
+ {AT76_SET_SCAN_TIMES,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0,
+ "scan_times"}, /* min_channel_time,
+ max_channel_time */
+ {AT76_SET_SCAN_MODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "scan_mode"}, /* 0 - active, 1 - passive scan */
+
+ {AT76_SET_INTL_ROAMING,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "intl_roaming"},
+};
+
+
+static const struct iw_handler_def at76_handler_def =
+{
+ .num_standard = ARRAY_SIZE(at76_handlers),
+ .num_private = ARRAY_SIZE(at76_priv_handlers),
+ .num_private_args = ARRAY_SIZE(at76_priv_args),
+ .standard = at76_handlers,
+ .private = at76_priv_handlers,
+ .private_args = at76_priv_args,
+ .get_wireless_stats = at76_get_wireless_stats,
+};
+
+
+/* A short overview on Ethernet-II, 802.2, 802.3 and SNAP
+ (taken from http://www.geocities.com/billalexander/ethernet.html):
+
+Ethernet Frame Formats:
+
+Ethernet (a.k.a. Ethernet II)
+
+ +---------+---------+---------+----------
+ | Dst | Src | Type | Data...
+ +---------+---------+---------+----------
+
+ <-- 6 --> <-- 6 --> <-- 2 --> <-46-1500->
+
+ Type 0x80 0x00 = TCP/IP
+ Type 0x06 0x00 = XNS
+ Type 0x81 0x37 = Novell NetWare
+
+
+802.3
+
+ +---------+---------+---------+----------
+ | Dst | Src | Length | Data...
+ +---------+---------+---------+----------
+
+ <-- 6 --> <-- 6 --> <-- 2 --> <-46-1500->
+
+802.2 (802.3 with 802.2 header)
+
+ +---------+---------+---------+-------+-------+-------+----------
+ | Dst | Src | Length | DSAP | SSAP |Control| Data...
+ +---------+---------+---------+-------+-------+-------+----------
+
+ <- 1 -> <- 1 -> <- 1 -> <-43-1497->
+
+SNAP (802.3 with 802.2 and SNAP headers)
+
+ +---------+---------+---------+-------+-------+-------+-----------+---------+-----------
+ | Dst | Src | Length | 0xAA | 0xAA | 0x03 | Org Code | Type | Data...
+ +---------+---------+---------+-------+-------+-------+-----------+---------+-----------
+
+ <-- 3 --> <-- 2 --> <-38-1492->
+
+*/
+static const u8 snapsig[] = { 0xaa, 0xaa, 0x03 };
+
+/* RFC 1042 encapsulates Ethernet frames in 802.2 SNAP (0xaa, 0xaa, 0x03) with
+ * a SNAP OID of 0 (0x00, 0x00, 0x00) */
+static const u8 rfc1042sig[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+
+static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ struct net_device_stats *stats = &dev->stats;
+ int ret = 0;
+ int wlen;
+ int submit_len;
+ struct at76_tx_buffer *tx_buffer = dev->bulk_out_buffer;
+ struct ieee80211_hdr_3addr *i802_11_hdr =
+ (struct ieee80211_hdr_3addr *)&(tx_buffer->packet);
+ u8 *payload = tx_buffer->packet + sizeof(struct ieee80211_hdr_3addr);
+
+ if (netif_queue_stopped(netdev)) {
+ err("%s: %s called while netdev is stopped", netdev->name,
+ __FUNCTION__);
+ /* skip this packet */
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ if (dev->write_urb->status == -EINPROGRESS) {
+ err("%s: %s called while dev->write_urb is pending for tx",
+ netdev->name, __FUNCTION__);
+ /* skip this packet */
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ if (skb->len < 2 * ETH_ALEN) {
+ err("%s: %s: skb too short (%d)", dev->netdev->name,
+ __FUNCTION__, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ at76_ledtrig_tx_activity(); /* tell the ledtrigger we send a packet */
+
+ /* we can get rid of memcpy, if we set netdev->hard_header_len
+ to 8 + sizeof(struct ieee80211_hdr_3addr), because then we have
+ enough space
+ at76_dbg(DBG_TX, "skb->data - skb->head = %d", skb->data - skb->head); */
+
+ if (ntohs(*(__be16 *) (skb->data + 2 * ETH_ALEN)) <= 1518) {
+ /* this is a 802.3 packet */
+ if (skb->data[2 * ETH_ALEN + 2] == rfc1042sig[0] &&
+ skb->data[2 * ETH_ALEN + 2 + 1] == rfc1042sig[1]) {
+ /* higher layer delivered SNAP header - keep it */
+ memcpy(payload, skb->data + 2*ETH_ALEN+2, skb->len - 2*ETH_ALEN -2);
+ wlen = sizeof(struct ieee80211_hdr_3addr) + skb->len - 2*ETH_ALEN -2;
+ } else {
+ err("%s: %s: no support for non-SNAP 802.2 packets "
+ "(DSAP x%02x SSAP x%02x cntrl x%02x)",
+ dev->netdev->name, __FUNCTION__,
+ skb->data[2 * ETH_ALEN + 2],
+ skb->data[2 * ETH_ALEN + 2 + 1],
+ skb->data[2 * ETH_ALEN + 2 + 2]);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ } else {
+ /* add RFC 1042 header in front */
+ memcpy(payload, rfc1042sig, sizeof(rfc1042sig));
+ memcpy(payload + sizeof(rfc1042sig),
+ skb->data + 2*ETH_ALEN, skb->len - 2*ETH_ALEN);
+ wlen = sizeof(struct ieee80211_hdr_3addr) + sizeof(rfc1042sig) +
+ skb->len - 2*ETH_ALEN;
+ }
+
+ /* make wireless header */
+ i802_11_hdr->frame_ctl =
+ cpu_to_le16(IEEE80211_FTYPE_DATA |
+ (dev->wep_enabled ? IEEE80211_FCTL_PROTECTED : 0) |
+ (dev->iw_mode ==
+ IW_MODE_INFRA ? IEEE80211_FCTL_TODS : 0));
+
+ if (dev->iw_mode == IW_MODE_ADHOC) {
+ memcpy(i802_11_hdr->addr1, skb->data, ETH_ALEN); /* destination */
+ memcpy(i802_11_hdr->addr2, skb->data + ETH_ALEN, ETH_ALEN); /* source */
+ memcpy(i802_11_hdr->addr3, dev->bssid, ETH_ALEN);
+ } else if (dev->iw_mode == IW_MODE_INFRA) {
+ memcpy(i802_11_hdr->addr1, dev->bssid, ETH_ALEN);
+ memcpy(i802_11_hdr->addr2, skb->data + ETH_ALEN, ETH_ALEN); /* source */
+ memcpy(i802_11_hdr->addr3, skb->data, ETH_ALEN); /* destination */
+ }
+
+ i802_11_hdr->duration_id = cpu_to_le16(0);
+ i802_11_hdr->seq_ctl = cpu_to_le16(0);
+
+ /* setup 'Atmel' header */
+ tx_buffer->wlength = cpu_to_le16(wlen);
+ tx_buffer->tx_rate = dev->txrate;
+ /* for broadcast destination addresses, the firmware 0.100.x
+ seems to choose the highest rate set with CMD_STARTUP in
+ basic_rate_set replacing this value */
+
+ memset(tx_buffer->reserved, 0, 4);
+
+ tx_buffer->padding = at76_calc_padding(wlen);
+ submit_len = wlen + AT76_TX_HDRLEN + tx_buffer->padding;
{
- /* output buffer for rates and bssid */
- char orates[4*2+1];
- char ocurr[6*3+1];
- tlv = req->info_element;
- memcpy(dev->obuf, tlv->data, min(sizeof(dev->obuf),(size_t)tlv->len));
- dev->obuf[IW_ESSID_MAX_SIZE] = '\0';
- next_ie(&tlv); /* points to IE of rates now */
- at76_dbg(DBG_TX_MGMT, "%s: ReAssocReq curr %s new %s capa x%04x ssid %s rates %s",
+ at76_dbg(DBG_TX_DATA_CONTENT, "%s skb->data %s", dev->netdev->name,
+ hex2str(dev->obuf, skb->data,
+ min((int)(sizeof(dev->obuf) - 1) / 2, 32), '\0'));
+ at76_dbg(DBG_TX_DATA, "%s tx wlen x%x pad x%x rate %d hdr %s",
dev->netdev->name,
- hex2str(ocurr, req->current_ap, ETH_ALEN, ':'),
- mac2str(mgmt->addr3), le16_to_cpu(req->capability), dev->obuf,
- hex2str(orates,tlv->data,min((sizeof(orates)-1)/2,(size_t)tlv->len),
- '\0'));
+ le16_to_cpu(tx_buffer->wlength),
+ tx_buffer->padding, tx_buffer->tx_rate,
+ hex2str(dev->obuf, i802_11_hdr,
+ min((sizeof(dev->obuf) - 1) / 2,
+ sizeof(struct ieee80211_hdr_3addr)), '\0'));
+ at76_dbg(DBG_TX_DATA_CONTENT, "%s payload %s", dev->netdev->name,
+ hex2str(dev->obuf, payload,
+ min((int)(sizeof(dev->obuf) - 1) / 2, 48), '\0'));
}
- /* either send immediately (if no data tx is pending
- or put it in pending list */
- return at76_send_mgmt_bulk(dev, tx_buffer);
+ /* send stuff */
+ netif_stop_queue(netdev);
+ netdev->trans_start = jiffies;
+
+ usb_fill_bulk_urb(dev->write_urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+ tx_buffer, submit_len,
+ at76_write_bulk_callback, dev);
+ ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC);
+ if (ret) {
+ stats->tx_errors++;
+ err("%s: error in tx submit urb: %d", netdev->name, ret);
+ if (ret == -EINVAL)
+ err("-EINVAL: urb %p urb->hcpriv %p urb->complete %p",
+ dev->write_urb,
+ dev->write_urb ? dev->write_urb->hcpriv : (void *)-1,
+ dev->write_urb ? dev->write_urb->complete : (void *)-1);
+ goto err;
+ }
+
+ stats->tx_bytes += skb->len;
+
+ dev_kfree_skb(skb);
+ return 0;
+ err:
+ return ret;
}
-/* Called after successful association */
-static void at76_work_assoc_done(struct work_struct *work)
+
+static void at76_tx_timeout(struct net_device *netdev)
{
- struct at76_priv *dev = container_of(work, struct at76_priv,
- work_assoc_done);
+ struct at76_priv *dev = netdev_priv(netdev);
- down(&dev->sem);
+ if (!dev)
+ return;
+ warn("%s: tx timeout.", netdev->name);
- at76_assert(dev->istate == ASSOCIATING || dev->istate == REASSOCIATING);
- if (dev->iw_mode == IW_MODE_INFRA) {
- at76_assert(dev->curr_bss != NULL);
- if (dev->curr_bss != NULL && dev->pm_mode != AT76_PM_OFF) {
- /* calculate the listen interval in units of
- beacon intervals of the curr_bss */
- u32 pm_period_beacon = (dev->pm_period >> 10) /
- dev->curr_bss->beacon_interval;
+ usb_unlink_urb(dev->write_urb);
+ dev->stats.tx_errors++;
+}
- pm_period_beacon = max(pm_period_beacon, 2u);
- pm_period_beacon = min(pm_period_beacon, 0xffffu);
- at76_dbg(DBG_PM, "%s: pm_mode %d assoc id x%x listen int %d",
- dev->netdev->name, dev->pm_mode,
- dev->curr_bss->assoc_id, pm_period_beacon);
+static int at76_submit_rx_urb(struct at76_priv *dev)
+{
+ int ret, size;
+ struct sk_buff *skb = dev->rx_skb;
- at76_set_associd(dev, dev->curr_bss->assoc_id);
- at76_set_listen_interval(dev, (u16)pm_period_beacon);
+ if (dev->read_urb == NULL) {
+ err("%s: dev->read_urb is NULL", __FUNCTION__);
+ return -EFAULT;
+ }
+
+ if (skb == NULL) {
+ skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
+ if (skb == NULL) {
+ err("%s: unable to allocate rx skbuff.", dev->netdev->name);
+ ret = -ENOMEM;
+ goto exit;
+ }
+ dev->rx_skb = skb;
+ } else {
+ skb_push(skb, skb_headroom(skb));
+ skb_trim(skb, 0);
+ }
+
+ size = skb_tailroom(skb);
+ usb_fill_bulk_urb(dev->read_urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+ skb_put(skb, size), size,
+ at76_read_bulk_callback, dev);
+ ret = usb_submit_urb(dev->read_urb, GFP_ATOMIC);
+ if (ret < 0) {
+ if (ret == -ENODEV)
+ at76_dbg(DBG_DEVSTART, "usb_submit_urb returned -ENODEV");
+ else
+ err("%s: rx, usb_submit_urb failed: %d", dev->netdev->name, ret);
+ }
+
+exit:
+ if (ret < 0) {
+ if (ret != -ENODEV) {
+ /* If we can't submit the URB, the adapter becomes completely
+ * useless, so try again later */
+ if (--dev->nr_submit_rx_tries > 0)
+ schedule_work(&dev->work_submit_rx);
+ else {
+ err("%s: giving up to submit rx urb after %d failures -"
+ " please unload the driver and/or power cycle the device",
+ dev->netdev->name, NR_SUBMIT_RX_TRIES);
+ }
+ }
+ } else
+ /* reset counter to initial value */
+ dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES;
+ return ret;
+}
+
+
+static int at76_open(struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ int ret = 0;
+
+ at76_dbg(DBG_PROC_ENTRY, "at76_open entry");
+
+ if (down_interruptible(&dev->sem))
+ return -EINTR;
+
+ /* if netdev->dev_addr != dev->mac_addr we must
+ set the mac address in the device ! */
+ if (compare_ether_addr(netdev->dev_addr, dev->mac_addr)) {
+ if (at76_add_mac_address(dev, netdev->dev_addr) >= 0)
+ at76_dbg(DBG_PROGRESS, "%s: set new MAC addr %s",
+ netdev->name, mac2str(netdev->dev_addr));
+ }
#ifdef DEBUG
- at76_dump_mib_mac(dev);
- at76_dump_mib_mac_mgmt(dev);
+ at76_dump_mib_mac_addr(dev);
#endif
- }
+
+ dev->scan_state = SCAN_IDLE;
+ dev->last_scan = jiffies;
+ dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES; /* init counter */
+
+ if ((ret = at76_submit_rx_urb(dev)) < 0) {
+ err("%s: open: submit_rx_urb failed: %d", netdev->name, ret);
+ goto err;
}
- at76_set_pm_mode(dev);
- netif_carrier_on(dev->netdev);
- netif_wake_queue(dev->netdev);
- dev->istate = CONNECTED;
- at76_iwevent_bss_connect(dev->netdev, dev->curr_bss->bssid);
- at76_dbg(DBG_PROGRESS, "%s: connected to BSSID %s",
- dev->netdev->name, mac2str(dev->curr_bss->bssid));
+ dev->open_count++;
+
+ schedule_work(&dev->work_restart);
+
+ at76_dbg(DBG_PROC_ENTRY, "at76_open end");
+ err:
+ up(&dev->sem);
+ return ret < 0 ? ret : 0;
+}
+
+
+static int at76_stop(struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ unsigned long flags;
+
+ at76_dbg(DBG_DEVSTART, "%s: ENTER", __FUNCTION__);
+
+ if (down_interruptible(&dev->sem))
+ return -EINTR;
+
+ netif_stop_queue(netdev);
+
+ dev->istate = INIT;
+
+ if (!(dev->device_unplugged)) {
+ /* we are called by "ifconfig ethX down", not because the
+ device isn't avail. anymore */
+ at76_set_radio(dev, 0);
+
+ /* we unlink the read urb, because the _open()
+ submits it again. _delete_device() takes care of the
+ read_urb otherwise. */
+ usb_kill_urb(dev->read_urb);
+ }
+
+ 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);
+
+ /* free the bss_list */
+ at76_free_bss_list(dev);
+
+ at76_assert(dev->open_count > 0);
+ dev->open_count--;
up(&dev->sem);
+ at76_dbg(DBG_DEVSTART, "%s: EXIT", __FUNCTION__);
+
+ return 0;
+}
+
+
+static void at76_ethtool_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ info->version[sizeof(info->version) - 1] = '\0';
+
+ snprintf(info->bus_info, sizeof(info->bus_info) - 1, "usb%d:%d",
+ dev->udev->bus->busnum, dev->udev->devnum);
+
+ snprintf(info->fw_version, sizeof(info->fw_version) - 1,
+ "%d.%d.%d-%d",
+ dev->fw_version.major, dev->fw_version.minor,
+ dev->fw_version.patch, dev->fw_version.build);
+}
+
+
+static u32 at76_ethtool_get_link(struct net_device *netdev)
+{
+ struct at76_priv *dev = netdev_priv(netdev);
+ return dev->istate == CONNECTED;
}
+
+static struct ethtool_ops at76_ethtool_ops = {
+ .get_drvinfo = at76_ethtool_get_drvinfo,
+ .get_link = at76_ethtool_get_link,
+};
+
+
+/**
+ * at76_init_new_device - continue device initialization after firmware download
+ *
+ * FIXME: We may have to move the register_netdev into at76_alloc_new_device,
+ * because hotplug may try to configure the netdev _before_ (or parallel to)
+ * the download of firmware
+ */
+static int at76_init_new_device(struct at76_priv *dev)
+{
+ struct net_device *netdev = dev->netdev;
+ int ret;
+
+ /* set up the endpoint information */
+ /* check out the endpoints */
+
+ dev->interface = dev->udev->actconfig->interface[0];
+
+ at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints",
+ dev->interface->cur_altsetting->desc.bNumEndpoints);
+
+ if ((ret = at76_alloc_urbs(dev)) < 0)
+ goto error;
+
+ /* get firmware version */
+ ret = at76_get_mib(dev->udev, MIB_FW_VERSION, &dev->fw_version,
+ sizeof(dev->fw_version));
+ if ((ret < 0) || ((dev->fw_version.major == 0) &&
+ (dev->fw_version.minor == 0) &&
+ (dev->fw_version.patch == 0) &&
+ (dev->fw_version.build == 0))) {
+ err("getting firmware failed with %d, or version is 0", ret);
+ err("this probably means that the ext. fw was not loaded correctly");
+ if(ret >= 0)
+ ret = -ENODEV;
+ goto error;
+ }
+
+ /* fw 0.84 doesn't send FCS with rx data */
+ if (dev->fw_version.major == 0 && dev->fw_version.minor <= 84)
+ dev->rx_data_fcs_len = 0;
+ else
+ dev->rx_data_fcs_len = 4;
+
+ 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,
+ dev->rx_data_fcs_len);
+
+ /* MAC address */
+ ret = at76_get_hw_config(dev);
+ if (ret < 0) {
+ err("could not get MAC address");
+ goto error;
+ }
+
+ dev->domain = at76_get_reg_domain(dev->regulatory_domain);
+ /* init. netdev->dev_addr */
+ memcpy(netdev->dev_addr, dev->mac_addr, ETH_ALEN);
+ info("device's MAC %s, regulatory domain %s (id %d)",
+ mac2str(dev->mac_addr), dev->domain->name, dev->regulatory_domain);
+
+ /* initializing */
+ dev->international_roaming = international_roaming;
+ dev->channel = DEF_CHANNEL;
+ dev->iw_mode = default_iw_mode;
+ memset(dev->essid, 0, IW_ESSID_MAX_SIZE);
+ dev->rts_threshold = DEF_RTS_THRESHOLD;
+ dev->frag_threshold = DEF_FRAG_THRESHOLD;
+ dev->short_retry_limit = DEF_SHORT_RETRY_LIMIT;
+ dev->txrate = TX_RATE_AUTO;
+ dev->preamble_type = preamble_type;
+ dev->beacon_period = 100;
+ dev->beacons_last_qual = jiffies_to_msecs(jiffies);
+ dev->auth_mode = auth_mode ? WLAN_AUTH_SHARED_KEY : WLAN_AUTH_OPEN;
+ dev->scan_min_time = scan_min_time;
+ dev->scan_max_time = scan_max_time;
+ dev->scan_mode = scan_mode;
+ dev->monitor_scan_min_time = monitor_scan_min_time;
+ dev->monitor_scan_max_time = monitor_scan_max_time;
+
+ netdev->flags &= ~IFF_MULTICAST; /* not yet or never */
+ netdev->open = at76_open;
+ netdev->stop = at76_stop;
+ netdev->get_stats = at76_get_stats;
+ netdev->ethtool_ops = &at76_ethtool_ops;
+
+ /* Add pointers to enable iwspy support. */
+ dev->wireless_data.spy_data = &dev->spy_data;
+ netdev->wireless_data = &dev->wireless_data;
+
+ netdev->hard_start_xmit = at76_tx;
+ netdev->tx_timeout = at76_tx_timeout;
+ netdev->watchdog_timeo = 2 * HZ;
+ netdev->wireless_handlers = &at76_handler_def;
+ netdev->set_multicast_list = at76_set_multicast;
+ netdev->set_mac_address = at76_set_mac_address;
+
+ ret = register_netdev(dev->netdev);
+ if (ret) {
+ err("unable to register netdevice %s (status %d)!",
+ dev->netdev->name, ret);
+ goto error;
+ }
+ info("registered %s", dev->netdev->name);
+ dev->netdev_registered = 1;
+
+ /* we let this timer run the whole time this driver instance lives */
+ mod_timer(&dev->bss_list_timer, jiffies + BSS_LIST_TIMEOUT);
+
+ return 0;
+ error:
+ at76_delete_device(dev);
+ return ret;
+}
+
+
/* Download external firmware */
static void at76_work_external_fw(struct work_struct *work)
{
@@ -2226,6 +4300,7 @@ static void at76_work_external_fw(struct work_struct *work)
up(&dev->sem);
}
+
/* Download internal firmware */
static void at76_work_internal_fw(struct work_struct *work)
{
@@ -2262,6 +4337,133 @@ static void at76_work_internal_fw(struct work_struct *work)
up(&dev->sem);
}
+
+static int at76_essid_matched(struct at76_priv *dev, struct bss_info *ptr)
+{
+ /* common criteria for both modi */
+
+ int ret = (dev->essid_size == 0 /* ANY ssid */ ||
+ (dev->essid_size == ptr->ssid_len &&
+ !memcmp(dev->essid, ptr->ssid, ptr->ssid_len)));
+ if (!ret)
+ at76_dbg(DBG_BSS_MATCH, "%s bss table entry %p: essid didn't match",
+ dev->netdev->name, ptr);
+ return ret;
+}
+
+
+static inline int at76_mode_matched(struct at76_priv *dev, struct bss_info *ptr)
+{
+ int ret;
+
+ if (dev->iw_mode == IW_MODE_ADHOC)
+ ret = ptr->capa & WLAN_CAPABILITY_IBSS;
+ else
+ ret = ptr->capa & WLAN_CAPABILITY_ESS;
+ if (!ret)
+ at76_dbg(DBG_BSS_MATCH, "%s bss table entry %p: mode didn't match",
+ dev->netdev->name, ptr);
+ return ret;
+}
+
+
+static int at76_rates_matched(struct at76_priv *dev, struct bss_info *ptr)
+{
+ int i;
+ u8 *rate;
+
+ for (i = 0, rate = ptr->rates; i < ptr->rates_len; i++, rate++)
+ if (*rate & 0x80) {
+ /* this is a basic rate we have to support
+ (see IEEE802.11, ch. 7.3.2.2) */
+ if (*rate != (0x80 | hw_rates[0])
+ && *rate != (0x80 | hw_rates[1])
+ && *rate != (0x80 | hw_rates[2])
+ && *rate != (0x80 | hw_rates[3])) {
+ at76_dbg(DBG_BSS_MATCH,
+ "%s: bss table entry %p: basic rate %02x not supported",
+ dev->netdev->name, ptr, *rate);
+ return 0;
+ }
+ }
+ /* if we use short preamble, the bss must support it */
+ if (dev->preamble_type == PREAMBLE_TYPE_SHORT &&
+ !(ptr->capa & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+ at76_dbg(DBG_BSS_MATCH, "%s: %p does not support short preamble",
+ dev->netdev->name, ptr);
+ return 0;
+ } else
+ return 1;
+}
+
+
+static inline int at76_wep_matched(struct at76_priv *dev, struct bss_info *ptr)
+{
+ if (!dev->wep_enabled && ptr->capa & WLAN_CAPABILITY_PRIVACY) {
+ /* we have disabled WEP, but the BSS signals privacy */
+ at76_dbg(DBG_BSS_MATCH, "%s: bss table entry %p: requires encryption",
+ dev->netdev->name, ptr);
+ return 0;
+ }
+ /* otherwise if the BSS does not signal privacy it may well
+ accept encrypted packets from us ... */
+ return 1;
+}
+
+
+static inline int at76_bssid_matched(struct at76_priv *dev,
+ struct bss_info *ptr)
+{
+ if (!dev->wanted_bssid_valid ||
+ !compare_ether_addr(ptr->bssid, dev->wanted_bssid)) {
+ return 1;
+ } else {
+ at76_dbg(DBG_BSS_MATCH, "%s: requested bssid - %s does not match",
+ dev->netdev->name, mac2str(dev->wanted_bssid));
+ at76_dbg(DBG_BSS_MATCH, " AP bssid - %s of bss table entry %p",
+ mac2str(ptr->bssid), ptr);
+ return 0;
+ }
+}
+
+
+/**
+ * at76_match_bss - try to find a matching bss in dev->bss
+ *
+ * last - last bss tried
+ *
+ * last == NULL signals a new round starting with dev->bss_list.next
+ * this function must be called inside an acquired dev->bss_list_spinlock
+ * otherwise the timeout on bss may remove the newly chosen entry
+ */
+static struct bss_info *at76_match_bss(struct at76_priv *dev,
+ struct bss_info *last)
+{
+ struct bss_info *ptr = NULL;
+ struct list_head *curr;
+
+ curr = last != NULL ? last->list.next : dev->bss_list.next;
+ while (curr != &dev->bss_list) {
+ ptr = list_entry(curr, struct bss_info, list);
+ if (at76_essid_matched(dev, ptr) &&
+ at76_mode_matched(dev, ptr) &&
+ at76_wep_matched(dev, ptr) &&
+ at76_rates_matched(dev, ptr) &&
+ at76_bssid_matched(dev, ptr))
+ break;
+ curr = curr->next;
+ }
+
+ if (curr == &dev->bss_list)
+ ptr = NULL;
+ /* otherwise ptr points to the struct bss_info we have chosen */
+
+ at76_dbg(DBG_BSS_TABLE, "%s %s: returned %p", dev->netdev->name,
+ __FUNCTION__, ptr);
+ return ptr;
+}
+
+
/* Try joining a BSS */
static void at76_work_join(struct work_struct *work)
{
@@ -2345,6 +4547,7 @@ static void at76_work_join(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_mgmt_timeout(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2355,6 +4558,7 @@ static void at76_work_mgmt_timeout(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_new_bss(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2390,6 +4594,7 @@ static void at76_work_new_bss(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_reset_device(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2401,6 +4606,150 @@ static void at76_work_reset_device(struct work_struct *work)
up(&dev->sem);
}
+
+static int at76_startup_device(struct at76_priv *dev)
+{
+ struct at76_card_config *ccfg = &dev->card_config;
+ int ret;
+
+ if (at76_debug & DBG_PARAMS) {
+ char ossid[IW_ESSID_MAX_SIZE + 1];
+
+ /* make dev->essid printable */
+ at76_assert(dev->essid_size <= IW_ESSID_MAX_SIZE);
+ memcpy(ossid, dev->essid, dev->essid_size);
+ ossid[dev->essid_size] = '\0';
+
+ dbg("%s param: ssid %s (%s) mode %s ch %d wep %s key %d keylen %d",
+ dev->netdev->name, ossid,
+ hex2str(dev->obuf, dev->essid,
+ min((int)(sizeof(dev->obuf)-1)/2,
+ IW_ESSID_MAX_SIZE), '\0'),
+ dev->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
+ dev->channel,
+ dev->wep_enabled ? "enabled" : "disabled",
+ dev->wep_key_id, dev->wep_keys_len[dev->wep_key_id]);
+ dbg("%s param: preamble %s rts %d retry %d frag %d "
+ "txrate %s auth_mode %d",
+ dev->netdev->name,
+ dev->preamble_type == PREAMBLE_TYPE_SHORT ? "short" : "long",
+ dev->rts_threshold, dev->short_retry_limit,
+ dev->frag_threshold,
+ dev->txrate == TX_RATE_1MBIT ? "1MBit" :
+ dev->txrate == TX_RATE_2MBIT ? "2MBit" :
+ dev->txrate == TX_RATE_5_5MBIT ? "5.5MBit" :
+ dev->txrate == TX_RATE_11MBIT ? "11MBit" :
+ dev->txrate == TX_RATE_AUTO ? "auto" : "<invalid>",
+ dev->auth_mode);
+ dbg("%s param: pm_mode %d pm_period %d auth_mode %s "
+ "scan_times %d %d scan_mode %s international_roaming %d",
+ dev->netdev->name,
+ dev->pm_mode, dev->pm_period,
+ dev->auth_mode == WLAN_AUTH_OPEN ?
+ "open" : "shared_secret",
+ dev->scan_min_time, dev->scan_max_time,
+ dev->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive",
+ dev->international_roaming);
+ }
+
+ memset(ccfg, 0, sizeof(struct at76_card_config));
+ ccfg->promiscuous_mode = 0;
+ ccfg->short_retry_limit = dev->short_retry_limit;
+
+ if (dev->wep_enabled) {
+ if (dev->wep_keys_len[dev->wep_key_id] > WEP_SMALL_KEY_LEN)
+ ccfg->encryption_type = 2;
+ else
+ ccfg->encryption_type = 1;
+
+ /* jal: always exclude unencrypted if WEP is active */
+ ccfg->exclude_unencrypted = 1;
+ } else {
+ ccfg->exclude_unencrypted = 0;
+ ccfg->encryption_type = 0;
+ }
+
+ ccfg->rts_threshold = cpu_to_le16(dev->rts_threshold);
+ ccfg->fragmentation_threshold = cpu_to_le16(dev->frag_threshold);
+
+ memcpy(ccfg->basic_rate_set, hw_rates, 4);
+ /* jal: really needed, we do a set_mib for autorate later ??? */
+ ccfg->auto_rate_fallback = (dev->txrate == TX_RATE_AUTO ? 1 : 0);
+ ccfg->channel = dev->channel;
+ ccfg->privacy_invoked = dev->wep_enabled;
+ memcpy(ccfg->current_ssid, dev->essid, IW_ESSID_MAX_SIZE);
+ ccfg->ssid_len = dev->essid_size;
+
+ ccfg->wep_default_key_id = dev->wep_key_id;
+ memcpy(ccfg->wep_default_key_value, dev->wep_keys, 4 * WEP_KEY_LEN);
+
+ ccfg->short_preamble = dev->preamble_type;
+ ccfg->beacon_period = cpu_to_le16(dev->beacon_period);
+
+ ret = at76_set_card_command(dev->udev, CMD_STARTUP, &dev->card_config,
+ sizeof(struct at76_card_config));
+ if (ret < 0) {
+ err("%s: at76_set_card_command failed: %d", dev->netdev->name, ret);
+ return ret;
+ }
+
+ at76_wait_completion(dev, CMD_STARTUP);
+
+ /* remove BSSID from previous run */
+ memset(dev->bssid, 0, ETH_ALEN);
+
+ if (at76_set_radio(dev, 1) == 1)
+ at76_wait_completion(dev, CMD_RADIO);
+
+ if ((ret = at76_set_preamble(dev, dev->preamble_type)) < 0)
+ return ret;
+
+ if ((ret = at76_set_frag(dev, dev->frag_threshold)) < 0)
+ return ret;
+
+ if ((ret = at76_set_rts(dev, dev->rts_threshold)) < 0)
+ return ret;
+
+ if ((ret = at76_set_autorate_fallback(dev, dev->txrate == TX_RATE_AUTO ? 1 : 0)) < 0)
+ return ret;
+
+ if ((ret = at76_set_pm_mode(dev)) < 0)
+ return ret;
+
+ if ((ret = at76_set_iroaming(dev, dev->international_roaming)) < 0)
+ return ret;
+
+ if (at76_debug & DBG_MIB) {
+ at76_dump_mib_mac(dev);
+ at76_dump_mib_mac_addr(dev);
+ at76_dump_mib_mac_mgmt(dev);
+ at76_dump_mib_mac_wep(dev);
+ at76_dump_mib_mdomain(dev);
+ at76_dump_mib_phy(dev);
+ at76_dump_mib_local(dev);
+ }
+
+ return 0;
+}
+
+
+/**
+ * set_monitor_mode - sets dev->netdev->type
+ */
+static void at76_set_monitor_mode(struct at76_priv *dev)
+{
+ if (dev->iw_mode == IW_MODE_MONITOR) {
+ at76_dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE ON",
+ dev->netdev->name);
+ dev->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
+ } else {
+ at76_dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE OFF",
+ dev->netdev->name);
+ dev->netdev->type = ARPHRD_ETHER;
+ }
+}
+
+
static void at76_work_restart(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2429,6 +4778,7 @@ static void at76_work_restart(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_scan(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2456,6 +4806,7 @@ static void at76_work_scan(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_set_promisc(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2478,6 +4829,7 @@ static void at76_work_set_promisc(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_start_ibss(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2526,6 +4878,7 @@ static void at76_work_start_ibss(struct work_struct *work)
up(&dev->sem);
}
+
static void at76_work_submit_rx(struct work_struct *work)
{
struct at76_priv *dev = container_of(work, struct at76_priv,
@@ -2536,159 +4889,10 @@ static void at76_work_submit_rx(struct work_struct *work)
up(&dev->sem);
}
-static int at76_essid_matched(struct at76_priv *dev, struct bss_info *ptr)
-{
- /* common criteria for both modi */
-
- int ret = (dev->essid_size == 0 /* ANY ssid */ ||
- (dev->essid_size == ptr->ssid_len &&
- !memcmp(dev->essid, ptr->ssid, ptr->ssid_len)));
- if (!ret)
- at76_dbg(DBG_BSS_MATCH, "%s bss table entry %p: essid didn't match",
- dev->netdev->name, ptr);
- return ret;
-}
-
-static inline int at76_mode_matched(struct at76_priv *dev, struct bss_info *ptr)
-{
- int ret;
-
- if (dev->iw_mode == IW_MODE_ADHOC)
- ret = ptr->capa & WLAN_CAPABILITY_IBSS;
- else
- ret = ptr->capa & WLAN_CAPABILITY_ESS;
- if (!ret)
- at76_dbg(DBG_BSS_MATCH, "%s bss table entry %p: mode didn't match",
- dev->netdev->name, ptr);
- return ret;
-}
-
-static int at76_rates_matched(struct at76_priv *dev, struct bss_info *ptr)
-{
- int i;
- u8 *rate;
-
- for (i = 0, rate = ptr->rates; i < ptr->rates_len; i++, rate++)
- if (*rate & 0x80) {
- /* this is a basic rate we have to support
- (see IEEE802.11, ch. 7.3.2.2) */
- if (*rate != (0x80 | hw_rates[0])
- && *rate != (0x80 | hw_rates[1])
- && *rate != (0x80 | hw_rates[2])
- && *rate != (0x80 | hw_rates[3])) {
- at76_dbg(DBG_BSS_MATCH,
- "%s: bss table entry %p: basic rate %02x not supported",
- dev->netdev->name, ptr, *rate);
- return 0;
- }
- }
- /* if we use short preamble, the bss must support it */
- if (dev->preamble_type == PREAMBLE_TYPE_SHORT &&
- !(ptr->capa & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
- at76_dbg(DBG_BSS_MATCH, "%s: %p does not support short preamble",
- dev->netdev->name, ptr);
- return 0;
- } else
- return 1;
-}
-
-static inline int at76_wep_matched(struct at76_priv *dev, struct bss_info *ptr)
-{
- if (!dev->wep_enabled && ptr->capa & WLAN_CAPABILITY_PRIVACY) {
- /* we have disabled WEP, but the BSS signals privacy */
- at76_dbg(DBG_BSS_MATCH, "%s: bss table entry %p: requires encryption",
- dev->netdev->name, ptr);
- return 0;
- }
- /* otherwise if the BSS does not signal privacy it may well
- accept encrypted packets from us ... */
- return 1;
-}
-
-static inline int at76_bssid_matched(struct at76_priv *dev, struct bss_info *ptr)
-{
- if (!dev->wanted_bssid_valid ||
- !compare_ether_addr(ptr->bssid, dev->wanted_bssid)) {
- return 1;
- } else {
- at76_dbg(DBG_BSS_MATCH, "%s: requested bssid - %s does not match",
- dev->netdev->name, mac2str(dev->wanted_bssid));
- at76_dbg(DBG_BSS_MATCH, " AP bssid - %s of bss table entry %p",
- mac2str(ptr->bssid), ptr);
- return 0;
- }
-}
-
-static void at76_dump_bss_table(struct at76_priv *dev)
-{
- struct bss_info *ptr;
- unsigned long flags;
- struct list_head *lptr;
- char obuf_s[3*32];
-
- spin_lock_irqsave(&dev->bss_list_spinlock, flags);
-
- pr_debug("%s BSS table (curr=%p, new=%p):", dev->netdev->name,
- dev->curr_bss, dev->new_bss);
-
- list_for_each(lptr, &dev->bss_list) {
- ptr = list_entry(lptr, struct bss_info, list);
- pr_debug("0x%p: bssid %s channel %d ssid %s (%s)"
- " capa x%04x rates %s rssi %d link %d noise %d",
- ptr, mac2str(ptr->bssid),
- ptr->channel,
- ptr->ssid,
- hex2str(dev->obuf, ptr->ssid,
- min((sizeof(dev->obuf) - 1) / 2,
- (size_t) ptr->ssid_len), '\0'),
- ptr->capa,
- hex2str(obuf_s, ptr->rates,
- min(sizeof(obuf_s) / 3,
- (size_t) ptr->rates_len), ' '),
- ptr->rssi, ptr->link_qual, ptr->noise_level);
- }
- spin_unlock_irqrestore(&dev->bss_list_spinlock, flags);
-}
-
-/**
- * at76_match_bss - try to find a matching bss in dev->bss
- *
- * last - last bss tried
- *
- * last == NULL signals a new round starting with dev->bss_list.next
- * this function must be called inside an acquired dev->bss_list_spinlock
- * otherwise the timeout on bss may remove the newly chosen entry
- */
-static struct bss_info *at76_match_bss(struct at76_priv *dev,
- struct bss_info *last)
-{
- struct bss_info *ptr = NULL;
- struct list_head *curr;
-
- curr = last != NULL ? last->list.next : dev->bss_list.next;
- while (curr != &dev->bss_list) {
- ptr = list_entry(curr, struct bss_info, list);
- if (at76_essid_matched(dev, ptr) &&
- at76_mode_matched(dev, ptr) &&
- at76_wep_matched(dev, ptr) &&
- at76_rates_matched(dev, ptr) &&
- at76_bssid_matched(dev, ptr))
- break;
- curr = curr->next;
- }
-
- if (curr == &dev->bss_list)
- ptr = NULL;
- /* otherwise ptr points to the struct bss_info we have chosen */
-
- at76_dbg(DBG_BSS_TABLE, "%s %s: returned %p", dev->netdev->name,
- __FUNCTION__, ptr);
- return ptr;
-}
-
/* we got an association response */
-static void at76_rx_mgmt_assoc(struct at76_priv *dev, struct at76_rx_buffer *buf)
+static void at76_rx_mgmt_assoc(struct at76_priv *dev,
+ struct at76_rx_buffer *buf)
{
struct ieee80211_assoc_response *resp =
(struct ieee80211_assoc_response *)buf->packet;
@@ -2728,7 +4932,7 @@ static void at76_rx_mgmt_assoc(struct at76_priv *dev, struct at76_rx_buffer *buf
static void at76_rx_mgmt_reassoc(struct at76_priv *dev,
- struct at76_rx_buffer *buf)
+ struct at76_rx_buffer *buf)
{
struct ieee80211_assoc_response *resp =
(struct ieee80211_assoc_response *)buf->packet;
@@ -2782,7 +4986,7 @@ static void at76_rx_mgmt_reassoc(struct at76_priv *dev,
static void at76_rx_mgmt_disassoc(struct at76_priv *dev,
- struct at76_rx_buffer *buf)
+ struct at76_rx_buffer *buf)
{
struct ieee80211_disassoc *resp =
(struct ieee80211_disassoc *)buf->packet;
@@ -2901,7 +5105,8 @@ static void at76_rx_mgmt_auth(struct at76_priv *dev, struct at76_rx_buffer *buf)
}
-static void at76_rx_mgmt_deauth(struct at76_priv *dev, struct at76_rx_buffer *buf)
+static void at76_rx_mgmt_deauth(struct at76_priv *dev,
+ struct at76_rx_buffer *buf)
{
struct ieee80211_disassoc *resp =
(struct ieee80211_disassoc *)buf->packet;
@@ -2943,7 +5148,8 @@ static void at76_rx_mgmt_deauth(struct at76_priv *dev, struct at76_rx_buffer *bu
}
-static void at76_rx_mgmt_beacon(struct at76_priv *dev, struct at76_rx_buffer *buf)
+static void at76_rx_mgmt_beacon(struct at76_priv *dev,
+ struct at76_rx_buffer *buf)
{
/* beacon content */
struct ieee80211_beacon *bdata = (struct ieee80211_beacon *)buf->packet;
@@ -3125,7 +5331,7 @@ rx_mgmt_beacon_end:
/* calc the link level from a given rx_buffer */
static void at76_calc_level(struct at76_priv *dev, struct at76_rx_buffer *buf,
- struct iw_quality *qual)
+ struct iw_quality *qual)
{
int max_rssi = 42; /* just a guess for now, might be different for other chips */
@@ -3137,7 +5343,8 @@ static void at76_calc_level(struct at76_priv *dev, struct at76_rx_buffer *buf,
/* calc the link quality from a given rx_buffer */
-static void at76_calc_qual(struct at76_priv *dev, struct at76_rx_buffer *buf, struct iw_quality* qual)
+static void at76_calc_qual(struct at76_priv *dev, struct at76_rx_buffer *buf,
+ struct iw_quality* qual)
{
if ((dev->board_type == BOARDTYPE_503_INTERSIL_3861) ||
(dev->board_type == BOARDTYPE_503_INTERSIL_3863)) {
@@ -3160,15 +5367,18 @@ static void at76_calc_qual(struct at76_priv *dev, struct at76_rx_buffer *buf, st
qual->updated |= IW_QUAL_QUAL_UPDATED;
}
+
/* calc the noise quality from a given rx_buffer */
static void at76_calc_noise(struct at76_priv *dev, struct at76_rx_buffer *buf,
- struct iw_quality *qual)
+ struct iw_quality *qual)
{
qual->noise = 0;
qual->updated |= IW_QUAL_NOISE_INVALID;
}
-static void at76_update_wstats(struct at76_priv *dev, struct at76_rx_buffer *buf)
+
+static void at76_update_wstats(struct at76_priv *dev,
+ struct at76_rx_buffer *buf)
{
struct iw_quality *qual = &dev->wstats.qual;
@@ -3185,6 +5395,7 @@ static void at76_update_wstats(struct at76_priv *dev, struct at76_rx_buffer *buf
}
}
+
static void at76_rx_mgmt(struct at76_priv *dev, struct at76_rx_buffer *buf)
{
struct ieee80211_hdr_3addr *mgmt =
@@ -3244,6 +5455,7 @@ static void at76_rx_mgmt(struct at76_priv *dev, struct at76_rx_buffer *buf)
return;
}
+
static void at76_dbg_dumpbuf(const char *tag, const u8 *buf, int size)
{
int i;
@@ -3262,53 +5474,6 @@ static void at76_dbg_dumpbuf(const char *tag, const u8 *buf, int size)
pr_debug("\n");
}
-/* A short overview on Ethernet-II, 802.2, 802.3 and SNAP
- (taken from http://www.geocities.com/billalexander/ethernet.html):
-
-Ethernet Frame Formats:
-
-Ethernet (a.k.a. Ethernet II)
-
- +---------+---------+---------+----------
- | Dst | Src | Type | Data...
- +---------+---------+---------+----------
-
- <-- 6 --> <-- 6 --> <-- 2 --> <-46-1500->
-
- Type 0x80 0x00 = TCP/IP
- Type 0x06 0x00 = XNS
- Type 0x81 0x37 = Novell NetWare
-
-
-802.3
-
- +---------+---------+---------+----------
- | Dst | Src | Length | Data...
- +---------+---------+---------+----------
-
- <-- 6 --> <-- 6 --> <-- 2 --> <-46-1500->
-
-802.2 (802.3 with 802.2 header)
-
- +---------+---------+---------+-------+-------+-------+----------
- | Dst | Src | Length | DSAP | SSAP |Control| Data...
- +---------+---------+---------+-------+-------+-------+----------
-
- <- 1 -> <- 1 -> <- 1 -> <-43-1497->
-
-SNAP (802.3 with 802.2 and SNAP headers)
-
- +---------+---------+---------+-------+-------+-------+-----------+---------+-----------
- | Dst | Src | Length | 0xAA | 0xAA | 0x03 | Org Code | Type | Data...
- +---------+---------+---------+-------+-------+-------+-----------+---------+-----------
-
- <-- 3 --> <-- 2 --> <-38-1492->
-
-*/
-static const u8 snapsig[] = { 0xaa, 0xaa, 0x03 };
-/* RFC 1042 encapsulates Ethernet frames in 802.2 SNAP (0xaa, 0xaa, 0x03) with
- * a SNAP OID of 0 (0x00, 0x00, 0x00) */
-static const u8 rfc1042sig[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Convert the 802.11 header on a packet into an ethernet-style header
* (basically, pretend we're an ethernet card receiving ethernet packets)
@@ -3401,9 +5566,9 @@ static void at76_ieee80211_to_eth(struct sk_buff *skb, int iw_mode)
ntohs(skb->protocol), skb->len,
hex2str(dev->obuf, skb->data,
min((int)sizeof(dev->obuf)/3,64), ' '));
-
}
+
/* Adjust the skb to trim the hardware header and CRC, and set up skb->mac,
* skb->protocol, etc.
*/
@@ -3460,6 +5625,7 @@ static void at76_ieee80211_fixup(struct sk_buff *skb, int iw_mode)
}
}
+
/* check for fragmented data in dev->rx_skb. If the packet was no fragment
or it was the last of a fragment set a skb containing the whole packet
is returned for further processing. Otherwise we get NULL and are
@@ -3725,77 +5891,6 @@ static void at76_rx_data(struct at76_priv *dev)
return;
}
-static int at76_submit_rx_urb(struct at76_priv *dev)
-{
- int ret, size;
- struct sk_buff *skb = dev->rx_skb;
-
- if (dev->read_urb == NULL) {
- err("%s: dev->read_urb is NULL", __FUNCTION__);
- return -EFAULT;
- }
-
- if (skb == NULL) {
- skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
- if (skb == NULL) {
- err("%s: unable to allocate rx skbuff.", dev->netdev->name);
- ret = -ENOMEM;
- goto exit;
- }
- dev->rx_skb = skb;
- } else {
- skb_push(skb, skb_headroom(skb));
- skb_trim(skb, 0);
- }
-
- size = skb_tailroom(skb);
- usb_fill_bulk_urb(dev->read_urb, dev->udev,
- usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
- skb_put(skb, size), size,
- at76_read_bulk_callback, dev);
- ret = usb_submit_urb(dev->read_urb, GFP_ATOMIC);
- if (ret < 0) {
- if (ret == -ENODEV)
- at76_dbg(DBG_DEVSTART, "usb_submit_urb returned -ENODEV");
- else
- err("%s: rx, usb_submit_urb failed: %d", dev->netdev->name, ret);
- }
-
-exit:
- if (ret < 0) {
- if (ret != -ENODEV) {
- /* If we can't submit the URB, the adapter becomes completely
- * useless, so try again later */
- if (--dev->nr_submit_rx_tries > 0)
- schedule_work(&dev->work_submit_rx);
- else {
- err("%s: giving up to submit rx urb after %d failures -"
- " please unload the driver and/or power cycle the device",
- dev->netdev->name, NR_SUBMIT_RX_TRIES);
- }
- }
- } else
- /* reset counter to initial value */
- dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES;
- return ret;
-}
-
-/* we are doing a lot of things here in an interrupt. Need
- a bh handler (Watching TV with a TV card is probably
- a good test: if you see flickers, we are doing too much.
- Currently I do see flickers... even with our tasklet :-( )
- Maybe because the bttv driver and usb-uhci use the same interrupt
-*/
-/* Or maybe because our BH handler is preempting bttv's BH handler.. BHs don't
- * solve everything.. (alex) */
-static void at76_read_bulk_callback(struct urb *urb)
-{
- struct at76_priv *priv = urb->context;
-
- priv->rx_urb = urb;
- tasklet_schedule(&priv->tasklet);
- return;
-}
static void at76_rx_monitor_mode(struct at76_priv *dev)
{
@@ -3860,6 +5955,30 @@ static void at76_rx_monitor_mode(struct at76_priv *dev)
}
+/**
+ * at76_iwspy_update - check if we spy on the sender address of buf and update stats
+ */
+static void at76_iwspy_update(struct at76_priv *dev, struct at76_rx_buffer *buf)
+{
+ struct ieee80211_hdr_3addr *hdr =
+ (struct ieee80211_hdr_3addr *)buf->packet;
+ struct iw_quality qual;
+
+ /* We can only set the level here */
+ qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
+ qual.level = 0;
+ qual.noise = 0;
+ at76_calc_level(dev, buf, &qual);
+
+ spin_lock_bh(&(dev->spy_spinlock));
+
+ if (dev->spy_data.spy_number > 0) {
+ wireless_spy_update(dev->netdev, hdr->addr2, &qual);
+ }
+ spin_unlock_bh(&(dev->spy_spinlock));
+}
+
+
static void at76_rx_tasklet(unsigned long param)
{
struct at76_priv *dev = (struct at76_priv *)param;
@@ -3953,1884 +6072,6 @@ static void at76_rx_tasklet(unsigned long param)
return;
}
-static void at76_write_bulk_callback(struct urb *urb)
-{
- struct at76_priv *dev = urb->context;
- struct net_device_stats *stats = &dev->stats;
- unsigned long flags;
- struct at76_tx_buffer *mgmt_buf;
- int ret;
-
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
- at76_dbg(DBG_URB,
- "%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
- } else
- return; /* urb has been unlinked */
- stats->tx_errors++;
- } else
- stats->tx_packets++;
-
- spin_lock_irqsave(&dev->mgmt_spinlock, flags);
- mgmt_buf = dev->next_mgmt_bulk;
- dev->next_mgmt_bulk = NULL;
- spin_unlock_irqrestore(&dev->mgmt_spinlock, flags);
-
- if (mgmt_buf) {
- /* we don't copy the padding bytes, but add them
- to the length */
- memcpy(dev->bulk_out_buffer, mgmt_buf,
- le16_to_cpu(mgmt_buf->wlength) +
- offsetof(struct at76_tx_buffer, packet));
- usb_fill_bulk_urb(dev->write_urb, dev->udev,
- usb_sndbulkpipe(dev->udev,
- dev->bulk_out_endpointAddr),
- dev->bulk_out_buffer,
- le16_to_cpu(mgmt_buf->wlength) +
- mgmt_buf->padding + AT76_TX_HDRLEN,
- at76_write_bulk_callback,
- dev);
- ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC);
- if (ret) {
- err("%s: %s error in tx submit urb: %d",
- dev->netdev->name, __FUNCTION__, ret);
- }
- kfree(mgmt_buf);
- } else
- netif_wake_queue(dev->netdev);
-
-}
-
-static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- struct net_device_stats *stats = &dev->stats;
- int ret = 0;
- int wlen;
- int submit_len;
- struct at76_tx_buffer *tx_buffer = dev->bulk_out_buffer;
- struct ieee80211_hdr_3addr *i802_11_hdr =
- (struct ieee80211_hdr_3addr *)&(tx_buffer->packet);
- u8 *payload = tx_buffer->packet + sizeof(struct ieee80211_hdr_3addr);
-
- if (netif_queue_stopped(netdev)) {
- err("%s: %s called while netdev is stopped", netdev->name,
- __FUNCTION__);
- /* skip this packet */
- dev_kfree_skb(skb);
- return 0;
- }
-
- if (dev->write_urb->status == -EINPROGRESS) {
- err("%s: %s called while dev->write_urb is pending for tx",
- netdev->name, __FUNCTION__);
- /* skip this packet */
- dev_kfree_skb(skb);
- return 0;
- }
-
- if (skb->len < 2 * ETH_ALEN) {
- err("%s: %s: skb too short (%d)", dev->netdev->name,
- __FUNCTION__, skb->len);
- dev_kfree_skb(skb);
- return 0;
- }
-
- at76_ledtrig_tx_activity(); /* tell the ledtrigger we send a packet */
-
- /* we can get rid of memcpy, if we set netdev->hard_header_len
- to 8 + sizeof(struct ieee80211_hdr_3addr), because then we have
- enough space
- at76_dbg(DBG_TX, "skb->data - skb->head = %d", skb->data - skb->head); */
-
- if (ntohs(*(__be16 *) (skb->data + 2 * ETH_ALEN)) <= 1518) {
- /* this is a 802.3 packet */
- if (skb->data[2 * ETH_ALEN + 2] == rfc1042sig[0] &&
- skb->data[2 * ETH_ALEN + 2 + 1] == rfc1042sig[1]) {
- /* higher layer delivered SNAP header - keep it */
- memcpy(payload, skb->data + 2*ETH_ALEN+2, skb->len - 2*ETH_ALEN -2);
- wlen = sizeof(struct ieee80211_hdr_3addr) + skb->len - 2*ETH_ALEN -2;
- } else {
- err("%s: %s: no support for non-SNAP 802.2 packets "
- "(DSAP x%02x SSAP x%02x cntrl x%02x)",
- dev->netdev->name, __FUNCTION__,
- skb->data[2 * ETH_ALEN + 2],
- skb->data[2 * ETH_ALEN + 2 + 1],
- skb->data[2 * ETH_ALEN + 2 + 2]);
- dev_kfree_skb(skb);
- return 0;
- }
- } else {
- /* add RFC 1042 header in front */
- memcpy(payload, rfc1042sig, sizeof(rfc1042sig));
- memcpy(payload + sizeof(rfc1042sig),
- skb->data + 2*ETH_ALEN, skb->len - 2*ETH_ALEN);
- wlen = sizeof(struct ieee80211_hdr_3addr) + sizeof(rfc1042sig) +
- skb->len - 2*ETH_ALEN;
- }
-
- /* make wireless header */
- i802_11_hdr->frame_ctl =
- cpu_to_le16(IEEE80211_FTYPE_DATA |
- (dev->wep_enabled ? IEEE80211_FCTL_PROTECTED : 0) |
- (dev->iw_mode ==
- IW_MODE_INFRA ? IEEE80211_FCTL_TODS : 0));
-
- if (dev->iw_mode == IW_MODE_ADHOC) {
- memcpy(i802_11_hdr->addr1, skb->data, ETH_ALEN); /* destination */
- memcpy(i802_11_hdr->addr2, skb->data + ETH_ALEN, ETH_ALEN); /* source */
- memcpy(i802_11_hdr->addr3, dev->bssid, ETH_ALEN);
- } else if (dev->iw_mode == IW_MODE_INFRA) {
- memcpy(i802_11_hdr->addr1, dev->bssid, ETH_ALEN);
- memcpy(i802_11_hdr->addr2, skb->data + ETH_ALEN, ETH_ALEN); /* source */
- memcpy(i802_11_hdr->addr3, skb->data, ETH_ALEN); /* destination */
- }
-
- i802_11_hdr->duration_id = cpu_to_le16(0);
- i802_11_hdr->seq_ctl = cpu_to_le16(0);
-
- /* setup 'Atmel' header */
- tx_buffer->wlength = cpu_to_le16(wlen);
- tx_buffer->tx_rate = dev->txrate;
- /* for broadcast destination addresses, the firmware 0.100.x
- seems to choose the highest rate set with CMD_STARTUP in
- basic_rate_set replacing this value */
-
- memset(tx_buffer->reserved, 0, 4);
-
- tx_buffer->padding = at76_calc_padding(wlen);
- submit_len = wlen + AT76_TX_HDRLEN + tx_buffer->padding;
-
- {
- at76_dbg(DBG_TX_DATA_CONTENT, "%s skb->data %s", dev->netdev->name,
- hex2str(dev->obuf, skb->data,
- min((int)(sizeof(dev->obuf) - 1) / 2, 32), '\0'));
- at76_dbg(DBG_TX_DATA, "%s tx wlen x%x pad x%x rate %d hdr %s",
- dev->netdev->name,
- le16_to_cpu(tx_buffer->wlength),
- tx_buffer->padding, tx_buffer->tx_rate,
- hex2str(dev->obuf, i802_11_hdr,
- min((sizeof(dev->obuf) - 1) / 2,
- sizeof(struct ieee80211_hdr_3addr)), '\0'));
- at76_dbg(DBG_TX_DATA_CONTENT, "%s payload %s", dev->netdev->name,
- hex2str(dev->obuf, payload,
- min((int)(sizeof(dev->obuf) - 1) / 2, 48), '\0'));
- }
-
- /* send stuff */
- netif_stop_queue(netdev);
- netdev->trans_start = jiffies;
-
- usb_fill_bulk_urb(dev->write_urb, dev->udev,
- usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
- tx_buffer, submit_len,
- at76_write_bulk_callback, dev);
- ret = usb_submit_urb(dev->write_urb, GFP_ATOMIC);
- if (ret) {
- stats->tx_errors++;
- err("%s: error in tx submit urb: %d", netdev->name, ret);
- if (ret == -EINVAL)
- err("-EINVAL: urb %p urb->hcpriv %p urb->complete %p",
- dev->write_urb,
- dev->write_urb ? dev->write_urb->hcpriv : (void *)-1,
- dev->write_urb ? dev->write_urb->complete : (void *)-1);
- goto err;
- }
-
- stats->tx_bytes += skb->len;
-
- dev_kfree_skb(skb);
- return 0;
-
- err:
- return ret;
-}
-
-static void at76_tx_timeout(struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- if (!dev)
- return;
- warn("%s: tx timeout.", netdev->name);
-
- usb_unlink_urb(dev->write_urb);
- dev->stats.tx_errors++;
-}
-
-static int at76_startup_device(struct at76_priv *dev)
-{
- struct at76_card_config *ccfg = &dev->card_config;
- int ret;
-
- if (at76_debug & DBG_PARAMS) {
- char ossid[IW_ESSID_MAX_SIZE + 1];
-
- /* make dev->essid printable */
- at76_assert(dev->essid_size <= IW_ESSID_MAX_SIZE);
- memcpy(ossid, dev->essid, dev->essid_size);
- ossid[dev->essid_size] = '\0';
-
- dbg("%s param: ssid %s (%s) mode %s ch %d wep %s key %d keylen %d",
- dev->netdev->name, ossid,
- hex2str(dev->obuf, dev->essid,
- min((int)(sizeof(dev->obuf)-1)/2,
- IW_ESSID_MAX_SIZE), '\0'),
- dev->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
- dev->channel,
- dev->wep_enabled ? "enabled" : "disabled",
- dev->wep_key_id, dev->wep_keys_len[dev->wep_key_id]);
- dbg("%s param: preamble %s rts %d retry %d frag %d "
- "txrate %s auth_mode %d",
- dev->netdev->name,
- dev->preamble_type == PREAMBLE_TYPE_SHORT ? "short" : "long",
- dev->rts_threshold, dev->short_retry_limit,
- dev->frag_threshold,
- dev->txrate == TX_RATE_1MBIT ? "1MBit" :
- dev->txrate == TX_RATE_2MBIT ? "2MBit" :
- dev->txrate == TX_RATE_5_5MBIT ? "5.5MBit" :
- dev->txrate == TX_RATE_11MBIT ? "11MBit" :
- dev->txrate == TX_RATE_AUTO ? "auto" : "<invalid>",
- dev->auth_mode);
- dbg("%s param: pm_mode %d pm_period %d auth_mode %s "
- "scan_times %d %d scan_mode %s international_roaming %d",
- dev->netdev->name,
- dev->pm_mode, dev->pm_period,
- dev->auth_mode == WLAN_AUTH_OPEN ?
- "open" : "shared_secret",
- dev->scan_min_time, dev->scan_max_time,
- dev->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive",
- dev->international_roaming);
- }
-
- memset(ccfg, 0, sizeof(struct at76_card_config));
- ccfg->promiscuous_mode = 0;
- ccfg->short_retry_limit = dev->short_retry_limit;
-
- if (dev->wep_enabled) {
- if (dev->wep_keys_len[dev->wep_key_id] > WEP_SMALL_KEY_LEN)
- ccfg->encryption_type = 2;
- else
- ccfg->encryption_type = 1;
-
- /* jal: always exclude unencrypted if WEP is active */
- ccfg->exclude_unencrypted = 1;
- } else {
- ccfg->exclude_unencrypted = 0;
- ccfg->encryption_type = 0;
- }
-
- ccfg->rts_threshold = cpu_to_le16(dev->rts_threshold);
- ccfg->fragmentation_threshold = cpu_to_le16(dev->frag_threshold);
-
- memcpy(ccfg->basic_rate_set, hw_rates, 4);
- /* jal: really needed, we do a set_mib for autorate later ??? */
- ccfg->auto_rate_fallback = (dev->txrate == TX_RATE_AUTO ? 1 : 0);
- ccfg->channel = dev->channel;
- ccfg->privacy_invoked = dev->wep_enabled;
- memcpy(ccfg->current_ssid, dev->essid, IW_ESSID_MAX_SIZE);
- ccfg->ssid_len = dev->essid_size;
-
- ccfg->wep_default_key_id = dev->wep_key_id;
- memcpy(ccfg->wep_default_key_value, dev->wep_keys, 4 * WEP_KEY_LEN);
-
- ccfg->short_preamble = dev->preamble_type;
- ccfg->beacon_period = cpu_to_le16(dev->beacon_period);
-
- ret = at76_set_card_command(dev->udev, CMD_STARTUP, &dev->card_config,
- sizeof(struct at76_card_config));
- if (ret < 0) {
- err("%s: at76_set_card_command failed: %d", dev->netdev->name, ret);
- return ret;
- }
-
- at76_wait_completion(dev, CMD_STARTUP);
-
- /* remove BSSID from previous run */
- memset(dev->bssid, 0, ETH_ALEN);
-
- if (at76_set_radio(dev, 1) == 1)
- at76_wait_completion(dev, CMD_RADIO);
-
- if ((ret = at76_set_preamble(dev, dev->preamble_type)) < 0)
- return ret;
-
- if ((ret = at76_set_frag(dev, dev->frag_threshold)) < 0)
- return ret;
-
- if ((ret = at76_set_rts(dev, dev->rts_threshold)) < 0)
- return ret;
-
- if ((ret = at76_set_autorate_fallback(dev, dev->txrate == TX_RATE_AUTO ? 1 : 0)) < 0)
- return ret;
-
- if ((ret = at76_set_pm_mode(dev)) < 0)
- return ret;
-
- if ((ret = at76_set_iroaming(dev, dev->international_roaming)) < 0)
- return ret;
-
- if (at76_debug & DBG_MIB) {
- at76_dump_mib_mac(dev);
- at76_dump_mib_mac_addr(dev);
- at76_dump_mib_mac_mgmt(dev);
- at76_dump_mib_mac_wep(dev);
- at76_dump_mib_mdomain(dev);
- at76_dump_mib_phy(dev);
- at76_dump_mib_local(dev);
- }
-
- return 0;
-}
-
-static int at76_open(struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = 0;
-
- at76_dbg(DBG_PROC_ENTRY, "at76_open entry");
-
- if (down_interruptible(&dev->sem))
- return -EINTR;
-
- /* if netdev->dev_addr != dev->mac_addr we must
- set the mac address in the device ! */
- if (compare_ether_addr(netdev->dev_addr, dev->mac_addr)) {
- if (at76_add_mac_address(dev, netdev->dev_addr) >= 0)
- at76_dbg(DBG_PROGRESS, "%s: set new MAC addr %s",
- netdev->name, mac2str(netdev->dev_addr));
- }
-#ifdef DEBUG
- at76_dump_mib_mac_addr(dev);
-#endif
-
- dev->scan_state = SCAN_IDLE;
- dev->last_scan = jiffies;
- dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES; /* init counter */
-
- if ((ret = at76_submit_rx_urb(dev)) < 0) {
- err("%s: open: submit_rx_urb failed: %d", netdev->name, ret);
- goto err;
- }
-
- dev->open_count++;
-
- schedule_work(&dev->work_restart);
-
- at76_dbg(DBG_PROC_ENTRY, "at76_open end");
- err:
- up(&dev->sem);
- return ret < 0 ? ret : 0;
-}
-
-static int at76_stop(struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- unsigned long flags;
-
- at76_dbg(DBG_DEVSTART, "%s: ENTER", __FUNCTION__);
-
- if (down_interruptible(&dev->sem))
- return -EINTR;
-
- netif_stop_queue(netdev);
-
- dev->istate = INIT;
-
- if (!(dev->device_unplugged)) {
- /* we are called by "ifconfig ethX down", not because the
- device isn't avail. anymore */
- at76_set_radio(dev, 0);
-
- /* we unlink the read urb, because the _open()
- submits it again. _delete_device() takes care of the
- read_urb otherwise. */
- usb_kill_urb(dev->read_urb);
- }
-
- 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);
-
- /* free the bss_list */
- at76_free_bss_list(dev);
-
- at76_assert(dev->open_count > 0);
- dev->open_count--;
-
- up(&dev->sem);
- at76_dbg(DBG_DEVSTART, "%s: EXIT", __FUNCTION__);
-
- return 0;
-}
-
-static struct net_device_stats *at76_get_stats(struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- return &dev->stats;
-}
-
-static struct iw_statistics *at76_get_wireless_stats(struct net_device
- *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- at76_dbg(DBG_IOCTL, "RETURN qual %d level %d noise %d updated %d",
- dev->wstats.qual.qual, dev->wstats.qual.level,
- dev->wstats.qual.noise, dev->wstats.qual.updated);
-
- return &dev->wstats;
-}
-
-static void at76_set_multicast(struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int promisc;
-
- promisc = ((netdev->flags & IFF_PROMISC) != 0);
- if (promisc != dev->promisc) {
- /* grmbl. This gets called in interrupt. */
- dev->promisc = promisc;
- schedule_work(&dev->work_set_promisc);
- }
-}
-
-/* we only store the new mac address in netdev struct,
- it gets set when the netdev is opened. */
-static int at76_set_mac_address(struct net_device *netdev, void *addr)
-{
- struct sockaddr *mac = addr;
- memcpy(netdev->dev_addr, mac->sa_data, ETH_ALEN);
- return 1;
-}
-
-/**
- * at76_iwspy_update - check if we spy on the sender address of buf and update stats
- */
-static void at76_iwspy_update(struct at76_priv *dev, struct at76_rx_buffer *buf)
-{
- struct ieee80211_hdr_3addr *hdr =
- (struct ieee80211_hdr_3addr *)buf->packet;
- struct iw_quality qual;
-
- /* We can only set the level here */
- qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
- qual.level = 0;
- qual.noise = 0;
- at76_calc_level(dev, buf, &qual);
-
- spin_lock_bh(&(dev->spy_spinlock));
-
- if (dev->spy_data.spy_number > 0) {
- wireless_spy_update(dev->netdev, hdr->addr2, &qual);
- }
- spin_unlock_bh(&(dev->spy_spinlock));
-}
-
-
-/*******************************************************************************
- * structure that describes the private ioctls/iw handlers of this driver
- */
-static const struct iw_priv_args at76_priv_args[] = {
- {AT76_SET_SHORT_PREAMBLE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
- "short_preamble"}, /* 0 - long, 1 -short */
-
- {AT76_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 */
-
- {AT76_SET_POWERSAVE_MODE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
- "powersave_mode"}, /* 1 - active, 2 - power save,
- 3 - smart power save */
- {AT76_SET_SCAN_TIMES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0,
- "scan_times"}, /* min_channel_time,
- max_channel_time */
- {AT76_SET_SCAN_MODE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
- "scan_mode"}, /* 0 - active, 1 - passive scan */
-
- {AT76_SET_INTL_ROAMING,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
- "intl_roaming"},
-};
-
-/*******************************************************************************
- * at76_priv implementations of iw_handler functions:
- */
-static int at76_iw_handler_commit(struct net_device *netdev,
- struct iw_request_info *info,
- void *null, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- unsigned long flags;
- at76_dbg(DBG_IOCTL, "%s %s: restarting the device", netdev->name,
- __FUNCTION__);
-
- /* TODO: stop any pending tx bulk urb */
- 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);
- }
-
- /* 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;
-}
-
-static int at76_iw_handler_get_name(struct net_device *netdev,
- struct iw_request_info *info,
- char *name, char *extra)
-{
- strcpy(name, "IEEE 802.11b");
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWNAME - name %s", netdev->name, name);
- return 0;
-}
-
-static int at76_iw_handler_set_freq(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int chan = -1;
- int ret = -EIWCOMMIT;
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - freq.m %d freq.e %d", netdev->name,
- freq->m, freq->e);
-
- 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->international_roaming) {
- if (!(dev->domain->channel_map & (1 << (chan - 1)))) {
- info("%s: channel %d not allowed for domain %s "
- "(and international_roaming is OFF)",
- dev->netdev->name, chan, dev->domain->name);
- ret = -EINVAL;
- }
- }
-
- if (ret == -EIWCOMMIT) {
- dev->channel = chan;
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - ch %d", netdev->name, chan);
- }
-
- return ret;
-}
-
-static int at76_iw_handler_get_freq(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- freq->m = dev->channel;
- freq->e = 0;
-
- if (dev->channel) {
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - freq %ld x 10e%d",
- netdev->name, channel_frequency[dev->channel - 1], 6);
- }
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - ch %d", netdev->name, dev->channel);
-
- return 0;
-}
-
-static int at76_iw_handler_set_mode(struct net_device *netdev,
- struct iw_request_info *info,
- __u32 * mode, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode);
-
- if ((*mode != IW_MODE_ADHOC) && (*mode != IW_MODE_INFRA) &&
- (*mode != IW_MODE_MONITOR)) {
- ret = -EINVAL;
- } else {
- dev->iw_mode = *mode;
- if( dev->iw_mode != IW_MODE_INFRA)
- dev->pm_mode = AT76_PM_OFF;
- }
- return ret;
-}
-
-static int at76_iw_handler_get_mode(struct net_device *netdev,
- struct iw_request_info *info,
- __u32 * mode, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- *mode = dev->iw_mode;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWMODE - %d", netdev->name, *mode);
-
- return 0;
-}
-
-static int at76_iw_handler_get_range(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- /* inspired by atmel.c */
- struct at76_priv *dev = netdev_priv(netdev);
- 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 = 100;
- range->max_qual.level = 100;
- range->max_qual.noise = 0;
- range->max_qual.updated = IW_QUAL_NOISE_INVALID;
-
- range->avg_qual.qual = 50;
- range->avg_qual.level = 50;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = IW_QUAL_NOISE_INVALID;
-
- 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->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_ON;
- range->pm_capa = IW_POWER_PERIOD | IW_POWER_ALL_R;
-
- 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 = WEP_KEYS;
-
- /* 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;
-
- range->we_version_source = WIRELESS_EXT;
- 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 = 255;
-
-
- range->num_channels = NUM_CHANNELS;
- range->num_frequency = 0;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- /* test if channel map bit is raised */
- if (dev->domain->channel_map & (0x1 << i)) {
- range->num_frequency += 1;
-
- range->freq[i].i = i + 1;
- range->freq[i].m = channel_frequency[i] * 100000;
- range->freq[i].e = 1; /* channel frequency*100000 * 10^1 */
- }
- }
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWRANGE", netdev->name);
-
- return 0;
-}
-
-static int at76_iw_handler_set_spy(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = 0;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWSPY - number of addresses %d",
- netdev->name, data->length);
-
- spin_lock_bh(&(dev->spy_spinlock));
- ret = iw_handler_set_spy(dev->netdev, info, (union iwreq_data *)data,
- extra);
- spin_unlock_bh(&(dev->spy_spinlock));
-
- return ret;
-}
-
-static int at76_iw_handler_get_spy(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
-
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = 0;
-
- spin_lock_bh(&(dev->spy_spinlock));
- ret = iw_handler_get_spy(dev->netdev, info,
- (union iwreq_data *)data, extra);
- spin_unlock_bh(&(dev->spy_spinlock));
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWSPY - number of addresses %d",
- netdev->name, data->length);
-
- return ret;
-}
-
-static int at76_iw_handler_set_thrspy(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret;
-
- at76_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;
-}
-
-static int at76_iw_handler_get_thrspy(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- 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));
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWTHRSPY - number of addresses %d)",
- netdev->name, data->length);
-
- return ret;
-}
-
-static int at76_iw_handler_set_wap(struct net_device *netdev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWAP - wap/bssid %s", netdev->name,
- mac2str(ap_addr->sa_data));
-
- /* if the incoming address == ff:ff:ff:ff:ff:ff, the user has
- chosen any or auto AP preference */
- if (is_broadcast_ether_addr(ap_addr->sa_data)
- || is_zero_ether_addr(ap_addr->sa_data)) {
- dev->wanted_bssid_valid = 0;
- } else {
- /* user wants to set a preferred AP address */
- dev->wanted_bssid_valid = 1;
- memcpy(dev->wanted_bssid, ap_addr->sa_data, ETH_ALEN);
- }
-
- return -EIWCOMMIT;
-}
-
-static int at76_iw_handler_get_wap(struct net_device *netdev,
- struct iw_request_info *info,
- struct sockaddr *ap_addr, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(ap_addr->sa_data, dev->bssid, ETH_ALEN);
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWAP - wap/bssid %s", netdev->name,
- mac2str(ap_addr->sa_data));
-
- return 0;
-}
-
-static int at76_iw_handler_set_scan(struct net_device *netdev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- unsigned long flags;
- int ret = 0;
- struct iw_scan_req *req = NULL;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name);
-
- if (!netif_running(netdev))
- return -ENETDOWN;
-
- /* jal: we don't allow "iwlist ethX scan" while we are
- in monitor mode */
- if (dev->iw_mode == IW_MODE_MONITOR)
- return -EBUSY;
-
- /* Discard old scan results */
- if ((jiffies - dev->last_scan) > (20 * HZ))
- dev->scan_state = SCAN_IDLE;
- dev->last_scan = jiffies;
-
- /* Initiate a scan command */
- if (dev->scan_state == SCAN_IN_PROGRESS)
- return -EBUSY;
-
- dev->scan_state = SCAN_IN_PROGRESS;
-
- /* 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);
- }
- /* Try to do passive or active scan if WE asks as. */
- if (wrqu->data.length
- && wrqu->data.length == sizeof(struct iw_scan_req)) {
- req = (struct iw_scan_req *)extra;
-
- if (req->scan_type == IW_SCAN_TYPE_PASSIVE)
- dev->scan_mode = SCAN_TYPE_PASSIVE;
- else if (req->scan_type == IW_SCAN_TYPE_ACTIVE)
- dev->scan_mode = SCAN_TYPE_ACTIVE;
-
- /* Sanity check values? */
- if (req->min_channel_time > 0) {
- if (dev->istate == MONITORING)
- dev->monitor_scan_min_time =
- req->min_channel_time;
- else
- dev->scan_min_time = req->min_channel_time;
- }
- if (req->max_channel_time > 0) {
- if (dev->istate == MONITORING)
- dev->monitor_scan_max_time =
- req->max_channel_time;
- else
- dev->scan_max_time = req->max_channel_time;
- }
- }
-
- /* change to scanning state */
- dev->istate = SCANNING;
- schedule_work(&dev->work_scan);
-
- return ret;
-}
-
-static int at76_iw_handler_get_scan(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- unsigned long flags;
- struct list_head *lptr, *nptr;
- struct bss_info *curr_bss;
- struct iw_event *iwe = kmalloc(sizeof(struct iw_event), GFP_KERNEL);
- char *curr_val, *curr_pos = extra;
- int i;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWSCAN", netdev->name);
-
- if (!iwe)
- return -ENOMEM;
-
- if (dev->scan_state != SCAN_COMPLETED)
- /* scan not yet finished */
- return -EAGAIN;
-
- 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;
- iwe->u.data.flags = 1;
-
- 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 & WLAN_CAPABILITY_IBSS) ?
- IW_MODE_ADHOC :
- (curr_bss->capa & WLAN_CAPABILITY_ESS) ?
- IW_MODE_MASTER : 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 & WLAN_CAPABILITY_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.noise = 0;
- iwe->u.qual.updated =
- IW_QUAL_NOISE_INVALID | IW_QUAL_LEVEL_UPDATED;
- iwe->u.qual.level = (curr_bss->rssi * 100 / 42);
- if (iwe->u.qual.level > 100)
- iwe->u.qual.level = 100;
- if ((dev->board_type == BOARDTYPE_503_INTERSIL_3861) ||
- (dev->board_type == BOARDTYPE_503_INTERSIL_3863)) {
- iwe->u.qual.qual = curr_bss->link_qual;
- } else {
- iwe->u.qual.qual = 0;
- iwe->u.qual.updated |= IW_QUAL_QUAL_INVALID;
- }
- /* 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);
- }
-
- /* Check if we added any event */
- if ((curr_val - curr_pos) > IW_EV_LCP_LEN)
- curr_pos = curr_val;
-
- /* more information may be sent back using IWECUSTOM */
-
- }
-
- spin_unlock_irqrestore(&(dev->bss_list_spinlock), flags);
-
- data->length = (curr_pos - extra);
- data->flags = 0;
-
- kfree(iwe);
- return 0;
-}
-
-static int at76_iw_handler_set_essid(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWESSID - %s", netdev->name, extra);
-
- if (data->flags) {
- memcpy(dev->essid, extra, data->length);
- dev->essid_size = data->length;
- } else {
- /* Use any SSID */
- dev->essid_size = 0;
- }
-
- return -EIWCOMMIT;
-}
-
-static int at76_iw_handler_get_essid(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- 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;
- }
- }
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWESSID - %s", netdev->name, extra);
-
- return 0;
-}
-
-static int at76_iw_handler_set_rate(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *bitrate, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = -EIWCOMMIT;
-
- at76_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;
-}
-
-static int at76_iw_handler_get_rate(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *bitrate, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- 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;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWRATE - %d", netdev->name,
- bitrate->value);
-
- return ret;
-}
-
-static int at76_iw_handler_set_rts(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = -EIWCOMMIT;
- int rthr = rts->value;
-
- at76_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;
-}
-
-static int at76_iw_handler_get_rts(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *rts, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- rts->value = dev->rts_threshold;
- rts->disabled = (rts->value >= MAX_RTS_THRESHOLD);
- rts->fixed = 1;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWRTS - value %d disabled %s",
- netdev->name, rts->value, (rts->disabled) ? "true" : "false");
-
- return 0;
-}
-
-static int at76_iw_handler_set_frag(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = -EIWCOMMIT;
- int fthr = frag->value;
-
- at76_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;
-}
-
-static int at76_iw_handler_get_frag(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *frag, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- frag->value = dev->frag_threshold;
- frag->disabled = (frag->value >= MAX_FRAG_THRESHOLD);
- frag->fixed = 1;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWFRAG - value %d, disabled %s",
- netdev->name, frag->value, (frag->disabled) ? "true" : "false");
-
- return 0;
-}
-
-static int at76_iw_handler_get_txpow(struct net_device *netdev,
- struct 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;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWTXPOW - txpow %d dBm", netdev->name,
- power->value);
-
- return 0;
-}
-
-/* jal: short retry is handled by the firmware (at least 0.90.x),
- while long retry is not (?) */
-static int at76_iw_handler_set_retry(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWRETRY disabled %d flags x%x val %d",
- netdev->name, retry->disabled, retry->flags, retry->value);
-
- if (!retry->disabled && (retry->flags & IW_RETRY_LIMIT)) {
- if ((retry->flags & IW_RETRY_MIN) ||
- !(retry->flags & IW_RETRY_MAX)) {
- dev->short_retry_limit = retry->value;
- } else
- ret = -EINVAL;
- } else {
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/* adapted (ripped) from atmel.c */
-static int at76_iw_handler_get_retry(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *retry, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWRETRY", netdev->name);
-
- retry->disabled = 0; /* Can't be disabled */
-
-
- retry->flags = IW_RETRY_LIMIT;
- retry->value = dev->short_retry_limit;
-
- return 0;
-}
-
-static int at76_iw_handler_set_encode(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *encoding,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
- int len = encoding->length;
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - enc.flags %08x "
- "pointer %p len %d", netdev->name, encoding->flags,
- encoding->pointer, encoding->length);
- at76_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 == WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
-
- /* take the old default key if index is invalid */
- if ((index < 0) || (index >= 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_LEN);
- 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 = WLAN_AUTH_SHARED_KEY;
- if (encoding->flags & IW_ENCODE_OPEN)
- dev->auth_mode = WLAN_AUTH_OPEN;
-
- at76_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 == WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
-
- return -EIWCOMMIT;
-}
-
-static int at76_iw_handler_get_encode(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_point *encoding,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
-
- if ((index < 0) || (index >= WEP_KEYS))
- index = dev->wep_key_id;
-
- encoding->flags =
- (dev->auth_mode == WLAN_AUTH_SHARED_KEY) ?
- 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);
- }
-
- at76_dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - enc.flags %08x "
- "pointer %p len %d", netdev->name, encoding->flags,
- encoding->pointer, encoding->length);
- at76_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 == WLAN_AUTH_SHARED_KEY) ?
- "restricted" : "open");
-
- return 0;
-}
-
-static int at76_iw_handler_set_power(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *prq, char *extra)
-{
- int err = -EIWCOMMIT;
- struct at76_priv *dev = netdev_priv(netdev);
-
- at76_dbg(DBG_IOCTL, "%s: SIOCSIWPOWER - disabled %s flags x%x value x%x",
- netdev->name, (prq->disabled) ? "true" : "false",
- prq->flags, prq->value);
-
- if (prq->disabled) {
- dev->pm_mode = AT76_PM_OFF;
- } else {
- switch (prq->flags & IW_POWER_MODE) {
- case IW_POWER_ALL_R:
- case IW_POWER_ON:
- break;
- default:
- err = -EINVAL;
- goto out;
- }
- if (prq->flags & IW_POWER_PERIOD) {
- dev->pm_period = prq->value;
- }
- if (prq->flags & IW_POWER_TIMEOUT) {
- err = -EINVAL;
- goto out;
- }
- dev->pm_mode = AT76_PM_ON;
- }
-out:
- return err;
-}
-
-static int at76_iw_handler_get_power(struct net_device *netdev,
- struct iw_request_info *info,
- struct iw_param *power, char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- if ((power->disabled = (dev->pm_mode == AT76_PM_OFF)))
- return 0;
- else {
- power->flags = IW_POWER_PERIOD;
- power->value = dev->pm_period;
- }
- power->flags |= IW_POWER_ALL_R;
-
- at76_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;
-}
-
-
-/*******************************************************************************
- * Private IOCTLS
- */
-static int at76_iw_set_short_preamble(struct net_device *netdev,
- struct iw_request_info *info, char *name,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int val = *((int *)name);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: AT76_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;
-}
-
-static int at76_iw_set_debug(struct net_device *netdev,
- struct 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;
- }
-
- dbg("%s: AT76_SET_DEBUG input %d: %s -> x%x",
- netdev->name, data->length, extra, val);
- } else {
- val = DBG_DEFAULTS;
- }
-
- dbg("%s: AT76_SET_DEBUG, old 0x%x new 0x%x",
- netdev->name, at76_debug, val);
-
- /* jal: some more output to pin down lockups */
- dbg("%s: netif running %d queue_stopped %d carrier_ok %d",
- netdev->name,
- netif_running(netdev),
- netif_queue_stopped(netdev), netif_carrier_ok(netdev));
-
- at76_debug = val;
-
- return 0;
-}
-
-static int at76_iw_set_powersave_mode(struct net_device *netdev,
- struct iw_request_info *info, char *name,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int val = *((int *)name);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: AT76_SET_POWERSAVE_MODE, %d (%s)",
- netdev->name, val,
- val == AT76_PM_OFF ? "active" : val == AT76_PM_ON ? "save" :
- val == AT76_PM_SMART ? "smart save" : "<invalid>");
- if (val < AT76_PM_OFF || val > AT76_PM_SMART) {
- ret = -EINVAL;
- } else {
- dev->pm_mode = val;
- }
-
- return ret;
-}
-
-static int at76_iw_set_scan_times(struct net_device *netdev,
- struct iw_request_info *info, char *name,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int mint = *((int *)name);
- int maxt = *((int *)name + 1);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: AT76_SET_SCAN_TIMES - min %d max %d",
- netdev->name, mint, maxt);
- if (mint <= 0 || maxt <= 0 || mint > maxt) {
- ret = -EINVAL;
- } else {
- if (dev->istate == MONITORING) {
- dev->monitor_scan_min_time = mint;
- dev->monitor_scan_max_time = maxt;
- ret = 0;
- } else {
- dev->scan_min_time = mint;
- dev->scan_max_time = maxt;
- }
- }
-
- return ret;
-}
-
-static int at76_iw_set_scan_mode(struct net_device *netdev,
- struct iw_request_info *info, char *name,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int val = *((int *)name);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: AT76_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;
-}
-
-static int at76_set_iroaming(struct at76_priv *dev, int onoff)
-{
- int ret = 0;
-
- memset(&dev->mib_buf, 0, sizeof(struct set_mib_buffer));
- dev->mib_buf.type = MIB_MAC_MGMT;
- dev->mib_buf.size = 1;
- dev->mib_buf.index = IROAMING_OFFSET;
- dev->mib_buf.data[0] = (dev->international_roaming ? 1 : 0);
- ret = at76_set_mib(dev, &dev->mib_buf);
- if (ret < 0) {
- err("%s: set_mib (intl_roaming_enable) failed: %d", dev->netdev->name, ret);
- }
-
- return ret;
-}
-
-static int at76_iw_set_intl_roaming(struct net_device *netdev,
- struct iw_request_info *info, char *name,
- char *extra)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- int val = *((int *)name);
- int ret = -EIWCOMMIT;
-
- at76_dbg(DBG_IOCTL, "%s: AT76_SET_INTL_ROAMING - mode %s",
- netdev->name, (val == IR_OFF) ? "off" :
- (val == IR_ON) ? "on" : "<invalid>");
-
- if (val != IR_OFF && val != IR_ON) {
- ret = -EINVAL;
- } else {
- if (dev->international_roaming != val) {
- dev->international_roaming = val;
- at76_set_iroaming(dev, val);
- }
- }
-
- return ret;
-}
-
-/**
- * set_monitor_mode - sets dev->netdev->type
- */
-static void at76_set_monitor_mode(struct at76_priv *dev)
-{
- if (dev->iw_mode == IW_MODE_MONITOR) {
- at76_dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE ON",
- dev->netdev->name);
- dev->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
- } else {
- at76_dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE OFF",
- dev->netdev->name);
- dev->netdev->type = ARPHRD_ETHER;
- }
-}
-
-
-/*******************************************************************************
- * structure that advertises the iw handlers of this driver
- */
-static const iw_handler at76_handlers[] =
-{
- [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) at76_iw_handler_commit,
- [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_name,
- [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_freq,
- [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_freq,
- [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_mode,
- [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_mode,
- [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_range,
- [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_spy,
- [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_spy,
- [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_thrspy,
- [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_thrspy,
- [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_wap,
- [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_wap,
- [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_scan,
- [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_scan,
- [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_essid,
- [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_essid,
- [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_rate,
- [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_rate,
- [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_rts,
- [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_rts,
- [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_frag,
- [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_frag,
- [SIOCGIWTXPOW -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_txpow,
- [SIOCSIWRETRY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_retry,
- [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_retry,
- [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_encode,
- [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_encode,
- [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) at76_iw_handler_set_power,
- [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) at76_iw_handler_get_power,
-};
-
-#define AT76_SET_PRIV(h, f) [h - SIOCIWFIRSTPRIV] = (iw_handler) f
-
-/*structure that advertises the private iw handlers of this driver */
-static const iw_handler at76_priv_handlers[] = {
- AT76_SET_PRIV(AT76_SET_SHORT_PREAMBLE, at76_iw_set_short_preamble),
- AT76_SET_PRIV(AT76_SET_DEBUG, at76_iw_set_debug),
- AT76_SET_PRIV(AT76_SET_POWERSAVE_MODE, at76_iw_set_powersave_mode),
- AT76_SET_PRIV(AT76_SET_SCAN_TIMES, at76_iw_set_scan_times),
- AT76_SET_PRIV(AT76_SET_SCAN_MODE, at76_iw_set_scan_mode),
- AT76_SET_PRIV(AT76_SET_INTL_ROAMING, at76_iw_set_intl_roaming),
-};
-
-static const struct iw_handler_def at76_handler_def =
-{
- .num_standard = ARRAY_SIZE(at76_handlers),
- .num_private = ARRAY_SIZE(at76_priv_handlers),
- .num_private_args = ARRAY_SIZE(at76_priv_args),
- .standard = at76_handlers,
- .private = at76_priv_handlers,
- .private_args = at76_priv_args,
- .get_wireless_stats = at76_get_wireless_stats,
-};
-
-
-static void at76_ethtool_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *info)
-{
- struct at76_priv *dev = netdev_priv(netdev);
-
- strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
-
- strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
- info->version[sizeof(info->version) - 1] = '\0';
-
- snprintf(info->bus_info, sizeof(info->bus_info) - 1, "usb%d:%d",
- dev->udev->bus->busnum, dev->udev->devnum);
-
- snprintf(info->fw_version, sizeof(info->fw_version) - 1,
- "%d.%d.%d-%d",
- dev->fw_version.major, dev->fw_version.minor,
- dev->fw_version.patch, dev->fw_version.build);
-}
-
-static u32 at76_ethtool_get_link(struct net_device *netdev)
-{
- struct at76_priv *dev = netdev_priv(netdev);
- return dev->istate == CONNECTED;
-}
-
-static struct ethtool_ops at76_ethtool_ops = {
- .get_drvinfo = at76_ethtool_get_drvinfo,
- .get_link = at76_ethtool_get_link,
-};
-
-static void at76_delete_device(struct at76_priv *dev)
-{
- int i;
-
- if (!dev)
- return;
-
- /* signal to _stop() that the device is gone */
- dev->device_unplugged = 1;
-
- at76_dbg(DBG_PROC_ENTRY, "%s: ENTER",__FUNCTION__);
-
- if (dev->netdev_registered) {
- unregister_netdev(dev->netdev);
- }
-
- usb_put_dev(dev->udev);
-
- /* assuming we used keventd, it must quiesce too */
- flush_scheduled_work();
-
- if (dev->bulk_out_buffer != NULL)
- kfree(dev->bulk_out_buffer);
-
- kfree(dev->ctrl_buffer);
-
- if (dev->write_urb != NULL) {
- usb_kill_urb(dev->write_urb);
- usb_free_urb(dev->write_urb);
- }
- if (dev->read_urb != NULL) {
- usb_kill_urb(dev->read_urb);
- usb_free_urb(dev->read_urb);
- }
- if (dev->ctrl_buffer != NULL) {
- usb_kill_urb(dev->ctrl_urb);
- usb_free_urb(dev->ctrl_urb);
- }
-
- at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __FUNCTION__);
-
- if (dev->rx_skb != NULL)
- kfree_skb(dev->rx_skb);
-
- at76_free_bss_list(dev);
- del_timer_sync(&dev->bss_list_timer);
-
- if (dev->istate == CONNECTED) {
- at76_iwevent_bss_disconnect(dev->netdev);
- }
-
- for (i = 0; i < NR_RX_DATA_BUF; i++)
- if (dev->rx_data[i].skb != NULL) {
- dev_kfree_skb(dev->rx_data[i].skb);
- dev->rx_data[i].skb = NULL;
- }
- at76_dbg(DBG_PROC_ENTRY, "%s: before freeing dev/netdev", __FUNCTION__);
- free_netdev(dev->netdev); /* dev is in netdev */
-
- at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __FUNCTION__);
-}
-
-static int at76_alloc_urbs(struct at76_priv *dev)
-{
- struct usb_interface *interface = dev->interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev = dev->udev;
- int i, buffer_size;
- struct usb_host_interface *iface_desc;
-
- at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __FUNCTION__);
-
- at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __FUNCTION__,
- interface->altsetting[0].desc.bNumEndpoints);
-
- iface_desc = interface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
- endpoint = &iface_desc->endpoint[i].desc;
-
- at76_dbg(DBG_URB, "%s: %d. endpoint: addr x%x attr x%x",
- __FUNCTION__,
- i, endpoint->bEndpointAddress, endpoint->bmAttributes);
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
-
- dev->read_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->read_urb) {
- err("No free urbs available");
- return -ENOMEM;
- }
- dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dev->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->write_urb) {
- err("no free urbs available");
- return -ENOMEM;
- }
- buffer_size = sizeof(struct at76_tx_buffer) +
- MAX_PADDING_SIZE;
- dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
- dev->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!dev->bulk_out_buffer) {
- err("couldn't allocate bulk_out_buffer");
- return -ENOMEM;
- }
- usb_fill_bulk_urb(dev->write_urb, udev,
- usb_sndbulkpipe(udev,
- endpoint->bEndpointAddress),
- dev->bulk_out_buffer, buffer_size,
- at76_write_bulk_callback, dev);
- }
- }
-
- dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->ctrl_urb) {
- err("no free urbs available");
- return -ENOMEM;
- }
- dev->ctrl_buffer = kmalloc(1024, GFP_KERNEL);
- if (!dev->ctrl_buffer) {
- err("couldn't allocate ctrl_buffer");
- return -ENOMEM;
- }
-
- at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __FUNCTION__);
-
- return 0;
-}
static struct at76_priv *at76_alloc_new_device(struct usb_device *udev,
int board_type)
@@ -5912,122 +6153,6 @@ static struct at76_priv *at76_alloc_new_device(struct usb_device *udev,
}
-/**
- * at76_init_new_device - continue device initialization after firmware download
- *
- * FIXME: We may have to move the register_netdev into at76_alloc_new_device,
- * because hotplug may try to configure the netdev _before_ (or parallel to)
- * the download of firmware
- */
-static int at76_init_new_device(struct at76_priv *dev)
-{
- struct net_device *netdev = dev->netdev;
- int ret;
-
- /* set up the endpoint information */
- /* check out the endpoints */
-
- dev->interface = dev->udev->actconfig->interface[0];
-
- at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints",
- dev->interface->cur_altsetting->desc.bNumEndpoints);
-
- if ((ret = at76_alloc_urbs(dev)) < 0)
- goto error;
-
- /* get firmware version */
- ret = at76_get_mib(dev->udev, MIB_FW_VERSION, &dev->fw_version,
- sizeof(dev->fw_version));
- if ((ret < 0) || ((dev->fw_version.major == 0) &&
- (dev->fw_version.minor == 0) &&
- (dev->fw_version.patch == 0) &&
- (dev->fw_version.build == 0))) {
- err("getting firmware failed with %d, or version is 0", ret);
- err("this probably means that the ext. fw was not loaded correctly");
- if(ret >= 0)
- ret = -ENODEV;
- goto error;
- }
-
- /* fw 0.84 doesn't send FCS with rx data */
- if (dev->fw_version.major == 0 && dev->fw_version.minor <= 84)
- dev->rx_data_fcs_len = 0;
- else
- dev->rx_data_fcs_len = 4;
-
- 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,
- dev->rx_data_fcs_len);
-
- /* MAC address */
- ret = at76_get_hw_config(dev);
- if (ret < 0) {
- err("could not get MAC address");
- goto error;
- }
-
- dev->domain = at76_get_reg_domain(dev->regulatory_domain);
- /* init. netdev->dev_addr */
- memcpy(netdev->dev_addr, dev->mac_addr, ETH_ALEN);
- info("device's MAC %s, regulatory domain %s (id %d)",
- mac2str(dev->mac_addr), dev->domain->name, dev->regulatory_domain);
-
- /* initializing */
- dev->international_roaming = international_roaming;
- dev->channel = DEF_CHANNEL;
- dev->iw_mode = default_iw_mode;
- memset(dev->essid, 0, IW_ESSID_MAX_SIZE);
- dev->rts_threshold = DEF_RTS_THRESHOLD;
- dev->frag_threshold = DEF_FRAG_THRESHOLD;
- dev->short_retry_limit = DEF_SHORT_RETRY_LIMIT;
- dev->txrate = TX_RATE_AUTO;
- dev->preamble_type = preamble_type;
- dev->beacon_period = 100;
- dev->beacons_last_qual = jiffies_to_msecs(jiffies);
- dev->auth_mode = auth_mode ? WLAN_AUTH_SHARED_KEY : WLAN_AUTH_OPEN;
- dev->scan_min_time = scan_min_time;
- dev->scan_max_time = scan_max_time;
- dev->scan_mode = scan_mode;
- dev->monitor_scan_min_time = monitor_scan_min_time;
- dev->monitor_scan_max_time = monitor_scan_max_time;
-
- netdev->flags &= ~IFF_MULTICAST; /* not yet or never */
- netdev->open = at76_open;
- netdev->stop = at76_stop;
- netdev->get_stats = at76_get_stats;
- netdev->ethtool_ops = &at76_ethtool_ops;
-
- /* Add pointers to enable iwspy support. */
- dev->wireless_data.spy_data = &dev->spy_data;
- netdev->wireless_data = &dev->wireless_data;
-
- netdev->hard_start_xmit = at76_tx;
- netdev->tx_timeout = at76_tx_timeout;
- netdev->watchdog_timeo = 2 * HZ;
- netdev->wireless_handlers = &at76_handler_def;
- netdev->set_multicast_list = at76_set_multicast;
- netdev->set_mac_address = at76_set_mac_address;
-
- ret = register_netdev(dev->netdev);
- if (ret) {
- err("unable to register netdevice %s (status %d)!",
- dev->netdev->name, ret);
- goto error;
- }
- info("registered %s", dev->netdev->name);
- dev->netdev_registered = 1;
-
- /* we let this timer run the whole time this driver instance lives */
- mod_timer(&dev->bss_list_timer, jiffies + BSS_LIST_TIMEOUT);
-
- return 0;
- error:
- at76_delete_device(dev);
- return ret;
-}
-
-
/* Parse the firmware image */
static int at76_parse_fw(struct at76_priv *dev, u8 *fw_data, int fw_size,
int board_type)
@@ -6069,6 +6194,7 @@ static int at76_parse_fw(struct at76_priv *dev, u8 *fw_data, int fw_size,
return 0;
}
+
static int at76_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -6179,6 +6305,7 @@ static int at76_probe(struct usb_interface *interface,
return ret;
}
+
static void at76_disconnect(struct usb_interface *interface)
{
struct at76_priv *priv;
@@ -6191,6 +6318,7 @@ static void at76_disconnect(struct usb_interface *interface)
info(DRIVER_NAME " disconnected");
}
+
/* structure for registering this driver with the USB subsystem */
static struct usb_driver at76_driver = {
.name = DRIVER_NAME,
@@ -6199,6 +6327,7 @@ static struct usb_driver at76_driver = {
.id_table = dev_table,
};
+
static int __init at76_mod_init(void)
{
int result;
@@ -6215,6 +6344,7 @@ static int __init at76_mod_init(void)
return result;
}
+
static void __exit at76_mod_exit(void)
{
int i;
@@ -6228,6 +6358,7 @@ static void __exit at76_mod_exit(void)
led_trigger_unregister_simple(ledtrig_tx);
}
+
module_param_named(debug, at76_debug, int, 0600);
MODULE_PARM_DESC(debug, "Debugging level");
module_param(rx_copybreak, int, 0400);