summaryrefslogtreecommitdiff
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c8
-rw-r--r--net/ipv6/icmp.c13
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/mcast.c10
-rw-r--r--net/ipv6/netfilter/ip6_tables.c34
-rw-r--r--net/ipv6/route.c4
-rw-r--r--net/ipv6/tcp_ipv6.c2
7 files changed, 54 insertions, 19 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8ea1e36bf8e..c7852b38e03 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -578,6 +578,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
ifa->flags = flags | IFA_F_TENTATIVE;
ifa->cstamp = ifa->tstamp = jiffies;
+ ifa->rt = rt;
+
ifa->idev = idev;
in6_dev_hold(idev);
/* For caller */
@@ -603,8 +605,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
}
#endif
- ifa->rt = rt;
-
in6_ifa_hold(ifa);
write_unlock(&idev->lock);
out2:
@@ -1909,11 +1909,11 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
if (!IS_ERR(ifp)) {
- spin_lock(&ifp->lock);
+ spin_lock_bh(&ifp->lock);
ifp->valid_lft = valid_lft;
ifp->prefered_lft = prefered_lft;
ifp->tstamp = jiffies;
- spin_unlock(&ifp->lock);
+ spin_unlock_bh(&ifp->lock);
addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 1044b6fce0d..3d6e9a35115 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -712,6 +712,11 @@ discard_it:
return 0;
}
+/*
+ * Special lock-class for __icmpv6_socket:
+ */
+static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
+
int __init icmpv6_init(struct net_proto_family *ops)
{
struct sock *sk;
@@ -730,6 +735,14 @@ int __init icmpv6_init(struct net_proto_family *ops)
sk = per_cpu(__icmpv6_socket, i)->sk;
sk->sk_allocation = GFP_ATOMIC;
+ /*
+ * Split off their lock-class, because sk->sk_dst_lock
+ * gets used from softirqs, which is safe for
+ * __icmpv6_socket (because those never get directly used
+ * via userspace syscalls), but unsafe for normal sockets.
+ */
+ lockdep_set_class(&sk->sk_dst_lock,
+ &icmpv6_socket_sk_dst_lock_key);
/* Enough space for 2 64K ICMP packets, including
* sk_buff struct overhead.
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 69451af6abe..4fb47a25291 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1095,7 +1095,7 @@ alloc_new_skb:
skb_prev->csum = csum_sub(skb_prev->csum,
skb->csum);
data += fraggap;
- skb_trim(skb_prev, maxfraglen);
+ pskb_trim_unique(skb_prev, maxfraglen);
}
copy = datalen - transhdrlen - fraggap;
if (copy < 0) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 9d697d4dcff..639eb20c9f1 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -268,13 +268,14 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) {
struct inet6_dev *idev = in6_dev_get(dev);
+ (void) ip6_mc_leave_src(sk, mc_lst, idev);
if (idev) {
- (void) ip6_mc_leave_src(sk,mc_lst,idev);
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
in6_dev_put(idev);
}
dev_put(dev);
- }
+ } else
+ (void) ip6_mc_leave_src(sk, mc_lst, NULL);
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return 0;
}
@@ -334,13 +335,14 @@ void ipv6_sock_mc_close(struct sock *sk)
if (dev) {
struct inet6_dev *idev = in6_dev_get(dev);
+ (void) ip6_mc_leave_src(sk, mc_lst, idev);
if (idev) {
- (void) ip6_mc_leave_src(sk, mc_lst, idev);
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
in6_dev_put(idev);
}
dev_put(dev);
- }
+ } else
+ (void) ip6_mc_leave_src(sk, mc_lst, NULL);
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index f26898b0034..c9d6b23cd3f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1398,23 +1398,39 @@ static int __init ip6_tables_init(void)
{
int ret;
- xt_proto_init(AF_INET6);
+ ret = xt_proto_init(AF_INET6);
+ if (ret < 0)
+ goto err1;
/* Noone else will be downing sem now, so we won't sleep */
- xt_register_target(&ip6t_standard_target);
- xt_register_target(&ip6t_error_target);
- xt_register_match(&icmp6_matchstruct);
+ ret = xt_register_target(&ip6t_standard_target);
+ if (ret < 0)
+ goto err2;
+ ret = xt_register_target(&ip6t_error_target);
+ if (ret < 0)
+ goto err3;
+ ret = xt_register_match(&icmp6_matchstruct);
+ if (ret < 0)
+ goto err4;
/* Register setsockopt */
ret = nf_register_sockopt(&ip6t_sockopts);
- if (ret < 0) {
- duprintf("Unable to register sockopts.\n");
- xt_proto_fini(AF_INET6);
- return ret;
- }
+ if (ret < 0)
+ goto err5;
printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
return 0;
+
+err5:
+ xt_unregister_match(&icmp6_matchstruct);
+err4:
+ xt_unregister_target(&ip6t_error_target);
+err3:
+ xt_unregister_target(&ip6t_standard_target);
+err2:
+ xt_proto_fini(AF_INET6);
+err1:
+ return ret;
}
static void __exit ip6_tables_fini(void)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 4b163711f3a..d9baca062d2 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1532,6 +1532,10 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
static int ip6_pkt_discard(struct sk_buff *skb)
{
+ int type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
+ if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED)
+ IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS);
+
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
kfree_skb(skb);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index b843a650be7..802a1a6b103 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -944,7 +944,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
* comment in that function for the gory details. -acme
*/
- sk->sk_gso_type = SKB_GSO_TCPV6;
+ newsk->sk_gso_type = SKB_GSO_TCPV6;
__ip6_dst_store(newsk, dst, NULL);
newtcp6sk = (struct tcp6_sock *)newsk;