aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/timestamping.txt12
-rw-r--r--include/uapi/linux/net_tstamp.h3
-rw-r--r--net/ipv4/ip_sockglue.c22
-rw-r--r--net/ipv6/datagram.c21
4 files changed, 52 insertions, 6 deletions
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt
index 1d6d02d6ba52..b08e27261ff9 100644
--- a/Documentation/networking/timestamping.txt
+++ b/Documentation/networking/timestamping.txt
@@ -122,7 +122,7 @@ SOF_TIMESTAMPING_RAW_HARDWARE:
122 122
1231.3.3 Timestamp Options 1231.3.3 Timestamp Options
124 124
125The interface supports one option 125The interface supports the options
126 126
127SOF_TIMESTAMPING_OPT_ID: 127SOF_TIMESTAMPING_OPT_ID:
128 128
@@ -145,6 +145,16 @@ SOF_TIMESTAMPING_OPT_ID:
145 stream sockets, it increments with every byte. 145 stream sockets, it increments with every byte.
146 146
147 147
148SOF_TIMESTAMPING_OPT_CMSG:
149
150 Support recv() cmsg for all timestamped packets. Control messages
151 are already supported unconditionally on all packets with receive
152 timestamps and on IPv6 packets with transmit timestamp. This option
153 extends them to IPv4 packets with transmit timestamp. One use case
154 is to correlate packets with their egress device, by enabling socket
155 option IP_PKTINFO simultaneously.
156
157
1481.4 Bytestream Timestamps 1581.4 Bytestream Timestamps
149 159
150The SO_TIMESTAMPING interface supports timestamping of bytes in a 160The SO_TIMESTAMPING interface supports timestamping of bytes in a
diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h
index ff354021bb69..edbc888ceb51 100644
--- a/include/uapi/linux/net_tstamp.h
+++ b/include/uapi/linux/net_tstamp.h
@@ -23,8 +23,9 @@ enum {
23 SOF_TIMESTAMPING_OPT_ID = (1<<7), 23 SOF_TIMESTAMPING_OPT_ID = (1<<7),
24 SOF_TIMESTAMPING_TX_SCHED = (1<<8), 24 SOF_TIMESTAMPING_TX_SCHED = (1<<8),
25 SOF_TIMESTAMPING_TX_ACK = (1<<9), 25 SOF_TIMESTAMPING_TX_ACK = (1<<9),
26 SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
26 27
27 SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_TX_ACK, 28 SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_CMSG,
28 SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | 29 SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
29 SOF_TIMESTAMPING_LAST 30 SOF_TIMESTAMPING_LAST
30}; 31};
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 59eba6c7a512..640f26c6a9fe 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -399,6 +399,22 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
399 kfree_skb(skb); 399 kfree_skb(skb);
400} 400}
401 401
402static bool ipv4_pktinfo_prepare_errqueue(const struct sock *sk,
403 const struct sk_buff *skb,
404 int ee_origin)
405{
406 struct in_pktinfo *info = PKTINFO_SKB_CB(skb);
407
408 if ((ee_origin != SO_EE_ORIGIN_TIMESTAMPING) ||
409 (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) ||
410 (!skb->dev))
411 return false;
412
413 info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr;
414 info->ipi_ifindex = skb->dev->ifindex;
415 return true;
416}
417
402/* 418/*
403 * Handle MSG_ERRQUEUE 419 * Handle MSG_ERRQUEUE
404 */ 420 */
@@ -446,7 +462,9 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
446 memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); 462 memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
447 sin = &errhdr.offender; 463 sin = &errhdr.offender;
448 sin->sin_family = AF_UNSPEC; 464 sin->sin_family = AF_UNSPEC;
449 if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) { 465
466 if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
467 ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) {
450 struct inet_sock *inet = inet_sk(sk); 468 struct inet_sock *inet = inet_sk(sk);
451 469
452 sin->sin_family = AF_INET; 470 sin->sin_family = AF_INET;
@@ -1051,7 +1069,7 @@ e_inval:
1051} 1069}
1052 1070
1053/** 1071/**
1054 * ipv4_pktinfo_prepare - transfert some info from rtable to skb 1072 * ipv4_pktinfo_prepare - transfer some info from rtable to skb
1055 * @sk: socket 1073 * @sk: socket
1056 * @skb: buffer 1074 * @skb: buffer
1057 * 1075 *
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index cc1139687fd7..2464a00e36ab 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -325,6 +325,16 @@ void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu)
325 kfree_skb(skb); 325 kfree_skb(skb);
326} 326}
327 327
328static void ip6_datagram_prepare_pktinfo_errqueue(struct sk_buff *skb)
329{
330 int ifindex = skb->dev ? skb->dev->ifindex : -1;
331
332 if (skb->protocol == htons(ETH_P_IPV6))
333 IP6CB(skb)->iif = ifindex;
334 else
335 PKTINFO_SKB_CB(skb)->ipi_ifindex = ifindex;
336}
337
328/* 338/*
329 * Handle MSG_ERRQUEUE 339 * Handle MSG_ERRQUEUE
330 */ 340 */
@@ -388,8 +398,12 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
388 sin->sin6_family = AF_INET6; 398 sin->sin6_family = AF_INET6;
389 sin->sin6_flowinfo = 0; 399 sin->sin6_flowinfo = 0;
390 sin->sin6_port = 0; 400 sin->sin6_port = 0;
391 if (np->rxopt.all) 401 if (np->rxopt.all) {
402 if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
403 serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6)
404 ip6_datagram_prepare_pktinfo_errqueue(skb);
392 ip6_datagram_recv_common_ctl(sk, msg, skb); 405 ip6_datagram_recv_common_ctl(sk, msg, skb);
406 }
393 if (skb->protocol == htons(ETH_P_IPV6)) { 407 if (skb->protocol == htons(ETH_P_IPV6)) {
394 sin->sin6_addr = ipv6_hdr(skb)->saddr; 408 sin->sin6_addr = ipv6_hdr(skb)->saddr;
395 if (np->rxopt.all) 409 if (np->rxopt.all)
@@ -491,7 +505,10 @@ void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg,
491 ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, 505 ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr,
492 &src_info.ipi6_addr); 506 &src_info.ipi6_addr);
493 } 507 }
494 put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); 508
509 if (src_info.ipi6_ifindex >= 0)
510 put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO,
511 sizeof(src_info), &src_info);
495 } 512 }
496} 513}
497 514