diff options
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 163 |
1 files changed, 133 insertions, 30 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f7142ba519ab..988eac58e9d1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -109,19 +109,13 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) | |||
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | 112 | static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
113 | char __user *optval, int optlen) | 113 | char __user *optval, int optlen) |
114 | { | 114 | { |
115 | struct ipv6_pinfo *np = inet6_sk(sk); | 115 | struct ipv6_pinfo *np = inet6_sk(sk); |
116 | int val, valbool; | 116 | int val, valbool; |
117 | int retv = -ENOPROTOOPT; | 117 | int retv = -ENOPROTOOPT; |
118 | 118 | ||
119 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
120 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
121 | |||
122 | if(level!=SOL_IPV6) | ||
123 | goto out; | ||
124 | |||
125 | if (optval == NULL) | 119 | if (optval == NULL) |
126 | val=0; | 120 | val=0; |
127 | else if (get_user(val, (int __user *) optval)) | 121 | else if (get_user(val, (int __user *) optval)) |
@@ -613,17 +607,9 @@ done: | |||
613 | retv = xfrm_user_policy(sk, optname, optval, optlen); | 607 | retv = xfrm_user_policy(sk, optname, optval, optlen); |
614 | break; | 608 | break; |
615 | 609 | ||
616 | #ifdef CONFIG_NETFILTER | ||
617 | default: | ||
618 | retv = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
619 | optlen); | ||
620 | break; | ||
621 | #endif | ||
622 | |||
623 | } | 610 | } |
624 | release_sock(sk); | 611 | release_sock(sk); |
625 | 612 | ||
626 | out: | ||
627 | return retv; | 613 | return retv; |
628 | 614 | ||
629 | e_inval: | 615 | e_inval: |
@@ -631,6 +617,65 @@ e_inval: | |||
631 | return -EINVAL; | 617 | return -EINVAL; |
632 | } | 618 | } |
633 | 619 | ||
620 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
621 | char __user *optval, int optlen) | ||
622 | { | ||
623 | int err; | ||
624 | |||
625 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
626 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
627 | |||
628 | if (level != SOL_IPV6) | ||
629 | return -ENOPROTOOPT; | ||
630 | |||
631 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
632 | #ifdef CONFIG_NETFILTER | ||
633 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
634 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
635 | optname != IPV6_XFRM_POLICY) { | ||
636 | lock_sock(sk); | ||
637 | err = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
638 | optlen); | ||
639 | release_sock(sk); | ||
640 | } | ||
641 | #endif | ||
642 | return err; | ||
643 | } | ||
644 | |||
645 | |||
646 | #ifdef CONFIG_COMPAT | ||
647 | int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
648 | char __user *optval, int optlen) | ||
649 | { | ||
650 | int err; | ||
651 | |||
652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
653 | if (udp_prot.compat_setsockopt) | ||
654 | return udp_prot.compat_setsockopt(sk, level, | ||
655 | optname, optval, optlen); | ||
656 | else | ||
657 | return udp_prot.setsockopt(sk, level, | ||
658 | optname, optval, optlen); | ||
659 | } | ||
660 | |||
661 | if (level != SOL_IPV6) | ||
662 | return -ENOPROTOOPT; | ||
663 | |||
664 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
665 | #ifdef CONFIG_NETFILTER | ||
666 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
667 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
668 | optname != IPV6_XFRM_POLICY) { | ||
669 | lock_sock(sk); | ||
670 | err = compat_nf_setsockopt(sk, PF_INET6, optname, optval, | ||
671 | optlen); | ||
672 | release_sock(sk); | ||
673 | } | ||
674 | #endif | ||
675 | return err; | ||
676 | } | ||
677 | #endif | ||
678 | |||
634 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | 679 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, |
635 | char __user *optval, int len) | 680 | char __user *optval, int len) |
636 | { | 681 | { |
@@ -642,17 +687,13 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | |||
642 | return len; | 687 | return len; |
643 | } | 688 | } |
644 | 689 | ||
645 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | 690 | static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
646 | char __user *optval, int __user *optlen) | 691 | char __user *optval, int __user *optlen) |
647 | { | 692 | { |
648 | struct ipv6_pinfo *np = inet6_sk(sk); | 693 | struct ipv6_pinfo *np = inet6_sk(sk); |
649 | int len; | 694 | int len; |
650 | int val; | 695 | int val; |
651 | 696 | ||
652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
653 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
654 | if(level!=SOL_IPV6) | ||
655 | return -ENOPROTOOPT; | ||
656 | if (get_user(len, optlen)) | 697 | if (get_user(len, optlen)) |
657 | return -EFAULT; | 698 | return -EFAULT; |
658 | switch (optname) { | 699 | switch (optname) { |
@@ -842,17 +883,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
842 | break; | 883 | break; |
843 | 884 | ||
844 | default: | 885 | default: |
845 | #ifdef CONFIG_NETFILTER | ||
846 | lock_sock(sk); | ||
847 | val = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
848 | &len); | ||
849 | release_sock(sk); | ||
850 | if (val >= 0) | ||
851 | val = put_user(len, optlen); | ||
852 | return val; | ||
853 | #else | ||
854 | return -EINVAL; | 886 | return -EINVAL; |
855 | #endif | ||
856 | } | 887 | } |
857 | len = min_t(unsigned int, sizeof(int), len); | 888 | len = min_t(unsigned int, sizeof(int), len); |
858 | if(put_user(len, optlen)) | 889 | if(put_user(len, optlen)) |
@@ -862,6 +893,78 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
862 | return 0; | 893 | return 0; |
863 | } | 894 | } |
864 | 895 | ||
896 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
897 | char __user *optval, int __user *optlen) | ||
898 | { | ||
899 | int err; | ||
900 | |||
901 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
902 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
903 | |||
904 | if(level != SOL_IPV6) | ||
905 | return -ENOPROTOOPT; | ||
906 | |||
907 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
908 | #ifdef CONFIG_NETFILTER | ||
909 | /* we need to exclude all possible EINVALs except default case */ | ||
910 | if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM && | ||
911 | optname != MCAST_MSFILTER) { | ||
912 | int len; | ||
913 | |||
914 | if (get_user(len, optlen)) | ||
915 | return -EFAULT; | ||
916 | |||
917 | lock_sock(sk); | ||
918 | err = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
919 | &len); | ||
920 | release_sock(sk); | ||
921 | if (err >= 0) | ||
922 | err = put_user(len, optlen); | ||
923 | } | ||
924 | #endif | ||
925 | return err; | ||
926 | } | ||
927 | |||
928 | #ifdef CONFIG_COMPAT | ||
929 | int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
930 | char __user *optval, int __user *optlen) | ||
931 | { | ||
932 | int err; | ||
933 | |||
934 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
935 | if (udp_prot.compat_getsockopt) | ||
936 | return udp_prot.compat_getsockopt(sk, level, | ||
937 | optname, optval, optlen); | ||
938 | else | ||
939 | return udp_prot.getsockopt(sk, level, | ||
940 | optname, optval, optlen); | ||
941 | } | ||
942 | |||
943 | if(level != SOL_IPV6) | ||
944 | return -ENOPROTOOPT; | ||
945 | |||
946 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
947 | #ifdef CONFIG_NETFILTER | ||
948 | /* we need to exclude all possible EINVALs except default case */ | ||
949 | if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM && | ||
950 | optname != MCAST_MSFILTER) { | ||
951 | int len; | ||
952 | |||
953 | if (get_user(len, optlen)) | ||
954 | return -EFAULT; | ||
955 | |||
956 | lock_sock(sk); | ||
957 | err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, | ||
958 | &len); | ||
959 | release_sock(sk); | ||
960 | if (err >= 0) | ||
961 | err = put_user(len, optlen); | ||
962 | } | ||
963 | #endif | ||
964 | return err; | ||
965 | } | ||
966 | #endif | ||
967 | |||
865 | void __init ipv6_packet_init(void) | 968 | void __init ipv6_packet_init(void) |
866 | { | 969 | { |
867 | dev_add_pack(&ipv6_packet_type); | 970 | dev_add_pack(&ipv6_packet_type); |