2626
2727#include <linux/tcp.h>
2828#include <linux/compiler.h>
29+ #include <linux/errqueue.h>
30+ #include <linux/net_tstamp.h>
31+
32+ #include <poll.h>
2933
3034static int pf = AF_INET ;
3135
36+ #ifndef SCM_TIMESTAMPING
37+ #define SCM_TIMESTAMPING SO_TIMESTAMPING
38+ #endif
39+
3240#ifndef IPPROTO_MPTCP
3341#define IPPROTO_MPTCP 262
3442#endif
@@ -128,6 +136,9 @@ struct so_state {
128136#define MIN (a , b ) ((a) < (b) ? (a) : (b))
129137#endif
130138
139+ static void enable_tx_timestamping (int fd );
140+ static void test_msg_errqueue_timestamping (int fd );
141+
131142static void __noreturn die_perror (const char * msg )
132143{
133144 perror (msg );
@@ -598,13 +609,17 @@ static void connect_one_server(int fd, int pipefd)
598609
599610 assert (strncmp (buf2 , "xmit" , 4 ) == 0 );
600611
612+ enable_tx_timestamping (fd );
613+
601614 ret = write (fd , buf , len );
602615 if (ret < 0 )
603616 die_perror ("write" );
604617
605618 if (ret != (ssize_t )len )
606619 xerror ("short write" );
607620
621+ test_msg_errqueue_timestamping (fd );
622+
608623 total = 0 ;
609624 do {
610625 ret = read (fd , buf2 + total , sizeof (buf2 ) - total );
@@ -769,6 +784,142 @@ static void test_ip_tos_sockopt(int fd)
769784 xerror ("expect socklen_t == -1" );
770785}
771786
787+ static void test_ip_recverr_sockopt (int fd )
788+ {
789+ struct iovec iov = {
790+ .iov_base = & (char ){ 0 },
791+ .iov_len = 1 ,
792+ };
793+ struct msghdr msg = {
794+ .msg_iov = & iov ,
795+ .msg_iovlen = 1 ,
796+ };
797+ int one = 1 , zero = 0 , val = -1 ;
798+ socklen_t s = sizeof (val );
799+ int level , optname , r ;
800+
801+ switch (pf ) {
802+ case AF_INET :
803+ level = SOL_IP ;
804+ optname = IP_RECVERR ;
805+ break ;
806+ case AF_INET6 :
807+ level = SOL_IPV6 ;
808+ optname = IPV6_RECVERR ;
809+ break ;
810+ default :
811+ xerror ("Unknown pf %d\n" , pf );
812+ }
813+
814+ r = setsockopt (fd , level , optname , & one , sizeof (one ));
815+ if (r )
816+ die_perror ("setsockopt recverr on" );
817+
818+ r = getsockopt (fd , level , optname , & val , & s );
819+ if (r )
820+ die_perror ("getsockopt recverr on" );
821+ if (s != sizeof (val ) || val != one )
822+ xerror ("recverr on mismatch val=%d len=%u" , val , s );
823+
824+ r = recvmsg (fd , & msg , MSG_ERRQUEUE | MSG_DONTWAIT );
825+ if (r != -1 || errno != EAGAIN )
826+ xerror ("expected empty errqueue to return EAGAIN, ret=%d errno=%d" , r , errno );
827+
828+ r = setsockopt (fd , level , optname , & zero , sizeof (zero ));
829+ if (r )
830+ die_perror ("setsockopt recverr off" );
831+
832+ val = -1 ;
833+ s = sizeof (val );
834+ r = getsockopt (fd , level , optname , & val , & s );
835+ if (r )
836+ die_perror ("getsockopt recverr off" );
837+ if (s != sizeof (val ) || val != zero )
838+ xerror ("recverr off mismatch val=%d len=%u" , val , s );
839+ }
840+
841+ static void enable_tx_timestamping (int fd )
842+ {
843+ int val = SOF_TIMESTAMPING_SOFTWARE |
844+ SOF_TIMESTAMPING_TX_SOFTWARE |
845+ SOF_TIMESTAMPING_OPT_TSONLY ;
846+ int ret ;
847+
848+ ret = setsockopt (fd , SOL_SOCKET , SO_TIMESTAMPING_OLD ,
849+ & val , sizeof (val ));
850+ if (ret )
851+ die_perror ("setsockopt SO_TIMESTAMPING" );
852+ }
853+
854+ static void test_msg_errqueue_timestamping (int fd )
855+ {
856+ char ctrl [512 ] = { 0 };
857+ char data [32 ] = { 0 };
858+ struct iovec iov = {
859+ .iov_base = data ,
860+ .iov_len = sizeof (data ),
861+ };
862+ struct msghdr msg = {
863+ .msg_iov = & iov ,
864+ .msg_iovlen = 1 ,
865+ .msg_control = ctrl ,
866+ .msg_controllen = sizeof (ctrl ),
867+ };
868+ struct pollfd pfd = {
869+ .fd = fd ,
870+ .events = POLLERR ,
871+ };
872+ struct cmsghdr * cm ;
873+ struct scm_timestamping * tss = NULL ;
874+ struct sock_extended_err * serr = NULL ;
875+ int ret , i ;
876+
877+ for (i = 0 ; i < 10 ; i ++ ) {
878+ ret = poll (& pfd , 1 , 1000 );
879+ if (ret < 0 )
880+ die_perror ("poll errqueue" );
881+ if (ret == 0 )
882+ continue ;
883+ if (!(pfd .revents & POLLERR ))
884+ xerror ("expected POLLERR, got revents %#x" , pfd .revents );
885+ break ;
886+ }
887+
888+ if (i == 10 )
889+ xerror ("timed out waiting for MSG_ERRQUEUE event" );
890+
891+ ret = recvmsg (fd , & msg , MSG_ERRQUEUE );
892+ if (ret < 0 )
893+ die_perror ("recvmsg timestamping errqueue" );
894+ if (!(msg .msg_flags & MSG_ERRQUEUE ))
895+ xerror ("expected MSG_ERRQUEUE in msg_flags, got %#x" ,
896+ msg .msg_flags );
897+
898+ for (cm = CMSG_FIRSTHDR (& msg ); cm ; cm = CMSG_NXTHDR (& msg , cm )) {
899+ if (cm -> cmsg_level == SOL_SOCKET &&
900+ cm -> cmsg_type == SCM_TIMESTAMPING )
901+ tss = (void * )CMSG_DATA (cm );
902+ if ((cm -> cmsg_level == SOL_IP &&
903+ cm -> cmsg_type == IP_RECVERR ) ||
904+ (cm -> cmsg_level == SOL_IPV6 &&
905+ cm -> cmsg_type == IPV6_RECVERR ))
906+ serr = (void * )CMSG_DATA (cm );
907+ }
908+
909+ if (!tss )
910+ xerror ("missing SCM_TIMESTAMPING cmsg" );
911+ if (!serr )
912+ xerror ("missing sock_extended_err cmsg" );
913+ if (serr -> ee_errno != ENOMSG ||
914+ serr -> ee_origin != SO_EE_ORIGIN_TIMESTAMPING )
915+ xerror ("unexpected timestamping err ee_errno=%u ee_origin=%u" ,
916+ serr -> ee_errno , serr -> ee_origin );
917+ if (!tss -> ts [0 ].tv_sec && !tss -> ts [0 ].tv_nsec &&
918+ !tss -> ts [1 ].tv_sec && !tss -> ts [1 ].tv_nsec &&
919+ !tss -> ts [2 ].tv_sec && !tss -> ts [2 ].tv_nsec )
920+ xerror ("all timestamp slots are zero" );
921+ }
922+
772923static int client (int pipefd )
773924{
774925 int fd = -1 ;
@@ -787,6 +938,7 @@ static int client(int pipefd)
787938 }
788939
789940 test_ip_tos_sockopt (fd );
941+ test_ip_recverr_sockopt (fd );
790942
791943 connect_one_server (fd , pipefd );
792944
0 commit comments