diff options
-rw-r--r-- | Documentation/networking/timestamping.txt | 12 | ||||
-rw-r--r-- | include/uapi/linux/net_tstamp.h | 3 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 22 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 21 |
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 | ||
123 | 1.3.3 Timestamp Options | 123 | 1.3.3 Timestamp Options |
124 | 124 | ||
125 | The interface supports one option | 125 | The interface supports the options |
126 | 126 | ||
127 | SOF_TIMESTAMPING_OPT_ID: | 127 | SOF_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 | ||
148 | SOF_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 | |||
148 | 1.4 Bytestream Timestamps | 158 | 1.4 Bytestream Timestamps |
149 | 159 | ||
150 | The SO_TIMESTAMPING interface supports timestamping of bytes in a | 160 | The 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 | ||
402 | static 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 | ||
328 | static 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 | ||