aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet
diff options
context:
space:
mode:
authorRichard Cochran <richardcochran@gmail.com>2010-04-07 18:41:28 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-13 04:30:48 -0400
commited85b565b825566da34e55eee9ad150ed93fdda0 (patch)
tree77b9bad66d0cd6a1b7c657995100d555b8ecb9eb /net/packet
parent7d53b80980a598836c56517290b29aa7b0766ef8 (diff)
packet: support for TX time stamps on RAW sockets
Enable the SO_TIMESTAMPING socket infrastructure for raw packet sockets. We introduce PACKET_TX_TIMESTAMP for the control message cmsg_type. Similar support for UDP and CAN sockets was added in commit 51f31cabe3ce5345b51e4a4f82138b38c4d5dc91 Signed-off-by: Richard Cochran <richard.cochran@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r--net/packet/af_packet.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index d7d0310dca9..f162d59d816 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -82,6 +82,7 @@
82#include <linux/mutex.h> 82#include <linux/mutex.h>
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 86
86#ifdef CONFIG_INET 87#ifdef CONFIG_INET
87#include <net/inet_common.h> 88#include <net/inet_common.h>
@@ -315,6 +316,8 @@ static inline struct packet_sock *pkt_sk(struct sock *sk)
315 316
316static void packet_sock_destruct(struct sock *sk) 317static void packet_sock_destruct(struct sock *sk)
317{ 318{
319 skb_queue_purge(&sk->sk_error_queue);
320
318 WARN_ON(atomic_read(&sk->sk_rmem_alloc)); 321 WARN_ON(atomic_read(&sk->sk_rmem_alloc));
319 WARN_ON(atomic_read(&sk->sk_wmem_alloc)); 322 WARN_ON(atomic_read(&sk->sk_wmem_alloc));
320 323
@@ -483,6 +486,9 @@ retry:
483 skb->dev = dev; 486 skb->dev = dev;
484 skb->priority = sk->sk_priority; 487 skb->priority = sk->sk_priority;
485 skb->mark = sk->sk_mark; 488 skb->mark = sk->sk_mark;
489 err = sock_tx_timestamp(msg, sk, skb_tx(skb));
490 if (err < 0)
491 goto out_unlock;
486 492
487 dev_queue_xmit(skb); 493 dev_queue_xmit(skb);
488 rcu_read_unlock(); 494 rcu_read_unlock();
@@ -1188,6 +1194,9 @@ static int packet_snd(struct socket *sock,
1188 err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len); 1194 err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
1189 if (err) 1195 if (err)
1190 goto out_free; 1196 goto out_free;
1197 err = sock_tx_timestamp(msg, sk, skb_tx(skb));
1198 if (err < 0)
1199 goto out_free;
1191 1200
1192 skb->protocol = proto; 1201 skb->protocol = proto;
1193 skb->dev = dev; 1202 skb->dev = dev;
@@ -1487,6 +1496,51 @@ out:
1487 return err; 1496 return err;
1488} 1497}
1489 1498
1499static int packet_recv_error(struct sock *sk, struct msghdr *msg, int len)
1500{
1501 struct sock_exterr_skb *serr;
1502 struct sk_buff *skb, *skb2;
1503 int copied, err;
1504
1505 err = -EAGAIN;
1506 skb = skb_dequeue(&sk->sk_error_queue);
1507 if (skb == NULL)
1508 goto out;
1509
1510 copied = skb->len;
1511 if (copied > len) {
1512 msg->msg_flags |= MSG_TRUNC;
1513 copied = len;
1514 }
1515 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
1516 if (err)
1517 goto out_free_skb;
1518
1519 sock_recv_timestamp(msg, sk, skb);
1520
1521 serr = SKB_EXT_ERR(skb);
1522 put_cmsg(msg, SOL_PACKET, PACKET_TX_TIMESTAMP,
1523 sizeof(serr->ee), &serr->ee);
1524
1525 msg->msg_flags |= MSG_ERRQUEUE;
1526 err = copied;
1527
1528 /* Reset and regenerate socket error */
1529 spin_lock_bh(&sk->sk_error_queue.lock);
1530 sk->sk_err = 0;
1531 if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
1532 sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
1533 spin_unlock_bh(&sk->sk_error_queue.lock);
1534 sk->sk_error_report(sk);
1535 } else
1536 spin_unlock_bh(&sk->sk_error_queue.lock);
1537
1538out_free_skb:
1539 kfree_skb(skb);
1540out:
1541 return err;
1542}
1543
1490/* 1544/*
1491 * Pull a packet from our receive queue and hand it to the user. 1545 * Pull a packet from our receive queue and hand it to the user.
1492 * If necessary we block. 1546 * If necessary we block.
@@ -1502,7 +1556,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
1502 int vnet_hdr_len = 0; 1556 int vnet_hdr_len = 0;
1503 1557
1504 err = -EINVAL; 1558 err = -EINVAL;
1505 if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) 1559 if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT|MSG_ERRQUEUE))
1506 goto out; 1560 goto out;
1507 1561
1508#if 0 1562#if 0
@@ -1511,6 +1565,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
1511 return -ENODEV; 1565 return -ENODEV;
1512#endif 1566#endif
1513 1567
1568 if (flags & MSG_ERRQUEUE) {
1569 err = packet_recv_error(sk, msg, len);
1570 goto out;
1571 }
1572
1514 /* 1573 /*
1515 * Call the generic datagram receiver. This handles all sorts 1574 * Call the generic datagram receiver. This handles all sorts
1516 * of horrible races and re-entrancy so we can forget about it 1575 * of horrible races and re-entrancy so we can forget about it