we will reuse it later for mmsg implementation Signed-off-by: Sabrina Dubroca <s...@queasysnail.net> Signed-off-by: Paolo Abeni <pab...@redhat.com> --- net/ipv4/udp.c | 67 ++++++++++++++++++++++++++++++++--------------------- net/ipv6/udp.c | 73 ++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 86 insertions(+), 54 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b3b6bc5..d99429d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1350,34 +1350,18 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) } EXPORT_SYMBOL(udp_ioctl); -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - int flags, int *addr_len) +static int udp_process_skb(struct sock *sk, struct sk_buff *skb, + struct msghdr *msg, size_t len, int flags, + int *addr_len, int off, int peeking, int peeked) { - struct inet_sock *inet = inet_sk(sk); DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked, peeking, off; - int err; + struct inet_sock *inet = inet_sk(sk); int is_udplite = IS_UDPLITE(sk); bool checksum_valid = false; + int ulen = skb->len; + int copied = len; + int err; - if (flags & MSG_ERRQUEUE) - return ip_recv_error(sk, msg, len, addr_len); - -try_again: - peeking = off = sk_peek_offset(sk, flags); - skb = __skb_recv_udp(sk, flags, noblock, &peeked, &off, &err); - if (!skb) - return err; - - ulen = skb->len; - copied = len; if (copied > ulen - off) copied = ulen - off; else if (copied < ulen) @@ -1446,10 +1430,41 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, } kfree_skb(skb); - /* starting over for a new packet, but check if we need to yield */ - cond_resched(); msg->msg_flags &= ~MSG_TRUNC; - goto try_again; + return -EINVAL; +} + +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ +int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, + int flags, int *addr_len) +{ + struct sk_buff *skb; + int peeked, peeking, off; + int err; + + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len, addr_len); + +try_again: + peeking = off = sk_peek_offset(sk, flags); + skb = __skb_recv_udp(sk, flags, noblock, &peeked, &off, &err); + if (!skb) + return err; + + err = udp_process_skb(sk, skb, msg, len, flags, addr_len, off, peeking, + peeked); + if (err < 0) { + if (err != -EINVAL) + return err; + + /* restarting for a new packet, but check if we need to yield */ + cond_resched(); + goto try_again; + } + return err; } int __udp_disconnect(struct sock *sk, int flags) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ba25ec2..3218c64 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -318,38 +318,19 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be EXPORT_SYMBOL_GPL(udp6_lib_lookup); #endif -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) +static int udp6_process_skb(struct sock *sk, struct sk_buff *skb, + struct msghdr *msg, size_t len, int flags, + int *addr_len, int off, int peeking, int peeked) { struct ipv6_pinfo *np = inet6_sk(sk); struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked, peeking, off; - int err; int is_udplite = IS_UDPLITE(sk); bool checksum_valid = false; + int ulen = skb->len; + int copied = len; int is_udp4; + int err; - if (flags & MSG_ERRQUEUE) - return ipv6_recv_error(sk, msg, len, addr_len); - - if (np->rxpmtu && np->rxopt.bits.rxpmtu) - return ipv6_recv_rxpmtu(sk, msg, len, addr_len); - -try_again: - peeking = off = sk_peek_offset(sk, flags); - skb = __skb_recv_udp(sk, flags, noblock, &peeked, &off, &err); - if (!skb) - return err; - - ulen = skb->len; - copied = len; if (copied > ulen - off) copied = ulen - off; else if (copied < ulen) @@ -456,10 +437,46 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, } kfree_skb(skb); - /* starting over for a new packet, but check if we need to yield */ - cond_resched(); msg->msg_flags &= ~MSG_TRUNC; - goto try_again; + return -EINVAL; +} + +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ +int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + int peeked, peeking, off; + struct sk_buff *skb; + int err; + + if (flags & MSG_ERRQUEUE) + return ipv6_recv_error(sk, msg, len, addr_len); + + if (np->rxpmtu && np->rxopt.bits.rxpmtu) + return ipv6_recv_rxpmtu(sk, msg, len, addr_len); + +try_again: + peeking = off = sk_peek_offset(sk, flags); + skb = __skb_recv_udp(sk, flags, noblock, &peeked, &off, &err); + if (!skb) + return err; + + err = udp6_process_skb(sk, skb, msg, len, flags, addr_len, off, peeking, + peeked); + if (err < 0) { + if (err != -EINVAL) + return err; + + /* restarting for a new packet, but check if we need to yield */ + cond_resched(); + goto try_again; + } + return err; + } void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, -- 1.8.3.1