aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjal2 <jal2>2004-08-29 11:41:18 +0000
committerjal2 <jal2>2004-08-29 11:41:18 +0000
commit312232e41c39a3a67fa4bad4fd1dca2bd93fbaeb (patch)
tree0cdfc3d0341866249530005e49f549d06a82c536
parent9759469463662be5337767cca804e6f7a2f86acc (diff)
- version 0.12beta18version_0_12beta18
- added support for international roaming - added support for "pseudo-monitor" mode, i.e. Kismet displays the contents of beacon and probe responses (both items thanks to the patch by Balint Seeber) - removed polling for scan completion in kevent() - this will hopefully remove the temporary system locks in managed mode when no AP is found. Removed RESCAN_TIME etc.
-rw-r--r--at76c503.c1024
-rw-r--r--at76c503.h98
2 files changed, 967 insertions, 155 deletions
diff --git a/at76c503.c b/at76c503.c
index 6dea6d6..4bc9357 100644
--- a/at76c503.c
+++ b/at76c503.c
@@ -1,11 +1,12 @@
/* -*- linux-c -*- */
-/* $Id: at76c503.c,v 1.67 2004/08/26 20:41:45 jal2 Exp $
+/* $Id: at76c503.c,v 1.68 2004/08/29 11:41:18 jal2 Exp $
*
* USB at76c503/at76c505 driver
*
* Copyright (c) 2002 - 2003 Oliver Kurth
* Copyright (c) 2004 Joerg Albert <joerg.albert@gmx.de>
* Copyright (c) 2004 Nick Jones
+ * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -189,30 +190,33 @@ static inline void usb_set_intfdata(struct usb_interface *intf, void *data) {}
#endif
/* debug bits */
-#define DBG_PROGRESS 0x000001 /* progress of scan-join-(auth-assoc)-connected */
-#define DBG_BSS_TABLE 0x000002 /* show the bss table after scans */
-#define DBG_IOCTL 0x000004 /* ioctl calls / settings */
-#define DBG_KEVENT 0x000008 /* kevents */
-#define DBG_TX_DATA 0x000010 /* tx header */
-#define DBG_TX_DATA_CONTENT 0x000020 /* tx content */
-#define DBG_TX_MGMT 0x000040
-#define DBG_RX_DATA 0x000080 /* rx data header */
-#define DBG_RX_DATA_CONTENT 0x000100 /* rx data content */
-#define DBG_RX_MGMT 0x000200 /* rx mgmt header except beacon and probe responses */
-#define DBG_RX_BEACON 0x000400 /* rx beacon */
-#define DBG_RX_CTRL 0x000800 /* rx control */
-#define DBG_RX_MGMT_CONTENT 0x001000 /* rx mgmt content */
-#define DBG_RX_FRAGS 0x002000 /* rx data fragment handling */
-#define DBG_DEVSTART 0x004000 /* fw download, device start */
-#define DBG_URB 0x008000 /* rx urb status, ... */
-#define DBG_RX_ATMEL_HDR 0x010000 /* the atmel specific header of each rx packet */
-#define DBG_PROC_ENTRY 0x020000 /* procedure entries and exits */
-#define DBG_PM 0x040000 /* power management settings */
-#define DBG_BSS_MATCH 0x080000 /* show why a certain bss did not match */
-#define DBG_PARAMS 0x100000 /* show the configured parameters */
-#define DBG_WAIT_COMPLETE 0x200000 /* show the wait_completion progress */
-#define DBG_RX_FRAGS_SKB 0x400000 /* show skb header for incoming rx fragments */
-#define DBG_BSS_TABLE_RM 0x800000 /* inform on removal of old bss table entries */
+#define DBG_PROGRESS 0x00000001 /* progress of scan-join-(auth-assoc)-connected */
+#define DBG_BSS_TABLE 0x00000002 /* show the bss table after scans */
+#define DBG_IOCTL 0x00000004 /* ioctl calls / settings */
+#define DBG_KEVENT 0x00000008 /* kevents */
+#define DBG_TX_DATA 0x00000010 /* tx header */
+#define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */
+#define DBG_TX_MGMT 0x00000040
+#define DBG_RX_DATA 0x00000080 /* rx data header */
+#define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */
+#define DBG_RX_MGMT 0x00000200 /* rx mgmt header except beacon and probe responses */
+#define DBG_RX_BEACON 0x00000400 /* rx beacon */
+#define DBG_RX_CTRL 0x00000800 /* rx control */
+#define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */
+#define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */
+#define DBG_DEVSTART 0x00004000 /* fw download, device start */
+#define DBG_URB 0x00008000 /* rx urb status, ... */
+#define DBG_RX_ATMEL_HDR 0x00010000 /* the atmel specific header of each rx packet */
+#define DBG_PROC_ENTRY 0x00020000 /* procedure entries and exits */
+#define DBG_PM 0x00040000 /* power management settings */
+#define DBG_BSS_MATCH 0x00080000 /* show why a certain bss did not match */
+#define DBG_PARAMS 0x00100000 /* show the configured parameters */
+#define DBG_WAIT_COMPLETE 0x00200000 /* show the wait_completion progress */
+#define DBG_RX_FRAGS_SKB 0x00400000 /* show skb header for incoming rx fragments */
+#define DBG_BSS_TABLE_RM 0x00800000 /* inform on removal of old bss table entries */
+#define DBG_MONITOR_MODE 0x01000000 /* debugs from monitor mode */
+#define DBG_MIB 0x02000000 /* dump all MIBs in startup_device */
+#define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */
#define DBG_DEFAULTS 0
static int debug = DBG_DEFAULTS;
@@ -256,16 +260,14 @@ static const u8 zeros[32];
/* the beacon timeout in infra mode when we are connected (in seconds) */
#define BEACON_TIMEOUT 10
-/* after how many seconds do we re-scan the channels in infra mode */
-#define RESCAN_TIME 10
-
/* Version Information */
#define DRIVER_DESC "Generic Atmel at76c503/at76c505 routines"
/* Module paramaters */
MODULE_PARM(debug, "i");
#define DRIVER_AUTHOR \
-"Oliver Kurth, Joerg Albert <joerg.albert@gmx.de>, Alex, Nick Jones"
+"Oliver Kurth, Joerg Albert <joerg.albert@gmx.de>, Alex, Nick Jones, "\
+"Balint Seeber <n0_5p4m_p13453@hotmail.com>"
MODULE_PARM_DESC(debug, "Debugging level");
static int rx_copybreak = 200;
@@ -301,6 +303,23 @@ static int pm_period = 0;
MODULE_PARM(pm_period, "i");
MODULE_PARM_DESC(pm_period, "period of waking up the device in usec");
+static int international_roaming = IR_OFF;
+MODULE_PARM(international_roaming, "i");
+MODULE_PARM_DESC(international_roaming, "enable international roaming: 0 (no, default), 1 (yes)");
+
+static int default_iw_mode = IW_MODE_INFRA;
+MODULE_PARM(default_iw_mode, "i");
+MODULE_PARM_DESC(default_iw_mode, "default IW mode for a new device: "
+ "1 (ad-hoc), 2 (infrastructure, def.), 6 (monitor mode)");
+
+static int monitor_scan_min_time = 50;
+MODULE_PARM(monitor_scan_min_time, "i");
+MODULE_PARM_DESC(monitor_scan_min_time, "scan min channel time in MONITOR MODE (default: 50)");
+
+static int monitor_scan_max_time = 600;
+MODULE_PARM(monitor_scan_max_time, "i");
+MODULE_PARM_DESC(monitor_scan_max_time, "scan max channel time in MONITOR MODE (default: 600)");
+
#define DEF_RTS_THRESHOLD 1536
#define DEF_FRAG_THRESHOLD 1536
#define DEF_SHORT_RETRY_LIMIT 8
@@ -437,6 +456,7 @@ struct ieee802_11_deauth_frame {
#define KEVENT_EXTERNAL_FW 11
#define KEVENT_INTERNAL_FW 12
#define KEVENT_RESET_DEVICE 13
+#define KEVENT_MONITOR 14
static DECLARE_WAIT_QUEUE_HEAD(wait_queue);
@@ -469,6 +489,9 @@ static int startup_device(struct at76c503 *dev);
static int update_usb_intf_descr(struct at76c503 *dev);
#endif
+static int set_iroaming(struct at76c503 *dev, int onoff);
+static void set_monitor_mode(struct at76c503 *dev, int use_prism);
+
/* disassemble the firmware image */
static int at76c503_get_fw_info(u8 *fw_data, int fw_size,
u32 *board, u32 *version, char **str,
@@ -1126,6 +1149,26 @@ int set_card_command(struct usb_device *udev, int cmd,
return -ENOMEM;
}
+#define MAKE_CMD_STATUS_CASE(c) case (c): return #c
+
+static const char* get_cmd_status_string(u8 cmd_status)
+{
+ switch (cmd_status)
+ {
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED);
+ }
+
+ return "UNKNOWN";
+}
+
/* TODO: should timeout */
int wait_completion(struct at76c503 *dev, int cmd)
{
@@ -1140,8 +1183,8 @@ int wait_completion(struct at76c503 *dev, int cmd)
break;
}
- dbg(DBG_WAIT_COMPLETE, "%s: cmd %d,cmd_status[5] = %d",
- dev->netdev->name, cmd, cmd_status[5]);
+ dbg(DBG_WAIT_COMPLETE, "%s: Waiting on cmd %d, cmd_status[5] = %d (%s)",
+ dev->netdev->name, cmd, cmd_status[5], get_cmd_status_string(cmd_status[5]));
if(cmd_status[5] == CMD_STATUS_IN_PROGRESS ||
cmd_status[5] == CMD_STATUS_IDLE){
@@ -1435,8 +1478,9 @@ static int dump_mib_mac_addr(struct at76c503 *dev)
goto err;
}
- dbg_uc("%s: MIB MAC_ADDR: mac_addr %s group_addr %s status %d %d %d %d",
+ dbg_uc("%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x group_addr %s status %d %d %d %d",
dev->netdev->name, mac2str(mac_addr->mac_addr),
+ mac_addr->res[0], mac_addr->res[1],
hex2str(dev->obuf, (u8 *)mac_addr->group_addr,
min((int)(sizeof(dev->obuf)-1)/2, 4*ETH_ALEN), '\0'),
mac_addr->group_addr_status[0], mac_addr->group_addr_status[1],
@@ -1493,6 +1537,7 @@ static int dump_mib_mac_mgmt(struct at76c503 *dev)
int ret = 0;
struct mib_mac_mgmt *mac_mgmt =
kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL);
+ char country_string[4];
if(!mac_mgmt){
ret = -ENOMEM;
@@ -1506,9 +1551,37 @@ static int dump_mib_mac_mgmt(struct at76c503 *dev)
goto err;
}
- dbg_uc("%s: MIB MAC_MGMT: station_id x%x pm_mode %d\n",
- dev->netdev->name, le16_to_cpu(mac_mgmt->station_id),
- mac_mgmt->power_mgmt_mode);
+ memcpy(&country_string, mac_mgmt->country_string, 3);
+ country_string[3] = '\0';
+
+ dbg_uc("%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration %d "
+ "medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
+ "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
+ "current_bssid %s current_essid %s current_bss_type %d "
+ "pm_mode %d ibss_change %d res %d "
+ "multi_domain_capability_implemented %d "
+ "international_roaming %d country_string %s",
+ dev->netdev->name,
+ le16_to_cpu(mac_mgmt->beacon_period),
+ le16_to_cpu(mac_mgmt->CFP_max_duration),
+ le16_to_cpu(mac_mgmt->medium_occupancy_limit),
+ le16_to_cpu(mac_mgmt->station_id),
+ le16_to_cpu(mac_mgmt->ATIM_window),
+ mac_mgmt->CFP_mode,
+ mac_mgmt->privacy_option_implemented,
+ mac_mgmt->DTIM_period,
+ mac_mgmt->CFP_period,
+ mac2str(mac_mgmt->current_bssid),
+ hex2str(dev->obuf, (u8 *)mac_mgmt->current_essid,
+ min((int)(sizeof(dev->obuf)-1)/2,
+ IW_ESSID_MAX_SIZE), '\0'),
+ mac_mgmt->current_bss_type,
+ mac_mgmt->power_mgmt_mode,
+ mac_mgmt->ibss_change,
+ mac_mgmt->res,
+ mac_mgmt->multi_domain_capability_implemented,
+ mac_mgmt->multi_domain_capability_enabled,
+ country_string);
err:
kfree(mac_mgmt);
exit:
@@ -1534,14 +1607,165 @@ static int dump_mib_mac(struct at76c503 *dev)
goto err;
}
- dbg_uc("%s: MIB MAC: listen_int %d",
- dev->netdev->name, le16_to_cpu(mac->listen_interval));
+ dbg_uc("%s: MIB MAC: max_tx_msdu_lifetime %d max_rx_lifetime %d "
+ "frag_threshold %d rts_threshold %d cwmin %d cwmax %d "
+ "short_retry_time %d long_retry_time %d scan_type %d "
+ "scan_channel %d probe_delay %u min_channel_time %d "
+ "max_channel_time %d listen_int %d desired_ssid %s "
+ "desired_bssid %s desired_bsstype %d",
+ dev->netdev->name,
+ le32_to_cpu(mac->max_tx_msdu_lifetime),
+ le32_to_cpu(mac->max_rx_lifetime),
+ le16_to_cpu(mac->frag_threshold),
+ le16_to_cpu(mac->rts_threshold),
+ le16_to_cpu(mac->cwmin),
+ le16_to_cpu(mac->cwmax),
+ mac->short_retry_time,
+ mac->long_retry_time,
+ mac->scan_type,
+ mac->scan_channel,
+ le16_to_cpu(mac->probe_delay),
+ le16_to_cpu(mac->min_channel_time),
+ le16_to_cpu(mac->max_channel_time),
+ le16_to_cpu(mac->listen_interval),
+ hex2str(dev->obuf, mac->desired_ssid,
+ min((int)(sizeof(dev->obuf)-1)/2,
+ IW_ESSID_MAX_SIZE), '\0'),
+ mac2str(mac->desired_bssid),
+ mac->desired_bsstype);
err:
kfree(mac);
exit:
return ret;
}
+static int dump_mib_phy(struct at76c503 *dev) __attribute__ ((unused));
+static int dump_mib_phy(struct at76c503 *dev)
+{
+ int ret = 0;
+ struct mib_phy *phy =
+ kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+ if(!phy){
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = get_mib(dev->udev, MIB_PHY,
+ (u8*)phy, sizeof(struct mib_phy));
+ if(ret < 0){
+ err("%s: get_mib failed: %d", dev->netdev->name, ret);
+ goto err;
+ }
+
+ dbg_uc("%s: MIB PHY: ed_threshold %d slot_time %d sifs_time %d "
+ "preamble_length %d plcp_header_length %d mpdu_max_length %d "
+ "cca_mode_supported %d operation_rate_set "
+ "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d "
+ "phy_type %d current_reg_domain %d",
+ dev->netdev->name,
+ le32_to_cpu(phy->ed_threshold),
+ le16_to_cpu(phy->slot_time),
+ le16_to_cpu(phy->sifs_time),
+ le16_to_cpu(phy->preamble_length),
+ le16_to_cpu(phy->plcp_header_length),
+ le16_to_cpu(phy->mpdu_max_length),
+ le16_to_cpu(phy->cca_mode_supported),
+ phy->operation_rate_set[0], phy->operation_rate_set[1],
+ phy->operation_rate_set[2], phy->operation_rate_set[3],
+ phy->channel_id,
+ phy->current_cca_mode,
+ phy->phy_type,
+ phy->current_reg_domain);
+ err:
+ kfree(phy);
+ exit:
+ return ret;
+}
+
+static int dump_mib_local(struct at76c503 *dev) __attribute__ ((unused));
+static int dump_mib_local(struct at76c503 *dev)
+{
+ int ret = 0;
+ struct mib_local *local =
+ kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+ if(!local){
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = get_mib(dev->udev, MIB_LOCAL,
+ (u8*)local, sizeof(struct mib_local));
+ if(ret < 0){
+ err("%s: get_mib failed: %d", dev->netdev->name, ret);
+ goto err;
+ }
+
+ dbg_uc("%s: MIB PHY: beacon_enable %d txautorate_fallback %d "
+ "ssid_size %d promiscuous_mode %d preamble_type %d",
+ dev->netdev->name,
+ local->beacon_enable,
+ local->txautorate_fallback,
+ local->ssid_size,
+ local->promiscuous_mode,
+ local->preamble_type);
+ err:
+ kfree(local);
+ exit:
+ return ret;
+}
+
+
+static int get_mib_mdomain(struct at76c503 *dev, struct mib_mdomain *val)
+ __attribute__ ((unused));
+static int get_mib_mdomain(struct at76c503 *dev, struct mib_mdomain *val)
+{
+ int ret = 0;
+ struct mib_mdomain *mdomain =
+ kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL);
+
+ if(!mdomain){
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = get_mib(dev->udev, MIB_MDOMAIN,
+ (u8*)mdomain, sizeof(struct mib_mdomain));
+ if(ret < 0){
+ err("%s: get_mib failed: %d", dev->netdev->name, ret);
+ goto err;
+ }
+
+ memcpy(val, mdomain, sizeof(*val));
+
+ err:
+ kfree(mdomain);
+ exit:
+ return ret;
+}
+
+static void dump_mib_mdomain(struct at76c503 *dev) __attribute__ ((unused));
+static void dump_mib_mdomain(struct at76c503 *dev)
+{
+ char obuf1[2*14+1], obuf2[2*14+1]; /* to hexdump tx_powerlevel,
+ channel_list */
+ int ret;
+ struct mib_mdomain mdomain;
+
+ if ((ret=get_mib_mdomain(dev, &mdomain)) < 0) {
+ err("%s: get_mib_mdomain returned %d", __FUNCTION__, ret);
+ return;
+ }
+
+ dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s tx_powerlevel %s",
+ dev->netdev->name,
+ hex2str(obuf1, mdomain.channel_list,
+ (sizeof(obuf1)-1)/2,'\0'),
+ hex2str(obuf2, mdomain.tx_powerlevel,
+ (sizeof(obuf2)-1)/2,'\0'));
+}
+
static
int get_current_bssid(struct at76c503 *dev)
{
@@ -1592,8 +1816,12 @@ int get_current_channel(struct at76c503 *dev)
return ret;
}
+/* == PROC start_scan ==
+ start a scan. use_essid is != 0 if any probe_delay (if scan mode is not
+ passive) should contain the ESSID configured. ir_step describes the
+ international roaming step (0, 1) */
static
-int start_scan(struct at76c503 *dev, int use_essid)
+int start_scan(struct at76c503 *dev, int use_essid, int ir_step)
{
struct at76c503_start_scan scan;
@@ -1606,18 +1834,47 @@ int start_scan(struct at76c503 *dev, int use_essid)
} else
scan.essid_size = 0;
- scan.probe_delay = cpu_to_le16(10000);
//jal: why should we start at a certain channel? we do scan the whole range
//allowed by reg domain.
scan.channel = dev->channel;
/* atmelwlandriver differs between scan type 0 and 1 (active/passive)
For ad-hoc mode, it uses type 0 only.*/
- scan.scan_type = dev->scan_mode;
- scan.min_channel_time = cpu_to_le16(dev->scan_min_time);
- scan.max_channel_time = cpu_to_le16(dev->scan_max_time);
+ if ((dev->international_roaming == IR_ON && ir_step == 0) ||
+ dev->iw_mode == IW_MODE_MONITOR)
+ scan.scan_type = SCAN_TYPE_PASSIVE;
+ else
+ scan.scan_type = dev->scan_mode;
+
+ /* INFO: For probe_delay, not multiplying by 1024 as this will be
+ slightly less than min_channel_time
+ (per spec: probe delay < min. channel time) */
+ if (dev->istate == MONITORING) {
+ scan.min_channel_time = cpu_to_le16(dev->monitor_scan_min_time);
+ scan.max_channel_time = cpu_to_le16(dev->monitor_scan_max_time);
+ scan.probe_delay = cpu_to_le16(dev->monitor_scan_min_time * 1000);
+ } else {
+ scan.min_channel_time = cpu_to_le16(dev->scan_min_time);
+ scan.max_channel_time = cpu_to_le16(dev->scan_max_time);
+ scan.probe_delay = cpu_to_le16(dev->scan_min_time * 1000);
+ }
+
+ if (dev->international_roaming == IR_ON && ir_step == 1)
+ scan.international_scan = 0;
+ else
+ scan.international_scan = dev->international_roaming;
+
/* other values are set to 0 for type 0 */
+ dbg(DBG_PROGRESS, "%s: start_scan (use_essid = %d, intl = %d, "
+ "channel = %d, probe_delay = %d, scan_min_time = %d, "
+ "scan_max_time = %d)",
+ dev->netdev->name, use_essid,
+ scan.international_scan, scan.channel,
+ le16_to_cpu(scan.probe_delay),
+ le16_to_cpu(scan.min_channel_time),
+ le16_to_cpu(scan.max_channel_time));
+
return set_card_command(dev->udev, CMD_SCAN,
(unsigned char*)&scan, sizeof(scan));
}
@@ -1713,19 +1970,134 @@ void mgmt_timeout(unsigned long par)
defer_kevent(dev, KEVENT_MGMT_TIMEOUT);
}
+/* == PROC handle_mgmt_timeout_scan == */
+/* called in istate SCANNING on expiry of the mgmt_timer, when a scan was run before
+ (dev->scan_runs > 0) */
+void handle_mgmt_timeout_scan(struct at76c503 *dev)
+{
+
+ u8 *cmd_status;
+ int ret;
+ struct mib_mdomain mdomain;
+
+ cmd_status = kmalloc(40, GFP_KERNEL);
+ if (cmd_status == NULL) {
+ err("%s: %s: cmd_status kmalloc returned NULL",
+ dev->netdev->name, __FUNCTION__);
+ return;
+ }
+
+
+ if ((ret=get_cmd_status(dev->udev, CMD_SCAN, cmd_status)) < 0) {
+ err("%s: %s: get_cmd_status failed with %d",
+ dev->netdev->name, __FUNCTION__, ret);
+ cmd_status[5] = CMD_STATUS_IN_PROGRESS;
+ /* INFO: Hope it was a one off error - if not, scanning
+ further down the line and stop this cycle */
+ }
+
+ dbg(DBG_PROGRESS, "%s %s:%d got cmd_status %d (istate %d, "
+ "scan_runs %d)",
+ dev->netdev->name, __FUNCTION__, __LINE__, cmd_status[5],
+ dev->istate, dev->scan_runs);
+
+ if (cmd_status[5] == CMD_STATUS_COMPLETE) {
+ if (dev->istate == SCANNING) {
+ dump_bss_table(dev,0);
+ switch (dev->scan_runs) {
+
+ case 1:
+ assert(dev->international_roaming);
+ if ((ret=get_mib_mdomain(dev, &mdomain)) < 0) {
+ err("get_mib_mdomain returned %d", ret);
+ } else {
+ char obuf1[2*14+1], obuf2[2*14+1];
+
+ dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s "
+ "tx_powerlevel %s",
+ dev->netdev->name,
+ hex2str(obuf1, mdomain.channel_list,
+ (sizeof(obuf1)-1)/2,'\0'),
+ hex2str(obuf2, mdomain.tx_powerlevel,
+ (sizeof(obuf2)-1)/2,'\0'));
+ }
+ if ((ret = start_scan(dev, 0, 1)) < 0) {
+ err("%s: %s: start_scan (ANY) failed with %d",
+ dev->netdev->name, __FUNCTION__, ret);
+ }
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
+ mod_timer(&dev->mgmt_timer, jiffies + HZ);
+ break;
+
+ case 2:
+ if ((ret = start_scan(dev, 1, 1)) < 0) {
+ err("%s: %s: start_scan (SSID) failed with %d",
+ dev->netdev->name, __FUNCTION__, ret);
+ }
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
+ mod_timer(&dev->mgmt_timer, jiffies + HZ);
+ break;
+
+ case 3:
+ /* report the end of scan to user space */
+ iwevent_scan_complete(dev->netdev);
+ NEW_STATE(dev,JOINING);
+ assert(dev->curr_bss == NULL); /* done in free_bss_list,
+ find_bss will start with first bss */
+ /* call join_bss immediately after
+ re-run of all other threads in kevent */
+ defer_kevent(dev,KEVENT_JOIN);
+ break;
+
+ default:
+ err("unexpected dev->scan_runs %d", dev->scan_runs);
+ } /* switch (dev->scan_runs)*/
+ dev->scan_runs++;
+ } else {
+
+ assert(dev->istate == MONITORING);
+ dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE: restart scan",
+ dev->netdev->name);
+ start_scan(dev, 0, 0);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
+ mod_timer(&dev->mgmt_timer, jiffies + HZ);
+ }
+
+ } else {
+ if ((cmd_status[5] != CMD_STATUS_IN_PROGRESS) &&
+ (cmd_status[5] != CMD_STATUS_IDLE))
+ err("%s: %s: Bad scan status: %s",
+ dev->netdev->name, __FUNCTION__,
+ get_cmd_status_string(cmd_status[5]));
+
+ /* the first cmd status after scan start is always a IDLE ->
+ start the timer to poll again until COMPLETED */
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
+ mod_timer(&dev->mgmt_timer, jiffies + HZ);
+ }
+
+ kfree(cmd_status);
+}
+
/* the deferred procedure called from kevent() */
void handle_mgmt_timeout(struct at76c503 *dev)
{
- if (dev->istate != SCANNING)
- /* this is normal behaviour in state SCANNING ... */
+ if ((dev->istate != SCANNING && dev->istate != MONITORING) ||
+ (debug & DBG_MGMT_TIMER))
+ /* this is normal behaviour in states MONITORING, SCANNING ... */
dbg(DBG_PROGRESS, "%s: timeout, state %d", dev->netdev->name,
dev->istate);
switch(dev->istate) {
- case SCANNING: /* we use the mgmt_timer to delay the next scan for some time */
- defer_kevent(dev, KEVENT_SCAN);
+ case MONITORING:
+ case SCANNING:
+ handle_mgmt_timeout_scan(dev);
break;
case JOINING:
@@ -1750,6 +2122,8 @@ void handle_mgmt_timeout(struct at76c503 *dev)
case AUTHENTICATING:
if (dev->retries-- >= 0) {
auth_req(dev, dev->curr_bss, 1, NULL);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer, jiffies+HZ);
} else {
/* try to get next matching BSS */
@@ -1761,6 +2135,8 @@ void handle_mgmt_timeout(struct at76c503 *dev)
case ASSOCIATING:
if (dev->retries-- >= 0) {
assoc_req(dev,dev->curr_bss);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer, jiffies+HZ);
} else {
/* jal: TODO: we may be authenticated to several
@@ -1783,12 +2159,16 @@ void handle_mgmt_timeout(struct at76c503 *dev)
dev->retries = DISASSOC_RETRIES;
disassoc_req(dev, dev->curr_bss);
}
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer, jiffies+HZ);
break;
case DISASSOCIATING:
if (dev->retries-- >= 0) {
disassoc_req(dev, dev->curr_bss);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer,jiffies+HZ);
} else {
/* we scan again ... */
@@ -2165,11 +2545,16 @@ int reassoc_req(struct at76c503 *dev, struct bss_info *curr_bss,
} /* reassoc_req */
+#if 0 /* delete it !!! */
+/* == PROC handle_scan == */
static
int handle_scan(struct at76c503 *dev)
{
+ char obuf1[2*14+1], obuf2[2*14+1]; /* to hexdump tx_powerlevel,
+ channel_list */
int ret;
-
+ struct mib_mdomain mdomain;
+
if (dev->istate == INIT) {
ret = -EPERM;
goto end_scan;
@@ -2178,31 +2563,56 @@ int handle_scan(struct at76c503 *dev)
/* empty the driver's bss list */
free_bss_list(dev);
+
+ if (dev->international_roaming) {
+ if ((ret = start_scan(dev, 1, 0)) < 0) {
+ err("%s: start_scan failed with %d",
+ dev->netdev->name, ret);
+ goto end_scan;
+ }
+
+ if ((ret = wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) {
+ err("%s: 1.start_scan completed with %d",
+ dev->netdev->name, ret);
+ goto end_scan;
+ }
+
+
+ if ((ret=get_mib_mdomain(dev, &mdomain)) < 0) {
+ err("get_mib_mdomain returned %d", ret);
+ goto end_scan;
+ }
+
+ dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s tx_powerlevel %s",
+ dev->netdev->name,
+ hex2str(obuf1, mdomain.channel_list,
+ (sizeof(obuf1)-1)/2,'\0'),
+ hex2str(obuf2, mdomain.tx_powerlevel,
+ (sizeof(obuf2)-1)/2,'\0'));
+
+ /* dump the results of the scan */
+ dump_bss_table(dev, 0);
- /* scan twice: first run with ProbeReq containing the
- empty SSID, the second run with the real SSID.
- APs in cloaked mode (e.g. Agere) will answer
- in the second run with their real SSID. */
-
- if ((ret = start_scan(dev, 0)) < 0) {
- err("%s: start_scan failed with %d", dev->netdev->name, ret);
+ }
+
+ if ((ret = start_scan(dev, 0, 1)) < 0) {
+ err("%s: start_scan (ANY) failed with %d",
+ dev->netdev->name, ret);
goto end_scan;
}
if ((ret = wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) {
- err("%s start_scan completed with %d",
- dev->netdev->name, ret);
+ err("%s: start_scan (ANY) completed with %d",
+ dev->netdev->name, ret);
goto end_scan;
}
- /* dump the results of the scan with ANY ssid */
- dump_bss_table(dev, 0);
-
- if ((ret = start_scan(dev, 1)) < 0) {
- err("%s: 2.start_scan failed with %d", dev->netdev->name, ret);
- goto end_scan;
+ if ((ret = start_scan(dev, 1, 1)) < 0) {
+ err("%s: start_scan (SSID) failed with %d",
+ dev->netdev->name, ret);
+ goto end_scan;
}
if ((ret = wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) {
- err("%s 2.start_scan completed with %d",
+ err("%s: start_scan (SSID) completed with %d",
dev->netdev->name, ret);
goto end_scan;
}
@@ -2215,6 +2625,7 @@ int handle_scan(struct at76c503 *dev)
end_scan:
return (ret < 0);
}
+#endif //#if 0
#if 0
/* == PROC re_register_intf ==
@@ -2288,7 +2699,7 @@ kevent(void *data)
is done. So work will be done next time something
else has to be done. This is ugly. TODO! (oku) */
- dbg(DBG_KEVENT, "%s: kevent entry flags=x%lx", dev->netdev->name,
+ dbg(DBG_KEVENT, "%s: kevent entry flags: 0x%lx", dev->netdev->name,
dev->kevent_flags);
down(&dev->sem);
@@ -2335,6 +2746,7 @@ kevent(void *data)
new_bss_clean:
kfree(mac_mgmt);
}
+
if(test_bit(KEVENT_SET_PROMISC, &dev->kevent_flags)){
info("%s: KEVENT_SET_PROMISC", dev->netdev->name);
@@ -2342,11 +2754,6 @@ kevent(void *data)
clear_bit(KEVENT_SET_PROMISC, &dev->kevent_flags);
}
- if(test_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags)){
- clear_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags);
- handle_mgmt_timeout(dev);
- }
-
/* check this _before_ KEVENT_JOIN, 'cause _JOIN sets _STARTIBSS bit */
if (test_bit(KEVENT_STARTIBSS, &dev->kevent_flags)) {
clear_bit(KEVENT_STARTIBSS, &dev->kevent_flags);
@@ -2439,6 +2846,8 @@ end_startibss:
/* send auth req */
NEW_STATE(dev,AUTHENTICATING);
auth_req(dev, dev->curr_bss, 1, NULL);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer, jiffies+HZ);
}
goto end_join;
@@ -2450,28 +2859,40 @@ end_startibss:
defer_kevent(dev,KEVENT_STARTIBSS);
goto end_join;
}
- /* haven't found a matching BSS
- in infra mode - use timer to try again in 10 seconds */
+ /* haven't found a matching BSS in infra mode - try again */
NEW_STATE(dev,SCANNING);
- mod_timer(&dev->mgmt_timer, jiffies+RESCAN_TIME*HZ);
+ defer_kevent(dev, KEVENT_SCAN);
} /* if (test_bit(KEVENT_JOIN, &dev->kevent_flags)) */
end_join:
+ if(test_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags)){
+ clear_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags);
+ handle_mgmt_timeout(dev);
+ }
+
if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) {
clear_bit(KEVENT_SCAN, &dev->kevent_flags);
-
- if (handle_scan(dev)) {
- goto end_scan;
+
+ assert(dev->istate == SCANNING);
+
+ /* empty the driver's bss list */
+ free_bss_list(dev);
+
+ /* jal: a hack: we have an additional scan run for
+ international roaming with use_essid == 1 */
+ dev->scan_runs = dev->international_roaming ? 1 : 2;
+ if ((ret=start_scan(dev, dev->international_roaming ?
+ 1 : 0, 0)) < 0) {
+ err("%s: %s: start_scan failed with %d",
+ dev->netdev->name, __FUNCTION__, ret);
+ } else {
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
+ mod_timer(&dev->mgmt_timer, jiffies + HZ);
}
-
- NEW_STATE(dev,JOINING);
- assert(dev->curr_bss == NULL); /* done in free_bss_list,
- find_bss will start with first bss */
- /* call join_bss immediately after
- re-run of all other threads in kevent */
- defer_kevent(dev,KEVENT_JOIN);
+
} /* if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) */
-end_scan:
+
if (test_bit(KEVENT_SUBMIT_RX, &dev->kevent_flags)) {
clear_bit(KEVENT_SUBMIT_RX, &dev->kevent_flags);
@@ -2483,9 +2904,26 @@ end_scan:
clear_bit(KEVENT_RESTART, &dev->kevent_flags);
assert(dev->istate == INIT);
startup_device(dev);
- /* scan again in a second */
- NEW_STATE(dev,SCANNING);
- mod_timer(&dev->mgmt_timer, jiffies+HZ);
+
+ /* call it here for default_iw_mode == IW_MODE_MONITOR and
+ no subsequent "iwconfig wlanX mode monitor" or
+ "iwpriv wlanX monitor 1|2 C" to set dev->netdev->type
+ correctly */
+ set_monitor_mode(dev, dev->monitor_prism_header);
+
+
+ netif_carrier_off(dev->netdev); /* disable running netdev watchdog */
+ netif_stop_queue(dev->netdev); /* stop tx data packets */
+ if (dev->iw_mode != IW_MODE_MONITOR) {
+ NEW_STATE(dev,SCANNING);
+ defer_kevent(dev,KEVENT_SCAN);
+ } else {
+ NEW_STATE(dev,MONITORING);
+ start_scan(dev,0,0);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
+ mod_timer(&dev->mgmt_timer, jiffies+HZ);
+ }
}
if (test_bit(KEVENT_ASSOC_DONE, &dev->kevent_flags)) {
@@ -2621,7 +3059,7 @@ end_internal_fw:
up(&dev->sem);
- dbg(DBG_KEVENT, "%s: kevent exit flags=x%lx", dev->netdev->name,
+ dbg(DBG_KEVENT, "%s: kevent exit flags: 0x%lx", dev->netdev->name,
dev->kevent_flags);
return;
@@ -2991,12 +3429,16 @@ static void rx_mgmt_auth(struct at76c503 *dev,
dev->retries = ASSOC_RETRIES;
NEW_STATE(dev,ASSOCIATING);
assoc_req(dev, dev->curr_bss);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer,jiffies+HZ);
return;
}
assert(seq_nr == 2);
auth_req(dev, dev->curr_bss, seq_nr+1, resp->challenge);
+ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer,jiffies+HZ);
}
/* else: ignore AuthFrames to other receipients */
@@ -3084,6 +3526,8 @@ static void rx_mgmt_beacon(struct at76c503 *dev,
if (dev->curr_bss == NULL)
goto rx_mgmt_beacon_end;
if (!memcmp(dev->curr_bss->bssid, mgmt->addr3, ETH_ALEN)) {
+ //dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer "
+ // "+BEACON_TIMEOUT*HZ", __FUNCTION__, __LINE__);
mod_timer(&dev->mgmt_timer, jiffies+BEACON_TIMEOUT*HZ);
dev->curr_bss->rssi = buf->rssi;
goto rx_mgmt_beacon_end;
@@ -3243,12 +3687,25 @@ rx_mgmt_beacon_end:
spin_unlock_irqrestore(&dev->bss_list_spinlock, flags);
} /* rx_mgmt_beacon */
+static void update_wstats(struct at76c503 *dev, struct at76c503_rx_buffer *buf)
+{
+ struct iw_statistics *wstats = &dev->wstats;
+ u16 lev_dbm;
+
+ if (buf->rssi > 1) {
+ lev_dbm = (buf->rssi * 5 / 2);
+ if (lev_dbm > 255)
+ lev_dbm = 255;
+ wstats->qual.qual = buf->link_quality;
+ wstats->qual.level = lev_dbm;
+ wstats->qual.noise = buf->noise_level;
+ wstats->qual.updated = 7;
+ }
+}
static void rx_mgmt(struct at76c503 *dev, struct at76c503_rx_buffer *buf)
{
struct ieee802_11_mgmt *mgmt = ( struct ieee802_11_mgmt *)buf->packet;
- struct iw_statistics *wstats = &dev->wstats;
- u16 lev_dbm;
u16 subtype = le16_to_cpu(mgmt->frame_ctl) & IEEE802_11_FCTL_STYPE;
/* update wstats */
@@ -3262,15 +3719,7 @@ static void rx_mgmt(struct at76c503 *dev, struct at76c503_rx_buffer *buf)
Atmel driver actually averages the present, and previous
values, we just present the raw value at the moment - TJS */
- if (buf->rssi > 1) {
- lev_dbm = (buf->rssi * 5 / 2);
- if (lev_dbm > 255)
- lev_dbm = 255;
- wstats->qual.qual = buf->link_quality;
- wstats->qual.level = lev_dbm;
- wstats->qual.noise = buf->noise_level;
- wstats->qual.updated = 7;
- }
+ update_wstats(dev, buf);
}
}
@@ -3873,6 +4322,120 @@ static void at76c503_read_bulk_callback (struct urb *urb)
return;
}
+static void rx_monitor_mode(struct at76c503 *dev)
+{
+ struct net_device *netdev = (struct net_device *)dev->netdev;
+ struct at76c503_rx_buffer *buf =
+ (struct at76c503_rx_buffer *)dev->rx_skb->data;
+ /* length including the IEEE802.11 header, excl. the trailing FCS,
+ excl. the struct at76c503_rx_buffer */
+ int length = le16_to_cpu(buf->wlength) - dev->rx_data_fcs_len;
+ struct sk_buff *skb = dev->rx_skb;
+ struct net_device_stats *stats = &dev->stats;
+ struct iw_statistics *wstats = &dev->wstats;
+
+ update_wstats(dev, buf);
+
+ if (length < 0) {
+ /* buffer contains no data */
+ dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE: rx skb without data",
+ dev->netdev->name);
+ return;
+ }
+
+ if (netdev->type == ARPHRD_IEEE80211_PRISM) {
+ int skblen = sizeof(p80211msg_lnxind_wlansniffrm_t) + length;
+ p80211msg_lnxind_wlansniffrm_t *prism;
+ u8* payload;
+
+ if ((skb = dev_alloc_skb(skblen)) == NULL) {
+ err("%s: MONITOR MODE: dev_alloc_skb for Prism header "
+ "returned NULL", dev->netdev->name);
+ return;
+ }
+
+ skb_put(skb, skblen);
+
+ prism = (p80211msg_lnxind_wlansniffrm_t*)skb->data;
+ payload = skb->data + sizeof(p80211msg_lnxind_wlansniffrm_t);
+
+ prism->msgcode = DIDmsg_lnxind_wlansniffrm;
+ prism->msglen = sizeof(p80211msg_lnxind_wlansniffrm_t);
+ strcpy(prism->devname, netdev->name);
+
+ prism->hosttime.did = DIDmsg_lnxind_wlansniffrm_hosttime;
+ prism->hosttime.status = 0;
+ prism->hosttime.len = 4;
+ prism->hosttime.data = jiffies;
+
+ prism->mactime.did = DIDmsg_lnxind_wlansniffrm_mactime;
+ prism->mactime.status = 0;
+ prism->mactime.len = 4;
+ memcpy(&prism->mactime.data, buf->rx_time, 4);
+
+ prism->channel.did = DIDmsg_lnxind_wlansniffrm_channel;
+ prism->channel.status = P80211ENUM_msgitem_status_no_value;
+ prism->channel.len = 4;
+ /* INFO: The channel is encoded in the beacon info.
+ (Kismet can figure it out, so less processing here) */
+ prism->channel.data = 0;
+
+ prism->rssi.did = DIDmsg_lnxind_wlansniffrm_rssi;
+ prism->rssi.status = 0;
+ prism->rssi.len = 4;
+ prism->rssi.data = buf->rssi;
+
+ prism->sq.did = DIDmsg_lnxind_wlansniffrm_sq;
+ prism->sq.status = 0;
+ prism->sq.len = 4;
+ prism->sq.data = wstats->qual.qual;
+
+ prism->signal.did = DIDmsg_lnxind_wlansniffrm_signal;
+ prism->signal.status = 0;
+ prism->signal.len = 4;
+ prism->signal.data = wstats->qual.level;
+
+ prism->noise.did = DIDmsg_lnxind_wlansniffrm_noise;
+ prism->noise.status = 0;
+ prism->noise.len = 4;
+ prism->noise.data = wstats->qual.noise;
+
+ prism->rate.did = DIDmsg_lnxind_wlansniffrm_rate;
+ prism->rate.status = 0;
+ prism->rate.len = 4;
+ prism->rate.data = hw_rates[buf->rx_rate] & (~0x80);
+
+ prism->istx.did = DIDmsg_lnxind_wlansniffrm_istx;
+ prism->istx.status = 0;
+ prism->istx.len = 4;
+ prism->istx.data = P80211ENUM_truth_false;
+
+ prism->frmlen.did = DIDmsg_lnxind_wlansniffrm_frmlen;
+ prism->frmlen.status = 0;
+ prism->frmlen.len = 4;
+ prism->frmlen.data = length;
+
+ memcpy(payload, buf->packet, length);
+ } else {
+ /* netdev->type != ARPHRD_IEEE80211_PRISM */
+ skb_pull(skb, AT76C503_RX_HDRLEN);
+ skb_trim(skb, length);
+ dev->rx_skb = NULL;
+ }
+
+ skb->dev = netdev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->mac.raw = skb->data;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_80211_RAW);
+
+ netdev->last_rx = jiffies;
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += length;
+} /* end of rx_monitor_mode */
+
+
static void rx_tasklet(unsigned long param)
{
struct at76c503 *dev = (struct at76c503 *)param;
@@ -3915,12 +4478,6 @@ static void rx_tasklet(unsigned long param)
return;
}
- /* there is a new bssid around, accept it: */
- if(buf->newbss && dev->iw_mode == IW_MODE_ADHOC){
- dbg(DBG_PROGRESS, "%s: rx newbss", netdev->name);
- defer_kevent(dev, KEVENT_NEW_BSS);
- }
-
if (debug & DBG_RX_ATMEL_HDR) {
dbg_uc("%s: rx frame: rate %d rssi %d noise %d link %d %s",
dev->netdev->name,
@@ -3930,6 +4487,17 @@ static void rx_tasklet(unsigned long param)
min((int)(sizeof(dev->obuf)-1)/2,48),'\0'));
}
+ if (dev->istate == MONITORING) {
+ rx_monitor_mode(dev);
+ goto finish;
+ }
+
+ /* there is a new bssid around, accept it: */
+ if(buf->newbss && dev->iw_mode == IW_MODE_ADHOC) {
+ dbg(DBG_PROGRESS, "%s: rx newbss", netdev->name);
+ defer_kevent(dev, KEVENT_NEW_BSS);
+ }
+
switch (frame_ctl & IEEE802_11_FCTL_FTYPE) {
case IEEE802_11_FTYPE_DATA:
rx_data(dev);
@@ -3954,7 +4522,7 @@ static void rx_tasklet(unsigned long param)
info("%s: it's a frame from mars: %2x", dev->netdev->name,
frame_ctl);
} /* switch (frame_ctl & IEEE802_11_FCTL_FTYPE) */
-
+finish:
submit_rx_urb(dev);
no_more_urb:
return;
@@ -4190,10 +4758,12 @@ int startup_device(struct at76c503 *dev)
dev->channel,
dev->wep_enabled ? "enabled" : "disabled",
dev->wep_key_id, dev->wep_keys_len[dev->wep_key_id]);
- dbg_uc("%s param: preamble %s rts %d retry %d frag %d txrate %s auth_mode %d",
+ dbg_uc("%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->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" :
@@ -4201,35 +4771,40 @@ int startup_device(struct at76c503 *dev)
dev->txrate == TX_RATE_AUTO ? "auto" : "<invalid>",
dev->auth_mode);
dbg_uc("%s param: pm_mode %d pm_period %d auth_mode %s "
- "scan_times %d %d scan_mode %s",
+ "scan_times %d %d scan_mode %s international_roaming %d",
dev->netdev->name,
dev->pm_mode, dev->pm_period_us,
dev->auth_mode == IEEE802_11_AUTH_ALG_OPEN_SYSTEM ?
"open" : "shared_secret",
dev->scan_min_time, dev->scan_max_time,
- dev->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive");
+ dev->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive",
+ dev->international_roaming);
}
memset(ccfg, 0, sizeof(struct at76c503_card_config));
- ccfg->exclude_unencrypted = 1; /* jal: always exclude unencrypted
- if WEP is active */
ccfg->promiscuous_mode = 0;
ccfg->short_retry_limit = dev->short_retry_limit;
//ccfg->long_retry_limit = dev->long_retry_limit;
-
- if (dev->wep_enabled &&
- dev->wep_keys_len[dev->wep_key_id] > WEP_SMALL_KEY_LEN)
- ccfg->encryption_type = 2;
- else
- ccfg->encryption_type = 1;
+ 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 == 4 ? 1 : 0);
+ 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);
@@ -4252,7 +4827,7 @@ int startup_device(struct at76c503 *dev)
/* remove BSSID from previous run */
memset(dev->bssid, 0, ETH_ALEN);
-
+
if (set_radio(dev, 1) == 1)
wait_completion(dev, CMD_RADIO);
@@ -4264,12 +4839,26 @@ int startup_device(struct at76c503 *dev)
if ((ret=set_rts(dev, dev->rts_threshold)) < 0)
return ret;
- if ((ret=set_autorate_fallback(dev, dev->txrate == 4 ? 1 : 0)) < 0)
+ if ((ret=set_autorate_fallback(dev, dev->txrate == TX_RATE_AUTO ? 1 : 0)) < 0)
return ret;
if ((ret=set_pm_mode(dev, dev->pm_mode)) < 0)
return ret;
+ if ((ret=set_iroaming(dev, dev->international_roaming)) < 0)
+ return ret;
+
+ if (debug & DBG_MIB)
+ {
+ dump_mib_mac(dev);
+ dump_mib_mac_addr(dev);
+ dump_mib_mac_mgmt(dev);
+ dump_mib_mac_wep(dev);
+ dump_mib_mdomain(dev);
+ dump_mib_phy(dev);
+ dump_mib_local(dev);
+ }
+
return 0;
}
@@ -4284,10 +4873,6 @@ int at76c503_open(struct net_device *netdev)
if(down_interruptible(&dev->sem))
return -EINTR;
- ret = startup_device(dev);
- if (ret < 0)
- goto err;
-
/* if netdev->dev_addr != dev->mac_addr we must
set the mac address in the device ! */
if (memcmp(netdev->dev_addr, dev->mac_addr, ETH_ALEN)) {
@@ -4302,18 +4887,15 @@ int at76c503_open(struct net_device *netdev)
dev->nr_submit_rx_tries = NR_SUBMIT_RX_TRIES; /* init counter */
- ret = submit_rx_urb(dev);
- if(ret < 0){
+ if((ret=submit_rx_urb(dev)) < 0){
err("%s: open: submit_rx_urb failed: %d", netdev->name, ret);
goto err;
}
- NEW_STATE(dev,SCANNING);
- defer_kevent(dev,KEVENT_SCAN);
- netif_carrier_off(dev->netdev); /* disable running netdev watchdog */
- netif_stop_queue(dev->netdev); /* stop tx data packets */
-
dev->open_count++;
+
+ defer_kevent(dev, KEVENT_RESTART);
+
dbg(DBG_PROC_ENTRY, "at76c503_open end");
err:
up(&dev->sem);
@@ -4541,6 +5123,17 @@ static const struct iw_priv_args at76c503_priv_args[] = {
{ PRIV_IOCTL_SET_SCAN_MODE,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
"scan_mode"}, // 0 - active, 1 - passive scan
+
+ { PRIV_IOCTL_SET_INTL_ROAMING,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
+ "intl_roaming"},
+
+ /* needed for Kismet, orinoco mode */
+ { PRIV_IOCTL_SET_MONITOR_MODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0,
+ "monitor"}, /* param1: monitor mode: 0 (off), 1 (on,Prism header),
+ 2 (on, no Prism header)
+ param2: channel (to start scan at) */
};
@@ -4642,9 +5235,10 @@ int at76c503_iw_handler_set_freq(struct net_device *netdev,
// either that or an invalid frequency was
// provided by the user
ret = -EINVAL;
- } else {
+ } else if (!dev->international_roaming) {
if (!(dev->domain->channel_map & (1 << (chan-1)))) {
- info("%s: channel %d not allowed for domain %s",
+ info("%s: channel %d not allowed for domain %s "
+ "(and international_roaming is OFF)",
dev->netdev->name, chan, dev->domain->name);
ret = -EINVAL;
}
@@ -4690,13 +5284,12 @@ int at76c503_iw_handler_set_mode(struct net_device *netdev,
dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode);
- if ((*mode != IW_MODE_ADHOC) &&
- (*mode != IW_MODE_INFRA)) {
+ if ((*mode != IW_MODE_ADHOC) && (*mode != IW_MODE_INFRA) &&
+ (*mode != IW_MODE_MONITOR)) {
ret = -EINVAL;
} else {
dev->iw_mode = *mode;
}
-
return ret;
}
@@ -5039,11 +5632,15 @@ int at76c503_iw_handler_set_scan(struct net_device *netdev,
char *extra)
{
struct at76c503 *dev = (struct at76c503*)netdev->priv;
- int ret = 0;
unsigned long flags;
dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name);
-
+
+ /* jal: we don't allow "iwlist wlanX scan" while we are
+ in monitor mode */
+ if (dev->iw_mode == IW_MODE_MONITOR)
+ return -EBUSY;
+
// stop pending management stuff
del_timer_sync(&(dev->mgmt_timer));
@@ -5062,16 +5659,9 @@ int at76c503_iw_handler_set_scan(struct net_device *netdev,
// change to scanning state
NEW_STATE(dev, SCANNING);
+ defer_kevent(dev, KEVENT_SCAN);
- ret = handle_scan(dev);
-
- if (!ret) {
- NEW_STATE(dev,JOINING);
- assert(dev->curr_bss == NULL);
- defer_kevent(dev, KEVENT_JOIN);
- }
-
- return (ret < 0) ? ret : 0;
+ return 0;
}
static
@@ -5772,8 +6362,14 @@ int at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_TIMES
if (mint <= 0 || maxt <= 0 || mint > maxt) {
ret = -EINVAL;
} else {
- dev->scan_min_time = mint;
- dev->scan_max_time = maxt;
+ 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;
@@ -5801,7 +6397,113 @@ int at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE
return ret;
}
+static
+int set_iroaming(struct at76c503 *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 = 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 at76c503_iw_handler_PRIV_IOCTL_SET_INTL_ROAMING
+ (struct net_device *netdev, IW_REQUEST_INFO *info,
+ char *name, char *extra)
+{
+ struct at76c503 *dev = (struct at76c503*)netdev->priv;
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_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;
+ set_iroaming(dev, val);
+ }
+ }
+
+ return ret;
+}
+
+/* == PROC set_monitor_mode ==
+ sets dev->netdev->type */
+static
+void set_monitor_mode(struct at76c503 *dev, int use_prism)
+{
+ if (dev->iw_mode == IW_MODE_MONITOR) {
+ if (use_prism) {
+ dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE ON: "
+ "Prism headers ARE used", dev->netdev->name);
+ dev->netdev->type = ARPHRD_IEEE80211_PRISM;
+ } else {
+ dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE ON: "
+ "Prism headers NOT used", dev->netdev->name);
+ dev->netdev->type = ARPHRD_IEEE80211;
+ }
+ } else {
+ dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE OFF",
+ dev->netdev->name);
+ dev->netdev->type = ARPHRD_ETHER;
+ }
+} /* set_monitor_mode */
+
+static
+int at76c503_iw_handler_PRIV_IOCTL_SET_MONITOR_MODE
+ (struct net_device *netdev, IW_REQUEST_INFO *info,
+ char *name, char *extra)
+{
+ struct at76c503 *dev = (struct at76c503*)netdev->priv;
+ int *params = ((int *)name);
+ int mode = params[0];
+ int channel = params[1];
+ int ret = 0;
+
+ dbg(DBG_IOCTL, "%s: PRIV_IOCTL_SET_MONITOR_MODE - mode %d ch %d",
+ netdev->name, mode, channel);
+
+ if (mode != MM_OFF && mode != MM_ON && mode != MM_ON_NO_PRISM)
+ ret = -EINVAL;
+ else {
+ if (mode != MM_OFF) {
+ if ((channel >= 1) &&
+ (channel <= (sizeof(channel_frequency) /
+ sizeof(channel_frequency[0]))))
+ // INFO: This doesn't actually affect the scan
+ dev->channel = channel;
+
+ dev->monitor_prism_header = (mode == MM_ON);
+
+ if (dev->iw_mode != IW_MODE_MONITOR) {
+ ret = -EIWCOMMIT;
+ dev->iw_mode = IW_MODE_MONITOR;
+ }
+ } else {
+ /* mode == MM_OFF */
+ if (dev->iw_mode == IW_MODE_MONITOR) {
+ ret = -EIWCOMMIT;
+ dev->iw_mode = IW_MODE_INFRA;
+ }
+ }
+ set_monitor_mode(dev, dev->monitor_prism_header);
+ }
+
+ return ret;
+}
#if WIRELESS_EXT > 12
/*******************************************************************************
@@ -5891,6 +6593,10 @@ static const iw_handler at76c503_priv_handlers[] =
(iw_handler) NULL,
(iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE,
(iw_handler) NULL,
+ (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_INTL_ROAMING,
+ (iw_handler) NULL,
+ (iw_handler) at76c503_iw_handler_PRIV_IOCTL_SET_MONITOR_MODE,
+ (iw_handler) NULL,
};
static const struct iw_handler_def at76c503_handler_def =
@@ -6306,6 +7012,16 @@ set_debug_end:
ret = at76c503_iw_handler_PRIV_IOCTL_SET_SCAN_MODE
(netdev, NULL, wrq->u.name, NULL);
break;
+
+ case PRIV_IOCTL_SET_INTL_ROAMING:
+ ret = at76c503_iw_handler_PRIV_IOCTL_SET_INTL_ROAMING
+ (netdev, NULL, wrq->u.name, NULL);
+ break;
+
+ case PRIV_IOCTL_SET_MONITOR_MODE:
+ ret = at76c503_iw_handler_PRIV_IOCTL_SET_MONITOR_MODE
+ (netdev, NULL, wrq->u.name, NULL);
+ break;
default:
dbg(DBG_IOCTL, "%s: ioctl not supported (0x%x)", netdev->name,
@@ -6591,7 +7307,7 @@ int init_new_device(struct at76c503 *dev)
else
dev->rx_data_fcs_len = 4;
- info("$Id: at76c503.c,v 1.67 2004/08/26 20:41:45 jal2 Exp $ compiled %s %s", __DATE__, __TIME__);
+ info("$Id: at76c503.c,v 1.68 2004/08/29 11:41:18 jal2 Exp $ compiled %s %s", __DATE__, __TIME__);
info("firmware version %d.%d.%d #%d (fcs_len %d)",
dev->fw_version.major, dev->fw_version.minor,
dev->fw_version.patch, dev->fw_version.build,
@@ -6612,8 +7328,10 @@ int init_new_device(struct at76c503 *dev)
dev->regulatory_domain);
/* initializing */
+ dev->international_roaming = international_roaming;
dev->channel = DEF_CHANNEL;
- dev->iw_mode = IW_MODE_ADHOC;
+ dev->iw_mode = default_iw_mode;
+ dev->monitor_prism_header = 1;
memset(dev->essid, 0, IW_ESSID_MAX_SIZE);
memcpy(dev->essid, DEF_ESSID, DEF_ESSID_LEN);
dev->essid_size = DEF_ESSID_LEN;
@@ -6629,6 +7347,8 @@ int init_new_device(struct at76c503 *dev)
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 = at76c503_open;
@@ -6890,8 +7610,6 @@ int at76c503_usbdfu_post(struct usb_device *udev)
return 0;
}
-/* == PROC == */
-
/**
* at76c503_init
diff --git a/at76c503.h b/at76c503.h
index 96994d6..33d5ea7 100644
--- a/at76c503.h
+++ b/at76c503.h
@@ -1,5 +1,5 @@
/* -*- linux-c -*- */
-/* $Id: at76c503.h,v 1.26 2004/08/18 22:01:45 jal2 Exp $
+/* $Id: at76c503.h,v 1.27 2004/08/29 11:41:18 jal2 Exp $
*
* Copyright (c) 2002 - 2003 Oliver Kurth
* (c) 2003 - 2004 Jörg Albert <joerg.albert@gmx.de>
@@ -48,7 +48,7 @@
#endif
/* current driver version */
-#define DRIVER_VERSION "v0.12beta17" VERSION_APPEND
+#define DRIVER_VERSION "v0.12beta18" VERSION_APPEND
/* Workqueue / task queue backwards compatibility stuff */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
@@ -91,6 +91,24 @@
#define PRIV_IOCTL_SET_SCAN_TIMES (SIOCIWFIRSTPRIV + 0x6)
/* set scan mode */
#define PRIV_IOCTL_SET_SCAN_MODE (SIOCIWFIRSTPRIV + 0x8)
+/* set international roaming */
+#define PRIV_IOCTL_SET_INTL_ROAMING (SIOCIWFIRSTPRIV + 0x10)
+/* set monitor mode */
+#define PRIV_IOCTL_SET_MONITOR_MODE (SIOCIWFIRSTPRIV + 0x12)
+
+#ifndef ETH_P_ECONET
+#define ETH_P_ECONET 0x0018 /* needed for 2.2.x kernels */
+#endif
+
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+
+#ifndef ARPHRD_IEEE80211
+#define ARPHRD_IEEE80211 801 /* kernel 2.4.6 */
+#endif
+
+#ifndef ARPHRD_IEEE80211_PRISM /* kernel 2.4.18 */
+#define ARPHRD_IEEE80211_PRISM 802
+#endif
#define DEVICE_VENDOR_REQUEST_OUT 0x40
#define DEVICE_VENDOR_REQUEST_IN 0xc0
@@ -153,6 +171,16 @@
#define PM_SAVE 2
#define PM_SMART_SAVE 3
+/* international roaming state */
+#define IR_OFF 0
+#define IR_ON 1
+
+/* monitor mode - param of private ioctl */
+#define MM_OFF 0
+#define MM_ON 1
+#define MM_ON_NO_PRISM 2
+
+
/* offsets into the MIBs we use to configure the device */
#define TX_AUTORATE_FALLBACK_OFFSET offsetof(struct mib_local,txautorate_fallback)
#define FRAGMENTATION_OFFSET offsetof(struct mib_mac,frag_threshold)
@@ -161,6 +189,7 @@
/* valid only for rfmd and 505 !*/
#define IBSS_CHANGE_OK_OFFSET offsetof(struct mib_mac_mgmt, ibss_change)
+#define IROAMING_IMPL_OFFSET offsetof(struct mib_mac_mgmt, multi_domain_capability_implemented)
#define IROAMING_OFFSET \
offsetof(struct mib_mac_mgmt, multi_domain_capability_enabled)
/* the AssocID */
@@ -168,6 +197,8 @@
#define POWER_MGMT_MODE_OFFSET offsetof(struct mib_mac_mgmt, power_mgmt_mode)
#define LISTEN_INTERVAL_OFFSET offsetof(struct mib_mac, listen_interval)
+#define PRIVACY_OPT_IMPL offsetof(struct mib_mac_mgmt, privacy_option_implemented)
+
#define BOARDTYPE_503_INTERSIL_3861 1
#define BOARDTYPE_503_INTERSIL_3863 2
#define BOARDTYPE_503_RFMD 3
@@ -425,6 +456,7 @@ enum infra_state {
INTFW_DOWNLOAD,
EXTFW_DOWNLOAD,
WAIT_FOR_DISCONNECT,
+ MONITORING,
};
/* a description of a regulatory domain and the allowed channels */
@@ -551,6 +583,7 @@ struct at76c503 {
int scan_min_time; /* scan min channel time */
int scan_max_time; /* scan max channel time */
int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */
+ int scan_runs; /* counts how many scans are started */
/* the list we got from scanning */
spinlock_t bss_list_spinlock; /* protects bss_list operations and setting
@@ -641,11 +674,72 @@ struct at76c503 {
char obuf[2*256+1]; /* global debug output buffer to reduce stack usage */
char obuf_s[3*32]; /* small global debug output buffer to reduce stack usage */
struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */
+
+ /* new whiz-bang feature flags */
+ int international_roaming;
+ int monitor_prism_header; /* if iw_mode == IW_MODE_MONITOR,
+ use Prism header */
+ int monitor_scan_min_time;
+ int monitor_scan_max_time;
};
#define AT76C503A_UNPLUG 1
#define AT76C503A_NETDEV_REGISTERED 2
+/* Quasi-monitor mode defs (copied from <kernel>/drivers/net/wireless/orinoco.h) */
+
+#define WLAN_DEVNAMELEN_MAX 16
+
+/* message data item for INT, BOUNDEDINT, ENUMINT */
+typedef struct p80211item_uint32
+{
+ uint32_t did __attribute__ ((packed));
+ uint16_t status __attribute__ ((packed));
+ uint16_t len __attribute__ ((packed));
+ uint32_t data __attribute__ ((packed));
+} __attribute__ ((packed)) p80211item_uint32_t;
+
+typedef struct p80211msg
+{
+ uint32_t msgcode __attribute__ ((packed));
+ uint32_t msglen __attribute__ ((packed));
+ uint8_t devname[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed));
+} __attribute__ ((packed)) p80211msg_t;
+
+#define P80211ENUM_msgitem_status_data_ok 0
+#define P80211ENUM_msgitem_status_no_value 1
+#define P80211ENUM_truth_false 0
+#define P80211ENUM_truth_true 1
+
+#define DIDmsg_lnxind_wlansniffrm 0x0041
+#define DIDmsg_lnxind_wlansniffrm_hosttime 0x1041
+#define DIDmsg_lnxind_wlansniffrm_mactime 0x2041
+#define DIDmsg_lnxind_wlansniffrm_channel 0x3041
+#define DIDmsg_lnxind_wlansniffrm_rssi 0x4041
+#define DIDmsg_lnxind_wlansniffrm_sq 0x5041
+#define DIDmsg_lnxind_wlansniffrm_signal 0x6041
+#define DIDmsg_lnxind_wlansniffrm_noise 0x7041
+#define DIDmsg_lnxind_wlansniffrm_rate 0x8041
+#define DIDmsg_lnxind_wlansniffrm_istx 0x9041
+#define DIDmsg_lnxind_wlansniffrm_frmlen 0xA041
+
+typedef struct p80211msg_lnxind_wlansniffrm
+{
+ uint32_t msgcode;
+ uint32_t msglen;
+ uint8_t devname[WLAN_DEVNAMELEN_MAX];
+ p80211item_uint32_t hosttime;
+ p80211item_uint32_t mactime;
+ p80211item_uint32_t channel;
+ p80211item_uint32_t rssi;
+ p80211item_uint32_t sq;
+ p80211item_uint32_t signal;
+ p80211item_uint32_t noise;
+ p80211item_uint32_t rate;
+ p80211item_uint32_t istx;
+ p80211item_uint32_t frmlen;
+} __attribute__ ((packed)) p80211msg_lnxind_wlansniffrm_t;
+
/* Function prototypes */
int at76c503_do_probe(struct module *mod, struct usb_device *udev,