From 8fbd962e39517dfb2bfd363eba4b51cdfa299593 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 29 Oct 2009 13:42:41 +0000 Subject: [PATCH 01/36] e100: e100_phy_init() isolates selected PHY, causes 10 second boot delay A change in how PHYs are electrically isolated caused all PHYs to be isolated followed by reverting that isolation for the selected PHY. Unfortunately, isolating the selected PHY for even a short period of time can result in DHCP negotiation taking more than 10 seconds on certain embedded configurations delaying boot time as reported by Bernhard Kaindl. This patch reverts the change to how PHYs are isolated yet still works around the issue for 82552 needing the selected PHY's BMCR register to be written after the unused PHYs are isolated. This code is moved below the setting of nic->phy ID in order to do the 82552-specific workaround. Cc: Bernhard Kaindl Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e100.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 679965c2bb86..d19b0845970a 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1426,19 +1426,31 @@ static int e100_phy_init(struct nic *nic) } else DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id); - /* Isolate all the PHY ids */ - for (addr = 0; addr < 32; addr++) - mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); - /* Select the discovered PHY */ - bmcr &= ~BMCR_ISOLATE; - mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr); - /* Get phy ID */ id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1); id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2); nic->phy = (u32)id_hi << 16 | (u32)id_lo; DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy); + /* Select the phy and isolate the rest */ + for (addr = 0; addr < 32; addr++) { + if (addr != nic->mii.phy_id) { + mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE); + } else if (nic->phy != phy_82552_v) { + bmcr = mdio_read(netdev, addr, MII_BMCR); + mdio_write(netdev, addr, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + } + } + /* + * Workaround for 82552: + * Clear the ISOLATE bit on selected phy_id last (mirrored on all + * other phy_id's) using bmcr value from addr discovery loop above. + */ + if (nic->phy == phy_82552_v) + mdio_write(netdev, nic->mii.phy_id, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + /* Handle National tx phys */ #define NCS_PHY_MODEL_MASK 0xFFF0FFFF if ((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) { From f523d2114e93c559dbcf1b49d46b339fc0eda37a Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 29 Oct 2009 13:45:45 +0000 Subject: [PATCH 02/36] e1000e: config PHY via software after resets On PCH-based (82577/82578) and some ICH8-based parts (82566) there is an issue with the hardware automatically configuring the PHY with contents from the EEPROM after the PHY is reset, so do the configuration by the driver instead. This was already similarly done for some 82566 parts in e1000_phy_hw_reset_ich8lan() but needs to be done after other resets, so move the PHY configuration code to its own function and call after all PHY resets. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/defines.h | 1 + drivers/net/e1000e/ich8lan.c | 295 ++++++++++++++++++++++++++--------- 2 files changed, 218 insertions(+), 78 deletions(-) diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index c0f185beb8bc..4741ef9ec385 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -347,6 +347,7 @@ /* Extended Configuration Control and Size */ #define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 +#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 #define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index b6388b9535fd..095ffa56ed94 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -124,9 +124,20 @@ #define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */ +/* SMBus Address Phy Register */ +#define HV_SMB_ADDR PHY_REG(768, 26) +#define HV_SMB_ADDR_PEC_EN 0x0200 +#define HV_SMB_ADDR_VALID 0x0080 + +/* Strapping Option Register - RO */ +#define E1000_STRAP 0x0000C +#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000 +#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17 + /* OEM Bits Phy Register */ #define HV_OEM_BITS PHY_REG(768, 25) #define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */ +#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */ #define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */ /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ @@ -208,6 +219,7 @@ static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); static s32 e1000_led_on_pchlan(struct e1000_hw *hw); static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); +static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -793,6 +805,191 @@ static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) return 0; } +/** + * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration + * @hw: pointer to the HW structure + * + * SW should configure the LCD from the NVM extended configuration region + * as a workaround for certain parts. + **/ +static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; + s32 ret_val; + u16 word_addr, reg_data, reg_addr, phy_page = 0; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + /* + * Initialize the PHY from the NVM on ICH platforms. This + * is needed due to an issue where the NVM configuration is + * not properly autoloaded after power transitions. + * Therefore, after each PHY reset, we will load the + * configuration data out of the NVM manually. + */ + if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) || + (hw->mac.type == e1000_pchlan)) { + struct e1000_adapter *adapter = hw->adapter; + + /* Check if SW needs to configure the PHY */ + if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) || + (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) || + (hw->mac.type == e1000_pchlan)) + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; + else + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + + data = er32(FEXTNVM); + if (!(data & sw_cfg_mask)) + goto out; + + /* Wait for basic configuration completes before proceeding */ + e1000_lan_init_done_ich8lan(hw); + + /* + * Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration + */ + data = er32(EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + goto out; + + cnf_size = er32(EXTCNF_SIZE); + cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; + cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; + if (!cnf_size) + goto out; + + cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; + cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; + + if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && + (hw->mac.type == e1000_pchlan)) { + /* + * HW configures the SMBus address and LEDs when the + * OEM and LCD Write Enable bits are set in the NVM. + * When both NVM bits are cleared, SW will configure + * them instead. + */ + data = er32(STRAP); + data &= E1000_STRAP_SMBUS_ADDRESS_MASK; + reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT; + reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; + ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, + reg_data); + if (ret_val) + goto out; + + data = er32(LEDCTL); + ret_val = e1000_write_phy_reg_hv_locked(hw, + HV_LED_CONFIG, + (u16)data); + if (ret_val) + goto out; + } + /* Configure LCD from extended configuration region. */ + + /* cnf_base_addr is in DWORD */ + word_addr = (u16)(cnf_base_addr << 1); + + for (i = 0; i < cnf_size; i++) { + ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1, + ®_data); + if (ret_val) + goto out; + + ret_val = e1000_read_nvm(hw, (word_addr + i * 2 + 1), + 1, ®_addr); + if (ret_val) + goto out; + + /* Save off the PHY page for future writes. */ + if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { + phy_page = reg_data; + continue; + } + + reg_addr &= PHY_REG_MASK; + reg_addr |= phy_page; + + ret_val = phy->ops.write_phy_reg_locked(hw, + (u32)reg_addr, + reg_data); + if (ret_val) + goto out; + } + } + +out: + hw->phy.ops.release_phy(hw); + return ret_val; +} + +/** + * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration + * @hw: pointer to the HW structure + * @d0_state: boolean if entering d0 or d3 device state + * + * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are + * collectively called OEM bits. The OEM Write Enable bit and SW Config bit + * in NVM determines whether HW should configure LPLU and Gbe Disable. + **/ +static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) +{ + s32 ret_val = 0; + u32 mac_reg; + u16 oem_reg; + + if (hw->mac.type != e1000_pchlan) + return ret_val; + + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + return ret_val; + + mac_reg = er32(EXTCNF_CTRL); + if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) + goto out; + + mac_reg = er32(FEXTNVM); + if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) + goto out; + + mac_reg = er32(PHY_CTRL); + + ret_val = hw->phy.ops.read_phy_reg_locked(hw, HV_OEM_BITS, &oem_reg); + if (ret_val) + goto out; + + oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); + + if (d0_state) { + if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) + oem_reg |= HV_OEM_BITS_GBE_DIS; + + if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) + oem_reg |= HV_OEM_BITS_LPLU; + } else { + if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE) + oem_reg |= HV_OEM_BITS_GBE_DIS; + + if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU) + oem_reg |= HV_OEM_BITS_LPLU; + } + /* Restart auto-neg to activate the bits */ + oem_reg |= HV_OEM_BITS_RESTART_AN; + ret_val = hw->phy.ops.write_phy_reg_locked(hw, HV_OEM_BITS, oem_reg); + +out: + hw->phy.ops.release_phy(hw); + + return ret_val; +} + + /** * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be * done after every PHY reset. @@ -882,11 +1079,8 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) { - struct e1000_phy_info *phy = &hw->phy; - u32 i; - u32 data, cnf_size, cnf_base_addr, sw_cfg_mask; - s32 ret_val; - u16 reg, word_addr, reg_data, reg_addr, phy_page = 0; + s32 ret_val = 0; + u16 reg; ret_val = e1000e_phy_hw_reset_generic(hw); if (ret_val) @@ -905,81 +1099,16 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pchlan) e1e_rphy(hw, BM_WUC, ®); - /* - * Initialize the PHY from the NVM on ICH platforms. This - * is needed due to an issue where the NVM configuration is - * not properly autoloaded after power transitions. - * Therefore, after each PHY reset, we will load the - * configuration data out of the NVM manually. - */ - if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) { - struct e1000_adapter *adapter = hw->adapter; + /* Configure the LCD with the extended configuration region in NVM */ + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; - /* Check if SW needs configure the PHY */ - if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) || - (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M)) - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; - else - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; - - data = er32(FEXTNVM); - if (!(data & sw_cfg_mask)) - return 0; - - /* Wait for basic configuration completes before proceeding */ - e1000_lan_init_done_ich8lan(hw); - - /* - * Make sure HW does not configure LCD from PHY - * extended configuration before SW configuration - */ - data = er32(EXTCNF_CTRL); - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - return 0; - - cnf_size = er32(EXTCNF_SIZE); - cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; - cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; - if (!cnf_size) - return 0; - - cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; - cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; - - /* Configure LCD from extended configuration region. */ - - /* cnf_base_addr is in DWORD */ - word_addr = (u16)(cnf_base_addr << 1); - - for (i = 0; i < cnf_size; i++) { - ret_val = e1000_read_nvm(hw, - (word_addr + i * 2), - 1, - ®_data); - if (ret_val) - return ret_val; - - ret_val = e1000_read_nvm(hw, - (word_addr + i * 2 + 1), - 1, - ®_addr); - if (ret_val) - return ret_val; - - /* Save off the PHY page for future writes. */ - if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { - phy_page = reg_data; - continue; - } - - reg_addr |= phy_page; - - ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data); - if (ret_val) - return ret_val; - } - } + /* Configure the LCD with the OEM bits in NVM */ + if (hw->mac.type == e1000_pchlan) + ret_val = e1000_oem_bits_config_ich8lan(hw, true); +out: return 0; } @@ -2386,6 +2515,15 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pchlan) e1e_rphy(hw, BM_WUC, ®); + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; + + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_oem_bits_config_ich8lan(hw, true); + if (ret_val) + goto out; + } /* * For PCH, this write will make sure that any noise * will be detected as a CRC error and be dropped rather than show up @@ -2404,6 +2542,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) if (hw->mac.type == e1000_pchlan) ret_val = e1000_hv_phy_workarounds_ich8lan(hw); +out: return ret_val; } From 1d5846b9216665d0ae743bf351d0b8fa90c40523 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Thu, 29 Oct 2009 13:46:05 +0000 Subject: [PATCH 03/36] e1000e: rework disable K1 at 1000Mbps for 82577/82578 This patch reworks a previous workaround (commit 7d3cabbcc) for an issue in hardware where noise on the interconnect between the MAC and PHY could be generated by a lower power mode (K1) at 1000Mbps resulting in bad packets. Disable K1 while at 1000 Mbps but keep it enabled for 10/100Mbps and when the cable is disconnected. The original version of this workaround was found to be incomplete. Signed-off-by: Bruce Allan Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/e1000e/defines.h | 1 + drivers/net/e1000e/e1000.h | 14 +++ drivers/net/e1000e/hw.h | 1 + drivers/net/e1000e/ich8lan.c | 187 +++++++++++++++++++++++++++++++---- drivers/net/e1000e/phy.c | 15 +-- 5 files changed, 190 insertions(+), 28 deletions(-) diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 4741ef9ec385..1190167a8b3d 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -76,6 +76,7 @@ /* Extended Device Control */ #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ #define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ #define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ #define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */ #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 405a144ebcad..189dfa2d6c76 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -141,6 +141,20 @@ struct e1000_info; #define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ #define HV_TNCRS_LOWER PHY_REG(778, 30) +/* BM PHY Copper Specific Status */ +#define BM_CS_STATUS 17 +#define BM_CS_STATUS_LINK_UP 0x0400 +#define BM_CS_STATUS_RESOLVED 0x0800 +#define BM_CS_STATUS_SPEED_MASK 0xC000 +#define BM_CS_STATUS_SPEED_1000 0x8000 + +/* 82577 Mobile Phy Status Register */ +#define HV_M_STATUS 26 +#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000 +#define HV_M_STATUS_SPEED_MASK 0x0300 +#define HV_M_STATUS_SPEED_1000 0x0200 +#define HV_M_STATUS_LINK_UP 0x0040 + enum e1000_boards { board_82571, board_82572, diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 7b05cf47f7f5..aaea41ef794d 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -903,6 +903,7 @@ struct e1000_shadow_ram { struct e1000_dev_spec_ich8lan { bool kmrn_lock_loss_workaround_enabled; struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; + bool nvm_k1_enabled; }; struct e1000_hw { diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 095ffa56ed94..51ddb04ab195 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -140,6 +140,9 @@ #define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */ #define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */ +#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */ +#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */ + /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ union ich8_hws_flash_status { @@ -220,6 +223,8 @@ static s32 e1000_led_on_pchlan(struct e1000_hw *hw); static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); +static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); +static s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -495,14 +500,6 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) goto out; } - if (hw->mac.type == e1000_pchlan) { - ret_val = e1000e_write_kmrn_reg(hw, - E1000_KMRNCTRLSTA_K1_CONFIG, - E1000_KMRNCTRLSTA_K1_ENABLE); - if (ret_val) - goto out; - } - /* * First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -512,6 +509,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) if (ret_val) goto out; + if (hw->mac.type == e1000_pchlan) { + ret_val = e1000_k1_gig_workaround_hv(hw, link); + if (ret_val) + goto out; + } + if (!link) goto out; /* No link detected */ @@ -928,6 +931,141 @@ out: return ret_val; } +/** + * e1000_k1_gig_workaround_hv - K1 Si workaround + * @hw: pointer to the HW structure + * @link: link up bool flag + * + * If K1 is enabled for 1Gbps, the MAC might stall when transitioning + * from a lower speed. This workaround disables K1 whenever link is at 1Gig + * If link is down, the function will restore the default K1 setting located + * in the NVM. + **/ +static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) +{ + s32 ret_val = 0; + u16 status_reg = 0; + bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; + + if (hw->mac.type != e1000_pchlan) + goto out; + + /* Wrap the whole flow with the sw flag */ + ret_val = hw->phy.ops.acquire_phy(hw); + if (ret_val) + goto out; + + /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ + if (link) { + if (hw->phy.type == e1000_phy_82578) { + ret_val = hw->phy.ops.read_phy_reg_locked(hw, + BM_CS_STATUS, + &status_reg); + if (ret_val) + goto release; + + status_reg &= BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_MASK; + + if (status_reg == (BM_CS_STATUS_LINK_UP | + BM_CS_STATUS_RESOLVED | + BM_CS_STATUS_SPEED_1000)) + k1_enable = false; + } + + if (hw->phy.type == e1000_phy_82577) { + ret_val = hw->phy.ops.read_phy_reg_locked(hw, + HV_M_STATUS, + &status_reg); + if (ret_val) + goto release; + + status_reg &= HV_M_STATUS_LINK_UP | + HV_M_STATUS_AUTONEG_COMPLETE | + HV_M_STATUS_SPEED_MASK; + + if (status_reg == (HV_M_STATUS_LINK_UP | + HV_M_STATUS_AUTONEG_COMPLETE | + HV_M_STATUS_SPEED_1000)) + k1_enable = false; + } + + /* Link stall fix for link up */ + ret_val = hw->phy.ops.write_phy_reg_locked(hw, PHY_REG(770, 19), + 0x0100); + if (ret_val) + goto release; + + } else { + /* Link stall fix for link down */ + ret_val = hw->phy.ops.write_phy_reg_locked(hw, PHY_REG(770, 19), + 0x4100); + if (ret_val) + goto release; + } + + ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); + +release: + hw->phy.ops.release_phy(hw); +out: + return ret_val; +} + +/** + * e1000_configure_k1_ich8lan - Configure K1 power state + * @hw: pointer to the HW structure + * @enable: K1 state to configure + * + * Configure the K1 power state based on the provided parameter. + * Assumes semaphore already acquired. + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + **/ +static s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) +{ + s32 ret_val = 0; + u32 ctrl_reg = 0; + u32 ctrl_ext = 0; + u32 reg = 0; + u16 kmrn_reg = 0; + + ret_val = e1000e_read_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + &kmrn_reg); + if (ret_val) + goto out; + + if (k1_enable) + kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; + else + kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; + + ret_val = e1000e_write_kmrn_reg_locked(hw, + E1000_KMRNCTRLSTA_K1_CONFIG, + kmrn_reg); + if (ret_val) + goto out; + + udelay(20); + ctrl_ext = er32(CTRL_EXT); + ctrl_reg = er32(CTRL); + + reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + reg |= E1000_CTRL_FRCSPD; + ew32(CTRL, reg); + + ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); + udelay(20); + ew32(CTRL, ctrl_reg); + ew32(CTRL_EXT, ctrl_ext); + udelay(20); + +out: + return ret_val; +} + /** * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration * @hw: pointer to the HW structure @@ -1030,10 +1168,20 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) ret_val = hw->phy.ops.acquire_phy(hw); if (ret_val) return ret_val; + hw->phy.addr = 1; - e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); + if (ret_val) + goto out; hw->phy.ops.release_phy(hw); + /* + * Configure the K1 Si workaround during phy reset assuming there is + * link so that it disables K1 if link is in 1Gbps. + */ + ret_val = e1000_k1_gig_workaround_hv(hw, true); + +out: return ret_val; } @@ -2435,6 +2583,7 @@ static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) **/ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) { + struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; u16 reg; u32 ctrl, icr, kab; s32 ret_val; @@ -2470,6 +2619,18 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ew32(PBS, E1000_PBS_16K); } + if (hw->mac.type == e1000_pchlan) { + /* Save the NVM K1 bit setting*/ + ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®); + if (ret_val) + return ret_val; + + if (reg & E1000_NVM_K1_ENABLE) + dev_spec->nvm_k1_enabled = true; + else + dev_spec->nvm_k1_enabled = false; + } + ctrl = er32(CTRL); if (!e1000_check_reset_block(hw)) { @@ -2847,14 +3008,6 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, if (ret_val) return ret_val; - if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) { - ret_val = e1000e_write_kmrn_reg(hw, - E1000_KMRNCTRLSTA_K1_CONFIG, - E1000_KMRNCTRLSTA_K1_DISABLE); - if (ret_val) - return ret_val; - } - if ((hw->mac.type == e1000_ich8lan) && (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index f9d33ab05e97..03175b3a2c9e 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -95,13 +95,6 @@ static const u16 e1000_igp_2_cable_length_table[] = /* BM PHY Copper Specific Control 1 */ #define BM_CS_CTRL1 16 -/* BM PHY Copper Specific Status */ -#define BM_CS_STATUS 17 -#define BM_CS_STATUS_LINK_UP 0x0400 -#define BM_CS_STATUS_RESOLVED 0x0800 -#define BM_CS_STATUS_SPEED_MASK 0xC000 -#define BM_CS_STATUS_SPEED_1000 0x8000 - #define HV_MUX_DATA_CTRL PHY_REG(776, 16) #define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400 #define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004 @@ -563,7 +556,7 @@ s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) } /** - * e1000_read_kmrn_reg_locked - Read kumeran register + * e1000e_read_kmrn_reg_locked - Read kumeran register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data @@ -572,7 +565,7 @@ s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) * information retrieved is stored in data. * Assumes semaphore already acquired. **/ -s32 e1000_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data) +s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data) { return __e1000_read_kmrn_reg(hw, offset, data, true); } @@ -631,7 +624,7 @@ s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) } /** - * e1000_write_kmrn_reg_locked - Write kumeran register + * e1000e_write_kmrn_reg_locked - Write kumeran register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset @@ -639,7 +632,7 @@ s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) * Write the data to PHY register at the offset using the kumeran interface. * Assumes semaphore already acquired. **/ -s32 e1000_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) +s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) { return __e1000_write_kmrn_reg(hw, offset, data, true); } From 14d18a81b5171d4433e41129619c75748b4f4d26 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 29 Oct 2009 00:10:37 +0000 Subject: [PATCH 04/36] net: fix kmemcheck annotations struct sk_buff kmemcheck annotations enlarged this structure by 8/16 bytes Fix this by moving 'protocol' inside flags1 bitfield, and queue_mapping inside flags2 bitfield. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index df7b23ac66e6..6aebfceca3eb 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -354,8 +354,8 @@ struct sk_buff { ipvs_property:1, peeked:1, nf_trace:1; + __be16 protocol:16; kmemcheck_bitfield_end(flags1); - __be16 protocol; void (*destructor)(struct sk_buff *skb); #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) @@ -367,7 +367,6 @@ struct sk_buff { #endif int iif; - __u16 queue_mapping; #ifdef CONFIG_NET_SCHED __u16 tc_index; /* traffic control index */ #ifdef CONFIG_NET_CLS_ACT @@ -376,6 +375,7 @@ struct sk_buff { #endif kmemcheck_bitfield_begin(flags2); + __u16 queue_mapping:16; #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif From b0c110ca8e89f2c9cd52ec7fb1b98c5b7aa78496 Mon Sep 17 00:00:00 2001 From: jamal Date: Sun, 18 Oct 2009 02:12:33 +0000 Subject: [PATCH 05/36] net: Fix RPF to work with policy routing Policy routing is not looked up by mark on reverse path filtering. This fixes it. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/net/ip_fib.h | 3 ++- net/ipv4/fib_frontend.c | 5 ++++- net/ipv4/route.c | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index ef91fe924ba4..4d22fabc7719 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -210,7 +210,8 @@ extern struct fib_table *fib_get_table(struct net *net, u32 id); extern const struct nla_policy rtm_ipv4_policy[]; extern void ip_fib_init(void); extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, - struct net_device *dev, __be32 *spec_dst, u32 *itag); + struct net_device *dev, __be32 *spec_dst, + u32 *itag, u32 mark); extern void fib_select_default(struct net *net, const struct flowi *flp, struct fib_result *res); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e2f950592566..aa00398be80e 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -229,14 +229,17 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, */ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, - struct net_device *dev, __be32 *spec_dst, u32 *itag) + struct net_device *dev, __be32 *spec_dst, + u32 *itag, u32 mark) { struct in_device *in_dev; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = src, .saddr = dst, .tos = tos } }, + .mark = mark, .iif = oif }; + struct fib_result res; int no_addr, rpf; int ret; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bb4199252026..5b1050a5d874 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1854,7 +1854,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, goto e_inval; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else if (fib_validate_source(saddr, 0, tos, 0, - dev, &spec_dst, &itag) < 0) + dev, &spec_dst, &itag, 0) < 0) goto e_inval; rth = dst_alloc(&ipv4_dst_ops); @@ -1967,7 +1967,7 @@ static int __mkroute_input(struct sk_buff *skb, err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), - in_dev->dev, &spec_dst, &itag); + in_dev->dev, &spec_dst, &itag, skb->mark); if (err < 0) { ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, saddr); @@ -2141,7 +2141,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, int result; result = fib_validate_source(saddr, daddr, tos, net->loopback_dev->ifindex, - dev, &spec_dst, &itag); + dev, &spec_dst, &itag, skb->mark); if (result < 0) goto martian_source; if (result) @@ -2170,7 +2170,7 @@ brd_input: spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); else { err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, - &itag); + &itag, skb->mark); if (err < 0) goto martian_source; if (err) From 18eb0893c12898253c18ba23b51a6ea9a07ba4c7 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Sat, 3 Oct 2009 11:26:55 +0000 Subject: [PATCH 06/36] ibmtr: possible Read buffer overflow? Prevent read outside array bounds. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller --- drivers/net/tokenring/ibmtr.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 525bbc5b9c9d..6a3c7510afd9 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -1143,9 +1143,16 @@ static void dir_open_adapter (struct net_device *dev) } else { char **prphase = printphase; char **prerror = printerror; + int pnr = err / 16 - 1; + int enr = err % 16 - 1; DPRINTK("TR Adapter misc open failure, error code = "); - printk("0x%x, Phase: %s, Error: %s\n", - err, prphase[err/16 -1], prerror[err%16 -1]); + if (pnr < 0 || pnr >= ARRAY_SIZE(printphase) || + enr < 0 || + enr >= ARRAY_SIZE(printerror)) + printk("0x%x, invalid Phase/Error.", err); + else + printk("0x%x, Phase: %s, Error: %s\n", err, + prphase[pnr], prerror[enr]); printk(" retrying after %ds delay...\n", TR_RETRY_INTERVAL/HZ); } From 207d6e8760c6a3323bf5ab098dbaa5c9d03bda83 Mon Sep 17 00:00:00 2001 From: Raimonds Cicans Date: Mon, 26 Oct 2009 10:52:37 +0000 Subject: [PATCH 07/36] r8169: Fix card drop incoming VLAN tagged MTU byte large jumbo frames r8169 card drop incoming VLAN tagged MTU byte large jumbo frames It looks to compare current and maximal packet sizes hardware use '<' operator, not '<='. Bug introduced by commit fdd7b4c3302c93f6833e338903ea77245eb510b4 ("r8169: fix crash when large packets are received") Signed-off-by: Raimonds Cicans Signed-off-by: David S. Miller --- drivers/net/r8169.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index f98ef523f525..fa4935678488 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3379,7 +3379,7 @@ static u16 rtl_rw_cpluscmd(void __iomem *ioaddr) static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz) { /* Low hurts. Let's disable the filtering. */ - RTL_W16(RxMaxSize, rx_buf_sz); + RTL_W16(RxMaxSize, rx_buf_sz + 1); } static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) From 63ca2d74ea4f9c7a7ac082c915609a7b224908e7 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Sat, 17 Oct 2009 15:39:20 +0000 Subject: [PATCH 08/36] pcnet_cs: add cis of PreMax PE-200 ethernet pcmcia card pcnet_cs,serial_cs: add cis of PreMax ethernet pcmcia card, and some Sierra Wireless serial card(AC555, AC7xx, AC8xx). use PROD_ID for AC7xx, because MANF_ID of AC7xx and AC8xx are the same. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller --- drivers/net/pcmcia/pcnet_cs.c | 2 +- drivers/serial/serial_cs.c | 8 ++++---- firmware/Makefile | 6 ++++-- firmware/WHENCE | 4 ++++ firmware/cis/PE-200.cis.ihex | 9 +++++++++ firmware/cis/SW_555_SER.cis.ihex | 12 ++++++++++++ firmware/cis/SW_7xx_SER.cis.ihex | 13 +++++++++++++ firmware/cis/SW_8xx_SER.cis.ihex | 13 +++++++++++++ 8 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 firmware/cis/PE-200.cis.ihex create mode 100644 firmware/cis/SW_555_SER.cis.ihex create mode 100644 firmware/cis/SW_7xx_SER.cis.ihex create mode 100644 firmware/cis/SW_8xx_SER.cis.ihex diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index bd3447f04902..94c9ad2746bc 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1760,7 +1760,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "cis/LA-PCM.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "PE520.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "PE-200.cis"), + PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "cis/tamarack.cis"), PCMCIA_DEVICE_PROD_ID12("Ethernet", "CF Size PC Card", 0x00b2e941, 0x43ac239b), PCMCIA_DEVICE_PROD_ID123("Fast Ethernet", "CF Size PC Card", "1.0", diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index ff4617e21426..7c7914f5fa02 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -879,10 +879,10 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"), - PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ - PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ - PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ - PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ + PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "cis/SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */ + PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC710/AC750", 0xd85f6206, 0x761b11e0, "cis/SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */ + PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */ + PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "cis/SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */ PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"), diff --git a/firmware/Makefile b/firmware/Makefile index a6c7c3e47e42..f4ca0c7eb51c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -69,11 +69,13 @@ fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis \ cis/DP83903.cis cis/NE2K.cis \ - cis/tamarack.cis + cis/tamarack.cis cis/PE-200.cis fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \ - cis/COMpad2.cis cis/COMpad4.cis + cis/COMpad2.cis cis/COMpad4.cis \ + cis/SW_555_SER.cis cis/SW_7xx_SER.cis \ + cis/SW_8xx_SER.cis fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ advansys/3550.bin advansys/38C0800.bin diff --git a/firmware/WHENCE b/firmware/WHENCE index c437e14f0b11..7a8adc06eb34 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -600,6 +600,7 @@ File: cis/LA-PCM.cis cis/DP83903.cis cis/NE2K.cis cis/tamarack.cis + cis/PE-200.cis Licence: GPL @@ -633,6 +634,9 @@ File: cis/MT5634ZLX.cis cis/RS-COM-2P.cis cis/COMpad2.cis cis/COMpad4.cis + cis/SW_555_SER.cis + cis/SW_7xx_SER.cis + cis/SW_8xx_SER.cis Licence: GPL diff --git a/firmware/cis/PE-200.cis.ihex b/firmware/cis/PE-200.cis.ihex new file mode 100644 index 000000000000..e6dbdab6eb79 --- /dev/null +++ b/firmware/cis/PE-200.cis.ihex @@ -0,0 +1,9 @@ +:1000000001030000FF151E0401504D582020200060 +:1000100050452D3230300045544845524E4554002D +:1000200052303100FF210206031A050101000101CF +:100030001B0EC181190155E051000F100F30FFFF59 +:040040001400FF00A9 +:00000001FF +# +# Replacement CIS for PE-200 ethernet card +# diff --git a/firmware/cis/SW_555_SER.cis.ihex b/firmware/cis/SW_555_SER.cis.ihex new file mode 100644 index 000000000000..9b9348acee7b --- /dev/null +++ b/firmware/cis/SW_555_SER.cis.ihex @@ -0,0 +1,12 @@ +:100000000101FF17034100FF20043F0110072102F7 +:100010000200152A070053696572726120576972E0 +:10002000656C657373004169724361726420353594 +:1000300035004135353500526576203100FF1A050F +:1000400001030007731B0BE00118A360F8030730DE +:10005000BC3F1B08A10108A360F802071B08A2010E +:1000600008A360E803071B08A30108A360E80207D0 +:0A0070001B04A40108231400FF0084 +:00000001FF +# +# Replacement CIS for AC555 provided by Sierra Wireless +# diff --git a/firmware/cis/SW_7xx_SER.cis.ihex b/firmware/cis/SW_7xx_SER.cis.ihex new file mode 100644 index 000000000000..11e44ad86437 --- /dev/null +++ b/firmware/cis/SW_7xx_SER.cis.ihex @@ -0,0 +1,13 @@ +:100000000101FF17034100FF2004920110072102A4 +:1000100002001537070053696572726120576972D3 +:10002000656C6573730041433731302F4143373579 +:10003000300047505253204E6574776F726B2041E9 +:1000400064617074657200523100FF1A050103008B +:1000500007731B10E00119784D555D25A360F80367 +:100060000730BC861B08A10108A360F802071B0823 +:10007000A20108A360E803071B08A30108A360E826 +:0C00800002071B04A40108231400FF0069 +:00000001FF +# +# Replacement CIS for AC7xx provided by Sierra Wireless +# diff --git a/firmware/cis/SW_8xx_SER.cis.ihex b/firmware/cis/SW_8xx_SER.cis.ihex new file mode 100644 index 000000000000..bbcfe6348328 --- /dev/null +++ b/firmware/cis/SW_8xx_SER.cis.ihex @@ -0,0 +1,13 @@ +:100000000101FF17034100FF2004920110072102A4 +:100010000200152F070053696572726120576972DB +:10002000656C657373004143383530003347204EAB +:100030006574776F726B20416461707465720052F1 +:100040003100FF1A0501030007731B10E001197846 +:100050004D555D25A360F8480730BC861B08A101FB +:1000600008A360F847071B08A20108A360E8480737 +:100070001B08A30108A360E847071B04A401082389 +:040080001400FF0069 +:00000001FF +# +# Replacement CIS for AC8xx provided by Sierra Wireless +# From 9d410c796067686b1e032d54ce475b7055537138 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 30 Oct 2009 05:03:53 +0000 Subject: [PATCH 09/36] net: fix sk_forward_alloc corruption On UDP sockets, we must call skb_free_datagram() with socket locked, or risk sk_forward_alloc corruption. This requirement is not respected in SUNRPC. Add a convenient helper, skb_free_datagram_locked() and use it in SUNRPC Reported-by: Francis Moreau Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 2 ++ net/core/datagram.c | 10 +++++++++- net/ipv4/udp.c | 4 +--- net/ipv6/udp.c | 4 +--- net/sunrpc/svcsock.c | 10 +++++----- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6aebfceca3eb..bcdd6606f468 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1757,6 +1757,8 @@ extern int skb_copy_datagram_const_iovec(const struct sk_buff *from, int to_offset, int size); extern void skb_free_datagram(struct sock *sk, struct sk_buff *skb); +extern void skb_free_datagram_locked(struct sock *sk, + struct sk_buff *skb); extern int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); extern __wsum skb_checksum(const struct sk_buff *skb, int offset, diff --git a/net/core/datagram.c b/net/core/datagram.c index 1c6cf3a1a4f6..4ade3011bb3c 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -224,6 +224,15 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) consume_skb(skb); sk_mem_reclaim_partial(sk); } +EXPORT_SYMBOL(skb_free_datagram); + +void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb) +{ + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +} +EXPORT_SYMBOL(skb_free_datagram_locked); /** * skb_kill_datagram - Free a datagram skbuff forcibly @@ -752,5 +761,4 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); EXPORT_SYMBOL(skb_copy_datagram_iovec); -EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_recv_datagram); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d0d436d6216c..0fa9f70e4b19 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -999,9 +999,7 @@ try_again: err = ulen; out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); + skb_free_datagram_locked(sk, skb); out: return err; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3a60f12b34ed..cf538ed5ef6a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -288,9 +288,7 @@ try_again: err = ulen; out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); + skb_free_datagram_locked(sk, skb); out: return err; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index ccc5e83cae5d..1c246a4f491e 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -111,7 +111,7 @@ static void svc_release_skb(struct svc_rqst *rqstp) rqstp->rq_xprt_ctxt = NULL; dprintk("svc: service %p, releasing skb %p\n", rqstp, skb); - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); } } @@ -578,7 +578,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) "svc: received unknown control message %d/%d; " "dropping RPC reply datagram\n", cmh->cmsg_level, cmh->cmsg_type); - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } @@ -588,18 +588,18 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) { local_bh_enable(); /* checksum error */ - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } local_bh_enable(); - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); } else { /* we can use it in-place */ rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr); rqstp->rq_arg.head[0].iov_len = len; if (skb_checksum_complete(skb)) { - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } rqstp->rq_xprt_ctxt = skb; From 33cb7d33a1c36e07839d08a4d1a33bf6a0f70bba Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Thu, 29 Oct 2009 13:58:07 +0000 Subject: [PATCH 10/36] sky2: set carrier off in probe Before bringing up a sky2 interface up ethtool reports "Link detected: yes". Do as ixgbe does and netif_carrier_off() on probe(). Signed-off-by: Brandon Philips Signed-off-by: David S. Miller --- drivers/net/sky2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2ab5c39f33ca..6a10d7ba5877 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4538,6 +4538,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_free_netdev; } + netif_carrier_off(dev); + netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT); err = request_irq(pdev->irq, sky2_intr, From 2e9526b352061ee0fd2a1580a2e3a5af960dabc4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 30 Oct 2009 05:51:48 +0000 Subject: [PATCH 11/36] gre: Fix dev_addr clobbering for gretap Nathan Neulinger noticed that gretap devices get their MAC address from the local IP address, which results in invalid MAC addresses half of the time. This is because gretap is still using the tunnel netdev ops rather than the correct tap netdev ops struct. This patch also fixes changelink to not clobber the MAC address for the gretap case. Signed-off-by: Herbert Xu Acked-by: Stephen Hemminger Tested-by: Nathan Neulinger Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 41ada9904d31..143333852624 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1464,7 +1464,7 @@ static void ipgre_tap_setup(struct net_device *dev) ether_setup(dev); - dev->netdev_ops = &ipgre_netdev_ops; + dev->netdev_ops = &ipgre_tap_netdev_ops; dev->destructor = free_netdev; dev->iflink = 0; @@ -1525,25 +1525,29 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], if (t->dev != dev) return -EEXIST; } else { - unsigned nflags = 0; - t = nt; - if (ipv4_is_multicast(p.iph.daddr)) - nflags = IFF_BROADCAST; - else if (p.iph.daddr) - nflags = IFF_POINTOPOINT; + if (dev->type != ARPHRD_ETHER) { + unsigned nflags = 0; - if ((dev->flags ^ nflags) & - (IFF_POINTOPOINT | IFF_BROADCAST)) - return -EINVAL; + if (ipv4_is_multicast(p.iph.daddr)) + nflags = IFF_BROADCAST; + else if (p.iph.daddr) + nflags = IFF_POINTOPOINT; + + if ((dev->flags ^ nflags) & + (IFF_POINTOPOINT | IFF_BROADCAST)) + return -EINVAL; + } ipgre_tunnel_unlink(ign, t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; t->parms.i_key = p.i_key; - memcpy(dev->dev_addr, &p.iph.saddr, 4); - memcpy(dev->broadcast, &p.iph.daddr, 4); + if (dev->type != ARPHRD_ETHER) { + memcpy(dev->dev_addr, &p.iph.saddr, 4); + memcpy(dev->broadcast, &p.iph.daddr, 4); + } ipgre_tunnel_link(ign, t); netdev_state_change(dev); } From e6c5fc53d0f44a772398402ee8a1879818e42b4e Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 15 Oct 2009 14:50:28 +0800 Subject: [PATCH 12/36] ipw2200: fix oops on missing firmware For non-monitor interfaces, the syntax for alloc_ieee80211/free_80211 is wrong. Because alloc_ieee80211 only creates (wiphy_new) a wiphy, but free_80211() does wiphy_unregister() also. This is only correct when the later wiphy_register() is called successfully, which apparently is not the case for your fw doesn't exist one. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 5 ++++- drivers/net/wireless/ipw2x00/ipw2200.c | 2 ++ drivers/net/wireless/ipw2x00/libipw.h | 1 + drivers/net/wireless/ipw2x00/libipw_module.c | 14 +++++++++----- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 240cff1e6979..a741d37fd96f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -6325,8 +6325,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, fail: if (dev) { - if (registered) + if (registered) { + unregister_ieee80211(priv->ieee); unregister_netdev(dev); + } ipw2100_hw_stop_adapter(priv); @@ -6383,6 +6385,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) /* Unregister the device first - this results in close() * being called if the device is open. If we free storage * first, then close() will crash. */ + unregister_ieee80211(priv->ieee); unregister_netdev(dev); /* ipw2100_down will ensure that there is no more pending work diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 8d58e6ed4e7d..04341a2a6193 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11821,6 +11821,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, if (err) { IPW_ERROR("Failed to register promiscuous network " "device (error %d).\n", err); + unregister_ieee80211(priv->ieee); unregister_netdev(priv->net_dev); goto out_remove_sysfs; } @@ -11871,6 +11872,7 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) mutex_unlock(&priv->mutex); + unregister_ieee80211(priv->ieee); unregister_netdev(priv->net_dev); if (priv->rxq) { diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h index bf45391172f3..f42ade6c2d3e 100644 --- a/drivers/net/wireless/ipw2x00/libipw.h +++ b/drivers/net/wireless/ipw2x00/libipw.h @@ -1020,6 +1020,7 @@ static inline int libipw_is_cck_rate(u8 rate) /* ieee80211.c */ extern void free_ieee80211(struct net_device *dev, int monitor); extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor); +extern void unregister_ieee80211(struct libipw_device *ieee); extern int libipw_change_mtu(struct net_device *dev, int new_mtu); extern void libipw_networks_age(struct libipw_device *ieee, diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index a0e9f6aed7da..be5b809ec97a 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -235,16 +235,19 @@ void free_ieee80211(struct net_device *dev, int monitor) libipw_networks_free(ieee); /* free cfg80211 resources */ - if (!monitor) { - wiphy_unregister(ieee->wdev.wiphy); - kfree(ieee->a_band.channels); - kfree(ieee->bg_band.channels); + if (!monitor) wiphy_free(ieee->wdev.wiphy); - } free_netdev(dev); } +void unregister_ieee80211(struct libipw_device *ieee) +{ + wiphy_unregister(ieee->wdev.wiphy); + kfree(ieee->a_band.channels); + kfree(ieee->bg_band.channels); +} + #ifdef CONFIG_LIBIPW_DEBUG static int debug = 0; @@ -330,3 +333,4 @@ module_init(libipw_init); EXPORT_SYMBOL(alloc_ieee80211); EXPORT_SYMBOL(free_ieee80211); +EXPORT_SYMBOL(unregister_ieee80211); From 227206455fde433f86305f9a5b8bdd1eca759929 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Mon, 19 Oct 2009 11:51:11 +0200 Subject: [PATCH 13/36] rt73usb.c : more ids stolen from windows inf file(07/17/2009, 1.03.05.0000) Ovislink 0x1b75, 0x7318 MSI 0x0db0, 0x4600 WideTell 0x7167, 0x3840 Signed-off-by: Xose Vazquez Perez Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index b8f5ee33445e..14e7bb210075 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2389,10 +2389,13 @@ static struct usb_device_id rt73usb_device_table[] = { { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) }, /* MSI */ + { USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, + /* Ovislink */ + { USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) }, /* Ralink */ { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, @@ -2420,6 +2423,8 @@ static struct usb_device_id rt73usb_device_table[] = { /* Planex */ { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, + /* WideTell */ + { USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) }, /* Zcom */ { USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) }, /* ZyXEL */ From f446d10f214091408b7300f15c9adf60569edf28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Oct 2009 15:12:32 +0100 Subject: [PATCH 14/36] mac80211: fix BSS leak The IBSS code leaks a BSS struct after telling cfg80211 about a given BSS by passing a frame. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ca8ecce31d34..f1362f32c17d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -73,6 +73,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; + struct cfg80211_bss *bss; u32 bss_change; u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; @@ -177,8 +178,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, mod_timer(&ifibss->timer, round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); - cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, - mgmt, skb->len, 0, GFP_KERNEL); + bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, + mgmt, skb->len, 0, GFP_KERNEL); + cfg80211_put_bss(bss); cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); } From 9a3f45116f5e08819136cd512fd7f6450ac22aa8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 28 Oct 2009 22:08:13 +0100 Subject: [PATCH 15/36] b43: Fix DMA TX bounce buffer copying b43 allocates a bouncebuffer, if the supplied TX skb is in an invalid memory range for DMA. However, this is broken in that it fails to copy over some metadata to the new skb. This patch fixes three problems: * Failure to adjust the ieee80211_tx_info pointer to the new buffer. This results in a kmemcheck warning. * Failure to copy the skb cb, which contains ieee80211_tx_info, to the new skb. This results in breakage of various TX-status postprocessing (Rate control). * Failure to transfer the queue mapping. This results in the wrong queue being stopped on saturation and can result in queue overflow. Signed-off-by: Michael Buesch Tested-by: Christian Casteyde Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 8701034569fa..de4e804bedf0 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1157,8 +1157,9 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) } static int dma_tx_fragment(struct b43_dmaring *ring, - struct sk_buff *skb) + struct sk_buff **in_skb) { + struct sk_buff *skb = *in_skb; const struct b43_dma_ops *ops = ring->ops; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; @@ -1224,8 +1225,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring, } memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len); + memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb)); + bounce_skb->dev = skb->dev; + skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb)); + info = IEEE80211_SKB_CB(bounce_skb); + dev_kfree_skb_any(skb); skb = bounce_skb; + *in_skb = bounce_skb; meta->skb = skb; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) { @@ -1355,7 +1362,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) * static, so we don't need to store it per frame. */ ring->queue_prio = skb_get_queue_mapping(skb); - err = dma_tx_fragment(ring, skb); + /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing + * into the skb data or cb now. */ + hdr = NULL; + info = NULL; + err = dma_tx_fragment(ring, &skb); if (unlikely(err == -ENOKEY)) { /* Drop this packet, as we don't have the encryption key * anymore and must not transmit it unencrypted. */ From e55ea2b152569f09ef6bb28d5a341a4e5a21f5ce Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 28 Oct 2009 20:19:06 -0400 Subject: [PATCH 16/36] ath9k: fix misplaced semicolon on rate control The patch e43419f9: ath9k: downgrade assert in rc.c for invalid rate downgraded an ASSERT to a WARN_ON() but also misplaced a semicolon at the end of the second check. What this did was force the rate control code to always return the rate even if we should have warned about it. Since this should not have happened anymore anyway this fix isn't critical as the proper rate would have been returned anyway. Cc: stable@kernel.org Reported-by: Jiri Slaby Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 16a271787b85..1895d63aad0a 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -679,7 +679,7 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, return rate; if (rate_table->info[rate].valid_single_stream && - !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)); + !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) return rate; /* This should not happen */ From 2171abc58644e09dbba546d91366b12743115396 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 08:34:00 +0100 Subject: [PATCH 17/36] mac80211: fix addba timer The addba timer function acquires the sta spinlock, but at the same time we try to del_timer_sync() it under the spinlock which can produce deadlocks. To fix this, always del_timer_sync() the timer in ieee80211_process_addba_resp() and add it again after checking the conditions, if necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index bd765f30dba2..b09948ceec4a 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -666,26 +666,25 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, state = &sta->ampdu_mlme.tid_state_tx[tid]; + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + spin_lock_bh(&sta->lock); - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->lock); - return; - } + if (!(*state & HT_ADDBA_REQUESTED_MSK)) + goto timer_still_needed; if (mgmt->u.action.u.addba_resp.dialog_token != sta->ampdu_mlme.tid_tx[tid]->dialog_token) { - spin_unlock_bh(&sta->lock); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - return; + goto timer_still_needed; } - del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) == WLAN_STATUS_SUCCESS) { u8 curstate = *state; @@ -699,5 +698,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, } else { ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); } + + goto out; + + timer_still_needed: + add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + out: spin_unlock_bh(&sta->lock); } From 372362ade2fe5c33d749e017f1c5bc8140769a3e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 10:09:28 +0100 Subject: [PATCH 18/36] mac80211: fix reason code output endianness When HT debugging is enabled and we receive a DelBA frame we print out the reason code in the wrong byte order. Fix that so we don't get weird values printed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ht.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 0891bfb06996..48ef1a282b91 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -153,7 +153,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, if (net_ratelimit()) printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n", mgmt->sa, initiator ? "initiator" : "recipient", tid, - mgmt->u.action.u.delba.reason_code); + le16_to_cpu(mgmt->u.action.u.delba.reason_code)); #endif /* CONFIG_MAC80211_HT_DEBUG */ if (initiator == WLAN_BACK_INITIATOR) From e9024a059f2c17fb2bfab212ee9d31511d7b8e57 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 30 Oct 2009 17:45:14 +0000 Subject: [PATCH 19/36] libertas if_usb: Fix crash on 64-bit machines On a 64-bit kernel, skb->tail is an offset, not a pointer. The libertas usb driver passes it to usb_fill_bulk_urb() anyway, causing interesting crashes. Fix that by using skb->data instead. This highlights a problem with usb_fill_bulk_urb(). It doesn't notice when dma_map_single() fails and return the error to its caller as it should. In fact it _can't_ currently return the error, since it returns void. So this problem was showing up only at unmap time, after we'd already suffered memory corruption by doing DMA to a bogus address. Signed-off-by: David Woodhouse Cc: stable@kernel.org Acked-by: David S. Miller Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 92bc8c5f1ca2..3fac4efa5ac8 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -508,7 +508,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, /* Fill the receive configuration URB and initialise the Rx call back */ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, usb_rcvbulkpipe(cardp->udev, cardp->ep_in), - (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET), + skb->data + IPFIELD_ALIGN_OFFSET, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, cardp); From 7400f42e9d765fa0656b432f3ab1245f9710f190 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 31 Oct 2009 07:40:37 +0100 Subject: [PATCH 20/36] cfg80211: fix NULL ptr deref commit 211a4d12abf86fe0df4cd68fc6327cbb58f56f81 Author: Johannes Berg Date: Tue Oct 20 15:08:53 2009 +0900 cfg80211: sme: deauthenticate on assoc failure introduced a potential NULL pointer dereference that some people have been hitting for some reason -- the params.bssid pointer is not guaranteed to be non-NULL for what seems to be a race between various ways of reaching the same thing. While I'm trying to analyse the problem more let's first fix the crash. I think the real fix may be to avoid doing _anything_ if it ended up being NULL, but right now I'm not sure yet. I think http://bugzilla.kernel.org/show_bug.cgi?id=14342 might also be this issue. Reported-by: Parag Warudkar Tested-by: Parag Warudkar Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/sme.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index ece378d531ef..9f0b2800a9d7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -165,7 +165,7 @@ void cfg80211_conn_work(struct work_struct *work) struct cfg80211_registered_device *rdev = container_of(work, struct cfg80211_registered_device, conn_work); struct wireless_dev *wdev; - u8 bssid[ETH_ALEN]; + u8 bssid_buf[ETH_ALEN], *bssid = NULL; rtnl_lock(); cfg80211_lock_rdev(rdev); @@ -181,7 +181,10 @@ void cfg80211_conn_work(struct work_struct *work) wdev_unlock(wdev); continue; } - memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); + if (wdev->conn->params.bssid) { + memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); + bssid = bssid_buf; + } if (cfg80211_conn_do_work(wdev)) __cfg80211_connect_result( wdev->netdev, bssid, From c1f9a764cf47686b1f5a0cf87ada68d90056136a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 1 Nov 2009 19:25:40 +0100 Subject: [PATCH 21/36] mac80211: check interface is down before type change For some strange reason the netif_running() check ended up after the actual type change instead of before, potentially causing all kinds of problems if the interface is up while changing the type; one of the problems manifests itself as a warning: WARNING: at net/mac80211/iface.c:651 ieee80211_teardown_sdata+0xda/0x1a0 [mac80211]() Hardware name: Aspire one Pid: 2596, comm: wpa_supplicant Tainted: G W 2.6.31-10-generic #32-Ubuntu Call Trace: [] warn_slowpath_common+0x6d/0xa0 [] warn_slowpath_null+0x15/0x20 [] ieee80211_teardown_sdata+0xda/0x1a0 [mac80211] [] ieee80211_if_change_type+0x4a/0xc0 [mac80211] [] ieee80211_change_iface+0x61/0xa0 [mac80211] [] cfg80211_wext_siwmode+0xc7/0x120 [cfg80211] [] ioctl_standard_call+0x58/0xf0 (http://www.kerneloops.org/searchweek.php?search=ieee80211_teardown_sdata) Cc: Arjan van de Ven Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5608f6c68413..7b5131bd6fa1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -72,6 +72,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata; int ret; + if (netif_running(dev)) + return -EBUSY; + if (!nl80211_type_check(type)) return -EINVAL; @@ -81,9 +84,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, if (ret) return ret; - if (netif_running(sdata->dev)) - return -EBUSY; - if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) ieee80211_sdata_set_mesh_id(sdata, params->mesh_id_len, From 3a19d56c71bd3a08412d609d219ac8eec0819166 Mon Sep 17 00:00:00 2001 From: Torgny Johansson Date: Wed, 4 Nov 2009 05:25:02 -0800 Subject: [PATCH 22/36] cdc_ether: additional Ericsson MBM PID's to the whitelist Signed-off-by: Torgny Johansson Signed-off-by: David S. Miller --- drivers/net/usb/Kconfig | 2 +- drivers/net/usb/cdc_ether.c | 42 ++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index c47237c2d638..32d93564a74d 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -174,7 +174,7 @@ config USB_NET_CDCETHER * Ericsson Mobile Broadband Module (all variants) * Motorola (DM100 and SB4100) * Broadcom Cable Modem (reference design) - * Toshiba (PCX1100U and F3507g) + * Toshiba (PCX1100U and F3507g/F3607gw) * ... This driver creates an interface named "ethX", where X depends on diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 4a6aff579403..21e1ba160008 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -544,20 +544,60 @@ static const struct usb_device_id products [] = { USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, }, { - /* Ericsson F3307 */ + /* Ericsson F3607gw ver 2 */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1905, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson F3607gw ver 3 */ USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1906, USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson F3307 */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x190a, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson F3307 ver 2 */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1909, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Ericsson C3607w */ + USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1049, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, }, { /* Toshiba F3507g */ USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130b, USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, +}, { + /* Toshiba F3607gw */ + USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130c, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Toshiba F3607gw ver 2 */ + USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x1311, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, }, { /* Dell F3507g */ USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8147, USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), .driver_info = (unsigned long) &cdc_info, +}, { + /* Dell F3607gw */ + USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8183, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, +}, { + /* Dell F3607gw ver 2 */ + USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8184, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &cdc_info, }, { }, // END }; From c8ee5538b091b8aca9ca738c6989c5ad6f9e67c0 Mon Sep 17 00:00:00 2001 From: Tonyliu Date: Wed, 4 Nov 2009 05:45:02 -0800 Subject: [PATCH 23/36] DaVinci EMAC: correct param for ISR emac_irq is declared as: static irqreturn_t emac_irq(int irq, void *dev_id) { struct net_device *ndev = (struct net_device *)dev_id; struct emac_priv *priv = netdev_priv(ndev); ... Clearly emac_irq() needs "struct net_device *" as "void *dev_id", so correct this. Signed-off-by: Tonyliu Signed-off-by: David S. Miller --- drivers/net/davinci_emac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index f72c56dec33c..3179521aee90 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -2221,7 +2221,7 @@ void emac_poll_controller(struct net_device *ndev) struct emac_priv *priv = netdev_priv(ndev); emac_int_disable(priv); - emac_irq(ndev->irq, priv); + emac_irq(ndev->irq, ndev); emac_int_enable(priv); } #endif From 02303d2028aef19889415364fc5f7bb374887157 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 4 Nov 2009 08:25:57 -0800 Subject: [PATCH 24/36] isdn: hisax: Fix lock imbalance. Add omittted unlocks to 2 functions. Signed-off-by: Jiri Slaby Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hisax/amd7930_fn.c | 1 + drivers/isdn/hisax/icc.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c index bf526a7a63af..d6fdf1f66754 100644 --- a/drivers/isdn/hisax/amd7930_fn.c +++ b/drivers/isdn/hisax/amd7930_fn.c @@ -594,6 +594,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg) if (cs->debug & L1_DEB_WARN) debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); break; } if (cs->debug & DEB_DLOG_HEX) diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index 9aba646ba221..c80cbb8a2ef9 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -468,6 +468,7 @@ ICC_l1hw(struct PStack *st, int pr, void *arg) if (cs->debug & L1_DEB_WARN) debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); + spin_unlock_irqrestore(&cs->lock, flags); break; } if (cs->debug & DEB_DLOG_HEX) From 08cb3f60b2f866c906a5a779444b30ba8f9a93c8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 4 Nov 2009 08:27:09 -0800 Subject: [PATCH 25/36] misdn: Fix reversed 'if' in st_own_ctrl The current code probably returns -EINVAL a lot. Otherwise it would oops. Compile tested only. Found by smatch (http://repo.or.cz/w/smatch.git). Signed-off-by: Dan Carpenter Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/mISDN/stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 3e1532a180ff..0d05ec43012c 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -364,7 +364,7 @@ add_layer2(struct mISDNchannel *ch, struct mISDNstack *st) static int st_own_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) { - if (!ch->st || ch->st->layer1) + if (!ch->st || !ch->st->layer1) return -EINVAL; return ch->st->layer1->ctrl(ch->st->layer1, cmd, arg); } From 1ea70841f07666af69e481d4ffdd6edb56db3c92 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 4 Nov 2009 08:28:12 -0800 Subject: [PATCH 26/36] isdn: eicon: Use offsetof Use offsetof instead of explicit implementation. * fixes bug with omitted & like: len = (byte)(((T30_INFO *) 0)->station_id + 20) * avoids compiler warnings with wrong sizes (pointer-to-char cast): len = (byte)(&(((T30_INFO *) 0)->universal_6)); * cleans up the code Signed-off-by: Jiri Slaby Cc: Karsten Keil Acked-by: Armin Schindler Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hardware/eicon/message.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 27d5dd68f4fb..ae89fb89da64 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -2692,7 +2692,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, if (!(fax_control_bits & T30_CONTROL_BIT_MORE_DOCUMENTS) || (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)) { - len = (byte)(&(((T30_INFO *) 0)->universal_6)); + len = offsetof(T30_INFO, universal_6); fax_info_change = false; if (ncpi->length >= 4) { @@ -2754,7 +2754,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, for (i = 0; i < w; i++) ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id[i] = fax_parms[4].info[1+i]; ((T30_INFO *)(plci->fax_connect_info_buffer))->head_line_len = 0; - len = (byte)(((T30_INFO *) 0)->station_id + 20); + len = offsetof(T30_INFO, station_id) + 20; w = fax_parms[5].length; if (w > 20) w = 20; @@ -2788,7 +2788,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, } else { - len = (byte)(&(((T30_INFO *) 0)->universal_6)); + len = offsetof(T30_INFO, universal_6); } fax_info_change = true; @@ -2892,7 +2892,7 @@ static byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_ENABLE_NSF) && (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)) { - len = ((byte)(((T30_INFO *) 0)->station_id + 20)); + len = offsetof(T30_INFO, station_id) + 20; if (plci->fax_connect_info_length < len) { ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0; @@ -3802,7 +3802,7 @@ static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, break; } ncpi = &m_parms[1]; - len = ((byte)(((T30_INFO *) 0)->station_id + 20)); + len = offsetof(T30_INFO, station_id) + 20; if (plci->fax_connect_info_length < len) { ((T30_INFO *)(plci->fax_connect_info_buffer))->station_id_len = 0; @@ -6844,7 +6844,7 @@ static void nl_ind(PLCI *plci) if ((plci->requested_options_conn | plci->requested_options | a->requested_options_table[plci->appl->Id-1]) & ((1L << PRIVATE_FAX_SUB_SEP_PWD) | (1L << PRIVATE_FAX_NONSTANDARD))) { - i = ((word)(((T30_INFO *) 0)->station_id + 20)) + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len; + i = offsetof(T30_INFO, station_id) + 20 + ((T30_INFO *)plci->NL.RBuffer->P)->head_line_len; while (i < plci->NL.RBuffer->length) plci->ncpi_buffer[++len] = plci->NL.RBuffer->P[i++]; } @@ -7236,7 +7236,7 @@ static void nl_ind(PLCI *plci) { plci->RData[1].P = plci->RData[0].P; plci->RData[1].PLength = plci->RData[0].PLength; - plci->RData[0].P = v120_header_buffer + (-((int) v120_header_buffer) & 3); + plci->RData[0].P = v120_header_buffer + (-((unsigned long)v120_header_buffer) & 3); if ((plci->NL.RBuffer->P[0] & V120_HEADER_EXTEND_BIT) || (plci->NL.RLength == 1)) plci->RData[0].PLength = 1; else @@ -8473,7 +8473,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp) fax_control_bits |= T30_CONTROL_BIT_ACCEPT_SEL_POLLING; } len = nlc[0]; - pos = ((byte)(((T30_INFO *) 0)->station_id + 20)); + pos = offsetof(T30_INFO, station_id) + 20; if (pos < plci->fax_connect_info_length) { for (i = 1 + plci->fax_connect_info_buffer[pos]; i != 0; i--) @@ -8525,7 +8525,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp) } PUT_WORD(&(((T30_INFO *)&nlc[1])->control_bits_low), fax_control_bits); - len = ((byte)(((T30_INFO *) 0)->station_id + 20)); + len = offsetof(T30_INFO, station_id) + 20; for (i = 0; i < len; i++) plci->fax_connect_info_buffer[i] = nlc[1+i]; ((T30_INFO *) plci->fax_connect_info_buffer)->head_line_len = 0; From b9db21f8b964e158f95bb581c887159b6cb98ffa Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 4 Nov 2009 08:30:08 -0800 Subject: [PATCH 27/36] isdn: eicon: Return on error When diva_strace_read_uint returns an error, return even from process_idi_event, because l2_state is uninitialized. Signed-off-by: Jiri Slaby Cc: Karsten Keil Acked-by: Armin Schindler Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hardware/eicon/maintidi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c index 23960cb6eaab..41c26e756452 100644 --- a/drivers/isdn/hardware/eicon/maintidi.c +++ b/drivers/isdn/hardware/eicon/maintidi.c @@ -959,8 +959,9 @@ static int process_idi_event (diva_strace_context_t* pLib, } if (!strncmp("State\\Layer2 No1", path, pVar->path_length)) { char* tmp = &pLib->lines[0].pInterface->Layer2[0]; - dword l2_state; - diva_strace_read_uint (pVar, &l2_state); + dword l2_state; + if (diva_strace_read_uint(pVar, &l2_state)) + return -1; switch (l2_state) { case 0: From a947c8f0313c0cf3691b8d8d2b9aaddf372afdcc Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 4 Nov 2009 08:31:19 -0800 Subject: [PATCH 28/36] isdn: hisax: Fix test in waitforxfw The negation makes it a bool before the comparison and hence it will never be 0x40. Signed-off-by: Roel Kluin Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hisax/diva.c | 2 +- drivers/isdn/hisax/hscx_irq.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c index 018bd293e580..0b0c2e5d806b 100644 --- a/drivers/isdn/hisax/diva.c +++ b/drivers/isdn/hisax/diva.c @@ -382,7 +382,7 @@ MemwaitforXFW(struct IsdnCardState *cs, int hscx) { int to = 50; - while ((!(MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + while (((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { udelay(1); to--; } diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c index 7b1ad5e4ecda..2387d76c721a 100644 --- a/drivers/isdn/hisax/hscx_irq.c +++ b/drivers/isdn/hisax/hscx_irq.c @@ -32,7 +32,7 @@ waitforXFW(struct IsdnCardState *cs, int hscx) { int to = 50; - while ((!(READHSCX(cs, hscx, HSCX_STAR) & 0x44) == 0x40) && to) { + while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { udelay(1); to--; } From 286e633ef0ff5bb63c07b4516665da8004966fec Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 4 Nov 2009 08:31:59 -0800 Subject: [PATCH 29/36] isdn: hfc_usb: Fix read buffer overflow Check whether index is within bounds before testing the element. Signed-off-by: Roel Kluin Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hisax/hfc_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index 9de54202c90c..a420b64472e3 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -817,8 +817,8 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish) } /* we have a complete hdlc packet */ if (finish) { - if ((!fifo->skbuff->data[fifo->skbuff->len - 1]) - && (fifo->skbuff->len > 3)) { + if (fifo->skbuff->len > 3 && + !fifo->skbuff->data[fifo->skbuff->len - 1]) { if (fifon == HFCUSB_D_RX) { DBG(HFCUSB_DBG_DCHANNEL, From dffc14365bb07812567ee7f3f8699277ef19aaa8 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 4 Nov 2009 09:38:58 -0800 Subject: [PATCH 30/36] MAINTAINERS: Add git net-next-2.6 Add a reference to the the git tree where most of the forward going network development occurs. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index cdbbaf59a43b..c856aee0f1e2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3632,6 +3632,7 @@ L: netdev@vger.kernel.org W: http://www.linuxfoundation.org/en/Net W: http://patchwork.ozlabs.org/project/netdev/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git S: Maintained F: net/ F: include/net/ From 22402529df88ec39a59b08a46bced73dd5722b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 5 Nov 2009 01:32:44 -0800 Subject: [PATCH 31/36] virtio_net: rename driver struct to please modpost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 3d1285b (move virtnet_remove to .devexit.text) introduced the first reference to __devexit in struct virtio_driver virtio_net which upset modpost ("Section mismatch in reference from the variable virtio_net to the function .devexit.text:virtnet_remove()"). Fix this by renaming virtio_net to virtio_net_driver. Signed-off-by: Uwe Kleine-König Reported-by: Michael S. Tsirkin Blame-taken-by: Rusty Russell Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d9ebac8a2d99..bb8b52d0d1ce 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -999,7 +999,7 @@ static unsigned int features[] = { VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, }; -static struct virtio_driver virtio_net = { +static struct virtio_driver virtio_net_driver = { .feature_table = features, .feature_table_size = ARRAY_SIZE(features), .driver.name = KBUILD_MODNAME, @@ -1012,12 +1012,12 @@ static struct virtio_driver virtio_net = { static int __init init(void) { - return register_virtio_driver(&virtio_net); + return register_virtio_driver(&virtio_net_driver); } static void __exit fini(void) { - unregister_virtio_driver(&virtio_net); + unregister_virtio_driver(&virtio_net_driver); } module_init(init); module_exit(fini); From 1056bd51674e529813213186471bb4ac6689a755 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Nov 2009 20:46:52 -0800 Subject: [PATCH 32/36] bridge: prevent bridging wrong device The bridge code assumes ethernet addressing, so be more strict in the what is allowed. This showed up when GRE had a bug and was not using correct address format. Add some more comments for increased clarity. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index b1b3b0fbf41c..4a9f52732655 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -377,12 +377,16 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) struct net_bridge_port *p; int err = 0; - if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) + /* Don't allow bridging non-ethernet like devices */ + if ((dev->flags & IFF_LOOPBACK) || + dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN) return -EINVAL; + /* No bridging of bridges */ if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) return -ELOOP; + /* Device is already being bridged */ if (dev->br_port != NULL) return -EBUSY; From b4ec824021493ba6cb7eeb61572f4d2f8a80a52e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:56:07 -0800 Subject: [PATCH 33/36] rose: device refcount leak While hunting dev_put() for net-next-2.6, I found a device refcount leak in ROSE, ioctl(SIOCADDRT) error path. Fix is to not touch device refcount, as we hold RTNL Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/rose/rose_route.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 9478d9b3d977..f3e21989b88c 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -578,18 +578,18 @@ static int rose_clear_routes(void) /* * Check that the device given is a valid AX.25 interface that is "up". + * called whith RTNL */ -static struct net_device *rose_ax25_dev_get(char *devname) +static struct net_device *rose_ax25_dev_find(char *devname) { struct net_device *dev; - if ((dev = dev_get_by_name(&init_net, devname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev; - dev_put(dev); return NULL; } @@ -720,27 +720,23 @@ int rose_rt_ioctl(unsigned int cmd, void __user *arg) case SIOCADDRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; - if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) + if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) return -EINVAL; - if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */ - dev_put(dev); + if (rose_dev_exists(&rose_route.address)) /* Can't add routes to ourself */ return -EINVAL; - } if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; if (rose_route.ndigis > AX25_MAX_DIGIS) return -EINVAL; err = rose_add_node(&rose_route, dev); - dev_put(dev); return err; case SIOCDELRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; - if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) + if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) return -EINVAL; err = rose_del_node(&rose_route, dev); - dev_put(dev); return err; case SIOCRSCLRRT: From f5209b4446d185cc95f46363f8043a743530c15a Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 6 Nov 2009 00:31:01 -0800 Subject: [PATCH 34/36] be2net: Fix CQE_STATUS_EXTD_SHIFT define Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/benet/be_cmds.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 49953787e41c..e5f9676cf1bc 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -68,7 +68,7 @@ enum { #define CQE_STATUS_COMPL_MASK 0xFFFF #define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */ #define CQE_STATUS_EXTD_MASK 0xFFFF -#define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */ +#define CQE_STATUS_EXTD_SHIFT 16 /* bits 16 - 31 */ struct be_mcc_compl { u32 status; /* dword 0 */ From f9dd09c7f7199685601d75882447a6598be8a3e0 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Fri, 6 Nov 2009 00:43:42 -0800 Subject: [PATCH 35/36] netfilter: nf_nat: fix NAT issue in 2.6.30.4+ Vitezslav Samel discovered that since 2.6.30.4+ active FTP can not work over NAT. The "cause" of the problem was a fix of unacknowledged data detection with NAT (commit a3a9f79e361e864f0e9d75ebe2a0cb43d17c4272). However, actually, that fix uncovered a long standing bug in TCP conntrack: when NAT was enabled, we simply updated the max of the right edge of the segments we have seen (td_end), by the offset NAT produced with changing IP/port in the data. However, we did not update the other parameter (td_maxend) which is affected by the NAT offset. Thus that could drift away from the correct value and thus resulted breaking active FTP. The patch below fixes the issue by *not* updating the conntrack parameters from NAT, but instead taking into account the NAT offsets in conntrack in a consistent way. (Updating from NAT would be more harder and expensive because it'd need to re-calculate parameters we already calculated in conntrack.) Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack.h | 8 ++-- include/net/netfilter/nf_nat_helper.h | 4 ++ net/ipv4/netfilter/nf_nat_core.c | 3 ++ net/ipv4/netfilter/nf_nat_helper.c | 34 +++++++++----- net/netfilter/nf_conntrack_core.c | 8 ++++ net/netfilter/nf_conntrack_proto_tcp.c | 64 +++++++++++--------------- 6 files changed, 67 insertions(+), 54 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index cbdd6284996d..5cf7270e3ffc 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -255,11 +255,9 @@ static inline bool nf_ct_kill(struct nf_conn *ct) } /* These are for NAT. Icky. */ -/* Update TCP window tracking data when NAT mangles the packet */ -extern void nf_conntrack_tcp_update(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conn *ct, int dir, - s16 offset); +extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); /* Fake conntrack entry for untracked connections */ extern struct nf_conn nf_conntrack_untracked; diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h index 237a961f40e1..4222220920a5 100644 --- a/include/net/netfilter/nf_nat_helper.h +++ b/include/net/netfilter/nf_nat_helper.h @@ -32,4 +32,8 @@ extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, * to port ct->master->saved_proto. */ extern void nf_nat_follow_master(struct nf_conn *ct, struct nf_conntrack_expect *this); + +extern s16 nf_nat_get_offset(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); #endif diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 68afc6ecd343..fe1a64479dd0 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -750,6 +750,8 @@ static int __init nf_nat_init(void) BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, nfnetlink_parse_nat_setup); + BUG_ON(nf_ct_nat_offset != NULL); + rcu_assign_pointer(nf_ct_nat_offset, nf_nat_get_offset); return 0; cleanup_extend: @@ -764,6 +766,7 @@ static void __exit nf_nat_cleanup(void) nf_ct_extend_unregister(&nat_extend); rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL); + rcu_assign_pointer(nf_ct_nat_offset, NULL); synchronize_net(); } diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 09172a65d9b6..f9520fa3aba9 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -73,6 +73,28 @@ adjust_tcp_sequence(u32 seq, DUMP_OFFSET(this_way); } +/* Get the offset value, for conntrack */ +s16 nf_nat_get_offset(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq) +{ + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_seq *this_way; + s16 offset; + + if (!nat) + return 0; + + this_way = &nat->seq[dir]; + spin_lock_bh(&nf_nat_seqofs_lock); + offset = after(seq, this_way->correction_pos) + ? this_way->offset_after : this_way->offset_before; + spin_unlock_bh(&nf_nat_seqofs_lock); + + return offset; +} +EXPORT_SYMBOL_GPL(nf_nat_get_offset); + /* Frobs data inside this packet, which is linear. */ static void mangle_contents(struct sk_buff *skb, unsigned int dataoff, @@ -189,11 +211,6 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, adjust_tcp_sequence(ntohl(tcph->seq), (int)rep_len - (int)match_len, ct, ctinfo); - /* Tell TCP window tracking about seq change */ - nf_conntrack_tcp_update(skb, ip_hdrlen(skb), - ct, CTINFO2DIR(ctinfo), - (int)rep_len - (int)match_len); - nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); } return 1; @@ -415,12 +432,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, tcph->seq = newseq; tcph->ack_seq = newack; - if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo)) - return 0; - - nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir, seqoff); - - return 1; + return nf_nat_sack_adjust(skb, tcph, ct, ctinfo); } /* Setup NAT on this expected conntrack so it follows master. */ diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7c9ec3dee96e..0cdfb388a191 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1350,6 +1350,11 @@ err_stat: return ret; } +s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); +EXPORT_SYMBOL_GPL(nf_ct_nat_offset); + int nf_conntrack_init(struct net *net) { int ret; @@ -1367,6 +1372,9 @@ int nf_conntrack_init(struct net *net) /* For use by REJECT target */ rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); + + /* Howto get NAT offsets */ + rcu_assign_pointer(nf_ct_nat_offset, NULL); } return 0; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 97a82ba75376..ba2b76937283 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -492,6 +492,21 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, } } +#ifdef CONFIG_NF_NAT_NEEDED +static inline s16 nat_offset(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq) +{ + typeof(nf_ct_nat_offset) get_offset = rcu_dereference(nf_ct_nat_offset); + + return get_offset != NULL ? get_offset(ct, dir, seq) : 0; +} +#define NAT_OFFSET(pf, ct, dir, seq) \ + (pf == NFPROTO_IPV4 ? nat_offset(ct, dir, seq) : 0) +#else +#define NAT_OFFSET(pf, ct, dir, seq) 0 +#endif + static bool tcp_in_window(const struct nf_conn *ct, struct ip_ct_tcp *state, enum ip_conntrack_dir dir, @@ -506,6 +521,7 @@ static bool tcp_in_window(const struct nf_conn *ct, struct ip_ct_tcp_state *receiver = &state->seen[!dir]; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; __u32 seq, ack, sack, end, win, swin; + s16 receiver_offset; bool res; /* @@ -519,11 +535,16 @@ static bool tcp_in_window(const struct nf_conn *ct, if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) tcp_sack(skb, dataoff, tcph, &sack); + /* Take into account NAT sequence number mangling */ + receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1); + ack -= receiver_offset; + sack -= receiver_offset; + pr_debug("tcp_in_window: START\n"); pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); - pr_debug("seq=%u ack=%u sack=%u win=%u end=%u\n", - seq, ack, sack, win, end); + pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", + seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -613,8 +634,8 @@ static bool tcp_in_window(const struct nf_conn *ct, pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); - pr_debug("seq=%u ack=%u sack =%u win=%u end=%u\n", - seq, ack, sack, win, end); + pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", + seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -700,7 +721,7 @@ static bool tcp_in_window(const struct nf_conn *ct, before(seq, sender->td_maxend + 1) ? after(end, sender->td_end - receiver->td_maxwin - 1) ? before(sack, receiver->td_end + 1) ? - after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG" + after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" : "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" @@ -715,39 +736,6 @@ static bool tcp_in_window(const struct nf_conn *ct, return res; } -#ifdef CONFIG_NF_NAT_NEEDED -/* Update sender->td_end after NAT successfully mangled the packet */ -/* Caller must linearize skb at tcp header. */ -void nf_conntrack_tcp_update(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conn *ct, int dir, - s16 offset) -{ - const struct tcphdr *tcph = (const void *)skb->data + dataoff; - const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir]; - const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[!dir]; - __u32 end; - - end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph); - - spin_lock_bh(&ct->lock); - /* - * We have to worry for the ack in the reply packet only... - */ - if (ct->proto.tcp.seen[dir].td_end + offset == end) - ct->proto.tcp.seen[dir].td_end = end; - ct->proto.tcp.last_end = end; - spin_unlock_bh(&ct->lock); - pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " - "receiver end=%u maxend=%u maxwin=%u scale=%i\n", - sender->td_end, sender->td_maxend, sender->td_maxwin, - sender->td_scale, - receiver->td_end, receiver->td_maxend, receiver->td_maxwin, - receiver->td_scale); -} -EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update); -#endif - #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 From 887e671f324d9898aaedb29a6ece6c853c394067 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 6 Nov 2009 00:50:39 -0800 Subject: [PATCH 36/36] decnet: netdevice refcount leak While working on device refcount stuff, I found a device refcount leak through DECNET. This nasty bug can be used to hold refcounts on any !DECNET netdevice. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/decnet/sysctl_net_decnet.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 26b0ab1e9f56..2036568beea9 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -263,11 +263,10 @@ static int dn_def_dev_strategy(ctl_table *table, return -ENODEV; rv = -ENODEV; - if (dev->dn_ptr != NULL) { + if (dev->dn_ptr != NULL) rv = dn_dev_set_default(dev, 1); - if (rv) - dev_put(dev); - } + if (rv) + dev_put(dev); } return rv;