net: Provide a generic socket error queue delivery method for Tx time stamps.
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>
This commit is contained in:
		
					parent
					
						
							
								0887a576a1
							
						
					
				
			
			
				commit
				
					
						cb820f8e4b
					
				
			
		
					 3 changed files with 51 additions and 46 deletions
				
			
		|  | @ -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 void sock_enable_timestamp(struct sock *sk, int flag); | ||||||
| extern int sock_get_timestamp(struct sock *, struct timeval __user *); | extern int sock_get_timestamp(struct sock *, struct timeval __user *); | ||||||
| extern int sock_get_timestampns(struct sock *, struct timespec __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 |  *	Enable debug/info messages | ||||||
|  |  | ||||||
|  | @ -93,6 +93,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <linux/capability.h> | #include <linux/capability.h> | ||||||
| #include <linux/errno.h> | #include <linux/errno.h> | ||||||
|  | #include <linux/errqueue.h> | ||||||
| #include <linux/types.h> | #include <linux/types.h> | ||||||
| #include <linux/socket.h> | #include <linux/socket.h> | ||||||
| #include <linux/in.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. |  *	Get a socket option on an socket. | ||||||
|  * |  * | ||||||
|  |  | ||||||
|  | @ -2638,51 +2638,6 @@ out: | ||||||
| 	return err; | 	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. |  *	Pull a packet from our receive queue and hand it to the user. | ||||||
|  *	If necessary we block. |  *	If necessary we block. | ||||||
|  | @ -2708,7 +2663,8 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	if (flags & MSG_ERRQUEUE) { | 	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; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Richard Cochran
				Richard Cochran