aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2015-01-05 16:56:17 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-05 22:44:46 -0500
commitad6f939ab193750cc94a265f58e007fb598c97b7 (patch)
treef00a55adcedfde95441ed2ec498a2a294623522e /net
parent5961de9f199bef6ff437d7d85fe69b6a1964739b (diff)
ip: Add offset parameter to ip_cmsg_recv
Add ip_cmsg_recv_offset function which takes an offset argument that indicates the starting offset in skb where data is being received from. This will be useful in the case of UDP and provided checksum to user space. ip_cmsg_recv is an inline call to ip_cmsg_recv_offset with offset of zero. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ip_sockglue.c41
-rw-r--r--net/ipv4/udp.c2
2 files changed, 41 insertions, 2 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 513d506ffebb..a317797b3cd0 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -37,6 +37,7 @@
37#include <net/route.h> 37#include <net/route.h>
38#include <net/xfrm.h> 38#include <net/xfrm.h>
39#include <net/compat.h> 39#include <net/compat.h>
40#include <net/checksum.h>
40#if IS_ENABLED(CONFIG_IPV6) 41#if IS_ENABLED(CONFIG_IPV6)
41#include <net/transp_v6.h> 42#include <net/transp_v6.h>
42#endif 43#endif
@@ -96,6 +97,20 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
96 put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); 97 put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
97} 98}
98 99
100static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
101 int offset)
102{
103 __wsum csum = skb->csum;
104
105 if (skb->ip_summed != CHECKSUM_COMPLETE)
106 return;
107
108 if (offset != 0)
109 csum = csum_sub(csum, csum_partial(skb->data, offset, 0));
110
111 put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
112}
113
99static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) 114static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
100{ 115{
101 char *secdata; 116 char *secdata;
@@ -191,9 +206,16 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
191 return; 206 return;
192 } 207 }
193 208
194 if (flags & IP_CMSG_ORIGDSTADDR) 209 if (flags & IP_CMSG_ORIGDSTADDR) {
195 ip_cmsg_recv_dstaddr(msg, skb); 210 ip_cmsg_recv_dstaddr(msg, skb);
196 211
212 flags &= ~IP_CMSG_ORIGDSTADDR;
213 if (!flags)
214 return;
215 }
216
217 if (flags & IP_CMSG_CHECKSUM)
218 ip_cmsg_recv_checksum(msg, skb, offset);
197} 219}
198EXPORT_SYMBOL(ip_cmsg_recv_offset); 220EXPORT_SYMBOL(ip_cmsg_recv_offset);
199 221
@@ -533,6 +555,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
533 case IP_MULTICAST_ALL: 555 case IP_MULTICAST_ALL:
534 case IP_MULTICAST_LOOP: 556 case IP_MULTICAST_LOOP:
535 case IP_RECVORIGDSTADDR: 557 case IP_RECVORIGDSTADDR:
558 case IP_CHECKSUM:
536 if (optlen >= sizeof(int)) { 559 if (optlen >= sizeof(int)) {
537 if (get_user(val, (int __user *) optval)) 560 if (get_user(val, (int __user *) optval))
538 return -EFAULT; 561 return -EFAULT;
@@ -630,6 +653,19 @@ static int do_ip_setsockopt(struct sock *sk, int level,
630 else 653 else
631 inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR; 654 inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
632 break; 655 break;
656 case IP_CHECKSUM:
657 if (val) {
658 if (!(inet->cmsg_flags & IP_CMSG_CHECKSUM)) {
659 inet_inc_convert_csum(sk);
660 inet->cmsg_flags |= IP_CMSG_CHECKSUM;
661 }
662 } else {
663 if (inet->cmsg_flags & IP_CMSG_CHECKSUM) {
664 inet_dec_convert_csum(sk);
665 inet->cmsg_flags &= ~IP_CMSG_CHECKSUM;
666 }
667 }
668 break;
633 case IP_TOS: /* This sets both TOS and Precedence */ 669 case IP_TOS: /* This sets both TOS and Precedence */
634 if (sk->sk_type == SOCK_STREAM) { 670 if (sk->sk_type == SOCK_STREAM) {
635 val &= ~INET_ECN_MASK; 671 val &= ~INET_ECN_MASK;
@@ -1233,6 +1269,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
1233 case IP_RECVORIGDSTADDR: 1269 case IP_RECVORIGDSTADDR:
1234 val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; 1270 val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
1235 break; 1271 break;
1272 case IP_CHECKSUM:
1273 val = (inet->cmsg_flags & IP_CMSG_CHECKSUM) != 0;
1274 break;
1236 case IP_TOS: 1275 case IP_TOS:
1237 val = inet->tos; 1276 val = inet->tos;
1238 break; 1277 break;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 53358d88f110..97ef1f8b7be8 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1329,7 +1329,7 @@ try_again:
1329 *addr_len = sizeof(*sin); 1329 *addr_len = sizeof(*sin);
1330 } 1330 }
1331 if (inet->cmsg_flags) 1331 if (inet->cmsg_flags)
1332 ip_cmsg_recv(msg, skb); 1332 ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr));
1333 1333
1334 err = copied; 1334 err = copied;
1335 if (flags & MSG_TRUNC) 1335 if (flags & MSG_TRUNC)