diff options
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
-rw-r--r-- | net/ipv4/ip_sockglue.c | 142 |
1 files changed, 123 insertions, 19 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index b5c4f61518e8..49ff1cd4e1c9 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -399,14 +399,12 @@ out: | |||
399 | * an IP socket. | 399 | * an IP socket. |
400 | */ | 400 | */ |
401 | 401 | ||
402 | int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) | 402 | static int do_ip_setsockopt(struct sock *sk, int level, |
403 | int optname, char __user *optval, int optlen) | ||
403 | { | 404 | { |
404 | struct inet_sock *inet = inet_sk(sk); | 405 | struct inet_sock *inet = inet_sk(sk); |
405 | int val=0,err; | 406 | int val=0,err; |
406 | 407 | ||
407 | if (level != SOL_IP) | ||
408 | return -ENOPROTOOPT; | ||
409 | |||
410 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | | 408 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | |
411 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | | 409 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | |
412 | (1<<IP_RETOPTS) | (1<<IP_TOS) | | 410 | (1<<IP_RETOPTS) | (1<<IP_TOS) | |
@@ -875,12 +873,7 @@ mc_msf_out: | |||
875 | break; | 873 | break; |
876 | 874 | ||
877 | default: | 875 | default: |
878 | #ifdef CONFIG_NETFILTER | ||
879 | err = nf_setsockopt(sk, PF_INET, optname, optval, | ||
880 | optlen); | ||
881 | #else | ||
882 | err = -ENOPROTOOPT; | 876 | err = -ENOPROTOOPT; |
883 | #endif | ||
884 | break; | 877 | break; |
885 | } | 878 | } |
886 | release_sock(sk); | 879 | release_sock(sk); |
@@ -891,12 +884,66 @@ e_inval: | |||
891 | return -EINVAL; | 884 | return -EINVAL; |
892 | } | 885 | } |
893 | 886 | ||
887 | int ip_setsockopt(struct sock *sk, int level, | ||
888 | int optname, char __user *optval, int optlen) | ||
889 | { | ||
890 | int err; | ||
891 | |||
892 | if (level != SOL_IP) | ||
893 | return -ENOPROTOOPT; | ||
894 | |||
895 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
896 | #ifdef CONFIG_NETFILTER | ||
897 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
898 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
899 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
900 | #ifdef CONFIG_IP_MROUTE | ||
901 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
902 | #endif | ||
903 | ) { | ||
904 | lock_sock(sk); | ||
905 | err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); | ||
906 | release_sock(sk); | ||
907 | } | ||
908 | #endif | ||
909 | return err; | ||
910 | } | ||
911 | |||
912 | #ifdef CONFIG_COMPAT | ||
913 | int compat_ip_setsockopt(struct sock *sk, int level, | ||
914 | int optname, char __user *optval, int optlen) | ||
915 | { | ||
916 | int err; | ||
917 | |||
918 | if (level != SOL_IP) | ||
919 | return -ENOPROTOOPT; | ||
920 | |||
921 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
922 | #ifdef CONFIG_NETFILTER | ||
923 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
924 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
925 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
926 | #ifdef CONFIG_IP_MROUTE | ||
927 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
928 | #endif | ||
929 | ) { | ||
930 | lock_sock(sk); | ||
931 | err = compat_nf_setsockopt(sk, PF_INET, | ||
932 | optname, optval, optlen); | ||
933 | release_sock(sk); | ||
934 | } | ||
935 | #endif | ||
936 | return err; | ||
937 | } | ||
938 | #endif | ||
939 | |||
894 | /* | 940 | /* |
895 | * Get the options. Note for future reference. The GET of IP options gets the | 941 | * Get the options. Note for future reference. The GET of IP options gets the |
896 | * _received_ ones. The set sets the _sent_ ones. | 942 | * _received_ ones. The set sets the _sent_ ones. |
897 | */ | 943 | */ |
898 | 944 | ||
899 | int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) | 945 | static int do_ip_getsockopt(struct sock *sk, int level, int optname, |
946 | char __user *optval, int __user *optlen) | ||
900 | { | 947 | { |
901 | struct inet_sock *inet = inet_sk(sk); | 948 | struct inet_sock *inet = inet_sk(sk); |
902 | int val; | 949 | int val; |
@@ -1080,17 +1127,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1080 | val = inet->freebind; | 1127 | val = inet->freebind; |
1081 | break; | 1128 | break; |
1082 | default: | 1129 | default: |
1083 | #ifdef CONFIG_NETFILTER | ||
1084 | val = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1085 | &len); | ||
1086 | release_sock(sk); | ||
1087 | if (val >= 0) | ||
1088 | val = put_user(len, optlen); | ||
1089 | return val; | ||
1090 | #else | ||
1091 | release_sock(sk); | 1130 | release_sock(sk); |
1092 | return -ENOPROTOOPT; | 1131 | return -ENOPROTOOPT; |
1093 | #endif | ||
1094 | } | 1132 | } |
1095 | release_sock(sk); | 1133 | release_sock(sk); |
1096 | 1134 | ||
@@ -1111,7 +1149,73 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1111 | return 0; | 1149 | return 0; |
1112 | } | 1150 | } |
1113 | 1151 | ||
1152 | int ip_getsockopt(struct sock *sk, int level, | ||
1153 | int optname, char __user *optval, int __user *optlen) | ||
1154 | { | ||
1155 | int err; | ||
1156 | |||
1157 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1158 | #ifdef CONFIG_NETFILTER | ||
1159 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1160 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1161 | #ifdef CONFIG_IP_MROUTE | ||
1162 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1163 | #endif | ||
1164 | ) { | ||
1165 | int len; | ||
1166 | |||
1167 | if(get_user(len,optlen)) | ||
1168 | return -EFAULT; | ||
1169 | |||
1170 | lock_sock(sk); | ||
1171 | err = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1172 | &len); | ||
1173 | release_sock(sk); | ||
1174 | if (err >= 0) | ||
1175 | err = put_user(len, optlen); | ||
1176 | return err; | ||
1177 | } | ||
1178 | #endif | ||
1179 | return err; | ||
1180 | } | ||
1181 | |||
1182 | #ifdef CONFIG_COMPAT | ||
1183 | int compat_ip_getsockopt(struct sock *sk, int level, | ||
1184 | int optname, char __user *optval, int __user *optlen) | ||
1185 | { | ||
1186 | int err; | ||
1187 | |||
1188 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1189 | #ifdef CONFIG_NETFILTER | ||
1190 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1191 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1192 | #ifdef CONFIG_IP_MROUTE | ||
1193 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1194 | #endif | ||
1195 | ) { | ||
1196 | int len; | ||
1197 | |||
1198 | if(get_user(len,optlen)) | ||
1199 | return -EFAULT; | ||
1200 | |||
1201 | lock_sock(sk); | ||
1202 | err = compat_nf_getsockopt(sk, PF_INET, | ||
1203 | optname, optval, &len); | ||
1204 | release_sock(sk); | ||
1205 | if (err >= 0) | ||
1206 | err = put_user(len, optlen); | ||
1207 | return err; | ||
1208 | } | ||
1209 | #endif | ||
1210 | return err; | ||
1211 | } | ||
1212 | #endif | ||
1213 | |||
1114 | EXPORT_SYMBOL(ip_cmsg_recv); | 1214 | EXPORT_SYMBOL(ip_cmsg_recv); |
1115 | 1215 | ||
1116 | EXPORT_SYMBOL(ip_getsockopt); | 1216 | EXPORT_SYMBOL(ip_getsockopt); |
1117 | EXPORT_SYMBOL(ip_setsockopt); | 1217 | EXPORT_SYMBOL(ip_setsockopt); |
1218 | #ifdef CONFIG_COMPAT | ||
1219 | EXPORT_SYMBOL(compat_ip_getsockopt); | ||
1220 | EXPORT_SYMBOL(compat_ip_setsockopt); | ||
1221 | #endif | ||