diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2009-02-12 00:03:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-16 01:43:35 -0500 |
commit | 20d4947353be60e909e6b1a79d241457edd6833f (patch) | |
tree | 939ced518fc52e57df9ee9efb0cd14b6e26a3bc4 /net/socket.c | |
parent | ac45f602ee3d1b6f326f68bc0c2591ceebf05ba4 (diff) |
net: socket infrastructure for SO_TIMESTAMPING
The overlap with the old SO_TIMESTAMP[NS] options is handled so
that time stamping in software (net_enable_timestamp()) is
enabled when SO_TIMESTAMP[NS] and/or SO_TIMESTAMPING_RX_SOFTWARE
is set. It's disabled if all of these are off.
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 84 |
1 files changed, 64 insertions, 20 deletions
diff --git a/net/socket.c b/net/socket.c index 35dd7371752a..47a3dc074eb0 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -545,6 +545,18 @@ void sock_release(struct socket *sock) | |||
545 | sock->file = NULL; | 545 | sock->file = NULL; |
546 | } | 546 | } |
547 | 547 | ||
548 | int sock_tx_timestamp(struct msghdr *msg, struct sock *sk, | ||
549 | union skb_shared_tx *shtx) | ||
550 | { | ||
551 | shtx->flags = 0; | ||
552 | if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) | ||
553 | shtx->hardware = 1; | ||
554 | if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) | ||
555 | shtx->software = 1; | ||
556 | return 0; | ||
557 | } | ||
558 | EXPORT_SYMBOL(sock_tx_timestamp); | ||
559 | |||
548 | static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, | 560 | static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, |
549 | struct msghdr *msg, size_t size) | 561 | struct msghdr *msg, size_t size) |
550 | { | 562 | { |
@@ -595,33 +607,65 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg, | |||
595 | return result; | 607 | return result; |
596 | } | 608 | } |
597 | 609 | ||
610 | static int ktime2ts(ktime_t kt, struct timespec *ts) | ||
611 | { | ||
612 | if (kt.tv64) { | ||
613 | *ts = ktime_to_timespec(kt); | ||
614 | return 1; | ||
615 | } else { | ||
616 | return 0; | ||
617 | } | ||
618 | } | ||
619 | |||
598 | /* | 620 | /* |
599 | * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) | 621 | * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) |
600 | */ | 622 | */ |
601 | void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, | 623 | void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, |
602 | struct sk_buff *skb) | 624 | struct sk_buff *skb) |
603 | { | 625 | { |
604 | ktime_t kt = skb->tstamp; | 626 | int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); |
605 | 627 | struct timespec ts[3]; | |
606 | if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { | 628 | int empty = 1; |
607 | struct timeval tv; | 629 | struct skb_shared_hwtstamps *shhwtstamps = |
608 | /* Race occurred between timestamp enabling and packet | 630 | skb_hwtstamps(skb); |
609 | receiving. Fill in the current time for now. */ | 631 | |
610 | if (kt.tv64 == 0) | 632 | /* Race occurred between timestamp enabling and packet |
611 | kt = ktime_get_real(); | 633 | receiving. Fill in the current time for now. */ |
612 | skb->tstamp = kt; | 634 | if (need_software_tstamp && skb->tstamp.tv64 == 0) |
613 | tv = ktime_to_timeval(kt); | 635 | __net_timestamp(skb); |
614 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, sizeof(tv), &tv); | 636 | |
615 | } else { | 637 | if (need_software_tstamp) { |
616 | struct timespec ts; | 638 | if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { |
617 | /* Race occurred between timestamp enabling and packet | 639 | struct timeval tv; |
618 | receiving. Fill in the current time for now. */ | 640 | skb_get_timestamp(skb, &tv); |
619 | if (kt.tv64 == 0) | 641 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, |
620 | kt = ktime_get_real(); | 642 | sizeof(tv), &tv); |
621 | skb->tstamp = kt; | 643 | } else { |
622 | ts = ktime_to_timespec(kt); | 644 | struct timespec ts; |
623 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof(ts), &ts); | 645 | skb_get_timestampns(skb, &ts); |
646 | put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, | ||
647 | sizeof(ts), &ts); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | |||
652 | memset(ts, 0, sizeof(ts)); | ||
653 | if (skb->tstamp.tv64 && | ||
654 | sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) { | ||
655 | skb_get_timestampns(skb, ts + 0); | ||
656 | empty = 0; | ||
657 | } | ||
658 | if (shhwtstamps) { | ||
659 | if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) && | ||
660 | ktime2ts(shhwtstamps->syststamp, ts + 1)) | ||
661 | empty = 0; | ||
662 | if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && | ||
663 | ktime2ts(shhwtstamps->hwtstamp, ts + 2)) | ||
664 | empty = 0; | ||
624 | } | 665 | } |
666 | if (!empty) | ||
667 | put_cmsg(msg, SOL_SOCKET, | ||
668 | SCM_TIMESTAMPING, sizeof(ts), &ts); | ||
625 | } | 669 | } |
626 | 670 | ||
627 | EXPORT_SYMBOL_GPL(__sock_recv_timestamp); | 671 | EXPORT_SYMBOL_GPL(__sock_recv_timestamp); |