net: Provide a generic socket error queue delivery method for Tx time stamps.
authorRichard Cochran <richardcochran@gmail.com>
Fri, 19 Jul 2013 17:40:09 +0000 (19:40 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 22 Jul 2013 21:58:19 +0000 (14:58 -0700)
This patch moves the private error queue delivery function from the
af_packet code to the core socket method. In this way, network layers
only needing the error queue for transmit time stamping can share common
code.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sock.h
net/core/sock.c
net/packet/af_packet.c

index 95a5a2c..e0473f6 100644 (file)
@@ -2249,6 +2249,8 @@ static inline struct sock *skb_steal_sock(struct sk_buff *skb)
 extern void sock_enable_timestamp(struct sock *sk, int flag);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
 extern int sock_get_timestampns(struct sock *, struct timespec __user *);
+extern int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
+                             int level, int type);
 
 /*
  *     Enable debug/info messages
index 548d716..85e8de1 100644 (file)
@@ -93,6 +93,7 @@
 
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <linux/errqueue.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/in.h>
@@ -2425,6 +2426,52 @@ void sock_enable_timestamp(struct sock *sk, int flag)
        }
 }
 
+int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
+                      int level, int type)
+{
+       struct sock_exterr_skb *serr;
+       struct sk_buff *skb, *skb2;
+       int copied, err;
+
+       err = -EAGAIN;
+       skb = skb_dequeue(&sk->sk_error_queue);
+       if (skb == NULL)
+               goto out;
+
+       copied = skb->len;
+       if (copied > len) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto out_free_skb;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       serr = SKB_EXT_ERR(skb);
+       put_cmsg(msg, level, type, sizeof(serr->ee), &serr->ee);
+
+       msg->msg_flags |= MSG_ERRQUEUE;
+       err = copied;
+
+       /* Reset and regenerate socket error */
+       spin_lock_bh(&sk->sk_error_queue.lock);
+       sk->sk_err = 0;
+       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
+               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+               spin_unlock_bh(&sk->sk_error_queue.lock);
+               sk->sk_error_report(sk);
+       } else
+               spin_unlock_bh(&sk->sk_error_queue.lock);
+
+out_free_skb:
+       kfree_skb(skb);
+out:
+       return err;
+}
+EXPORT_SYMBOL(sock_recv_errqueue);
+
 /*
  *     Get a socket option on an socket.
  *
index 4b66c75..4cb28a7 100644 (file)
@@ -2638,51 +2638,6 @@ out:
        return err;
 }
 
-static int packet_recv_error(struct sock *sk, struct msghdr *msg, int len)
-{
-       struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
-       int copied, err;
-
-       err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
-       if (skb == NULL)
-               goto out;
-
-       copied = skb->len;
-       if (copied > len) {
-               msg->msg_flags |= MSG_TRUNC;
-               copied = len;
-       }
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-       if (err)
-               goto out_free_skb;
-
-       sock_recv_timestamp(msg, sk, skb);
-
-       serr = SKB_EXT_ERR(skb);
-       put_cmsg(msg, SOL_PACKET, PACKET_TX_TIMESTAMP,
-                sizeof(serr->ee), &serr->ee);
-
-       msg->msg_flags |= MSG_ERRQUEUE;
-       err = copied;
-
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-
-out_free_skb:
-       kfree_skb(skb);
-out:
-       return err;
-}
-
 /*
  *     Pull a packet from our receive queue and hand it to the user.
  *     If necessary we block.
@@ -2708,7 +2663,8 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
 #endif
 
        if (flags & MSG_ERRQUEUE) {
-               err = packet_recv_error(sk, msg, len);
+               err = sock_recv_errqueue(sk, msg, len,
+                                        SOL_PACKET, PACKET_TX_TIMESTAMP);
                goto out;
        }