From ee8e365aa6395e721399127ccf3d28d269136f0e Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 14 Sep 2005 09:47:29 -0500 Subject: Ran scripts/Lindent on drivers/net/wireless/ipw2{1,2}00.{c,h} No other changes. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 2217 ++++++++++++++++++++-------------------- drivers/net/wireless/ipw2100.h | 156 ++- 2 files changed, 1155 insertions(+), 1218 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index ad7f8cd76db9..a15eef1c2a62 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -174,10 +174,9 @@ that only one external action is invoked at a time. #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" - /* Debugging stuff */ #ifdef CONFIG_IPW_DEBUG -#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */ +#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */ #endif MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -220,18 +219,18 @@ do { \ } while (0) #else #define IPW_DEBUG(level, message...) do {} while (0) -#endif /* CONFIG_IPW_DEBUG */ +#endif /* CONFIG_IPW_DEBUG */ #ifdef CONFIG_IPW_DEBUG static const char *command_types[] = { "undefined", - "unused", /* HOST_ATTENTION */ + "unused", /* HOST_ATTENTION */ "HOST_COMPLETE", - "unused", /* SLEEP */ - "unused", /* HOST_POWER_DOWN */ + "unused", /* SLEEP */ + "unused", /* HOST_POWER_DOWN */ "unused", "SYSTEM_CONFIG", - "unused", /* SET_IMR */ + "unused", /* SET_IMR */ "SSID", "MANDATORY_BSSID", "AUTHENTICATION_TYPE", @@ -277,17 +276,16 @@ static const char *command_types[] = { "GROUP_ORDINALS", "SHORT_RETRY_LIMIT", "LONG_RETRY_LIMIT", - "unused", /* SAVE_CALIBRATION */ - "unused", /* RESTORE_CALIBRATION */ + "unused", /* SAVE_CALIBRATION */ + "unused", /* RESTORE_CALIBRATION */ "undefined", "undefined", "undefined", "HOST_PRE_POWER_DOWN", - "unused", /* HOST_INTERRUPT_COALESCING */ + "unused", /* HOST_INTERRUPT_COALESCING */ "undefined", "CARD_DISABLE_PHY_OFF", - "MSDU_TX_RATES" - "undefined", + "MSDU_TX_RATES" "undefined", "undefined", "SET_STATION_STAT_BITS", "CLEAR_STATIONS_STAT_BITS", @@ -298,7 +296,6 @@ static const char *command_types[] = { }; #endif - /* Pre-decl until we get the code solid and then we can clean it up */ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv); static void ipw2100_tx_send_data(struct ipw2100_priv *priv); @@ -321,11 +318,10 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv, static int ipw2100_ucode_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw); static void ipw2100_wx_event_work(struct ipw2100_priv *priv); -static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev); +static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev); static struct iw_handler_def ipw2100_wx_handler_def; - -static inline void read_register(struct net_device *dev, u32 reg, u32 *val) +static inline void read_register(struct net_device *dev, u32 reg, u32 * val) { *val = readl((void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val); @@ -337,13 +333,14 @@ static inline void write_register(struct net_device *dev, u32 reg, u32 val) IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val); } -static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val) +static inline void read_register_word(struct net_device *dev, u32 reg, + u16 * val) { *val = readw((void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val); } -static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val) +static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val) { *val = readb((void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val); @@ -355,14 +352,13 @@ static inline void write_register_word(struct net_device *dev, u32 reg, u16 val) IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val); } - static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val) { writeb(val, (void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val); } -static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 *val) +static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val) { write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, addr & IPW_REG_INDIRECT_ADDR_MASK); @@ -376,7 +372,7 @@ static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val) write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); } -static inline void read_nic_word(struct net_device *dev, u32 addr, u16 *val) +static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val) { write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, addr & IPW_REG_INDIRECT_ADDR_MASK); @@ -390,7 +386,7 @@ static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val) write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val); } -static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 *val) +static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val) { write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, addr & IPW_REG_INDIRECT_ADDR_MASK); @@ -416,7 +412,7 @@ static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val) } static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len, - const u8 *buf) + const u8 * buf) { u32 aligned_addr; u32 aligned_len; @@ -431,32 +427,30 @@ static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len, write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); for (i = dif_len; i < 4; i++, buf++) - write_register_byte( - dev, IPW_REG_INDIRECT_ACCESS_DATA + i, - *buf); + write_register_byte(dev, + IPW_REG_INDIRECT_ACCESS_DATA + i, + *buf); len -= dif_len; aligned_addr += 4; } /* read DWs through autoincrement registers */ - write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, - aligned_addr); + write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr); aligned_len = len & (~0x3); for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) - write_register( - dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *)buf); + write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf); /* copy the last nibble */ dif_len = len - aligned_len; write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); for (i = 0; i < dif_len; i++, buf++) - write_register_byte( - dev, IPW_REG_INDIRECT_ACCESS_DATA + i, *buf); + write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, + *buf); } static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len, - u8 *buf) + u8 * buf) { u32 aligned_addr; u32 aligned_len; @@ -471,39 +465,38 @@ static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len, write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); for (i = dif_len; i < 4; i++, buf++) - read_register_byte( - dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf); + read_register_byte(dev, + IPW_REG_INDIRECT_ACCESS_DATA + i, + buf); len -= dif_len; aligned_addr += 4; } /* read DWs through autoincrement registers */ - write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, - aligned_addr); + write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr); aligned_len = len & (~0x3); for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) - read_register(dev, IPW_REG_AUTOINCREMENT_DATA, - (u32 *)buf); + read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf); /* copy the last nibble */ dif_len = len - aligned_len; - write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, - aligned_addr); + write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); for (i = 0; i < dif_len; i++, buf++) - read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + - i, buf); + read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf); } static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev) { return (dev->base_addr && - (readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START)) + (readl + ((void __iomem *)(dev->base_addr + + IPW_REG_DOA_DEBUG_AREA_START)) == IPW_DATA_DOA_DEBUG_VALUE)); } static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, - void *val, u32 *len) + void *val, u32 * len) { struct ipw2100_ordinals *ordinals = &priv->ordinals; u32 addr; @@ -529,8 +522,8 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, return -EINVAL; } - read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2), - &addr); + read_nic_dword(priv->net_dev, + ordinals->table1_addr + (ord << 2), &addr); read_nic_dword(priv->net_dev, addr, val); *len = IPW_ORD_TAB_1_ENTRY_SIZE; @@ -543,8 +536,8 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, ord -= IPW_START_ORD_TAB_2; /* get the address of statistic */ - read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3), - &addr); + read_nic_dword(priv->net_dev, + ordinals->table2_addr + (ord << 3), &addr); /* get the second DW of statistics ; * two 16-bit words - first is length, second is count */ @@ -553,10 +546,10 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, &field_info); /* get each entry length */ - field_len = *((u16 *)&field_info); + field_len = *((u16 *) & field_info); /* get number of entries */ - field_count = *(((u16 *)&field_info) + 1); + field_count = *(((u16 *) & field_info) + 1); /* abort if no enought memory */ total_length = field_len * field_count; @@ -581,8 +574,8 @@ static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, return -EINVAL; } -static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val, - u32 *len) +static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val, + u32 * len) { struct ipw2100_ordinals *ordinals = &priv->ordinals; u32 addr; @@ -594,8 +587,8 @@ static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val, return -EINVAL; } - read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2), - &addr); + read_nic_dword(priv->net_dev, + ordinals->table1_addr + (ord << 2), &addr); write_nic_dword(priv->net_dev, addr, *val); @@ -612,7 +605,7 @@ static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 *val, } static char *snprint_line(char *buf, size_t count, - const u8 *data, u32 len, u32 ofs) + const u8 * data, u32 len, u32 ofs) { int out, i, j, l; char c; @@ -646,7 +639,7 @@ static char *snprint_line(char *buf, size_t count, return buf; } -static void printk_buf(int level, const u8 *data, u32 len) +static void printk_buf(int level, const u8 * data, u32 len) { char line[81]; u32 ofs = 0; @@ -662,8 +655,6 @@ static void printk_buf(int level, const u8 *data, u32 len) } } - - #define MAX_RESET_BACKOFF 10 static inline void schedule_reset(struct ipw2100_priv *priv) @@ -703,7 +694,7 @@ static inline void schedule_reset(struct ipw2100_priv *priv) #define HOST_COMPLETE_TIMEOUT (2 * HZ) static int ipw2100_hw_send_command(struct ipw2100_priv *priv, - struct host_command * cmd) + struct host_command *cmd) { struct list_head *element; struct ipw2100_tx_packet *packet; @@ -713,25 +704,28 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", command_types[cmd->host_command], cmd->host_command, cmd->host_command_length); - printk_buf(IPW_DL_HC, (u8*)cmd->host_command_parameters, + printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters, cmd->host_command_length); spin_lock_irqsave(&priv->low_lock, flags); if (priv->fatal_error) { - IPW_DEBUG_INFO("Attempt to send command while hardware in fatal error condition.\n"); + IPW_DEBUG_INFO + ("Attempt to send command while hardware in fatal error condition.\n"); err = -EIO; goto fail_unlock; } if (!(priv->status & STATUS_RUNNING)) { - IPW_DEBUG_INFO("Attempt to send command while hardware is not running.\n"); + IPW_DEBUG_INFO + ("Attempt to send command while hardware is not running.\n"); err = -EIO; goto fail_unlock; } if (priv->status & STATUS_CMD_ACTIVE) { - IPW_DEBUG_INFO("Attempt to send command while another command is pending.\n"); + IPW_DEBUG_INFO + ("Attempt to send command while another command is pending.\n"); err = -EBUSY; goto fail_unlock; } @@ -752,7 +746,8 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, /* initialize the firmware command packet */ packet->info.c_struct.cmd->host_command_reg = cmd->host_command; packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1; - packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length; + packet->info.c_struct.cmd->host_command_len_reg = + cmd->host_command_length; packet->info.c_struct.cmd->sequence = cmd->host_command_sequence; memcpy(packet->info.c_struct.cmd->host_command_params_reg, @@ -776,9 +771,11 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, * then there is a problem. */ - err = wait_event_interruptible_timeout( - priv->wait_command_queue, !(priv->status & STATUS_CMD_ACTIVE), - HOST_COMPLETE_TIMEOUT); + err = + wait_event_interruptible_timeout(priv->wait_command_queue, + !(priv-> + status & STATUS_CMD_ACTIVE), + HOST_COMPLETE_TIMEOUT); if (err == 0) { IPW_DEBUG_INFO("Command completion failed out after %dms.\n", @@ -804,13 +801,12 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, return 0; - fail_unlock: + fail_unlock: spin_unlock_irqrestore(&priv->low_lock, flags); return err; } - /* * Verify the values and data access of the hardware * No locks needed or used. No functions called. @@ -825,8 +821,7 @@ static int ipw2100_verify(struct ipw2100_priv *priv) /* Domain 0 check - all values should be DOA_DEBUG */ for (address = IPW_REG_DOA_DEBUG_AREA_START; - address < IPW_REG_DOA_DEBUG_AREA_END; - address += sizeof(u32)) { + address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) { read_register(priv->net_dev, address, &data1); if (data1 != IPW_DATA_DOA_DEBUG_VALUE) return -EIO; @@ -898,7 +893,6 @@ static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state) return -EIO; } - /********************************************************************* Procedure : sw_reset_and_clock Purpose : Asserts s/w reset, asserts clock initialization @@ -975,17 +969,16 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv) if (priv->fatal_error) { IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after " - "fatal error %d. Interface must be brought down.\n", - priv->net_dev->name, priv->fatal_error); + "fatal error %d. Interface must be brought down.\n", + priv->net_dev->name, priv->fatal_error); return -EINVAL; } - #ifdef CONFIG_PM if (!ipw2100_firmware.version) { err = ipw2100_get_firmware(priv, &ipw2100_firmware); if (err) { IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", - priv->net_dev->name, err); + priv->net_dev->name, err); priv->fatal_error = IPW2100_ERR_FW_LOAD; goto fail; } @@ -994,7 +987,7 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv) err = ipw2100_get_firmware(priv, &ipw2100_firmware); if (err) { IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", - priv->net_dev->name, err); + priv->net_dev->name, err); priv->fatal_error = IPW2100_ERR_FW_LOAD; goto fail; } @@ -1005,21 +998,20 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv) err = sw_reset_and_clock(priv); if (err) { IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n", - priv->net_dev->name, err); + priv->net_dev->name, err); goto fail; } err = ipw2100_verify(priv); if (err) { IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n", - priv->net_dev->name, err); + priv->net_dev->name, err); goto fail; } /* Hold ARC */ write_nic_dword(priv->net_dev, - IPW_INTERNAL_REGISTER_HALT_AND_RESET, - 0x80000000); + IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000); /* allow ARC to run */ write_register(priv->net_dev, IPW_REG_RESET_REG, 0); @@ -1034,13 +1026,13 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv) /* release ARC */ write_nic_dword(priv->net_dev, - IPW_INTERNAL_REGISTER_HALT_AND_RESET, - 0x00000000); + IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000); /* s/w reset and clock stabilization (again!!!) */ err = sw_reset_and_clock(priv); if (err) { - printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n", + printk(KERN_ERR DRV_NAME + ": %s: sw_reset_and_clock failed: %d\n", priv->net_dev->name, err); goto fail; } @@ -1049,10 +1041,9 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv) err = ipw2100_fw_download(priv, &ipw2100_firmware); if (err) { IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n", - priv->net_dev->name, err); + priv->net_dev->name, err); goto fail; } - #ifndef CONFIG_PM /* * When the .resume method of the driver is called, the other @@ -1084,7 +1075,7 @@ static int ipw2100_download_firmware(struct ipw2100_priv *priv) return 0; - fail: + fail: ipw2100_release_firmware(priv, &ipw2100_firmware); return err; } @@ -1105,7 +1096,6 @@ static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv) write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0); } - static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv) { struct ipw2100_ordinals *ord = &priv->ordinals; @@ -1177,11 +1167,10 @@ static int ipw2100_get_hw_features(struct ipw2100_priv *priv) * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1 */ len = sizeof(addr); - if (ipw2100_get_ordinal( - priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, - &addr, &len)) { + if (ipw2100_get_ordinal + (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); + __LINE__); return -EIO; } @@ -1194,7 +1183,7 @@ static int ipw2100_get_hw_features(struct ipw2100_priv *priv) priv->eeprom_version = (val >> 24) & 0xFF; IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version); - /* + /* * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware * * notice that the EEPROM bit is reverse polarity, i.e. @@ -1206,8 +1195,7 @@ static int ipw2100_get_hw_features(struct ipw2100_priv *priv) priv->hw_features |= HW_FEATURE_RFKILL; IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n", - (priv->hw_features & HW_FEATURE_RFKILL) ? - "" : "not "); + (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not "); return 0; } @@ -1234,7 +1222,8 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv) * fw & dino ucode */ if (ipw2100_download_firmware(priv)) { - printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n", + printk(KERN_ERR DRV_NAME + ": %s: Failed to power on the adapter.\n", priv->net_dev->name); return -EIO; } @@ -1293,7 +1282,8 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv) i ? "SUCCESS" : "FAILED"); if (!i) { - printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n", + printk(KERN_WARNING DRV_NAME + ": %s: Firmware did not initialize.\n", priv->net_dev->name); return -EIO; } @@ -1326,7 +1316,6 @@ static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv) priv->fatal_error = 0; } - /* NOTE: Our interrupt is disabled when this method is called */ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) { @@ -1350,19 +1339,19 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) break; - } while(i--); + } while (i--); priv->status &= ~STATUS_RESET_PENDING; if (!i) { - IPW_DEBUG_INFO("exit - waited too long for master assert stop\n"); + IPW_DEBUG_INFO + ("exit - waited too long for master assert stop\n"); return -EIO; } write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_SW_RESET); - /* Reset any fatal_error conditions */ ipw2100_reset_fatalerror(priv); @@ -1415,7 +1404,6 @@ static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) return -EIO; } - static int ipw2100_enable_adapter(struct ipw2100_priv *priv) { struct host_command cmd = { @@ -1445,9 +1433,8 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv) err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED); if (err) { - IPW_DEBUG_INFO( - "%s: card not responding to init command.\n", - priv->net_dev->name); + IPW_DEBUG_INFO("%s: card not responding to init command.\n", + priv->net_dev->name); goto fail_up; } @@ -1456,7 +1443,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv) queue_delayed_work(priv->workqueue, &priv->hang_check, HZ / 2); } -fail_up: + fail_up: up(&priv->adapter_sem); return err; } @@ -1488,7 +1475,8 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) err = ipw2100_hw_phy_off(priv); if (err) - printk(KERN_WARNING DRV_NAME ": Error disabling radio %d\n", err); + printk(KERN_WARNING DRV_NAME + ": Error disabling radio %d\n", err); /* * If in D0-standby mode going directly to D3 may cause a @@ -1566,7 +1554,6 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) return 0; } - static int ipw2100_disable_adapter(struct ipw2100_priv *priv) { struct host_command cmd = { @@ -1593,19 +1580,21 @@ static int ipw2100_disable_adapter(struct ipw2100_priv *priv) err = ipw2100_hw_send_command(priv, &cmd); if (err) { - printk(KERN_WARNING DRV_NAME ": exit - failed to send CARD_DISABLE command\n"); + printk(KERN_WARNING DRV_NAME + ": exit - failed to send CARD_DISABLE command\n"); goto fail_up; } err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED); if (err) { - printk(KERN_WARNING DRV_NAME ": exit - card failed to change to DISABLED\n"); + printk(KERN_WARNING DRV_NAME + ": exit - card failed to change to DISABLED\n"); goto fail_up; } IPW_DEBUG_INFO("TODO: implement scan state machine\n"); -fail_up: + fail_up: up(&priv->adapter_sem); return err; } @@ -1709,8 +1698,9 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) (priv->status & STATUS_RESET_PENDING)) { /* Power cycle the card ... */ if (ipw2100_power_cycle_adapter(priv)) { - printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n", - priv->net_dev->name); + printk(KERN_WARNING DRV_NAME + ": %s: Could not cycle adapter.\n", + priv->net_dev->name); rc = 1; goto exit; } @@ -1719,8 +1709,9 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Load the firmware, start the clocks, etc. */ if (ipw2100_start_adapter(priv)) { - printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n", - priv->net_dev->name); + printk(KERN_ERR DRV_NAME + ": %s: Failed to start the firmware.\n", + priv->net_dev->name); rc = 1; goto exit; } @@ -1729,16 +1720,18 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Determine capabilities of this particular HW configuration */ if (ipw2100_get_hw_features(priv)) { - printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n", - priv->net_dev->name); + printk(KERN_ERR DRV_NAME + ": %s: Failed to determine HW features.\n", + priv->net_dev->name); rc = 1; goto exit; } lock = LOCK_NONE; if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { - printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n", - priv->net_dev->name); + printk(KERN_ERR DRV_NAME + ": %s: Failed to clear ordinal lock.\n", + priv->net_dev->name); rc = 1; goto exit; } @@ -1764,7 +1757,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) * HOST_COMPLETE */ if (ipw2100_adapter_setup(priv)) { printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n", - priv->net_dev->name); + priv->net_dev->name); rc = 1; goto exit; } @@ -1773,20 +1766,19 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Enable the adapter - sends HOST_COMPLETE */ if (ipw2100_enable_adapter(priv)) { printk(KERN_ERR DRV_NAME ": " - "%s: failed in call to enable adapter.\n", - priv->net_dev->name); + "%s: failed in call to enable adapter.\n", + priv->net_dev->name); ipw2100_hw_stop_adapter(priv); rc = 1; goto exit; } - /* Start a scan . . . */ ipw2100_set_scan_options(priv); ipw2100_start_scan(priv); } - exit: + exit: return rc; } @@ -1802,8 +1794,7 @@ static void ipw2100_down(struct ipw2100_priv *priv) unsigned long flags; union iwreq_data wrqu = { .ap_addr = { - .sa_family = ARPHRD_ETHER - } + .sa_family = ARPHRD_ETHER} }; int associated = priv->status & STATUS_ASSOCIATED; @@ -1862,8 +1853,7 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv) unsigned long flags; union iwreq_data wrqu = { .ap_addr = { - .sa_family = ARPHRD_ETHER - } + .sa_family = ARPHRD_ETHER} }; int associated = priv->status & STATUS_ASSOCIATED; @@ -1894,7 +1884,6 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv) } - static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) { @@ -1904,7 +1893,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 txrate; u32 chan; char *txratename; - u8 bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN]; /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1918,16 +1907,15 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) essid, &essid_len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); + __LINE__); return; } len = sizeof(u32); - ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, - &txrate, &len); + ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); + __LINE__); return; } @@ -1935,19 +1923,18 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); + __LINE__); return; } len = ETH_ALEN; - ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); + ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", - __LINE__); + __LINE__); return; } memcpy(priv->ieee->bssid, bssid, ETH_ALEN); - switch (txrate) { case TX_RATE_1_MBIT: txratename = "1Mbps"; @@ -1974,7 +1961,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { - priv->essid_len = min((u8)essid_len, (u8)IW_ESSID_MAX_SIZE); + priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE); memcpy(priv->essid, essid, priv->essid_len); } priv->channel = chan; @@ -1986,7 +1973,6 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) queue_delayed_work(priv->workqueue, &priv->wx_event_work, HZ / 10); } - static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, int length, int batch_mode) { @@ -2001,8 +1987,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); if (ssid_len) - memcpy((char*)cmd.host_command_parameters, - essid, ssid_len); + memcpy((char *)cmd.host_command_parameters, essid, ssid_len); if (!batch_mode) { err = ipw2100_disable_adapter(priv); @@ -2014,7 +1999,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, * disable auto association -- so we cheat by setting a bogus SSID */ if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) { int i; - u8 *bogus = (u8*)cmd.host_command_parameters; + u8 *bogus = (u8 *) cmd.host_command_parameters; for (i = 0; i < IW_ESSID_MAX_SIZE; i++) bogus[i] = 0x18 + i; cmd.host_command_length = IW_ESSID_MAX_SIZE; @@ -2025,8 +2010,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, err = ipw2100_hw_send_command(priv, &cmd); if (!err) { - memset(priv->essid + ssid_len, 0, - IW_ESSID_MAX_SIZE - ssid_len); + memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len); memcpy(priv->essid, essid, ssid_len); priv->essid_len = ssid_len; } @@ -2071,7 +2055,7 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) { IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n", - priv->net_dev->name); + priv->net_dev->name); /* RF_KILL is now enabled (else we wouldn't be here) */ priv->status |= STATUS_RF_KILL_HW; @@ -2102,16 +2086,16 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status) #define IPW2100_HANDLER(v, f) { v, f, # v } struct ipw2100_status_indicator { int status; - void (*cb)(struct ipw2100_priv *priv, u32 status); + void (*cb) (struct ipw2100_priv * priv, u32 status); char *name; }; #else #define IPW2100_HANDLER(v, f) { v, f } struct ipw2100_status_indicator { int status; - void (*cb)(struct ipw2100_priv *priv, u32 status); + void (*cb) (struct ipw2100_priv * priv, u32 status); }; -#endif /* CONFIG_IPW_DEBUG */ +#endif /* CONFIG_IPW_DEBUG */ static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status) { @@ -2135,7 +2119,6 @@ static const struct ipw2100_status_indicator status_handlers[] = { IPW2100_HANDLER(-1, NULL) }; - static void isr_status_change(struct ipw2100_priv *priv, int status) { int i; @@ -2153,7 +2136,7 @@ static void isr_status_change(struct ipw2100_priv *priv, int status) for (i = 0; status_handlers[i].status != -1; i++) { if (status == status_handlers[i].status) { IPW_DEBUG_NOTIF("Status change: %s\n", - status_handlers[i].name); + status_handlers[i].name); if (status_handlers[i].cb) status_handlers[i].cb(priv, status); priv->wstats.status = status; @@ -2164,9 +2147,8 @@ static void isr_status_change(struct ipw2100_priv *priv, int status) IPW_DEBUG_NOTIF("unknown status received: %04x\n", status); } -static void isr_rx_complete_command( - struct ipw2100_priv *priv, - struct ipw2100_cmd_header *cmd) +static void isr_rx_complete_command(struct ipw2100_priv *priv, + struct ipw2100_cmd_header *cmd) { #ifdef CONFIG_IPW_DEBUG if (cmd->host_command_reg < ARRAY_SIZE(command_types)) { @@ -2196,10 +2178,8 @@ static const char *frame_types[] = { }; #endif - -static inline int ipw2100_alloc_skb( - struct ipw2100_priv *priv, - struct ipw2100_rx_packet *packet) +static inline int ipw2100_alloc_skb(struct ipw2100_priv *priv, + struct ipw2100_rx_packet *packet) { packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx)); if (!packet->skb) @@ -2215,7 +2195,6 @@ static inline int ipw2100_alloc_skb( return 0; } - #define SEARCH_ERROR 0xffffffff #define SEARCH_FAIL 0xfffffffe #define SEARCH_SUCCESS 0xfffffff0 @@ -2229,10 +2208,10 @@ static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv) if (priv->snapshot[0]) return 1; for (i = 0; i < 0x30; i++) { - priv->snapshot[i] = (u8*)kmalloc(0x1000, GFP_ATOMIC); + priv->snapshot[i] = (u8 *) kmalloc(0x1000, GFP_ATOMIC); if (!priv->snapshot[i]) { IPW_DEBUG_INFO("%s: Error allocating snapshot " - "buffer %d\n", priv->net_dev->name, i); + "buffer %d\n", priv->net_dev->name, i); while (i > 0) kfree(priv->snapshot[--i]); priv->snapshot[0] = NULL; @@ -2253,7 +2232,7 @@ static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv) priv->snapshot[0] = NULL; } -static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf, +static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf, size_t len, int mode) { u32 i, j; @@ -2270,9 +2249,9 @@ static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf, for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) { read_nic_dword(priv->net_dev, i, &tmp); if (mode == SEARCH_SNAPSHOT) - *(u32 *)SNAPSHOT_ADDR(i) = tmp; + *(u32 *) SNAPSHOT_ADDR(i) = tmp; if (ret == SEARCH_FAIL) { - d = (u8*)&tmp; + d = (u8 *) & tmp; for (j = 0; j < 4; j++) { if (*s != *d) { s = in_buf; @@ -2310,8 +2289,7 @@ static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 *in_buf, static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH]; #endif -static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, - int i) +static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) { #ifdef CONFIG_IPW_DEBUG_C3 struct ipw2100_status *status = &priv->status_queue.drv[i]; @@ -2346,9 +2324,9 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) break; - } while (j--); + } while (j--); - match = ipw2100_match_buf(priv, (u8*)status, + match = ipw2100_match_buf(priv, (u8 *) status, sizeof(struct ipw2100_status), SEARCH_SNAPSHOT); if (match < SEARCH_SUCCESS) @@ -2360,7 +2338,7 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, IPW_DEBUG_INFO("%s: No DMA status match in " "Firmware.\n", priv->net_dev->name); - printk_buf((u8*)priv->status_queue.drv, + printk_buf((u8 *) priv->status_queue.drv, sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH); #endif @@ -2401,17 +2379,15 @@ static inline void isr_rx(struct ipw2100_priv *priv, int i, } if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && - !(priv->status & STATUS_ASSOCIATED))) { + !(priv->status & STATUS_ASSOCIATED))) { IPW_DEBUG_DROP("Dropping packet while not associated.\n"); priv->wstats.discard.misc++; return; } - pci_unmap_single(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); + sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); skb_put(packet->skb, status->frame_size); @@ -2438,8 +2414,8 @@ static inline void isr_rx(struct ipw2100_priv *priv, int i, /* We need to allocate a new SKB and attach it to the RDB. */ if (unlikely(ipw2100_alloc_skb(priv, packet))) { printk(KERN_WARNING DRV_NAME ": " - "%s: Unable to allocate SKB onto RBD ring - disabling " - "adapter.\n", priv->net_dev->name); + "%s: Unable to allocate SKB onto RBD ring - disabling " + "adapter.\n", priv->net_dev->name); /* TODO: schedule adapter shutdown */ IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); } @@ -2534,11 +2510,11 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) /* Sync the DMA for the STATUS buffer so CPU is sure to get * the correct values */ - pci_dma_sync_single_for_cpu( - priv->pci_dev, - sq->nic + sizeof(struct ipw2100_status) * i, - sizeof(struct ipw2100_status), - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(priv->pci_dev, + sq->nic + + sizeof(struct ipw2100_status) * i, + sizeof(struct ipw2100_status), + PCI_DMA_FROMDEVICE); /* Sync the DMA for the RX buffer so CPU is sure to get * the correct values */ @@ -2552,8 +2528,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) } u = packet->rxp; - frame_type = sq->drv[i].status_fields & - STATUS_TYPE_MASK; + frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK; stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM; stats.len = sq->drv[i].frame_size; @@ -2562,16 +2537,14 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) stats.mask |= IEEE80211_STATMASK_RSSI; stats.freq = IEEE80211_24GHZ_BAND; - IPW_DEBUG_RX( - "%s: '%s' frame type received (%d).\n", - priv->net_dev->name, frame_types[frame_type], - stats.len); + IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n", + priv->net_dev->name, frame_types[frame_type], + stats.len); switch (frame_type) { case COMMAND_STATUS_VAL: /* Reset Rx watchdog */ - isr_rx_complete_command( - priv, &u->rx_data.command); + isr_rx_complete_command(priv, &u->rx_data.command); break; case STATUS_CHANGE_VAL: @@ -2588,12 +2561,10 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) #endif if (stats.len < sizeof(u->rx_data.header)) break; - switch (WLAN_FC_GET_TYPE(u->rx_data.header. - frame_ctl)) { + switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) { case IEEE80211_FTYPE_MGMT: ieee80211_rx_mgt(priv->ieee, - &u->rx_data.header, - &stats); + &u->rx_data.header, &stats); break; case IEEE80211_FTYPE_CTL: @@ -2607,7 +2578,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) break; } - increment: + increment: /* clear status field associated with this RBD */ rxq->drv[i].status.info.field = 0; @@ -2619,12 +2590,10 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) rxq->next = (i ? i : rxq->entries) - 1; write_register(priv->net_dev, - IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, - rxq->next); + IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next); } } - /* * __ipw2100_tx_process * @@ -2667,7 +2636,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv) static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) { struct ipw2100_bd_queue *txq = &priv->tx_queue; - struct ipw2100_bd *tbd; + struct ipw2100_bd *tbd; struct list_head *element; struct ipw2100_tx_packet *packet; int descriptors_used; @@ -2680,7 +2649,7 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) element = priv->fw_pend_list.next; packet = list_entry(element, struct ipw2100_tx_packet, list); - tbd = &txq->drv[packet->index]; + tbd = &txq->drv[packet->index]; /* Determine how many TBD entries must be finished... */ switch (packet->type) { @@ -2693,14 +2662,14 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) case DATA: /* DATA uses two slots; advance and loop position. */ descriptors_used = tbd->num_fragments; - frag_num = tbd->num_fragments - 1; + frag_num = tbd->num_fragments - 1; e = txq->oldest + frag_num; e %= txq->entries; break; default: printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n", - priv->net_dev->name); + priv->net_dev->name); return 0; } @@ -2716,13 +2685,12 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n", priv->net_dev->name); - /* + /* * txq->next is the index of the last packet written txq->oldest is * the index of the r is the index of the next packet to be read by * firmware */ - /* * Quick graphic to help you visualize the following * if / else statement @@ -2750,23 +2718,20 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) #ifdef CONFIG_IPW_DEBUG { int i = txq->oldest; - IPW_DEBUG_TX( - "TX%d V=%p P=%04X T=%04X L=%d\n", i, - &txq->drv[i], - (u32)(txq->nic + i * sizeof(struct ipw2100_bd)), - txq->drv[i].host_addr, - txq->drv[i].buf_length); + IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, + &txq->drv[i], + (u32) (txq->nic + i * sizeof(struct ipw2100_bd)), + txq->drv[i].host_addr, txq->drv[i].buf_length); if (packet->type == DATA) { i = (i + 1) % txq->entries; - IPW_DEBUG_TX( - "TX%d V=%p P=%04X T=%04X L=%d\n", i, - &txq->drv[i], - (u32)(txq->nic + i * - sizeof(struct ipw2100_bd)), - (u32)txq->drv[i].host_addr, - txq->drv[i].buf_length); + IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i, + &txq->drv[i], + (u32) (txq->nic + i * + sizeof(struct ipw2100_bd)), + (u32) txq->drv[i].host_addr, + txq->drv[i].buf_length); } } #endif @@ -2782,21 +2747,19 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) /* DATA packet; we have to unmap and free the SKB */ priv->ieee->stats.tx_packets++; for (i = 0; i < frag_num; i++) { - tbd = &txq->drv[(packet->index + 1 + i) % - txq->entries]; + tbd = &txq->drv[(packet->index + 1 + i) % txq->entries]; - IPW_DEBUG_TX( - "TX%d P=%08x L=%d\n", - (packet->index + 1 + i) % txq->entries, - tbd->host_addr, tbd->buf_length); + IPW_DEBUG_TX("TX%d P=%08x L=%d\n", + (packet->index + 1 + i) % txq->entries, + tbd->host_addr, tbd->buf_length); pci_unmap_single(priv->pci_dev, tbd->host_addr, - tbd->buf_length, - PCI_DMA_TODEVICE); + tbd->buf_length, PCI_DMA_TODEVICE); } - priv->ieee->stats.tx_bytes += packet->info.d_struct.txb->payload_size; + priv->ieee->stats.tx_bytes += + packet->info.d_struct.txb->payload_size; ieee80211_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; @@ -2808,8 +2771,8 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) if (priv->status & STATUS_ASSOCIATED && netif_queue_stopped(priv->net_dev)) { IPW_DEBUG_INFO(KERN_INFO - "%s: Waking net queue.\n", - priv->net_dev->name); + "%s: Waking net queue.\n", + priv->net_dev->name); netif_wake_queue(priv->net_dev); } @@ -2829,11 +2792,12 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) #ifdef CONFIG_IPW_DEBUG if (packet->info.c_struct.cmd->host_command_reg < sizeof(command_types) / sizeof(*command_types)) - IPW_DEBUG_TX( - "Command '%s (%d)' processed: %d.\n", - command_types[packet->info.c_struct.cmd->host_command_reg], - packet->info.c_struct.cmd->host_command_reg, - packet->info.c_struct.cmd->cmd_status_reg); + IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n", + command_types[packet->info.c_struct.cmd-> + host_command_reg], + packet->info.c_struct.cmd-> + host_command_reg, + packet->info.c_struct.cmd->cmd_status_reg); #endif list_add_tail(element, &priv->msg_free_list); @@ -2848,17 +2812,17 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) SET_STAT(&priv->txq_stat, txq->available); IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n", - jiffies - packet->jiffy_start); + jiffies - packet->jiffy_start); return (!list_empty(&priv->fw_pend_list)); } - static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv) { int i = 0; - while (__ipw2100_tx_process(priv) && i < 200) i++; + while (__ipw2100_tx_process(priv) && i < 200) + i++; if (i == 200) { printk(KERN_WARNING DRV_NAME ": " @@ -2867,7 +2831,6 @@ static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv) } } - static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) { struct list_head *element; @@ -2892,13 +2855,12 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) list_del(element); DEC_STAT(&priv->msg_pend_stat); - packet = list_entry(element, - struct ipw2100_tx_packet, list); + packet = list_entry(element, struct ipw2100_tx_packet, list); IPW_DEBUG_TX("using TBD at virt=%p, phys=%p\n", - &txq->drv[txq->next], - (void*)(txq->nic + txq->next * - sizeof(struct ipw2100_bd))); + &txq->drv[txq->next], + (void *)(txq->nic + txq->next * + sizeof(struct ipw2100_bd))); packet->index = txq->next; @@ -2911,8 +2873,8 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) * with f/w debug version */ tbd->num_fragments = 1; tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_COMMAND | - IPW_BD_STATUS_TX_INTERRUPT_ENABLE; + IPW_BD_STATUS_TX_FRAME_COMMAND | + IPW_BD_STATUS_TX_INTERRUPT_ENABLE; /* update TBD queue counters */ txq->next++; @@ -2934,7 +2896,6 @@ static void ipw2100_tx_send_commands(struct ipw2100_priv *priv) } } - /* * ipw2100_tx_send_data * @@ -2946,7 +2907,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) struct ipw2100_bd_queue *txq = &priv->tx_queue; struct ipw2100_bd *tbd; int next = txq->next; - int i = 0; + int i = 0; struct ipw2100_data_header *ipw_hdr; struct ieee80211_hdr_3addr *hdr; @@ -2958,20 +2919,18 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) * maintained between the r and w indexes */ element = priv->tx_pend_list.next; - packet = list_entry(element, struct ipw2100_tx_packet, list); + packet = list_entry(element, struct ipw2100_tx_packet, list); if (unlikely(1 + packet->info.d_struct.txb->nr_frags > IPW_MAX_BDS)) { /* TODO: Support merging buffers if more than * IPW_MAX_BDS are used */ - IPW_DEBUG_INFO( - "%s: Maximum BD theshold exceeded. " - "Increase fragmentation level.\n", - priv->net_dev->name); + IPW_DEBUG_INFO("%s: Maximum BD theshold exceeded. " + "Increase fragmentation level.\n", + priv->net_dev->name); } - if (txq->available <= 3 + - packet->info.d_struct.txb->nr_frags) { + if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) { IPW_DEBUG_TX("no room in tx_queue\n"); break; } @@ -2985,7 +2944,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) ipw_hdr = packet->info.d_struct.data; hdr = (struct ieee80211_hdr_3addr *)packet->info.d_struct.txb-> - fragments[0]->data; + fragments[0]->data; if (priv->ieee->iw_mode == IW_MODE_INFRA) { /* To DS: Addr1 = BSSID, Addr2 = SA, @@ -3007,7 +2966,8 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted; if (packet->info.d_struct.txb->nr_frags > 1) ipw_hdr->fragment_size = - packet->info.d_struct.txb->frag_size - IEEE80211_3ADDR_LEN; + packet->info.d_struct.txb->frag_size - + IEEE80211_3ADDR_LEN; else ipw_hdr->fragment_size = 0; @@ -3015,54 +2975,53 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) tbd->buf_length = sizeof(struct ipw2100_data_header); tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags; tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_802_3 | - IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; + IPW_BD_STATUS_TX_FRAME_802_3 | + IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; txq->next++; txq->next %= txq->entries; - IPW_DEBUG_TX( - "data header tbd TX%d P=%08x L=%d\n", - packet->index, tbd->host_addr, - tbd->buf_length); + IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n", + packet->index, tbd->host_addr, tbd->buf_length); #ifdef CONFIG_IPW_DEBUG if (packet->info.d_struct.txb->nr_frags > 1) IPW_DEBUG_FRAG("fragment Tx: %d frames\n", packet->info.d_struct.txb->nr_frags); #endif - for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) { - tbd = &txq->drv[txq->next]; + for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) { + tbd = &txq->drv[txq->next]; if (i == packet->info.d_struct.txb->nr_frags - 1) tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_802_3 | - IPW_BD_STATUS_TX_INTERRUPT_ENABLE; + IPW_BD_STATUS_TX_FRAME_802_3 | + IPW_BD_STATUS_TX_INTERRUPT_ENABLE; else tbd->status.info.field = - IPW_BD_STATUS_TX_FRAME_802_3 | - IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; + IPW_BD_STATUS_TX_FRAME_802_3 | + IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT; tbd->buf_length = packet->info.d_struct.txb-> - fragments[i]->len - IEEE80211_3ADDR_LEN; + fragments[i]->len - IEEE80211_3ADDR_LEN; - tbd->host_addr = pci_map_single( - priv->pci_dev, - packet->info.d_struct.txb->fragments[i]->data + - IEEE80211_3ADDR_LEN, - tbd->buf_length, - PCI_DMA_TODEVICE); + tbd->host_addr = pci_map_single(priv->pci_dev, + packet->info.d_struct. + txb->fragments[i]-> + data + + IEEE80211_3ADDR_LEN, + tbd->buf_length, + PCI_DMA_TODEVICE); - IPW_DEBUG_TX( - "data frag tbd TX%d P=%08x L=%d\n", - txq->next, tbd->host_addr, tbd->buf_length); + IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n", + txq->next, tbd->host_addr, + tbd->buf_length); - pci_dma_sync_single_for_device( - priv->pci_dev, tbd->host_addr, - tbd->buf_length, - PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(priv->pci_dev, + tbd->host_addr, + tbd->buf_length, + PCI_DMA_TODEVICE); txq->next++; txq->next %= txq->entries; - } + } txq->available -= 1 + packet->info.d_struct.txb->nr_frags; SET_STAT(&priv->txq_stat, txq->available); @@ -3078,7 +3037,7 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX, txq->next); } - return; + return; } static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) @@ -3106,11 +3065,9 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) if (inta & IPW2100_INTA_FATAL_ERROR) { printk(KERN_WARNING DRV_NAME - ": Fatal interrupt. Scheduling firmware restart.\n"); + ": Fatal interrupt. Scheduling firmware restart.\n"); priv->inta_other++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_FATAL_ERROR); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR); read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error); IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n", @@ -3125,11 +3082,10 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) } if (inta & IPW2100_INTA_PARITY_ERROR) { - printk(KERN_ERR DRV_NAME ": ***** PARITY ERROR INTERRUPT !!!! \n"); + printk(KERN_ERR DRV_NAME + ": ***** PARITY ERROR INTERRUPT !!!! \n"); priv->inta_other++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_PARITY_ERROR); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR); } if (inta & IPW2100_INTA_RX_TRANSFER) { @@ -3137,9 +3093,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) priv->rx_interrupts++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_RX_TRANSFER); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER); __ipw2100_rx_process(priv); __ipw2100_tx_complete(priv); @@ -3150,8 +3104,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) priv->tx_interrupts++; - write_register(dev, IPW_REG_INTA, - IPW2100_INTA_TX_TRANSFER); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER); __ipw2100_tx_complete(priv); ipw2100_tx_send_commands(priv); @@ -3161,9 +3114,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) if (inta & IPW2100_INTA_TX_COMPLETE) { IPW_DEBUG_ISR("TX complete\n"); priv->inta_other++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_TX_COMPLETE); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE); __ipw2100_tx_complete(priv); } @@ -3171,9 +3122,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) if (inta & IPW2100_INTA_EVENT_INTERRUPT) { /* ipw2100_handle_event(dev); */ priv->inta_other++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_EVENT_INTERRUPT); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT); } if (inta & IPW2100_INTA_FW_INIT_DONE) { @@ -3183,30 +3132,25 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) read_register(dev, IPW_REG_INTA, &tmp); if (tmp & (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) { - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_FATAL_ERROR | - IPW2100_INTA_PARITY_ERROR); + write_register(dev, IPW_REG_INTA, + IPW2100_INTA_FATAL_ERROR | + IPW2100_INTA_PARITY_ERROR); } - write_register(dev, IPW_REG_INTA, - IPW2100_INTA_FW_INIT_DONE); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE); } if (inta & IPW2100_INTA_STATUS_CHANGE) { IPW_DEBUG_ISR("Status change interrupt\n"); priv->inta_other++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_STATUS_CHANGE); + write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE); } if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) { IPW_DEBUG_ISR("slave host mode interrupt\n"); priv->inta_other++; - write_register( - dev, IPW_REG_INTA, - IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE); + write_register(dev, IPW_REG_INTA, + IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE); } priv->in_isr--; @@ -3217,9 +3161,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv) IPW_DEBUG_ISR("exit\n"); } - -static irqreturn_t ipw2100_interrupt(int irq, void *data, - struct pt_regs *regs) +static irqreturn_t ipw2100_interrupt(int irq, void *data, struct pt_regs *regs) { struct ipw2100_priv *priv = data; u32 inta, inta_mask; @@ -3227,7 +3169,7 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data, if (!data) return IRQ_NONE; - spin_lock(&priv->low_lock); + spin_lock(&priv->low_lock); /* We check to see if we should be ignoring interrupts before * we touch the hardware. During ucode load if we try and handle @@ -3261,10 +3203,10 @@ static irqreturn_t ipw2100_interrupt(int irq, void *data, ipw2100_disable_interrupts(priv); tasklet_schedule(&priv->irq_tasklet); - spin_unlock(&priv->low_lock); + spin_unlock(&priv->low_lock); return IRQ_HANDLED; - none: + none: spin_unlock(&priv->low_lock); return IRQ_NONE; } @@ -3294,10 +3236,8 @@ static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, packet->info.d_struct.txb = txb; - IPW_DEBUG_TX("Sending fragment (%d bytes):\n", - txb->fragments[0]->len); - printk_buf(IPW_DL_TX, txb->fragments[0]->data, - txb->fragments[0]->len); + IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len); + printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len); packet->jiffy_start = jiffies; @@ -3312,22 +3252,23 @@ static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev, spin_unlock_irqrestore(&priv->low_lock, flags); return 0; - fail_unlock: + fail_unlock: netif_stop_queue(dev); spin_unlock_irqrestore(&priv->low_lock, flags); return 1; } - static int ipw2100_msg_allocate(struct ipw2100_priv *priv) { int i, j, err = -EINVAL; void *v; dma_addr_t p; - priv->msg_buffers = (struct ipw2100_tx_packet *)kmalloc( - IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet), - GFP_KERNEL); + priv->msg_buffers = + (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE * + sizeof(struct + ipw2100_tx_packet), + GFP_KERNEL); if (!priv->msg_buffers) { printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg " "buffers.\n", priv->net_dev->name); @@ -3335,15 +3276,12 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) } for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - v = pci_alloc_consistent( - priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - &p); + v = pci_alloc_consistent(priv->pci_dev, + sizeof(struct ipw2100_cmd_header), &p); if (!v) { printk(KERN_ERR DRV_NAME ": " "%s: PCI alloc failed for msg " - "buffers.\n", - priv->net_dev->name); + "buffers.\n", priv->net_dev->name); err = -ENOMEM; break; } @@ -3352,7 +3290,7 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) priv->msg_buffers[i].type = COMMAND; priv->msg_buffers[i].info.c_struct.cmd = - (struct ipw2100_cmd_header*)v; + (struct ipw2100_cmd_header *)v; priv->msg_buffers[i].info.c_struct.cmd_phys = p; } @@ -3360,11 +3298,11 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_free_consistent( - priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[j].info.c_struct.cmd, - priv->msg_buffers[j].info.c_struct.cmd_phys); + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[j].info.c_struct.cmd, + priv->msg_buffers[j].info.c_struct. + cmd_phys); } kfree(priv->msg_buffers); @@ -3398,7 +3336,8 @@ static void ipw2100_msg_free(struct ipw2100_priv *priv) pci_free_consistent(priv->pci_dev, sizeof(struct ipw2100_cmd_header), priv->msg_buffers[i].info.c_struct.cmd, - priv->msg_buffers[i].info.c_struct.cmd_phys); + priv->msg_buffers[i].info.c_struct. + cmd_phys); } kfree(priv->msg_buffers); @@ -3424,6 +3363,7 @@ static ssize_t show_pci(struct device *d, struct device_attribute *attr, return out - buf; } + static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, @@ -3432,209 +3372,269 @@ static ssize_t show_cfg(struct device *d, struct device_attribute *attr, struct ipw2100_priv *p = d->driver_data; return sprintf(buf, "0x%08x\n", (int)p->config); } + static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); static ssize_t show_status(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *p = d->driver_data; return sprintf(buf, "0x%08x\n", (int)p->status); } + static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static ssize_t show_capability(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *p = d->driver_data; return sprintf(buf, "0x%08x\n", (int)p->capability); } -static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL); +static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL); #define IPW2100_REG(x) { IPW_ ##x, #x } static const struct { u32 addr; const char *name; } hw_data[] = { - IPW2100_REG(REG_GP_CNTRL), - IPW2100_REG(REG_GPIO), - IPW2100_REG(REG_INTA), - IPW2100_REG(REG_INTA_MASK), - IPW2100_REG(REG_RESET_REG), -}; +IPW2100_REG(REG_GP_CNTRL), + IPW2100_REG(REG_GPIO), + IPW2100_REG(REG_INTA), + IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),}; #define IPW2100_NIC(x, s) { x, #x, s } static const struct { u32 addr; const char *name; size_t size; } nic_data[] = { - IPW2100_NIC(IPW2100_CONTROL_REG, 2), - IPW2100_NIC(0x210014, 1), - IPW2100_NIC(0x210000, 1), -}; +IPW2100_NIC(IPW2100_CONTROL_REG, 2), + IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),}; #define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d } static const struct { u8 index; const char *name; const char *desc; } ord_data[] = { - IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), - IPW2100_ORD(STAT_TX_HOST_COMPLETE, "successful Host Tx's (MSDU)"), - IPW2100_ORD(STAT_TX_DIR_DATA, "successful Directed Tx's (MSDU)"), - IPW2100_ORD(STAT_TX_DIR_DATA1, "successful Directed Tx's (MSDU) @ 1MB"), - IPW2100_ORD(STAT_TX_DIR_DATA2, "successful Directed Tx's (MSDU) @ 2MB"), - IPW2100_ORD(STAT_TX_DIR_DATA5_5, "successful Directed Tx's (MSDU) @ 5_5MB"), - IPW2100_ORD(STAT_TX_DIR_DATA11, "successful Directed Tx's (MSDU) @ 11MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA1, "successful Non_Directed Tx's (MSDU) @ 1MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA2, "successful Non_Directed Tx's (MSDU) @ 2MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA5_5, "successful Non_Directed Tx's (MSDU) @ 5.5MB"), - IPW2100_ORD(STAT_TX_NODIR_DATA11, "successful Non_Directed Tx's (MSDU) @ 11MB"), - IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"), - IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"), - IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"), - IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"), - IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"), - IPW2100_ORD(STAT_TX_ASSN_RESP, "successful Association response Tx's"), - IPW2100_ORD(STAT_TX_REASSN, "successful Reassociation Tx's"), - IPW2100_ORD(STAT_TX_REASSN_RESP, "successful Reassociation response Tx's"), - IPW2100_ORD(STAT_TX_PROBE, "probes successfully transmitted"), - IPW2100_ORD(STAT_TX_PROBE_RESP, "probe responses successfully transmitted"), - IPW2100_ORD(STAT_TX_BEACON, "tx beacon"), - IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"), - IPW2100_ORD(STAT_TX_DISASSN, "successful Disassociation TX"), - IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"), - IPW2100_ORD(STAT_TX_DEAUTH, "successful Deauthentication TX"), - IPW2100_ORD(STAT_TX_TOTAL_BYTES, "Total successful Tx data bytes"), - IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"), - IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"), - IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"), - IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"), - IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"), - IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"), - IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,"times max tries in a hop failed"), - IPW2100_ORD(STAT_TX_DISASSN_FAIL, "times disassociation failed"), - IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"), - IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"), - IPW2100_ORD(STAT_RX_HOST, "packets passed to host"), - IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"), - IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"), - IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"), - IPW2100_ORD(STAT_RX_DIR_DATA5_5, "directed packets at 5.5MB"), - IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA,"nondirected packets"), - IPW2100_ORD(STAT_RX_NODIR_DATA1, "nondirected packets at 1MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA2, "nondirected packets at 2MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA5_5, "nondirected packets at 5.5MB"), - IPW2100_ORD(STAT_RX_NODIR_DATA11, "nondirected packets at 11MB"), - IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"), - IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), - IPW2100_ORD(STAT_RX_CTS, "Rx CTS"), - IPW2100_ORD(STAT_RX_ACK, "Rx ACK"), - IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"), - IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"), - IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"), - IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"), - IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"), - IPW2100_ORD(STAT_RX_REASSN_RESP, "Reassociation response Rx's"), - IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"), - IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"), - IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"), - IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"), - IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"), - IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"), - IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"), - IPW2100_ORD(STAT_RX_TOTAL_BYTES,"Total rx data bytes received"), - IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"), - IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"), - IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"), - IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"), - IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"), - IPW2100_ORD(STAT_RX_DUPLICATE1, "duplicate rx packets at 1MB"), - IPW2100_ORD(STAT_RX_DUPLICATE2, "duplicate rx packets at 2MB"), - IPW2100_ORD(STAT_RX_DUPLICATE5_5, "duplicate rx packets at 5.5MB"), - IPW2100_ORD(STAT_RX_DUPLICATE11, "duplicate rx packets at 11MB"), - IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"), - IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"), - IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"), - IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"), - IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, "rx frames with invalid protocol"), - IPW2100_ORD(SYS_BOOT_TIME, "Boot time"), - IPW2100_ORD(STAT_RX_NO_BUFFER, "rx frames rejected due to no buffer"), - IPW2100_ORD(STAT_RX_MISSING_FRAG, "rx frames dropped due to missing fragment"), - IPW2100_ORD(STAT_RX_ORPHAN_FRAG, "rx frames dropped due to non-sequential fragment"), - IPW2100_ORD(STAT_RX_ORPHAN_FRAME, "rx frames dropped due to unmatched 1st frame"), - IPW2100_ORD(STAT_RX_FRAG_AGEOUT, "rx frames dropped due to uncompleted frame"), - IPW2100_ORD(STAT_RX_ICV_ERRORS, "ICV errors during decryption"), - IPW2100_ORD(STAT_PSP_SUSPENSION,"times adapter suspended"), - IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"), - IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, "poll response timeouts"), - IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, "timeouts waiting for last {broad,multi}cast pkt"), - IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"), - IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"), - IPW2100_ORD(STAT_PSP_STATION_ID,"PSP Station ID"), - IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"), - IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,"current calculation of % missed beacons"), - IPW2100_ORD(STAT_PERCENT_RETRIES,"current calculation of % missed tx retries"), - IPW2100_ORD(ASSOCIATED_AP_PTR, "0 if not associated, else pointer to AP table entry"), - IPW2100_ORD(AVAILABLE_AP_CNT, "AP's decsribed in the AP table"), - IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"), - IPW2100_ORD(STAT_AP_ASSNS, "associations"), - IPW2100_ORD(STAT_ASSN_FAIL, "association failures"), - IPW2100_ORD(STAT_ASSN_RESP_FAIL,"failures due to response fail"), - IPW2100_ORD(STAT_FULL_SCANS, "full scans"), - IPW2100_ORD(CARD_DISABLED, "Card Disabled"), - IPW2100_ORD(STAT_ROAM_INHIBIT, "times roaming was inhibited due to activity"), - IPW2100_ORD(RSSI_AT_ASSN, "RSSI of associated AP at time of association"), - IPW2100_ORD(STAT_ASSN_CAUSE1, "reassociation: no probe response or TX on hop"), - IPW2100_ORD(STAT_ASSN_CAUSE2, "reassociation: poor tx/rx quality"), - IPW2100_ORD(STAT_ASSN_CAUSE3, "reassociation: tx/rx quality (excessive AP load"), - IPW2100_ORD(STAT_ASSN_CAUSE4, "reassociation: AP RSSI level"), - IPW2100_ORD(STAT_ASSN_CAUSE5, "reassociations due to load leveling"), - IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"), - IPW2100_ORD(STAT_AUTH_RESP_FAIL,"times authentication response failed"), - IPW2100_ORD(STATION_TABLE_CNT, "entries in association table"), - IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"), - IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"), - IPW2100_ORD(COUNTRY_CODE, "IEEE country code as recv'd from beacon"), - IPW2100_ORD(COUNTRY_CHANNELS, "channels suported by country"), - IPW2100_ORD(RESET_CNT, "adapter resets (warm)"), - IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"), - IPW2100_ORD(ANTENNA_DIVERSITY, "TRUE if antenna diversity is disabled"), - IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"), - IPW2100_ORD(OUR_FREQ, "current radio freq lower digits - channel ID"), - IPW2100_ORD(RTC_TIME, "current RTC time"), - IPW2100_ORD(PORT_TYPE, "operating mode"), - IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"), - IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"), - IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"), - IPW2100_ORD(BASIC_RATES, "basic tx rates"), - IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"), - IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"), - IPW2100_ORD(CAPABILITIES, "Management frame capability field"), - IPW2100_ORD(AUTH_TYPE, "Type of authentication"), - IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"), - IPW2100_ORD(RTS_THRESHOLD, "Min packet length for RTS handshaking"), - IPW2100_ORD(INT_MODE, "International mode"), - IPW2100_ORD(FRAGMENTATION_THRESHOLD, "protocol frag threshold"), - IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, "EEPROM offset in SRAM"), - IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, "EEPROM size in SRAM"), - IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"), - IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, "EEPROM IBSS 11b channel set"), - IPW2100_ORD(MAC_VERSION, "MAC Version"), - IPW2100_ORD(MAC_REVISION, "MAC Revision"), - IPW2100_ORD(RADIO_VERSION, "Radio Version"), - IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"), - IPW2100_ORD(UCODE_VERSION, "Ucode Version"), -}; - +IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"), + IPW2100_ORD(STAT_TX_HOST_COMPLETE, + "successful Host Tx's (MSDU)"), + IPW2100_ORD(STAT_TX_DIR_DATA, + "successful Directed Tx's (MSDU)"), + IPW2100_ORD(STAT_TX_DIR_DATA1, + "successful Directed Tx's (MSDU) @ 1MB"), + IPW2100_ORD(STAT_TX_DIR_DATA2, + "successful Directed Tx's (MSDU) @ 2MB"), + IPW2100_ORD(STAT_TX_DIR_DATA5_5, + "successful Directed Tx's (MSDU) @ 5_5MB"), + IPW2100_ORD(STAT_TX_DIR_DATA11, + "successful Directed Tx's (MSDU) @ 11MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA1, + "successful Non_Directed Tx's (MSDU) @ 1MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA2, + "successful Non_Directed Tx's (MSDU) @ 2MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA5_5, + "successful Non_Directed Tx's (MSDU) @ 5.5MB"), + IPW2100_ORD(STAT_TX_NODIR_DATA11, + "successful Non_Directed Tx's (MSDU) @ 11MB"), + IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"), + IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"), + IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"), + IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"), + IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"), + IPW2100_ORD(STAT_TX_ASSN_RESP, + "successful Association response Tx's"), + IPW2100_ORD(STAT_TX_REASSN, + "successful Reassociation Tx's"), + IPW2100_ORD(STAT_TX_REASSN_RESP, + "successful Reassociation response Tx's"), + IPW2100_ORD(STAT_TX_PROBE, + "probes successfully transmitted"), + IPW2100_ORD(STAT_TX_PROBE_RESP, + "probe responses successfully transmitted"), + IPW2100_ORD(STAT_TX_BEACON, "tx beacon"), + IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"), + IPW2100_ORD(STAT_TX_DISASSN, + "successful Disassociation TX"), + IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"), + IPW2100_ORD(STAT_TX_DEAUTH, + "successful Deauthentication TX"), + IPW2100_ORD(STAT_TX_TOTAL_BYTES, + "Total successful Tx data bytes"), + IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"), + IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"), + IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"), + IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"), + IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"), + IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"), + IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP, + "times max tries in a hop failed"), + IPW2100_ORD(STAT_TX_DISASSN_FAIL, + "times disassociation failed"), + IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"), + IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"), + IPW2100_ORD(STAT_RX_HOST, "packets passed to host"), + IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"), + IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"), + IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"), + IPW2100_ORD(STAT_RX_DIR_DATA5_5, + "directed packets at 5.5MB"), + IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"), + IPW2100_ORD(STAT_RX_NODIR_DATA1, + "nondirected packets at 1MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA2, + "nondirected packets at 2MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA5_5, + "nondirected packets at 5.5MB"), + IPW2100_ORD(STAT_RX_NODIR_DATA11, + "nondirected packets at 11MB"), + IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"), + IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS, + "Rx CTS"), + IPW2100_ORD(STAT_RX_ACK, "Rx ACK"), + IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"), + IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"), + IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"), + IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"), + IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"), + IPW2100_ORD(STAT_RX_REASSN_RESP, + "Reassociation response Rx's"), + IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"), + IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"), + IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"), + IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"), + IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"), + IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"), + IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"), + IPW2100_ORD(STAT_RX_TOTAL_BYTES, + "Total rx data bytes received"), + IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"), + IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"), + IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"), + IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"), + IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"), + IPW2100_ORD(STAT_RX_DUPLICATE1, + "duplicate rx packets at 1MB"), + IPW2100_ORD(STAT_RX_DUPLICATE2, + "duplicate rx packets at 2MB"), + IPW2100_ORD(STAT_RX_DUPLICATE5_5, + "duplicate rx packets at 5.5MB"), + IPW2100_ORD(STAT_RX_DUPLICATE11, + "duplicate rx packets at 11MB"), + IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"), + IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"), + IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"), + IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"), + IPW2100_ORD(STAT_RX_INVALID_PROTOCOL, + "rx frames with invalid protocol"), + IPW2100_ORD(SYS_BOOT_TIME, "Boot time"), + IPW2100_ORD(STAT_RX_NO_BUFFER, + "rx frames rejected due to no buffer"), + IPW2100_ORD(STAT_RX_MISSING_FRAG, + "rx frames dropped due to missing fragment"), + IPW2100_ORD(STAT_RX_ORPHAN_FRAG, + "rx frames dropped due to non-sequential fragment"), + IPW2100_ORD(STAT_RX_ORPHAN_FRAME, + "rx frames dropped due to unmatched 1st frame"), + IPW2100_ORD(STAT_RX_FRAG_AGEOUT, + "rx frames dropped due to uncompleted frame"), + IPW2100_ORD(STAT_RX_ICV_ERRORS, + "ICV errors during decryption"), + IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"), + IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"), + IPW2100_ORD(STAT_PSP_POLL_TIMEOUT, + "poll response timeouts"), + IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT, + "timeouts waiting for last {broad,multi}cast pkt"), + IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"), + IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"), + IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"), + IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"), + IPW2100_ORD(STAT_PERCENT_MISSED_BCNS, + "current calculation of % missed beacons"), + IPW2100_ORD(STAT_PERCENT_RETRIES, + "current calculation of % missed tx retries"), + IPW2100_ORD(ASSOCIATED_AP_PTR, + "0 if not associated, else pointer to AP table entry"), + IPW2100_ORD(AVAILABLE_AP_CNT, + "AP's decsribed in the AP table"), + IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"), + IPW2100_ORD(STAT_AP_ASSNS, "associations"), + IPW2100_ORD(STAT_ASSN_FAIL, "association failures"), + IPW2100_ORD(STAT_ASSN_RESP_FAIL, + "failures due to response fail"), + IPW2100_ORD(STAT_FULL_SCANS, "full scans"), + IPW2100_ORD(CARD_DISABLED, "Card Disabled"), + IPW2100_ORD(STAT_ROAM_INHIBIT, + "times roaming was inhibited due to activity"), + IPW2100_ORD(RSSI_AT_ASSN, + "RSSI of associated AP at time of association"), + IPW2100_ORD(STAT_ASSN_CAUSE1, + "reassociation: no probe response or TX on hop"), + IPW2100_ORD(STAT_ASSN_CAUSE2, + "reassociation: poor tx/rx quality"), + IPW2100_ORD(STAT_ASSN_CAUSE3, + "reassociation: tx/rx quality (excessive AP load"), + IPW2100_ORD(STAT_ASSN_CAUSE4, + "reassociation: AP RSSI level"), + IPW2100_ORD(STAT_ASSN_CAUSE5, + "reassociations due to load leveling"), + IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"), + IPW2100_ORD(STAT_AUTH_RESP_FAIL, + "times authentication response failed"), + IPW2100_ORD(STATION_TABLE_CNT, + "entries in association table"), + IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"), + IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"), + IPW2100_ORD(COUNTRY_CODE, + "IEEE country code as recv'd from beacon"), + IPW2100_ORD(COUNTRY_CHANNELS, + "channels suported by country"), + IPW2100_ORD(RESET_CNT, "adapter resets (warm)"), + IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"), + IPW2100_ORD(ANTENNA_DIVERSITY, + "TRUE if antenna diversity is disabled"), + IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"), + IPW2100_ORD(OUR_FREQ, + "current radio freq lower digits - channel ID"), + IPW2100_ORD(RTC_TIME, "current RTC time"), + IPW2100_ORD(PORT_TYPE, "operating mode"), + IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"), + IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"), + IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"), + IPW2100_ORD(BASIC_RATES, "basic tx rates"), + IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"), + IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"), + IPW2100_ORD(CAPABILITIES, + "Management frame capability field"), + IPW2100_ORD(AUTH_TYPE, "Type of authentication"), + IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"), + IPW2100_ORD(RTS_THRESHOLD, + "Min packet length for RTS handshaking"), + IPW2100_ORD(INT_MODE, "International mode"), + IPW2100_ORD(FRAGMENTATION_THRESHOLD, + "protocol frag threshold"), + IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS, + "EEPROM offset in SRAM"), + IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE, + "EEPROM size in SRAM"), + IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"), + IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS, + "EEPROM IBSS 11b channel set"), + IPW2100_ORD(MAC_VERSION, "MAC Version"), + IPW2100_ORD(MAC_REVISION, "MAC Revision"), + IPW2100_ORD(RADIO_VERSION, "Radio Version"), + IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"), + IPW2100_ORD(UCODE_VERSION, "Ucode Version"),}; static ssize_t show_registers(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { int i; struct ipw2100_priv *priv = dev_get_drvdata(d); struct net_device *dev = priv->net_dev; - char * out = buf; + char *out = buf; u32 val = 0; out += sprintf(out, "%30s [Address ] : Hex\n", "Register"); @@ -3647,15 +3647,15 @@ static ssize_t show_registers(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); +static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); static ssize_t show_hardware(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); struct net_device *dev = priv->net_dev; - char * out = buf; + char *out = buf; int i; out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry"); @@ -3688,11 +3688,11 @@ static ssize_t show_hardware(struct device *d, struct device_attribute *attr, } return out - buf; } -static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL); +static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL); static ssize_t show_memory(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); struct net_device *dev = priv->net_dev; @@ -3708,10 +3708,13 @@ static ssize_t show_memory(struct device *d, struct device_attribute *attr, /* sysfs provides us PAGE_SIZE buffer */ while (len < PAGE_SIZE - 128 && loop < 0x30000) { - if (priv->snapshot[0]) for (i = 0; i < 4; i++) - buffer[i] = *(u32 *)SNAPSHOT_ADDR(loop + i * 4); - else for (i = 0; i < 4; i++) - read_nic_dword(dev, loop + i * 4, &buffer[i]); + if (priv->snapshot[0]) + for (i = 0; i < 4; i++) + buffer[i] = + *(u32 *) SNAPSHOT_ADDR(loop + i * 4); + else + for (i = 0; i < 4; i++) + read_nic_dword(dev, loop + i * 4, &buffer[i]); if (priv->dump_raw) len += sprintf(buf + len, @@ -3719,26 +3722,26 @@ static ssize_t show_memory(struct device *d, struct device_attribute *attr, "%c%c%c%c" "%c%c%c%c" "%c%c%c%c", - ((u8*)buffer)[0x0], - ((u8*)buffer)[0x1], - ((u8*)buffer)[0x2], - ((u8*)buffer)[0x3], - ((u8*)buffer)[0x4], - ((u8*)buffer)[0x5], - ((u8*)buffer)[0x6], - ((u8*)buffer)[0x7], - ((u8*)buffer)[0x8], - ((u8*)buffer)[0x9], - ((u8*)buffer)[0xa], - ((u8*)buffer)[0xb], - ((u8*)buffer)[0xc], - ((u8*)buffer)[0xd], - ((u8*)buffer)[0xe], - ((u8*)buffer)[0xf]); + ((u8 *) buffer)[0x0], + ((u8 *) buffer)[0x1], + ((u8 *) buffer)[0x2], + ((u8 *) buffer)[0x3], + ((u8 *) buffer)[0x4], + ((u8 *) buffer)[0x5], + ((u8 *) buffer)[0x6], + ((u8 *) buffer)[0x7], + ((u8 *) buffer)[0x8], + ((u8 *) buffer)[0x9], + ((u8 *) buffer)[0xa], + ((u8 *) buffer)[0xb], + ((u8 *) buffer)[0xc], + ((u8 *) buffer)[0xd], + ((u8 *) buffer)[0xe], + ((u8 *) buffer)[0xf]); else len += sprintf(buf + len, "%s\n", snprint_line(line, sizeof(line), - (u8*)buffer, 16, loop)); + (u8 *) buffer, 16, loop)); loop += 16; } @@ -3746,7 +3749,7 @@ static ssize_t show_memory(struct device *d, struct device_attribute *attr, } static ssize_t store_memory(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct ipw2100_priv *priv = dev_get_drvdata(d); struct net_device *dev = priv->net_dev; @@ -3758,32 +3761,30 @@ static ssize_t store_memory(struct device *d, struct device_attribute *attr, if (p[0] == '1' || (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) { IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n", - dev->name); + dev->name); priv->dump_raw = 1; } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' && - tolower(p[1]) == 'f')) { + tolower(p[1]) == 'f')) { IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n", - dev->name); + dev->name); priv->dump_raw = 0; } else if (tolower(p[0]) == 'r') { - IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", - dev->name); + IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name); ipw2100_snapshot_free(priv); } else IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, " - "reset = clear memory snapshot\n", - dev->name); + "reset = clear memory snapshot\n", dev->name); return count; } -static DEVICE_ATTR(memory, S_IWUSR|S_IRUGO, show_memory, store_memory); +static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory); static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); u32 val = 0; @@ -3814,14 +3815,14 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, return len; } -static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL); +static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL); static ssize_t show_stats(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); - char * out = buf; + char *out = buf; out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n", priv->interrupts, priv->tx_interrupts, @@ -3835,8 +3836,8 @@ static ssize_t show_stats(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); +static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) { @@ -3864,19 +3865,18 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) priv->last_mode = priv->ieee->iw_mode; priv->net_dev->type = ARPHRD_IEEE80211; break; -#endif /* CONFIG_IPW2100_MONITOR */ +#endif /* CONFIG_IPW2100_MONITOR */ } priv->ieee->iw_mode = mode; #ifdef CONFIG_PM - /* Indicate ipw2100_download_firmware download firmware + /* Indicate ipw2100_download_firmware download firmware * from disk instead of memory. */ ipw2100_firmware.version = 0; #endif - printk(KERN_INFO "%s: Reseting on mode change.\n", - priv->net_dev->name); + printk(KERN_INFO "%s: Reseting on mode change.\n", priv->net_dev->name); priv->reset_backoff = 0; schedule_reset(priv); @@ -3884,12 +3884,12 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) } static ssize_t show_internals(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); int len = 0; -#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" # y "\n", priv-> x) +#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x) if (priv->status & STATUS_ASSOCIATED) len += sprintf(buf + len, "connected: %lu\n", @@ -3897,52 +3897,54 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, else len += sprintf(buf + len, "not connected\n"); - DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], p); - DUMP_VAR(status, 08lx); - DUMP_VAR(config, 08lx); - DUMP_VAR(capability, 08lx); + DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p"); + DUMP_VAR(status, "08lx"); + DUMP_VAR(config, "08lx"); + DUMP_VAR(capability, "08lx"); - len += sprintf(buf + len, "last_rtc: %lu\n", (unsigned long)priv->last_rtc); + len += + sprintf(buf + len, "last_rtc: %lu\n", + (unsigned long)priv->last_rtc); - DUMP_VAR(fatal_error, d); - DUMP_VAR(stop_hang_check, d); - DUMP_VAR(stop_rf_kill, d); - DUMP_VAR(messages_sent, d); + DUMP_VAR(fatal_error, "d"); + DUMP_VAR(stop_hang_check, "d"); + DUMP_VAR(stop_rf_kill, "d"); + DUMP_VAR(messages_sent, "d"); - DUMP_VAR(tx_pend_stat.value, d); - DUMP_VAR(tx_pend_stat.hi, d); + DUMP_VAR(tx_pend_stat.value, "d"); + DUMP_VAR(tx_pend_stat.hi, "d"); - DUMP_VAR(tx_free_stat.value, d); - DUMP_VAR(tx_free_stat.lo, d); + DUMP_VAR(tx_free_stat.value, "d"); + DUMP_VAR(tx_free_stat.lo, "d"); - DUMP_VAR(msg_free_stat.value, d); - DUMP_VAR(msg_free_stat.lo, d); + DUMP_VAR(msg_free_stat.value, "d"); + DUMP_VAR(msg_free_stat.lo, "d"); - DUMP_VAR(msg_pend_stat.value, d); - DUMP_VAR(msg_pend_stat.hi, d); + DUMP_VAR(msg_pend_stat.value, "d"); + DUMP_VAR(msg_pend_stat.hi, "d"); - DUMP_VAR(fw_pend_stat.value, d); - DUMP_VAR(fw_pend_stat.hi, d); + DUMP_VAR(fw_pend_stat.value, "d"); + DUMP_VAR(fw_pend_stat.hi, "d"); - DUMP_VAR(txq_stat.value, d); - DUMP_VAR(txq_stat.lo, d); + DUMP_VAR(txq_stat.value, "d"); + DUMP_VAR(txq_stat.lo, "d"); - DUMP_VAR(ieee->scans, d); - DUMP_VAR(reset_backoff, d); + DUMP_VAR(ieee->scans, "d"); + DUMP_VAR(reset_backoff, "d"); return len; } -static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL); +static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL); static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); char essid[IW_ESSID_MAX_SIZE + 1]; u8 bssid[ETH_ALEN]; u32 chan = 0; - char * out = buf; + char *out = buf; int length; int ret; @@ -3976,8 +3978,8 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); +static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); #ifdef CONFIG_IPW_DEBUG static ssize_t show_debug_level(struct device_driver *d, char *buf) @@ -4000,27 +4002,26 @@ static ssize_t store_debug_level(struct device_driver *d, const char *buf, val = simple_strtoul(p, &p, 10); if (p == buf) IPW_DEBUG_INFO(DRV_NAME - ": %s is not in hex or decimal form.\n", buf); + ": %s is not in hex or decimal form.\n", buf); else ipw2100_debug_level = val; return strnlen(buf, count); } + static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, store_debug_level); -#endif /* CONFIG_IPW_DEBUG */ - +#endif /* CONFIG_IPW_DEBUG */ static ssize_t show_fatal_error(struct device *d, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); char *out = buf; int i; if (priv->fatal_error) - out += sprintf(out, "0x%08X\n", - priv->fatal_error); + out += sprintf(out, "0x%08X\n", priv->fatal_error); else out += sprintf(out, "0\n"); @@ -4038,24 +4039,26 @@ static ssize_t show_fatal_error(struct device *d, } static ssize_t store_fatal_error(struct device *d, - struct device_attribute *attr, const char *buf, size_t count) + struct device_attribute *attr, const char *buf, + size_t count) { struct ipw2100_priv *priv = dev_get_drvdata(d); schedule_reset(priv); return count; } -static DEVICE_ATTR(fatal_error, S_IWUSR|S_IRUGO, show_fatal_error, store_fatal_error); +static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error, + store_fatal_error); static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { struct ipw2100_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%d\n", priv->ieee->scan_age); } static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct ipw2100_priv *priv = dev_get_drvdata(d); struct net_device *dev = priv->net_dev; @@ -4078,8 +4081,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, } else val = simple_strtoul(p, &p, 10); if (p == buffer) { - IPW_DEBUG_INFO("%s: user supplied invalid value.\n", - dev->name); + IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); } else { priv->ieee->scan_age = val; IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); @@ -4088,11 +4090,11 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, IPW_DEBUG_INFO("exit\n"); return len; } -static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); +static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, - char *buf) + char *buf) { /* 0 - RF kill not enabled 1 - SW based RF kill active (sysfs) @@ -4100,7 +4102,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, 3 - Both HW and SW baed RF kill active */ struct ipw2100_priv *priv = (struct ipw2100_priv *)d->driver_data; int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) | - (rf_kill_active(priv) ? 0x2 : 0x0); + (rf_kill_active(priv) ? 0x2 : 0x0); return sprintf(buf, "%i\n", val); } @@ -4108,7 +4110,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) { if ((disable_radio ? 1 : 0) == (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) - return 0 ; + return 0; IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", disable_radio ? "OFF" : "ON"); @@ -4126,8 +4128,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) /* Make sure the RF_KILL check timer is running */ priv->stop_rf_kill = 0; cancel_delayed_work(&priv->rf_kill); - queue_delayed_work(priv->workqueue, &priv->rf_kill, - HZ); + queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ); } else schedule_reset(priv); } @@ -4137,14 +4138,14 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) } static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) + const char *buf, size_t count) { struct ipw2100_priv *priv = dev_get_drvdata(d); ipw_radio_kill_sw(priv, buf[0] == '1'); return count; } -static DEVICE_ATTR(rf_kill, S_IWUSR|S_IRUGO, show_rf_kill, store_rf_kill); +static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static struct attribute *ipw2100_sysfs_entries[] = { &dev_attr_hardware.attr, @@ -4168,7 +4169,6 @@ static struct attribute_group ipw2100_attribute_group = { .attrs = ipw2100_sysfs_entries, }; - static int status_queue_allocate(struct ipw2100_priv *priv, int entries) { struct ipw2100_status_queue *q = &priv->status_queue; @@ -4176,11 +4176,11 @@ static int status_queue_allocate(struct ipw2100_priv *priv, int entries) IPW_DEBUG_INFO("enter\n"); q->size = entries * sizeof(struct ipw2100_status); - q->drv = (struct ipw2100_status *)pci_alloc_consistent( - priv->pci_dev, q->size, &q->nic); + q->drv = + (struct ipw2100_status *)pci_alloc_consistent(priv->pci_dev, + q->size, &q->nic); if (!q->drv) { - IPW_DEBUG_WARNING( - "Can not allocate status queue.\n"); + IPW_DEBUG_WARNING("Can not allocate status queue.\n"); return -ENOMEM; } @@ -4196,9 +4196,9 @@ static void status_queue_free(struct ipw2100_priv *priv) IPW_DEBUG_INFO("enter\n"); if (priv->status_queue.drv) { - pci_free_consistent( - priv->pci_dev, priv->status_queue.size, - priv->status_queue.drv, priv->status_queue.nic); + pci_free_consistent(priv->pci_dev, priv->status_queue.size, + priv->status_queue.drv, + priv->status_queue.nic); priv->status_queue.drv = NULL; } @@ -4216,7 +4216,8 @@ static int bd_queue_allocate(struct ipw2100_priv *priv, q->size = entries * sizeof(struct ipw2100_bd); q->drv = pci_alloc_consistent(priv->pci_dev, q->size, &q->nic); if (!q->drv) { - IPW_DEBUG_INFO("can't allocate shared memory for buffer descriptors\n"); + IPW_DEBUG_INFO + ("can't allocate shared memory for buffer descriptors\n"); return -ENOMEM; } memset(q->drv, 0, q->size); @@ -4226,8 +4227,7 @@ static int bd_queue_allocate(struct ipw2100_priv *priv, return 0; } -static void bd_queue_free(struct ipw2100_priv *priv, - struct ipw2100_bd_queue *q) +static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q) { IPW_DEBUG_INFO("enter\n"); @@ -4235,21 +4235,21 @@ static void bd_queue_free(struct ipw2100_priv *priv, return; if (q->drv) { - pci_free_consistent(priv->pci_dev, - q->size, q->drv, q->nic); + pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic); q->drv = NULL; } IPW_DEBUG_INFO("exit\n"); } -static void bd_queue_initialize( - struct ipw2100_priv *priv, struct ipw2100_bd_queue * q, - u32 base, u32 size, u32 r, u32 w) +static void bd_queue_initialize(struct ipw2100_priv *priv, + struct ipw2100_bd_queue *q, u32 base, u32 size, + u32 r, u32 w) { IPW_DEBUG_INFO("enter\n"); - IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, (u32)q->nic); + IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv, + (u32) q->nic); write_register(priv->net_dev, base, q->nic); write_register(priv->net_dev, size, q->entries); @@ -4285,32 +4285,38 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH); if (err) { IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n", - priv->net_dev->name); + priv->net_dev->name); return err; } - priv->tx_buffers = (struct ipw2100_tx_packet *)kmalloc( - TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet), - GFP_ATOMIC); + priv->tx_buffers = + (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH * + sizeof(struct + ipw2100_tx_packet), + GFP_ATOMIC); if (!priv->tx_buffers) { - printk(KERN_ERR DRV_NAME ": %s: alloc failed form tx buffers.\n", + printk(KERN_ERR DRV_NAME + ": %s: alloc failed form tx buffers.\n", priv->net_dev->name); bd_queue_free(priv, &priv->tx_queue); return -ENOMEM; } for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { - v = pci_alloc_consistent( - priv->pci_dev, sizeof(struct ipw2100_data_header), &p); + v = pci_alloc_consistent(priv->pci_dev, + sizeof(struct ipw2100_data_header), + &p); if (!v) { - printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx " - "buffers.\n", priv->net_dev->name); + printk(KERN_ERR DRV_NAME + ": %s: PCI alloc failed for tx " "buffers.\n", + priv->net_dev->name); err = -ENOMEM; break; } priv->tx_buffers[i].type = DATA; - priv->tx_buffers[i].info.d_struct.data = (struct ipw2100_data_header*)v; + priv->tx_buffers[i].info.d_struct.data = + (struct ipw2100_data_header *)v; priv->tx_buffers[i].info.d_struct.data_phys = p; priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -4319,11 +4325,11 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_free_consistent( - priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[j].info.d_struct.data, - priv->tx_buffers[j].info.d_struct.data_phys); + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[j].info.d_struct.data, + priv->tx_buffers[j].info.d_struct. + data_phys); } kfree(priv->tx_buffers); @@ -4356,7 +4362,8 @@ static void ipw2100_tx_initialize(struct ipw2100_priv *priv) /* We simply drop any SKBs that have been queued for * transmit */ if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb); + ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } @@ -4394,15 +4401,17 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv) for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { if (priv->tx_buffers[i].info.d_struct.txb) { - ieee80211_txb_free(priv->tx_buffers[i].info.d_struct.txb); + ieee80211_txb_free(priv->tx_buffers[i].info.d_struct. + txb); priv->tx_buffers[i].info.d_struct.txb = NULL; } if (priv->tx_buffers[i].info.d_struct.data) - pci_free_consistent( - priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[i].info.d_struct.data, - priv->tx_buffers[i].info.d_struct.data_phys); + pci_free_consistent(priv->pci_dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[i].info.d_struct. + data, + priv->tx_buffers[i].info.d_struct. + data_phys); } kfree(priv->tx_buffers); @@ -4411,8 +4420,6 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv) IPW_DEBUG_INFO("exit\n"); } - - static int ipw2100_rx_allocate(struct ipw2100_priv *priv) { int i, j, err = -EINVAL; @@ -4542,14 +4549,13 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) int err; - err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, - mac, &length); + err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length); if (err) { IPW_DEBUG_INFO("MAC address read failed\n"); return -EIO; } IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN); @@ -4576,8 +4582,7 @@ static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode) IPW_DEBUG_INFO("enter\n"); if (priv->config & CFG_CUSTOM_MAC) { - memcpy(cmd.host_command_parameters, priv->mac_addr, - ETH_ALEN); + memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); } else memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr, @@ -4614,7 +4619,8 @@ static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type, if (!batch_mode) { err = ipw2100_disable_adapter(priv); if (err) { - printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", priv->net_dev->name, err); return err; } @@ -4629,7 +4635,6 @@ static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type, return err; } - static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel, int batch_mode) { @@ -4660,8 +4665,7 @@ static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel, err = ipw2100_hw_send_command(priv, &cmd); if (err) { - IPW_DEBUG_INFO("Failed to set channel to %d", - channel); + IPW_DEBUG_INFO("Failed to set channel to %d", channel); return err; } @@ -4703,15 +4707,14 @@ static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode) cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START; cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK | - IPW_CFG_BSS_MASK | - IPW_CFG_802_1x_ENABLE; + IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE; if (!(priv->config & CFG_LONG_PREAMBLE)) cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO; err = ipw2100_get_ordinal(priv, IPW_ORD_EEPROM_IBSS_11B_CHANNELS, - &ibss_mask, &len); + &ibss_mask, &len); if (err) ibss_mask = IPW_IBSS_11B_DEFAULT_MASK; @@ -4719,7 +4722,7 @@ static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode) cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask; /* 11b only */ - /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A;*/ + /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */ err = ipw2100_hw_send_command(priv, &cmd); if (err) @@ -4783,8 +4786,7 @@ static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate, return 0; } -static int ipw2100_set_power_mode(struct ipw2100_priv *priv, - int power_level) +static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level) { struct host_command cmd = { .host_command = POWER_MODE, @@ -4805,11 +4807,10 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, priv->power_mode = IPW_POWER_ENABLED | power_level; #ifdef CONFIG_IPW2100_TX_POWER - if (priv->port_type == IBSS && - priv->adhoc_power != DFTL_IBSS_TX_POWER) { + if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) { /* Set beacon interval */ cmd.host_command = TX_POWER_INDEX; - cmd.host_command_parameters[0] = (u32)priv->adhoc_power; + cmd.host_command_parameters[0] = (u32) priv->adhoc_power; err = ipw2100_hw_send_command(priv, &cmd); if (err) @@ -4820,7 +4821,6 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, return 0; } - static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold) { struct host_command cmd = { @@ -4925,8 +4925,7 @@ static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry) return 0; } - -static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid, +static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, int batch_mode) { struct host_command cmd = { @@ -4938,16 +4937,15 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 *bssid, #ifdef CONFIG_IPW_DEBUG if (bssid != NULL) - IPW_DEBUG_HC( - "MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], - bssid[5]); + IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], + bssid[5]); else IPW_DEBUG_HC("MANDATORY_BSSID: \n"); #endif /* if BSSID is empty then we disable mandatory bssid mode */ if (bssid != NULL) - memcpy((u8 *)cmd.host_command_parameters, bssid, ETH_ALEN); + memcpy((u8 *) cmd.host_command_parameters, bssid, ETH_ALEN); if (!batch_mode) { err = ipw2100_disable_adapter(priv); @@ -4997,8 +4995,7 @@ void x(struct ieee80211_assoc_frame *wpa_assoc) { struct ipw2100_wpa_assoc_frame frame; frame->fixed_ie_mask = IPW_WPA_CAPABILTIES | - IPW_WPA_LISTENINTERVAL | - IPW_WPA_AP_ADDRESS; + IPW_WPA_LISTENINTERVAL | IPW_WPA_AP_ADDRESS; frame->capab_info = wpa_assoc->capab_info; frame->lisen_interval = wpa_assoc->listent_interval; memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN); @@ -5011,18 +5008,15 @@ void x(struct ieee80211_assoc_frame *wpa_assoc) * the IEs from wpa_frame into frame. */ frame->var_ie_len = calculate_ie_len(wpa_assoc); - memcpy(frame->var_ie, wpa_assoc->variable, frame->var_ie_len); + memcpy(frame->var_ie, wpa_assoc->variable, frame->var_ie_len); ipw2100_set_wpa_ie(priv, &frame, 0); } #endif - - - static int ipw2100_set_wpa_ie(struct ipw2100_priv *, struct ipw2100_wpa_assoc_frame *, int) -__attribute__ ((unused)); + __attribute__ ((unused)); static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv, struct ipw2100_wpa_assoc_frame *wpa_frame, @@ -5076,7 +5070,7 @@ static int ipw2100_set_security_information(struct ipw2100_priv *priv, .host_command_length = sizeof(struct security_info_params) }; struct security_info_params *security = - (struct security_info_params *)&cmd.host_command_parameters; + (struct security_info_params *)&cmd.host_command_parameters; int err; memset(security, 0, sizeof(*security)); @@ -5094,25 +5088,25 @@ static int ipw2100_set_security_information(struct ipw2100_priv *priv, break; case SEC_LEVEL_1: security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER; + IPW_WEP104_CIPHER; break; case SEC_LEVEL_2: security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER | IPW_TKIP_CIPHER; + IPW_WEP104_CIPHER | IPW_TKIP_CIPHER; break; case SEC_LEVEL_2_CKIP: security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER | IPW_CKIP_CIPHER; + IPW_WEP104_CIPHER | IPW_CKIP_CIPHER; break; case SEC_LEVEL_3: security->allowed_ciphers = IPW_WEP40_CIPHER | - IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER; + IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER; break; } - IPW_DEBUG_HC( - "SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n", - security->auth_mode, security->allowed_ciphers, security_level); + IPW_DEBUG_HC + ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n", + security->auth_mode, security->allowed_ciphers, security_level); security->replay_counters_number = 0; @@ -5130,8 +5124,7 @@ static int ipw2100_set_security_information(struct ipw2100_priv *priv, return err; } -static int ipw2100_set_tx_power(struct ipw2100_priv *priv, - u32 tx_power) +static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power) { struct host_command cmd = { .host_command = TX_POWER_INDEX, @@ -5185,7 +5178,6 @@ static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, return 0; } - void ipw2100_queues_initialize(struct ipw2100_priv *priv) { ipw2100_tx_initialize(priv); @@ -5203,13 +5195,12 @@ void ipw2100_queues_free(struct ipw2100_priv *priv) int ipw2100_queues_allocate(struct ipw2100_priv *priv) { if (ipw2100_tx_allocate(priv) || - ipw2100_rx_allocate(priv) || - ipw2100_msg_allocate(priv)) + ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv)) goto fail; return 0; - fail: + fail: ipw2100_tx_free(priv); ipw2100_rx_free(priv); ipw2100_msg_free(priv); @@ -5235,7 +5226,8 @@ static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags, if (!batch_mode) { err = ipw2100_disable_adapter(priv); if (err) { - printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", priv->net_dev->name, err); return err; } @@ -5262,7 +5254,6 @@ struct ipw2100_wep_key { #define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4] #define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10] - /** * Set a the wep key * @@ -5287,11 +5278,11 @@ static int ipw2100_set_key(struct ipw2100_priv *priv, .host_command_sequence = 0, .host_command_length = sizeof(struct ipw2100_wep_key), }; - struct ipw2100_wep_key *wep_key = (void*)cmd.host_command_parameters; + struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters; int err; IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n", - idx, keylen, len); + idx, keylen, len); /* NOTE: We don't check cached values in case the firmware was reset * or some other problem is occuring. If the user is setting the key, @@ -5308,22 +5299,23 @@ static int ipw2100_set_key(struct ipw2100_priv *priv, /* Will be optimized out on debug not being configured in */ if (keylen == 0) IPW_DEBUG_WEP("%s: Clearing key %d\n", - priv->net_dev->name, wep_key->idx); + priv->net_dev->name, wep_key->idx); else if (keylen == 5) IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n", - priv->net_dev->name, wep_key->idx, wep_key->len, - WEP_STR_64(wep_key->key)); + priv->net_dev->name, wep_key->idx, wep_key->len, + WEP_STR_64(wep_key->key)); else IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128 - "\n", - priv->net_dev->name, wep_key->idx, wep_key->len, - WEP_STR_128(wep_key->key)); + "\n", + priv->net_dev->name, wep_key->idx, wep_key->len, + WEP_STR_128(wep_key->key)); if (!batch_mode) { err = ipw2100_disable_adapter(priv); /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */ if (err) { - printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", priv->net_dev->name, err); return err; } @@ -5347,7 +5339,7 @@ static int ipw2100_set_key_index(struct ipw2100_priv *priv, .host_command = WEP_KEY_INDEX, .host_command_sequence = 0, .host_command_length = 4, - .host_command_parameters = { idx }, + .host_command_parameters = {idx}, }; int err; @@ -5359,7 +5351,8 @@ static int ipw2100_set_key_index(struct ipw2100_priv *priv, if (!batch_mode) { err = ipw2100_disable_adapter(priv); if (err) { - printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n", + printk(KERN_ERR DRV_NAME + ": %s: Could not disable adapter %d\n", priv->net_dev->name, err); return err; } @@ -5374,9 +5367,7 @@ static int ipw2100_set_key_index(struct ipw2100_priv *priv, return err; } - -static int ipw2100_configure_security(struct ipw2100_priv *priv, - int batch_mode) +static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) { int i, err, auth_mode, sec_level, use_group; @@ -5390,8 +5381,9 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, } if (!priv->sec.enabled) { - err = ipw2100_set_security_information( - priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1); + err = + ipw2100_set_security_information(priv, IPW_AUTH_OPEN, + SEC_LEVEL_0, 0, 1); } else { auth_mode = IPW_AUTH_OPEN; if ((priv->sec.flags & SEC_AUTH_MODE) && @@ -5406,8 +5398,9 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, if (priv->sec.flags & SEC_UNICAST_GROUP) use_group = priv->sec.unicast_uses_group; - err = ipw2100_set_security_information( - priv, auth_mode, sec_level, use_group, 1); + err = + ipw2100_set_security_information(priv, auth_mode, sec_level, + use_group, 1); } if (err) @@ -5433,14 +5426,16 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, /* Always enable privacy so the Host can filter WEP packets if * encrypted data is sent up */ - err = ipw2100_set_wep_flags( - priv, priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, 1); + err = + ipw2100_set_wep_flags(priv, + priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, + 1); if (err) goto exit; priv->status &= ~STATUS_SECURITY_UPDATED; - exit: + exit: if (!batch_mode) ipw2100_enable_adapter(priv); @@ -5498,31 +5493,29 @@ static void shim__set_security(struct net_device *dev, priv->status |= STATUS_SECURITY_UPDATED; } - if (sec->flags & SEC_ENABLED && - priv->sec.enabled != sec->enabled) { + if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) { priv->sec.flags |= SEC_ENABLED; priv->sec.enabled = sec->enabled; priv->status |= STATUS_SECURITY_UPDATED; force_update = 1; } - if (sec->flags & SEC_LEVEL && - priv->sec.level != sec->level) { + if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) { priv->sec.level = sec->level; priv->sec.flags |= SEC_LEVEL; priv->status |= STATUS_SECURITY_UPDATED; } IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n", - priv->sec.flags & (1<<8) ? '1' : '0', - priv->sec.flags & (1<<7) ? '1' : '0', - priv->sec.flags & (1<<6) ? '1' : '0', - priv->sec.flags & (1<<5) ? '1' : '0', - priv->sec.flags & (1<<4) ? '1' : '0', - priv->sec.flags & (1<<3) ? '1' : '0', - priv->sec.flags & (1<<2) ? '1' : '0', - priv->sec.flags & (1<<1) ? '1' : '0', - priv->sec.flags & (1<<0) ? '1' : '0'); + priv->sec.flags & (1 << 8) ? '1' : '0', + priv->sec.flags & (1 << 7) ? '1' : '0', + priv->sec.flags & (1 << 6) ? '1' : '0', + priv->sec.flags & (1 << 5) ? '1' : '0', + priv->sec.flags & (1 << 4) ? '1' : '0', + priv->sec.flags & (1 << 3) ? '1' : '0', + priv->sec.flags & (1 << 2) ? '1' : '0', + priv->sec.flags & (1 << 1) ? '1' : '0', + priv->sec.flags & (1 << 0) ? '1' : '0'); /* As a temporary work around to enable WPA until we figure out why * wpa_supplicant toggles the security capability of the driver, which @@ -5531,7 +5524,7 @@ static void shim__set_security(struct net_device *dev, * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/ if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) ipw2100_configure_security(priv, 0); -done: + done: up(&priv->action_sem); } @@ -5556,7 +5549,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv) return 0; } -#endif /* CONFIG_IPW2100_MONITOR */ +#endif /* CONFIG_IPW2100_MONITOR */ err = ipw2100_read_mac_address(priv); if (err) @@ -5576,7 +5569,7 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv) return err; } - err = ipw2100_system_config(priv, batch_mode); + err = ipw2100_system_config(priv, batch_mode); if (err) return err; @@ -5614,8 +5607,10 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv) return err; if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - err = ipw2100_set_ibss_beacon_interval( - priv, priv->beacon_interval, batch_mode); + err = + ipw2100_set_ibss_beacon_interval(priv, + priv->beacon_interval, + batch_mode); if (err) return err; @@ -5625,18 +5620,17 @@ static int ipw2100_adapter_setup(struct ipw2100_priv *priv) } /* - err = ipw2100_set_fragmentation_threshold( - priv, priv->frag_threshold, batch_mode); - if (err) - return err; - */ + err = ipw2100_set_fragmentation_threshold( + priv, priv->frag_threshold, batch_mode); + if (err) + return err; + */ IPW_DEBUG_INFO("exit\n"); return 0; } - /************************************************************************* * * EXTERNALLY CALLED METHODS @@ -5669,7 +5663,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p) ipw2100_reset_adapter(priv); return 0; - done: + done: up(&priv->action_sem); return err; } @@ -5708,7 +5702,7 @@ static int ipw2100_close(struct net_device *dev) /* Flush the TX queue ... */ while (!list_empty(&priv->tx_pend_list)) { element = priv->tx_pend_list.next; - packet = list_entry(element, struct ipw2100_tx_packet, list); + packet = list_entry(element, struct ipw2100_tx_packet, list); list_del(element); DEC_STAT(&priv->tx_pend_stat); @@ -5726,8 +5720,6 @@ static int ipw2100_close(struct net_device *dev) return 0; } - - /* * TODO: Fix this function... its just wrong */ @@ -5747,7 +5739,6 @@ static void ipw2100_tx_timeout(struct net_device *dev) schedule_reset(priv); } - /* * TODO: reimplement it so that it reads statistics * from the adapter using ordinal tables @@ -5796,7 +5787,7 @@ static struct net_device_stats *ipw2100_stats(struct net_device *dev) struct ipw2100_param { u32 cmd; u8 sta_addr[ETH_ALEN]; - union { + union { struct { u8 name; u32 value; @@ -5805,16 +5796,16 @@ struct ipw2100_param { u32 len; u8 *data; } wpa_ie; - struct{ + struct { int command; - int reason_code; + int reason_code; } mlme; struct { u8 alg[IPW2100_CRYPT_ALG_NAME_LEN]; u8 set_tx; u32 err; u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ u16 key_len; u8 key[0]; } crypt; @@ -5824,7 +5815,8 @@ struct ipw2100_param { /* end of driver_ipw2100.c code */ -static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){ +static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) +{ struct ieee80211_device *ieee = priv->ieee; struct ieee80211_security sec = { @@ -5834,7 +5826,7 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){ ieee->wpa_enabled = value; - if (value){ + if (value) { sec.level = SEC_LEVEL_3; sec.enabled = 1; } else { @@ -5853,7 +5845,8 @@ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value){ #define AUTH_ALG_OPEN_SYSTEM 0x1 #define AUTH_ALG_SHARED_KEY 0x2 -static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){ +static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) +{ struct ieee80211_device *ieee = priv->ieee; struct ieee80211_security sec = { @@ -5861,7 +5854,7 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){ }; int ret = 0; - if (value & AUTH_ALG_SHARED_KEY){ + if (value & AUTH_ALG_SHARED_KEY) { sec.auth_mode = WLAN_AUTH_SHARED_KEY; ieee->open_wep = 0; } else { @@ -5877,72 +5870,73 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value){ return ret; } - -static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value){ +static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) +{ struct ipw2100_priv *priv = ieee80211_priv(dev); - int ret=0; + int ret = 0; - switch(name){ - case IPW2100_PARAM_WPA_ENABLED: - ret = ipw2100_wpa_enable(priv, value); - break; + switch (name) { + case IPW2100_PARAM_WPA_ENABLED: + ret = ipw2100_wpa_enable(priv, value); + break; - case IPW2100_PARAM_TKIP_COUNTERMEASURES: - priv->ieee->tkip_countermeasures=value; - break; + case IPW2100_PARAM_TKIP_COUNTERMEASURES: + priv->ieee->tkip_countermeasures = value; + break; - case IPW2100_PARAM_DROP_UNENCRYPTED: - priv->ieee->drop_unencrypted=value; - break; + case IPW2100_PARAM_DROP_UNENCRYPTED: + priv->ieee->drop_unencrypted = value; + break; - case IPW2100_PARAM_PRIVACY_INVOKED: - priv->ieee->privacy_invoked=value; - break; + case IPW2100_PARAM_PRIVACY_INVOKED: + priv->ieee->privacy_invoked = value; + break; - case IPW2100_PARAM_AUTH_ALGS: - ret = ipw2100_wpa_set_auth_algs(priv, value); - break; + case IPW2100_PARAM_AUTH_ALGS: + ret = ipw2100_wpa_set_auth_algs(priv, value); + break; - case IPW2100_PARAM_IEEE_802_1X: - priv->ieee->ieee802_1x=value; - break; + case IPW2100_PARAM_IEEE_802_1X: + priv->ieee->ieee802_1x = value; + break; - default: - printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n", - dev->name, name); - ret = -EOPNOTSUPP; + default: + printk(KERN_ERR DRV_NAME ": %s: Unknown WPA param: %d\n", + dev->name, name); + ret = -EOPNOTSUPP; } return ret; } -static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason){ +static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason) +{ struct ipw2100_priv *priv = ieee80211_priv(dev); - int ret=0; + int ret = 0; - switch(command){ - case IPW2100_MLME_STA_DEAUTH: - // silently ignore - break; + switch (command) { + case IPW2100_MLME_STA_DEAUTH: + // silently ignore + break; - case IPW2100_MLME_STA_DISASSOC: - ipw2100_disassociate_bssid(priv); - break; + case IPW2100_MLME_STA_DISASSOC: + ipw2100_disassociate_bssid(priv); + break; - default: - printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n", - dev->name, command); - ret = -EOPNOTSUPP; + default: + printk(KERN_ERR DRV_NAME ": %s: Unknown MLME request: %d\n", + dev->name, command); + ret = -EOPNOTSUPP; } return ret; } - void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, - char *wpa_ie, int wpa_ie_len){ + char *wpa_ie, int wpa_ie_len) +{ struct ipw2100_wpa_assoc_frame frame; @@ -5957,23 +5951,22 @@ void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, ipw2100_set_wpa_ie(priv, &frame, 0); } - static int ipw2100_wpa_set_wpa_ie(struct net_device *dev, - struct ipw2100_param *param, int plen){ + struct ipw2100_param *param, int plen) +{ struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; u8 *buf; - if (! ieee->wpa_enabled) - return -EOPNOTSUPP; + if (!ieee->wpa_enabled) + return -EOPNOTSUPP; if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || - (param->u.wpa_ie.len && - param->u.wpa_ie.data==NULL)) + (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) return -EINVAL; - if (param->u.wpa_ie.len){ + if (param->u.wpa_ie.len) { buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); if (buf == NULL) return -ENOMEM; @@ -5998,7 +5991,9 @@ static int ipw2100_wpa_set_wpa_ie(struct net_device *dev, /* implementation borrowed from hostap driver */ static int ipw2100_wpa_set_encryption(struct net_device *dev, - struct ipw2100_param *param, int param_len){ + struct ipw2100_param *param, + int param_len) +{ int ret = 0; struct ipw2100_priv *priv = ieee80211_priv(dev); @@ -6014,9 +6009,10 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, param->u.crypt.alg[IPW2100_CRYPT_ALG_NAME_LEN - 1] = '\0'; if (param_len != - (int) ((char *) param->u.crypt.key - (char *) param) + - param->u.crypt.key_len){ - IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, param->u.crypt.key_len); + (int)((char *)param->u.crypt.key - (char *)param) + + param->u.crypt.key_len) { + IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, + param->u.crypt.key_len); return -EINVAL; } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && @@ -6030,7 +6026,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, } if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt){ + if (crypt) { sec.enabled = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_ENABLED | SEC_LEVEL; @@ -6054,7 +6050,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, } if (ops == NULL) { IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n", - dev->name, param->u.crypt.alg); + dev->name, param->u.crypt.alg); param->u.crypt.err = IPW2100_CRYPT_ERR_UNKNOWN_ALG; ret = -EINVAL; goto done; @@ -6066,7 +6062,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, ieee80211_crypt_delayed_deinit(ieee, crypt); new_crypt = (struct ieee80211_crypt_data *) - kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL); + kmalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; goto done; @@ -6074,12 +6070,13 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); new_crypt->ops = ops; if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx); + new_crypt->priv = + new_crypt->ops->init(param->u.crypt.idx); if (new_crypt->priv == NULL) { kfree(new_crypt); param->u.crypt.err = - IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED; + IPW2100_CRYPT_ERR_CRYPT_INIT_FAILED; ret = -EINVAL; goto done; } @@ -6091,24 +6088,25 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, (*crypt)->ops->set_key(param->u.crypt.key, param->u.crypt.key_len, param->u.crypt.seq, (*crypt)->priv) < 0) { - IPW_DEBUG_INFO("%s: key setting failed\n", - dev->name); + IPW_DEBUG_INFO("%s: key setting failed\n", dev->name); param->u.crypt.err = IPW2100_CRYPT_ERR_KEY_SET_FAILED; ret = -EINVAL; goto done; } - if (param->u.crypt.set_tx){ + if (param->u.crypt.set_tx) { ieee->tx_keyidx = param->u.crypt.idx; sec.active_key = param->u.crypt.idx; sec.flags |= SEC_ACTIVE_KEY; } - if (ops->name != NULL){ + if (ops->name != NULL) { if (strcmp(ops->name, "WEP") == 0) { - memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, param->u.crypt.key_len); - sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; + memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, + param->u.crypt.key_len); + sec.key_sizes[param->u.crypt.idx] = + param->u.crypt.key_len; sec.flags |= (1 << param->u.crypt.idx); sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_1; @@ -6120,7 +6118,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, sec.level = SEC_LEVEL_3; } } - done: + done: if (ieee->set_security) ieee->set_security(ieee->dev, &sec); @@ -6131,8 +6129,7 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, * the callbacks structures used to initialize the 802.11 stack. */ if (ieee->reset_on_keychange && ieee->iw_mode != IW_MODE_INFRA && - ieee->reset_port && - ieee->reset_port(dev)) { + ieee->reset_port && ieee->reset_port(dev)) { IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name); param->u.crypt.err = IPW2100_CRYPT_ERR_CARD_CONF_FAILED; return -EINVAL; @@ -6141,11 +6138,11 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, return ret; } - -static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){ +static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p) +{ struct ipw2100_param *param; - int ret=0; + int ret = 0; IPW_DEBUG_IOCTL("wpa_supplicant: len=%d\n", p->length); @@ -6156,12 +6153,12 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){ if (param == NULL) return -ENOMEM; - if (copy_from_user(param, p->pointer, p->length)){ + if (copy_from_user(param, p->pointer, p->length)) { kfree(param); return -EFAULT; } - switch (param->cmd){ + switch (param->cmd) { case IPW2100_CMD_SET_WPA_PARAM: ret = ipw2100_wpa_set_param(dev, param->u.wpa_param.name, @@ -6182,8 +6179,9 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){ break; default: - printk(KERN_ERR DRV_NAME ": %s: Unknown WPA supplicant request: %d\n", - dev->name, param->cmd); + printk(KERN_ERR DRV_NAME + ": %s: Unknown WPA supplicant request: %d\n", dev->name, + param->cmd); ret = -EOPNOTSUPP; } @@ -6194,28 +6192,27 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p){ kfree(param); return ret; } -#endif /* CONFIG_IEEE80211_WPA */ +#endif /* CONFIG_IEEE80211_WPA */ static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { #ifdef CONFIG_IEEE80211_WPA - struct iwreq *wrq = (struct iwreq *) rq; - int ret=-1; - switch (cmd){ - case IPW2100_IOCTL_WPA_SUPPLICANT: + struct iwreq *wrq = (struct iwreq *)rq; + int ret = -1; + switch (cmd) { + case IPW2100_IOCTL_WPA_SUPPLICANT: ret = ipw2100_wpa_supplicant(dev, &wrq->u.data); return ret; - default: + default: return -EOPNOTSUPP; } -#endif /* CONFIG_IEEE80211_WPA */ +#endif /* CONFIG_IEEE80211_WPA */ return -EOPNOTSUPP; } - static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { @@ -6236,14 +6233,13 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev, static u32 ipw2100_ethtool_get_link(struct net_device *dev) { - struct ipw2100_priv *priv = ieee80211_priv(dev); - return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; + struct ipw2100_priv *priv = ieee80211_priv(dev); + return (priv->status & STATUS_ASSOCIATED) ? 1 : 0; } - static struct ethtool_ops ipw2100_ethtool_ops = { - .get_link = ipw2100_ethtool_get_link, - .get_drvinfo = ipw_ethtool_get_drvinfo, + .get_link = ipw2100_ethtool_get_link, + .get_drvinfo = ipw_ethtool_get_drvinfo, }; static void ipw2100_hang_check(void *adapter) @@ -6288,7 +6284,6 @@ static void ipw2100_hang_check(void *adapter) spin_unlock_irqrestore(&priv->low_lock, flags); } - static void ipw2100_rf_kill(void *adapter) { struct ipw2100_priv *priv = adapter; @@ -6313,7 +6308,7 @@ static void ipw2100_rf_kill(void *adapter) IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still " "enabled\n"); - exit_unlock: + exit_unlock: spin_unlock_irqrestore(&priv->low_lock, flags); } @@ -6321,11 +6316,10 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); /* Look into using netdev destructor to shutdown ieee80211? */ -static struct net_device *ipw2100_alloc_device( - struct pci_dev *pci_dev, - void __iomem *base_addr, - unsigned long mem_start, - unsigned long mem_len) +static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, + void __iomem * base_addr, + unsigned long mem_start, + unsigned long mem_len) { struct ipw2100_priv *priv; struct net_device *dev; @@ -6351,7 +6345,7 @@ static struct net_device *ipw2100_alloc_device( dev->wireless_handlers = &ipw2100_wx_handler_def; dev->get_wireless_stats = ipw2100_wx_wireless_stats; dev->set_mac_address = ipw2100_set_address; - dev->watchdog_timeo = 3*HZ; + dev->watchdog_timeo = 3 * HZ; dev->irq = 0; dev->base_addr = (unsigned long)base_addr; @@ -6364,22 +6358,19 @@ static struct net_device *ipw2100_alloc_device( * ends up causing problems. So, we just handle * the WX extensions through the ipw2100_ioctl interface */ - /* memset() puts everything to 0, so we only have explicitely set * those values that need to be something else */ /* If power management is turned on, default to AUTO mode */ priv->power_mode = IPW_POWER_AUTO; - - #ifdef CONFIG_IEEE80211_WPA priv->ieee->wpa_enabled = 0; priv->ieee->tkip_countermeasures = 0; priv->ieee->drop_unencrypted = 0; priv->ieee->privacy_invoked = 0; priv->ieee->ieee802_1x = 1; -#endif /* CONFIG_IEEE80211_WPA */ +#endif /* CONFIG_IEEE80211_WPA */ /* Set module parameters */ switch (mode) { @@ -6401,8 +6392,7 @@ static struct net_device *ipw2100_alloc_device( priv->status |= STATUS_RF_KILL_SW; if (channel != 0 && - ((channel >= REG_MIN_CHANNEL) && - (channel <= REG_MAX_CHANNEL))) { + ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) { priv->config |= CFG_STATIC_CHANNEL; priv->channel = channel; } @@ -6441,7 +6431,6 @@ static struct net_device *ipw2100_alloc_device( INIT_LIST_HEAD(&priv->fw_pend_list); INIT_STAT(&priv->fw_pend_stat); - #ifdef CONFIG_SOFTWARE_SUSPEND2 priv->workqueue = create_workqueue(DRV_NAME, 0); #else @@ -6535,7 +6524,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, return err; } - /* We disable the RETRY_TIMEOUT register (0x41) to keep + /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_read_config_dword(pci_dev, 0x40, &val); if ((val & 0x0000ff00) != 0) @@ -6566,12 +6555,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, ipw2100_queues_initialize(priv); err = request_irq(pci_dev->irq, - ipw2100_interrupt, SA_SHIRQ, - dev->name, priv); + ipw2100_interrupt, SA_SHIRQ, dev->name, priv); if (err) { printk(KERN_WARNING DRV_NAME - "Error calling request_irq: %d.\n", - pci_dev->irq); + "Error calling request_irq: %d.\n", pci_dev->irq); goto fail; } dev->irq = pci_dev->irq; @@ -6634,10 +6621,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, return 0; - fail_unlock: + fail_unlock: up(&priv->action_sem); - fail: + fail: if (dev) { if (registered) unregister_netdev(dev); @@ -6653,7 +6640,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, /* These are safe to call even if they weren't allocated */ ipw2100_queues_free(priv); - sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); + sysfs_remove_group(&pci_dev->dev.kobj, + &ipw2100_attribute_group); free_ieee80211(dev); pci_set_drvdata(pci_dev, NULL); @@ -6679,7 +6667,8 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) priv->status &= ~STATUS_INITIALIZED; dev = priv->net_dev; - sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); + sysfs_remove_group(&pci_dev->dev.kobj, + &ipw2100_attribute_group); #ifdef CONFIG_PM if (ipw2100_firmware.version) @@ -6721,7 +6710,6 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) IPW_DEBUG_INFO("exit\n"); } - #ifdef CONFIG_PM #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state) @@ -6732,8 +6720,7 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); struct net_device *dev = priv->net_dev; - IPW_DEBUG_INFO("%s: Going into suspend...\n", - dev->name); + IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name); down(&priv->action_sem); if (priv->status & STATUS_INITIALIZED) { @@ -6745,7 +6732,7 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) netif_device_detach(dev); pci_save_state(pci_dev); - pci_disable_device (pci_dev); + pci_disable_device(pci_dev); pci_set_power_state(pci_dev, PCI_D3hot); up(&priv->action_sem); @@ -6764,8 +6751,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev) down(&priv->action_sem); - IPW_DEBUG_INFO("%s: Coming out of suspend...\n", - dev->name); + IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name); pci_set_power_state(pci_dev, PCI_D0); pci_enable_device(pci_dev); @@ -6785,9 +6771,9 @@ static int ipw2100_resume(struct pci_dev *pci_dev) * the queue of needed */ netif_device_attach(dev); - /* Bring the device back up */ - if (!(priv->status & STATUS_RF_KILL_SW)) - ipw2100_up(priv, 0); + /* Bring the device back up */ + if (!(priv->status & STATUS_RF_KILL_SW)) + ipw2100_up(priv, 0); up(&priv->action_sem); @@ -6795,56 +6781,55 @@ static int ipw2100_resume(struct pci_dev *pci_dev) } #endif - #define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x } static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = { - IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */ - IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */ - IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */ - IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */ - IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */ - - IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */ - IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */ - IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */ - - IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */ - IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */ - IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */ - - IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */ + IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */ + IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */ + IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */ + IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */ + + IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */ + IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */ + IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */ + + IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */ + IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */ + IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */ + + IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */ {0,}, }; @@ -6861,7 +6846,6 @@ static struct pci_driver ipw2100_pci_driver = { #endif }; - /** * Initialize the ipw2100 driver/module * @@ -6893,7 +6877,6 @@ static int __init ipw2100_init(void) return ret; } - /** * Cleanup ipw2100 driver registration */ @@ -6949,7 +6932,6 @@ static int ipw2100_wx_get_name(struct net_device *dev, return 0; } - static int ipw2100_wx_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -6969,8 +6951,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev, /* if setting by freq convert to channel */ if (fwrq->e == 1) { - if ((fwrq->m >= (int) 2.412e8 && - fwrq->m <= (int) 2.487e8)) { + if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) { int f = fwrq->m / 100000; int c = 0; @@ -6986,17 +6967,16 @@ static int ipw2100_wx_set_freq(struct net_device *dev, if (fwrq->e > 0 || fwrq->m > 1000) return -EOPNOTSUPP; - else { /* Set the channel */ + else { /* Set the channel */ IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); err = ipw2100_set_channel(priv, fwrq->m, 0); } - done: + done: up(&priv->action_sem); return err; } - static int ipw2100_wx_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -7045,7 +7025,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev, case IW_MODE_MONITOR: err = ipw2100_switch_mode(priv, IW_MODE_MONITOR); break; -#endif /* CONFIG_IPW2100_MONITOR */ +#endif /* CONFIG_IPW2100_MONITOR */ case IW_MODE_ADHOC: err = ipw2100_switch_mode(priv, IW_MODE_ADHOC); break; @@ -7056,9 +7036,9 @@ static int ipw2100_wx_set_mode(struct net_device *dev, break; } -done: + done: up(&priv->action_sem); - return err; + return err; } static int ipw2100_wx_get_mode(struct net_device *dev, @@ -7077,7 +7057,6 @@ static int ipw2100_wx_get_mode(struct net_device *dev, return 0; } - #define POWER_MODES 5 /* Values are in microsecond */ @@ -7124,19 +7103,19 @@ static int ipw2100_wx_get_range(struct net_device *dev, /* ~5 Mb/s real (802.11b) */ range->throughput = 5 * 1000 * 1000; -// range->sensitivity; /* signal level threshold range */ +// range->sensitivity; /* signal level threshold range */ range->max_qual.qual = 100; /* TODO: Find real max RSSI and stick here */ range->max_qual.level = 0; range->max_qual.noise = 0; - range->max_qual.updated = 7; /* Updated all three */ + range->max_qual.updated = 7; /* Updated all three */ - range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ + range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM; range->avg_qual.noise = 0; - range->avg_qual.updated = 7; /* Updated all three */ + range->avg_qual.updated = 7; /* Updated all three */ range->num_bitrates = RATE_COUNT; @@ -7150,61 +7129,62 @@ static int ipw2100_wx_get_range(struct net_device *dev, range->max_frag = MAX_FRAG_THRESHOLD; range->min_pmp = period_duration[0]; /* Minimal PM period */ - range->max_pmp = period_duration[POWER_MODES-1];/* Maximal PM period */ - range->min_pmt = timeout_duration[POWER_MODES-1]; /* Minimal PM timeout */ - range->max_pmt = timeout_duration[0];/* Maximal PM timeout */ + range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */ + range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */ + range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */ - /* How to decode max/min PM period */ + /* How to decode max/min PM period */ range->pmp_flags = IW_POWER_PERIOD; - /* How to decode max/min PM period */ + /* How to decode max/min PM period */ range->pmt_flags = IW_POWER_TIMEOUT; /* What PM options are supported */ range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD; range->encoding_size[0] = 5; - range->encoding_size[1] = 13; /* Different token sizes */ - range->num_encoding_sizes = 2; /* Number of entry in the list */ - range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */ -// range->encoding_login_index; /* token index for login token */ + range->encoding_size[1] = 13; /* Different token sizes */ + range->num_encoding_sizes = 2; /* Number of entry in the list */ + range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */ +// range->encoding_login_index; /* token index for login token */ if (priv->ieee->iw_mode == IW_MODE_ADHOC) { range->txpower_capa = IW_TXPOW_DBM; range->num_txpower = IW_MAX_TXPOWER; - for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); i < IW_MAX_TXPOWER; - i++, level -= ((IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM) * 16) / - (IW_MAX_TXPOWER - 1)) + for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16); + i < IW_MAX_TXPOWER; + i++, level -= + ((IPW_TX_POWER_MAX_DBM - + IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1)) range->txpower[i] = level / 16; } else { range->txpower_capa = 0; range->num_txpower = 0; } - /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 16; -// range->retry_capa; /* What retry options are supported */ -// range->retry_flags; /* How to decode max/min retry limit */ -// range->r_time_flags; /* How to decode max/min retry life */ -// range->min_retry; /* Minimal number of retries */ -// range->max_retry; /* Maximal number of retries */ -// range->min_r_time; /* Minimal retry lifetime */ -// range->max_r_time; /* Maximal retry lifetime */ +// range->retry_capa; /* What retry options are supported */ +// range->retry_flags; /* How to decode max/min retry limit */ +// range->r_time_flags; /* How to decode max/min retry life */ +// range->min_retry; /* Minimal number of retries */ +// range->max_retry; /* Maximal number of retries */ +// range->min_r_time; /* Minimal retry lifetime */ +// range->max_r_time; /* Maximal retry lifetime */ - range->num_channels = FREQ_COUNT; + range->num_channels = FREQ_COUNT; val = 0; for (i = 0; i < FREQ_COUNT; i++) { // TODO: Include only legal frequencies for some countries -// if (local->channel_mask & (1 << i)) { - range->freq[val].i = i + 1; - range->freq[val].m = ipw2100_frequencies[i] * 100000; - range->freq[val].e = 1; - val++; -// } +// if (local->channel_mask & (1 << i)) { + range->freq[val].i = i + 1; + range->freq[val].m = ipw2100_frequencies[i] * 100000; + range->freq[val].e = 1; + val++; +// } if (val == IW_MAX_FREQUENCIES) - break; + break; } range->num_frequency = val; @@ -7259,7 +7239,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, wrqu->ap_addr.sa_data[4] & 0xff, wrqu->ap_addr.sa_data[5] & 0xff); - done: + done: up(&priv->action_sem); return err; } @@ -7276,8 +7256,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ - if (priv->config & CFG_STATIC_BSSID || - priv->status & STATUS_ASSOCIATED) { + if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) { wrqu->ap_addr.sa_family = ARPHRD_ETHER; memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN); } else @@ -7293,7 +7272,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw2100_priv *priv = ieee80211_priv(dev); - char *essid = ""; /* ANY */ + char *essid = ""; /* ANY */ int length = 0; int err = 0; @@ -7333,7 +7312,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, err = ipw2100_set_essid(priv, essid, length, 0); - done: + done: up(&priv->action_sem); return err; } @@ -7350,17 +7329,16 @@ static int ipw2100_wx_get_essid(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ - if (priv->config & CFG_STATIC_ESSID || - priv->status & STATUS_ASSOCIATED) { + if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { IPW_DEBUG_WX("Getting essid: '%s'\n", escape_essid(priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; - wrqu->essid.flags = 1; /* active */ + wrqu->essid.flags = 1; /* active */ } else { IPW_DEBUG_WX("Getting essid: ANY\n"); wrqu->essid.length = 0; - wrqu->essid.flags = 0; /* active */ + wrqu->essid.flags = 0; /* active */ } return 0; @@ -7379,9 +7357,9 @@ static int ipw2100_wx_set_nick(struct net_device *dev, if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; - wrqu->data.length = min((size_t)wrqu->data.length, sizeof(priv->nick)); + wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, extra, wrqu->data.length); + memcpy(priv->nick, extra, wrqu->data.length); IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick); @@ -7400,7 +7378,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev, wrqu->data.length = strlen(priv->nick) + 1; memcpy(extra, priv->nick, wrqu->data.length); - wrqu->data.flags = 1; /* active */ + wrqu->data.flags = 1; /* active */ IPW_DEBUG_WX("GET Nickname -> %s \n", extra); @@ -7442,12 +7420,11 @@ static int ipw2100_wx_set_rate(struct net_device *dev, err = ipw2100_set_tx_rates(priv, rate, 0); IPW_DEBUG_WX("SET Rate -> %04X \n", rate); - done: + done: up(&priv->action_sem); return err; } - static int ipw2100_wx_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -7495,7 +7472,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); - done: + done: up(&priv->action_sem); return err; } @@ -7520,8 +7497,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev, if (wrqu->rts.disabled) value = priv->rts_threshold | RTS_DISABLED; else { - if (wrqu->rts.value < 1 || - wrqu->rts.value > 2304) { + if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) { err = -EINVAL; goto done; } @@ -7531,7 +7507,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev, err = ipw2100_set_rts_threshold(priv, value); IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value); - done: + done: up(&priv->action_sem); return err; } @@ -7547,7 +7523,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED; - wrqu->rts.fixed = 1; /* no auto select */ + wrqu->rts.fixed = 1; /* no auto select */ /* If RTS is set to the default value, then it is disabled */ wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0; @@ -7575,7 +7551,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, return -EINVAL; value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 / - (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); + (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); } down(&priv->action_sem); @@ -7588,7 +7564,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, IPW_DEBUG_WX("SET TX Power -> %d \n", value); - done: + done: up(&priv->action_sem); return err; } @@ -7616,10 +7592,10 @@ static int ipw2100_wx_get_txpow(struct net_device *dev, wrqu->power.disabled = 0; wrqu->power.fixed = 1; wrqu->power.value = - (priv->tx_power * - (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) / - (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) + - IPW_TX_POWER_MIN_DBM; + (priv->tx_power * + (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) / + (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) + + IPW_TX_POWER_MIN_DBM; } wrqu->power.flags = IW_TXPOW_DBM; @@ -7684,8 +7660,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int err = 0; - if (wrqu->retry.flags & IW_RETRY_LIFETIME || - wrqu->retry.disabled) + if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) return -EINVAL; if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) @@ -7700,14 +7675,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev, if (wrqu->retry.flags & IW_RETRY_MIN) { err = ipw2100_set_short_retry(priv, wrqu->retry.value); IPW_DEBUG_WX("SET Short Retry Limit -> %d \n", - wrqu->retry.value); + wrqu->retry.value); goto done; } if (wrqu->retry.flags & IW_RETRY_MAX) { err = ipw2100_set_long_retry(priv, wrqu->retry.value); IPW_DEBUG_WX("SET Long Retry Limit -> %d \n", - wrqu->retry.value); + wrqu->retry.value); goto done; } @@ -7717,7 +7692,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev, IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value); - done: + done: up(&priv->action_sem); return err; } @@ -7732,10 +7707,9 @@ static int ipw2100_wx_get_retry(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); - wrqu->retry.disabled = 0; /* can't be disabled */ + wrqu->retry.disabled = 0; /* can't be disabled */ - if ((wrqu->retry.flags & IW_RETRY_TYPE) == - IW_RETRY_LIFETIME) + if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) return -EINVAL; if (wrqu->retry.flags & IW_RETRY_MAX) { @@ -7769,15 +7743,14 @@ static int ipw2100_wx_set_scan(struct net_device *dev, } IPW_DEBUG_WX("Initiating scan...\n"); - if (ipw2100_set_scan_options(priv) || - ipw2100_start_scan(priv)) { + if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) { IPW_DEBUG_WX("Start scan failed.\n"); /* TODO: Mark a scan as pending so when hardware initialized * a scan starts */ } - done: + done: up(&priv->action_sem); return err; } @@ -7794,7 +7767,6 @@ static int ipw2100_wx_get_scan(struct net_device *dev, return ieee80211_wx_get_scan(priv->ieee, info, wrqu, extra); } - /* * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c */ @@ -7823,8 +7795,8 @@ static int ipw2100_wx_get_encode(struct net_device *dev, } static int ipw2100_wx_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct ipw2100_priv *priv = ieee80211_priv(dev); int err = 0; @@ -7843,11 +7815,11 @@ static int ipw2100_wx_set_power(struct net_device *dev, } switch (wrqu->power.flags & IW_POWER_MODE) { - case IW_POWER_ON: /* If not specified */ - case IW_POWER_MODE: /* If set all mask */ - case IW_POWER_ALL_R: /* If explicitely state all */ + case IW_POWER_ON: /* If not specified */ + case IW_POWER_MODE: /* If set all mask */ + case IW_POWER_ALL_R: /* If explicitely state all */ break; - default: /* Otherwise we don't support it */ + default: /* Otherwise we don't support it */ IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", wrqu->power.flags); err = -EOPNOTSUPP; @@ -7859,18 +7831,17 @@ static int ipw2100_wx_set_power(struct net_device *dev, priv->power_mode = IPW_POWER_ENABLED | priv->power_mode; err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); - IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", - priv->power_mode); + IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); - done: + done: up(&priv->action_sem); return err; } static int ipw2100_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { /* * This can be called at any time. No action lock required @@ -7890,7 +7861,6 @@ static int ipw2100_wx_get_power(struct net_device *dev, return 0; } - /* * * IWPRIV handlers @@ -7923,7 +7893,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev, if (priv->ieee->iw_mode == IW_MODE_MONITOR) err = ipw2100_switch_mode(priv, priv->last_mode); } - done: + done: up(&priv->action_sem); return err; } @@ -7958,7 +7928,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, if (priv->power_mode != mode) err = ipw2100_set_power_mode(priv, mode); - done: + done: up(&priv->action_sem); return err; } @@ -7986,8 +7956,8 @@ static int ipw2100_wx_get_powermode(struct net_device *dev, "Power save level: %d (None)", level); break; case IPW_POWER_AUTO: - snprintf(extra, MAX_POWER_STRING, - "Power save level: %d (Auto)", 0); + snprintf(extra, MAX_POWER_STRING, + "Power save level: %d (Auto)", 0); break; default: timeout = timeout_duration[level - 1] / 1000; @@ -8004,7 +7974,6 @@ static int ipw2100_wx_get_powermode(struct net_device *dev, return 0; } - static int ipw2100_wx_set_preamble(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -8029,14 +7998,14 @@ static int ipw2100_wx_set_preamble(struct net_device *dev, err = ipw2100_system_config(priv, 0); -done: + done: up(&priv->action_sem); return err; } static int ipw2100_wx_get_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { /* * This can be called at any time. No action lock required @@ -8052,54 +8021,53 @@ static int ipw2100_wx_get_preamble(struct net_device *dev, return 0; } -static iw_handler ipw2100_wx_handlers[] = -{ - NULL, /* SIOCSIWCOMMIT */ - ipw2100_wx_get_name, /* SIOCGIWNAME */ - NULL, /* SIOCSIWNWID */ - NULL, /* SIOCGIWNWID */ - ipw2100_wx_set_freq, /* SIOCSIWFREQ */ - ipw2100_wx_get_freq, /* SIOCGIWFREQ */ - ipw2100_wx_set_mode, /* SIOCSIWMODE */ - ipw2100_wx_get_mode, /* SIOCGIWMODE */ - NULL, /* SIOCSIWSENS */ - NULL, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - ipw2100_wx_get_range, /* SIOCGIWRANGE */ - NULL, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ - NULL, /* SIOCSIWSPY */ - NULL, /* SIOCGIWSPY */ - NULL, /* SIOCGIWTHRSPY */ - NULL, /* SIOCWIWTHRSPY */ - ipw2100_wx_set_wap, /* SIOCSIWAP */ - ipw2100_wx_get_wap, /* SIOCGIWAP */ - NULL, /* -- hole -- */ - NULL, /* SIOCGIWAPLIST -- deprecated */ - ipw2100_wx_set_scan, /* SIOCSIWSCAN */ - ipw2100_wx_get_scan, /* SIOCGIWSCAN */ - ipw2100_wx_set_essid, /* SIOCSIWESSID */ - ipw2100_wx_get_essid, /* SIOCGIWESSID */ - ipw2100_wx_set_nick, /* SIOCSIWNICKN */ - ipw2100_wx_get_nick, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - ipw2100_wx_set_rate, /* SIOCSIWRATE */ - ipw2100_wx_get_rate, /* SIOCGIWRATE */ - ipw2100_wx_set_rts, /* SIOCSIWRTS */ - ipw2100_wx_get_rts, /* SIOCGIWRTS */ - ipw2100_wx_set_frag, /* SIOCSIWFRAG */ - ipw2100_wx_get_frag, /* SIOCGIWFRAG */ - ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */ - ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */ - ipw2100_wx_set_retry, /* SIOCSIWRETRY */ - ipw2100_wx_get_retry, /* SIOCGIWRETRY */ - ipw2100_wx_set_encode, /* SIOCSIWENCODE */ - ipw2100_wx_get_encode, /* SIOCGIWENCODE */ - ipw2100_wx_set_power, /* SIOCSIWPOWER */ - ipw2100_wx_get_power, /* SIOCGIWPOWER */ +static iw_handler ipw2100_wx_handlers[] = { + NULL, /* SIOCSIWCOMMIT */ + ipw2100_wx_get_name, /* SIOCGIWNAME */ + NULL, /* SIOCSIWNWID */ + NULL, /* SIOCGIWNWID */ + ipw2100_wx_set_freq, /* SIOCSIWFREQ */ + ipw2100_wx_get_freq, /* SIOCGIWFREQ */ + ipw2100_wx_set_mode, /* SIOCSIWMODE */ + ipw2100_wx_get_mode, /* SIOCGIWMODE */ + NULL, /* SIOCSIWSENS */ + NULL, /* SIOCGIWSENS */ + NULL, /* SIOCSIWRANGE */ + ipw2100_wx_get_range, /* SIOCGIWRANGE */ + NULL, /* SIOCSIWPRIV */ + NULL, /* SIOCGIWPRIV */ + NULL, /* SIOCSIWSTATS */ + NULL, /* SIOCGIWSTATS */ + NULL, /* SIOCSIWSPY */ + NULL, /* SIOCGIWSPY */ + NULL, /* SIOCGIWTHRSPY */ + NULL, /* SIOCWIWTHRSPY */ + ipw2100_wx_set_wap, /* SIOCSIWAP */ + ipw2100_wx_get_wap, /* SIOCGIWAP */ + NULL, /* -- hole -- */ + NULL, /* SIOCGIWAPLIST -- deprecated */ + ipw2100_wx_set_scan, /* SIOCSIWSCAN */ + ipw2100_wx_get_scan, /* SIOCGIWSCAN */ + ipw2100_wx_set_essid, /* SIOCSIWESSID */ + ipw2100_wx_get_essid, /* SIOCGIWESSID */ + ipw2100_wx_set_nick, /* SIOCSIWNICKN */ + ipw2100_wx_get_nick, /* SIOCGIWNICKN */ + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + ipw2100_wx_set_rate, /* SIOCSIWRATE */ + ipw2100_wx_get_rate, /* SIOCGIWRATE */ + ipw2100_wx_set_rts, /* SIOCSIWRTS */ + ipw2100_wx_get_rts, /* SIOCGIWRTS */ + ipw2100_wx_set_frag, /* SIOCSIWFRAG */ + ipw2100_wx_get_frag, /* SIOCGIWFRAG */ + ipw2100_wx_set_txpow, /* SIOCSIWTXPOW */ + ipw2100_wx_get_txpow, /* SIOCGIWTXPOW */ + ipw2100_wx_set_retry, /* SIOCSIWRETRY */ + ipw2100_wx_get_retry, /* SIOCGIWRETRY */ + ipw2100_wx_set_encode, /* SIOCSIWENCODE */ + ipw2100_wx_get_encode, /* SIOCGIWENCODE */ + ipw2100_wx_set_power, /* SIOCSIWPOWER */ + ipw2100_wx_get_power, /* SIOCGIWPOWER */ }; #define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV @@ -8113,55 +8081,49 @@ static const struct iw_priv_args ipw2100_private_args[] = { #ifdef CONFIG_IPW2100_MONITOR { - IPW2100_PRIV_SET_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor" - }, + IPW2100_PRIV_SET_MONITOR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, { - IPW2100_PRIV_RESET, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset" - }, -#endif /* CONFIG_IPW2100_MONITOR */ + IPW2100_PRIV_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, +#endif /* CONFIG_IPW2100_MONITOR */ { - IPW2100_PRIV_SET_POWER, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power" - }, + IPW2100_PRIV_SET_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"}, { - IPW2100_PRIV_GET_POWER, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, "get_power" - }, + IPW2100_PRIV_GET_POWER, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING, + "get_power"}, { - IPW2100_PRIV_SET_LONGPREAMBLE, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble" - }, + IPW2100_PRIV_SET_LONGPREAMBLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"}, { - IPW2100_PRIV_GET_LONGPREAMBLE, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble" - }, + IPW2100_PRIV_GET_LONGPREAMBLE, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"}, }; static iw_handler ipw2100_private_handler[] = { #ifdef CONFIG_IPW2100_MONITOR ipw2100_wx_set_promisc, ipw2100_wx_reset, -#else /* CONFIG_IPW2100_MONITOR */ +#else /* CONFIG_IPW2100_MONITOR */ NULL, NULL, -#endif /* CONFIG_IPW2100_MONITOR */ +#endif /* CONFIG_IPW2100_MONITOR */ ipw2100_wx_set_powermode, ipw2100_wx_get_powermode, ipw2100_wx_set_preamble, ipw2100_wx_get_preamble, }; -static struct iw_handler_def ipw2100_wx_handler_def = -{ +static struct iw_handler_def ipw2100_wx_handler_def = { .standard = ipw2100_wx_handlers, .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler), .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler), - .num_private_args = sizeof(ipw2100_private_args) / - sizeof(struct iw_priv_args), - .private = (iw_handler *)ipw2100_private_handler, + .num_private_args = sizeof(ipw2100_private_args) / + sizeof(struct iw_priv_args), + .private = (iw_handler *) ipw2100_private_handler, .private_args = (struct iw_priv_args *)ipw2100_private_args, }; @@ -8170,7 +8132,7 @@ static struct iw_handler_def ipw2100_wx_handler_def = * Called by /proc/net/wireless * Also called by SIOCGIWSTATS */ -static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) +static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) { enum { POOR = 30, @@ -8190,7 +8152,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) u32 ord_len = sizeof(u32); if (!priv) - return (struct iw_statistics *) NULL; + return (struct iw_statistics *)NULL; wstats = &priv->wstats; @@ -8207,7 +8169,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) wstats->qual.noise = 0; wstats->qual.updated = 7; wstats->qual.updated |= IW_QUAL_NOISE_INVALID | - IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; return wstats; } @@ -8215,7 +8177,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) &missed_beacons, &ord_len)) goto fail_get_ordinal; - /* If we don't have a connection the quality and level is 0*/ + /* If we don't have a connection the quality and level is 0 */ if (!(priv->status & STATUS_ASSOCIATED)) { wstats->qual.qual = 0; wstats->qual.level = 0; @@ -8232,10 +8194,10 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR; else if (rssi < 30) rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) / - 10 + GOOD; + 10 + GOOD; else rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) / - 10 + VERY_GOOD; + 10 + VERY_GOOD; if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES, &tx_retries, &ord_len)) @@ -8249,25 +8211,25 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; else if (tx_retries > 50) tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / - 15 + GOOD; + 15 + GOOD; else tx_qual = (50 - tx_retries) * - (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; + (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; if (missed_beacons > 50) beacon_qual = (60 - missed_beacons) * POOR / 10; else if (missed_beacons > 40) beacon_qual = (50 - missed_beacons) * (FAIR - POOR) / - 10 + POOR; + 10 + POOR; else if (missed_beacons > 32) beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) / - 18 + FAIR; + 18 + FAIR; else if (missed_beacons > 20) beacon_qual = (32 - missed_beacons) * - (VERY_GOOD - GOOD) / 20 + GOOD; + (VERY_GOOD - GOOD) / 20 + GOOD; else beacon_qual = (20 - missed_beacons) * - (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; + (PERFECT - VERY_GOOD) / 20 + VERY_GOOD; quality = min(beacon_qual, min(tx_qual, rssi_qual)); @@ -8290,7 +8252,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) wstats->qual.updated = 7; wstats->qual.updated |= IW_QUAL_NOISE_INVALID; - /* FIXME: this is percent and not a # */ + /* FIXME: this is percent and not a # */ wstats->miss.beacon = missed_beacons; if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES, @@ -8300,10 +8262,10 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device * dev) return wstats; - fail_get_ordinal: + fail_get_ordinal: IPW_DEBUG_WX("failed querying ordinals.\n"); - return (struct iw_statistics *) NULL; + return (struct iw_statistics *)NULL; } static void ipw2100_wx_event_work(struct ipw2100_priv *priv) @@ -8326,7 +8288,7 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) || priv->status & STATUS_RF_KILL_MASK || ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, - &priv->bssid, &len)) { + &priv->bssid, &len)) { memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } else { /* We now have the BSSID, so can finish setting to the full @@ -8351,7 +8313,8 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) /* This is a disassociation event, so kick the firmware to * look for another AP */ if (priv->config & CFG_STATIC_ESSID) - ipw2100_set_essid(priv, priv->essid, priv->essid_len, 0); + ipw2100_set_essid(priv, priv->essid, priv->essid_len, + 0); else ipw2100_set_essid(priv, NULL, 0, 0); up(&priv->action_sem); @@ -8374,7 +8337,6 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) #define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw" - /* BINARY FIRMWARE HEADER FORMAT @@ -8396,12 +8358,10 @@ struct ipw2100_fw_header { unsigned int uc_size; } __attribute__ ((packed)); - - static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) { struct ipw2100_fw_header *h = - (struct ipw2100_fw_header *)fw->fw_entry->data; + (struct ipw2100_fw_header *)fw->fw_entry->data; if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) { printk(KERN_WARNING DRV_NAME ": Firmware image not compatible " @@ -8420,7 +8380,6 @@ static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) return 0; } - static int ipw2100_get_firmware(struct ipw2100_priv *priv, struct ipw2100_fw *fw) { @@ -8428,7 +8387,7 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv, int rc; IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n", - priv->net_dev->name); + priv->net_dev->name); switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: @@ -8454,7 +8413,7 @@ static int ipw2100_get_firmware(struct ipw2100_priv *priv, return rc; } IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data, - fw->fw_entry->size); + fw->fw_entry->size); ipw2100_mod_firmware_load(fw); @@ -8470,7 +8429,6 @@ static void ipw2100_release_firmware(struct ipw2100_priv *priv, fw->fw_entry = NULL; } - static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, size_t max) { @@ -8479,8 +8437,7 @@ static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf, u32 tmp; int i; /* firmware version is an ascii string (max len of 14) */ - if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, - ver, &len)) + if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len)) return -EIO; tmp = max; if (len >= max) @@ -8497,8 +8454,7 @@ static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, u32 ver; u32 len = sizeof(ver); /* microcode version is a 32 bit integer */ - if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, - &ver, &len)) + if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len)) return -EIO; return snprintf(buf, max, "%08X", ver); } @@ -8506,8 +8462,7 @@ static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf, /* * On exit, the firmware will have been freed from the fw list */ -static int ipw2100_fw_download(struct ipw2100_priv *priv, - struct ipw2100_fw *fw) +static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw) { /* firmware is constructed of N contiguous entries, each entry is * structured as: @@ -8515,7 +8470,7 @@ static int ipw2100_fw_download(struct ipw2100_priv *priv, * offset sie desc * 0 4 address to write to * 4 2 length of data run - * 6 length data + * 6 length data */ unsigned int addr; unsigned short len; @@ -8524,12 +8479,12 @@ static int ipw2100_fw_download(struct ipw2100_priv *priv, unsigned int firmware_data_left = fw->fw.size; while (firmware_data_left > 0) { - addr = *(u32 *)(firmware_data); - firmware_data += 4; + addr = *(u32 *) (firmware_data); + firmware_data += 4; firmware_data_left -= 4; - len = *(u16 *)(firmware_data); - firmware_data += 2; + len = *(u16 *) (firmware_data); + firmware_data += 2; firmware_data_left -= 2; if (len > 32) { @@ -8540,7 +8495,7 @@ static int ipw2100_fw_download(struct ipw2100_priv *priv, } write_nic_memory(priv->net_dev, addr, len, firmware_data); - firmware_data += len; + firmware_data += len; firmware_data_left -= len; } @@ -8654,21 +8609,19 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv, for (i = 0; i < 30; i++) { /* Read alive response structure */ for (j = 0; - j < (sizeof(struct symbol_alive_response) >> 1); - j++) - read_nic_word(dev, 0x210004, - ((u16 *)&response) + j); + j < (sizeof(struct symbol_alive_response) >> 1); j++) + read_nic_word(dev, 0x210004, ((u16 *) & response) + j); - if ((response.cmd_id == 1) && - (response.ucode_valid == 0x1)) + if ((response.cmd_id == 1) && (response.ucode_valid == 0x1)) break; udelay(10); } if (i == 30) { - printk(KERN_ERR DRV_NAME ": %s: No response from Symbol - hw not alive\n", + printk(KERN_ERR DRV_NAME + ": %s: No response from Symbol - hw not alive\n", dev->name); - printk_buf(IPW_DL_ERROR, (u8*)&response, sizeof(response)); + printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response)); return -EIO; } diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index c9e99ce15d66..3eb5c384eaab 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -93,7 +93,6 @@ struct ipw2100_rx_packet; #define IPW_DL_IOCTL (1<<14) #define IPW_DL_RF_KILL (1<<17) - #define IPW_DL_MANAGE (1<<15) #define IPW_DL_FW (1<<16) @@ -156,7 +155,9 @@ extern const char *band_str[]; struct bd_status { union { - struct { u8 nlf:1, txType:2, intEnabled:1, reserved:4;} fields; + struct { + u8 nlf:1, txType:2, intEnabled:1, reserved:4; + } fields; u8 field; } info; } __attribute__ ((packed)); @@ -165,7 +166,7 @@ struct ipw2100_bd { u32 host_addr; u32 buf_length; struct bd_status status; - /* number of fragments for frame (should be set only for + /* number of fragments for frame (should be set only for * 1st TBD) */ u8 num_fragments; u8 reserved[6]; @@ -293,10 +294,10 @@ struct ipw2100_cmd_header { struct ipw2100_data_header { u32 host_command_reg; u32 host_command_reg1; - u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver + u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key - u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV + u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV u8 key[16]; u8 reserved[10]; // f/w reserved u8 src_addr[ETH_ALEN]; @@ -306,14 +307,13 @@ struct ipw2100_data_header { /* Host command data structure */ struct host_command { - u32 host_command; // COMMAND ID - u32 host_command1; // COMMAND ID + u32 host_command; // COMMAND ID + u32 host_command1; // COMMAND ID u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID) u32 host_command_length; // LENGTH u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS } __attribute__ ((packed)); - typedef enum { POWER_ON_RESET, EXIT_POWER_DOWN_RESET, @@ -328,17 +328,16 @@ enum { RX }; - struct ipw2100_tx_packet { int type; int index; union { - struct { /* COMMAND */ - struct ipw2100_cmd_header* cmd; + struct { /* COMMAND */ + struct ipw2100_cmd_header *cmd; dma_addr_t cmd_phys; } c_struct; - struct { /* DATA */ - struct ipw2100_data_header* data; + struct { /* DATA */ + struct ipw2100_data_header *data; dma_addr_t data_phys; struct ieee80211_txb *txb; } d_struct; @@ -348,7 +347,6 @@ struct ipw2100_tx_packet { struct list_head list; }; - struct ipw2100_rx_packet { struct ipw2100_rx *rxp; dma_addr_t dma_addr; @@ -432,13 +430,13 @@ enum { }; #define STATUS_POWERED (1<<0) -#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */ -#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */ -#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */ -#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */ -#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */ -#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */ -#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */ +#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */ +#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */ +#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */ +#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */ +#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */ +#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */ +#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */ #define STATUS_INT_ENABLED (1<<11) #define STATUS_RF_KILL_HW (1<<12) #define STATUS_RF_KILL_SW (1<<13) @@ -451,9 +449,7 @@ enum { #define STATUS_SCAN_COMPLETE (1<<26) #define STATUS_WX_EVENT_PENDING (1<<27) #define STATUS_RESET_PENDING (1<<29) -#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */ - - +#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */ /* Internal NIC states */ #define IPW_STATE_INITIALIZED (1<<0) @@ -469,11 +465,9 @@ enum { #define IPW_STATE_POWER_DOWN (1<<10) #define IPW_STATE_SCANNING (1<<11) - - -#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ -#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ -#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ +#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */ +#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ +#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ #define CFG_CUSTOM_MAC (1<<3) #define CFG_LONG_PREAMBLE (1<<4) #define CFG_ASSOCIATE (1<<6) @@ -482,13 +476,13 @@ enum { #define CFG_C3_DISABLED (1<<9) #define CFG_PASSIVE_SCAN (1<<10) -#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ -#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ +#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ +#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ struct ipw2100_priv { - int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ - int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ + int stop_hang_check; /* Set 1 when shutting down to kill hang_check */ + int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */ struct ieee80211_device *ieee; unsigned long status; @@ -519,8 +513,8 @@ struct ipw2100_priv { unsigned long hw_features; int hangs; u32 last_rtc; - int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */ - u8* snapshot[0x30]; + int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */ + u8 *snapshot[0x30]; u8 mandatory_bssid_mac[ETH_ALEN]; u8 mac_addr[ETH_ALEN]; @@ -531,7 +525,6 @@ struct ipw2100_priv { struct ieee80211_security sec; int messages_sent; - int short_retry_limit; int long_retry_limit; @@ -599,7 +592,6 @@ struct ipw2100_priv { wait_queue_head_t wait_command_queue; }; - /********************************************************* * Host Command -> From Driver to FW *********************************************************/ @@ -646,7 +638,6 @@ struct ipw2100_priv { #define CARD_DISABLE_PHY_OFF 61 #define MSDU_TX_RATES 62 - /* Rogue AP Detection */ #define SET_STATION_STAT_BITS 64 #define CLEAR_STATIONS_STAT_BITS 65 @@ -655,8 +646,6 @@ struct ipw2100_priv { #define DISASSOCIATION_BSSID 68 #define SET_WPA_IE 69 - - /* system configuration bit mask: */ #define IPW_CFG_MONITOR 0x00004 #define IPW_CFG_PREAMBLE_AUTO 0x00010 @@ -704,7 +693,7 @@ struct ipw2100_priv { #define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB) #define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1 #define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2 -#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3 +#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3 #define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4 #define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5 #define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16 @@ -784,9 +773,6 @@ struct ipw2100_priv { #define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli #define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli - - - #define IPW_HEADER_802_11_SIZE sizeof(struct ieee80211_hdr_3addr) #define IPW_MAX_80211_PAYLOAD_SIZE 2304U #define IPW_MAX_802_11_PAYLOAD_LENGTH 2312 @@ -843,8 +829,8 @@ struct ipw2100_rx { #define IPW_TX_POWER_MIN_DBM (-12) #define IPW_TX_POWER_MAX_DBM 16 -#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan -#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan +#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan +#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan #define REG_MIN_CHANNEL 0 #define REG_MAX_CHANNEL 14 @@ -856,7 +842,6 @@ struct ipw2100_rx { #define DIVERSITY_ANTENNA_A 1 // Use antenna A #define DIVERSITY_ANTENNA_B 2 // Use antenna B - #define HOST_COMMAND_WAIT 0 #define HOST_COMMAND_NO_WAIT 1 @@ -873,7 +858,6 @@ struct ipw2100_rx { #define TYPE_ASSOCIATION_REQUEST 0x0013 #define TYPE_REASSOCIATION_REQUEST 0x0014 - #define HW_FEATURE_RFKILL (0x0001) #define RF_KILLSWITCH_OFF (1) #define RF_KILLSWITCH_ON (0) @@ -895,7 +879,7 @@ struct ipw2100_rx { // Fixed size data: Ordinal Table 1 typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW // Transmit statistics - IPW_ORD_STAT_TX_HOST_REQUESTS = 1,// # of requested Host Tx's (MSDU) + IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU) IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU) IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU) @@ -905,42 +889,42 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB - IPW_ORD_STAT_TX_NODIR_DATA1 = 13,// # of successful Non_Directed Tx's (MSDU) @ 1MB + IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's - IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS - IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS - IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK - IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's + IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS + IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS + IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK + IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's - IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's + IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's - IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted + IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted - IPW_ORD_STAT_TX_BEACON, // # of tx beacon - IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM + IPW_ORD_STAT_TX_BEACON, // # of tx beacon + IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX - IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx - IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX + IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx + IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX - IPW_ORD_STAT_TX_TOTAL_BYTES = 41,// Total successful Tx data bytes - IPW_ORD_STAT_TX_RETRIES, // # of Tx retries - IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS - IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS - IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS - IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS + IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes + IPW_ORD_STAT_TX_RETRIES, // # of Tx retries + IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS + IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS + IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS + IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time - IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP,// # of times max tries in a hop failed + IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed - IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames - IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent + IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames + IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks // Receive statistics @@ -952,7 +936,7 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB - IPW_ORD_STAT_RX_NODIR_DATA = 71,// # of nondirected packets + IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB @@ -977,18 +961,18 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW IPW_ORD_STAT_RX_AUTH, // # of authentication Rx IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx - IPW_ORD_STAT_RX_TOTAL_BYTES = 101,// Total rx data bytes received - IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error - IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB - IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB - IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB - IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB + IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received + IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error + IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB + IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB + IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB + IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB - IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB - IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB - IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB - IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB - IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets + IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB + IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB + IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB + IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB + IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db @@ -1006,17 +990,17 @@ typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption // PSP Statistics - IPW_ORD_STAT_PSP_SUSPENSION = 137,// # of times adapter suspended + IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts - IPW_ORD_STAT_PSP_NONDIR_TIMEOUT,// # of timeouts waiting for last broadcast/muticast pkt + IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID // Association and roaming IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association - IPW_ORD_STAT_PERCENT_MISSED_BCNS,// current calculation of % missed beacons + IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated // AP table entry. set to 0 if not associated @@ -1151,7 +1135,7 @@ struct ipw2100_fw_chunk { }; struct ipw2100_fw_chunk_set { - const void *data; + const void *data; unsigned long size; }; @@ -1164,4 +1148,4 @@ struct ipw2100_fw { #define MAX_FW_VERSION_LEN 14 -#endif /* _IPW2100_H */ +#endif /* _IPW2100_H */ -- cgit v1.2.3-59-g8ed1b From a1e695adca76f5729224242e4f2f9f6ceb6863d1 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 4 Jul 2005 14:06:00 +0800 Subject: IPW_DEBUG has already included DRV_NAME, remove double prefix print. --- drivers/net/wireless/ipw2100.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index a15eef1c2a62..449c1c085fb9 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1833,7 +1833,7 @@ static void ipw2100_down(struct ipw2100_priv *priv) #ifdef ACPI_CSTATE_LIMIT_DEFINED if (priv->config & CFG_C3_DISABLED) { - IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n"); + IPW_DEBUG_INFO(": Resetting C3 transitions.\n"); acpi_set_cstate_limit(priv->cstate_limit); priv->config &= ~CFG_C3_DISABLED; } @@ -1858,8 +1858,7 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv) int associated = priv->status & STATUS_ASSOCIATED; spin_lock_irqsave(&priv->low_lock, flags); - IPW_DEBUG_INFO(DRV_NAME ": %s: Restarting adapter.\n", - priv->net_dev->name); + IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name); priv->resets++; priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); priv->status |= STATUS_SECURITY_UPDATED; @@ -2062,7 +2061,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status) #ifdef ACPI_CSTATE_LIMIT_DEFINED if (priv->config & CFG_C3_DISABLED) { - IPW_DEBUG_INFO(DRV_NAME ": Resetting C3 transitions.\n"); + IPW_DEBUG_INFO(": Resetting C3 transitions.\n"); acpi_set_cstate_limit(priv->cstate_limit); priv->config &= ~CFG_C3_DISABLED; } @@ -2300,11 +2299,11 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i) int limit; #endif - IPW_DEBUG_INFO(DRV_NAME ": PCI latency error detected at " - "0x%04zX.\n", i * sizeof(struct ipw2100_status)); + IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n", + i * sizeof(struct ipw2100_status)); #ifdef ACPI_CSTATE_LIMIT_DEFINED - IPW_DEBUG_INFO(DRV_NAME ": Disabling C3 transitions.\n"); + IPW_DEBUG_INFO(": Disabling C3 transitions.\n"); limit = acpi_get_cstate_limit(); if (limit > 2) { priv->cstate_limit = limit; @@ -4001,8 +4000,7 @@ static ssize_t store_debug_level(struct device_driver *d, const char *buf, } else val = simple_strtoul(p, &p, 10); if (p == buf) - IPW_DEBUG_INFO(DRV_NAME - ": %s is not in hex or decimal form.\n", buf); + IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf); else ipw2100_debug_level = val; -- cgit v1.2.3-59-g8ed1b From ea2b26e0a0264650e13acac8e66d315bb818897c Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 24 Aug 2005 21:25:16 -0500 Subject: Catch ipw2200 up to equivelancy with v1.0.1 This commit contains the following fixes: Fixed #559: iwconfig rate support (thanks to Florian Hackenberger) Improved link signal quality calculation (thanks to Bill Moss) Fixed a problem with sensitivity threshold during association Added iwpriv for turning forcing long preamble support: % iwpriv eth1 set_preamble 1|0 Fixed #542 and #377 support for short preamble Fixed locked BSSID reporting channel number (thanks to Pedro Ramalhais) Fixed type-o with scan watchdog timeout message (thanks to Pedro Ramalhais) Changed logic for displaying get_mode output so the code is easier to follow (thanks to Pedro Ramalhais) Added initial support for WPA (thanks to Yi Zhu) -- tested with wpa_supplicant (either tip w/ ipw driver, or with -Dipw2100) with both CCMP and TKIP Fixed problem with CCMP not working due to uninitialized 802.11 header fields (thanks to Pedro Ramalhais) Bug references are to defects stored on http://bughost.org Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 1694 +++++++++++++++++++++++++++++----------- drivers/net/wireless/ipw2200.h | 23 +- 2 files changed, 1247 insertions(+), 470 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 3db0c32afe82..ddbee3edcd8c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -32,7 +32,7 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.0" +#define IPW2200_VERSION "1.0.1" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" #define DRV_VERSION IPW2200_VERSION @@ -44,7 +44,6 @@ MODULE_LICENSE("GPL"); static int debug = 0; static int channel = 0; -static char *ifname; static int mode = 0; static u32 ipw_debug_level; @@ -289,32 +288,33 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, { u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; u32 dif_len = addr - aligned_addr; - u32 aligned_len; u32 i; IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); + if (num <= 0) { + return; + } + /* Read the first nibble byte by byte */ if (unlikely(dif_len)) { - /* Start reading at aligned_addr + dif_len */ _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); - for (i = dif_len; i < 4; i++, buf++) - *buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i); - num -= dif_len; + /* Start reading at aligned_addr + dif_len */ + for (i = dif_len; ((i < 4) && (num > 0)); i++, num--) + *buf++ = _ipw_read8(priv, CX2_INDIRECT_DATA + i); aligned_addr += 4; } - /* Read DWs through autoinc register */ _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); - aligned_len = num & CX2_INDIRECT_ADDR_MASK; - for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) - *(u32 *) buf = ipw_read32(priv, CX2_AUTOINC_DATA); + for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) + *(u32 *) buf = _ipw_read32(priv, CX2_AUTOINC_DATA); /* Copy the last nibble */ - dif_len = num - aligned_len; - _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); - for (i = 0; i < dif_len; i++, buf++) - *buf = ipw_read8(priv, CX2_INDIRECT_DATA + i); + if (unlikely(num)) { + _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); + for (i = 0; num > 0; i++, num--) + *buf++ = ipw_read8(priv, CX2_INDIRECT_DATA + i); + } } static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, @@ -322,32 +322,33 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, { u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; u32 dif_len = addr - aligned_addr; - u32 aligned_len; u32 i; IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); + if (num <= 0) { + return; + } + /* Write the first nibble byte by byte */ if (unlikely(dif_len)) { - /* Start writing at aligned_addr + dif_len */ _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); - for (i = dif_len; i < 4; i++, buf++) + /* Start reading at aligned_addr + dif_len */ + for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); - num -= dif_len; aligned_addr += 4; } - /* Write DWs through autoinc register */ _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); - aligned_len = num & CX2_INDIRECT_ADDR_MASK; - for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) + for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf); /* Copy the last nibble */ - dif_len = num - aligned_len; - _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); - for (i = 0; i < dif_len; i++, buf++) - _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); + if (unlikely(num)) { + _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); + for (i = 0; num > 0; i++, num--, buf++) + _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); + } } static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, @@ -945,7 +946,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) { if ((disable_radio ? 1 : 0) == - (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) + ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0)) return 0; IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", @@ -987,6 +988,17 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); +static void notify_wx_assoc_event(struct ipw_priv *priv) +{ + union iwreq_data wrqu; + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + if (priv->status & STATUS_ASSOCIATED) + memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); + else + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); +} + static void ipw_irq_tasklet(struct ipw_priv *priv) { u32 inta, inta_mask, handled = 0; @@ -1071,6 +1083,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) wake_up_interruptible(&priv->wait_command_queue); netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev); + priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); + notify_wx_assoc_event(priv); cancel_delayed_work(&priv->request_scan); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); handled |= CX2_INTA_BIT_RF_KILL_DONE; @@ -1162,7 +1176,7 @@ static char *get_cmd_string(u8 cmd) return "UNKNOWN"; } } -#endif /* CONFIG_IPW_DEBUG */ +#endif #define HOST_COMPLETE_TIMEOUT HZ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) @@ -2445,10 +2459,10 @@ static int ipw_load(struct ipw_priv *priv) rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); break; -#ifdef CONFIG_IPW_PROMISC +#ifdef CONFIG_IPW_MONITOR case IW_MODE_MONITOR: rc = ipw_get_fw(priv, &ucode, - IPW_FW_NAME("ibss_ucode")); + IPW_FW_NAME("sniffer_ucode")); if (rc) goto error; @@ -2929,17 +2943,6 @@ static void ipw_disassociate(void *data) ipw_send_disassociate(data, 0); } -static void notify_wx_assoc_event(struct ipw_priv *priv) -{ - union iwreq_data wrqu; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (priv->status & STATUS_ASSOCIATED) - memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); - else - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); - wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); -} - struct ipw_status_code { u16 status; const char *reason; @@ -2997,7 +3000,7 @@ static const char *ipw_get_status_code(u16 status) { int i; for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++) - if (ipw_status_codes[i].status == status) + if (ipw_status_codes[i].status == (status & 0xff)) return ipw_status_codes[i].reason; return "Unknown status value."; } @@ -3076,18 +3079,30 @@ static inline u32 ipw_get_max_rate(struct ipw_priv *priv) while (i && !(mask & i)) i >>= 1; switch (i) { - case IEEE80211_CCK_RATE_1MB_MASK: return 1000000; - case IEEE80211_CCK_RATE_2MB_MASK: return 2000000; - case IEEE80211_CCK_RATE_5MB_MASK: return 5500000; - case IEEE80211_OFDM_RATE_6MB_MASK: return 6000000; - case IEEE80211_OFDM_RATE_9MB_MASK: return 9000000; - case IEEE80211_CCK_RATE_11MB_MASK: return 11000000; - case IEEE80211_OFDM_RATE_12MB_MASK: return 12000000; - case IEEE80211_OFDM_RATE_18MB_MASK: return 18000000; - case IEEE80211_OFDM_RATE_24MB_MASK: return 24000000; - case IEEE80211_OFDM_RATE_36MB_MASK: return 36000000; - case IEEE80211_OFDM_RATE_48MB_MASK: return 48000000; - case IEEE80211_OFDM_RATE_54MB_MASK: return 54000000; + case IEEE80211_CCK_RATE_1MB_MASK: + return 1000000; + case IEEE80211_CCK_RATE_2MB_MASK: + return 2000000; + case IEEE80211_CCK_RATE_5MB_MASK: + return 5500000; + case IEEE80211_OFDM_RATE_6MB_MASK: + return 6000000; + case IEEE80211_OFDM_RATE_9MB_MASK: + return 9000000; + case IEEE80211_CCK_RATE_11MB_MASK: + return 11000000; + case IEEE80211_OFDM_RATE_12MB_MASK: + return 12000000; + case IEEE80211_OFDM_RATE_18MB_MASK: + return 18000000; + case IEEE80211_OFDM_RATE_24MB_MASK: + return 24000000; + case IEEE80211_OFDM_RATE_36MB_MASK: + return 36000000; + case IEEE80211_OFDM_RATE_48MB_MASK: + return 48000000; + case IEEE80211_OFDM_RATE_54MB_MASK: + return 54000000; } if (priv->ieee->mode == IEEE_B) @@ -3115,24 +3130,36 @@ static u32 ipw_get_current_rate(struct ipw_priv *priv) return ipw_get_max_rate(priv); switch (rate) { - case IPW_TX_RATE_1MB: return 1000000; - case IPW_TX_RATE_2MB: return 2000000; - case IPW_TX_RATE_5MB: return 5500000; - case IPW_TX_RATE_6MB: return 6000000; - case IPW_TX_RATE_9MB: return 9000000; - case IPW_TX_RATE_11MB: return 11000000; - case IPW_TX_RATE_12MB: return 12000000; - case IPW_TX_RATE_18MB: return 18000000; - case IPW_TX_RATE_24MB: return 24000000; - case IPW_TX_RATE_36MB: return 36000000; - case IPW_TX_RATE_48MB: return 48000000; - case IPW_TX_RATE_54MB: return 54000000; + case IPW_TX_RATE_1MB: + return 1000000; + case IPW_TX_RATE_2MB: + return 2000000; + case IPW_TX_RATE_5MB: + return 5500000; + case IPW_TX_RATE_6MB: + return 6000000; + case IPW_TX_RATE_9MB: + return 9000000; + case IPW_TX_RATE_11MB: + return 11000000; + case IPW_TX_RATE_12MB: + return 12000000; + case IPW_TX_RATE_18MB: + return 18000000; + case IPW_TX_RATE_24MB: + return 24000000; + case IPW_TX_RATE_36MB: + return 36000000; + case IPW_TX_RATE_48MB: + return 48000000; + case IPW_TX_RATE_54MB: + return 54000000; } return 0; } -#define PERFECT_RSSI (-50) +#define PERFECT_RSSI (-20) #define WORST_RSSI (-85) #define IPW_STATS_INTERVAL (2 * HZ) static void ipw_gather_stats(struct ipw_priv *priv) @@ -3145,6 +3172,7 @@ static void ipw_gather_stats(struct ipw_priv *priv) s16 rssi; u32 beacon_quality, signal_quality, tx_quality, rx_quality, rate_quality; + u32 max_rate; if (!(priv->status & STATUS_ASSOCIATED)) { priv->quality = 0; @@ -3201,7 +3229,8 @@ static void ipw_gather_stats(struct ipw_priv *priv) beacon_quality, missed_beacons_percent); priv->last_rate = ipw_get_current_rate(priv); - rate_quality = priv->last_rate * 40 / priv->last_rate + 60; + max_rate = ipw_get_max_rate(priv); + rate_quality = priv->last_rate * 40 / max_rate + 60; IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n", rate_quality, priv->last_rate / 1000000); @@ -3226,9 +3255,16 @@ static void ipw_gather_stats(struct ipw_priv *priv) signal_quality = 100; else if (rssi < WORST_RSSI) signal_quality = 0; - else - signal_quality = (rssi - WORST_RSSI) * 100 / - (PERFECT_RSSI - WORST_RSSI); + else /* qual = 100a^2 - 15ab + 62b^2 / a^2 */ + signal_quality = + (100 * + (PERFECT_RSSI - WORST_RSSI) * + (PERFECT_RSSI - WORST_RSSI) - + (PERFECT_RSSI - rssi) * + (15 * (PERFECT_RSSI - WORST_RSSI) + + 62 * (PERFECT_RSSI - rssi))) / + ((PERFECT_RSSI - WORST_RSSI) * (PERFECT_RSSI - WORST_RSSI)); + IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", signal_quality, rssi); @@ -3257,6 +3293,62 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_STATS_INTERVAL); } +static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, + int missed_count) +{ + priv->notif_missed_beacons = missed_count; + + if (missed_count > priv->missed_beacon_threshold && + priv->status & STATUS_ASSOCIATED) { + /* If associated and we've hit the missed + * beacon threshold, disassociate, turn + * off roaming, and abort any active scans */ + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE, + "Missed beacon: %d - disassociate\n", missed_count); + priv->status &= ~STATUS_ROAMING; + if (priv->status & STATUS_SCANNING) + queue_work(priv->workqueue, &priv->abort_scan); + queue_work(priv->workqueue, &priv->disassociate); + return; + } + + if (priv->status & STATUS_ROAMING) { + /* If we are currently roaming, then just + * print a debug statement... */ + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, + "Missed beacon: %d - roam in progress\n", + missed_count); + return; + } + + if (missed_count > priv->roaming_threshold) { + /* If we are not already roaming, set the ROAM + * bit in the status and kick off a scan */ + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, + "Missed beacon: %d - initiate " + "roaming\n", missed_count); + if (!(priv->status & STATUS_ROAMING)) { + priv->status |= STATUS_ROAMING; + if (!(priv->status & STATUS_SCANNING)) + queue_work(priv->workqueue, + &priv->request_scan); + } + return; + } + + if (priv->status & STATUS_SCANNING) { + /* Stop scan to keep fw from getting + * stuck (only if we aren't roaming -- + * otherwise we'll never scan more than 2 or 3 + * channels..) */ + queue_work(priv->workqueue, &priv->abort_scan); + } + + IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); + +} + /** * Handle host notification packet. * Called from interrupt routine @@ -3383,6 +3475,24 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, } case CMAS_INIT:{ + if (priv->status & STATUS_AUTH) { + struct + ieee80211_assoc_response + *resp; + resp = + (struct + ieee80211_assoc_response + *)¬if->u.raw; + IPW_DEBUG(IPW_DL_NOTIF | + IPW_DL_STATE | + IPW_DL_ASSOC, + "association failed (0x%04X): %s\n", + ntohs(resp->status), + ipw_get_status_code + (ntohs + (resp->status))); + } + IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "disassociated: '%s' " MAC_FMT @@ -3629,36 +3739,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, break; } - if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) { - if (priv->status & STATUS_SCANNING) { - /* Stop scan to keep fw from getting - * stuck... */ - queue_work(priv->workqueue, - &priv->abort_scan); - } - - if (x->number > priv->missed_beacon_threshold && - priv->status & STATUS_ASSOCIATED) { - IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | - IPW_DL_STATE, - "Missed beacon: %d - disassociate\n", - x->number); - queue_work(priv->workqueue, - &priv->disassociate); - } else if (x->number > priv->roaming_threshold) { - IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "Missed beacon: %d - initiate " - "roaming\n", x->number); - queue_work(priv->workqueue, - &priv->roam); - } else { - IPW_DEBUG_NOTIF("Missed beacon: %d\n", - x->number); - } - - priv->notif_missed_beacons = x->number; - - } + if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) + ipw_handle_missed_beacon(priv, x->number); break; } @@ -4137,6 +4219,13 @@ static int ipw_compatible_rates(struct ipw_priv *priv, for (i = 0; i < num_rates; i++) { if (!ipw_is_rate_in_mask (priv, network->mode, network->rates[i])) { + if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { + IPW_DEBUG_SCAN + ("Basic rate %02X masked: 0x%08X\n", + network->rates[i], priv->rates_mask); + return 0; + } + IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", network->rates[i], priv->rates_mask); continue; @@ -4150,6 +4239,13 @@ static int ipw_compatible_rates(struct ipw_priv *priv, for (i = 0; i < num_rates; i++) { if (!ipw_is_rate_in_mask (priv, network->mode, network->rates_ex[i])) { + if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { + IPW_DEBUG_SCAN + ("Basic rate %02X masked: 0x%08X\n", + network->rates_ex[i], priv->rates_mask); + return 0; + } + IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", network->rates_ex[i], priv->rates_mask); continue; @@ -4159,7 +4255,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv, network->rates_ex[i]; } - return rates->num_rates; + return 1; } static inline void ipw_copy_rates(struct ipw_supported_rates *dest, @@ -4322,7 +4418,7 @@ static int ipw_best_network(struct ipw_priv *priv, /* If this network has already had an association attempt within the * last 3 seconds, do not try and associate again... */ if (network->last_associate && - time_after(network->last_associate + (HZ * 5UL), jiffies)) { + time_after(network->last_associate + (HZ * 3UL), jiffies)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " "because of storming (%lu since last " "assoc attempt).\n", @@ -4334,7 +4430,7 @@ static int ipw_best_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && - jiffies - network->last_scanned > priv->ieee->scan_age) { + time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " "because of age: %lums.\n", escape_essid(network->ssid, network->ssid_len), @@ -4386,7 +4482,17 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } - ipw_compatible_rates(priv, network, &rates); + /* Ensure that the rates supported by the driver are compatible with + * this AP, including verification of basic rates (mandatory) */ + if (!ipw_compatible_rates(priv, network, &rates)) { + IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + "because configured rate mask excludes " + "AP mandatory rate.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + if (rates.num_rates == 0) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " "because of no compatible rates.\n", @@ -4448,6 +4554,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, memcpy(network->ssid, priv->essid, priv->essid_len); memset(&network->stats, 0, sizeof(network->stats)); network->capability = WLAN_CAPABILITY_IBSS; + if (!(priv->config & CFG_PREAMBLE_LONG)) + network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; if (priv->capability & CAP_PRIVACY_ON) network->capability |= WLAN_CAPABILITY_PRIVACY; network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH); @@ -4530,7 +4638,8 @@ static void ipw_debug_config(struct ipw_priv *priv) else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel); + IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n", + MAC_ARG(priv->bssid)); else IPW_DEBUG_INFO("BSSID unlocked.\n"); if (priv->capability & CAP_PRIVACY_ON) @@ -4561,6 +4670,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, /* IEEE_A */ if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { /* Invalid fixed rate mask */ + IPW_DEBUG_WX + ("invalid fixed rate mask in ipw_set_fixed_rate\n"); fr.tx_rates = 0; break; } @@ -4573,6 +4684,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, if (network->mode == IEEE_B) { if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { /* Invalid fixed rate mask */ + IPW_DEBUG_WX + ("invalid fixed rate mask in ipw_set_fixed_rate\n"); fr.tx_rates = 0; } break; @@ -4582,6 +4695,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | IEEE80211_OFDM_RATES_MASK)) { /* Invalid fixed rate mask */ + IPW_DEBUG_WX + ("invalid fixed rate mask in ipw_set_fixed_rate\n"); fr.tx_rates = 0; break; } @@ -4609,134 +4724,748 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, ipw_write_reg32(priv, reg, *(u32 *) & fr); } -static int ipw_associate_network(struct ipw_priv *priv, - struct ieee80211_network *network, - struct ipw_supported_rates *rates, int roaming) +static void ipw_abort_scan(struct ipw_priv *priv) { int err; - if (priv->config & CFG_FIXED_RATE) - ipw_set_fixed_rate(priv, network); + if (priv->status & STATUS_SCAN_ABORTING) { + IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); + return; + } + priv->status |= STATUS_SCAN_ABORTING; - if (!(priv->config & CFG_STATIC_ESSID)) { - priv->essid_len = min(network->ssid_len, - (u8) IW_ESSID_MAX_SIZE); - memcpy(priv->essid, network->ssid, priv->essid_len); + err = ipw_send_scan_abort(priv); + if (err) + IPW_DEBUG_HC("Request to abort scan failed.\n"); +} + +static int ipw_request_scan(struct ipw_priv *priv) +{ + struct ipw_scan_request_ext scan; + int channel_index = 0; + int i, err, scan_type; + + if (priv->status & STATUS_EXIT_PENDING) { + IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n"); + priv->status |= STATUS_SCAN_PENDING; + return 0; } - network->last_associate = jiffies; + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); + priv->status |= STATUS_SCAN_PENDING; + ipw_abort_scan(priv); + return 0; + } - memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); - priv->assoc_request.channel = network->channel; - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->capability & CAP_SHARED_KEY)) { - priv->assoc_request.auth_type = AUTH_SHARED_KEY; - priv->assoc_request.auth_key = priv->sec.active_key; - } else { - priv->assoc_request.auth_type = AUTH_OPEN; - priv->assoc_request.auth_key = 0; + if (priv->status & STATUS_SCAN_ABORTING) { + IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); + priv->status |= STATUS_SCAN_PENDING; + return 0; } - if (priv->capability & CAP_PRIVACY_ON) - ipw_send_wep_keys(priv); + if (priv->status & STATUS_RF_KILL_MASK) { + IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); + priv->status |= STATUS_SCAN_PENDING; + return 0; + } - /* - * It is valid for our ieee device to support multiple modes, but - * when it comes to associating to a given network we have to choose - * just one mode. - */ - if (network->mode & priv->ieee->mode & IEEE_A) - priv->assoc_request.ieee_mode = IPW_A_MODE; - else if (network->mode & priv->ieee->mode & IEEE_G) - priv->assoc_request.ieee_mode = IPW_G_MODE; - else if (network->mode & priv->ieee->mode & IEEE_B) - priv->assoc_request.ieee_mode = IPW_B_MODE; + memset(&scan, 0, sizeof(scan)); - IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " - "802.11%c [%d], enc=%s%s%s%c%c\n", - roaming ? "Rea" : "A", - escape_essid(priv->essid, priv->essid_len), - network->channel, - ipw_modes[priv->assoc_request.ieee_mode], - rates->num_rates, - priv->capability & CAP_PRIVACY_ON ? "on " : "off", - priv->capability & CAP_PRIVACY_ON ? - (priv->capability & CAP_SHARED_KEY ? "(shared)" : - "(open)") : "", - priv->capability & CAP_PRIVACY_ON ? " key=" : "", - priv->capability & CAP_PRIVACY_ON ? - '1' + priv->sec.active_key : '.', - priv->capability & CAP_PRIVACY_ON ? '.' : ' '); + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; - priv->assoc_request.beacon_interval = network->beacon_interval; - if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && - (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) { - priv->assoc_request.assoc_type = HC_IBSS_START; - priv->assoc_request.assoc_tsf_msw = 0; - priv->assoc_request.assoc_tsf_lsw = 0; - } else { - if (unlikely(roaming)) - priv->assoc_request.assoc_type = HC_REASSOCIATE; - else - priv->assoc_request.assoc_type = HC_ASSOCIATE; - priv->assoc_request.assoc_tsf_msw = network->time_stamp[1]; - priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; - } + scan.full_scan_index = ieee80211_get_scans(priv->ieee); - memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN); +#ifdef CONFIG_IPW_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + u8 band = 0, channel = priv->channel; - if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); - priv->assoc_request.atim_window = network->atim_window; + if (is_valid_channel(IEEE_A, channel)) + band = (u8) (IPW_A_MODE << 6) | 1; + + if (is_valid_channel(IEEE_B | IEEE_G, channel)) + band = (u8) (IPW_B_MODE << 6) | 1; + + if (band == 0) { + band = (u8) (IPW_B_MODE << 6) | 1; + channel = 9; + } + + scan.channels_list[channel_index++] = band; + scan.channels_list[channel_index] = channel; + ipw_set_scan_type(&scan, channel_index, + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); + + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 2000; } else { - memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN); - priv->assoc_request.atim_window = 0; - } +#endif /* CONFIG_IPW_MONITOR */ + /* If we are roaming, then make this a directed scan for the current + * network. Otherwise, ensure that every other scan is a fast + * channel hop scan */ + if ((priv->status & STATUS_ROAMING) + || (!(priv->status & STATUS_ASSOCIATED) + && (priv->config & CFG_STATIC_ESSID) + && (scan.full_scan_index % 2))) { + err = ipw_send_ssid(priv, priv->essid, priv->essid_len); + if (err) { + IPW_DEBUG_HC + ("Attempt to send SSID command failed.\n"); + return err; + } - priv->assoc_request.capability = network->capability; - priv->assoc_request.listen_interval = network->listen_interval; + scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; + } else { + scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; + } - err = ipw_send_ssid(priv, priv->essid, priv->essid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); - return err; - } + if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { + int start = channel_index; + for (i = 0; i < MAX_A_CHANNELS; i++) { + if (band_a_active_channel[i] == 0) + break; + if ((priv->status & STATUS_ASSOCIATED) && + band_a_active_channel[i] == priv->channel) + continue; + channel_index++; + scan.channels_list[channel_index] = + band_a_active_channel[i]; + ipw_set_scan_type(&scan, channel_index, + scan_type); + } - rates->ieee_mode = priv->assoc_request.ieee_mode; - rates->purpose = IPW_RATE_CONNECT; - ipw_send_supported_rates(priv, rates); + if (start != channel_index) { + scan.channels_list[start] = + (u8) (IPW_A_MODE << 6) | (channel_index - + start); + channel_index++; + } + } - if (priv->assoc_request.ieee_mode == IPW_G_MODE) - priv->sys_config.dot11g_auto_detection = 1; - else - priv->sys_config.dot11g_auto_detection = 0; - err = ipw_send_system_config(priv, &priv->sys_config); - if (err) { - IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); - return err; + if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { + int start = channel_index; + for (i = 0; i < MAX_B_CHANNELS; i++) { + if (band_b_active_channel[i] == 0) + break; + if ((priv->status & STATUS_ASSOCIATED) && + band_b_active_channel[i] == priv->channel) + continue; + channel_index++; + scan.channels_list[channel_index] = + band_b_active_channel[i]; + ipw_set_scan_type(&scan, channel_index, + scan_type); + } + + if (start != channel_index) { + scan.channels_list[start] = + (u8) (IPW_B_MODE << 6) | (channel_index - + start); + } + } +#ifdef CONFIG_IPW_MONITOR } +#endif - IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); - err = ipw_set_sensitivity(priv, network->stats.rssi); + err = ipw_send_scan_request_ext(priv, &scan); if (err) { - IPW_DEBUG_HC("Attempt to send associate command failed.\n"); - return err; + IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); + return -EIO; } - /* - * If preemption is enabled, it is possible for the association - * to complete before we return from ipw_send_associate. Therefore - * we have to be sure and update our priviate data first. - */ - priv->channel = network->channel; - memcpy(priv->bssid, network->bssid, ETH_ALEN); - priv->status |= STATUS_ASSOCIATING; - priv->status &= ~STATUS_SECURITY_UPDATED; + priv->status |= STATUS_SCANNING; + priv->status &= ~STATUS_SCAN_PENDING; - priv->assoc_network = network; + return 0; +} - err = ipw_send_associate(priv, &priv->assoc_request); - if (err) { +/* Support for wpa_supplicant. Will be replaced with WEXT once + * they get WPA support. */ +#ifdef CONFIG_IEEE80211_WPA + +/* following definitions must match definitions in driver_ipw.c */ + +#define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 + +#define IPW_CMD_SET_WPA_PARAM 1 +#define IPW_CMD_SET_WPA_IE 2 +#define IPW_CMD_SET_ENCRYPTION 3 +#define IPW_CMD_MLME 4 + +#define IPW_PARAM_WPA_ENABLED 1 +#define IPW_PARAM_TKIP_COUNTERMEASURES 2 +#define IPW_PARAM_DROP_UNENCRYPTED 3 +#define IPW_PARAM_PRIVACY_INVOKED 4 +#define IPW_PARAM_AUTH_ALGS 5 +#define IPW_PARAM_IEEE_802_1X 6 + +#define IPW_MLME_STA_DEAUTH 1 +#define IPW_MLME_STA_DISASSOC 2 + +#define IPW_CRYPT_ERR_UNKNOWN_ALG 2 +#define IPW_CRYPT_ERR_UNKNOWN_ADDR 3 +#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4 +#define IPW_CRYPT_ERR_KEY_SET_FAILED 5 +#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6 +#define IPW_CRYPT_ERR_CARD_CONF_FAILED 7 + +#define IPW_CRYPT_ALG_NAME_LEN 16 + +struct ipw_param { + u32 cmd; + u8 sta_addr[ETH_ALEN]; + union { + struct { + u8 name; + u32 value; + } wpa_param; + struct { + u32 len; + u8 *data; + } wpa_ie; + struct { + int command; + int reason_code; + } mlme; + struct { + u8 alg[IPW_CRYPT_ALG_NAME_LEN]; + u8 set_tx; + u32 err; + u8 idx; + u8 seq[8]; /* sequence counter (set: RX, get: TX) */ + u16 key_len; + u8 key[0]; + } crypt; + + } u; +}; + +/* end of driver_ipw.c code */ + +static int ipw_wpa_enable(struct ipw_priv *priv, int value) +{ + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_security sec = { + .flags = SEC_LEVEL | SEC_ENABLED, + }; + int ret = 0; + + ieee->wpa_enabled = value; + + if (value) { + sec.level = SEC_LEVEL_3; + sec.enabled = 1; + } else { + sec.level = SEC_LEVEL_0; + sec.enabled = 0; + } + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + else + ret = -EOPNOTSUPP; + + return ret; +} + +#define AUTH_ALG_OPEN_SYSTEM 0x1 +#define AUTH_ALG_SHARED_KEY 0x2 + +static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) +{ + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_security sec = { + .flags = SEC_AUTH_MODE, + }; + int ret = 0; + + if (value & AUTH_ALG_SHARED_KEY) { + sec.auth_mode = WLAN_AUTH_SHARED_KEY; + ieee->open_wep = 0; + } else { + sec.auth_mode = WLAN_AUTH_OPEN; + ieee->open_wep = 1; + } + + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + else + ret = -EOPNOTSUPP; + + return ret; +} + +static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int ret = 0; + + switch (name) { + case IPW_PARAM_WPA_ENABLED: + ret = ipw_wpa_enable(priv, value); + break; + + case IPW_PARAM_TKIP_COUNTERMEASURES: + priv->ieee->tkip_countermeasures = value; + break; + + case IPW_PARAM_DROP_UNENCRYPTED: + priv->ieee->drop_unencrypted = value; + break; + + case IPW_PARAM_PRIVACY_INVOKED: + priv->ieee->privacy_invoked = value; + break; + + case IPW_PARAM_AUTH_ALGS: + ret = ipw_wpa_set_auth_algs(priv, value); + break; + + case IPW_PARAM_IEEE_802_1X: + priv->ieee->ieee802_1x = value; + break; + + default: + IPW_ERROR("%s: Unknown WPA param: %d\n", dev->name, name); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int ret = 0; + + switch (command) { + case IPW_MLME_STA_DEAUTH: + // silently ignore + break; + + case IPW_MLME_STA_DISASSOC: + ipw_disassociate(priv); + break; + + default: + IPW_ERROR("%s: Unknown MLME request: %d\n", dev->name, command); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int ipw_set_rsn_capa(struct ipw_priv *priv, + char *capabilities, int length) +{ + struct host_cmd cmd = { + .cmd = IPW_CMD_RSN_CAPABILITIES, + .len = length, + }; + + IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); + + memcpy(&cmd.param, capabilities, length); + if (ipw_send_cmd(priv, &cmd)) { + IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); + return -1; + } + return 0; +} + +void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) +{ + /* make sure WPA is enabled */ + ipw_wpa_enable(priv, 1); + + if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) + ipw_disassociate(priv); +} + +static int ipw_wpa_set_wpa_ie(struct net_device *dev, + struct ipw_param *param, int plen) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + u8 *buf; + + if (!ieee->wpa_enabled) + return -EOPNOTSUPP; + + if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || + (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) + return -EINVAL; + + if (param->u.wpa_ie.len) { + buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = param->u.wpa_ie.len; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); + return 0; +} + +/* implementation borrowed from hostap driver */ + +static int ipw_wpa_set_encryption(struct net_device *dev, + struct ipw_param *param, int param_len) +{ + int ret = 0; + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_crypto_ops *ops; + struct ieee80211_crypt_data **crypt; + + struct ieee80211_security sec = { + .flags = 0, + }; + + param->u.crypt.err = 0; + param->u.crypt.alg[IPW_CRYPT_ALG_NAME_LEN - 1] = '\0'; + + if (param_len != + (int)((char *)param->u.crypt.key - (char *)param) + + param->u.crypt.key_len) { + IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, + param->u.crypt.key_len); + return -EINVAL; + } + if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && + param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (param->u.crypt.idx >= WEP_KEYS) + return -EINVAL; + crypt = &ieee->crypt[param->u.crypt.idx]; + } else { + return -EINVAL; + } + + if (strcmp(param->u.crypt.alg, "none") == 0) { + if (crypt) { + sec.enabled = 0; + sec.level = SEC_LEVEL_0; + sec.flags |= SEC_ENABLED | SEC_LEVEL; + ieee80211_crypt_delayed_deinit(ieee, crypt); + } + goto done; + } + sec.enabled = 1; + sec.flags |= SEC_ENABLED; + + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { + request_module("ieee80211_crypt_wep"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { + request_module("ieee80211_crypt_tkip"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { + request_module("ieee80211_crypt_ccmp"); + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + } + if (ops == NULL) { + IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n", + dev->name, param->u.crypt.alg); + param->u.crypt.err = IPW_CRYPT_ERR_UNKNOWN_ALG; + ret = -EINVAL; + goto done; + } + + if (*crypt == NULL || (*crypt)->ops != ops) { + struct ieee80211_crypt_data *new_crypt; + + ieee80211_crypt_delayed_deinit(ieee, crypt); + + new_crypt = (struct ieee80211_crypt_data *) + kmalloc(sizeof(*new_crypt), GFP_KERNEL); + if (new_crypt == NULL) { + ret = -ENOMEM; + goto done; + } + memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); + new_crypt->ops = ops; + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = + new_crypt->ops->init(param->u.crypt.idx); + + if (new_crypt->priv == NULL) { + kfree(new_crypt); + param->u.crypt.err = IPW_CRYPT_ERR_CRYPT_INIT_FAILED; + ret = -EINVAL; + goto done; + } + + *crypt = new_crypt; + } + + if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && + (*crypt)->ops->set_key(param->u.crypt.key, + param->u.crypt.key_len, param->u.crypt.seq, + (*crypt)->priv) < 0) { + IPW_DEBUG_INFO("%s: key setting failed\n", dev->name); + param->u.crypt.err = IPW_CRYPT_ERR_KEY_SET_FAILED; + ret = -EINVAL; + goto done; + } + + if (param->u.crypt.set_tx) { + ieee->tx_keyidx = param->u.crypt.idx; + sec.active_key = param->u.crypt.idx; + sec.flags |= SEC_ACTIVE_KEY; + } + + if (ops->name != NULL) { + if (strcmp(ops->name, "WEP") == 0) { + memcpy(sec.keys[param->u.crypt.idx], + param->u.crypt.key, param->u.crypt.key_len); + sec.key_sizes[param->u.crypt.idx] = + param->u.crypt.key_len; + sec.flags |= (1 << param->u.crypt.idx); + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } else if (strcmp(ops->name, "TKIP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_2; + } else if (strcmp(ops->name, "CCMP") == 0) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_3; + } + } + done: + if (ieee->set_security) + ieee->set_security(ieee->dev, &sec); + + /* Do not reset port if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. If your hardware requires a reset after WEP + * configuration (for example... Prism2), implement the reset_port in + * the callbacks structures used to initialize the 802.11 stack. */ + if (ieee->reset_on_keychange && + ieee->iw_mode != IW_MODE_INFRA && + ieee->reset_port && ieee->reset_port(dev)) { + IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name); + param->u.crypt.err = IPW_CRYPT_ERR_CARD_CONF_FAILED; + return -EINVAL; + } + + return ret; +} + +static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) +{ + struct ipw_param *param; + int ret = 0; + + IPW_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); + + if (p->length < sizeof(struct ipw_param) || !p->pointer) + return -EINVAL; + + param = (struct ipw_param *)kmalloc(p->length, GFP_KERNEL); + if (param == NULL) + return -ENOMEM; + + if (copy_from_user(param, p->pointer, p->length)) { + kfree(param); + return -EFAULT; + } + + switch (param->cmd) { + + case IPW_CMD_SET_WPA_PARAM: + ret = ipw_wpa_set_param(dev, param->u.wpa_param.name, + param->u.wpa_param.value); + break; + + case IPW_CMD_SET_WPA_IE: + ret = ipw_wpa_set_wpa_ie(dev, param, p->length); + break; + + case IPW_CMD_SET_ENCRYPTION: + ret = ipw_wpa_set_encryption(dev, param, p->length); + break; + + case IPW_CMD_MLME: + ret = ipw_wpa_mlme(dev, param->u.mlme.command, + param->u.mlme.reason_code); + break; + + default: + IPW_ERROR("%s: Unknown WPA supplicant request: %d\n", + dev->name, param->cmd); + ret = -EOPNOTSUPP; + } + + if (ret == 0 && copy_to_user(p->pointer, param, p->length)) + ret = -EFAULT; + + kfree(param); + return ret; +} +#endif /* CONFIG_IEEE80211_WPA */ + +static int ipw_associate_network(struct ipw_priv *priv, + struct ieee80211_network *network, + struct ipw_supported_rates *rates, int roaming) +{ + int err; + + if (priv->config & CFG_FIXED_RATE) + ipw_set_fixed_rate(priv, network); + + if (!(priv->config & CFG_STATIC_ESSID)) { + priv->essid_len = min(network->ssid_len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->essid, network->ssid, priv->essid_len); + } + + network->last_associate = jiffies; + + memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); + priv->assoc_request.channel = network->channel; + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->capability & CAP_SHARED_KEY)) { + priv->assoc_request.auth_type = AUTH_SHARED_KEY; + priv->assoc_request.auth_key = priv->sec.active_key; + } else { + priv->assoc_request.auth_type = AUTH_OPEN; + priv->assoc_request.auth_key = 0; + } + + if (priv->capability & CAP_PRIVACY_ON) + ipw_send_wep_keys(priv); + +#ifdef CONFIG_IEEE80211_WPA + if (priv->ieee->wpa_enabled) { + priv->assoc_request.policy_support = 0x02; /* RSN active */ + ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, + priv->ieee->wpa_ie_len); + } +#endif + + /* + * It is valid for our ieee device to support multiple modes, but + * when it comes to associating to a given network we have to choose + * just one mode. + */ + if (network->mode & priv->ieee->mode & IEEE_A) + priv->assoc_request.ieee_mode = IPW_A_MODE; + else if (network->mode & priv->ieee->mode & IEEE_G) + priv->assoc_request.ieee_mode = IPW_G_MODE; + else if (network->mode & priv->ieee->mode & IEEE_B) + priv->assoc_request.ieee_mode = IPW_B_MODE; + + priv->assoc_request.capability = network->capability; + if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + && !(priv->config & CFG_PREAMBLE_LONG)) { + priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE; + } else { + priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE; + + /* Clear the short preamble if we won't be supporting it */ + priv->assoc_request.capability &= + ~WLAN_CAPABILITY_SHORT_PREAMBLE; + } + + IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " + "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", + roaming ? "Rea" : "A", + escape_essid(priv->essid, priv->essid_len), + network->channel, + ipw_modes[priv->assoc_request.ieee_mode], + rates->num_rates, + (priv->assoc_request.preamble_length == + DCT_FLAG_LONG_PREAMBLE) ? "long" : "short", + network->capability & + WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long", + priv->capability & CAP_PRIVACY_ON ? "on " : "off", + priv->capability & CAP_PRIVACY_ON ? + (priv->capability & CAP_SHARED_KEY ? "(shared)" : + "(open)") : "", + priv->capability & CAP_PRIVACY_ON ? " key=" : "", + priv->capability & CAP_PRIVACY_ON ? + '1' + priv->sec.active_key : '.', + priv->capability & CAP_PRIVACY_ON ? '.' : ' '); + + priv->assoc_request.beacon_interval = network->beacon_interval; + if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && + (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) { + priv->assoc_request.assoc_type = HC_IBSS_START; + priv->assoc_request.assoc_tsf_msw = 0; + priv->assoc_request.assoc_tsf_lsw = 0; + } else { + if (unlikely(roaming)) + priv->assoc_request.assoc_type = HC_REASSOCIATE; + else + priv->assoc_request.assoc_type = HC_ASSOCIATE; + priv->assoc_request.assoc_tsf_msw = network->time_stamp[1]; + priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; + } + + memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN); + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); + priv->assoc_request.atim_window = network->atim_window; + } else { + memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN); + priv->assoc_request.atim_window = 0; + } + + priv->assoc_request.listen_interval = network->listen_interval; + + err = ipw_send_ssid(priv, priv->essid, priv->essid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); + return err; + } + + rates->ieee_mode = priv->assoc_request.ieee_mode; + rates->purpose = IPW_RATE_CONNECT; + ipw_send_supported_rates(priv, rates); + + if (priv->assoc_request.ieee_mode == IPW_G_MODE) + priv->sys_config.dot11g_auto_detection = 1; + else + priv->sys_config.dot11g_auto_detection = 0; + err = ipw_send_system_config(priv, &priv->sys_config); + if (err) { + IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); + return err; + } + + IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); + err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM); + if (err) { + IPW_DEBUG_HC("Attempt to send associate command failed.\n"); + return err; + } + + /* + * If preemption is enabled, it is possible for the association + * to complete before we return from ipw_send_associate. Therefore + * we have to be sure and update our priviate data first. + */ + priv->channel = network->channel; + memcpy(priv->bssid, network->bssid, ETH_ALEN); + priv->status |= STATUS_ASSOCIATING; + priv->status &= ~STATUS_SECURITY_UPDATED; + + priv->assoc_network = network; + + err = ipw_send_associate(priv, &priv->assoc_request); + if (err) { IPW_DEBUG_HC("Attempt to send associate command failed.\n"); return err; } @@ -4899,6 +5628,32 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, rxb->skb = NULL; } +static inline int is_network_packet(struct ipw_priv *priv, + struct ieee80211_hdr_4addr *header) +{ + /* Filter incoming packets to determine if they are targetted toward + * this network, discarding packets coming from ourselves */ + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (is_broadcast_ether_addr(header->addr1) || + is_multicast_ether_addr(header->addr1)) + return !memcmp(header->addr3, priv->bssid, ETH_ALEN); + else + return memcmp(header->addr1, priv->net_dev->dev_addr, + ETH_ALEN); + break; + case IW_MODE_INFRA: + if (is_broadcast_ether_addr(header->addr3) || + is_multicast_ether_addr(header->addr3)) + return !memcmp(header->addr1, priv->bssid, ETH_ALEN); + else + return memcmp(header->addr3, priv->net_dev->dev_addr, + ETH_ALEN); + break; + } + return 1; +} + /* * Main entry function for recieving a packet with 80211 headers. This * should be called when ever the FW has notified us that there is a new @@ -4962,7 +5717,7 @@ static void ipw_rx(struct ipw_priv *priv) priv->rx_packets++; -#ifdef CONFIG_IPW_PROMISC +#ifdef CONFIG_IPW_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { ipw_handle_data_packet(priv, rxb, &stats); @@ -4979,35 +5734,9 @@ static void ipw_rx(struct ipw_priv *priv) * correctly -- we should probably use the * frame control of the packet and disregard * the current iw_mode */ - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - network_packet = - !memcmp(header->addr1, - priv->net_dev->dev_addr, - ETH_ALEN) || - !memcmp(header->addr3, - priv->bssid, ETH_ALEN) || - is_broadcast_ether_addr(header-> - addr1) - || is_multicast_ether_addr(header-> - addr1); - break; - - case IW_MODE_INFRA: - default: - network_packet = - !memcmp(header->addr3, - priv->bssid, ETH_ALEN) || - !memcmp(header->addr1, - priv->net_dev->dev_addr, - ETH_ALEN) || - is_broadcast_ether_addr(header-> - addr1) - || is_multicast_ether_addr(header-> - addr1); - break; - } + network_packet = + is_network_packet(priv, header); if (network_packet && priv->assoc_network) { priv->assoc_network->stats.rssi = stats.rssi; @@ -5108,130 +5837,6 @@ static void ipw_rx(struct ipw_priv *priv) ipw_rx_queue_restock(priv); } -static void ipw_abort_scan(struct ipw_priv *priv) -{ - int err; - - if (priv->status & STATUS_SCAN_ABORTING) { - IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); - return; - } - priv->status |= STATUS_SCAN_ABORTING; - - err = ipw_send_scan_abort(priv); - if (err) - IPW_DEBUG_HC("Request to abort scan failed.\n"); -} - -static int ipw_request_scan(struct ipw_priv *priv) -{ - struct ipw_scan_request_ext scan; - int channel_index = 0; - int i, err, scan_type; - - if (priv->status & STATUS_EXIT_PENDING) { - IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n"); - priv->status |= STATUS_SCAN_PENDING; - return 0; - } - - if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); - priv->status |= STATUS_SCAN_PENDING; - ipw_abort_scan(priv); - return 0; - } - - if (priv->status & STATUS_SCAN_ABORTING) { - IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); - priv->status |= STATUS_SCAN_PENDING; - return 0; - } - - if (priv->status & STATUS_RF_KILL_MASK) { - IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); - priv->status |= STATUS_SCAN_PENDING; - return 0; - } - - memset(&scan, 0, sizeof(scan)); - - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; - - scan.full_scan_index = ieee80211_get_scans(priv->ieee); - /* If we are roaming, then make this a directed scan for the current - * network. Otherwise, ensure that every other scan is a fast - * channel hop scan */ - if ((priv->status & STATUS_ROAMING) - || (!(priv->status & STATUS_ASSOCIATED) - && (priv->config & CFG_STATIC_ESSID) - && (scan.full_scan_index % 2))) { - err = ipw_send_ssid(priv, priv->essid, priv->essid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); - return err; - } - - scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; - } else { - scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; - } - - if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { - int start = channel_index; - for (i = 0; i < MAX_A_CHANNELS; i++) { - if (band_a_active_channel[i] == 0) - break; - if ((priv->status & STATUS_ASSOCIATED) && - band_a_active_channel[i] == priv->channel) - continue; - channel_index++; - scan.channels_list[channel_index] = - band_a_active_channel[i]; - ipw_set_scan_type(&scan, channel_index, scan_type); - } - - if (start != channel_index) { - scan.channels_list[start] = (u8) (IPW_A_MODE << 6) | - (channel_index - start); - channel_index++; - } - } - - if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { - int start = channel_index; - for (i = 0; i < MAX_B_CHANNELS; i++) { - if (band_b_active_channel[i] == 0) - break; - if ((priv->status & STATUS_ASSOCIATED) && - band_b_active_channel[i] == priv->channel) - continue; - channel_index++; - scan.channels_list[channel_index] = - band_b_active_channel[i]; - ipw_set_scan_type(&scan, channel_index, scan_type); - } - - if (start != channel_index) { - scan.channels_list[start] = (u8) (IPW_B_MODE << 6) | - (channel_index - start); - } - } - - err = ipw_send_scan_request_ext(priv, &scan); - if (err) { - IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); - return -EIO; - } - - priv->status |= STATUS_SCANNING; - priv->status &= ~STATUS_SCAN_PENDING; - - return 0; -} - /* * This file defines the Wireless Extension handlers. It does not * define any methods of hardware manipulation and relies on the @@ -5357,7 +5962,7 @@ static int ipw_wx_set_mode(struct net_device *dev, return 0; switch (wrqu->mode) { -#ifdef CONFIG_IPW_PROMISC +#ifdef CONFIG_IPW_MONITOR case IW_MODE_MONITOR: #endif case IW_MODE_ADHOC: @@ -5370,13 +5975,13 @@ static int ipw_wx_set_mode(struct net_device *dev, return -EINVAL; } -#ifdef CONFIG_IPW_PROMISC +#ifdef CONFIG_IPW_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) priv->net_dev->type = ARPHRD_ETHER; if (wrqu->mode == IW_MODE_MONITOR) priv->net_dev->type = ARPHRD_IEEE80211; -#endif /* CONFIG_IPW_PROMISC */ +#endif /* CONFIG_IPW_MONITOR */ #ifdef CONFIG_PM /* Free the existing firmware and reset the fw_loaded @@ -5680,8 +6285,111 @@ static int ipw_wx_set_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); - return -EOPNOTSUPP; + /* TODO: We should use semaphores or locks for access to priv */ + struct ipw_priv *priv = ieee80211_priv(dev); + u32 target_rate = wrqu->bitrate.value; + u32 fixed, mask; + + /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */ + /* value = X, fixed = 1 means only rate X */ + /* value = X, fixed = 0 means all rates lower equal X */ + + if (target_rate == -1) { + fixed = 0; + mask = IEEE80211_DEFAULT_RATES_MASK; + /* Now we should reassociate */ + goto apply; + } + + mask = 0; + fixed = wrqu->bitrate.fixed; + + if (target_rate == 1000000 || !fixed) + mask |= IEEE80211_CCK_RATE_1MB_MASK; + if (target_rate == 1000000) + goto apply; + + if (target_rate == 2000000 || !fixed) + mask |= IEEE80211_CCK_RATE_2MB_MASK; + if (target_rate == 2000000) + goto apply; + + if (target_rate == 5500000 || !fixed) + mask |= IEEE80211_CCK_RATE_5MB_MASK; + if (target_rate == 5500000) + goto apply; + + if (target_rate == 6000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_6MB_MASK; + if (target_rate == 6000000) + goto apply; + + if (target_rate == 9000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_9MB_MASK; + if (target_rate == 9000000) + goto apply; + + if (target_rate == 11000000 || !fixed) + mask |= IEEE80211_CCK_RATE_11MB_MASK; + if (target_rate == 11000000) + goto apply; + + if (target_rate == 12000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_12MB_MASK; + if (target_rate == 12000000) + goto apply; + + if (target_rate == 18000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_18MB_MASK; + if (target_rate == 18000000) + goto apply; + + if (target_rate == 24000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_24MB_MASK; + if (target_rate == 24000000) + goto apply; + + if (target_rate == 36000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_36MB_MASK; + if (target_rate == 36000000) + goto apply; + + if (target_rate == 48000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_48MB_MASK; + if (target_rate == 48000000) + goto apply; + + if (target_rate == 54000000 || !fixed) + mask |= IEEE80211_OFDM_RATE_54MB_MASK; + if (target_rate == 54000000) + goto apply; + + IPW_DEBUG_WX("invalid rate specified, returning error\n"); + return -EINVAL; + + apply: + IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", + mask, fixed ? "fixed" : "sub-rates"); + + if (mask == IEEE80211_DEFAULT_RATES_MASK) + priv->config &= ~CFG_FIXED_RATE; + else + priv->config |= CFG_FIXED_RATE; + + if (priv->rates_mask != mask) { + priv->rates_mask = mask; + /* If we are already associated or are currently trying to + * associate, disassociate and try again */ + if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { + IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); + ipw_disassociate(priv); + } + } else { + /* We are not yet associated, so kick one off... */ + ipw_associate(priv); + } + + return 0; } static int ipw_wx_get_rate(struct net_device *dev, @@ -5888,7 +6596,6 @@ static int ipw_wx_set_power(struct net_device *dev, IPW_DEBUG_WX("failed setting power mode.\n"); return err; } - IPW_DEBUG_WX("SET Power Management Mode -> off\n"); return 0; @@ -6069,37 +6776,30 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); - switch (priv->ieee->freq_band) { - case IEEE80211_24GHZ_BAND: - switch (priv->ieee->modulation) { - case IEEE80211_CCK_MODULATION: - strncpy(extra, "802.11b (2)", MAX_WX_STRING); - break; - case IEEE80211_OFDM_MODULATION: - strncpy(extra, "802.11g (4)", MAX_WX_STRING); - break; - default: - strncpy(extra, "802.11bg (6)", MAX_WX_STRING); - break; - } - break; - - case IEEE80211_52GHZ_BAND: + switch (priv->ieee->mode) { + case IEEE_A: strncpy(extra, "802.11a (1)", MAX_WX_STRING); break; - - default: /* Mixed Band */ - switch (priv->ieee->modulation) { - case IEEE80211_CCK_MODULATION: - strncpy(extra, "802.11ab (3)", MAX_WX_STRING); - break; - case IEEE80211_OFDM_MODULATION: - strncpy(extra, "802.11ag (5)", MAX_WX_STRING); - break; - default: - strncpy(extra, "802.11abg (7)", MAX_WX_STRING); - break; - } + case IEEE_B: + strncpy(extra, "802.11b (2)", MAX_WX_STRING); + break; + case IEEE_A | IEEE_B: + strncpy(extra, "802.11ab (3)", MAX_WX_STRING); + break; + case IEEE_G: + strncpy(extra, "802.11g (4)", MAX_WX_STRING); + break; + case IEEE_A | IEEE_G: + strncpy(extra, "802.11ag (5)", MAX_WX_STRING); + break; + case IEEE_B | IEEE_G: + strncpy(extra, "802.11bg (6)", MAX_WX_STRING); + break; + case IEEE_A | IEEE_B | IEEE_G: + strncpy(extra, "802.11abg (7)", MAX_WX_STRING); + break; + default: + strncpy(extra, "unknown", MAX_WX_STRING); break; } @@ -6110,8 +6810,55 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, return 0; } -#ifdef CONFIG_IPW_PROMISC -static int ipw_wx_set_promisc(struct net_device *dev, +static int ipw_wx_set_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int mode = *(int *)extra; + + /* Switching from SHORT -> LONG requires a disassociation */ + if (mode == 1) { + if (!(priv->config & CFG_PREAMBLE_LONG)) { + priv->config |= CFG_PREAMBLE_LONG; + if (priv->status & + (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { + IPW_DEBUG_ASSOC + ("Disassociating due to preamble " + "change.\n"); + ipw_disassociate(priv); + } + } + goto done; + } + + if (mode == 0) { + priv->config &= ~CFG_PREAMBLE_LONG; + goto done; + } + + return -EINVAL; + + done: + return 0; +} + +static int ipw_wx_get_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + + if (priv->config & CFG_PREAMBLE_LONG) + snprintf(wrqu->name, IFNAMSIZ, "long (1)"); + else + snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); + + return 0; +} + +#ifdef CONFIG_IPW_MONITOR +static int ipw_wx_set_monitor(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { @@ -6119,7 +6866,7 @@ static int ipw_wx_set_promisc(struct net_device *dev, int *parms = (int *)extra; int enable = (parms[0] > 0); - IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]); + IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); if (enable) { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { priv->net_dev->type = ARPHRD_IEEE80211; @@ -6145,47 +6892,49 @@ static int ipw_wx_reset(struct net_device *dev, ipw_adapter_restart(priv); return 0; } -#endif // CONFIG_IPW_PROMISC +#endif // CONFIG_IPW_MONITOR /* Rebase the WE IOCTLs to zero for the handler array */ #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] static iw_handler ipw_wx_handlers[] = { - IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, - IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, - IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, - IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, - IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, - IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, - IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, - IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, - IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, - IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, - IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, - IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, - IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, - IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, - IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, - IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, - IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, - IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, - IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, - IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, - IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, - IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, - IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, - IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, - IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, - IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, - IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, - IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, + IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, + IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, + IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, + IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, + IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, + IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, + IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, + IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, + IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, + IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, + IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, + IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, + IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, + IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, + IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, + IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, + IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, + IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, + IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, + IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, + IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, + IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, + IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, + IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, + IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, + IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, + IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, + IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, }; #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV #define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1 #define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2 #define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3 -#define IPW_PRIV_SET_PROMISC SIOCIWFIRSTPRIV+4 -#define IPW_PRIV_RESET SIOCIWFIRSTPRIV+5 +#define IPW_PRIV_SET_PREAMBLE SIOCIWFIRSTPRIV+4 +#define IPW_PRIV_GET_PREAMBLE SIOCIWFIRSTPRIV+5 +#define IPW_PRIV_SET_MONITOR SIOCIWFIRSTPRIV+6 +#define IPW_PRIV_RESET SIOCIWFIRSTPRIV+7 static struct iw_priv_args ipw_priv_args[] = { { @@ -6204,14 +6953,22 @@ static struct iw_priv_args ipw_priv_args[] = { .cmd = IPW_PRIV_GET_MODE, .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, .name = "get_mode"}, -#ifdef CONFIG_IPW_PROMISC { - IPW_PRIV_SET_PROMISC, + .cmd = IPW_PRIV_SET_PREAMBLE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_preamble"}, + { + .cmd = IPW_PRIV_GET_PREAMBLE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, + .name = "get_preamble"}, +#ifdef CONFIG_IPW_MONITOR + { + IPW_PRIV_SET_MONITOR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, { IPW_PRIV_RESET, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, -#endif /* CONFIG_IPW_PROMISC */ +#endif /* CONFIG_IPW_MONITOR */ }; static iw_handler ipw_priv_handler[] = { @@ -6219,19 +6976,21 @@ static iw_handler ipw_priv_handler[] = { ipw_wx_get_powermode, ipw_wx_set_wireless_mode, ipw_wx_get_wireless_mode, -#ifdef CONFIG_IPW_PROMISC - ipw_wx_set_promisc, + ipw_wx_set_preamble, + ipw_wx_get_preamble, +#ifdef CONFIG_IPW_MONITOR + ipw_wx_set_monitor, ipw_wx_reset, #endif }; static struct iw_handler_def ipw_wx_handler_def = { - .standard = ipw_wx_handlers, - .num_standard = ARRAY_SIZE(ipw_wx_handlers), - .num_private = ARRAY_SIZE(ipw_priv_handler), - .num_private_args = ARRAY_SIZE(ipw_priv_args), - .private = ipw_priv_handler, - .private_args = ipw_priv_args, + .standard = ipw_wx_handlers, + .num_standard = ARRAY_SIZE(ipw_wx_handlers), + .num_private = ARRAY_SIZE(ipw_priv_handler), + .num_private_args = ARRAY_SIZE(ipw_priv_args), + .private = ipw_priv_handler, + .private_args = ipw_priv_args, }; /* @@ -6246,7 +7005,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) wstats = &priv->wstats; - /* if hw is disabled, then ipw2100_get_ordinal() can't be called. + /* if hw is disabled, then ipw_get_ordinal() can't be called. * ipw2100_wx_wireless_stats seems to be called before fw is * initialized. STATUS_ASSOCIATED will only be set if the hw is up * and associated; if not associcated, the values are all meaningless @@ -6384,8 +7143,8 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) else tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM; - if (priv->config & CFG_PREAMBLE) - tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL; + if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) + tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); @@ -6568,11 +7327,11 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, } static struct ethtool_ops ipw_ethtool_ops = { - .get_link = ipw_ethtool_get_link, - .get_drvinfo = ipw_ethtool_get_drvinfo, - .get_eeprom_len = ipw_ethtool_get_eeprom_len, - .get_eeprom = ipw_ethtool_get_eeprom, - .set_eeprom = ipw_ethtool_set_eeprom, + .get_link = ipw_ethtool_get_link, + .get_drvinfo = ipw_ethtool_get_drvinfo, + .get_eeprom_len = ipw_ethtool_get_eeprom_len, + .get_eeprom = ipw_ethtool_get_eeprom, + .set_eeprom = ipw_ethtool_set_eeprom, }; static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) @@ -6918,6 +7677,25 @@ static void ipw_down(struct ipw_priv *priv) ipw_stop_nic(priv); } +static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ +#ifdef CONFIG_IEEE80211_WPA + struct iwreq *wrq = (struct iwreq *)rq; + int ret = -1; + switch (cmd) { + case IPW_IOCTL_WPA_SUPPLICANT: + ret = ipw_wpa_supplicant(dev, &wrq->u.data); + return ret; + + default: + return -EOPNOTSUPP; + } + +#endif /* CONFIG_IEEE80211_WPA */ + + return -EOPNOTSUPP; +} + /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { @@ -7065,9 +7843,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Initialize module parameter values here */ - if (ifname) - strncpy(net_dev->name, ifname, IFNAMSIZ); - if (associate) priv->config |= CFG_ASSOCIATE; else @@ -7095,7 +7870,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) case 1: priv->ieee->iw_mode = IW_MODE_ADHOC; break; -#ifdef CONFIG_IPW_PROMISC +#ifdef CONFIG_IPW_MONITOR case 2: priv->ieee->iw_mode = IW_MODE_MONITOR; break; @@ -7164,6 +7939,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) net_dev->open = ipw_net_open; net_dev->stop = ipw_net_stop; net_dev->init = ipw_net_init; + net_dev->do_ioctl = ipw_ioctl; net_dev->get_stats = ipw_net_get_stats; net_dev->set_multicast_list = ipw_net_set_multicast_list; net_dev->set_mac_address = ipw_net_set_mac_address; @@ -7287,13 +8063,10 @@ static int ipw_pci_resume(struct pci_dev *pdev) printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); - pci_set_power_state(pdev, 0); + pci_set_power_state(pdev, PCI_D0); pci_enable_device(pdev); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) - pci_restore_state(pdev, priv->pm_state); -#else pci_restore_state(pdev); -#endif + /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries @@ -7371,10 +8144,7 @@ MODULE_PARM_DESC(debug, "debug output mask"); module_param(channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); -module_param(ifname, charp, 0444); -MODULE_PARM_DESC(ifname, "network device name (default eth%d)"); - -#ifdef CONFIG_IPW_PROMISC +#ifdef CONFIG_IPW_MONITOR module_param(mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); #else diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index e9cf32bf3e31..068027963181 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -168,7 +168,8 @@ enum connection_manager_assoc_states { #define DCT_FLAG_CTS_REQUIRED 0x02 /* use short preamble */ -#define DCT_FLAG_SHORT_PREMBL 0x04 +#define DCT_FLAG_LONG_PREAMBLE 0x00 +#define DCT_FLAG_SHORT_PREAMBLE 0x04 /* RTS/CTS first */ #define DCT_FLAG_RTS_REQD 0x08 @@ -899,7 +900,7 @@ struct ipw_cmd { #define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */ #define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */ #define CFG_CUSTOM_MAC (1<<3) -#define CFG_PREAMBLE (1<<4) +#define CFG_PREAMBLE_LONG (1<<4) #define CFG_ADHOC_PERSIST (1<<5) #define CFG_ASSOCIATE (1<<6) #define CFG_FIXED_RATE (1<<7) @@ -1206,12 +1207,18 @@ do { if (ipw_debug_level & (level)) \ /* * RESET Register Bit Indexes */ -#define CBD_RESET_REG_PRINCETON_RESET 0x00000001 /* Bit 0 (LSB) */ -#define CX2_RESET_REG_SW_RESET 0x00000080 /* Bit 7 */ -#define CX2_RESET_REG_MASTER_DISABLED 0x00000100 /* Bit 8 */ -#define CX2_RESET_REG_STOP_MASTER 0x00000200 /* Bit 9 */ -#define CX2_ARC_KESHET_CONFIG 0x08000000 /* Bit 27 */ -#define CX2_START_STANDBY 0x00000004 /* Bit 2 */ +#define CBD_RESET_REG_PRINCETON_RESET (1<<0) +#define CX2_START_STANDBY (1<<2) +#define CX2_ACTIVITY_LED (1<<4) +#define CX2_ASSOCIATED_LED (1<<5) +#define CX2_OFDM_LED (1<<6) +#define CX2_RESET_REG_SW_RESET (1<<7) +#define CX2_RESET_REG_MASTER_DISABLED (1<<8) +#define CX2_RESET_REG_STOP_MASTER (1<<9) +#define CX2_GATE_ODMA (1<<25) +#define CX2_GATE_IDMA (1<<26) +#define CX2_ARC_KESHET_CONFIG (1<<27) +#define CX2_GATE_ADMA (1<<29) #define CX2_CSR_CIS_UPPER_BOUND 0x00000200 #define CX2_DOMAIN_0_END 0x1000 -- cgit v1.2.3-59-g8ed1b From a613bffd3aac89bb0a8c9b7afa72af9b0ae30f0a Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 24 Aug 2005 21:43:11 -0500 Subject: Catch ipw2200 up to equivelancy with v1.0.2 Removed unneeded parenthesis around numeric constant defines Added support for iwspy Put in fix for Ad-Hoc mode not passing through all packets (thanks to KKH) Put in fix for fragmentation not working for fragment sizes between 441-464 bytes (thanks to Mohamed Abbas) Fixed #592 problem of CONFIG_IEEE80211_WPA_MODULE not including WPA support into the driver -- fixed as a result of no longer limiting WPAs inclusion Fixed #594 problem with user rates mask causing lack of association if AP mandatory rate is masked out. We now add back in as a supported rate any mandatory rate. Fixed #597 kernel oops due to calling dev_kfree_skb on an skb multiple times. Added code to control LEDs that can be controlled through the wireless NIC (vs. non-wireless HW interfaces) -- this is currently disabled by default due to reports by some users of it hanging their laptop. Added some more debug messages around fragmentation logic Added locking around STATUS_HCMD_ACTIVE to prevent re-entry race conditions Moved ipw_adapter_restart to only execute on the priv->workqueue to keep keyboard errors from occuring during adapter restart Added CFG_BACKGROUND_SCAN to easily allow people to play with background scanning implementations Modified WPA logic to send WPA IE if one is set (vs. being based on wpa_enabled) Modified scan result logic to report WPA and RSN IEs if set (vs. being based on wpa_enabled) Fixed issues with endianess compatability between the host and wireless adapter (thanks to York Liu and Yi Zhu) Fixed problem with Ad-Hoc network creation causing a firmware error if a scan was actively running (thanks to Mohamed Abbas) Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 962 +++++++++++++++++++++++++++++++---------- drivers/net/wireless/ipw2200.h | 73 ++-- 2 files changed, 773 insertions(+), 262 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index ddbee3edcd8c..ea7a3dcf1daa 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -32,7 +32,7 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.1" +#define IPW2200_VERSION "1.0.2" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" #define DRV_VERSION IPW2200_VERSION @@ -49,6 +49,7 @@ static int mode = 0; static u32 ipw_debug_level; static int associate = 1; static int auto_create = 1; +static int led = 0; static int disable = 0; static const char ipw_modes[] = { 'a', 'b', 'g', '?' @@ -637,6 +638,313 @@ static void ipw_init_ordinals(struct ipw_priv *priv) } +u32 ipw_register_toggle(u32 reg) +{ + reg &= ~CX2_START_STANDBY; + if (reg & CX2_GATE_ODMA) + reg &= ~CX2_GATE_ODMA; + if (reg & CX2_GATE_IDMA) + reg &= ~CX2_GATE_IDMA; + if (reg & CX2_GATE_ADMA) + reg &= ~CX2_GATE_ADMA; + return reg; +} + +/* + * LED behavior: + * - On radio ON, turn on any LEDs that require to be on during start + * - On initialization, start unassociated blink + * - On association, disable unassociated blink + * - On disassociation, start unassociated blink + * - On radio OFF, turn off any LEDs started during radio on + * + */ +#define LD_TIME_LINK_ON 300 +#define LD_TIME_LINK_OFF 2700 +#define LD_TIME_ACT_ON 250 + +void ipw_led_link_on(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* If configured to not use LEDs, or nic_type is 1, + * then we don't toggle a LINK led */ + if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (!(priv->status & STATUS_RF_KILL_MASK) && + !(priv->status & STATUS_LED_LINK_ON)) { + IPW_DEBUG_LED("Link LED On\n"); + led = ipw_read_reg32(priv, CX2_EVENT_REG); + led |= priv->led_association_on; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, CX2_EVENT_REG, led); + + priv->status |= STATUS_LED_LINK_ON; + + /* If we aren't associated, schedule turning the LED off */ + if (!(priv->status & STATUS_ASSOCIATED)) + queue_delayed_work(priv->workqueue, + &priv->led_link_off, + LD_TIME_LINK_ON); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipw_led_link_off(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* If configured not to use LEDs, or nic type is 1, + * then we don't goggle the LINK led. */ + if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->status & STATUS_LED_LINK_ON) { + led = ipw_read_reg32(priv, CX2_EVENT_REG); + led &= priv->led_association_off; + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, CX2_EVENT_REG, led); + + IPW_DEBUG_LED("Link LED Off\n"); + + priv->status &= ~STATUS_LED_LINK_ON; + + /* If we aren't associated and the radio is on, schedule + * turning the LED on (blink while unassociated) */ + if (!(priv->status & STATUS_RF_KILL_MASK) && + !(priv->status & STATUS_ASSOCIATED)) + queue_delayed_work(priv->workqueue, &priv->led_link_on, + LD_TIME_LINK_OFF); + + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipw_led_activity_on(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + if (priv->config & CFG_NO_LED) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->status & STATUS_RF_KILL_MASK) { + spin_unlock_irqrestore(&priv->lock, flags); + return; + } + + if (!(priv->status & STATUS_LED_ACT_ON)) { + led = ipw_read_reg32(priv, CX2_EVENT_REG); + led |= priv->led_activity_on; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, CX2_EVENT_REG, led); + + IPW_DEBUG_LED("Activity LED On\n"); + + priv->status |= STATUS_LED_ACT_ON; + + queue_delayed_work(priv->workqueue, &priv->led_act_off, + LD_TIME_ACT_ON); + } else { + /* Reschedule LED off for full time period */ + cancel_delayed_work(&priv->led_act_off); + queue_delayed_work(priv->workqueue, &priv->led_act_off, + LD_TIME_ACT_ON); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipw_led_activity_off(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + if (priv->config & CFG_NO_LED) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->status & STATUS_LED_ACT_ON) { + led = ipw_read_reg32(priv, CX2_EVENT_REG); + led &= priv->led_activity_off; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, CX2_EVENT_REG, led); + + IPW_DEBUG_LED("Activity LED Off\n"); + + priv->status &= ~STATUS_LED_ACT_ON; + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipw_led_band_on(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* Only nic type 1 supports mode LEDs */ + if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + led = ipw_read_reg32(priv, CX2_EVENT_REG); + if (priv->assoc_network->mode == IEEE_A) { + led |= priv->led_ofdm_on; + led &= priv->led_association_off; + IPW_DEBUG_LED("Mode LED On: 802.11a\n"); + } else if (priv->assoc_network->mode == IEEE_G) { + led |= priv->led_ofdm_on; + led |= priv->led_association_on; + IPW_DEBUG_LED("Mode LED On: 802.11g\n"); + } else { + led &= priv->led_ofdm_off; + led |= priv->led_association_on; + IPW_DEBUG_LED("Mode LED On: 802.11b\n"); + } + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, CX2_EVENT_REG, led); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipw_led_band_off(struct ipw_priv *priv) +{ + unsigned long flags; + u32 led; + + /* Only nic type 1 supports mode LEDs */ + if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) + return; + + spin_lock_irqsave(&priv->lock, flags); + + led = ipw_read_reg32(priv, CX2_EVENT_REG); + led &= priv->led_ofdm_off; + led &= priv->led_association_off; + + led = ipw_register_toggle(led); + + IPW_DEBUG_LED("Reg: 0x%08X\n", led); + ipw_write_reg32(priv, CX2_EVENT_REG, led); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipw_led_radio_on(struct ipw_priv *priv) +{ + ipw_led_link_on(priv); +} + +void ipw_led_radio_off(struct ipw_priv *priv) +{ + ipw_led_activity_off(priv); + ipw_led_link_off(priv); +} + +void ipw_led_link_up(struct ipw_priv *priv) +{ + /* Set the Link Led on for all nic types */ + ipw_led_link_on(priv); +} + +void ipw_led_link_down(struct ipw_priv *priv) +{ + ipw_led_activity_off(priv); + ipw_led_link_off(priv); + + if (priv->status & STATUS_RF_KILL_MASK) + ipw_led_radio_off(priv); +} + +void ipw_led_init(struct ipw_priv *priv) +{ + priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; + + /* Set the default PINs for the link and activity leds */ + priv->led_activity_on = CX2_ACTIVITY_LED; + priv->led_activity_off = ~(CX2_ACTIVITY_LED); + + priv->led_association_on = CX2_ASSOCIATED_LED; + priv->led_association_off = ~(CX2_ASSOCIATED_LED); + + /* Set the default PINs for the OFDM leds */ + priv->led_ofdm_on = CX2_OFDM_LED; + priv->led_ofdm_off = ~(CX2_OFDM_LED); + + switch (priv->nic_type) { + case EEPROM_NIC_TYPE_1: + /* In this NIC type, the LEDs are reversed.... */ + priv->led_activity_on = CX2_ASSOCIATED_LED; + priv->led_activity_off = ~(CX2_ASSOCIATED_LED); + priv->led_association_on = CX2_ACTIVITY_LED; + priv->led_association_off = ~(CX2_ACTIVITY_LED); + + if (!(priv->config & CFG_NO_LED)) + ipw_led_band_on(priv); + + /* And we don't blink link LEDs for this nic, so + * just return here */ + return; + + case EEPROM_NIC_TYPE_3: + case EEPROM_NIC_TYPE_2: + case EEPROM_NIC_TYPE_4: + case EEPROM_NIC_TYPE_0: + break; + + default: + IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n", + priv->nic_type); + priv->nic_type = EEPROM_NIC_TYPE_0; + break; + } + + if (!(priv->config & CFG_NO_LED)) { + if (priv->status & STATUS_ASSOCIATED) + ipw_led_link_on(priv); + else + ipw_led_link_off(priv); + } +} + +void ipw_led_shutdown(struct ipw_priv *priv) +{ + cancel_delayed_work(&priv->led_link_on); + cancel_delayed_work(&priv->led_link_off); + cancel_delayed_work(&priv->led_act_off); + ipw_led_activity_off(priv); + ipw_led_link_off(priv); + ipw_led_band_off(priv); +} + /* * The following adds a new attribute to the sysfs representation * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) @@ -648,8 +956,9 @@ static ssize_t show_debug_level(struct device_driver *d, char *buf) { return sprintf(buf, "0x%08X\n", ipw_debug_level); } -static ssize_t store_debug_level(struct device_driver *d, - const char *buf, size_t count) + +static ssize_t store_debug_level(struct device_driver *d, const char *buf, + size_t count) { char *p = (char *)buf; u32 val; @@ -673,6 +982,82 @@ static ssize_t store_debug_level(struct device_driver *d, static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, store_debug_level); +static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d\n", priv->ieee->scan_age); +} + +static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + struct net_device *dev = priv->net_dev; + char buffer[] = "00000000"; + unsigned long len = + (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; + unsigned long val; + char *p = buffer; + + IPW_DEBUG_INFO("enter\n"); + + strncpy(buffer, buf, len); + buffer[len] = 0; + + if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { + p++; + if (p[0] == 'x' || p[0] == 'X') + p++; + val = simple_strtoul(p, &p, 16); + } else + val = simple_strtoul(p, &p, 10); + if (p == buffer) { + IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); + } else { + priv->ieee->scan_age = val; + IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); + } + + IPW_DEBUG_INFO("exit\n"); + return len; +} + +static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); + +static ssize_t show_led(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1); +} + +static ssize_t store_led(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + + IPW_DEBUG_INFO("enter\n"); + + if (count == 0) + return 0; + + if (*buf == 0) { + IPW_DEBUG_LED("Disabling LED control.\n"); + priv->config |= CFG_NO_LED; + ipw_led_shutdown(priv); + } else { + IPW_DEBUG_LED("Enabling LED control.\n"); + priv->config &= ~CFG_NO_LED; + ipw_led_init(priv); + } + + IPW_DEBUG_INFO("exit\n"); + return count; +} + +static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); + static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) { @@ -694,23 +1079,8 @@ static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); static ssize_t show_nic_type(struct device *d, struct device_attribute *attr, char *buf) { - struct ipw_priv *p = d->driver_data; - u8 type = p->eeprom[EEPROM_NIC_TYPE]; - - switch (type) { - case EEPROM_NIC_TYPE_STANDARD: - return sprintf(buf, "STANDARD\n"); - case EEPROM_NIC_TYPE_DELL: - return sprintf(buf, "DELL\n"); - case EEPROM_NIC_TYPE_FUJITSU: - return sprintf(buf, "FUJITSU\n"); - case EEPROM_NIC_TYPE_IBM: - return sprintf(buf, "IBM\n"); - case EEPROM_NIC_TYPE_HP: - return sprintf(buf, "HP\n"); - } - - return sprintf(buf, "UNKNOWN\n"); + struct ipw_priv *priv = d->driver_data; + return sprintf(buf, "TYPE: %d\n", priv->nic_type); } static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); @@ -955,9 +1325,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) if (disable_radio) { priv->status |= STATUS_RF_KILL_SW; - if (priv->workqueue) { + if (priv->workqueue) cancel_delayed_work(&priv->request_scan); - } wake_up_interruptible(&priv->wait_command_queue); queue_work(priv->workqueue, &priv->down); } else { @@ -1081,11 +1450,9 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); priv->status |= STATUS_RF_KILL_HW; wake_up_interruptible(&priv->wait_command_queue); - netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); - notify_wx_assoc_event(priv); cancel_delayed_work(&priv->request_scan); + schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); handled |= CX2_INTA_BIT_RF_KILL_DONE; } @@ -1182,9 +1549,12 @@ static char *get_cmd_string(u8 cmd) static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) { int rc = 0; + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { IPW_ERROR("Already sending a command\n"); + spin_unlock_irqrestore(&priv->lock, flags); return -1; } @@ -1195,19 +1565,30 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); - if (rc) + if (rc) { + priv->status &= ~STATUS_HCMD_ACTIVE; + spin_unlock_irqrestore(&priv->lock, flags); return rc; + } + spin_unlock_irqrestore(&priv->lock, flags); rc = wait_event_interruptible_timeout(priv->wait_command_queue, !(priv-> status & STATUS_HCMD_ACTIVE), HOST_COMPLETE_TIMEOUT); if (rc == 0) { - IPW_DEBUG_INFO("Command completion failed out after %dms.\n", - jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - priv->status &= ~STATUS_HCMD_ACTIVE; - return -EIO; + spin_lock_irqsave(&priv->lock, flags); + if (priv->status & STATUS_HCMD_ACTIVE) { + IPW_DEBUG_INFO("Command completion failed out after " + "%dms.\n", + 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); + priv->status &= ~STATUS_HCMD_ACTIVE; + spin_unlock_irqrestore(&priv->lock, flags); + return -EIO; + } + spin_unlock_irqrestore(&priv->lock, flags); } + if (priv->status & STATUS_RF_KILL_MASK) { IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n"); return -EIO; @@ -1304,6 +1685,11 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) return 0; } +/* + * NOTE: This must be executed from our workqueue as it results in udelay + * being called which may corrupt the keyboard if executed on default + * workqueue + */ static void ipw_adapter_restart(void *adapter) { struct ipw_priv *priv = adapter; @@ -1327,7 +1713,7 @@ static void ipw_scan_check(void *data) IPW_DEBUG_SCAN("Scan completion watchdog resetting " "adapter (%dms).\n", IPW_SCAN_CHECK_WATCHDOG / 100); - ipw_adapter_restart(priv); + queue_work(priv->workqueue, &priv->adapter_restart); } } @@ -1400,12 +1786,25 @@ static int ipw_send_associate(struct ipw_priv *priv, .len = sizeof(*associate) }; + struct ipw_associate tmp_associate; + memcpy(&tmp_associate, associate, sizeof(*associate)); + tmp_associate.policy_support = + cpu_to_le16(tmp_associate.policy_support); + tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw); + tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw); + tmp_associate.capability = cpu_to_le16(tmp_associate.capability); + tmp_associate.listen_interval = + cpu_to_le16(tmp_associate.listen_interval); + tmp_associate.beacon_interval = + cpu_to_le16(tmp_associate.beacon_interval); + tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); + if (!priv || !associate) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(&cmd.param, associate, sizeof(*associate)); + memcpy(&cmd.param, &tmp_associate, sizeof(*associate)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send ASSOCIATE command\n"); return -1; @@ -1706,7 +2105,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv) /* read entire contents of eeprom into private buffer */ for (i = 0; i < 128; i++) - eeprom[i] = eeprom_read_u16(priv, (u8) i); + eeprom[i] = le16_to_cpu(eeprom_read_u16(priv, (u8) i)); /* If the data looks correct, then copy it to our private @@ -2001,6 +2400,9 @@ static void ipw_remove_current_network(struct ipw_priv *priv) { struct list_head *element, *safe; struct ieee80211_network *network = NULL; + unsigned long flags; + + spin_lock_irqsave(&priv->ieee->lock, flags); list_for_each_safe(element, safe, &priv->ieee->network_list) { network = list_entry(element, struct ieee80211_network, list); if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { @@ -2009,6 +2411,7 @@ static void ipw_remove_current_network(struct ipw_priv *priv) &priv->ieee->network_free_list); } } + spin_unlock_irqrestore(&priv->ieee->lock, flags); } /** @@ -2158,7 +2561,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) */ /* load new ipw uCode */ for (i = 0; i < len / 2; i++) - ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]); + ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, + cpu_to_le16(image[i])); /* enable DINO */ ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); @@ -2181,7 +2585,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) for (i = 0; i < ARRAY_SIZE(response_buffer); i++) response_buffer[i] = - ipw_read_reg32(priv, CX2_BASEBAND_RX_FIFO_READ); + le32_to_cpu(ipw_read_reg32(priv, + CX2_BASEBAND_RX_FIFO_READ)); memcpy(&priv->dino_alive, response_buffer, sizeof(priv->dino_alive)); if (priv->dino_alive.alive_command == 1 @@ -2250,13 +2655,14 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) * offeset*/ /* Dma loading */ rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, - chunk->address, chunk->length); + le32_to_cpu(chunk->address), + le32_to_cpu(chunk->length)); if (rc) { IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); goto out; } - offset += chunk->length; + offset += le32_to_cpu(chunk->length); } while (offset < len); /* Run the DMA and wait for the answer */ @@ -2351,14 +2757,17 @@ static int ipw_init_nic(struct ipw_priv *priv) static int ipw_reset_nic(struct ipw_priv *priv) { int rc = 0; + unsigned long flags; IPW_DEBUG_TRACE(">>\n"); rc = ipw_init_nic(priv); + spin_lock_irqsave(&priv->lock, flags); /* Clear the 'host command active' bit... */ priv->status &= ~STATUS_HCMD_ACTIVE; wake_up_interruptible(&priv->wait_command_queue); + spin_unlock_irqrestore(&priv->lock, flags); IPW_DEBUG_TRACE("<<\n"); return rc; @@ -2378,17 +2787,18 @@ static int ipw_get_fw(struct ipw_priv *priv, } header = (struct fw_header *)(*fw)->data; - if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) { + if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) { IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", name, - IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION); + IPW_FW_MAJOR(le32_to_cpu(header->version)), + IPW_FW_MAJOR_VERSION); return -EINVAL; } IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", name, - IPW_FW_MAJOR(header->version), - IPW_FW_MINOR(header->version), + IPW_FW_MAJOR(le32_to_cpu(header->version)), + IPW_FW_MINOR(le32_to_cpu(header->version)), (*fw)->size - sizeof(struct fw_header)); return 0; } @@ -2414,6 +2824,7 @@ static inline void ipw_rx_queue_reset(struct ipw_priv *priv, pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxq->pool[i].skb); + rxq->pool[i].skb = NULL; } list_add_tail(&rxq->pool[i].list, &rxq->rx_used); } @@ -2769,16 +3180,18 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, return; /* sanity check */ - if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) { - IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks); + if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) { + IPW_ERROR("Too many chunks: %i\n", + le32_to_cpu(bd->u.data.num_chunks)); /** @todo issue fatal error, it is quite serious situation */ return; } /* unmap chunks if any */ - for (i = 0; i < bd->u.data.num_chunks; i++) { - pci_unmap_single(dev, bd->u.data.chunk_ptr[i], - bd->u.data.chunk_len[i], PCI_DMA_TODEVICE); + for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) { + pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]), + le16_to_cpu(bd->u.data.chunk_len[i]), + PCI_DMA_TODEVICE); if (txq->txb[txq->q.last_used]) { ieee80211_txb_free(txq->txb[txq->q.last_used]); txq->txb[txq->q.last_used] = NULL; @@ -2841,9 +3254,8 @@ static void inline __maybe_wake_tx(struct ipw_priv *priv) switch (priv->port_type) { case DCR_TYPE_MU_BSS: case DCR_TYPE_MU_IBSS: - if (!(priv->status & STATUS_ASSOCIATED)) { + if (!(priv->status & STATUS_ASSOCIATED)) return; - } } netif_wake_queue(priv->net_dev); } @@ -3307,8 +3719,13 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, IPW_DL_STATE, "Missed beacon: %d - disassociate\n", missed_count); priv->status &= ~STATUS_ROAMING; - if (priv->status & STATUS_SCANNING) + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE, + "Aborting scan with missed beacon.\n"); queue_work(priv->workqueue, &priv->abort_scan); + } + queue_work(priv->workqueue, &priv->disassociate); return; } @@ -3342,6 +3759,8 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, * stuck (only if we aren't roaming -- * otherwise we'll never scan more than 2 or 3 * channels..) */ + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE, "Aborting scan with missed beacon.\n"); queue_work(priv->workqueue, &priv->abort_scan); } @@ -3356,6 +3775,8 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, static inline void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { + notif->size = le16_to_cpu(notif->size); + IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size); switch (notif->subtype) { @@ -3400,29 +3821,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, priv->status &= ~STATUS_ASSOCIATING; priv->status |= STATUS_ASSOCIATED; - netif_carrier_on(priv->net_dev); - if (netif_queue_stopped(priv->net_dev)) { - IPW_DEBUG_NOTIF - ("waking queue\n"); - netif_wake_queue(priv->net_dev); - } else { - IPW_DEBUG_NOTIF - ("starting queue\n"); - netif_start_queue(priv-> - net_dev); - } + schedule_work(&priv->link_up); - ipw_reset_stats(priv); - /* Ensure the rate is updated immediately */ - priv->last_rate = - ipw_get_current_rate(priv); - schedule_work(&priv->gather_stats); - notify_wx_assoc_event(priv); - -/* queue_delayed_work(priv->workqueue, - &priv->request_scan, - SCAN_ASSOCIATED_INTERVAL); -*/ break; } @@ -3455,12 +3855,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, STATUS_AUTH | STATUS_ASSOCIATED); - netif_carrier_off(priv-> - net_dev); - netif_stop_queue(priv->net_dev); - queue_work(priv->workqueue, - &priv->request_scan); - notify_wx_assoc_event(priv); + schedule_work(&priv->link_down); break; } @@ -3506,31 +3901,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, STATUS_ASSOCIATING | STATUS_ASSOCIATED | STATUS_AUTH); - netif_stop_queue(priv->net_dev); - if (!(priv->status & STATUS_ROAMING)) { - netif_carrier_off(priv-> - net_dev); - notify_wx_assoc_event(priv); - - /* Cancel any queued work ... */ - cancel_delayed_work(&priv-> - request_scan); - cancel_delayed_work(&priv-> - adhoc_check); - - /* Queue up another scan... */ - queue_work(priv->workqueue, - &priv->request_scan); - - cancel_delayed_work(&priv-> - gather_stats); - } else { - priv->status |= STATUS_ROAMING; - queue_work(priv->workqueue, - &priv->request_scan); - } + schedule_work(&priv->link_down); - ipw_reset_stats(priv); break; } @@ -3576,11 +3948,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, STATUS_AUTH | STATUS_ASSOCIATED); - netif_carrier_off(priv->net_dev); - netif_stop_queue(priv->net_dev); - queue_work(priv->workqueue, - &priv->request_scan); - notify_wx_assoc_event(priv); + schedule_work(&priv->link_down); break; case CMAS_TX_AUTH_SEQ_1: @@ -3682,6 +4050,10 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, } else if (priv->status & STATUS_SCAN_PENDING) queue_work(priv->workqueue, &priv->request_scan); + else if (priv->config & CFG_BACKGROUND_SCAN + && priv->status & STATUS_ASSOCIATED) + queue_delayed_work(priv->workqueue, + &priv->request_scan, HZ); priv->ieee->scans++; break; @@ -3690,13 +4062,13 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{ struct notif_frag_length *x = ¬if->u.frag_len; - if (notif->size == sizeof(*x)) { - IPW_ERROR("Frag length: %d\n", x->frag_length); - } else { + if (notif->size == sizeof(*x)) + IPW_ERROR("Frag length: %d\n", + le16_to_cpu(x->frag_length)); + else IPW_ERROR("Frag length of wrong size %d " "(should be %zd)\n", notif->size, sizeof(*x)); - } break; } @@ -3722,11 +4094,9 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{ IPW_ERROR("Dino config\n"); if (priv->hcmd - && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) { - /* TODO: Do anything special? */ - } else { + && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG) IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n"); - } + break; } @@ -3739,8 +4109,11 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, break; } - if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) - ipw_handle_missed_beacon(priv, x->number); + if (le32_to_cpu(x->state) == + HOST_NOTIFICATION_STATUS_BEACON_MISSING) + ipw_handle_missed_beacon(priv, + le32_to_cpu(x-> + number)); break; } @@ -3779,7 +4152,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_NOISE_STATS:{ if (notif->size == sizeof(u32)) { priv->last_noise = - (u8) (notif->u.noise.value & 0xff); + (u8) (le32_to_cpu(notif->u.noise.value) & + 0xff); average_add(&priv->average_noise, priv->last_noise); break; @@ -3896,9 +4270,8 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv, priv->tx_packets++; } done: - if (ipw_queue_space(q) > q->low_mark && qindex >= 0) { + if (ipw_queue_space(q) > q->low_mark && qindex >= 0) __maybe_wake_tx(priv); - } used = q->first_empty - q->last_used; if (used < 0) used += q->n_bd; @@ -4217,13 +4590,16 @@ static int ipw_compatible_rates(struct ipw_priv *priv, num_rates = min(network->rates_len, (u8) IPW_MAX_RATES); rates->num_rates = 0; for (i = 0; i < num_rates; i++) { - if (!ipw_is_rate_in_mask - (priv, network->mode, network->rates[i])) { + if (!ipw_is_rate_in_mask(priv, network->mode, + network->rates[i])) { + if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { - IPW_DEBUG_SCAN - ("Basic rate %02X masked: 0x%08X\n", - network->rates[i], priv->rates_mask); - return 0; + IPW_DEBUG_SCAN("Adding masked mandatory " + "rate %02X\n", + network->rates[i]); + rates->supported_rates[rates->num_rates++] = + network->rates[i]; + continue; } IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", @@ -4234,16 +4610,18 @@ static int ipw_compatible_rates(struct ipw_priv *priv, rates->supported_rates[rates->num_rates++] = network->rates[i]; } - num_rates = - min(network->rates_ex_len, (u8) (IPW_MAX_RATES - num_rates)); + num_rates = min(network->rates_ex_len, + (u8) (IPW_MAX_RATES - num_rates)); for (i = 0; i < num_rates; i++) { - if (!ipw_is_rate_in_mask - (priv, network->mode, network->rates_ex[i])) { + if (!ipw_is_rate_in_mask(priv, network->mode, + network->rates_ex[i])) { if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { - IPW_DEBUG_SCAN - ("Basic rate %02X masked: 0x%08X\n", - network->rates_ex[i], priv->rates_mask); - return 0; + IPW_DEBUG_SCAN("Adding masked mandatory " + "rate %02X\n", + network->rates_ex[i]); + rates->supported_rates[rates->num_rates++] = + network->rates[i]; + continue; } IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", @@ -4531,9 +4909,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * FW fatal error. */ network->mode = is_valid_channel(priv->ieee->mode, priv->channel); - if (network->mode) { - network->channel = priv->channel; - } else { + if (!network->mode) { IPW_WARNING("Overriding invalid channel\n"); if (priv->ieee->mode & IEEE_A) { network->mode = IEEE_A; @@ -4572,10 +4948,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, network->beacon_interval = 100; /* Default */ network->listen_interval = 10; /* Default */ network->atim_window = 0; /* Default */ -#ifdef CONFIG_IEEE80211_WPA network->wpa_ie_len = 0; network->rsn_ie_len = 0; -#endif /* CONFIG_IEEE80211_WPA */ } static void ipw_send_wep_keys(struct ipw_priv *priv) @@ -4593,9 +4967,9 @@ static void ipw_send_wep_keys(struct ipw_priv *priv) for (i = 0; i < 4; i++) { key->key_index = i; - if (!(priv->sec.flags & (1 << i))) { + if (!(priv->sec.flags & (1 << i))) key->key_size = 0; - } else { + else { key->key_size = priv->sec.key_sizes[i]; memcpy(key->key, priv->sec.keys[i], key->key_size); } @@ -4752,9 +5126,10 @@ static int ipw_request_scan(struct ipw_priv *priv) } if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); + IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); +// IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); priv->status |= STATUS_SCAN_PENDING; - ipw_abort_scan(priv); +// ipw_abort_scan(priv); return 0; } @@ -4772,11 +5147,12 @@ static int ipw_request_scan(struct ipw_priv *priv) memset(&scan, 0, sizeof(scan)); - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = + cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); - scan.full_scan_index = ieee80211_get_scans(priv->ieee); + scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); #ifdef CONFIG_IPW_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { @@ -4798,7 +5174,8 @@ static int ipw_request_scan(struct ipw_priv *priv) ipw_set_scan_type(&scan, channel_index, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 2000; + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(2000); } else { #endif /* CONFIG_IPW_MONITOR */ /* If we are roaming, then make this a directed scan for the current @@ -4807,7 +5184,7 @@ static int ipw_request_scan(struct ipw_priv *priv) if ((priv->status & STATUS_ROAMING) || (!(priv->status & STATUS_ASSOCIATED) && (priv->config & CFG_STATIC_ESSID) - && (scan.full_scan_index % 2))) { + && (le32_to_cpu(scan.full_scan_index) % 2))) { err = ipw_send_ssid(priv, priv->essid, priv->essid_len); if (err) { IPW_DEBUG_HC @@ -4882,7 +5259,6 @@ static int ipw_request_scan(struct ipw_priv *priv) /* Support for wpa_supplicant. Will be replaced with WEXT once * they get WPA support. */ -#ifdef CONFIG_IEEE80211_WPA /* following definitions must match definitions in driver_ipw.c */ @@ -4959,6 +5335,7 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) } else { sec.level = SEC_LEVEL_0; sec.enabled = 0; + ieee->wpa_ie_len = 0; } if (ieee->set_security) @@ -4999,6 +5376,8 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) { struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_crypt_data *crypt; + unsigned long flags; int ret = 0; switch (name) { @@ -5007,7 +5386,22 @@ static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) break; case IPW_PARAM_TKIP_COUNTERMEASURES: - priv->ieee->tkip_countermeasures = value; + crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { + IPW_WARNING("Can't set TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + flags = crypt->ops->get_flags(crypt->priv); + + if (value) + flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + else + flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + + crypt->ops->set_flags(flags, crypt->priv); + break; case IPW_PARAM_DROP_UNENCRYPTED: @@ -5313,7 +5707,6 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) kfree(param); return ret; } -#endif /* CONFIG_IEEE80211_WPA */ static int ipw_associate_network(struct ipw_priv *priv, struct ieee80211_network *network, @@ -5346,13 +5739,11 @@ static int ipw_associate_network(struct ipw_priv *priv, if (priv->capability & CAP_PRIVACY_ON) ipw_send_wep_keys(priv); -#ifdef CONFIG_IEEE80211_WPA - if (priv->ieee->wpa_enabled) { + if (priv->ieee->wpa_ie_len) { priv->assoc_request.policy_support = 0x02; /* RSN active */ ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, priv->ieee->wpa_ie_len); } -#endif /* * It is valid for our ieee device to support multiple modes, but @@ -5511,12 +5902,15 @@ static void ipw_roam(void *data) if (priv->status & STATUS_ASSOCIATED) { /* First pass through ROAM process -- look for a better * network */ + unsigned long flags; u8 rssi = priv->assoc_network->stats.rssi; priv->assoc_network->stats.rssi = -128; + spin_lock_irqsave(&priv->ieee->lock, flags); list_for_each_entry(network, &priv->ieee->network_list, list) { if (network != priv->assoc_network) ipw_best_network(priv, &match, network, 1); } + spin_unlock_irqrestore(&priv->ieee->lock, flags); priv->assoc_network->stats.rssi = rssi; if (match.network == priv->assoc_network) { @@ -5549,6 +5943,7 @@ static void ipw_associate(void *data) }; struct ipw_supported_rates *rates; struct list_head *element; + unsigned long flags; if (!(priv->config & CFG_ASSOCIATE) && !(priv->config & (CFG_STATIC_ESSID | @@ -5557,6 +5952,8 @@ static void ipw_associate(void *data) return; } + /* Protect our use of the network_list */ + spin_lock_irqsave(&priv->ieee->lock, flags); list_for_each_entry(network, &priv->ieee->network_list, list) ipw_best_network(priv, &match, network, 0); @@ -5567,6 +5964,7 @@ static void ipw_associate(void *data) priv->ieee->iw_mode == IW_MODE_ADHOC && priv->config & CFG_ADHOC_CREATE && priv->config & CFG_STATIC_ESSID && + priv->config & CFG_STATIC_CHANNEL && !list_empty(&priv->ieee->network_free_list)) { element = priv->ieee->network_free_list.next; network = list_entry(element, struct ieee80211_network, list); @@ -5575,14 +5973,16 @@ static void ipw_associate(void *data) list_del(element); list_add_tail(&network->list, &priv->ieee->network_list); } + spin_unlock_irqrestore(&priv->ieee->lock, flags); /* If we reached the end of the list, then we don't have any valid * matching APs */ if (!network) { ipw_debug_config(priv); - queue_delayed_work(priv->workqueue, &priv->request_scan, - SCAN_INTERVAL); + if (!(priv->status & STATUS_SCANNING)) + queue_delayed_work(priv->workqueue, &priv->request_scan, + SCAN_INTERVAL); return; } @@ -5601,7 +6001,7 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, /* We only process data packets if the * interface is open */ - if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) > + if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) { priv->ieee->stats.rx_errors++; priv->wstats.discard.misc++; @@ -5618,14 +6018,16 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data)); /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, pkt->u.frame.length); + skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length)); IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) priv->ieee->stats.rx_errors++; - else /* ieee80211_rx succeeded, so it now owns the SKB */ + else { /* ieee80211_rx succeeded, so it now owns the SKB */ rxb->skb = NULL; + ipw_led_activity_on(priv); + } } static inline int is_network_packet(struct ipw_priv *priv, @@ -5634,23 +6036,29 @@ static inline int is_network_packet(struct ipw_priv *priv, /* Filter incoming packets to determine if they are targetted toward * this network, discarding packets coming from ourselves */ switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: + case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ + /* {broad,multi}cast packets to our IBSS go through */ if (is_broadcast_ether_addr(header->addr1) || is_multicast_ether_addr(header->addr1)) return !memcmp(header->addr3, priv->bssid, ETH_ALEN); - else - return memcmp(header->addr1, priv->net_dev->dev_addr, - ETH_ALEN); + + /* packets to our adapter go through */ + return !memcmp(header->addr1, priv->net_dev->dev_addr, + ETH_ALEN); break; - case IW_MODE_INFRA: - if (is_broadcast_ether_addr(header->addr3) || - is_multicast_ether_addr(header->addr3)) - return !memcmp(header->addr1, priv->bssid, ETH_ALEN); - else - return memcmp(header->addr3, priv->net_dev->dev_addr, - ETH_ALEN); + + case IW_MODE_INFRA: /* Header: Dest. | AP{BSSID} | Source */ + /* {broad,multi}cast packets to our IBSS go through */ + if (is_broadcast_ether_addr(header->addr1) || + is_multicast_ether_addr(header->addr1)) + return !memcmp(header->addr2, priv->bssid, ETH_ALEN); + + /* packets to our adapter go through */ + return !memcmp(header->addr1, priv->net_dev->dev_addr, + ETH_ALEN); break; } + return 1; } @@ -5695,7 +6103,7 @@ static void ipw_rx(struct ipw_priv *priv) struct ieee80211_rx_stats stats = { .rssi = pkt->u.frame.rssi_dbm - IPW_RSSI_TO_DBM, - .signal = pkt->u.frame.signal, + /* .signal = le16_to_cpu(pkt->u.frame.signal), */ .rate = pkt->u.frame.rate, .mac_time = jiffies, .received_channel = @@ -5705,7 +6113,7 @@ static void ipw_rx(struct ipw_priv *priv) control & (1 << 0)) ? IEEE80211_24GHZ_BAND : IEEE80211_52GHZ_BAND, - .len = pkt->u.frame.length, + .len = le16_to_cpu(pkt->u.frame.length), }; if (stats.rssi != 0) @@ -5746,9 +6154,10 @@ static void ipw_rx(struct ipw_priv *priv) } IPW_DEBUG_RX("Frame: len=%u\n", - pkt->u.frame.length); + le16_to_cpu(pkt->u.frame.length)); - if (pkt->u.frame.length < frame_hdr_len(header)) { + if (le16_to_cpu(pkt->u.frame.length) < + frame_hdr_len(header)) { IPW_DEBUG_DROP ("Received packet is too small. " "Dropping.\n"); @@ -5757,19 +6166,20 @@ static void ipw_rx(struct ipw_priv *priv) break; } - switch (WLAN_FC_GET_TYPE(header->frame_ctl)) { + switch (WLAN_FC_GET_TYPE + (le16_to_cpu(header->frame_ctl))) { case IEEE80211_FTYPE_MGMT: ieee80211_rx_mgt(priv->ieee, header, &stats); if (priv->ieee->iw_mode == IW_MODE_ADHOC && ((WLAN_FC_GET_STYPE - (header->frame_ctl) == - IEEE80211_STYPE_PROBE_RESP) + (le16_to_cpu(header->frame_ctl)) + == IEEE80211_STYPE_PROBE_RESP) || (WLAN_FC_GET_STYPE - (header->frame_ctl) == - IEEE80211_STYPE_BEACON)) + (le16_to_cpu(header->frame_ctl)) + == IEEE80211_STYPE_BEACON)) && !memcmp(header->addr3, priv->bssid, ETH_ALEN)) ipw_add_station(priv, @@ -5852,7 +6262,9 @@ static int ipw_wx_get_name(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - if (!(priv->status & STATUS_ASSOCIATED)) + if (priv->status & STATUS_RF_KILL_MASK) { + strcpy(wrqu->name, "radio off"); + } else if (!(priv->status & STATUS_ASSOCIATED)) strcpy(wrqu->name, "unassociated"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", @@ -5892,9 +6304,8 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_ASSOC("Disassociating due to channel change.\n"); ipw_disassociate(priv); - } else { + } else if (!(priv->status & (STATUS_SCANNING))) ipw_associate(priv); - } return 0; } @@ -5986,9 +6397,8 @@ static int ipw_wx_set_mode(struct net_device *dev, #ifdef CONFIG_PM /* Free the existing firmware and reset the fw_loaded * flag so ipw_load() will bring in the new firmawre */ - if (fw_loaded) { + if (fw_loaded) fw_loaded = 0; - } release_firmware(bootfw); release_firmware(ucode); @@ -5997,7 +6407,7 @@ static int ipw_wx_set_mode(struct net_device *dev, #endif priv->ieee->iw_mode = wrqu->mode; - ipw_adapter_restart(priv); + queue_work(priv->workqueue, &priv->adapter_restart); return err; } @@ -6149,9 +6559,8 @@ static int ipw_wx_set_wap(struct net_device *dev, if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n"); ipw_disassociate(priv); - } else { + } else if (!(priv->status & (STATUS_SCANNING))) ipw_associate(priv); - } return 0; } @@ -6220,9 +6629,8 @@ static int ipw_wx_set_essid(struct net_device *dev, if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n"); ipw_disassociate(priv); - } else { + } else if (!(priv->status & (STATUS_SCANNING))) ipw_associate(priv); - } return 0; } @@ -6383,10 +6791,10 @@ static int ipw_wx_set_rate(struct net_device *dev, if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); ipw_disassociate(priv); + } else if (!(priv->status & (STATUS_SCANNING))) { + /* We are not yet associated, so kick one off... */ + ipw_associate(priv); } - } else { - /* We are not yet associated, so kick one off... */ - ipw_associate(priv); } return 0; @@ -6635,11 +7043,10 @@ static int ipw_wx_get_power(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); - if (!(priv->power_mode & IPW_POWER_ENABLED)) { + if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; - } else { + else wrqu->power.disabled = 0; - } IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); @@ -6764,6 +7171,9 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, } else ipw_send_supported_rates(priv, &priv->rates); + /* Update the band LEDs */ + ipw_led_band_on(priv); + IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", mode & IEEE_A ? 'a' : '.', mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); @@ -6870,7 +7280,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, if (enable) { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { priv->net_dev->type = ARPHRD_IEEE80211; - ipw_adapter_restart(priv); + queue_work(priv->workqueue, &priv->adapter_restart); } ipw_set_channel(priv, parms[1]); @@ -6878,7 +7288,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, if (priv->ieee->iw_mode != IW_MODE_MONITOR) return 0; priv->net_dev->type = ARPHRD_ETHER; - ipw_adapter_restart(priv); + queue_work(priv->workqueue, &priv->adapter_restart); } return 0; } @@ -6889,7 +7299,7 @@ static int ipw_wx_reset(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("RESET\n"); - ipw_adapter_restart(priv); + queue_work(priv->workqueue, &priv->adapter_restart); return 0; } #endif // CONFIG_IPW_MONITOR @@ -6925,6 +7335,10 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, + IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy, + IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, + IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, + IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, }; #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV @@ -6993,6 +7407,8 @@ static struct iw_handler_def ipw_wx_handler_def = { .private_args = ipw_priv_args, }; +static struct iw_public_data ipw_wx_data; + /* * Get wireless statistics. * Called by /proc/net/wireless @@ -7057,7 +7473,7 @@ static inline void init_sys_config(struct ipw_sys_config *sys_config) sys_config->dot11g_auto_detection = 0; sys_config->enable_cts_to_self = 0; sys_config->bt_coexist_collision_thr = 0; - sys_config->pass_noise_stats_to_host = 1; + sys_config->pass_noise_stats_to_host = 0; //1 -- fix for 256 } static int ipw_net_open(struct net_device *dev) @@ -7131,7 +7547,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; tfd->u.data.cmd_id = DINO_CMD_TX; - tfd->u.data.len = txb->payload_size; + tfd->u.data.len = cpu_to_le16(txb->payload_size); remaining_bytes = txb->payload_size; if (unlikely(!unicast)) tfd->u.data.tx_flags = DCT_FLAG_NO_WEP; @@ -7149,8 +7565,14 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); /* payload */ - tfd->u.data.num_chunks = min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags); - for (i = 0; i < tfd->u.data.num_chunks; i++) { + tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2), + txb->nr_frags)); + IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n", + txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks)); + for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) { + IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n", + i, le32_to_cpu(tfd->u.data.num_chunks), + txb->fragments[i]->len - hdr_len); IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n", i, tfd->u.data.num_chunks, txb->fragments[i]->len - hdr_len); @@ -7158,11 +7580,13 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) txb->fragments[i]->len - hdr_len); tfd->u.data.chunk_ptr[i] = - pci_map_single(priv->pci_dev, - txb->fragments[i]->data + hdr_len, - txb->fragments[i]->len - hdr_len, - PCI_DMA_TODEVICE); - tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len; + cpu_to_le32(pci_map_single + (priv->pci_dev, + txb->fragments[i]->data + hdr_len, + txb->fragments[i]->len - hdr_len, + PCI_DMA_TODEVICE)); + tfd->u.data.chunk_len[i] = + cpu_to_le16(txb->fragments[i]->len - hdr_len); } if (i != txb->nr_frags) { @@ -7177,7 +7601,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) remaining_bytes); skb = alloc_skb(remaining_bytes, GFP_ATOMIC); if (skb != NULL) { - tfd->u.data.chunk_len[i] = remaining_bytes; + tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); for (j = i; j < txb->nr_frags; j++) { int size = txb->fragments[j]->len - hdr_len; printk(KERN_INFO "Adding frag %d %d...\n", @@ -7188,10 +7612,14 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) dev_kfree_skb_any(txb->fragments[i]); txb->fragments[i] = skb; tfd->u.data.chunk_ptr[i] = - pci_map_single(priv->pci_dev, skb->data, - tfd->u.data.chunk_len[i], - PCI_DMA_TODEVICE); - tfd->u.data.num_chunks++; + cpu_to_le32(pci_map_single + (priv->pci_dev, skb->data, + tfd->u.data.chunk_len[i], + PCI_DMA_TODEVICE)); + + tfd->u.data.num_chunks = + cpu_to_le32(le32_to_cpu(tfd->u.data.num_chunks) + + 1); } } @@ -7227,6 +7655,7 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, } ipw_tx_skb(priv, txb); + ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -7260,7 +7689,7 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(priv->mac_addr)); - ipw_adapter_restart(priv); + queue_work(priv->workqueue, &priv->adapter_restart); return 0; } @@ -7414,6 +7843,46 @@ static void ipw_rf_kill(void *adapter) spin_unlock_irqrestore(&priv->lock, flags); } +void ipw_link_up(struct ipw_priv *priv) +{ + netif_carrier_on(priv->net_dev); + if (netif_queue_stopped(priv->net_dev)) { + IPW_DEBUG_NOTIF("waking queue\n"); + netif_wake_queue(priv->net_dev); + } else { + IPW_DEBUG_NOTIF("starting queue\n"); + netif_start_queue(priv->net_dev); + } + + ipw_reset_stats(priv); + /* Ensure the rate is updated immediately */ + priv->last_rate = ipw_get_current_rate(priv); + ipw_gather_stats(priv); + ipw_led_link_up(priv); + notify_wx_assoc_event(priv); + + if (priv->config & CFG_BACKGROUND_SCAN) + queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); +} + +void ipw_link_down(struct ipw_priv *priv) +{ + ipw_led_link_down(priv); + netif_carrier_off(priv->net_dev); + netif_stop_queue(priv->net_dev); + notify_wx_assoc_event(priv); + + /* Cancel any queued work ... */ + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->adhoc_check); + cancel_delayed_work(&priv->gather_stats); + + ipw_reset_stats(priv); + + /* Queue up another scan... */ + queue_work(priv->workqueue, &priv->request_scan); +} + static int ipw_setup_deferred_work(struct ipw_priv *priv) { int ret = 0; @@ -7436,6 +7905,13 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv); INIT_WORK(&priv->roam, ipw_roam, priv); INIT_WORK(&priv->scan_check, ipw_scan_check, priv); + INIT_WORK(&priv->link_up, (void (*)(void *))ipw_link_up, priv); + INIT_WORK(&priv->link_down, (void (*)(void *))ipw_link_down, priv); + INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_led_link_on, priv); + INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_led_link_off, + priv); + INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_led_activity_off, + priv); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw_irq_tasklet, (unsigned long)priv); @@ -7636,8 +8112,9 @@ static int ipw_up(struct ipw_priv *priv) rc = ipw_config(priv); if (!rc) { IPW_DEBUG_INFO("Configured device on count %i\n", i); + ipw_led_init(priv); + ipw_led_radio_on(priv); priv->notif_missed_beacons = 0; - netif_start_queue(priv->net_dev); return 0; } else { IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", @@ -7675,11 +8152,12 @@ static void ipw_down(struct ipw_priv *priv) netif_stop_queue(priv->net_dev); ipw_stop_nic(priv); + + ipw_led_radio_off(priv); } static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { -#ifdef CONFIG_IEEE80211_WPA struct iwreq *wrq = (struct iwreq *)rq; int ret = -1; switch (cmd) { @@ -7691,8 +8169,6 @@ static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EOPNOTSUPP; } -#endif /* CONFIG_IEEE80211_WPA */ - return -EOPNOTSUPP; } @@ -7739,7 +8215,7 @@ static struct pci_device_id card_ids[] = { {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ - {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 2225BG */ + {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ @@ -7764,6 +8240,8 @@ static struct attribute *ipw_sysfs_entries[] = { &dev_attr_eeprom_delay.attr, &dev_attr_ucode_version.attr, &dev_attr_rtc.attr, + &dev_attr_scan_age.attr, + &dev_attr_led.attr, NULL }; @@ -7789,6 +8267,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv = ieee80211_priv(net_dev); priv->ieee = netdev_priv(net_dev); + priv->net_dev = net_dev; priv->pci_dev = pdev; #ifdef CONFIG_IPW_DEBUG @@ -7843,6 +8322,12 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Initialize module parameter values here */ + + /* We default to disabling the LED code as right now it causes + * too many systems to lock up... */ + if (!led) + priv->config |= CFG_NO_LED; + if (associate) priv->config |= CFG_ASSOCIATE; else @@ -7893,14 +8378,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->adapter = IPW_2915ABG; priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; } else { - if (priv->pci_dev->device == 0x4221) - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2225BG Network " - "Connection\n"); - else - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2200BG Network " - "Connection\n"); + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2200BG Network " + "Connection\n"); priv->ieee->abg_true = 0; band = IEEE80211_24GHZ_BAND; @@ -7933,6 +8413,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); + ipw_wx_data.spy_data = &priv->ieee->spy_data; + ipw_wx_data.ieee80211 = priv->ieee; + priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; priv->ieee->set_security = shim__set_security; @@ -7944,6 +8427,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) net_dev->set_multicast_list = ipw_net_set_multicast_list; net_dev->set_mac_address = ipw_net_set_mac_address; net_dev->get_wireless_stats = ipw_get_wireless_stats; + net_dev->wireless_data = &ipw_wx_data; net_dev->wireless_handlers = &ipw_wx_handler_def; net_dev->ethtool_ops = &ipw_ethtool_ops; net_dev->irq = pdev->irq; @@ -7960,12 +8444,12 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = register_netdev(net_dev); if (err) { IPW_ERROR("failed to register network device\n"); - goto out_remove_group; + goto out_remove_sysfs; } return 0; - out_remove_group: + out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); out_release_irq: free_irq(pdev->irq, priv); @@ -8005,17 +8489,17 @@ static void ipw_pci_remove(struct pci_dev *pdev) } ipw_tx_queue_free(priv); + ipw_led_shutdown(priv); + /* ipw_down will ensure that there is no more pending work * in the workqueue's, so we can safely remove them now. */ - if (priv->workqueue) { - cancel_delayed_work(&priv->adhoc_check); - cancel_delayed_work(&priv->gather_stats); - cancel_delayed_work(&priv->request_scan); - cancel_delayed_work(&priv->rf_kill); - cancel_delayed_work(&priv->scan_check); - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; - } + cancel_delayed_work(&priv->adhoc_check); + cancel_delayed_work(&priv->gather_stats); + cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->rf_kill); + cancel_delayed_work(&priv->scan_check); + destroy_workqueue(priv->workqueue); + priv->workqueue = NULL; free_irq(pdev->irq, priv); iounmap(priv->hw_base); @@ -8138,6 +8622,10 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); +module_param(led, int, 0444); +MODULE_PARM_DESC(auto_create, + "enable led control on some systems (default 0 off)\n"); + module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 068027963181..1b339cb7a522 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -403,9 +403,9 @@ struct clx2_tx_queue { #define RX_FREE_BUFFERS 32 #define RX_LOW_WATERMARK 8 -#define SUP_RATE_11A_MAX_NUM_CHANNELS (8) -#define SUP_RATE_11B_MAX_NUM_CHANNELS (4) -#define SUP_RATE_11G_MAX_NUM_CHANNELS (12) +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 // Used for passing to driver number of successes and failures per rate struct rate_histogram { @@ -890,6 +890,9 @@ struct ipw_cmd { #define STATUS_SCANNING (1<<21) #define STATUS_SCAN_ABORTING (1<<22) +#define STATUS_LED_LINK_ON (1<<24) +#define STATUS_LED_ACT_ON (1<<25) + #define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */ #define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */ #define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */ @@ -905,6 +908,8 @@ struct ipw_cmd { #define CFG_ASSOCIATE (1<<6) #define CFG_FIXED_RATE (1<<7) #define CFG_ADHOC_CREATE (1<<8) +#define CFG_NO_LED (1<<9) +#define CFG_BACKGROUND_SCAN (1<<10) #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ @@ -1046,9 +1051,24 @@ struct ipw_priv { struct work_struct abort_scan; struct work_struct roam; struct work_struct scan_check; + struct work_struct link_up; + struct work_struct link_down; struct tasklet_struct irq_tasklet; + /* LED related variables and work_struct */ + u8 nic_type; + u32 led_activity_on; + u32 led_activity_off; + u32 led_association_on; + u32 led_association_off; + u32 led_ofdm_on; + u32 led_ofdm_off; + + struct work_struct led_link_on; + struct work_struct led_link_off; + struct work_struct led_act_off; + #define IPW_2200BG 1 #define IPW_2915ABG 2 u8 adapter; @@ -1126,6 +1146,8 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DL_RF_KILL (1<<17) #define IPW_DL_FW_ERRORS (1<<18) +#define IPW_DL_LED (1<<19) + #define IPW_DL_ORD (1<<20) #define IPW_DL_FRAG (1<<21) @@ -1151,6 +1173,7 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a) #define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a) #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a) +#define IPW_DEBUG_LED(f, a...) IPW_DEBUG(IPW_DL_LED, f, ## a) #define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a) #define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a) #define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a) @@ -1268,25 +1291,25 @@ do { if (ipw_debug_level & (level)) \ #define CX2_DMA_I_DMA_CONTROL 0x003000A4 #define CX2_DMA_I_CB_BASE 0x003000A0 -#define CX2_TX_CMD_QUEUE_BD_BASE (0x00000200) -#define CX2_TX_CMD_QUEUE_BD_SIZE (0x00000204) -#define CX2_TX_QUEUE_0_BD_BASE (0x00000208) +#define CX2_TX_CMD_QUEUE_BD_BASE 0x00000200 +#define CX2_TX_CMD_QUEUE_BD_SIZE 0x00000204 +#define CX2_TX_QUEUE_0_BD_BASE 0x00000208 #define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C) -#define CX2_TX_QUEUE_1_BD_BASE (0x00000210) -#define CX2_TX_QUEUE_1_BD_SIZE (0x00000214) -#define CX2_TX_QUEUE_2_BD_BASE (0x00000218) +#define CX2_TX_QUEUE_1_BD_BASE 0x00000210 +#define CX2_TX_QUEUE_1_BD_SIZE 0x00000214 +#define CX2_TX_QUEUE_2_BD_BASE 0x00000218 #define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C) -#define CX2_TX_QUEUE_3_BD_BASE (0x00000220) -#define CX2_TX_QUEUE_3_BD_SIZE (0x00000224) -#define CX2_RX_BD_BASE (0x00000240) -#define CX2_RX_BD_SIZE (0x00000244) -#define CX2_RFDS_TABLE_LOWER (0x00000500) - -#define CX2_TX_CMD_QUEUE_READ_INDEX (0x00000280) -#define CX2_TX_QUEUE_0_READ_INDEX (0x00000284) -#define CX2_TX_QUEUE_1_READ_INDEX (0x00000288) +#define CX2_TX_QUEUE_3_BD_BASE 0x00000220 +#define CX2_TX_QUEUE_3_BD_SIZE 0x00000224 +#define CX2_RX_BD_BASE 0x00000240 +#define CX2_RX_BD_SIZE 0x00000244 +#define CX2_RFDS_TABLE_LOWER 0x00000500 + +#define CX2_TX_CMD_QUEUE_READ_INDEX 0x00000280 +#define CX2_TX_QUEUE_0_READ_INDEX 0x00000284 +#define CX2_TX_QUEUE_1_READ_INDEX 0x00000288 #define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C) -#define CX2_TX_QUEUE_3_READ_INDEX (0x00000290) +#define CX2_TX_QUEUE_3_READ_INDEX 0x00000290 #define CX2_RX_READ_INDEX (0x000002A0) #define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) @@ -1333,15 +1356,15 @@ do { if (ipw_debug_level & (level)) \ #define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ /* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/ -#define EEPROM_NIC_TYPE_STANDARD 0 -#define EEPROM_NIC_TYPE_DELL 1 -#define EEPROM_NIC_TYPE_FUJITSU 2 -#define EEPROM_NIC_TYPE_IBM 3 -#define EEPROM_NIC_TYPE_HP 4 +#define EEPROM_NIC_TYPE_0 0 +#define EEPROM_NIC_TYPE_1 1 +#define EEPROM_NIC_TYPE_2 2 +#define EEPROM_NIC_TYPE_3 3 +#define EEPROM_NIC_TYPE_4 4 #define FW_MEM_REG_LOWER_BOUND 0x00300000 #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) - +#define CX2_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) #define EEPROM_BIT_SK (1<<0) #define EEPROM_BIT_CS (1<<1) #define EEPROM_BIT_DI (1<<2) -- cgit v1.2.3-59-g8ed1b From c848d0af404f00835f038e370005733d90a186fd Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 24 Aug 2005 21:56:24 -0500 Subject: Catch ipw2200 up to equivelancy with v1.0.3 * Fix #616 problem with OOPS on module load (thanks to Yi Zhu) * Fixed problem with led module parameter being described as 'auto_create' * Added support to merge between adhoc networks (thanks to Mohamed Abbas) * Added semaphore lock at the driver's entry points to protect against re-entry (thanks to Mohamed Abbas) * Added semaphore lock to background scheduled driver actions (thanks to Mohamed Abbas) * Changed how signal quality is reported for scan output (thanks to Peter Jones) * Fixed how high/low clamp values of signal quality are reported so a more consistent ramp is provided (thanks to Bill Moss) * Fix #624 problem with duplicate addresses (again) (thanks to Bernard Blackham) * Fix #385 problem with fragmentation and certain sized packets (thanks to Mohamed Abbas) * Modified iwconfig network name if RF kill is enabled to say 'radio off' * Fix #382 problem with driver not responding to probe requests in Ad-Hoc mode (thanks to Mohamed Abbas) Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 841 ++++++++++++++++++++++++++++++++--------- drivers/net/wireless/ipw2200.h | 5 +- 2 files changed, 668 insertions(+), 178 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index ea7a3dcf1daa..0bf1931ac5f3 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -32,7 +32,7 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.2" +#define IPW2200_VERSION "1.0.3" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" #define DRV_VERSION IPW2200_VERSION @@ -68,9 +68,10 @@ static void ipw_tx_queue_free(struct ipw_priv *); static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *); static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *); static void ipw_rx_queue_replenish(void *); - static int ipw_up(struct ipw_priv *); +static void ipw_bg_up(void *); static void ipw_down(struct ipw_priv *); +static void ipw_bg_down(void *); static int ipw_config(struct ipw_priv *); static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); @@ -473,6 +474,11 @@ static void ipw_dump_nic_event_log(struct ipw_priv *priv) } } +static inline int ipw_is_init(struct ipw_priv *priv) +{ + return (priv->status & STATUS_INIT) ? 1 : 0; +} + static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len) { u32 addr, field_info, field_len, field_count, total_len; @@ -698,6 +704,14 @@ void ipw_led_link_on(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } +static void ipw_bg_led_link_on(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_led_link_on(data); + up(&priv->sem); +} + void ipw_led_link_off(struct ipw_priv *priv) { unsigned long flags; @@ -734,6 +748,14 @@ void ipw_led_link_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } +static void ipw_bg_led_link_off(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_led_link_off(data); + up(&priv->sem); +} + void ipw_led_activity_on(struct ipw_priv *priv) { unsigned long flags; @@ -762,6 +784,7 @@ void ipw_led_activity_on(struct ipw_priv *priv) priv->status |= STATUS_LED_ACT_ON; + cancel_delayed_work(&priv->led_act_off); queue_delayed_work(priv->workqueue, &priv->led_act_off, LD_TIME_ACT_ON); } else { @@ -801,13 +824,22 @@ void ipw_led_activity_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } +static void ipw_bg_led_activity_off(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_led_activity_off(data); + up(&priv->sem); +} + void ipw_led_band_on(struct ipw_priv *priv) { unsigned long flags; u32 led; /* Only nic type 1 supports mode LEDs */ - if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) + if (priv->config & CFG_NO_LED || + priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network) return; spin_lock_irqsave(&priv->lock, flags); @@ -993,7 +1025,9 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { struct ipw_priv *priv = dev_get_drvdata(d); +#ifdef CONFIG_IPW_DEBUG struct net_device *dev = priv->net_dev; +#endif char buffer[] = "00000000"; unsigned long len = (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; @@ -1704,6 +1738,14 @@ static void ipw_adapter_restart(void *adapter) } } +static void ipw_bg_adapter_restart(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_adapter_restart(data); + up(&priv->sem); +} + #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) static void ipw_scan_check(void *data) @@ -1717,6 +1759,14 @@ static void ipw_scan_check(void *data) } } +static void ipw_bg_scan_check(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_scan_check(data); + up(&priv->sem); +} + static int ipw_send_scan_request_ext(struct ipw_priv *priv, struct ipw_scan_request_ext *request) { @@ -2982,6 +3032,8 @@ static int ipw_load(struct ipw_priv *priv) /* Ensure interrupts are disabled */ ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); + /* ack pending interrupts */ + ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); /* kick start the device */ ipw_start_nic(priv); @@ -3350,9 +3402,21 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) } -static void ipw_disassociate(void *data) +static int ipw_disassociate(void *data) { + struct ipw_priv *priv = data; + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) + return 0; ipw_send_disassociate(data, 0); + return 1; +} + +static void ipw_bg_disassociate(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_disassociate(data); + up(&priv->sem); } struct ipw_status_code { @@ -3571,8 +3635,6 @@ static u32 ipw_get_current_rate(struct ipw_priv *priv) return 0; } -#define PERFECT_RSSI (-20) -#define WORST_RSSI (-85) #define IPW_STATS_INTERVAL (2 * HZ) static void ipw_gather_stats(struct ipw_priv *priv) { @@ -3663,19 +3725,19 @@ static void ipw_gather_stats(struct ipw_priv *priv) tx_quality, tx_failures_delta, tx_packets_delta); rssi = average_value(&priv->average_rssi); - if (rssi > PERFECT_RSSI) + signal_quality = + (100 * + (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * + (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) - + (priv->ieee->perfect_rssi - rssi) * + (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) + + 62 * (priv->ieee->perfect_rssi - rssi))) / + ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) * + (priv->ieee->perfect_rssi - priv->ieee->worst_rssi)); + if (signal_quality > 100) signal_quality = 100; - else if (rssi < WORST_RSSI) + else if (signal_quality < 1) signal_quality = 0; - else /* qual = 100a^2 - 15ab + 62b^2 / a^2 */ - signal_quality = - (100 * - (PERFECT_RSSI - WORST_RSSI) * - (PERFECT_RSSI - WORST_RSSI) - - (PERFECT_RSSI - rssi) * - (15 * (PERFECT_RSSI - WORST_RSSI) + - 62 * (PERFECT_RSSI - rssi))) / - ((PERFECT_RSSI - WORST_RSSI) * (PERFECT_RSSI - WORST_RSSI)); IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", signal_quality, rssi); @@ -3705,6 +3767,14 @@ static void ipw_gather_stats(struct ipw_priv *priv) IPW_STATS_INTERVAL); } +static void ipw_bg_gather_stats(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_gather_stats(data); + up(&priv->sem); +} + static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, int missed_count) { @@ -4456,6 +4526,14 @@ static void ipw_rx_queue_replenish(void *data) ipw_rx_queue_restock(priv); } +static void ipw_bg_rx_queue_replenish(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_rx_queue_replenish(data); + up(&priv->sem); +} + /* Assumes that the skb field of the buffers in 'pool' is kept accurate. * If an SKB has been detached, the POOL needs to have it's SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to @@ -4715,6 +4793,215 @@ struct ipw_network_match { struct ipw_supported_rates rates; }; +static int ipw_find_adhoc_network(struct ipw_priv *priv, + struct ipw_network_match *match, + struct ieee80211_network *network, + int roaming) +{ + struct ipw_supported_rates rates; + + /* Verify that this network's capability is compatible with the + * current mode (AdHoc or Infrastructure) */ + if ((priv->ieee->iw_mode == IW_MODE_ADHOC && + !(network->capability & WLAN_CAPABILITY_IBSS))) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to " + "capability mismatch.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + + /* If we do not have an ESSID for this AP, we can not associate with + * it */ + if (network->flags & NETWORK_EMPTY_ESSID) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of hidden ESSID.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + + if (unlikely(roaming)) { + /* If we are roaming, then ensure check if this is a valid + * network to try and roam to */ + if ((network->ssid_len != match->network->ssid_len) || + memcmp(network->ssid, match->network->ssid, + network->ssid_len)) { + IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded " + "because of non-network ESSID.\n", + escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + } else { + /* If an ESSID has been configured then compare the broadcast + * ESSID to ours */ + if ((priv->config & CFG_STATIC_ESSID) && + ((network->ssid_len != priv->essid_len) || + memcmp(network->ssid, priv->essid, + min(network->ssid_len, priv->essid_len)))) { + char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + strncpy(escaped, + escape_essid(network->ssid, network->ssid_len), + sizeof(escaped)); + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of ESSID mismatch: '%s'.\n", + escaped, MAC_ARG(network->bssid), + escape_essid(priv->essid, + priv->essid_len)); + return 0; + } + } + + /* If the old network rate is better than this one, don't bother + * testing everything else. */ + + if (network->time_stamp[0] < match->network->time_stamp[0]) { + IPW_DEBUG_MERGE + ("Network '%s excluded because newer than current network.\n", + escape_essid(match->network->ssid, + match->network->ssid_len)); + return 0; + } else if (network->time_stamp[1] < match->network->time_stamp[1]) { + IPW_DEBUG_MERGE + ("Network '%s excluded because newer than current network.\n", + escape_essid(match->network->ssid, + match->network->ssid_len)); + return 0; + } + + /* Now go through and see if the requested network is valid... */ + if (priv->ieee->scan_age != 0 && + time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of age: %lums.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid), + (jiffies - network->last_scanned) / (HZ / 100)); + return 0; + } + + if ((priv->config & CFG_STATIC_CHANNEL) && + (network->channel != priv->channel)) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of channel mismatch: %d != %d.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid), + network->channel, priv->channel); + return 0; + } + + /* Verify privacy compatability */ + if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != + ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of privacy mismatch: %s != %s.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid), + priv->capability & CAP_PRIVACY_ON ? "on" : + "off", + network->capability & + WLAN_CAPABILITY_PRIVACY ? "on" : "off"); + return 0; + } + + if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of the same BSSID match: " MAC_FMT + ".\n", escape_essid(network->ssid, + network->ssid_len), + MAC_ARG(network->bssid), MAC_ARG(priv->bssid)); + return 0; + } + + /* Filter out any incompatible freq / mode combinations */ + if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of invalid frequency/mode " + "combination.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + + /* Ensure that the rates supported by the driver are compatible with + * this AP, including verification of basic rates (mandatory) */ + if (!ipw_compatible_rates(priv, network, &rates)) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because configured rate mask excludes " + "AP mandatory rate.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + + if (rates.num_rates == 0) { + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " + "because of no compatible rates.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + + /* TODO: Perform any further minimal comparititive tests. We do not + * want to put too much policy logic here; intelligent scan selection + * should occur within a generic IEEE 802.11 user space tool. */ + + /* Set up 'new' AP to this network */ + ipw_copy_rates(&match->rates, &rates); + match->network = network; + IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + + return 1; +} + +static void ipw_merge_adhoc_network(void *data) +{ + struct ipw_priv *priv = data; + struct ieee80211_network *network = NULL; + struct ipw_network_match match = { + .network = priv->assoc_network + }; + + if ((priv->status & STATUS_ASSOCIATED) + && (priv->ieee->iw_mode == IW_MODE_ADHOC)) { + /* First pass through ROAM process -- look for a better + * network */ + unsigned long flags; + + spin_lock_irqsave(&priv->ieee->lock, flags); + list_for_each_entry(network, &priv->ieee->network_list, list) { + if (network != priv->assoc_network) + ipw_find_adhoc_network(priv, &match, network, + 1); + } + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + if (match.network == priv->assoc_network) { + IPW_DEBUG_MERGE("No better ADHOC in this network to " + "merge to.\n"); + return; + } + + down(&priv->sem); + if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { + IPW_DEBUG_MERGE("remove network %s\n", + escape_essid(priv->essid, + priv->essid_len)); + ipw_remove_current_network(priv); + } + + ipw_disassociate(priv); + priv->assoc_network = match.network; + up(&priv->sem); + return; + } + +} + static int ipw_best_network(struct ipw_priv *priv, struct ipw_network_match *match, struct ieee80211_network *network, int roaming) @@ -4997,6 +5284,14 @@ static void ipw_adhoc_check(void *data) priv->assoc_request.beacon_interval); } +static void ipw_bg_adhoc_check(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_adhoc_check(data); + up(&priv->sem); +} + #ifdef CONFIG_IPW_DEBUG static void ipw_debug_config(struct ipw_priv *priv) { @@ -5181,10 +5476,9 @@ static int ipw_request_scan(struct ipw_priv *priv) /* If we are roaming, then make this a directed scan for the current * network. Otherwise, ensure that every other scan is a fast * channel hop scan */ - if ((priv->status & STATUS_ROAMING) - || (!(priv->status & STATUS_ASSOCIATED) - && (priv->config & CFG_STATIC_ESSID) - && (le32_to_cpu(scan.full_scan_index) % 2))) { + if ((priv->status & STATUS_ROAMING) || (!(priv->status & STATUS_ASSOCIATED) && (priv->config & CFG_STATIC_ESSID) && (le32_to_cpu(scan.full_scan_index) % 2))) { /* || ( + (priv->status & STATUS_ASSOCIATED) && + (priv->ieee->iw_mode == IW_MODE_ADHOC))) { */ err = ipw_send_ssid(priv, priv->essid, priv->essid_len); if (err) { IPW_DEBUG_HC @@ -5257,6 +5551,22 @@ static int ipw_request_scan(struct ipw_priv *priv) return 0; } +static void ipw_bg_request_scan(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_request_scan(data); + up(&priv->sem); +} + +static void ipw_bg_abort_scan(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_abort_scan(data); + up(&priv->sem); +} + /* Support for wpa_supplicant. Will be replaced with WEXT once * they get WPA support. */ @@ -5473,8 +5783,7 @@ void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) /* make sure WPA is enabled */ ipw_wpa_enable(priv, 1); - if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) - ipw_disassociate(priv); + ipw_disassociate(priv); } static int ipw_wpa_set_wpa_ie(struct net_device *dev, @@ -5830,6 +6139,12 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->sys_config.dot11g_auto_detection = 1; else priv->sys_config.dot11g_auto_detection = 0; + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + priv->sys_config.answer_broadcast_ssid_probe = 1; + else + priv->sys_config.answer_broadcast_ssid_probe = 0; + err = ipw_send_system_config(priv, &priv->sys_config); if (err) { IPW_DEBUG_HC("Attempt to send sys config command failed.\n"); @@ -5933,7 +6248,15 @@ static void ipw_roam(void *data) priv->status &= ~STATUS_ROAMING; } -static void ipw_associate(void *data) +static void ipw_bg_roam(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_roam(data); + up(&priv->sem); +} + +static int ipw_associate(void *data) { struct ipw_priv *priv = data; @@ -5945,11 +6268,23 @@ static void ipw_associate(void *data) struct list_head *element; unsigned long flags; + if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { + IPW_DEBUG_ASSOC + ("Not attempting association (already in progress)\n"); + return 0; + } + + if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { + IPW_DEBUG_ASSOC + ("Not attempting association (scanning or not initialized)\n"); + return 0; + } + if (!(priv->config & CFG_ASSOCIATE) && !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) { IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); - return; + return 0; } /* Protect our use of the network_list */ @@ -5984,10 +6319,20 @@ static void ipw_associate(void *data) queue_delayed_work(priv->workqueue, &priv->request_scan, SCAN_INTERVAL); - return; + return 0; } ipw_associate_network(priv, network, rates, 0); + + return 1; +} + +static void ipw_bg_associate(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_associate(data); + up(&priv->sem); } static inline void ipw_handle_data_packet(struct ipw_priv *priv, @@ -6037,6 +6382,10 @@ static inline int is_network_packet(struct ipw_priv *priv, * this network, discarding packets coming from ourselves */ switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ + /* packets from our adapter are dropped (echo) */ + if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) + return 0; + /* {broad,multi}cast packets to our IBSS go through */ if (is_broadcast_ether_addr(header->addr1) || is_multicast_ether_addr(header->addr1)) @@ -6045,9 +6394,12 @@ static inline int is_network_packet(struct ipw_priv *priv, /* packets to our adapter go through */ return !memcmp(header->addr1, priv->net_dev->dev_addr, ETH_ALEN); - break; case IW_MODE_INFRA: /* Header: Dest. | AP{BSSID} | Source */ + /* packets from our adapter are dropped (echo) */ + if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN)) + return 0; + /* {broad,multi}cast packets to our IBSS go through */ if (is_broadcast_ether_addr(header->addr1) || is_multicast_ether_addr(header->addr1)) @@ -6056,7 +6408,6 @@ static inline int is_network_packet(struct ipw_priv *priv, /* packets to our adapter go through */ return !memcmp(header->addr1, priv->net_dev->dev_addr, ETH_ALEN); - break; } return 1; @@ -6101,9 +6452,13 @@ static void ipw_rx(struct ipw_priv *priv) switch (pkt->header.message_type) { case RX_FRAME_TYPE: /* 802.11 frame */ { struct ieee80211_rx_stats stats = { - .rssi = pkt->u.frame.rssi_dbm - + .rssi = + le16_to_cpu(pkt->u.frame.rssi_dbm) - IPW_RSSI_TO_DBM, - /* .signal = le16_to_cpu(pkt->u.frame.signal), */ + .signal = + le16_to_cpu(pkt->u.frame.signal), + .noise = + le16_to_cpu(pkt->u.frame.noise), .rate = pkt->u.frame.rate, .mac_time = jiffies, .received_channel = @@ -6120,6 +6475,8 @@ static void ipw_rx(struct ipw_priv *priv) stats.mask |= IEEE80211_STATMASK_RSSI; if (stats.signal != 0) stats.mask |= IEEE80211_STATMASK_SIGNAL; + if (stats.noise != 0) + stats.mask |= IEEE80211_STATMASK_NOISE; if (stats.rate != 0) stats.mask |= IEEE80211_STATMASK_RATE; @@ -6179,11 +6536,34 @@ static void ipw_rx(struct ipw_priv *priv) || (WLAN_FC_GET_STYPE (le16_to_cpu(header->frame_ctl)) - == IEEE80211_STYPE_BEACON)) - && !memcmp(header->addr3, - priv->bssid, ETH_ALEN)) - ipw_add_station(priv, - header->addr2); + == IEEE80211_STYPE_BEACON))) { + if (!memcmp + (header->addr3, priv->bssid, + ETH_ALEN)) + ipw_add_station(priv, + header-> + addr2); + else { + struct + ieee80211_probe_response + *beacon; + beacon = + (struct + ieee80211_probe_response + *)header; + if (le16_to_cpu + (beacon-> + capability) & + WLAN_CAPABILITY_IBSS) + { + queue_work + (priv-> + workqueue, + &priv-> + merge_networks); + } + } + } break; case IEEE80211_FTYPE_CTL: @@ -6262,14 +6642,16 @@ static int ipw_wx_get_name(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - if (priv->status & STATUS_RF_KILL_MASK) { + down(&priv->sem); + if (priv->status & STATUS_RF_KILL_MASK) strcpy(wrqu->name, "radio off"); - } else if (!(priv->status & STATUS_ASSOCIATED)) + else if (!(priv->status & STATUS_ASSOCIATED)) strcpy(wrqu->name, "unassociated"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", ipw_modes[priv->assoc_request.ieee_mode]); IPW_DEBUG_WX("Name: %s\n", wrqu->name); + up(&priv->sem); return 0; } @@ -6278,13 +6660,9 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) if (channel == 0) { IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); priv->config &= ~CFG_STATIC_CHANNEL; - if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | - STATUS_ASSOCIATING))) { - IPW_DEBUG_ASSOC("Attempting to associate with new " - "parameters.\n"); - ipw_associate(priv); - } - + IPW_DEBUG_ASSOC("Attempting to associate with new " + "parameters.\n"); + ipw_associate(priv); return 0; } @@ -6299,12 +6677,9 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); priv->channel = channel; - /* If we are currently associated, or trying to associate - * then see if this is a new channel (causing us to disassociate) */ - if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_ASSOC("Disassociating due to channel change.\n"); - ipw_disassociate(priv); - } else if (!(priv->status & (STATUS_SCANNING))) + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n"); + if (!ipw_disassociate(priv)) ipw_associate(priv); return 0; @@ -6316,6 +6691,7 @@ static int ipw_wx_set_freq(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_freq *fwrq = &wrqu->freq; + int ret = 0; /* if setting by freq convert to channel */ if (fwrq->e == 1) { @@ -6337,7 +6713,10 @@ static int ipw_wx_set_freq(struct net_device *dev, return -EOPNOTSUPP; IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); - return ipw_set_channel(priv, (u8) fwrq->m); + down(&priv->sem); + ret = ipw_set_channel(priv, (u8) fwrq->m); + up(&priv->sem); + return ret; } static int ipw_wx_get_freq(struct net_device *dev, @@ -6350,12 +6729,14 @@ static int ipw_wx_get_freq(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured CHANNEL then return that; otherwise return ANY */ + down(&priv->sem); if (priv->config & CFG_STATIC_CHANNEL || priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) wrqu->freq.m = priv->channel; else wrqu->freq.m = 0; + up(&priv->sem); IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); return 0; } @@ -6368,9 +6749,11 @@ static int ipw_wx_set_mode(struct net_device *dev, int err = 0; IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); - - if (wrqu->mode == priv->ieee->iw_mode) + down(&priv->sem); + if (wrqu->mode == priv->ieee->iw_mode) { + up(&priv->sem); return 0; + } switch (wrqu->mode) { #ifdef CONFIG_IPW_MONITOR @@ -6383,6 +6766,7 @@ static int ipw_wx_set_mode(struct net_device *dev, wrqu->mode = IW_MODE_INFRA; break; default: + up(&priv->sem); return -EINVAL; } @@ -6407,8 +6791,9 @@ static int ipw_wx_set_mode(struct net_device *dev, #endif priv->ieee->iw_mode = wrqu->mode; - queue_work(priv->workqueue, &priv->adapter_restart); + queue_work(priv->workqueue, &priv->adapter_restart); + up(&priv->sem); return err; } @@ -6417,10 +6802,10 @@ static int ipw_wx_get_mode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); - + up(&priv->sem); return 0; } @@ -6466,7 +6851,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->max_qual.qual = 100; /* TODO: Find real max RSSI and stick here */ range->max_qual.level = 0; - range->max_qual.noise = 0; + range->max_qual.noise = priv->ieee->worst_rssi + 0x100; range->max_qual.updated = 7; /* Updated all three */ range->avg_qual.qual = 70; @@ -6474,7 +6859,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->avg_qual.level = 0; /* FIXME to real average level */ range->avg_qual.noise = 0; range->avg_qual.updated = 7; /* Updated all three */ - + down(&priv->sem); range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); for (i = 0; i < range->num_bitrates; i++) @@ -6507,7 +6892,7 @@ static int ipw_wx_get_range(struct net_device *dev, break; } range->num_frequency = val; - + up(&priv->sem); IPW_DEBUG_WX("GET Range\n"); return 0; } @@ -6527,25 +6912,23 @@ static int ipw_wx_set_wap(struct net_device *dev, if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) return -EINVAL; - + down(&priv->sem); if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { /* we disable mandatory BSSID association */ IPW_DEBUG_WX("Setting AP BSSID to ANY\n"); priv->config &= ~CFG_STATIC_BSSID; - if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | - STATUS_ASSOCIATING))) { - IPW_DEBUG_ASSOC("Attempting to associate with new " - "parameters.\n"); - ipw_associate(priv); - } - + IPW_DEBUG_ASSOC("Attempting to associate with new " + "parameters.\n"); + ipw_associate(priv); + up(&priv->sem); return 0; } priv->config |= CFG_STATIC_BSSID; if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { IPW_DEBUG_WX("BSSID set to current BSSID.\n"); + up(&priv->sem); return 0; } @@ -6554,14 +6937,12 @@ static int ipw_wx_set_wap(struct net_device *dev, memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); - /* If we are currently associated, or trying to associate - * then see if this is a new BSSID (causing us to disassociate) */ - if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n"); - ipw_disassociate(priv); - } else if (!(priv->status & (STATUS_SCANNING))) + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n"); + if (!ipw_disassociate(priv)) ipw_associate(priv); + up(&priv->sem); return 0; } @@ -6572,6 +6953,7 @@ static int ipw_wx_get_wap(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ + down(&priv->sem); if (priv->config & CFG_STATIC_BSSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { wrqu->ap_addr.sa_family = ARPHRD_ETHER; @@ -6581,6 +6963,7 @@ static int ipw_wx_get_wap(struct net_device *dev, IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", MAC_ARG(wrqu->ap_addr.sa_data)); + up(&priv->sem); return 0; } @@ -6591,7 +6974,7 @@ static int ipw_wx_set_essid(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); char *essid = ""; /* ANY */ int length = 0; - + down(&priv->sem); if (wrqu->essid.flags && wrqu->essid.length) { length = wrqu->essid.length - 1; essid = extra; @@ -6599,13 +6982,12 @@ static int ipw_wx_set_essid(struct net_device *dev, if (length == 0) { IPW_DEBUG_WX("Setting ESSID to ANY\n"); priv->config &= ~CFG_STATIC_ESSID; - if (!(priv->status & (STATUS_SCANNING | STATUS_ASSOCIATED | - STATUS_ASSOCIATING))) { + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { IPW_DEBUG_ASSOC("Attempting to associate with new " "parameters.\n"); ipw_associate(priv); } - + up(&priv->sem); return 0; } @@ -6615,6 +6997,7 @@ static int ipw_wx_set_essid(struct net_device *dev, if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { IPW_DEBUG_WX("ESSID set to current ESSID.\n"); + up(&priv->sem); return 0; } @@ -6624,14 +7007,12 @@ static int ipw_wx_set_essid(struct net_device *dev, priv->essid_len = length; memcpy(priv->essid, essid, priv->essid_len); - /* If we are currently associated, or trying to associate - * then see if this is a new ESSID (causing us to disassociate) */ - if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n"); - ipw_disassociate(priv); - } else if (!(priv->status & (STATUS_SCANNING))) + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n"); + if (!ipw_disassociate(priv)) ipw_associate(priv); + up(&priv->sem); return 0; } @@ -6643,6 +7024,7 @@ static int ipw_wx_get_essid(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ + down(&priv->sem); if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", @@ -6655,7 +7037,7 @@ static int ipw_wx_get_essid(struct net_device *dev, wrqu->essid.length = 0; wrqu->essid.flags = 0; /* active */ } - + up(&priv->sem); return 0; } @@ -6668,11 +7050,12 @@ static int ipw_wx_set_nick(struct net_device *dev, IPW_DEBUG_WX("Setting nick to '%s'\n", extra); if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; - + down(&priv->sem); wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); memcpy(priv->nick, extra, wrqu->data.length); IPW_DEBUG_TRACE("<<\n"); + up(&priv->sem); return 0; } @@ -6683,9 +7066,11 @@ static int ipw_wx_get_nick(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("Getting nick\n"); + down(&priv->sem); wrqu->data.length = strlen(priv->nick) + 1; memcpy(extra, priv->nick, wrqu->data.length); wrqu->data.flags = 1; /* active */ + up(&priv->sem); return 0; } @@ -6778,25 +7163,26 @@ static int ipw_wx_set_rate(struct net_device *dev, apply: IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", mask, fixed ? "fixed" : "sub-rates"); - + down(&priv->sem); if (mask == IEEE80211_DEFAULT_RATES_MASK) priv->config &= ~CFG_FIXED_RATE; else priv->config |= CFG_FIXED_RATE; - if (priv->rates_mask != mask) { - priv->rates_mask = mask; - /* If we are already associated or are currently trying to - * associate, disassociate and try again */ - if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { - IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); - ipw_disassociate(priv); - } else if (!(priv->status & (STATUS_SCANNING))) { - /* We are not yet associated, so kick one off... */ - ipw_associate(priv); - } + if (priv->rates_mask == mask) { + IPW_DEBUG_WX("Mask set to current mask.\n"); + up(&priv->sem); + return 0; } + priv->rates_mask = mask; + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + + up(&priv->sem); return 0; } @@ -6805,8 +7191,9 @@ static int ipw_wx_get_rate(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + down(&priv->sem); wrqu->bitrate.value = priv->last_rate; - + up(&priv->sem); IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); return 0; } @@ -6816,18 +7203,20 @@ static int ipw_wx_set_rts(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); if (wrqu->rts.disabled) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; else { if (wrqu->rts.value < MIN_RTS_THRESHOLD || - wrqu->rts.value > MAX_RTS_THRESHOLD) + wrqu->rts.value > MAX_RTS_THRESHOLD) { + up(&priv->sem); return -EINVAL; - + } priv->rts_threshold = wrqu->rts.value; } ipw_send_rts_threshold(priv, priv->rts_threshold); + up(&priv->sem); IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); return 0; } @@ -6837,10 +7226,11 @@ static int ipw_wx_get_rts(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + down(&priv->sem); wrqu->rts.value = priv->rts_threshold; wrqu->rts.fixed = 0; /* no auto select */ wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); - + up(&priv->sem); IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); return 0; } @@ -6852,15 +7242,21 @@ static int ipw_wx_set_txpow(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct ipw_tx_power tx_power; int i; - - if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) + down(&priv->sem); + if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { + up(&priv->sem); return -EINPROGRESS; + } - if (wrqu->power.flags != IW_TXPOW_DBM) + if (wrqu->power.flags != IW_TXPOW_DBM) { + up(&priv->sem); return -EINVAL; + } - if ((wrqu->power.value > 20) || (wrqu->power.value < -12)) + if ((wrqu->power.value > 20) || (wrqu->power.value < -12)) { + up(&priv->sem); return -EINVAL; + } priv->tx_power = wrqu->power.value; @@ -6881,9 +7277,11 @@ static int ipw_wx_set_txpow(struct net_device *dev, if (ipw_send_tx_power(priv, &tx_power)) goto error; + up(&priv->sem); return 0; error: + up(&priv->sem); return -EIO; } @@ -6892,11 +7290,12 @@ static int ipw_wx_get_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); wrqu->power.value = priv->tx_power; wrqu->power.fixed = 1; wrqu->power.flags = IW_TXPOW_DBM; wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; + up(&priv->sem); IPW_DEBUG_WX("GET TX Power -> %s %d \n", wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value); @@ -6909,7 +7308,7 @@ static int ipw_wx_set_frag(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); if (wrqu->frag.disabled) priv->ieee->fts = DEFAULT_FTS; else { @@ -6921,6 +7320,7 @@ static int ipw_wx_set_frag(struct net_device *dev, } ipw_send_frag_threshold(priv, wrqu->frag.value); + up(&priv->sem); IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); return 0; } @@ -6930,10 +7330,11 @@ static int ipw_wx_get_frag(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + down(&priv->sem); wrqu->frag.value = priv->ieee->fts; wrqu->frag.fixed = 0; /* no auto select */ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); - + up(&priv->sem); IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); return 0; @@ -6961,8 +7362,12 @@ static int ipw_wx_set_scan(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("Start scan\n"); - if (ipw_request_scan(priv)) + down(&priv->sem); + if (ipw_request_scan(priv)) { + up(&priv->sem); return -EIO; + } + up(&priv->sem); return 0; } @@ -6996,16 +7401,17 @@ static int ipw_wx_set_power(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int err; - + down(&priv->sem); if (wrqu->power.disabled) { priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); + up(&priv->sem); return err; } IPW_DEBUG_WX("SET Power Management Mode -> off\n"); - + up(&priv->sem); return 0; } @@ -7017,6 +7423,7 @@ static int ipw_wx_set_power(struct net_device *dev, default: /* Otherwise we don't support it */ IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", wrqu->power.flags); + up(&priv->sem); return -EOPNOTSUPP; } @@ -7029,11 +7436,12 @@ static int ipw_wx_set_power(struct net_device *dev, err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); + up(&priv->sem); return err; } IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); - + up(&priv->sem); return 0; } @@ -7042,12 +7450,13 @@ static int ipw_wx_get_power(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; else wrqu->power.disabled = 0; + up(&priv->sem); IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); return 0; @@ -7060,7 +7469,7 @@ static int ipw_wx_set_powermode(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; int err; - + down(&priv->sem); if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { mode = IPW_POWER_AC; priv->power_mode = mode; @@ -7073,10 +7482,11 @@ static int ipw_wx_set_powermode(struct net_device *dev, if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); + up(&priv->sem); return err; } } - + up(&priv->sem); return 0; } @@ -7125,7 +7535,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); return -EINVAL; } - + down(&priv->sem); if (priv->adapter == IPW_2915ABG) { priv->ieee->abg_true = 1; if (mode & IEEE_A) { @@ -7137,6 +7547,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, if (mode & IEEE_A) { IPW_WARNING("Attempt to set 2200BG into " "802.11a mode\n"); + up(&priv->sem); return -EINVAL; } @@ -7160,16 +7571,12 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, priv->ieee->modulation = modulation; init_supported_rates(priv, &priv->rates); - /* If we are currently associated, or trying to associate - * then see if this is a new configuration (causing us to - * disassociate) */ - if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - /* The resulting association will trigger - * the new rates to be sent to the device */ - IPW_DEBUG_ASSOC("Disassociating due to mode change.\n"); - ipw_disassociate(priv); - } else + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n"); + if (!ipw_disassociate(priv)) { ipw_send_supported_rates(priv, &priv->rates); + ipw_associate(priv); + } /* Update the band LEDs */ ipw_led_band_on(priv); @@ -7177,6 +7584,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", mode & IEEE_A ? 'a' : '.', mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); + up(&priv->sem); return 0; } @@ -7185,7 +7593,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); switch (priv->ieee->mode) { case IEEE_A: strncpy(extra, "802.11a (1)", MAX_WX_STRING); @@ -7216,6 +7624,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); wrqu->data.length = strlen(extra) + 1; + up(&priv->sem); return 0; } @@ -7226,18 +7635,17 @@ static int ipw_wx_set_preamble(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; - + down(&priv->sem); /* Switching from SHORT -> LONG requires a disassociation */ if (mode == 1) { if (!(priv->config & CFG_PREAMBLE_LONG)) { priv->config |= CFG_PREAMBLE_LONG; - if (priv->status & - (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_ASSOC - ("Disassociating due to preamble " - "change.\n"); - ipw_disassociate(priv); - } + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC + ("[re]association triggered due to preamble change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); } goto done; } @@ -7246,10 +7654,11 @@ static int ipw_wx_set_preamble(struct net_device *dev, priv->config &= ~CFG_PREAMBLE_LONG; goto done; } - + up(&priv->sem); return -EINVAL; done: + up(&priv->sem); return 0; } @@ -7258,12 +7667,12 @@ static int ipw_wx_get_preamble(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); if (priv->config & CFG_PREAMBLE_LONG) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); else snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); - + up(&priv->sem); return 0; } @@ -7275,7 +7684,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); - + down(&priv->sem); IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); if (enable) { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { @@ -7285,11 +7694,14 @@ static int ipw_wx_set_monitor(struct net_device *dev, ipw_set_channel(priv, parms[1]); } else { - if (priv->ieee->iw_mode != IW_MODE_MONITOR) + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + up(&priv->sem); return 0; + } priv->net_dev->type = ARPHRD_ETHER; queue_work(priv->workqueue, &priv->adapter_restart); } + up(&priv->sem); return 0; } @@ -7473,7 +7885,7 @@ static inline void init_sys_config(struct ipw_sys_config *sys_config) sys_config->dot11g_auto_detection = 0; sys_config->enable_cts_to_self = 0; sys_config->bt_coexist_collision_thr = 0; - sys_config->pass_noise_stats_to_host = 0; //1 -- fix for 256 + sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 } static int ipw_net_open(struct net_device *dev) @@ -7481,9 +7893,11 @@ static int ipw_net_open(struct net_device *dev) struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_INFO("dev->open\n"); /* we should be verifying the device is ready to be opened */ + down(&priv->sem); if (!(priv->status & STATUS_RF_KILL_MASK) && (priv->status & STATUS_ASSOCIATED)) netif_start_queue(dev); + up(&priv->sem); return 0; } @@ -7511,6 +7925,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) struct clx2_queue *q = &txq->q; u8 id, hdr_len, unicast; u16 remaining_bytes; + int fc; switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: @@ -7562,6 +7977,9 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; + fc = le16_to_cpu(hdr->frame_ctl); + hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS); + memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); /* payload */ @@ -7644,7 +8062,6 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, unsigned long flags; IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); - spin_lock_irqsave(&priv->lock, flags); if (!(priv->status & STATUS_ASSOCIATED)) { @@ -7655,13 +8072,15 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, } ipw_tx_skb(priv, txb); + spin_unlock_irqrestore(&priv->lock, flags); ipw_led_activity_on(priv); - spin_unlock_irqrestore(&priv->lock, flags); +// up(&priv->sem); return 0; fail_unlock: spin_unlock_irqrestore(&priv->lock, flags); +// up(&priv->sem); return 1; } @@ -7685,11 +8104,13 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + down(&priv->sem); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(priv->mac_addr)); queue_work(priv->workqueue, &priv->adapter_restart); + up(&priv->sem); return 0; } @@ -7733,8 +8154,9 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) return -EINVAL; - + down(&p->sem); memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len); + up(&p->sem); return 0; } @@ -7746,12 +8168,12 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) return -EINVAL; - + down(&p->sem); memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len); for (i = IPW_EEPROM_DATA; i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++) ipw_write8(p, i, p->eeprom[i]); - + up(&p->sem); return 0; } @@ -7775,6 +8197,8 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) if (!(priv->status & STATUS_INT_ENABLED)) { /* Shared IRQ */ +// ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); +// return IRQ_HANDLED; goto none; } @@ -7843,6 +8267,14 @@ static void ipw_rf_kill(void *adapter) spin_unlock_irqrestore(&priv->lock, flags); } +static void ipw_bg_rf_kill(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_rf_kill(data); + up(&priv->sem); +} + void ipw_link_up(struct ipw_priv *priv) { netif_carrier_on(priv->net_dev); @@ -7854,6 +8286,7 @@ void ipw_link_up(struct ipw_priv *priv) netif_start_queue(priv->net_dev); } + cancel_delayed_work(&priv->request_scan); ipw_reset_stats(priv); /* Ensure the rate is updated immediately */ priv->last_rate = ipw_get_current_rate(priv); @@ -7865,6 +8298,14 @@ void ipw_link_up(struct ipw_priv *priv) queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); } +static void ipw_bg_link_up(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_link_up(data); + up(&priv->sem); +} + void ipw_link_down(struct ipw_priv *priv) { ipw_led_link_down(priv); @@ -7883,6 +8324,14 @@ void ipw_link_down(struct ipw_priv *priv) queue_work(priv->workqueue, &priv->request_scan); } +static void ipw_bg_link_down(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_link_down(data); + up(&priv->sem); +} + static int ipw_setup_deferred_work(struct ipw_priv *priv) { int ret = 0; @@ -7890,28 +8339,31 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) priv->workqueue = create_workqueue(DRV_NAME); init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->adhoc_check, ipw_adhoc_check, priv); - INIT_WORK(&priv->associate, ipw_associate, priv); - INIT_WORK(&priv->disassociate, ipw_disassociate, priv); - INIT_WORK(&priv->rx_replenish, ipw_rx_queue_replenish, priv); - INIT_WORK(&priv->adapter_restart, ipw_adapter_restart, priv); - INIT_WORK(&priv->rf_kill, ipw_rf_kill, priv); - INIT_WORK(&priv->up, (void (*)(void *))ipw_up, priv); - INIT_WORK(&priv->down, (void (*)(void *))ipw_down, priv); + INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); + INIT_WORK(&priv->associate, ipw_bg_associate, priv); + INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); + INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); + INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); + INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); + INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv); + INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv); INIT_WORK(&priv->request_scan, - (void (*)(void *))ipw_request_scan, priv); + (void (*)(void *))ipw_bg_request_scan, priv); INIT_WORK(&priv->gather_stats, - (void (*)(void *))ipw_gather_stats, priv); - INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv); - INIT_WORK(&priv->roam, ipw_roam, priv); - INIT_WORK(&priv->scan_check, ipw_scan_check, priv); - INIT_WORK(&priv->link_up, (void (*)(void *))ipw_link_up, priv); - INIT_WORK(&priv->link_down, (void (*)(void *))ipw_link_down, priv); - INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_led_link_on, priv); - INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_led_link_off, + (void (*)(void *))ipw_bg_gather_stats, priv); + INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv); + INIT_WORK(&priv->roam, ipw_bg_roam, priv); + INIT_WORK(&priv->scan_check, ipw_bg_scan_check, priv); + INIT_WORK(&priv->link_up, (void (*)(void *))ipw_bg_link_up, priv); + INIT_WORK(&priv->link_down, (void (*)(void *))ipw_bg_link_down, priv); + INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_bg_led_link_on, + priv); + INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_bg_led_link_off, priv); - INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_led_activity_off, + INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_bg_led_activity_off, priv); + INIT_WORK(&priv->merge_networks, + (void (*)(void *))ipw_merge_adhoc_network, priv); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw_irq_tasklet, (unsigned long)priv); @@ -7924,7 +8376,7 @@ static void shim__set_security(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int i; - + down(&priv->sem); for (i = 0; i < 4; i++) { if (sec->flags & (1 << i)) { priv->sec.key_sizes[i] = sec->key_sizes[i]; @@ -7989,6 +8441,7 @@ static void shim__set_security(struct net_device *dev, ipw_disassociate(priv); } #endif + up(&priv->sem); } static int init_supported_rates(struct ipw_priv *priv, @@ -8054,6 +8507,11 @@ static int ipw_config(struct ipw_priv *priv) /* set basic system config settings */ init_sys_config(&priv->sys_config); + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + priv->sys_config.answer_broadcast_ssid_probe = 1; + else + priv->sys_config.answer_broadcast_ssid_probe = 0; + if (ipw_send_system_config(priv, &priv->sys_config)) goto error; @@ -8075,8 +8533,10 @@ static int ipw_config(struct ipw_priv *priv) goto error; /* If configured to try and auto-associate, kick off a scan */ - if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv)) + if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv)) { + IPW_WARNING("error sending scan request\n"); goto error; + } return 0; @@ -8106,8 +8566,9 @@ static int ipw_up(struct ipw_priv *priv) eeprom_parse_mac(priv, priv->mac_addr); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - if (priv->status & STATUS_RF_KILL_MASK) + if (priv->status & STATUS_RF_KILL_MASK) { return 0; + } rc = ipw_config(priv); if (!rc) { @@ -8115,12 +8576,11 @@ static int ipw_up(struct ipw_priv *priv) ipw_led_init(priv); ipw_led_radio_on(priv); priv->notif_missed_beacons = 0; + priv->status |= STATUS_INIT; return 0; - } else { - IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", - rc); } + IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc); IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n", i, MAX_HW_RESTARTS); @@ -8132,13 +8592,22 @@ static int ipw_up(struct ipw_priv *priv) /* tried to restart and config the device for as long as our * patience could withstand */ IPW_ERROR("Unable to initialize device after %d attempts.\n", i); + return -EIO; } +static void ipw_bg_up(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_up(data); + up(&priv->sem); +} + static void ipw_down(struct ipw_priv *priv) { - /* Attempt to disable the card */ #if 0 + /* Attempt to disable the card */ ipw_send_card_disable(priv, 0); #endif @@ -8147,7 +8616,6 @@ static void ipw_down(struct ipw_priv *priv) /* Clear all bits but the RF Kill */ priv->status &= STATUS_RF_KILL_MASK; - netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev); @@ -8156,6 +8624,14 @@ static void ipw_down(struct ipw_priv *priv) ipw_led_radio_off(priv); } +static void ipw_bg_down(void *data) +{ + struct ipw_priv *priv = data; + down(&priv->sem); + ipw_down(data); + up(&priv->sem); +} + static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct iwreq *wrq = (struct iwreq *)rq; @@ -8176,21 +8652,26 @@ static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int ipw_net_init(struct net_device *dev) { struct ipw_priv *priv = ieee80211_priv(dev); - + down(&priv->sem); if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); + up(&priv->sem); return 0; } else if (rf_kill_active(priv)) { IPW_WARNING("Radio Frequency Kill Switch is On:\n" "Kill switch must be turned off for " "wireless networking to work.\n"); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); + up(&priv->sem); return 0; } - if (ipw_up(priv)) + if (ipw_up(priv)) { + up(&priv->sem); return -EIO; + } + up(&priv->sem); return 0; } @@ -8275,6 +8756,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #endif spin_lock_init(&priv->lock); + init_MUTEX(&priv->sem); if (pci_enable_device(pdev)) { err = -ENODEV; goto out_free_ieee80211; @@ -8416,9 +8898,14 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ipw_wx_data.spy_data = &priv->ieee->spy_data; ipw_wx_data.ieee80211 = priv->ieee; + down(&priv->sem); + priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; priv->ieee->set_security = shim__set_security; + priv->ieee->perfect_rssi = -20; + priv->ieee->worst_rssi = -85; + net_dev->open = ipw_net_open; net_dev->stop = ipw_net_stop; net_dev->init = ipw_net_init; @@ -8438,15 +8925,16 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); if (err) { IPW_ERROR("failed to create sysfs device attributes\n"); + up(&priv->sem); goto out_release_irq; } + up(&priv->sem); err = register_netdev(net_dev); if (err) { IPW_ERROR("failed to register network device\n"); goto out_remove_sysfs; } - return 0; out_remove_sysfs: @@ -8623,8 +9111,7 @@ module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); module_param(led, int, 0444); -MODULE_PARM_DESC(auto_create, - "enable led control on some systems (default 0 off)\n"); +MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n"); module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 1b339cb7a522..243b8ea14140 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -936,8 +936,8 @@ struct ipw_priv { struct ieee80211_device *ieee; struct ieee80211_security sec; - /* spinlock */ spinlock_t lock; + struct semaphore sem; /* basic pci-network driver stuff */ struct pci_dev *pci_dev; @@ -1068,6 +1068,7 @@ struct ipw_priv { struct work_struct led_link_on; struct work_struct led_link_off; struct work_struct led_act_off; + struct work_struct merge_networks; #define IPW_2200BG 1 #define IPW_2915ABG 2 @@ -1160,6 +1161,7 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DL_TRACE (1<<28) #define IPW_DL_STATS (1<<29) +#define IPW_DL_MERGE (1<<30) #define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) #define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) @@ -1187,6 +1189,7 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) #define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a) +#define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a) #include -- cgit v1.2.3-59-g8ed1b From b095c3819805f87d73d41641a53e4c070360d783 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 24 Aug 2005 22:04:42 -0500 Subject: Catch ipw2200 up to equivelancy with v1.0.4 * Fixed #627 problem with open APs not working with wpa_supplicant * Fixed #632 problem with 'txpower auto' setting power incorrectly (thanks to Kai Groner) * Fixed #634 problem with 'iwconfig eth1 frag 0' hanging the shell * Fixed problem with adapter not fully powering off during suspend to RAM or when module unloaded. * Fixed #645 problem with turning fixed rates off not taking effect until you reload the driver * Fixed problem with firmware restart if wpa_supplicant was used to set a key that wasn't exactly 5 or 13 bytes in length. * Fixed #623 Added iwpriv sw_reset extension to reset sw parameters * Added managment frame export to user space with frame statistics * Fixed #652 Modified the driver to load the EEPROM data even if RF KILL is active during driver load * Global s:CX2_:IPW_:g to make code more consistent * Fixed #572 problem with setting txpower to auto * Fixed #656 problem with kernel oops if mode auto; modprobe -r ipw2200 * Added QoS (CONFIG_IPW_QOS) support. This is being actively developed but is the first step in getting WMM support into the driver and the kernel. * Fixed some race conditions with channel changes, association, and scan abort that could periodically cause a firmware restart. * Added some extensions to export scan and network statistics to user space (exposed through speed_scan and net_stats sysfs entries) * Fixed a few bugs in how monitor mode was supported (scan lists weren't quite right) * Updated the firmware requirement from 2.2 to 2.3 which supports monitor mode. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 2604 +++++++++++++++++++++++++++++----------- drivers/net/wireless/ipw2200.h | 457 ++++--- 2 files changed, 2177 insertions(+), 884 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0bf1931ac5f3..0a583afbcddf 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -32,11 +32,13 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.3" +#define IPW2200_VERSION "1.0.4" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" #define DRV_VERSION IPW2200_VERSION +#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1) + MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); @@ -51,10 +53,78 @@ static int associate = 1; static int auto_create = 1; static int led = 0; static int disable = 0; +static int hwcrypto = 1; static const char ipw_modes[] = { 'a', 'b', 'g', '?' }; +#ifdef CONFIG_IPW_QOS +static int qos_enable = 0; +static int qos_burst_enable = 0; +static int qos_no_ack_mask = 0; +static int burst_duration_CCK = 0; +static int burst_duration_OFDM = 0; + +static struct ieee80211_qos_parameters def_qos_parameters_OFDM = { + {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM, + QOS_TX3_CW_MIN_OFDM}, + {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM, + QOS_TX3_CW_MAX_OFDM}, + {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, + {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, + {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM, + QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM} +}; + +static struct ieee80211_qos_parameters def_qos_parameters_CCK = { + {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK, + QOS_TX3_CW_MIN_CCK}, + {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK, + QOS_TX3_CW_MAX_CCK}, + {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS}, + {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM}, + {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK, + QOS_TX3_TXOP_LIMIT_CCK} +}; + +static struct ieee80211_qos_parameters def_parameters_OFDM = { + {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM, + DEF_TX3_CW_MIN_OFDM}, + {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM, + DEF_TX3_CW_MAX_OFDM}, + {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, + {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, + {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM, + DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM} +}; + +static struct ieee80211_qos_parameters def_parameters_CCK = { + {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK, + DEF_TX3_CW_MIN_CCK}, + {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK, + DEF_TX3_CW_MAX_CCK}, + {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS}, + {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM}, + {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK, + DEF_TX3_TXOP_LIMIT_CCK} +}; + +static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; + +static int from_priority_to_tx_queue[] = { + IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1, + IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4 +}; + +static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv); + +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters + *qos_param); +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element + *qos_param); +#endif /* CONFIG_IPW_QOS */ + +static void ipw_remove_current_network(struct ipw_priv *priv); static void ipw_rx(struct ipw_priv *priv); static int ipw_queue_tx_reclaim(struct ipw_priv *priv, struct clx2_tx_queue *txq, int qindex); @@ -75,33 +145,8 @@ static void ipw_bg_down(void *); static int ipw_config(struct ipw_priv *); static int init_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *prates); - -static u8 band_b_active_channel[MAX_B_CHANNELS] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0 -}; -static u8 band_a_active_channel[MAX_A_CHANNELS] = { - 36, 40, 44, 48, 149, 153, 157, 161, 165, 52, 56, 60, 64, 0 -}; - -static int is_valid_channel(int mode_mask, int channel) -{ - int i; - - if (!channel) - return 0; - - if (mode_mask & IEEE_A) - for (i = 0; i < MAX_A_CHANNELS; i++) - if (band_a_active_channel[i] == channel) - return IEEE_A; - - if (mode_mask & (IEEE_B | IEEE_G)) - for (i = 0; i < MAX_B_CHANNELS; i++) - if (band_b_active_channel[i] == channel) - return mode_mask & (IEEE_B | IEEE_G); - - return 0; -} +static void ipw_set_hwcrypto_keys(struct ipw_priv *); +static void ipw_send_wep_keys(struct ipw_priv *, int); static char *snprint_line(char *buf, size_t count, const u8 * data, u32 len, u32 ofs) @@ -241,24 +286,24 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) { IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value); - _ipw_write32(priv, CX2_INDIRECT_ADDR, reg); - _ipw_write32(priv, CX2_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); + _ipw_write32(priv, IPW_INDIRECT_DATA, value); } static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) { IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK); - _ipw_write8(priv, CX2_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); + _ipw_write8(priv, IPW_INDIRECT_DATA, value); IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n", - (unsigned long)(priv->hw_base + CX2_INDIRECT_DATA), value); + (unsigned long)(priv->hw_base + IPW_INDIRECT_DATA), value); } static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) { IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK); - _ipw_write16(priv, CX2_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); + _ipw_write16(priv, IPW_INDIRECT_DATA, value); } /* indirect read s */ @@ -266,9 +311,9 @@ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) { u32 word; - _ipw_write32(priv, CX2_INDIRECT_ADDR, reg & CX2_INDIRECT_ADDR_MASK); + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); IPW_DEBUG_IO(" reg = 0x%8X : \n", reg); - word = _ipw_read32(priv, CX2_INDIRECT_DATA); + word = _ipw_read32(priv, IPW_INDIRECT_DATA); return (word >> ((reg & 0x3) * 8)) & 0xff; } @@ -278,8 +323,8 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg); - _ipw_write32(priv, CX2_INDIRECT_ADDR, reg); - value = _ipw_read32(priv, CX2_INDIRECT_DATA); + _ipw_write32(priv, IPW_INDIRECT_ADDR, reg); + value = _ipw_read32(priv, IPW_INDIRECT_DATA); IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value); return value; } @@ -288,7 +333,7 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; u32 dif_len = addr - aligned_addr; u32 i; @@ -300,29 +345,29 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, /* Read the first nibble byte by byte */ if (unlikely(dif_len)) { - _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); /* Start reading at aligned_addr + dif_len */ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--) - *buf++ = _ipw_read8(priv, CX2_INDIRECT_DATA + i); + *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i); aligned_addr += 4; } - _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); + _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) - *(u32 *) buf = _ipw_read32(priv, CX2_AUTOINC_DATA); + *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA); /* Copy the last nibble */ if (unlikely(num)) { - _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--) - *buf++ = ipw_read8(priv, CX2_INDIRECT_DATA + i); + *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i); } } static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; u32 dif_len = addr - aligned_addr; u32 i; @@ -334,22 +379,22 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, /* Write the first nibble byte by byte */ if (unlikely(dif_len)) { - _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); /* Start reading at aligned_addr + dif_len */ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) - _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); + _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); aligned_addr += 4; } - _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); + _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) - _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf); + _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf); /* Copy the last nibble */ if (unlikely(num)) { - _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--, buf++) - _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); + _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); } } @@ -374,7 +419,7 @@ static inline void ipw_enable_interrupts(struct ipw_priv *priv) if (priv->status & STATUS_INT_ENABLED) return; priv->status |= STATUS_INT_ENABLED; - ipw_write32(priv, CX2_INTA_MASK_R, CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL); } static inline void ipw_disable_interrupts(struct ipw_priv *priv) @@ -382,7 +427,7 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv) if (!(priv->status & STATUS_INT_ENABLED)) return; priv->status &= ~STATUS_INT_ENABLED; - ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); } static char *ipw_error_desc(u32 val) @@ -397,29 +442,29 @@ static char *ipw_error_desc(u32 val) case IPW_FW_ERROR_MEMORY_OVERFLOW: return "MEMORY_OVERFLOW"; case IPW_FW_ERROR_BAD_PARAM: - return "ERROR_BAD_PARAM"; + return "BAD_PARAM"; case IPW_FW_ERROR_BAD_CHECKSUM: - return "ERROR_BAD_CHECKSUM"; + return "BAD_CHECKSUM"; case IPW_FW_ERROR_NMI_INTERRUPT: - return "ERROR_NMI_INTERRUPT"; + return "NMI_INTERRUPT"; case IPW_FW_ERROR_BAD_DATABASE: - return "ERROR_BAD_DATABASE"; + return "BAD_DATABASE"; case IPW_FW_ERROR_ALLOC_FAIL: - return "ERROR_ALLOC_FAIL"; + return "ALLOC_FAIL"; case IPW_FW_ERROR_DMA_UNDERRUN: - return "ERROR_DMA_UNDERRUN"; + return "DMA_UNDERRUN"; case IPW_FW_ERROR_DMA_STATUS: - return "ERROR_DMA_STATUS"; - case IPW_FW_ERROR_DINOSTATUS_ERROR: - return "ERROR_DINOSTATUS_ERROR"; - case IPW_FW_ERROR_EEPROMSTATUS_ERROR: - return "ERROR_EEPROMSTATUS_ERROR"; + return "DMA_STATUS"; + case IPW_FW_ERROR_DINO_ERROR: + return "DINO_ERROR"; + case IPW_FW_ERROR_EEPROM_ERROR: + return "EEPROM_ERROR"; case IPW_FW_ERROR_SYSASSERT: - return "ERROR_SYSASSERT"; + return "SYSASSERT"; case IPW_FW_ERROR_FATAL_ERROR: - return "ERROR_FATALSTATUS_ERROR"; + return "FATAL_ERROR"; default: - return "UNKNOWNSTATUS_ERROR"; + return "UNKNOWN_ERROR"; } } @@ -646,13 +691,13 @@ static void ipw_init_ordinals(struct ipw_priv *priv) u32 ipw_register_toggle(u32 reg) { - reg &= ~CX2_START_STANDBY; - if (reg & CX2_GATE_ODMA) - reg &= ~CX2_GATE_ODMA; - if (reg & CX2_GATE_IDMA) - reg &= ~CX2_GATE_IDMA; - if (reg & CX2_GATE_ADMA) - reg &= ~CX2_GATE_ADMA; + reg &= ~IPW_START_STANDBY; + if (reg & IPW_GATE_ODMA) + reg &= ~IPW_GATE_ODMA; + if (reg & IPW_GATE_IDMA) + reg &= ~IPW_GATE_IDMA; + if (reg & IPW_GATE_ADMA) + reg &= ~IPW_GATE_ADMA; return reg; } @@ -684,13 +729,13 @@ void ipw_led_link_on(struct ipw_priv *priv) if (!(priv->status & STATUS_RF_KILL_MASK) && !(priv->status & STATUS_LED_LINK_ON)) { IPW_DEBUG_LED("Link LED On\n"); - led = ipw_read_reg32(priv, CX2_EVENT_REG); + led = ipw_read_reg32(priv, IPW_EVENT_REG); led |= priv->led_association_on; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, CX2_EVENT_REG, led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); priv->status |= STATUS_LED_LINK_ON; @@ -725,12 +770,12 @@ void ipw_led_link_off(struct ipw_priv *priv) spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_LED_LINK_ON) { - led = ipw_read_reg32(priv, CX2_EVENT_REG); + led = ipw_read_reg32(priv, IPW_EVENT_REG); led &= priv->led_association_off; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, CX2_EVENT_REG, led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); IPW_DEBUG_LED("Link LED Off\n"); @@ -756,29 +801,24 @@ static void ipw_bg_led_link_off(void *data) up(&priv->sem); } -void ipw_led_activity_on(struct ipw_priv *priv) +static inline void __ipw_led_activity_on(struct ipw_priv *priv) { - unsigned long flags; u32 led; if (priv->config & CFG_NO_LED) return; - spin_lock_irqsave(&priv->lock, flags); - - if (priv->status & STATUS_RF_KILL_MASK) { - spin_unlock_irqrestore(&priv->lock, flags); + if (priv->status & STATUS_RF_KILL_MASK) return; - } if (!(priv->status & STATUS_LED_ACT_ON)) { - led = ipw_read_reg32(priv, CX2_EVENT_REG); + led = ipw_read_reg32(priv, IPW_EVENT_REG); led |= priv->led_activity_on; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, CX2_EVENT_REG, led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); IPW_DEBUG_LED("Activity LED On\n"); @@ -793,7 +833,13 @@ void ipw_led_activity_on(struct ipw_priv *priv) queue_delayed_work(priv->workqueue, &priv->led_act_off, LD_TIME_ACT_ON); } +} +void ipw_led_activity_on(struct ipw_priv *priv) +{ + unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); + __ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags); } @@ -808,13 +854,13 @@ void ipw_led_activity_off(struct ipw_priv *priv) spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_LED_ACT_ON) { - led = ipw_read_reg32(priv, CX2_EVENT_REG); + led = ipw_read_reg32(priv, IPW_EVENT_REG); led &= priv->led_activity_off; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, CX2_EVENT_REG, led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); IPW_DEBUG_LED("Activity LED Off\n"); @@ -844,7 +890,7 @@ void ipw_led_band_on(struct ipw_priv *priv) spin_lock_irqsave(&priv->lock, flags); - led = ipw_read_reg32(priv, CX2_EVENT_REG); + led = ipw_read_reg32(priv, IPW_EVENT_REG); if (priv->assoc_network->mode == IEEE_A) { led |= priv->led_ofdm_on; led &= priv->led_association_off; @@ -862,7 +908,7 @@ void ipw_led_band_on(struct ipw_priv *priv) led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, CX2_EVENT_REG, led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); spin_unlock_irqrestore(&priv->lock, flags); } @@ -878,14 +924,14 @@ void ipw_led_band_off(struct ipw_priv *priv) spin_lock_irqsave(&priv->lock, flags); - led = ipw_read_reg32(priv, CX2_EVENT_REG); + led = ipw_read_reg32(priv, IPW_EVENT_REG); led &= priv->led_ofdm_off; led &= priv->led_association_off; led = ipw_register_toggle(led); IPW_DEBUG_LED("Reg: 0x%08X\n", led); - ipw_write_reg32(priv, CX2_EVENT_REG, led); + ipw_write_reg32(priv, IPW_EVENT_REG, led); spin_unlock_irqrestore(&priv->lock, flags); } @@ -921,23 +967,23 @@ void ipw_led_init(struct ipw_priv *priv) priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; /* Set the default PINs for the link and activity leds */ - priv->led_activity_on = CX2_ACTIVITY_LED; - priv->led_activity_off = ~(CX2_ACTIVITY_LED); + priv->led_activity_on = IPW_ACTIVITY_LED; + priv->led_activity_off = ~(IPW_ACTIVITY_LED); - priv->led_association_on = CX2_ASSOCIATED_LED; - priv->led_association_off = ~(CX2_ASSOCIATED_LED); + priv->led_association_on = IPW_ASSOCIATED_LED; + priv->led_association_off = ~(IPW_ASSOCIATED_LED); /* Set the default PINs for the OFDM leds */ - priv->led_ofdm_on = CX2_OFDM_LED; - priv->led_ofdm_off = ~(CX2_OFDM_LED); + priv->led_ofdm_on = IPW_OFDM_LED; + priv->led_ofdm_off = ~(IPW_OFDM_LED); switch (priv->nic_type) { case EEPROM_NIC_TYPE_1: /* In this NIC type, the LEDs are reversed.... */ - priv->led_activity_on = CX2_ASSOCIATED_LED; - priv->led_activity_off = ~(CX2_ASSOCIATED_LED); - priv->led_association_on = CX2_ACTIVITY_LED; - priv->led_association_off = ~(CX2_ACTIVITY_LED); + priv->led_activity_on = IPW_ASSOCIATED_LED; + priv->led_activity_off = ~(IPW_ASSOCIATED_LED); + priv->led_association_on = IPW_ACTIVITY_LED; + priv->led_association_off = ~(IPW_ACTIVITY_LED); if (!(priv->config & CFG_NO_LED)) ipw_led_band_on(priv); @@ -1203,7 +1249,7 @@ static ssize_t show_command_event_reg(struct device *d, u32 reg = 0; struct ipw_priv *p = d->driver_data; - reg = ipw_read_reg32(p, CX2_INTERNAL_CMD_EVENT); + reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT); return sprintf(buf, "0x%08x\n", reg); } static ssize_t store_command_event_reg(struct device *d, @@ -1214,7 +1260,7 @@ static ssize_t store_command_event_reg(struct device *d, struct ipw_priv *p = d->driver_data; sscanf(buf, "%x", ®); - ipw_write_reg32(p, CX2_INTERNAL_CMD_EVENT, reg); + ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg); return strnlen(buf, count); } @@ -1361,7 +1407,6 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) if (priv->workqueue) cancel_delayed_work(&priv->request_scan); - wake_up_interruptible(&priv->wait_command_queue); queue_work(priv->workqueue, &priv->down); } else { priv->status &= ~STATUS_RF_KILL_SW; @@ -1391,6 +1436,82 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); +static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + int pos = 0, len = 0; + if (priv->config & CFG_SPEED_SCAN) { + while (priv->speed_scan[pos] != 0) + len += sprintf(&buf[len], "%d ", + priv->speed_scan[pos++]); + return len + sprintf(&buf[len], "\n"); + } + + return sprintf(buf, "0\n"); +} + +static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + int channel, pos = 0; + const char *p = buf; + + /* list of space separated channels to scan, optionally ending with 0 */ + while ((channel = simple_strtol(p, NULL, 0))) { + if (pos == MAX_SPEED_SCAN - 1) { + priv->speed_scan[pos] = 0; + break; + } + + if (ieee80211_is_valid_channel(priv->ieee, channel)) + priv->speed_scan[pos++] = channel; + else + IPW_WARNING("Skipping invalid channel request: %d\n", + channel); + p = strchr(p, ' '); + if (!p) + break; + while (*p == ' ' || *p == '\t') + p++; + } + + if (pos == 0) + priv->config &= ~CFG_SPEED_SCAN; + else { + priv->speed_scan_pos = 0; + priv->config |= CFG_SPEED_SCAN; + } + + return count; +} + +static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, + store_speed_scan); + +static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0'); +} + +static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = (struct ipw_priv *)d->driver_data; + if (buf[0] == '1') + priv->config |= CFG_NET_STATS; + else + priv->config &= ~CFG_NET_STATS; + + return count; +} + +static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, show_net_stats, + store_net_stats); + static void notify_wx_assoc_event(struct ipw_priv *priv) { union iwreq_data wrqu; @@ -1410,77 +1531,77 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) spin_lock_irqsave(&priv->lock, flags); - inta = ipw_read32(priv, CX2_INTA_RW); - inta_mask = ipw_read32(priv, CX2_INTA_MASK_R); - inta &= (CX2_INTA_MASK_ALL & inta_mask); + inta = ipw_read32(priv, IPW_INTA_RW); + inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); + inta &= (IPW_INTA_MASK_ALL & inta_mask); /* Add any cached INTA values that need to be handled */ inta |= priv->isr_inta; /* handle all the justifications for the interrupt */ - if (inta & CX2_INTA_BIT_RX_TRANSFER) { + if (inta & IPW_INTA_BIT_RX_TRANSFER) { ipw_rx(priv); - handled |= CX2_INTA_BIT_RX_TRANSFER; + handled |= IPW_INTA_BIT_RX_TRANSFER; } - if (inta & CX2_INTA_BIT_TX_CMD_QUEUE) { + if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) { IPW_DEBUG_HC("Command completed.\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1); priv->status &= ~STATUS_HCMD_ACTIVE; wake_up_interruptible(&priv->wait_command_queue); - handled |= CX2_INTA_BIT_TX_CMD_QUEUE; + handled |= IPW_INTA_BIT_TX_CMD_QUEUE; } - if (inta & CX2_INTA_BIT_TX_QUEUE_1) { + if (inta & IPW_INTA_BIT_TX_QUEUE_1) { IPW_DEBUG_TX("TX_QUEUE_1\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[0], 0); - handled |= CX2_INTA_BIT_TX_QUEUE_1; + handled |= IPW_INTA_BIT_TX_QUEUE_1; } - if (inta & CX2_INTA_BIT_TX_QUEUE_2) { + if (inta & IPW_INTA_BIT_TX_QUEUE_2) { IPW_DEBUG_TX("TX_QUEUE_2\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[1], 1); - handled |= CX2_INTA_BIT_TX_QUEUE_2; + handled |= IPW_INTA_BIT_TX_QUEUE_2; } - if (inta & CX2_INTA_BIT_TX_QUEUE_3) { + if (inta & IPW_INTA_BIT_TX_QUEUE_3) { IPW_DEBUG_TX("TX_QUEUE_3\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[2], 2); - handled |= CX2_INTA_BIT_TX_QUEUE_3; + handled |= IPW_INTA_BIT_TX_QUEUE_3; } - if (inta & CX2_INTA_BIT_TX_QUEUE_4) { + if (inta & IPW_INTA_BIT_TX_QUEUE_4) { IPW_DEBUG_TX("TX_QUEUE_4\n"); rc = ipw_queue_tx_reclaim(priv, &priv->txq[3], 3); - handled |= CX2_INTA_BIT_TX_QUEUE_4; + handled |= IPW_INTA_BIT_TX_QUEUE_4; } - if (inta & CX2_INTA_BIT_STATUS_CHANGE) { + if (inta & IPW_INTA_BIT_STATUS_CHANGE) { IPW_WARNING("STATUS_CHANGE\n"); - handled |= CX2_INTA_BIT_STATUS_CHANGE; + handled |= IPW_INTA_BIT_STATUS_CHANGE; } - if (inta & CX2_INTA_BIT_BEACON_PERIOD_EXPIRED) { + if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) { IPW_WARNING("TX_PERIOD_EXPIRED\n"); - handled |= CX2_INTA_BIT_BEACON_PERIOD_EXPIRED; + handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED; } - if (inta & CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) { + if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) { IPW_WARNING("HOST_CMD_DONE\n"); - handled |= CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE; + handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE; } - if (inta & CX2_INTA_BIT_FW_INITIALIZATION_DONE) { + if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) { IPW_WARNING("FW_INITIALIZATION_DONE\n"); - handled |= CX2_INTA_BIT_FW_INITIALIZATION_DONE; + handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE; } - if (inta & CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) { + if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) { IPW_WARNING("PHY_OFF_DONE\n"); - handled |= CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE; + handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE; } - if (inta & CX2_INTA_BIT_RF_KILL_DONE) { + if (inta & IPW_INTA_BIT_RF_KILL_DONE) { IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); priv->status |= STATUS_RF_KILL_HW; wake_up_interruptible(&priv->wait_command_queue); @@ -1488,10 +1609,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) cancel_delayed_work(&priv->request_scan); schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); - handled |= CX2_INTA_BIT_RF_KILL_DONE; + handled |= IPW_INTA_BIT_RF_KILL_DONE; } - if (inta & CX2_INTA_BIT_FATAL_ERROR) { + if (inta & IPW_INTA_BIT_FATAL_ERROR) { IPW_ERROR("Firmware error detected. Restarting.\n"); #ifdef CONFIG_IPW_DEBUG if (ipw_debug_level & IPW_DL_FW_ERRORS) { @@ -1499,13 +1620,23 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) ipw_dump_nic_event_log(priv); } #endif + /* XXX: If hardware encryption is for WPA/WPA2, + * we have to notify the supplicant. */ + if (priv->ieee->sec.encrypt) { + priv->status &= ~STATUS_ASSOCIATED; + notify_wx_assoc_event(priv); + } + + /* Keep the restart process from trying to send host + * commands by clearing the INIT status bit */ + priv->status &= ~STATUS_INIT; queue_work(priv->workqueue, &priv->adapter_restart); - handled |= CX2_INTA_BIT_FATAL_ERROR; + handled |= IPW_INTA_BIT_FATAL_ERROR; } - if (inta & CX2_INTA_BIT_PARITY_ERROR) { + if (inta & IPW_INTA_BIT_PARITY_ERROR) { IPW_ERROR("Parity error\n"); - handled |= CX2_INTA_BIT_PARITY_ERROR; + handled |= IPW_INTA_BIT_PARITY_ERROR; } if (handled != inta) { @@ -1594,8 +1725,9 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) priv->status |= STATUS_HCMD_ACTIVE; - IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", - get_cmd_string(cmd->cmd), cmd->cmd, cmd->len); + IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", + get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, + priv->status); printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); @@ -1623,7 +1755,7 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) spin_unlock_irqrestore(&priv->lock, flags); } - if (priv->status & STATUS_RF_KILL_MASK) { + if (priv->status & STATUS_RF_KILL_HW) { IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n"); return -EIO; } @@ -1732,10 +1864,20 @@ static void ipw_adapter_restart(void *adapter) return; ipw_down(priv); + + if (priv->assoc_network && + (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS)) + ipw_remove_current_network(priv); + if (ipw_up(priv)) { IPW_ERROR("Failed to up device\n"); return; } + + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.level == SEC_LEVEL_1) && + !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) + ipw_set_hwcrypto_keys(priv); } static void ipw_bg_adapter_restart(void *data) @@ -1775,11 +1917,6 @@ static int ipw_send_scan_request_ext(struct ipw_priv *priv, .len = sizeof(*request) }; - if (!priv || !request) { - IPW_ERROR("Invalid args\n"); - return -1; - } - memcpy(&cmd.param, request, sizeof(*request)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n"); @@ -1907,7 +2044,6 @@ static int ipw_set_random_seed(struct ipw_priv *priv) return 0; } -#if 0 static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) { struct host_cmd cmd = { @@ -1929,7 +2065,6 @@ static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) return 0; } -#endif static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) { @@ -2166,7 +2301,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv) IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n"); /* write the eeprom data to sram */ - for (i = 0; i < CX2_EEPROM_IMAGE_SIZE; i++) + for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]); /* Do not load eeprom data on fatal error or suspend */ @@ -2186,14 +2321,14 @@ static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count) count >>= 2; if (!count) return; - _ipw_write32(priv, CX2_AUTOINC_ADDR, start); + _ipw_write32(priv, IPW_AUTOINC_ADDR, start); while (count--) - _ipw_write32(priv, CX2_AUTOINC_DATA, 0); + _ipw_write32(priv, IPW_AUTOINC_DATA, 0); } static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv) { - ipw_zero_memory(priv, CX2_SHARED_SRAM_DMA_CONTROL, + ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL, CB_NUMBER_OF_ELEMENTS_SMALL * sizeof(struct command_block)); } @@ -2207,7 +2342,7 @@ static int ipw_fw_dma_enable(struct ipw_priv *priv) ipw_fw_dma_reset_command_blocks(priv); /* Write CB base address */ - ipw_write_reg32(priv, CX2_DMA_I_CB_BASE, CX2_SHARED_SRAM_DMA_CONTROL); + ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL); IPW_DEBUG_FW("<< : \n"); return 0; @@ -2221,7 +2356,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv) //set the Stop and Abort bit control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT; - ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control); + ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); priv->sram_desc.last_cb_index = 0; IPW_DEBUG_FW("<< \n"); @@ -2231,7 +2366,7 @@ static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index, struct command_block *cb) { u32 address = - CX2_SHARED_SRAM_DMA_CONTROL + + IPW_SHARED_SRAM_DMA_CONTROL + (sizeof(struct command_block) * index); IPW_DEBUG_FW(">> :\n"); @@ -2255,13 +2390,13 @@ static int ipw_fw_dma_kick(struct ipw_priv *priv) &priv->sram_desc.cb_list[index]); /* Enable the DMA in the CSR register */ - ipw_clear_bit(priv, CX2_RESET_REG, - CX2_RESET_REG_MASTER_DISABLED | - CX2_RESET_REG_STOP_MASTER); + ipw_clear_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED | + IPW_RESET_REG_STOP_MASTER); /* Set the Start bit. */ control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START; - ipw_write_reg32(priv, CX2_DMA_I_DMA_CONTROL, control); + ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control); IPW_DEBUG_FW("<< :\n"); return 0; @@ -2274,12 +2409,12 @@ static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv) u32 cb_fields_address = 0; IPW_DEBUG_FW(">> :\n"); - address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB); + address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB); IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address); /* Read the DMA Controlor register */ - register_value = ipw_read_reg32(priv, CX2_DMA_I_DMA_CONTROL); - IPW_DEBUG_FW_INFO("CX2_DMA_I_DMA_CONTROL is 0x%x \n", register_value); + register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL); + IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value); /* Print the CB values */ cb_fields_address = address; @@ -2308,9 +2443,9 @@ static int ipw_fw_dma_command_block_index(struct ipw_priv *priv) u32 current_cb_index = 0; IPW_DEBUG_FW("<< :\n"); - current_cb_address = ipw_read_reg32(priv, CX2_DMA_I_CURRENT_CB); + current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB); - current_cb_index = (current_cb_address - CX2_SHARED_SRAM_DMA_CONTROL) / + current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) / sizeof(struct command_block); IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n", @@ -2439,8 +2574,8 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv) ipw_fw_dma_abort(priv); /*Disable the DMA in the CSR register */ - ipw_set_bit(priv, CX2_RESET_REG, - CX2_RESET_REG_MASTER_DISABLED | CX2_RESET_REG_STOP_MASTER); + ipw_set_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER); IPW_DEBUG_FW("<< dmaWaitSync \n"); return 0; @@ -2504,10 +2639,10 @@ static int ipw_stop_master(struct ipw_priv *priv) IPW_DEBUG_TRACE(">> \n"); /* stop master. typical delay - 0 */ - ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER); + ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); - rc = ipw_poll_bit(priv, CX2_RESET_REG, - CX2_RESET_REG_MASTER_DISABLED, 100); + rc = ipw_poll_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED, 100); if (rc < 0) { IPW_ERROR("stop master failed in 10ms\n"); return -1; @@ -2523,7 +2658,7 @@ static void ipw_arc_release(struct ipw_priv *priv) IPW_DEBUG_TRACE(">> \n"); mdelay(5); - ipw_clear_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); + ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); /* no one knows timing, for safety add some delay */ mdelay(5); @@ -2540,7 +2675,7 @@ struct fw_chunk { }; #define IPW_FW_MAJOR_VERSION 2 -#define IPW_FW_MINOR_VERSION 2 +#define IPW_FW_MINOR_VERSION 3 #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) #define IPW_FW_MAJOR(x) (x & 0xff) @@ -2574,8 +2709,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) // spin_lock_irqsave(&priv->lock, flags); - for (addr = CX2_SHARED_LOWER_BOUND; - addr < CX2_REGISTER_DOMAIN1_END; addr += 4) { + for (addr = IPW_SHARED_LOWER_BOUND; + addr < IPW_REGISTER_DOMAIN1_END; addr += 4) { ipw_write32(priv, addr, 0); } @@ -2584,16 +2719,16 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) /* destroy DMA queues */ /* reset sequence */ - ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_ON); + ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON); ipw_arc_release(priv); - ipw_write_reg32(priv, CX2_MEM_HALT_AND_RESET, CX2_BIT_HALT_RESET_OFF); + ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF); mdelay(1); /* reset PHY */ - ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, CX2_BASEBAND_POWER_DOWN); + ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN); mdelay(1); - ipw_write_reg32(priv, CX2_INTERNAL_CMD_EVENT, 0); + ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0); mdelay(1); /* enable ucode store */ @@ -2611,19 +2746,19 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) */ /* load new ipw uCode */ for (i = 0; i < len / 2; i++) - ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, + ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE, cpu_to_le16(image[i])); /* enable DINO */ - ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); - ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM); /* this is where the igx / win driver deveates from the VAP driver. */ /* wait for alive response */ for (i = 0; i < 100; i++) { /* poll for incoming data */ - cr = ipw_read_reg8(priv, CX2_BASEBAND_CONTROL_STATUS); + cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS); if (cr & DINO_RXFIFO_DATA) break; mdelay(1); @@ -2636,7 +2771,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) for (i = 0; i < ARRAY_SIZE(response_buffer); i++) response_buffer[i] = le32_to_cpu(ipw_read_reg32(priv, - CX2_BASEBAND_RX_FIFO_READ)); + IPW_BASEBAND_RX_FIFO_READ)); memcpy(&priv->dino_alive, response_buffer, sizeof(priv->dino_alive)); if (priv->dino_alive.alive_command == 1 @@ -2665,7 +2800,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) /* disable DINO, otherwise for some reason firmware have problem getting alive resp. */ - ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); // spin_unlock_irqrestore(&priv->lock, flags); @@ -2738,16 +2873,16 @@ static int ipw_stop_nic(struct ipw_priv *priv) int rc = 0; /* stop */ - ipw_write32(priv, CX2_RESET_REG, CX2_RESET_REG_STOP_MASTER); + ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); - rc = ipw_poll_bit(priv, CX2_RESET_REG, - CX2_RESET_REG_MASTER_DISABLED, 500); + rc = ipw_poll_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED, 500); if (rc < 0) { IPW_ERROR("wait for reg master disabled failed\n"); return rc; } - ipw_set_bit(priv, CX2_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); + ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET); return rc; } @@ -2757,14 +2892,14 @@ static void ipw_start_nic(struct ipw_priv *priv) IPW_DEBUG_TRACE(">>\n"); /* prvHwStartNic release ARC */ - ipw_clear_bit(priv, CX2_RESET_REG, - CX2_RESET_REG_MASTER_DISABLED | - CX2_RESET_REG_STOP_MASTER | + ipw_clear_bit(priv, IPW_RESET_REG, + IPW_RESET_REG_MASTER_DISABLED | + IPW_RESET_REG_STOP_MASTER | CBD_RESET_REG_PRINCETON_RESET); /* enable power management */ - ipw_set_bit(priv, CX2_GP_CNTRL_RW, - CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); + ipw_set_bit(priv, IPW_GP_CNTRL_RW, + IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); IPW_DEBUG_TRACE("<<\n"); } @@ -2777,25 +2912,25 @@ static int ipw_init_nic(struct ipw_priv *priv) /* reset */ /*prvHwInitNic */ /* set "initialization complete" bit to move adapter to D0 state */ - ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE); + ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE); /* low-level PLL activation */ - ipw_write32(priv, CX2_READ_INT_REGISTER, - CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER); + ipw_write32(priv, IPW_READ_INT_REGISTER, + IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER); /* wait for clock stabilization */ - rc = ipw_poll_bit(priv, CX2_GP_CNTRL_RW, - CX2_GP_CNTRL_BIT_CLOCK_READY, 250); + rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW, + IPW_GP_CNTRL_BIT_CLOCK_READY, 250); if (rc < 0) IPW_DEBUG_INFO("FAILED wait for clock stablization\n"); /* assert SW reset */ - ipw_set_bit(priv, CX2_RESET_REG, CX2_RESET_REG_SW_RESET); + ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET); udelay(10); /* set "initialization complete" bit to move adapter to D0 state */ - ipw_set_bit(priv, CX2_GP_CNTRL_RW, CX2_GP_CNTRL_BIT_INIT_DONE); + ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE); IPW_DEBUG_TRACE(">>\n"); return 0; @@ -2853,7 +2988,7 @@ static int ipw_get_fw(struct ipw_priv *priv, return 0; } -#define CX2_RX_BUF_SIZE (3000) +#define IPW_RX_BUF_SIZE (3000) static inline void ipw_rx_queue_reset(struct ipw_priv *priv, struct ipw_rx_queue *rxq) @@ -2872,7 +3007,7 @@ static inline void ipw_rx_queue_reset(struct ipw_priv *priv, * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].skb != NULL) { pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxq->pool[i].skb); rxq->pool[i].skb = NULL; } @@ -2920,7 +3055,7 @@ static int ipw_load(struct ipw_priv *priv) rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); break; -#ifdef CONFIG_IPW_MONITOR +#ifdef CONFIG_IPW2200_MONITOR case IW_MODE_MONITOR: rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("sniffer_ucode")); @@ -2962,11 +3097,11 @@ static int ipw_load(struct ipw_priv *priv) retry: /* Ensure interrupts are disabled */ - ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); priv->status &= ~STATUS_INT_ENABLED; /* ack pending interrupts */ - ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); ipw_stop_nic(priv); @@ -2976,8 +3111,8 @@ static int ipw_load(struct ipw_priv *priv) goto error; } - ipw_zero_memory(priv, CX2_NIC_SRAM_LOWER_BOUND, - CX2_NIC_SRAM_UPPER_BOUND - CX2_NIC_SRAM_LOWER_BOUND); + ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, + IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); /* DMA the initial boot firmware into the device */ rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), @@ -2991,8 +3126,8 @@ static int ipw_load(struct ipw_priv *priv) ipw_start_nic(priv); /* wait for the device to finish it's initial startup sequence */ - rc = ipw_poll_bit(priv, CX2_INTA_RW, - CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500); + rc = ipw_poll_bit(priv, IPW_INTA_RW, + IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); if (rc < 0) { IPW_ERROR("device failed to boot initial fw image\n"); goto error; @@ -3000,7 +3135,7 @@ static int ipw_load(struct ipw_priv *priv) IPW_DEBUG_INFO("initial device response after %dms\n", rc); /* ack fw init done interrupt */ - ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE); + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); /* DMA the ucode into the device */ rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), @@ -3031,14 +3166,14 @@ static int ipw_load(struct ipw_priv *priv) } /* Ensure interrupts are disabled */ - ipw_write32(priv, CX2_INTA_MASK_R, ~CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); /* ack pending interrupts */ - ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); /* kick start the device */ ipw_start_nic(priv); - if (ipw_read32(priv, CX2_INTA_RW) & CX2_INTA_BIT_PARITY_ERROR) { + if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) { if (retries > 0) { IPW_WARNING("Parity error. Retrying init.\n"); retries--; @@ -3051,8 +3186,8 @@ static int ipw_load(struct ipw_priv *priv) } /* wait for the device */ - rc = ipw_poll_bit(priv, CX2_INTA_RW, - CX2_INTA_BIT_FW_INITIALIZATION_DONE, 500); + rc = ipw_poll_bit(priv, IPW_INTA_RW, + IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); if (rc < 0) { IPW_ERROR("device failed to start after 500ms\n"); goto error; @@ -3060,7 +3195,7 @@ static int ipw_load(struct ipw_priv *priv) IPW_DEBUG_INFO("device response after %dms\n", rc); /* ack fw init done interrupt */ - ipw_write32(priv, CX2_INTA_RW, CX2_INTA_BIT_FW_INITIALIZATION_DONE); + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); /* read eeprom data and initialize the eeprom region of sram */ priv->eeprom_delay = 1; @@ -3072,10 +3207,10 @@ static int ipw_load(struct ipw_priv *priv) /* Ensure our queue has valid packets */ ipw_rx_queue_replenish(priv); - ipw_write32(priv, CX2_RX_READ_INDEX, priv->rxq->read); + ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read); /* ack pending interrupts */ - ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); + ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); #ifndef CONFIG_PM release_firmware(bootfw); @@ -3829,8 +3964,8 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, * stuck (only if we aren't roaming -- * otherwise we'll never scan more than 2 or 3 * channels..) */ - IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | - IPW_DL_STATE, "Aborting scan with missed beacon.\n"); + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE, + "Aborting scan with missed beacon.\n"); queue_work(priv->workqueue, &priv->abort_scan); } @@ -3891,6 +4026,35 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, priv->status &= ~STATUS_ASSOCIATING; priv->status |= STATUS_ASSOCIATED; +#ifdef CONFIG_IPW_QOS + if (priv->status & STATUS_AUTH) { + if ((sizeof + (struct + ieee80211_assoc_response_frame) + <= notif->size) + && (notif->size <= 2314)) { + struct + ieee80211_rx_stats + stats = { + .len = + notif-> + size - 1, + }; + + IPW_DEBUG_QOS + ("QoS Associate " + "size %d\n", + notif->size); + ieee80211_rx_mgt(priv-> + ieee, + (struct + ieee80211_hdr + *) + ¬if->u.raw, &stats); + } + } +#endif + schedule_work(&priv->link_up); break; @@ -3970,12 +4134,21 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, ~(STATUS_DISASSOCIATING | STATUS_ASSOCIATING | STATUS_ASSOCIATED | STATUS_AUTH); + if (priv->assoc_network + && (priv->assoc_network-> + capability & + WLAN_CAPABILITY_IBSS)) + ipw_remove_current_network + (priv); schedule_work(&priv->link_down); break; } + case CMAS_RX_ASSOC_RESP: + break; + default: IPW_ERROR("assoc: unknown (%d)\n", assoc->state); @@ -4060,6 +4233,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, case CMAS_RX_ASSOC_RESP: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, "RX_ASSOC_RESP\n"); + break; case CMAS_ASSOCIATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | @@ -4106,6 +4280,19 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, cancel_delayed_work(&priv->scan_check); + if (priv->status & STATUS_EXIT_PENDING) + break; + + priv->ieee->scans++; + +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + queue_work(priv->workqueue, + &priv->request_scan); + break; + } +#endif /* CONFIG_IPW2200_MONITOR */ + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING | STATUS_ROAMING | @@ -4124,8 +4311,6 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, && priv->status & STATUS_ASSOCIATED) queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); - - priv->ieee->scans++; break; } @@ -4256,43 +4441,43 @@ static int ipw_queue_reset(struct ipw_priv *priv) ipw_tx_queue_free(priv); /* Tx CMD queue */ rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd, - CX2_TX_CMD_QUEUE_READ_INDEX, - CX2_TX_CMD_QUEUE_WRITE_INDEX, - CX2_TX_CMD_QUEUE_BD_BASE, - CX2_TX_CMD_QUEUE_BD_SIZE); + IPW_TX_CMD_QUEUE_READ_INDEX, + IPW_TX_CMD_QUEUE_WRITE_INDEX, + IPW_TX_CMD_QUEUE_BD_BASE, + IPW_TX_CMD_QUEUE_BD_SIZE); if (rc) { IPW_ERROR("Tx Cmd queue init failed\n"); goto error; } /* Tx queue(s) */ rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx, - CX2_TX_QUEUE_0_READ_INDEX, - CX2_TX_QUEUE_0_WRITE_INDEX, - CX2_TX_QUEUE_0_BD_BASE, CX2_TX_QUEUE_0_BD_SIZE); + IPW_TX_QUEUE_0_READ_INDEX, + IPW_TX_QUEUE_0_WRITE_INDEX, + IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE); if (rc) { IPW_ERROR("Tx 0 queue init failed\n"); goto error; } rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx, - CX2_TX_QUEUE_1_READ_INDEX, - CX2_TX_QUEUE_1_WRITE_INDEX, - CX2_TX_QUEUE_1_BD_BASE, CX2_TX_QUEUE_1_BD_SIZE); + IPW_TX_QUEUE_1_READ_INDEX, + IPW_TX_QUEUE_1_WRITE_INDEX, + IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE); if (rc) { IPW_ERROR("Tx 1 queue init failed\n"); goto error; } rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx, - CX2_TX_QUEUE_2_READ_INDEX, - CX2_TX_QUEUE_2_WRITE_INDEX, - CX2_TX_QUEUE_2_BD_BASE, CX2_TX_QUEUE_2_BD_SIZE); + IPW_TX_QUEUE_2_READ_INDEX, + IPW_TX_QUEUE_2_WRITE_INDEX, + IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE); if (rc) { IPW_ERROR("Tx 2 queue init failed\n"); goto error; } rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx, - CX2_TX_QUEUE_3_READ_INDEX, - CX2_TX_QUEUE_3_WRITE_INDEX, - CX2_TX_QUEUE_3_BD_BASE, CX2_TX_QUEUE_3_BD_SIZE); + IPW_TX_QUEUE_3_READ_INDEX, + IPW_TX_QUEUE_3_WRITE_INDEX, + IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE); if (rc) { IPW_ERROR("Tx 3 queue init failed\n"); goto error; @@ -4382,7 +4567,7 @@ static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, * Rx theory of operation * * The host allocates 32 DMA target addresses and passes the host address - * to the firmware at register CX2_RFDS_TABLE_LOWER + N * RFD_SIZE where N is + * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is * 0 to 31 * * Rx Queue Indexes @@ -4466,7 +4651,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv) rxb = list_entry(element, struct ipw_rx_mem_buffer, list); list_del(element); - ipw_write32(priv, CX2_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE, + ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE, rxb->dma_addr); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE; @@ -4481,7 +4666,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv) /* If we've added more space for the firmware to place data, tell it */ if (write != rxq->write) - ipw_write32(priv, CX2_RX_WRITE_INDEX, rxq->write); + ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write); } /* @@ -4502,7 +4687,7 @@ static void ipw_rx_queue_replenish(void *data) while (!list_empty(&rxq->rx_used)) { element = rxq->rx_used.next; rxb = list_entry(element, struct ipw_rx_mem_buffer, list); - rxb->skb = alloc_skb(CX2_RX_BUF_SIZE, GFP_ATOMIC); + rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC); if (!rxb->skb) { printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n", priv->net_dev->name); @@ -4516,7 +4701,7 @@ static void ipw_rx_queue_replenish(void *data) rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data; rxb->dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, - CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; @@ -4549,7 +4734,7 @@ static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq) for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].skb != NULL) { pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(rxq->pool[i].skb); } } @@ -5195,20 +5380,21 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * with an invalid channel for wireless mode will trigger a * FW fatal error. */ - network->mode = is_valid_channel(priv->ieee->mode, priv->channel); - if (!network->mode) { + if (!ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); IPW_WARNING("Overriding invalid channel\n"); if (priv->ieee->mode & IEEE_A) { network->mode = IEEE_A; - priv->channel = band_a_active_channel[0]; + priv->channel = geo->a[0].channel; } else if (priv->ieee->mode & IEEE_G) { network->mode = IEEE_G; - priv->channel = band_b_active_channel[0]; + priv->channel = geo->bg[0].channel; } else { network->mode = IEEE_B; - priv->channel = band_b_active_channel[0]; + priv->channel = geo->bg[0].channel; } - } + } else + network->mode = priv->ieee->mode; network->channel = priv->channel; priv->config |= CFG_ADHOC_PERSIST; @@ -5239,7 +5425,34 @@ static void ipw_adhoc_create(struct ipw_priv *priv, network->rsn_ie_len = 0; } -static void ipw_send_wep_keys(struct ipw_priv *priv) +static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index) +{ + struct ipw_tgi_tx_key *key; + struct host_cmd cmd = { + .cmd = IPW_CMD_TGI_TX_KEY, + .len = sizeof(*key) + }; + + if (!(priv->ieee->sec.flags & (1 << index))) + return; + + key = (struct ipw_tgi_tx_key *)&cmd.param; + key->key_id = index; + memcpy(key->key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); + key->security_type = type; + key->station_index = 0; /* always 0 for BSS */ + key->flags = 0; + /* 0 for new key; previous value of counter (after fatal error) */ + key->tx_counter[0] = 0; + key->tx_counter[1] = 0; + + if (ipw_send_cmd(priv, &cmd)) { + IPW_ERROR("failed to send TGI_TX_KEY command\n"); + return; + } +} + +static void ipw_send_wep_keys(struct ipw_priv *priv, int type) { struct ipw_wep_key *key; int i; @@ -5252,15 +5465,18 @@ static void ipw_send_wep_keys(struct ipw_priv *priv) key->cmd_id = DINO_CMD_WEP_KEY; key->seq_num = 0; + /* Note: AES keys cannot be set for multiple times. + * Only set it at the first time. */ for (i = 0; i < 4; i++) { - key->key_index = i; - if (!(priv->sec.flags & (1 << i))) + key->key_index = i | type; + if (!(priv->ieee->sec.flags & (1 << i))) { key->key_size = 0; - else { - key->key_size = priv->sec.key_sizes[i]; - memcpy(key->key, priv->sec.keys[i], key->key_size); + continue; } + key->key_size = priv->ieee->sec.key_sizes[i]; + memcpy(key->key, priv->ieee->sec.keys[i], key->key_size); + if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send WEP_KEY command\n"); return; @@ -5268,6 +5484,52 @@ static void ipw_send_wep_keys(struct ipw_priv *priv) } } +static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) +{ + switch (priv->ieee->sec.level) { + case SEC_LEVEL_3: + if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) + ipw_send_tgi_tx_key(priv, + DCT_FLAG_EXT_SECURITY_CCM, + priv->ieee->sec.active_key); + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); + + priv->sys_config.disable_unicast_decryption = 0; + priv->sys_config.disable_multicast_decryption = 0; + priv->ieee->host_decrypt = 0; + if (ipw_send_system_config(priv, &priv->sys_config)) + IPW_ERROR("ipw_send_system_config failed\n"); + + break; + case SEC_LEVEL_2: + if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) + ipw_send_tgi_tx_key(priv, + DCT_FLAG_EXT_SECURITY_TKIP, + priv->ieee->sec.active_key); + + priv->sys_config.disable_unicast_decryption = 1; + priv->sys_config.disable_multicast_decryption = 1; + priv->ieee->host_decrypt = 1; + if (ipw_send_system_config(priv, &priv->sys_config)) + IPW_ERROR("ipw_send_system_config failed\n"); + + break; + case SEC_LEVEL_1: + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); + + priv->sys_config.disable_unicast_decryption = 0; + priv->sys_config.disable_multicast_decryption = 0; + priv->ieee->host_decrypt = 0; + if (ipw_send_system_config(priv, &priv->sys_config)) + IPW_ERROR("ipw_send_system_config failed\n"); + + break; + case SEC_LEVEL_0: + default: + break; + } +} + static void ipw_adhoc_check(void *data) { struct ipw_priv *priv = data; @@ -5321,8 +5583,7 @@ static void ipw_debug_config(struct ipw_priv *priv) #define ipw_debug_config(x) do {} while (0) #endif -static inline void ipw_set_fixed_rate(struct ipw_priv *priv, - struct ieee80211_network *network) +static inline void ipw_set_fixed_rate(struct ipw_priv *priv, int mode) { /* TODO: Verify that this works... */ struct ipw_fixed_rate fr = { @@ -5350,7 +5611,7 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, default: /* 2.4Ghz or Mixed */ /* IEEE_B */ - if (network->mode == IEEE_B) { + if (mode == IEEE_B) { if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { /* Invalid fixed rate mask */ IPW_DEBUG_WX @@ -5412,78 +5673,98 @@ static int ipw_request_scan(struct ipw_priv *priv) { struct ipw_scan_request_ext scan; int channel_index = 0; - int i, err, scan_type; + int i, err = 0, scan_type; + const struct ieee80211_geo *geo; +#ifdef CONFIG_IPW2200_MONITOR + u8 channel; +#endif - if (priv->status & STATUS_EXIT_PENDING) { - IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n"); - priv->status |= STATUS_SCAN_PENDING; - return 0; - } + down(&priv->sem); + + geo = ieee80211_get_geo(priv->ieee); if (priv->status & STATUS_SCANNING) { IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); -// IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); priv->status |= STATUS_SCAN_PENDING; -// ipw_abort_scan(priv); - return 0; + goto done; } if (priv->status & STATUS_SCAN_ABORTING) { IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); priv->status |= STATUS_SCAN_PENDING; - return 0; + goto done; } if (priv->status & STATUS_RF_KILL_MASK) { IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); priv->status |= STATUS_SCAN_PENDING; - return 0; + goto done; } memset(&scan, 0, sizeof(scan)); - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = cpu_to_le16(20); + if (priv->config & CFG_SPEED_SCAN) + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = + cpu_to_le16(30); + else + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = + cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = cpu_to_le16(20); scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); -#ifdef CONFIG_IPW_MONITOR +#ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - u8 band = 0, channel = priv->channel; + u8 band = 0; - if (is_valid_channel(IEEE_A, channel)) + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + case IEEE80211_52GHZ_BAND: band = (u8) (IPW_A_MODE << 6) | 1; + channel = priv->channel; + break; - if (is_valid_channel(IEEE_B | IEEE_G, channel)) + case IEEE80211_24GHZ_BAND: band = (u8) (IPW_B_MODE << 6) | 1; + channel = priv->channel; + break; - if (band == 0) { + default: band = (u8) (IPW_B_MODE << 6) | 1; channel = 9; + break; } - scan.channels_list[channel_index++] = band; - scan.channels_list[channel_index] = channel; - ipw_set_scan_type(&scan, channel_index, - IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); + scan.channels_list[0] = band; + scan.channels_list[1] = channel; + ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); + /* NOTE: The card will sit on this channel for this time + * period. Scan aborts are timing sensitive and frequently + * result in firmware restarts. As such, it is best to + * set a small dwell_time here and just keep re-issuing + * scans. Otherwise fast channel hopping will not actually + * hop channels. + * + * TODO: Move SPEED SCAN support to all modes and bands */ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(2000); } else { -#endif /* CONFIG_IPW_MONITOR */ - /* If we are roaming, then make this a directed scan for the current - * network. Otherwise, ensure that every other scan is a fast - * channel hop scan */ - if ((priv->status & STATUS_ROAMING) || (!(priv->status & STATUS_ASSOCIATED) && (priv->config & CFG_STATIC_ESSID) && (le32_to_cpu(scan.full_scan_index) % 2))) { /* || ( - (priv->status & STATUS_ASSOCIATED) && - (priv->ieee->iw_mode == IW_MODE_ADHOC))) { */ +#endif /* CONFIG_IPW2200_MONITOR */ + /* If we are roaming, then make this a directed scan for the + * current network. Otherwise, ensure that every other scan + * is a fast channel hop scan */ + if ((priv->status & STATUS_ROAMING) + || (!(priv->status & STATUS_ASSOCIATED) + && (priv->config & CFG_STATIC_ESSID) + && (le32_to_cpu(scan.full_scan_index) % 2))) { err = ipw_send_ssid(priv, priv->essid, priv->essid_len); if (err) { - IPW_DEBUG_HC - ("Attempt to send SSID command failed.\n"); - return err; + IPW_DEBUG_HC("Attempt to send SSID command " + "failed.\n"); + goto done; } scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; @@ -5491,17 +5772,16 @@ static int ipw_request_scan(struct ipw_priv *priv) scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; } + /* Add channels to the scan list */ if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { int start = channel_index; - for (i = 0; i < MAX_A_CHANNELS; i++) { - if (band_a_active_channel[i] == 0) - break; + for (i = 0; i < geo->a_channels; i++) { if ((priv->status & STATUS_ASSOCIATED) && - band_a_active_channel[i] == priv->channel) + geo->a[i].channel == priv->channel) continue; channel_index++; scan.channels_list[channel_index] = - band_a_active_channel[i]; + geo->a[i].channel; ipw_set_scan_type(&scan, channel_index, scan_type); } @@ -5516,17 +5796,55 @@ static int ipw_request_scan(struct ipw_priv *priv) if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { int start = channel_index; - for (i = 0; i < MAX_B_CHANNELS; i++) { - if (band_b_active_channel[i] == 0) - break; - if ((priv->status & STATUS_ASSOCIATED) && - band_b_active_channel[i] == priv->channel) - continue; - channel_index++; - scan.channels_list[channel_index] = - band_b_active_channel[i]; - ipw_set_scan_type(&scan, channel_index, - scan_type); + if (priv->config & CFG_SPEED_SCAN) { + u8 channels[IEEE80211_24GHZ_CHANNELS] = { + /* nop out the list */ + [0] = 0 + }; + + u8 channel; + while (channel_index < IPW_SCAN_CHANNELS) { + channel = + priv->speed_scan[priv-> + speed_scan_pos]; + if (channel == 0) { + priv->speed_scan_pos = 0; + channel = priv->speed_scan[0]; + } + if ((priv->status & STATUS_ASSOCIATED) + && channel == priv->channel) { + priv->speed_scan_pos++; + continue; + } + + /* If this channel has already been + * added in scan, break from loop + * and this will be the first channel + * in the next scan. + */ + if (channels[channel - 1] != 0) + break; + + channels[channel - 1] = 1; + priv->speed_scan_pos++; + channel_index++; + scan.channels_list[channel_index] = + channel; + ipw_set_scan_type(&scan, channel_index, + scan_type); + } + } else { + for (i = 0; i < geo->bg_channels; i++) { + if ((priv->status & STATUS_ASSOCIATED) + && geo->bg[i].channel == + priv->channel) + continue; + channel_index++; + scan.channels_list[channel_index] = + geo->bg[i].channel; + ipw_set_scan_type(&scan, channel_index, + scan_type); + } } if (start != channel_index) { @@ -5535,28 +5853,22 @@ static int ipw_request_scan(struct ipw_priv *priv) start); } } -#ifdef CONFIG_IPW_MONITOR +#ifdef CONFIG_IPW2200_MONITOR } #endif err = ipw_send_scan_request_ext(priv, &scan); if (err) { IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); - return -EIO; + goto done; } priv->status |= STATUS_SCANNING; priv->status &= ~STATUS_SCAN_PENDING; - return 0; -} - -static void ipw_bg_request_scan(void *data) -{ - struct ipw_priv *priv = data; - down(&priv->sem); - ipw_request_scan(data); + done: up(&priv->sem); + return err; } static void ipw_bg_abort_scan(void *data) @@ -5608,7 +5920,8 @@ struct ipw_param { } wpa_param; struct { u32 len; - u8 *data; + u8 reserved[32]; + u8 data[0]; } wpa_ie; struct { int command; @@ -5631,29 +5944,9 @@ struct ipw_param { static int ipw_wpa_enable(struct ipw_priv *priv, int value) { - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { - .flags = SEC_LEVEL | SEC_ENABLED, - }; - int ret = 0; - - ieee->wpa_enabled = value; - - if (value) { - sec.level = SEC_LEVEL_3; - sec.enabled = 1; - } else { - sec.level = SEC_LEVEL_0; - sec.enabled = 0; - ieee->wpa_ie_len = 0; - } - - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - else - ret = -EOPNOTSUPP; - - return ret; + /* This is called when wpa_supplicant loads and closes the driver + * interface. */ + return 0; } #define AUTH_ALG_OPEN_SYSTEM 0x1 @@ -5714,9 +6007,37 @@ static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) break; - case IPW_PARAM_DROP_UNENCRYPTED: - priv->ieee->drop_unencrypted = value; - break; + case IPW_PARAM_DROP_UNENCRYPTED:{ + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = value, + }; + priv->ieee->drop_unencrypted = value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (priv->ieee->set_security) + priv->ieee->set_security(priv->ieee->dev, &sec); + break; + } case IPW_PARAM_PRIVACY_INVOKED: priv->ieee->privacy_invoked = value; @@ -5793,9 +6114,6 @@ static int ipw_wpa_set_wpa_ie(struct net_device *dev, struct ieee80211_device *ieee = priv->ieee; u8 *buf; - if (!ieee->wpa_enabled) - return -EOPNOTSUPP; - if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) return -EINVAL; @@ -5857,6 +6175,7 @@ static int ipw_wpa_set_encryption(struct net_device *dev, if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) { sec.enabled = 0; + sec.encrypt = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_ENABLED | SEC_LEVEL; ieee80211_crypt_delayed_deinit(ieee, crypt); @@ -5864,8 +6183,14 @@ static int ipw_wpa_set_encryption(struct net_device *dev, goto done; } sec.enabled = 1; + sec.encrypt = 1; sec.flags |= SEC_ENABLED; + /* IPW HW cannot build TKIP MIC, host decryption still needed. */ + if (!(ieee->host_encrypt || ieee->host_decrypt) && + strcmp(param->u.crypt.alg, "TKIP")) + goto skip_host_crypt; + ops = ieee80211_get_crypto_ops(param->u.crypt.alg); if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { request_module("ieee80211_crypt_wep"); @@ -5922,25 +6247,27 @@ static int ipw_wpa_set_encryption(struct net_device *dev, goto done; } + skip_host_crypt: if (param->u.crypt.set_tx) { ieee->tx_keyidx = param->u.crypt.idx; sec.active_key = param->u.crypt.idx; sec.flags |= SEC_ACTIVE_KEY; - } + } else + sec.flags &= ~SEC_ACTIVE_KEY; - if (ops->name != NULL) { - if (strcmp(ops->name, "WEP") == 0) { - memcpy(sec.keys[param->u.crypt.idx], - param->u.crypt.key, param->u.crypt.key_len); - sec.key_sizes[param->u.crypt.idx] = - param->u.crypt.key_len; - sec.flags |= (1 << param->u.crypt.idx); + if (param->u.crypt.alg != NULL) { + memcpy(sec.keys[param->u.crypt.idx], + param->u.crypt.key, param->u.crypt.key_len); + sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; + sec.flags |= (1 << param->u.crypt.idx); + + if (strcmp(param->u.crypt.alg, "WEP") == 0) { sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_1; - } else if (strcmp(ops->name, "TKIP") == 0) { + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_2; - } else if (strcmp(ops->name, "CCMP") == 0) { + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_3; } @@ -6017,38 +6344,552 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) return ret; } -static int ipw_associate_network(struct ipw_priv *priv, - struct ieee80211_network *network, - struct ipw_supported_rates *rates, int roaming) +#ifdef CONFIG_IPW_QOS + +/* QoS */ +/* +* get the modulation type of the current network or +* the card current mode +*/ +u8 ipw_qos_current_mode(struct ipw_priv * priv) { - int err; + u8 mode = 0; - if (priv->config & CFG_FIXED_RATE) - ipw_set_fixed_rate(priv, network); + if (priv->status & STATUS_ASSOCIATED) { + unsigned long flags; - if (!(priv->config & CFG_STATIC_ESSID)) { - priv->essid_len = min(network->ssid_len, - (u8) IW_ESSID_MAX_SIZE); - memcpy(priv->essid, network->ssid, priv->essid_len); + spin_lock_irqsave(&priv->ieee->lock, flags); + mode = priv->assoc_network->mode; + spin_unlock_irqrestore(&priv->ieee->lock, flags); + } else { + mode = priv->ieee->mode; } + IPW_DEBUG_QOS("QoS network/card mode %d \n", mode); + return mode; +} - network->last_associate = jiffies; - - memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); - priv->assoc_request.channel = network->channel; - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->capability & CAP_SHARED_KEY)) { - priv->assoc_request.auth_type = AUTH_SHARED_KEY; - priv->assoc_request.auth_key = priv->sec.active_key; +/* +* Handle management frame beacon and probe response +*/ +static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, + int active_network, + struct ieee80211_network *network) +{ + u32 size = sizeof(struct ieee80211_qos_parameters); + + if ((network->capability & WLAN_CAPABILITY_IBSS)) + network->qos_data.active = network->qos_data.supported; + + if (network->flags & NETWORK_HAS_QOS_MASK) { + if (active_network + && (network->flags & NETWORK_HAS_QOS_PARAMETERS)) + network->qos_data.active = network->qos_data.supported; + + if ((network->qos_data.active == 1) && (active_network == 1) && + (network->flags & NETWORK_HAS_QOS_PARAMETERS) && + (network->qos_data.old_param_count != + network->qos_data.param_count)) { + network->qos_data.old_param_count = + network->qos_data.param_count; + schedule_work(&priv->qos_activate); + IPW_DEBUG_QOS + ("QoS parameters change call qos_activate\n"); + } } else { - priv->assoc_request.auth_type = AUTH_OPEN; - priv->assoc_request.auth_key = 0; + if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) { + memcpy(&(network->qos_data.parameters), + &def_parameters_CCK, size); + } else { + memcpy(&(network->qos_data.parameters), + &def_parameters_OFDM, size); + } + if ((network->qos_data.active == 1) && (active_network == 1)) { + IPW_DEBUG_QOS("QoS was disabled call qos_activate \n"); + schedule_work(&priv->qos_activate); + } + + network->qos_data.active = 0; + network->qos_data.supported = 0; } + if ((priv->status & STATUS_ASSOCIATED) + && (priv->ieee->iw_mode == IW_MODE_ADHOC) + && (active_network == 0)) { + + if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) { + if ((network->capability & WLAN_CAPABILITY_IBSS) + && !(network->flags & NETWORK_EMPTY_ESSID)) { + if ((network->ssid_len == + priv->assoc_network->ssid_len) + && !memcmp(network->ssid, + priv->assoc_network->ssid, + network->ssid_len)) { + queue_work(priv->workqueue, + &priv->merge_networks); + } - if (priv->capability & CAP_PRIVACY_ON) - ipw_send_wep_keys(priv); + } + } + } - if (priv->ieee->wpa_ie_len) { + return 0; +} + +/* +* This function set up the firmware to support QoS. It sends +* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO +*/ +static int ipw_qos_activate(struct ipw_priv *priv, + struct ieee80211_qos_data *qos_network_data) +{ + int err; + struct ieee80211_qos_parameters qos_parameters[QOS_QOS_SETS]; + struct ieee80211_qos_parameters *active_one = NULL; + u32 size = sizeof(struct ieee80211_qos_parameters); + u32 burst_duration; + int i; + u8 type; + + type = ipw_qos_current_mode(priv); + + active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]); + memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size); + active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]); + memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size); + + if (qos_network_data == NULL) { + if (type == IEEE_B) { + IPW_DEBUG_QOS("QoS activate network mode %d\n", type); + active_one = &def_parameters_CCK; + } else + active_one = &def_parameters_OFDM; + + memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, + size); + burst_duration = ipw_qos_get_burst_duration(priv); + for (i = 0; i < QOS_QUEUE_NUM; i++) + qos_parameters[QOS_PARAM_SET_ACTIVE]. + tx_op_limit[i] = (u16) burst_duration; + } else if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { + if (type == IEEE_B) { + IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", + type); + if (priv->qos_data.qos_enable == 0) + active_one = &def_parameters_CCK; + else + active_one = priv->qos_data.def_qos_parm_CCK; + } else { + if (priv->qos_data.qos_enable == 0) + active_one = &def_parameters_OFDM; + else + active_one = priv->qos_data.def_qos_parm_OFDM; + } + memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, + size); + } else { + unsigned long flags; + int active; + + spin_lock_irqsave(&priv->ieee->lock, flags); + active_one = &(qos_network_data->parameters); + qos_network_data->old_param_count = + qos_network_data->param_count; + memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, + size); + active = qos_network_data->supported; + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + if (active == 0) { + burst_duration = ipw_qos_get_burst_duration(priv); + for (i = 0; i < QOS_QUEUE_NUM; i++) + qos_parameters[QOS_PARAM_SET_ACTIVE]. + tx_op_limit[i] = (u16) burst_duration; + } + } + + IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); + err = + ipw_send_qos_params_command(priv, + (struct ieee80211_qos_parameters *) + &(qos_parameters[0])); + if (err) + IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); + + return err; +} + +/* +* send IPW_CMD_WME_INFO to the firmware +*/ +static int ipw_qos_set_info_element(struct ipw_priv *priv) +{ + int ret = 0; + struct ieee80211_qos_information_element qos_info; + + if (priv == NULL) + return -1; + + qos_info.elementID = QOS_ELEMENT_ID; + qos_info.length = sizeof(struct ieee80211_qos_information_element) - 2; + + qos_info.version = QOS_VERSION_1; + qos_info.ac_info = 0; + + memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN); + qos_info.qui_type = QOS_OUI_TYPE; + qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE; + + ret = ipw_send_qos_info_command(priv, &qos_info); + if (ret != 0) { + IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n"); + } + return ret; +} + +/* +* Set the QoS parameter with the association request structure +*/ +static int ipw_qos_association(struct ipw_priv *priv, + struct ieee80211_network *network) +{ + int err = 0; + struct ieee80211_qos_data *qos_data = NULL; + struct ieee80211_qos_data ibss_data = { + .supported = 1, + .active = 1, + }; + + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (!(network->capability & WLAN_CAPABILITY_IBSS)) + BUG(); + + qos_data = &ibss_data; + break; + + case IW_MODE_INFRA: + qos_data = &network->qos_data; + break; + + default: + BUG(); + break; + } + + err = ipw_qos_activate(priv, qos_data); + if (err) { + priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC; + return err; + } + + if (priv->qos_data.qos_enable && qos_data->supported) { + IPW_DEBUG_QOS("QoS will be enabled for this association\n"); + priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC; + return ipw_qos_set_info_element(priv); + } + + return 0; +} + +/* +* handling the beaconing responces. if we get different QoS setting +* of the network from the the associated setting adjust the QoS +* setting +*/ +static int ipw_qos_association_resp(struct ipw_priv *priv, + struct ieee80211_network *network) +{ + int ret = 0; + unsigned long flags; + u32 size = sizeof(struct ieee80211_qos_parameters); + int set_qos_param = 0; + + if ((priv == NULL) || (network == NULL) + || (priv->assoc_network == NULL)) + + return ret; + + if (!(priv->status & STATUS_ASSOCIATED)) + return ret; + + if ((priv->ieee->iw_mode != IW_MODE_INFRA)) { + return ret; + } + + spin_lock_irqsave(&priv->ieee->lock, flags); + if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { + memcpy(&(priv->assoc_network->qos_data), &(network->qos_data), + sizeof(struct ieee80211_qos_data)); + priv->assoc_network->qos_data.active = 1; + if ((network->qos_data.old_param_count != + network->qos_data.param_count)) { + set_qos_param = 1; + network->qos_data.old_param_count = + network->qos_data.param_count; + } + + } else { + if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) { + memcpy(&(priv->assoc_network->qos_data.parameters), + &def_parameters_CCK, size); + } else { + memcpy(&(priv->assoc_network->qos_data.parameters), + &def_parameters_OFDM, size); + } + priv->assoc_network->qos_data.active = 0; + priv->assoc_network->qos_data.supported = 0; + set_qos_param = 1; + } + + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + if (set_qos_param == 1) + schedule_work(&priv->qos_activate); + + return ret; +} + +static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) +{ + u32 ret = 0; + + if ((priv == NULL)) + return 0; + + if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) { + ret = priv->qos_data.burst_duration_CCK; + } else { + ret = priv->qos_data.burst_duration_OFDM; + } + return ret; +} + +/* +* Initialize the setting of QoS global +*/ +static void ipw_qos_init(struct ipw_priv *priv, int enable, + int burst_enable, u32 burst_duration_CCK, + u32 burst_duration_OFDM) +{ + priv->qos_data.qos_enable = enable; + + if (priv->qos_data.qos_enable) { + priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK; + priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM; + IPW_DEBUG_QOS("QoS is enabled\n"); + } else { + priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK; + priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM; + IPW_DEBUG_QOS("QoS is not enabled\n"); + } + + priv->qos_data.burst_enable = burst_enable; + + if (burst_enable) { + priv->qos_data.burst_duration_CCK = burst_duration_CCK; + priv->qos_data.burst_duration_OFDM = burst_duration_OFDM; + } else { + priv->qos_data.burst_duration_CCK = 0; + priv->qos_data.burst_duration_OFDM = 0; + } +} + +/* +* map the packet priority to the right TX Queue +*/ +static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) +{ + if (priority > 7 || !priv->qos_data.qos_enable) + priority = 0; + + return from_priority_to_tx_queue[priority] - 1; +} + +/* +* add QoS parameter to the TX command +*/ +static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, + u16 priority, + struct tfd_data *tfd, u8 unicast) +{ + int ret = 0; + int tx_queue_id = 0; + struct ieee80211_qos_data *qos_data = NULL; + int active, supported; + unsigned long flags; + + if (!(priv->status & STATUS_ASSOCIATED)) + return 0; + + qos_data = &priv->assoc_network->qos_data; + + spin_lock_irqsave(&priv->ieee->lock, flags); + + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + if (unicast == 0) + qos_data->active = 0; + else + qos_data->active = qos_data->supported; + } + + active = qos_data->active; + supported = qos_data->supported; + + spin_unlock_irqrestore(&priv->ieee->lock, flags); + + IPW_DEBUG_QOS + ("QoS %d network is QoS active %d supported %d unicast %d\n", + priv->qos_data.qos_enable, active, supported, unicast); + if (active && priv->qos_data.qos_enable) { + ret = from_priority_to_tx_queue[priority]; + tx_queue_id = ret - 1; + IPW_DEBUG_QOS("QoS packet priority is %d \n", priority); + if (priority <= 7) { + tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; + tfd->tfd.tfd_26.mchdr.qos_ctrl = priority; + tfd->tfd.tfd_26.mchdr.frame_ctl |= + IEEE80211_STYPE_QOS_DATA; + + if (priv->qos_data.qos_no_ack_mask & + (1UL << tx_queue_id)) { + tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; + tfd->tfd.tfd_26.mchdr.qos_ctrl |= + CTRL_QOS_NO_ACK; + } + } + } + + return ret; +} + +/* +* background support to run QoS activate functionality +*/ +static void ipw_bg_qos_activate(void *data) +{ + struct ipw_priv *priv = data; + + if (priv == NULL) + return; + + down(&priv->sem); + + if (priv->status & STATUS_ASSOCIATED) + ipw_qos_activate(priv, &(priv->assoc_network->qos_data)); + + up(&priv->sem); +} + +/* +* Handler for probe responce and beacon frame +*/ +static int ipw_handle_management_frame(struct net_device *dev, + struct ieee80211_network *network, + u16 type) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int active_network; + + if (priv->status & STATUS_ASSOCIATED && network == priv->assoc_network) + active_network = 1; + else + active_network = 0; + + switch (type) { + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON: + ipw_qos_handle_probe_reponse(priv, active_network, network); + break; + case IEEE80211_STYPE_ASSOC_RESP: + ipw_qos_association_resp(priv, network); + break; + default: + break; + } + + return 0; +} + +static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters + *qos_param) +{ + struct host_cmd cmd = { + .cmd = IPW_CMD_QOS_PARAMETERS, + .len = (sizeof(struct ieee80211_qos_parameters) * 3) + }; + + if (!priv || !qos_param) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + memcpy(&cmd.param, qos_param, + (sizeof(struct ieee80211_qos_parameters) * 3)); + if (ipw_send_cmd(priv, &cmd)) { + IPW_ERROR("failed to send IPW_CMD_QOS_PARAMETERS command\n"); + return -1; + } + + return 0; +} + +static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element + *qos_param) +{ + struct host_cmd cmd = { + .cmd = IPW_CMD_WME_INFO, + .len = sizeof(*qos_param) + }; + + if (!priv || !qos_param) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + memcpy(&cmd.param, qos_param, sizeof(*qos_param)); + if (ipw_send_cmd(priv, &cmd)) { + IPW_ERROR("failed to send CMD_QOS_INFO command\n"); + return -1; + } + + return 0; +} + +#endif /* CONFIG_IPW_QOS */ + +static int ipw_associate_network(struct ipw_priv *priv, + struct ieee80211_network *network, + struct ipw_supported_rates *rates, int roaming) +{ + int err; + + if (priv->config & CFG_FIXED_RATE) + ipw_set_fixed_rate(priv, network->mode); + + if (!(priv->config & CFG_STATIC_ESSID)) { + priv->essid_len = min(network->ssid_len, + (u8) IW_ESSID_MAX_SIZE); + memcpy(priv->essid, network->ssid, priv->essid_len); + } + + network->last_associate = jiffies; + + memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); + priv->assoc_request.channel = network->channel; + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->capability & CAP_SHARED_KEY)) { + priv->assoc_request.auth_type = AUTH_SHARED_KEY; + priv->assoc_request.auth_key = priv->ieee->sec.active_key; + + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.level == SEC_LEVEL_1) && + !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); + } else { + priv->assoc_request.auth_type = AUTH_OPEN; + priv->assoc_request.auth_key = 0; + } + + if (priv->ieee->wpa_ie_len) { priv->assoc_request.policy_support = 0x02; /* RSN active */ ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, priv->ieee->wpa_ie_len); @@ -6095,7 +6936,7 @@ static int ipw_associate_network(struct ipw_priv *priv, "(open)") : "", priv->capability & CAP_PRIVACY_ON ? " key=" : "", priv->capability & CAP_PRIVACY_ON ? - '1' + priv->sec.active_key : '.', + '1' + priv->ieee->sec.active_key : '.', priv->capability & CAP_PRIVACY_ON ? '.' : ' '); priv->assoc_request.beacon_interval = network->beacon_interval; @@ -6170,6 +7011,10 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->assoc_network = network; +#ifdef CONFIG_IPW_QOS + ipw_qos_association(priv, network); +#endif + err = ipw_send_associate(priv, &priv->assoc_request); if (err) { IPW_DEBUG_HC("Attempt to send associate command failed.\n"); @@ -6268,6 +7113,11 @@ static int ipw_associate(void *data) struct list_head *element; unsigned long flags; + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n"); + return 0; + } + if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_ASSOC ("Not attempting association (already in progress)\n"); @@ -6315,9 +7165,15 @@ static int ipw_associate(void *data) if (!network) { ipw_debug_config(priv); - if (!(priv->status & STATUS_SCANNING)) - queue_delayed_work(priv->workqueue, &priv->request_scan, - SCAN_INTERVAL); + if (!(priv->status & STATUS_SCANNING)) { + if (!(priv->config & CFG_SPEED_SCAN)) + queue_delayed_work(priv->workqueue, + &priv->request_scan, + SCAN_INTERVAL); + else + queue_work(priv->workqueue, + &priv->request_scan); + } return 0; } @@ -6335,9 +7191,48 @@ static void ipw_bg_associate(void *data) up(&priv->sem); } -static inline void ipw_handle_data_packet(struct ipw_priv *priv, - struct ipw_rx_mem_buffer *rxb, - struct ieee80211_rx_stats *stats) +static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + u16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = le16_to_cpu(hdr->frame_ctl); + if (!(fc & IEEE80211_FCTL_PROTECTED)) + return; + + fc &= ~IEEE80211_FCTL_PROTECTED; + hdr->frame_ctl = cpu_to_le16(fc); + switch (priv->ieee->sec.level) { + case SEC_LEVEL_3: + /* Remove CCMP HDR */ + memmove(skb->data + IEEE80211_3ADDR_LEN, + skb->data + IEEE80211_3ADDR_LEN + 8, + skb->len - IEEE80211_3ADDR_LEN - 8); + skb_trim(skb, skb->len - 8); /* MIC */ + break; + case SEC_LEVEL_2: + break; + case SEC_LEVEL_1: + /* Remove IV */ + memmove(skb->data + IEEE80211_3ADDR_LEN, + skb->data + IEEE80211_3ADDR_LEN + 4, + skb->len - IEEE80211_3ADDR_LEN - 4); + skb_trim(skb, skb->len - 4); /* ICV */ + break; + case SEC_LEVEL_0: + break; + default: + printk(KERN_ERR "Unknow security level %d\n", + priv->ieee->sec.level); + break; + } +} + +static void ipw_handle_data_packet(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) { struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; @@ -6367,11 +7262,15 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ + if (!priv->ieee->host_decrypt) + ipw_rebuild_decrypted_skb(priv, rxb->skb); + if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) priv->ieee->stats.rx_errors++; else { /* ieee80211_rx succeeded, so it now owns the SKB */ rxb->skb = NULL; - ipw_led_activity_on(priv); + __ipw_led_activity_on(priv); } } @@ -6413,6 +7312,53 @@ static inline int is_network_packet(struct ipw_priv *priv, return 1; } +static void ipw_handle_mgmt_packet(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct sk_buff *skb = rxb->skb; + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data; + struct ieee80211_hdr_4addr *header = (struct ieee80211_hdr_4addr *) + (skb->data + IPW_RX_FRAME_SIZE); + + ieee80211_rx_mgt(priv->ieee, header, stats); + + if (priv->ieee->iw_mode == IW_MODE_ADHOC && + ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == + IEEE80211_STYPE_PROBE_RESP) || + (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) == + IEEE80211_STYPE_BEACON))) { + if (!memcmp(header->addr3, priv->bssid, ETH_ALEN)) + ipw_add_station(priv, header->addr2); + } + + if (priv->config & CFG_NET_STATS) { + IPW_DEBUG_HC("sending stat packet\n"); + + /* Set the size of the skb to the size of the full + * ipw header and 802.11 frame */ + skb_put(skb, le16_to_cpu(pkt->u.frame.length) + + IPW_RX_FRAME_SIZE); + + /* Advance past the ipw packet header to the 802.11 frame */ + skb_pull(skb, IPW_RX_FRAME_SIZE); + + /* Push the ieee80211_rx_stats before the 802.11 frame */ + memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats)); + + skb->dev = priv->ieee->dev; + + /* Point raw at the ieee80211_stats */ + skb->mac.raw = skb->data; + + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = __constant_htons(ETH_P_80211_STATS); + memset(skb->cb, 0, sizeof(rxb->skb->cb)); + netif_rx(skb); + rxb->skb = NULL; + } +} + /* * Main entry function for recieving a packet with 80211 headers. This * should be called when ever the FW has notified us that there is a new @@ -6426,8 +7372,8 @@ static void ipw_rx(struct ipw_priv *priv) u32 r, w, i; u8 network_packet; - r = ipw_read32(priv, CX2_RX_READ_INDEX); - w = ipw_read32(priv, CX2_RX_WRITE_INDEX); + r = ipw_read32(priv, IPW_RX_READ_INDEX); + w = ipw_read32(priv, IPW_RX_WRITE_INDEX); i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE; while (i != r) { @@ -6441,7 +7387,7 @@ static void ipw_rx(struct ipw_priv *priv) priv->rxq->queue[i] = NULL; pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, - CX2_RX_BUF_SIZE, + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); pkt = (struct ipw_rx_packet *)rxb->skb->data; @@ -6482,7 +7428,7 @@ static void ipw_rx(struct ipw_priv *priv) priv->rx_packets++; -#ifdef CONFIG_IPW_MONITOR +#ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { ipw_handle_data_packet(priv, rxb, &stats); @@ -6525,56 +7471,17 @@ static void ipw_rx(struct ipw_priv *priv) switch (WLAN_FC_GET_TYPE (le16_to_cpu(header->frame_ctl))) { + case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(priv->ieee, header, - &stats); - if (priv->ieee->iw_mode == IW_MODE_ADHOC - && - ((WLAN_FC_GET_STYPE - (le16_to_cpu(header->frame_ctl)) - == IEEE80211_STYPE_PROBE_RESP) - || - (WLAN_FC_GET_STYPE - (le16_to_cpu(header->frame_ctl)) - == IEEE80211_STYPE_BEACON))) { - if (!memcmp - (header->addr3, priv->bssid, - ETH_ALEN)) - ipw_add_station(priv, - header-> - addr2); - else { - struct - ieee80211_probe_response - *beacon; - beacon = - (struct - ieee80211_probe_response - *)header; - if (le16_to_cpu - (beacon-> - capability) & - WLAN_CAPABILITY_IBSS) - { - queue_work - (priv-> - workqueue, - &priv-> - merge_networks); - } - } - } + ipw_handle_mgmt_packet(priv, rxb, + &stats); break; case IEEE80211_FTYPE_CTL: break; case IEEE80211_FTYPE_DATA: - if (network_packet) - ipw_handle_data_packet(priv, - rxb, - &stats); - else + if (unlikely(!network_packet)) { IPW_DEBUG_DROP("Dropping: " MAC_FMT ", " MAC_FMT ", " @@ -6585,6 +7492,12 @@ static void ipw_rx(struct ipw_priv *priv) addr2), MAC_ARG(header-> addr3)); + break; + } + + ipw_handle_data_packet(priv, rxb, + &stats); + break; } break; @@ -6615,7 +7528,7 @@ static void ipw_rx(struct ipw_priv *priv) } pci_unmap_single(priv->pci_dev, rxb->dma_addr, - CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); list_add_tail(&rxb->list, &priv->rxq->rx_used); i = (i + 1) % RX_QUEUE_SIZE; @@ -6657,6 +7570,8 @@ static int ipw_wx_get_name(struct net_device *dev, static int ipw_set_channel(struct ipw_priv *priv, u8 channel) { + int i; + if (channel == 0) { IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); priv->config &= ~CFG_STATIC_CHANNEL; @@ -6677,6 +7592,27 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel); priv->channel = channel; +#ifdef CONFIG_IPW2200_MONITOR + if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_SCAN("scan abort triggered due to " + "channel change.\n"); + queue_work(priv->workqueue, &priv->abort_scan); + } + + for (i = 1000; i && (priv->status & STATUS_SCANNING); i--) + udelay(10); + + if (priv->status & STATUS_SCANNING) + IPW_DEBUG_SCAN("Still scanning...\n"); + else + IPW_DEBUG_SCAN("Took %dms to abort current scan\n", + 1000 - i); + + return 0; + } +#endif /* CONFIG_IPW2200_MONITOR */ + /* Network configuration changed -- force [re]association */ IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n"); if (!ipw_disassociate(priv)) @@ -6692,29 +7628,30 @@ static int ipw_wx_set_freq(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct iw_freq *fwrq = &wrqu->freq; int ret = 0; + u8 channel; + + if (fwrq->m == 0) { + IPW_DEBUG_WX("SET Freq/Channel -> any\n"); + down(&priv->sem); + ret = ipw_set_channel(priv, 0); + up(&priv->sem); + return ret; + } /* if setting by freq convert to channel */ if (fwrq->e == 1) { - if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) { - int f = fwrq->m / 100000; - int c = 0; - - while ((c < REG_MAX_CHANNEL) && - (f != ipw_frequencies[c])) - c++; - - /* hack to fall through */ - fwrq->e = 0; - fwrq->m = c + 1; - } - } + channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); + if (channel == 0) + return -EINVAL; + } else + channel = fwrq->m; - if (fwrq->e > 0 || fwrq->m > 1000) - return -EOPNOTSUPP; + if (!ieee80211_is_valid_channel(priv->ieee, channel)) + return -EINVAL; IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); down(&priv->sem); - ret = ipw_set_channel(priv, (u8) fwrq->m); + ret = ipw_set_channel(priv, channel); up(&priv->sem); return ret; } @@ -6749,14 +7686,9 @@ static int ipw_wx_set_mode(struct net_device *dev, int err = 0; IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode); - down(&priv->sem); - if (wrqu->mode == priv->ieee->iw_mode) { - up(&priv->sem); - return 0; - } switch (wrqu->mode) { -#ifdef CONFIG_IPW_MONITOR +#ifdef CONFIG_IPW2200_MONITOR case IW_MODE_MONITOR: #endif case IW_MODE_ADHOC: @@ -6766,17 +7698,19 @@ static int ipw_wx_set_mode(struct net_device *dev, wrqu->mode = IW_MODE_INFRA; break; default: - up(&priv->sem); return -EINVAL; } + if (wrqu->mode == priv->ieee->iw_mode) + return 0; -#ifdef CONFIG_IPW_MONITOR + down(&priv->sem); +#ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) priv->net_dev->type = ARPHRD_ETHER; if (wrqu->mode == IW_MODE_MONITOR) priv->net_dev->type = ARPHRD_IEEE80211; -#endif /* CONFIG_IPW_MONITOR */ +#endif /* CONFIG_IPW2200_MONITOR */ #ifdef CONFIG_PM /* Free the existing firmware and reset the fw_loaded @@ -6839,8 +7773,8 @@ static int ipw_wx_get_range(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_range *range = (struct iw_range *)extra; - u16 val; - int i; + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + int i = 0, j; wrqu->data.length = sizeof(*range); memset(range, 0, sizeof(*range)); @@ -6879,19 +7813,28 @@ static int ipw_wx_get_range(struct net_device *dev, range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 16; - range->num_channels = FREQ_COUNT; - - val = 0; - for (i = 0; i < FREQ_COUNT; i++) { - range->freq[val].i = i + 1; - range->freq[val].m = ipw_frequencies[i] * 100000; - range->freq[val].e = 1; - val++; + i = 0; + if (priv->ieee->mode & (IEEE_B | IEEE_G)) { + for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; + i++, j++) { + range->freq[i].i = geo->bg[j].channel; + range->freq[i].m = geo->bg[j].freq * 100000; + range->freq[i].e = 1; + } + } - if (val == IW_MAX_FREQUENCIES) - break; + if (priv->ieee->mode & IEEE_A) { + for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; + i++, j++) { + range->freq[i].i = geo->a[j].channel; + range->freq[i].m = geo->a[j].freq * 100000; + range->freq[i].e = 1; + } } - range->num_frequency = val; + + range->num_channels = i; + range->num_frequency = i; + up(&priv->sem); IPW_DEBUG_WX("GET Range\n"); return 0; @@ -7164,9 +8107,10 @@ static int ipw_wx_set_rate(struct net_device *dev, IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", mask, fixed ? "fixed" : "sub-rates"); down(&priv->sem); - if (mask == IEEE80211_DEFAULT_RATES_MASK) + if (mask == IEEE80211_DEFAULT_RATES_MASK) { priv->config &= ~CFG_FIXED_RATE; - else + ipw_set_fixed_rate(priv, priv->ieee->mode); + } else priv->config |= CFG_FIXED_RATE; if (priv->rates_mask == mask) { @@ -7242,18 +8186,23 @@ static int ipw_wx_set_txpow(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct ipw_tx_power tx_power; int i; + down(&priv->sem); if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { up(&priv->sem); return -EINPROGRESS; } + if (!wrqu->power.fixed) + wrqu->power.value = IPW_TX_POWER_DEFAULT; + if (wrqu->power.flags != IW_TXPOW_DBM) { up(&priv->sem); return -EINVAL; } - if ((wrqu->power.value > 20) || (wrqu->power.value < -12)) { + if ((wrqu->power.value > IPW_TX_POWER_MAX) || + (wrqu->power.value < -IPW_TX_POWER_MAX) || !wrqu->power.fixed) { up(&priv->sem); return -EINVAL; } @@ -7313,8 +8262,10 @@ static int ipw_wx_set_frag(struct net_device *dev, priv->ieee->fts = DEFAULT_FTS; else { if (wrqu->frag.value < MIN_FRAG_THRESHOLD || - wrqu->frag.value > MAX_FRAG_THRESHOLD) + wrqu->frag.value > MAX_FRAG_THRESHOLD) { + up(&priv->sem); return -EINVAL; + } priv->ieee->fts = wrqu->frag.value & ~0x1; } @@ -7362,12 +8313,9 @@ static int ipw_wx_set_scan(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("Start scan\n"); - down(&priv->sem); - if (ipw_request_scan(priv)) { - up(&priv->sem); - return -EIO; - } - up(&priv->sem); + + queue_work(priv->workqueue, &priv->request_scan); + return 0; } @@ -7621,100 +8569,243 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, break; } - IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); + IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); + + wrqu->data.length = strlen(extra) + 1; + up(&priv->sem); + + return 0; +} + +static int ipw_wx_set_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int mode = *(int *)extra; + down(&priv->sem); + /* Switching from SHORT -> LONG requires a disassociation */ + if (mode == 1) { + if (!(priv->config & CFG_PREAMBLE_LONG)) { + priv->config |= CFG_PREAMBLE_LONG; + + /* Network configuration changed -- force [re]association */ + IPW_DEBUG_ASSOC + ("[re]association triggered due to preamble change.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); + } + goto done; + } + + if (mode == 0) { + priv->config &= ~CFG_PREAMBLE_LONG; + goto done; + } + up(&priv->sem); + return -EINVAL; + + done: + up(&priv->sem); + return 0; +} + +static int ipw_wx_get_preamble(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + down(&priv->sem); + if (priv->config & CFG_PREAMBLE_LONG) + snprintf(wrqu->name, IFNAMSIZ, "long (1)"); + else + snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); + up(&priv->sem); + return 0; +} + +#ifdef CONFIG_IPW2200_MONITOR +static int ipw_wx_set_monitor(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int *parms = (int *)extra; + int enable = (parms[0] > 0); + down(&priv->sem); + IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); + if (enable) { + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + priv->net_dev->type = ARPHRD_IEEE80211; + queue_work(priv->workqueue, &priv->adapter_restart); + } + + ipw_set_channel(priv, parms[1]); + } else { + if (priv->ieee->iw_mode != IW_MODE_MONITOR) { + up(&priv->sem); + return 0; + } + priv->net_dev->type = ARPHRD_ETHER; + queue_work(priv->workqueue, &priv->adapter_restart); + } + up(&priv->sem); + return 0; +} + +#endif // CONFIG_IPW2200_MONITOR + +static int ipw_wx_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + IPW_DEBUG_WX("RESET\n"); + queue_work(priv->workqueue, &priv->adapter_restart); + return 0; +} + +static void ipw_sw_reset(struct ipw_priv *priv, int init) +{ + int band, modulation; + + /* Initialize module parameter values here */ + priv->config = 0; + + /* We default to disabling the LED code as right now it causes + * too many systems to lock up... */ + if (!led) + priv->config |= CFG_NO_LED; + + if (associate) + priv->config |= CFG_ASSOCIATE; + else + IPW_DEBUG_INFO("Auto associate disabled.\n"); + + if (auto_create) + priv->config |= CFG_ADHOC_CREATE; + else + IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); + + if (disable) { + priv->status |= STATUS_RF_KILL_SW; + IPW_DEBUG_INFO("Radio disabled.\n"); + } + + if (channel != 0) { + priv->config |= CFG_STATIC_CHANNEL; + priv->channel = channel; + IPW_DEBUG_INFO("Bind to static channel %d\n", channel); + /* TODO: Validate that provided channel is in range */ + } +#ifdef CONFIG_IPW_QOS + ipw_qos_init(priv, qos_enable, qos_burst_enable, + burst_duration_CCK, burst_duration_OFDM); +#endif /* CONFIG_IPW_QOS */ + + switch (mode) { + case 1: + priv->ieee->iw_mode = IW_MODE_ADHOC; + priv->net_dev->type = ARPHRD_ETHER; + + break; +#ifdef CONFIG_IPW2200_MONITOR + case 2: + priv->ieee->iw_mode = IW_MODE_MONITOR; + priv->net_dev->type = ARPHRD_IEEE80211; + break; +#endif + default: + case 0: + priv->net_dev->type = ARPHRD_ETHER; + priv->ieee->iw_mode = IW_MODE_INFRA; + break; + } + + if (hwcrypto) { + priv->ieee->host_encrypt = 0; + priv->ieee->host_decrypt = 0; + } + IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); + + if ((priv->pci_dev->device == 0x4223) || + (priv->pci_dev->device == 0x4224)) { + if (init) + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2915ABG Network " + "Connection\n"); + priv->ieee->abg_true = 1; + band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; + modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + priv->adapter = IPW_2915ABG; + priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; + } else { + if (init) + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2200BG Network " + "Connection\n"); + + priv->ieee->abg_true = 0; + band = IEEE80211_24GHZ_BAND; + modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + priv->adapter = IPW_2200BG; + priv->ieee->mode = IEEE_G | IEEE_B; + } + + priv->ieee->freq_band = band; + priv->ieee->modulation = modulation; - wrqu->data.length = strlen(extra) + 1; - up(&priv->sem); + priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; - return 0; + priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; + priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; + + priv->rts_threshold = DEFAULT_RTS_THRESHOLD; + + /* If power management is turned on, default to AC mode */ + priv->power_mode = IPW_POWER_AC; + priv->tx_power = IPW_TX_POWER_DEFAULT; } -static int ipw_wx_set_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) +static int ipw_wx_sw_reset(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - int mode = *(int *)extra; - down(&priv->sem); - /* Switching from SHORT -> LONG requires a disassociation */ - if (mode == 1) { - if (!(priv->config & CFG_PREAMBLE_LONG)) { - priv->config |= CFG_PREAMBLE_LONG; + union iwreq_data wrqu_sec = { + .encoding = { + .flags = IW_ENCODE_DISABLED, + }, + }; - /* Network configuration changed -- force [re]association */ - IPW_DEBUG_ASSOC - ("[re]association triggered due to preamble change.\n"); - if (!ipw_disassociate(priv)) - ipw_associate(priv); - } - goto done; - } + IPW_DEBUG_WX("SW_RESET\n"); - if (mode == 0) { - priv->config &= ~CFG_PREAMBLE_LONG; - goto done; - } - up(&priv->sem); - return -EINVAL; + down(&priv->sem); - done: - up(&priv->sem); - return 0; -} + ipw_sw_reset(priv, 0); -static int ipw_wx_get_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); - if (priv->config & CFG_PREAMBLE_LONG) - snprintf(wrqu->name, IFNAMSIZ, "long (1)"); - else - snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); - up(&priv->sem); - return 0; -} + /* The SW reset bit might have been toggled on by the 'disable' + * module parameter, so take appropriate action */ + ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); -#ifdef CONFIG_IPW_MONITOR -static int ipw_wx_set_monitor(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int *parms = (int *)extra; - int enable = (parms[0] > 0); + up(&priv->sem); + ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); down(&priv->sem); - IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); - if (enable) { - if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - priv->net_dev->type = ARPHRD_IEEE80211; - queue_work(priv->workqueue, &priv->adapter_restart); - } - ipw_set_channel(priv, parms[1]); - } else { - if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - up(&priv->sem); - return 0; - } - priv->net_dev->type = ARPHRD_ETHER; - queue_work(priv->workqueue, &priv->adapter_restart); + if (!(priv->status & STATUS_RF_KILL_MASK)) { + /* Configuration likely changed -- force [re]association */ + IPW_DEBUG_ASSOC("[re]association triggered due to sw " + "reset.\n"); + if (!ipw_disassociate(priv)) + ipw_associate(priv); } + up(&priv->sem); - return 0; -} -static int ipw_wx_reset(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - IPW_DEBUG_WX("RESET\n"); - queue_work(priv->workqueue, &priv->adapter_restart); return 0; } -#endif // CONFIG_IPW_MONITOR /* Rebase the WE IOCTLs to zero for the handler array */ #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] @@ -7753,14 +8844,19 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, }; -#define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV -#define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1 -#define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2 -#define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3 -#define IPW_PRIV_SET_PREAMBLE SIOCIWFIRSTPRIV+4 -#define IPW_PRIV_GET_PREAMBLE SIOCIWFIRSTPRIV+5 -#define IPW_PRIV_SET_MONITOR SIOCIWFIRSTPRIV+6 -#define IPW_PRIV_RESET SIOCIWFIRSTPRIV+7 +enum { + IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV, + IPW_PRIV_GET_POWER, + IPW_PRIV_SET_MODE, + IPW_PRIV_GET_MODE, + IPW_PRIV_SET_PREAMBLE, + IPW_PRIV_GET_PREAMBLE, + IPW_PRIV_RESET, + IPW_PRIV_SW_RESET, +#ifdef CONFIG_IPW2200_MONITOR + IPW_PRIV_SET_MONITOR, +#endif +}; static struct iw_priv_args ipw_priv_args[] = { { @@ -7787,14 +8883,17 @@ static struct iw_priv_args ipw_priv_args[] = { .cmd = IPW_PRIV_GET_PREAMBLE, .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, .name = "get_preamble"}, -#ifdef CONFIG_IPW_MONITOR - { - IPW_PRIV_SET_MONITOR, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, { IPW_PRIV_RESET, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, -#endif /* CONFIG_IPW_MONITOR */ + { + IPW_PRIV_SW_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"}, +#ifdef CONFIG_IPW2200_MONITOR + { + IPW_PRIV_SET_MONITOR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, +#endif /* CONFIG_IPW2200_MONITOR */ }; static iw_handler ipw_priv_handler[] = { @@ -7804,9 +8903,10 @@ static iw_handler ipw_priv_handler[] = { ipw_wx_get_wireless_mode, ipw_wx_set_preamble, ipw_wx_get_preamble, -#ifdef CONFIG_IPW_MONITOR - ipw_wx_set_monitor, ipw_wx_reset, + ipw_wx_sw_reset, +#ifdef CONFIG_IPW2200_MONITOR + ipw_wx_set_monitor, #endif }; @@ -7915,13 +9015,19 @@ modify to send one tfd per fragment instead of using chunking. otherwise we need to heavily modify the ieee80211_skb_to_txb. */ -static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) +static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, + int pri) { struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) txb->fragments[0]->data; int i = 0; struct tfd_frame *tfd; +#ifdef CONFIG_IPW_QOS + int tx_id = ipw_get_tx_queue_number(priv, pri); + struct clx2_tx_queue *txq = &priv->txq[tx_id]; +#else struct clx2_tx_queue *txq = &priv->txq[0]; +#endif struct clx2_queue *q = &txq->q; u8 id, hdr_len, unicast; u16 remaining_bytes; @@ -7964,15 +9070,11 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) tfd->u.data.cmd_id = DINO_CMD_TX; tfd->u.data.len = cpu_to_le16(txb->payload_size); remaining_bytes = txb->payload_size; - if (unlikely(!unicast)) - tfd->u.data.tx_flags = DCT_FLAG_NO_WEP; - else - tfd->u.data.tx_flags = DCT_FLAG_NO_WEP | DCT_FLAG_ACK_REQD; if (priv->assoc_request.ieee_mode == IPW_B_MODE) - tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_CCK; + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK; else - tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM; + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM; if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; @@ -7982,6 +9084,58 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); + if (likely(unicast)) + tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD; + + if (txb->encrypted && !priv->ieee->host_encrypt) { + switch (priv->ieee->sec.level) { + case SEC_LEVEL_3: + tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= + IEEE80211_FCTL_PROTECTED; + /* XXX: ACK flag must be set for CCMP even if it + * is a multicast/broadcast packet, because CCMP + * group communication encrypted by GTK is + * actually done by the AP. */ + if (!unicast) + tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD; + + tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM; + tfd->u.data.key_index = 0; + tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE; + break; + case SEC_LEVEL_2: + tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= + IEEE80211_FCTL_PROTECTED; + tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP; + tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP; + tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE; + break; + case SEC_LEVEL_1: + tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= + IEEE80211_FCTL_PROTECTED; + tfd->u.data.key_index = priv->ieee->tx_keyidx; + if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <= + 40) + tfd->u.data.key_index |= DCT_WEP_KEY_64Bit; + else + tfd->u.data.key_index |= DCT_WEP_KEY_128Bit; + break; + case SEC_LEVEL_0: + break; + default: + printk(KERN_ERR "Unknow security level %d\n", + priv->ieee->sec.level); + break; + } + } else + /* No hardware encryption */ + tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP; + +#ifdef CONFIG_IPW_QOS + ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data), unicast); +#endif /* CONFIG_IPW_QOS */ + /* payload */ tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags)); @@ -8071,16 +9225,14 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, goto fail_unlock; } - ipw_tx_skb(priv, txb); + ipw_tx_skb(priv, txb, pri); + __ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags); - ipw_led_activity_on(priv); -// up(&priv->sem); return 0; fail_unlock: spin_unlock_irqrestore(&priv->lock, flags); -// up(&priv->sem); return 1; } @@ -8133,7 +9285,7 @@ static void ipw_ethtool_get_drvinfo(struct net_device *dev, snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)", vers, date); strcpy(info->bus_info, pci_name(p->pci_dev)); - info->eedump_len = CX2_EEPROM_IMAGE_SIZE; + info->eedump_len = IPW_EEPROM_IMAGE_SIZE; } static u32 ipw_ethtool_get_link(struct net_device *dev) @@ -8144,7 +9296,7 @@ static u32 ipw_ethtool_get_link(struct net_device *dev) static int ipw_ethtool_get_eeprom_len(struct net_device *dev) { - return CX2_EEPROM_IMAGE_SIZE; + return IPW_EEPROM_IMAGE_SIZE; } static int ipw_ethtool_get_eeprom(struct net_device *dev, @@ -8152,7 +9304,7 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, { struct ipw_priv *p = ieee80211_priv(dev); - if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) + if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; down(&p->sem); memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len); @@ -8166,12 +9318,12 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, struct ipw_priv *p = ieee80211_priv(dev); int i; - if (eeprom->offset + eeprom->len > CX2_EEPROM_IMAGE_SIZE) + if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; down(&p->sem); memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len); for (i = IPW_EEPROM_DATA; - i < IPW_EEPROM_DATA + CX2_EEPROM_IMAGE_SIZE; i++) + i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) ipw_write8(p, i, p->eeprom[i]); up(&p->sem); return 0; @@ -8197,13 +9349,11 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) if (!(priv->status & STATUS_INT_ENABLED)) { /* Shared IRQ */ -// ipw_write32(priv, CX2_INTA_RW, CX2_INTA_MASK_ALL); -// return IRQ_HANDLED; goto none; } - inta = ipw_read32(priv, CX2_INTA_RW); - inta_mask = ipw_read32(priv, CX2_INTA_MASK_R); + inta = ipw_read32(priv, IPW_INTA_RW); + inta_mask = ipw_read32(priv, IPW_INTA_MASK_R); if (inta == 0xFFFFFFFF) { /* Hardware disappeared */ @@ -8211,7 +9361,7 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) goto none; } - if (!(inta & (CX2_INTA_MASK_ALL & inta_mask))) { + if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) { /* Shared interrupt */ goto none; } @@ -8220,8 +9370,8 @@ static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) ipw_disable_interrupts(priv); /* ack current interrupts */ - inta &= (CX2_INTA_MASK_ALL & inta_mask); - ipw_write32(priv, CX2_INTA_RW, inta); + inta &= (IPW_INTA_MASK_ALL & inta_mask); + ipw_write32(priv, IPW_INTA_RW, inta); /* Cache INTA value for our tasklet */ priv->isr_inta = inta; @@ -8348,7 +9498,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->up, (void (*)(void *))ipw_bg_up, priv); INIT_WORK(&priv->down, (void (*)(void *))ipw_bg_down, priv); INIT_WORK(&priv->request_scan, - (void (*)(void *))ipw_bg_request_scan, priv); + (void (*)(void *))ipw_request_scan, priv); INIT_WORK(&priv->gather_stats, (void (*)(void *))ipw_bg_gather_stats, priv); INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv); @@ -8365,6 +9515,11 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->merge_networks, (void (*)(void *))ipw_merge_adhoc_network, priv); +#ifdef CONFIG_IPW_QOS + INIT_WORK(&priv->qos_activate, (void (*)(void *))ipw_bg_qos_activate, + priv); +#endif /* CONFIG_IPW_QOS */ + tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) ipw_irq_tasklet, (unsigned long)priv); @@ -8379,31 +9534,33 @@ static void shim__set_security(struct net_device *dev, down(&priv->sem); for (i = 0; i < 4; i++) { if (sec->flags & (1 << i)) { - priv->sec.key_sizes[i] = sec->key_sizes[i]; + priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; if (sec->key_sizes[i] == 0) - priv->sec.flags &= ~(1 << i); - else - memcpy(priv->sec.keys[i], sec->keys[i], + priv->ieee->sec.flags &= ~(1 << i); + else { + memcpy(priv->ieee->sec.keys[i], sec->keys[i], sec->key_sizes[i]); - priv->sec.flags |= (1 << i); + priv->ieee->sec.flags |= (1 << i); + } priv->status |= STATUS_SECURITY_UPDATED; - } + } else if (sec->level != SEC_LEVEL_1) + priv->ieee->sec.flags &= ~(1 << i); } - if ((sec->flags & SEC_ACTIVE_KEY) && - priv->sec.active_key != sec->active_key) { + if (sec->flags & SEC_ACTIVE_KEY) { if (sec->active_key <= 3) { - priv->sec.active_key = sec->active_key; - priv->sec.flags |= SEC_ACTIVE_KEY; + priv->ieee->sec.active_key = sec->active_key; + priv->ieee->sec.flags |= SEC_ACTIVE_KEY; } else - priv->sec.flags &= ~SEC_ACTIVE_KEY; + priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; priv->status |= STATUS_SECURITY_UPDATED; - } + } else + priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; if ((sec->flags & SEC_AUTH_MODE) && - (priv->sec.auth_mode != sec->auth_mode)) { - priv->sec.auth_mode = sec->auth_mode; - priv->sec.flags |= SEC_AUTH_MODE; + (priv->ieee->sec.auth_mode != sec->auth_mode)) { + priv->ieee->sec.auth_mode = sec->auth_mode; + priv->ieee->sec.flags |= SEC_AUTH_MODE; if (sec->auth_mode == WLAN_AUTH_SHARED_KEY) priv->capability |= CAP_SHARED_KEY; else @@ -8411,22 +9568,26 @@ static void shim__set_security(struct net_device *dev, priv->status |= STATUS_SECURITY_UPDATED; } - if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) { - priv->sec.flags |= SEC_ENABLED; - priv->sec.enabled = sec->enabled; + if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) { + priv->ieee->sec.flags |= SEC_ENABLED; + priv->ieee->sec.enabled = sec->enabled; priv->status |= STATUS_SECURITY_UPDATED; if (sec->enabled) priv->capability |= CAP_PRIVACY_ON; else priv->capability &= ~CAP_PRIVACY_ON; } + priv->ieee->sec.encrypt = sec->encrypt; - if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) { - priv->sec.level = sec->level; - priv->sec.flags |= SEC_LEVEL; + if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { + priv->ieee->sec.level = sec->level; + priv->ieee->sec.flags |= SEC_LEVEL; priv->status |= STATUS_SECURITY_UPDATED; } + if (!priv->ieee->host_encrypt) + ipw_set_hwcrypto_keys(priv); + /* To match current functionality of ipw2100 (which works well w/ * various supplicants, we don't force a disassociate if the * privacy capability changes ... */ @@ -8524,6 +9685,10 @@ static int ipw_config(struct ipw_priv *priv) if (ipw_send_rts_threshold(priv, priv->rts_threshold)) goto error; } +#ifdef CONFIG_IPW_QOS + IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n"); + ipw_qos_activate(priv, NULL); +#endif /* CONFIG_IPW_QOS */ if (ipw_set_random_seed(priv)) goto error; @@ -8533,10 +9698,8 @@ static int ipw_config(struct ipw_priv *priv) goto error; /* If configured to try and auto-associate, kick off a scan */ - if ((priv->config & CFG_ASSOCIATE) && ipw_request_scan(priv)) { - IPW_WARNING("error sending scan request\n"); - goto error; - } + if (priv->config & CFG_ASSOCIATE) + queue_work(priv->workqueue, &priv->request_scan); return 0; @@ -8566,7 +9729,15 @@ static int ipw_up(struct ipw_priv *priv) eeprom_parse_mac(priv, priv->mac_addr); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - if (priv->status & STATUS_RF_KILL_MASK) { + if (priv->status & STATUS_RF_KILL_SW) { + IPW_WARNING("Radio disabled by module parameter.\n"); + return 0; + } else if (rf_kill_active(priv)) { + IPW_WARNING("Radio Frequency Kill Switch is On:\n" + "Kill switch must be turned off for " + "wireless networking to work.\n"); + queue_delayed_work(priv->workqueue, &priv->rf_kill, + 2 * HZ); return 0; } @@ -8604,18 +9775,61 @@ static void ipw_bg_up(void *data) up(&priv->sem); } -static void ipw_down(struct ipw_priv *priv) +static void ipw_deinit(struct ipw_priv *priv) { -#if 0 + int i; + + if (priv->status & STATUS_SCANNING) { + IPW_DEBUG_INFO("Aborting scan during shutdown.\n"); + ipw_abort_scan(priv); + } + + if (priv->status & STATUS_ASSOCIATED) { + IPW_DEBUG_INFO("Disassociating during shutdown.\n"); + ipw_disassociate(priv); + } + + ipw_led_shutdown(priv); + + /* Wait up to 1s for status to change to not scanning and not + * associated (disassociation can take a while for a ful 802.11 + * exchange */ + for (i = 1000; i && (priv->status & + (STATUS_DISASSOCIATING | + STATUS_ASSOCIATED | STATUS_SCANNING)); i--) + udelay(10); + + if (priv->status & (STATUS_DISASSOCIATING | + STATUS_ASSOCIATED | STATUS_SCANNING)) + IPW_DEBUG_INFO("Still associated or scanning...\n"); + else + IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i); + /* Attempt to disable the card */ ipw_send_card_disable(priv, 0); -#endif + + priv->status &= ~STATUS_INIT; +} + +static void ipw_down(struct ipw_priv *priv) +{ + int exit_pending = priv->status & STATUS_EXIT_PENDING; + + priv->status |= STATUS_EXIT_PENDING; + + if (ipw_is_init(priv)) + ipw_deinit(priv); + + /* Wipe out the EXIT_PENDING status bit if we are not actually + * exiting the module */ + if (!exit_pending) + priv->status &= ~STATUS_EXIT_PENDING; /* tell the device to stop sending interrupts */ ipw_disable_interrupts(priv); /* Clear all bits but the RF Kill */ - priv->status &= STATUS_RF_KILL_MASK; + priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING; netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev); @@ -8653,18 +9867,6 @@ static int ipw_net_init(struct net_device *dev) { struct ipw_priv *priv = ieee80211_priv(dev); down(&priv->sem); - if (priv->status & STATUS_RF_KILL_SW) { - IPW_WARNING("Radio disabled by module parameter.\n"); - up(&priv->sem); - return 0; - } else if (rf_kill_active(priv)) { - IPW_WARNING("Radio Frequency Kill Switch is On:\n" - "Kill switch must be turned off for " - "wireless networking to work.\n"); - queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); - up(&priv->sem); - return 0; - } if (ipw_up(priv)) { up(&priv->sem); @@ -8723,6 +9925,8 @@ static struct attribute *ipw_sysfs_entries[] = { &dev_attr_rtc.attr, &dev_attr_scan_age.attr, &dev_attr_led.attr, + &dev_attr_speed_scan.attr, + &dev_attr_net_stats.attr, NULL }; @@ -8738,7 +9942,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *base; u32 length, val; struct ipw_priv *priv; - int band, modulation; net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); if (net_dev == NULL) { @@ -8803,88 +10006,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_iounmap; } - /* Initialize module parameter values here */ - - /* We default to disabling the LED code as right now it causes - * too many systems to lock up... */ - if (!led) - priv->config |= CFG_NO_LED; - - if (associate) - priv->config |= CFG_ASSOCIATE; - else - IPW_DEBUG_INFO("Auto associate disabled.\n"); - - if (auto_create) - priv->config |= CFG_ADHOC_CREATE; - else - IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); - - if (disable) { - priv->status |= STATUS_RF_KILL_SW; - IPW_DEBUG_INFO("Radio disabled.\n"); - } - - if (channel != 0) { - priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); - /* TODO: Validate that provided channel is in range */ - } - - switch (mode) { - case 1: - priv->ieee->iw_mode = IW_MODE_ADHOC; - break; -#ifdef CONFIG_IPW_MONITOR - case 2: - priv->ieee->iw_mode = IW_MODE_MONITOR; - break; -#endif - default: - case 0: - priv->ieee->iw_mode = IW_MODE_INFRA; - break; - } - - if ((priv->pci_dev->device == 0x4223) || - (priv->pci_dev->device == 0x4224)) { - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2915ABG Network " - "Connection\n"); - priv->ieee->abg_true = 1; - band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - priv->adapter = IPW_2915ABG; - priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; - } else { - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2200BG Network " - "Connection\n"); - - priv->ieee->abg_true = 0; - band = IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - priv->adapter = IPW_2200BG; - priv->ieee->mode = IEEE_G | IEEE_B; - } - - priv->ieee->freq_band = band; - priv->ieee->modulation = modulation; - - priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; - - priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; - priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; - - priv->rts_threshold = DEFAULT_RTS_THRESHOLD; - - /* If power management is turned on, default to AC mode */ - priv->power_mode = IPW_POWER_AC; - priv->tx_power = IPW_DEFAULT_TX_POWER; + ipw_sw_reset(priv, 1); err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv); if (err) { @@ -8903,6 +10025,10 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; priv->ieee->set_security = shim__set_security; +#ifdef CONFIG_IPW_QOS + priv->ieee->handle_management_frame = ipw_handle_management_frame; +#endif /* CONFIG_IPW_QOS */ + priv->ieee->perfect_rssi = -20; priv->ieee->worst_rssi = -85; @@ -8960,14 +10086,14 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void ipw_pci_remove(struct pci_dev *pdev) { struct ipw_priv *priv = pci_get_drvdata(pdev); + if (!priv) return; - priv->status |= STATUS_EXIT_PENDING; - - sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); - + down(&priv->sem); ipw_down(priv); + sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); + up(&priv->sem); unregister_netdev(priv->net_dev); @@ -8977,8 +10103,6 @@ static void ipw_pci_remove(struct pci_dev *pdev) } ipw_tx_queue_free(priv); - ipw_led_shutdown(priv); - /* ipw_down will ensure that there is no more pending work * in the workqueue's, so we can safely remove them now. */ cancel_delayed_work(&priv->adhoc_check); @@ -9119,7 +10243,24 @@ MODULE_PARM_DESC(debug, "debug output mask"); module_param(channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); -#ifdef CONFIG_IPW_MONITOR +#ifdef CONFIG_IPW_QOS +module_param(qos_enable, int, 0444); +MODULE_PARM_DESC(qos_enable, "enable all QoS functionalitis"); + +module_param(qos_burst_enable, int, 0444); +MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode"); + +module_param(qos_no_ack_mask, int, 0444); +MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack"); + +module_param(burst_duration_CCK, int, 0444); +MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value"); + +module_param(burst_duration_OFDM, int, 0444); +MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value"); +#endif /* CONFIG_IPW_QOS */ + +#ifdef CONFIG_IPW2200_MONITOR module_param(mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); #else @@ -9127,5 +10268,8 @@ module_param(mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); #endif +module_param(hwcrypto, int, 0444); +MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)"); + module_exit(ipw_exit); module_init(ipw_init); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 243b8ea14140..9dbd73a42094 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -161,6 +161,16 @@ enum connection_manager_assoc_states { * TX Queue Flag Definitions */ +/* tx wep key definition */ +#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00 +#define DCT_WEP_KEY_64Bit 0x40 +#define DCT_WEP_KEY_128Bit 0x80 +#define DCT_WEP_KEY_128bitIV 0xC0 +#define DCT_WEP_KEY_SIZE_MASK 0xC0 + +#define DCT_WEP_KEY_INDEX_MASK 0x0F +#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20 + /* abort attempt if mgmt frame is rx'd */ #define DCT_FLAG_ABORT_MGMT 0x01 @@ -186,9 +196,23 @@ enum connection_manager_assoc_states { /* ACK rx is expected to follow */ #define DCT_FLAG_ACK_REQD 0x80 +/* TX flags extension */ #define DCT_FLAG_EXT_MODE_CCK 0x01 #define DCT_FLAG_EXT_MODE_OFDM 0x00 +#define DCT_FLAG_EXT_SECURITY_WEP 0x00 +#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP +#define DCT_FLAG_EXT_SECURITY_CKIP 0x04 +#define DCT_FLAG_EXT_SECURITY_CCM 0x08 +#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C +#define DCT_FLAG_EXT_SECURITY_MASK 0x0C + +#define DCT_FLAG_EXT_QOS_ENABLED 0x10 + +#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00 +#define DCT_FLAG_EXT_HC_SIFS 0x20 +#define DCT_FLAG_EXT_HC_PIFS 0x40 + #define TX_RX_TYPE_MASK 0xFF #define TX_FRAME_TYPE 0x00 #define TX_HOST_COMMAND_TYPE 0x01 @@ -234,6 +258,117 @@ enum connection_manager_assoc_states { #define DCR_TYPE_SNIFFER 0x06 #define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS +/* QoS definitions */ + +#define CW_MIN_OFDM 15 +#define CW_MAX_OFDM 1023 +#define CW_MIN_CCK 31 +#define CW_MAX_CCK 1023 + +#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM +#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM +#define QOS_TX2_CW_MIN_OFDM ( (CW_MIN_OFDM + 1) / 2 - 1 ) +#define QOS_TX3_CW_MIN_OFDM ( (CW_MIN_OFDM + 1) / 4 - 1 ) + +#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK +#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK +#define QOS_TX2_CW_MIN_CCK ( (CW_MIN_CCK + 1) / 2 - 1 ) +#define QOS_TX3_CW_MIN_CCK ( (CW_MIN_CCK + 1) / 4 - 1 ) + +#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM +#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM +#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM +#define QOS_TX3_CW_MAX_OFDM ( (CW_MIN_OFDM + 1) / 2 - 1 ) + +#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK +#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK +#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK +#define QOS_TX3_CW_MAX_CCK ( (CW_MIN_CCK + 1) / 2 - 1 ) + +#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE) +#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE) +#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE) +#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE) + +#define QOS_TX0_ACM 0 +#define QOS_TX1_ACM 0 +#define QOS_TX2_ACM 0 +#define QOS_TX3_ACM 0 + +#define QOS_TX0_TXOP_LIMIT_CCK 0 +#define QOS_TX1_TXOP_LIMIT_CCK 0 +#define QOS_TX2_TXOP_LIMIT_CCK 6016 +#define QOS_TX3_TXOP_LIMIT_CCK 3264 + +#define QOS_TX0_TXOP_LIMIT_OFDM 0 +#define QOS_TX1_TXOP_LIMIT_OFDM 0 +#define QOS_TX2_TXOP_LIMIT_OFDM 3008 +#define QOS_TX3_TXOP_LIMIT_OFDM 1504 + +#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM + +#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK + +#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM + +#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK + +#define DEF_TX0_AIFS 0 +#define DEF_TX1_AIFS 0 +#define DEF_TX2_AIFS 0 +#define DEF_TX3_AIFS 0 + +#define DEF_TX0_ACM 0 +#define DEF_TX1_ACM 0 +#define DEF_TX2_ACM 0 +#define DEF_TX3_ACM 0 + +#define DEF_TX0_TXOP_LIMIT_CCK 0 +#define DEF_TX1_TXOP_LIMIT_CCK 0 +#define DEF_TX2_TXOP_LIMIT_CCK 0 +#define DEF_TX3_TXOP_LIMIT_CCK 0 + +#define DEF_TX0_TXOP_LIMIT_OFDM 0 +#define DEF_TX1_TXOP_LIMIT_OFDM 0 +#define DEF_TX2_TXOP_LIMIT_OFDM 0 +#define DEF_TX3_TXOP_LIMIT_OFDM 0 + +#define QOS_QOS_SETS 3 +#define QOS_PARAM_SET_ACTIVE 0 +#define QOS_PARAM_SET_DEF_CCK 1 +#define QOS_PARAM_SET_DEF_OFDM 2 + +#define CTRL_QOS_NO_ACK (0x0020) + +#define IPW_TX_QUEUE_1 1 +#define IPW_TX_QUEUE_2 2 +#define IPW_TX_QUEUE_3 3 +#define IPW_TX_QUEUE_4 4 + +/* QoS sturctures */ +struct ipw_qos_info { + int qos_enable; + struct ieee80211_qos_parameters *def_qos_parm_OFDM; + struct ieee80211_qos_parameters *def_qos_parm_CCK; + u32 burst_duration_CCK; + u32 burst_duration_OFDM; + u16 qos_no_ack_mask; + int burst_enable; +}; + +/**************************************************************/ /** * Generic queue structure * @@ -658,6 +793,19 @@ struct ipw_multicast_addr { u8 mac4[6]; } __attribute__ ((packed)); +#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */ +#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */ + +#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00 +#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20 +#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30 + +#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */ +#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */ +#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */ +#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */ +//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */ + struct ipw_wep_key { u8 cmd_id; u8 seq_num; @@ -819,14 +967,6 @@ struct ipw_tx_power { struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS]; } __attribute__ ((packed)); -struct ipw_qos_parameters { - u16 cw_min[4]; - u16 cw_max[4]; - u8 aifs[4]; - u8 flag[4]; - u16 tx_op_limit[4]; -} __attribute__ ((packed)); - struct ipw_rsn_capabilities { u8 id; u8 length; @@ -910,6 +1050,8 @@ struct ipw_cmd { #define CFG_ADHOC_CREATE (1<<8) #define CFG_NO_LED (1<<9) #define CFG_BACKGROUND_SCAN (1<<10) +#define CFG_SPEED_SCAN (1<<11) +#define CFG_NET_STATS (1<<12) #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ @@ -931,10 +1073,11 @@ struct average { s32 sum; }; +#define MAX_SPEED_SCAN 100 + struct ipw_priv { /* ieee device used by generic ieee processing code */ struct ieee80211_device *ieee; - struct ieee80211_security sec; spinlock_t lock; struct semaphore sem; @@ -1030,6 +1173,9 @@ struct ipw_priv { u32 tx_packets; u32 quality; + u8 speed_scan[MAX_SPEED_SCAN]; + u8 speed_scan_pos; + /* eeprom */ u8 eeprom[0x100]; /* 256 bytes of eeprom */ int eeprom_delay; @@ -1074,8 +1220,7 @@ struct ipw_priv { #define IPW_2915ABG 2 u8 adapter; -#define IPW_DEFAULT_TX_POWER 0x14 - u8 tx_power; + s8 tx_power; #ifdef CONFIG_PM u32 pm_state[16]; @@ -1086,6 +1231,11 @@ struct ipw_priv { /* Used to pass the current INTA value from ISR to Tasklet */ u32 isr_inta; + /* QoS */ + struct ipw_qos_info qos_data; + struct work_struct qos_activate; + /*********************************/ + /* debugging info */ u32 indirect_dword; u32 direct_dword; @@ -1162,6 +1312,7 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DL_STATS (1<<29) #define IPW_DL_MERGE (1<<30) +#define IPW_DL_QOS (1<<31) #define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) #define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) @@ -1190,6 +1341,7 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a) #define IPW_DEBUG_STATS(f, a...) IPW_DEBUG(IPW_DL_STATS, f, ## a) #define IPW_DEBUG_MERGE(f, a...) IPW_DEBUG(IPW_DL_MERGE, f, ## a) +#define IPW_DEBUG_QOS(f, a...) IPW_DEBUG(IPW_DL_QOS, f, ## a) #include @@ -1204,65 +1356,65 @@ do { if (ipw_debug_level & (level)) \ #define DINO_RXFIFO_DATA 0x01 #define DINO_CONTROL_REG 0x00200000 -#define CX2_INTA_RW 0x00000008 -#define CX2_INTA_MASK_R 0x0000000C -#define CX2_INDIRECT_ADDR 0x00000010 -#define CX2_INDIRECT_DATA 0x00000014 -#define CX2_AUTOINC_ADDR 0x00000018 -#define CX2_AUTOINC_DATA 0x0000001C -#define CX2_RESET_REG 0x00000020 -#define CX2_GP_CNTRL_RW 0x00000024 +#define IPW_INTA_RW 0x00000008 +#define IPW_INTA_MASK_R 0x0000000C +#define IPW_INDIRECT_ADDR 0x00000010 +#define IPW_INDIRECT_DATA 0x00000014 +#define IPW_AUTOINC_ADDR 0x00000018 +#define IPW_AUTOINC_DATA 0x0000001C +#define IPW_RESET_REG 0x00000020 +#define IPW_GP_CNTRL_RW 0x00000024 -#define CX2_READ_INT_REGISTER 0xFF4 +#define IPW_READ_INT_REGISTER 0xFF4 -#define CX2_GP_CNTRL_BIT_INIT_DONE 0x00000004 +#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004 -#define CX2_REGISTER_DOMAIN1_END 0x00001000 -#define CX2_SRAM_READ_INT_REGISTER 0x00000ff4 +#define IPW_REGISTER_DOMAIN1_END 0x00001000 +#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4 -#define CX2_SHARED_LOWER_BOUND 0x00000200 -#define CX2_INTERRUPT_AREA_LOWER_BOUND 0x00000f80 +#define IPW_SHARED_LOWER_BOUND 0x00000200 +#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80 -#define CX2_NIC_SRAM_LOWER_BOUND 0x00000000 -#define CX2_NIC_SRAM_UPPER_BOUND 0x00030000 +#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000 +#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000 -#define CX2_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29) -#define CX2_GP_CNTRL_BIT_CLOCK_READY 0x00000001 -#define CX2_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002 +#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29) +#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001 +#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002 /* * RESET Register Bit Indexes */ #define CBD_RESET_REG_PRINCETON_RESET (1<<0) -#define CX2_START_STANDBY (1<<2) -#define CX2_ACTIVITY_LED (1<<4) -#define CX2_ASSOCIATED_LED (1<<5) -#define CX2_OFDM_LED (1<<6) -#define CX2_RESET_REG_SW_RESET (1<<7) -#define CX2_RESET_REG_MASTER_DISABLED (1<<8) -#define CX2_RESET_REG_STOP_MASTER (1<<9) -#define CX2_GATE_ODMA (1<<25) -#define CX2_GATE_IDMA (1<<26) -#define CX2_ARC_KESHET_CONFIG (1<<27) -#define CX2_GATE_ADMA (1<<29) - -#define CX2_CSR_CIS_UPPER_BOUND 0x00000200 -#define CX2_DOMAIN_0_END 0x1000 +#define IPW_START_STANDBY (1<<2) +#define IPW_ACTIVITY_LED (1<<4) +#define IPW_ASSOCIATED_LED (1<<5) +#define IPW_OFDM_LED (1<<6) +#define IPW_RESET_REG_SW_RESET (1<<7) +#define IPW_RESET_REG_MASTER_DISABLED (1<<8) +#define IPW_RESET_REG_STOP_MASTER (1<<9) +#define IPW_GATE_ODMA (1<<25) +#define IPW_GATE_IDMA (1<<26) +#define IPW_ARC_KESHET_CONFIG (1<<27) +#define IPW_GATE_ADMA (1<<29) + +#define IPW_CSR_CIS_UPPER_BOUND 0x00000200 +#define IPW_DOMAIN_0_END 0x1000 #define CLX_MEM_BAR_SIZE 0x1000 -#define CX2_BASEBAND_CONTROL_STATUS 0X00200000 -#define CX2_BASEBAND_TX_FIFO_WRITE 0X00200004 -#define CX2_BASEBAND_RX_FIFO_READ 0X00200004 -#define CX2_BASEBAND_CONTROL_STORE 0X00200010 +#define IPW_BASEBAND_CONTROL_STATUS 0X00200000 +#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004 +#define IPW_BASEBAND_RX_FIFO_READ 0X00200004 +#define IPW_BASEBAND_CONTROL_STORE 0X00200010 -#define CX2_INTERNAL_CMD_EVENT 0X00300004 -#define CX2_BASEBAND_POWER_DOWN 0x00000001 +#define IPW_INTERNAL_CMD_EVENT 0X00300004 +#define IPW_BASEBAND_POWER_DOWN 0x00000001 -#define CX2_MEM_HALT_AND_RESET 0x003000e0 +#define IPW_MEM_HALT_AND_RESET 0x003000e0 /* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */ -#define CX2_BIT_HALT_RESET_ON 0x80000000 -#define CX2_BIT_HALT_RESET_OFF 0x00000000 +#define IPW_BIT_HALT_RESET_ON 0x80000000 +#define IPW_BIT_HALT_RESET_OFF 0x00000000 #define CB_LAST_VALID 0x20000000 #define CB_INT_ENABLED 0x40000000 @@ -1281,63 +1433,63 @@ do { if (ipw_debug_level & (level)) \ #define DMA_CB_STOP_AND_ABORT 0x00000C00 #define DMA_CB_START 0x00000100 -#define CX2_SHARED_SRAM_SIZE 0x00030000 -#define CX2_SHARED_SRAM_DMA_CONTROL 0x00027000 +#define IPW_SHARED_SRAM_SIZE 0x00030000 +#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000 #define CB_MAX_LENGTH 0x1FFF -#define CX2_HOST_EEPROM_DATA_SRAM_SIZE 0xA18 -#define CX2_EEPROM_IMAGE_SIZE 0x100 +#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18 +#define IPW_EEPROM_IMAGE_SIZE 0x100 /* DMA defs */ -#define CX2_DMA_I_CURRENT_CB 0x003000D0 -#define CX2_DMA_O_CURRENT_CB 0x003000D4 -#define CX2_DMA_I_DMA_CONTROL 0x003000A4 -#define CX2_DMA_I_CB_BASE 0x003000A0 - -#define CX2_TX_CMD_QUEUE_BD_BASE 0x00000200 -#define CX2_TX_CMD_QUEUE_BD_SIZE 0x00000204 -#define CX2_TX_QUEUE_0_BD_BASE 0x00000208 -#define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C) -#define CX2_TX_QUEUE_1_BD_BASE 0x00000210 -#define CX2_TX_QUEUE_1_BD_SIZE 0x00000214 -#define CX2_TX_QUEUE_2_BD_BASE 0x00000218 -#define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C) -#define CX2_TX_QUEUE_3_BD_BASE 0x00000220 -#define CX2_TX_QUEUE_3_BD_SIZE 0x00000224 -#define CX2_RX_BD_BASE 0x00000240 -#define CX2_RX_BD_SIZE 0x00000244 -#define CX2_RFDS_TABLE_LOWER 0x00000500 - -#define CX2_TX_CMD_QUEUE_READ_INDEX 0x00000280 -#define CX2_TX_QUEUE_0_READ_INDEX 0x00000284 -#define CX2_TX_QUEUE_1_READ_INDEX 0x00000288 -#define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C) -#define CX2_TX_QUEUE_3_READ_INDEX 0x00000290 -#define CX2_RX_READ_INDEX (0x000002A0) - -#define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) -#define CX2_TX_QUEUE_0_WRITE_INDEX (0x00000F84) -#define CX2_TX_QUEUE_1_WRITE_INDEX (0x00000F88) -#define CX2_TX_QUEUE_2_WRITE_INDEX (0x00000F8C) -#define CX2_TX_QUEUE_3_WRITE_INDEX (0x00000F90) -#define CX2_RX_WRITE_INDEX (0x00000FA0) +#define IPW_DMA_I_CURRENT_CB 0x003000D0 +#define IPW_DMA_O_CURRENT_CB 0x003000D4 +#define IPW_DMA_I_DMA_CONTROL 0x003000A4 +#define IPW_DMA_I_CB_BASE 0x003000A0 + +#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200 +#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204 +#define IPW_TX_QUEUE_0_BD_BASE 0x00000208 +#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C) +#define IPW_TX_QUEUE_1_BD_BASE 0x00000210 +#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214 +#define IPW_TX_QUEUE_2_BD_BASE 0x00000218 +#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C) +#define IPW_TX_QUEUE_3_BD_BASE 0x00000220 +#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224 +#define IPW_RX_BD_BASE 0x00000240 +#define IPW_RX_BD_SIZE 0x00000244 +#define IPW_RFDS_TABLE_LOWER 0x00000500 + +#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280 +#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284 +#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288 +#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C) +#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290 +#define IPW_RX_READ_INDEX (0x000002A0) + +#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) +#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84) +#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88) +#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C) +#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90) +#define IPW_RX_WRITE_INDEX (0x00000FA0) /* * EEPROM Related Definitions */ -#define IPW_EEPROM_DATA_SRAM_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x814) -#define IPW_EEPROM_DATA_SRAM_SIZE (CX2_SHARED_LOWER_BOUND + 0x818) -#define IPW_EEPROM_LOAD_DISABLE (CX2_SHARED_LOWER_BOUND + 0x81C) -#define IPW_EEPROM_DATA (CX2_SHARED_LOWER_BOUND + 0x820) -#define IPW_EEPROM_UPPER_ADDRESS (CX2_SHARED_LOWER_BOUND + 0x9E0) +#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814) +#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818) +#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C) +#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820) +#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0) -#define IPW_STATION_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0xA0C) -#define IPW_STATION_TABLE_UPPER (CX2_SHARED_LOWER_BOUND + 0xB0C) -#define IPW_REQUEST_ATIM (CX2_SHARED_LOWER_BOUND + 0xB0C) -#define IPW_ATIM_SENT (CX2_SHARED_LOWER_BOUND + 0xB10) -#define IPW_WHO_IS_AWAKE (CX2_SHARED_LOWER_BOUND + 0xB14) -#define IPW_DURING_ATIM_WINDOW (CX2_SHARED_LOWER_BOUND + 0xB18) +#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C) +#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C) +#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C) +#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10) +#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14) +#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18) #define MSB 1 #define LSB 0 @@ -1367,7 +1519,7 @@ do { if (ipw_debug_level & (level)) \ #define FW_MEM_REG_LOWER_BOUND 0x00300000 #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) -#define CX2_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) +#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) #define EEPROM_BIT_SK (1<<0) #define EEPROM_BIT_CS (1<<1) #define EEPROM_BIT_DI (1<<2) @@ -1376,50 +1528,47 @@ do { if (ipw_debug_level & (level)) \ #define EEPROM_CMD_READ 0x2 /* Interrupts masks */ -#define CX2_INTA_NONE 0x00000000 +#define IPW_INTA_NONE 0x00000000 -#define CX2_INTA_BIT_RX_TRANSFER 0x00000002 -#define CX2_INTA_BIT_STATUS_CHANGE 0x00000010 -#define CX2_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020 +#define IPW_INTA_BIT_RX_TRANSFER 0x00000002 +#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010 +#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020 //Inta Bits for CF -#define CX2_INTA_BIT_TX_CMD_QUEUE 0x00000800 -#define CX2_INTA_BIT_TX_QUEUE_1 0x00001000 -#define CX2_INTA_BIT_TX_QUEUE_2 0x00002000 -#define CX2_INTA_BIT_TX_QUEUE_3 0x00004000 -#define CX2_INTA_BIT_TX_QUEUE_4 0x00008000 +#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800 +#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000 +#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000 +#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000 +#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000 -#define CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000 +#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000 -#define CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000 -#define CX2_INTA_BIT_POWER_DOWN 0x00200000 +#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000 +#define IPW_INTA_BIT_POWER_DOWN 0x00200000 -#define CX2_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000 -#define CX2_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000 -#define CX2_INTA_BIT_RF_KILL_DONE 0x04000000 -#define CX2_INTA_BIT_FATAL_ERROR 0x40000000 -#define CX2_INTA_BIT_PARITY_ERROR 0x80000000 +#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000 +#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000 +#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000 +#define IPW_INTA_BIT_FATAL_ERROR 0x40000000 +#define IPW_INTA_BIT_PARITY_ERROR 0x80000000 /* Interrupts enabled at init time. */ -#define CX2_INTA_MASK_ALL \ - (CX2_INTA_BIT_TX_QUEUE_1 | \ - CX2_INTA_BIT_TX_QUEUE_2 | \ - CX2_INTA_BIT_TX_QUEUE_3 | \ - CX2_INTA_BIT_TX_QUEUE_4 | \ - CX2_INTA_BIT_TX_CMD_QUEUE | \ - CX2_INTA_BIT_RX_TRANSFER | \ - CX2_INTA_BIT_FATAL_ERROR | \ - CX2_INTA_BIT_PARITY_ERROR | \ - CX2_INTA_BIT_STATUS_CHANGE | \ - CX2_INTA_BIT_FW_INITIALIZATION_DONE | \ - CX2_INTA_BIT_BEACON_PERIOD_EXPIRED | \ - CX2_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \ - CX2_INTA_BIT_PREPARE_FOR_POWER_DOWN | \ - CX2_INTA_BIT_POWER_DOWN | \ - CX2_INTA_BIT_RF_KILL_DONE ) - -#define IPWSTATUS_ERROR_LOG (CX2_SHARED_LOWER_BOUND + 0x410) -#define IPW_EVENT_LOG (CX2_SHARED_LOWER_BOUND + 0x414) +#define IPW_INTA_MASK_ALL \ + (IPW_INTA_BIT_TX_QUEUE_1 | \ + IPW_INTA_BIT_TX_QUEUE_2 | \ + IPW_INTA_BIT_TX_QUEUE_3 | \ + IPW_INTA_BIT_TX_QUEUE_4 | \ + IPW_INTA_BIT_TX_CMD_QUEUE | \ + IPW_INTA_BIT_RX_TRANSFER | \ + IPW_INTA_BIT_FATAL_ERROR | \ + IPW_INTA_BIT_PARITY_ERROR | \ + IPW_INTA_BIT_STATUS_CHANGE | \ + IPW_INTA_BIT_FW_INITIALIZATION_DONE | \ + IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \ + IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \ + IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \ + IPW_INTA_BIT_POWER_DOWN | \ + IPW_INTA_BIT_RF_KILL_DONE ) /* FW event log definitions */ #define EVENT_ELEM_SIZE (3 * sizeof(u32)) @@ -1429,6 +1578,11 @@ do { if (ipw_debug_level & (level)) \ #define ERROR_ELEM_SIZE (7 * sizeof(u32)) #define ERROR_START_OFFSET (1 * sizeof(u32)) +/* TX power level (dbm) */ +#define IPW_TX_POWER_MIN -12 +#define IPW_TX_POWER_MAX 20 +#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX + enum { IPW_FW_ERROR_OK = 0, IPW_FW_ERROR_FAIL, @@ -1441,8 +1595,8 @@ enum { IPW_FW_ERROR_ALLOC_FAIL, IPW_FW_ERROR_DMA_UNDERRUN, IPW_FW_ERROR_DMA_STATUS, - IPW_FW_ERROR_DINOSTATUS_ERROR, - IPW_FW_ERROR_EEPROMSTATUS_ERROR, + IPW_FW_ERROR_DINO_ERROR, + IPW_FW_ERROR_EEPROM_ERROR, IPW_FW_ERROR_SYSASSERT, IPW_FW_ERROR_FATAL_ERROR }; @@ -1458,6 +1612,8 @@ enum { #define HC_IBSS_RECONF 4 #define HC_DISASSOC_QUIET 5 +#define HC_QOS_SUPPORT_ASSOC 0x01 + #define IPW_RATE_CAPABILITIES 1 #define IPW_RATE_CONNECT 0 @@ -1628,18 +1784,20 @@ enum { IPW_ORD_TABLE_7_LAST }; -#define IPW_ORDINALS_TABLE_LOWER (CX2_SHARED_LOWER_BOUND + 0x500) -#define IPW_ORDINALS_TABLE_0 (CX2_SHARED_LOWER_BOUND + 0x180) -#define IPW_ORDINALS_TABLE_1 (CX2_SHARED_LOWER_BOUND + 0x184) -#define IPW_ORDINALS_TABLE_2 (CX2_SHARED_LOWER_BOUND + 0x188) -#define IPW_MEM_FIXED_OVERRIDE (CX2_SHARED_LOWER_BOUND + 0x41C) +#define IPWSTATUS_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410) +#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414) +#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500) +#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180) +#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184) +#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188) +#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C) struct ipw_fixed_rate { u16 tx_rates; u16 reserved; } __attribute__ ((packed)); -#define CX2_INDIRECT_ADDR_MASK (~0x3ul) +#define IPW_INDIRECT_ADDR_MASK (~0x3ul) struct host_cmd { u8 cmd; @@ -1676,15 +1834,6 @@ struct host_cmd { #define REG_CHANNEL_MASK 0x00003FFF #define IPW_IBSS_11B_DEFAULT_MASK 0x87ff -static const long ipw_frequencies[] = { - 2412, 2417, 2422, 2427, - 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, - 2472, 2484 -}; - -#define FREQ_COUNT ARRAY_SIZE(ipw_frequencies) - #define IPW_MAX_CONFIG_RETRIES 10 static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr) -- cgit v1.2.3-59-g8ed1b From 823283549da144ff49e65c6e4a670b7784203e0b Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 24 Aug 2005 22:33:31 -0500 Subject: Catch ipw2100 up to equivelancy with v1.1.1 * Added WE-18 support. This allows the use of -Dext with wpa_supplicant > 0.4.x (thanks to Hong Liu) * Fixed #339 problem with iwconfig set/get txpower (thanks to Hong Liu) * Fixed #598 problem when with error messages when module loaded with 'disable=1' (thanks to Hong Liu) * Fixed #640 problem with 'iwlist retry' now showing min/max retry * Fixed compatibility with wpa_supplicant and the new -Dipw interface (that included a fix for 64-bit compatibility) * Added CFG_CRC_CHECK which allows passing through packets with bad CRCs while in monitor mode. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 577 +++++++++++++++++++++++++++++++---------- drivers/net/wireless/ipw2100.h | 11 +- 2 files changed, 451 insertions(+), 137 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 449c1c085fb9..e7c222119da6 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -167,12 +167,12 @@ that only one external action is invoked at a time. #include "ipw2100.h" -#define IPW2100_VERSION "1.1.0" +#define IPW2100_VERSION "1.1.1" #define DRV_NAME "ipw2100" #define DRV_VERSION IPW2100_VERSION #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" /* Debugging stuff */ #ifdef CONFIG_IPW_DEBUG @@ -779,7 +779,7 @@ static int ipw2100_hw_send_command(struct ipw2100_priv *priv, if (err == 0) { IPW_DEBUG_INFO("Command completion failed out after %dms.\n", - HOST_COMPLETE_TIMEOUT / (HZ / 100)); + 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT; priv->status &= ~STATUS_CMD_ACTIVE; schedule_reset(priv); @@ -1986,7 +1986,7 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); if (ssid_len) - memcpy((char *)cmd.host_command_parameters, essid, ssid_len); + memcpy(cmd.host_command_parameters, essid, ssid_len); if (!batch_mode) { err = ipw2100_disable_adapter(priv); @@ -2369,13 +2369,15 @@ static inline void isr_rx(struct ipw2100_priv *priv, int i, IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); return; } - +#ifdef CONFIG_IPW2100_MONITOR if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR && + priv->config & CFG_CRC_CHECK && status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); priv->ieee->stats.rx_errors++; return; } +#endif if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && !(priv->status & STATUS_ASSOCIATED))) { @@ -2744,7 +2746,6 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) priv->net_dev->name, txq->oldest, packet->index); /* DATA packet; we have to unmap and free the SKB */ - priv->ieee->stats.tx_packets++; for (i = 0; i < frag_num; i++) { tbd = &txq->drv[(packet->index + 1 + i) % txq->entries]; @@ -2757,8 +2758,6 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) tbd->buf_length, PCI_DMA_TODEVICE); } - priv->ieee->stats.tx_bytes += - packet->info.d_struct.txb->payload_size; ieee80211_txb_free(packet->info.d_struct.txb); packet->info.d_struct.txb = NULL; @@ -2767,13 +2766,8 @@ static inline int __ipw2100_tx_process(struct ipw2100_priv *priv) /* We have a free slot in the Tx queue, so wake up the * transmit layer if it is stopped. */ - if (priv->status & STATUS_ASSOCIATED && - netif_queue_stopped(priv->net_dev)) { - IPW_DEBUG_INFO(KERN_INFO - "%s: Waking net queue.\n", - priv->net_dev->name); + if (priv->status & STATUS_ASSOCIATED) netif_wake_queue(priv->net_dev); - } /* A packet was processed by the hardware, so update the * watchdog */ @@ -3791,6 +3785,9 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, u32 val_len; static int loop = 0; + if (priv->status & STATUS_RF_KILL_MASK) + return 0; + if (loop >= sizeof(ord_data) / sizeof(*ord_data)) loop = 0; @@ -3947,6 +3944,9 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, int length; int ret; + if (priv->status & STATUS_RF_KILL_MASK) + return 0; + memset(essid, 0, sizeof(essid)); memset(bssid, 0, sizeof(bssid)); @@ -3986,8 +3986,8 @@ static ssize_t show_debug_level(struct device_driver *d, char *buf) return sprintf(buf, "0x%08X\n", ipw2100_debug_level); } -static ssize_t store_debug_level(struct device_driver *d, const char *buf, - size_t count) +static ssize_t store_debug_level(struct device_driver *d, + const char *buf, size_t count) { char *p = (char *)buf; u32 val; @@ -4943,7 +4943,7 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, #endif /* if BSSID is empty then we disable mandatory bssid mode */ if (bssid != NULL) - memcpy((u8 *) cmd.host_command_parameters, bssid, ETH_ALEN); + memcpy(cmd.host_command_parameters, bssid, ETH_ALEN); if (!batch_mode) { err = ipw2100_disable_adapter(priv); @@ -4959,7 +4959,6 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, return err; } -#ifdef CONFIG_IEEE80211_WPA static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv) { struct host_command cmd = { @@ -4983,34 +4982,6 @@ static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv) return err; } -#endif - -/* - * Pseudo code for setting up wpa_frame: - */ -#if 0 -void x(struct ieee80211_assoc_frame *wpa_assoc) -{ - struct ipw2100_wpa_assoc_frame frame; - frame->fixed_ie_mask = IPW_WPA_CAPABILTIES | - IPW_WPA_LISTENINTERVAL | IPW_WPA_AP_ADDRESS; - frame->capab_info = wpa_assoc->capab_info; - frame->lisen_interval = wpa_assoc->listent_interval; - memcpy(frame->current_ap, wpa_assoc->current_ap, ETH_ALEN); - - /* UNKNOWN -- I'm not postivive about this part; don't have any WPA - * setup here to test it with. - * - * Walk the IEs in the wpa_assoc and figure out the total size of all - * that data. Stick that into frame->var_ie_len. Then memcpy() all of - * the IEs from wpa_frame into frame. - */ - frame->var_ie_len = calculate_ie_len(wpa_assoc); - memcpy(frame->var_ie, wpa_assoc->variable, frame->var_ie_len); - - ipw2100_set_wpa_ie(priv, &frame, 0); -} -#endif static int ipw2100_set_wpa_ie(struct ipw2100_priv *, struct ipw2100_wpa_assoc_frame *, int) @@ -5750,11 +5721,10 @@ static struct net_device_stats *ipw2100_stats(struct net_device *dev) return &priv->ieee->stats; } -/* Support for wpa_supplicant. Will be replaced with WEXT once - * they get WPA support. */ -#ifdef CONFIG_IEEE80211_WPA +#if WIRELESS_EXT < 18 +/* Support for wpa_supplicant before WE-18, deprecated. */ -/* following definitions must match definitions in driver_ipw2100.c */ +/* following definitions must match definitions in driver_ipw.c */ #define IPW2100_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 @@ -5792,11 +5762,12 @@ struct ipw2100_param { } wpa_param; struct { u32 len; - u8 *data; + u8 reserved[32]; + u8 data[0]; } wpa_ie; struct { - int command; - int reason_code; + u32 command; + u32 reason_code; } mlme; struct { u8 alg[IPW2100_CRYPT_ALG_NAME_LEN]; @@ -5811,37 +5782,21 @@ struct ipw2100_param { } u; }; -/* end of driver_ipw2100.c code */ +/* end of driver_ipw.c code */ +#endif /* WIRELESS_EXT < 18 */ static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value) { - - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_security sec = { - .flags = SEC_LEVEL | SEC_ENABLED, - }; - int ret = 0; - - ieee->wpa_enabled = value; - - if (value) { - sec.level = SEC_LEVEL_3; - sec.enabled = 1; - } else { - sec.level = SEC_LEVEL_0; - sec.enabled = 0; - } - - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - else - ret = -EOPNOTSUPP; - - return ret; + /* This is called when wpa_supplicant loads and closes the driver + * interface. */ + priv->ieee->wpa_enabled = value; + return 0; } -#define AUTH_ALG_OPEN_SYSTEM 0x1 -#define AUTH_ALG_SHARED_KEY 0x2 +#if WIRELESS_EXT < 18 +#define IW_AUTH_ALG_OPEN_SYSTEM 0x1 +#define IW_AUTH_ALG_SHARED_KEY 0x2 +#endif static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) { @@ -5852,13 +5807,14 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) }; int ret = 0; - if (value & AUTH_ALG_SHARED_KEY) { + if (value & IW_AUTH_ALG_SHARED_KEY) { sec.auth_mode = WLAN_AUTH_SHARED_KEY; ieee->open_wep = 0; - } else { + } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { sec.auth_mode = WLAN_AUTH_OPEN; ieee->open_wep = 1; - } + } else + return -EINVAL; if (ieee->set_security) ieee->set_security(ieee->dev, &sec); @@ -5868,10 +5824,29 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) return ret; } -static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) +void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, + char *wpa_ie, int wpa_ie_len) { + struct ipw2100_wpa_assoc_frame frame; + + frame.fixed_ie_mask = 0; + + /* copy WPA IE */ + memcpy(frame.var_ie, wpa_ie, wpa_ie_len); + frame.var_ie_len = wpa_ie_len; + + /* make sure WPA is enabled */ + ipw2100_wpa_enable(priv, 1); + ipw2100_set_wpa_ie(priv, &frame, 0); +} + +#if WIRELESS_EXT < 18 +static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) +{ struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_crypt_data *crypt; + unsigned long flags; int ret = 0; switch (name) { @@ -5880,7 +5855,22 @@ static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) break; case IPW2100_PARAM_TKIP_COUNTERMEASURES: - priv->ieee->tkip_countermeasures = value; + crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { + IPW_DEBUG_WARNING("Can't set TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + flags = crypt->ops->get_flags(crypt->priv); + + if (value) + flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + else + flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + + crypt->ops->set_flags(flags, crypt->priv); + break; case IPW2100_PARAM_DROP_UNENCRYPTED: @@ -5932,23 +5922,6 @@ static int ipw2100_wpa_mlme(struct net_device *dev, int command, int reason) return ret; } -void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, - char *wpa_ie, int wpa_ie_len) -{ - - struct ipw2100_wpa_assoc_frame frame; - - frame.fixed_ie_mask = 0; - - /* copy WPA IE */ - memcpy(frame.var_ie, wpa_ie, wpa_ie_len); - frame.var_ie_len = wpa_ie_len; - - /* make sure WPA is enabled */ - ipw2100_wpa_enable(priv, 1); - ipw2100_set_wpa_ie(priv, &frame, 0); -} - static int ipw2100_wpa_set_wpa_ie(struct net_device *dev, struct ipw2100_param *param, int plen) { @@ -5992,7 +5965,6 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, struct ipw2100_param *param, int param_len) { - int ret = 0; struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; @@ -6101,8 +6073,8 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, if (ops->name != NULL) { if (strcmp(ops->name, "WEP") == 0) { - memcpy(sec.keys[param->u.crypt.idx], param->u.crypt.key, - param->u.crypt.key_len); + memcpy(sec.keys[param->u.crypt.idx], + param->u.crypt.key, param->u.crypt.key_len); sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; sec.flags |= (1 << param->u.crypt.idx); @@ -6190,11 +6162,9 @@ static int ipw2100_wpa_supplicant(struct net_device *dev, struct iw_point *p) kfree(param); return ret; } -#endif /* CONFIG_IEEE80211_WPA */ static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { -#ifdef CONFIG_IEEE80211_WPA struct iwreq *wrq = (struct iwreq *)rq; int ret = -1; switch (cmd) { @@ -6206,10 +6176,9 @@ static int ipw2100_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EOPNOTSUPP; } -#endif /* CONFIG_IEEE80211_WPA */ - return -EOPNOTSUPP; } +#endif /* WIRELESS_EXT < 18 */ static void ipw_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -6333,10 +6302,15 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, priv->ieee->hard_start_xmit = ipw2100_tx; priv->ieee->set_security = shim__set_security; + priv->ieee->perfect_rssi = -20; + priv->ieee->worst_rssi = -85; + dev->open = ipw2100_open; dev->stop = ipw2100_close; dev->init = ipw2100_net_init; +#if WIRELESS_EXT < 18 dev->do_ioctl = ipw2100_ioctl; +#endif dev->get_stats = ipw2100_stats; dev->ethtool_ops = &ipw2100_ethtool_ops; dev->tx_timeout = ipw2100_tx_timeout; @@ -6362,13 +6336,13 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, /* If power management is turned on, default to AUTO mode */ priv->power_mode = IPW_POWER_AUTO; -#ifdef CONFIG_IEEE80211_WPA +#ifdef CONFIG_IPW2100_MONITOR + priv->config |= CFG_CRC_CHECK; +#endif priv->ieee->wpa_enabled = 0; - priv->ieee->tkip_countermeasures = 0; priv->ieee->drop_unencrypted = 0; priv->ieee->privacy_invoked = 0; priv->ieee->ieee802_1x = 1; -#endif /* CONFIG_IEEE80211_WPA */ /* Set module parameters */ switch (mode) { @@ -6429,7 +6403,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, INIT_LIST_HEAD(&priv->fw_pend_list); INIT_STAT(&priv->fw_pend_stat); -#ifdef CONFIG_SOFTWARE_SUSPEND2 +#ifdef PF_SYNCTHREAD priv->workqueue = create_workqueue(DRV_NAME, 0); #else priv->workqueue = create_workqueue(DRV_NAME); @@ -6591,7 +6565,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, /* perform this after register_netdev so that dev->name is set */ sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group); - netif_carrier_off(dev); /* If the RF Kill switch is disabled, go ahead and complete the * startup sequence */ @@ -6860,10 +6833,6 @@ static int __init ipw2100_init(void) printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT); -#ifdef CONFIG_IEEE80211_NOWEP - IPW_DEBUG_INFO(DRV_NAME ": Compiled with WEP disabled.\n"); -#endif - ret = pci_module_init(&ipw2100_pci_driver); #ifdef CONFIG_IPW_DEBUG @@ -6963,9 +6932,10 @@ static int ipw2100_wx_set_freq(struct net_device *dev, } } - if (fwrq->e > 0 || fwrq->m > 1000) - return -EOPNOTSUPP; - else { /* Set the channel */ + if (fwrq->e > 0 || fwrq->m > 1000) { + err = -EOPNOTSUPP; + goto done; + } else { /* Set the channel */ IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); err = ipw2100_set_channel(priv, fwrq->m, 0); } @@ -7256,7 +7226,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, * configured BSSID then return that; otherwise return ANY */ if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) { wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN); + memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); @@ -7711,13 +7681,13 @@ static int ipw2100_wx_get_retry(struct net_device *dev, return -EINVAL; if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX; + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; wrqu->retry.value = priv->long_retry_limit; } else { wrqu->retry.flags = (priv->short_retry_limit != priv->long_retry_limit) ? - IW_RETRY_LIMIT & IW_RETRY_MIN : IW_RETRY_LIMIT; + IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT; wrqu->retry.value = priv->short_retry_limit; } @@ -7847,9 +7817,9 @@ static int ipw2100_wx_get_power(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); - if (!(priv->power_mode & IPW_POWER_ENABLED)) { + if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; - } else { + else { wrqu->power.disabled = 0; wrqu->power.flags = 0; } @@ -7859,6 +7829,273 @@ static int ipw2100_wx_get_power(struct net_device *dev, return 0; } +#if WIRELESS_EXT > 17 +/* + * WE-18 WPA support + */ + +/* SIOCSIWGENIE */ +static int ipw2100_wx_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + u8 *buf; + + if (!ieee->wpa_enabled) + return -EOPNOTSUPP; + + if (wrqu->data.length > MAX_WPA_IE_LEN || + (wrqu->data.length && extra == NULL)) + return -EINVAL; + + if (wrqu->data.length) { + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + memcpy(buf, extra, wrqu->data.length); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = wrqu->data.length; + } else { + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; + } + + ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); + + return 0; +} + +/* SIOCGIWGENIE */ +static int ipw2100_wx_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + + if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { + wrqu->data.length = 0; + return 0; + } + + if (wrqu->data.length < ieee->wpa_ie_len) + return -E2BIG; + + wrqu->data.length = ieee->wpa_ie_len; + memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); + + return 0; +} + +/* SIOCSIWAUTH */ +static int ipw2100_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct iw_param *param = &wrqu->param; + struct ieee80211_crypt_data *crypt; + unsigned long flags; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * ipw2200 does not use these parameters + */ + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { + IPW_DEBUG_WARNING("Can't set TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + flags = crypt->ops->get_flags(crypt->priv); + + if (param->value) + flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + else + flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + + crypt->ops->set_flags(flags, crypt->priv); + + break; + + case IW_AUTH_DROP_UNENCRYPTED:{ + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = param->value, + }; + priv->ieee->drop_unencrypted = param->value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!param->value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (priv->ieee->set_security) + priv->ieee->set_security(priv->ieee->dev, &sec); + break; + } + + case IW_AUTH_80211_AUTH_ALG: + ret = ipw2100_wpa_set_auth_algs(priv, param->value); + break; + + case IW_AUTH_WPA_ENABLED: + ret = ipw2100_wpa_enable(priv, param->value); + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = param->value; + break; + + //case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = param->value; + break; + + default: + return -EOPNOTSUPP; + } + return ret; +} + +/* SIOCGIWAUTH */ +static int ipw2100_wx_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_crypt_data *crypt; + struct iw_param *param = &wrqu->param; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * wpa_supplicant will control these internally + */ + ret = -EOPNOTSUPP; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + if (!crypt || !crypt->ops->get_flags) { + IPW_DEBUG_WARNING("Can't get TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + param->value = (crypt->ops->get_flags(crypt->priv) & + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; + + break; + + case IW_AUTH_DROP_UNENCRYPTED: + param->value = ieee->drop_unencrypted; + break; + + case IW_AUTH_80211_AUTH_ALG: + param->value = priv->sec.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = ieee->wpa_enabled; + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + param->value = ieee->ieee802_1x; + break; + + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + param->value = ieee->privacy_invoked; + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* SIOCSIWENCODEEXT */ +static int ipw2100_wx_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCGIWENCODEEXT */ +static int ipw2100_wx_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCSIWMLME */ +static int ipw2100_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + u16 reason; + + reason = cpu_to_le16(mlme->reason_code); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + // silently ignore + break; + + case IW_MLME_DISASSOC: + ipw2100_disassociate_bssid(priv); + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} +#endif /* WIRELESS_EXT > 17 */ + /* * * IWPRIV handlers @@ -8019,6 +8256,54 @@ static int ipw2100_wx_get_preamble(struct net_device *dev, return 0; } +#ifdef CONFIG_IPW2100_MONITOR +static int ipw2100_wx_set_crc_check(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw2100_priv *priv = ieee80211_priv(dev); + int err, mode = *(int *)extra; + + down(&priv->action_sem); + if (!(priv->status & STATUS_INITIALIZED)) { + err = -EIO; + goto done; + } + + if (mode == 1) + priv->config |= CFG_CRC_CHECK; + else if (mode == 0) + priv->config &= ~CFG_CRC_CHECK; + else { + err = -EINVAL; + goto done; + } + err = 0; + + done: + up(&priv->action_sem); + return err; +} + +static int ipw2100_wx_get_crc_check(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + /* + * This can be called at any time. No action lock required + */ + + struct ipw2100_priv *priv = ieee80211_priv(dev); + + if (priv->config & CFG_CRC_CHECK) + snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)"); + else + snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)"); + + return 0; +} +#endif /* CONFIG_IPW2100_MONITOR */ + static iw_handler ipw2100_wx_handlers[] = { NULL, /* SIOCSIWCOMMIT */ ipw2100_wx_get_name, /* SIOCGIWNAME */ @@ -8042,7 +8327,11 @@ static iw_handler ipw2100_wx_handlers[] = { NULL, /* SIOCWIWTHRSPY */ ipw2100_wx_set_wap, /* SIOCSIWAP */ ipw2100_wx_get_wap, /* SIOCGIWAP */ +#if WIRELESS_EXT > 17 + ipw2100_wx_set_mlme, /* SIOCSIWMLME */ +#else NULL, /* -- hole -- */ +#endif NULL, /* SIOCGIWAPLIST -- deprecated */ ipw2100_wx_set_scan, /* SIOCSIWSCAN */ ipw2100_wx_get_scan, /* SIOCGIWSCAN */ @@ -8066,6 +8355,17 @@ static iw_handler ipw2100_wx_handlers[] = { ipw2100_wx_get_encode, /* SIOCGIWENCODE */ ipw2100_wx_set_power, /* SIOCSIWPOWER */ ipw2100_wx_get_power, /* SIOCGIWPOWER */ +#if WIRELESS_EXT > 17 + NULL, /* -- hole -- */ + NULL, /* -- hole -- */ + ipw2100_wx_set_genie, /* SIOCSIWGENIE */ + ipw2100_wx_get_genie, /* SIOCGIWGENIE */ + ipw2100_wx_set_auth, /* SIOCSIWAUTH */ + ipw2100_wx_get_auth, /* SIOCGIWAUTH */ + ipw2100_wx_set_encodeext, /* SIOCSIWENCODEEXT */ + ipw2100_wx_get_encodeext, /* SIOCGIWENCODEEXT */ + NULL, /* SIOCSIWPMKSA */ +#endif }; #define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV @@ -8074,6 +8374,8 @@ static iw_handler ipw2100_wx_handlers[] = { #define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3 #define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4 #define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5 +#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6 +#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7 static const struct iw_priv_args ipw2100_private_args[] = { @@ -8099,6 +8401,14 @@ static const struct iw_priv_args ipw2100_private_args[] = { { IPW2100_PRIV_GET_LONGPREAMBLE, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"}, +#ifdef CONFIG_IPW2100_MONITOR + { + IPW2100_PRIV_SET_CRC_CHECK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"}, + { + IPW2100_PRIV_GET_CRC_CHECK, + 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"}, +#endif /* CONFIG_IPW2100_MONITOR */ }; static iw_handler ipw2100_private_handler[] = { @@ -8113,6 +8423,13 @@ static iw_handler ipw2100_private_handler[] = { ipw2100_wx_get_powermode, ipw2100_wx_set_preamble, ipw2100_wx_get_preamble, +#ifdef CONFIG_IPW2100_MONITOR + ipw2100_wx_set_crc_check, + ipw2100_wx_get_crc_check, +#else /* CONFIG_IPW2100_MONITOR */ + NULL, + NULL, +#endif /* CONFIG_IPW2100_MONITOR */ }; static struct iw_handler_def ipw2100_wx_handler_def = { @@ -8292,17 +8609,11 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) /* We now have the BSSID, so can finish setting to the full * associated state */ memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); - memcpy(&priv->ieee->bssid, priv->bssid, ETH_ALEN); + memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN); priv->status &= ~STATUS_ASSOCIATING; priv->status |= STATUS_ASSOCIATED; netif_carrier_on(priv->net_dev); - if (netif_queue_stopped(priv->net_dev)) { - IPW_DEBUG_INFO("Waking net queue.\n"); - netif_wake_queue(priv->net_dev); - } else { - IPW_DEBUG_INFO("Starting net queue.\n"); - netif_start_queue(priv->net_dev); - } + netif_wake_queue(priv->net_dev); } if (!(priv->status & STATUS_ASSOCIATED)) { diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 3eb5c384eaab..99fce99b701a 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -475,6 +475,9 @@ enum { #define CFG_ADHOC_CREATE (1<<8) #define CFG_C3_DISABLED (1<<9) #define CFG_PASSIVE_SCAN (1<<10) +#ifdef CONFIG_IPW2100_MONITOR +#define CFG_CRC_CHECK (1<<11) +#endif #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ @@ -858,9 +861,9 @@ struct ipw2100_rx { #define TYPE_ASSOCIATION_REQUEST 0x0013 #define TYPE_REASSOCIATION_REQUEST 0x0014 -#define HW_FEATURE_RFKILL (0x0001) -#define RF_KILLSWITCH_OFF (1) -#define RF_KILLSWITCH_ON (0) +#define HW_FEATURE_RFKILL 0x0001 +#define RF_KILLSWITCH_OFF 1 +#define RF_KILLSWITCH_ON 0 #define IPW_COMMAND_POOL_SIZE 40 -- cgit v1.2.3-59-g8ed1b From 25b645be1e25e16ea7a25678ac195a0e7595c629 Mon Sep 17 00:00:00 2001 From: Date: Tue, 12 Jul 2005 15:45:30 -0500 Subject: Fixed WEP on ipw2100 (priv->sec was being used instead of priv->ieee->sec) --- drivers/net/wireless/ipw2100.c | 97 ++++++++++++++++++++++-------------------- drivers/net/wireless/ipw2100.h | 2 - 2 files changed, 51 insertions(+), 48 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index e7c222119da6..cf5da20d1d45 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1616,7 +1616,7 @@ static int ipw2100_set_scan_options(struct ipw2100_priv *priv) if (!(priv->config & CFG_ASSOCIATE)) cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE; - if ((priv->sec.flags & SEC_ENABLED) && priv->sec.enabled) + if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled) cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL; if (priv->config & CFG_PASSIVE_SCAN) cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE; @@ -5349,23 +5349,23 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) return err; } - if (!priv->sec.enabled) { + if (!priv->ieee->sec.enabled) { err = ipw2100_set_security_information(priv, IPW_AUTH_OPEN, SEC_LEVEL_0, 0, 1); } else { auth_mode = IPW_AUTH_OPEN; - if ((priv->sec.flags & SEC_AUTH_MODE) && - (priv->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) + if ((priv->ieee->sec.flags & SEC_AUTH_MODE) && + (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) auth_mode = IPW_AUTH_SHARED; sec_level = SEC_LEVEL_0; - if (priv->sec.flags & SEC_LEVEL) - sec_level = priv->sec.level; + if (priv->ieee->sec.flags & SEC_LEVEL) + sec_level = priv->ieee->sec.level; use_group = 0; - if (priv->sec.flags & SEC_UNICAST_GROUP) - use_group = priv->sec.unicast_uses_group; + if (priv->ieee->sec.flags & SEC_UNICAST_GROUP) + use_group = priv->ieee->sec.unicast_uses_group; err = ipw2100_set_security_information(priv, auth_mode, sec_level, @@ -5375,16 +5375,16 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) if (err) goto exit; - if (priv->sec.enabled) { + if (priv->ieee->sec.enabled) { for (i = 0; i < 4; i++) { - if (!(priv->sec.flags & (1 << i))) { - memset(priv->sec.keys[i], 0, WEP_KEY_LEN); - priv->sec.key_sizes[i] = 0; + if (!(priv->ieee->sec.flags & (1 << i))) { + memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN); + priv->ieee->sec.key_sizes[i] = 0; } else { err = ipw2100_set_key(priv, i, - priv->sec.keys[i], - priv->sec.key_sizes[i], - 1); + priv->ieee->sec.keys[i], + priv->ieee->sec. + key_sizes[i], 1); if (err) goto exit; } @@ -5397,8 +5397,8 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) * encrypted data is sent up */ err = ipw2100_set_wep_flags(priv, - priv->sec.enabled ? IPW_PRIVACY_CAPABLE : 0, - 1); + priv->ieee->sec. + enabled ? IPW_PRIVACY_CAPABLE : 0, 1); if (err) goto exit; @@ -5433,58 +5433,61 @@ static void shim__set_security(struct net_device *dev, for (i = 0; i < 4; i++) { if (sec->flags & (1 << i)) { - priv->sec.key_sizes[i] = sec->key_sizes[i]; + priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; if (sec->key_sizes[i] == 0) - priv->sec.flags &= ~(1 << i); + priv->ieee->sec.flags &= ~(1 << i); else - memcpy(priv->sec.keys[i], sec->keys[i], + memcpy(priv->ieee->sec.keys[i], sec->keys[i], sec->key_sizes[i]); - priv->sec.flags |= (1 << i); + priv->ieee->sec.flags |= (1 << i); priv->status |= STATUS_SECURITY_UPDATED; } } if ((sec->flags & SEC_ACTIVE_KEY) && - priv->sec.active_key != sec->active_key) { + priv->ieee->sec.active_key != sec->active_key) { if (sec->active_key <= 3) { - priv->sec.active_key = sec->active_key; - priv->sec.flags |= SEC_ACTIVE_KEY; + priv->ieee->sec.active_key = sec->active_key; + priv->ieee->sec.flags |= SEC_ACTIVE_KEY; } else - priv->sec.flags &= ~SEC_ACTIVE_KEY; + priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY; priv->status |= STATUS_SECURITY_UPDATED; } if ((sec->flags & SEC_AUTH_MODE) && - (priv->sec.auth_mode != sec->auth_mode)) { - priv->sec.auth_mode = sec->auth_mode; - priv->sec.flags |= SEC_AUTH_MODE; + (priv->ieee->sec.auth_mode != sec->auth_mode)) { + priv->ieee->sec.auth_mode = sec->auth_mode; + priv->ieee->sec.flags |= SEC_AUTH_MODE; priv->status |= STATUS_SECURITY_UPDATED; } - if (sec->flags & SEC_ENABLED && priv->sec.enabled != sec->enabled) { - priv->sec.flags |= SEC_ENABLED; - priv->sec.enabled = sec->enabled; + if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) { + priv->ieee->sec.flags |= SEC_ENABLED; + priv->ieee->sec.enabled = sec->enabled; priv->status |= STATUS_SECURITY_UPDATED; force_update = 1; } - if (sec->flags & SEC_LEVEL && priv->sec.level != sec->level) { - priv->sec.level = sec->level; - priv->sec.flags |= SEC_LEVEL; + if (sec->flags & SEC_ENCRYPT) + priv->ieee->sec.encrypt = sec->encrypt; + + if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { + priv->ieee->sec.level = sec->level; + priv->ieee->sec.flags |= SEC_LEVEL; priv->status |= STATUS_SECURITY_UPDATED; } IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n", - priv->sec.flags & (1 << 8) ? '1' : '0', - priv->sec.flags & (1 << 7) ? '1' : '0', - priv->sec.flags & (1 << 6) ? '1' : '0', - priv->sec.flags & (1 << 5) ? '1' : '0', - priv->sec.flags & (1 << 4) ? '1' : '0', - priv->sec.flags & (1 << 3) ? '1' : '0', - priv->sec.flags & (1 << 2) ? '1' : '0', - priv->sec.flags & (1 << 1) ? '1' : '0', - priv->sec.flags & (1 << 0) ? '1' : '0'); + priv->ieee->sec.flags & (1 << 8) ? '1' : '0', + priv->ieee->sec.flags & (1 << 7) ? '1' : '0', + priv->ieee->sec.flags & (1 << 6) ? '1' : '0', + priv->ieee->sec.flags & (1 << 5) ? '1' : '0', + priv->ieee->sec.flags & (1 << 4) ? '1' : '0', + priv->ieee->sec.flags & (1 << 3) ? '1' : '0', + priv->ieee->sec.flags & (1 << 2) ? '1' : '0', + priv->ieee->sec.flags & (1 << 1) ? '1' : '0', + priv->ieee->sec.flags & (1 << 0) ? '1' : '0'); /* As a temporary work around to enable WPA until we figure out why * wpa_supplicant toggles the security capability of the driver, which @@ -5995,17 +5998,19 @@ static int ipw2100_wpa_set_encryption(struct net_device *dev, return -EINVAL; } + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) { sec.enabled = 0; + sec.encrypt = 0; sec.level = SEC_LEVEL_0; - sec.flags |= SEC_ENABLED | SEC_LEVEL; + sec.flags |= SEC_LEVEL; ieee80211_crypt_delayed_deinit(ieee, crypt); } goto done; } sec.enabled = 1; - sec.flags |= SEC_ENABLED; + sec.encrypt = 1; ops = ieee80211_get_crypto_ops(param->u.crypt.alg); if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { @@ -8029,7 +8034,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, break; case IW_AUTH_80211_AUTH_ALG: - param->value = priv->sec.auth_mode; + param->value = priv->ieee->sec.auth_mode; break; case IW_AUTH_WPA_ENABLED: diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 99fce99b701a..a1a9cbcf6c2f 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -524,8 +524,6 @@ struct ipw2100_priv { int power_mode; - /* WEP data */ - struct ieee80211_security sec; int messages_sent; int short_retry_limit; -- cgit v1.2.3-59-g8ed1b From f75459e6f64ca0632f23029e2ca47b424dd33373 Mon Sep 17 00:00:00 2001 From: Liu Hong Date: Wed, 13 Jul 2005 12:29:21 -0500 Subject: [Bug 339] Fix ipw2100 iwconfig set/get txpower. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index cf5da20d1d45..73287ab7bff1 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5102,6 +5102,10 @@ static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power) }; int err = 0; + if (tx_power != IPW_TX_POWER_DEFAULT) + tx_power = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 / + (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); + cmd.host_command_parameters[0] = tx_power; if (priv->ieee->iw_mode == IW_MODE_ADHOC) @@ -7523,8 +7527,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, wrqu->txpower.value > IPW_TX_POWER_MAX_DBM) return -EINVAL; - value = (wrqu->txpower.value - IPW_TX_POWER_MIN_DBM) * 16 / - (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); + value = wrqu->txpower.value; } down(&priv->action_sem); @@ -7564,11 +7567,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev, } else { wrqu->power.disabled = 0; wrqu->power.fixed = 1; - wrqu->power.value = - (priv->tx_power * - (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM)) / - (IPW_TX_POWER_MAX - IPW_TX_POWER_MIN) + - IPW_TX_POWER_MIN_DBM; + wrqu->power.value = priv->tx_power; } wrqu->power.flags = IW_TXPOW_DBM; -- cgit v1.2.3-59-g8ed1b From e4cc28998724661c19cd979a78eaf9a424da52ef Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 13 Jul 2005 12:30:34 -0500 Subject: Move code from ipw2100_wpa_enable to IPW2100_PARAM_DROP_UNENCRYPTED to support wpa_supplicant with open AP. We need this to make driver_ipw work. driver_ext has already had the similar code with the WE-18 support added. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 73287ab7bff1..eaf47078ee56 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5880,9 +5880,27 @@ static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) break; - case IPW2100_PARAM_DROP_UNENCRYPTED: - priv->ieee->drop_unencrypted = value; - break; + case IPW2100_PARAM_DROP_UNENCRYPTED:{ + /* See IW_AUTH_DROP_UNENCRYPTED handling for details */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = value, + }; + priv->ieee->drop_unencrypted = value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (priv->ieee->set_security) + priv->ieee->set_security(priv->ieee->dev, &sec); + break; + } case IPW2100_PARAM_PRIVACY_INVOKED: priv->ieee->privacy_invoked = value; -- cgit v1.2.3-59-g8ed1b From afbf30a2b78cac38e6ddae10a73063943b4783ee Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 25 Aug 2005 00:05:33 -0500 Subject: Catch ipw2200 up to equivelancy with v1.0.5 * Fixed #452 problem with setting retry limit (thanks to Hong Liu) * Fixed #592 race condition during association causing firmware errors * Fixed #602 problem with building in 64-bit environment * Fixed #625 problem with SCAN_REQUEST_EXT sometimes failing * Fixed #645 problem with bit rate not decreasing when moving laptop farther from AP * Fixed #656 problem with 'iwconfig eth1 mode auto' and 'modprobe' locking the system * Fixed #667 problem with "No space for Tx" for hwcrypto=1 * Fixed #685 kernel panic in rmmod caused by led work is still queued * Fixed #695 problem with network doesn't reassociate after suspend/resume * Fixed #701 problem with 'iwprvi sw_reset' not resetting the card from monitor mode * Fixed #710 problem with monitor mode being used after a WEP key has been configured * Fixed network->mode vs. priv->ieee->iw_mode checking (thanks to Ben Cahill) * Fixed "Unknown management packet %d" warning * Fixed setting channels multiple times in monitor mode causes scan stopped * Fixed ipw_wx_sw_reset doesn't switch firmware if mode is changed. * Add duplicate packet checking code (kill ping DUP! and TKIP replay warning) * Fix hardware encryption (both WEP and AES) doesn't work with fragmentation. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 1544 ++++++++++++++++++++++++++++------------ drivers/net/wireless/ipw2200.h | 26 +- 2 files changed, 1123 insertions(+), 447 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0a583afbcddf..1b6f0277a3e9 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. 802.11 status code portion of this file from ethereal-0.10.6: Copyright 2000, Axis Communications AB @@ -32,7 +32,7 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.4" +#define IPW2200_VERSION "1.0.5" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" #define DRV_VERSION IPW2200_VERSION @@ -273,14 +273,14 @@ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); #define ipw_read_indirect(a, b, c, d) \ - IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ + IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ _ipw_read_indirect(a, b, c, d) static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, int num); #define ipw_write_indirect(a, b, c, d) \ IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ - _ipw_write_indirect(a, b, c, d) + _ipw_write_indirect(a, b, c, d) /* indirect write s */ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) @@ -295,8 +295,6 @@ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); _ipw_write8(priv, IPW_INDIRECT_DATA, value); - IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n", - (unsigned long)(priv->hw_base + IPW_INDIRECT_DATA), value); } static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) @@ -1015,12 +1013,12 @@ void ipw_led_init(struct ipw_priv *priv) void ipw_led_shutdown(struct ipw_priv *priv) { - cancel_delayed_work(&priv->led_link_on); - cancel_delayed_work(&priv->led_link_off); - cancel_delayed_work(&priv->led_act_off); ipw_led_activity_off(priv); ipw_led_link_off(priv); ipw_led_band_off(priv); + cancel_delayed_work(&priv->led_link_on); + cancel_delayed_work(&priv->led_link_off); + cancel_delayed_work(&priv->led_act_off); } /* @@ -1296,6 +1294,7 @@ static ssize_t show_indirect_dword(struct device *d, { u32 reg = 0; struct ipw_priv *priv = d->driver_data; + if (priv->status & STATUS_INDIRECT_DWORD) reg = ipw_read_reg32(priv, priv->indirect_dword); else @@ -1322,6 +1321,7 @@ static ssize_t show_indirect_byte(struct device *d, { u8 reg = 0; struct ipw_priv *priv = d->driver_data; + if (priv->status & STATUS_INDIRECT_BYTE) reg = ipw_read_reg8(priv, priv->indirect_byte); else @@ -1509,8 +1509,8 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, show_net_stats, - store_net_stats); +static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, + show_net_stats, store_net_stats); static void notify_wx_assoc_event(struct ipw_priv *priv) { @@ -1630,6 +1630,11 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) /* Keep the restart process from trying to send host * commands by clearing the INIT status bit */ priv->status &= ~STATUS_INIT; + + /* Cancel currently queued command. */ + priv->status &= ~STATUS_HCMD_ACTIVE; + wake_up_interruptible(&priv->wait_command_queue); + queue_work(priv->workqueue, &priv->adapter_restart); handled |= IPW_INTA_BIT_FATAL_ERROR; } @@ -1796,7 +1801,7 @@ static int ipw_send_system_config(struct ipw_priv *priv, return -1; } - memcpy(&cmd.param, config, sizeof(*config)); + memcpy(cmd.param, config, sizeof(*config)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send SYSTEM_CONFIG command\n"); return -1; @@ -1817,7 +1822,7 @@ static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) return -1; } - memcpy(&cmd.param, ssid, cmd.len); + memcpy(cmd.param, ssid, cmd.len); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send SSID command\n"); return -1; @@ -1841,8 +1846,7 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(mac)); - memcpy(&cmd.param, mac, ETH_ALEN); - + memcpy(cmd.param, mac, ETH_ALEN); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send ADAPTER_ADDRESS command\n"); return -1; @@ -1873,11 +1877,6 @@ static void ipw_adapter_restart(void *adapter) IPW_ERROR("Failed to up device\n"); return; } - - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.level == SEC_LEVEL_1) && - !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) - ipw_set_hwcrypto_keys(priv); } static void ipw_bg_adapter_restart(void *data) @@ -1917,14 +1916,12 @@ static int ipw_send_scan_request_ext(struct ipw_priv *priv, .len = sizeof(*request) }; - memcpy(&cmd.param, request, sizeof(*request)); + memcpy(cmd.param, request, sizeof(*request)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n"); return -1; } - queue_delayed_work(priv->workqueue, &priv->scan_check, - IPW_SCAN_CHECK_WATCHDOG); return 0; } @@ -1991,7 +1988,7 @@ static int ipw_send_associate(struct ipw_priv *priv, return -1; } - memcpy(&cmd.param, &tmp_associate, sizeof(*associate)); + memcpy(cmd.param, &tmp_associate, sizeof(*associate)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send ASSOCIATE command\n"); return -1; @@ -2013,7 +2010,7 @@ static int ipw_send_supported_rates(struct ipw_priv *priv, return -1; } - memcpy(&cmd.param, rates, sizeof(*rates)); + memcpy(cmd.param, rates, sizeof(*rates)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send SUPPORTED_RATES command\n"); return -1; @@ -2078,7 +2075,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) return -1; } - memcpy(&cmd.param, power, sizeof(*power)); + memcpy(cmd.param, power, sizeof(*power)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send TX_POWER command\n"); return -1; @@ -2102,7 +2099,7 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) return -1; } - memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold)); + memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send RTS_THRESHOLD command\n"); return -1; @@ -2126,7 +2123,7 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) return -1; } - memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold)); + memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send FRAG_THRESHOLD command\n"); return -1; @@ -2170,6 +2167,31 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) return 0; } +static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) +{ + struct ipw_retry_limit retry_limit = { + .short_retry_limit = slimit, + .long_retry_limit = llimit + }; + struct host_cmd cmd = { + .cmd = IPW_CMD_RETRY_LIMIT, + .len = sizeof(retry_limit) + }; + + if (!priv) { + IPW_ERROR("Invalid args\n"); + return -1; + } + + memcpy(cmd.param, &retry_limit, sizeof(retry_limit)); + if (ipw_send_cmd(priv, &cmd)) { + IPW_ERROR("failed to send RETRY_LIMIT command\n"); + return -1; + } + + return 0; +} + /* * The IPW device contains a Microwire compatible EEPROM that stores * various data like the MAC address. Usually the firmware has exclusive @@ -2269,8 +2291,7 @@ static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr) /* data's copy of the eeprom data */ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) { - u8 *ee = (u8 *) priv->eeprom; - memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6); + memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6); } /* @@ -2680,8 +2701,7 @@ struct fw_chunk { #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) #define IPW_FW_MAJOR(x) (x & 0xff) -#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \ - IPW_FW_MAJOR_VERSION) +#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION) #define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ "." __stringify(IPW_FW_MINOR_VERSION) "-" @@ -2952,6 +2972,8 @@ static int ipw_reset_nic(struct ipw_priv *priv) /* Clear the 'host command active' bit... */ priv->status &= ~STATUS_HCMD_ACTIVE; wake_up_interruptible(&priv->wait_command_queue); + priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); + wake_up_interruptible(&priv->wait_state); spin_unlock_irqrestore(&priv->lock, flags); IPW_DEBUG_TRACE("<<\n"); @@ -3027,6 +3049,19 @@ static int fw_loaded = 0; static const struct firmware *bootfw = NULL; static const struct firmware *firmware = NULL; static const struct firmware *ucode = NULL; + +static void free_firmware(void) +{ + if (fw_loaded) { + release_firmware(bootfw); + release_firmware(ucode); + release_firmware(firmware); + bootfw = ucode = firmware = NULL; + fw_loaded = 0; + } +} +#else +#define free_firmware() do {} while (0) #endif static int ipw_load(struct ipw_priv *priv) @@ -3915,13 +3950,13 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, { priv->notif_missed_beacons = missed_count; - if (missed_count > priv->missed_beacon_threshold && + if (missed_count > priv->disassociate_threshold && priv->status & STATUS_ASSOCIATED) { /* If associated and we've hit the missed * beacon threshold, disassociate, turn * off roaming, and abort any active scans */ IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | - IPW_DL_STATE, + IPW_DL_STATE | IPW_DL_ASSOC, "Missed beacon: %d - disassociate\n", missed_count); priv->status &= ~STATUS_ROAMING; if (priv->status & STATUS_SCANNING) { @@ -4027,7 +4062,11 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, priv->status |= STATUS_ASSOCIATED; #ifdef CONFIG_IPW_QOS - if (priv->status & STATUS_AUTH) { +#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ + le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl)) + if ((priv->status & STATUS_AUTH) && + (IPW_GET_PACKET_STYPE(¬if->u.raw) + == IEEE80211_STYPE_ASSOC_RESP)) { if ((sizeof (struct ieee80211_assoc_response_frame) @@ -4287,10 +4326,12 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + priv->status |= STATUS_SCAN_FORCED; queue_work(priv->workqueue, &priv->request_scan); break; } + priv->status &= ~STATUS_SCAN_FORCED; #endif /* CONFIG_IPW2200_MONITOR */ if (!(priv->status & (STATUS_ASSOCIATED | @@ -4330,6 +4371,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{ struct notif_link_deterioration *x = ¬if->u.link_deterioration; + if (notif->size == sizeof(*x)) { IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, "link deterioration: '%s' " MAC_FMT @@ -5027,6 +5069,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, memcmp(network->ssid, priv->essid, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + strncpy(escaped, escape_essid(network->ssid, network->ssid_len), sizeof(escaped)); @@ -5043,16 +5086,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, * testing everything else. */ if (network->time_stamp[0] < match->network->time_stamp[0]) { - IPW_DEBUG_MERGE - ("Network '%s excluded because newer than current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + IPW_DEBUG_MERGE("Network '%s excluded because newer than " + "current network.\n", + escape_essid(match->network->ssid, + match->network->ssid_len)); return 0; } else if (network->time_stamp[1] < match->network->time_stamp[1]) { - IPW_DEBUG_MERGE - ("Network '%s excluded because newer than current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + IPW_DEBUG_MERGE("Network '%s excluded because newer than " + "current network.\n", + escape_essid(match->network->ssid, + match->network->ssid_len)); return 0; } @@ -5063,7 +5106,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, "because of age: %lums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - (jiffies - network->last_scanned) / (HZ / 100)); + 1000 * (jiffies - network->last_scanned) / HZ); return 0; } @@ -5084,10 +5127,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, "because of privacy mismatch: %s != %s.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - priv->capability & CAP_PRIVACY_ON ? "on" : - "off", - network->capability & - WLAN_CAPABILITY_PRIVACY ? "on" : "off"); + priv-> + capability & CAP_PRIVACY_ON ? "on" : "off", + network-> + capability & WLAN_CAPABILITY_PRIVACY ? "on" : + "off"); return 0; } @@ -5151,8 +5195,8 @@ static void ipw_merge_adhoc_network(void *data) .network = priv->assoc_network }; - if ((priv->status & STATUS_ASSOCIATED) - && (priv->ieee->iw_mode == IW_MODE_ADHOC)) { + if ((priv->status & STATUS_ASSOCIATED) && + (priv->ieee->iw_mode == IW_MODE_ADHOC)) { /* First pass through ROAM process -- look for a better * network */ unsigned long flags; @@ -5184,7 +5228,6 @@ static void ipw_merge_adhoc_network(void *data) up(&priv->sem); return; } - } static int ipw_best_network(struct ipw_priv *priv, @@ -5270,7 +5313,7 @@ static int ipw_best_network(struct ipw_priv *priv, if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of storming (%lu since last " + "because of storming (%lus since last " "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), @@ -5285,7 +5328,7 @@ static int ipw_best_network(struct ipw_priv *priv, "because of age: %lums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - (jiffies - network->last_scanned) / (HZ / 100)); + 1000 * (jiffies - network->last_scanned) / HZ); return 0; } @@ -5369,6 +5412,9 @@ static int ipw_best_network(struct ipw_priv *priv, static void ipw_adhoc_create(struct ipw_priv *priv, struct ieee80211_network *network) { + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + int i; + /* * For the purposes of scanning, we can set our wireless mode * to trigger scans across combinations of bands, but when it @@ -5379,9 +5425,28 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * chossen band. Attempting to create a new ad-hoc network * with an invalid channel for wireless mode will trigger a * FW fatal error. + * */ - if (!ieee80211_is_valid_channel(priv->ieee, priv->channel)) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + case IEEE80211_52GHZ_BAND: + network->mode = IEEE_A; + i = ieee80211_channel_to_index(priv->ieee, priv->channel); + if (i == -1) + BUG(); + if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + IPW_WARNING("Overriding invalid channel\n"); + priv->channel = geo->a[0].channel; + } + break; + + case IEEE80211_24GHZ_BAND: + if (priv->ieee->mode & IEEE_G) + network->mode = IEEE_G; + else + network->mode = IEEE_B; + break; + + default: IPW_WARNING("Overriding invalid channel\n"); if (priv->ieee->mode & IEEE_A) { network->mode = IEEE_A; @@ -5393,8 +5458,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, network->mode = IEEE_B; priv->channel = geo->bg[0].channel; } - } else - network->mode = priv->ieee->mode; + break; + } network->channel = priv->channel; priv->config |= CFG_ADHOC_PERSIST; @@ -5488,10 +5553,11 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) { switch (priv->ieee->sec.level) { case SEC_LEVEL_3: - if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) - ipw_send_tgi_tx_key(priv, - DCT_FLAG_EXT_SECURITY_CCM, - priv->ieee->sec.active_key); + if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) + break; + + ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_CCM, + priv->ieee->sec.active_key); ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); priv->sys_config.disable_unicast_decryption = 0; @@ -5502,10 +5568,11 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) break; case SEC_LEVEL_2: - if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) - ipw_send_tgi_tx_key(priv, - DCT_FLAG_EXT_SECURITY_TKIP, - priv->ieee->sec.active_key); + if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) + break; + + ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_TKIP, + priv->ieee->sec.active_key); priv->sys_config.disable_unicast_decryption = 1; priv->sys_config.disable_multicast_decryption = 1; @@ -5534,9 +5601,12 @@ static void ipw_adhoc_check(void *data) { struct ipw_priv *priv = data; - if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold && + if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold && !(priv->config & CFG_ADHOC_PERSIST)) { - IPW_DEBUG_SCAN("Disassociating due to missed beacons\n"); + IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | + IPW_DL_STATE | IPW_DL_ASSOC, + "Missed beacon: %d - disassociate\n", + priv->missed_adhoc_beacons); ipw_remove_current_network(priv); ipw_disassociate(priv); return; @@ -5669,27 +5739,110 @@ static void ipw_abort_scan(struct ipw_priv *priv) IPW_DEBUG_HC("Request to abort scan failed.\n"); } -static int ipw_request_scan(struct ipw_priv *priv) +static void ipw_add_scan_channels(struct ipw_priv *priv, + struct ipw_scan_request_ext *scan, + int scan_type) { - struct ipw_scan_request_ext scan; int channel_index = 0; - int i, err = 0, scan_type; const struct ieee80211_geo *geo; -#ifdef CONFIG_IPW2200_MONITOR - u8 channel; -#endif - - down(&priv->sem); + int i; geo = ieee80211_get_geo(priv->ieee); + if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { + int start = channel_index; + for (i = 0; i < geo->a_channels; i++) { + if ((priv->status & STATUS_ASSOCIATED) && + geo->a[i].channel == priv->channel) + continue; + channel_index++; + scan->channels_list[channel_index] = geo->a[i].channel; + ipw_set_scan_type(scan, channel_index, scan_type); + } + + if (start != channel_index) { + scan->channels_list[start] = (u8) (IPW_A_MODE << 6) | + (channel_index - start); + channel_index++; + } + } + + if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { + int start = channel_index; + if (priv->config & CFG_SPEED_SCAN) { + u8 channels[IEEE80211_24GHZ_CHANNELS] = { + /* nop out the list */ + [0] = 0 + }; + + u8 channel; + while (channel_index < IPW_SCAN_CHANNELS) { + channel = + priv->speed_scan[priv->speed_scan_pos]; + if (channel == 0) { + priv->speed_scan_pos = 0; + channel = priv->speed_scan[0]; + } + if ((priv->status & STATUS_ASSOCIATED) && + channel == priv->channel) { + priv->speed_scan_pos++; + continue; + } + + /* If this channel has already been + * added in scan, break from loop + * and this will be the first channel + * in the next scan. + */ + if (channels[channel - 1] != 0) + break; + + channels[channel - 1] = 1; + priv->speed_scan_pos++; + channel_index++; + scan->channels_list[channel_index] = channel; + ipw_set_scan_type(scan, channel_index, + scan_type); + } + } else { + for (i = 0; i < geo->bg_channels; i++) { + if ((priv->status & STATUS_ASSOCIATED) && + geo->bg[i].channel == priv->channel) + continue; + channel_index++; + scan->channels_list[channel_index] = + geo->bg[i].channel; + ipw_set_scan_type(scan, channel_index, + scan_type); + } + } + + if (start != channel_index) { + scan->channels_list[start] = (u8) (IPW_B_MODE << 6) | + (channel_index - start); + } + } +} + +static int ipw_request_scan(struct ipw_priv *priv) +{ + struct ipw_scan_request_ext scan; + int err = 0, scan_type; + + if (!(priv->status & STATUS_INIT) || + (priv->status & STATUS_EXIT_PENDING)) + return 0; + + down(&priv->sem); + if (priv->status & STATUS_SCANNING) { IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); priv->status |= STATUS_SCAN_PENDING; goto done; } - if (priv->status & STATUS_SCAN_ABORTING) { + if (!(priv->status & STATUS_SCAN_FORCED) && + priv->status & STATUS_SCAN_ABORTING) { IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); priv->status |= STATUS_SCAN_PENDING; goto done; @@ -5718,6 +5871,7 @@ static int ipw_request_scan(struct ipw_priv *priv) #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + u8 channel; u8 band = 0; switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { @@ -5768,91 +5922,10 @@ static int ipw_request_scan(struct ipw_priv *priv) } scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; - } else { + } else scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; - } - - /* Add channels to the scan list */ - if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { - int start = channel_index; - for (i = 0; i < geo->a_channels; i++) { - if ((priv->status & STATUS_ASSOCIATED) && - geo->a[i].channel == priv->channel) - continue; - channel_index++; - scan.channels_list[channel_index] = - geo->a[i].channel; - ipw_set_scan_type(&scan, channel_index, - scan_type); - } - - if (start != channel_index) { - scan.channels_list[start] = - (u8) (IPW_A_MODE << 6) | (channel_index - - start); - channel_index++; - } - } - - if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { - int start = channel_index; - if (priv->config & CFG_SPEED_SCAN) { - u8 channels[IEEE80211_24GHZ_CHANNELS] = { - /* nop out the list */ - [0] = 0 - }; - - u8 channel; - while (channel_index < IPW_SCAN_CHANNELS) { - channel = - priv->speed_scan[priv-> - speed_scan_pos]; - if (channel == 0) { - priv->speed_scan_pos = 0; - channel = priv->speed_scan[0]; - } - if ((priv->status & STATUS_ASSOCIATED) - && channel == priv->channel) { - priv->speed_scan_pos++; - continue; - } - - /* If this channel has already been - * added in scan, break from loop - * and this will be the first channel - * in the next scan. - */ - if (channels[channel - 1] != 0) - break; - - channels[channel - 1] = 1; - priv->speed_scan_pos++; - channel_index++; - scan.channels_list[channel_index] = - channel; - ipw_set_scan_type(&scan, channel_index, - scan_type); - } - } else { - for (i = 0; i < geo->bg_channels; i++) { - if ((priv->status & STATUS_ASSOCIATED) - && geo->bg[i].channel == - priv->channel) - continue; - channel_index++; - scan.channels_list[channel_index] = - geo->bg[i].channel; - ipw_set_scan_type(&scan, channel_index, - scan_type); - } - } - if (start != channel_index) { - scan.channels_list[start] = - (u8) (IPW_B_MODE << 6) | (channel_index - - start); - } - } + ipw_add_scan_channels(priv, &scan, scan_type); #ifdef CONFIG_IPW2200_MONITOR } #endif @@ -5865,7 +5938,8 @@ static int ipw_request_scan(struct ipw_priv *priv) priv->status |= STATUS_SCANNING; priv->status &= ~STATUS_SCAN_PENDING; - + queue_delayed_work(priv->workqueue, &priv->scan_check, + IPW_SCAN_CHECK_WATCHDOG); done: up(&priv->sem); return err; @@ -5879,8 +5953,8 @@ static void ipw_bg_abort_scan(void *data) up(&priv->sem); } -/* Support for wpa_supplicant. Will be replaced with WEXT once - * they get WPA support. */ +#if WIRELESS_EXT < 18 +/* Support for wpa_supplicant before WE-18, deprecated. */ /* following definitions must match definitions in driver_ipw.c */ @@ -5924,8 +5998,8 @@ struct ipw_param { u8 data[0]; } wpa_ie; struct { - int command; - int reason_code; + u32 command; + u32 reason_code; } mlme; struct { u8 alg[IPW_CRYPT_ALG_NAME_LEN]; @@ -5941,6 +6015,7 @@ struct ipw_param { }; /* end of driver_ipw.c code */ +#endif static int ipw_wpa_enable(struct ipw_priv *priv, int value) { @@ -5949,8 +6024,10 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) return 0; } -#define AUTH_ALG_OPEN_SYSTEM 0x1 -#define AUTH_ALG_SHARED_KEY 0x2 +#if WIRELESS_EXT < 18 +#define IW_AUTH_ALG_OPEN_SYSTEM 0x1 +#define IW_AUTH_ALG_SHARED_KEY 0x2 +#endif static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) { @@ -5960,13 +6037,14 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) }; int ret = 0; - if (value & AUTH_ALG_SHARED_KEY) { + if (value & IW_AUTH_ALG_SHARED_KEY) { sec.auth_mode = WLAN_AUTH_SHARED_KEY; ieee->open_wep = 0; - } else { + } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { sec.auth_mode = WLAN_AUTH_OPEN; ieee->open_wep = 1; - } + } else + return -EINVAL; if (ieee->set_security) ieee->set_security(ieee->dev, &sec); @@ -5976,6 +6054,33 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) return ret; } +void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) +{ + /* make sure WPA is enabled */ + ipw_wpa_enable(priv, 1); + + ipw_disassociate(priv); +} + +static int ipw_set_rsn_capa(struct ipw_priv *priv, + char *capabilities, int length) +{ + struct host_cmd cmd = { + .cmd = IPW_CMD_RSN_CAPABILITIES, + .len = length, + }; + + IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); + + memcpy(cmd.param, capabilities, length); + if (ipw_send_cmd(priv, &cmd)) { + IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); + return -1; + } + return 0; +} + +#if WIRELESS_EXT < 18 static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) { struct ipw_priv *priv = ieee80211_priv(dev); @@ -6081,32 +6186,6 @@ static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) return ret; } -static int ipw_set_rsn_capa(struct ipw_priv *priv, - char *capabilities, int length) -{ - struct host_cmd cmd = { - .cmd = IPW_CMD_RSN_CAPABILITIES, - .len = length, - }; - - IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); - - memcpy(&cmd.param, capabilities, length); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); - return -1; - } - return 0; -} - -void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) -{ - /* make sure WPA is enabled */ - ipw_wpa_enable(priv, 1); - - ipw_disassociate(priv); -} - static int ipw_wpa_set_wpa_ie(struct net_device *dev, struct ipw_param *param, int plen) { @@ -6172,23 +6251,26 @@ static int ipw_wpa_set_encryption(struct net_device *dev, return -EINVAL; } + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) { sec.enabled = 0; sec.encrypt = 0; sec.level = SEC_LEVEL_0; - sec.flags |= SEC_ENABLED | SEC_LEVEL; + sec.flags |= SEC_LEVEL; ieee80211_crypt_delayed_deinit(ieee, crypt); } goto done; } sec.enabled = 1; sec.encrypt = 1; - sec.flags |= SEC_ENABLED; /* IPW HW cannot build TKIP MIC, host decryption still needed. */ - if (!(ieee->host_encrypt || ieee->host_decrypt) && - strcmp(param->u.crypt.alg, "TKIP")) + if (strcmp(param->u.crypt.alg, "TKIP") == 0) + ieee->host_encrypt_msdu = 1; + + if (!(ieee->host_encrypt || ieee->host_encrypt_msdu || + ieee->host_decrypt)) goto skip_host_crypt; ops = ieee80211_get_crypto_ops(param->u.crypt.alg); @@ -6295,6 +6377,7 @@ static int ipw_wpa_set_encryption(struct net_device *dev, static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) { struct ipw_param *param; + struct ipw_priv *priv = ieee80211_priv(dev); int ret = 0; IPW_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); @@ -6311,6 +6394,7 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) return -EFAULT; } + down(&priv->sem); switch (param->cmd) { case IPW_CMD_SET_WPA_PARAM: @@ -6337,35 +6421,336 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) ret = -EOPNOTSUPP; } + up(&priv->sem); if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ret = -EFAULT; kfree(param); return ret; } - -#ifdef CONFIG_IPW_QOS - -/* QoS */ +#else /* -* get the modulation type of the current network or -* the card current mode -*/ -u8 ipw_qos_current_mode(struct ipw_priv * priv) + * WE-18 support + */ + +/* SIOCSIWGENIE */ +static int ipw_wx_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { - u8 mode = 0; + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + u8 *buf; + int err = 0; - if (priv->status & STATUS_ASSOCIATED) { - unsigned long flags; + if (wrqu->data.length > MAX_WPA_IE_LEN || + (wrqu->data.length && extra == NULL)) + return -EINVAL; - spin_lock_irqsave(&priv->ieee->lock, flags); - mode = priv->assoc_network->mode; - spin_unlock_irqrestore(&priv->ieee->lock, flags); + //down(&priv->sem); + + //if (!ieee->wpa_enabled) { + // err = -EOPNOTSUPP; + // goto out; + //} + + if (wrqu->data.length) { + buf = kmalloc(wrqu->data.length, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto out; + } + + memcpy(buf, extra, wrqu->data.length); + kfree(ieee->wpa_ie); + ieee->wpa_ie = buf; + ieee->wpa_ie_len = wrqu->data.length; } else { - mode = priv->ieee->mode; + kfree(ieee->wpa_ie); + ieee->wpa_ie = NULL; + ieee->wpa_ie_len = 0; } - IPW_DEBUG_QOS("QoS network/card mode %d \n", mode); - return mode; + + ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); + out: + //up(&priv->sem); + return err; +} + +/* SIOCGIWGENIE */ +static int ipw_wx_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + int err = 0; + + //down(&priv->sem); + + //if (!ieee->wpa_enabled) { + // err = -EOPNOTSUPP; + // goto out; + //} + + if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { + wrqu->data.length = 0; + goto out; + } + + if (wrqu->data.length < ieee->wpa_ie_len) { + err = -E2BIG; + goto out; + } + + wrqu->data.length = ieee->wpa_ie_len; + memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); + + out: + //up(&priv->sem); + return err; +} + +/* SIOCSIWAUTH */ +static int ipw_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct iw_param *param = &wrqu->param; + struct ieee80211_crypt_data *crypt; + unsigned long flags; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * ipw2200 does not use these parameters + */ + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { + IPW_WARNING("Can't set TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + flags = crypt->ops->get_flags(crypt->priv); + + if (param->value) + flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + else + flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; + + crypt->ops->set_flags(flags, crypt->priv); + + break; + + case IW_AUTH_DROP_UNENCRYPTED:{ + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + struct ieee80211_security sec = { + .flags = SEC_ENABLED, + .enabled = param->value, + }; + priv->ieee->drop_unencrypted = param->value; + /* We only change SEC_LEVEL for open mode. Others + * are set by ipw_wpa_set_encryption. + */ + if (!param->value) { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_0; + } else { + sec.flags |= SEC_LEVEL; + sec.level = SEC_LEVEL_1; + } + if (priv->ieee->set_security) + priv->ieee->set_security(priv->ieee->dev, &sec); + break; + } + + case IW_AUTH_80211_AUTH_ALG: + ret = ipw_wpa_set_auth_algs(priv, param->value); + break; + + case IW_AUTH_WPA_ENABLED: + ret = ipw_wpa_enable(priv, param->value); + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = param->value; + break; + + //case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = param->value; + break; + + default: + return -EOPNOTSUPP; + } + return ret; +} + +/* SIOCGIWAUTH */ +static int ipw_wx_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct ieee80211_device *ieee = priv->ieee; + struct ieee80211_crypt_data *crypt; + struct iw_param *param = &wrqu->param; + int ret = 0; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * wpa_supplicant will control these internally + */ + ret = -EOPNOTSUPP; + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + if (!crypt || !crypt->ops->get_flags) { + IPW_WARNING("Can't get TKIP countermeasures: " + "crypt not set!\n"); + break; + } + + param->value = (crypt->ops->get_flags(crypt->priv) & + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; + + break; + + case IW_AUTH_DROP_UNENCRYPTED: + param->value = ieee->drop_unencrypted; + break; + + case IW_AUTH_80211_AUTH_ALG: + param->value = ieee->sec.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + param->value = ieee->wpa_enabled; + break; + + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + param->value = ieee->ieee802_1x; + break; + + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + param->value = ieee->privacy_invoked; + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* SIOCSIWENCODEEXT */ +static int ipw_wx_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + + if (hwcrypto) { + /* IPW HW can't build TKIP MIC, host decryption still needed */ + if (ext->alg == IW_ENCODE_ALG_TKIP) { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 1; + priv->ieee->host_decrypt = 1; + } else { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 0; + priv->ieee->host_decrypt = 0; + } + } + + return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCGIWENCODEEXT */ +static int ipw_wx_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); +} + +/* SIOCSIWMLME */ +static int ipw_wx_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + u16 reason; + + reason = cpu_to_le16(mlme->reason_code); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + // silently ignore + break; + + case IW_MLME_DISASSOC: + ipw_disassociate(priv); + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} +#endif + +#ifdef CONFIG_IPW_QOS + +/* QoS */ +/* +* get the modulation type of the current network or +* the card current mode +*/ +u8 ipw_qos_current_mode(struct ipw_priv * priv) +{ + u8 mode = 0; + + if (priv->status & STATUS_ASSOCIATED) { + unsigned long flags; + + spin_lock_irqsave(&priv->ieee->lock, flags); + mode = priv->assoc_network->mode; + spin_unlock_irqrestore(&priv->ieee->lock, flags); + } else { + mode = priv->ieee->mode; + } + IPW_DEBUG_QOS("QoS network/card mode %d \n", mode); + return mode; } /* @@ -6377,12 +6762,12 @@ static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, { u32 size = sizeof(struct ieee80211_qos_parameters); - if ((network->capability & WLAN_CAPABILITY_IBSS)) + if (network->capability & WLAN_CAPABILITY_IBSS) network->qos_data.active = network->qos_data.supported; if (network->flags & NETWORK_HAS_QOS_MASK) { - if (active_network - && (network->flags & NETWORK_HAS_QOS_PARAMETERS)) + if (active_network && + (network->flags & NETWORK_HAS_QOS_PARAMETERS)) network->qos_data.active = network->qos_data.supported; if ((network->qos_data.active == 1) && (active_network == 1) && @@ -6392,17 +6777,17 @@ static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, network->qos_data.old_param_count = network->qos_data.param_count; schedule_work(&priv->qos_activate); - IPW_DEBUG_QOS - ("QoS parameters change call qos_activate\n"); + IPW_DEBUG_QOS("QoS parameters change call " + "qos_activate\n"); } } else { - if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) { - memcpy(&(network->qos_data.parameters), + if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) + memcpy(&network->qos_data.parameters, &def_parameters_CCK, size); - } else { - memcpy(&(network->qos_data.parameters), + else + memcpy(&network->qos_data.parameters, &def_parameters_OFDM, size); - } + if ((network->qos_data.active == 1) && (active_network == 1)) { IPW_DEBUG_QOS("QoS was disabled call qos_activate \n"); schedule_work(&priv->qos_activate); @@ -6411,24 +6796,19 @@ static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, network->qos_data.active = 0; network->qos_data.supported = 0; } - if ((priv->status & STATUS_ASSOCIATED) - && (priv->ieee->iw_mode == IW_MODE_ADHOC) - && (active_network == 0)) { - - if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - if ((network->capability & WLAN_CAPABILITY_IBSS) - && !(network->flags & NETWORK_EMPTY_ESSID)) { + if ((priv->status & STATUS_ASSOCIATED) && + (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { + if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) + if ((network->capability & WLAN_CAPABILITY_IBSS) && + !(network->flags & NETWORK_EMPTY_ESSID)) if ((network->ssid_len == - priv->assoc_network->ssid_len) - && !memcmp(network->ssid, - priv->assoc_network->ssid, - network->ssid_len)) { + priv->assoc_network->ssid_len) && + !memcmp(network->ssid, + priv->assoc_network->ssid, + network->ssid_len)) { queue_work(priv->workqueue, &priv->merge_networks); } - - } - } } return 0; @@ -6463,13 +6843,12 @@ static int ipw_qos_activate(struct ipw_priv *priv, } else active_one = &def_parameters_OFDM; - memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, - size); + memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); burst_duration = ipw_qos_get_burst_duration(priv); for (i = 0; i < QOS_QUEUE_NUM; i++) - qos_parameters[QOS_PARAM_SET_ACTIVE]. - tx_op_limit[i] = (u16) burst_duration; - } else if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { + qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] = + (u16) burst_duration; + } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { if (type == IEEE_B) { IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", type); @@ -6483,8 +6862,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, else active_one = priv->qos_data.def_qos_parm_OFDM; } - memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, - size); + memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); } else { unsigned long flags; int active; @@ -6493,8 +6871,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, active_one = &(qos_network_data->parameters); qos_network_data->old_param_count = qos_network_data->param_count; - memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, - size); + memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); active = qos_network_data->supported; spin_unlock_irqrestore(&priv->ieee->lock, flags); @@ -6507,10 +6884,9 @@ static int ipw_qos_activate(struct ipw_priv *priv, } IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); - err = - ipw_send_qos_params_command(priv, - (struct ieee80211_qos_parameters *) - &(qos_parameters[0])); + err = ipw_send_qos_params_command(priv, + (struct ieee80211_qos_parameters *) + &(qos_parameters[0])); if (err) IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); @@ -6603,21 +6979,19 @@ static int ipw_qos_association_resp(struct ipw_priv *priv, u32 size = sizeof(struct ieee80211_qos_parameters); int set_qos_param = 0; - if ((priv == NULL) || (network == NULL) - || (priv->assoc_network == NULL)) - + if ((priv == NULL) || (network == NULL) || + (priv->assoc_network == NULL)) return ret; if (!(priv->status & STATUS_ASSOCIATED)) return ret; - if ((priv->ieee->iw_mode != IW_MODE_INFRA)) { + if ((priv->ieee->iw_mode != IW_MODE_INFRA)) return ret; - } spin_lock_irqsave(&priv->ieee->lock, flags); if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { - memcpy(&(priv->assoc_network->qos_data), &(network->qos_data), + memcpy(&priv->assoc_network->qos_data, &network->qos_data, sizeof(struct ieee80211_qos_data)); priv->assoc_network->qos_data.active = 1; if ((network->qos_data.old_param_count != @@ -6628,13 +7002,12 @@ static int ipw_qos_association_resp(struct ipw_priv *priv, } } else { - if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) { - memcpy(&(priv->assoc_network->qos_data.parameters), + if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) + memcpy(&priv->assoc_network->qos_data.parameters, &def_parameters_CCK, size); - } else { - memcpy(&(priv->assoc_network->qos_data.parameters), + else + memcpy(&priv->assoc_network->qos_data.parameters, &def_parameters_OFDM, size); - } priv->assoc_network->qos_data.active = 0; priv->assoc_network->qos_data.supported = 0; set_qos_param = 1; @@ -6655,11 +7028,11 @@ static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) if ((priv == NULL)) return 0; - if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) { + if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) ret = priv->qos_data.burst_duration_CCK; - } else { + else ret = priv->qos_data.burst_duration_OFDM; - } + return ret; } @@ -6736,9 +7109,9 @@ static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, spin_unlock_irqrestore(&priv->ieee->lock, flags); - IPW_DEBUG_QOS - ("QoS %d network is QoS active %d supported %d unicast %d\n", - priv->qos_data.qos_enable, active, supported, unicast); + IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " + "unicast %d\n", + priv->qos_data.qos_enable, active, supported, unicast); if (active && priv->qos_data.qos_enable) { ret = from_priority_to_tx_queue[priority]; tx_queue_id = ret - 1; @@ -6822,8 +7195,7 @@ static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_q return -1; } - memcpy(&cmd.param, qos_param, - (sizeof(struct ieee80211_qos_parameters) * 3)); + memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send IPW_CMD_QOS_PARAMETERS command\n"); return -1; @@ -6845,7 +7217,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos return -1; } - memcpy(&cmd.param, qos_param, sizeof(*qos_param)); + memcpy(cmd.param, qos_param, sizeof(*qos_param)); if (ipw_send_cmd(priv, &cmd)) { IPW_ERROR("failed to send CMD_QOS_INFO command\n"); return -1; @@ -6919,6 +7291,11 @@ static int ipw_associate_network(struct ipw_priv *priv, ~WLAN_CAPABILITY_SHORT_PREAMBLE; } + /* Clear capability bits that aren't used in Ad Hoc */ + if (priv->ieee->iw_mode == IW_MODE_ADHOC) + priv->assoc_request.capability &= + ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", roaming ? "Rea" : "A", @@ -6954,13 +7331,13 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; } - memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN); + memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN); if (priv->ieee->iw_mode == IW_MODE_ADHOC) { memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); priv->assoc_request.atim_window = network->atim_window; } else { - memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN); + memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN); priv->assoc_request.atim_window = 0; } @@ -7119,14 +7496,14 @@ static int ipw_associate(void *data) } if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { - IPW_DEBUG_ASSOC - ("Not attempting association (already in progress)\n"); + IPW_DEBUG_ASSOC("Not attempting association (already in " + "progress)\n"); return 0; } if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { - IPW_DEBUG_ASSOC - ("Not attempting association (scanning or not initialized)\n"); + IPW_DEBUG_ASSOC("Not attempting association (scanning or not " + "initialized)\n"); return 0; } @@ -7285,9 +7662,8 @@ static inline int is_network_packet(struct ipw_priv *priv, if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) return 0; - /* {broad,multi}cast packets to our IBSS go through */ - if (is_broadcast_ether_addr(header->addr1) || - is_multicast_ether_addr(header->addr1)) + /* multicast packets to our IBSS go through */ + if (is_multicast_ether_addr(header->addr1)) return !memcmp(header->addr3, priv->bssid, ETH_ALEN); /* packets to our adapter go through */ @@ -7300,8 +7676,7 @@ static inline int is_network_packet(struct ipw_priv *priv, return 0; /* {broad,multi}cast packets to our IBSS go through */ - if (is_broadcast_ether_addr(header->addr1) || - is_multicast_ether_addr(header->addr1)) + if (is_multicast_ether_addr(header->addr1)) return !memcmp(header->addr2, priv->bssid, ETH_ALEN); /* packets to our adapter go through */ @@ -7312,6 +7687,79 @@ static inline int is_network_packet(struct ipw_priv *priv, return 1; } +#define IPW_PACKET_RETRY_TIME HZ + +static inline int is_duplicate_packet(struct ipw_priv *priv, + struct ieee80211_hdr_4addr *header) +{ + u16 fc = le16_to_cpu(header->frame_ctl); + u16 sc = le16_to_cpu(header->seq_ctl); + u16 seq = WLAN_GET_SEQ_SEQ(sc); + u16 frag = WLAN_GET_SEQ_FRAG(sc); + u16 *last_seq, *last_frag; + unsigned long *last_time; + + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + { + struct list_head *p; + struct ipw_ibss_seq *entry = NULL; + u8 *mac = header->addr2; + int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE; + + __list_for_each(p, &priv->ibss_mac_hash[index]) { + entry = + list_entry(p, struct ipw_ibss_seq, list); + if (!memcmp(entry->mac, mac, ETH_ALEN)) + break; + } + if (p == &priv->ibss_mac_hash[index]) { + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) { + IPW_ERROR + ("Cannot malloc new mac entry\n"); + return 0; + } + memcpy(entry->mac, mac, ETH_ALEN); + entry->seq_num = seq; + entry->frag_num = frag; + entry->packet_time = jiffies; + list_add(&entry->list, + &priv->ibss_mac_hash[index]); + return 0; + } + last_seq = &entry->seq_num; + last_frag = &entry->frag_num; + last_time = &entry->packet_time; + break; + } + case IW_MODE_INFRA: + last_seq = &priv->last_seq_num; + last_frag = &priv->last_frag_num; + last_time = &priv->last_packet_time; + break; + default: + return 0; + } + if ((*last_seq == seq) && + time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) { + if (*last_frag == frag) + goto drop; + if (*last_frag + 1 != frag) + /* out-of-order fragment */ + goto drop; + *last_frag = frag; + } else + *last_seq = seq; + + *last_time = jiffies; + return 0; + + drop: + BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); + return 1; +} + static void ipw_handle_mgmt_packet(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, struct ieee80211_rx_stats *stats) @@ -7481,7 +7929,10 @@ static void ipw_rx(struct ipw_priv *priv) break; case IEEE80211_FTYPE_DATA: - if (unlikely(!network_packet)) { + if (unlikely(!network_packet || + is_duplicate_packet(priv, + header))) + { IPW_DEBUG_DROP("Dropping: " MAC_FMT ", " MAC_FMT ", " @@ -7540,6 +7991,123 @@ static void ipw_rx(struct ipw_priv *priv) ipw_rx_queue_restock(priv); } +#define DEFAULT_RTS_THRESHOLD 2304U +#define MIN_RTS_THRESHOLD 1U +#define MAX_RTS_THRESHOLD 2304U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +static int ipw_sw_reset(struct ipw_priv *priv, int init) +{ + int band, modulation; + int old_mode = priv->ieee->iw_mode; + + /* Initialize module parameter values here */ + priv->config = 0; + + /* We default to disabling the LED code as right now it causes + * too many systems to lock up... */ + if (!led) + priv->config |= CFG_NO_LED; + + if (associate) + priv->config |= CFG_ASSOCIATE; + else + IPW_DEBUG_INFO("Auto associate disabled.\n"); + + if (auto_create) + priv->config |= CFG_ADHOC_CREATE; + else + IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); + + if (disable) { + priv->status |= STATUS_RF_KILL_SW; + IPW_DEBUG_INFO("Radio disabled.\n"); + } + + if (channel != 0) { + priv->config |= CFG_STATIC_CHANNEL; + priv->channel = channel; + IPW_DEBUG_INFO("Bind to static channel %d\n", channel); + /* TODO: Validate that provided channel is in range */ + } +#ifdef CONFIG_IPW_QOS + ipw_qos_init(priv, qos_enable, qos_burst_enable, + burst_duration_CCK, burst_duration_OFDM); +#endif /* CONFIG_IPW_QOS */ + + switch (mode) { + case 1: + priv->ieee->iw_mode = IW_MODE_ADHOC; + priv->net_dev->type = ARPHRD_ETHER; + + break; +#ifdef CONFIG_IPW2200_MONITOR + case 2: + priv->ieee->iw_mode = IW_MODE_MONITOR; + priv->net_dev->type = ARPHRD_IEEE80211; + break; +#endif + default: + case 0: + priv->net_dev->type = ARPHRD_ETHER; + priv->ieee->iw_mode = IW_MODE_INFRA; + break; + } + + if (hwcrypto) { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 0; + priv->ieee->host_decrypt = 0; + } + IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); + + if ((priv->pci_dev->device == 0x4223) || + (priv->pci_dev->device == 0x4224)) { + if (init) + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2915ABG Network " + "Connection\n"); + priv->ieee->abg_true = 1; + band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; + modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + priv->adapter = IPW_2915ABG; + priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; + } else { + if (init) + printk(KERN_INFO DRV_NAME + ": Detected Intel PRO/Wireless 2200BG Network " + "Connection\n"); + + priv->ieee->abg_true = 0; + band = IEEE80211_24GHZ_BAND; + modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + priv->adapter = IPW_2200BG; + priv->ieee->mode = IEEE_G | IEEE_B; + } + + priv->ieee->freq_band = band; + priv->ieee->modulation = modulation; + + priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; + + priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; + priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; + + priv->rts_threshold = DEFAULT_RTS_THRESHOLD; + priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; + priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; + + /* If power management is turned on, default to AC mode */ + priv->power_mode = IPW_POWER_AC; + priv->tx_power = IPW_TX_POWER_DEFAULT; + + return old_mode == priv->ieee->mode; +} + /* * This file defines the Wireless Extension handlers. It does not * define any methods of hardware manipulation and relies on the @@ -7569,9 +8137,7 @@ static int ipw_wx_get_name(struct net_device *dev, } static int ipw_set_channel(struct ipw_priv *priv, u8 channel) -{ - int i; - +{ if (channel == 0) { IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); priv->config &= ~CFG_STATIC_CHANNEL; @@ -7594,10 +8160,11 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { + int i; if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_SCAN("scan abort triggered due to " + IPW_DEBUG_SCAN("Scan abort triggered due to " "channel change.\n"); - queue_work(priv->workqueue, &priv->abort_scan); + ipw_abort_scan(priv); } for (i = 1000; i && (priv->status & STATUS_SCANNING); i--) @@ -7626,8 +8193,9 @@ static int ipw_wx_set_freq(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); struct iw_freq *fwrq = &wrqu->freq; - int ret = 0; + int ret = 0, i; u8 channel; if (fwrq->m == 0) { @@ -7637,7 +8205,6 @@ static int ipw_wx_set_freq(struct net_device *dev, up(&priv->sem); return ret; } - /* if setting by freq convert to channel */ if (fwrq->e == 1) { channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); @@ -7649,6 +8216,16 @@ static int ipw_wx_set_freq(struct net_device *dev, if (!ieee80211_is_valid_channel(priv->ieee, channel)) return -EINVAL; + if (priv->ieee->iw_mode == IW_MODE_ADHOC && priv->ieee->mode & IEEE_A) { + i = ieee80211_channel_to_index(priv->ieee, channel); + if (i == -1) + return -EINVAL; + if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); + return -EINVAL; + } + } + IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); down(&priv->sem); ret = ipw_set_channel(priv, channel); @@ -7704,6 +8281,9 @@ static int ipw_wx_set_mode(struct net_device *dev, return 0; down(&priv->sem); + + ipw_sw_reset(priv, 0); + #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) priv->net_dev->type = ARPHRD_ETHER; @@ -7712,17 +8292,9 @@ static int ipw_wx_set_mode(struct net_device *dev, priv->net_dev->type = ARPHRD_IEEE80211; #endif /* CONFIG_IPW2200_MONITOR */ -#ifdef CONFIG_PM /* Free the existing firmware and reset the fw_loaded * flag so ipw_load() will bring in the new firmawre */ - if (fw_loaded) - fw_loaded = 0; - - release_firmware(bootfw); - release_firmware(ucode); - release_firmware(firmware); - bootfw = ucode = firmware = NULL; -#endif + free_firmware(); priv->ieee->iw_mode = wrqu->mode; @@ -7743,13 +8315,6 @@ static int ipw_wx_get_mode(struct net_device *dev, return 0; } -#define DEFAULT_RTS_THRESHOLD 2304U -#define MIN_RTS_THRESHOLD 1U -#define MAX_RTS_THRESHOLD 2304U -#define DEFAULT_BEACON_INTERVAL 100U -#define DEFAULT_SHORT_RETRY_LIMIT 7U -#define DEFAULT_LONG_RETRY_LIMIT 4U - /* Values are in microsecond */ static const s32 timeout_duration[] = { 350000, @@ -7900,7 +8465,7 @@ static int ipw_wx_get_wap(struct net_device *dev, if (priv->config & CFG_STATIC_BSSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN); + memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); @@ -7924,10 +8489,12 @@ static int ipw_wx_set_essid(struct net_device *dev, } if (length == 0) { IPW_DEBUG_WX("Setting ESSID to ANY\n"); - priv->config &= ~CFG_STATIC_ESSID; - if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { + if ((priv->config & CFG_STATIC_ESSID) && + !(priv->status & (STATUS_ASSOCIATED | + STATUS_ASSOCIATING))) { IPW_DEBUG_ASSOC("Attempting to associate with new " "parameters.\n"); + priv->config &= ~CFG_STATIC_ESSID; ipw_associate(priv); } up(&priv->sem); @@ -8202,7 +8769,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, } if ((wrqu->power.value > IPW_TX_POWER_MAX) || - (wrqu->power.value < -IPW_TX_POWER_MAX) || !wrqu->power.fixed) { + (wrqu->power.value < IPW_TX_POWER_MIN)) { up(&priv->sem); return -EINVAL; } @@ -8295,23 +8862,149 @@ static int ipw_wx_set_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); - return -EOPNOTSUPP; + struct ipw_priv *priv = ieee80211_priv(dev); + + if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) + return -EINVAL; + + if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) + return 0; + + if (wrqu->retry.value < 0 || wrqu->retry.value > 255) + return -EINVAL; + + down(&priv->sem); + if (wrqu->retry.flags & IW_RETRY_MIN) + priv->short_retry_limit = (u8) wrqu->retry.value; + else if (wrqu->retry.flags & IW_RETRY_MAX) + priv->long_retry_limit = (u8) wrqu->retry.value; + else { + priv->short_retry_limit = (u8) wrqu->retry.value; + priv->long_retry_limit = (u8) wrqu->retry.value; + } + + ipw_send_retry_limit(priv, priv->short_retry_limit, + priv->long_retry_limit); + up(&priv->sem); + IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n", + priv->short_retry_limit, priv->long_retry_limit); + return 0; } static int ipw_wx_get_retry(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); - return -EOPNOTSUPP; + struct ipw_priv *priv = ieee80211_priv(dev); + + down(&priv->sem); + wrqu->retry.disabled = 0; + + if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + up(&priv->sem); + return -EINVAL; + } + + if (wrqu->retry.flags & IW_RETRY_MAX) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + wrqu->retry.value = priv->long_retry_limit; + } else if (wrqu->retry.flags & IW_RETRY_MIN) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + wrqu->retry.value = priv->short_retry_limit; + } else { + wrqu->retry.flags = IW_RETRY_LIMIT; + wrqu->retry.value = priv->short_retry_limit; + } + up(&priv->sem); + + IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value); + + return 0; +} + +#if WIRELESS_EXT > 17 +static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, + int essid_len) +{ + struct ipw_scan_request_ext scan; + int err = 0, scan_type; + + down(&priv->sem); + + if (priv->status & STATUS_RF_KILL_MASK) { + IPW_DEBUG_HC("Aborting scan due to RF kill activation\n"); + priv->status |= STATUS_SCAN_PENDING; + goto done; + } + + IPW_DEBUG_HC("starting request direct scan!\n"); + + if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { + err = wait_event_interruptible(priv->wait_state, + !(priv-> + status & (STATUS_SCANNING | + STATUS_SCAN_ABORTING))); + if (err) { + IPW_DEBUG_HC("aborting direct scan"); + goto done; + } + } + memset(&scan, 0, sizeof(scan)); + + if (priv->config & CFG_SPEED_SCAN) + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = + cpu_to_le16(30); + else + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = + cpu_to_le16(20); + + scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = + cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); + + scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); + + err = ipw_send_ssid(priv, essid, essid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command failed\n"); + goto done; + } + scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; + + ipw_add_scan_channels(priv, &scan, scan_type); + + err = ipw_send_scan_request_ext(priv, &scan); + if (err) { + IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); + goto done; + } + + priv->status |= STATUS_SCANNING; + + done: + up(&priv->sem); + return err; } +#endif /* WIRELESS_EXT > 17 */ static int ipw_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); +#if WIRELESS_EXT > 17 + struct iw_scan_req *req = NULL; + if (wrqu->data.length + && wrqu->data.length == sizeof(struct iw_scan_req)) { + req = (struct iw_scan_req *)extra; + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + ipw_request_direct_scan(priv, req->essid, + req->essid_len); + return 0; + } + } +#endif IPW_DEBUG_WX("Start scan\n"); queue_work(priv->workqueue, &priv->request_scan); @@ -8332,7 +9025,13 @@ static int ipw_wx_set_encode(struct net_device *dev, union iwreq_data *wrqu, char *key) { struct ipw_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + int ret; + + down(&priv->sem); + ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); + up(&priv->sem); + + return ret; } static int ipw_wx_get_encode(struct net_device *dev, @@ -8665,110 +9364,6 @@ static int ipw_wx_reset(struct net_device *dev, return 0; } -static void ipw_sw_reset(struct ipw_priv *priv, int init) -{ - int band, modulation; - - /* Initialize module parameter values here */ - priv->config = 0; - - /* We default to disabling the LED code as right now it causes - * too many systems to lock up... */ - if (!led) - priv->config |= CFG_NO_LED; - - if (associate) - priv->config |= CFG_ASSOCIATE; - else - IPW_DEBUG_INFO("Auto associate disabled.\n"); - - if (auto_create) - priv->config |= CFG_ADHOC_CREATE; - else - IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); - - if (disable) { - priv->status |= STATUS_RF_KILL_SW; - IPW_DEBUG_INFO("Radio disabled.\n"); - } - - if (channel != 0) { - priv->config |= CFG_STATIC_CHANNEL; - priv->channel = channel; - IPW_DEBUG_INFO("Bind to static channel %d\n", channel); - /* TODO: Validate that provided channel is in range */ - } -#ifdef CONFIG_IPW_QOS - ipw_qos_init(priv, qos_enable, qos_burst_enable, - burst_duration_CCK, burst_duration_OFDM); -#endif /* CONFIG_IPW_QOS */ - - switch (mode) { - case 1: - priv->ieee->iw_mode = IW_MODE_ADHOC; - priv->net_dev->type = ARPHRD_ETHER; - - break; -#ifdef CONFIG_IPW2200_MONITOR - case 2: - priv->ieee->iw_mode = IW_MODE_MONITOR; - priv->net_dev->type = ARPHRD_IEEE80211; - break; -#endif - default: - case 0: - priv->net_dev->type = ARPHRD_ETHER; - priv->ieee->iw_mode = IW_MODE_INFRA; - break; - } - - if (hwcrypto) { - priv->ieee->host_encrypt = 0; - priv->ieee->host_decrypt = 0; - } - IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); - - if ((priv->pci_dev->device == 0x4223) || - (priv->pci_dev->device == 0x4224)) { - if (init) - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2915ABG Network " - "Connection\n"); - priv->ieee->abg_true = 1; - band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - priv->adapter = IPW_2915ABG; - priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; - } else { - if (init) - printk(KERN_INFO DRV_NAME - ": Detected Intel PRO/Wireless 2200BG Network " - "Connection\n"); - - priv->ieee->abg_true = 0; - band = IEEE80211_24GHZ_BAND; - modulation = IEEE80211_OFDM_MODULATION | - IEEE80211_CCK_MODULATION; - priv->adapter = IPW_2200BG; - priv->ieee->mode = IEEE_G | IEEE_B; - } - - priv->ieee->freq_band = band; - priv->ieee->modulation = modulation; - - priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; - - priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; - priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; - - priv->rts_threshold = DEFAULT_RTS_THRESHOLD; - - /* If power management is turned on, default to AC mode */ - priv->power_mode = IPW_POWER_AC; - priv->tx_power = IPW_TX_POWER_DEFAULT; -} - static int ipw_wx_sw_reset(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -8779,12 +9374,17 @@ static int ipw_wx_sw_reset(struct net_device *dev, .flags = IW_ENCODE_DISABLED, }, }; + int ret; IPW_DEBUG_WX("SW_RESET\n"); down(&priv->sem); - ipw_sw_reset(priv, 0); + ret = ipw_sw_reset(priv, 0); + if (!ret) { + free_firmware(); + ipw_adapter_restart(priv); + } /* The SW reset bit might have been toggled on by the 'disable' * module parameter, so take appropriate action */ @@ -8842,6 +9442,15 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, +#if WIRELESS_EXT > 17 + IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie, + IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie, + IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme, + IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth, + IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth, + IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext, + IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext, +#endif }; enum { @@ -8934,7 +9543,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) wstats = &priv->wstats; /* if hw is disabled, then ipw_get_ordinal() can't be called. - * ipw2100_wx_wireless_stats seems to be called before fw is + * netdev->get_wireless_stats seems to be called before fw is * initialized. STATUS_ASSOCIATED will only be set if the hw is up * and associated; if not associcated, the values are all meaningless * anyway, so set them all to NULL and INVALID */ @@ -9036,8 +9645,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: hdr_len = IEEE80211_3ADDR_LEN; - unicast = !is_broadcast_ether_addr(hdr->addr1) && - !is_multicast_ether_addr(hdr->addr1); + unicast = !is_multicast_ether_addr(hdr->addr1); id = ipw_find_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { id = ipw_add_station(priv, hdr->addr1); @@ -9052,8 +9660,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, case IW_MODE_INFRA: default: - unicast = !is_broadcast_ether_addr(hdr->addr3) && - !is_multicast_ether_addr(hdr->addr3); + unicast = !is_multicast_ether_addr(hdr->addr3); hdr_len = IEEE80211_3ADDR_LEN; id = 0; break; @@ -9176,6 +9783,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); for (j = i; j < txb->nr_frags; j++) { int size = txb->fragments[j]->len - hdr_len; + printk(KERN_INFO "Adding frag %d %d...\n", j, size); memcpy(skb_put(skb, size), @@ -9307,7 +9915,7 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; down(&p->sem); - memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len); + memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len); up(&p->sem); return 0; } @@ -9321,7 +9929,7 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; down(&p->sem); - memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len); + memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); for (i = IPW_EEPROM_DATA; i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) ipw_write8(p, i, p->eeprom[i]); @@ -9427,6 +10035,10 @@ static void ipw_bg_rf_kill(void *data) void ipw_link_up(struct ipw_priv *priv) { + priv->last_seq_num = -1; + priv->last_frag_num = -1; + priv->last_packet_time = 0; + netif_carrier_on(priv->net_dev); if (netif_queue_stopped(priv->net_dev)) { IPW_DEBUG_NOTIF("waking queue\n"); @@ -9470,8 +10082,10 @@ void ipw_link_down(struct ipw_priv *priv) ipw_reset_stats(priv); - /* Queue up another scan... */ - queue_work(priv->workqueue, &priv->request_scan); + if (!(priv->status & STATUS_EXIT_PENDING)) { + /* Queue up another scan... */ + queue_work(priv->workqueue, &priv->request_scan); + } } static void ipw_bg_link_down(void *data) @@ -9488,6 +10102,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) priv->workqueue = create_workqueue(DRV_NAME); init_waitqueue_head(&priv->wait_command_queue); + init_waitqueue_head(&priv->wait_state); INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); INIT_WORK(&priv->associate, ipw_bg_associate, priv); @@ -9531,9 +10146,9 @@ static void shim__set_security(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int i; - down(&priv->sem); for (i = 0; i < 4; i++) { if (sec->flags & (1 << i)) { + priv->ieee->sec.encode_alg[i] = sec->encode_alg[i]; priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; if (sec->key_sizes[i] == 0) priv->ieee->sec.flags &= ~(1 << i); @@ -9577,7 +10192,9 @@ static void shim__set_security(struct net_device *dev, else priv->capability &= ~CAP_PRIVACY_ON; } - priv->ieee->sec.encrypt = sec->encrypt; + + if (sec->flags & SEC_ENCRYPT) + priv->ieee->sec.encrypt = sec->encrypt; if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { priv->ieee->sec.level = sec->level; @@ -9602,7 +10219,6 @@ static void shim__set_security(struct net_device *dev, ipw_disassociate(priv); } #endif - up(&priv->sem); } static int init_supported_rates(struct ipw_priv *priv, @@ -9707,6 +10323,24 @@ static int ipw_config(struct ipw_priv *priv) return -EIO; } +static const struct ieee80211_geo ipw_geo = { + "---", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 8, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, +}; + #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { @@ -9729,6 +10363,10 @@ static int ipw_up(struct ipw_priv *priv) eeprom_parse_mac(priv, priv->mac_addr); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); + memcpy(priv->country, &priv->eeprom[EEPROM_COUNTRY_CODE], 3); + priv->country[3] = '\0'; + ieee80211_set_geo(priv->ieee, &ipw_geo); + if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); return 0; @@ -9748,6 +10386,14 @@ static int ipw_up(struct ipw_priv *priv) ipw_led_radio_on(priv); priv->notif_missed_beacons = 0; priv->status |= STATUS_INIT; + + /* Set hardware WEP key if it is configured. */ + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.level == SEC_LEVEL_1) && + !(priv->ieee->host_encrypt || + priv->ieee->host_decrypt)) + ipw_set_hwcrypto_keys(priv); + return 0; } @@ -9846,6 +10492,7 @@ static void ipw_bg_down(void *data) up(&priv->sem); } +#if WIRELESS_EXT < 18 static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct iwreq *wrq = (struct iwreq *)rq; @@ -9861,6 +10508,7 @@ static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EOPNOTSUPP; } +#endif /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) @@ -9942,6 +10590,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *base; u32 length, val; struct ipw_priv *priv; + int i; net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); if (net_dev == NULL) { @@ -9958,6 +10607,8 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ipw_debug_level = debug; #endif spin_lock_init(&priv->lock); + for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) + INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); init_MUTEX(&priv->sem); if (pci_enable_device(pdev)) { @@ -10035,7 +10686,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) net_dev->open = ipw_net_open; net_dev->stop = ipw_net_stop; net_dev->init = ipw_net_init; +#if WIRELESS_EXT < 18 net_dev->do_ioctl = ipw_ioctl; +#endif net_dev->get_stats = ipw_net_get_stats; net_dev->set_multicast_list = ipw_net_set_multicast_list; net_dev->set_mac_address = ipw_net_set_mac_address; @@ -10086,13 +10739,18 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static void ipw_pci_remove(struct pci_dev *pdev) { struct ipw_priv *priv = pci_get_drvdata(pdev); + struct list_head *p, *q; + int i; if (!priv) return; down(&priv->sem); + + priv->status |= STATUS_EXIT_PENDING; ipw_down(priv); sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); + up(&priv->sem); unregister_netdev(priv->net_dev); @@ -10113,21 +10771,21 @@ static void ipw_pci_remove(struct pci_dev *pdev) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; + /* Free MAC hash list for ADHOC */ + for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) { + list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { + kfree(list_entry(p, struct ipw_ibss_seq, list)); + list_del(p); + } + } + free_irq(pdev->irq, priv); iounmap(priv->hw_base); pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); free_ieee80211(priv->net_dev); - -#ifdef CONFIG_PM - if (fw_loaded) { - release_firmware(bootfw); - release_firmware(ucode); - release_firmware(firmware); - fw_loaded = 0; - } -#endif + free_firmware(); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 9dbd73a42094..915f469fa1d6 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -244,7 +244,7 @@ enum connection_manager_assoc_states { #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 -#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 24 +#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 9 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 #define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300 @@ -699,8 +699,8 @@ struct ipw_rx_packet { } __attribute__ ((packed)); #define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12 -#define IPW_RX_FRAME_SIZE sizeof(struct ipw_rx_header) + \ - sizeof(struct ipw_rx_frame) +#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \ + sizeof(struct ipw_rx_frame)) struct ipw_rx_mem_buffer { dma_addr_t dma_addr; @@ -1029,6 +1029,7 @@ struct ipw_cmd { #define STATUS_SCAN_PENDING (1<<20) #define STATUS_SCANNING (1<<21) #define STATUS_SCAN_ABORTING (1<<22) +#define STATUS_SCAN_FORCED (1<<23) #define STATUS_LED_LINK_ON (1<<24) #define STATUS_LED_ACT_ON (1<<25) @@ -1074,6 +1075,15 @@ struct average { }; #define MAX_SPEED_SCAN 100 +#define IPW_IBSS_MAC_HASH_SIZE 31 + +struct ipw_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; struct ipw_priv { /* ieee device used by generic ieee processing code */ @@ -1115,7 +1125,7 @@ struct ipw_priv { int rx_bufs_min; /**< minimum number of bufs in Rx queue */ int rx_pend_max; /**< maximum pending buffers for one IRQ */ u32 hcmd_seq; /**< sequence number for hcmd */ - u32 missed_beacon_threshold; + u32 disassociate_threshold; u32 roaming_threshold; struct ipw_associate assoc_request; @@ -1156,6 +1166,8 @@ struct ipw_priv { u8 mac_addr[ETH_ALEN]; u8 num_stations; u8 stations[MAX_STATIONS][ETH_ALEN]; + u8 short_retry_limit; + u8 long_retry_limit; u32 notif_missed_beacons; @@ -1176,8 +1188,14 @@ struct ipw_priv { u8 speed_scan[MAX_SPEED_SCAN]; u8 speed_scan_pos; + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE]; + /* eeprom */ u8 eeprom[0x100]; /* 256 bytes of eeprom */ + u8 country[4]; int eeprom_delay; struct iw_statistics wstats; -- cgit v1.2.3-59-g8ed1b From a2d73e60bb018da74ba508943c79c83659f3a883 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 13 Jul 2005 12:24:51 -0500 Subject: Fix hardware encryption (both WEP and AES) doesn't work with fragmentation. Firmware sends received packets with double sized ICV/MIC. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 1b6f0277a3e9..8f7e9ac37f86 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7587,7 +7587,10 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, memmove(skb->data + IEEE80211_3ADDR_LEN, skb->data + IEEE80211_3ADDR_LEN + 8, skb->len - IEEE80211_3ADDR_LEN - 8); - skb_trim(skb, skb->len - 8); /* MIC */ + if (fc & IEEE80211_FCTL_MOREFRAGS) + skb_trim(skb, skb->len - 16); /* 2*MIC */ + else + skb_trim(skb, skb->len - 8); /* MIC */ break; case SEC_LEVEL_2: break; @@ -7596,7 +7599,10 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, memmove(skb->data + IEEE80211_3ADDR_LEN, skb->data + IEEE80211_3ADDR_LEN + 4, skb->len - IEEE80211_3ADDR_LEN - 4); - skb_trim(skb, skb->len - 4); /* ICV */ + if (fc & IEEE80211_FCTL_MOREFRAGS) + skb_trim(skb, skb->len - 8); /* 2*ICV */ + else + skb_trim(skb, skb->len - 4); /* ICV */ break; case SEC_LEVEL_0: break; -- cgit v1.2.3-59-g8ed1b From f57ce7ce9c7498fe9c4090aaf389c89f3bd70f7e Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 13 Jul 2005 12:22:15 -0500 Subject: Fix is_duplicate_packet() bug for fragmentation number setting. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 8f7e9ac37f86..93ed8718fd6b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7754,10 +7754,10 @@ static inline int is_duplicate_packet(struct ipw_priv *priv, if (*last_frag + 1 != frag) /* out-of-order fragment */ goto drop; - *last_frag = frag; } else *last_seq = seq; + *last_frag = frag; *last_time = jiffies; return 0; -- cgit v1.2.3-59-g8ed1b From d8bad6df045249cd1cff6a0d167c8f1b9caade7e Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 13 Jul 2005 12:25:38 -0500 Subject: [bug 667] Fix the notorious "No space for Tx" bug. We send SYSTEM_CONFIG command after the TGI_KEY command if hardware encryption is enabled. It sometimes causes a firmware stall (firmware doesn't respond to any request) and finally bungs up the Tx send queue. The solution is to send SYSTEM_CONFIG command in the post association stage from a workqueue. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 46 +++++++++++++++++++++--------------------- drivers/net/wireless/ipw2200.h | 1 + 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 93ed8718fd6b..f3048f8e8238 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -3589,6 +3589,12 @@ static void ipw_bg_disassociate(void *data) up(&priv->sem); } +static void ipw_system_config(void *data) +{ + struct ipw_priv *priv = data; + ipw_send_system_config(priv, &priv->sys_config); +} + struct ipw_status_code { u16 status; const char *reason; @@ -4060,6 +4066,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, priv->status &= ~STATUS_ASSOCIATING; priv->status |= STATUS_ASSOCIATED; + queue_work(priv->workqueue, + &priv->system_config); #ifdef CONFIG_IPW_QOS #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ @@ -5553,45 +5561,36 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) { switch (priv->ieee->sec.level) { case SEC_LEVEL_3: - if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) - break; + if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) + ipw_send_tgi_tx_key(priv, + DCT_FLAG_EXT_SECURITY_CCM, + priv->ieee->sec.active_key); - ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_CCM, - priv->ieee->sec.active_key); ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); - priv->sys_config.disable_unicast_decryption = 0; priv->sys_config.disable_multicast_decryption = 0; priv->ieee->host_decrypt = 0; - if (ipw_send_system_config(priv, &priv->sys_config)) - IPW_ERROR("ipw_send_system_config failed\n"); - break; case SEC_LEVEL_2: - if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) - break; - - ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_TKIP, - priv->ieee->sec.active_key); + if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) + ipw_send_tgi_tx_key(priv, + DCT_FLAG_EXT_SECURITY_TKIP, + priv->ieee->sec.active_key); priv->sys_config.disable_unicast_decryption = 1; priv->sys_config.disable_multicast_decryption = 1; priv->ieee->host_decrypt = 1; - if (ipw_send_system_config(priv, &priv->sys_config)) - IPW_ERROR("ipw_send_system_config failed\n"); - break; case SEC_LEVEL_1: ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); - priv->sys_config.disable_unicast_decryption = 0; priv->sys_config.disable_multicast_decryption = 0; priv->ieee->host_decrypt = 0; - if (ipw_send_system_config(priv, &priv->sys_config)) - IPW_ERROR("ipw_send_system_config failed\n"); - break; case SEC_LEVEL_0: + priv->sys_config.disable_unicast_decryption = 1; + priv->sys_config.disable_multicast_decryption = 1; + break; default: break; } @@ -10113,6 +10112,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); INIT_WORK(&priv->associate, ipw_bg_associate, priv); INIT_WORK(&priv->disassociate, ipw_bg_disassociate, priv); + INIT_WORK(&priv->system_config, ipw_system_config, priv); INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish, priv); INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart, priv); INIT_WORK(&priv->rf_kill, ipw_bg_rf_kill, priv); @@ -10206,10 +10206,10 @@ static void shim__set_security(struct net_device *dev, priv->ieee->sec.level = sec->level; priv->ieee->sec.flags |= SEC_LEVEL; priv->status |= STATUS_SECURITY_UPDATED; - } - if (!priv->ieee->host_encrypt) - ipw_set_hwcrypto_keys(priv); + if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) + ipw_set_hwcrypto_keys(priv); + } /* To match current functionality of ipw2100 (which works well w/ * various supplicants, we don't force a disassociate if the diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 915f469fa1d6..28667d3c946a 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1205,6 +1205,7 @@ struct ipw_priv { struct work_struct adhoc_check; struct work_struct associate; struct work_struct disassociate; + struct work_struct system_config; struct work_struct rx_replenish; struct work_struct request_scan; struct work_struct adapter_restart; -- cgit v1.2.3-59-g8ed1b From 8400a1ceb445f2ace4b8d3c35c181b2b416a81ce Mon Sep 17 00:00:00 2001 From: Liu Hong Date: Wed, 13 Jul 2005 12:27:17 -0500 Subject: [Bug 637] Set tx power for A band. It uses the ieee80211-geo info to set the tx power of the a/b/g band. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f3048f8e8238..0923038ca788 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8756,6 +8756,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); struct ipw_tx_power tx_power; int i; @@ -8785,10 +8786,15 @@ static int ipw_wx_set_txpow(struct net_device *dev, /* configure device for 'G' band */ tx_power.ieee_mode = IPW_G_MODE; - tx_power.num_channels = 11; - for (i = 0; i < 11; i++) { + tx_power.num_channels = geo->bg_channels; + for (i = 0; i < geo->bg_channels; i++) { + int max_power = geo->bg[i].max_power; + tx_power.channels_tx_power[i].channel_number = i + 1; - tx_power.channels_tx_power[i].tx_power = priv->tx_power; + if (max_power != 0 && priv->tx_power > max_power) + tx_power.channels_tx_power[i].tx_power = max_power; + else + tx_power.channels_tx_power[i].tx_power = priv->tx_power; } if (ipw_send_tx_power(priv, &tx_power)) goto error; @@ -8798,6 +8804,25 @@ static int ipw_wx_set_txpow(struct net_device *dev, if (ipw_send_tx_power(priv, &tx_power)) goto error; + /* configure device to also handle 'A' band */ + if (priv->ieee->abg_true) { + tx_power.ieee_mode = IPW_A_MODE; + tx_power.num_channels = geo->a_channels; + for (i = 0; i < geo->a_channels; i++) { + int max_power = geo->a[i].max_power; + + tx_power.channels_tx_power[i].channel_number = i + 1; + if (max_power != 0 && priv->tx_power > max_power) + tx_power.channels_tx_power[i].tx_power = + max_power; + else + tx_power.channels_tx_power[i].tx_power = + priv->tx_power; + } + if (ipw_send_tx_power(priv, &tx_power)) + goto error; + } + up(&priv->sem); return 0; -- cgit v1.2.3-59-g8ed1b From d2021cb4e28c512c395a439d65556c260b94e47e Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 14 Jul 2005 10:35:05 -0500 Subject: Changed default # of missed beacons to miss before disassociation to 24 (vs. 9 which is too low in most environments) Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 28667d3c946a..9bf8aa427d8c 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -244,7 +244,7 @@ enum connection_manager_assoc_states { #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 -#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 9 +#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 24 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 #define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300 -- cgit v1.2.3-59-g8ed1b From 227d2dc1f109e3348564320cf42fc56770428ed3 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 28 Jul 2005 16:25:55 -0500 Subject: Updated to support ieee80211 callback to is_queue_full for 802.11e support. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0923038ca788..3b3a4a077c0e 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9654,8 +9654,8 @@ modify to send one tfd per fragment instead of using chunking. otherwise we need to heavily modify the ieee80211_skb_to_txb. */ -static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, - int pri) +static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, + int pri) { struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) txb->fragments[0]->data; @@ -9672,6 +9672,11 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, u16 remaining_bytes; int fc; + /* If there isn't room in the queue, we return busy and let the + * network stack requeue the packet for us */ + if (ipw_queue_space(q) < q->high_mark) + return NETDEV_TX_BUSY; + switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: hdr_len = IEEE80211_3ADDR_LEN; @@ -9837,14 +9842,28 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); ipw_write32(priv, q->reg_w, q->first_empty); - if (ipw_queue_space(q) < q->high_mark) - netif_stop_queue(priv->net_dev); - - return; + return NETDEV_TX_OK; drop: IPW_DEBUG_DROP("Silently dropping Tx packet.\n"); ieee80211_txb_free(txb); + return NETDEV_TX_OK; +} + +static int ipw_net_is_queue_full(struct net_device *dev, int pri) +{ + struct ipw_priv *priv = ieee80211_priv(dev); +#ifdef CONFIG_IPW_QOS + int tx_id = ipw_get_tx_queue_number(priv, pri); + struct clx2_tx_queue *txq = &priv->txq[tx_id]; +#else + struct clx2_tx_queue *txq = &priv->txq[0]; +#endif /* CONFIG_IPW_QOS */ + + if (ipw_queue_space(&txq->q) < txq->q.high_mark) + return 1; + + return 0; } static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, @@ -9852,6 +9871,7 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, { struct ipw_priv *priv = ieee80211_priv(dev); unsigned long flags; + int ret; IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size); spin_lock_irqsave(&priv->lock, flags); @@ -9863,11 +9883,12 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, goto fail_unlock; } - ipw_tx_skb(priv, txb, pri); - __ipw_led_activity_on(priv); + ret = ipw_tx_skb(priv, txb, pri); + if (ret == NETDEV_TX_OK) + __ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags); - return 0; + return ret; fail_unlock: spin_unlock_irqrestore(&priv->lock, flags); @@ -10706,6 +10727,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; priv->ieee->set_security = shim__set_security; + priv->ieee->is_queue_full = ipw_net_is_queue_full; #ifdef CONFIG_IPW_QOS priv->ieee->handle_management_frame = ipw_handle_management_frame; -- cgit v1.2.3-59-g8ed1b From 2b184d5b5401bf87036cd0c2a0242fa5320129d7 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 3 Aug 2005 20:33:14 -0500 Subject: Fixed some compiler issues if CONFIG_IPW2200_QOS is enabled. Updated a copyright date. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 3b3a4a077c0e..073721f10577 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -34,7 +34,7 @@ #define IPW2200_VERSION "1.0.5" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" #define DRV_VERSION IPW2200_VERSION #define ETH_P_80211_STATS (ETH_P_80211_RAW + 1) @@ -4077,7 +4077,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, == IEEE80211_STYPE_ASSOC_RESP)) { if ((sizeof (struct - ieee80211_assoc_response_frame) + ieee80211_assoc_response) <= notif->size) && (notif->size <= 2314)) { struct @@ -4095,7 +4095,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, ieee80211_rx_mgt(priv-> ieee, (struct - ieee80211_hdr + ieee80211_hdr_4addr *) ¬if->u.raw, &stats); } @@ -7154,9 +7154,8 @@ static void ipw_bg_qos_activate(void *data) /* * Handler for probe responce and beacon frame */ -static int ipw_handle_management_frame(struct net_device *dev, - struct ieee80211_network *network, - u16 type) +static int ipw_handle_management(struct net_device *dev, + struct ieee80211_network *network, u16 type) { struct ipw_priv *priv = ieee80211_priv(dev); int active_network; @@ -10730,7 +10729,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->ieee->is_queue_full = ipw_net_is_queue_full; #ifdef CONFIG_IPW_QOS - priv->ieee->handle_management_frame = ipw_handle_management_frame; + priv->ieee->handle_management = ipw_handle_management; #endif /* CONFIG_IPW_QOS */ priv->ieee->perfect_rssi = -20; -- cgit v1.2.3-59-g8ed1b From 4f36f8088ada6c63719a970616078887f82e226c Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 3 Aug 2005 20:36:56 -0500 Subject: Added more useful geography encoding so people's experience with iwconfig matches what their hardware can actually do in regard to supported channel maps, etc. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 279 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 259 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 073721f10577..6e79ae24ee1c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -10374,28 +10374,256 @@ static int ipw_config(struct ipw_priv *priv) return -EIO; } -static const struct ieee80211_geo ipw_geo = { - "---", - .bg_channels = 11, - .bg = {{2412, 1}, {2417, 2}, {2422, 3}, - {2427, 4}, {2432, 5}, {2437, 6}, - {2442, 7}, {2447, 8}, {2452, 9}, - {2457, 10}, {2462, 11}}, - .a_channels = 8, - .a = {{5180, 36}, - {5200, 40}, - {5220, 44}, - {5240, 48}, - {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, - {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, - {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, - {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, +/* + * NOTE: + * + * These tables have been tested in conjunction with the + * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters. + * + * Altering this values, using it on other hardware, or in geographies + * not intended for resale of the above mentioned Intel adapters has + * not been tested. + * + */ +static const struct ieee80211_geo ipw_geos[] = { + { /* Restricted */ + "---", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + }, + + { /* Custom US/Canada */ + "ZZF", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 8, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Rest of World */ + "ZZD", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}}, + }, + + { /* Custom USA & Europe & High */ + "ZZA", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 13, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149}, + {5765, 153}, + {5785, 157}, + {5805, 161}, + {5825, 165}}, + }, + + { /* Custom NA & Europe */ + "ZZB", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 13, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, + {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, + {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, + {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, + {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Custom Japan */ + "ZZC", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 4, + .a = {{5170, 34}, {5190, 38}, + {5210, 42}, {5230, 46}}, + }, + + { /* Custom */ + "ZZM", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + }, + + { /* Europe */ + "ZZE", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}}, + .a_channels = 19, + .a = {{5180, 36}, + {5200, 40}, + {5220, 44}, + {5240, 48}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, + {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, + {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, + {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, + {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, + {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, + {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, + {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, + {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, + {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, + {5700, 140, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Custom Japan */ + "ZZJ", + .bg_channels = 14, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY}}, + .a_channels = 4, + .a = {{5170, 34}, {5190, 38}, + {5210, 42}, {5230, 46}}, + }, + + { /* High Band */ + "ZZH", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, + {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, + {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + .a_channels = 4, + .a = {{5745, 149}, {5765, 153}, + {5785, 157}, {5805, 161}}, + }, + + { /* Custom Europe */ + "ZZG", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, + {2467, 12}, {2472, 13}}, + .a_channels = 4, + .a = {{5180, 36}, {5200, 40}, + {5220, 44}, {5240, 48}}, + }, + + { /* Europe */ + "ZZK", + .bg_channels = 13, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, + {2467, 12, IEEE80211_CH_PASSIVE_ONLY}, + {2472, 13, IEEE80211_CH_PASSIVE_ONLY}}, + .a_channels = 24, + .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, + {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, + {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, + {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5500, 100, IEEE80211_CH_PASSIVE_ONLY}, + {5520, 104, IEEE80211_CH_PASSIVE_ONLY}, + {5540, 108, IEEE80211_CH_PASSIVE_ONLY}, + {5560, 112, IEEE80211_CH_PASSIVE_ONLY}, + {5580, 116, IEEE80211_CH_PASSIVE_ONLY}, + {5600, 120, IEEE80211_CH_PASSIVE_ONLY}, + {5620, 124, IEEE80211_CH_PASSIVE_ONLY}, + {5640, 128, IEEE80211_CH_PASSIVE_ONLY}, + {5660, 132, IEEE80211_CH_PASSIVE_ONLY}, + {5680, 136, IEEE80211_CH_PASSIVE_ONLY}, + {5700, 140, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, + {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, + {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, + {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, + {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + }, + + { /* Europe */ + "ZZL", + .bg_channels = 11, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}}, + .a_channels = 13, + .a = {{5180, 36, IEEE80211_CH_PASSIVE_ONLY}, + {5200, 40, IEEE80211_CH_PASSIVE_ONLY}, + {5220, 44, IEEE80211_CH_PASSIVE_ONLY}, + {5240, 48, IEEE80211_CH_PASSIVE_ONLY}, + {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, + {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, + {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, + {5320, 64, IEEE80211_CH_PASSIVE_ONLY}, + {5745, 149, IEEE80211_CH_PASSIVE_ONLY}, + {5765, 153, IEEE80211_CH_PASSIVE_ONLY}, + {5785, 157, IEEE80211_CH_PASSIVE_ONLY}, + {5805, 161, IEEE80211_CH_PASSIVE_ONLY}, + {5825, 165, IEEE80211_CH_PASSIVE_ONLY}}, + } }; #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { - int rc, i; + int rc, i, j; if (priv->status & STATUS_EXIT_PENDING) return -EIO; @@ -10414,9 +10642,20 @@ static int ipw_up(struct ipw_priv *priv) eeprom_parse_mac(priv, priv->mac_addr); memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); - memcpy(priv->country, &priv->eeprom[EEPROM_COUNTRY_CODE], 3); - priv->country[3] = '\0'; - ieee80211_set_geo(priv->ieee, &ipw_geo); + for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) { + if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE], + ipw_geos[j].name, 3)) + break; + } + if (j == ARRAY_SIZE(ipw_geos)) + j = 0; + if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { + IPW_WARNING("Could not set geography."); + return 0; + } + + IPW_DEBUG_INFO("Geography %03d [%s] detected.\n", + j, priv->ieee->geo.name); if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); -- cgit v1.2.3-59-g8ed1b From 87b016cb64b267a6f791494a4cfd84e84e022ebb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 5 Aug 2005 17:17:35 +0800 Subject: Workaround kernel BUG_ON panic caused by unexpected duplicate packets. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 6e79ae24ee1c..483993a4ca4b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7696,7 +7696,6 @@ static inline int is_network_packet(struct ipw_priv *priv, static inline int is_duplicate_packet(struct ipw_priv *priv, struct ieee80211_hdr_4addr *header) { - u16 fc = le16_to_cpu(header->frame_ctl); u16 sc = le16_to_cpu(header->seq_ctl); u16 seq = WLAN_GET_SEQ_SEQ(sc); u16 frag = WLAN_GET_SEQ_FRAG(sc); @@ -7760,7 +7759,10 @@ static inline int is_duplicate_packet(struct ipw_priv *priv, return 0; drop: - BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); + /* Comment this line now since we observed the card receives + * duplicate packets but the FCTL_RETRY bit is not set in the + * IBSS mode with fragmentation enabled. + BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */ return 1; } -- cgit v1.2.3-59-g8ed1b From e402c9374112aaf1fc5796013dc3040ebb3954ca Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 5 Aug 2005 17:20:40 +0800 Subject: Disable host fragmentation in open mode since IPW2200/2915 hardware support hardware fragmentation. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 483993a4ca4b..f8dac52df93a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8069,6 +8069,9 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) } IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); + /* IPW2200/2915 is abled to do hardware fragmentation. */ + priv->ieee->host_open_frag = 0; + if ((priv->pci_dev->device == 0x4223) || (priv->pci_dev->device == 0x4224)) { if (init) -- cgit v1.2.3-59-g8ed1b From 1fbfea549f07f1f7afd436f1e45b25437f0172c2 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 5 Aug 2005 17:22:56 +0800 Subject: [Bug 792] Fix WPA-PSK AES both for -Dipw and -Dwext. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 141 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 125 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f8dac52df93a..c6da5f534250 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5557,6 +5557,55 @@ static void ipw_send_wep_keys(struct ipw_priv *priv, int type) } } +static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level) +{ + if (priv->ieee->host_encrypt) + return; + + switch (level) { + case SEC_LEVEL_3: + priv->sys_config.disable_unicast_decryption = 0; + priv->ieee->host_decrypt = 0; + break; + case SEC_LEVEL_2: + priv->sys_config.disable_unicast_decryption = 1; + priv->ieee->host_decrypt = 1; + break; + case SEC_LEVEL_1: + priv->sys_config.disable_unicast_decryption = 0; + priv->ieee->host_decrypt = 0; + break; + case SEC_LEVEL_0: + priv->sys_config.disable_unicast_decryption = 1; + break; + default: + break; + } +} + +static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level) +{ + if (priv->ieee->host_encrypt) + return; + + switch (level) { + case SEC_LEVEL_3: + priv->sys_config.disable_multicast_decryption = 0; + break; + case SEC_LEVEL_2: + priv->sys_config.disable_multicast_decryption = 1; + break; + case SEC_LEVEL_1: + priv->sys_config.disable_multicast_decryption = 0; + break; + case SEC_LEVEL_0: + priv->sys_config.disable_multicast_decryption = 1; + break; + default: + break; + } +} + static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) { switch (priv->ieee->sec.level) { @@ -5567,33 +5616,23 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) priv->ieee->sec.active_key); ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); - priv->sys_config.disable_unicast_decryption = 0; - priv->sys_config.disable_multicast_decryption = 0; - priv->ieee->host_decrypt = 0; break; case SEC_LEVEL_2: if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_TKIP, priv->ieee->sec.active_key); - - priv->sys_config.disable_unicast_decryption = 1; - priv->sys_config.disable_multicast_decryption = 1; - priv->ieee->host_decrypt = 1; break; case SEC_LEVEL_1: ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); - priv->sys_config.disable_unicast_decryption = 0; - priv->sys_config.disable_multicast_decryption = 0; - priv->ieee->host_decrypt = 0; break; case SEC_LEVEL_0: - priv->sys_config.disable_unicast_decryption = 1; - priv->sys_config.disable_multicast_decryption = 1; - break; default: break; } + + ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level); + ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level); } static void ipw_adhoc_check(void *data) @@ -6185,12 +6224,31 @@ static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) return ret; } +static int ipw_wpa_ie_cipher2level(u8 cipher) +{ + switch (cipher) { + case 4: /* CCMP */ + return SEC_LEVEL_3; + case 2: /* TKIP */ + return SEC_LEVEL_2; + case 5: /* WEP104 */ + case 1: /* WEP40 */ + return SEC_LEVEL_1; + case 0: /* NONE */ + return SEC_LEVEL_0; + default: + return -1; + } +} + static int ipw_wpa_set_wpa_ie(struct net_device *dev, struct ipw_param *param, int plen) { struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; u8 *buf; + u8 *ptk, *gtk; + int level; if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) @@ -6209,8 +6267,35 @@ static int ipw_wpa_set_wpa_ie(struct net_device *dev, kfree(ieee->wpa_ie); ieee->wpa_ie = NULL; ieee->wpa_ie_len = 0; + goto done; + } + + if (priv->ieee->host_encrypt) + goto done; + + /* HACK: Parse wpa_ie here to get pairwise suite, otherwise + * we need to change driver_ipw.c from wpa_supplicant. This + * is OK since -Dipw is deprecated. The -Dwext driver has a + * clean way to handle this. */ + gtk = ptk = (u8 *) ieee->wpa_ie; + if (ieee->wpa_ie[0] == 0x30) { /* RSN IE */ + gtk += 4 + 3; + ptk += 4 + 4 + 2 + 3; + } else { /* WPA IE */ + gtk += 8 + 3; + ptk += 8 + 4 + 2 + 3; } + if (ptk - (u8 *) ieee->wpa_ie > ieee->wpa_ie_len) + return -EINVAL; + + level = ipw_wpa_ie_cipher2level(*gtk); + ipw_set_hw_decrypt_multicast(priv, level); + + level = ipw_wpa_ie_cipher2level(*ptk); + ipw_set_hw_decrypt_unicast(priv, level); + + done: ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); return 0; } @@ -6510,6 +6595,23 @@ static int ipw_wx_get_genie(struct net_device *dev, return err; } +static int wext_cipher2level(int cipher) +{ + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + return SEC_LEVEL_0; + case IW_AUTH_CIPHER_WEP40: + case IW_AUTH_CIPHER_WEP104: + return SEC_LEVEL_1; + case IW_AUTH_CIPHER_TKIP: + return SEC_LEVEL_2; + case IW_AUTH_CIPHER_CCMP: + return SEC_LEVEL_3; + default: + return -1; + } +} + /* SIOCSIWAUTH */ static int ipw_wx_set_auth(struct net_device *dev, struct iw_request_info *info, @@ -6524,8 +6626,15 @@ static int ipw_wx_set_auth(struct net_device *dev, switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: + break; case IW_AUTH_CIPHER_PAIRWISE: + ipw_set_hw_decrypt_unicast(priv, + wext_cipher2level(param->value)); + break; case IW_AUTH_CIPHER_GROUP: + ipw_set_hw_decrypt_multicast(priv, + wext_cipher2level(param->value)); + break; case IW_AUTH_KEY_MGMT: /* * ipw2200 does not use these parameters @@ -10256,11 +10365,11 @@ static void shim__set_security(struct net_device *dev, priv->ieee->sec.level = sec->level; priv->ieee->sec.flags |= SEC_LEVEL; priv->status |= STATUS_SECURITY_UPDATED; - - if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) - ipw_set_hwcrypto_keys(priv); } + if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT)) + ipw_set_hwcrypto_keys(priv); + /* To match current functionality of ipw2100 (which works well w/ * various supplicants, we don't force a disassociate if the * privacy capability changes ... */ -- cgit v1.2.3-59-g8ed1b From caeff81b4e6479884f3cd2ced526bebd4f0c5eff Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Fri, 5 Aug 2005 17:25:50 +0800 Subject: Fixes the ad-hoc network WEP key list issue. If we configure the wep keys after creating the ibss network, the beacons of this network will not show correctly (it still shows "key off" in iwlist scan report). This is because we don't update the beacon info in firmware. Signed-off-by: Hong Liu Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index c6da5f534250..626e78a336eb 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9169,11 +9169,19 @@ static int ipw_wx_set_encode(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int ret; + u32 cap = priv->capability; down(&priv->sem); ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); - up(&priv->sem); + /* In IBSS mode, we need to notify the firmware to update + * the beacon info after we changed the capability. */ + if (cap != priv->capability && + priv->ieee->iw_mode == IW_MODE_ADHOC && + priv->status & STATUS_ASSOCIATED) + ipw_disassociate(priv); + + up(&priv->sem); return ret; } -- cgit v1.2.3-59-g8ed1b From 0ece35b557c5097c90df9e8fbf47e4da46377df1 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 5 Aug 2005 17:26:51 +0800 Subject: [Bug 701] Fix a misuse of ieee->mode with ieee->iw_mode. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 626e78a336eb..2633e0de7f79 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8223,7 +8223,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) priv->power_mode = IPW_POWER_AC; priv->tx_power = IPW_TX_POWER_DEFAULT; - return old_mode == priv->ieee->mode; + return old_mode == priv->ieee->iw_mode; } /* -- cgit v1.2.3-59-g8ed1b From 22501c8ed70398178e8c8d55e65da97b7e7fb610 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 11 Aug 2005 10:49:17 +0800 Subject: Fix ipw_wx_get_txpow shows wrong disabled value. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 2633e0de7f79..105b1146f396 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8957,7 +8957,7 @@ static int ipw_wx_get_txpow(struct net_device *dev, up(&priv->sem); IPW_DEBUG_WX("GET TX Power -> %s %d \n", - wrqu->power.disabled ? "ON" : "OFF", wrqu->power.value); + wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); return 0; } -- cgit v1.2.3-59-g8ed1b From 6de9f7f27defe6f1a2d33d0b78af6b1a0ad18330 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 11 Aug 2005 14:39:33 +0800 Subject: Fix firmware error when setting tx_power. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 131 +++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 76 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 105b1146f396..f825aa462c99 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2084,6 +2084,50 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) return 0; } +static int ipw_set_tx_power(struct ipw_priv *priv) +{ + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + struct ipw_tx_power tx_power; + s8 max_power; + int i; + + memset(&tx_power, 0, sizeof(tx_power)); + + /* configure device for 'G' band */ + tx_power.ieee_mode = IPW_G_MODE; + tx_power.num_channels = geo->bg_channels; + for (i = 0; i < geo->bg_channels; i++) { + max_power = geo->bg[i].max_power; + tx_power.channels_tx_power[i].channel_number = + geo->bg[i].channel; + tx_power.channels_tx_power[i].tx_power = max_power ? + min(max_power, priv->tx_power) : priv->tx_power; + } + if (ipw_send_tx_power(priv, &tx_power)) + return -EIO; + + /* configure device to also handle 'B' band */ + tx_power.ieee_mode = IPW_B_MODE; + if (ipw_send_tx_power(priv, &tx_power)) + return -EIO; + + /* configure device to also handle 'A' band */ + if (priv->ieee->abg_true) { + tx_power.ieee_mode = IPW_A_MODE; + tx_power.num_channels = geo->a_channels; + for (i = 0; i < tx_power.num_channels; i++) { + max_power = geo->a[i].max_power; + tx_power.channels_tx_power[i].channel_number = + geo->a[i].channel; + tx_power.channels_tx_power[i].tx_power = max_power ? + min(max_power, priv->tx_power) : priv->tx_power; + } + if (ipw_send_tx_power(priv, &tx_power)) + return -EIO; + } + return 0; +} + static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) { struct ipw_rts_threshold rts_threshold = { @@ -8869,79 +8913,33 @@ static int ipw_wx_set_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); - struct ipw_tx_power tx_power; - int i; + int err = 0; down(&priv->sem); if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { - up(&priv->sem); - return -EINPROGRESS; + err = -EINPROGRESS; + goto out; } if (!wrqu->power.fixed) wrqu->power.value = IPW_TX_POWER_DEFAULT; if (wrqu->power.flags != IW_TXPOW_DBM) { - up(&priv->sem); - return -EINVAL; + err = -EINVAL; + goto out; } if ((wrqu->power.value > IPW_TX_POWER_MAX) || (wrqu->power.value < IPW_TX_POWER_MIN)) { - up(&priv->sem); - return -EINVAL; + err = -EINVAL; + goto out; } priv->tx_power = wrqu->power.value; - - memset(&tx_power, 0, sizeof(tx_power)); - - /* configure device for 'G' band */ - tx_power.ieee_mode = IPW_G_MODE; - tx_power.num_channels = geo->bg_channels; - for (i = 0; i < geo->bg_channels; i++) { - int max_power = geo->bg[i].max_power; - - tx_power.channels_tx_power[i].channel_number = i + 1; - if (max_power != 0 && priv->tx_power > max_power) - tx_power.channels_tx_power[i].tx_power = max_power; - else - tx_power.channels_tx_power[i].tx_power = priv->tx_power; - } - if (ipw_send_tx_power(priv, &tx_power)) - goto error; - - /* configure device to also handle 'B' band */ - tx_power.ieee_mode = IPW_B_MODE; - if (ipw_send_tx_power(priv, &tx_power)) - goto error; - - /* configure device to also handle 'A' band */ - if (priv->ieee->abg_true) { - tx_power.ieee_mode = IPW_A_MODE; - tx_power.num_channels = geo->a_channels; - for (i = 0; i < geo->a_channels; i++) { - int max_power = geo->a[i].max_power; - - tx_power.channels_tx_power[i].channel_number = i + 1; - if (max_power != 0 && priv->tx_power > max_power) - tx_power.channels_tx_power[i].tx_power = - max_power; - else - tx_power.channels_tx_power[i].tx_power = - priv->tx_power; - } - if (ipw_send_tx_power(priv, &tx_power)) - goto error; - } - - up(&priv->sem); - return 0; - - error: + err = ipw_set_tx_power(priv); + out: up(&priv->sem); - return -EIO; + return err; } static int ipw_wx_get_txpow(struct net_device *dev, @@ -10426,29 +10424,10 @@ static int init_supported_rates(struct ipw_priv *priv, static int ipw_config(struct ipw_priv *priv) { - int i; - struct ipw_tx_power tx_power; - - memset(&priv->sys_config, 0, sizeof(priv->sys_config)); - memset(&tx_power, 0, sizeof(tx_power)); - /* This is only called from ipw_up, which resets/reloads the firmware so, we don't need to first disable the card before we configure it */ - - /* configure device for 'G' band */ - tx_power.ieee_mode = IPW_G_MODE; - tx_power.num_channels = 11; - for (i = 0; i < 11; i++) { - tx_power.channels_tx_power[i].channel_number = i + 1; - tx_power.channels_tx_power[i].tx_power = priv->tx_power; - } - if (ipw_send_tx_power(priv, &tx_power)) - goto error; - - /* configure device to also handle 'B' band */ - tx_power.ieee_mode = IPW_B_MODE; - if (ipw_send_tx_power(priv, &tx_power)) + if (ipw_set_tx_power(priv)) goto error; /* initialize adapter address */ -- cgit v1.2.3-59-g8ed1b From e666619e232308c8ee2aba6b87f28ad26b38d905 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Fri, 12 Aug 2005 09:17:04 -0500 Subject: Modified ipw_config and STATUS_INIT setting to correct race condition with request_scan being called before initialized if invoked from insmod, resulting in no association occurring during boot until iwlist scan is run. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f825aa462c99..6e862c2905de 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -10465,9 +10465,17 @@ static int ipw_config(struct ipw_priv *priv) if (ipw_send_host_complete(priv)) goto error; - /* If configured to try and auto-associate, kick off a scan */ - if (priv->config & CFG_ASSOCIATE) - queue_work(priv->workqueue, &priv->request_scan); + priv->status |= STATUS_INIT; + + ipw_led_init(priv); + ipw_led_radio_on(priv); + priv->notif_missed_beacons = 0; + + /* Set hardware WEP key if it is configured. */ + if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.level == SEC_LEVEL_1) && + !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) + ipw_set_hwcrypto_keys(priv); return 0; @@ -10773,17 +10781,10 @@ static int ipw_up(struct ipw_priv *priv) rc = ipw_config(priv); if (!rc) { IPW_DEBUG_INFO("Configured device on count %i\n", i); - ipw_led_init(priv); - ipw_led_radio_on(priv); - priv->notif_missed_beacons = 0; - priv->status |= STATUS_INIT; - - /* Set hardware WEP key if it is configured. */ - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.level == SEC_LEVEL_1) && - !(priv->ieee->host_encrypt || - priv->ieee->host_decrypt)) - ipw_set_hwcrypto_keys(priv); + + /* If configure to try and auto-associate, kick + * off a scan. */ + queue_work(priv->workqueue, &priv->request_scan); return 0; } -- cgit v1.2.3-59-g8ed1b From b39860c60b135ef16c1c16a3e2a757ff8070c5ad Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Fri, 12 Aug 2005 09:36:32 -0500 Subject: Switched firmware error dumping so that it will capture a log available via sysfs even if debugging disabled. When a firmware error is captured, it will be dumped to the kernel log (if debug enabled) and captured in memory to be retrieved via sysfs. If an error has already been captured, subsequent errors will be dropped. The existing error can be cleared by writing to the error log entry. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 251 ++++++++++++++++++++++++++++------------- drivers/net/wireless/ipw2200.h | 30 ++++- 2 files changed, 204 insertions(+), 77 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 6e862c2905de..a3283caaa872 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -428,6 +428,7 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv) ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL); } +#ifdef CONFIG_IPW_DEBUG static char *ipw_error_desc(u32 val) { switch (val) { @@ -466,56 +467,35 @@ static char *ipw_error_desc(u32 val) } } -static void ipw_dump_nic_error_log(struct ipw_priv *priv) +static void ipw_dump_error_log(struct ipw_priv *priv, + struct ipw_fw_error *error) { - u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base; - - base = ipw_read32(priv, IPWSTATUS_ERROR_LOG); - count = ipw_read_reg32(priv, base); + u32 i; - if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { - IPW_ERROR("Start IPW Error Log Dump:\n"); - IPW_ERROR("Status: 0x%08X, Config: %08X\n", - priv->status, priv->config); + if (!error) { + IPW_ERROR("Error allocating and capturing error log. " + "Nothing to dump.\n"); + return; } - for (i = ERROR_START_OFFSET; - i <= count * ERROR_ELEM_SIZE; i += ERROR_ELEM_SIZE) { - desc = ipw_read_reg32(priv, base + i); - time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32)); - blink1 = ipw_read_reg32(priv, base + i + 2 * sizeof(u32)); - blink2 = ipw_read_reg32(priv, base + i + 3 * sizeof(u32)); - ilink1 = ipw_read_reg32(priv, base + i + 4 * sizeof(u32)); - ilink2 = ipw_read_reg32(priv, base + i + 5 * sizeof(u32)); - idata = ipw_read_reg32(priv, base + i + 6 * sizeof(u32)); + IPW_ERROR("Start IPW Error Log Dump:\n"); + IPW_ERROR("Status: 0x%08X, Config: %08X\n", + error->status, error->config); + for (i = 0; i < error->elem_len; i++) IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", - ipw_error_desc(desc), time, blink1, blink2, - ilink1, ilink2, idata); - } + ipw_error_desc(error->elem[i].desc), + error->elem[i].time, + error->elem[i].blink1, + error->elem[i].blink2, + error->elem[i].link1, + error->elem[i].link2, error->elem[i].data); + for (i = 0; i < error->log_len; i++) + IPW_ERROR("%i\t0x%08x\t%i\n", + error->log[i].time, + error->log[i].event, error->log[i].data); } - -static void ipw_dump_nic_event_log(struct ipw_priv *priv) -{ - u32 ev, time, data, i, count, base; - - base = ipw_read32(priv, IPW_EVENT_LOG); - count = ipw_read_reg32(priv, base); - - if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE) - IPW_ERROR("Start IPW Event Log Dump:\n"); - - for (i = EVENT_START_OFFSET; - i <= count * EVENT_ELEM_SIZE; i += EVENT_ELEM_SIZE) { - ev = ipw_read_reg32(priv, base + i); - time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32)); - data = ipw_read_reg32(priv, base + i + 2 * sizeof(u32)); - -#ifdef CONFIG_IPW_DEBUG - IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev); #endif - } -} static inline int ipw_is_init(struct ipw_priv *priv) { @@ -1058,6 +1038,130 @@ static ssize_t store_debug_level(struct device_driver *d, const char *buf, static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, store_debug_level); +static inline u32 ipw_get_event_log_len(struct ipw_priv *priv) +{ + return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG)); +} + +static void ipw_capture_event_log(struct ipw_priv *priv, + u32 log_len, struct ipw_event *log) +{ + u32 base; + + if (log_len) { + base = ipw_read32(priv, IPW_EVENT_LOG); + ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32), + (u8 *) log, sizeof(*log) * log_len); + } +} + +static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv) +{ + struct ipw_fw_error *error; + u32 log_len = ipw_get_event_log_len(priv); + u32 base = ipw_read32(priv, IPW_ERROR_LOG); + u32 elem_len = ipw_read_reg32(priv, base); + + error = kmalloc(sizeof(*error) + + sizeof(*error->elem) * elem_len + + sizeof(*error->log) * log_len, GFP_ATOMIC); + if (!error) { + IPW_ERROR("Memory allocation for firmware error log " + "failed.\n"); + return NULL; + } + error->status = priv->status; + error->config = priv->config; + error->elem_len = elem_len; + error->log_len = log_len; + error->elem = (struct ipw_error_elem *)error->payload; + error->log = (struct ipw_event *)(error->elem + + (sizeof(*error->elem) * elem_len)); + + ipw_capture_event_log(priv, log_len, error->log); + + if (elem_len) + ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem, + sizeof(*error->elem) * elem_len); + + return error; +} + +static void ipw_free_error_log(struct ipw_fw_error *error) +{ + if (error) + kfree(error); +} + +static ssize_t show_event_log(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + u32 log_len = ipw_get_event_log_len(priv); + struct ipw_event log[log_len]; + u32 len = 0, i; + + ipw_capture_event_log(priv, log_len, log); + + len += snprintf(buf + len, PAGE_SIZE - len, "%08X", log_len); + for (i = 0; i < log_len; i++) + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X%08X%08X", + log[i].time, log[i].event, log[i].data); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} + +static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL); + +static ssize_t show_error(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + u32 len = 0, i; + if (!priv->error) + return 0; + len += snprintf(buf + len, PAGE_SIZE - len, + "%08X%08X%08X", + priv->error->status, + priv->error->config, priv->error->elem_len); + for (i = 0; i < priv->error->elem_len; i++) + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X%08X%08X%08X%08X%08X%08X", + priv->error->elem[i].time, + priv->error->elem[i].desc, + priv->error->elem[i].blink1, + priv->error->elem[i].blink2, + priv->error->elem[i].link1, + priv->error->elem[i].link2, + priv->error->elem[i].data); + + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X", priv->error->log_len); + for (i = 0; i < priv->error->log_len; i++) + len += snprintf(buf + len, PAGE_SIZE - len, + "\n%08X%08X%08X", + priv->error->log[i].time, + priv->error->log[i].event, + priv->error->log[i].data); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} + +static ssize_t clear_error(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + if (priv->error) { + ipw_free_error_log(priv->error); + priv->error = NULL; + } + return count; +} + +static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error); + static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, char *buf) { @@ -1163,34 +1267,6 @@ static ssize_t show_nic_type(struct device *d, static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); -static ssize_t dump_error_log(struct device *d, - struct device_attribute *attr, const char *buf, - size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - ipw_dump_nic_error_log((struct ipw_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log); - -static ssize_t dump_event_log(struct device *d, - struct device_attribute *attr, const char *buf, - size_t count) -{ - char *p = (char *)buf; - - if (p[0] == '1') - ipw_dump_nic_event_log((struct ipw_priv *)d->driver_data); - - return strnlen(buf, count); -} - -static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); - static ssize_t show_ucode_version(struct device *d, struct device_attribute *attr, char *buf) { @@ -1614,12 +1690,30 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) if (inta & IPW_INTA_BIT_FATAL_ERROR) { IPW_ERROR("Firmware error detected. Restarting.\n"); + if (priv->error) { + IPW_ERROR("Sysfs 'error' log already exists.\n"); #ifdef CONFIG_IPW_DEBUG - if (ipw_debug_level & IPW_DL_FW_ERRORS) { - ipw_dump_nic_error_log(priv); - ipw_dump_nic_event_log(priv); - } + if (ipw_debug_level & IPW_DL_FW_ERRORS) { + struct ipw_fw_error *error = + ipw_alloc_error_log(priv); + ipw_dump_error_log(priv, error); + if (error) + ipw_free_error_log(error); + } +#endif + } else { + priv->error = ipw_alloc_error_log(priv); + if (priv->error) + IPW_ERROR("Sysfs 'error' log captured.\n"); + else + IPW_ERROR("Error allocating sysfs 'error' " + "log.\n"); +#ifdef CONFIG_IPW_DEBUG + if (ipw_debug_level & IPW_DL_FW_ERRORS) + ipw_dump_error_log(priv, priv->error); #endif + } + /* XXX: If hardware encryption is for WPA/WPA2, * we have to notify the supplicant. */ if (priv->ieee->sec.encrypt) { @@ -10958,8 +11052,8 @@ static struct attribute *ipw_sysfs_entries[] = { &dev_attr_nic_type.attr, &dev_attr_status.attr, &dev_attr_cfg.attr, - &dev_attr_dump_errors.attr, - &dev_attr_dump_events.attr, + &dev_attr_error.attr, + &dev_attr_event_log.attr, &dev_attr_eeprom_delay.attr, &dev_attr_ucode_version.attr, &dev_attr_rtc.attr, @@ -11172,6 +11266,11 @@ static void ipw_pci_remove(struct pci_dev *pdev) } } + if (priv->error) { + ipw_free_error_log(priv->error); + priv->error = NULL; + } + free_irq(pdev->irq, priv); iounmap(priv->hw_base); pci_release_regions(pdev); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 9bf8aa427d8c..9bf03ac55390 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1085,6 +1085,32 @@ struct ipw_ibss_seq { struct list_head list; }; +struct ipw_error_elem { + u32 desc; + u32 time; + u32 blink1; + u32 blink2; + u32 link1; + u32 link2; + u32 data; +}; + +struct ipw_event { + u32 event; + u32 time; + u32 data; +} __attribute__ ((packed)); + +struct ipw_fw_error { + u32 status; + u32 config; + u32 elem_len; + u32 log_len; + struct ipw_error_elem *elem; + struct ipw_event *log; + u8 payload[0]; +} __attribute__ ((packed)); + struct ipw_priv { /* ieee device used by generic ieee processing code */ struct ieee80211_device *ieee; @@ -1245,6 +1271,8 @@ struct ipw_priv { u32 pm_state[16]; #endif + struct ipw_fw_error *error; + /* network state */ /* Used to pass the current INTA value from ISR to Tasklet */ @@ -1803,7 +1831,7 @@ enum { IPW_ORD_TABLE_7_LAST }; -#define IPWSTATUS_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410) +#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410) #define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414) #define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500) #define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180) -- cgit v1.2.3-59-g8ed1b From 9ddf84f6f20335ce896feb459b19c3258bbf2e96 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 16 Aug 2005 17:07:11 -0500 Subject: Changed all of the ipw_send_cmd() calls to return any ipw_send_cmd error codes to the caller and changed ipw_send_cmd itself to print the error message to the syslog indicating which command failed to be sent. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 187 ++++++++--------------------------------- 1 file changed, 34 insertions(+), 153 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index a3283caaa872..ef1007785030 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1817,9 +1817,10 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { - IPW_ERROR("Already sending a command\n"); + IPW_ERROR("Failed to send %s: Already sending a command.\n", + get_cmd_string(cmd->cmd)); spin_unlock_irqrestore(&priv->lock, flags); - return -1; + return -EAGAIN; } priv->status |= STATUS_HCMD_ACTIVE; @@ -1832,6 +1833,8 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); if (rc) { priv->status &= ~STATUS_HCMD_ACTIVE; + IPW_ERROR("Failed to send %s: Reason %d\n", + get_cmd_string(cmd->cmd), rc); spin_unlock_irqrestore(&priv->lock, flags); return rc; } @@ -1844,9 +1847,8 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) if (rc == 0) { spin_lock_irqsave(&priv->lock, flags); if (priv->status & STATUS_HCMD_ACTIVE) { - IPW_DEBUG_INFO("Command completion failed out after " - "%dms.\n", - 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); + IPW_ERROR("Failed to send %s: Command timed out.\n", + get_cmd_string(cmd->cmd)); priv->status &= ~STATUS_HCMD_ACTIVE; spin_unlock_irqrestore(&priv->lock, flags); return -EIO; @@ -1855,7 +1857,8 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) } if (priv->status & STATUS_RF_KILL_HW) { - IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n"); + IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", + get_cmd_string(cmd->cmd)); return -EIO; } @@ -1874,12 +1877,7 @@ static int ipw_send_host_complete(struct ipw_priv *priv) return -1; } - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send HOST_COMPLETE command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_system_config(struct ipw_priv *priv, @@ -1896,12 +1894,7 @@ static int ipw_send_system_config(struct ipw_priv *priv, } memcpy(cmd.param, config, sizeof(*config)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SYSTEM_CONFIG command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) @@ -1917,12 +1910,7 @@ static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) } memcpy(cmd.param, ssid, cmd.len); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SSID command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) @@ -1941,12 +1929,7 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) priv->net_dev->name, MAC_ARG(mac)); memcpy(cmd.param, mac, ETH_ALEN); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send ADAPTER_ADDRESS command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } /* @@ -2011,12 +1994,7 @@ static int ipw_send_scan_request_ext(struct ipw_priv *priv, }; memcpy(cmd.param, request, sizeof(*request)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_scan_abort(struct ipw_priv *priv) @@ -2031,12 +2009,7 @@ static int ipw_send_scan_abort(struct ipw_priv *priv) return -1; } - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SCAN_ABORT command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) @@ -2048,12 +2021,7 @@ static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *) &cmd.param; calib->beacon_rssi_raw = sens; - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SENSITIVITY CALIB command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_associate(struct ipw_priv *priv, @@ -2083,12 +2051,7 @@ static int ipw_send_associate(struct ipw_priv *priv, } memcpy(cmd.param, &tmp_associate, sizeof(*associate)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send ASSOCIATE command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_supported_rates(struct ipw_priv *priv, @@ -2105,12 +2068,7 @@ static int ipw_send_supported_rates(struct ipw_priv *priv, } memcpy(cmd.param, rates, sizeof(*rates)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SUPPORTED_RATES command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_set_random_seed(struct ipw_priv *priv) @@ -2127,12 +2085,7 @@ static int ipw_set_random_seed(struct ipw_priv *priv) get_random_bytes(&cmd.param, sizeof(u32)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send SEED_NUMBER command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) @@ -2149,12 +2102,7 @@ static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) *((u32 *) & cmd.param) = phy_off; - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send CARD_DISABLE command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) @@ -2170,12 +2118,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) } memcpy(cmd.param, power, sizeof(*power)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send TX_POWER command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_set_tx_power(struct ipw_priv *priv) @@ -2238,12 +2181,7 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) } memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send RTS_THRESHOLD command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) @@ -2262,12 +2200,7 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) } memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send FRAG_THRESHOLD command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) @@ -2297,12 +2230,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) break; } - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send POWER_MODE command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) @@ -2322,12 +2250,7 @@ static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) } memcpy(cmd.param, &retry_limit, sizeof(retry_limit)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send RETRY_LIMIT command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } /* @@ -3608,20 +3531,6 @@ static void ipw_tx_queue_free(struct ipw_priv *priv) ipw_queue_tx_free(priv, &priv->txq[3]); } -static void inline __maybe_wake_tx(struct ipw_priv *priv) -{ - if (netif_running(priv->net_dev)) { - switch (priv->port_type) { - case DCR_TYPE_MU_BSS: - case DCR_TYPE_MU_IBSS: - if (!(priv->status & STATUS_ASSOCIATED)) - return; - } - netif_wake_queue(priv->net_dev); - } - -} - static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid) { /* First 3 bytes are manufacturer */ @@ -4713,8 +4622,10 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv, priv->tx_packets++; } done: - if (ipw_queue_space(q) > q->low_mark && qindex >= 0) - __maybe_wake_tx(priv); + if ((ipw_queue_space(q) > q->low_mark) && + (qindex >= 0) && + (priv->status & STATUS_ASSOCIATED) && netif_running(priv->net_dev)) + netif_wake_queue(priv->net_dev); used = q->first_empty - q->last_used; if (used < 0) used += q->n_bd; @@ -5657,10 +5568,7 @@ static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index) key->tx_counter[0] = 0; key->tx_counter[1] = 0; - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send TGI_TX_KEY command\n"); - return; - } + ipw_send_cmd(priv, &cmd); } static void ipw_send_wep_keys(struct ipw_priv *priv, int type) @@ -5688,10 +5596,7 @@ static void ipw_send_wep_keys(struct ipw_priv *priv, int type) key->key_size = priv->ieee->sec.key_sizes[i]; memcpy(key->key, priv->ieee->sec.keys[i], key->key_size); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send WEP_KEY command\n"); - return; - } + ipw_send_cmd(priv, &cmd); } } @@ -6249,11 +6154,7 @@ static int ipw_set_rsn_capa(struct ipw_priv *priv, IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); memcpy(cmd.param, capabilities, length); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); - return -1; - } - return 0; + return ipw_send_cmd(priv, &cmd); } #if WIRELESS_EXT < 18 @@ -7435,18 +7336,8 @@ static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_q .len = (sizeof(struct ieee80211_qos_parameters) * 3) }; - if (!priv || !qos_param) { - IPW_ERROR("Invalid args\n"); - return -1; - } - memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send IPW_CMD_QOS_PARAMETERS command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element @@ -7457,18 +7348,8 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos .len = sizeof(*qos_param) }; - if (!priv || !qos_param) { - IPW_ERROR("Invalid args\n"); - return -1; - } - memcpy(cmd.param, qos_param, sizeof(*qos_param)); - if (ipw_send_cmd(priv, &cmd)) { - IPW_ERROR("failed to send CMD_QOS_INFO command\n"); - return -1; - } - - return 0; + return ipw_send_cmd(priv, &cmd); } #endif /* CONFIG_IPW_QOS */ -- cgit v1.2.3-59-g8ed1b From f6c5cb7c6f8a85045996bfc3442af963d6578d60 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 25 Aug 2005 00:39:09 -0500 Subject: Added cmdlog in non-debug systems. You can now specify via the module parameter 'cmdlog' to allocate a ring buffer for caching host commands sent to the firmware. They can then be dumped at any time via the sysfs entry 'cmd_log' Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 120 ++++++++++++++++++++++++++++++++++++----- drivers/net/wireless/ipw2200.h | 11 ++++ 2 files changed, 117 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index ef1007785030..bcb5993b68bd 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -44,6 +44,7 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); +static int cmdlog = 0; static int debug = 0; static int channel = 0; static int mode = 0; @@ -148,8 +149,8 @@ static int init_supported_rates(struct ipw_priv *priv, static void ipw_set_hwcrypto_keys(struct ipw_priv *); static void ipw_send_wep_keys(struct ipw_priv *, int); -static char *snprint_line(char *buf, size_t count, - const u8 * data, u32 len, u32 ofs) +static int snprint_line(char *buf, size_t count, + const u8 * data, u32 len, u32 ofs) { int out, i, j, l; char c; @@ -180,7 +181,7 @@ static char *snprint_line(char *buf, size_t count, out += snprintf(buf + out, count - out, " "); } - return buf; + return out; } static void printk_buf(int level, const u8 * data, u32 len) @@ -191,14 +192,33 @@ static void printk_buf(int level, const u8 * data, u32 len) return; while (len) { - printk(KERN_DEBUG "%s\n", - snprint_line(line, sizeof(line), &data[ofs], - min(len, 16U), ofs)); + snprint_line(line, sizeof(line), &data[ofs], + min(len, 16U), ofs); + printk(KERN_DEBUG "%s\n", line); ofs += 16; len -= min(len, 16U); } } +static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len) +{ + size_t out = size; + u32 ofs = 0; + int total = 0; + + while (size && len) { + out = snprint_line(output, size, &data[ofs], + min_t(size_t, len, 16U), ofs); + + ofs += 16; + output += out; + size -= out; + len -= min_t(size_t, len, 16U); + total += out; + } + return total; +} + static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); #define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) @@ -272,9 +292,15 @@ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); -#define ipw_read_indirect(a, b, c, d) \ - IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ - _ipw_read_indirect(a, b, c, d) +static inline void __ipw_read_indirect(const char *f, int l, + struct ipw_priv *a, u32 b, u8 * c, int d) +{ + IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b), + d); + _ipw_read_indirect(a, b, c, d); +} + +#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d) static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, int num); @@ -1070,6 +1096,7 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv) "failed.\n"); return NULL; } + error->jiffies = jiffies; error->status = priv->status; error->config = priv->config; error->elem_len = elem_len; @@ -1122,7 +1149,8 @@ static ssize_t show_error(struct device *d, if (!priv->error) return 0; len += snprintf(buf + len, PAGE_SIZE - len, - "%08X%08X%08X", + "%08lX%08X%08X%08X", + priv->error->jiffies, priv->error->status, priv->error->config, priv->error->elem_len); for (i = 0; i < priv->error->elem_len; i++) @@ -1162,6 +1190,33 @@ static ssize_t clear_error(struct device *d, static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error); +static ssize_t show_cmd_log(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct ipw_priv *priv = dev_get_drvdata(d); + u32 len = 0, i; + if (!priv->cmdlog) + return 0; + for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len; + (i != priv->cmdlog_pos) && (PAGE_SIZE - len); + i = (i + 1) % priv->cmdlog_len) { + len += + snprintf(buf + len, PAGE_SIZE - len, + "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies, + priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd, + priv->cmdlog[i].cmd.len); + len += + snprintk_buf(buf + len, PAGE_SIZE - len, + (u8 *) priv->cmdlog[i].cmd.param, + priv->cmdlog[i].cmd.len); + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + return len; +} + +static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); + static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, char *buf) { @@ -1825,6 +1880,15 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) priv->status |= STATUS_HCMD_ACTIVE; + if (priv->cmdlog) { + priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies; + priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd; + priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len; + memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param, + cmd->len); + priv->cmdlog[priv->cmdlog_pos].retcode = -1; + } + IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, priv->status); @@ -1836,7 +1900,7 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) IPW_ERROR("Failed to send %s: Reason %d\n", get_cmd_string(cmd->cmd), rc); spin_unlock_irqrestore(&priv->lock, flags); - return rc; + goto exit; } spin_unlock_irqrestore(&priv->lock, flags); @@ -1851,7 +1915,8 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) get_cmd_string(cmd->cmd)); priv->status &= ~STATUS_HCMD_ACTIVE; spin_unlock_irqrestore(&priv->lock, flags); - return -EIO; + rc = -EIO; + goto exit; } spin_unlock_irqrestore(&priv->lock, flags); } @@ -1859,10 +1924,16 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) if (priv->status & STATUS_RF_KILL_HW) { IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", get_cmd_string(cmd->cmd)); - return -EIO; + rc = -EIO; + goto exit; } - return 0; + exit: + if (priv->cmdlog) { + priv->cmdlog[priv->cmdlog_pos++].retcode = rc; + priv->cmdlog_pos %= priv->cmdlog_len; + } + return rc; } static int ipw_send_host_complete(struct ipw_priv *priv) @@ -10712,6 +10783,18 @@ static int ipw_up(struct ipw_priv *priv) if (priv->status & STATUS_EXIT_PENDING) return -EIO; + if (cmdlog && !priv->cmdlog) { + priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog, + GFP_KERNEL); + if (priv->cmdlog == NULL) { + IPW_ERROR("Error allocating %d command log entries.\n", + cmdlog); + } else { + memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog); + priv->cmdlog_len = cmdlog; + } + } + for (i = 0; i < MAX_HW_RESTARTS; i++) { /* Load the microcode, firmware, and eeprom. * Also start the clocks. */ @@ -10935,6 +11018,7 @@ static struct attribute *ipw_sysfs_entries[] = { &dev_attr_cfg.attr, &dev_attr_error.attr, &dev_attr_event_log.attr, + &dev_attr_cmd_log.attr, &dev_attr_eeprom_delay.attr, &dev_attr_ucode_version.attr, &dev_attr_rtc.attr, @@ -11129,6 +11213,10 @@ static void ipw_pci_remove(struct pci_dev *pdev) } ipw_tx_queue_free(priv); + if (priv->cmdlog) { + kfree(priv->cmdlog); + priv->cmdlog = NULL; + } /* ipw_down will ensure that there is no more pending work * in the workqueue's, so we can safely remove them now. */ cancel_delayed_work(&priv->adhoc_check); @@ -11302,5 +11390,9 @@ MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); module_param(hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)"); +module_param(cmdlog, int, 0444); +MODULE_PARM_DESC(cmdlog, + "allocate a ring buffer for logging firmware commands"); + module_exit(ipw_exit); module_init(ipw_init); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 9bf03ac55390..255f0cb66f64 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1102,6 +1102,7 @@ struct ipw_event { } __attribute__ ((packed)); struct ipw_fw_error { + unsigned long jiffies; u32 status; u32 config; u32 elem_len; @@ -1261,6 +1262,10 @@ struct ipw_priv { struct work_struct led_act_off; struct work_struct merge_networks; + struct ipw_cmd_log *cmdlog; + int cmdlog_len; + int cmdlog_pos; + #define IPW_2200BG 1 #define IPW_2915ABG 2 u8 adapter; @@ -1853,6 +1858,12 @@ struct host_cmd { u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH]; } __attribute__ ((packed)); +struct ipw_cmd_log { + unsigned long jiffies; + int retcode; + struct host_cmd cmd; +}; + #define CFG_BT_COEXISTENCE_MIN 0x00 #define CFG_BT_COEXISTENCE_DEFER 0x02 #define CFG_BT_COEXISTENCE_KILL 0x04 -- cgit v1.2.3-59-g8ed1b From 1fe0adb4314009362d28205bbf09f6d758e82002 Mon Sep 17 00:00:00 2001 From: Liu Hong Date: Fri, 19 Aug 2005 09:33:10 -0500 Subject: Migrated some of the channel verification code back into the driver to keep regulatory consistency in one location. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 173 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 152 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index bcb5993b68bd..40759e5f3cc5 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -149,6 +149,12 @@ static int init_supported_rates(struct ipw_priv *priv, static void ipw_set_hwcrypto_keys(struct ipw_priv *); static void ipw_send_wep_keys(struct ipw_priv *, int); +static int ipw_is_valid_channel(struct ieee80211_device *, u8); +static int ipw_channel_to_index(struct ieee80211_device *, u8); +static u8 ipw_freq_to_channel(struct ieee80211_device *, u32); +static int ipw_set_geo(struct ieee80211_device *, const struct ieee80211_geo *); +static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *); + static int snprint_line(char *buf, size_t count, const u8 * data, u32 len, u32 ofs) { @@ -1596,7 +1602,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, break; } - if (ieee80211_is_valid_channel(priv->ieee, channel)) + if (ipw_is_valid_channel(priv->ieee, channel)) priv->speed_scan[pos++] = channel; else IPW_WARNING("Skipping invalid channel request: %d\n", @@ -2194,7 +2200,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) static int ipw_set_tx_power(struct ipw_priv *priv) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); struct ipw_tx_power tx_power; s8 max_power; int i; @@ -5503,6 +5509,15 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } + /* Filter out invalid channel in current GEO */ + if (!ipw_is_valid_channel(priv->ieee, network->channel)) { + IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + "because of invalid channel in current GEO\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { @@ -5540,7 +5555,7 @@ static int ipw_best_network(struct ipw_priv *priv, static void ipw_adhoc_create(struct ipw_priv *priv, struct ieee80211_network *network) { - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); int i; /* @@ -5555,10 +5570,10 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * FW fatal error. * */ - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + switch (ipw_is_valid_channel(priv->ieee, priv->channel)) { case IEEE80211_52GHZ_BAND: network->mode = IEEE_A; - i = ieee80211_channel_to_index(priv->ieee, priv->channel); + i = ipw_channel_to_index(priv->ieee, priv->channel); if (i == -1) BUG(); if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { @@ -5572,6 +5587,13 @@ static void ipw_adhoc_create(struct ipw_priv *priv, network->mode = IEEE_G; else network->mode = IEEE_B; + i = ipw_channel_to_index(priv->ieee, priv->channel); + if (i == -1) + BUG(); + if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + IPW_WARNING("Overriding invalid channel\n"); + priv->channel = geo->bg[0].channel; + } break; default: @@ -5899,7 +5921,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, const struct ieee80211_geo *geo; int i; - geo = ieee80211_get_geo(priv->ieee); + geo = ipw_get_geo(priv->ieee); if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { int start = channel_index; @@ -5909,7 +5931,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, continue; channel_index++; scan->channels_list[channel_index] = geo->a[i].channel; - ipw_set_scan_type(scan, channel_index, scan_type); + ipw_set_scan_type(scan, channel_index, + geo->a[i]. + flags & IEEE80211_CH_PASSIVE_ONLY ? + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN : + scan_type); } if (start != channel_index) { @@ -5922,6 +5948,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { int start = channel_index; if (priv->config & CFG_SPEED_SCAN) { + int index; u8 channels[IEEE80211_24GHZ_CHANNELS] = { /* nop out the list */ [0] = 0 @@ -5953,8 +5980,14 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, priv->speed_scan_pos++; channel_index++; scan->channels_list[channel_index] = channel; + index = + ipw_channel_to_index(priv->ieee, channel); ipw_set_scan_type(scan, channel_index, - scan_type); + geo->bg[index]. + flags & + IEEE80211_CH_PASSIVE_ONLY ? + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN + : scan_type); } } else { for (i = 0; i < geo->bg_channels; i++) { @@ -5965,7 +5998,11 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, scan->channels_list[channel_index] = geo->bg[i].channel; ipw_set_scan_type(scan, channel_index, - scan_type); + geo->bg[i]. + flags & + IEEE80211_CH_PASSIVE_ONLY ? + IPW_SCAN_PASSIVE_FULL_DWELL_SCAN + : scan_type); } } @@ -6017,7 +6054,7 @@ static int ipw_request_scan(struct ipw_priv *priv) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); @@ -6026,7 +6063,7 @@ static int ipw_request_scan(struct ipw_priv *priv) u8 channel; u8 band = 0; - switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { + switch (ipw_is_valid_channel(priv->ieee, priv->channel)) { case IEEE80211_52GHZ_BAND: band = (u8) (IPW_A_MODE << 6) | 1; channel = priv->channel; @@ -8401,10 +8438,11 @@ static int ipw_wx_set_freq(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); struct iw_freq *fwrq = &wrqu->freq; int ret = 0, i; - u8 channel; + u8 channel, flags; + int band; if (fwrq->m == 0) { IPW_DEBUG_WX("SET Freq/Channel -> any\n"); @@ -8415,20 +8453,23 @@ static int ipw_wx_set_freq(struct net_device *dev, } /* if setting by freq convert to channel */ if (fwrq->e == 1) { - channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); + channel = ipw_freq_to_channel(priv->ieee, fwrq->m); if (channel == 0) return -EINVAL; } else channel = fwrq->m; - if (!ieee80211_is_valid_channel(priv->ieee, channel)) + if (!(band = ipw_is_valid_channel(priv->ieee, channel))) return -EINVAL; - if (priv->ieee->iw_mode == IW_MODE_ADHOC && priv->ieee->mode & IEEE_A) { - i = ieee80211_channel_to_index(priv->ieee, channel); + if (priv->ieee->iw_mode == IW_MODE_ADHOC) { + i = ipw_channel_to_index(priv->ieee, channel); if (i == -1) return -EINVAL; - if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { + + flags = (band == IEEE80211_24GHZ_BAND) ? + geo->bg[i].flags : geo->a[i].flags; + if (flags & IEEE80211_CH_PASSIVE_ONLY) { IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); return -EINVAL; } @@ -8546,7 +8587,7 @@ static int ipw_wx_get_range(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); int i = 0, j; wrqu->data.length = sizeof(*range); @@ -9147,7 +9188,7 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); @@ -10775,6 +10816,96 @@ static const struct ieee80211_geo ipw_geos[] = { } }; +/* GEO code borrowed from ieee80211_geo.c */ +static int ipw_is_valid_channel(struct ieee80211_device *ieee, u8 channel) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + /* NOTE: If G mode is currently supported but + * this is a B only channel, we don't see it + * as valid. */ + if ((ieee->geo.bg[i].channel == channel) && + (!(ieee->mode & IEEE_G) || + !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) + return IEEE80211_24GHZ_BAND; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].channel == channel) + return IEEE80211_52GHZ_BAND; + + return 0; +} + +static int ipw_channel_to_index(struct ieee80211_device *ieee, u8 channel) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + if (ieee->geo.bg[i].channel == channel) + return i; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].channel == channel) + return i; + + return -1; +} + +static u8 ipw_freq_to_channel(struct ieee80211_device *ieee, u32 freq) +{ + int i; + + /* Driver needs to initialize the geography map before using + * these helper functions */ + BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + + freq /= 100000; + + if (ieee->freq_band & IEEE80211_24GHZ_BAND) + for (i = 0; i < ieee->geo.bg_channels; i++) + if (ieee->geo.bg[i].freq == freq) + return ieee->geo.bg[i].channel; + + if (ieee->freq_band & IEEE80211_52GHZ_BAND) + for (i = 0; i < ieee->geo.a_channels; i++) + if (ieee->geo.a[i].freq == freq) + return ieee->geo.a[i].channel; + + return 0; +} + +static int ipw_set_geo(struct ieee80211_device *ieee, + const struct ieee80211_geo *geo) +{ + memcpy(ieee->geo.name, geo->name, 3); + ieee->geo.name[3] = '\0'; + ieee->geo.bg_channels = geo->bg_channels; + ieee->geo.a_channels = geo->a_channels; + memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * + sizeof(struct ieee80211_channel)); + memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * + sizeof(struct ieee80211_channel)); + return 0; +} + +static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *ieee) +{ + return &ieee->geo; +} + #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { @@ -10816,7 +10947,7 @@ static int ipw_up(struct ipw_priv *priv) } if (j == ARRAY_SIZE(ipw_geos)) j = 0; - if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { + if (ipw_set_geo(priv->ieee, &ipw_geos[j])) { IPW_WARNING("Could not set geography."); return 0; } -- cgit v1.2.3-59-g8ed1b From 3b9990cb1751d3d267c0e5c94bff0f155c944c66 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Fri, 19 Aug 2005 13:18:55 -0500 Subject: Updated ipw2200 to use the new ieee80211 callbacks (handle_probe_response, handle_beacon, handle_association_response). Fixed a problem with ipw_send_cmd() returning non-zero on success. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 61 ++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 40759e5f3cc5..53a6bb2dbd4c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1925,7 +1925,8 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) goto exit; } spin_unlock_irqrestore(&priv->lock, flags); - } + } else + rc = 0; if (priv->status & STATUS_RF_KILL_HW) { IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", @@ -7011,9 +7012,9 @@ u8 ipw_qos_current_mode(struct ipw_priv * priv) /* * Handle management frame beacon and probe response */ -static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, - int active_network, - struct ieee80211_network *network) +static int ipw_qos_handle_probe_response(struct ipw_priv *priv, + int active_network, + struct ieee80211_network *network) { u32 size = sizeof(struct ieee80211_qos_parameters); @@ -7407,35 +7408,41 @@ static void ipw_bg_qos_activate(void *data) up(&priv->sem); } -/* -* Handler for probe responce and beacon frame -*/ -static int ipw_handle_management(struct net_device *dev, - struct ieee80211_network *network, u16 type) +static int ipw_handle_probe_response(struct net_device *dev, + struct ieee80211_probe_response *resp, + struct ieee80211_network *network) { struct ipw_priv *priv = ieee80211_priv(dev); - int active_network; + int active_network = ((priv->status & STATUS_ASSOCIATED) && + (network == priv->assoc_network)); - if (priv->status & STATUS_ASSOCIATED && network == priv->assoc_network) - active_network = 1; - else - active_network = 0; + ipw_qos_handle_probe_response(priv, active_network, network); - switch (type) { - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_BEACON: - ipw_qos_handle_probe_reponse(priv, active_network, network); - break; - case IEEE80211_STYPE_ASSOC_RESP: - ipw_qos_association_resp(priv, network); - break; - default: - break; - } + return 0; +} + +static int ipw_handle_beacon(struct net_device *dev, + struct ieee80211_beacon *resp, + struct ieee80211_network *network) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int active_network = ((priv->status & STATUS_ASSOCIATED) && + (network == priv->assoc_network)); + + ipw_qos_handle_probe_response(priv, active_network, network); return 0; } +static int ipw_handle_assoc_response(struct net_device *dev, + struct ieee80211_assoc_response *resp, + struct ieee80211_network *network) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + ipw_qos_association_resp(priv, network); + return 0; +} + static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters *qos_param) { @@ -11260,7 +11267,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->ieee->is_queue_full = ipw_net_is_queue_full; #ifdef CONFIG_IPW_QOS - priv->ieee->handle_management = ipw_handle_management; + priv->ieee->handle_probe_response = ipw_handle_beacon; + priv->ieee->handle_beacon = ipw_handle_probe_response; + priv->ieee->handle_assoc_response = ipw_handle_assoc_response; #endif /* CONFIG_IPW_QOS */ priv->ieee->perfect_rssi = -20; -- cgit v1.2.3-59-g8ed1b From a0e04ab36048eb1c3da2524b5b0b802b6ab064f0 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 25 Aug 2005 00:49:43 -0500 Subject: Added wait_state wakeup on scan completion. Fixed copyright date in ipw2200.h Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 1 + drivers/net/wireless/ipw2200.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 53a6bb2dbd4c..9ced5b778a77 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4450,6 +4450,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); + wake_up_interruptible(&priv->wait_state); cancel_delayed_work(&priv->scan_check); if (priv->status & STATUS_EXIT_PENDING) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 255f0cb66f64..f2056b62254e 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as -- cgit v1.2.3-59-g8ed1b From 7b99659f97ca20e5f1ea56253a9449d278d825d5 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Thu, 25 Aug 2005 17:36:13 +0800 Subject: [Bug 455] Fix frequent channel change generates firmware fatal error. Because of the frequent channel change, it is possible that when we are try to associate with channel 1 (authenticated but not associated). Another channel change comes at this time, then the driver will issue disassociate command to the firmware which will cause the fatal error. It seems that the association/disassociation procedure should not be interrupted. The patch attached adds test on STATUS_ASSOCIATING | STATUS_DISASSOCIATING in ipw_send_cmd(), when ensures that commands will not be sent to firmware when we are in these two status. Signed-off-by: Hong Liu Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 9ced5b778a77..4cdb4748b761 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1884,6 +1884,18 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) return -EAGAIN; } + if (priv->status & STATUS_ASSOCIATING) { + IPW_DEBUG_HC("abandon a command while associating\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return -1; + } + + if (priv->status & STATUS_DISASSOCIATING) { + IPW_DEBUG_HC("abandon a command while disassociating\n"); + spin_unlock_irqrestore(&priv->lock, flags); + return -1; + } + priv->status |= STATUS_HCMD_ACTIVE; if (priv->cmdlog) { @@ -3671,7 +3683,13 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) { int err; - if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) { + if (priv->status & STATUS_ASSOCIATING) { + IPW_DEBUG_ASSOC("Disassociating while associating.\n"); + queue_work(priv->workqueue, &priv->disassociate); + return; + } + + if (!(priv->status & STATUS_ASSOCIATED)) { IPW_DEBUG_ASSOC("Disassociating while not associated.\n"); return; } @@ -3681,9 +3699,6 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) MAC_ARG(priv->assoc_request.bssid), priv->assoc_request.channel); - priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); - priv->status |= STATUS_DISASSOCIATING; - if (quiet) priv->assoc_request.assoc_type = HC_DISASSOC_QUIET; else @@ -3695,6 +3710,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } + priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); + priv->status |= STATUS_DISASSOCIATING; + } static int ipw_disassociate(void *data) @@ -7625,8 +7643,6 @@ static int ipw_associate_network(struct ipw_priv *priv, */ priv->channel = network->channel; memcpy(priv->bssid, network->bssid, ETH_ALEN); - priv->status |= STATUS_ASSOCIATING; - priv->status &= ~STATUS_SECURITY_UPDATED; priv->assoc_network = network; @@ -7640,6 +7656,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } + priv->status |= STATUS_ASSOCIATING; + priv->status &= ~STATUS_SECURITY_UPDATED; + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n", escape_essid(priv->essid, priv->essid_len), MAC_ARG(priv->bssid)); -- cgit v1.2.3-59-g8ed1b From 55135791819270a412dfb99f66301f02c72edadf Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 25 Aug 2005 17:43:14 +0800 Subject: [Bug 760] Fix setting WEP key in monitor mode causes IV lost. Signed-off-by: Zhu Yi --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 4cdb4748b761..bda292f7f82c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7907,7 +7907,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ - if (!priv->ieee->host_decrypt) + if (!priv->ieee->host_decrypt && priv->ieee->iw_mode != IW_MODE_MONITOR) ipw_rebuild_decrypted_skb(priv, rxb->skb); if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) -- cgit v1.2.3-59-g8ed1b From 054b08d48464bfa8e5be69829b59bd599c5dcd72 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Thu, 25 Aug 2005 17:45:49 +0800 Subject: Don't set hardware WEP if we are actually using TKIP/AES. Signed-off-by: Hong Liu --- drivers/net/wireless/ipw2100.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index eaf47078ee56..83ba08c0c33c 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5443,8 +5443,11 @@ static void shim__set_security(struct net_device *dev, else memcpy(priv->ieee->sec.keys[i], sec->keys[i], sec->key_sizes[i]); - priv->ieee->sec.flags |= (1 << i); - priv->status |= STATUS_SECURITY_UPDATED; + if (sec->level == SEC_LEVEL_1) { + priv->ieee->sec.flags |= (1 << i); + priv->status |= STATUS_SECURITY_UPDATED; + } else + priv->ieee->sec.flags &= ~(1 << i); } } -- cgit v1.2.3-59-g8ed1b From a4f6bbb305123c2c42322a10a770be64089a17ca Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 26 Aug 2005 00:33:34 -0500 Subject: Make all the places the firmware fails to load showerrors (in decimal, so you can cross-reference errno.h easily). Signed-off-by: Peter Jones Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index bda292f7f82c..79697e8e8d96 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -3304,7 +3304,7 @@ static int ipw_load(struct ipw_priv *priv) rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), bootfw->size - sizeof(struct fw_header)); if (rc < 0) { - IPW_ERROR("Unable to load boot firmware\n"); + IPW_ERROR("Unable to load boot firmware: %d\n", rc); goto error; } @@ -3327,7 +3327,7 @@ static int ipw_load(struct ipw_priv *priv) rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), ucode->size - sizeof(struct fw_header)); if (rc < 0) { - IPW_ERROR("Unable to load ucode\n"); + IPW_ERROR("Unable to load ucode: %d\n", rc); goto error; } @@ -3339,7 +3339,7 @@ static int ipw_load(struct ipw_priv *priv) sizeof(struct fw_header), firmware->size - sizeof(struct fw_header)); if (rc < 0) { - IPW_ERROR("Unable to load firmware\n"); + IPW_ERROR("Unable to load firmware: %d\n", rc); goto error; } @@ -10958,7 +10958,7 @@ static int ipw_up(struct ipw_priv *priv) * Also start the clocks. */ rc = ipw_load(priv); if (rc) { - IPW_ERROR("Unable to load firmware: 0x%08X\n", rc); + IPW_ERROR("Unable to load firmware: %d\n", rc); return rc; } -- cgit v1.2.3-59-g8ed1b From 24a47dbd89a2738bc149de4685ae5a2a97193ae1 Mon Sep 17 00:00:00 2001 From: Mike Kershaw Date: Fri, 26 Aug 2005 00:41:54 -0500 Subject: Adds radiotap support to ipw2200 in monitor mode.. Signed-off-by: Mike Kershaw Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 185 +++++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/ipw2200.h | 1 + 2 files changed, 186 insertions(+) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 79697e8e8d96..86a4c2358f9d 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7918,6 +7918,173 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, } } +#ifdef CONFIG_IEEE80211_RADIOTAP +static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, + struct ipw_rx_mem_buffer *rxb, + struct ieee80211_rx_stats *stats) +{ + struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; + struct ipw_rx_frame *frame = &pkt->u.frame; + + /* initial pull of some data */ + u16 received_channel = frame->received_channel; + u8 antennaAndPhy = frame->antennaAndPhy; + s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */ + u16 pktrate = frame->rate; + + /* Magic struct that slots into the radiotap header -- no reason + * to build this manually element by element, we can write it much + * more efficiently than we can parse it. ORDER MATTERS HERE */ + struct ipw_rt_hdr { + struct ieee80211_radiotap_header rt_hdr; + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + u16 rt_channel; /* channel in mhz */ + u16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ + u8 rt_antenna; /* antenna number */ + } *ipw_rt; + + short len = le16_to_cpu(pkt->u.frame.length); + + /* We received data from the HW, so stop the watchdog */ + priv->net_dev->trans_start = jiffies; + + /* We only process data packets if the + * interface is open */ + if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > + skb_tailroom(rxb->skb))) { + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Corruption detected! Oh no!\n"); + return; + } else if (unlikely(!netif_running(priv->net_dev))) { + priv->ieee->stats.rx_dropped++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use + * that now */ + if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) { + /* FIXME: Should alloc bigger skb instead */ + priv->ieee->stats.rx_dropped++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping too large packet in monitor\n"); + return; + } + + /* copy the frame itself */ + memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), + rxb->skb->data + IPW_RX_FRAME_SIZE, len); + + /* Zero the radiotap static buffer ... We only need to zero the bytes NOT + * part of our real header, saves a little time. + * + * No longer necessary since we fill in all our data. Purge before merging + * patch officially. + * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, + * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); + */ + + ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; + + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ + ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ + + /* Big bitfield of all the fields we provide in radiotap */ + ipw_rt->rt_hdr.it_present = + ((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_ANTENNA)); + + /* Zero the flags, we'll add to them as we go */ + ipw_rt->rt_flags = 0; + + /* Convert signal to DBM */ + ipw_rt->rt_dbmsignal = antsignal; + + /* Convert the channel data and set the flags */ + ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel)); + if (received_channel > 14) { /* 802.11a */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); + } else if (antennaAndPhy & 32) { /* 802.11b */ + ipw_rt->rt_chbitmask = + cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); + } else { /* 802.11g */ + ipw_rt->rt_chbitmask = + (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); + } + + /* set the rate in multiples of 500k/s */ + switch (pktrate) { + case IPW_TX_RATE_1MB: + ipw_rt->rt_rate = 2; + break; + case IPW_TX_RATE_2MB: + ipw_rt->rt_rate = 4; + break; + case IPW_TX_RATE_5MB: + ipw_rt->rt_rate = 10; + break; + case IPW_TX_RATE_6MB: + ipw_rt->rt_rate = 12; + break; + case IPW_TX_RATE_9MB: + ipw_rt->rt_rate = 18; + break; + case IPW_TX_RATE_11MB: + ipw_rt->rt_rate = 22; + break; + case IPW_TX_RATE_12MB: + ipw_rt->rt_rate = 24; + break; + case IPW_TX_RATE_18MB: + ipw_rt->rt_rate = 36; + break; + case IPW_TX_RATE_24MB: + ipw_rt->rt_rate = 48; + break; + case IPW_TX_RATE_36MB: + ipw_rt->rt_rate = 72; + break; + case IPW_TX_RATE_48MB: + ipw_rt->rt_rate = 96; + break; + case IPW_TX_RATE_54MB: + ipw_rt->rt_rate = 108; + break; + default: + ipw_rt->rt_rate = 0; + break; + } + + /* antenna number */ + ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */ + + /* set the preamble flag if we have it */ + if ((antennaAndPhy & 64)) + ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + /* Set the size of the skb to the size of the frame */ + skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr)); + + IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); + + if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) + priv->ieee->stats.rx_errors++; + else { /* ieee80211_rx succeeded, so it now owns the SKB */ + rxb->skb = NULL; + /* no LED during capture */ + } +} +#endif + static inline int is_network_packet(struct ipw_priv *priv, struct ieee80211_hdr_4addr *header) { @@ -8147,8 +8314,14 @@ static void ipw_rx(struct ipw_priv *priv) #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { +#ifdef CONFIG_IEEE80211_RADIOTAP + ipw_handle_data_packet_monitor(priv, + rxb, + &stats); +#else ipw_handle_data_packet(priv, rxb, &stats); +#endif break; } #endif @@ -8315,7 +8488,11 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) #ifdef CONFIG_IPW2200_MONITOR case 2: priv->ieee->iw_mode = IW_MODE_MONITOR; +#ifdef CONFIG_IEEE80211_RADIOTAP + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; +#else priv->net_dev->type = ARPHRD_IEEE80211; +#endif break; #endif default: @@ -8565,7 +8742,11 @@ static int ipw_wx_set_mode(struct net_device *dev, priv->net_dev->type = ARPHRD_ETHER; if (wrqu->mode == IW_MODE_MONITOR) +#ifdef CONFIG_IEEE80211_RADIOTAP + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; +#else priv->net_dev->type = ARPHRD_IEEE80211; +#endif #endif /* CONFIG_IPW2200_MONITOR */ /* Free the existing firmware and reset the fw_loaded @@ -9598,7 +9779,11 @@ static int ipw_wx_set_monitor(struct net_device *dev, IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); if (enable) { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { +#ifdef CONFIG_IEEE80211_RADIOTAP + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; +#else priv->net_dev->type = ARPHRD_IEEE80211; +#endif queue_work(priv->workqueue, &priv->adapter_restart); } diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index f2056b62254e..28f1216f8ea4 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -50,6 +50,7 @@ #include #include +#include #define DRV_NAME "ipw2200" -- cgit v1.2.3-59-g8ed1b From 90700fd982022f0519e7bd7595adb8084f36d1c6 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 26 Aug 2005 16:51:06 -0500 Subject: Fixed is_network_packet() to include checking for broadcast packets. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 86a4c2358f9d..d417ed7af7c1 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8096,21 +8096,23 @@ static inline int is_network_packet(struct ipw_priv *priv, if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) return 0; - /* multicast packets to our IBSS go through */ - if (is_multicast_ether_addr(header->addr1)) + /* {broad,multi}cast packets to our BSSID go through */ + if (is_multicast_ether_addr(header->addr1) || + is_broadcast_ether_addr(header->addr1)) return !memcmp(header->addr3, priv->bssid, ETH_ALEN); /* packets to our adapter go through */ return !memcmp(header->addr1, priv->net_dev->dev_addr, ETH_ALEN); - case IW_MODE_INFRA: /* Header: Dest. | AP{BSSID} | Source */ + case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */ /* packets from our adapter are dropped (echo) */ if (!memcmp(header->addr3, priv->net_dev->dev_addr, ETH_ALEN)) return 0; - /* {broad,multi}cast packets to our IBSS go through */ - if (is_multicast_ether_addr(header->addr1)) + /* {broad,multi}cast packets to our BSS go through */ + if (is_multicast_ether_addr(header->addr1) || + is_broadcast_ether_addr(header->addr1)) return !memcmp(header->addr2, priv->bssid, ETH_ALEN); /* packets to our adapter go through */ -- cgit v1.2.3-59-g8ed1b From 567deaf6d4a3372cd16b8719741ca3a6157c9615 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Wed, 31 Aug 2005 18:07:22 +0800 Subject: Mixed PTK/GTK CCMP/TKIP support. Signed-off-by: Hong Liu --- drivers/net/wireless/ipw2200.c | 50 +++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d417ed7af7c1..c9b306a8116c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5771,7 +5771,8 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) DCT_FLAG_EXT_SECURITY_CCM, priv->ieee->sec.active_key); - ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); + if (!priv->ieee->host_mc_decrypt) + ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); break; case SEC_LEVEL_2: if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) @@ -5786,9 +5787,6 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) default: break; } - - ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level); - ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level); } static void ipw_adhoc_check(void *data) @@ -6473,6 +6471,7 @@ static int ipw_wpa_set_encryption(struct net_device *dev, struct ipw_param *param, int param_len) { int ret = 0; + int group_key = 0; struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct ieee80211_crypto_ops *ops; @@ -6502,6 +6501,9 @@ static int ipw_wpa_set_encryption(struct net_device *dev, return -EINVAL; } + if (param->u.crypt.idx != 0) + group_key = 1; + sec.flags |= SEC_ENABLED | SEC_ENCRYPT; if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) { @@ -6517,11 +6519,19 @@ static int ipw_wpa_set_encryption(struct net_device *dev, sec.encrypt = 1; /* IPW HW cannot build TKIP MIC, host decryption still needed. */ - if (strcmp(param->u.crypt.alg, "TKIP") == 0) - ieee->host_encrypt_msdu = 1; + if (strcmp(param->u.crypt.alg, "TKIP") == 0) { + if (group_key) + ieee->host_mc_decrypt = 1; + else + ieee->host_encrypt_msdu = 1; + } - if (!(ieee->host_encrypt || ieee->host_encrypt_msdu || - ieee->host_decrypt)) + /*if (!(ieee->host_encrypt || ieee->host_encrypt_msdu || + ieee->host_decrypt)) + goto skip_host_crypt; */ + if (group_key ? !ieee->host_mc_decrypt : + !(ieee->host_encrypt || ieee->host_decrypt || + ieee->host_encrypt_msdu)) goto skip_host_crypt; ops = ieee80211_get_crypto_ops(param->u.crypt.alg); @@ -6604,6 +6614,9 @@ static int ipw_wpa_set_encryption(struct net_device *dev, sec.flags |= SEC_LEVEL; sec.level = SEC_LEVEL_3; } + /* Don't set sec level for group keys. */ + if (group_key) + sec.flags &= ~SEC_LEVEL; } done: if (ieee->set_security) @@ -6953,15 +6966,21 @@ static int ipw_wx_set_encodeext(struct net_device *dev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; if (hwcrypto) { - /* IPW HW can't build TKIP MIC, host decryption still needed */ if (ext->alg == IW_ENCODE_ALG_TKIP) { - priv->ieee->host_encrypt = 0; - priv->ieee->host_encrypt_msdu = 1; - priv->ieee->host_decrypt = 1; + /* IPW HW can't build TKIP MIC, + host decryption still needed */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + priv->ieee->host_mc_decrypt = 1; + else { + priv->ieee->host_encrypt = 0; + priv->ieee->host_encrypt_msdu = 1; + priv->ieee->host_decrypt = 1; + } } else { priv->ieee->host_encrypt = 0; priv->ieee->host_encrypt_msdu = 0; priv->ieee->host_decrypt = 0; + priv->ieee->host_mc_decrypt = 0; } } @@ -7878,6 +7897,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, struct ipw_rx_mem_buffer *rxb, struct ieee80211_rx_stats *stats) { + struct ieee80211_hdr_4addr *hdr; struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data; /* We received data from the HW, so stop the watchdog */ @@ -7907,7 +7927,10 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ - if (!priv->ieee->host_decrypt && priv->ieee->iw_mode != IW_MODE_MONITOR) + hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data; + if (priv->ieee->iw_mode != IW_MODE_MONITOR && + (is_multicast_ether_addr(hdr->addr1) ? + !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt)) ipw_rebuild_decrypted_skb(priv, rxb->skb); if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) @@ -8508,6 +8531,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) priv->ieee->host_encrypt = 0; priv->ieee->host_encrypt_msdu = 0; priv->ieee->host_decrypt = 0; + priv->ieee->host_mc_decrypt = 0; } IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); -- cgit v1.2.3-59-g8ed1b From cdd1fa1e10a2231b5e24bde82550ac499aa5dcc4 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Wed, 31 Aug 2005 18:14:27 +0800 Subject: Card with WEP enabled and using shared-key auth will have firmware error when it tries to auth to a WPA ap. The patch filters out WPA networks if the card is not wpa enabled when selecting network to associate to. Signed-off-by: Hong Liu --- drivers/net/wireless/ipw2200.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index c9b306a8116c..e36a1fd9eefd 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5510,6 +5510,15 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } + if (!priv->ieee->wpa_enabled && (network->wpa_ie_len > 0 || + network->rsn_ie_len > 0)) { + IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " + "because of WPA capability mismatch.\n", + escape_essid(network->ssid, network->ssid_len), + MAC_ARG(network->bssid)); + return 0; + } + if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " @@ -6228,6 +6237,7 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) { /* This is called when wpa_supplicant loads and closes the driver * interface. */ + priv->ieee->wpa_enabled = value; return 0; } -- cgit v1.2.3-59-g8ed1b From fb7ccc9e6d1a2872ea8a07154f1689d19a7576c5 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 7 Sep 2005 18:19:08 -0500 Subject: Fixed problem with get_cmd_string not existing if CONFIG_IPW_DEBUG disabled. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index e36a1fd9eefd..43dab7a5cc91 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1809,7 +1809,6 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -#ifdef CONFIG_IPW_DEBUG #define IPW_CMD(x) case IPW_CMD_ ## x : return #x static char *get_cmd_string(u8 cmd) { @@ -1868,7 +1867,6 @@ static char *get_cmd_string(u8 cmd) return "UNKNOWN"; } } -#endif #define HOST_COMPLETE_TIMEOUT HZ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) -- cgit v1.2.3-59-g8ed1b From 392d0f6d0752e6a3e25c3e3da95d78c53b0fd7a1 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 7 Sep 2005 18:39:03 -0500 Subject: Removed PF_SYNCTHREAD legacy. The PF_SYNCTHREAD check was introduced to try and remain compatible with SWSUSP2. This check is no longer needed with newer versions. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 83ba08c0c33c..23a74accd50a 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -6433,11 +6433,8 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, INIT_LIST_HEAD(&priv->fw_pend_list); INIT_STAT(&priv->fw_pend_stat); -#ifdef PF_SYNCTHREAD - priv->workqueue = create_workqueue(DRV_NAME, 0); -#else priv->workqueue = create_workqueue(DRV_NAME); -#endif + INIT_WORK(&priv->reset_work, (void (*)(void *))ipw2100_reset_adapter, priv); INIT_WORK(&priv->security_work, -- cgit v1.2.3-59-g8ed1b From 29cb843e6457c45c4a257a0d2080da3fd7fb9d1e Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Mon, 12 Sep 2005 10:43:33 -0500 Subject: Fixes problem with WEP not working (association succeeds, but no Tx/Rx) Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 43dab7a5cc91..217b6579e901 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5789,6 +5789,8 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) break; case SEC_LEVEL_1: ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); + ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level); + ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level); break; case SEC_LEVEL_0: default: -- cgit v1.2.3-59-g8ed1b From f4ff497d45c7071166277a39590cc59b50dc893c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 12 Sep 2005 10:48:48 -0500 Subject: [Fix bug# 771] Too many (8) bytes recieved when using AES/hwcrypto Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 217b6579e901..549f582551e5 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7877,10 +7877,7 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, memmove(skb->data + IEEE80211_3ADDR_LEN, skb->data + IEEE80211_3ADDR_LEN + 8, skb->len - IEEE80211_3ADDR_LEN - 8); - if (fc & IEEE80211_FCTL_MOREFRAGS) - skb_trim(skb, skb->len - 16); /* 2*MIC */ - else - skb_trim(skb, skb->len - 8); /* MIC */ + skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */ break; case SEC_LEVEL_2: break; @@ -7889,10 +7886,7 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, memmove(skb->data + IEEE80211_3ADDR_LEN, skb->data + IEEE80211_3ADDR_LEN + 4, skb->len - IEEE80211_3ADDR_LEN - 4); - if (fc & IEEE80211_FCTL_MOREFRAGS) - skb_trim(skb, skb->len - 8); /* 2*ICV */ - else - skb_trim(skb, skb->len - 4); /* ICV */ + skb_trim(skb, skb->len - 8); /* IV + ICV */ break; case SEC_LEVEL_0: break; -- cgit v1.2.3-59-g8ed1b From e63247269de722c3e753991025fb7f15c6aba9aa Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Wed, 14 Sep 2005 21:04:15 -0500 Subject: Fixes WEP firmware error condition. The problem is caused by the patch in bug455 -- Channel change flood generates fatal error. The patch set the DISASSOCIATING status bit after sending the command. The process was scheduled out when waiting for the command to be sent to the card. The disassociated notification clears the DISASSOCIATING bit in the tasklet before the process set the bit. Move the bit setting code before sending the command now. Signed-off-by: Hong Liu Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 549f582551e5..a7630920ace8 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1882,18 +1882,6 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) return -EAGAIN; } - if (priv->status & STATUS_ASSOCIATING) { - IPW_DEBUG_HC("abandon a command while associating\n"); - spin_unlock_irqrestore(&priv->lock, flags); - return -1; - } - - if (priv->status & STATUS_DISASSOCIATING) { - IPW_DEBUG_HC("abandon a command while disassociating\n"); - spin_unlock_irqrestore(&priv->lock, flags); - return -1; - } - priv->status |= STATUS_HCMD_ACTIVE; if (priv->cmdlog) { @@ -3697,10 +3685,14 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) MAC_ARG(priv->assoc_request.bssid), priv->assoc_request.channel); + priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); + priv->status |= STATUS_DISASSOCIATING; + if (quiet) priv->assoc_request.assoc_type = HC_DISASSOC_QUIET; else priv->assoc_request.assoc_type = HC_DISASSOCIATE; + err = ipw_send_associate(priv, &priv->assoc_request); if (err) { IPW_DEBUG_HC("Attempt to send [dis]associate command " @@ -3708,9 +3700,6 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } - priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); - priv->status |= STATUS_DISASSOCIATING; - } static int ipw_disassociate(void *data) @@ -7672,6 +7661,8 @@ static int ipw_associate_network(struct ipw_priv *priv, */ priv->channel = network->channel; memcpy(priv->bssid, network->bssid, ETH_ALEN); + priv->status |= STATUS_ASSOCIATING; + priv->status &= ~STATUS_SECURITY_UPDATED; priv->assoc_network = network; @@ -7685,9 +7676,6 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - priv->status |= STATUS_ASSOCIATING; - priv->status &= ~STATUS_SECURITY_UPDATED; - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n", escape_essid(priv->essid, priv->essid_len), MAC_ARG(priv->bssid)); @@ -7791,6 +7779,13 @@ static int ipw_associate(void *data) return 0; } + if (priv->status & STATUS_DISASSOCIATING) { + IPW_DEBUG_ASSOC("Not attempting association (in " + "disassociating)\n "); + queue_work(priv->workqueue, &priv->associate); + return 0; + } + if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { IPW_DEBUG_ASSOC("Not attempting association (scanning or not " "initialized)\n"); -- cgit v1.2.3-59-g8ed1b From 9ef539d0d6fca1cd0b1f9b884be8b92cb80159c9 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 15 Sep 2005 00:42:42 -0500 Subject: Updated driver version stamps for ipw2100 (1.1.3) and ipw2200 (1.0.7) Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 2 +- drivers/net/wireless/ipw2200.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 23a74accd50a..dba1049bcf91 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -167,7 +167,7 @@ that only one external action is invoked at a time. #include "ipw2100.h" -#define IPW2100_VERSION "1.1.1" +#define IPW2100_VERSION "1.1.3" #define DRV_NAME "ipw2100" #define DRV_VERSION IPW2100_VERSION diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index a7630920ace8..0b1c6fe54262 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -32,7 +32,7 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.5" +#define IPW2200_VERSION "1.0.7" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" #define DRV_VERSION IPW2200_VERSION -- cgit v1.2.3-59-g8ed1b From 87bb5e3814572b85cf5d4650fb1f88267411845f Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 15 Sep 2005 01:00:31 -0500 Subject: Pulled out a stray KERNEL_VERSION check around the suspend handler. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index dba1049bcf91..ed4f1a5e6b0a 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -6709,11 +6709,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) } #ifdef CONFIG_PM -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) -static int ipw2100_suspend(struct pci_dev *pci_dev, u32 state) -#else static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) -#endif { struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); struct net_device *dev = priv->net_dev; -- cgit v1.2.3-59-g8ed1b From 97a78ca968b84a5e9d8854622b4760cec5058f77 Mon Sep 17 00:00:00 2001 From: Benoit Boissinot Date: Thu, 15 Sep 2005 17:30:28 +0000 Subject: Fix 'Driver using old /proc/net/wireless support, please fix driver !' message. Wireless extensions moved the get_wireless_stats handler from being in net_device into wireless_handler. Signed-off-by: Benoit Boissinot Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 19 ++++++++++++------- drivers/net/wireless/ipw2200.h | 2 ++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0b1c6fe54262..b89ede14419c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -125,6 +125,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos *qos_param); #endif /* CONFIG_IPW_QOS */ +static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev); static void ipw_remove_current_network(struct ipw_priv *priv); static void ipw_rx(struct ipw_priv *priv); static int ipw_queue_tx_reclaim(struct ipw_priv *priv, @@ -8883,6 +8884,13 @@ static int ipw_wx_get_range(struct net_device *dev, range->num_frequency = i; up(&priv->sem); + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | + IW_EVENT_CAPA_MASK(SIOCGIWAP)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + IPW_DEBUG_WX("GET Range\n"); return 0; } @@ -9999,10 +10007,9 @@ static struct iw_handler_def ipw_wx_handler_def = { .num_private_args = ARRAY_SIZE(ipw_priv_args), .private = ipw_priv_handler, .private_args = ipw_priv_args, + .get_wireless_stats = ipw_get_wireless_stats, }; -static struct iw_public_data ipw_wx_data; - /* * Get wireless statistics. * Called by /proc/net/wireless @@ -11487,9 +11494,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); - ipw_wx_data.spy_data = &priv->ieee->spy_data; - ipw_wx_data.ieee80211 = priv->ieee; - down(&priv->sem); priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; @@ -11514,8 +11518,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) net_dev->get_stats = ipw_net_get_stats; net_dev->set_multicast_list = ipw_net_set_multicast_list; net_dev->set_mac_address = ipw_net_set_mac_address; - net_dev->get_wireless_stats = ipw_get_wireless_stats; - net_dev->wireless_data = &ipw_wx_data; + priv->wireless_data.spy_data = &priv->ieee->spy_data; + priv->wireless_data.ieee80211 = priv->ieee; + net_dev->wireless_data = &priv->wireless_data; net_dev->wireless_handlers = &ipw_wx_handler_def; net_dev->ethtool_ops = &ipw_ethtool_ops; net_dev->irq = pdev->irq; diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 28f1216f8ea4..3e7699430c6c 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1228,6 +1228,8 @@ struct ipw_priv { struct iw_statistics wstats; + struct iw_public_data wireless_data; + struct workqueue_struct *workqueue; struct work_struct adhoc_check; -- cgit v1.2.3-59-g8ed1b From 8935f39e86e3707770e091fb58d9060307edf959 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 5 Oct 2005 15:59:08 -0500 Subject: Removed legacy WIRELESS_EXT checks from ipw2200.c Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 508 +---------------------------------------- 1 file changed, 1 insertion(+), 507 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b89ede14419c..8e17308b5539 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6159,70 +6159,6 @@ static void ipw_bg_abort_scan(void *data) up(&priv->sem); } -#if WIRELESS_EXT < 18 -/* Support for wpa_supplicant before WE-18, deprecated. */ - -/* following definitions must match definitions in driver_ipw.c */ - -#define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 - -#define IPW_CMD_SET_WPA_PARAM 1 -#define IPW_CMD_SET_WPA_IE 2 -#define IPW_CMD_SET_ENCRYPTION 3 -#define IPW_CMD_MLME 4 - -#define IPW_PARAM_WPA_ENABLED 1 -#define IPW_PARAM_TKIP_COUNTERMEASURES 2 -#define IPW_PARAM_DROP_UNENCRYPTED 3 -#define IPW_PARAM_PRIVACY_INVOKED 4 -#define IPW_PARAM_AUTH_ALGS 5 -#define IPW_PARAM_IEEE_802_1X 6 - -#define IPW_MLME_STA_DEAUTH 1 -#define IPW_MLME_STA_DISASSOC 2 - -#define IPW_CRYPT_ERR_UNKNOWN_ALG 2 -#define IPW_CRYPT_ERR_UNKNOWN_ADDR 3 -#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define IPW_CRYPT_ERR_KEY_SET_FAILED 5 -#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define IPW_CRYPT_ERR_CARD_CONF_FAILED 7 - -#define IPW_CRYPT_ALG_NAME_LEN 16 - -struct ipw_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u8 name; - u32 value; - } wpa_param; - struct { - u32 len; - u8 reserved[32]; - u8 data[0]; - } wpa_ie; - struct { - u32 command; - u32 reason_code; - } mlme; - struct { - u8 alg[IPW_CRYPT_ALG_NAME_LEN]; - u8 set_tx; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - - } u; -}; - -/* end of driver_ipw.c code */ -#endif - static int ipw_wpa_enable(struct ipw_priv *priv, int value) { /* This is called when wpa_supplicant loads and closes the driver @@ -6231,11 +6167,6 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) return 0; } -#if WIRELESS_EXT < 18 -#define IW_AUTH_ALG_OPEN_SYSTEM 0x1 -#define IW_AUTH_ALG_SHARED_KEY 0x2 -#endif - static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) { struct ieee80211_device *ieee = priv->ieee; @@ -6283,416 +6214,6 @@ static int ipw_set_rsn_capa(struct ipw_priv *priv, return ipw_send_cmd(priv, &cmd); } -#if WIRELESS_EXT < 18 -static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_crypt_data *crypt; - unsigned long flags; - int ret = 0; - - switch (name) { - case IPW_PARAM_WPA_ENABLED: - ret = ipw_wpa_enable(priv, value); - break; - - case IPW_PARAM_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { - IPW_WARNING("Can't set TKIP countermeasures: " - "crypt not set!\n"); - break; - } - - flags = crypt->ops->get_flags(crypt->priv); - - if (value) - flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - else - flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; - - crypt->ops->set_flags(flags, crypt->priv); - - break; - - case IPW_PARAM_DROP_UNENCRYPTED:{ - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - struct ieee80211_security sec = { - .flags = SEC_ENABLED, - .enabled = value, - }; - priv->ieee->drop_unencrypted = value; - /* We only change SEC_LEVEL for open mode. Others - * are set by ipw_wpa_set_encryption. - */ - if (!value) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_0; - } else { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } - if (priv->ieee->set_security) - priv->ieee->set_security(priv->ieee->dev, &sec); - break; - } - - case IPW_PARAM_PRIVACY_INVOKED: - priv->ieee->privacy_invoked = value; - break; - - case IPW_PARAM_AUTH_ALGS: - ret = ipw_wpa_set_auth_algs(priv, value); - break; - - case IPW_PARAM_IEEE_802_1X: - priv->ieee->ieee802_1x = value; - break; - - default: - IPW_ERROR("%s: Unknown WPA param: %d\n", dev->name, name); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - int ret = 0; - - switch (command) { - case IPW_MLME_STA_DEAUTH: - // silently ignore - break; - - case IPW_MLME_STA_DISASSOC: - ipw_disassociate(priv); - break; - - default: - IPW_ERROR("%s: Unknown MLME request: %d\n", dev->name, command); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static int ipw_wpa_ie_cipher2level(u8 cipher) -{ - switch (cipher) { - case 4: /* CCMP */ - return SEC_LEVEL_3; - case 2: /* TKIP */ - return SEC_LEVEL_2; - case 5: /* WEP104 */ - case 1: /* WEP40 */ - return SEC_LEVEL_1; - case 0: /* NONE */ - return SEC_LEVEL_0; - default: - return -1; - } -} - -static int ipw_wpa_set_wpa_ie(struct net_device *dev, - struct ipw_param *param, int plen) -{ - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - u8 *buf; - u8 *ptk, *gtk; - int level; - - if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || - (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) - return -EINVAL; - - if (param->u.wpa_ie.len) { - buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = param->u.wpa_ie.len; - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - goto done; - } - - if (priv->ieee->host_encrypt) - goto done; - - /* HACK: Parse wpa_ie here to get pairwise suite, otherwise - * we need to change driver_ipw.c from wpa_supplicant. This - * is OK since -Dipw is deprecated. The -Dwext driver has a - * clean way to handle this. */ - gtk = ptk = (u8 *) ieee->wpa_ie; - if (ieee->wpa_ie[0] == 0x30) { /* RSN IE */ - gtk += 4 + 3; - ptk += 4 + 4 + 2 + 3; - } else { /* WPA IE */ - gtk += 8 + 3; - ptk += 8 + 4 + 2 + 3; - } - - if (ptk - (u8 *) ieee->wpa_ie > ieee->wpa_ie_len) - return -EINVAL; - - level = ipw_wpa_ie_cipher2level(*gtk); - ipw_set_hw_decrypt_multicast(priv, level); - - level = ipw_wpa_ie_cipher2level(*ptk); - ipw_set_hw_decrypt_unicast(priv, level); - - done: - ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); - return 0; -} - -/* implementation borrowed from hostap driver */ - -static int ipw_wpa_set_encryption(struct net_device *dev, - struct ipw_param *param, int param_len) -{ - int ret = 0; - int group_key = 0; - struct ipw_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; - - struct ieee80211_security sec = { - .flags = 0, - }; - - param->u.crypt.err = 0; - param->u.crypt.alg[IPW_CRYPT_ALG_NAME_LEN - 1] = '\0'; - - if (param_len != - (int)((char *)param->u.crypt.key - (char *)param) + - param->u.crypt.key_len) { - IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, - param->u.crypt.key_len); - return -EINVAL; - } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { - if (param->u.crypt.idx >= WEP_KEYS) - return -EINVAL; - crypt = &ieee->crypt[param->u.crypt.idx]; - } else { - return -EINVAL; - } - - if (param->u.crypt.idx != 0) - group_key = 1; - - sec.flags |= SEC_ENABLED | SEC_ENCRYPT; - if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt) { - sec.enabled = 0; - sec.encrypt = 0; - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_LEVEL; - ieee80211_crypt_delayed_deinit(ieee, crypt); - } - goto done; - } - sec.enabled = 1; - sec.encrypt = 1; - - /* IPW HW cannot build TKIP MIC, host decryption still needed. */ - if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - if (group_key) - ieee->host_mc_decrypt = 1; - else - ieee->host_encrypt_msdu = 1; - } - - /*if (!(ieee->host_encrypt || ieee->host_encrypt_msdu || - ieee->host_decrypt)) - goto skip_host_crypt; */ - if (group_key ? !ieee->host_mc_decrypt : - !(ieee->host_encrypt || ieee->host_decrypt || - ieee->host_encrypt_msdu)) - goto skip_host_crypt; - - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("ieee80211_crypt_wep"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("ieee80211_crypt_tkip"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("ieee80211_crypt_ccmp"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - } - if (ops == NULL) { - IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n", - dev->name, param->u.crypt.alg); - param->u.crypt.err = IPW_CRYPT_ERR_UNKNOWN_ALG; - ret = -EINVAL; - goto done; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; - - ieee80211_crypt_delayed_deinit(ieee, crypt); - - new_crypt = (struct ieee80211_crypt_data *) - kmalloc(sizeof(*new_crypt), GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); - new_crypt->ops = ops; - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = - new_crypt->ops->init(param->u.crypt.idx); - - if (new_crypt->priv == NULL) { - kfree(new_crypt); - param->u.crypt.err = IPW_CRYPT_ERR_CRYPT_INIT_FAILED; - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(param->u.crypt.key, - param->u.crypt.key_len, param->u.crypt.seq, - (*crypt)->priv) < 0) { - IPW_DEBUG_INFO("%s: key setting failed\n", dev->name); - param->u.crypt.err = IPW_CRYPT_ERR_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - - skip_host_crypt: - if (param->u.crypt.set_tx) { - ieee->tx_keyidx = param->u.crypt.idx; - sec.active_key = param->u.crypt.idx; - sec.flags |= SEC_ACTIVE_KEY; - } else - sec.flags &= ~SEC_ACTIVE_KEY; - - if (param->u.crypt.alg != NULL) { - memcpy(sec.keys[param->u.crypt.idx], - param->u.crypt.key, param->u.crypt.key_len); - sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; - sec.flags |= (1 << param->u.crypt.idx); - - if (strcmp(param->u.crypt.alg, "WEP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_2; - } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_3; - } - /* Don't set sec level for group keys. */ - if (group_key) - sec.flags &= ~SEC_LEVEL; - } - done: - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - - /* Do not reset port if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. If your hardware requires a reset after WEP - * configuration (for example... Prism2), implement the reset_port in - * the callbacks structures used to initialize the 802.11 stack. */ - if (ieee->reset_on_keychange && - ieee->iw_mode != IW_MODE_INFRA && - ieee->reset_port && ieee->reset_port(dev)) { - IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name); - param->u.crypt.err = IPW_CRYPT_ERR_CARD_CONF_FAILED; - return -EINVAL; - } - - return ret; -} - -static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) -{ - struct ipw_param *param; - struct ipw_priv *priv = ieee80211_priv(dev); - int ret = 0; - - IPW_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); - - if (p->length < sizeof(struct ipw_param) || !p->pointer) - return -EINVAL; - - param = (struct ipw_param *)kmalloc(p->length, GFP_KERNEL); - if (param == NULL) - return -ENOMEM; - - if (copy_from_user(param, p->pointer, p->length)) { - kfree(param); - return -EFAULT; - } - - down(&priv->sem); - switch (param->cmd) { - - case IPW_CMD_SET_WPA_PARAM: - ret = ipw_wpa_set_param(dev, param->u.wpa_param.name, - param->u.wpa_param.value); - break; - - case IPW_CMD_SET_WPA_IE: - ret = ipw_wpa_set_wpa_ie(dev, param, p->length); - break; - - case IPW_CMD_SET_ENCRYPTION: - ret = ipw_wpa_set_encryption(dev, param, p->length); - break; - - case IPW_CMD_MLME: - ret = ipw_wpa_mlme(dev, param->u.mlme.command, - param->u.mlme.reason_code); - break; - - default: - IPW_ERROR("%s: Unknown WPA supplicant request: %d\n", - dev->name, param->cmd); - ret = -EOPNOTSUPP; - } - - up(&priv->sem); - if (ret == 0 && copy_to_user(p->pointer, param, p->length)) - ret = -EFAULT; - - kfree(param); - return ret; -} -#else /* * WE-18 support */ @@ -7021,7 +6542,6 @@ static int ipw_wx_set_mlme(struct net_device *dev, } return 0; } -#endif #ifdef CONFIG_IPW_QOS @@ -9391,7 +8911,6 @@ static int ipw_wx_get_retry(struct net_device *dev, return 0; } -#if WIRELESS_EXT > 17 static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, int essid_len) { @@ -9455,14 +8974,12 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, up(&priv->sem); return err; } -#endif /* WIRELESS_EXT > 17 */ static int ipw_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); -#if WIRELESS_EXT > 17 struct iw_scan_req *req = NULL; if (wrqu->data.length && wrqu->data.length == sizeof(struct iw_scan_req)) { @@ -9473,7 +8990,7 @@ static int ipw_wx_set_scan(struct net_device *dev, return 0; } } -#endif + IPW_DEBUG_WX("Start scan\n"); queue_work(priv->workqueue, &priv->request_scan); @@ -9923,7 +9440,6 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, -#if WIRELESS_EXT > 17 IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie, IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie, IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme, @@ -9931,7 +9447,6 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth, IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext, IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext, -#endif }; enum { @@ -11317,24 +10832,6 @@ static void ipw_bg_down(void *data) up(&priv->sem); } -#if WIRELESS_EXT < 18 -static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct iwreq *wrq = (struct iwreq *)rq; - int ret = -1; - switch (cmd) { - case IPW_IOCTL_WPA_SUPPLICANT: - ret = ipw_wpa_supplicant(dev, &wrq->u.data); - return ret; - - default: - return -EOPNOTSUPP; - } - - return -EOPNOTSUPP; -} -#endif - /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { @@ -11512,9 +11009,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) net_dev->open = ipw_net_open; net_dev->stop = ipw_net_stop; net_dev->init = ipw_net_init; -#if WIRELESS_EXT < 18 - net_dev->do_ioctl = ipw_ioctl; -#endif net_dev->get_stats = ipw_net_get_stats; net_dev->set_multicast_list = ipw_net_set_multicast_list; net_dev->set_mac_address = ipw_net_set_mac_address; -- cgit v1.2.3-59-g8ed1b From e758256104c3c2475f7746bc1b348c99cdb207f2 Mon Sep 17 00:00:00 2001 From: Ben Cahill Date: Thu, 6 Oct 2005 15:34:41 -0500 Subject: Fixes missed beacon logic in relation to on-network AP roaming. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 27 ++++++++++++++++++++------- drivers/net/wireless/ipw2200.h | 3 +++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 8e17308b5539..894192964c0b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4082,6 +4082,11 @@ static void ipw_bg_gather_stats(void *data) up(&priv->sem); } +/* Missed beacon behavior: + * 1st missed -> roaming_threshold, just wait, don't do any scan/roam. + * roaming_threshold -> disassociate_threshold, scan and roam for better signal. + * Above disassociate threshold, give up and stop scanning. + * Roaming is disabled if disassociate_threshold <= roaming_threshold */ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, int missed_count) { @@ -4116,9 +4121,12 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, return; } - if (missed_count > priv->roaming_threshold) { + if (missed_count > priv->roaming_threshold && + missed_count <= priv->disassociate_threshold) { /* If we are not already roaming, set the ROAM - * bit in the status and kick off a scan */ + * bit in the status and kick off a scan. + * This can happen several times before we reach + * disassociate_threshold. */ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, "Missed beacon: %d - initiate " "roaming\n", missed_count); @@ -4480,11 +4488,16 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, STATUS_DISASSOCIATING))) queue_work(priv->workqueue, &priv->associate); else if (priv->status & STATUS_ROAMING) { - /* If a scan completed and we are in roam mode, then - * the scan that completed was the one requested as a - * result of entering roam... so, schedule the - * roam work */ - queue_work(priv->workqueue, &priv->roam); + if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) + /* If a scan completed and we are in roam mode, then + * the scan that completed was the one requested as a + * result of entering roam... so, schedule the + * roam work */ + queue_work(priv->workqueue, + &priv->roam); + else + /* Don't schedule if we aborted the scan */ + priv->status &= ~STATUS_ROAMING; } else if (priv->status & STATUS_SCAN_PENDING) queue_work(priv->workqueue, &priv->request_scan); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 3e7699430c6c..617ec4dba17a 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -590,6 +590,9 @@ struct notif_channel_result { u8 uReserved; } __attribute__ ((packed)); +#define SCAN_COMPLETED_STATUS_COMPLETE 1 +#define SCAN_COMPLETED_STATUS_ABORTED 2 + struct notif_scan_complete { u8 scan_type; u8 num_channels; -- cgit v1.2.3-59-g8ed1b From 991d1cc5963f4926478f3139ec0b0dd26a2c888c Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 13 Oct 2005 09:26:48 +0000 Subject: Removed warning about TKIP not being configured if countermeasures are configured. Countermeasures default to being turned off when wpa_supplicant runs, regardless of if TKIP is being used. They are only turned on if a TKIP is running. The warning we were printing is therefore not needed. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2100.c | 10 ++-------- drivers/net/wireless/ipw2200.c | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index ed4f1a5e6b0a..76841cb8301b 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5866,11 +5866,8 @@ static int ipw2100_wpa_set_param(struct net_device *dev, u8 name, u32 value) case IPW2100_PARAM_TKIP_COUNTERMEASURES: crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { - IPW_DEBUG_WARNING("Can't set TKIP countermeasures: " - "crypt not set!\n"); + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; - } flags = crypt->ops->get_flags(crypt->priv); @@ -7935,11 +7932,8 @@ static int ipw2100_wx_set_auth(struct net_device *dev, case IW_AUTH_TKIP_COUNTERMEASURES: crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { - IPW_DEBUG_WARNING("Can't set TKIP countermeasures: " - "crypt not set!\n"); + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; - } flags = crypt->ops->get_flags(crypt->priv); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 894192964c0b..750e43e9310a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6357,11 +6357,8 @@ static int ipw_wx_set_auth(struct net_device *dev, case IW_AUTH_TKIP_COUNTERMEASURES: crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; - if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { - IPW_WARNING("Can't set TKIP countermeasures: " - "crypt not set!\n"); + if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; - } flags = crypt->ops->get_flags(crypt->priv); @@ -6453,11 +6450,8 @@ static int ipw_wx_get_auth(struct net_device *dev, case IW_AUTH_TKIP_COUNTERMEASURES: crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; - if (!crypt || !crypt->ops->get_flags) { - IPW_WARNING("Can't get TKIP countermeasures: " - "crypt not set!\n"); + if (!crypt || !crypt->ops->get_flags) break; - } param->value = (crypt->ops->get_flags(crypt->priv) & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; -- cgit v1.2.3-59-g8ed1b From 035205760e4f28082fedb258a20c804746c84ffe Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 19 Oct 2005 16:12:31 -0500 Subject: Added channel support for ipw2200 cards identified as 'ZZR' Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 750e43e9310a..081957ab1194 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -10495,6 +10495,17 @@ static const struct ieee80211_geo ipw_geos[] = { {5210, 42}, {5230, 46}}, }, + { /* Rest of World */ + "ZZR", + .bg_channels = 14, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14, IEEE80211_CH_B_ONLY | + IEEE80211_CH_PASSIVE_ONLY}}, + }, + { /* High Band */ "ZZH", .bg_channels = 13, @@ -10711,8 +10722,13 @@ static int ipw_up(struct ipw_priv *priv) ipw_geos[j].name, 3)) break; } - if (j == ARRAY_SIZE(ipw_geos)) + if (j == ARRAY_SIZE(ipw_geos)) { + IPW_WARNING("SKU [%c%c%c] not recognized.\n", + priv->eeprom[EEPROM_COUNTRY_CODE + 0], + priv->eeprom[EEPROM_COUNTRY_CODE + 1], + priv->eeprom[EEPROM_COUNTRY_CODE + 2]); j = 0; + } if (ipw_set_geo(priv->ieee, &ipw_geos[j])) { IPW_WARNING("Could not set geography."); return 0; -- cgit v1.2.3-59-g8ed1b From 9d5b880bb8e977426d64a4caebe3fd3ae73a2862 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Wed, 19 Oct 2005 16:25:33 -0500 Subject: Fixed problem with not being able to send broadcast packets. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 081957ab1194..c1ae6d4065e0 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7456,7 +7456,8 @@ static void ipw_handle_data_packet(struct ipw_priv *priv, /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */ hdr = (struct ieee80211_hdr_4addr *)rxb->skb->data; if (priv->ieee->iw_mode != IW_MODE_MONITOR && - (is_multicast_ether_addr(hdr->addr1) ? + ((is_multicast_ether_addr(hdr->addr1) || + is_broadcast_ether_addr(hdr->addr1)) ? !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt)) ipw_rebuild_decrypted_skb(priv, rxb->skb); @@ -9652,7 +9653,8 @@ static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: hdr_len = IEEE80211_3ADDR_LEN; - unicast = !is_multicast_ether_addr(hdr->addr1); + unicast = !(is_multicast_ether_addr(hdr->addr1) || + is_broadcast_ether_addr(hdr->addr1)); id = ipw_find_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { id = ipw_add_station(priv, hdr->addr1); @@ -9667,7 +9669,8 @@ static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, case IW_MODE_INFRA: default: - unicast = !is_multicast_ether_addr(hdr->addr3); + unicast = !(is_multicast_ether_addr(hdr->addr3) || + is_broadcast_ether_addr(hdr->addr3)); hdr_len = IEEE80211_3ADDR_LEN; id = 0; break; -- cgit v1.2.3-59-g8ed1b From 286568ab1e8f0e09a76cfa58e8ed48ddc44484b5 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 30 Aug 2005 10:34:25 -0500 Subject: Fixed parameter reordering in firmware log routine. Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index c1ae6d4065e0..f49b0125375b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -526,7 +526,7 @@ static void ipw_dump_error_log(struct ipw_priv *priv, for (i = 0; i < error->log_len; i++) IPW_ERROR("%i\t0x%08x\t%i\n", error->log[i].time, - error->log[i].event, error->log[i].data); + error->log[i].data, error->log[i].event); } #endif -- cgit v1.2.3-59-g8ed1b From 81715376de909637b957f856e30880871fbd78fc Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 25 Aug 2005 01:37:28 -0500 Subject: Updated firmware version stamp to 2.4 from 2.3 so it will use the latest firmware. You can obtain the firmware at http://ipw2200.sf.net/firmware.php Signed-off-by: James Ketrenos --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f49b0125375b..56709d2921a6 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2834,7 +2834,7 @@ struct fw_chunk { }; #define IPW_FW_MAJOR_VERSION 2 -#define IPW_FW_MINOR_VERSION 3 +#define IPW_FW_MINOR_VERSION 4 #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) #define IPW_FW_MAJOR(x) (x & 0xff) -- cgit v1.2.3-59-g8ed1b From cf1b479b6922c6736d9f00d90c2b78e977692c93 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Thu, 20 Oct 2005 16:35:24 -0500 Subject: Update version ipw2200 stamp to 1.0.8 --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 56709d2921a6..136884cef908 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -32,7 +32,7 @@ #include "ipw2200.h" -#define IPW2200_VERSION "1.0.7" +#define IPW2200_VERSION "git-1.0.8" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" #define DRV_VERSION IPW2200_VERSION -- cgit v1.2.3-59-g8ed1b From 826d2abe9945372c8838398bfd88a1caa5844d41 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Mon, 7 Nov 2005 18:56:59 -0600 Subject: Updated READMEs and MAINTAINERS for the ipw2100 and ipw2200 drivers. Signed-off-by: James Ketrenos --- Documentation/networking/README.ipw2100 | 132 ++++++++++++++------- Documentation/networking/README.ipw2200 | 196 ++++++++++++++++++++++++++------ MAINTAINERS | 18 +++ 3 files changed, 272 insertions(+), 74 deletions(-) diff --git a/Documentation/networking/README.ipw2100 b/Documentation/networking/README.ipw2100 index 2046948b020d..3ab40379d1cf 100644 --- a/Documentation/networking/README.ipw2100 +++ b/Documentation/networking/README.ipw2100 @@ -1,27 +1,82 @@ -=========================== -Intel(R) PRO/Wireless 2100 Network Connection Driver for Linux +Intel(R) PRO/Wireless 2100 Driver for Linux in support of: + +Intel(R) PRO/Wireless 2100 Network Connection + +Copyright (C) 2003-2005, Intel Corporation + README.ipw2100 -March 14, 2005 +Version: 1.1.3 +Date : October 17, 2005 -=========================== Index ---------------------------- -0. Introduction -1. Release 1.1.0 Current Features -2. Command Line Parameters -3. Sysfs Helper Files -4. Radio Kill Switch -5. Dynamic Firmware -6. Power Management -7. Support -8. License - - -=========================== -0. Introduction ------------- ----- ----- ---- --- -- - +----------------------------------------------- +0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER +1. Introduction +2. Release 1.1.3 Current Features +3. Command Line Parameters +4. Sysfs Helper Files +5. Radio Kill Switch +6. Dynamic Firmware +7. Power Management +8. Support +9. License + + +0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER +----------------------------------------------- + +Important Notice FOR ALL USERS OR DISTRIBUTORS!!!! + +Intel wireless LAN adapters are engineered, manufactured, tested, and +quality checked to ensure that they meet all necessary local and +governmental regulatory agency requirements for the regions that they +are designated and/or marked to ship into. Since wireless LANs are +generally unlicensed devices that share spectrum with radars, +satellites, and other licensed and unlicensed devices, it is sometimes +necessary to dynamically detect, avoid, and limit usage to avoid +interference with these devices. In many instances Intel is required to +provide test data to prove regional and local compliance to regional and +governmental regulations before certification or approval to use the +product is granted. Intel's wireless LAN's EEPROM, firmware, and +software driver are designed to carefully control parameters that affect +radio operation and to ensure electromagnetic compliance (EMC). These +parameters include, without limitation, RF power, spectrum usage, +channel scanning, and human exposure. + +For these reasons Intel cannot permit any manipulation by third parties +of the software provided in binary format with the wireless WLAN +adapters (e.g., the EEPROM and firmware). Furthermore, if you use any +patches, utilities, or code with the Intel wireless LAN adapters that +have been manipulated by an unauthorized party (i.e., patches, +utilities, or code (including open source code modifications) which have +not been validated by Intel), (i) you will be solely responsible for +ensuring the regulatory compliance of the products, (ii) Intel will bear +no liability, under any theory of liability for any issues associated +with the modified products, including without limitation, claims under +the warranty and/or issues arising from regulatory non-compliance, and +(iii) Intel will not provide or be required to assist in providing +support to any third parties for such modified products. + +Note: Many regulatory agencies consider Wireless LAN adapters to be +modules, and accordingly, condition system-level regulatory approval +upon receipt and review of test data documenting that the antennas and +system configuration do not cause the EMC and radio operation to be +non-compliant. + +The drivers available for download from SourceForge are provided as a +part of a development project. Conformance to local regulatory +requirements is the responsibility of the individual developer. As +such, if you are interested in deploying or shipping a driver as part of +solution intended to be used for purposes other than development, please +obtain a tested driver from Intel Customer Support at: + +http://support.intel.com/support/notebook/sb/CS-006408.htm + + +1. Introduction +----------------------------------------------- This document provides a brief overview of the features supported by the IPW2100 driver project. The main project website, where the latest @@ -34,9 +89,8 @@ potential fixes and patches, as well as links to the development mailing list for the driver project. -=========================== -1. Release 1.1.0 Current Supported Features ---------------------------- +2. Release 1.1.3 Current Supported Features +----------------------------------------------- - Managed (BSS) and Ad-Hoc (IBSS) - WEP (shared key and open) - Wireless Tools support @@ -51,9 +105,8 @@ on the amount of validation and interoperability testing that has been performed on a given feature. -=========================== -2. Command Line Parameters ---------------------------- +3. Command Line Parameters +----------------------------------------------- If the driver is built as a module, the following optional parameters are used by entering them on the command line with the modprobe command using this @@ -75,9 +128,9 @@ associate boolean associate=0 /* Do NOT auto associate */ disable boolean disable=1 /* Do not power the HW */ -=========================== -3. Sysfs Helper Files +4. Sysfs Helper Files --------------------------- +----------------------------------------------- There are several ways to control the behavior of the driver. Many of the general capabilities are exposed through the Wireless Tools (iwconfig). There @@ -120,9 +173,8 @@ For the device level files, see /sys/bus/pci/drivers/ipw2100: based RF kill from ON -> OFF -> ON, the radio will NOT come back on -=========================== -4. Radio Kill Switch ---------------------------- +5. Radio Kill Switch +----------------------------------------------- Most laptops provide the ability for the user to physically disable the radio. Some vendors have implemented this as a physical switch that requires no software to turn the radio off and on. On other laptops, however, the switch @@ -134,9 +186,8 @@ See the Sysfs helper file 'rf_kill' for determining the state of the RF switch on your system. -=========================== -5. Dynamic Firmware ---------------------------- +6. Dynamic Firmware +----------------------------------------------- As the firmware is licensed under a restricted use license, it can not be included within the kernel sources. To enable the IPW2100 you will need a firmware image to load into the wireless NIC's processors. @@ -146,9 +197,8 @@ You can obtain these images from . See INSTALL for instructions on installing the firmware. -=========================== -6. Power Management ---------------------------- +7. Power Management +----------------------------------------------- The IPW2100 supports the configuration of the Power Save Protocol through a private wireless extension interface. The IPW2100 supports the following different modes: @@ -200,9 +250,8 @@ xxxx/yyyy will be replaced with 'off' -- the level reported will be the active level if `iwconfig eth1 power on` is invoked. -=========================== -7. Support ---------------------------- +8. Support +----------------------------------------------- For general development information and support, go to: @@ -218,9 +267,8 @@ For installation support on the ipw2100 1.1.0 driver on Linux kernels http://supportmail.intel.com -=========================== -8. License ---------------------------- +9. License +----------------------------------------------- Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200 index 6916080c5f03..c6492d3839fa 100644 --- a/Documentation/networking/README.ipw2200 +++ b/Documentation/networking/README.ipw2200 @@ -1,33 +1,89 @@ Intel(R) PRO/Wireless 2915ABG Driver for Linux in support of: -Intel(R) PRO/Wireless 2200BG Network Connection -Intel(R) PRO/Wireless 2915ABG Network Connection +Intel(R) PRO/Wireless 2200BG Network Connection +Intel(R) PRO/Wireless 2915ABG Network Connection -Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R) -PRO/Wireless 2200BG Driver for Linux is a unified driver that works on -both hardware adapters listed above. In this document the Intel(R) -PRO/Wireless 2915ABG Driver for Linux will be used to reference the +Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R) +PRO/Wireless 2200BG Driver for Linux is a unified driver that works on +both hardware adapters listed above. In this document the Intel(R) +PRO/Wireless 2915ABG Driver for Linux will be used to reference the unified driver. Copyright (C) 2004-2005, Intel Corporation README.ipw2200 -Version: 1.0.0 -Date : January 31, 2005 +Version: 1.0.8 +Date : October 20, 2005 Index ----------------------------------------------- +0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER 1. Introduction 1.1. Overview of features 1.2. Module parameters 1.3. Wireless Extension Private Methods 1.4. Sysfs Helper Files -2. About the Version Numbers -3. Support -4. License +2. Ad-Hoc Networking +3. Interacting with Wireless Tools +3.1. iwconfig mode +4. About the Version Numbers +5. Firmware installation +6. Support +7. License + + +0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER +----------------------------------------------- + +Important Notice FOR ALL USERS OR DISTRIBUTORS!!!! + +Intel wireless LAN adapters are engineered, manufactured, tested, and +quality checked to ensure that they meet all necessary local and +governmental regulatory agency requirements for the regions that they +are designated and/or marked to ship into. Since wireless LANs are +generally unlicensed devices that share spectrum with radars, +satellites, and other licensed and unlicensed devices, it is sometimes +necessary to dynamically detect, avoid, and limit usage to avoid +interference with these devices. In many instances Intel is required to +provide test data to prove regional and local compliance to regional and +governmental regulations before certification or approval to use the +product is granted. Intel's wireless LAN's EEPROM, firmware, and +software driver are designed to carefully control parameters that affect +radio operation and to ensure electromagnetic compliance (EMC). These +parameters include, without limitation, RF power, spectrum usage, +channel scanning, and human exposure. + +For these reasons Intel cannot permit any manipulation by third parties +of the software provided in binary format with the wireless WLAN +adapters (e.g., the EEPROM and firmware). Furthermore, if you use any +patches, utilities, or code with the Intel wireless LAN adapters that +have been manipulated by an unauthorized party (i.e., patches, +utilities, or code (including open source code modifications) which have +not been validated by Intel), (i) you will be solely responsible for +ensuring the regulatory compliance of the products, (ii) Intel will bear +no liability, under any theory of liability for any issues associated +with the modified products, including without limitation, claims under +the warranty and/or issues arising from regulatory non-compliance, and +(iii) Intel will not provide or be required to assist in providing +support to any third parties for such modified products. + +Note: Many regulatory agencies consider Wireless LAN adapters to be +modules, and accordingly, condition system-level regulatory approval +upon receipt and review of test data documenting that the antennas and +system configuration do not cause the EMC and radio operation to be +non-compliant. + +The drivers available for download from SourceForge are provided as a +part of a development project. Conformance to local regulatory +requirements is the responsibility of the individual developer. As +such, if you are interested in deploying or shipping a driver as part of +solution intended to be used for purposes other than development, please +obtain a tested driver from Intel Customer Support at: + +http://support.intel.com/support/notebook/sb/CS-006408.htm 1. Introduction @@ -45,7 +101,7 @@ file. 1.1. Overview of Features ----------------------------------------------- -The current release (1.0.0) supports the following features: +The current release (1.0.8) supports the following features: + BSS mode (Infrastructure, Managed) + IBSS mode (Ad-Hoc) @@ -56,17 +112,27 @@ The current release (1.0.0) supports the following features: + Full A rate support (2915 only) + Transmit power control + S state support (ACPI suspend/resume) + +The following features are currently enabled, but not officially +supported: + ++ WPA + long/short preamble support ++ Monitor mode (aka RFMon) + +The distinction between officially supported and enabled is a reflection +on the amount of validation and interoperability testing that has been +performed on a given feature. 1.2. Command Line Parameters ----------------------------------------------- -Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless -2915ABG Driver for Linux allows certain configuration options to be -provided as module parameters. The most common way to specify a module -parameter is via the command line. +Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless +2915ABG Driver for Linux allows configuration options to be provided +as module parameters. The most common way to specify a module parameter +is via the command line. The general form is: @@ -96,14 +162,18 @@ Where the supported parameter are: debug If using a debug build, this is used to control the amount of debug - info is logged. See the 'dval' and 'load' script for more info on - how to use this (the dval and load scripts are provided as part + info is logged. See the 'dvals' and 'load' script for more info on + how to use this (the dvals and load scripts are provided as part of the ipw2200 development snapshot releases available from the SourceForge project at http://ipw2200.sf.net) + + led + Can be used to turn on experimental LED code. + 0 = Off, 1 = On. Default is 0. mode Can be used to set the default mode of the adapter. - 0 = Managed, 1 = Ad-Hoc + 0 = Managed, 1 = Ad-Hoc, 2 = Monitor 1.3. Wireless Extension Private Methods @@ -164,8 +234,8 @@ The supported private methods are: ----------------------------------------------- The Linux kernel provides a pseudo file system that can be used to -access various components of the operating system. The Intel(R) -PRO/Wireless 2915ABG Driver for Linux exposes several configuration +access various components of the operating system. The Intel(R) +PRO/Wireless 2915ABG Driver for Linux exposes several configuration parameters through this mechanism. An entry in the sysfs can support reading and/or writing. You can @@ -184,13 +254,13 @@ You can set the debug level via: Where $VALUE would be a number in the case of this sysfs entry. The input to sysfs files does not have to be a number. For example, the -firmware loader used by hotplug utilizes sysfs entries for transferring +firmware loader used by hotplug utilizes sysfs entries for transfering the firmware image from user space into the driver. The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries -at two levels -- driver level, which apply to all instances of the -driver (in the event that there are more than one device installed) and -device level, which applies only to the single specific instance. +at two levels -- driver level, which apply to all instances of the driver +(in the event that there are more than one device installed) and device +level, which applies only to the single specific instance. 1.4.1 Driver Level Sysfs Helper Files @@ -203,6 +273,7 @@ For the driver level files, look in /sys/bus/pci/drivers/ipw2200/ This controls the same global as the 'debug' module parameter + 1.4.2 Device Level Sysfs Helper Files ----------------------------------------------- @@ -213,7 +284,7 @@ For the device level files, look in For example: /sys/bus/pci/drivers/ipw2200/0000:02:01.0 -For the device level files, see /sys/bus/pci/[drivers/ipw2200: +For the device level files, see /sys/bus/pci/drivers/ipw2200: rf_kill read - @@ -231,8 +302,59 @@ For the device level files, see /sys/bus/pci/[drivers/ipw2200: ucode read-only access to the ucode version number + led + read - + 0 = LED code disabled + 1 = LED code enabled + write - + 0 = Disable LED code + 1 = Enable LED code + + NOTE: The LED code has been reported to hang some systems when + running ifconfig and is therefore disabled by default. + + +2. Ad-Hoc Networking +----------------------------------------------- + +When using a device in an Ad-Hoc network, it is useful to understand the +sequence and requirements for the driver to be able to create, join, or +merge networks. + +The following attempts to provide enough information so that you can +have a consistent experience while using the driver as a member of an +Ad-Hoc network. + +2.1. Joining an Ad-Hoc Network +----------------------------------------------- + +The easiest way to get onto an Ad-Hoc network is to join one that +already exists. -2. About the Version Numbers +2.2. Creating an Ad-Hoc Network +----------------------------------------------- + +An Ad-Hoc networks is created using the syntax of the Wireless tool. + +For Example: +iwconfig eth1 mode ad-hoc essid testing channel 2 + +2.3. Merging Ad-Hoc Networks +----------------------------------------------- + + +3. Interaction with Wireless Tools +----------------------------------------------- + +3.1 iwconfig mode +----------------------------------------------- + +When configuring the mode of the adapter, all run-time configured parameters +are reset to the value used when the module was loaded. This includes +channels, rates, ESSID, etc. + + +4. About the Version Numbers ----------------------------------------------- Due to the nature of open source development projects, there are @@ -259,12 +381,23 @@ available as quickly as possible, unknown anomalies should be expected. The major version number will be incremented when significant changes are made to the driver. Currently, there are no major changes planned. +5. Firmware installation +---------------------------------------------- + +The driver requires a firmware image, download it and extract the +files under /lib/firmware (or wherever your hotplug's firmware.agent +will look for firmware files) + +The firmware can be downloaded from the following URL: -3. Support + http://ipw2200.sf.net/ + + +6. Support ----------------------------------------------- -For installation support of the 1.0.0 version, you can contact -http://supportmail.intel.com, or you can use the open source project +For direct support of the 1.0.0 version, you can contact +http://supportmail.intel.com, or you can use the open source project support. For general information and support, go to: @@ -272,7 +405,7 @@ For general information and support, go to: http://ipw2200.sf.net/ -4. License +7. License ----------------------------------------------- Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. @@ -297,4 +430,3 @@ For general information and support, go to: James P. Ketrenos Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - diff --git a/MAINTAINERS b/MAINTAINERS index d57c491212b1..c051f493d0dc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1310,6 +1310,24 @@ M: john.ronciak@intel.com W: http://sourceforge.net/projects/e1000/ S: Supported +INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT +P: Yi Zhu +M: yi.zhu@intel.com +P: James Ketrenos +M: jketreno@linux.intel.com +L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel +W: http://ipw2100.sourceforge.net +S: Supported + +INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT +P: Yi Zhu +M: yi.zhu@intel.com +P: James Ketrenos +M: jketreno@linux.intel.com +L: http://lists.sourceforge.net/mailman/listinfo/ipw2100-devel +W: http://ipw2200.sourceforge.net +S: Supported + IOC3 DRIVER P: Ralf Baechle M: ralf@linux-mips.org -- cgit v1.2.3-59-g8ed1b