aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2014-01-19 21:43:08 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-19 22:53:18 -0500
commit4b261c75a99f29c93a0b6babfc180cdf566bd654 (patch)
tree2c1fcebd79d2fcb1625f89ef5067605151953010
parenta6e2fe17eba47681e82cdb9cfed5a67b57802a78 (diff)
ipv6: make IPV6_RECVPKTINFO work for ipv4 datagrams
We currently don't report IPV6_RECVPKTINFO in cmsg access ancillary data for IPv4 datagrams on IPv6 sockets. This patch splits the ip6_datagram_recv_ctl into two functions, one which handles both protocol families, AF_INET and AF_INET6, while the ip6_datagram_recv_specific_ctl only handles IPv6 cmsg data. ip6_datagram_recv_*_ctl never reported back any errors, so we can make them return void. Also provide a helper for protocols which don't offer dual personality to further use ip6_datagram_recv_ctl, which is exported to modules. I needed to shuffle the code for ping around a bit to make it easier to implement dual personality for ping ipv6 sockets in future. Reported-by: Gert Doering <gert@space.net> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/ipv6.h3
-rw-r--r--include/net/ip.h1
-rw-r--r--include/net/ping.h8
-rw-r--r--include/net/transp_v6.h9
-rw-r--r--net/ipv4/ip_sockglue.c6
-rw-r--r--net/ipv4/ping.c7
-rw-r--r--net/ipv6/datagram.c38
-rw-r--r--net/ipv6/ipv6_sockglue.c4
-rw-r--r--net/ipv6/ping.c10
-rw-r--r--net/ipv6/udp.c6
10 files changed, 68 insertions, 24 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 1084304fd75a..2faef339d8f2 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -284,6 +284,8 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
284 284
285#define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only) 285#define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only)
286#define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk)) 286#define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk))
287#define ipv6_sk_rxinfo(sk) ((sk)->sk_family == PF_INET6 && \
288 inet6_sk(sk)->rxopt.bits.rxinfo)
287 289
288static inline const struct in6_addr *inet6_rcv_saddr(const struct sock *sk) 290static inline const struct in6_addr *inet6_rcv_saddr(const struct sock *sk)
289{ 291{
@@ -300,6 +302,7 @@ static inline int inet_v6_ipv6only(const struct sock *sk)
300#else 302#else
301#define __ipv6_only_sock(sk) 0 303#define __ipv6_only_sock(sk) 0
302#define ipv6_only_sock(sk) 0 304#define ipv6_only_sock(sk) 0
305#define ipv6_sk_rxinfo(sk) 0
303 306
304static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) 307static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk)
305{ 308{
diff --git a/include/net/ip.h b/include/net/ip.h
index 7876e3b96ce3..23be0fd37937 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -63,6 +63,7 @@ struct ipcm_cookie {
63}; 63};
64 64
65#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) 65#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
66#define PKTINFO_SKB_CB(skb) ((struct in_pktinfo *)((skb)->cb))
66 67
67struct ip_ra_chain { 68struct ip_ra_chain {
68 struct ip_ra_chain __rcu *next; 69 struct ip_ra_chain __rcu *next;
diff --git a/include/net/ping.h b/include/net/ping.h
index 76013653e08c..026479b61a2d 100644
--- a/include/net/ping.h
+++ b/include/net/ping.h
@@ -33,8 +33,12 @@
33struct pingv6_ops { 33struct pingv6_ops {
34 int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len, 34 int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len,
35 int *addr_len); 35 int *addr_len);
36 int (*ip6_datagram_recv_ctl)(struct sock *sk, struct msghdr *msg, 36 void (*ip6_datagram_recv_common_ctl)(struct sock *sk,
37 struct sk_buff *skb); 37 struct msghdr *msg,
38 struct sk_buff *skb);
39 void (*ip6_datagram_recv_specific_ctl)(struct sock *sk,
40 struct msghdr *msg,
41 struct sk_buff *skb);
38 int (*icmpv6_err_convert)(u8 type, u8 code, int *err); 42 int (*icmpv6_err_convert)(u8 type, u8 code, int *err);
39 void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err, 43 void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err,
40 __be16 port, u32 info, u8 *payload); 44 __be16 port, u32 info, u8 *payload);
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 48660e50ae90..b927413dde86 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -32,8 +32,13 @@ void tcpv6_exit(void);
32 32
33int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); 33int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len);
34 34
35int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, 35/* this does all the common and the specific ctl work */
36 struct sk_buff *skb); 36void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
37 struct sk_buff *skb);
38void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
39 struct sk_buff *skb);
40void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
41 struct sk_buff *skb);
37 42
38int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg, 43int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg,
39 struct flowi6 *fl6, struct ipv6_txoptions *opt, 44 struct flowi6 *fl6, struct ipv6_txoptions *opt,
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 22f15eb1c260..580dd96666e0 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -56,7 +56,6 @@
56/* 56/*
57 * SOL_IP control messages. 57 * SOL_IP control messages.
58 */ 58 */
59#define PKTINFO_SKB_CB(__skb) ((struct in_pktinfo *)((__skb)->cb))
60 59
61static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) 60static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
62{ 61{
@@ -1055,9 +1054,10 @@ e_inval:
1055void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) 1054void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
1056{ 1055{
1057 struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); 1056 struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
1057 bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) ||
1058 ipv6_sk_rxinfo(sk);
1058 1059
1059 if ((inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) && 1060 if (prepare && skb_rtable(skb)) {
1060 skb_rtable(skb)) {
1061 pktinfo->ipi_ifindex = inet_iif(skb); 1061 pktinfo->ipi_ifindex = inet_iif(skb);
1062 pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb); 1062 pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
1063 } else { 1063 } else {
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index e09e8839d622..4a9e4266a0c3 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -906,7 +906,12 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
906 } 906 }
907 907
908 if (inet6_sk(sk)->rxopt.all) 908 if (inet6_sk(sk)->rxopt.all)
909 pingv6_ops.ip6_datagram_recv_ctl(sk, msg, skb); 909 pingv6_ops.ip6_datagram_recv_common_ctl(sk, msg, skb);
910 if (skb->protocol == htons(ETH_P_IPV6) &&
911 inet6_sk(sk)->rxopt.all)
912 pingv6_ops.ip6_datagram_recv_specific_ctl(sk, msg, skb);
913 else if (skb->protocol == htons(ETH_P_IP) && isk->cmsg_flags)
914 ip_cmsg_recv(msg, skb);
910#endif 915#endif
911 } else { 916 } else {
912 BUG(); 917 BUG();
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index bce73cbd203a..cd8699bd2e6b 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -377,10 +377,12 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
377 sin->sin6_family = AF_INET6; 377 sin->sin6_family = AF_INET6;
378 sin->sin6_flowinfo = 0; 378 sin->sin6_flowinfo = 0;
379 sin->sin6_port = 0; 379 sin->sin6_port = 0;
380 if (np->rxopt.all)
381 ip6_datagram_recv_common_ctl(sk, msg, skb);
380 if (skb->protocol == htons(ETH_P_IPV6)) { 382 if (skb->protocol == htons(ETH_P_IPV6)) {
381 sin->sin6_addr = ipv6_hdr(skb)->saddr; 383 sin->sin6_addr = ipv6_hdr(skb)->saddr;
382 if (np->rxopt.all) 384 if (np->rxopt.all)
383 ip6_datagram_recv_ctl(sk, msg, skb); 385 ip6_datagram_recv_specific_ctl(sk, msg, skb);
384 sin->sin6_scope_id = 386 sin->sin6_scope_id =
385 ipv6_iface_scope_id(&sin->sin6_addr, 387 ipv6_iface_scope_id(&sin->sin6_addr,
386 IP6CB(skb)->iif); 388 IP6CB(skb)->iif);
@@ -471,20 +473,34 @@ out:
471} 473}
472 474
473 475
474int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, 476void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
475 struct sk_buff *skb) 477 struct sk_buff *skb)
476{ 478{
477 struct ipv6_pinfo *np = inet6_sk(sk); 479 struct ipv6_pinfo *np = inet6_sk(sk);
478 struct inet6_skb_parm *opt = IP6CB(skb); 480 bool is_ipv6 = skb->protocol == htons(ETH_P_IPV6);
479 unsigned char *nh = skb_network_header(skb);
480 481
481 if (np->rxopt.bits.rxinfo) { 482 if (np->rxopt.bits.rxinfo) {
482 struct in6_pktinfo src_info; 483 struct in6_pktinfo src_info;
483 484
484 src_info.ipi6_ifindex = opt->iif; 485 if (is_ipv6) {
485 src_info.ipi6_addr = ipv6_hdr(skb)->daddr; 486 src_info.ipi6_ifindex = IP6CB(skb)->iif;
487 src_info.ipi6_addr = ipv6_hdr(skb)->daddr;
488 } else {
489 src_info.ipi6_ifindex =
490 PKTINFO_SKB_CB(skb)->ipi_ifindex;
491 ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
492 &src_info.ipi6_addr);
493 }
486 put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); 494 put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
487 } 495 }
496}
497
498void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
499 struct sk_buff *skb)
500{
501 struct ipv6_pinfo *np = inet6_sk(sk);
502 struct inet6_skb_parm *opt = IP6CB(skb);
503 unsigned char *nh = skb_network_header(skb);
488 504
489 if (np->rxopt.bits.rxhlim) { 505 if (np->rxopt.bits.rxhlim) {
490 int hlim = ipv6_hdr(skb)->hop_limit; 506 int hlim = ipv6_hdr(skb)->hop_limit;
@@ -602,7 +618,13 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
602 put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6); 618 put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);
603 } 619 }
604 } 620 }
605 return 0; 621}
622
623void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
624 struct sk_buff *skb)
625{
626 ip6_datagram_recv_common_ctl(sk, msg, skb);
627 ip6_datagram_recv_specific_ctl(sk, msg, skb);
606} 628}
607EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); 629EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl);
608 630
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 7024a874e901..0a00f449de5e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1002,10 +1002,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1002 release_sock(sk); 1002 release_sock(sk);
1003 1003
1004 if (skb) { 1004 if (skb) {
1005 int err = ip6_datagram_recv_ctl(sk, &msg, skb); 1005 ip6_datagram_recv_ctl(sk, &msg, skb);
1006 kfree_skb(skb); 1006 kfree_skb(skb);
1007 if (err)
1008 return err;
1009 } else { 1007 } else {
1010 if (np->rxopt.bits.rxinfo) { 1008 if (np->rxopt.bits.rxinfo) {
1011 struct in6_pktinfo src_info; 1009 struct in6_pktinfo src_info;
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index cd71f3a540be..94a3d04c3200 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -62,10 +62,9 @@ static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len,
62{ 62{
63 return -EAFNOSUPPORT; 63 return -EAFNOSUPPORT;
64} 64}
65static int dummy_ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, 65static void dummy_ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
66 struct sk_buff *skb) 66 struct sk_buff *skb)
67{ 67{
68 return -EAFNOSUPPORT;
69} 68}
70static int dummy_icmpv6_err_convert(u8 type, u8 code, int *err) 69static int dummy_icmpv6_err_convert(u8 type, u8 code, int *err)
71{ 70{
@@ -254,7 +253,9 @@ int __init pingv6_init(void)
254 return ret; 253 return ret;
255#endif 254#endif
256 pingv6_ops.ipv6_recv_error = ipv6_recv_error; 255 pingv6_ops.ipv6_recv_error = ipv6_recv_error;
257 pingv6_ops.ip6_datagram_recv_ctl = ip6_datagram_recv_ctl; 256 pingv6_ops.ip6_datagram_recv_common_ctl = ip6_datagram_recv_common_ctl;
257 pingv6_ops.ip6_datagram_recv_specific_ctl =
258 ip6_datagram_recv_specific_ctl;
258 pingv6_ops.icmpv6_err_convert = icmpv6_err_convert; 259 pingv6_ops.icmpv6_err_convert = icmpv6_err_convert;
259 pingv6_ops.ipv6_icmp_error = ipv6_icmp_error; 260 pingv6_ops.ipv6_icmp_error = ipv6_icmp_error;
260 pingv6_ops.ipv6_chk_addr = ipv6_chk_addr; 261 pingv6_ops.ipv6_chk_addr = ipv6_chk_addr;
@@ -267,7 +268,8 @@ int __init pingv6_init(void)
267void pingv6_exit(void) 268void pingv6_exit(void)
268{ 269{
269 pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error; 270 pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error;
270 pingv6_ops.ip6_datagram_recv_ctl = dummy_ip6_datagram_recv_ctl; 271 pingv6_ops.ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl;
272 pingv6_ops.ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl;
271 pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert; 273 pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert;
272 pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error; 274 pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error;
273 pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr; 275 pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 233c3ab6aee4..1e586d92260e 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -477,12 +477,16 @@ try_again:
477 } 477 }
478 *addr_len = sizeof(*sin6); 478 *addr_len = sizeof(*sin6);
479 } 479 }
480
481 if (np->rxopt.all)
482 ip6_datagram_recv_common_ctl(sk, msg, skb);
483
480 if (is_udp4) { 484 if (is_udp4) {
481 if (inet->cmsg_flags) 485 if (inet->cmsg_flags)
482 ip_cmsg_recv(msg, skb); 486 ip_cmsg_recv(msg, skb);
483 } else { 487 } else {
484 if (np->rxopt.all) 488 if (np->rxopt.all)
485 ip6_datagram_recv_ctl(sk, msg, skb); 489 ip6_datagram_recv_specific_ctl(sk, msg, skb);
486 } 490 }
487 491
488 err = copied; 492 err = copied;