Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 22 Jan 2008 03:42:25 +0000 (19:42 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 22 Jan 2008 03:42:25 +0000 (19:42 -0800)
* 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

20 files changed:
drivers/atm/idt77105.c
drivers/atm/suni.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/netdev.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/veth.c
net/bridge/br_netfilter.c
net/core/neighbour.c
net/core/rtnetlink.c
net/ipv4/fib_hash.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv6/icmp.c
net/ipv6/inet6_hashtables.c
net/ipv6/proc.c
net/ipv6/route.c
net/irda/af_irda.c
net/key/af_key.c
net/rfkill/rfkill.c

index 0bd657f..84672dc 100644 (file)
@@ -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;
index f04f39c..b1d063c 100644 (file)
@@ -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;
 
index 0c9a6f7..76c0fa6 100644 (file)
@@ -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);
 
index 2ab3bfb..9cc5a6b 100644 (file)
@@ -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);
index d2fb88d..4f63839 100644 (file)
@@ -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);
index de3f45e..a4265bc 100644 (file)
@@ -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);
index 43af9e9..3f67a29 100644 (file)
@@ -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);
index 5d8b939..9f78a69 100644 (file)
@@ -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;
index cc8a2f1..29b8ee4 100644 (file)
@@ -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);
 }
 
index e1ba26f..fed95a3 100644 (file)
@@ -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);
index 527a6e0..0dfee27 100644 (file)
@@ -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;
index 8d8c291..1010b46 100644 (file)
@@ -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)
index 233de06..82baea0 100644 (file)
@@ -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;
index 9bb031f..f124068 100644 (file)
@@ -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);
index adc73ad..0765d8b 100644 (file)
@@ -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
index 8631ed7..4493761 100644 (file)
@@ -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",
 };
 
 
index 6ecb5e6..20083e0 100644 (file)
@@ -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;
 }
 
index d5e4dd7..07dfa7f 100644 (file)
@@ -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);
index 26d5e63..76dcd88 100644 (file)
@@ -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,
index 4469a7b..d06d338 100644 (file)
@@ -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;
        }