diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2010-12-09 12:17:25 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-12-09 12:17:25 -0500 |
commit | d834a9dcecae834cd6b2bc5e50e1907738d9cf6a (patch) | |
tree | 0589d753465d3fe359ba451ba6cb7798df03aaa2 /net/ipv6 | |
parent | a38c5380ef9f088be9f49b6e4c5d80af8b1b5cd4 (diff) | |
parent | f658bcfb2607bf0808966a69cf74135ce98e5c2d (diff) |
Merge branch 'x86/amd-nb' into x86/apic-cleanups
Reason: apic cleanup series depends on x86/apic, x86/amd-nb x86/platform
Conflicts:
arch/x86/include/asm/io_apic.h
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'net/ipv6')
30 files changed, 745 insertions, 451 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 324fac3b6c16..b41ce0f0d514 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -243,7 +243,7 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev) | |||
243 | /* Check if a route is valid prefix route */ | 243 | /* Check if a route is valid prefix route */ |
244 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) | 244 | static inline int addrconf_is_prefix_route(const struct rt6_info *rt) |
245 | { | 245 | { |
246 | return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0); | 246 | return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0; |
247 | } | 247 | } |
248 | 248 | ||
249 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) | 249 | static void addrconf_del_timer(struct inet6_ifaddr *ifp) |
@@ -836,7 +836,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
836 | { | 836 | { |
837 | struct inet6_dev *idev = ifp->idev; | 837 | struct inet6_dev *idev = ifp->idev; |
838 | struct in6_addr addr, *tmpaddr; | 838 | struct in6_addr addr, *tmpaddr; |
839 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp; | 839 | unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp, age; |
840 | unsigned long regen_advance; | 840 | unsigned long regen_advance; |
841 | int tmp_plen; | 841 | int tmp_plen; |
842 | int ret = 0; | 842 | int ret = 0; |
@@ -886,12 +886,13 @@ retry: | |||
886 | goto out; | 886 | goto out; |
887 | } | 887 | } |
888 | memcpy(&addr.s6_addr[8], idev->rndid, 8); | 888 | memcpy(&addr.s6_addr[8], idev->rndid, 8); |
889 | age = (jiffies - ifp->tstamp) / HZ; | ||
889 | tmp_valid_lft = min_t(__u32, | 890 | tmp_valid_lft = min_t(__u32, |
890 | ifp->valid_lft, | 891 | ifp->valid_lft, |
891 | idev->cnf.temp_valid_lft); | 892 | idev->cnf.temp_valid_lft + age); |
892 | tmp_prefered_lft = min_t(__u32, | 893 | tmp_prefered_lft = min_t(__u32, |
893 | ifp->prefered_lft, | 894 | ifp->prefered_lft, |
894 | idev->cnf.temp_prefered_lft - | 895 | idev->cnf.temp_prefered_lft + age - |
895 | idev->cnf.max_desync_factor); | 896 | idev->cnf.max_desync_factor); |
896 | tmp_plen = ifp->prefix_len; | 897 | tmp_plen = ifp->prefix_len; |
897 | max_addresses = idev->cnf.max_addresses; | 898 | max_addresses = idev->cnf.max_addresses; |
@@ -1426,8 +1427,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1426 | { | 1427 | { |
1427 | struct inet6_dev *idev = ifp->idev; | 1428 | struct inet6_dev *idev = ifp->idev; |
1428 | 1429 | ||
1429 | if (addrconf_dad_end(ifp)) | 1430 | if (addrconf_dad_end(ifp)) { |
1431 | in6_ifa_put(ifp); | ||
1430 | return; | 1432 | return; |
1433 | } | ||
1431 | 1434 | ||
1432 | if (net_ratelimit()) | 1435 | if (net_ratelimit()) |
1433 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", | 1436 | printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", |
@@ -1544,7 +1547,7 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) | |||
1544 | return 0; | 1547 | return 0; |
1545 | } | 1548 | } |
1546 | 1549 | ||
1547 | int __ipv6_isatap_ifid(u8 *eui, __be32 addr) | 1550 | static int __ipv6_isatap_ifid(u8 *eui, __be32 addr) |
1548 | { | 1551 | { |
1549 | if (addr == 0) | 1552 | if (addr == 0) |
1550 | return -1; | 1553 | return -1; |
@@ -1560,7 +1563,6 @@ int __ipv6_isatap_ifid(u8 *eui, __be32 addr) | |||
1560 | memcpy(eui + 4, &addr, 4); | 1563 | memcpy(eui + 4, &addr, 4); |
1561 | return 0; | 1564 | return 0; |
1562 | } | 1565 | } |
1563 | EXPORT_SYMBOL(__ipv6_isatap_ifid); | ||
1564 | 1566 | ||
1565 | static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) | 1567 | static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) |
1566 | { | 1568 | { |
@@ -2022,10 +2024,11 @@ ok: | |||
2022 | ipv6_ifa_notify(0, ift); | 2024 | ipv6_ifa_notify(0, ift); |
2023 | } | 2025 | } |
2024 | 2026 | ||
2025 | if (create && in6_dev->cnf.use_tempaddr > 0) { | 2027 | if ((create || list_empty(&in6_dev->tempaddr_list)) && in6_dev->cnf.use_tempaddr > 0) { |
2026 | /* | 2028 | /* |
2027 | * When a new public address is created as described in [ADDRCONF], | 2029 | * When a new public address is created as described in [ADDRCONF], |
2028 | * also create a new temporary address. | 2030 | * also create a new temporary address. Also create a temporary |
2031 | * address if it's enabled but no temporary address currently exists. | ||
2029 | */ | 2032 | */ |
2030 | read_unlock_bh(&in6_dev->lock); | 2033 | read_unlock_bh(&in6_dev->lock); |
2031 | ipv6_create_tempaddr(ifp, NULL); | 2034 | ipv6_create_tempaddr(ifp, NULL); |
@@ -2737,10 +2740,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2737 | /* Flag it for later restoration when link comes up */ | 2740 | /* Flag it for later restoration when link comes up */ |
2738 | ifa->flags |= IFA_F_TENTATIVE; | 2741 | ifa->flags |= IFA_F_TENTATIVE; |
2739 | ifa->state = INET6_IFADDR_STATE_DAD; | 2742 | ifa->state = INET6_IFADDR_STATE_DAD; |
2740 | |||
2741 | write_unlock_bh(&idev->lock); | ||
2742 | |||
2743 | in6_ifa_hold(ifa); | ||
2744 | } else { | 2743 | } else { |
2745 | list_del(&ifa->if_list); | 2744 | list_del(&ifa->if_list); |
2746 | 2745 | ||
@@ -2755,19 +2754,15 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2755 | ifa->state = INET6_IFADDR_STATE_DEAD; | 2754 | ifa->state = INET6_IFADDR_STATE_DEAD; |
2756 | spin_unlock_bh(&ifa->state_lock); | 2755 | spin_unlock_bh(&ifa->state_lock); |
2757 | 2756 | ||
2758 | if (state == INET6_IFADDR_STATE_DEAD) | 2757 | if (state == INET6_IFADDR_STATE_DEAD) { |
2759 | goto put_ifa; | 2758 | in6_ifa_put(ifa); |
2759 | } else { | ||
2760 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | ||
2761 | atomic_notifier_call_chain(&inet6addr_chain, | ||
2762 | NETDEV_DOWN, ifa); | ||
2763 | } | ||
2764 | write_lock_bh(&idev->lock); | ||
2760 | } | 2765 | } |
2761 | |||
2762 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | ||
2763 | if (ifa->state == INET6_IFADDR_STATE_DEAD) | ||
2764 | atomic_notifier_call_chain(&inet6addr_chain, | ||
2765 | NETDEV_DOWN, ifa); | ||
2766 | |||
2767 | put_ifa: | ||
2768 | in6_ifa_put(ifa); | ||
2769 | |||
2770 | write_lock_bh(&idev->lock); | ||
2771 | } | 2766 | } |
2772 | 2767 | ||
2773 | list_splice(&keep_list, &idev->addr_list); | 2768 | list_splice(&keep_list, &idev->addr_list); |
@@ -2964,7 +2959,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
2964 | start sending router solicitations. | 2959 | start sending router solicitations. |
2965 | */ | 2960 | */ |
2966 | 2961 | ||
2967 | if (ifp->idev->cnf.forwarding == 0 && | 2962 | if ((ifp->idev->cnf.forwarding == 0 || |
2963 | ifp->idev->cnf.forwarding == 2) && | ||
2968 | ifp->idev->cnf.rtr_solicits > 0 && | 2964 | ifp->idev->cnf.rtr_solicits > 0 && |
2969 | (dev->flags&IFF_LOOPBACK) == 0 && | 2965 | (dev->flags&IFF_LOOPBACK) == 0 && |
2970 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { | 2966 | (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { |
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 8175f802651b..c8993e5a337c 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -518,10 +518,9 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
518 | 518 | ||
519 | static inline int ip6addrlbl_msgsize(void) | 519 | static inline int ip6addrlbl_msgsize(void) |
520 | { | 520 | { |
521 | return (NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) | 521 | return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) |
522 | + nla_total_size(16) /* IFAL_ADDRESS */ | 522 | + nla_total_size(16) /* IFAL_ADDRESS */ |
523 | + nla_total_size(4) /* IFAL_LABEL */ | 523 | + nla_total_size(4); /* IFAL_LABEL */ |
524 | ); | ||
525 | } | 524 | } |
526 | 525 | ||
527 | static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, | 526 | static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 56b9bf2516f4..54e8e42f7a88 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -343,7 +343,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
343 | */ | 343 | */ |
344 | v4addr = LOOPBACK4_IPV6; | 344 | v4addr = LOOPBACK4_IPV6; |
345 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { | 345 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { |
346 | if (!ipv6_chk_addr(net, &addr->sin6_addr, | 346 | if (!inet->transparent && |
347 | !ipv6_chk_addr(net, &addr->sin6_addr, | ||
347 | dev, 0)) { | 348 | dev, 0)) { |
348 | err = -EADDRNOTAVAIL; | 349 | err = -EADDRNOTAVAIL; |
349 | goto out_unlock; | 350 | goto out_unlock; |
@@ -467,7 +468,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
467 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 468 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
468 | sin->sin6_scope_id = sk->sk_bound_dev_if; | 469 | sin->sin6_scope_id = sk->sk_bound_dev_if; |
469 | *uaddr_len = sizeof(*sin); | 470 | *uaddr_len = sizeof(*sin); |
470 | return(0); | 471 | return 0; |
471 | } | 472 | } |
472 | 473 | ||
473 | EXPORT_SYMBOL(inet6_getname); | 474 | EXPORT_SYMBOL(inet6_getname); |
@@ -488,7 +489,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
488 | case SIOCADDRT: | 489 | case SIOCADDRT: |
489 | case SIOCDELRT: | 490 | case SIOCDELRT: |
490 | 491 | ||
491 | return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); | 492 | return ipv6_route_ioctl(net, cmd, (void __user *)arg); |
492 | 493 | ||
493 | case SIOCSIFADDR: | 494 | case SIOCSIFADDR: |
494 | return addrconf_add_ifaddr(net, (void __user *) arg); | 495 | return addrconf_add_ifaddr(net, (void __user *) arg); |
@@ -502,7 +503,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
502 | return sk->sk_prot->ioctl(sk, cmd, arg); | 503 | return sk->sk_prot->ioctl(sk, cmd, arg); |
503 | } | 504 | } |
504 | /*NOTREACHED*/ | 505 | /*NOTREACHED*/ |
505 | return(0); | 506 | return 0; |
506 | } | 507 | } |
507 | 508 | ||
508 | EXPORT_SYMBOL(inet6_ioctl); | 509 | EXPORT_SYMBOL(inet6_ioctl); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index ef371aa01ac5..320bdb877eed 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -577,6 +577,25 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) | |||
577 | u8 *ptr = nh + opt->dst1; | 577 | u8 *ptr = nh + opt->dst1; |
578 | put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); | 578 | put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); |
579 | } | 579 | } |
580 | if (np->rxopt.bits.rxorigdstaddr) { | ||
581 | struct sockaddr_in6 sin6; | ||
582 | u16 *ports = (u16 *) skb_transport_header(skb); | ||
583 | |||
584 | if (skb_transport_offset(skb) + 4 <= skb->len) { | ||
585 | /* All current transport protocols have the port numbers in the | ||
586 | * first four bytes of the transport header and this function is | ||
587 | * written with this assumption in mind. | ||
588 | */ | ||
589 | |||
590 | sin6.sin6_family = AF_INET6; | ||
591 | ipv6_addr_copy(&sin6.sin6_addr, &ipv6_hdr(skb)->daddr); | ||
592 | sin6.sin6_port = ports[1]; | ||
593 | sin6.sin6_flowinfo = 0; | ||
594 | sin6.sin6_scope_id = 0; | ||
595 | |||
596 | put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6); | ||
597 | } | ||
598 | } | ||
580 | return 0; | 599 | return 0; |
581 | } | 600 | } |
582 | 601 | ||
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c index e1caa5d526c2..14ed0a955b56 100644 --- a/net/ipv6/exthdrs_core.c +++ b/net/ipv6/exthdrs_core.c | |||
@@ -13,12 +13,12 @@ int ipv6_ext_hdr(u8 nexthdr) | |||
13 | /* | 13 | /* |
14 | * find out if nexthdr is an extension header or a protocol | 14 | * find out if nexthdr is an extension header or a protocol |
15 | */ | 15 | */ |
16 | return ( (nexthdr == NEXTHDR_HOP) || | 16 | return (nexthdr == NEXTHDR_HOP) || |
17 | (nexthdr == NEXTHDR_ROUTING) || | 17 | (nexthdr == NEXTHDR_ROUTING) || |
18 | (nexthdr == NEXTHDR_FRAGMENT) || | 18 | (nexthdr == NEXTHDR_FRAGMENT) || |
19 | (nexthdr == NEXTHDR_AUTH) || | 19 | (nexthdr == NEXTHDR_AUTH) || |
20 | (nexthdr == NEXTHDR_NONE) || | 20 | (nexthdr == NEXTHDR_NONE) || |
21 | (nexthdr == NEXTHDR_DEST) ); | 21 | (nexthdr == NEXTHDR_DEST); |
22 | } | 22 | } |
23 | 23 | ||
24 | /* | 24 | /* |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index b1108ede18e1..d829874d8946 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -34,11 +34,10 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | |||
34 | { | 34 | { |
35 | struct fib_lookup_arg arg = { | 35 | struct fib_lookup_arg arg = { |
36 | .lookup_ptr = lookup, | 36 | .lookup_ptr = lookup, |
37 | .flags = FIB_LOOKUP_NOREF, | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg); | 40 | fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg); |
40 | if (arg.rule) | ||
41 | fib_rule_put(arg.rule); | ||
42 | 41 | ||
43 | if (arg.result) | 42 | if (arg.result) |
44 | return arg.result; | 43 | return arg.result; |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b6a585909d35..de382114609b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1500,15 +1500,18 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
1500 | 1500 | ||
1501 | static int __net_init fib6_net_init(struct net *net) | 1501 | static int __net_init fib6_net_init(struct net *net) |
1502 | { | 1502 | { |
1503 | size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ; | ||
1504 | |||
1503 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1505 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
1504 | 1506 | ||
1505 | net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); | 1507 | net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); |
1506 | if (!net->ipv6.rt6_stats) | 1508 | if (!net->ipv6.rt6_stats) |
1507 | goto out_timer; | 1509 | goto out_timer; |
1508 | 1510 | ||
1509 | net->ipv6.fib_table_hash = kcalloc(FIB6_TABLE_HASHSZ, | 1511 | /* Avoid false sharing : Use at least a full cache line */ |
1510 | sizeof(*net->ipv6.fib_table_hash), | 1512 | size = max_t(size_t, size, L1_CACHE_BYTES); |
1511 | GFP_KERNEL); | 1513 | |
1514 | net->ipv6.fib_table_hash = kzalloc(size, GFP_KERNEL); | ||
1512 | if (!net->ipv6.fib_table_hash) | 1515 | if (!net->ipv6.fib_table_hash) |
1513 | goto out_rt6_stats; | 1516 | goto out_rt6_stats; |
1514 | 1517 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 980912ed7a38..99157b4cd56e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -637,7 +637,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
637 | } | 637 | } |
638 | mtu -= hlen + sizeof(struct frag_hdr); | 638 | mtu -= hlen + sizeof(struct frag_hdr); |
639 | 639 | ||
640 | if (skb_has_frags(skb)) { | 640 | if (skb_has_frag_list(skb)) { |
641 | int first_len = skb_pagelen(skb); | 641 | int first_len = skb_pagelen(skb); |
642 | struct sk_buff *frag2; | 642 | struct sk_buff *frag2; |
643 | 643 | ||
@@ -878,8 +878,8 @@ static inline int ip6_rt_check(struct rt6key *rt_key, | |||
878 | struct in6_addr *fl_addr, | 878 | struct in6_addr *fl_addr, |
879 | struct in6_addr *addr_cache) | 879 | struct in6_addr *addr_cache) |
880 | { | 880 | { |
881 | return ((rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && | 881 | return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && |
882 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache))); | 882 | (addr_cache == NULL || !ipv6_addr_equal(fl_addr, addr_cache)); |
883 | } | 883 | } |
884 | 884 | ||
885 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | 885 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 0fd027f3f47e..2a59610c2a58 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -75,7 +75,7 @@ MODULE_LICENSE("GPL"); | |||
75 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ | 75 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ |
76 | (HASH_SIZE - 1)) | 76 | (HASH_SIZE - 1)) |
77 | 77 | ||
78 | static void ip6_tnl_dev_init(struct net_device *dev); | 78 | static int ip6_tnl_dev_init(struct net_device *dev); |
79 | static void ip6_tnl_dev_setup(struct net_device *dev); | 79 | static void ip6_tnl_dev_setup(struct net_device *dev); |
80 | 80 | ||
81 | static int ip6_tnl_net_id __read_mostly; | 81 | static int ip6_tnl_net_id __read_mostly; |
@@ -83,15 +83,42 @@ struct ip6_tnl_net { | |||
83 | /* the IPv6 tunnel fallback device */ | 83 | /* the IPv6 tunnel fallback device */ |
84 | struct net_device *fb_tnl_dev; | 84 | struct net_device *fb_tnl_dev; |
85 | /* lists for storing tunnels in use */ | 85 | /* lists for storing tunnels in use */ |
86 | struct ip6_tnl *tnls_r_l[HASH_SIZE]; | 86 | struct ip6_tnl __rcu *tnls_r_l[HASH_SIZE]; |
87 | struct ip6_tnl *tnls_wc[1]; | 87 | struct ip6_tnl __rcu *tnls_wc[1]; |
88 | struct ip6_tnl **tnls[2]; | 88 | struct ip6_tnl __rcu **tnls[2]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
92 | struct pcpu_tstats { | ||
93 | unsigned long rx_packets; | ||
94 | unsigned long rx_bytes; | ||
95 | unsigned long tx_packets; | ||
96 | unsigned long tx_bytes; | ||
97 | }; | ||
98 | |||
99 | static struct net_device_stats *ip6_get_stats(struct net_device *dev) | ||
100 | { | ||
101 | struct pcpu_tstats sum = { 0 }; | ||
102 | int i; | ||
103 | |||
104 | for_each_possible_cpu(i) { | ||
105 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | ||
106 | |||
107 | sum.rx_packets += tstats->rx_packets; | ||
108 | sum.rx_bytes += tstats->rx_bytes; | ||
109 | sum.tx_packets += tstats->tx_packets; | ||
110 | sum.tx_bytes += tstats->tx_bytes; | ||
111 | } | ||
112 | dev->stats.rx_packets = sum.rx_packets; | ||
113 | dev->stats.rx_bytes = sum.rx_bytes; | ||
114 | dev->stats.tx_packets = sum.tx_packets; | ||
115 | dev->stats.tx_bytes = sum.tx_bytes; | ||
116 | return &dev->stats; | ||
117 | } | ||
118 | |||
91 | /* | 119 | /* |
92 | * Locking : hash tables are protected by RCU and a spinlock | 120 | * Locking : hash tables are protected by RCU and RTNL |
93 | */ | 121 | */ |
94 | static DEFINE_SPINLOCK(ip6_tnl_lock); | ||
95 | 122 | ||
96 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | 123 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) |
97 | { | 124 | { |
@@ -138,8 +165,8 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | |||
138 | static struct ip6_tnl * | 165 | static struct ip6_tnl * |
139 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | 166 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) |
140 | { | 167 | { |
141 | unsigned h0 = HASH(remote); | 168 | unsigned int h0 = HASH(remote); |
142 | unsigned h1 = HASH(local); | 169 | unsigned int h1 = HASH(local); |
143 | struct ip6_tnl *t; | 170 | struct ip6_tnl *t; |
144 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 171 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
145 | 172 | ||
@@ -167,7 +194,7 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | |||
167 | * Return: head of IPv6 tunnel list | 194 | * Return: head of IPv6 tunnel list |
168 | **/ | 195 | **/ |
169 | 196 | ||
170 | static struct ip6_tnl ** | 197 | static struct ip6_tnl __rcu ** |
171 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | 198 | ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) |
172 | { | 199 | { |
173 | struct in6_addr *remote = &p->raddr; | 200 | struct in6_addr *remote = &p->raddr; |
@@ -190,12 +217,10 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) | |||
190 | static void | 217 | static void |
191 | ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | 218 | ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) |
192 | { | 219 | { |
193 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); | 220 | struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms); |
194 | 221 | ||
195 | spin_lock_bh(&ip6_tnl_lock); | 222 | rcu_assign_pointer(t->next , rtnl_dereference(*tp)); |
196 | t->next = *tp; | ||
197 | rcu_assign_pointer(*tp, t); | 223 | rcu_assign_pointer(*tp, t); |
198 | spin_unlock_bh(&ip6_tnl_lock); | ||
199 | } | 224 | } |
200 | 225 | ||
201 | /** | 226 | /** |
@@ -206,18 +231,25 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
206 | static void | 231 | static void |
207 | ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | 232 | ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) |
208 | { | 233 | { |
209 | struct ip6_tnl **tp; | 234 | struct ip6_tnl __rcu **tp; |
210 | 235 | struct ip6_tnl *iter; | |
211 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { | 236 | |
212 | if (t == *tp) { | 237 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); |
213 | spin_lock_bh(&ip6_tnl_lock); | 238 | (iter = rtnl_dereference(*tp)) != NULL; |
214 | *tp = t->next; | 239 | tp = &iter->next) { |
215 | spin_unlock_bh(&ip6_tnl_lock); | 240 | if (t == iter) { |
241 | rcu_assign_pointer(*tp, t->next); | ||
216 | break; | 242 | break; |
217 | } | 243 | } |
218 | } | 244 | } |
219 | } | 245 | } |
220 | 246 | ||
247 | static void ip6_dev_free(struct net_device *dev) | ||
248 | { | ||
249 | free_percpu(dev->tstats); | ||
250 | free_netdev(dev); | ||
251 | } | ||
252 | |||
221 | /** | 253 | /** |
222 | * ip6_tnl_create() - create a new tunnel | 254 | * ip6_tnl_create() - create a new tunnel |
223 | * @p: tunnel parameters | 255 | * @p: tunnel parameters |
@@ -256,7 +288,9 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) | |||
256 | 288 | ||
257 | t = netdev_priv(dev); | 289 | t = netdev_priv(dev); |
258 | t->parms = *p; | 290 | t->parms = *p; |
259 | ip6_tnl_dev_init(dev); | 291 | err = ip6_tnl_dev_init(dev); |
292 | if (err < 0) | ||
293 | goto failed_free; | ||
260 | 294 | ||
261 | if ((err = register_netdevice(dev)) < 0) | 295 | if ((err = register_netdevice(dev)) < 0) |
262 | goto failed_free; | 296 | goto failed_free; |
@@ -266,7 +300,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) | |||
266 | return t; | 300 | return t; |
267 | 301 | ||
268 | failed_free: | 302 | failed_free: |
269 | free_netdev(dev); | 303 | ip6_dev_free(dev); |
270 | failed: | 304 | failed: |
271 | return NULL; | 305 | return NULL; |
272 | } | 306 | } |
@@ -290,10 +324,13 @@ static struct ip6_tnl *ip6_tnl_locate(struct net *net, | |||
290 | { | 324 | { |
291 | struct in6_addr *remote = &p->raddr; | 325 | struct in6_addr *remote = &p->raddr; |
292 | struct in6_addr *local = &p->laddr; | 326 | struct in6_addr *local = &p->laddr; |
327 | struct ip6_tnl __rcu **tp; | ||
293 | struct ip6_tnl *t; | 328 | struct ip6_tnl *t; |
294 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 329 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
295 | 330 | ||
296 | for (t = *ip6_tnl_bucket(ip6n, p); t; t = t->next) { | 331 | for (tp = ip6_tnl_bucket(ip6n, p); |
332 | (t = rtnl_dereference(*tp)) != NULL; | ||
333 | tp = &t->next) { | ||
297 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 334 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
298 | ipv6_addr_equal(remote, &t->parms.raddr)) | 335 | ipv6_addr_equal(remote, &t->parms.raddr)) |
299 | return t; | 336 | return t; |
@@ -318,13 +355,10 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
318 | struct net *net = dev_net(dev); | 355 | struct net *net = dev_net(dev); |
319 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 356 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
320 | 357 | ||
321 | if (dev == ip6n->fb_tnl_dev) { | 358 | if (dev == ip6n->fb_tnl_dev) |
322 | spin_lock_bh(&ip6_tnl_lock); | 359 | rcu_assign_pointer(ip6n->tnls_wc[0], NULL); |
323 | ip6n->tnls_wc[0] = NULL; | 360 | else |
324 | spin_unlock_bh(&ip6_tnl_lock); | ||
325 | } else { | ||
326 | ip6_tnl_unlink(ip6n, t); | 361 | ip6_tnl_unlink(ip6n, t); |
327 | } | ||
328 | ip6_tnl_dst_reset(t); | 362 | ip6_tnl_dst_reset(t); |
329 | dev_put(dev); | 363 | dev_put(dev); |
330 | } | 364 | } |
@@ -702,6 +736,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
702 | 736 | ||
703 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 737 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
704 | &ipv6h->daddr)) != NULL) { | 738 | &ipv6h->daddr)) != NULL) { |
739 | struct pcpu_tstats *tstats; | ||
740 | |||
705 | if (t->parms.proto != ipproto && t->parms.proto != 0) { | 741 | if (t->parms.proto != ipproto && t->parms.proto != 0) { |
706 | rcu_read_unlock(); | 742 | rcu_read_unlock(); |
707 | goto discard; | 743 | goto discard; |
@@ -724,10 +760,16 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
724 | skb->pkt_type = PACKET_HOST; | 760 | skb->pkt_type = PACKET_HOST; |
725 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); | 761 | memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); |
726 | 762 | ||
727 | skb_tunnel_rx(skb, t->dev); | 763 | tstats = this_cpu_ptr(t->dev->tstats); |
764 | tstats->rx_packets++; | ||
765 | tstats->rx_bytes += skb->len; | ||
766 | |||
767 | __skb_tunnel_rx(skb, t->dev); | ||
728 | 768 | ||
729 | dscp_ecn_decapsulate(t, ipv6h, skb); | 769 | dscp_ecn_decapsulate(t, ipv6h, skb); |
770 | |||
730 | netif_rx(skb); | 771 | netif_rx(skb); |
772 | |||
731 | rcu_read_unlock(); | 773 | rcu_read_unlock(); |
732 | return 0; | 774 | return 0; |
733 | } | 775 | } |
@@ -934,8 +976,10 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
934 | err = ip6_local_out(skb); | 976 | err = ip6_local_out(skb); |
935 | 977 | ||
936 | if (net_xmit_eval(err) == 0) { | 978 | if (net_xmit_eval(err) == 0) { |
937 | stats->tx_bytes += pkt_len; | 979 | struct pcpu_tstats *tstats = this_cpu_ptr(t->dev->tstats); |
938 | stats->tx_packets++; | 980 | |
981 | tstats->tx_bytes += pkt_len; | ||
982 | tstats->tx_packets++; | ||
939 | } else { | 983 | } else { |
940 | stats->tx_errors++; | 984 | stats->tx_errors++; |
941 | stats->tx_aborted_errors++; | 985 | stats->tx_aborted_errors++; |
@@ -1240,6 +1284,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1240 | t = netdev_priv(dev); | 1284 | t = netdev_priv(dev); |
1241 | 1285 | ||
1242 | ip6_tnl_unlink(ip6n, t); | 1286 | ip6_tnl_unlink(ip6n, t); |
1287 | synchronize_net(); | ||
1243 | err = ip6_tnl_change(t, &p); | 1288 | err = ip6_tnl_change(t, &p); |
1244 | ip6_tnl_link(ip6n, t); | 1289 | ip6_tnl_link(ip6n, t); |
1245 | netdev_state_change(dev); | 1290 | netdev_state_change(dev); |
@@ -1300,12 +1345,14 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) | |||
1300 | 1345 | ||
1301 | 1346 | ||
1302 | static const struct net_device_ops ip6_tnl_netdev_ops = { | 1347 | static const struct net_device_ops ip6_tnl_netdev_ops = { |
1303 | .ndo_uninit = ip6_tnl_dev_uninit, | 1348 | .ndo_uninit = ip6_tnl_dev_uninit, |
1304 | .ndo_start_xmit = ip6_tnl_xmit, | 1349 | .ndo_start_xmit = ip6_tnl_xmit, |
1305 | .ndo_do_ioctl = ip6_tnl_ioctl, | 1350 | .ndo_do_ioctl = ip6_tnl_ioctl, |
1306 | .ndo_change_mtu = ip6_tnl_change_mtu, | 1351 | .ndo_change_mtu = ip6_tnl_change_mtu, |
1352 | .ndo_get_stats = ip6_get_stats, | ||
1307 | }; | 1353 | }; |
1308 | 1354 | ||
1355 | |||
1309 | /** | 1356 | /** |
1310 | * ip6_tnl_dev_setup - setup virtual tunnel device | 1357 | * ip6_tnl_dev_setup - setup virtual tunnel device |
1311 | * @dev: virtual device associated with tunnel | 1358 | * @dev: virtual device associated with tunnel |
@@ -1317,7 +1364,7 @@ static const struct net_device_ops ip6_tnl_netdev_ops = { | |||
1317 | static void ip6_tnl_dev_setup(struct net_device *dev) | 1364 | static void ip6_tnl_dev_setup(struct net_device *dev) |
1318 | { | 1365 | { |
1319 | dev->netdev_ops = &ip6_tnl_netdev_ops; | 1366 | dev->netdev_ops = &ip6_tnl_netdev_ops; |
1320 | dev->destructor = free_netdev; | 1367 | dev->destructor = ip6_dev_free; |
1321 | 1368 | ||
1322 | dev->type = ARPHRD_TUNNEL6; | 1369 | dev->type = ARPHRD_TUNNEL6; |
1323 | dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); | 1370 | dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); |
@@ -1325,6 +1372,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev) | |||
1325 | dev->flags |= IFF_NOARP; | 1372 | dev->flags |= IFF_NOARP; |
1326 | dev->addr_len = sizeof(struct in6_addr); | 1373 | dev->addr_len = sizeof(struct in6_addr); |
1327 | dev->features |= NETIF_F_NETNS_LOCAL; | 1374 | dev->features |= NETIF_F_NETNS_LOCAL; |
1375 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
1328 | } | 1376 | } |
1329 | 1377 | ||
1330 | 1378 | ||
@@ -1333,12 +1381,17 @@ static void ip6_tnl_dev_setup(struct net_device *dev) | |||
1333 | * @dev: virtual device associated with tunnel | 1381 | * @dev: virtual device associated with tunnel |
1334 | **/ | 1382 | **/ |
1335 | 1383 | ||
1336 | static inline void | 1384 | static inline int |
1337 | ip6_tnl_dev_init_gen(struct net_device *dev) | 1385 | ip6_tnl_dev_init_gen(struct net_device *dev) |
1338 | { | 1386 | { |
1339 | struct ip6_tnl *t = netdev_priv(dev); | 1387 | struct ip6_tnl *t = netdev_priv(dev); |
1388 | |||
1340 | t->dev = dev; | 1389 | t->dev = dev; |
1341 | strcpy(t->parms.name, dev->name); | 1390 | strcpy(t->parms.name, dev->name); |
1391 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1392 | if (!dev->tstats) | ||
1393 | return -ENOMEM; | ||
1394 | return 0; | ||
1342 | } | 1395 | } |
1343 | 1396 | ||
1344 | /** | 1397 | /** |
@@ -1346,11 +1399,15 @@ ip6_tnl_dev_init_gen(struct net_device *dev) | |||
1346 | * @dev: virtual device associated with tunnel | 1399 | * @dev: virtual device associated with tunnel |
1347 | **/ | 1400 | **/ |
1348 | 1401 | ||
1349 | static void ip6_tnl_dev_init(struct net_device *dev) | 1402 | static int ip6_tnl_dev_init(struct net_device *dev) |
1350 | { | 1403 | { |
1351 | struct ip6_tnl *t = netdev_priv(dev); | 1404 | struct ip6_tnl *t = netdev_priv(dev); |
1352 | ip6_tnl_dev_init_gen(dev); | 1405 | int err = ip6_tnl_dev_init_gen(dev); |
1406 | |||
1407 | if (err) | ||
1408 | return err; | ||
1353 | ip6_tnl_link_config(t); | 1409 | ip6_tnl_link_config(t); |
1410 | return 0; | ||
1354 | } | 1411 | } |
1355 | 1412 | ||
1356 | /** | 1413 | /** |
@@ -1360,25 +1417,29 @@ static void ip6_tnl_dev_init(struct net_device *dev) | |||
1360 | * Return: 0 | 1417 | * Return: 0 |
1361 | **/ | 1418 | **/ |
1362 | 1419 | ||
1363 | static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) | 1420 | static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev) |
1364 | { | 1421 | { |
1365 | struct ip6_tnl *t = netdev_priv(dev); | 1422 | struct ip6_tnl *t = netdev_priv(dev); |
1366 | struct net *net = dev_net(dev); | 1423 | struct net *net = dev_net(dev); |
1367 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1424 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
1425 | int err = ip6_tnl_dev_init_gen(dev); | ||
1426 | |||
1427 | if (err) | ||
1428 | return err; | ||
1368 | 1429 | ||
1369 | ip6_tnl_dev_init_gen(dev); | ||
1370 | t->parms.proto = IPPROTO_IPV6; | 1430 | t->parms.proto = IPPROTO_IPV6; |
1371 | dev_hold(dev); | 1431 | dev_hold(dev); |
1372 | ip6n->tnls_wc[0] = t; | 1432 | rcu_assign_pointer(ip6n->tnls_wc[0], t); |
1433 | return 0; | ||
1373 | } | 1434 | } |
1374 | 1435 | ||
1375 | static struct xfrm6_tunnel ip4ip6_handler = { | 1436 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { |
1376 | .handler = ip4ip6_rcv, | 1437 | .handler = ip4ip6_rcv, |
1377 | .err_handler = ip4ip6_err, | 1438 | .err_handler = ip4ip6_err, |
1378 | .priority = 1, | 1439 | .priority = 1, |
1379 | }; | 1440 | }; |
1380 | 1441 | ||
1381 | static struct xfrm6_tunnel ip6ip6_handler = { | 1442 | static struct xfrm6_tunnel ip6ip6_handler __read_mostly = { |
1382 | .handler = ip6ip6_rcv, | 1443 | .handler = ip6ip6_rcv, |
1383 | .err_handler = ip6ip6_err, | 1444 | .err_handler = ip6ip6_err, |
1384 | .priority = 1, | 1445 | .priority = 1, |
@@ -1391,14 +1452,14 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | |||
1391 | LIST_HEAD(list); | 1452 | LIST_HEAD(list); |
1392 | 1453 | ||
1393 | for (h = 0; h < HASH_SIZE; h++) { | 1454 | for (h = 0; h < HASH_SIZE; h++) { |
1394 | t = ip6n->tnls_r_l[h]; | 1455 | t = rtnl_dereference(ip6n->tnls_r_l[h]); |
1395 | while (t != NULL) { | 1456 | while (t != NULL) { |
1396 | unregister_netdevice_queue(t->dev, &list); | 1457 | unregister_netdevice_queue(t->dev, &list); |
1397 | t = t->next; | 1458 | t = rtnl_dereference(t->next); |
1398 | } | 1459 | } |
1399 | } | 1460 | } |
1400 | 1461 | ||
1401 | t = ip6n->tnls_wc[0]; | 1462 | t = rtnl_dereference(ip6n->tnls_wc[0]); |
1402 | unregister_netdevice_queue(t->dev, &list); | 1463 | unregister_netdevice_queue(t->dev, &list); |
1403 | unregister_netdevice_many(&list); | 1464 | unregister_netdevice_many(&list); |
1404 | } | 1465 | } |
@@ -1419,7 +1480,9 @@ static int __net_init ip6_tnl_init_net(struct net *net) | |||
1419 | goto err_alloc_dev; | 1480 | goto err_alloc_dev; |
1420 | dev_net_set(ip6n->fb_tnl_dev, net); | 1481 | dev_net_set(ip6n->fb_tnl_dev, net); |
1421 | 1482 | ||
1422 | ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev); | 1483 | err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev); |
1484 | if (err < 0) | ||
1485 | goto err_register; | ||
1423 | 1486 | ||
1424 | err = register_netdev(ip6n->fb_tnl_dev); | 1487 | err = register_netdev(ip6n->fb_tnl_dev); |
1425 | if (err < 0) | 1488 | if (err < 0) |
@@ -1427,7 +1490,7 @@ static int __net_init ip6_tnl_init_net(struct net *net) | |||
1427 | return 0; | 1490 | return 0; |
1428 | 1491 | ||
1429 | err_register: | 1492 | err_register: |
1430 | free_netdev(ip6n->fb_tnl_dev); | 1493 | ip6_dev_free(ip6n->fb_tnl_dev); |
1431 | err_alloc_dev: | 1494 | err_alloc_dev: |
1432 | return err; | 1495 | return err; |
1433 | } | 1496 | } |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 66078dad7fe8..6f32ffce7022 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -667,6 +667,7 @@ static int pim6_rcv(struct sk_buff *skb) | |||
667 | skb_tunnel_rx(skb, reg_dev); | 667 | skb_tunnel_rx(skb, reg_dev); |
668 | 668 | ||
669 | netif_rx(skb); | 669 | netif_rx(skb); |
670 | |||
670 | dev_put(reg_dev); | 671 | dev_put(reg_dev); |
671 | return 0; | 672 | return 0; |
672 | drop: | 673 | drop: |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index a7f66bc8f0b0..d1770e061c08 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -342,6 +342,25 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
342 | retv = 0; | 342 | retv = 0; |
343 | break; | 343 | break; |
344 | 344 | ||
345 | case IPV6_TRANSPARENT: | ||
346 | if (!capable(CAP_NET_ADMIN)) { | ||
347 | retv = -EPERM; | ||
348 | break; | ||
349 | } | ||
350 | if (optlen < sizeof(int)) | ||
351 | goto e_inval; | ||
352 | /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ | ||
353 | inet_sk(sk)->transparent = valbool; | ||
354 | retv = 0; | ||
355 | break; | ||
356 | |||
357 | case IPV6_RECVORIGDSTADDR: | ||
358 | if (optlen < sizeof(int)) | ||
359 | goto e_inval; | ||
360 | np->rxopt.bits.rxorigdstaddr = valbool; | ||
361 | retv = 0; | ||
362 | break; | ||
363 | |||
345 | case IPV6_HOPOPTS: | 364 | case IPV6_HOPOPTS: |
346 | case IPV6_RTHDRDSTOPTS: | 365 | case IPV6_RTHDRDSTOPTS: |
347 | case IPV6_RTHDR: | 366 | case IPV6_RTHDR: |
@@ -1104,6 +1123,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1104 | break; | 1123 | break; |
1105 | } | 1124 | } |
1106 | 1125 | ||
1126 | case IPV6_TRANSPARENT: | ||
1127 | val = inet_sk(sk)->transparent; | ||
1128 | break; | ||
1129 | |||
1130 | case IPV6_RECVORIGDSTADDR: | ||
1131 | val = np->rxopt.bits.rxorigdstaddr; | ||
1132 | break; | ||
1133 | |||
1107 | case IPV6_UNICAST_HOPS: | 1134 | case IPV6_UNICAST_HOPS: |
1108 | case IPV6_MULTICAST_HOPS: | 1135 | case IPV6_MULTICAST_HOPS: |
1109 | { | 1136 | { |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 58841c4ae947..998d6d27e7cf 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -91,7 +91,9 @@ | |||
91 | #include <linux/netfilter.h> | 91 | #include <linux/netfilter.h> |
92 | #include <linux/netfilter_ipv6.h> | 92 | #include <linux/netfilter_ipv6.h> |
93 | 93 | ||
94 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); | 94 | static u32 ndisc_hash(const void *pkey, |
95 | const struct net_device *dev, | ||
96 | __u32 rnd); | ||
95 | static int ndisc_constructor(struct neighbour *neigh); | 97 | static int ndisc_constructor(struct neighbour *neigh); |
96 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 98 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
97 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); | 99 | static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); |
@@ -228,12 +230,12 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, | |||
228 | do { | 230 | do { |
229 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 231 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
230 | } while(cur < end && cur->nd_opt_type != type); | 232 | } while(cur < end && cur->nd_opt_type != type); |
231 | return (cur <= end && cur->nd_opt_type == type ? cur : NULL); | 233 | return cur <= end && cur->nd_opt_type == type ? cur : NULL; |
232 | } | 234 | } |
233 | 235 | ||
234 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) | 236 | static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) |
235 | { | 237 | { |
236 | return (opt->nd_opt_type == ND_OPT_RDNSS); | 238 | return opt->nd_opt_type == ND_OPT_RDNSS; |
237 | } | 239 | } |
238 | 240 | ||
239 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | 241 | static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, |
@@ -244,7 +246,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | |||
244 | do { | 246 | do { |
245 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 247 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
246 | } while(cur < end && !ndisc_is_useropt(cur)); | 248 | } while(cur < end && !ndisc_is_useropt(cur)); |
247 | return (cur <= end && ndisc_is_useropt(cur) ? cur : NULL); | 249 | return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; |
248 | } | 250 | } |
249 | 251 | ||
250 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | 252 | static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, |
@@ -319,7 +321,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, | |||
319 | int prepad = ndisc_addr_option_pad(dev->type); | 321 | int prepad = ndisc_addr_option_pad(dev->type); |
320 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) | 322 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) |
321 | return NULL; | 323 | return NULL; |
322 | return (lladdr + prepad); | 324 | return lladdr + prepad; |
323 | } | 325 | } |
324 | 326 | ||
325 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) | 327 | int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) |
@@ -350,7 +352,9 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d | |||
350 | 352 | ||
351 | EXPORT_SYMBOL(ndisc_mc_map); | 353 | EXPORT_SYMBOL(ndisc_mc_map); |
352 | 354 | ||
353 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev) | 355 | static u32 ndisc_hash(const void *pkey, |
356 | const struct net_device *dev, | ||
357 | __u32 hash_rnd) | ||
354 | { | 358 | { |
355 | const u32 *p32 = pkey; | 359 | const u32 *p32 = pkey; |
356 | u32 addr_hash, i; | 360 | u32 addr_hash, i; |
@@ -359,7 +363,7 @@ static u32 ndisc_hash(const void *pkey, const struct net_device *dev) | |||
359 | for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) | 363 | for (i = 0; i < (sizeof(struct in6_addr) / sizeof(u32)); i++) |
360 | addr_hash ^= *p32++; | 364 | addr_hash ^= *p32++; |
361 | 365 | ||
362 | return jhash_2words(addr_hash, dev->ifindex, nd_tbl.hash_rnd); | 366 | return jhash_2words(addr_hash, dev->ifindex, hash_rnd); |
363 | } | 367 | } |
364 | 368 | ||
365 | static int ndisc_constructor(struct neighbour *neigh) | 369 | static int ndisc_constructor(struct neighbour *neigh) |
@@ -1105,6 +1109,18 @@ errout: | |||
1105 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); | 1109 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
1106 | } | 1110 | } |
1107 | 1111 | ||
1112 | static inline int accept_ra(struct inet6_dev *in6_dev) | ||
1113 | { | ||
1114 | /* | ||
1115 | * If forwarding is enabled, RA are not accepted unless the special | ||
1116 | * hybrid mode (accept_ra=2) is enabled. | ||
1117 | */ | ||
1118 | if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2) | ||
1119 | return 0; | ||
1120 | |||
1121 | return in6_dev->cnf.accept_ra; | ||
1122 | } | ||
1123 | |||
1108 | static void ndisc_router_discovery(struct sk_buff *skb) | 1124 | static void ndisc_router_discovery(struct sk_buff *skb) |
1109 | { | 1125 | { |
1110 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); | 1126 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
@@ -1158,8 +1174,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1158 | return; | 1174 | return; |
1159 | } | 1175 | } |
1160 | 1176 | ||
1161 | /* skip route and link configuration on routers */ | 1177 | if (!accept_ra(in6_dev)) |
1162 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) | ||
1163 | goto skip_linkparms; | 1178 | goto skip_linkparms; |
1164 | 1179 | ||
1165 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1180 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
@@ -1309,8 +1324,7 @@ skip_linkparms: | |||
1309 | NEIGH_UPDATE_F_ISROUTER); | 1324 | NEIGH_UPDATE_F_ISROUTER); |
1310 | } | 1325 | } |
1311 | 1326 | ||
1312 | /* skip route and link configuration on routers */ | 1327 | if (!accept_ra(in6_dev)) |
1313 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) | ||
1314 | goto out; | 1328 | goto out; |
1315 | 1329 | ||
1316 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1330 | #ifdef CONFIG_IPV6_ROUTE_INFO |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 29d643bcafa4..448464844a25 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -5,10 +5,15 @@ | |||
5 | menu "IPv6: Netfilter Configuration" | 5 | menu "IPv6: Netfilter Configuration" |
6 | depends on INET && IPV6 && NETFILTER | 6 | depends on INET && IPV6 && NETFILTER |
7 | 7 | ||
8 | config NF_DEFRAG_IPV6 | ||
9 | tristate | ||
10 | default n | ||
11 | |||
8 | config NF_CONNTRACK_IPV6 | 12 | config NF_CONNTRACK_IPV6 |
9 | tristate "IPv6 connection tracking support" | 13 | tristate "IPv6 connection tracking support" |
10 | depends on INET && IPV6 && NF_CONNTRACK | 14 | depends on INET && IPV6 && NF_CONNTRACK |
11 | default m if NETFILTER_ADVANCED=n | 15 | default m if NETFILTER_ADVANCED=n |
16 | select NF_DEFRAG_IPV6 | ||
12 | ---help--- | 17 | ---help--- |
13 | Connection tracking keeps a record of what packets have passed | 18 | Connection tracking keeps a record of what packets have passed |
14 | through your machine, in order to figure out how they are related | 19 | through your machine, in order to figure out how they are related |
@@ -132,10 +137,10 @@ config IP6_NF_MATCH_RT | |||
132 | # The targets | 137 | # The targets |
133 | config IP6_NF_TARGET_HL | 138 | config IP6_NF_TARGET_HL |
134 | tristate '"HL" hoplimit target support' | 139 | tristate '"HL" hoplimit target support' |
135 | depends on NETFILTER_ADVANCED | 140 | depends on NETFILTER_ADVANCED && IP6_NF_MANGLE |
136 | select NETFILTER_XT_TARGET_HL | 141 | select NETFILTER_XT_TARGET_HL |
137 | ---help--- | 142 | ---help--- |
138 | This is a backwards-compat option for the user's convenience | 143 | This is a backwards-compatible option for the user's convenience |
139 | (e.g. when running oldconfig). It selects | 144 | (e.g. when running oldconfig). It selects |
140 | CONFIG_NETFILTER_XT_TARGET_HL. | 145 | CONFIG_NETFILTER_XT_TARGET_HL. |
141 | 146 | ||
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index aafbba30c899..0a432c9b0795 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -11,10 +11,14 @@ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o | |||
11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o | 11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o |
12 | 12 | ||
13 | # objects for l3 independent conntrack | 13 | # objects for l3 independent conntrack |
14 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o | 14 | nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o |
15 | 15 | ||
16 | # l3 independent conntrack | 16 | # l3 independent conntrack |
17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o |
18 | |||
19 | # defrag | ||
20 | nf_defrag_ipv6-objs := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | ||
21 | obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | ||
18 | 22 | ||
19 | # matches | 23 | # matches |
20 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 24 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 8e754be92c24..455582384ece 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -82,13 +82,13 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); | |||
82 | int | 82 | int |
83 | ip6t_ext_hdr(u8 nexthdr) | 83 | ip6t_ext_hdr(u8 nexthdr) |
84 | { | 84 | { |
85 | return ( (nexthdr == IPPROTO_HOPOPTS) || | 85 | return (nexthdr == IPPROTO_HOPOPTS) || |
86 | (nexthdr == IPPROTO_ROUTING) || | 86 | (nexthdr == IPPROTO_ROUTING) || |
87 | (nexthdr == IPPROTO_FRAGMENT) || | 87 | (nexthdr == IPPROTO_FRAGMENT) || |
88 | (nexthdr == IPPROTO_ESP) || | 88 | (nexthdr == IPPROTO_ESP) || |
89 | (nexthdr == IPPROTO_AH) || | 89 | (nexthdr == IPPROTO_AH) || |
90 | (nexthdr == IPPROTO_NONE) || | 90 | (nexthdr == IPPROTO_NONE) || |
91 | (nexthdr == IPPROTO_DSTOPTS) ); | 91 | (nexthdr == IPPROTO_DSTOPTS); |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Returns whether matches rule or not. */ | 94 | /* Returns whether matches rule or not. */ |
@@ -215,7 +215,7 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6) | |||
215 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; | 215 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; |
216 | } | 216 | } |
217 | 217 | ||
218 | static inline const struct ip6t_entry_target * | 218 | static inline const struct xt_entry_target * |
219 | ip6t_get_target_c(const struct ip6t_entry *e) | 219 | ip6t_get_target_c(const struct ip6t_entry *e) |
220 | { | 220 | { |
221 | return ip6t_get_target((struct ip6t_entry *)e); | 221 | return ip6t_get_target((struct ip6t_entry *)e); |
@@ -260,9 +260,9 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, | |||
260 | const char *hookname, const char **chainname, | 260 | const char *hookname, const char **chainname, |
261 | const char **comment, unsigned int *rulenum) | 261 | const char **comment, unsigned int *rulenum) |
262 | { | 262 | { |
263 | const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s); | 263 | const struct xt_standard_target *t = (void *)ip6t_get_target_c(s); |
264 | 264 | ||
265 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { | 265 | if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) { |
266 | /* Head of user chain: ERROR target with chainname */ | 266 | /* Head of user chain: ERROR target with chainname */ |
267 | *chainname = t->target.data; | 267 | *chainname = t->target.data; |
268 | (*rulenum) = 0; | 268 | (*rulenum) = 0; |
@@ -271,7 +271,7 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, | |||
271 | 271 | ||
272 | if (s->target_offset == sizeof(struct ip6t_entry) && | 272 | if (s->target_offset == sizeof(struct ip6t_entry) && |
273 | strcmp(t->target.u.kernel.target->name, | 273 | strcmp(t->target.u.kernel.target->name, |
274 | IP6T_STANDARD_TARGET) == 0 && | 274 | XT_STANDARD_TARGET) == 0 && |
275 | t->verdict < 0 && | 275 | t->verdict < 0 && |
276 | unconditional(&s->ipv6)) { | 276 | unconditional(&s->ipv6)) { |
277 | /* Tail of chains: STANDARD target (return/policy) */ | 277 | /* Tail of chains: STANDARD target (return/policy) */ |
@@ -369,7 +369,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
369 | e = get_entry(table_base, private->hook_entry[hook]); | 369 | e = get_entry(table_base, private->hook_entry[hook]); |
370 | 370 | ||
371 | do { | 371 | do { |
372 | const struct ip6t_entry_target *t; | 372 | const struct xt_entry_target *t; |
373 | const struct xt_entry_match *ematch; | 373 | const struct xt_entry_match *ematch; |
374 | 374 | ||
375 | IP_NF_ASSERT(e); | 375 | IP_NF_ASSERT(e); |
@@ -403,10 +403,10 @@ ip6t_do_table(struct sk_buff *skb, | |||
403 | if (!t->u.kernel.target->target) { | 403 | if (!t->u.kernel.target->target) { |
404 | int v; | 404 | int v; |
405 | 405 | ||
406 | v = ((struct ip6t_standard_target *)t)->verdict; | 406 | v = ((struct xt_standard_target *)t)->verdict; |
407 | if (v < 0) { | 407 | if (v < 0) { |
408 | /* Pop from stack? */ | 408 | /* Pop from stack? */ |
409 | if (v != IP6T_RETURN) { | 409 | if (v != XT_RETURN) { |
410 | verdict = (unsigned)(-v) - 1; | 410 | verdict = (unsigned)(-v) - 1; |
411 | break; | 411 | break; |
412 | } | 412 | } |
@@ -434,7 +434,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
434 | acpar.targinfo = t->data; | 434 | acpar.targinfo = t->data; |
435 | 435 | ||
436 | verdict = t->u.kernel.target->target(skb, &acpar); | 436 | verdict = t->u.kernel.target->target(skb, &acpar); |
437 | if (verdict == IP6T_CONTINUE) | 437 | if (verdict == XT_CONTINUE) |
438 | e = ip6t_next_entry(e); | 438 | e = ip6t_next_entry(e); |
439 | else | 439 | else |
440 | /* Verdict */ | 440 | /* Verdict */ |
@@ -474,7 +474,7 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
474 | e->counters.pcnt = pos; | 474 | e->counters.pcnt = pos; |
475 | 475 | ||
476 | for (;;) { | 476 | for (;;) { |
477 | const struct ip6t_standard_target *t | 477 | const struct xt_standard_target *t |
478 | = (void *)ip6t_get_target_c(e); | 478 | = (void *)ip6t_get_target_c(e); |
479 | int visited = e->comefrom & (1 << hook); | 479 | int visited = e->comefrom & (1 << hook); |
480 | 480 | ||
@@ -488,13 +488,13 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
488 | /* Unconditional return/END. */ | 488 | /* Unconditional return/END. */ |
489 | if ((e->target_offset == sizeof(struct ip6t_entry) && | 489 | if ((e->target_offset == sizeof(struct ip6t_entry) && |
490 | (strcmp(t->target.u.user.name, | 490 | (strcmp(t->target.u.user.name, |
491 | IP6T_STANDARD_TARGET) == 0) && | 491 | XT_STANDARD_TARGET) == 0) && |
492 | t->verdict < 0 && | 492 | t->verdict < 0 && |
493 | unconditional(&e->ipv6)) || visited) { | 493 | unconditional(&e->ipv6)) || visited) { |
494 | unsigned int oldpos, size; | 494 | unsigned int oldpos, size; |
495 | 495 | ||
496 | if ((strcmp(t->target.u.user.name, | 496 | if ((strcmp(t->target.u.user.name, |
497 | IP6T_STANDARD_TARGET) == 0) && | 497 | XT_STANDARD_TARGET) == 0) && |
498 | t->verdict < -NF_MAX_VERDICT - 1) { | 498 | t->verdict < -NF_MAX_VERDICT - 1) { |
499 | duprintf("mark_source_chains: bad " | 499 | duprintf("mark_source_chains: bad " |
500 | "negative verdict (%i)\n", | 500 | "negative verdict (%i)\n", |
@@ -537,7 +537,7 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
537 | int newpos = t->verdict; | 537 | int newpos = t->verdict; |
538 | 538 | ||
539 | if (strcmp(t->target.u.user.name, | 539 | if (strcmp(t->target.u.user.name, |
540 | IP6T_STANDARD_TARGET) == 0 && | 540 | XT_STANDARD_TARGET) == 0 && |
541 | newpos >= 0) { | 541 | newpos >= 0) { |
542 | if (newpos > newinfo->size - | 542 | if (newpos > newinfo->size - |
543 | sizeof(struct ip6t_entry)) { | 543 | sizeof(struct ip6t_entry)) { |
@@ -565,7 +565,7 @@ mark_source_chains(const struct xt_table_info *newinfo, | |||
565 | return 1; | 565 | return 1; |
566 | } | 566 | } |
567 | 567 | ||
568 | static void cleanup_match(struct ip6t_entry_match *m, struct net *net) | 568 | static void cleanup_match(struct xt_entry_match *m, struct net *net) |
569 | { | 569 | { |
570 | struct xt_mtdtor_param par; | 570 | struct xt_mtdtor_param par; |
571 | 571 | ||
@@ -581,14 +581,14 @@ static void cleanup_match(struct ip6t_entry_match *m, struct net *net) | |||
581 | static int | 581 | static int |
582 | check_entry(const struct ip6t_entry *e, const char *name) | 582 | check_entry(const struct ip6t_entry *e, const char *name) |
583 | { | 583 | { |
584 | const struct ip6t_entry_target *t; | 584 | const struct xt_entry_target *t; |
585 | 585 | ||
586 | if (!ip6_checkentry(&e->ipv6)) { | 586 | if (!ip6_checkentry(&e->ipv6)) { |
587 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); | 587 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); |
588 | return -EINVAL; | 588 | return -EINVAL; |
589 | } | 589 | } |
590 | 590 | ||
591 | if (e->target_offset + sizeof(struct ip6t_entry_target) > | 591 | if (e->target_offset + sizeof(struct xt_entry_target) > |
592 | e->next_offset) | 592 | e->next_offset) |
593 | return -EINVAL; | 593 | return -EINVAL; |
594 | 594 | ||
@@ -599,7 +599,7 @@ check_entry(const struct ip6t_entry *e, const char *name) | |||
599 | return 0; | 599 | return 0; |
600 | } | 600 | } |
601 | 601 | ||
602 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) | 602 | static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) |
603 | { | 603 | { |
604 | const struct ip6t_ip6 *ipv6 = par->entryinfo; | 604 | const struct ip6t_ip6 *ipv6 = par->entryinfo; |
605 | int ret; | 605 | int ret; |
@@ -618,7 +618,7 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) | |||
618 | } | 618 | } |
619 | 619 | ||
620 | static int | 620 | static int |
621 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) | 621 | find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) |
622 | { | 622 | { |
623 | struct xt_match *match; | 623 | struct xt_match *match; |
624 | int ret; | 624 | int ret; |
@@ -643,7 +643,7 @@ err: | |||
643 | 643 | ||
644 | static int check_target(struct ip6t_entry *e, struct net *net, const char *name) | 644 | static int check_target(struct ip6t_entry *e, struct net *net, const char *name) |
645 | { | 645 | { |
646 | struct ip6t_entry_target *t = ip6t_get_target(e); | 646 | struct xt_entry_target *t = ip6t_get_target(e); |
647 | struct xt_tgchk_param par = { | 647 | struct xt_tgchk_param par = { |
648 | .net = net, | 648 | .net = net, |
649 | .table = name, | 649 | .table = name, |
@@ -670,7 +670,7 @@ static int | |||
670 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | 670 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
671 | unsigned int size) | 671 | unsigned int size) |
672 | { | 672 | { |
673 | struct ip6t_entry_target *t; | 673 | struct xt_entry_target *t; |
674 | struct xt_target *target; | 674 | struct xt_target *target; |
675 | int ret; | 675 | int ret; |
676 | unsigned int j; | 676 | unsigned int j; |
@@ -721,7 +721,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, | |||
721 | 721 | ||
722 | static bool check_underflow(const struct ip6t_entry *e) | 722 | static bool check_underflow(const struct ip6t_entry *e) |
723 | { | 723 | { |
724 | const struct ip6t_entry_target *t; | 724 | const struct xt_entry_target *t; |
725 | unsigned int verdict; | 725 | unsigned int verdict; |
726 | 726 | ||
727 | if (!unconditional(&e->ipv6)) | 727 | if (!unconditional(&e->ipv6)) |
@@ -729,7 +729,7 @@ static bool check_underflow(const struct ip6t_entry *e) | |||
729 | t = ip6t_get_target_c(e); | 729 | t = ip6t_get_target_c(e); |
730 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | 730 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) |
731 | return false; | 731 | return false; |
732 | verdict = ((struct ip6t_standard_target *)t)->verdict; | 732 | verdict = ((struct xt_standard_target *)t)->verdict; |
733 | verdict = -verdict - 1; | 733 | verdict = -verdict - 1; |
734 | return verdict == NF_DROP || verdict == NF_ACCEPT; | 734 | return verdict == NF_DROP || verdict == NF_ACCEPT; |
735 | } | 735 | } |
@@ -752,7 +752,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
752 | } | 752 | } |
753 | 753 | ||
754 | if (e->next_offset | 754 | if (e->next_offset |
755 | < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) { | 755 | < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) { |
756 | duprintf("checking: element %p size %u\n", | 756 | duprintf("checking: element %p size %u\n", |
757 | e, e->next_offset); | 757 | e, e->next_offset); |
758 | return -EINVAL; | 758 | return -EINVAL; |
@@ -784,7 +784,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
784 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) | 784 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
785 | { | 785 | { |
786 | struct xt_tgdtor_param par; | 786 | struct xt_tgdtor_param par; |
787 | struct ip6t_entry_target *t; | 787 | struct xt_entry_target *t; |
788 | struct xt_entry_match *ematch; | 788 | struct xt_entry_match *ematch; |
789 | 789 | ||
790 | /* Cleanup all matches */ | 790 | /* Cleanup all matches */ |
@@ -985,8 +985,8 @@ copy_entries_to_user(unsigned int total_size, | |||
985 | /* ... then go back and fix counters and names */ | 985 | /* ... then go back and fix counters and names */ |
986 | for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ | 986 | for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ |
987 | unsigned int i; | 987 | unsigned int i; |
988 | const struct ip6t_entry_match *m; | 988 | const struct xt_entry_match *m; |
989 | const struct ip6t_entry_target *t; | 989 | const struct xt_entry_target *t; |
990 | 990 | ||
991 | e = (struct ip6t_entry *)(loc_cpu_entry + off); | 991 | e = (struct ip6t_entry *)(loc_cpu_entry + off); |
992 | if (copy_to_user(userptr + off | 992 | if (copy_to_user(userptr + off |
@@ -1003,7 +1003,7 @@ copy_entries_to_user(unsigned int total_size, | |||
1003 | m = (void *)e + i; | 1003 | m = (void *)e + i; |
1004 | 1004 | ||
1005 | if (copy_to_user(userptr + off + i | 1005 | if (copy_to_user(userptr + off + i |
1006 | + offsetof(struct ip6t_entry_match, | 1006 | + offsetof(struct xt_entry_match, |
1007 | u.user.name), | 1007 | u.user.name), |
1008 | m->u.kernel.match->name, | 1008 | m->u.kernel.match->name, |
1009 | strlen(m->u.kernel.match->name)+1) | 1009 | strlen(m->u.kernel.match->name)+1) |
@@ -1015,7 +1015,7 @@ copy_entries_to_user(unsigned int total_size, | |||
1015 | 1015 | ||
1016 | t = ip6t_get_target_c(e); | 1016 | t = ip6t_get_target_c(e); |
1017 | if (copy_to_user(userptr + off + e->target_offset | 1017 | if (copy_to_user(userptr + off + e->target_offset |
1018 | + offsetof(struct ip6t_entry_target, | 1018 | + offsetof(struct xt_entry_target, |
1019 | u.user.name), | 1019 | u.user.name), |
1020 | t->u.kernel.target->name, | 1020 | t->u.kernel.target->name, |
1021 | strlen(t->u.kernel.target->name)+1) != 0) { | 1021 | strlen(t->u.kernel.target->name)+1) != 0) { |
@@ -1053,7 +1053,7 @@ static int compat_calc_entry(const struct ip6t_entry *e, | |||
1053 | const void *base, struct xt_table_info *newinfo) | 1053 | const void *base, struct xt_table_info *newinfo) |
1054 | { | 1054 | { |
1055 | const struct xt_entry_match *ematch; | 1055 | const struct xt_entry_match *ematch; |
1056 | const struct ip6t_entry_target *t; | 1056 | const struct xt_entry_target *t; |
1057 | unsigned int entry_offset; | 1057 | unsigned int entry_offset; |
1058 | int off, i, ret; | 1058 | int off, i, ret; |
1059 | 1059 | ||
@@ -1105,7 +1105,7 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1105 | static int get_info(struct net *net, void __user *user, | 1105 | static int get_info(struct net *net, void __user *user, |
1106 | const int *len, int compat) | 1106 | const int *len, int compat) |
1107 | { | 1107 | { |
1108 | char name[IP6T_TABLE_MAXNAMELEN]; | 1108 | char name[XT_TABLE_MAXNAMELEN]; |
1109 | struct xt_table *t; | 1109 | struct xt_table *t; |
1110 | int ret; | 1110 | int ret; |
1111 | 1111 | ||
@@ -1118,7 +1118,7 @@ static int get_info(struct net *net, void __user *user, | |||
1118 | if (copy_from_user(name, user, sizeof(name)) != 0) | 1118 | if (copy_from_user(name, user, sizeof(name)) != 0) |
1119 | return -EFAULT; | 1119 | return -EFAULT; |
1120 | 1120 | ||
1121 | name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; | 1121 | name[XT_TABLE_MAXNAMELEN-1] = '\0'; |
1122 | #ifdef CONFIG_COMPAT | 1122 | #ifdef CONFIG_COMPAT |
1123 | if (compat) | 1123 | if (compat) |
1124 | xt_compat_lock(AF_INET6); | 1124 | xt_compat_lock(AF_INET6); |
@@ -1137,6 +1137,7 @@ static int get_info(struct net *net, void __user *user, | |||
1137 | private = &tmp; | 1137 | private = &tmp; |
1138 | } | 1138 | } |
1139 | #endif | 1139 | #endif |
1140 | memset(&info, 0, sizeof(info)); | ||
1140 | info.valid_hooks = t->valid_hooks; | 1141 | info.valid_hooks = t->valid_hooks; |
1141 | memcpy(info.hook_entry, private->hook_entry, | 1142 | memcpy(info.hook_entry, private->hook_entry, |
1142 | sizeof(info.hook_entry)); | 1143 | sizeof(info.hook_entry)); |
@@ -1415,14 +1416,14 @@ do_add_counters(struct net *net, const void __user *user, unsigned int len, | |||
1415 | 1416 | ||
1416 | #ifdef CONFIG_COMPAT | 1417 | #ifdef CONFIG_COMPAT |
1417 | struct compat_ip6t_replace { | 1418 | struct compat_ip6t_replace { |
1418 | char name[IP6T_TABLE_MAXNAMELEN]; | 1419 | char name[XT_TABLE_MAXNAMELEN]; |
1419 | u32 valid_hooks; | 1420 | u32 valid_hooks; |
1420 | u32 num_entries; | 1421 | u32 num_entries; |
1421 | u32 size; | 1422 | u32 size; |
1422 | u32 hook_entry[NF_INET_NUMHOOKS]; | 1423 | u32 hook_entry[NF_INET_NUMHOOKS]; |
1423 | u32 underflow[NF_INET_NUMHOOKS]; | 1424 | u32 underflow[NF_INET_NUMHOOKS]; |
1424 | u32 num_counters; | 1425 | u32 num_counters; |
1425 | compat_uptr_t counters; /* struct ip6t_counters * */ | 1426 | compat_uptr_t counters; /* struct xt_counters * */ |
1426 | struct compat_ip6t_entry entries[0]; | 1427 | struct compat_ip6t_entry entries[0]; |
1427 | }; | 1428 | }; |
1428 | 1429 | ||
@@ -1431,7 +1432,7 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | |||
1431 | unsigned int *size, struct xt_counters *counters, | 1432 | unsigned int *size, struct xt_counters *counters, |
1432 | unsigned int i) | 1433 | unsigned int i) |
1433 | { | 1434 | { |
1434 | struct ip6t_entry_target *t; | 1435 | struct xt_entry_target *t; |
1435 | struct compat_ip6t_entry __user *ce; | 1436 | struct compat_ip6t_entry __user *ce; |
1436 | u_int16_t target_offset, next_offset; | 1437 | u_int16_t target_offset, next_offset; |
1437 | compat_uint_t origsize; | 1438 | compat_uint_t origsize; |
@@ -1466,7 +1467,7 @@ compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | |||
1466 | } | 1467 | } |
1467 | 1468 | ||
1468 | static int | 1469 | static int |
1469 | compat_find_calc_match(struct ip6t_entry_match *m, | 1470 | compat_find_calc_match(struct xt_entry_match *m, |
1470 | const char *name, | 1471 | const char *name, |
1471 | const struct ip6t_ip6 *ipv6, | 1472 | const struct ip6t_ip6 *ipv6, |
1472 | unsigned int hookmask, | 1473 | unsigned int hookmask, |
@@ -1488,7 +1489,7 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
1488 | 1489 | ||
1489 | static void compat_release_entry(struct compat_ip6t_entry *e) | 1490 | static void compat_release_entry(struct compat_ip6t_entry *e) |
1490 | { | 1491 | { |
1491 | struct ip6t_entry_target *t; | 1492 | struct xt_entry_target *t; |
1492 | struct xt_entry_match *ematch; | 1493 | struct xt_entry_match *ematch; |
1493 | 1494 | ||
1494 | /* Cleanup all matches */ | 1495 | /* Cleanup all matches */ |
@@ -1509,7 +1510,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1509 | const char *name) | 1510 | const char *name) |
1510 | { | 1511 | { |
1511 | struct xt_entry_match *ematch; | 1512 | struct xt_entry_match *ematch; |
1512 | struct ip6t_entry_target *t; | 1513 | struct xt_entry_target *t; |
1513 | struct xt_target *target; | 1514 | struct xt_target *target; |
1514 | unsigned int entry_offset; | 1515 | unsigned int entry_offset; |
1515 | unsigned int j; | 1516 | unsigned int j; |
@@ -1591,7 +1592,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1591 | unsigned int *size, const char *name, | 1592 | unsigned int *size, const char *name, |
1592 | struct xt_table_info *newinfo, unsigned char *base) | 1593 | struct xt_table_info *newinfo, unsigned char *base) |
1593 | { | 1594 | { |
1594 | struct ip6t_entry_target *t; | 1595 | struct xt_entry_target *t; |
1595 | struct xt_target *target; | 1596 | struct xt_target *target; |
1596 | struct ip6t_entry *de; | 1597 | struct ip6t_entry *de; |
1597 | unsigned int origsize; | 1598 | unsigned int origsize; |
@@ -1899,7 +1900,7 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, | |||
1899 | } | 1900 | } |
1900 | 1901 | ||
1901 | struct compat_ip6t_get_entries { | 1902 | struct compat_ip6t_get_entries { |
1902 | char name[IP6T_TABLE_MAXNAMELEN]; | 1903 | char name[XT_TABLE_MAXNAMELEN]; |
1903 | compat_uint_t size; | 1904 | compat_uint_t size; |
1904 | struct compat_ip6t_entry entrytable[0]; | 1905 | struct compat_ip6t_entry entrytable[0]; |
1905 | }; | 1906 | }; |
@@ -2054,7 +2055,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
2054 | 2055 | ||
2055 | case IP6T_SO_GET_REVISION_MATCH: | 2056 | case IP6T_SO_GET_REVISION_MATCH: |
2056 | case IP6T_SO_GET_REVISION_TARGET: { | 2057 | case IP6T_SO_GET_REVISION_TARGET: { |
2057 | struct ip6t_get_revision rev; | 2058 | struct xt_get_revision rev; |
2058 | int target; | 2059 | int target; |
2059 | 2060 | ||
2060 | if (*len != sizeof(rev)) { | 2061 | if (*len != sizeof(rev)) { |
@@ -2191,7 +2192,7 @@ static int icmp6_checkentry(const struct xt_mtchk_param *par) | |||
2191 | /* The built-in targets: standard (NULL) and error. */ | 2192 | /* The built-in targets: standard (NULL) and error. */ |
2192 | static struct xt_target ip6t_builtin_tg[] __read_mostly = { | 2193 | static struct xt_target ip6t_builtin_tg[] __read_mostly = { |
2193 | { | 2194 | { |
2194 | .name = IP6T_STANDARD_TARGET, | 2195 | .name = XT_STANDARD_TARGET, |
2195 | .targetsize = sizeof(int), | 2196 | .targetsize = sizeof(int), |
2196 | .family = NFPROTO_IPV6, | 2197 | .family = NFPROTO_IPV6, |
2197 | #ifdef CONFIG_COMPAT | 2198 | #ifdef CONFIG_COMPAT |
@@ -2201,9 +2202,9 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = { | |||
2201 | #endif | 2202 | #endif |
2202 | }, | 2203 | }, |
2203 | { | 2204 | { |
2204 | .name = IP6T_ERROR_TARGET, | 2205 | .name = XT_ERROR_TARGET, |
2205 | .target = ip6t_error, | 2206 | .target = ip6t_error, |
2206 | .targetsize = IP6T_FUNCTION_MAXNAMELEN, | 2207 | .targetsize = XT_FUNCTION_MAXNAMELEN, |
2207 | .family = NFPROTO_IPV6, | 2208 | .family = NFPROTO_IPV6, |
2208 | }, | 2209 | }, |
2209 | }; | 2210 | }; |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 0a07ae7b933f..09c88891a753 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/netfilter/x_tables.h> | 23 | #include <linux/netfilter/x_tables.h> |
24 | #include <linux/netfilter_ipv6/ip6_tables.h> | 24 | #include <linux/netfilter_ipv6/ip6_tables.h> |
25 | #include <net/netfilter/nf_log.h> | 25 | #include <net/netfilter/nf_log.h> |
26 | #include <net/netfilter/xt_log.h> | ||
26 | 27 | ||
27 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); | 28 | MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>"); |
28 | MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); | 29 | MODULE_DESCRIPTION("Xtables: IPv6 packet logging to syslog"); |
@@ -32,11 +33,9 @@ struct in_device; | |||
32 | #include <net/route.h> | 33 | #include <net/route.h> |
33 | #include <linux/netfilter_ipv6/ip6t_LOG.h> | 34 | #include <linux/netfilter_ipv6/ip6t_LOG.h> |
34 | 35 | ||
35 | /* Use lock to serialize, so printks don't overlap */ | ||
36 | static DEFINE_SPINLOCK(log_lock); | ||
37 | |||
38 | /* One level of recursion won't kill us */ | 36 | /* One level of recursion won't kill us */ |
39 | static void dump_packet(const struct nf_loginfo *info, | 37 | static void dump_packet(struct sbuff *m, |
38 | const struct nf_loginfo *info, | ||
40 | const struct sk_buff *skb, unsigned int ip6hoff, | 39 | const struct sk_buff *skb, unsigned int ip6hoff, |
41 | int recurse) | 40 | int recurse) |
42 | { | 41 | { |
@@ -55,15 +54,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
55 | 54 | ||
56 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); | 55 | ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h); |
57 | if (ih == NULL) { | 56 | if (ih == NULL) { |
58 | printk("TRUNCATED"); | 57 | sb_add(m, "TRUNCATED"); |
59 | return; | 58 | return; |
60 | } | 59 | } |
61 | 60 | ||
62 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ | 61 | /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ |
63 | printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); | 62 | sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); |
64 | 63 | ||
65 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ | 64 | /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ |
66 | printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", | 65 | sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", |
67 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), | 66 | ntohs(ih->payload_len) + sizeof(struct ipv6hdr), |
68 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, | 67 | (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20, |
69 | ih->hop_limit, | 68 | ih->hop_limit, |
@@ -78,35 +77,35 @@ static void dump_packet(const struct nf_loginfo *info, | |||
78 | 77 | ||
79 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | 78 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); |
80 | if (hp == NULL) { | 79 | if (hp == NULL) { |
81 | printk("TRUNCATED"); | 80 | sb_add(m, "TRUNCATED"); |
82 | return; | 81 | return; |
83 | } | 82 | } |
84 | 83 | ||
85 | /* Max length: 48 "OPT (...) " */ | 84 | /* Max length: 48 "OPT (...) " */ |
86 | if (logflags & IP6T_LOG_IPOPT) | 85 | if (logflags & IP6T_LOG_IPOPT) |
87 | printk("OPT ( "); | 86 | sb_add(m, "OPT ( "); |
88 | 87 | ||
89 | switch (currenthdr) { | 88 | switch (currenthdr) { |
90 | case IPPROTO_FRAGMENT: { | 89 | case IPPROTO_FRAGMENT: { |
91 | struct frag_hdr _fhdr; | 90 | struct frag_hdr _fhdr; |
92 | const struct frag_hdr *fh; | 91 | const struct frag_hdr *fh; |
93 | 92 | ||
94 | printk("FRAG:"); | 93 | sb_add(m, "FRAG:"); |
95 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), | 94 | fh = skb_header_pointer(skb, ptr, sizeof(_fhdr), |
96 | &_fhdr); | 95 | &_fhdr); |
97 | if (fh == NULL) { | 96 | if (fh == NULL) { |
98 | printk("TRUNCATED "); | 97 | sb_add(m, "TRUNCATED "); |
99 | return; | 98 | return; |
100 | } | 99 | } |
101 | 100 | ||
102 | /* Max length: 6 "65535 " */ | 101 | /* Max length: 6 "65535 " */ |
103 | printk("%u ", ntohs(fh->frag_off) & 0xFFF8); | 102 | sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8); |
104 | 103 | ||
105 | /* Max length: 11 "INCOMPLETE " */ | 104 | /* Max length: 11 "INCOMPLETE " */ |
106 | if (fh->frag_off & htons(0x0001)) | 105 | if (fh->frag_off & htons(0x0001)) |
107 | printk("INCOMPLETE "); | 106 | sb_add(m, "INCOMPLETE "); |
108 | 107 | ||
109 | printk("ID:%08x ", ntohl(fh->identification)); | 108 | sb_add(m, "ID:%08x ", ntohl(fh->identification)); |
110 | 109 | ||
111 | if (ntohs(fh->frag_off) & 0xFFF8) | 110 | if (ntohs(fh->frag_off) & 0xFFF8) |
112 | fragment = 1; | 111 | fragment = 1; |
@@ -120,7 +119,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
120 | case IPPROTO_HOPOPTS: | 119 | case IPPROTO_HOPOPTS: |
121 | if (fragment) { | 120 | if (fragment) { |
122 | if (logflags & IP6T_LOG_IPOPT) | 121 | if (logflags & IP6T_LOG_IPOPT) |
123 | printk(")"); | 122 | sb_add(m, ")"); |
124 | return; | 123 | return; |
125 | } | 124 | } |
126 | hdrlen = ipv6_optlen(hp); | 125 | hdrlen = ipv6_optlen(hp); |
@@ -132,10 +131,10 @@ static void dump_packet(const struct nf_loginfo *info, | |||
132 | const struct ip_auth_hdr *ah; | 131 | const struct ip_auth_hdr *ah; |
133 | 132 | ||
134 | /* Max length: 3 "AH " */ | 133 | /* Max length: 3 "AH " */ |
135 | printk("AH "); | 134 | sb_add(m, "AH "); |
136 | 135 | ||
137 | if (fragment) { | 136 | if (fragment) { |
138 | printk(")"); | 137 | sb_add(m, ")"); |
139 | return; | 138 | return; |
140 | } | 139 | } |
141 | 140 | ||
@@ -146,13 +145,13 @@ static void dump_packet(const struct nf_loginfo *info, | |||
146 | * Max length: 26 "INCOMPLETE [65535 | 145 | * Max length: 26 "INCOMPLETE [65535 |
147 | * bytes] )" | 146 | * bytes] )" |
148 | */ | 147 | */ |
149 | printk("INCOMPLETE [%u bytes] )", | 148 | sb_add(m, "INCOMPLETE [%u bytes] )", |
150 | skb->len - ptr); | 149 | skb->len - ptr); |
151 | return; | 150 | return; |
152 | } | 151 | } |
153 | 152 | ||
154 | /* Length: 15 "SPI=0xF1234567 */ | 153 | /* Length: 15 "SPI=0xF1234567 */ |
155 | printk("SPI=0x%x ", ntohl(ah->spi)); | 154 | sb_add(m, "SPI=0x%x ", ntohl(ah->spi)); |
156 | 155 | ||
157 | } | 156 | } |
158 | 157 | ||
@@ -164,10 +163,10 @@ static void dump_packet(const struct nf_loginfo *info, | |||
164 | const struct ip_esp_hdr *eh; | 163 | const struct ip_esp_hdr *eh; |
165 | 164 | ||
166 | /* Max length: 4 "ESP " */ | 165 | /* Max length: 4 "ESP " */ |
167 | printk("ESP "); | 166 | sb_add(m, "ESP "); |
168 | 167 | ||
169 | if (fragment) { | 168 | if (fragment) { |
170 | printk(")"); | 169 | sb_add(m, ")"); |
171 | return; | 170 | return; |
172 | } | 171 | } |
173 | 172 | ||
@@ -177,23 +176,23 @@ static void dump_packet(const struct nf_loginfo *info, | |||
177 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), | 176 | eh = skb_header_pointer(skb, ptr, sizeof(_esph), |
178 | &_esph); | 177 | &_esph); |
179 | if (eh == NULL) { | 178 | if (eh == NULL) { |
180 | printk("INCOMPLETE [%u bytes] )", | 179 | sb_add(m, "INCOMPLETE [%u bytes] )", |
181 | skb->len - ptr); | 180 | skb->len - ptr); |
182 | return; | 181 | return; |
183 | } | 182 | } |
184 | 183 | ||
185 | /* Length: 16 "SPI=0xF1234567 )" */ | 184 | /* Length: 16 "SPI=0xF1234567 )" */ |
186 | printk("SPI=0x%x )", ntohl(eh->spi) ); | 185 | sb_add(m, "SPI=0x%x )", ntohl(eh->spi) ); |
187 | 186 | ||
188 | } | 187 | } |
189 | return; | 188 | return; |
190 | default: | 189 | default: |
191 | /* Max length: 20 "Unknown Ext Hdr 255" */ | 190 | /* Max length: 20 "Unknown Ext Hdr 255" */ |
192 | printk("Unknown Ext Hdr %u", currenthdr); | 191 | sb_add(m, "Unknown Ext Hdr %u", currenthdr); |
193 | return; | 192 | return; |
194 | } | 193 | } |
195 | if (logflags & IP6T_LOG_IPOPT) | 194 | if (logflags & IP6T_LOG_IPOPT) |
196 | printk(") "); | 195 | sb_add(m, ") "); |
197 | 196 | ||
198 | currenthdr = hp->nexthdr; | 197 | currenthdr = hp->nexthdr; |
199 | ptr += hdrlen; | 198 | ptr += hdrlen; |
@@ -205,7 +204,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
205 | const struct tcphdr *th; | 204 | const struct tcphdr *th; |
206 | 205 | ||
207 | /* Max length: 10 "PROTO=TCP " */ | 206 | /* Max length: 10 "PROTO=TCP " */ |
208 | printk("PROTO=TCP "); | 207 | sb_add(m, "PROTO=TCP "); |
209 | 208 | ||
210 | if (fragment) | 209 | if (fragment) |
211 | break; | 210 | break; |
@@ -213,40 +212,40 @@ static void dump_packet(const struct nf_loginfo *info, | |||
213 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | 212 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ |
214 | th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); | 213 | th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph); |
215 | if (th == NULL) { | 214 | if (th == NULL) { |
216 | printk("INCOMPLETE [%u bytes] ", skb->len - ptr); | 215 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); |
217 | return; | 216 | return; |
218 | } | 217 | } |
219 | 218 | ||
220 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | 219 | /* Max length: 20 "SPT=65535 DPT=65535 " */ |
221 | printk("SPT=%u DPT=%u ", | 220 | sb_add(m, "SPT=%u DPT=%u ", |
222 | ntohs(th->source), ntohs(th->dest)); | 221 | ntohs(th->source), ntohs(th->dest)); |
223 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ | 222 | /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ |
224 | if (logflags & IP6T_LOG_TCPSEQ) | 223 | if (logflags & IP6T_LOG_TCPSEQ) |
225 | printk("SEQ=%u ACK=%u ", | 224 | sb_add(m, "SEQ=%u ACK=%u ", |
226 | ntohl(th->seq), ntohl(th->ack_seq)); | 225 | ntohl(th->seq), ntohl(th->ack_seq)); |
227 | /* Max length: 13 "WINDOW=65535 " */ | 226 | /* Max length: 13 "WINDOW=65535 " */ |
228 | printk("WINDOW=%u ", ntohs(th->window)); | 227 | sb_add(m, "WINDOW=%u ", ntohs(th->window)); |
229 | /* Max length: 9 "RES=0x3C " */ | 228 | /* Max length: 9 "RES=0x3C " */ |
230 | printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); | 229 | sb_add(m, "RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22)); |
231 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ | 230 | /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ |
232 | if (th->cwr) | 231 | if (th->cwr) |
233 | printk("CWR "); | 232 | sb_add(m, "CWR "); |
234 | if (th->ece) | 233 | if (th->ece) |
235 | printk("ECE "); | 234 | sb_add(m, "ECE "); |
236 | if (th->urg) | 235 | if (th->urg) |
237 | printk("URG "); | 236 | sb_add(m, "URG "); |
238 | if (th->ack) | 237 | if (th->ack) |
239 | printk("ACK "); | 238 | sb_add(m, "ACK "); |
240 | if (th->psh) | 239 | if (th->psh) |
241 | printk("PSH "); | 240 | sb_add(m, "PSH "); |
242 | if (th->rst) | 241 | if (th->rst) |
243 | printk("RST "); | 242 | sb_add(m, "RST "); |
244 | if (th->syn) | 243 | if (th->syn) |
245 | printk("SYN "); | 244 | sb_add(m, "SYN "); |
246 | if (th->fin) | 245 | if (th->fin) |
247 | printk("FIN "); | 246 | sb_add(m, "FIN "); |
248 | /* Max length: 11 "URGP=65535 " */ | 247 | /* Max length: 11 "URGP=65535 " */ |
249 | printk("URGP=%u ", ntohs(th->urg_ptr)); | 248 | sb_add(m, "URGP=%u ", ntohs(th->urg_ptr)); |
250 | 249 | ||
251 | if ((logflags & IP6T_LOG_TCPOPT) && | 250 | if ((logflags & IP6T_LOG_TCPOPT) && |
252 | th->doff * 4 > sizeof(struct tcphdr)) { | 251 | th->doff * 4 > sizeof(struct tcphdr)) { |
@@ -260,15 +259,15 @@ static void dump_packet(const struct nf_loginfo *info, | |||
260 | ptr + sizeof(struct tcphdr), | 259 | ptr + sizeof(struct tcphdr), |
261 | optsize, _opt); | 260 | optsize, _opt); |
262 | if (op == NULL) { | 261 | if (op == NULL) { |
263 | printk("OPT (TRUNCATED)"); | 262 | sb_add(m, "OPT (TRUNCATED)"); |
264 | return; | 263 | return; |
265 | } | 264 | } |
266 | 265 | ||
267 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ | 266 | /* Max length: 127 "OPT (" 15*4*2chars ") " */ |
268 | printk("OPT ("); | 267 | sb_add(m, "OPT ("); |
269 | for (i =0; i < optsize; i++) | 268 | for (i =0; i < optsize; i++) |
270 | printk("%02X", op[i]); | 269 | sb_add(m, "%02X", op[i]); |
271 | printk(") "); | 270 | sb_add(m, ") "); |
272 | } | 271 | } |
273 | break; | 272 | break; |
274 | } | 273 | } |
@@ -279,9 +278,9 @@ static void dump_packet(const struct nf_loginfo *info, | |||
279 | 278 | ||
280 | if (currenthdr == IPPROTO_UDP) | 279 | if (currenthdr == IPPROTO_UDP) |
281 | /* Max length: 10 "PROTO=UDP " */ | 280 | /* Max length: 10 "PROTO=UDP " */ |
282 | printk("PROTO=UDP " ); | 281 | sb_add(m, "PROTO=UDP " ); |
283 | else /* Max length: 14 "PROTO=UDPLITE " */ | 282 | else /* Max length: 14 "PROTO=UDPLITE " */ |
284 | printk("PROTO=UDPLITE "); | 283 | sb_add(m, "PROTO=UDPLITE "); |
285 | 284 | ||
286 | if (fragment) | 285 | if (fragment) |
287 | break; | 286 | break; |
@@ -289,12 +288,12 @@ static void dump_packet(const struct nf_loginfo *info, | |||
289 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | 288 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ |
290 | uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); | 289 | uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph); |
291 | if (uh == NULL) { | 290 | if (uh == NULL) { |
292 | printk("INCOMPLETE [%u bytes] ", skb->len - ptr); | 291 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); |
293 | return; | 292 | return; |
294 | } | 293 | } |
295 | 294 | ||
296 | /* Max length: 20 "SPT=65535 DPT=65535 " */ | 295 | /* Max length: 20 "SPT=65535 DPT=65535 " */ |
297 | printk("SPT=%u DPT=%u LEN=%u ", | 296 | sb_add(m, "SPT=%u DPT=%u LEN=%u ", |
298 | ntohs(uh->source), ntohs(uh->dest), | 297 | ntohs(uh->source), ntohs(uh->dest), |
299 | ntohs(uh->len)); | 298 | ntohs(uh->len)); |
300 | break; | 299 | break; |
@@ -304,7 +303,7 @@ static void dump_packet(const struct nf_loginfo *info, | |||
304 | const struct icmp6hdr *ic; | 303 | const struct icmp6hdr *ic; |
305 | 304 | ||
306 | /* Max length: 13 "PROTO=ICMPv6 " */ | 305 | /* Max length: 13 "PROTO=ICMPv6 " */ |
307 | printk("PROTO=ICMPv6 "); | 306 | sb_add(m, "PROTO=ICMPv6 "); |
308 | 307 | ||
309 | if (fragment) | 308 | if (fragment) |
310 | break; | 309 | break; |
@@ -312,18 +311,18 @@ static void dump_packet(const struct nf_loginfo *info, | |||
312 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ | 311 | /* Max length: 25 "INCOMPLETE [65535 bytes] " */ |
313 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); | 312 | ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h); |
314 | if (ic == NULL) { | 313 | if (ic == NULL) { |
315 | printk("INCOMPLETE [%u bytes] ", skb->len - ptr); | 314 | sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr); |
316 | return; | 315 | return; |
317 | } | 316 | } |
318 | 317 | ||
319 | /* Max length: 18 "TYPE=255 CODE=255 " */ | 318 | /* Max length: 18 "TYPE=255 CODE=255 " */ |
320 | printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); | 319 | sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code); |
321 | 320 | ||
322 | switch (ic->icmp6_type) { | 321 | switch (ic->icmp6_type) { |
323 | case ICMPV6_ECHO_REQUEST: | 322 | case ICMPV6_ECHO_REQUEST: |
324 | case ICMPV6_ECHO_REPLY: | 323 | case ICMPV6_ECHO_REPLY: |
325 | /* Max length: 19 "ID=65535 SEQ=65535 " */ | 324 | /* Max length: 19 "ID=65535 SEQ=65535 " */ |
326 | printk("ID=%u SEQ=%u ", | 325 | sb_add(m, "ID=%u SEQ=%u ", |
327 | ntohs(ic->icmp6_identifier), | 326 | ntohs(ic->icmp6_identifier), |
328 | ntohs(ic->icmp6_sequence)); | 327 | ntohs(ic->icmp6_sequence)); |
329 | break; | 328 | break; |
@@ -334,35 +333,35 @@ static void dump_packet(const struct nf_loginfo *info, | |||
334 | 333 | ||
335 | case ICMPV6_PARAMPROB: | 334 | case ICMPV6_PARAMPROB: |
336 | /* Max length: 17 "POINTER=ffffffff " */ | 335 | /* Max length: 17 "POINTER=ffffffff " */ |
337 | printk("POINTER=%08x ", ntohl(ic->icmp6_pointer)); | 336 | sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer)); |
338 | /* Fall through */ | 337 | /* Fall through */ |
339 | case ICMPV6_DEST_UNREACH: | 338 | case ICMPV6_DEST_UNREACH: |
340 | case ICMPV6_PKT_TOOBIG: | 339 | case ICMPV6_PKT_TOOBIG: |
341 | case ICMPV6_TIME_EXCEED: | 340 | case ICMPV6_TIME_EXCEED: |
342 | /* Max length: 3+maxlen */ | 341 | /* Max length: 3+maxlen */ |
343 | if (recurse) { | 342 | if (recurse) { |
344 | printk("["); | 343 | sb_add(m, "["); |
345 | dump_packet(info, skb, ptr + sizeof(_icmp6h), | 344 | dump_packet(m, info, skb, |
346 | 0); | 345 | ptr + sizeof(_icmp6h), 0); |
347 | printk("] "); | 346 | sb_add(m, "] "); |
348 | } | 347 | } |
349 | 348 | ||
350 | /* Max length: 10 "MTU=65535 " */ | 349 | /* Max length: 10 "MTU=65535 " */ |
351 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) | 350 | if (ic->icmp6_type == ICMPV6_PKT_TOOBIG) |
352 | printk("MTU=%u ", ntohl(ic->icmp6_mtu)); | 351 | sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu)); |
353 | } | 352 | } |
354 | break; | 353 | break; |
355 | } | 354 | } |
356 | /* Max length: 10 "PROTO=255 " */ | 355 | /* Max length: 10 "PROTO=255 " */ |
357 | default: | 356 | default: |
358 | printk("PROTO=%u ", currenthdr); | 357 | sb_add(m, "PROTO=%u ", currenthdr); |
359 | } | 358 | } |
360 | 359 | ||
361 | /* Max length: 15 "UID=4294967295 " */ | 360 | /* Max length: 15 "UID=4294967295 " */ |
362 | if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { | 361 | if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { |
363 | read_lock_bh(&skb->sk->sk_callback_lock); | 362 | read_lock_bh(&skb->sk->sk_callback_lock); |
364 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) | 363 | if (skb->sk->sk_socket && skb->sk->sk_socket->file) |
365 | printk("UID=%u GID=%u ", | 364 | sb_add(m, "UID=%u GID=%u ", |
366 | skb->sk->sk_socket->file->f_cred->fsuid, | 365 | skb->sk->sk_socket->file->f_cred->fsuid, |
367 | skb->sk->sk_socket->file->f_cred->fsgid); | 366 | skb->sk->sk_socket->file->f_cred->fsgid); |
368 | read_unlock_bh(&skb->sk->sk_callback_lock); | 367 | read_unlock_bh(&skb->sk->sk_callback_lock); |
@@ -370,10 +369,11 @@ static void dump_packet(const struct nf_loginfo *info, | |||
370 | 369 | ||
371 | /* Max length: 16 "MARK=0xFFFFFFFF " */ | 370 | /* Max length: 16 "MARK=0xFFFFFFFF " */ |
372 | if (!recurse && skb->mark) | 371 | if (!recurse && skb->mark) |
373 | printk("MARK=0x%x ", skb->mark); | 372 | sb_add(m, "MARK=0x%x ", skb->mark); |
374 | } | 373 | } |
375 | 374 | ||
376 | static void dump_mac_header(const struct nf_loginfo *info, | 375 | static void dump_mac_header(struct sbuff *m, |
376 | const struct nf_loginfo *info, | ||
377 | const struct sk_buff *skb) | 377 | const struct sk_buff *skb) |
378 | { | 378 | { |
379 | struct net_device *dev = skb->dev; | 379 | struct net_device *dev = skb->dev; |
@@ -387,7 +387,7 @@ static void dump_mac_header(const struct nf_loginfo *info, | |||
387 | 387 | ||
388 | switch (dev->type) { | 388 | switch (dev->type) { |
389 | case ARPHRD_ETHER: | 389 | case ARPHRD_ETHER: |
390 | printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ", | 390 | sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ", |
391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, | 391 | eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest, |
392 | ntohs(eth_hdr(skb)->h_proto)); | 392 | ntohs(eth_hdr(skb)->h_proto)); |
393 | return; | 393 | return; |
@@ -396,7 +396,7 @@ static void dump_mac_header(const struct nf_loginfo *info, | |||
396 | } | 396 | } |
397 | 397 | ||
398 | fallback: | 398 | fallback: |
399 | printk("MAC="); | 399 | sb_add(m, "MAC="); |
400 | if (dev->hard_header_len && | 400 | if (dev->hard_header_len && |
401 | skb->mac_header != skb->network_header) { | 401 | skb->mac_header != skb->network_header) { |
402 | const unsigned char *p = skb_mac_header(skb); | 402 | const unsigned char *p = skb_mac_header(skb); |
@@ -408,19 +408,19 @@ fallback: | |||
408 | p = NULL; | 408 | p = NULL; |
409 | 409 | ||
410 | if (p != NULL) { | 410 | if (p != NULL) { |
411 | printk("%02x", *p++); | 411 | sb_add(m, "%02x", *p++); |
412 | for (i = 1; i < len; i++) | 412 | for (i = 1; i < len; i++) |
413 | printk(":%02x", p[i]); | 413 | sb_add(m, ":%02x", p[i]); |
414 | } | 414 | } |
415 | printk(" "); | 415 | sb_add(m, " "); |
416 | 416 | ||
417 | if (dev->type == ARPHRD_SIT) { | 417 | if (dev->type == ARPHRD_SIT) { |
418 | const struct iphdr *iph = | 418 | const struct iphdr *iph = |
419 | (struct iphdr *)skb_mac_header(skb); | 419 | (struct iphdr *)skb_mac_header(skb); |
420 | printk("TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); | 420 | sb_add(m, "TUNNEL=%pI4->%pI4 ", &iph->saddr, &iph->daddr); |
421 | } | 421 | } |
422 | } else | 422 | } else |
423 | printk(" "); | 423 | sb_add(m, " "); |
424 | } | 424 | } |
425 | 425 | ||
426 | static struct nf_loginfo default_loginfo = { | 426 | static struct nf_loginfo default_loginfo = { |
@@ -442,22 +442,23 @@ ip6t_log_packet(u_int8_t pf, | |||
442 | const struct nf_loginfo *loginfo, | 442 | const struct nf_loginfo *loginfo, |
443 | const char *prefix) | 443 | const char *prefix) |
444 | { | 444 | { |
445 | struct sbuff *m = sb_open(); | ||
446 | |||
445 | if (!loginfo) | 447 | if (!loginfo) |
446 | loginfo = &default_loginfo; | 448 | loginfo = &default_loginfo; |
447 | 449 | ||
448 | spin_lock_bh(&log_lock); | 450 | sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, |
449 | printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level, | 451 | prefix, |
450 | prefix, | 452 | in ? in->name : "", |
451 | in ? in->name : "", | 453 | out ? out->name : ""); |
452 | out ? out->name : ""); | ||
453 | 454 | ||
454 | /* MAC logging for input path only. */ | 455 | /* MAC logging for input path only. */ |
455 | if (in && !out) | 456 | if (in && !out) |
456 | dump_mac_header(loginfo, skb); | 457 | dump_mac_header(m, loginfo, skb); |
458 | |||
459 | dump_packet(m, loginfo, skb, skb_network_offset(skb), 1); | ||
457 | 460 | ||
458 | dump_packet(loginfo, skb, skb_network_offset(skb), 1); | 461 | sb_close(m); |
459 | printk("\n"); | ||
460 | spin_unlock_bh(&log_lock); | ||
461 | } | 462 | } |
462 | 463 | ||
463 | static unsigned int | 464 | static unsigned int |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index ff43461704be..c8af58b22562 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
18 | #include <linux/icmp.h> | 18 | #include <linux/icmp.h> |
19 | #include <linux/sysctl.h> | ||
20 | #include <net/ipv6.h> | 19 | #include <net/ipv6.h> |
21 | #include <net/inet_frag.h> | 20 | #include <net/inet_frag.h> |
22 | 21 | ||
@@ -29,6 +28,7 @@ | |||
29 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
30 | #include <net/netfilter/nf_conntrack_zones.h> | 29 | #include <net/netfilter/nf_conntrack_zones.h> |
31 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 30 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
31 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
32 | #include <net/netfilter/nf_log.h> | 32 | #include <net/netfilter/nf_log.h> |
33 | 33 | ||
34 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, | 34 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, |
@@ -189,53 +189,6 @@ out: | |||
189 | return nf_conntrack_confirm(skb); | 189 | return nf_conntrack_confirm(skb); |
190 | } | 190 | } |
191 | 191 | ||
192 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | ||
193 | struct sk_buff *skb) | ||
194 | { | ||
195 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
196 | |||
197 | if (skb->nfct) | ||
198 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
199 | |||
200 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
201 | if (skb->nf_bridge && | ||
202 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | ||
203 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | ||
204 | #endif | ||
205 | if (hooknum == NF_INET_PRE_ROUTING) | ||
206 | return IP6_DEFRAG_CONNTRACK_IN + zone; | ||
207 | else | ||
208 | return IP6_DEFRAG_CONNTRACK_OUT + zone; | ||
209 | |||
210 | } | ||
211 | |||
212 | static unsigned int ipv6_defrag(unsigned int hooknum, | ||
213 | struct sk_buff *skb, | ||
214 | const struct net_device *in, | ||
215 | const struct net_device *out, | ||
216 | int (*okfn)(struct sk_buff *)) | ||
217 | { | ||
218 | struct sk_buff *reasm; | ||
219 | |||
220 | /* Previously seen (loopback)? */ | ||
221 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) | ||
222 | return NF_ACCEPT; | ||
223 | |||
224 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | ||
225 | /* queued */ | ||
226 | if (reasm == NULL) | ||
227 | return NF_STOLEN; | ||
228 | |||
229 | /* error occured or not fragmented */ | ||
230 | if (reasm == skb) | ||
231 | return NF_ACCEPT; | ||
232 | |||
233 | nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, | ||
234 | (struct net_device *)out, okfn); | ||
235 | |||
236 | return NF_STOLEN; | ||
237 | } | ||
238 | |||
239 | static unsigned int __ipv6_conntrack_in(struct net *net, | 192 | static unsigned int __ipv6_conntrack_in(struct net *net, |
240 | unsigned int hooknum, | 193 | unsigned int hooknum, |
241 | struct sk_buff *skb, | 194 | struct sk_buff *skb, |
@@ -288,13 +241,6 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, | |||
288 | 241 | ||
289 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | 242 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { |
290 | { | 243 | { |
291 | .hook = ipv6_defrag, | ||
292 | .owner = THIS_MODULE, | ||
293 | .pf = NFPROTO_IPV6, | ||
294 | .hooknum = NF_INET_PRE_ROUTING, | ||
295 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
296 | }, | ||
297 | { | ||
298 | .hook = ipv6_conntrack_in, | 244 | .hook = ipv6_conntrack_in, |
299 | .owner = THIS_MODULE, | 245 | .owner = THIS_MODULE, |
300 | .pf = NFPROTO_IPV6, | 246 | .pf = NFPROTO_IPV6, |
@@ -309,13 +255,6 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | |||
309 | .priority = NF_IP6_PRI_CONNTRACK, | 255 | .priority = NF_IP6_PRI_CONNTRACK, |
310 | }, | 256 | }, |
311 | { | 257 | { |
312 | .hook = ipv6_defrag, | ||
313 | .owner = THIS_MODULE, | ||
314 | .pf = NFPROTO_IPV6, | ||
315 | .hooknum = NF_INET_LOCAL_OUT, | ||
316 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
317 | }, | ||
318 | { | ||
319 | .hook = ipv6_confirm, | 258 | .hook = ipv6_confirm, |
320 | .owner = THIS_MODULE, | 259 | .owner = THIS_MODULE, |
321 | .pf = NFPROTO_IPV6, | 260 | .pf = NFPROTO_IPV6, |
@@ -387,10 +326,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | |||
387 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, | 326 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, |
388 | .nla_policy = ipv6_nla_policy, | 327 | .nla_policy = ipv6_nla_policy, |
389 | #endif | 328 | #endif |
390 | #ifdef CONFIG_SYSCTL | ||
391 | .ctl_table_path = nf_net_netfilter_sysctl_path, | ||
392 | .ctl_table = nf_ct_ipv6_sysctl_table, | ||
393 | #endif | ||
394 | .me = THIS_MODULE, | 329 | .me = THIS_MODULE, |
395 | }; | 330 | }; |
396 | 331 | ||
@@ -403,16 +338,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
403 | int ret = 0; | 338 | int ret = 0; |
404 | 339 | ||
405 | need_conntrack(); | 340 | need_conntrack(); |
341 | nf_defrag_ipv6_enable(); | ||
406 | 342 | ||
407 | ret = nf_ct_frag6_init(); | ||
408 | if (ret < 0) { | ||
409 | pr_err("nf_conntrack_ipv6: can't initialize frag6.\n"); | ||
410 | return ret; | ||
411 | } | ||
412 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); | 343 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6); |
413 | if (ret < 0) { | 344 | if (ret < 0) { |
414 | pr_err("nf_conntrack_ipv6: can't register tcp.\n"); | 345 | pr_err("nf_conntrack_ipv6: can't register tcp.\n"); |
415 | goto cleanup_frag6; | 346 | return ret; |
416 | } | 347 | } |
417 | 348 | ||
418 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); | 349 | ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6); |
@@ -450,8 +381,6 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
450 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); | 381 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); |
451 | cleanup_tcp: | 382 | cleanup_tcp: |
452 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | 383 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); |
453 | cleanup_frag6: | ||
454 | nf_ct_frag6_cleanup(); | ||
455 | return ret; | 384 | return ret; |
456 | } | 385 | } |
457 | 386 | ||
@@ -463,7 +392,6 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void) | |||
463 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); | 392 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); |
464 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); | 393 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6); |
465 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | 394 | nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6); |
466 | nf_ct_frag6_cleanup(); | ||
467 | } | 395 | } |
468 | 396 | ||
469 | module_init(nf_conntrack_l3proto_ipv6_init); | 397 | module_init(nf_conntrack_l3proto_ipv6_init); |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 578f3c1a16db..79d43aa8fa8d 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -73,7 +73,7 @@ static struct inet_frags nf_frags; | |||
73 | static struct netns_frags nf_init_frags; | 73 | static struct netns_frags nf_init_frags; |
74 | 74 | ||
75 | #ifdef CONFIG_SYSCTL | 75 | #ifdef CONFIG_SYSCTL |
76 | struct ctl_table nf_ct_ipv6_sysctl_table[] = { | 76 | struct ctl_table nf_ct_frag6_sysctl_table[] = { |
77 | { | 77 | { |
78 | .procname = "nf_conntrack_frag6_timeout", | 78 | .procname = "nf_conntrack_frag6_timeout", |
79 | .data = &nf_init_frags.timeout, | 79 | .data = &nf_init_frags.timeout, |
@@ -97,6 +97,8 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { | |||
97 | }, | 97 | }, |
98 | { } | 98 | { } |
99 | }; | 99 | }; |
100 | |||
101 | static struct ctl_table_header *nf_ct_frag6_sysctl_header; | ||
100 | #endif | 102 | #endif |
101 | 103 | ||
102 | static unsigned int nf_hashfn(struct inet_frag_queue *q) | 104 | static unsigned int nf_hashfn(struct inet_frag_queue *q) |
@@ -284,7 +286,7 @@ found: | |||
284 | 286 | ||
285 | /* Check for overlap with preceding fragment. */ | 287 | /* Check for overlap with preceding fragment. */ |
286 | if (prev && | 288 | if (prev && |
287 | (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0) | 289 | (NFCT_FRAG6_CB(prev)->offset + prev->len) > offset) |
288 | goto discard_fq; | 290 | goto discard_fq; |
289 | 291 | ||
290 | /* Look for overlap with succeeding segment. */ | 292 | /* Look for overlap with succeeding segment. */ |
@@ -363,7 +365,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
363 | /* If the first fragment is fragmented itself, we split | 365 | /* If the first fragment is fragmented itself, we split |
364 | * it to two chunks: the first with data and paged part | 366 | * it to two chunks: the first with data and paged part |
365 | * and the second, holding only fragments. */ | 367 | * and the second, holding only fragments. */ |
366 | if (skb_has_frags(head)) { | 368 | if (skb_has_frag_list(head)) { |
367 | struct sk_buff *clone; | 369 | struct sk_buff *clone; |
368 | int i, plen = 0; | 370 | int i, plen = 0; |
369 | 371 | ||
@@ -623,11 +625,24 @@ int nf_ct_frag6_init(void) | |||
623 | inet_frags_init_net(&nf_init_frags); | 625 | inet_frags_init_net(&nf_init_frags); |
624 | inet_frags_init(&nf_frags); | 626 | inet_frags_init(&nf_frags); |
625 | 627 | ||
628 | #ifdef CONFIG_SYSCTL | ||
629 | nf_ct_frag6_sysctl_header = register_sysctl_paths(nf_net_netfilter_sysctl_path, | ||
630 | nf_ct_frag6_sysctl_table); | ||
631 | if (!nf_ct_frag6_sysctl_header) { | ||
632 | inet_frags_fini(&nf_frags); | ||
633 | return -ENOMEM; | ||
634 | } | ||
635 | #endif | ||
636 | |||
626 | return 0; | 637 | return 0; |
627 | } | 638 | } |
628 | 639 | ||
629 | void nf_ct_frag6_cleanup(void) | 640 | void nf_ct_frag6_cleanup(void) |
630 | { | 641 | { |
642 | #ifdef CONFIG_SYSCTL | ||
643 | unregister_sysctl_table(nf_ct_frag6_sysctl_header); | ||
644 | nf_ct_frag6_sysctl_header = NULL; | ||
645 | #endif | ||
631 | inet_frags_fini(&nf_frags); | 646 | inet_frags_fini(&nf_frags); |
632 | 647 | ||
633 | nf_init_frags.low_thresh = 0; | 648 | nf_init_frags.low_thresh = 0; |
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c new file mode 100644 index 000000000000..99abfb53bab9 --- /dev/null +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/ipv6.h> | ||
11 | #include <linux/in6.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/icmp.h> | ||
16 | #include <linux/sysctl.h> | ||
17 | #include <net/ipv6.h> | ||
18 | #include <net/inet_frag.h> | ||
19 | |||
20 | #include <linux/netfilter_ipv6.h> | ||
21 | #include <linux/netfilter_bridge.h> | ||
22 | #include <net/netfilter/nf_conntrack.h> | ||
23 | #include <net/netfilter/nf_conntrack_helper.h> | ||
24 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
25 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
26 | #include <net/netfilter/nf_conntrack_core.h> | ||
27 | #include <net/netfilter/nf_conntrack_zones.h> | ||
28 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | ||
29 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> | ||
30 | |||
31 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | ||
32 | struct sk_buff *skb) | ||
33 | { | ||
34 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
35 | |||
36 | if (skb->nfct) | ||
37 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
38 | |||
39 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
40 | if (skb->nf_bridge && | ||
41 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | ||
42 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | ||
43 | #endif | ||
44 | if (hooknum == NF_INET_PRE_ROUTING) | ||
45 | return IP6_DEFRAG_CONNTRACK_IN + zone; | ||
46 | else | ||
47 | return IP6_DEFRAG_CONNTRACK_OUT + zone; | ||
48 | |||
49 | } | ||
50 | |||
51 | static unsigned int ipv6_defrag(unsigned int hooknum, | ||
52 | struct sk_buff *skb, | ||
53 | const struct net_device *in, | ||
54 | const struct net_device *out, | ||
55 | int (*okfn)(struct sk_buff *)) | ||
56 | { | ||
57 | struct sk_buff *reasm; | ||
58 | |||
59 | /* Previously seen (loopback)? */ | ||
60 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) | ||
61 | return NF_ACCEPT; | ||
62 | |||
63 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | ||
64 | /* queued */ | ||
65 | if (reasm == NULL) | ||
66 | return NF_STOLEN; | ||
67 | |||
68 | /* error occured or not fragmented */ | ||
69 | if (reasm == skb) | ||
70 | return NF_ACCEPT; | ||
71 | |||
72 | nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, | ||
73 | (struct net_device *)out, okfn); | ||
74 | |||
75 | return NF_STOLEN; | ||
76 | } | ||
77 | |||
78 | static struct nf_hook_ops ipv6_defrag_ops[] = { | ||
79 | { | ||
80 | .hook = ipv6_defrag, | ||
81 | .owner = THIS_MODULE, | ||
82 | .pf = NFPROTO_IPV6, | ||
83 | .hooknum = NF_INET_PRE_ROUTING, | ||
84 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
85 | }, | ||
86 | { | ||
87 | .hook = ipv6_defrag, | ||
88 | .owner = THIS_MODULE, | ||
89 | .pf = NFPROTO_IPV6, | ||
90 | .hooknum = NF_INET_LOCAL_OUT, | ||
91 | .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, | ||
92 | }, | ||
93 | }; | ||
94 | |||
95 | static int __init nf_defrag_init(void) | ||
96 | { | ||
97 | int ret = 0; | ||
98 | |||
99 | ret = nf_ct_frag6_init(); | ||
100 | if (ret < 0) { | ||
101 | pr_err("nf_defrag_ipv6: can't initialize frag6.\n"); | ||
102 | return ret; | ||
103 | } | ||
104 | ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); | ||
105 | if (ret < 0) { | ||
106 | pr_err("nf_defrag_ipv6: can't register hooks\n"); | ||
107 | goto cleanup_frag6; | ||
108 | } | ||
109 | return ret; | ||
110 | |||
111 | cleanup_frag6: | ||
112 | nf_ct_frag6_cleanup(); | ||
113 | return ret; | ||
114 | |||
115 | } | ||
116 | |||
117 | static void __exit nf_defrag_fini(void) | ||
118 | { | ||
119 | nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops)); | ||
120 | nf_ct_frag6_cleanup(); | ||
121 | } | ||
122 | |||
123 | void nf_defrag_ipv6_enable(void) | ||
124 | { | ||
125 | } | ||
126 | EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); | ||
127 | |||
128 | module_init(nf_defrag_init); | ||
129 | module_exit(nf_defrag_fini); | ||
130 | |||
131 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index d082eaeefa25..24b3558b8e67 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -126,6 +126,8 @@ static const struct snmp_mib snmp6_udp6_list[] = { | |||
126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), | 126 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), |
127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), | 127 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), |
128 | SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 128 | SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
129 | SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
130 | SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
129 | SNMP_MIB_SENTINEL | 131 | SNMP_MIB_SENTINEL |
130 | }; | 132 | }; |
131 | 133 | ||
@@ -134,6 +136,8 @@ static const struct snmp_mib snmp6_udplite6_list[] = { | |||
134 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), | 136 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), |
135 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), | 137 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), |
136 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), | 138 | SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), |
139 | SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS), | ||
140 | SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS), | ||
137 | SNMP_MIB_SENTINEL | 141 | SNMP_MIB_SENTINEL |
138 | }; | 142 | }; |
139 | 143 | ||
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 1fa3468f0f32..9a7978fdc02a 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
@@ -25,28 +25,15 @@ | |||
25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
26 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
27 | 27 | ||
28 | const struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; | 28 | const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; |
29 | static DEFINE_SPINLOCK(inet6_proto_lock); | ||
30 | |||
31 | 29 | ||
32 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) | 30 | int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) |
33 | { | 31 | { |
34 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 32 | int hash = protocol & (MAX_INET_PROTOS - 1); |
35 | |||
36 | spin_lock_bh(&inet6_proto_lock); | ||
37 | |||
38 | if (inet6_protos[hash]) { | ||
39 | ret = -1; | ||
40 | } else { | ||
41 | inet6_protos[hash] = prot; | ||
42 | ret = 0; | ||
43 | } | ||
44 | |||
45 | spin_unlock_bh(&inet6_proto_lock); | ||
46 | 33 | ||
47 | return ret; | 34 | return !cmpxchg((const struct inet6_protocol **)&inet6_protos[hash], |
35 | NULL, prot) ? 0 : -1; | ||
48 | } | 36 | } |
49 | |||
50 | EXPORT_SYMBOL(inet6_add_protocol); | 37 | EXPORT_SYMBOL(inet6_add_protocol); |
51 | 38 | ||
52 | /* | 39 | /* |
@@ -57,20 +44,11 @@ int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol | |||
57 | { | 44 | { |
58 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); | 45 | int ret, hash = protocol & (MAX_INET_PROTOS - 1); |
59 | 46 | ||
60 | spin_lock_bh(&inet6_proto_lock); | 47 | ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[hash], |
61 | 48 | prot, NULL) == prot) ? 0 : -1; | |
62 | if (inet6_protos[hash] != prot) { | ||
63 | ret = -1; | ||
64 | } else { | ||
65 | inet6_protos[hash] = NULL; | ||
66 | ret = 0; | ||
67 | } | ||
68 | |||
69 | spin_unlock_bh(&inet6_proto_lock); | ||
70 | 49 | ||
71 | synchronize_net(); | 50 | synchronize_net(); |
72 | 51 | ||
73 | return ret; | 52 | return ret; |
74 | } | 53 | } |
75 | |||
76 | EXPORT_SYMBOL(inet6_del_protocol); | 54 | EXPORT_SYMBOL(inet6_del_protocol); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index e677937a07fc..86c39526ba5e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -373,7 +373,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, | |||
373 | 373 | ||
374 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | 374 | static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) |
375 | { | 375 | { |
376 | if ((raw6_sk(sk)->checksum || sk->sk_filter) && | 376 | if ((raw6_sk(sk)->checksum || rcu_dereference_raw(sk->sk_filter)) && |
377 | skb_checksum_complete(skb)) { | 377 | skb_checksum_complete(skb)) { |
378 | atomic_inc(&sk->sk_drops); | 378 | atomic_inc(&sk->sk_drops); |
379 | kfree_skb(skb); | 379 | kfree_skb(skb); |
@@ -764,7 +764,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
764 | return -EINVAL; | 764 | return -EINVAL; |
765 | 765 | ||
766 | if (sin6->sin6_family && sin6->sin6_family != AF_INET6) | 766 | if (sin6->sin6_family && sin6->sin6_family != AF_INET6) |
767 | return(-EAFNOSUPPORT); | 767 | return -EAFNOSUPPORT; |
768 | 768 | ||
769 | /* port is the proto value [0..255] carried in nexthdr */ | 769 | /* port is the proto value [0..255] carried in nexthdr */ |
770 | proto = ntohs(sin6->sin6_port); | 770 | proto = ntohs(sin6->sin6_port); |
@@ -772,10 +772,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
772 | if (!proto) | 772 | if (!proto) |
773 | proto = inet->inet_num; | 773 | proto = inet->inet_num; |
774 | else if (proto != inet->inet_num) | 774 | else if (proto != inet->inet_num) |
775 | return(-EINVAL); | 775 | return -EINVAL; |
776 | 776 | ||
777 | if (proto > 255) | 777 | if (proto > 255) |
778 | return(-EINVAL); | 778 | return -EINVAL; |
779 | 779 | ||
780 | daddr = &sin6->sin6_addr; | 780 | daddr = &sin6->sin6_addr; |
781 | if (np->sndflow) { | 781 | if (np->sndflow) { |
@@ -985,7 +985,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
985 | /* You may get strange result with a positive odd offset; | 985 | /* You may get strange result with a positive odd offset; |
986 | RFC2292bis agrees with me. */ | 986 | RFC2292bis agrees with me. */ |
987 | if (val > 0 && (val&1)) | 987 | if (val > 0 && (val&1)) |
988 | return(-EINVAL); | 988 | return -EINVAL; |
989 | if (val < 0) { | 989 | if (val < 0) { |
990 | rp->checksum = 0; | 990 | rp->checksum = 0; |
991 | } else { | 991 | } else { |
@@ -997,7 +997,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
997 | break; | 997 | break; |
998 | 998 | ||
999 | default: | 999 | default: |
1000 | return(-ENOPROTOOPT); | 1000 | return -ENOPROTOOPT; |
1001 | } | 1001 | } |
1002 | } | 1002 | } |
1003 | 1003 | ||
@@ -1190,7 +1190,7 @@ static int rawv6_init_sk(struct sock *sk) | |||
1190 | default: | 1190 | default: |
1191 | break; | 1191 | break; |
1192 | } | 1192 | } |
1193 | return(0); | 1193 | return 0; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | struct proto rawv6_prot = { | 1196 | struct proto rawv6_prot = { |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 64cfef1b0a4c..0f2766453759 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -349,7 +349,7 @@ found: | |||
349 | 349 | ||
350 | /* Check for overlap with preceding fragment. */ | 350 | /* Check for overlap with preceding fragment. */ |
351 | if (prev && | 351 | if (prev && |
352 | (FRAG6_CB(prev)->offset + prev->len) - offset > 0) | 352 | (FRAG6_CB(prev)->offset + prev->len) > offset) |
353 | goto discard_fq; | 353 | goto discard_fq; |
354 | 354 | ||
355 | /* Look for overlap with succeeding segment. */ | 355 | /* Look for overlap with succeeding segment. */ |
@@ -458,7 +458,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
458 | /* If the first fragment is fragmented itself, we split | 458 | /* If the first fragment is fragmented itself, we split |
459 | * it to two chunks: the first with data and paged part | 459 | * it to two chunks: the first with data and paged part |
460 | * and the second, holding only fragments. */ | 460 | * and the second, holding only fragments. */ |
461 | if (skb_has_frags(head)) { | 461 | if (skb_has_frag_list(head)) { |
462 | struct sk_buff *clone; | 462 | struct sk_buff *clone; |
463 | int i, plen = 0; | 463 | int i, plen = 0; |
464 | 464 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a275c6e1e25c..96455ffb76fb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -109,7 +109,6 @@ static struct dst_ops ip6_dst_ops_template = { | |||
109 | .link_failure = ip6_link_failure, | 109 | .link_failure = ip6_link_failure, |
110 | .update_pmtu = ip6_rt_update_pmtu, | 110 | .update_pmtu = ip6_rt_update_pmtu, |
111 | .local_out = __ip6_local_out, | 111 | .local_out = __ip6_local_out, |
112 | .entries = ATOMIC_INIT(0), | ||
113 | }; | 112 | }; |
114 | 113 | ||
115 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | 114 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -122,7 +121,6 @@ static struct dst_ops ip6_dst_blackhole_ops = { | |||
122 | .destroy = ip6_dst_destroy, | 121 | .destroy = ip6_dst_destroy, |
123 | .check = ip6_dst_check, | 122 | .check = ip6_dst_check, |
124 | .update_pmtu = ip6_rt_blackhole_update_pmtu, | 123 | .update_pmtu = ip6_rt_blackhole_update_pmtu, |
125 | .entries = ATOMIC_INIT(0), | ||
126 | }; | 124 | }; |
127 | 125 | ||
128 | static struct rt6_info ip6_null_entry_template = { | 126 | static struct rt6_info ip6_null_entry_template = { |
@@ -217,14 +215,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | |||
217 | 215 | ||
218 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) | 216 | static __inline__ int rt6_check_expired(const struct rt6_info *rt) |
219 | { | 217 | { |
220 | return (rt->rt6i_flags & RTF_EXPIRES && | 218 | return (rt->rt6i_flags & RTF_EXPIRES) && |
221 | time_after(jiffies, rt->rt6i_expires)); | 219 | time_after(jiffies, rt->rt6i_expires); |
222 | } | 220 | } |
223 | 221 | ||
224 | static inline int rt6_need_strict(struct in6_addr *daddr) | 222 | static inline int rt6_need_strict(struct in6_addr *daddr) |
225 | { | 223 | { |
226 | return (ipv6_addr_type(daddr) & | 224 | return ipv6_addr_type(daddr) & |
227 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK)); | 225 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); |
228 | } | 226 | } |
229 | 227 | ||
230 | /* | 228 | /* |
@@ -440,7 +438,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) | |||
440 | __func__, match); | 438 | __func__, match); |
441 | 439 | ||
442 | net = dev_net(rt0->rt6i_dev); | 440 | net = dev_net(rt0->rt6i_dev); |
443 | return (match ? match : net->ipv6.ip6_null_entry); | 441 | return match ? match : net->ipv6.ip6_null_entry; |
444 | } | 442 | } |
445 | 443 | ||
446 | #ifdef CONFIG_IPV6_ROUTE_INFO | 444 | #ifdef CONFIG_IPV6_ROUTE_INFO |
@@ -859,7 +857,7 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl | |||
859 | 857 | ||
860 | dst_release(*dstp); | 858 | dst_release(*dstp); |
861 | *dstp = new; | 859 | *dstp = new; |
862 | return (new ? 0 : -ENOMEM); | 860 | return new ? 0 : -ENOMEM; |
863 | } | 861 | } |
864 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | 862 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); |
865 | 863 | ||
@@ -1058,19 +1056,22 @@ static int ip6_dst_gc(struct dst_ops *ops) | |||
1058 | int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; | 1056 | int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; |
1059 | int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; | 1057 | int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; |
1060 | unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; | 1058 | unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; |
1059 | int entries; | ||
1061 | 1060 | ||
1061 | entries = dst_entries_get_fast(ops); | ||
1062 | if (time_after(rt_last_gc + rt_min_interval, now) && | 1062 | if (time_after(rt_last_gc + rt_min_interval, now) && |
1063 | atomic_read(&ops->entries) <= rt_max_size) | 1063 | entries <= rt_max_size) |
1064 | goto out; | 1064 | goto out; |
1065 | 1065 | ||
1066 | net->ipv6.ip6_rt_gc_expire++; | 1066 | net->ipv6.ip6_rt_gc_expire++; |
1067 | fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); | 1067 | fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); |
1068 | net->ipv6.ip6_rt_last_gc = now; | 1068 | net->ipv6.ip6_rt_last_gc = now; |
1069 | if (atomic_read(&ops->entries) < ops->gc_thresh) | 1069 | entries = dst_entries_get_slow(ops); |
1070 | if (entries < ops->gc_thresh) | ||
1070 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; | 1071 | net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; |
1071 | out: | 1072 | out: |
1072 | net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; | 1073 | net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; |
1073 | return (atomic_read(&ops->entries) > rt_max_size); | 1074 | return entries > rt_max_size; |
1074 | } | 1075 | } |
1075 | 1076 | ||
1076 | /* Clean host part of a prefix. Not necessary in radix tree, | 1077 | /* Clean host part of a prefix. Not necessary in radix tree, |
@@ -1169,6 +1170,8 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1169 | 1170 | ||
1170 | if (addr_type & IPV6_ADDR_MULTICAST) | 1171 | if (addr_type & IPV6_ADDR_MULTICAST) |
1171 | rt->dst.input = ip6_mc_input; | 1172 | rt->dst.input = ip6_mc_input; |
1173 | else if (cfg->fc_flags & RTF_LOCAL) | ||
1174 | rt->dst.input = ip6_input; | ||
1172 | else | 1175 | else |
1173 | rt->dst.input = ip6_forward; | 1176 | rt->dst.input = ip6_forward; |
1174 | 1177 | ||
@@ -1190,7 +1193,8 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1190 | they would result in kernel looping; promote them to reject routes | 1193 | they would result in kernel looping; promote them to reject routes |
1191 | */ | 1194 | */ |
1192 | if ((cfg->fc_flags & RTF_REJECT) || | 1195 | if ((cfg->fc_flags & RTF_REJECT) || |
1193 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { | 1196 | (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK) |
1197 | && !(cfg->fc_flags&RTF_LOCAL))) { | ||
1194 | /* hold loopback dev/idev if we haven't done so. */ | 1198 | /* hold loopback dev/idev if we haven't done so. */ |
1195 | if (dev != net->loopback_dev) { | 1199 | if (dev != net->loopback_dev) { |
1196 | if (dev) { | 1200 | if (dev) { |
@@ -1941,8 +1945,12 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1941 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); | 1945 | struct rt6_info *rt = ip6_dst_alloc(&net->ipv6.ip6_dst_ops); |
1942 | struct neighbour *neigh; | 1946 | struct neighbour *neigh; |
1943 | 1947 | ||
1944 | if (rt == NULL) | 1948 | if (rt == NULL) { |
1949 | if (net_ratelimit()) | ||
1950 | pr_warning("IPv6: Maximum number of routes reached," | ||
1951 | " consider increasing route/max_size.\n"); | ||
1945 | return ERR_PTR(-ENOMEM); | 1952 | return ERR_PTR(-ENOMEM); |
1953 | } | ||
1946 | 1954 | ||
1947 | dev_hold(net->loopback_dev); | 1955 | dev_hold(net->loopback_dev); |
1948 | in6_dev_hold(idev); | 1956 | in6_dev_hold(idev); |
@@ -2102,6 +2110,9 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
2102 | if (rtm->rtm_type == RTN_UNREACHABLE) | 2110 | if (rtm->rtm_type == RTN_UNREACHABLE) |
2103 | cfg->fc_flags |= RTF_REJECT; | 2111 | cfg->fc_flags |= RTF_REJECT; |
2104 | 2112 | ||
2113 | if (rtm->rtm_type == RTN_LOCAL) | ||
2114 | cfg->fc_flags |= RTF_LOCAL; | ||
2115 | |||
2105 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; | 2116 | cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; |
2106 | cfg->fc_nlinfo.nlh = nlh; | 2117 | cfg->fc_nlinfo.nlh = nlh; |
2107 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); | 2118 | cfg->fc_nlinfo.nl_net = sock_net(skb->sk); |
@@ -2222,6 +2233,8 @@ static int rt6_fill_node(struct net *net, | |||
2222 | NLA_PUT_U32(skb, RTA_TABLE, table); | 2233 | NLA_PUT_U32(skb, RTA_TABLE, table); |
2223 | if (rt->rt6i_flags&RTF_REJECT) | 2234 | if (rt->rt6i_flags&RTF_REJECT) |
2224 | rtm->rtm_type = RTN_UNREACHABLE; | 2235 | rtm->rtm_type = RTN_UNREACHABLE; |
2236 | else if (rt->rt6i_flags&RTF_LOCAL) | ||
2237 | rtm->rtm_type = RTN_LOCAL; | ||
2225 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) | 2238 | else if (rt->rt6i_dev && (rt->rt6i_dev->flags&IFF_LOOPBACK)) |
2226 | rtm->rtm_type = RTN_LOCAL; | 2239 | rtm->rtm_type = RTN_LOCAL; |
2227 | else | 2240 | else |
@@ -2516,7 +2529,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) | |||
2516 | net->ipv6.rt6_stats->fib_rt_alloc, | 2529 | net->ipv6.rt6_stats->fib_rt_alloc, |
2517 | net->ipv6.rt6_stats->fib_rt_entries, | 2530 | net->ipv6.rt6_stats->fib_rt_entries, |
2518 | net->ipv6.rt6_stats->fib_rt_cache, | 2531 | net->ipv6.rt6_stats->fib_rt_cache, |
2519 | atomic_read(&net->ipv6.ip6_dst_ops.entries), | 2532 | dst_entries_get_slow(&net->ipv6.ip6_dst_ops), |
2520 | net->ipv6.rt6_stats->fib_discarded_routes); | 2533 | net->ipv6.rt6_stats->fib_discarded_routes); |
2521 | 2534 | ||
2522 | return 0; | 2535 | return 0; |
@@ -2658,11 +2671,14 @@ static int __net_init ip6_route_net_init(struct net *net) | |||
2658 | memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, | 2671 | memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, |
2659 | sizeof(net->ipv6.ip6_dst_ops)); | 2672 | sizeof(net->ipv6.ip6_dst_ops)); |
2660 | 2673 | ||
2674 | if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) | ||
2675 | goto out_ip6_dst_ops; | ||
2676 | |||
2661 | net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, | 2677 | net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, |
2662 | sizeof(*net->ipv6.ip6_null_entry), | 2678 | sizeof(*net->ipv6.ip6_null_entry), |
2663 | GFP_KERNEL); | 2679 | GFP_KERNEL); |
2664 | if (!net->ipv6.ip6_null_entry) | 2680 | if (!net->ipv6.ip6_null_entry) |
2665 | goto out_ip6_dst_ops; | 2681 | goto out_ip6_dst_entries; |
2666 | net->ipv6.ip6_null_entry->dst.path = | 2682 | net->ipv6.ip6_null_entry->dst.path = |
2667 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2683 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
2668 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; | 2684 | net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; |
@@ -2712,6 +2728,8 @@ out_ip6_prohibit_entry: | |||
2712 | out_ip6_null_entry: | 2728 | out_ip6_null_entry: |
2713 | kfree(net->ipv6.ip6_null_entry); | 2729 | kfree(net->ipv6.ip6_null_entry); |
2714 | #endif | 2730 | #endif |
2731 | out_ip6_dst_entries: | ||
2732 | dst_entries_destroy(&net->ipv6.ip6_dst_ops); | ||
2715 | out_ip6_dst_ops: | 2733 | out_ip6_dst_ops: |
2716 | goto out; | 2734 | goto out; |
2717 | } | 2735 | } |
@@ -2727,6 +2745,7 @@ static void __net_exit ip6_route_net_exit(struct net *net) | |||
2727 | kfree(net->ipv6.ip6_prohibit_entry); | 2745 | kfree(net->ipv6.ip6_prohibit_entry); |
2728 | kfree(net->ipv6.ip6_blk_hole_entry); | 2746 | kfree(net->ipv6.ip6_blk_hole_entry); |
2729 | #endif | 2747 | #endif |
2748 | dst_entries_destroy(&net->ipv6.ip6_dst_ops); | ||
2730 | } | 2749 | } |
2731 | 2750 | ||
2732 | static struct pernet_operations ip6_route_net_ops = { | 2751 | static struct pernet_operations ip6_route_net_ops = { |
@@ -2750,10 +2769,14 @@ int __init ip6_route_init(void) | |||
2750 | if (!ip6_dst_ops_template.kmem_cachep) | 2769 | if (!ip6_dst_ops_template.kmem_cachep) |
2751 | goto out; | 2770 | goto out; |
2752 | 2771 | ||
2753 | ret = register_pernet_subsys(&ip6_route_net_ops); | 2772 | ret = dst_entries_init(&ip6_dst_blackhole_ops); |
2754 | if (ret) | 2773 | if (ret) |
2755 | goto out_kmem_cache; | 2774 | goto out_kmem_cache; |
2756 | 2775 | ||
2776 | ret = register_pernet_subsys(&ip6_route_net_ops); | ||
2777 | if (ret) | ||
2778 | goto out_dst_entries; | ||
2779 | |||
2757 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; | 2780 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; |
2758 | 2781 | ||
2759 | /* Registering of the loopback is done before this portion of code, | 2782 | /* Registering of the loopback is done before this portion of code, |
@@ -2800,6 +2823,8 @@ out_fib6_init: | |||
2800 | fib6_gc_cleanup(); | 2823 | fib6_gc_cleanup(); |
2801 | out_register_subsys: | 2824 | out_register_subsys: |
2802 | unregister_pernet_subsys(&ip6_route_net_ops); | 2825 | unregister_pernet_subsys(&ip6_route_net_ops); |
2826 | out_dst_entries: | ||
2827 | dst_entries_destroy(&ip6_dst_blackhole_ops); | ||
2803 | out_kmem_cache: | 2828 | out_kmem_cache: |
2804 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); | 2829 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); |
2805 | goto out; | 2830 | goto out; |
@@ -2812,5 +2837,6 @@ void ip6_route_cleanup(void) | |||
2812 | xfrm6_fini(); | 2837 | xfrm6_fini(); |
2813 | fib6_gc_cleanup(); | 2838 | fib6_gc_cleanup(); |
2814 | unregister_pernet_subsys(&ip6_route_net_ops); | 2839 | unregister_pernet_subsys(&ip6_route_net_ops); |
2840 | dst_entries_destroy(&ip6_dst_blackhole_ops); | ||
2815 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); | 2841 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); |
2816 | } | 2842 | } |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4699cd3c3118..d6bfaec3bbbf 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -63,36 +63,63 @@ | |||
63 | #define HASH_SIZE 16 | 63 | #define HASH_SIZE 16 |
64 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 64 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
65 | 65 | ||
66 | static void ipip6_tunnel_init(struct net_device *dev); | 66 | static int ipip6_tunnel_init(struct net_device *dev); |
67 | static void ipip6_tunnel_setup(struct net_device *dev); | 67 | static void ipip6_tunnel_setup(struct net_device *dev); |
68 | static void ipip6_dev_free(struct net_device *dev); | ||
68 | 69 | ||
69 | static int sit_net_id __read_mostly; | 70 | static int sit_net_id __read_mostly; |
70 | struct sit_net { | 71 | struct sit_net { |
71 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | 72 | struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE]; |
72 | struct ip_tunnel *tunnels_r[HASH_SIZE]; | 73 | struct ip_tunnel __rcu *tunnels_r[HASH_SIZE]; |
73 | struct ip_tunnel *tunnels_l[HASH_SIZE]; | 74 | struct ip_tunnel __rcu *tunnels_l[HASH_SIZE]; |
74 | struct ip_tunnel *tunnels_wc[1]; | 75 | struct ip_tunnel __rcu *tunnels_wc[1]; |
75 | struct ip_tunnel **tunnels[4]; | 76 | struct ip_tunnel __rcu **tunnels[4]; |
76 | 77 | ||
77 | struct net_device *fb_tunnel_dev; | 78 | struct net_device *fb_tunnel_dev; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | /* | 81 | /* |
81 | * Locking : hash tables are protected by RCU and a spinlock | 82 | * Locking : hash tables are protected by RCU and RTNL |
82 | */ | 83 | */ |
83 | static DEFINE_SPINLOCK(ipip6_lock); | ||
84 | 84 | ||
85 | #define for_each_ip_tunnel_rcu(start) \ | 85 | #define for_each_ip_tunnel_rcu(start) \ |
86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | 86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) |
87 | 87 | ||
88 | /* often modified stats are per cpu, other are shared (netdev->stats) */ | ||
89 | struct pcpu_tstats { | ||
90 | unsigned long rx_packets; | ||
91 | unsigned long rx_bytes; | ||
92 | unsigned long tx_packets; | ||
93 | unsigned long tx_bytes; | ||
94 | }; | ||
95 | |||
96 | static struct net_device_stats *ipip6_get_stats(struct net_device *dev) | ||
97 | { | ||
98 | struct pcpu_tstats sum = { 0 }; | ||
99 | int i; | ||
100 | |||
101 | for_each_possible_cpu(i) { | ||
102 | const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i); | ||
103 | |||
104 | sum.rx_packets += tstats->rx_packets; | ||
105 | sum.rx_bytes += tstats->rx_bytes; | ||
106 | sum.tx_packets += tstats->tx_packets; | ||
107 | sum.tx_bytes += tstats->tx_bytes; | ||
108 | } | ||
109 | dev->stats.rx_packets = sum.rx_packets; | ||
110 | dev->stats.rx_bytes = sum.rx_bytes; | ||
111 | dev->stats.tx_packets = sum.tx_packets; | ||
112 | dev->stats.tx_bytes = sum.tx_bytes; | ||
113 | return &dev->stats; | ||
114 | } | ||
88 | /* | 115 | /* |
89 | * Must be invoked with rcu_read_lock | 116 | * Must be invoked with rcu_read_lock |
90 | */ | 117 | */ |
91 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 118 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, |
92 | struct net_device *dev, __be32 remote, __be32 local) | 119 | struct net_device *dev, __be32 remote, __be32 local) |
93 | { | 120 | { |
94 | unsigned h0 = HASH(remote); | 121 | unsigned int h0 = HASH(remote); |
95 | unsigned h1 = HASH(local); | 122 | unsigned int h1 = HASH(local); |
96 | struct ip_tunnel *t; | 123 | struct ip_tunnel *t; |
97 | struct sit_net *sitn = net_generic(net, sit_net_id); | 124 | struct sit_net *sitn = net_generic(net, sit_net_id); |
98 | 125 | ||
@@ -121,12 +148,12 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | |||
121 | return NULL; | 148 | return NULL; |
122 | } | 149 | } |
123 | 150 | ||
124 | static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | 151 | static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn, |
125 | struct ip_tunnel_parm *parms) | 152 | struct ip_tunnel_parm *parms) |
126 | { | 153 | { |
127 | __be32 remote = parms->iph.daddr; | 154 | __be32 remote = parms->iph.daddr; |
128 | __be32 local = parms->iph.saddr; | 155 | __be32 local = parms->iph.saddr; |
129 | unsigned h = 0; | 156 | unsigned int h = 0; |
130 | int prio = 0; | 157 | int prio = 0; |
131 | 158 | ||
132 | if (remote) { | 159 | if (remote) { |
@@ -140,7 +167,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, | |||
140 | return &sitn->tunnels[prio][h]; | 167 | return &sitn->tunnels[prio][h]; |
141 | } | 168 | } |
142 | 169 | ||
143 | static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | 170 | static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, |
144 | struct ip_tunnel *t) | 171 | struct ip_tunnel *t) |
145 | { | 172 | { |
146 | return __ipip6_bucket(sitn, &t->parms); | 173 | return __ipip6_bucket(sitn, &t->parms); |
@@ -148,13 +175,14 @@ static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, | |||
148 | 175 | ||
149 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | 176 | static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) |
150 | { | 177 | { |
151 | struct ip_tunnel **tp; | 178 | struct ip_tunnel __rcu **tp; |
152 | 179 | struct ip_tunnel *iter; | |
153 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { | 180 | |
154 | if (t == *tp) { | 181 | for (tp = ipip6_bucket(sitn, t); |
155 | spin_lock_bh(&ipip6_lock); | 182 | (iter = rtnl_dereference(*tp)) != NULL; |
156 | *tp = t->next; | 183 | tp = &iter->next) { |
157 | spin_unlock_bh(&ipip6_lock); | 184 | if (t == iter) { |
185 | rcu_assign_pointer(*tp, t->next); | ||
158 | break; | 186 | break; |
159 | } | 187 | } |
160 | } | 188 | } |
@@ -162,12 +190,10 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | |||
162 | 190 | ||
163 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) | 191 | static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) |
164 | { | 192 | { |
165 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); | 193 | struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t); |
166 | 194 | ||
167 | spin_lock_bh(&ipip6_lock); | 195 | rcu_assign_pointer(t->next, rtnl_dereference(*tp)); |
168 | t->next = *tp; | ||
169 | rcu_assign_pointer(*tp, t); | 196 | rcu_assign_pointer(*tp, t); |
170 | spin_unlock_bh(&ipip6_lock); | ||
171 | } | 197 | } |
172 | 198 | ||
173 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | 199 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) |
@@ -187,17 +213,20 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | |||
187 | #endif | 213 | #endif |
188 | } | 214 | } |
189 | 215 | ||
190 | static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | 216 | static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, |
191 | struct ip_tunnel_parm *parms, int create) | 217 | struct ip_tunnel_parm *parms, int create) |
192 | { | 218 | { |
193 | __be32 remote = parms->iph.daddr; | 219 | __be32 remote = parms->iph.daddr; |
194 | __be32 local = parms->iph.saddr; | 220 | __be32 local = parms->iph.saddr; |
195 | struct ip_tunnel *t, **tp, *nt; | 221 | struct ip_tunnel *t, *nt; |
222 | struct ip_tunnel __rcu **tp; | ||
196 | struct net_device *dev; | 223 | struct net_device *dev; |
197 | char name[IFNAMSIZ]; | 224 | char name[IFNAMSIZ]; |
198 | struct sit_net *sitn = net_generic(net, sit_net_id); | 225 | struct sit_net *sitn = net_generic(net, sit_net_id); |
199 | 226 | ||
200 | for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { | 227 | for (tp = __ipip6_bucket(sitn, parms); |
228 | (t = rtnl_dereference(*tp)) != NULL; | ||
229 | tp = &t->next) { | ||
201 | if (local == t->parms.iph.saddr && | 230 | if (local == t->parms.iph.saddr && |
202 | remote == t->parms.iph.daddr && | 231 | remote == t->parms.iph.daddr && |
203 | parms->link == t->parms.link) { | 232 | parms->link == t->parms.link) { |
@@ -213,7 +242,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
213 | if (parms->name[0]) | 242 | if (parms->name[0]) |
214 | strlcpy(name, parms->name, IFNAMSIZ); | 243 | strlcpy(name, parms->name, IFNAMSIZ); |
215 | else | 244 | else |
216 | sprintf(name, "sit%%d"); | 245 | strcpy(name, "sit%d"); |
217 | 246 | ||
218 | dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); | 247 | dev = alloc_netdev(sizeof(*t), name, ipip6_tunnel_setup); |
219 | if (dev == NULL) | 248 | if (dev == NULL) |
@@ -229,7 +258,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
229 | nt = netdev_priv(dev); | 258 | nt = netdev_priv(dev); |
230 | 259 | ||
231 | nt->parms = *parms; | 260 | nt->parms = *parms; |
232 | ipip6_tunnel_init(dev); | 261 | if (ipip6_tunnel_init(dev) < 0) |
262 | goto failed_free; | ||
233 | ipip6_tunnel_clone_6rd(dev, sitn); | 263 | ipip6_tunnel_clone_6rd(dev, sitn); |
234 | 264 | ||
235 | if (parms->i_flags & SIT_ISATAP) | 265 | if (parms->i_flags & SIT_ISATAP) |
@@ -244,7 +274,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
244 | return nt; | 274 | return nt; |
245 | 275 | ||
246 | failed_free: | 276 | failed_free: |
247 | free_netdev(dev); | 277 | ipip6_dev_free(dev); |
248 | failed: | 278 | failed: |
249 | return NULL; | 279 | return NULL; |
250 | } | 280 | } |
@@ -340,7 +370,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
340 | 370 | ||
341 | ASSERT_RTNL(); | 371 | ASSERT_RTNL(); |
342 | 372 | ||
343 | for (p = t->prl; p; p = p->next) { | 373 | for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) { |
344 | if (p->addr == a->addr) { | 374 | if (p->addr == a->addr) { |
345 | if (chg) { | 375 | if (chg) { |
346 | p->flags = a->flags; | 376 | p->flags = a->flags; |
@@ -451,15 +481,12 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
451 | struct sit_net *sitn = net_generic(net, sit_net_id); | 481 | struct sit_net *sitn = net_generic(net, sit_net_id); |
452 | 482 | ||
453 | if (dev == sitn->fb_tunnel_dev) { | 483 | if (dev == sitn->fb_tunnel_dev) { |
454 | spin_lock_bh(&ipip6_lock); | 484 | rcu_assign_pointer(sitn->tunnels_wc[0], NULL); |
455 | sitn->tunnels_wc[0] = NULL; | ||
456 | spin_unlock_bh(&ipip6_lock); | ||
457 | dev_put(dev); | ||
458 | } else { | 485 | } else { |
459 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); | 486 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); |
460 | ipip6_tunnel_del_prl(netdev_priv(dev), NULL); | 487 | ipip6_tunnel_del_prl(netdev_priv(dev), NULL); |
461 | dev_put(dev); | ||
462 | } | 488 | } |
489 | dev_put(dev); | ||
463 | } | 490 | } |
464 | 491 | ||
465 | 492 | ||
@@ -548,6 +575,8 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
548 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 575 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
549 | iph->saddr, iph->daddr); | 576 | iph->saddr, iph->daddr); |
550 | if (tunnel != NULL) { | 577 | if (tunnel != NULL) { |
578 | struct pcpu_tstats *tstats; | ||
579 | |||
551 | secpath_reset(skb); | 580 | secpath_reset(skb); |
552 | skb->mac_header = skb->network_header; | 581 | skb->mac_header = skb->network_header; |
553 | skb_reset_network_header(skb); | 582 | skb_reset_network_header(skb); |
@@ -563,10 +592,16 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
563 | return 0; | 592 | return 0; |
564 | } | 593 | } |
565 | 594 | ||
566 | skb_tunnel_rx(skb, tunnel->dev); | 595 | tstats = this_cpu_ptr(tunnel->dev->tstats); |
596 | tstats->rx_packets++; | ||
597 | tstats->rx_bytes += skb->len; | ||
598 | |||
599 | __skb_tunnel_rx(skb, tunnel->dev); | ||
567 | 600 | ||
568 | ipip6_ecn_decapsulate(iph, skb); | 601 | ipip6_ecn_decapsulate(iph, skb); |
602 | |||
569 | netif_rx(skb); | 603 | netif_rx(skb); |
604 | |||
570 | rcu_read_unlock(); | 605 | rcu_read_unlock(); |
571 | return 0; | 606 | return 0; |
572 | } | 607 | } |
@@ -590,7 +625,7 @@ __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) | |||
590 | #ifdef CONFIG_IPV6_SIT_6RD | 625 | #ifdef CONFIG_IPV6_SIT_6RD |
591 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | 626 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, |
592 | tunnel->ip6rd.prefixlen)) { | 627 | tunnel->ip6rd.prefixlen)) { |
593 | unsigned pbw0, pbi0; | 628 | unsigned int pbw0, pbi0; |
594 | int pbi1; | 629 | int pbi1; |
595 | u32 d; | 630 | u32 d; |
596 | 631 | ||
@@ -625,14 +660,13 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
625 | struct net_device *dev) | 660 | struct net_device *dev) |
626 | { | 661 | { |
627 | struct ip_tunnel *tunnel = netdev_priv(dev); | 662 | struct ip_tunnel *tunnel = netdev_priv(dev); |
628 | struct net_device_stats *stats = &dev->stats; | 663 | struct pcpu_tstats *tstats; |
629 | struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); | ||
630 | struct iphdr *tiph = &tunnel->parms.iph; | 664 | struct iphdr *tiph = &tunnel->parms.iph; |
631 | struct ipv6hdr *iph6 = ipv6_hdr(skb); | 665 | struct ipv6hdr *iph6 = ipv6_hdr(skb); |
632 | u8 tos = tunnel->parms.iph.tos; | 666 | u8 tos = tunnel->parms.iph.tos; |
633 | __be16 df = tiph->frag_off; | 667 | __be16 df = tiph->frag_off; |
634 | struct rtable *rt; /* Route to the other host */ | 668 | struct rtable *rt; /* Route to the other host */ |
635 | struct net_device *tdev; /* Device to other host */ | 669 | struct net_device *tdev; /* Device to other host */ |
636 | struct iphdr *iph; /* Our new IP header */ | 670 | struct iphdr *iph; /* Our new IP header */ |
637 | unsigned int max_headroom; /* The extra header space needed */ | 671 | unsigned int max_headroom; /* The extra header space needed */ |
638 | __be32 dst = tiph->daddr; | 672 | __be32 dst = tiph->daddr; |
@@ -703,20 +737,20 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
703 | .oif = tunnel->parms.link, | 737 | .oif = tunnel->parms.link, |
704 | .proto = IPPROTO_IPV6 }; | 738 | .proto = IPPROTO_IPV6 }; |
705 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { | 739 | if (ip_route_output_key(dev_net(dev), &rt, &fl)) { |
706 | stats->tx_carrier_errors++; | 740 | dev->stats.tx_carrier_errors++; |
707 | goto tx_error_icmp; | 741 | goto tx_error_icmp; |
708 | } | 742 | } |
709 | } | 743 | } |
710 | if (rt->rt_type != RTN_UNICAST) { | 744 | if (rt->rt_type != RTN_UNICAST) { |
711 | ip_rt_put(rt); | 745 | ip_rt_put(rt); |
712 | stats->tx_carrier_errors++; | 746 | dev->stats.tx_carrier_errors++; |
713 | goto tx_error_icmp; | 747 | goto tx_error_icmp; |
714 | } | 748 | } |
715 | tdev = rt->dst.dev; | 749 | tdev = rt->dst.dev; |
716 | 750 | ||
717 | if (tdev == dev) { | 751 | if (tdev == dev) { |
718 | ip_rt_put(rt); | 752 | ip_rt_put(rt); |
719 | stats->collisions++; | 753 | dev->stats.collisions++; |
720 | goto tx_error; | 754 | goto tx_error; |
721 | } | 755 | } |
722 | 756 | ||
@@ -724,7 +758,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
724 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); | 758 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); |
725 | 759 | ||
726 | if (mtu < 68) { | 760 | if (mtu < 68) { |
727 | stats->collisions++; | 761 | dev->stats.collisions++; |
728 | ip_rt_put(rt); | 762 | ip_rt_put(rt); |
729 | goto tx_error; | 763 | goto tx_error; |
730 | } | 764 | } |
@@ -763,7 +797,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
763 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); | 797 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); |
764 | if (!new_skb) { | 798 | if (!new_skb) { |
765 | ip_rt_put(rt); | 799 | ip_rt_put(rt); |
766 | txq->tx_dropped++; | 800 | dev->stats.tx_dropped++; |
767 | dev_kfree_skb(skb); | 801 | dev_kfree_skb(skb); |
768 | return NETDEV_TX_OK; | 802 | return NETDEV_TX_OK; |
769 | } | 803 | } |
@@ -799,14 +833,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
799 | iph->ttl = iph6->hop_limit; | 833 | iph->ttl = iph6->hop_limit; |
800 | 834 | ||
801 | nf_reset(skb); | 835 | nf_reset(skb); |
802 | 836 | tstats = this_cpu_ptr(dev->tstats); | |
803 | IPTUNNEL_XMIT(); | 837 | __IPTUNNEL_XMIT(tstats, &dev->stats); |
804 | return NETDEV_TX_OK; | 838 | return NETDEV_TX_OK; |
805 | 839 | ||
806 | tx_error_icmp: | 840 | tx_error_icmp: |
807 | dst_link_failure(skb); | 841 | dst_link_failure(skb); |
808 | tx_error: | 842 | tx_error: |
809 | stats->tx_errors++; | 843 | dev->stats.tx_errors++; |
810 | dev_kfree_skb(skb); | 844 | dev_kfree_skb(skb); |
811 | return NETDEV_TX_OK; | 845 | return NETDEV_TX_OK; |
812 | } | 846 | } |
@@ -929,6 +963,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
929 | } | 963 | } |
930 | t = netdev_priv(dev); | 964 | t = netdev_priv(dev); |
931 | ipip6_tunnel_unlink(sitn, t); | 965 | ipip6_tunnel_unlink(sitn, t); |
966 | synchronize_net(); | ||
932 | t->parms.iph.saddr = p.iph.saddr; | 967 | t->parms.iph.saddr = p.iph.saddr; |
933 | t->parms.iph.daddr = p.iph.daddr; | 968 | t->parms.iph.daddr = p.iph.daddr; |
934 | memcpy(dev->dev_addr, &p.iph.saddr, 4); | 969 | memcpy(dev->dev_addr, &p.iph.saddr, 4); |
@@ -1083,12 +1118,19 @@ static const struct net_device_ops ipip6_netdev_ops = { | |||
1083 | .ndo_start_xmit = ipip6_tunnel_xmit, | 1118 | .ndo_start_xmit = ipip6_tunnel_xmit, |
1084 | .ndo_do_ioctl = ipip6_tunnel_ioctl, | 1119 | .ndo_do_ioctl = ipip6_tunnel_ioctl, |
1085 | .ndo_change_mtu = ipip6_tunnel_change_mtu, | 1120 | .ndo_change_mtu = ipip6_tunnel_change_mtu, |
1121 | .ndo_get_stats = ipip6_get_stats, | ||
1086 | }; | 1122 | }; |
1087 | 1123 | ||
1124 | static void ipip6_dev_free(struct net_device *dev) | ||
1125 | { | ||
1126 | free_percpu(dev->tstats); | ||
1127 | free_netdev(dev); | ||
1128 | } | ||
1129 | |||
1088 | static void ipip6_tunnel_setup(struct net_device *dev) | 1130 | static void ipip6_tunnel_setup(struct net_device *dev) |
1089 | { | 1131 | { |
1090 | dev->netdev_ops = &ipip6_netdev_ops; | 1132 | dev->netdev_ops = &ipip6_netdev_ops; |
1091 | dev->destructor = free_netdev; | 1133 | dev->destructor = ipip6_dev_free; |
1092 | 1134 | ||
1093 | dev->type = ARPHRD_SIT; | 1135 | dev->type = ARPHRD_SIT; |
1094 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 1136 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); |
@@ -1098,9 +1140,10 @@ static void ipip6_tunnel_setup(struct net_device *dev) | |||
1098 | dev->iflink = 0; | 1140 | dev->iflink = 0; |
1099 | dev->addr_len = 4; | 1141 | dev->addr_len = 4; |
1100 | dev->features |= NETIF_F_NETNS_LOCAL; | 1142 | dev->features |= NETIF_F_NETNS_LOCAL; |
1143 | dev->features |= NETIF_F_LLTX; | ||
1101 | } | 1144 | } |
1102 | 1145 | ||
1103 | static void ipip6_tunnel_init(struct net_device *dev) | 1146 | static int ipip6_tunnel_init(struct net_device *dev) |
1104 | { | 1147 | { |
1105 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1148 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1106 | 1149 | ||
@@ -1111,9 +1154,14 @@ static void ipip6_tunnel_init(struct net_device *dev) | |||
1111 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); | 1154 | memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); |
1112 | 1155 | ||
1113 | ipip6_tunnel_bind_dev(dev); | 1156 | ipip6_tunnel_bind_dev(dev); |
1157 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1158 | if (!dev->tstats) | ||
1159 | return -ENOMEM; | ||
1160 | |||
1161 | return 0; | ||
1114 | } | 1162 | } |
1115 | 1163 | ||
1116 | static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) | 1164 | static int __net_init ipip6_fb_tunnel_init(struct net_device *dev) |
1117 | { | 1165 | { |
1118 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1166 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1119 | struct iphdr *iph = &tunnel->parms.iph; | 1167 | struct iphdr *iph = &tunnel->parms.iph; |
@@ -1128,11 +1176,15 @@ static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) | |||
1128 | iph->ihl = 5; | 1176 | iph->ihl = 5; |
1129 | iph->ttl = 64; | 1177 | iph->ttl = 64; |
1130 | 1178 | ||
1179 | dev->tstats = alloc_percpu(struct pcpu_tstats); | ||
1180 | if (!dev->tstats) | ||
1181 | return -ENOMEM; | ||
1131 | dev_hold(dev); | 1182 | dev_hold(dev); |
1132 | sitn->tunnels_wc[0] = tunnel; | 1183 | sitn->tunnels_wc[0] = tunnel; |
1184 | return 0; | ||
1133 | } | 1185 | } |
1134 | 1186 | ||
1135 | static struct xfrm_tunnel sit_handler = { | 1187 | static struct xfrm_tunnel sit_handler __read_mostly = { |
1136 | .handler = ipip6_rcv, | 1188 | .handler = ipip6_rcv, |
1137 | .err_handler = ipip6_err, | 1189 | .err_handler = ipip6_err, |
1138 | .priority = 1, | 1190 | .priority = 1, |
@@ -1173,7 +1225,10 @@ static int __net_init sit_init_net(struct net *net) | |||
1173 | } | 1225 | } |
1174 | dev_net_set(sitn->fb_tunnel_dev, net); | 1226 | dev_net_set(sitn->fb_tunnel_dev, net); |
1175 | 1227 | ||
1176 | ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); | 1228 | err = ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); |
1229 | if (err) | ||
1230 | goto err_dev_free; | ||
1231 | |||
1177 | ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); | 1232 | ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); |
1178 | 1233 | ||
1179 | if ((err = register_netdev(sitn->fb_tunnel_dev))) | 1234 | if ((err = register_netdev(sitn->fb_tunnel_dev))) |
@@ -1183,7 +1238,8 @@ static int __net_init sit_init_net(struct net *net) | |||
1183 | 1238 | ||
1184 | err_reg_dev: | 1239 | err_reg_dev: |
1185 | dev_put(sitn->fb_tunnel_dev); | 1240 | dev_put(sitn->fb_tunnel_dev); |
1186 | free_netdev(sitn->fb_tunnel_dev); | 1241 | err_dev_free: |
1242 | ipip6_dev_free(sitn->fb_tunnel_dev); | ||
1187 | err_alloc_dev: | 1243 | err_alloc_dev: |
1188 | return err; | 1244 | return err; |
1189 | } | 1245 | } |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fe6d40418c0b..7e41e2cbb85e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -139,7 +139,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
139 | return -EINVAL; | 139 | return -EINVAL; |
140 | 140 | ||
141 | if (usin->sin6_family != AF_INET6) | 141 | if (usin->sin6_family != AF_INET6) |
142 | return(-EAFNOSUPPORT); | 142 | return -EAFNOSUPPORT; |
143 | 143 | ||
144 | memset(&fl, 0, sizeof(fl)); | 144 | memset(&fl, 0, sizeof(fl)); |
145 | 145 | ||
@@ -1409,7 +1409,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1409 | 1409 | ||
1410 | newsk = tcp_create_openreq_child(sk, req, skb); | 1410 | newsk = tcp_create_openreq_child(sk, req, skb); |
1411 | if (newsk == NULL) | 1411 | if (newsk == NULL) |
1412 | goto out; | 1412 | goto out_nonewsk; |
1413 | 1413 | ||
1414 | /* | 1414 | /* |
1415 | * No need to charge this sock to the relevant IPv6 refcnt debug socks | 1415 | * No need to charge this sock to the relevant IPv6 refcnt debug socks |
@@ -1497,18 +1497,22 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1497 | } | 1497 | } |
1498 | #endif | 1498 | #endif |
1499 | 1499 | ||
1500 | if (__inet_inherit_port(sk, newsk) < 0) { | ||
1501 | sock_put(newsk); | ||
1502 | goto out; | ||
1503 | } | ||
1500 | __inet6_hash(newsk, NULL); | 1504 | __inet6_hash(newsk, NULL); |
1501 | __inet_inherit_port(sk, newsk); | ||
1502 | 1505 | ||
1503 | return newsk; | 1506 | return newsk; |
1504 | 1507 | ||
1505 | out_overflow: | 1508 | out_overflow: |
1506 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); | 1509 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); |
1507 | out: | 1510 | out_nonewsk: |
1508 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
1509 | if (opt && opt != np->opt) | 1511 | if (opt && opt != np->opt) |
1510 | sock_kfree_s(sk, opt, opt->tot_len); | 1512 | sock_kfree_s(sk, opt, opt->tot_len); |
1511 | dst_release(dst); | 1513 | dst_release(dst); |
1514 | out: | ||
1515 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); | ||
1512 | return NULL; | 1516 | return NULL; |
1513 | } | 1517 | } |
1514 | 1518 | ||
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index fc3c86a47452..4f3cec12aa85 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -30,28 +30,31 @@ | |||
30 | #include <net/protocol.h> | 30 | #include <net/protocol.h> |
31 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
32 | 32 | ||
33 | static struct xfrm6_tunnel *tunnel6_handlers; | 33 | static struct xfrm6_tunnel __rcu *tunnel6_handlers __read_mostly; |
34 | static struct xfrm6_tunnel *tunnel46_handlers; | 34 | static struct xfrm6_tunnel __rcu *tunnel46_handlers __read_mostly; |
35 | static DEFINE_MUTEX(tunnel6_mutex); | 35 | static DEFINE_MUTEX(tunnel6_mutex); |
36 | 36 | ||
37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) | 37 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) |
38 | { | 38 | { |
39 | struct xfrm6_tunnel **pprev; | 39 | struct xfrm6_tunnel __rcu **pprev; |
40 | struct xfrm6_tunnel *t; | ||
40 | int ret = -EEXIST; | 41 | int ret = -EEXIST; |
41 | int priority = handler->priority; | 42 | int priority = handler->priority; |
42 | 43 | ||
43 | mutex_lock(&tunnel6_mutex); | 44 | mutex_lock(&tunnel6_mutex); |
44 | 45 | ||
45 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; | 46 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
46 | *pprev; pprev = &(*pprev)->next) { | 47 | (t = rcu_dereference_protected(*pprev, |
47 | if ((*pprev)->priority > priority) | 48 | lockdep_is_held(&tunnel6_mutex))) != NULL; |
49 | pprev = &t->next) { | ||
50 | if (t->priority > priority) | ||
48 | break; | 51 | break; |
49 | if ((*pprev)->priority == priority) | 52 | if (t->priority == priority) |
50 | goto err; | 53 | goto err; |
51 | } | 54 | } |
52 | 55 | ||
53 | handler->next = *pprev; | 56 | handler->next = *pprev; |
54 | *pprev = handler; | 57 | rcu_assign_pointer(*pprev, handler); |
55 | 58 | ||
56 | ret = 0; | 59 | ret = 0; |
57 | 60 | ||
@@ -65,14 +68,17 @@ EXPORT_SYMBOL(xfrm6_tunnel_register); | |||
65 | 68 | ||
66 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | 69 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) |
67 | { | 70 | { |
68 | struct xfrm6_tunnel **pprev; | 71 | struct xfrm6_tunnel __rcu **pprev; |
72 | struct xfrm6_tunnel *t; | ||
69 | int ret = -ENOENT; | 73 | int ret = -ENOENT; |
70 | 74 | ||
71 | mutex_lock(&tunnel6_mutex); | 75 | mutex_lock(&tunnel6_mutex); |
72 | 76 | ||
73 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; | 77 | for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; |
74 | *pprev; pprev = &(*pprev)->next) { | 78 | (t = rcu_dereference_protected(*pprev, |
75 | if (*pprev == handler) { | 79 | lockdep_is_held(&tunnel6_mutex))) != NULL; |
80 | pprev = &t->next) { | ||
81 | if (t == handler) { | ||
76 | *pprev = handler->next; | 82 | *pprev = handler->next; |
77 | ret = 0; | 83 | ret = 0; |
78 | break; | 84 | break; |
@@ -88,6 +94,11 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | |||
88 | 94 | ||
89 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); | 95 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); |
90 | 96 | ||
97 | #define for_each_tunnel_rcu(head, handler) \ | ||
98 | for (handler = rcu_dereference(head); \ | ||
99 | handler != NULL; \ | ||
100 | handler = rcu_dereference(handler->next)) \ | ||
101 | |||
91 | static int tunnel6_rcv(struct sk_buff *skb) | 102 | static int tunnel6_rcv(struct sk_buff *skb) |
92 | { | 103 | { |
93 | struct xfrm6_tunnel *handler; | 104 | struct xfrm6_tunnel *handler; |
@@ -95,7 +106,7 @@ static int tunnel6_rcv(struct sk_buff *skb) | |||
95 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 106 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
96 | goto drop; | 107 | goto drop; |
97 | 108 | ||
98 | for (handler = tunnel6_handlers; handler; handler = handler->next) | 109 | for_each_tunnel_rcu(tunnel6_handlers, handler) |
99 | if (!handler->handler(skb)) | 110 | if (!handler->handler(skb)) |
100 | return 0; | 111 | return 0; |
101 | 112 | ||
@@ -113,7 +124,7 @@ static int tunnel46_rcv(struct sk_buff *skb) | |||
113 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 124 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
114 | goto drop; | 125 | goto drop; |
115 | 126 | ||
116 | for (handler = tunnel46_handlers; handler; handler = handler->next) | 127 | for_each_tunnel_rcu(tunnel46_handlers, handler) |
117 | if (!handler->handler(skb)) | 128 | if (!handler->handler(skb)) |
118 | return 0; | 129 | return 0; |
119 | 130 | ||
@@ -129,7 +140,7 @@ static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
129 | { | 140 | { |
130 | struct xfrm6_tunnel *handler; | 141 | struct xfrm6_tunnel *handler; |
131 | 142 | ||
132 | for (handler = tunnel6_handlers; handler; handler = handler->next) | 143 | for_each_tunnel_rcu(tunnel6_handlers, handler) |
133 | if (!handler->err_handler(skb, opt, type, code, offset, info)) | 144 | if (!handler->err_handler(skb, opt, type, code, offset, info)) |
134 | break; | 145 | break; |
135 | } | 146 | } |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5acb3560ff15..91def93bec85 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -122,8 +122,8 @@ static void udp_v6_rehash(struct sock *sk) | |||
122 | 122 | ||
123 | static inline int compute_score(struct sock *sk, struct net *net, | 123 | static inline int compute_score(struct sock *sk, struct net *net, |
124 | unsigned short hnum, | 124 | unsigned short hnum, |
125 | struct in6_addr *saddr, __be16 sport, | 125 | const struct in6_addr *saddr, __be16 sport, |
126 | struct in6_addr *daddr, __be16 dport, | 126 | const struct in6_addr *daddr, __be16 dport, |
127 | int dif) | 127 | int dif) |
128 | { | 128 | { |
129 | int score = -1; | 129 | int score = -1; |
@@ -239,8 +239,8 @@ exact_match: | |||
239 | } | 239 | } |
240 | 240 | ||
241 | static struct sock *__udp6_lib_lookup(struct net *net, | 241 | static struct sock *__udp6_lib_lookup(struct net *net, |
242 | struct in6_addr *saddr, __be16 sport, | 242 | const struct in6_addr *saddr, __be16 sport, |
243 | struct in6_addr *daddr, __be16 dport, | 243 | const struct in6_addr *daddr, __be16 dport, |
244 | int dif, struct udp_table *udptable) | 244 | int dif, struct udp_table *udptable) |
245 | { | 245 | { |
246 | struct sock *sk, *result; | 246 | struct sock *sk, *result; |
@@ -320,6 +320,14 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, | |||
320 | udptable); | 320 | udptable); |
321 | } | 321 | } |
322 | 322 | ||
323 | struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, | ||
324 | const struct in6_addr *daddr, __be16 dport, int dif) | ||
325 | { | ||
326 | return __udp6_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table); | ||
327 | } | ||
328 | EXPORT_SYMBOL_GPL(udp6_lib_lookup); | ||
329 | |||
330 | |||
323 | /* | 331 | /* |
324 | * This should be easy, if there is something there we | 332 | * This should be easy, if there is something there we |
325 | * return it, otherwise we block. | 333 | * return it, otherwise we block. |
@@ -519,7 +527,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
519 | } | 527 | } |
520 | } | 528 | } |
521 | 529 | ||
522 | if (sk->sk_filter) { | 530 | if (rcu_dereference_raw(sk->sk_filter)) { |
523 | if (udp_lib_checksum_complete(skb)) | 531 | if (udp_lib_checksum_complete(skb)) |
524 | goto drop; | 532 | goto drop; |
525 | } | 533 | } |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6baeabbbca82..7e74023ea6e4 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -199,7 +199,7 @@ static inline int xfrm6_garbage_collect(struct dst_ops *ops) | |||
199 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); | 199 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); |
200 | 200 | ||
201 | xfrm6_policy_afinfo.garbage_collect(net); | 201 | xfrm6_policy_afinfo.garbage_collect(net); |
202 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | 202 | return dst_entries_get_fast(ops) > ops->gc_thresh * 2; |
203 | } | 203 | } |
204 | 204 | ||
205 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | 205 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -255,7 +255,6 @@ static struct dst_ops xfrm6_dst_ops = { | |||
255 | .ifdown = xfrm6_dst_ifdown, | 255 | .ifdown = xfrm6_dst_ifdown, |
256 | .local_out = __ip6_local_out, | 256 | .local_out = __ip6_local_out, |
257 | .gc_thresh = 1024, | 257 | .gc_thresh = 1024, |
258 | .entries = ATOMIC_INIT(0), | ||
259 | }; | 258 | }; |
260 | 259 | ||
261 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | 260 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { |
@@ -312,11 +311,13 @@ int __init xfrm6_init(void) | |||
312 | */ | 311 | */ |
313 | gc_thresh = FIB6_TABLE_HASHSZ * 8; | 312 | gc_thresh = FIB6_TABLE_HASHSZ * 8; |
314 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; | 313 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; |
314 | dst_entries_init(&xfrm6_dst_ops); | ||
315 | 315 | ||
316 | ret = xfrm6_policy_init(); | 316 | ret = xfrm6_policy_init(); |
317 | if (ret) | 317 | if (ret) { |
318 | dst_entries_destroy(&xfrm6_dst_ops); | ||
318 | goto out; | 319 | goto out; |
319 | 320 | } | |
320 | ret = xfrm6_state_init(); | 321 | ret = xfrm6_state_init(); |
321 | if (ret) | 322 | if (ret) |
322 | goto out_policy; | 323 | goto out_policy; |
@@ -341,4 +342,5 @@ void xfrm6_fini(void) | |||
341 | //xfrm6_input_fini(); | 342 | //xfrm6_input_fini(); |
342 | xfrm6_policy_fini(); | 343 | xfrm6_policy_fini(); |
343 | xfrm6_state_fini(); | 344 | xfrm6_state_fini(); |
345 | dst_entries_destroy(&xfrm6_dst_ops); | ||
344 | } | 346 | } |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 2ce3a8278f26..2969cad408de 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -199,7 +199,7 @@ static void x6spi_destroy_rcu(struct rcu_head *head) | |||
199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | 199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); |
200 | } | 200 | } |
201 | 201 | ||
202 | void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | 202 | static void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) |
203 | { | 203 | { |
204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | 204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); |
205 | struct xfrm6_tunnel_spi *x6spi; | 205 | struct xfrm6_tunnel_spi *x6spi; |
@@ -223,8 +223,6 @@ void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | |||
223 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); | 223 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
224 | } | 224 | } |
225 | 225 | ||
226 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); | ||
227 | |||
228 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | 226 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
229 | { | 227 | { |
230 | skb_push(skb, -skb_network_offset(skb)); | 228 | skb_push(skb, -skb_network_offset(skb)); |
@@ -317,13 +315,13 @@ static const struct xfrm_type xfrm6_tunnel_type = { | |||
317 | .output = xfrm6_tunnel_output, | 315 | .output = xfrm6_tunnel_output, |
318 | }; | 316 | }; |
319 | 317 | ||
320 | static struct xfrm6_tunnel xfrm6_tunnel_handler = { | 318 | static struct xfrm6_tunnel xfrm6_tunnel_handler __read_mostly = { |
321 | .handler = xfrm6_tunnel_rcv, | 319 | .handler = xfrm6_tunnel_rcv, |
322 | .err_handler = xfrm6_tunnel_err, | 320 | .err_handler = xfrm6_tunnel_err, |
323 | .priority = 2, | 321 | .priority = 2, |
324 | }; | 322 | }; |
325 | 323 | ||
326 | static struct xfrm6_tunnel xfrm46_tunnel_handler = { | 324 | static struct xfrm6_tunnel xfrm46_tunnel_handler __read_mostly = { |
327 | .handler = xfrm6_tunnel_rcv, | 325 | .handler = xfrm6_tunnel_rcv, |
328 | .err_handler = xfrm6_tunnel_err, | 326 | .err_handler = xfrm6_tunnel_err, |
329 | .priority = 2, | 327 | .priority = 2, |