diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/icmp.c | 4 | ||||
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 80 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 12 | ||||
-rw-r--r-- | net/ipv6/ipcomp6.c | 8 | ||||
-rw-r--r-- | net/ipv6/netfilter.c | 52 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 31 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 4 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_filter.c | 21 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_mangle.c | 33 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_raw.c | 15 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 179 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 12 | ||||
-rw-r--r-- | net/ipv6/proc.c | 4 | ||||
-rw-r--r-- | net/ipv6/sit.c | 2 | ||||
-rw-r--r-- | net/ipv6/tunnel6.c | 8 |
15 files changed, 236 insertions, 229 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 21eb725e885f..1044b6fce0d5 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -717,7 +717,7 @@ int __init icmpv6_init(struct net_proto_family *ops) struct sock *sk; int err, i, j; - for_each_cpu(i) { + for_each_possible_cpu(i) { err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &per_cpu(__icmpv6_socket, i)); if (err < 0) { @@ -763,7 +763,7 @@ void icmpv6_cleanup(void) { int i; - for_each_cpu(i) { + for_each_possible_cpu(i) { sock_release(per_cpu(__icmpv6_socket, i)); } inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index bb8ffb8a14c5..2ae84c961678 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -23,6 +23,86 @@ #include <net/inet6_hashtables.h> #include <net/ip.h> +void __inet6_hash(struct inet_hashinfo *hashinfo, + struct sock *sk) +{ + struct hlist_head *list; + rwlock_t *lock; + + BUG_TRAP(sk_unhashed(sk)); + + if (sk->sk_state == TCP_LISTEN) { + list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; + lock = &hashinfo->lhash_lock; + inet_listen_wlock(hashinfo); + } else { + unsigned int hash; + sk->sk_hash = hash = inet6_sk_ehashfn(sk); + hash &= (hashinfo->ehash_size - 1); + list = &hashinfo->ehash[hash].chain; + lock = &hashinfo->ehash[hash].lock; + write_lock(lock); + } + + __sk_add_node(sk, list); + sock_prot_inc_use(sk->sk_prot); + write_unlock(lock); +} +EXPORT_SYMBOL(__inet6_hash); + +/* + * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so + * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM + * + * The sockhash lock must be held as a reader here. + */ +struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, + const struct in6_addr *saddr, + const u16 sport, + const struct in6_addr *daddr, + const u16 hnum, + const int dif) +{ + struct sock *sk; + const struct hlist_node *node; + const __u32 ports = INET_COMBINED_PORTS(sport, hnum); + /* Optimize here for direct hit, only listening connections can + * have wildcards anyways. + */ + unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport); + struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); + + prefetch(head->chain.first); + read_lock(&head->lock); + sk_for_each(sk, node, &head->chain) { + /* For IPV6 do the cheaper port and family tests first. */ + if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif)) + goto hit; /* You sunk my battleship! */ + } + /* Must check for a TIME_WAIT'er before going to listener hash. */ + sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { + const struct inet_timewait_sock *tw = inet_twsk(sk); + + if(*((__u32 *)&(tw->tw_dport)) == ports && + sk->sk_family == PF_INET6) { + const struct inet6_timewait_sock *tw6 = inet6_twsk(sk); + + if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && + ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && + (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) + goto hit; + } + } + read_unlock(&head->lock); + return NULL; + +hit: + sock_hold(sk); + read_unlock(&head->lock); + return sk; +} +EXPORT_SYMBOL(__inet6_lookup_established); + struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, const unsigned short hnum, const int dif) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index ff9040c92556..a995796b5a57 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -519,9 +519,6 @@ ip6ip6_rcv(struct sk_buff *skb) struct ipv6hdr *ipv6h; struct ip6_tnl *t; - if (!pskb_may_pull(skb, sizeof (*ipv6h))) - goto discard; - ipv6h = skb->nh.ipv6h; read_lock(&ip6ip6_lock); @@ -529,8 +526,7 @@ ip6ip6_rcv(struct sk_buff *skb) if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { read_unlock(&ip6ip6_lock); - kfree_skb(skb); - return 0; + goto discard; } if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { @@ -557,9 +553,11 @@ ip6ip6_rcv(struct sk_buff *skb) return 0; } read_unlock(&ip6ip6_lock); - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); -discard: return 1; + +discard: + kfree_skb(skb); + return 0; } static inline struct ipv6_txoptions *create_tel(__u8 encap_limit) diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 00f3fadfcca7..05eb67def39f 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -290,7 +290,7 @@ static void ipcomp6_free_scratches(void) if (!scratches) return; - for_each_cpu(i) { + for_each_possible_cpu(i) { void *scratch = *per_cpu_ptr(scratches, i); vfree(scratch); @@ -313,7 +313,7 @@ static void **ipcomp6_alloc_scratches(void) ipcomp6_scratches = scratches; - for_each_cpu(i) { + for_each_possible_cpu(i) { void *scratch = vmalloc(IPCOMP_SCRATCH_SIZE); if (!scratch) return NULL; @@ -344,7 +344,7 @@ static void ipcomp6_free_tfms(struct crypto_tfm **tfms) if (!tfms) return; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); crypto_free_tfm(tfm); } @@ -384,7 +384,7 @@ static struct crypto_tfm **ipcomp6_alloc_tfms(const char *alg_name) if (!tfms) goto error; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { struct crypto_tfm *tfm = crypto_alloc_tfm(alg_name, 0); if (!tfm) goto error; diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index d750cfc019dc..395a417ba955 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -7,6 +7,7 @@ #include <net/ipv6.h> #include <net/ip6_route.h> #include <net/xfrm.h> +#include <net/ip6_checksum.h> int ip6_route_me_harder(struct sk_buff *skb) { @@ -54,7 +55,7 @@ struct ip6_rt_info { struct in6_addr saddr; }; -static void save(const struct sk_buff *skb, struct nf_info *info) +static void nf_ip6_saveroute(const struct sk_buff *skb, struct nf_info *info) { struct ip6_rt_info *rt_info = nf_info_reroute(info); @@ -66,7 +67,7 @@ static void save(const struct sk_buff *skb, struct nf_info *info) } } -static int reroute(struct sk_buff **pskb, const struct nf_info *info) +static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info) { struct ip6_rt_info *rt_info = nf_info_reroute(info); @@ -79,15 +80,50 @@ static int reroute(struct sk_buff **pskb, const struct nf_info *info) return 0; } -static struct nf_queue_rerouter ip6_reroute = { - .rer_size = sizeof(struct ip6_rt_info), - .save = &save, - .reroute = &reroute, +unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol) +{ + struct ipv6hdr *ip6h = skb->nh.ipv6h; + unsigned int csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_HW: + if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN) + break; + if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + skb->len - dataoff, protocol, + csum_sub(skb->csum, + skb_checksum(skb, 0, + dataoff, 0)))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } + /* fall through */ + case CHECKSUM_NONE: + skb->csum = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + skb->len - dataoff, + protocol, + csum_sub(0, + skb_checksum(skb, 0, + dataoff, 0))); + csum = __skb_checksum_complete(skb); + } + return csum; +} + +EXPORT_SYMBOL(nf_ip6_checksum); + +static struct nf_afinfo nf_ip6_afinfo = { + .family = AF_INET6, + .checksum = nf_ip6_checksum, + .saveroute = nf_ip6_saveroute, + .reroute = nf_ip6_reroute, + .route_key_size = sizeof(struct ip6_rt_info), }; int __init ipv6_netfilter_init(void) { - return nf_register_queue_rerouter(PF_INET6, &ip6_reroute); + return nf_register_afinfo(&nf_ip6_afinfo); } /* This can be called from inet6_init() on errors, so it cannot @@ -95,5 +131,5 @@ int __init ipv6_netfilter_init(void) */ void ipv6_netfilter_fini(void) { - nf_unregister_queue_rerouter(PF_INET6); + nf_unregister_afinfo(&nf_ip6_afinfo); } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e81c6a9dab81..b4b7d441af25 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -658,15 +658,11 @@ static struct nf_queue_handler nfqh = { .outfn = &ipq_enqueue_packet, }; -static int -init_or_cleanup(int init) +static int __init ip6_queue_init(void) { int status = -ENOMEM; struct proc_dir_entry *proc; - if (!init) - goto cleanup; - netlink_register_notifier(&ipq_nl_notifier); ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk, THIS_MODULE); @@ -693,11 +689,6 @@ init_or_cleanup(int init) } return status; -cleanup: - nf_unregister_queue_handlers(&nfqh); - synchronize_net(); - ipq_flush(NF_DROP); - cleanup_sysctl: unregister_sysctl_table(ipq_sysctl_header); unregister_netdevice_notifier(&ipq_dev_notifier); @@ -713,15 +704,21 @@ cleanup_netlink_notifier: return status; } -static int __init ip6_queue_init(void) -{ - - return init_or_cleanup(1); -} - static void __exit ip6_queue_fini(void) { - init_or_cleanup(0); + nf_unregister_queue_handlers(&nfqh); + synchronize_net(); + ipq_flush(NF_DROP); + + unregister_sysctl_table(ipq_sysctl_header); + unregister_netdevice_notifier(&ipq_dev_notifier); + proc_net_remove(IPQ_PROC_FS_NAME); + + sock_release(ipqnl->sk_socket); + mutex_lock(&ipqnl_mutex); + mutex_unlock(&ipqnl_mutex); + + netlink_unregister_notifier(&ipq_nl_notifier); } MODULE_DESCRIPTION("IPv6 packet queue handler"); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 3ecf2db841f8..642b4b11464f 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -788,7 +788,7 @@ translate_table(const char *name, } /* And one copy for every other CPU */ - for_each_cpu(i) { + for_each_possible_cpu(i) { if (newinfo->entries[i] && newinfo->entries[i] != entry0) memcpy(newinfo->entries[i], entry0, newinfo->size); } @@ -841,7 +841,7 @@ get_counters(const struct xt_table_info *t, counters, &i); - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { if (cpu == curcpu) continue; i = 0; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index e5e724d9ee60..60976c0c58e8 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -177,37 +177,20 @@ static int __init ip6table_filter_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ip6t_ops[0]); + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ip6t_ops[1]); - if (ret < 0) - goto cleanup_hook0; - - ret = nf_register_hook(&ip6t_ops[2]); - if (ret < 0) - goto cleanup_hook1; - return ret; - cleanup_hook1: - nf_unregister_hook(&ip6t_ops[1]); - cleanup_hook0: - nf_unregister_hook(&ip6t_ops[0]); cleanup_table: ip6t_unregister_table(&packet_filter); - return ret; } static void __exit ip6table_filter_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ip6t_ops[i]); - + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); ip6t_unregister_table(&packet_filter); } diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index e1f0f6ae9841..03a13eab1dae 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -238,49 +238,20 @@ static int __init ip6table_mangle_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ip6t_ops[0]); + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ip6t_ops[1]); - if (ret < 0) - goto cleanup_hook0; - - ret = nf_register_hook(&ip6t_ops[2]); - if (ret < 0) - goto cleanup_hook1; - - ret = nf_register_hook(&ip6t_ops[3]); - if (ret < 0) - goto cleanup_hook2; - - ret = nf_register_hook(&ip6t_ops[4]); - if (ret < 0) - goto cleanup_hook3; - return ret; - cleanup_hook3: - nf_unregister_hook(&ip6t_ops[3]); - cleanup_hook2: - nf_unregister_hook(&ip6t_ops[2]); - cleanup_hook1: - nf_unregister_hook(&ip6t_ops[1]); - cleanup_hook0: - nf_unregister_hook(&ip6t_ops[0]); cleanup_table: ip6t_unregister_table(&packet_mangler); - return ret; } static void __exit ip6table_mangle_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ip6t_ops[i]); - + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); ip6t_unregister_table(&packet_mangler); } diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 54d1fffd62ba..61a7c58e99f8 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -152,31 +152,20 @@ static int __init ip6table_raw_init(void) return ret; /* Register hooks */ - ret = nf_register_hook(&ip6t_ops[0]); + ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); if (ret < 0) goto cleanup_table; - ret = nf_register_hook(&ip6t_ops[1]); - if (ret < 0) - goto cleanup_hook0; - return ret; - cleanup_hook0: - nf_unregister_hook(&ip6t_ops[0]); cleanup_table: ip6t_unregister_table(&packet_raw); - return ret; } static void __exit ip6table_raw_fini(void) { - unsigned int i; - - for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) - nf_unregister_hook(&ip6t_ops[i]); - + nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); ip6t_unregister_table(&packet_raw); } diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index c8b5a96cbb0f..93bae36f2663 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -286,55 +286,49 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum, return ipv6_conntrack_in(hooknum, pskb, in, out, okfn); } -/* Connection tracking may drop packets, but never alters them, so - make it the first hook. */ -static struct nf_hook_ops ipv6_conntrack_defrag_ops = { - .hook = ipv6_defrag, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ipv6_conntrack_in_ops = { - .hook = ipv6_conntrack_in, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_PRE_ROUTING, - .priority = NF_IP6_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ipv6_conntrack_local_out_ops = { - .hook = ipv6_conntrack_local, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = { - .hook = ipv6_defrag, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_OUT, - .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, -}; - -/* Refragmenter; last chance. */ -static struct nf_hook_ops ipv6_conntrack_out_ops = { - .hook = ipv6_confirm, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_POST_ROUTING, - .priority = NF_IP6_PRI_LAST, -}; - -static struct nf_hook_ops ipv6_conntrack_local_in_ops = { - .hook = ipv6_confirm, - .owner = THIS_MODULE, - .pf = PF_INET6, - .hooknum = NF_IP6_LOCAL_IN, - .priority = NF_IP6_PRI_LAST-1, +static struct nf_hook_ops ipv6_conntrack_ops[] = { + { + .hook = ipv6_defrag, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ipv6_conntrack_in, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_CONNTRACK, + }, + { + .hook = ipv6_conntrack_local, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_CONNTRACK, + }, + { + .hook = ipv6_defrag, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ipv6_confirm, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_POST_ROUTING, + .priority = NF_IP6_PRI_LAST, + }, + { + .hook = ipv6_confirm, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_IN, + .priority = NF_IP6_PRI_LAST-1, + }, }; #ifdef CONFIG_SYSCTL @@ -470,16 +464,21 @@ extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6; extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6; extern int nf_ct_frag6_init(void); extern void nf_ct_frag6_cleanup(void); -static int init_or_cleanup(int init) + +MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); + +static int __init nf_conntrack_l3proto_ipv6_init(void) { int ret = 0; - if (!init) goto cleanup; + need_conntrack(); ret = nf_ct_frag6_init(); if (ret < 0) { printk("nf_conntrack_ipv6: can't initialize frag6.\n"); - goto cleanup_nothing; + return ret; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6); if (ret < 0) { @@ -505,71 +504,27 @@ static int init_or_cleanup(int init) goto cleanup_icmpv6; } - ret = nf_register_hook(&ipv6_conntrack_defrag_ops); + ret = nf_register_hooks(ipv6_conntrack_ops, + ARRAY_SIZE(ipv6_conntrack_ops)); if (ret < 0) { printk("nf_conntrack_ipv6: can't register pre-routing defrag " "hook.\n"); goto cleanup_ipv6; } - - ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register local_out defrag " - "hook.\n"); - goto cleanup_defragops; - } - - ret = nf_register_hook(&ipv6_conntrack_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register pre-routing hook.\n"); - goto cleanup_defraglocalops; - } - - ret = nf_register_hook(&ipv6_conntrack_local_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register local out hook.\n"); - goto cleanup_inops; - } - - ret = nf_register_hook(&ipv6_conntrack_out_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register post-routing hook.\n"); - goto cleanup_inandlocalops; - } - - ret = nf_register_hook(&ipv6_conntrack_local_in_ops); - if (ret < 0) { - printk("nf_conntrack_ipv6: can't register local in hook.\n"); - goto cleanup_inoutandlocalops; - } - #ifdef CONFIG_SYSCTL nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); if (nf_ct_ipv6_sysctl_header == NULL) { printk("nf_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; - goto cleanup_localinops; + goto cleanup_hooks; } #endif return ret; - cleanup: - synchronize_net(); #ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_ipv6_sysctl_header); - cleanup_localinops: + cleanup_hooks: + nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); #endif - nf_unregister_hook(&ipv6_conntrack_local_in_ops); - cleanup_inoutandlocalops: - nf_unregister_hook(&ipv6_conntrack_out_ops); - cleanup_inandlocalops: - nf_unregister_hook(&ipv6_conntrack_local_out_ops); - cleanup_inops: - nf_unregister_hook(&ipv6_conntrack_in_ops); - cleanup_defraglocalops: - nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops); - cleanup_defragops: - nf_unregister_hook(&ipv6_conntrack_defrag_ops); cleanup_ipv6: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); cleanup_icmpv6: @@ -580,23 +535,21 @@ static int init_or_cleanup(int init) nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); cleanup_frag6: nf_ct_frag6_cleanup(); - cleanup_nothing: return ret; } -MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); - -static int __init nf_conntrack_l3proto_ipv6_init(void) -{ - need_conntrack(); - return init_or_cleanup(1); -} - static void __exit nf_conntrack_l3proto_ipv6_fini(void) { - init_or_cleanup(0); + synchronize_net(); +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(nf_ct_ipv6_sysctl_header); +#endif + nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); + nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6); + nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); + nf_ct_frag6_cleanup(); } module_init(nf_conntrack_l3proto_ipv6_init); diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 09945c333055..86c6703265d0 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -233,21 +233,13 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff, return -NF_ACCEPT; } - if (hooknum != NF_IP6_PRE_ROUTING) - goto skipped; - - /* Ignore it if the checksum's bogus. */ - if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr, - skb->len - dataoff, IPPROTO_ICMPV6, - skb_checksum(skb, dataoff, - skb->len - dataoff, 0))) { + if (hooknum == NF_IP6_PRE_ROUTING && + nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, "nf_ct_icmpv6: ICMPv6 checksum failed\n"); return -NF_ACCEPT; } -skipped: - /* is not error message ? */ if (icmp6h->icmp6_type >= 128) return NF_ACCEPT; diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 4238b1ed8860..779ddf77f4d4 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -38,7 +38,7 @@ static int fold_prot_inuse(struct proto *proto) int res = 0; int cpu; - for_each_cpu(cpu) + for_each_possible_cpu(cpu) res += proto->stats[cpu].inuse; return res; @@ -140,7 +140,7 @@ fold_field(void *mib[], int offt) unsigned long res = 0; int i; - for_each_cpu(i) { + for_each_possible_cpu(i) { res += *(((unsigned long *)per_cpu_ptr(mib[0], i)) + offt); res += *(((unsigned long *)per_cpu_ptr(mib[1], i)) + offt); } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c2d3e17beae6..6578c3080f47 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -397,7 +397,7 @@ static int ipip6_rcv(struct sk_buff *skb) return 0; } - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); kfree_skb(skb); read_unlock(&ipip6_lock); out: diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 5659b52284bd..0ef9a35798d1 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -19,11 +19,13 @@ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> */ +#include <linux/icmpv6.h> #include <linux/init.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/netdevice.h> #include <linux/skbuff.h> +#include <net/ipv6.h> #include <net/protocol.h> #include <net/xfrm.h> @@ -87,10 +89,16 @@ static int tunnel6_rcv(struct sk_buff **pskb) struct sk_buff *skb = *pskb; struct xfrm6_tunnel *handler; + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + for (handler = tunnel6_handlers; handler; handler = handler->next) if (!handler->handler(skb)) return 0; + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); + +drop: kfree_skb(skb); return 0; } |