aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_sockglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_sockglue.c')
-rw-r--r--net/ipv4/ip_sockglue.c170
1 files changed, 150 insertions, 20 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 2bf8d782f678..12e0bf19f24a 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -50,6 +50,7 @@
50#define IP_CMSG_TOS 4 50#define IP_CMSG_TOS 4
51#define IP_CMSG_RECVOPTS 8 51#define IP_CMSG_RECVOPTS 8
52#define IP_CMSG_RETOPTS 16 52#define IP_CMSG_RETOPTS 16
53#define IP_CMSG_PASSSEC 32
53 54
54/* 55/*
55 * SOL_IP control messages. 56 * SOL_IP control messages.
@@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
109 put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); 110 put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
110} 111}
111 112
113static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
114{
115 char *secdata;
116 u32 seclen;
117 int err;
118
119 err = security_socket_getpeersec_dgram(skb, &secdata, &seclen);
120 if (err)
121 return;
122
123 put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
124}
125
112 126
113void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) 127void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
114{ 128{
@@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
138 152
139 if (flags & 1) 153 if (flags & 1)
140 ip_cmsg_recv_retopts(msg, skb); 154 ip_cmsg_recv_retopts(msg, skb);
155 if ((flags>>=1) == 0)
156 return;
157
158 if (flags & 1)
159 ip_cmsg_recv_security(msg, skb);
141} 160}
142 161
143int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) 162int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -380,20 +399,19 @@ out:
380 * an IP socket. 399 * an IP socket.
381 */ 400 */
382 401
383int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) 402static int do_ip_setsockopt(struct sock *sk, int level,
403 int optname, char __user *optval, int optlen)
384{ 404{
385 struct inet_sock *inet = inet_sk(sk); 405 struct inet_sock *inet = inet_sk(sk);
386 int val=0,err; 406 int val=0,err;
387 407
388 if (level != SOL_IP)
389 return -ENOPROTOOPT;
390
391 if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 408 if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
392 (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 409 (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
393 (1<<IP_RETOPTS) | (1<<IP_TOS) | 410 (1<<IP_RETOPTS) | (1<<IP_TOS) |
394 (1<<IP_TTL) | (1<<IP_HDRINCL) | 411 (1<<IP_TTL) | (1<<IP_HDRINCL) |
395 (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 412 (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
396 (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 413 (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
414 (1<<IP_PASSSEC))) ||
397 optname == IP_MULTICAST_TTL || 415 optname == IP_MULTICAST_TTL ||
398 optname == IP_MULTICAST_LOOP) { 416 optname == IP_MULTICAST_LOOP) {
399 if (optlen >= sizeof(int)) { 417 if (optlen >= sizeof(int)) {
@@ -478,6 +496,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
478 else 496 else
479 inet->cmsg_flags &= ~IP_CMSG_RETOPTS; 497 inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
480 break; 498 break;
499 case IP_PASSSEC:
500 if (val)
501 inet->cmsg_flags |= IP_CMSG_PASSSEC;
502 else
503 inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
504 break;
481 case IP_TOS: /* This sets both TOS and Precedence */ 505 case IP_TOS: /* This sets both TOS and Precedence */
482 if (sk->sk_type == SOCK_STREAM) { 506 if (sk->sk_type == SOCK_STREAM) {
483 val &= ~3; 507 val &= ~3;
@@ -849,12 +873,7 @@ mc_msf_out:
849 break; 873 break;
850 874
851 default: 875 default:
852#ifdef CONFIG_NETFILTER
853 err = nf_setsockopt(sk, PF_INET, optname, optval,
854 optlen);
855#else
856 err = -ENOPROTOOPT; 876 err = -ENOPROTOOPT;
857#endif
858 break; 877 break;
859 } 878 }
860 release_sock(sk); 879 release_sock(sk);
@@ -865,12 +884,68 @@ e_inval:
865 return -EINVAL; 884 return -EINVAL;
866} 885}
867 886
887int 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
913int compat_ip_setsockopt(struct sock *sk, int level, int optname,
914 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, optname,
932 optval, optlen);
933 release_sock(sk);
934 }
935#endif
936 return err;
937}
938
939EXPORT_SYMBOL(compat_ip_setsockopt);
940#endif
941
868/* 942/*
869 * Get the options. Note for future reference. The GET of IP options gets the 943 * Get the options. Note for future reference. The GET of IP options gets the
870 * _received_ ones. The set sets the _sent_ ones. 944 * _received_ ones. The set sets the _sent_ ones.
871 */ 945 */
872 946
873int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) 947static int do_ip_getsockopt(struct sock *sk, int level, int optname,
948 char __user *optval, int __user *optlen)
874{ 949{
875 struct inet_sock *inet = inet_sk(sk); 950 struct inet_sock *inet = inet_sk(sk);
876 int val; 951 int val;
@@ -932,6 +1007,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
932 case IP_RETOPTS: 1007 case IP_RETOPTS:
933 val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0; 1008 val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
934 break; 1009 break;
1010 case IP_PASSSEC:
1011 val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
1012 break;
935 case IP_TOS: 1013 case IP_TOS:
936 val = inet->tos; 1014 val = inet->tos;
937 break; 1015 break;
@@ -1051,17 +1129,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
1051 val = inet->freebind; 1129 val = inet->freebind;
1052 break; 1130 break;
1053 default: 1131 default:
1054#ifdef CONFIG_NETFILTER
1055 val = nf_getsockopt(sk, PF_INET, optname, optval,
1056 &len);
1057 release_sock(sk);
1058 if (val >= 0)
1059 val = put_user(len, optlen);
1060 return val;
1061#else
1062 release_sock(sk); 1132 release_sock(sk);
1063 return -ENOPROTOOPT; 1133 return -ENOPROTOOPT;
1064#endif
1065 } 1134 }
1066 release_sock(sk); 1135 release_sock(sk);
1067 1136
@@ -1082,6 +1151,67 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
1082 return 0; 1151 return 0;
1083} 1152}
1084 1153
1154int ip_getsockopt(struct sock *sk, int level,
1155 int optname, char __user *optval, int __user *optlen)
1156{
1157 int err;
1158
1159 err = do_ip_getsockopt(sk, level, optname, optval, optlen);
1160#ifdef CONFIG_NETFILTER
1161 /* we need to exclude all possible ENOPROTOOPTs except default case */
1162 if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS
1163#ifdef CONFIG_IP_MROUTE
1164 && (optname < MRT_BASE || optname > MRT_BASE+10)
1165#endif
1166 ) {
1167 int len;
1168
1169 if(get_user(len,optlen))
1170 return -EFAULT;
1171
1172 lock_sock(sk);
1173 err = nf_getsockopt(sk, PF_INET, optname, optval,
1174 &len);
1175 release_sock(sk);
1176 if (err >= 0)
1177 err = put_user(len, optlen);
1178 return err;
1179 }
1180#endif
1181 return err;
1182}
1183
1184#ifdef CONFIG_COMPAT
1185int compat_ip_getsockopt(struct sock *sk, int level, int optname,
1186 char __user *optval, int __user *optlen)
1187{
1188 int 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, optname, optval, &len);
1203 release_sock(sk);
1204 if (err >= 0)
1205 err = put_user(len, optlen);
1206 return err;
1207 }
1208#endif
1209 return err;
1210}
1211
1212EXPORT_SYMBOL(compat_ip_getsockopt);
1213#endif
1214
1085EXPORT_SYMBOL(ip_cmsg_recv); 1215EXPORT_SYMBOL(ip_cmsg_recv);
1086 1216
1087EXPORT_SYMBOL(ip_getsockopt); 1217EXPORT_SYMBOL(ip_getsockopt);