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.c72
1 files changed, 55 insertions, 17 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 465abf0a9869..43c05854d752 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -48,6 +48,7 @@
48#define IP_CMSG_RECVOPTS 8 48#define IP_CMSG_RECVOPTS 8
49#define IP_CMSG_RETOPTS 16 49#define IP_CMSG_RETOPTS 16
50#define IP_CMSG_PASSSEC 32 50#define IP_CMSG_PASSSEC 32
51#define IP_CMSG_ORIGDSTADDR 64
51 52
52/* 53/*
53 * SOL_IP control messages. 54 * SOL_IP control messages.
@@ -94,7 +95,7 @@ static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
94static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) 95static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
95{ 96{
96 unsigned char optbuf[sizeof(struct ip_options) + 40]; 97 unsigned char optbuf[sizeof(struct ip_options) + 40];
97 struct ip_options * opt = (struct ip_options*)optbuf; 98 struct ip_options * opt = (struct ip_options *)optbuf;
98 99
99 if (IPCB(skb)->opt.optlen == 0) 100 if (IPCB(skb)->opt.optlen == 0)
100 return; 101 return;
@@ -126,6 +127,27 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
126 security_release_secctx(secdata, seclen); 127 security_release_secctx(secdata, seclen);
127} 128}
128 129
130static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
131{
132 struct sockaddr_in sin;
133 struct iphdr *iph = ip_hdr(skb);
134 __be16 *ports = (__be16 *)skb_transport_header(skb);
135
136 if (skb_transport_offset(skb) + 4 > skb->len)
137 return;
138
139 /* All current transport protocols have the port numbers in the
140 * first four bytes of the transport header and this function is
141 * written with this assumption in mind.
142 */
143
144 sin.sin_family = AF_INET;
145 sin.sin_addr.s_addr = iph->daddr;
146 sin.sin_port = ports[1];
147 memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
148
149 put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
150}
129 151
130void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) 152void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
131{ 153{
@@ -160,6 +182,12 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
160 182
161 if (flags & 1) 183 if (flags & 1)
162 ip_cmsg_recv_security(msg, skb); 184 ip_cmsg_recv_security(msg, skb);
185
186 if ((flags>>=1) == 0)
187 return;
188 if (flags & 1)
189 ip_cmsg_recv_dstaddr(msg, skb);
190
163} 191}
164 192
165int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) 193int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -411,7 +439,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
411 int optname, char __user *optval, int optlen) 439 int optname, char __user *optval, int optlen)
412{ 440{
413 struct inet_sock *inet = inet_sk(sk); 441 struct inet_sock *inet = inet_sk(sk);
414 int val=0,err; 442 int val = 0, err;
415 443
416 if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | 444 if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
417 (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | 445 (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
@@ -421,7 +449,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
421 (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | 449 (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
422 (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) || 450 (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
423 optname == IP_MULTICAST_TTL || 451 optname == IP_MULTICAST_TTL ||
424 optname == IP_MULTICAST_LOOP) { 452 optname == IP_MULTICAST_LOOP ||
453 optname == IP_RECVORIGDSTADDR) {
425 if (optlen >= sizeof(int)) { 454 if (optlen >= sizeof(int)) {
426 if (get_user(val, (int __user *) optval)) 455 if (get_user(val, (int __user *) optval))
427 return -EFAULT; 456 return -EFAULT;
@@ -437,7 +466,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
437 /* If optlen==0, it is equivalent to val == 0 */ 466 /* If optlen==0, it is equivalent to val == 0 */
438 467
439 if (ip_mroute_opt(optname)) 468 if (ip_mroute_opt(optname))
440 return ip_mroute_setsockopt(sk,optname,optval,optlen); 469 return ip_mroute_setsockopt(sk, optname, optval, optlen);
441 470
442 err = 0; 471 err = 0;
443 lock_sock(sk); 472 lock_sock(sk);
@@ -509,6 +538,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
509 else 538 else
510 inet->cmsg_flags &= ~IP_CMSG_PASSSEC; 539 inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
511 break; 540 break;
541 case IP_RECVORIGDSTADDR:
542 if (val)
543 inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
544 else
545 inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
546 break;
512 case IP_TOS: /* This sets both TOS and Precedence */ 547 case IP_TOS: /* This sets both TOS and Precedence */
513 if (sk->sk_type == SOCK_STREAM) { 548 if (sk->sk_type == SOCK_STREAM) {
514 val &= ~3; 549 val &= ~3;
@@ -549,7 +584,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
549 goto e_inval; 584 goto e_inval;
550 if (optlen<1) 585 if (optlen<1)
551 goto e_inval; 586 goto e_inval;
552 if (val==-1) 587 if (val == -1)
553 val = 1; 588 val = 1;
554 if (val < 0 || val > 255) 589 if (val < 0 || val > 255)
555 goto e_inval; 590 goto e_inval;
@@ -573,12 +608,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
573 608
574 err = -EFAULT; 609 err = -EFAULT;
575 if (optlen >= sizeof(struct ip_mreqn)) { 610 if (optlen >= sizeof(struct ip_mreqn)) {
576 if (copy_from_user(&mreq,optval,sizeof(mreq))) 611 if (copy_from_user(&mreq, optval, sizeof(mreq)))
577 break; 612 break;
578 } else { 613 } else {
579 memset(&mreq, 0, sizeof(mreq)); 614 memset(&mreq, 0, sizeof(mreq));
580 if (optlen >= sizeof(struct in_addr) && 615 if (optlen >= sizeof(struct in_addr) &&
581 copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr))) 616 copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr)))
582 break; 617 break;
583 } 618 }
584 619
@@ -626,11 +661,11 @@ static int do_ip_setsockopt(struct sock *sk, int level,
626 goto e_inval; 661 goto e_inval;
627 err = -EFAULT; 662 err = -EFAULT;
628 if (optlen >= sizeof(struct ip_mreqn)) { 663 if (optlen >= sizeof(struct ip_mreqn)) {
629 if (copy_from_user(&mreq,optval,sizeof(mreq))) 664 if (copy_from_user(&mreq, optval, sizeof(mreq)))
630 break; 665 break;
631 } else { 666 } else {
632 memset(&mreq, 0, sizeof(mreq)); 667 memset(&mreq, 0, sizeof(mreq));
633 if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq))) 668 if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq)))
634 break; 669 break;
635 } 670 }
636 671
@@ -808,7 +843,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
808 err = -ENOBUFS; 843 err = -ENOBUFS;
809 break; 844 break;
810 } 845 }
811 gsf = kmalloc(optlen,GFP_KERNEL); 846 gsf = kmalloc(optlen, GFP_KERNEL);
812 if (!gsf) { 847 if (!gsf) {
813 err = -ENOBUFS; 848 err = -ENOBUFS;
814 break; 849 break;
@@ -828,7 +863,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
828 goto mc_msf_out; 863 goto mc_msf_out;
829 } 864 }
830 msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); 865 msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
831 msf = kmalloc(msize,GFP_KERNEL); 866 msf = kmalloc(msize, GFP_KERNEL);
832 if (!msf) { 867 if (!msf) {
833 err = -ENOBUFS; 868 err = -ENOBUFS;
834 goto mc_msf_out; 869 goto mc_msf_out;
@@ -971,9 +1006,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
971 return -EOPNOTSUPP; 1006 return -EOPNOTSUPP;
972 1007
973 if (ip_mroute_opt(optname)) 1008 if (ip_mroute_opt(optname))
974 return ip_mroute_getsockopt(sk,optname,optval,optlen); 1009 return ip_mroute_getsockopt(sk, optname, optval, optlen);
975 1010
976 if (get_user(len,optlen)) 1011 if (get_user(len, optlen))
977 return -EFAULT; 1012 return -EFAULT;
978 if (len < 0) 1013 if (len < 0)
979 return -EINVAL; 1014 return -EINVAL;
@@ -984,7 +1019,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
984 case IP_OPTIONS: 1019 case IP_OPTIONS:
985 { 1020 {
986 unsigned char optbuf[sizeof(struct ip_options)+40]; 1021 unsigned char optbuf[sizeof(struct ip_options)+40];
987 struct ip_options * opt = (struct ip_options*)optbuf; 1022 struct ip_options * opt = (struct ip_options *)optbuf;
988 opt->optlen = 0; 1023 opt->optlen = 0;
989 if (inet->opt) 1024 if (inet->opt)
990 memcpy(optbuf, inet->opt, 1025 memcpy(optbuf, inet->opt,
@@ -1022,6 +1057,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
1022 case IP_PASSSEC: 1057 case IP_PASSSEC:
1023 val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; 1058 val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
1024 break; 1059 break;
1060 case IP_RECVORIGDSTADDR:
1061 val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
1062 break;
1025 case IP_TOS: 1063 case IP_TOS:
1026 val = inet->tos; 1064 val = inet->tos;
1027 break; 1065 break;
@@ -1154,13 +1192,13 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
1154 len = 1; 1192 len = 1;
1155 if (put_user(len, optlen)) 1193 if (put_user(len, optlen))
1156 return -EFAULT; 1194 return -EFAULT;
1157 if (copy_to_user(optval,&ucval,1)) 1195 if (copy_to_user(optval, &ucval, 1))
1158 return -EFAULT; 1196 return -EFAULT;
1159 } else { 1197 } else {
1160 len = min_t(unsigned int, sizeof(int), len); 1198 len = min_t(unsigned int, sizeof(int), len);
1161 if (put_user(len, optlen)) 1199 if (put_user(len, optlen))
1162 return -EFAULT; 1200 return -EFAULT;
1163 if (copy_to_user(optval,&val,len)) 1201 if (copy_to_user(optval, &val, len))
1164 return -EFAULT; 1202 return -EFAULT;
1165 } 1203 }
1166 return 0; 1204 return 0;
@@ -1178,7 +1216,7 @@ int ip_getsockopt(struct sock *sk, int level,
1178 !ip_mroute_opt(optname)) { 1216 !ip_mroute_opt(optname)) {
1179 int len; 1217 int len;
1180 1218
1181 if (get_user(len,optlen)) 1219 if (get_user(len, optlen))
1182 return -EFAULT; 1220 return -EFAULT;
1183 1221
1184 lock_sock(sk); 1222 lock_sock(sk);