aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet/af_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r--net/packet/af_packet.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2078a277e06..9a17f28b125 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -83,6 +83,7 @@
83#include <linux/if_vlan.h> 83#include <linux/if_vlan.h>
84#include <linux/virtio_net.h> 84#include <linux/virtio_net.h>
85#include <linux/errqueue.h> 85#include <linux/errqueue.h>
86#include <linux/net_tstamp.h>
86 87
87#ifdef CONFIG_INET 88#ifdef CONFIG_INET
88#include <net/inet_common.h> 89#include <net/inet_common.h>
@@ -202,6 +203,7 @@ struct packet_sock {
202 unsigned int tp_hdrlen; 203 unsigned int tp_hdrlen;
203 unsigned int tp_reserve; 204 unsigned int tp_reserve;
204 unsigned int tp_loss:1; 205 unsigned int tp_loss:1;
206 unsigned int tp_tstamp;
205 struct packet_type prot_hook ____cacheline_aligned_in_smp; 207 struct packet_type prot_hook ____cacheline_aligned_in_smp;
206}; 208};
207 209
@@ -656,6 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
656 struct sk_buff *copy_skb = NULL; 658 struct sk_buff *copy_skb = NULL;
657 struct timeval tv; 659 struct timeval tv;
658 struct timespec ts; 660 struct timespec ts;
661 struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
659 662
660 if (skb->pkt_type == PACKET_LOOPBACK) 663 if (skb->pkt_type == PACKET_LOOPBACK)
661 goto drop; 664 goto drop;
@@ -737,7 +740,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
737 h.h1->tp_snaplen = snaplen; 740 h.h1->tp_snaplen = snaplen;
738 h.h1->tp_mac = macoff; 741 h.h1->tp_mac = macoff;
739 h.h1->tp_net = netoff; 742 h.h1->tp_net = netoff;
740 if (skb->tstamp.tv64) 743 if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
744 && shhwtstamps->syststamp.tv64)
745 tv = ktime_to_timeval(shhwtstamps->syststamp);
746 else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
747 && shhwtstamps->hwtstamp.tv64)
748 tv = ktime_to_timeval(shhwtstamps->hwtstamp);
749 else if (skb->tstamp.tv64)
741 tv = ktime_to_timeval(skb->tstamp); 750 tv = ktime_to_timeval(skb->tstamp);
742 else 751 else
743 do_gettimeofday(&tv); 752 do_gettimeofday(&tv);
@@ -750,7 +759,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
750 h.h2->tp_snaplen = snaplen; 759 h.h2->tp_snaplen = snaplen;
751 h.h2->tp_mac = macoff; 760 h.h2->tp_mac = macoff;
752 h.h2->tp_net = netoff; 761 h.h2->tp_net = netoff;
753 if (skb->tstamp.tv64) 762 if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
763 && shhwtstamps->syststamp.tv64)
764 ts = ktime_to_timespec(shhwtstamps->syststamp);
765 else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
766 && shhwtstamps->hwtstamp.tv64)
767 ts = ktime_to_timespec(shhwtstamps->hwtstamp);
768 else if (skb->tstamp.tv64)
754 ts = ktime_to_timespec(skb->tstamp); 769 ts = ktime_to_timespec(skb->tstamp);
755 else 770 else
756 getnstimeofday(&ts); 771 getnstimeofday(&ts);
@@ -2027,6 +2042,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
2027 po->has_vnet_hdr = !!val; 2042 po->has_vnet_hdr = !!val;
2028 return 0; 2043 return 0;
2029 } 2044 }
2045 case PACKET_TIMESTAMP:
2046 {
2047 int val;
2048
2049 if (optlen != sizeof(val))
2050 return -EINVAL;
2051 if (copy_from_user(&val, optval, sizeof(val)))
2052 return -EFAULT;
2053
2054 po->tp_tstamp = val;
2055 return 0;
2056 }
2030 default: 2057 default:
2031 return -ENOPROTOOPT; 2058 return -ENOPROTOOPT;
2032 } 2059 }
@@ -2119,6 +2146,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
2119 val = po->tp_loss; 2146 val = po->tp_loss;
2120 data = &val; 2147 data = &val;
2121 break; 2148 break;
2149 case PACKET_TIMESTAMP:
2150 if (len > sizeof(int))
2151 len = sizeof(int);
2152 val = po->tp_tstamp;
2153 data = &val;
2154 break;
2122 default: 2155 default:
2123 return -ENOPROTOOPT; 2156 return -ENOPROTOOPT;
2124 } 2157 }