From a1d7c1b4b8dfbc5ecadcff9284d64bb6ad4c0196 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 14 May 2010 21:18:17 +0200 Subject: netfilter: nf_ct_sip: handle non-linear skbs Handle non-linear skbs by linearizing them instead of silently failing. Long term the helper should be fixed to either work with non-linear skbs directly by using the string search API or work on a copy of the data. Based on patch by Jason Gunthorpe Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_sip.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index b20f4275893c..53d892210a04 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1393,10 +1393,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, nf_ct_refresh(ct, skb, sip_timeout * HZ); - if (skb_is_nonlinear(skb)) { - pr_debug("Copy of skbuff not supported yet.\n"); - return NF_ACCEPT; - } + if (unlikely(skb_linearize(skb))) + return NF_DROP; dptr = skb->data + dataoff; datalen = skb->len - dataoff; @@ -1455,10 +1453,8 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, nf_ct_refresh(ct, skb, sip_timeout * HZ); - if (skb_is_nonlinear(skb)) { - pr_debug("Copy of skbuff not supported yet.\n"); - return NF_ACCEPT; - } + if (unlikely(skb_linearize(skb))) + return NF_DROP; dptr = skb->data + dataoff; datalen = skb->len - dataoff; -- cgit v1.2.3 From fc350777c705a39a312728ac5e8a6f164a828f5d Mon Sep 17 00:00:00 2001 From: Joerg Marx Date: Thu, 20 May 2010 15:55:30 +0200 Subject: netfilter: nf_conntrack: fix a race in __nf_conntrack_confirm against nf_ct_get_next_corpse() This race was triggered by a 'conntrack -F' command running in parallel to the insertion of a hash for a new connection. Losing this race led to a dead conntrack entry effectively blocking traffic for a particular connection until timeout or flushing the conntrack hashes again. Now the check for an already dying connection is done inside the lock. Signed-off-by: Joerg Marx Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_core.h | 2 +- net/netfilter/nf_conntrack_core.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index dffde8e6920e..3d7524fba194 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -61,7 +61,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb) int ret = NF_ACCEPT; if (ct && ct != &nf_conntrack_untracked) { - if (!nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) + if (!nf_ct_is_confirmed(ct)) ret = __nf_conntrack_confirm(skb); if (likely(ret == NF_ACCEPT)) nf_ct_deliver_cached_events(ct); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b83c530c5e0a..eeeb8bc73982 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -424,6 +424,16 @@ __nf_conntrack_confirm(struct sk_buff *skb) spin_lock_bh(&nf_conntrack_lock); + /* We have to check the DYING flag inside the lock to prevent + a race against nf_ct_get_next_corpse() possibly called from + user context, else we insert an already 'dead' hash, blocking + further use of that particular connection -JM */ + + if (unlikely(nf_ct_is_dying(ct))) { + spin_unlock_bh(&nf_conntrack_lock); + return NF_ACCEPT; + } + /* See if there's one in the list already, including reverse: NAT could have grabbed it without realizing, since we're not in the hash. If there is, we lost race. */ -- cgit v1.2.3 From 7ea7b858f4bc4fa1645f1327cf9e72c93981aa58 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 20 May 2010 15:59:16 +0200 Subject: netfilter: fix description of expected checkentry return code on xt_target The text describing the return codes that are expected on calls to checkentry() was incorrect. Instead of returning true or false, or an error code, it should return 0 or an error code. Signed-off-by: Luciano Coelho Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index c2ee5d8550cf..c00cc0c4d0b7 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -333,7 +333,7 @@ struct xt_target { /* Called when user tries to insert an entry of this type: hook_mask is a bitmask of hooks from which it can be called. */ - /* Should return true or false, or an error code (-Exxxx). */ + /* Should return 0 on success or an error code otherwise (-Exxxx). */ int (*checkentry)(const struct xt_tgchk_param *); /* Called when entry of this type deleted. */ -- cgit v1.2.3 From 3a24934f065d23145f1c9c70da9f630c7a37795f Mon Sep 17 00:00:00 2001 From: Inaky Perez-Gonzalez Date: Thu, 20 May 2010 12:27:58 -0700 Subject: wimax/i2400m: fix bad race condition check in RX path The i2400m->rx_roq data structure is protected against race conditions with a reference count (i2400m->rx_roq_refcount); the pointer can be read-referenced under the i2400m->rx_lock spinlock. The code in i2400m_rx_edata() wasn't properly following access protocol, performing an invalid check on i2400m->rx_roq (which is cleared to NULL when the refcount drops to zero). As such, it was missing to detect when the data structure is no longer valid and oopsing with a NULL pointer dereference. This commit fixes said check by verifying, under the rx_lock spinlock, that i2400m->rx_roq is non-NULL and then increasing the reference count before dropping the spinlock. Signed-off-by: Inaky Perez-Gonzalez --- drivers/net/wimax/i2400m/rx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index c835ae8b89ce..6cd12d64fc7a 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -1033,12 +1033,12 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx, ro_sn = (reorder >> I2400M_RO_SN_SHIFT) & I2400M_RO_SN; spin_lock_irqsave(&i2400m->rx_lock, flags); - roq = &i2400m->rx_roq[ro_cin]; - if (roq == NULL) { + if (i2400m->rx_roq == NULL) { kfree_skb(skb); /* rx_roq is already destroyed */ spin_unlock_irqrestore(&i2400m->rx_lock, flags); goto error; } + roq = &i2400m->rx_roq[ro_cin]; kref_get(&i2400m->rx_roq_refcount); spin_unlock_irqrestore(&i2400m->rx_lock, flags); -- cgit v1.2.3 From 119fc60a2d20b63439fdae99f0c7022d3dd99def Mon Sep 17 00:00:00 2001 From: Mallikarjuna R Chilakala Date: Thu, 20 May 2010 23:07:06 -0700 Subject: ixgbe:add support for a new 82599 10G Base-T device This adds support for a new copper device for 82599, device id 0x151c. This 82599 10GBase-T device uses the PHY's internal temperature sensor to guard against over-temp conditions. In this scenario the PHY will be put in a low power mode and link will no longer be able to transmit or receive any data. When this occurs, the over-temp interrupt is latched and driver logs this error message. A HW reset or power cycle is required to clear this status. Signed-off-by: Mallikarjuna R Chilakala Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe.h | 3 ++ drivers/net/ixgbe/ixgbe_82598.c | 1 + drivers/net/ixgbe/ixgbe_82599.c | 1 + drivers/net/ixgbe/ixgbe_main.c | 69 +++++++++++++++++++++++++++++++++++++++++ drivers/net/ixgbe/ixgbe_phy.c | 30 ++++++++++++++++++ drivers/net/ixgbe/ixgbe_phy.h | 3 ++ drivers/net/ixgbe/ixgbe_type.h | 4 +++ 7 files changed, 111 insertions(+) diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index d0ea3d6dea95..ffae480587ae 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -360,6 +360,7 @@ struct ixgbe_adapter { u32 flags2; #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1) #define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1) +#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -407,6 +408,8 @@ struct ixgbe_adapter { u16 eeprom_version; int node; + struct work_struct check_overtemp_task; + u32 interrupt_event; /* SR-IOV */ DECLARE_BITMAP(active_vfs, IXGBE_MAX_VF_FUNCTIONS); diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index f2b7ff44215b..9c02d6014cc4 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -1236,6 +1236,7 @@ static struct ixgbe_phy_operations phy_ops_82598 = { .setup_link = &ixgbe_setup_phy_link_generic, .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598, + .check_overtemp = &ixgbe_tn_check_overtemp, }; struct ixgbe_info ixgbe_82598_info = { diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index e9706eb8e4ff..a4e2901f2f08 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -2395,6 +2395,7 @@ static struct ixgbe_phy_operations phy_ops_82599 = { .write_i2c_byte = &ixgbe_write_i2c_byte_generic, .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic, .write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic, + .check_overtemp = &ixgbe_tn_check_overtemp, }; struct ixgbe_info ixgbe_82599_info = { diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 9551cbb7bf01..d571d101de08 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -108,6 +108,8 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = { board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_CX4), board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_T3_LOM), + board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE), board_82599 }, @@ -1618,6 +1620,48 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) } } +/** + * ixgbe_check_overtemp_task - worker thread to check over tempurature + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_check_overtemp_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + check_overtemp_task); + struct ixgbe_hw *hw = &adapter->hw; + u32 eicr = adapter->interrupt_event; + + if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) { + switch (hw->device_id) { + case IXGBE_DEV_ID_82599_T3_LOM: { + u32 autoneg; + bool link_up = false; + + if (hw->mac.ops.check_link) + hw->mac.ops.check_link(hw, &autoneg, &link_up, false); + + if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) || + (eicr & IXGBE_EICR_LSC)) + /* Check if this is due to overtemp */ + if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) + break; + } + return; + default: + if (!(eicr & IXGBE_EICR_GPI_SDP0)) + return; + break; + } + DPRINTK(DRV, ERR, "Network adapter has been stopped because it " + "has over heated. Restart the computer. If the problem " + "persists, power off the system and replace the " + "adapter\n"); + /* write to clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0); + } +} + static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) { struct ixgbe_hw *hw = &adapter->hw; @@ -1689,6 +1733,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (hw->mac.type == ixgbe_mac_82599EB) { ixgbe_check_sfp_event(adapter, eicr); + adapter->interrupt_event = eicr; + if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) + schedule_work(&adapter->check_overtemp_task); /* Handle Flow Director Full threshold interrupt */ if (eicr & IXGBE_EICR_FLOW_DIR) { @@ -2190,6 +2238,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) u32 mask; mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); + if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) + mask |= IXGBE_EIMS_GPI_SDP0; if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) mask |= IXGBE_EIMS_GPI_SDP1; if (adapter->hw.mac.type == ixgbe_mac_82599EB) { @@ -2250,6 +2300,9 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_sfp_event(adapter, eicr); ixgbe_check_fan_failure(adapter, eicr); + if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) + schedule_work(&adapter->check_overtemp_task); if (napi_schedule_prep(&(q_vector->napi))) { adapter->tx_ring[0]->total_packets = 0; @@ -3265,6 +3318,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); } + /* Enable Thermal over heat sensor interrupt */ + if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) { + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + gpie |= IXGBE_SDP0_GPIEN; + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + } + /* Enable fan failure interrupt if media type is copper */ if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); @@ -3666,6 +3726,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter) adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) cancel_work_sync(&adapter->fdir_reinit_task); + if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) + cancel_work_sync(&adapter->check_overtemp_task); + /* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { j = adapter->tx_ring[i]->reg_idx; @@ -4645,6 +4708,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599; adapter->flags2 |= IXGBE_FLAG2_RSC_CAPABLE; adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED; + if (hw->device_id == IXGBE_DEV_ID_82599_T3_LOM) + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE; if (dev->features & NETIF_F_NTUPLE) { /* Flow Director perfect filter enabled */ adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE; @@ -6561,7 +6626,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, } /* reset_hw fills in the perm_addr as well */ + hw->phy.reset_if_overtemp = true; err = hw->mac.ops.reset_hw(hw); + hw->phy.reset_if_overtemp = false; if (err == IXGBE_ERR_SFP_NOT_PRESENT && hw->mac.type == ixgbe_mac_82598EB) { /* @@ -6730,6 +6797,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); + if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) + INIT_WORK(&adapter->check_overtemp_task, ixgbe_check_overtemp_task); #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 22d21af14783..09e1911ff510 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -135,6 +135,11 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) **/ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) { + /* Don't reset PHY if it's shut down due to overtemp. */ + if (!hw->phy.reset_if_overtemp && + (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) + return 0; + /* * Perform soft PHY reset to the PHY_XS. * This will cause a soft reset to the PHY @@ -1345,3 +1350,28 @@ s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, return status; } +/** + * ixgbe_tn_check_overtemp - Checks if an overtemp occured. + * @hw: pointer to hardware structure + * + * Checks if the LASI temp alarm status was triggered due to overtemp + **/ +s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) +{ + s32 status = 0; + u16 phy_data = 0; + + if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM) + goto out; + + /* Check that the LASI temp alarm status was triggered */ + hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG, + MDIO_MMD_PMAPMD, &phy_data); + + if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM)) + goto out; + + status = IXGBE_ERR_OVERTEMP; +out: + return status; +} diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index c9c545941407..ef4ba834c593 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -80,6 +80,8 @@ #define IXGBE_I2C_T_SU_STO 4 #define IXGBE_I2C_T_BUF 5 +#define IXGBE_TN_LASI_STATUS_REG 0x9005 +#define IXGBE_TN_LASI_STATUS_TEMP_ALARM 0x0008 s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); @@ -106,6 +108,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, u16 *list_offset, u16 *data_offset); +s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw); s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 39b9be897439..2eb6e151016c 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -51,6 +51,7 @@ #define IXGBE_DEV_ID_82599_KX4 0x10F7 #define IXGBE_DEV_ID_82599_KX4_MEZZ 0x1514 #define IXGBE_DEV_ID_82599_KR 0x1517 +#define IXGBE_DEV_ID_82599_T3_LOM 0x151C #define IXGBE_DEV_ID_82599_CX4 0x10F9 #define IXGBE_DEV_ID_82599_SFP 0x10FB #define IXGBE_DEV_ID_82599_SFP_EM 0x1507 @@ -2470,6 +2471,7 @@ struct ixgbe_phy_operations { s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); + s32 (*check_overtemp)(struct ixgbe_hw *); }; struct ixgbe_eeprom_info { @@ -2518,6 +2520,7 @@ struct ixgbe_phy_info { enum ixgbe_smart_speed smart_speed; bool smart_speed_active; bool multispeed_fiber; + bool reset_if_overtemp; }; #include "ixgbe_mbx.h" @@ -2605,6 +2608,7 @@ struct ixgbe_info { #define IXGBE_ERR_FDIR_REINIT_FAILED -23 #define IXGBE_ERR_EEPROM_VERSION -24 #define IXGBE_ERR_NO_SPACE -25 +#define IXGBE_ERR_OVERTEMP -26 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ -- cgit v1.2.3 From 622e0ca1cd4d459f5af4f2c65f4dc0dd823cb4c3 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 20 May 2010 23:07:56 -0700 Subject: gro: Fix bogus gso_size on the first fraglist entry When GRO produces fraglist entries, and the resulting skb hits an interface that is incapable of TSO but capable of FRAGLIST, we end up producing a bogus packet with gso_size non-zero. This was reported in the field with older versions of KVM that did not set the TSO bits on tuntap. This patch fixes that. Reported-by: Igor Zhang Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/skbuff.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c543dd252433..4c11000a96aa 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2718,6 +2718,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); skb_shinfo(nskb)->frag_list = p; skb_shinfo(nskb)->gso_size = pinfo->gso_size; + pinfo->gso_size = 0; skb_header_release(p); nskb->prev = p; -- cgit v1.2.3 From 0f0b405cd16f7aaff84a935984cae421897d725d Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Thu, 20 May 2010 04:00:59 +0000 Subject: sh_eth: Fix memleak in sh_mdio_release Allocated memory for IRQs should be freed when releasing the mii_bus Signed-off-by: Denis Kirjanov Acked-by: Nobuhiro Iwamatsu Signed-off-by: David S. Miller --- drivers/net/sh_eth.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 586ed0915a29..501a55ffce57 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1294,6 +1294,9 @@ static int sh_mdio_release(struct net_device *ndev) /* remove mdio bus info from net_device */ dev_set_drvdata(&ndev->dev, NULL); + /* free interrupts memory */ + kfree(bus->irq); + /* free bitbang info */ free_mdio_bitbang(bus); -- cgit v1.2.3 From 1f01bfd202bc539bccd282befa2bbdb8d6ad80ee Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 19 May 2010 06:46:38 +0000 Subject: can: SJA1000 add missing spin_lock_init() As remarked by Sam Ravnborg the spin_lock variable, that has been introduced in commit 57c8a456640fa3ca777652f11f2db4179a3e66b6 ("can: Fix SJA1000 command register writes on SMP systems") has not been initialized properly. This patch adds the initialization to allow spinlock debugging. Signed-off-by: Oliver Hartkopp CC: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/net/can/sja1000/sja1000.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 85f7cbfe8e5f..0a8de01d52f7 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -599,6 +599,8 @@ struct net_device *alloc_sja1000dev(int sizeof_priv) priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_BERR_REPORTING; + spin_lock_init(&priv->cmdreg_lock); + if (sizeof_priv) priv->priv = (void *)priv + sizeof(struct sja1000_priv); -- cgit v1.2.3 From 76cc8b13a6e41b537fd262b600da1571314add62 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Thu, 20 May 2010 18:37:59 +0000 Subject: net: fix problem in dequeuing from input_pkt_queue Fix some issues introduced in batch skb dequeuing for input_pkt_queue. The primary issue it that the queue head must be incremented only after a packet has been processed, that is only after __netif_receive_skb has been called. This is needed for the mechanism to prevent OOO packet in RFS. Also when flushing the input_pkt_queue and process_queue, the process queue should be done first to prevent OOO packets. Because the input_pkt_queue has been effectively split into two queues, the calculation of the tail ptr is no longer correct. The correct value would be head+input_pkt_queue->len+process_queue->len. To avoid this calculation we added an explict input_queue_tail in softnet_data. The tail value is simply incremented when queuing to input_pkt_queue. Signed-off-by: Tom Herbert Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 14 +++++++++++--- net/core/dev.c | 28 +++++++++++++++------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a1bff6518166..256419583d9d 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1407,17 +1407,25 @@ struct softnet_data { struct softnet_data *rps_ipi_next; unsigned int cpu; unsigned int input_queue_head; + unsigned int input_queue_tail; #endif unsigned dropped; struct sk_buff_head input_pkt_queue; struct napi_struct backlog; }; -static inline void input_queue_head_add(struct softnet_data *sd, - unsigned int len) +static inline void input_queue_head_incr(struct softnet_data *sd) { #ifdef CONFIG_RPS - sd->input_queue_head += len; + sd->input_queue_head++; +#endif +} + +static inline void input_queue_tail_incr_save(struct softnet_data *sd, + unsigned int *qtail) +{ +#ifdef CONFIG_RPS + *qtail = ++sd->input_queue_tail; #endif } diff --git a/net/core/dev.c b/net/core/dev.c index 6c820650b80f..0aab66d68b19 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2426,10 +2426,7 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu, if (skb_queue_len(&sd->input_pkt_queue)) { enqueue: __skb_queue_tail(&sd->input_pkt_queue, skb); -#ifdef CONFIG_RPS - *qtail = sd->input_queue_head + - skb_queue_len(&sd->input_pkt_queue); -#endif + input_queue_tail_incr_save(sd, qtail); rps_unlock(sd); local_irq_restore(flags); return NET_RX_SUCCESS; @@ -2964,7 +2961,7 @@ static void flush_backlog(void *arg) if (skb->dev == dev) { __skb_unlink(skb, &sd->input_pkt_queue); kfree_skb(skb); - input_queue_head_add(sd, 1); + input_queue_head_incr(sd); } } rps_unlock(sd); @@ -2973,6 +2970,7 @@ static void flush_backlog(void *arg) if (skb->dev == dev) { __skb_unlink(skb, &sd->process_queue); kfree_skb(skb); + input_queue_head_incr(sd); } } } @@ -3328,18 +3326,20 @@ static int process_backlog(struct napi_struct *napi, int quota) while ((skb = __skb_dequeue(&sd->process_queue))) { local_irq_enable(); __netif_receive_skb(skb); - if (++work >= quota) - return work; local_irq_disable(); + input_queue_head_incr(sd); + if (++work >= quota) { + local_irq_enable(); + return work; + } } rps_lock(sd); qlen = skb_queue_len(&sd->input_pkt_queue); - if (qlen) { - input_queue_head_add(sd, qlen); + if (qlen) skb_queue_splice_tail_init(&sd->input_pkt_queue, &sd->process_queue); - } + if (qlen < quota - work) { /* * Inline a custom version of __napi_complete(). @@ -5679,12 +5679,14 @@ static int dev_cpu_callback(struct notifier_block *nfb, local_irq_enable(); /* Process offline CPU's input_pkt_queue */ - while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) { + while ((skb = __skb_dequeue(&oldsd->process_queue))) { netif_rx(skb); - input_queue_head_add(oldsd, 1); + input_queue_head_incr(oldsd); } - while ((skb = __skb_dequeue(&oldsd->process_queue))) + while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) { netif_rx(skb); + input_queue_head_incr(oldsd); + } return NOTIFY_OK; } -- cgit v1.2.3 From 22fe88d3d85850267ff4535b465794a5768f868a Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 13 May 2010 10:34:08 +0530 Subject: cfg80211: Fix signal_type comparison signal_type is enum cfg80211_signal_type. This fixes the gcc warning: scan.c: In function `cfg80211_inform_bss': scan.c:518:6: warning: comparison between `enum cfg80211_signal_type' and `enum nl80211_bss' scan.c: In function `cfg80211_inform_bss_frame': scan.c:574:6: warning: comparison between `enum cfg80211_signal_type' and `enum nl80211_bss' Signed-off-by: Sujith Signed-off-by: John W. Linville --- net/wireless/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index a026c6d56bd3..58401d246bda 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -515,7 +515,7 @@ cfg80211_inform_bss(struct wiphy *wiphy, privsz = wiphy->bss_priv_size; - if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && + if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && (signal < 0 || signal > 100))) return NULL; @@ -571,7 +571,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, u.probe_resp.variable); size_t privsz = wiphy->bss_priv_size; - if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && + if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && (signal < 0 || signal > 100))) return NULL; -- cgit v1.2.3 From 073d5eab6fc85b6c278d507a5633b759a85dc878 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 13 May 2010 14:49:44 -0700 Subject: iwlwifi: fix internal scan race It is possible for internal scan to race against itself if the device is not returning the scan results from first requests. What happens in this case is the cleanup done during the abort of the first internal scan also cleans up part of the new scan, causing it to access memory it shouldn't. Here are details: * First internal scan is triggered and scan command sent to device. * After seven seconds there is no scan results so the watchdog timer triggers a scan abort. * The scan abort succeeds and a SCAN_COMPLETE_NOTIFICATION is received for failed scan. * During processing of SCAN_COMPLETE_NOTIFICATION we clear STATUS_SCANNING and queue the "scan_completed" work. ** At this time, since the problem that caused the internal scan in first place is still present, a new internal scan is triggered. The behavior at this point is a bit different between 2.6.34 and 2.6.35 since 2.6.35 has a lot of this synchronized. The rest of the race description will thus be generalized. ** As part of preparing for the scan "is_internal_short_scan" is set to true. * At this point the completion work for fist scan is run. As part of this there is some locking missing around the "is_internal_short_scan" variable and it is set to "false". ** Now the second scan runs and it considers itself a real (not internal0 scan and thus causes problems with wrong memory being accessed. The fix is twofold. * Since "is_internal_short_scan" should be protected by mutex, fix this in scan completion work so that changes to it can be serialized. * Do not queue a new internal scan if one is in progress. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=15824 Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 107e173112f6..5d3f51ff2f0d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -376,6 +376,11 @@ void iwl_bg_start_internal_scan(struct work_struct *work) mutex_lock(&priv->mutex); + if (priv->is_internal_short_scan == true) { + IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); + goto unlock; + } + if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); goto unlock; @@ -497,17 +502,27 @@ void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); + bool internal = false; IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); cancel_delayed_work(&priv->scan_check); - if (!priv->is_internal_short_scan) - ieee80211_scan_completed(priv->hw, false); - else { + mutex_lock(&priv->mutex); + if (priv->is_internal_short_scan) { priv->is_internal_short_scan = false; IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); + internal = true; } + mutex_unlock(&priv->mutex); + + /* + * Do not hold mutex here since this will cause mac80211 to call + * into driver again into functions that will attempt to take + * mutex. + */ + if (!internal) + ieee80211_scan_completed(priv->hw, false); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; -- cgit v1.2.3 From b9f2e39d4c2bcd8e94f73ae14450d7764f930a41 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Fri, 14 May 2010 10:46:24 +0300 Subject: wl1271: Fix RX data path frame lengths The current frame length used by the driver for RX frames is the SPI bus transfer length. This length has padding bytes, which do not belong to the WLAN frame. As there is no other length information in the WLAN frame except the skb length this problem caused for instance extra ESSID's to be listed at the end of scan results (IE id 0) with zero length. Fix the frame length by removing padding. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/wl1271_rx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 57f4bfd959c8..b98fb643fab0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -113,6 +113,8 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length) wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len, beacon ? "beacon" : ""); + skb_trim(skb, skb->len - desc->pad_len); + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); ieee80211_rx_ni(wl->hw, skb); } -- cgit v1.2.3 From 9fbc630c89fd210e15ffe84fd6e968a2d39000b0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 15 May 2010 15:46:17 +0200 Subject: cfg80211: fix crash in cfg80211_set_freq() Since wdev can be NULL, check it before dereferencing it Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- net/wireless/chan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/chan.c b/net/wireless/chan.c index d92d088026bf..b01a6f6397d7 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -50,7 +50,7 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, struct ieee80211_channel *chan; int result; - if (wdev->iftype == NL80211_IFTYPE_MONITOR) + if (wdev && wdev->iftype == NL80211_IFTYPE_MONITOR) wdev = NULL; if (wdev) { -- cgit v1.2.3 From ab1d864431a557580945387477bcbcb9dc7f7135 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 17 May 2010 13:15:30 -0400 Subject: ath9k: remove AR9003 from PCI IDs for now We tried to squeeze as much AR9003 support into this kernel release cycle but there are a few features which are still being tested and developed. Some of these features are critical to the stable operation of AR9003 so for now disable AR9003 support all together. This will get re-enabled once all necessary features are in place but very likely will not happen for 2.6.35. Reviewed-by: Don Breslin Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 257b10ba6f57..1ec836cf1c0d 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -28,7 +28,6 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ - { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ { 0 } }; -- cgit v1.2.3 From b6411fc23c70d7a9f57a0bfb35212ad92b5c2b5e Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 18 May 2010 11:20:51 +0300 Subject: rndis_wlan: replace wireless_send_event with cfg80211_disconnected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove (hopefully) last use of WEXT in rndis_wlan. Replace wireless_send_event with missing cfg80211_disconnected in rndis_wlan_do_link_down_work. Reported-by: "Rogério Brito" Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/rndis_wlan.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2d2890878dea..4bd61ee627c0 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2572,14 +2572,18 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) static void rndis_wlan_do_link_down_work(struct usbnet *usbdev) { - union iwreq_data evt; + struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); - netif_carrier_off(usbdev->net); + if (priv->connected) { + priv->connected = false; + memset(priv->bssid, 0, ETH_ALEN); + + deauthenticate(usbdev); - evt.data.flags = 0; - evt.data.length = 0; - memset(evt.ap_addr.sa_data, 0, ETH_ALEN); - wireless_send_event(usbdev->net, SIOCGIWAP, &evt, NULL); + cfg80211_disconnected(usbdev->net, 0, NULL, 0, GFP_KERNEL); + } + + netif_carrier_off(usbdev->net); } static void rndis_wlan_worker(struct work_struct *work) -- cgit v1.2.3 From 579d7534ca83235794b6d9ef3cd473ffc14e9d42 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 May 2010 14:36:34 +0200 Subject: cfg80211: add missing braces Specifying a valid channel type will get goto out rather than continuing, due to missing braces. This affects both remain on channel and action frame TX commands. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index aaa1aad566cd..db71150b8040 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4443,9 +4443,10 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, if (channel_type != NL80211_CHAN_NO_HT && channel_type != NL80211_CHAN_HT20 && channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) + channel_type != NL80211_CHAN_HT40MINUS) { err = -EINVAL; goto out; + } } freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); @@ -4717,9 +4718,10 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) if (channel_type != NL80211_CHAN_NO_HT && channel_type != NL80211_CHAN_HT20 && channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) + channel_type != NL80211_CHAN_HT40MINUS) { err = -EINVAL; goto out; + } } freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); -- cgit v1.2.3 From 6fc7f5730b71916bc44389015d404f668674c64c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 22 May 2010 17:29:52 +0000 Subject: enic: bug fix: sprintf UUID to string as u8[] rather than u16[] array Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index e125113759a5..7e973237bf98 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1034,9 +1034,10 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, { struct vic_provinfo *vp; u8 oui[3] = VIC_PROVINFO_CISCO_OUI; - unsigned short *uuid; + u8 *uuid; char uuid_str[38]; - static char *uuid_fmt = "%04X%04X-%04X-%04X-%04X-%04X%04X%04X"; + static char *uuid_fmt = "%02X%02X%02X%02X-%02X%02X-%02X%02X-" + "%02X%02X-%02X%02X%02X%02X%0X%02X"; int err; if (!name) @@ -1058,20 +1059,24 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, ETH_ALEN, mac); if (instance_uuid) { - uuid = (unsigned short *)instance_uuid; + uuid = instance_uuid; sprintf(uuid_str, uuid_fmt, - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7]); + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); vic_provinfo_add_tlv(vp, VIC_LINUX_PROV_TLV_CLIENT_UUID_STR, sizeof(uuid_str), uuid_str); } if (host_uuid) { - uuid = (unsigned short *)host_uuid; + uuid = host_uuid; sprintf(uuid_str, uuid_fmt, - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7]); + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); vic_provinfo_add_tlv(vp, VIC_LINUX_PROV_TLV_HOST_UUID_STR, sizeof(uuid_str), uuid_str); -- cgit v1.2.3 From 418c437d8b4b87815f3afed89da2aa0078d5379d Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 22 May 2010 17:29:58 +0000 Subject: enic: Use random mac addr when associating port-profile Use random mac addr for interface when associating port-profile to dynamic enic device, in the case no mac addr was previous assigned. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/enic/enic_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 7e973237bf98..6586b5c7e4b6 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1132,6 +1132,14 @@ static int enic_set_vf_port(struct net_device *netdev, int vf, switch (request) { case PORT_REQUEST_ASSOCIATE: + /* If the interface mac addr hasn't been assigned, + * assign a random mac addr before setting port- + * profile. + */ + + if (is_zero_ether_addr(netdev->dev_addr)) + random_ether_addr(netdev->dev_addr); + if (port[IFLA_PORT_PROFILE]) name = nla_data(port[IFLA_PORT_PROFILE]); -- cgit v1.2.3 From a6c0f8217c17d46da22fa56923f3cbd03615cb7c Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Sun, 23 May 2010 05:45:45 +0000 Subject: ieee802154: Fix possible NULL pointer dereference in wpan_phy_alloc Check for NULL pointer after kzalloc Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- net/ieee802154/wpan-class.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c index 3d803a1b9fb6..1627ef2e8522 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/wpan-class.c @@ -147,13 +147,15 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size) struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size, GFP_KERNEL); + if (!phy) + goto out; mutex_lock(&wpan_phy_mutex); phy->idx = wpan_phy_idx++; if (unlikely(!wpan_phy_idx_valid(phy->idx))) { wpan_phy_idx--; mutex_unlock(&wpan_phy_mutex); kfree(phy); - return NULL; + goto out; } mutex_unlock(&wpan_phy_mutex); @@ -168,6 +170,9 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size) phy->current_page = 0; /* for compatibility */ return phy; + +out: + return NULL; } EXPORT_SYMBOL(wpan_phy_alloc); -- cgit v1.2.3 From 53b0f08042f04813cd1a7473dacd3edfacb28eb3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 22 May 2010 20:37:44 +0000 Subject: net_sched: Fix qdisc_notify() Ben Pfaff reported a kernel oops and provided a test program to reproduce it. https://kerneltrap.org/mailarchive/linux-netdev/2010/5/21/6277805 tc_fill_qdisc() should not be called for builtin qdisc, or it dereference a NULL pointer to get device ifindex. Fix is to always use tc_qdisc_dump_ignore() before calling tc_fill_qdisc(). Reported-by: Ben Pfaff Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/sched/sch_api.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index fe35c1f338c2..b9e8c3b7d406 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1195,6 +1195,11 @@ nla_put_failure: return -1; } +static bool tc_qdisc_dump_ignore(struct Qdisc *q) +{ + return (q->flags & TCQ_F_BUILTIN) ? true : false; +} + static int qdisc_notify(struct net *net, struct sk_buff *oskb, struct nlmsghdr *n, u32 clid, struct Qdisc *old, struct Qdisc *new) @@ -1206,11 +1211,11 @@ static int qdisc_notify(struct net *net, struct sk_buff *oskb, if (!skb) return -ENOBUFS; - if (old && old->handle) { + if (old && !tc_qdisc_dump_ignore(old)) { if (tc_fill_qdisc(skb, old, clid, pid, n->nlmsg_seq, 0, RTM_DELQDISC) < 0) goto err_out; } - if (new) { + if (new && !tc_qdisc_dump_ignore(new)) { if (tc_fill_qdisc(skb, new, clid, pid, n->nlmsg_seq, old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0) goto err_out; } @@ -1223,11 +1228,6 @@ err_out: return -EINVAL; } -static bool tc_qdisc_dump_ignore(struct Qdisc *q) -{ - return (q->flags & TCQ_F_BUILTIN) ? true : false; -} - static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, struct netlink_callback *cb, int *q_idx_p, int s_q_idx) -- cgit v1.2.3 From eb1669aed950cb5f34622bcceba66bef5980e97a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 21 May 2010 10:45:20 +0000 Subject: net-caif: drop redundant Kconfig entries There is already a submenu entry that is always displayed, so there is no need to also show a dedicated CAIF comment. Drop dead commented code while we're here, and change the submenu text to better match the style everyone else is using. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- net/caif/Kconfig | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/net/caif/Kconfig b/net/caif/Kconfig index cd1daf6008bd..ed651786f16b 100644 --- a/net/caif/Kconfig +++ b/net/caif/Kconfig @@ -2,10 +2,8 @@ # CAIF net configurations # -#menu "CAIF Support" -comment "CAIF Support" menuconfig CAIF - tristate "Enable CAIF support" + tristate "CAIF support" select CRC_CCITT default n ---help--- @@ -45,4 +43,3 @@ config CAIF_NETDEV If unsure say Y. endif -#endmenu -- cgit v1.2.3 From 253683bbfb6bc5864417c8c35cb6ef13b5e259e6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 21 May 2010 02:25:27 +0000 Subject: rtnetlink: Fix error handling in do_setlink() Commit c02db8c6290bb992442fec1407643c94cc414375: Author: Chris Wright Date: Sun May 16 01:05:45 2010 -0700 Subject: rtnetlink: make SR-IOV VF interface symmetric adds broken error handling to do_setlink() in net/core/rtnetlink.c. The problem is the following chunk of code: if (tb[IFLA_VFINFO_LIST]) { struct nlattr *attr; int rem; nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { if (nla_type(attr) != IFLA_VF_INFO) ----> goto errout; err = do_setvfinfo(dev, attr); if (err < 0) goto errout; modified = 1; } } which can get to errout without setting err, resulting in the following error: net/core/rtnetlink.c: In function 'do_setlink': net/core/rtnetlink.c:904: warning: 'err' may be used uninitialized in this function Change the code to return -EINVAL in this case. Note that this might not be the appropriate error though. Signed-off-by: David Howells cc: Chris Wright cc: David S. Miller Acked-by: Chris Wright Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e4b9870e4706..7ab86f3a1ea4 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1199,8 +1199,10 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, struct nlattr *attr; int rem; nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { - if (nla_type(attr) != IFLA_VF_INFO) + if (nla_type(attr) != IFLA_VF_INFO) { + err = -EINVAL; goto errout; + } err = do_setvfinfo(dev, attr); if (err < 0) goto errout; -- cgit v1.2.3 From ee02a4ef40f2e049c80f9cc04e21a9b48288b6ff Mon Sep 17 00:00:00 2001 From: Thomas Chou Date: Sun, 23 May 2010 16:44:02 +0000 Subject: ethoc: fix null dereference in ethoc_probe Dan reported the patch 0baa080c75c: "ethoc: use system memory as buffer" introduced a potential null dereference. 1060 free: 1061 if (priv->dma_alloc) ^^^^^^^^^^^^^^^ priv can be null here. He also suggested that the error handling is not complete. This patch fixes the null priv issue and improves resources releasing in ethoc_probe() and ethoc_remove(). Reported-by: Dan Carpenter Signed-off-by: Thomas Chou Signed-off-by: David S. Miller --- drivers/net/ethoc.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index 14cbde5cf68e..6ed2df14ec84 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -174,6 +174,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); * @iobase: pointer to I/O memory region * @membase: pointer to buffer memory region * @dma_alloc: dma allocated buffer size + * @io_region_size: I/O memory region size * @num_tx: number of send buffers * @cur_tx: last send buffer written * @dty_tx: last buffer actually sent @@ -193,6 +194,7 @@ struct ethoc { void __iomem *iobase; void __iomem *membase; int dma_alloc; + resource_size_t io_region_size; unsigned int num_tx; unsigned int cur_tx; @@ -943,6 +945,7 @@ static int ethoc_probe(struct platform_device *pdev) priv = netdev_priv(netdev); priv->netdev = netdev; priv->dma_alloc = 0; + priv->io_region_size = mmio->end - mmio->start + 1; priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, resource_size(mmio)); @@ -1047,20 +1050,34 @@ static int ethoc_probe(struct platform_device *pdev) ret = register_netdev(netdev); if (ret < 0) { dev_err(&netdev->dev, "failed to register interface\n"); - goto error; + goto error2; } goto out; +error2: + netif_napi_del(&priv->napi); error: mdiobus_unregister(priv->mdio); free_mdio: kfree(priv->mdio->irq); mdiobus_free(priv->mdio); free: - if (priv->dma_alloc) - dma_free_coherent(NULL, priv->dma_alloc, priv->membase, - netdev->mem_start); + if (priv) { + if (priv->dma_alloc) + dma_free_coherent(NULL, priv->dma_alloc, priv->membase, + netdev->mem_start); + else if (priv->membase) + devm_iounmap(&pdev->dev, priv->membase); + if (priv->iobase) + devm_iounmap(&pdev->dev, priv->iobase); + } + if (mem) + devm_release_mem_region(&pdev->dev, mem->start, + mem->end - mem->start + 1); + if (mmio) + devm_release_mem_region(&pdev->dev, mmio->start, + mmio->end - mmio->start + 1); free_netdev(netdev); out: return ret; @@ -1078,6 +1095,7 @@ static int ethoc_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (netdev) { + netif_napi_del(&priv->napi); phy_disconnect(priv->phy); priv->phy = NULL; @@ -1089,6 +1107,14 @@ static int ethoc_remove(struct platform_device *pdev) if (priv->dma_alloc) dma_free_coherent(NULL, priv->dma_alloc, priv->membase, netdev->mem_start); + else { + devm_iounmap(&pdev->dev, priv->membase); + devm_release_mem_region(&pdev->dev, netdev->mem_start, + netdev->mem_end - netdev->mem_start + 1); + } + devm_iounmap(&pdev->dev, priv->iobase); + devm_release_mem_region(&pdev->dev, netdev->base_addr, + priv->io_region_size); unregister_netdev(netdev); free_netdev(netdev); } -- cgit v1.2.3 From 7f267de41fde594500cbbccb1b29acb4475f2da2 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Tue, 18 May 2010 01:34:46 +0000 Subject: bfin_mac: fix memleak in mii_bus{probe|remove} Fix memory leak with miibus->irq Signed-off-by: Denis Kirjanov Signed-off-by: David S. Miller --- drivers/net/bfin_mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 39a54bad397f..368f33313fb6 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -1626,6 +1626,7 @@ static int __devinit bfin_mii_bus_probe(struct platform_device *pdev) return 0; out_err_mdiobus_register: + kfree(miibus->irq); mdiobus_free(miibus); out_err_alloc: peripheral_free_list(pin_req); @@ -1638,6 +1639,7 @@ static int __devexit bfin_mii_bus_remove(struct platform_device *pdev) struct mii_bus *miibus = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); mdiobus_unregister(miibus); + kfree(miibus->irq); mdiobus_free(miibus); peripheral_free_list(pin_req); return 0; -- cgit v1.2.3 From a4ed89cb92f93d406ac45fe5507228a2475e32ba Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 18 May 2010 06:56:32 +0000 Subject: net: Fix definition of netif_vdbg() when VERBOSE_DEBUG is not defined Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 256419583d9d..40291f375024 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2334,7 +2334,7 @@ do { \ #define netif_vdbg(priv, type, dev, format, args...) \ ({ \ if (0) \ - netif_printk(KERN_DEBUG, dev, format, ##args); \ + netif_printk(priv, type, KERN_DEBUG, dev, format, ##args); \ 0; \ }) #endif -- cgit v1.2.3 From 8ce6cebc2f126f3ecf2d80746ea54245adf18057 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 19 May 2010 10:12:19 +0000 Subject: net-2.6 : V2 - fix dev_get_valid_name the commit: commit d90310243fd750240755e217c5faa13e24f41536 Author: Octavian Purdila Date: Wed Nov 18 02:36:59 2009 +0000 net: device name allocation cleanups introduced a bug when there is a hash collision making impossible to rename a device with eth%d. This bug is very hard to reproduce and appears rarely. The problem is coming from we don't pass a temporary buffer to __dev_alloc_name but 'dev->name' which is modified by the function. A detailed explanation is here: http://marc.info/?l=linux-netdev&m=127417784011987&w=2 Changelog: V2 : replaced strings comparison by pointers comparison Signed-off-by: Daniel Lezcano Reviewed-by: Octavian Purdila Signed-off-by: David S. Miller --- net/core/dev.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 0aab66d68b19..07a48e2bf7db 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -954,18 +954,22 @@ int dev_alloc_name(struct net_device *dev, const char *name) } EXPORT_SYMBOL(dev_alloc_name); -static int dev_get_valid_name(struct net *net, const char *name, char *buf, - bool fmt) +static int dev_get_valid_name(struct net_device *dev, const char *name, bool fmt) { + struct net *net; + + BUG_ON(!dev_net(dev)); + net = dev_net(dev); + if (!dev_valid_name(name)) return -EINVAL; if (fmt && strchr(name, '%')) - return __dev_alloc_name(net, name, buf); + return dev_alloc_name(dev, name); else if (__dev_get_by_name(net, name)) return -EEXIST; - else if (buf != name) - strlcpy(buf, name, IFNAMSIZ); + else if (dev->name != name) + strlcpy(dev->name, name, IFNAMSIZ); return 0; } @@ -997,7 +1001,7 @@ int dev_change_name(struct net_device *dev, const char *newname) memcpy(oldname, dev->name, IFNAMSIZ); - err = dev_get_valid_name(net, newname, dev->name, 1); + err = dev_get_valid_name(dev, newname, 1); if (err < 0) return err; @@ -4965,7 +4969,7 @@ int register_netdevice(struct net_device *dev) } } - ret = dev_get_valid_name(net, dev->name, dev->name, 0); + ret = dev_get_valid_name(dev, dev->name, 0); if (ret) goto err_uninit; @@ -5574,7 +5578,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* We get here if we can't use the current device name */ if (!pat) goto out; - if (dev_get_valid_name(net, pat, dev->name, 1)) + if (dev_get_valid_name(dev, pat, 1)) goto out; } -- cgit v1.2.3 From 9e4b816bc31962ebbb8784d602acd5fa25a08ad8 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Fri, 21 May 2010 02:16:07 +0000 Subject: caif: Bugfix - wait_ev*_timeout returns long. Discovered bug when testing on 64bit architecture. Fixed by using long to store result from wait_event_interruptible_timeout. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- net/caif/caif_socket.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index c3a70c5c893a..77e99568acda 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -920,17 +920,17 @@ wait_connect: timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); release_sock(sk); - err = wait_event_interruptible_timeout(*sk_sleep(sk), + err = -ERESTARTSYS; + timeo = wait_event_interruptible_timeout(*sk_sleep(sk), sk->sk_state != CAIF_CONNECTING, timeo); lock_sock(sk); - if (err < 0) + if (timeo < 0) goto out; /* -ERESTARTSYS */ - if (err == 0 && sk->sk_state != CAIF_CONNECTED) { - err = -ETIMEDOUT; - goto out; - } + err = -ETIMEDOUT; + if (timeo == 0 && sk->sk_state != CAIF_CONNECTED) + goto out; if (sk->sk_state != CAIF_CONNECTED) { sock->state = SS_UNCONNECTED; err = sock_error(sk); @@ -945,7 +945,6 @@ out: return err; } - /* * caif_release() - Disconnect a CAIF Socket * Copied and modified af_irda.c:irda_release(). -- cgit v1.2.3 From 7aecf4944f2c05aafb73b4820e469c74b4ec8517 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Fri, 21 May 2010 02:16:08 +0000 Subject: caif: Bugfix - use standard Linux lists Discovered bug when running high number of parallel connect requests. Replace buggy home brewed list with linux/list.h. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- include/net/caif/cfctrl.h | 4 +-- net/caif/cfctrl.c | 92 ++++++++++++++--------------------------------- 2 files changed, 28 insertions(+), 68 deletions(-) diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h index 997603f2bf4c..9402543fc20d 100644 --- a/include/net/caif/cfctrl.h +++ b/include/net/caif/cfctrl.h @@ -94,8 +94,8 @@ struct cfctrl_request_info { enum cfctrl_cmd cmd; u8 channel_id; struct cfctrl_link_param param; - struct cfctrl_request_info *next; struct cflayer *client_layer; + struct list_head list; }; struct cfctrl { @@ -103,7 +103,7 @@ struct cfctrl { struct cfctrl_rsp res; atomic_t req_seq_no; atomic_t rsp_seq_no; - struct cfctrl_request_info *first_req; + struct list_head list; /* Protects from simultaneous access to first_req list */ spinlock_t info_list_lock; #ifndef CAIF_NO_LOOP diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index 0ffe1e1ce901..fcfda98a5e6d 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -44,13 +44,14 @@ struct cflayer *cfctrl_create(void) dev_info.id = 0xff; memset(this, 0, sizeof(*this)); cfsrvl_init(&this->serv, 0, &dev_info); - spin_lock_init(&this->info_list_lock); atomic_set(&this->req_seq_no, 1); atomic_set(&this->rsp_seq_no, 1); this->serv.layer.receive = cfctrl_recv; sprintf(this->serv.layer.name, "ctrl"); this->serv.layer.ctrlcmd = cfctrl_ctrlcmd; spin_lock_init(&this->loop_linkid_lock); + spin_lock_init(&this->info_list_lock); + INIT_LIST_HEAD(&this->list); this->loop_linkid = 1; return &this->serv.layer; } @@ -112,20 +113,10 @@ bool cfctrl_req_eq(struct cfctrl_request_info *r1, void cfctrl_insert_req(struct cfctrl *ctrl, struct cfctrl_request_info *req) { - struct cfctrl_request_info *p; spin_lock(&ctrl->info_list_lock); - req->next = NULL; atomic_inc(&ctrl->req_seq_no); req->sequence_no = atomic_read(&ctrl->req_seq_no); - if (ctrl->first_req == NULL) { - ctrl->first_req = req; - spin_unlock(&ctrl->info_list_lock); - return; - } - p = ctrl->first_req; - while (p->next != NULL) - p = p->next; - p->next = req; + list_add_tail(&req->list, &ctrl->list); spin_unlock(&ctrl->info_list_lock); } @@ -133,46 +124,28 @@ void cfctrl_insert_req(struct cfctrl *ctrl, struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl, struct cfctrl_request_info *req) { - struct cfctrl_request_info *p; - struct cfctrl_request_info *ret; + struct cfctrl_request_info *p, *tmp, *first; spin_lock(&ctrl->info_list_lock); - if (ctrl->first_req == NULL) { - spin_unlock(&ctrl->info_list_lock); - return NULL; - } - - if (cfctrl_req_eq(req, ctrl->first_req)) { - ret = ctrl->first_req; - caif_assert(ctrl->first_req); - atomic_set(&ctrl->rsp_seq_no, - ctrl->first_req->sequence_no); - ctrl->first_req = ctrl->first_req->next; - spin_unlock(&ctrl->info_list_lock); - return ret; - } + first = list_first_entry(&ctrl->list, struct cfctrl_request_info, list); - p = ctrl->first_req; - - while (p->next != NULL) { - if (cfctrl_req_eq(req, p->next)) { - pr_warning("CAIF: %s(): Requests are not " + list_for_each_entry_safe(p, tmp, &ctrl->list, list) { + if (cfctrl_req_eq(req, p)) { + if (p != first) + pr_warning("CAIF: %s(): Requests are not " "received in order\n", __func__); - ret = p->next; + atomic_set(&ctrl->rsp_seq_no, - p->next->sequence_no); - p->next = p->next->next; - spin_unlock(&ctrl->info_list_lock); - return ret; + p->sequence_no); + list_del(&p->list); + goto out; } - p = p->next; } + p = NULL; +out: spin_unlock(&ctrl->info_list_lock); - - pr_warning("CAIF: %s(): Request does not match\n", - __func__); - return NULL; + return p; } struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer) @@ -388,31 +361,18 @@ void cfctrl_getstartreason_req(struct cflayer *layer) void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer) { - struct cfctrl_request_info *p, *req; + struct cfctrl_request_info *p, *tmp; struct cfctrl *ctrl = container_obj(layr); spin_lock(&ctrl->info_list_lock); - - if (ctrl->first_req == NULL) { - spin_unlock(&ctrl->info_list_lock); - return; - } - - if (ctrl->first_req->client_layer == adap_layer) { - - req = ctrl->first_req; - ctrl->first_req = ctrl->first_req->next; - kfree(req); - } - - p = ctrl->first_req; - while (p != NULL && p->next != NULL) { - if (p->next->client_layer == adap_layer) { - - req = p->next; - p->next = p->next->next; - kfree(p->next); + pr_warning("CAIF: %s(): enter\n", __func__); + + list_for_each_entry_safe(p, tmp, &ctrl->list, list) { + if (p->client_layer == adap_layer) { + pr_warning("CAIF: %s(): cancel req :%d\n", __func__, + p->sequence_no); + list_del(&p->list); + kfree(p); } - p = p->next; } spin_unlock(&ctrl->info_list_lock); @@ -634,7 +594,7 @@ static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND: case CAIF_CTRLCMD_FLOW_OFF_IND: spin_lock(&this->info_list_lock); - if (this->first_req != NULL) { + if (!list_empty(&this->list)) { pr_debug("CAIF: %s(): Received flow off in " "control layer", __func__); } -- cgit v1.2.3 From 638e628a600a5c542d46dfb06771cf9c229ef5f3 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Fri, 21 May 2010 02:16:09 +0000 Subject: caif: Bugfix - handle mem-allocation failures Discovered bugs when injecting slab allocation failures. Add checks on all memory allocation. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- net/caif/cfpkt_skbuff.c | 25 +++++++++++++++++-------- net/caif/cfserl.c | 3 ++- net/caif/cfsrvl.c | 6 ++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c index 83fff2ff6658..a6fdf899741a 100644 --- a/net/caif/cfpkt_skbuff.c +++ b/net/caif/cfpkt_skbuff.c @@ -238,6 +238,7 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) struct sk_buff *lastskb; u8 *to; const u8 *data = data2; + int ret; if (unlikely(is_erronous(pkt))) return -EPROTO; if (unlikely(skb_headroom(skb) < len)) { @@ -246,9 +247,10 @@ int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) } /* Make sure data is writable */ - if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) { + ret = skb_cow_data(skb, 0, &lastskb); + if (unlikely(ret < 0)) { PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n"); - return -EPROTO; + return ret; } to = skb_push(skb, len); @@ -316,6 +318,8 @@ EXPORT_SYMBOL(cfpkt_setlen); struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len) { struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); + if (!pkt) + return NULL; if (unlikely(data != NULL)) cfpkt_add_body(pkt, data, len); return pkt; @@ -344,12 +348,13 @@ struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, if (dst->tail + neededtailspace > dst->end) { /* Create a dumplicate of 'dst' with more tail space */ + struct cfpkt *tmppkt; dstlen = skb_headlen(dst); createlen = dstlen + neededtailspace; - tmp = pkt_to_skb( - cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX)); - if (!tmp) + tmppkt = cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX); + if (tmppkt == NULL) return NULL; + tmp = pkt_to_skb(tmppkt); skb_set_tail_pointer(tmp, dstlen); tmp->len = dstlen; memcpy(tmp->data, dst->data, dstlen); @@ -368,6 +373,7 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) { struct sk_buff *skb2; struct sk_buff *skb = pkt_to_skb(pkt); + struct cfpkt *tmppkt; u8 *split = skb->data + pos; u16 len2nd = skb_tail_pointer(skb) - split; @@ -381,9 +387,12 @@ struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) } /* Create a new packet for the second part of the data */ - skb2 = pkt_to_skb( - cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX, - PKT_PREFIX)); + tmppkt = cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX, + PKT_PREFIX); + if (tmppkt == NULL) + return NULL; + skb2 = pkt_to_skb(tmppkt); + if (skb2 == NULL) return NULL; diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c index 06029ea2da2f..cb4325a3dc83 100644 --- a/net/caif/cfserl.c +++ b/net/caif/cfserl.c @@ -67,6 +67,8 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) layr->incomplete_frm = cfpkt_append(layr->incomplete_frm, newpkt, expectlen); pkt = layr->incomplete_frm; + if (pkt == NULL) + return -ENOMEM; } else { pkt = newpkt; } @@ -154,7 +156,6 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) if (layr->usestx) { if (tail_pkt != NULL) pkt = cfpkt_append(pkt, tail_pkt, 0); - /* Start search for next STX if frame failed */ continue; } else { diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c index aff31f34528f..6e5b7079a684 100644 --- a/net/caif/cfsrvl.c +++ b/net/caif/cfsrvl.c @@ -123,6 +123,12 @@ static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl) struct caif_payload_info *info; u8 flow_off = SRVL_FLOW_OFF; pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE); + if (!pkt) { + pr_warning("CAIF: %s(): Out of memory\n", + __func__); + return -ENOMEM; + } + if (cfpkt_add_head(pkt, &flow_off, 1) < 0) { pr_err("CAIF: %s(): Packet is erroneous!\n", __func__); -- cgit v1.2.3 From ca6a09f25cde1d2d86f8e821cf69f4f650c30dbf Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Fri, 21 May 2010 02:16:10 +0000 Subject: caif: Bugfix - Poll can't return POLLHUP while connecting. Discovered bug when testing async connect. While connecting poll should not return POLLHUP, but POLLOUT when connected. Also fixed the sysfs flow-control-counters. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- net/caif/caif_socket.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 77e99568acda..732897d64f41 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -138,7 +138,7 @@ void caif_flow_ctrl(struct sock *sk, int mode) { struct caifsock *cf_sk; cf_sk = container_of(sk, struct caifsock, sk); - if (cf_sk->layer.dn) + if (cf_sk->layer.dn && cf_sk->layer.dn->modemcmd) cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode); } @@ -162,9 +162,8 @@ int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) atomic_read(&cf_sk->sk.sk_rmem_alloc), sk_rcvbuf_lowwater(cf_sk)); set_rx_flow_off(cf_sk); - if (cf_sk->layer.dn) - cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, - CAIF_MODEMCMD_FLOW_OFF_REQ); + dbfs_atomic_inc(&cnt.num_rx_flow_off); + caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); } err = sk_filter(sk, skb); @@ -175,9 +174,8 @@ int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) trace_printk("CAIF: %s():" " sending flow OFF due to rmem_schedule\n", __func__); - if (cf_sk->layer.dn) - cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, - CAIF_MODEMCMD_FLOW_OFF_REQ); + dbfs_atomic_inc(&cnt.num_rx_flow_off); + caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_OFF_REQ); } skb->dev = NULL; skb_set_owner_r(skb, sk); @@ -285,16 +283,13 @@ static void caif_check_flow_release(struct sock *sk) { struct caifsock *cf_sk = container_of(sk, struct caifsock, sk); - if (cf_sk->layer.dn == NULL || cf_sk->layer.dn->modemcmd == NULL) - return; if (rx_flow_is_on(cf_sk)) return; if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) { dbfs_atomic_inc(&cnt.num_rx_flow_on); set_rx_flow_on(cf_sk); - cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, - CAIF_MODEMCMD_FLOW_ON_REQ); + caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ); } } /* @@ -1018,10 +1013,6 @@ static unsigned int caif_poll(struct file *file, (sk->sk_shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; - /* Connection-based need to check for termination and startup */ - if (sk->sk_state == CAIF_DISCONNECTED) - mask |= POLLHUP; - /* * we set writable also when the other side has shut down the * connection. This prevents stuck sockets. -- cgit v1.2.3 From a9a8f1070d8733b37418b3a2d58df4e771b61f88 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Fri, 21 May 2010 02:16:11 +0000 Subject: caif: Bugfix - missing spin_unlock Splint found missing spin_unlock. Corrected this an some other trivial split warnings. Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- net/caif/caif_socket.c | 10 +++++----- net/caif/cfmuxl.c | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 732897d64f41..691a5710974e 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -60,7 +60,7 @@ struct debug_fs_counter { atomic_t num_rx_flow_off; atomic_t num_rx_flow_on; }; -struct debug_fs_counter cnt; +static struct debug_fs_counter cnt; #define dbfs_atomic_inc(v) atomic_inc(v) #define dbfs_atomic_dec(v) atomic_dec(v) #else @@ -128,13 +128,13 @@ static void caif_read_unlock(struct sock *sk) mutex_unlock(&cf_sk->readlock); } -int sk_rcvbuf_lowwater(struct caifsock *cf_sk) +static int sk_rcvbuf_lowwater(struct caifsock *cf_sk) { /* A quarter of full buffer is used a low water mark */ return cf_sk->sk.sk_rcvbuf / 4; } -void caif_flow_ctrl(struct sock *sk, int mode) +static void caif_flow_ctrl(struct sock *sk, int mode) { struct caifsock *cf_sk; cf_sk = container_of(sk, struct caifsock, sk); @@ -146,7 +146,7 @@ void caif_flow_ctrl(struct sock *sk, int mode) * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are * not dropped, but CAIF is sending flow off instead. */ -int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) +static int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { int err; int skb_len; @@ -1184,7 +1184,7 @@ static struct net_proto_family caif_family_ops = { .owner = THIS_MODULE, }; -int af_caif_init(void) +static int af_caif_init(void) { int err = sock_register(&caif_family_ops); if (!err) diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c index 7372f27f1d32..80c8d332b258 100644 --- a/net/caif/cfmuxl.c +++ b/net/caif/cfmuxl.c @@ -174,10 +174,11 @@ struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id) spin_lock(&muxl->receive_lock); up = get_up(muxl, id); if (up == NULL) - return NULL; + goto out; memset(muxl->up_cache, 0, sizeof(muxl->up_cache)); list_del(&up->node); cfsrvl_put(up); +out: spin_unlock(&muxl->receive_lock); return up; } -- cgit v1.2.3 From dcda138d2f27e32bd0d6250cc42839b0d70bb4b8 Mon Sep 17 00:00:00 2001 From: Sjur Braendeland Date: Fri, 21 May 2010 02:16:12 +0000 Subject: caif: Bugfix - use MSG_TRUNC in receive Fixed handling when skb don't fit in user buffer, instead of returning -EMSGSIZE, the buffer is truncated (just as unix seqpakcet does). Signed-off-by: Sjur Braendeland Signed-off-by: David S. Miller --- net/caif/caif_socket.c | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 691a5710974e..3d0e09584fae 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -292,53 +292,42 @@ static void caif_check_flow_release(struct sock *sk) caif_flow_ctrl(sk, CAIF_MODEMCMD_FLOW_ON_REQ); } } + /* - * Copied from sock.c:sock_queue_rcv_skb(), and added check that user buffer - * has sufficient size. + * Copied from unix_dgram_recvmsg, but removed credit checks, + * changed locking, address handling and added MSG_TRUNC. */ - static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t buf_len, int flags) + struct msghdr *m, size_t len, int flags) { struct sock *sk = sock->sk; struct sk_buff *skb; - int ret = 0; - int len; + int ret; + int copylen; - if (unlikely(!buf_len)) - return -EINVAL; + ret = -EOPNOTSUPP; + if (m->msg_flags&MSG_OOB) + goto read_error; skb = skb_recv_datagram(sk, flags, 0 , &ret); if (!skb) goto read_error; - - len = skb->len; - - if (skb && skb->len > buf_len && !(flags & MSG_PEEK)) { - len = buf_len; - /* - * Push skb back on receive queue if buffer too small. - * This has a built-in race where multi-threaded receive - * may get packet in wrong order, but multiple read does - * not really guarantee ordered delivery anyway. - * Let's optimize for speed without taking locks. - */ - - skb_queue_head(&sk->sk_receive_queue, skb); - ret = -EMSGSIZE; - goto read_error; + copylen = skb->len; + if (len < copylen) { + m->msg_flags |= MSG_TRUNC; + copylen = len; } - ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, len); + ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, copylen); if (ret) - goto read_error; + goto out_free; + ret = (flags & MSG_TRUNC) ? skb->len : copylen; +out_free: skb_free_datagram(sk, skb); - caif_check_flow_release(sk); - - return len; + return ret; read_error: return ret; -- cgit v1.2.3 From a5e93151e4390e4d27bee27ddb73f78f58260594 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 22 May 2010 10:27:48 +0000 Subject: pppoe: uninitialized variable in pppoe_flush_dev() This assignment got deleted along with the checks by mistake. This comes from: 8753d29fd "pppoe: remove unnecessary checks in pppoe_flush_dev" Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index b1b93ff2351f..805b64d1e893 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -289,6 +289,7 @@ static void pppoe_flush_dev(struct net_device *dev) struct pppoe_net *pn; int i; + pn = pppoe_pernet(dev_net(dev)); write_lock_bh(&pn->hash_lock); for (i = 0; i < PPPOE_HASH_SIZE; i++) { struct pppox_sock *po = pn->hash_table[i]; -- cgit v1.2.3 From 85a83560afa69862639fb2d6f670b4440a003335 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 23 May 2010 01:02:08 +0000 Subject: isdn/capi: make reset_ctr op truly optional The CAPI controller operation reset_ctr is marked as optional, and not all drivers do implement it. Add a check to the kernel CAPI whether it exists before trying to call it. Signed-off-by: Tilman Schmidt Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/capi/kcapi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index bd00dceacaf0..bde3c88b8b27 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -1147,6 +1147,12 @@ load_unlock_out: if (ctr->state == CAPI_CTR_DETECTED) goto reset_unlock_out; + if (ctr->reset_ctr == NULL) { + printk(KERN_DEBUG "kcapi: reset: no reset function\n"); + retval = -ESRCH; + goto reset_unlock_out; + } + ctr->reset_ctr(ctr); retval = wait_on_ctr_state(ctr, CAPI_CTR_DETECTED); -- cgit v1.2.3 From e487639dc8ca6bd6c19a4140f45ebc88da56ddd5 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 23 May 2010 01:02:38 +0000 Subject: isdn/gigaset: remove dummy CAPI method implementations Dummy implementations for the optional CAPI controller operations load_firmware and reset_ctr can cause userspace callers to hang indefinitely. It's better not to implement them at all. Signed-off-by: Tilman Schmidt Acked-by: Karsten Keil Signed-off-by: David S. Miller --- drivers/isdn/gigaset/capi.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 964a55fb1486..e72f86bccaa5 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -932,30 +932,6 @@ void gigaset_isdn_stop(struct cardstate *cs) * ============================ */ -/* - * load firmware - */ -static int gigaset_load_firmware(struct capi_ctr *ctr, capiloaddata *data) -{ - struct cardstate *cs = ctr->driverdata; - - /* AVM specific operation, not needed for Gigaset -- ignore */ - dev_notice(cs->dev, "load_firmware ignored\n"); - - return 0; -} - -/* - * reset (deactivate) controller - */ -static void gigaset_reset_ctr(struct capi_ctr *ctr) -{ - struct cardstate *cs = ctr->driverdata; - - /* AVM specific operation, not needed for Gigaset -- ignore */ - dev_notice(cs->dev, "reset_ctr ignored\n"); -} - /* * register CAPI application */ @@ -2213,8 +2189,8 @@ int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) iif->ctr.driverdata = cs; strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name)); iif->ctr.driver_name = "gigaset"; - iif->ctr.load_firmware = gigaset_load_firmware; - iif->ctr.reset_ctr = gigaset_reset_ctr; + iif->ctr.load_firmware = NULL; + iif->ctr.reset_ctr = NULL; iif->ctr.register_appl = gigaset_register_appl; iif->ctr.release_appl = gigaset_release_appl; iif->ctr.send_message = gigaset_send_message; -- cgit v1.2.3 From eda6e6f86b5f95b982ac7ebf7cf5be2a29a291e9 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Sat, 22 May 2010 22:00:10 +0000 Subject: net/irda: bfin_sir: IRDA is not affected by anomaly 05000230 Anomaly 05000230 (over sampling of the UART STOP bit) applies only when the peripheral is operating in UART mode. So drop the anomaly handling in the IRDA code. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- drivers/net/irda/bfin_sir.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c index 911c082cee5a..f940dfa1f7f8 100644 --- a/drivers/net/irda/bfin_sir.c +++ b/drivers/net/irda/bfin_sir.c @@ -107,8 +107,12 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) case 57600: case 115200: - quot = (port->clk + (8 * speed)) / (16 * speed)\ - - ANOMALY_05000230; + /* + * IRDA is not affected by anomaly 05000230, so there is no + * need to tweak the divisor like he UART driver (which will + * slightly speed up the baud rate on us). + */ + quot = (port->clk + (8 * speed)) / (16 * speed); do { udelay(utime); -- cgit v1.2.3 From f845172531fb7410c7fb7780b1a6e51ee6df7d52 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 24 May 2010 00:12:34 -0700 Subject: cls_cgroup: Store classid in struct sock Up until now cls_cgroup has relied on fetching the classid out of the current executing thread. This runs into trouble when a packet processing is delayed in which case it may execute out of another thread's context. Furthermore, even when a packet is not delayed we may fail to classify it if soft IRQs have been disabled, because this scenario is indistinguishable from one where a packet unrelated to the current thread is processed by a real soft IRQ. In fact, the current semantics is inherently broken, as a single skb may be constructed out of the writes of two different tasks. A different manifestation of this problem is when the TCP stack transmits in response of an incoming ACK. This is currently unclassified. As we already have a concept of packet ownership for accounting purposes in the skb->sk pointer, this is a natural place to store the classid in a persistent manner. This patch adds the cls_cgroup classid in struct sock, filling up an existing hole on 64-bit :) The value is set at socket creation time. So all sockets created via socket(2) automatically gains the ID of the thread creating it. Whenever another process touches the socket by either reading or writing to it, we will change the socket classid to that of the process if it has a valid (non-zero) classid. For sockets created on inbound connections through accept(2), we inherit the classid of the original listening socket through sk_clone, possibly preceding the actual accept(2) call. In order to minimise risks, I have not made this the authoritative classid. For now it is only used as a backup when we execute with soft IRQs disabled. Once we're completely happy with its semantics we can use it as the sole classid. Footnote: I have rearranged the error path on cls_group module creation. If we didn't do this, then there is a window where someone could create a tc rule using cls_group before the cgroup subsystem has been registered. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/cls_cgroup.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ include/net/sock.h | 10 +++++++- net/core/sock.c | 18 ++++++++++++++ net/sched/cls_cgroup.c | 50 ++++++++++++++++++++++++++------------ net/socket.c | 9 +++++++ 5 files changed, 133 insertions(+), 17 deletions(-) create mode 100644 include/net/cls_cgroup.h diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h new file mode 100644 index 000000000000..ef2df1475b51 --- /dev/null +++ b/include/net/cls_cgroup.h @@ -0,0 +1,63 @@ +/* + * cls_cgroup.h Control Group Classifier + * + * Authors: Thomas Graf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _NET_CLS_CGROUP_H +#define _NET_CLS_CGROUP_H + +#include +#include +#include + +#ifdef CONFIG_CGROUPS +struct cgroup_cls_state +{ + struct cgroup_subsys_state css; + u32 classid; +}; + +#ifdef CONFIG_NET_CLS_CGROUP +static inline u32 task_cls_classid(struct task_struct *p) +{ + if (in_interrupt()) + return 0; + + return container_of(task_subsys_state(p, net_cls_subsys_id), + struct cgroup_cls_state, css).classid; +} +#else +extern int net_cls_subsys_id; + +static inline u32 task_cls_classid(struct task_struct *p) +{ + int id; + u32 classid; + + if (in_interrupt()) + return 0; + + rcu_read_lock(); + id = rcu_dereference(net_cls_subsys_id); + if (id >= 0) + classid = container_of(task_subsys_state(p, id), + struct cgroup_cls_state, css)->classid; + rcu_read_unlock(); + + return classid; +} +#endif +#else +static inline u32 task_cls_classid(struct task_struct *p) +{ + return 0; +} +#endif +#endif /* _NET_CLS_CGROUP_H */ diff --git a/include/net/sock.h b/include/net/sock.h index 5697caf8cc76..d24f382cb712 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -312,7 +312,7 @@ struct sock { void *sk_security; #endif __u32 sk_mark; - /* XXX 4 bytes hole on 64 bit */ + u32 sk_classid; void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk, int bytes); void (*sk_write_space)(struct sock *sk); @@ -1074,6 +1074,14 @@ extern void *sock_kmalloc(struct sock *sk, int size, extern void sock_kfree_s(struct sock *sk, void *mem, int size); extern void sk_send_sigurg(struct sock *sk); +#ifdef CONFIG_CGROUPS +extern void sock_update_classid(struct sock *sk); +#else +static inline void sock_update_classid(struct sock *sk) +{ +} +#endif + /* * Functions to fill in entries in struct proto_ops when a protocol * does not implement a particular function. diff --git a/net/core/sock.c b/net/core/sock.c index bf88a167c8f2..a05ae7f9771e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -123,6 +123,7 @@ #include #include #include +#include #include @@ -217,6 +218,11 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); EXPORT_SYMBOL(sysctl_optmem_max); +#if defined(CONFIG_CGROUPS) && !defined(CONFIG_NET_CLS_CGROUP) +int net_cls_subsys_id = -1; +EXPORT_SYMBOL_GPL(net_cls_subsys_id); +#endif + static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) { struct timeval tv; @@ -1050,6 +1056,16 @@ static void sk_prot_free(struct proto *prot, struct sock *sk) module_put(owner); } +#ifdef CONFIG_CGROUPS +void sock_update_classid(struct sock *sk) +{ + u32 classid = task_cls_classid(current); + + if (classid && classid != sk->sk_classid) + sk->sk_classid = classid; +} +#endif + /** * sk_alloc - All socket objects are allocated here * @net: the applicable net namespace @@ -1073,6 +1089,8 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, sock_lock_init(sk); sock_net_set(sk, get_net(net)); atomic_set(&sk->sk_wmem_alloc, 1); + + sock_update_classid(sk); } return sk; diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index 221180384fd7..78ef2c5e130b 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -16,14 +16,11 @@ #include #include #include +#include #include #include - -struct cgroup_cls_state -{ - struct cgroup_subsys_state css; - u32 classid; -}; +#include +#include static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, struct cgroup *cgrp); @@ -112,6 +109,10 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, struct cls_cgroup_head *head = tp->root; u32 classid; + rcu_read_lock(); + classid = task_cls_state(current)->classid; + rcu_read_unlock(); + /* * Due to the nature of the classifier it is required to ignore all * packets originating from softirq context as accessing `current' @@ -122,12 +123,12 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, * calls by looking at the number of nested bh disable calls because * softirqs always disables bh. */ - if (softirq_count() != SOFTIRQ_OFFSET) - return -1; - - rcu_read_lock(); - classid = task_cls_state(current)->classid; - rcu_read_unlock(); + if (softirq_count() != SOFTIRQ_OFFSET) { + /* If there is an sk_classid we'll use that. */ + if (!skb->sk) + return -1; + classid = skb->sk->sk_classid; + } if (!classid) return -1; @@ -289,18 +290,35 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { static int __init init_cgroup_cls(void) { - int ret = register_tcf_proto_ops(&cls_cgroup_ops); - if (ret) - return ret; + int ret; + ret = cgroup_load_subsys(&net_cls_subsys); if (ret) - unregister_tcf_proto_ops(&cls_cgroup_ops); + goto out; + +#ifndef CONFIG_NET_CLS_CGROUP + /* We can't use rcu_assign_pointer because this is an int. */ + smp_wmb(); + net_cls_subsys_id = net_cls_subsys.subsys_id; +#endif + + ret = register_tcf_proto_ops(&cls_cgroup_ops); + if (ret) + cgroup_unload_subsys(&net_cls_subsys); + +out: return ret; } static void __exit exit_cgroup_cls(void) { unregister_tcf_proto_ops(&cls_cgroup_ops); + +#ifndef CONFIG_NET_CLS_CGROUP + net_cls_subsys_id = -1; + synchronize_rcu(); +#endif + cgroup_unload_subsys(&net_cls_subsys); } diff --git a/net/socket.c b/net/socket.c index f9f7d0872cac..367d5477d00f 100644 --- a/net/socket.c +++ b/net/socket.c @@ -94,6 +94,7 @@ #include #include +#include #include #include @@ -558,6 +559,8 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct sock_iocb *si = kiocb_to_siocb(iocb); int err; + sock_update_classid(sock->sk); + si->sock = sock; si->scm = NULL; si->msg = msg; @@ -684,6 +687,8 @@ static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, { struct sock_iocb *si = kiocb_to_siocb(iocb); + sock_update_classid(sock->sk); + si->sock = sock; si->scm = NULL; si->msg = msg; @@ -777,6 +782,8 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, if (unlikely(!sock->ops->splice_read)) return -EINVAL; + sock_update_classid(sock->sk); + return sock->ops->splice_read(sock, ppos, pipe, len, flags); } @@ -3069,6 +3076,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, int kernel_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { + sock_update_classid(sock->sk); + if (sock->ops->sendpage) return sock->ops->sendpage(sock, page, offset, size, flags); -- cgit v1.2.3 From 8286274284e15b11b0f531b6ceeef21fbe00a8dd Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 24 May 2010 00:14:10 -0700 Subject: tun: Update classid on packet injection This patch makes tun update its socket classid every time we inject a packet into the network stack. This is so that any updates made by the admin to the process writing packets to tun is effected. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/tun.c | 2 ++ net/core/sock.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 97b25533e5fb..8793c2bf7f15 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -526,6 +526,8 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun, struct sk_buff *skb; int err; + sock_update_classid(sk); + /* Under a page? Don't bother with paged skb. */ if (prepad + len < PAGE_SIZE || !linear) linear = len; diff --git a/net/core/sock.c b/net/core/sock.c index a05ae7f9771e..37fe9b6adade 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1064,6 +1064,7 @@ void sock_update_classid(struct sock *sk) if (classid && classid != sk->sk_classid) sk->sk_classid = classid; } +EXPORT_SYMBOL(sock_update_classid); #endif /** -- cgit v1.2.3 From 5eb32bd059379530fc3809a7fcf183feca75f601 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 24 May 2010 00:36:13 -0700 Subject: fec: add support for PHY interface platform data The i.MX25 PDK uses RMII to communicate with its PHY. This patch adds the ability to configure RMII, based on platform data. Signed-off-by: Baruch Siach Acked-by: Greg Ungerer Signed-off-by: David S. Miller --- drivers/net/fec.c | 22 ++++++++++++++++++++++ drivers/net/fec.h | 2 ++ include/linux/fec.h | 21 +++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 include/linux/fec.h diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 42d9ac9ba395..326465ffbb23 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -182,6 +183,7 @@ struct fec_enet_private { struct phy_device *phy_dev; int mii_timeout; uint phy_speed; + phy_interface_t phy_interface; int index; int link; int full_duplex; @@ -1191,6 +1193,21 @@ fec_restart(struct net_device *dev, int duplex) /* Set MII speed */ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); +#ifdef FEC_MIIGSK_ENR + if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) { + /* disable the gasket and wait */ + writel(0, fep->hwp + FEC_MIIGSK_ENR); + while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) + udelay(1); + + /* configure the gasket: RMII, 50 MHz, no loopback, no echo */ + writel(1, fep->hwp + FEC_MIIGSK_CFGR); + + /* re-enable the gasket */ + writel(2, fep->hwp + FEC_MIIGSK_ENR); + } +#endif + /* And last, enable the transmit and receive processing */ writel(2, fep->hwp + FEC_ECNTRL); writel(0, fep->hwp + FEC_R_DES_ACTIVE); @@ -1226,6 +1243,7 @@ static int __devinit fec_probe(struct platform_device *pdev) { struct fec_enet_private *fep; + struct fec_platform_data *pdata; struct net_device *ndev; int i, irq, ret = 0; struct resource *r; @@ -1259,6 +1277,10 @@ fec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); + pdata = pdev->dev.platform_data; + if (pdata) + fep->phy_interface = pdata->phy; + /* This device has up to three irqs on some platforms */ for (i = 0; i < 3; i++) { irq = platform_get_irq(pdev, i); diff --git a/drivers/net/fec.h b/drivers/net/fec.h index cc47f3f057c7..2c48b25668d5 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -43,6 +43,8 @@ #define FEC_R_DES_START 0x180 /* Receive descriptor ring */ #define FEC_X_DES_START 0x184 /* Transmit descriptor ring */ #define FEC_R_BUFF_SIZE 0x188 /* Maximum receive buff size */ +#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */ +#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */ #else diff --git a/include/linux/fec.h b/include/linux/fec.h new file mode 100644 index 000000000000..5d3523d8dd0c --- /dev/null +++ b/include/linux/fec.h @@ -0,0 +1,21 @@ +/* include/linux/fec.h + * + * Copyright (c) 2009 Orex Computed Radiography + * Baruch Siach + * + * Header file for the FEC platform data + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_FEC_H__ +#define __LINUX_FEC_H__ + +#include + +struct fec_platform_data { + phy_interface_t phy; +}; + +#endif -- cgit v1.2.3 From b5eae9ff5ba6d76de19286dd6429acd7cde3f79d Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Wed, 19 May 2010 10:18:16 +0900 Subject: ath5k: consistently use rx_bufsize for RX DMA We should use the same buffer size we set up for DMA also in the hardware descriptor. Previously we used common->rx_bufsize for setting up the DMA mapping, but used skb_tailroom(skb) for the size we tell to the hardware in the descriptor itself. The problem is that skb_tailroom(skb) can give us a larger value than the size we set up for DMA before. This allows the hardware to write into memory locations not set up for DMA. In practice this should rarely happen because all packets should be smaller than the maximum 802.11 packet size. On the tested platform rx_bufsize is 2528, and we allocated an skb of 2559 bytes length (including padding for cache alignment) but sbk_tailroom() was 2592. Just consistently use rx_bufsize for all RX DMA memory sizes. Also use the return value of the descriptor setup function. Cc: stable@kernel.org Signed-off-by: Bruno Randolf Reviewed-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 5f04cf38a5bc..cc6d41dec332 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1214,6 +1214,7 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) struct ath5k_hw *ah = sc->ah; struct sk_buff *skb = bf->skb; struct ath5k_desc *ds; + int ret; if (!skb) { skb = ath5k_rx_skb_alloc(sc, &bf->skbaddr); @@ -1240,9 +1241,9 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ds = bf->desc; ds->ds_link = bf->daddr; /* link to self */ ds->ds_data = bf->skbaddr; - ah->ah_setup_rx_desc(ah, ds, - skb_tailroom(skb), /* buffer size */ - 0); + ret = ah->ah_setup_rx_desc(ah, ds, ah->common.rx_bufsize, 0); + if (ret) + return ret; if (sc->rxlink != NULL) *sc->rxlink = bf->daddr; -- cgit v1.2.3 From 52a9bd2a8fac5193435bb575313c89656709aea8 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 19 May 2010 08:47:59 +0200 Subject: rt2x00: don't use to_pci_dev in rt2x00pci_uninitialize Don't use to_pci_dev in rt2x00pci_uninitialize to get the allocated irq as it won't work for platform devices (SoC). Instead, use the irq field that's already used everywhere else. Signed-off-by: Helmut Schaa Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index a016f7ccde29..f71eee67f977 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -206,7 +206,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev) /* * Free irq line. */ - free_irq(to_pci_dev(rt2x00dev->dev)->irq, rt2x00dev); + free_irq(rt2x00dev->irq, rt2x00dev); /* * Free DMA -- cgit v1.2.3 From 617f3d0d71e2eae4d8d475cefe9363b140e52083 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 30 Mar 2010 02:52:38 +0900 Subject: wireless: update gfp/slab.h includes Implicit slab.h inclusion via percpu.h is about to go away. Make sure gfp.h or slab.h is included as necessary. Signed-off-by: Tejun Heo Cc: Stephen Rothwell Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc.h | 1 + drivers/net/wireless/iwlwifi/iwl-agn-ict.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index ad556aa8da39..c251603ab032 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "common.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index a273e373b7b0..c92b2c0cbd91 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "iwl-dev.h" -- cgit v1.2.3 From 3dc3fc52ea1537f5f37ab301d2b1468a0e79988f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 24 May 2010 13:36:37 -0400 Subject: Revert "ath9k: Group Key fix for VAPs" This reverts commit 03ceedea972a82d343fa5c2528b3952fa9e615d5. This patch was reported to cause a regression in which connectivity is lost and cannot be reestablished after a suspend/resume cycle. Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 28 +++------------------------- include/net/mac80211.h | 1 - net/mac80211/key.c | 1 - 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 893b552981a0..abfa0493236f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -752,7 +752,6 @@ static int ath_key_config(struct ath_common *common, struct ath_hw *ah = common->ah; struct ath9k_keyval hk; const u8 *mac = NULL; - u8 gmac[ETH_ALEN]; int ret = 0; int idx; @@ -776,30 +775,9 @@ static int ath_key_config(struct ath_common *common, memcpy(hk.kv_val, key->key, key->keylen); if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { - - if (key->ap_addr) { - /* - * Group keys on hardware that supports multicast frame - * key search use a mac that is the sender's address with - * the high bit set instead of the app-specified address. - */ - memcpy(gmac, key->ap_addr, ETH_ALEN); - gmac[0] |= 0x80; - mac = gmac; - - if (key->alg == ALG_TKIP) - idx = ath_reserve_key_cache_slot_tkip(common); - else - idx = ath_reserve_key_cache_slot(common); - if (idx < 0) - mac = NULL; /* no free key cache entries */ - } - - if (!mac) { - /* For now, use the default keys for broadcast keys. This may - * need to change with virtual interfaces. */ - idx = key->keyidx; - } + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; } else if (key->keyidx) { if (WARN_ON(!sta)) return -EOPNOTSUPP; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5be900d19660..e24b0363e6cb 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -831,7 +831,6 @@ struct ieee80211_key_conf { u8 iv_len; u8 hw_key_idx; u8 flags; - u8 *ap_addr; s8 keyidx; u8 keylen; u8 key[0]; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 8d4b41787dcf..e8f6e3b252d8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -140,7 +140,6 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) struct ieee80211_sub_if_data, u.ap); - key->conf.ap_addr = sdata->dev->dev_addr; ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf); if (!ret) { -- cgit v1.2.3 From 9655a6ec19ca656af246fb80817aa337892aefbf Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Thu, 13 May 2010 21:16:03 +0200 Subject: rt2x00: Fix failed SLEEP->AWAKE and AWAKE->SLEEP transitions. (Based on a patch created by Ondrej Zary) In some circumstances the Ralink devices do not properly go to sleep or wake up, with timeouts occurring. Fix this by retrying telling the device that it has to wake up or sleep. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 9 +++++---- drivers/net/wireless/rt2x00/rt2500pci.c | 9 +++++---- drivers/net/wireless/rt2x00/rt61pci.c | 7 ++++--- drivers/net/wireless/rt2x00/rt73usb.c | 7 ++++--- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4ba7b038928f..ad2c98af7e9d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -926,7 +926,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev) static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - u32 reg; + u32 reg, reg2; unsigned int i; char put_to_sleep; char bbp_state; @@ -947,11 +947,12 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); - bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); - rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®2); + bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); + rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); if (bbp_state == state && rf_state == state) return 0; + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); msleep(10); } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 89d132d4af12..41da3d218c65 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1084,7 +1084,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev) static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - u32 reg; + u32 reg, reg2; unsigned int i; char put_to_sleep; char bbp_state; @@ -1105,11 +1105,12 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev, * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®); - bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE); - rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE); + rt2x00pci_register_read(rt2x00dev, PWRCSR1, ®2); + bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE); + rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE); if (bbp_state == state && rf_state == state) return 0; + rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg); msleep(10); } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2e3076f67535..6a74baf4e934 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1689,7 +1689,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev) static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - u32 reg; + u32 reg, reg2; unsigned int i; char put_to_sleep; @@ -1706,10 +1706,11 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®); - state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + rt2x00pci_register_read(rt2x00dev, MAC_CSR12, ®2); + state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; + rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg); msleep(10); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index e35bd19c3c5a..6e0d82efe924 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1366,7 +1366,7 @@ static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - u32 reg; + u32 reg, reg2; unsigned int i; char put_to_sleep; @@ -1383,10 +1383,11 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); - state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®2); + state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; + rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); msleep(10); } -- cgit v1.2.3 From 663cb47cc2c5acd32850f67d051e47d62ed199c9 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Thu, 13 May 2010 21:16:04 +0200 Subject: rt2x00: Fix rt2800usb TX descriptor writing. The recent changes to skb handling introduced a bug in the rt2800usb TX descriptor writing whereby the length of the USB packet wasn't calculated correctly. Found via code inspection, as the devices themselves didn't seem to mind. Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0f8b84b7224c..699161327d65 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -413,7 +413,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ rt2x00_desc_read(txi, 0, &word); rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, - skb->len + TXWI_DESC_SIZE); + skb->len - TXINFO_DESC_SIZE); rt2x00_set_field32(&word, TXINFO_W0_WIV, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); -- cgit v1.2.3 From 690e781c5a3241d2366a3120ca410162da9c365e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 May 2010 16:50:56 +0200 Subject: ath9k_htc: dereferencing before check in hif_usb_tx_cb() After c11d8f89d3b7: "ath9k_htc: Simplify TX URB management" we no longer assume that tx_buf is a non-null pointer. Signed-off-by: Dan Carpenter Acked-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 46dc41a16faa..ac82911ee609 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -107,12 +107,14 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, static void hif_usb_tx_cb(struct urb *urb) { struct tx_buf *tx_buf = (struct tx_buf *) urb->context; - struct hif_device_usb *hif_dev = tx_buf->hif_dev; + struct hif_device_usb *hif_dev; struct sk_buff *skb; - if (!hif_dev || !tx_buf) + if (!tx_buf || !tx_buf->hif_dev) return; + hif_dev = tx_buf->hif_dev; + switch (urb->status) { case 0: break; -- cgit v1.2.3 From 7606688afc767c0b94bb2d79512affe3ba1264ce Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 May 2010 16:52:37 +0200 Subject: ath9k_htc: rare leak in ath9k_hif_usb_alloc_tx_urbs() This is obviously a small picky thing. The original error handling code doesn't free the most recent allocations which haven't been added to the hif_dev->tx.tx_buf list yet. Signed-off-by: Dan Carpenter Acked-by: Sujith Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index ac82911ee609..77b359162d6c 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -609,6 +609,10 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) return 0; err: + if (tx_buf) { + kfree(tx_buf->buf); + kfree(tx_buf); + } ath9k_hif_usb_dealloc_tx_urbs(hif_dev); return -ENOMEM; } -- cgit v1.2.3 From 96900c751dd16fc9455e7184cbe8758ac7aa7e79 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 May 2010 16:53:46 +0200 Subject: iwlwifi: testing the wrong variable in iwl_add_bssid_station() The intent here is to test that "sta_id_r" is a valid pointer. We do this same test later on in the function. Btw iwl_add_bssid_station() is called from two places and "sta_id_r" is a valid pointer from both callers. Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 85ed235ac901..83a26361a9b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -431,7 +431,7 @@ int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs, struct iwl_link_quality_cmd *link_cmd; unsigned long flags; - if (*sta_id_r) + if (sta_id_r) *sta_id_r = IWL_INVALID_STATION; ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id); -- cgit v1.2.3 From 4e8998f09bd777f99ea3dae6f87f2c367979e6c0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 21 May 2010 11:28:33 -0700 Subject: wireless: fix mac80211.h kernel-doc warnings Fix kernel-doc warnings in mac80211.h: Warning(include/net/mac80211.h:838): No description found for parameter 'ap_addr' Warning(include/net/mac80211.h:1726): No description found for parameter 'get_survey' Signed-off-by: Randy Dunlap Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e24b0363e6cb..de22cbfef232 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -815,6 +815,7 @@ enum ieee80211_key_flags { * encrypted in hardware. * @alg: The key algorithm. * @flags: key flags, see &enum ieee80211_key_flags. + * @ap_addr: AP's MAC address * @keyidx: the key index (0-3) * @keylen: key material length * @key: key material. For ALG_TKIP the key is encoded as a 256-bit (32 byte) @@ -1637,6 +1638,8 @@ enum ieee80211_ampdu_mlme_action { * Returns a negative error code on failure. * The callback must be atomic. * + * @get_survey: Return per-channel survey information + * * @rfkill_poll: Poll rfkill hardware state. If you need this, you also * need to set wiphy->rfkill_poll to %true before registration, * and need to call wiphy_rfkill_set_hw_state() in the callback. -- cgit v1.2.3 From a0c9101c05389e69a5382967667ca686a8d8fbd3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 21 May 2010 11:28:41 -0700 Subject: wireless: fix sta_info.h kernel-doc warnings Fix sta_info.h kernel-doc warnings: Warning(net/mac80211/sta_info.h:164): No description found for parameter 'tid_active_rx[STA_TID_NUM]' Warning(net/mac80211/sta_info.h:164): Excess struct/union/enum/typedef member 'tid_state_rx' description in 'sta_ampdu_mlme' Signed-off-by: Randy Dunlap Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 48a5e80957f0..df9d45544ca5 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -145,7 +145,7 @@ enum plink_state { /** * struct sta_ampdu_mlme - STA aggregation information. * - * @tid_state_rx: TID's state in Rx session state machine. + * @tid_active_rx: TID's state in Rx session state machine. * @tid_rx: aggregation info for Rx per TID * @tid_state_tx: TID's state in Tx session state machine. * @tid_tx: aggregation info for Tx per TID -- cgit v1.2.3 From ededf1f82ac8f06a0311097a68ccb582d32e70d5 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Sat, 22 May 2010 23:58:13 -0700 Subject: ath9k: Fix rx of mcast/bcast frames in PS mode with auto sleep The functionality to keep the device awake until it is done with the rx of any mcast/bcast frames which are pending on AP should also be added to the hardwares which support auto sleep feature. This patch fixes frequent failures in ARP resolution when it is initiated by the other end. Currently auto sleep is enabled only for ar9003 in ath9k. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index ba139132c85f..ca6065b71b46 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -19,6 +19,12 @@ #define SKB_CB_ATHBUF(__skb) (*((struct ath_buf **)__skb->cb)) +static inline bool ath9k_check_auto_sleep(struct ath_softc *sc) +{ + return sc->ps_enabled && + (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP); +} + static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc, struct ieee80211_hdr *hdr) { @@ -616,8 +622,8 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) hdr = (struct ieee80211_hdr *)skb->data; /* Process Beacon and CAB receive in PS state */ - if ((sc->ps_flags & PS_WAIT_FOR_BEACON) && - ieee80211_is_beacon(hdr->frame_control)) + if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) + && ieee80211_is_beacon(hdr->frame_control)) ath_rx_ps_beacon(sc, skb); else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && (ieee80211_is_data(hdr->frame_control) || @@ -932,9 +938,10 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) sc->rx.rxotherant = 0; } - if (unlikely(sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA))) + if (unlikely(ath9k_check_auto_sleep(sc) || + (sc->ps_flags & (PS_WAIT_FOR_BEACON | + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA)))) ath_rx_ps(sc, skb); ath_rx_send_to_mac80211(hw, sc, skb, rxs); -- cgit v1.2.3 From d9b52dc6fd1fbb2bad645cbc86a60f984c1cb179 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 24 May 2010 18:37:02 -0700 Subject: net/dccp: expansion of error code size Because MIPS's EDQUOT value is 1133(0x46d). It's larger than u8. Signed-off-by: Yoichi Yuasa Signed-off-by: David S. Miller --- net/dccp/input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/dccp/input.c b/net/dccp/input.c index 58f7bc156850..6beb6a7d6fba 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -124,9 +124,9 @@ static int dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) return queued; } -static u8 dccp_reset_code_convert(const u8 code) +static u16 dccp_reset_code_convert(const u8 code) { - const u8 error_code[] = { + const u16 error_code[] = { [DCCP_RESET_CODE_CLOSED] = 0, /* normal termination */ [DCCP_RESET_CODE_UNSPECIFIED] = 0, /* nothing known */ [DCCP_RESET_CODE_ABORTED] = ECONNRESET, @@ -148,7 +148,7 @@ static u8 dccp_reset_code_convert(const u8 code) static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb) { - u8 err = dccp_reset_code_convert(dccp_hdr_reset(skb)->dccph_reset_code); + u16 err = dccp_reset_code_convert(dccp_hdr_reset(skb)->dccph_reset_code); sk->sk_err = err; -- cgit v1.2.3 From 556ae19110f2de5ace4733e0c19e5fa01fad08b3 Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Mon, 24 May 2010 18:38:25 -0700 Subject: be2net: Bug fix in init code in probe PCI function reset needs to invoked after fw init ioctl is issued. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 058d7f95f5ae..1c79c2009e40 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2487,10 +2487,6 @@ static int __devinit be_probe(struct pci_dev *pdev, status = be_cmd_POST(adapter); if (status) goto ctrl_clean; - - status = be_cmd_reset_function(adapter); - if (status) - goto ctrl_clean; } /* tell fw we're ready to fire cmds */ @@ -2498,6 +2494,12 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto ctrl_clean; + if (be_physfn(adapter)) { + status = be_cmd_reset_function(adapter); + if (status) + goto ctrl_clean; + } + status = be_stats_init(adapter); if (status) goto ctrl_clean; -- cgit v1.2.3 From f16d3d57486cd079b29ae7a6c3b31c90e69c9c44 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 24 May 2010 07:02:25 +0000 Subject: macvlan: do proper cleanup in macvlan_common_newlink() V2 Fixes possible memory leak. Signed-off-by: Jiri Pirko Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 4e238afab4a3..87e8d4cb4057 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -634,11 +634,18 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, err = register_netdevice(dev); if (err < 0) - return err; + goto destroy_port; list_add_tail(&vlan->list, &port->vlans); netif_stacked_transfer_operstate(lowerdev, dev); + return 0; + +destroy_port: + if (list_empty(&port->vlans)) + macvlan_port_destroy(lowerdev); + + return err; } EXPORT_SYMBOL_GPL(macvlan_common_newlink); -- cgit v1.2.3 From 937eada45fa7bd233dfa59bbd8c0b436b02b6491 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 24 May 2010 23:53:37 -0700 Subject: cls_cgroup: Fix build error when built-in There is a typo in cgroup_cls_state when cls_cgroup is built-in. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/cls_cgroup.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h index ef2df1475b51..6cf44866cecd 100644 --- a/include/net/cls_cgroup.h +++ b/include/net/cls_cgroup.h @@ -31,7 +31,7 @@ static inline u32 task_cls_classid(struct task_struct *p) return 0; return container_of(task_subsys_state(p, net_cls_subsys_id), - struct cgroup_cls_state, css).classid; + struct cgroup_cls_state, css)->classid; } #else extern int net_cls_subsys_id; -- cgit v1.2.3 From acfbe96a3035639619a6533e04d88ed4ef9ccb61 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 24 May 2010 23:54:18 -0700 Subject: sock.h: fix kernel-doc warning Fix sock.h kernel-doc warning: Warning(include/net/sock.h:1438): No description found for parameter 'wq' Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- include/net/sock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/sock.h b/include/net/sock.h index d24f382cb712..d2a71b04a5ae 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1412,7 +1412,7 @@ static inline int sk_has_allocations(const struct sock *sk) /** * wq_has_sleeper - check if there are any waiting processes - * @sk: struct socket_wq + * @wq: struct socket_wq * * Returns true if socket_wq has waiting processes * -- cgit v1.2.3 From 774610e4f26cb3d9da14a8b5974324c9e51017bd Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 13 May 2010 20:37:24 +0200 Subject: ath9k: change beacon allocation to prefer the first beacon slot This fixes IBSS beacon transmissions without VEOL enabled Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index c8a4558f79ba..77face76e05f 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -274,17 +274,11 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) avp->av_bslot = 0; for (slot = 0; slot < ATH_BCBUF; slot++) if (sc->beacon.bslot[slot] == NULL) { - /* - * XXX hack, space out slots to better - * deal with misses - */ - if (slot+1 < ATH_BCBUF && - sc->beacon.bslot[slot+1] == NULL) { - avp->av_bslot = slot+1; - break; - } avp->av_bslot = slot; + /* NB: keep looking for a double slot */ + if (slot == 0 || !sc->beacon.bslot[slot-1]) + break; } BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); sc->beacon.bslot[avp->av_bslot] = vif; -- cgit v1.2.3 From a65e4cb402b5f3e120570ba1faca4354d47e8f2f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 13 May 2010 20:37:25 +0200 Subject: ath9k: remove VEOL support for ad-hoc With VEOL, Beacon transmission in ad-hoc does not currently work. I believe for larger ad-hoc networks, VEOL is too unreliable, as it can get beacon transmissions stuck during synchronization. Use SWBA based beacon trasmission similar to AP mode instead. Signed-off-by: Felix Fietkau Acked-by: Benoit Papillault Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 63 ++++++--------------------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 77face76e05f..f43d85a302c4 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -76,22 +76,13 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, ds = bf->bf_desc; flags = ATH9K_TXDESC_NOACK; - if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || - (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) && - (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { - ds->ds_link = bf->bf_daddr; /* self-linked */ - flags |= ATH9K_TXDESC_VEOL; - /* Let hardware handle antenna switching. */ - antenna = 0; - } else { - ds->ds_link = 0; - /* - * Switch antenna every beacon. - * Should only switch every beacon period, not for every SWBA - * XXX assumes two antennae - */ - antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); - } + ds->ds_link = 0; + /* + * Switch antenna every beacon. + * Should only switch every beacon period, not for every SWBA + * XXX assumes two antennae + */ + antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; @@ -215,36 +206,6 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, return bf; } -/* - * Startup beacon transmission for adhoc mode when they are sent entirely - * by the hardware using the self-linked descriptor + veol trick. -*/ -static void ath_beacon_start_adhoc(struct ath_softc *sc, - struct ieee80211_vif *vif) -{ - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ath_buf *bf; - struct ath_vif *avp; - struct sk_buff *skb; - - avp = (void *)vif->drv_priv; - - if (avp->av_bcbuf == NULL) - return; - - bf = avp->av_bcbuf; - skb = bf->bf_mpdu; - - ath_beacon_setup(sc, avp, bf, 0); - - /* NB: caller is known to have already stopped tx dma */ - ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); - ath9k_hw_txstart(ah, sc->beacon.beaconq); - ath_print(common, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", - sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); -} - int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) { struct ath_softc *sc = aphy->sc; @@ -265,7 +226,8 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) list_del(&avp->av_bcbuf->list); if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || - !(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { + sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC || + sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { int slot; /* * Assign the vif to a beacon xmit slot. As @@ -715,8 +677,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, * self-linked tx descriptor and let the hardware deal with things. */ intval |= ATH9K_BEACON_ENA; - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) - ah->imask |= ATH9K_INT_SWBA; + ah->imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); @@ -726,10 +687,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); - - /* FIXME: Handle properly when vif is NULL */ - if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL) - ath_beacon_start_adhoc(sc, vif); } void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) -- cgit v1.2.3 From e513480e28cdfd868755f05c1a654fcfcee58070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Tue, 25 May 2010 16:08:39 -0700 Subject: Phonet: fix potential use-after-free in pep_sock_close() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sk_common_release() might destroy our last reference to the socket. So an extra temporary reference is needed during cleanup. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/pep.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/phonet/pep.c b/net/phonet/pep.c index af4d38bc3b22..7b048a35ca58 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -626,6 +626,7 @@ static void pep_sock_close(struct sock *sk, long timeout) struct pep_sock *pn = pep_sk(sk); int ifindex = 0; + sock_hold(sk); /* keep a reference after sk_common_release() */ sk_common_release(sk); lock_sock(sk); @@ -644,6 +645,7 @@ static void pep_sock_close(struct sock *sk, long timeout) if (ifindex) gprs_detach(sk); + sock_put(sk); } static int pep_wait_connreq(struct sock *sk, int noblock) -- cgit v1.2.3 From dd7496f217462a23a9a8a15b9925866eaad76e22 Mon Sep 17 00:00:00 2001 From: Filip Aben Date: Tue, 25 May 2010 16:09:23 -0700 Subject: hso: add support for new products This patch adds a few new product id's for the hso driver. Signed-off-by: Filip Aben Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9964df199511..0a3c41faea9c 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -475,6 +475,9 @@ static const struct usb_device_id hso_ids[] = { {USB_DEVICE(0x0af0, 0x8302)}, {USB_DEVICE(0x0af0, 0x8304)}, {USB_DEVICE(0x0af0, 0x8400)}, + {USB_DEVICE(0x0af0, 0x8600)}, + {USB_DEVICE(0x0af0, 0x8800)}, + {USB_DEVICE(0x0af0, 0x8900)}, {USB_DEVICE(0x0af0, 0xd035)}, {USB_DEVICE(0x0af0, 0xd055)}, {USB_DEVICE(0x0af0, 0xd155)}, -- cgit v1.2.3 From 563b04671017ea00ba563ebeebdc36bce79b1b60 Mon Sep 17 00:00:00 2001 From: "J. R. Okajima" Date: Tue, 25 May 2010 16:10:14 -0700 Subject: proc_dointvec: write a single value The commit 00b7c3395aec3df43de5bd02a3c5a099ca51169f "sysctl: refactor integer handling proc code" modified the behaviour of writing to /proc. Before the commit, write("1\n") to /proc/sys/kernel/printk succeeded. But now it returns EINVAL. This commit supports writing a single value to a multi-valued entry. Signed-off-by: J. R. Okajima Reviewed-and-tested-by: WANG Cong Signed-off-by: David S. Miller --- kernel/sysctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b12583047757..f948f20f09cb 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2253,6 +2253,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, if (write) { left -= proc_skip_spaces(&kbuf); + if (!left) + break; err = proc_get_long(&kbuf, &left, &lval, &neg, proc_wspace_sep, sizeof(proc_wspace_sep), NULL); @@ -2279,7 +2281,7 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, if (!write && !first && left && !err) err = proc_put_char(&buffer, &left, '\n'); - if (write && !err) + if (write && !err && left) left -= proc_skip_spaces(&kbuf); free: if (write) { -- cgit v1.2.3 From dd131e76e562fa0c6f9dd53130e8d08d39a0b62c Mon Sep 17 00:00:00 2001 From: Sarveshwar Bandi Date: Tue, 25 May 2010 16:16:32 -0700 Subject: be2net: Bug fix to avoid disabling bottom half during firmware upgrade. Certain firmware commands/operations to upgrade firmware could take several seconds to complete. The code presently disables bottom half during these operations which could lead to unpredictable behaviour in certain cases. This patch now does all firmware upgrade operations asynchronously using a completion variable. Signed-off-by: Sarveshwar Bandi Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 2 ++ drivers/net/benet/be_cmds.c | 19 +++++++++++++++++-- drivers/net/benet/be_main.c | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 373c1a563474..b46be490cd2a 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -283,6 +283,8 @@ struct be_adapter { u8 port_type; u8 transceiver; u8 generation; /* BladeEngine ASIC generation */ + u32 flash_status; + struct completion flash_compl; bool sriov_enabled; u32 vf_if_handle[BE_MAX_VF]; diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index e79bf8b9af3b..c911bfb55b19 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -59,6 +59,13 @@ static int be_mcc_compl_process(struct be_adapter *adapter, compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & CQE_STATUS_COMPL_MASK; + + if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) && + (compl->tag1 == CMD_SUBSYSTEM_COMMON)) { + adapter->flash_status = compl_status; + complete(&adapter->flash_compl); + } + if (compl_status == MCC_STATUS_SUCCESS) { if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) { struct be_cmd_resp_get_stats *resp = @@ -1417,6 +1424,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, int status; spin_lock_bh(&adapter->mcc_lock); + adapter->flash_status = 0; wrb = wrb_from_mccq(adapter); if (!wrb) { @@ -1428,6 +1436,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, be_wrb_hdr_prepare(wrb, cmd->size, false, 1, OPCODE_COMMON_WRITE_FLASHROM); + wrb->tag1 = CMD_SUBSYSTEM_COMMON; be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_WRITE_FLASHROM, cmd->size); @@ -1439,10 +1448,16 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, req->params.op_code = cpu_to_le32(flash_opcode); req->params.data_buf_size = cpu_to_le32(buf_size); - status = be_mcc_notify_wait(adapter); + be_mcc_notify(adapter); + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->flash_compl, + msecs_to_jiffies(12000))) + status = -1; + else + status = adapter->flash_status; err: - spin_unlock_bh(&adapter->mcc_lock); return status; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 1c79c2009e40..aa065c71ddd8 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2319,6 +2319,7 @@ static int be_ctrl_init(struct be_adapter *adapter) spin_lock_init(&adapter->mcc_lock); spin_lock_init(&adapter->mcc_cq_lock); + init_completion(&adapter->flash_compl); pci_save_state(adapter->pdev); return 0; -- cgit v1.2.3 From f925b1303e0672effc78547353bd2ddfe11f5b5f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 25 May 2010 16:24:03 -0700 Subject: drivers/net/usb/asix.c: Fix pointer cast. Stephen Rothwell reports the following new warning: drivers/net/usb/asix.c: In function 'asix_rx_fixup': drivers/net/usb/asix.c:325: warning: cast from pointer to integer of different size drivers/net/usb/asix.c:354: warning: cast from pointer to integer of different size The code just cares about the low alignment bits, so use an "unsigned long" cast instead of one to "u32". Signed-off-by: David S. Miller --- drivers/net/usb/asix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 31b73310ec77..1f802e90474c 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -322,7 +322,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) size = (u16) (header & 0x0000ffff); if ((skb->len) - ((size + 1) & 0xfffe) == 0) { - u8 alignment = (u32)skb->data & 0x3; + u8 alignment = (unsigned long)skb->data & 0x3; if (alignment != 0x2) { /* * not 16bit aligned so use the room provided by @@ -351,7 +351,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } ax_skb = skb_clone(skb, GFP_ATOMIC); if (ax_skb) { - u8 alignment = (u32)packet & 0x3; + u8 alignment = (unsigned long)packet & 0x3; ax_skb->len = size; if (alignment != 0x2) { -- cgit v1.2.3