From: Linus Torvalds Date: Tue, 22 Jan 2008 03:42:25 +0000 (-0800) Subject: Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6 X-Git-Tag: v2.6.24~26 X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f290fc3669d659a915e29b6bdb82d454b437cf93;hp=240d3b54e3a8a8d469f0ff6deacf52f4b751f55a;p=pandora-kernel.git Merge git://git./linux/kernel/git/davem/net-2.6 * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: [ICMP]: ICMP_MIB_OUTMSGS increment duplicated [IPV6]: RFC 2011 compatibility broken [IPV6]: ICMP6_MIB_OUTMSGS increment duplicated [NET]: rtnl_link: fix use-after-free [AF_KEY]: Fix skb leak on pfkey_send_migrate() error [ATM] atm/suni.c: Fix section mismatch. [ATM] atm/idt77105.c: Fix section mismatch. [IrDA]: af_irda memory leak fixes [NEIGH]: Revert 'Fix race between neigh_parms_release and neightbl_fill_parms' [NETFILTER]: bridge-netfilter: fix net_device refcnt leaks [IPV6] ROUTE: Make sending algorithm more friendly with RFC 4861. [IPV4] FIB_HASH : Avoid unecessary loop in fn_hash_dump_zone() [NET]: Fix interrupt semaphore corruption in Intel drivers. [IPV4] fib_trie: fix duplicated route issue [IPV4] fib_hash: fix duplicated route issue [IPV6]: Mischecked tw match in __inet6_check_established. rfkill: call rfkill_led_trigger_unregister() on error --- diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index 0bd657f5dd2a..84672dc57f7a 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -357,7 +357,7 @@ static const struct atmphy_ops idt77105_ops = { }; -int __devinit idt77105_init(struct atm_dev *dev) +int idt77105_init(struct atm_dev *dev) { dev->phy = &idt77105_ops; return 0; diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index f04f39c00833..b1d063cc4fbe 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -289,7 +289,7 @@ static const struct atmphy_ops suni_ops = { }; -int __devinit suni_init(struct atm_dev *dev) +int suni_init(struct atm_dev *dev) { unsigned char mri; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 0c9a6f7104d2..76c0fa690cc6 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -632,6 +632,7 @@ e1000_down(struct e1000_adapter *adapter) #ifdef CONFIG_E1000_NAPI napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); #endif e1000_irq_disable(adapter); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 2ab3bfbb8a63..9cc5a6b01bc1 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -2183,6 +2183,7 @@ void e1000e_down(struct e1000_adapter *adapter) msleep(10); napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); e1000_irq_disable(adapter); del_timer_sync(&adapter->watchdog_timer); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index d2fb88d5cda2..4f63839051b0 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -296,6 +296,11 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) { struct net_device *netdev = adapter->netdev; +#ifdef CONFIG_IXGB_NAPI + napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); +#endif + ixgb_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev); @@ -304,9 +309,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog) if(kill_watchdog) del_timer_sync(&adapter->watchdog_timer); -#ifdef CONFIG_IXGB_NAPI - napi_disable(&adapter->napi); -#endif + adapter->link_speed = 0; adapter->link_duplex = 0; netif_carrier_off(netdev); diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index de3f45e4c5ae..a4265bc1cebb 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1409,9 +1409,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter) IXGBE_WRITE_FLUSH(&adapter->hw); msleep(10); + napi_disable(&adapter->napi); + atomic_set(&adapter->irq_sem, 0); + ixgbe_irq_disable(adapter); - napi_disable(&adapter->napi); del_timer_sync(&adapter->watchdog_timer); netif_carrier_off(netdev); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 43af9e9b2652..3f67a29593bc 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -459,19 +459,7 @@ static __init int veth_init(void) static __exit void veth_exit(void) { - struct veth_priv *priv, *next; - - rtnl_lock(); - /* - * cannot trust __rtnl_link_unregister() to unregister all - * devices, as each ->dellink call will remove two devices - * from the list at once. - */ - list_for_each_entry_safe(priv, next, &veth_list, list) - veth_dellink(priv->dev); - - __rtnl_link_unregister(&veth_link_ops); - rtnl_unlock(); + rtnl_link_unregister(&veth_link_ops); } module_init(veth_init); diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 5d8b939eded1..9f78a69d6b8b 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -142,6 +142,23 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) return skb->nf_bridge; } +static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb) +{ + struct nf_bridge_info *nf_bridge = skb->nf_bridge; + + if (atomic_read(&nf_bridge->use) > 1) { + struct nf_bridge_info *tmp = nf_bridge_alloc(skb); + + if (tmp) { + memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info)); + atomic_set(&tmp->use, 1); + nf_bridge_put(nf_bridge); + } + nf_bridge = tmp; + } + return nf_bridge; +} + static inline void nf_bridge_push_encap_header(struct sk_buff *skb) { unsigned int len = nf_bridge_encap_header_len(skb); @@ -637,6 +654,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb, if (!skb->nf_bridge) return NF_ACCEPT; + /* Need exclusive nf_bridge_info since we might have multiple + * different physoutdevs. */ + if (!nf_bridge_unshare(skb)) + return NF_DROP; + parent = bridge_parent(out); if (!parent) return NF_DROP; @@ -718,6 +740,11 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb, if (!skb->nf_bridge) return NF_ACCEPT; + /* Need exclusive nf_bridge_info since we might have multiple + * different physoutdevs. */ + if (!nf_bridge_unshare(skb)) + return NF_DROP; + nf_bridge = skb->nf_bridge; if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT)) return NF_ACCEPT; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index cc8a2f190acf..29b8ee4e35d6 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1316,6 +1316,8 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) *p = parms->next; parms->dead = 1; write_unlock_bh(&tbl->lock); + if (parms->dev) + dev_put(parms->dev); call_rcu(&parms->rcu_head, neigh_rcu_free_parms); return; } @@ -1326,8 +1328,6 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) void neigh_parms_destroy(struct neigh_parms *parms) { - if (parms->dev) - dev_put(parms->dev); kfree(parms); } diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e1ba26fb4bf2..fed95a323b28 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -308,9 +308,12 @@ void __rtnl_link_unregister(struct rtnl_link_ops *ops) struct net *net; for_each_net(net) { +restart: for_each_netdev_safe(net, dev, n) { - if (dev->rtnl_link_ops == ops) + if (dev->rtnl_link_ops == ops) { ops->dellink(dev); + goto restart; + } } } list_del(&ops->list); diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 527a6e0af5b6..0dfee27cfbcd 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -444,6 +444,9 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) struct fib_info *fi_drop; u8 state; + if (fi->fib_treeref > 1) + goto out; + write_lock_bh(&fib_hash_lock); fi_drop = fa->fa_info; fa->fa_info = fi; @@ -718,19 +721,18 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, { int h, s_h; + if (fz->fz_hash == NULL) + return skb->len; s_h = cb->args[3]; - for (h=0; h < fz->fz_divisor; h++) { - if (h < s_h) continue; - if (h > s_h) - memset(&cb->args[4], 0, - sizeof(cb->args) - 4*sizeof(cb->args[0])); - if (fz->fz_hash == NULL || - hlist_empty(&fz->fz_hash[h])) + for (h = s_h; h < fz->fz_divisor; h++) { + if (hlist_empty(&fz->fz_hash[h])) continue; - if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { + if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h]) < 0) { cb->args[3] = h; return -1; } + memset(&cb->args[4], 0, + sizeof(cb->args) - 4*sizeof(cb->args[0])); } cb->args[3] = h; return skb->len; @@ -746,14 +748,13 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin read_lock(&fib_hash_lock); for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { if (m < s_m) continue; - if (m > s_m) - memset(&cb->args[3], 0, - sizeof(cb->args) - 3*sizeof(cb->args[0])); if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { cb->args[2] = m; read_unlock(&fib_hash_lock); return -1; } + memset(&cb->args[3], 0, + sizeof(cb->args) - 3*sizeof(cb->args[0])); } read_unlock(&fib_hash_lock); cb->args[2] = m; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 8d8c2915e064..1010b469d7d3 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1214,6 +1214,9 @@ static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) struct fib_info *fi_drop; u8 state; + if (fi->fib_treeref > 1) + goto out; + err = -ENOBUFS; new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); if (new_fa == NULL) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 233de0634298..82baea026484 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -540,7 +540,6 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param.data.icmph.checksum = 0; icmp_param.skb = skb_in; icmp_param.offset = skb_network_offset(skb_in); - icmp_out_count(icmp_param.data.icmph.type); inet_sk(icmp_socket->sk)->tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 9bb031fa1c2f..f1240688dc58 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -458,8 +458,6 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, } err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr)); - ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); - out_put: if (likely(idev != NULL)) in6_dev_put(idev); diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index adc73adadfae..0765d8bd380f 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -193,7 +193,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, sk2->sk_family == PF_INET6 && ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && - sk2->sk_bound_dev_if == sk->sk_bound_dev_if) { + (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) { if (twsk_unique(sk, sk2, twp)) goto unique; else diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 8631ed7fe8a9..44937616057e 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -88,7 +88,7 @@ static char *icmp6type2name[256] = { [ICMPV6_PKT_TOOBIG] = "PktTooBigs", [ICMPV6_TIME_EXCEED] = "TimeExcds", [ICMPV6_PARAMPROB] = "ParmProblems", - [ICMPV6_ECHO_REQUEST] = "EchoRequest", + [ICMPV6_ECHO_REQUEST] = "Echos", [ICMPV6_ECHO_REPLY] = "EchoReplies", [ICMPV6_MGM_QUERY] = "GroupMembQueries", [ICMPV6_MGM_REPORT] = "GroupMembResponses", @@ -98,7 +98,7 @@ static char *icmp6type2name[256] = { [NDISC_ROUTER_SOLICITATION] = "RouterSolicits", [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements", [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits", - [NDISC_REDIRECT] = "NeighborRedirects", + [NDISC_REDIRECT] = "Redirects", }; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6ecb5e6fae2e..20083e0d3995 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -329,7 +329,7 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) static inline int rt6_check_neigh(struct rt6_info *rt) { struct neighbour *neigh = rt->rt6i_nexthop; - int m = 0; + int m; if (rt->rt6i_flags & RTF_NONEXTHOP || !(rt->rt6i_flags & RTF_GATEWAY)) m = 1; @@ -337,10 +337,15 @@ static inline int rt6_check_neigh(struct rt6_info *rt) read_lock_bh(&neigh->lock); if (neigh->nud_state & NUD_VALID) m = 2; - else if (!(neigh->nud_state & NUD_FAILED)) +#ifdef CONFIG_IPV6_ROUTER_PREF + else if (neigh->nud_state & NUD_FAILED) + m = 0; +#endif + else m = 1; read_unlock_bh(&neigh->lock); - } + } else + m = 0; return m; } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index d5e4dd75200b..07dfa7fdd2a0 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -802,12 +802,18 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } #endif /* CONFIG_IRDA_ULTRA */ + self->ias_obj = irias_new_object(addr->sir_name, jiffies); + if (self->ias_obj == NULL) + return -ENOMEM; + err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); - if (err < 0) + if (err < 0) { + kfree(self->ias_obj->name); + kfree(self->ias_obj); return err; + } /* Register with LM-IAS */ - self->ias_obj = irias_new_object(addr->sir_name, jiffies); irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", self->stsap_sel, IAS_KERNEL_ATTR); irias_insert_object(self->ias_obj); @@ -1825,7 +1831,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, struct irda_ias_set *ias_opt; struct ias_object *ias_obj; struct ias_attrib * ias_attr; /* Attribute in IAS object */ - int opt; + int opt, free_ias = 0; IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); @@ -1881,11 +1887,20 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, /* Create a new object */ ias_obj = irias_new_object(ias_opt->irda_class_name, jiffies); + if (ias_obj == NULL) { + kfree(ias_opt); + return -ENOMEM; + } + free_ias = 1; } /* Do we have the attribute already ? */ if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) { kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } return -EINVAL; } @@ -1904,6 +1919,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, if(ias_opt->attribute.irda_attrib_octet_seq.len > IAS_MAX_OCTET_STRING) { kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } + return -EINVAL; } /* Add an octet sequence attribute */ @@ -1932,6 +1952,10 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, break; default : kfree(ias_opt); + if (free_ias) { + kfree(ias_obj->name); + kfree(ias_obj); + } return -EINVAL; } irias_insert_object(ias_obj); diff --git a/net/key/af_key.c b/net/key/af_key.c index 26d5e63c4cc5..76dcd882f87b 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3593,27 +3593,29 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, /* old ipsecrequest */ int mode = pfkey_mode_from_xfrm(mp->mode); if (mode < 0) - return -EINVAL; + goto err; if (set_ipsecrequest(skb, mp->proto, mode, (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), mp->reqid, mp->old_family, - &mp->old_saddr, &mp->old_daddr) < 0) { - return -EINVAL; - } + &mp->old_saddr, &mp->old_daddr) < 0) + goto err; /* new ipsecrequest */ if (set_ipsecrequest(skb, mp->proto, mode, (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), mp->reqid, mp->new_family, - &mp->new_saddr, &mp->new_daddr) < 0) { - return -EINVAL; - } + &mp->new_saddr, &mp->new_daddr) < 0) + goto err; } /* broadcast migrate message to sockets */ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); return 0; + +err: + kfree_skb(skb); + return -EINVAL; } #else static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 4469a7be006c..d06d338812e9 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -392,11 +392,14 @@ int rfkill_register(struct rfkill *rfkill) rfkill_led_trigger_register(rfkill); error = rfkill_add_switch(rfkill); - if (error) + if (error) { + rfkill_led_trigger_unregister(rfkill); return error; + } error = device_add(dev); if (error) { + rfkill_led_trigger_unregister(rfkill); rfkill_remove_switch(rfkill); return error; }