diff options
Diffstat (limited to 'net/ipv6/af_inet6.c')
-rw-r--r-- | net/ipv6/af_inet6.c | 221 |
1 files changed, 177 insertions, 44 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index f0aa97738746..1731b0abf7f5 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -92,9 +92,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol) | |||
92 | int try_loading_module = 0; | 92 | int try_loading_module = 0; |
93 | int err; | 93 | int err; |
94 | 94 | ||
95 | if (net != &init_net) | ||
96 | return -EAFNOSUPPORT; | ||
97 | |||
98 | if (sock->type != SOCK_RAW && | 95 | if (sock->type != SOCK_RAW && |
99 | sock->type != SOCK_DGRAM && | 96 | sock->type != SOCK_DGRAM && |
100 | !inet_ehash_secret) | 97 | !inet_ehash_secret) |
@@ -248,6 +245,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
248 | struct sock *sk = sock->sk; | 245 | struct sock *sk = sock->sk; |
249 | struct inet_sock *inet = inet_sk(sk); | 246 | struct inet_sock *inet = inet_sk(sk); |
250 | struct ipv6_pinfo *np = inet6_sk(sk); | 247 | struct ipv6_pinfo *np = inet6_sk(sk); |
248 | struct net *net = sock_net(sk); | ||
251 | __be32 v4addr = 0; | 249 | __be32 v4addr = 0; |
252 | unsigned short snum; | 250 | unsigned short snum; |
253 | int addr_type = 0; | 251 | int addr_type = 0; |
@@ -278,7 +276,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
278 | /* Check if the address belongs to the host. */ | 276 | /* Check if the address belongs to the host. */ |
279 | if (addr_type == IPV6_ADDR_MAPPED) { | 277 | if (addr_type == IPV6_ADDR_MAPPED) { |
280 | v4addr = addr->sin6_addr.s6_addr32[3]; | 278 | v4addr = addr->sin6_addr.s6_addr32[3]; |
281 | if (inet_addr_type(&init_net, v4addr) != RTN_LOCAL) { | 279 | if (inet_addr_type(net, v4addr) != RTN_LOCAL) { |
282 | err = -EADDRNOTAVAIL; | 280 | err = -EADDRNOTAVAIL; |
283 | goto out; | 281 | goto out; |
284 | } | 282 | } |
@@ -300,7 +298,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
300 | err = -EINVAL; | 298 | err = -EINVAL; |
301 | goto out; | 299 | goto out; |
302 | } | 300 | } |
303 | dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); | 301 | dev = dev_get_by_index(net, sk->sk_bound_dev_if); |
304 | if (!dev) { | 302 | if (!dev) { |
305 | err = -ENODEV; | 303 | err = -ENODEV; |
306 | goto out; | 304 | goto out; |
@@ -312,7 +310,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
312 | */ | 310 | */ |
313 | v4addr = LOOPBACK4_IPV6; | 311 | v4addr = LOOPBACK4_IPV6; |
314 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { | 312 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { |
315 | if (!ipv6_chk_addr(&init_net, &addr->sin6_addr, | 313 | if (!ipv6_chk_addr(net, &addr->sin6_addr, |
316 | dev, 0)) { | 314 | dev, 0)) { |
317 | if (dev) | 315 | if (dev) |
318 | dev_put(dev); | 316 | dev_put(dev); |
@@ -440,6 +438,7 @@ EXPORT_SYMBOL(inet6_getname); | |||
440 | int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | 438 | int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
441 | { | 439 | { |
442 | struct sock *sk = sock->sk; | 440 | struct sock *sk = sock->sk; |
441 | struct net *net = sock_net(sk); | ||
443 | 442 | ||
444 | switch(cmd) | 443 | switch(cmd) |
445 | { | 444 | { |
@@ -452,14 +451,14 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
452 | case SIOCADDRT: | 451 | case SIOCADDRT: |
453 | case SIOCDELRT: | 452 | case SIOCDELRT: |
454 | 453 | ||
455 | return(ipv6_route_ioctl(cmd,(void __user *)arg)); | 454 | return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); |
456 | 455 | ||
457 | case SIOCSIFADDR: | 456 | case SIOCSIFADDR: |
458 | return addrconf_add_ifaddr((void __user *) arg); | 457 | return addrconf_add_ifaddr(net, (void __user *) arg); |
459 | case SIOCDIFADDR: | 458 | case SIOCDIFADDR: |
460 | return addrconf_del_ifaddr((void __user *) arg); | 459 | return addrconf_del_ifaddr(net, (void __user *) arg); |
461 | case SIOCSIFDSTADDR: | 460 | case SIOCSIFDSTADDR: |
462 | return addrconf_set_dstaddr((void __user *) arg); | 461 | return addrconf_set_dstaddr(net, (void __user *) arg); |
463 | default: | 462 | default: |
464 | if (!sk->sk_prot->ioctl) | 463 | if (!sk->sk_prot->ioctl) |
465 | return -ENOIOCTLCMD; | 464 | return -ENOIOCTLCMD; |
@@ -678,6 +677,129 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) | |||
678 | 677 | ||
679 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); | 678 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); |
680 | 679 | ||
680 | static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, | ||
681 | int proto) | ||
682 | { | ||
683 | struct inet6_protocol *ops = NULL; | ||
684 | |||
685 | for (;;) { | ||
686 | struct ipv6_opt_hdr *opth; | ||
687 | int len; | ||
688 | |||
689 | if (proto != NEXTHDR_HOP) { | ||
690 | ops = rcu_dereference(inet6_protos[proto]); | ||
691 | |||
692 | if (unlikely(!ops)) | ||
693 | break; | ||
694 | |||
695 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
696 | break; | ||
697 | } | ||
698 | |||
699 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
700 | break; | ||
701 | |||
702 | opth = (void *)skb->data; | ||
703 | len = ipv6_optlen(opth); | ||
704 | |||
705 | if (unlikely(!pskb_may_pull(skb, len))) | ||
706 | break; | ||
707 | |||
708 | proto = opth->nexthdr; | ||
709 | __skb_pull(skb, len); | ||
710 | } | ||
711 | |||
712 | return ops; | ||
713 | } | ||
714 | |||
715 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
716 | { | ||
717 | struct ipv6hdr *ipv6h; | ||
718 | struct inet6_protocol *ops; | ||
719 | int err = -EINVAL; | ||
720 | |||
721 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
722 | goto out; | ||
723 | |||
724 | ipv6h = ipv6_hdr(skb); | ||
725 | __skb_pull(skb, sizeof(*ipv6h)); | ||
726 | err = -EPROTONOSUPPORT; | ||
727 | |||
728 | rcu_read_lock(); | ||
729 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
730 | if (likely(ops && ops->gso_send_check)) { | ||
731 | skb_reset_transport_header(skb); | ||
732 | err = ops->gso_send_check(skb); | ||
733 | } | ||
734 | rcu_read_unlock(); | ||
735 | |||
736 | out: | ||
737 | return err; | ||
738 | } | ||
739 | |||
740 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | ||
741 | { | ||
742 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
743 | struct ipv6hdr *ipv6h; | ||
744 | struct inet6_protocol *ops; | ||
745 | |||
746 | if (!(features & NETIF_F_V6_CSUM)) | ||
747 | features &= ~NETIF_F_SG; | ||
748 | |||
749 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
750 | ~(SKB_GSO_UDP | | ||
751 | SKB_GSO_DODGY | | ||
752 | SKB_GSO_TCP_ECN | | ||
753 | SKB_GSO_TCPV6 | | ||
754 | 0))) | ||
755 | goto out; | ||
756 | |||
757 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
758 | goto out; | ||
759 | |||
760 | ipv6h = ipv6_hdr(skb); | ||
761 | __skb_pull(skb, sizeof(*ipv6h)); | ||
762 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
763 | |||
764 | rcu_read_lock(); | ||
765 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
766 | if (likely(ops && ops->gso_segment)) { | ||
767 | skb_reset_transport_header(skb); | ||
768 | segs = ops->gso_segment(skb, features); | ||
769 | } | ||
770 | rcu_read_unlock(); | ||
771 | |||
772 | if (unlikely(IS_ERR(segs))) | ||
773 | goto out; | ||
774 | |||
775 | for (skb = segs; skb; skb = skb->next) { | ||
776 | ipv6h = ipv6_hdr(skb); | ||
777 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | ||
778 | sizeof(*ipv6h)); | ||
779 | } | ||
780 | |||
781 | out: | ||
782 | return segs; | ||
783 | } | ||
784 | |||
785 | static struct packet_type ipv6_packet_type = { | ||
786 | .type = __constant_htons(ETH_P_IPV6), | ||
787 | .func = ipv6_rcv, | ||
788 | .gso_send_check = ipv6_gso_send_check, | ||
789 | .gso_segment = ipv6_gso_segment, | ||
790 | }; | ||
791 | |||
792 | static int __init ipv6_packet_init(void) | ||
793 | { | ||
794 | dev_add_pack(&ipv6_packet_type); | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | static void ipv6_packet_cleanup(void) | ||
799 | { | ||
800 | dev_remove_pack(&ipv6_packet_type); | ||
801 | } | ||
802 | |||
681 | static int __init init_ipv6_mibs(void) | 803 | static int __init init_ipv6_mibs(void) |
682 | { | 804 | { |
683 | if (snmp_mib_init((void **)ipv6_statistics, | 805 | if (snmp_mib_init((void **)ipv6_statistics, |
@@ -720,6 +842,8 @@ static void cleanup_ipv6_mibs(void) | |||
720 | 842 | ||
721 | static int inet6_net_init(struct net *net) | 843 | static int inet6_net_init(struct net *net) |
722 | { | 844 | { |
845 | int err = 0; | ||
846 | |||
723 | net->ipv6.sysctl.bindv6only = 0; | 847 | net->ipv6.sysctl.bindv6only = 0; |
724 | net->ipv6.sysctl.flush_delay = 0; | 848 | net->ipv6.sysctl.flush_delay = 0; |
725 | net->ipv6.sysctl.ip6_rt_max_size = 4096; | 849 | net->ipv6.sysctl.ip6_rt_max_size = 4096; |
@@ -731,12 +855,36 @@ static int inet6_net_init(struct net *net) | |||
731 | net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; | 855 | net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; |
732 | net->ipv6.sysctl.icmpv6_time = 1*HZ; | 856 | net->ipv6.sysctl.icmpv6_time = 1*HZ; |
733 | 857 | ||
734 | return 0; | 858 | #ifdef CONFIG_PROC_FS |
859 | err = udp6_proc_init(net); | ||
860 | if (err) | ||
861 | goto out; | ||
862 | err = tcp6_proc_init(net); | ||
863 | if (err) | ||
864 | goto proc_tcp6_fail; | ||
865 | err = ac6_proc_init(net); | ||
866 | if (err) | ||
867 | goto proc_ac6_fail; | ||
868 | out: | ||
869 | #endif | ||
870 | return err; | ||
871 | |||
872 | #ifdef CONFIG_PROC_FS | ||
873 | proc_ac6_fail: | ||
874 | tcp6_proc_exit(net); | ||
875 | proc_tcp6_fail: | ||
876 | udp6_proc_exit(net); | ||
877 | goto out; | ||
878 | #endif | ||
735 | } | 879 | } |
736 | 880 | ||
737 | static void inet6_net_exit(struct net *net) | 881 | static void inet6_net_exit(struct net *net) |
738 | { | 882 | { |
739 | return; | 883 | #ifdef CONFIG_PROC_FS |
884 | udp6_proc_exit(net); | ||
885 | tcp6_proc_exit(net); | ||
886 | ac6_proc_exit(net); | ||
887 | #endif | ||
740 | } | 888 | } |
741 | 889 | ||
742 | static struct pernet_operations inet6_net_ops = { | 890 | static struct pernet_operations inet6_net_ops = { |
@@ -802,19 +950,13 @@ static int __init inet6_init(void) | |||
802 | err = register_pernet_subsys(&inet6_net_ops); | 950 | err = register_pernet_subsys(&inet6_net_ops); |
803 | if (err) | 951 | if (err) |
804 | goto register_pernet_fail; | 952 | goto register_pernet_fail; |
805 | 953 | err = icmpv6_init(); | |
806 | #ifdef CONFIG_SYSCTL | ||
807 | err = ipv6_sysctl_register(); | ||
808 | if (err) | ||
809 | goto sysctl_fail; | ||
810 | #endif | ||
811 | err = icmpv6_init(&inet6_family_ops); | ||
812 | if (err) | 954 | if (err) |
813 | goto icmp_fail; | 955 | goto icmp_fail; |
814 | err = ndisc_init(&inet6_family_ops); | 956 | err = ndisc_init(); |
815 | if (err) | 957 | if (err) |
816 | goto ndisc_fail; | 958 | goto ndisc_fail; |
817 | err = igmp6_init(&inet6_family_ops); | 959 | err = igmp6_init(); |
818 | if (err) | 960 | if (err) |
819 | goto igmp_fail; | 961 | goto igmp_fail; |
820 | err = ipv6_netfilter_init(); | 962 | err = ipv6_netfilter_init(); |
@@ -825,17 +967,10 @@ static int __init inet6_init(void) | |||
825 | err = -ENOMEM; | 967 | err = -ENOMEM; |
826 | if (raw6_proc_init()) | 968 | if (raw6_proc_init()) |
827 | goto proc_raw6_fail; | 969 | goto proc_raw6_fail; |
828 | if (tcp6_proc_init()) | ||
829 | goto proc_tcp6_fail; | ||
830 | if (udp6_proc_init()) | ||
831 | goto proc_udp6_fail; | ||
832 | if (udplite6_proc_init()) | 970 | if (udplite6_proc_init()) |
833 | goto proc_udplite6_fail; | 971 | goto proc_udplite6_fail; |
834 | if (ipv6_misc_proc_init()) | 972 | if (ipv6_misc_proc_init()) |
835 | goto proc_misc6_fail; | 973 | goto proc_misc6_fail; |
836 | |||
837 | if (ac6_proc_init()) | ||
838 | goto proc_anycast6_fail; | ||
839 | if (if6_proc_init()) | 974 | if (if6_proc_init()) |
840 | goto proc_if6_fail; | 975 | goto proc_if6_fail; |
841 | #endif | 976 | #endif |
@@ -874,9 +1009,19 @@ static int __init inet6_init(void) | |||
874 | err = ipv6_packet_init(); | 1009 | err = ipv6_packet_init(); |
875 | if (err) | 1010 | if (err) |
876 | goto ipv6_packet_fail; | 1011 | goto ipv6_packet_fail; |
1012 | |||
1013 | #ifdef CONFIG_SYSCTL | ||
1014 | err = ipv6_sysctl_register(); | ||
1015 | if (err) | ||
1016 | goto sysctl_fail; | ||
1017 | #endif | ||
877 | out: | 1018 | out: |
878 | return err; | 1019 | return err; |
879 | 1020 | ||
1021 | #ifdef CONFIG_SYSCTL | ||
1022 | sysctl_fail: | ||
1023 | ipv6_packet_cleanup(); | ||
1024 | #endif | ||
880 | ipv6_packet_fail: | 1025 | ipv6_packet_fail: |
881 | tcpv6_exit(); | 1026 | tcpv6_exit(); |
882 | tcpv6_fail: | 1027 | tcpv6_fail: |
@@ -897,16 +1042,10 @@ ip6_route_fail: | |||
897 | #ifdef CONFIG_PROC_FS | 1042 | #ifdef CONFIG_PROC_FS |
898 | if6_proc_exit(); | 1043 | if6_proc_exit(); |
899 | proc_if6_fail: | 1044 | proc_if6_fail: |
900 | ac6_proc_exit(); | ||
901 | proc_anycast6_fail: | ||
902 | ipv6_misc_proc_exit(); | 1045 | ipv6_misc_proc_exit(); |
903 | proc_misc6_fail: | 1046 | proc_misc6_fail: |
904 | udplite6_proc_exit(); | 1047 | udplite6_proc_exit(); |
905 | proc_udplite6_fail: | 1048 | proc_udplite6_fail: |
906 | udp6_proc_exit(); | ||
907 | proc_udp6_fail: | ||
908 | tcp6_proc_exit(); | ||
909 | proc_tcp6_fail: | ||
910 | raw6_proc_exit(); | 1049 | raw6_proc_exit(); |
911 | proc_raw6_fail: | 1050 | proc_raw6_fail: |
912 | #endif | 1051 | #endif |
@@ -918,10 +1057,6 @@ igmp_fail: | |||
918 | ndisc_fail: | 1057 | ndisc_fail: |
919 | icmpv6_cleanup(); | 1058 | icmpv6_cleanup(); |
920 | icmp_fail: | 1059 | icmp_fail: |
921 | #ifdef CONFIG_SYSCTL | ||
922 | ipv6_sysctl_unregister(); | ||
923 | sysctl_fail: | ||
924 | #endif | ||
925 | unregister_pernet_subsys(&inet6_net_ops); | 1060 | unregister_pernet_subsys(&inet6_net_ops); |
926 | register_pernet_fail: | 1061 | register_pernet_fail: |
927 | cleanup_ipv6_mibs(); | 1062 | cleanup_ipv6_mibs(); |
@@ -949,6 +1084,9 @@ static void __exit inet6_exit(void) | |||
949 | /* Disallow any further netlink messages */ | 1084 | /* Disallow any further netlink messages */ |
950 | rtnl_unregister_all(PF_INET6); | 1085 | rtnl_unregister_all(PF_INET6); |
951 | 1086 | ||
1087 | #ifdef CONFIG_SYSCTL | ||
1088 | ipv6_sysctl_unregister(); | ||
1089 | #endif | ||
952 | udpv6_exit(); | 1090 | udpv6_exit(); |
953 | udplitev6_exit(); | 1091 | udplitev6_exit(); |
954 | tcpv6_exit(); | 1092 | tcpv6_exit(); |
@@ -964,11 +1102,8 @@ static void __exit inet6_exit(void) | |||
964 | 1102 | ||
965 | /* Cleanup code parts. */ | 1103 | /* Cleanup code parts. */ |
966 | if6_proc_exit(); | 1104 | if6_proc_exit(); |
967 | ac6_proc_exit(); | ||
968 | ipv6_misc_proc_exit(); | 1105 | ipv6_misc_proc_exit(); |
969 | udplite6_proc_exit(); | 1106 | udplite6_proc_exit(); |
970 | udp6_proc_exit(); | ||
971 | tcp6_proc_exit(); | ||
972 | raw6_proc_exit(); | 1107 | raw6_proc_exit(); |
973 | #endif | 1108 | #endif |
974 | ipv6_netfilter_fini(); | 1109 | ipv6_netfilter_fini(); |
@@ -976,9 +1111,7 @@ static void __exit inet6_exit(void) | |||
976 | ndisc_cleanup(); | 1111 | ndisc_cleanup(); |
977 | icmpv6_cleanup(); | 1112 | icmpv6_cleanup(); |
978 | rawv6_exit(); | 1113 | rawv6_exit(); |
979 | #ifdef CONFIG_SYSCTL | 1114 | |
980 | ipv6_sysctl_unregister(); | ||
981 | #endif | ||
982 | unregister_pernet_subsys(&inet6_net_ops); | 1115 | unregister_pernet_subsys(&inet6_net_ops); |
983 | cleanup_ipv6_mibs(); | 1116 | cleanup_ipv6_mibs(); |
984 | proto_unregister(&rawv6_prot); | 1117 | proto_unregister(&rawv6_prot); |