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