From 3cc76caa98b092a8fb3e7b4303c70f847db0651f Mon Sep 17 00:00:00 2001 From: Yang Hongyang Date: Fri, 29 Aug 2008 14:06:51 -0700 Subject: [PATCH 01/17] ipv6: When we droped a packet, we should return NET_RX_DROP instead of 0 Signed-off-by: Yang Hongyang Signed-off-by: David S. Miller --- net/ipv6/raw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 01d47674f7e..e53e493606c 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -377,14 +377,14 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) skb_checksum_complete(skb)) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } /* Charge it to the socket. */ if (sock_queue_rcv_skb(sk,skb)<0) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } return 0; @@ -429,7 +429,7 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) if (skb_checksum_complete(skb)) { atomic_inc(&sk->sk_drops); kfree_skb(skb); - return 0; + return NET_RX_DROP; } } From 102396ae65108b026e4e1868e30fa013f45a169e Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Fri, 29 Aug 2008 14:21:52 -0700 Subject: [PATCH 02/17] pkt_sched: Fix locking of qdisc_root with qdisc_root_sleeping_lock() Use qdisc_root_sleeping_lock() instead of qdisc_root_lock() where appropriate. The only difference is while dev is deactivated, when currently we can use a sleeping qdisc with the lock of noop_qdisc. This shouldn't be dangerous since after deactivation root lock could be used only by gen_estimator code, but looks wrong anyway. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/cls_api.c | 2 +- net/sched/cls_route.c | 2 +- net/sched/sch_api.c | 8 ++++---- net/sched/sch_cbq.c | 2 +- net/sched/sch_htb.c | 4 ++-- net/sched/sch_netem.c | 2 +- net/sched/sch_teql.c | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5cafdd4c801..8eb79e92e94 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -205,7 +205,7 @@ replay: } } - root_lock = qdisc_root_lock(q); + root_lock = qdisc_root_sleeping_lock(q); if (tp == NULL) { /* Proto-tcf does not exist, create new one */ diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 481260a4f10..e3d8455eebc 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -75,7 +75,7 @@ static __inline__ int route4_fastmap_hash(u32 id, int iif) static inline void route4_reset_fastmap(struct Qdisc *q, struct route4_head *head, u32 id) { - spinlock_t *root_lock = qdisc_root_lock(q); + spinlock_t *root_lock = qdisc_root_sleeping_lock(q); spin_lock_bh(root_lock); memset(head->fastmap, 0, sizeof(head->fastmap)); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 506b709510b..1122c952aa9 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1169,8 +1169,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, if (q->stab && qdisc_dump_stab(skb, q->stab) < 0) goto nla_put_failure; - if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, qdisc_root_lock(q), &d) < 0) + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, + qdisc_root_sleeping_lock(q), &d) < 0) goto nla_put_failure; if (q->ops->dump_stats && q->ops->dump_stats(q, &d) < 0) @@ -1461,8 +1461,8 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, if (cl_ops->dump && cl_ops->dump(q, cl, skb, tcm) < 0) goto nla_put_failure; - if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, - TCA_XSTATS, qdisc_root_lock(q), &d) < 0) + if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS, TCA_XSTATS, + qdisc_root_sleeping_lock(q), &d) < 0) goto nla_put_failure; if (cl_ops->dump_stats && cl_ops->dump_stats(q, cl, &d) < 0) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 9b720adedea..8b06fa90048 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1754,7 +1754,7 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg) if (--cl->refcnt == 0) { #ifdef CONFIG_NET_CLS_ACT - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct cbq_sched_data *q = qdisc_priv(sch); spin_lock_bh(root_lock); diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 97d4761cc31..d14f02056ae 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1043,7 +1043,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt) static int htb_dump(struct Qdisc *sch, struct sk_buff *skb) { - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct htb_sched *q = qdisc_priv(sch); struct nlattr *nest; struct tc_htb_glob gopt; @@ -1075,7 +1075,7 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb, struct tcmsg *tcm) { struct htb_class *cl = (struct htb_class *)arg; - spinlock_t *root_lock = qdisc_root_lock(sch); + spinlock_t *root_lock = qdisc_root_sleeping_lock(sch); struct nlattr *nest; struct tc_htb_opt opt; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index fb0294d0b55..3781e55046d 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -341,7 +341,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) for (i = 0; i < n; i++) d->table[i] = data[i]; - root_lock = qdisc_root_lock(sch); + root_lock = qdisc_root_sleeping_lock(sch); spin_lock_bh(root_lock); d = xchg(&q->delay_dist, d); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 2c35c678563..d35ef059abb 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -161,7 +161,7 @@ teql_destroy(struct Qdisc* sch) txq = netdev_get_tx_queue(master->dev, 0); master->slaves = NULL; - root_lock = qdisc_root_lock(txq->qdisc); + root_lock = qdisc_root_sleeping_lock(txq->qdisc); spin_lock_bh(root_lock); qdisc_reset(txq->qdisc); spin_unlock_bh(root_lock); From 7c19a3d280297d43ef5ff7c6b205dc208a16d3d1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Aug 2008 14:37:23 -0700 Subject: [PATCH 03/17] net: Unbreak userspace usage of linux/mroute.h Nothing in linux/pim.h should be exported to userspace. This should fix the XORP build failure reported by Jose Calhariz, the debain package maintainer. Nothing originally in linux/mroute.h was exported to userspace ever, but some of this stuff started to be when it was moved into this new linux/pim.h, and that was wrong. If we didn't provide these definitions for 10 years we can reasonably expect that applications defined this stuff locally or used GLIBC headers providing the protocol definitions. And as such the only result of this can be conflict and userland build breakage. Signed-off-by: David S. Miller --- include/linux/Kbuild | 1 - include/linux/mroute.h | 2 +- include/linux/mroute6.h | 1 + include/linux/pim.h | 18 ------------------ 4 files changed, 2 insertions(+), 20 deletions(-) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 7d970678f94..59391250d51 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -297,7 +297,6 @@ unifdef-y += parport.h unifdef-y += patchkey.h unifdef-y += pci.h unifdef-y += personality.h -unifdef-y += pim.h unifdef-y += pktcdvd.h unifdef-y += pmu.h unifdef-y += poll.h diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 07112ee9293..8a455694d68 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -6,7 +6,6 @@ #ifdef __KERNEL__ #include #endif -#include /* * Based on the MROUTING 3.5 defines primarily to keep @@ -130,6 +129,7 @@ struct igmpmsg */ #ifdef __KERNEL__ +#include #include #ifdef CONFIG_IP_MROUTE diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index 5cf50473a10..6f4c180179e 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -115,6 +115,7 @@ struct sioc_mif_req6 #ifdef __KERNEL__ +#include #include /* for struct sk_buff_head */ #ifdef CONFIG_IPV6_MROUTE diff --git a/include/linux/pim.h b/include/linux/pim.h index 236ffd31739..1ba0661561a 100644 --- a/include/linux/pim.h +++ b/include/linux/pim.h @@ -3,22 +3,6 @@ #include -#ifndef __KERNEL__ -struct pim { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 pim_type:4, /* PIM message type */ - pim_ver:4; /* PIM version */ -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 pim_ver:4; /* PIM version */ - pim_type:4; /* PIM message type */ -#endif - __u8 pim_rsv; /* Reserved */ - __be16 pim_cksum; /* Checksum */ -}; - -#define PIM_MINLEN 8 -#endif - /* Message types - V1 */ #define PIM_V1_VERSION __constant_htonl(0x10000000) #define PIM_V1_REGISTER 1 @@ -27,7 +11,6 @@ struct pim { #define PIM_VERSION 2 #define PIM_REGISTER 1 -#if defined(__KERNEL__) #define PIM_NULL_REGISTER __constant_htonl(0x40000000) /* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ @@ -42,4 +25,3 @@ struct pimreghdr struct sk_buff; extern int pim_rcv_v1(struct sk_buff *); #endif -#endif From d9664741e0e2216770d6e52646474d3982b8eb55 Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Tue, 2 Sep 2008 15:26:34 +0200 Subject: [PATCH 04/17] net/wireless/Kconfig: clarify the description for CONFIG_WIRELESS_EXT_SYSFS Current setup with hal and NetworkManager will fail to work without newest hal version with this config option disabled. Although this will solve itself by time, at the moment it is dishonest to say that we don't know any software that uses it, if there are many many people relying on old hal versions. Signed-off-by: Florian Mickler Signed-off-by: John W. Linville --- net/wireless/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index ab015c62d56..833b024f8f6 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -39,4 +39,5 @@ config WIRELESS_EXT_SYSFS files in /sys/class/net/*/wireless/. The same information is available via the ioctls as well. - Say Y if you have programs using it (we don't know of any). + Say Y if you have programs using it, like old versions of + hal. From 49898852e6aa8a6de9a5bc0bab2cf305b3583bbf Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 2 Sep 2008 15:07:18 -0400 Subject: [PATCH 05/17] iwlwifi: do not use GFP_DMA in iwl_tx_queue_init GFP_DMA is not necessary for the iwlwifi hardware and it can cause allocation failures and/or invoke the OOM killer on lots of systems. For reference: https://bugzilla.redhat.com/show_bug.cgi?id=459709 Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index d82823b5c8a..ff879d46624 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -426,7 +426,7 @@ static int iwl_tx_queue_init(struct iwl_priv *priv, continue; } - txq->cmd[i] = kmalloc(len, GFP_KERNEL | GFP_DMA); + txq->cmd[i] = kmalloc(len, GFP_KERNEL); if (!txq->cmd[i]) return -ENOMEM; } From cf88c433bf64b6f7395a39f840bec88a8c58b58b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 28 Aug 2008 17:25:04 +0800 Subject: [PATCH 06/17] iwlwifi: workaround interrupt handling no some platforms This patch adds workaround for an interrupt related hardware bug on some platforms. (Apparently these platforms boot-up w/ INTX_DISABLED set. -- JWL) Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 061ffba9c88..c0b73c4d6f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2602,6 +2602,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; + u16 pci_cmd; IWL_DEBUG_MAC80211("enter\n"); @@ -2612,6 +2613,13 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) pci_restore_state(priv->pci_dev); pci_enable_msi(priv->pci_dev); + /* enable interrupts if needed: hw bug w/a */ + pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); + } + ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, DRV_NAME, priv); if (ret) { From 1d3e6c61342292140dfe1b921991ee793ec1e0ae Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Thu, 28 Aug 2008 17:25:05 +0800 Subject: [PATCH 07/17] iwlwifi: fix apm_stop (wrong bit polarity for FLAG_INIT_DONE) The patch fixes CSR_GP_CNTRL_REG_FLAG_INIT_DONE was set instead of cleared which disabled moving device to D0U state. Signed-off-by: Mohamed Abbas Signed-off-by: Tomas Winkler Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-5000.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index e2581229d8b..23fed329896 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -474,8 +474,8 @@ static void iwl4965_apm_stop(struct iwl_priv *priv) iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); - - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + /* clear "init complete" move adapter D0A* --> D0U state */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index cbc01a00eaf..d95fb42b2bd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -145,7 +145,8 @@ static void iwl5000_apm_stop(struct iwl_priv *priv) udelay(10); - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + /* clear "init complete" move adapter D0A* --> D0U state */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); spin_unlock_irqrestore(&priv->lock, flags); } From f0b9f5cb4adcec9424142592ca7bf024fe6c91a9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 28 Aug 2008 17:25:10 +0800 Subject: [PATCH 08/17] iwlwifi: fix 64bit platform firmware loading This patch fixes loading firmware from memory above 32bit. Signed-off-by: Tomas Winkler Signed-off-by: Emmanuel Grumbach Signed-off-by: Zhu Yi Acked-by: Marcel Holtmann Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 11 ++++------- drivers/net/wireless/iwlwifi/iwl-fh.h | 1 + 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index d95fb42b2bd..b08036a9d89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -578,14 +578,11 @@ static int iwl5000_load_section(struct iwl_priv *priv, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - /* FIME: write the MSB of the phy_addr in CTRL1 - * iwl_write_direct32(priv, - IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL), - ((phy_addr & MSB_MSK) - << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count); - */ iwl_write_direct32(priv, - FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt); + FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), + (iwl_get_dma_hi_address(phy_addr) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 944642450d3..cd11c0ca299 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -287,6 +287,7 @@ #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) +#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 /** * Transmit DMA Channel Control/Status Registers (TCSR) From 667d41008eb8a0e1d495d6c0a6143b43fe587c98 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sat, 23 Aug 2008 19:03:34 +0100 Subject: [PATCH 09/17] orinoco: Multicast to the specified addresses When multicasting the driver sets the number of group addresses using the count from the previous set multicast command. In general this means you have to set the multicast addresses twice to get the behaviour you want. If we were multicasting, and reduce the number of addresses we are multicasting to, then the driver would write uninitialised data from the stack into the group addresses to multicast to. Only write the multicast addresses we have specifically set. Signed-off-by: David Kilroy Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 1ebcafe7ca5..36c004e1560 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1970,6 +1970,9 @@ __orinoco_set_multicast_list(struct net_device *dev) priv->promiscuous = promisc; } + /* If we're not in promiscuous mode, then we need to set the + * group address if either we want to multicast, or if we were + * multicasting and want to stop */ if (! promisc && (mc_count || priv->mc_count) ) { struct dev_mc_list *p = dev->mc_list; struct hermes_multicast mclist; @@ -1989,9 +1992,10 @@ __orinoco_set_multicast_list(struct net_device *dev) printk(KERN_WARNING "%s: Multicast list is " "longer than mc_count\n", dev->name); - err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, - HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), - &mclist); + err = hermes_write_ltv(hw, USER_BAP, + HERMES_RID_CNFGROUPADDRESSES, + HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN), + &mclist); if (err) printk(KERN_ERR "%s: Error %d setting multicast list.\n", dev->name, err); From 9a52028e534b0567913a4144060e774891c00a37 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 28 Aug 2008 01:05:08 +0300 Subject: [PATCH 10/17] wireless/libertas/if_cs.c: fix memory leaks The leak in if_cs_prog_helper() is obvious. It looks a bit as if not freeing "fw" in if_cs_prog_real() was done intentionally, but I'm not seeing why it shouldn't be freed. Reported-by: Adrian Bunk Signed-off-by: Adrian Bunk Acked-by: Holger Schurig Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_cs.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 04d7a251e3f..8941919001b 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -595,7 +595,7 @@ static int if_cs_prog_helper(struct if_cs_card *card) if (ret < 0) { lbs_pr_err("can't download helper at 0x%x, ret %d\n", sent, ret); - goto done; + goto err_release; } if (count == 0) @@ -604,9 +604,8 @@ static int if_cs_prog_helper(struct if_cs_card *card) sent += count; } +err_release: release_firmware(fw); - ret = 0; - done: lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret); return ret; @@ -676,14 +675,8 @@ static int if_cs_prog_real(struct if_cs_card *card) } ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a); - if (ret < 0) { + if (ret < 0) lbs_pr_err("firmware download failed\n"); - goto err_release; - } - - ret = 0; - goto done; - err_release: release_firmware(fw); From 2b58b209399844995ad48e421267e359e16c03db Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 28 Aug 2008 15:12:06 +0300 Subject: [PATCH 11/17] mac80211: Fix debugfs union misuse and pointer corruption debugfs union in struct ieee80211_sub_if_data is misused by including a common default_key dentry as a union member. This ends occupying the same memory area with the first dentry in other union members (structures; usually drop_unencrypted). Consequently, debugfs operations on default_key symlinks and drop_unencrypted entry are using the same dentry pointer even though they are supposed to be separate ones. This can lead to removing entries incorrectly or potentially leaving something behind since one of the dentry pointers gets lost. Fix this by moving the default_key dentry to a new struct (common_debugfs) that contains dentries (more to be added in future) that are shared by all vif types. The debugfs union must only be used for vif type-specific entries to avoid this type of pointer corruption. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_key.c | 6 +++--- net/mac80211/ieee80211_i.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7439b63df5d..cf82acec913 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -265,7 +265,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) key = sdata->default_key; if (key) { sprintf(buf, "../keys/%d", key->debugfs.cnt); - sdata->debugfs.default_key = + sdata->common_debugfs.default_key = debugfs_create_symlink("default_key", sdata->debugfsdir, buf); } else @@ -277,8 +277,8 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) if (!sdata) return; - debugfs_remove(sdata->debugfs.default_key); - sdata->debugfs.default_key = NULL; + debugfs_remove(sdata->common_debugfs.default_key); + sdata->common_debugfs.default_key = NULL; } void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 586a9b49b0f..4498d871365 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -496,8 +496,10 @@ struct ieee80211_sub_if_data { struct { struct dentry *mode; } monitor; - struct dentry *default_key; } debugfs; + struct { + struct dentry *default_key; + } common_debugfs; #ifdef CONFIG_MAC80211_MESH struct dentry *mesh_stats_dir; From 445df54fec7c1924f44018c4db2a9613b877f10e Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Mon, 1 Sep 2008 14:47:19 +0300 Subject: [PATCH 12/17] rt2x00: Compiler warning unmasked by fix of BUILD_BUG_ON A "Set" to a sign-bit in an "&" operation causes a compiler warning. Make calculations unsigned. [ The warning was masked by the old definition of BUILD_BUG_ON() ] Also remove __builtin_constant_p from FIELD_CHECK since BUILD_BUG_ON no longer permits non-const values. Signed-off-by: Boaz Harrosh CC: Ingo Molnar CC: Rusty Russell Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00reg.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index 7e88ce5651b..2ea7866abd5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -136,7 +136,7 @@ struct rt2x00_field32 { */ #define is_power_of_two(x) ( !((x) & ((x)-1)) ) #define low_bit_mask(x) ( ((x)-1) & ~(x) ) -#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x)) +#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) /* * Macro's to find first set bit in a variable. @@ -173,8 +173,7 @@ struct rt2x00_field32 { * does not exceed the given typelimit. */ #define FIELD_CHECK(__mask, __type) \ - BUILD_BUG_ON(!__builtin_constant_p(__mask) || \ - !(__mask) || \ + BUILD_BUG_ON(!(__mask) || \ !is_valid_mask(__mask) || \ (__mask) != (__type)(__mask)) \ From 1b96175b7e5801a908718d8b5270a4f7d94fed28 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 1 Sep 2008 19:45:21 +0530 Subject: [PATCH 13/17] ath9k: Incorrect key used when group and pairwise ciphers are different. Updating sc_keytype multiple times when groupwise and pairwise ciphers are different results in incorrect pairwise key type assumed for TX control and normal ping fails. This works fine for cases where both groupwise and pairwise ciphers are same. Also use mac80211 provided enums for key length calculation. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/hw.c | 8 ++++---- drivers/net/wireless/ath9k/main.c | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index a17eb130f57..6dbfed0b414 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -7285,15 +7285,15 @@ ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, } break; case ATH9K_CIPHER_WEP: - if (k->kv_len < 40 / NBBY) { + if (k->kv_len < LEN_WEP40) { DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, "%s: WEP key length %u too small\n", __func__, k->kv_len); return false; } - if (k->kv_len <= 40 / NBBY) + if (k->kv_len <= LEN_WEP40) keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= 104 / NBBY) + else if (k->kv_len <= LEN_WEP104) keyType = AR_KEYTABLE_TYPE_104; else keyType = AR_KEYTABLE_TYPE_128; @@ -7313,7 +7313,7 @@ ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; - if (k->kv_len <= 104 / NBBY) + if (k->kv_len <= LEN_WEP104) key4 &= 0xff; if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2888778040e..95b33714948 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -206,7 +206,8 @@ static int ath_key_config(struct ath_softc *sc, if (!ret) return -EIO; - sc->sc_keytype = hk.kv_type; + if (mac) + sc->sc_keytype = hk.kv_type; return 0; } @@ -756,7 +757,8 @@ static int ath9k_set_key(struct ieee80211_hw *hw, key->hw_key_idx = key->keyidx; /* push IV and Michael MIC generation to stack */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + if (key->alg == ALG_TKIP) + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; } break; case DISABLE_KEY: From 773b4e02be28220e9ead80a5fdb180031361439a Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Mon, 1 Sep 2008 19:58:20 +0530 Subject: [PATCH 14/17] ath9: Fix ath_rx_flush_tid() for IRQs disabled kernel warning message. This patch addresses an issue with the locking order. ath_rx_flush_tid() uses spin_lock/unlock_bh when IRQs are disabled in sta_notify by mac80211. As node clean up is still pending with ath9k and this problematic portion of the code is expected to change anyway, thinking of a proper fix may not be worthwhile. So having this interim fix helps the users to get rid of the kernel warning message. Pasted the kernel warning message for reference. kernel: ath0: No ProbeResp from current AP 00:1b:11:60:7a:3d - assume out of range kernel: ------------[ cut here ]------------ kernel: WARNING: at kernel/softirq.c:136 local_bh_enable+0x3c/0xab() kernel: Pid: 1029, comm: ath9k Not tainted 2.6.27-rc4-wt-w1fi-wl kernel: kernel: Call Trace: kernel: [] warn_on_slowpath+0x51/0x77 kernel: [] check_preempt_wakeup+0xf3/0x123 kernel: [] autoremove_wake_function+0x9/0x2e kernel: [] local_bh_enable+0x3c/0xab kernel: [] ath_rx_node_cleanup+0x38/0x6e [ath9k] kernel: [] ath_node_detach+0x3b/0xb6 [ath9k] kernel: [] ath9k_sta_notify+0x12b/0x165 [ath9k] kernel: [] queue_work+0x1d/0x49 kernel: [] add_todo+0x70/0x99 [mac80211] kernel: [] __sta_info_unlink+0x16b/0x19e [mac80211] kernel: [] sta_info_unlink+0x18/0x43 [mac80211] kernel: [] ieee80211_associated+0xaa/0x16d [mac80211] kernel: [] ieee80211_sta_work+0x4fb/0x6b4 [mac80211] kernel: [] thread_return+0x30/0xa9 kernel: [] ieee80211_sta_work+0x0/0x6b4 [mac80211] kernel: [] run_workqueue+0xb1/0x17a kernel: [] worker_thread+0xd0/0xdb kernel: [] autoremove_wake_function+0x0/0x2e kernel: [] worker_thread+0x0/0xdb kernel: [] kthread+0x47/0x75 kernel: [] schedule_tail+0x18/0x50 kernel: [] child_rip+0xa/0x11 kernel: [] kthread+0x0/0x75 kernel: [] child_rip+0x0/0x11 kernel: kernel: ---[ end trace e9bb5da661055827 ]--- Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath9k/recv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 2fe806175c0..20ddb7acdb9 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -360,8 +360,9 @@ static void ath_rx_flush_tid(struct ath_softc *sc, struct ath_arx_tid *rxtid, int drop) { struct ath_rxbuf *rxbuf; + unsigned long flag; - spin_lock_bh(&rxtid->tidlock); + spin_lock_irqsave(&rxtid->tidlock, flag); while (rxtid->baw_head != rxtid->baw_tail) { rxbuf = rxtid->rxbuf + rxtid->baw_head; if (!rxbuf->rx_wbuf) { @@ -382,7 +383,7 @@ static void ath_rx_flush_tid(struct ath_softc *sc, INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); } - spin_unlock_bh(&rxtid->tidlock); + spin_unlock_irqrestore(&rxtid->tidlock, flag); } static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, From 9d7d74029e0f5fde3b88b39892b9b9cfdf4ea10a Mon Sep 17 00:00:00 2001 From: Julien Brunel Date: Tue, 2 Sep 2008 17:24:28 -0700 Subject: [PATCH 15/17] net/xfrm: Use an IS_ERR test rather than a NULL test In case of error, the function xfrm_bundle_create returns an ERR pointer, but never returns a NULL pointer. So a NULL test that comes after an IS_ERR test should be deleted. The semantic match that finds this problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @match_bad_null_test@ expression x, E; statement S1,S2; @@ x = xfrm_bundle_create(...) ... when != x = E * if (x != NULL) S1 else S2 // Signed-off-by: Julien Brunel Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- net/xfrm/xfrm_policy.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 841b32a2e68..46914b79d85 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1731,8 +1731,7 @@ restart: * We can't enlist stable bundles either. */ write_unlock_bh(&policy->lock); - if (dst) - dst_free(dst); + dst_free(dst); if (pol_dead) XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD); @@ -1748,8 +1747,7 @@ restart: err = xfrm_dst_update_origin(dst, fl); if (unlikely(err)) { write_unlock_bh(&policy->lock); - if (dst) - dst_free(dst); + dst_free(dst); XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); goto error; } From 06770843c2f0f929a6e0c758dc433902a01aabfb Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 2 Sep 2008 17:28:58 -0700 Subject: [PATCH 16/17] ipv: Re-enable IP when MTU > 68 Re-enable IP when the MTU gets back to a valid size. This patch just checks if the in_dev is NULL on a NETDEV_CHANGEMTU event and if MTU is valid (bigger than 68), then re-enable in_dev. Also a function that checks valid MTU size was created. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 91d3d96805d..b12dae2b0b2 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1029,6 +1029,11 @@ skip: } } +static inline bool inetdev_valid_mtu(unsigned mtu) +{ + return mtu >= 68; +} + /* Called only under RTNL semaphore */ static int inetdev_event(struct notifier_block *this, unsigned long event, @@ -1048,6 +1053,10 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, IN_DEV_CONF_SET(in_dev, NOXFRM, 1); IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); } + } else if (event == NETDEV_CHANGEMTU) { + /* Re-enabling IP */ + if (inetdev_valid_mtu(dev->mtu)) + in_dev = inetdev_init(dev); } goto out; } @@ -1058,7 +1067,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, dev->ip_ptr = NULL; break; case NETDEV_UP: - if (dev->mtu < 68) + if (!inetdev_valid_mtu(dev->mtu)) break; if (dev->flags & IFF_LOOPBACK) { struct in_ifaddr *ifa; @@ -1080,9 +1089,9 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ip_mc_down(in_dev); break; case NETDEV_CHANGEMTU: - if (dev->mtu >= 68) + if (inetdev_valid_mtu(dev->mtu)) break; - /* MTU falled under 68, disable IP */ + /* disable IP when MTU is not enough */ case NETDEV_UNREGISTER: inetdev_destroy(in_dev); break; From 37b08e34a98c664bea86e3fae718ac45a46b7276 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 2 Sep 2008 20:14:15 -0700 Subject: [PATCH 17/17] ipsec: Fix deadlock in xfrm_state management. Ever since commit 4c563f7669c10a12354b72b518c2287ffc6ebfb3 ("[XFRM]: Speed up xfrm_policy and xfrm_state walking") it is illegal to call __xfrm_state_destroy (and thus xfrm_state_put()) with xfrm_state_lock held. If we do, we'll deadlock since we have the lock already and __xfrm_state_destroy() tries to take it again. Fix this by pushing the xfrm_state_put() calls after the lock is dropped. Signed-off-by: David S. Miller --- net/xfrm/xfrm_state.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 4c6914ef7d9..7bd62f61593 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -780,11 +780,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, { unsigned int h; struct hlist_node *entry; - struct xfrm_state *x, *x0; + struct xfrm_state *x, *x0, *to_put; int acquire_in_progress = 0; int error = 0; struct xfrm_state *best = NULL; + to_put = NULL; + spin_lock_bh(&xfrm_state_lock); h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { @@ -833,7 +835,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, if (tmpl->id.spi && (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, tmpl->id.proto, family)) != NULL) { - xfrm_state_put(x0); + to_put = x0; error = -EEXIST; goto out; } @@ -849,7 +851,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); if (error) { x->km.state = XFRM_STATE_DEAD; - xfrm_state_put(x); + to_put = x; x = NULL; goto out; } @@ -870,7 +872,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, xfrm_hash_grow_check(x->bydst.next != NULL); } else { x->km.state = XFRM_STATE_DEAD; - xfrm_state_put(x); + to_put = x; x = NULL; error = -ESRCH; } @@ -881,6 +883,8 @@ out: else *err = acquire_in_progress ? -EAGAIN : error; spin_unlock_bh(&xfrm_state_lock); + if (to_put) + xfrm_state_put(to_put); return x; } @@ -1067,18 +1071,20 @@ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); int xfrm_state_add(struct xfrm_state *x) { - struct xfrm_state *x1; + struct xfrm_state *x1, *to_put; int family; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); family = x->props.family; + to_put = NULL; + spin_lock_bh(&xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, family); if (x1) { - xfrm_state_put(x1); + to_put = x1; x1 = NULL; err = -EEXIST; goto out; @@ -1088,7 +1094,7 @@ int xfrm_state_add(struct xfrm_state *x) x1 = __xfrm_find_acq_byseq(x->km.seq); if (x1 && ((x1->id.proto != x->id.proto) || xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { - xfrm_state_put(x1); + to_put = x1; x1 = NULL; } } @@ -1110,6 +1116,9 @@ out: xfrm_state_put(x1); } + if (to_put) + xfrm_state_put(to_put); + return err; } EXPORT_SYMBOL(xfrm_state_add); @@ -1269,10 +1278,12 @@ EXPORT_SYMBOL(xfrm_state_migrate); int xfrm_state_update(struct xfrm_state *x) { - struct xfrm_state *x1; + struct xfrm_state *x1, *to_put; int err; int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); + to_put = NULL; + spin_lock_bh(&xfrm_state_lock); x1 = __xfrm_state_locate(x, use_spi, x->props.family); @@ -1281,7 +1292,7 @@ int xfrm_state_update(struct xfrm_state *x) goto out; if (xfrm_state_kern(x1)) { - xfrm_state_put(x1); + to_put = x1; err = -EEXIST; goto out; } @@ -1295,6 +1306,9 @@ int xfrm_state_update(struct xfrm_state *x) out: spin_unlock_bh(&xfrm_state_lock); + if (to_put) + xfrm_state_put(to_put); + if (err) return err;