Skip to content

Commit

Permalink
ip: Add offset parameter to ip_cmsg_recv
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Tom Herbert authored and davem330 committed Jan 6, 2015
1 parent 5961de9 commit ad6f939
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
1 change: 1 addition & 0 deletions include/net/inet_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ struct inet_sock {
#define IP_CMSG_RETOPTS BIT(4)
#define IP_CMSG_PASSSEC BIT(5)
#define IP_CMSG_ORIGDSTADDR BIT(6)
#define IP_CMSG_CHECKSUM BIT(7)

static inline struct inet_sock *inet_sk(const struct sock *sk)
{
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/in.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ struct in_addr {

#define IP_MINTTL 21
#define IP_NODEFRAG 22
#define IP_CHECKSUM 23

/* IP_MTU_DISCOVER values */
#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
Expand Down
41 changes: 40 additions & 1 deletion net/ipv4/ip_sockglue.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <net/route.h>
#include <net/xfrm.h>
#include <net/compat.h>
#include <net/checksum.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/transp_v6.h>
#endif
Expand Down Expand Up @@ -96,6 +97,20 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
}

static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
int offset)
{
__wsum csum = skb->csum;

if (skb->ip_summed != CHECKSUM_COMPLETE)
return;

if (offset != 0)
csum = csum_sub(csum, csum_partial(skb->data, offset, 0));

put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
}

static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
{
char *secdata;
Expand Down Expand Up @@ -191,9 +206,16 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
return;
}

if (flags & IP_CMSG_ORIGDSTADDR)
if (flags & IP_CMSG_ORIGDSTADDR) {
ip_cmsg_recv_dstaddr(msg, skb);

flags &= ~IP_CMSG_ORIGDSTADDR;
if (!flags)
return;
}

if (flags & IP_CMSG_CHECKSUM)
ip_cmsg_recv_checksum(msg, skb, offset);
}
EXPORT_SYMBOL(ip_cmsg_recv_offset);

Expand Down Expand Up @@ -533,6 +555,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
case IP_MULTICAST_ALL:
case IP_MULTICAST_LOOP:
case IP_RECVORIGDSTADDR:
case IP_CHECKSUM:
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
return -EFAULT;
Expand Down Expand Up @@ -630,6 +653,19 @@ static int do_ip_setsockopt(struct sock *sk, int level,
else
inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
break;
case IP_CHECKSUM:
if (val) {
if (!(inet->cmsg_flags & IP_CMSG_CHECKSUM)) {
inet_inc_convert_csum(sk);
inet->cmsg_flags |= IP_CMSG_CHECKSUM;
}
} else {
if (inet->cmsg_flags & IP_CMSG_CHECKSUM) {
inet_dec_convert_csum(sk);
inet->cmsg_flags &= ~IP_CMSG_CHECKSUM;
}
}
break;
case IP_TOS: /* This sets both TOS and Precedence */
if (sk->sk_type == SOCK_STREAM) {
val &= ~INET_ECN_MASK;
Expand Down Expand Up @@ -1233,6 +1269,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_RECVORIGDSTADDR:
val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
break;
case IP_CHECKSUM:
val = (inet->cmsg_flags & IP_CMSG_CHECKSUM) != 0;
break;
case IP_TOS:
val = inet->tos;
break;
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
*addr_len = sizeof(*sin);
}
if (inet->cmsg_flags)
ip_cmsg_recv(msg, skb);
ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr));

err = copied;
if (flags & MSG_TRUNC)
Expand Down

0 comments on commit ad6f939

Please sign in to comment.