aboutsummaryrefslogtreecommitdiff
path: root/net/ipv4/ping.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ping.c')
-rw-r--r--net/ipv4/ping.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 0bb83e7ce8c7..7ec8e7204222 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -260,6 +260,10 @@ int ping_init_sock(struct sock *sk)
kgid_t low, high;
int ret = 0;
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == AF_INET6)
+ inet6_sk(sk)->ipv6only = 1;
+#endif
inet_get_ping_group_range_net(net, &low, &high);
if (gid_lte(low, group) && gid_lte(group, high))
return 0;
@@ -306,6 +310,11 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
if (addr_len < sizeof(*addr))
return -EINVAL;
+ if (addr->sin_family != AF_INET &&
+ !(addr->sin_family == AF_UNSPEC &&
+ addr->sin_addr.s_addr == htonl(INADDR_ANY)))
+ return -EAFNOSUPPORT;
+
pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
@@ -331,7 +340,7 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
return -EINVAL;
if (addr->sin6_family != AF_INET6)
- return -EINVAL;
+ return -EAFNOSUPPORT;
pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n",
sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port));
@@ -717,7 +726,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
if (msg->msg_namelen < sizeof(*usin))
return -EINVAL;
if (usin->sin_family != AF_INET)
- return -EINVAL;
+ return -EAFNOSUPPORT;
daddr = usin->sin_addr.s_addr;
/* no remote port */
} else {
@@ -975,8 +984,11 @@ void ping_rcv(struct sk_buff *skb)
sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
if (sk != NULL) {
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
pr_debug("rcv on socket %p\n", sk);
- ping_queue_rcv_skb(sk, skb_get(skb));
+ if (skb2)
+ ping_queue_rcv_skb(sk, skb2);
sock_put(sk);
return;
}