aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/inet_sock.h1
-rw-r--r--include/uapi/linux/in.h1
-rw-r--r--net/ipv4/ip_sockglue.c41
-rw-r--r--net/ipv4/udp.c2
4 files changed, 43 insertions, 2 deletions
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 605ca421d5ab..eb16c7beed1e 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -203,6 +203,7 @@ struct inet_sock {
203#define IP_CMSG_RETOPTS BIT(4) 203#define IP_CMSG_RETOPTS BIT(4)
204#define IP_CMSG_PASSSEC BIT(5) 204#define IP_CMSG_PASSSEC BIT(5)
205#define IP_CMSG_ORIGDSTADDR BIT(6) 205#define IP_CMSG_ORIGDSTADDR BIT(6)
206#define IP_CMSG_CHECKSUM BIT(7)
206 207
207static inline struct inet_sock *inet_sk(const struct sock *sk) 208static inline struct inet_sock *inet_sk(const struct sock *sk)
208{ 209{
diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
index c33a65e3d62c..589ced069e8a 100644
--- a/include/uapi/linux/in.h
+++ b/include/uapi/linux/in.h
@@ -109,6 +109,7 @@ struct in_addr {
109 109
110#define IP_MINTTL 21 110#define IP_MINTTL 21
111#define IP_NODEFRAG 22 111#define IP_NODEFRAG 22
112#define IP_CHECKSUM 23
112 113
113/* IP_MTU_DISCOVER values */ 114/* IP_MTU_DISCOVER values */
114#define IP_PMTUDISC_DONT 0 /* Never send DF frames */ 115#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
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)