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, |
