mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	packet: add PACKET_RESERVE sockopt
Add new sockopt to reserve some headroom in the mmaped ring frames in front of the packet payload. This can be used f.i. when the VLAN header needs to be (re)constructed to avoid moving the entire payload. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									3ca4095f24
								
							
						
					
					
						commit
						8913336a7e
					
				
					 2 changed files with 27 additions and 3 deletions
				
			
		| 
						 | 
					@ -45,6 +45,7 @@ struct sockaddr_ll
 | 
				
			||||||
#define PACKET_ORIGDEV			9
 | 
					#define PACKET_ORIGDEV			9
 | 
				
			||||||
#define PACKET_VERSION			10
 | 
					#define PACKET_VERSION			10
 | 
				
			||||||
#define PACKET_HDRLEN			11
 | 
					#define PACKET_HDRLEN			11
 | 
				
			||||||
 | 
					#define PACKET_RESERVE			12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tpacket_stats
 | 
					struct tpacket_stats
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,6 +188,7 @@ struct packet_sock {
 | 
				
			||||||
	unsigned int		pg_vec_len;
 | 
						unsigned int		pg_vec_len;
 | 
				
			||||||
	enum tpacket_versions	tp_version;
 | 
						enum tpacket_versions	tp_version;
 | 
				
			||||||
	unsigned int		tp_hdrlen;
 | 
						unsigned int		tp_hdrlen;
 | 
				
			||||||
 | 
						unsigned int		tp_reserve;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -635,11 +636,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
 | 
				
			||||||
		snaplen = res;
 | 
							snaplen = res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sk->sk_type == SOCK_DGRAM) {
 | 
						if (sk->sk_type == SOCK_DGRAM) {
 | 
				
			||||||
		macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16;
 | 
							macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16 +
 | 
				
			||||||
 | 
									  po->tp_reserve;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		unsigned maclen = skb_network_offset(skb);
 | 
							unsigned maclen = skb_network_offset(skb);
 | 
				
			||||||
		netoff = TPACKET_ALIGN(po->tp_hdrlen +
 | 
							netoff = TPACKET_ALIGN(po->tp_hdrlen +
 | 
				
			||||||
				       (maclen < 16 ? 16 : maclen));
 | 
									       (maclen < 16 ? 16 : maclen)) +
 | 
				
			||||||
 | 
								po->tp_reserve;
 | 
				
			||||||
		macoff = netoff - maclen;
 | 
							macoff = netoff - maclen;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1448,6 +1451,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						case PACKET_RESERVE:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							unsigned int val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (optlen != sizeof(val))
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							if (po->pg_vec)
 | 
				
			||||||
 | 
								return -EBUSY;
 | 
				
			||||||
 | 
							if (copy_from_user(&val, optval, sizeof(val)))
 | 
				
			||||||
 | 
								return -EFAULT;
 | 
				
			||||||
 | 
							po->tp_reserve = val;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	case PACKET_AUXDATA:
 | 
						case PACKET_AUXDATA:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -1547,6 +1563,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		data = &val;
 | 
							data = &val;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case PACKET_RESERVE:
 | 
				
			||||||
 | 
							if (len > sizeof(unsigned int))
 | 
				
			||||||
 | 
								len = sizeof(unsigned int);
 | 
				
			||||||
 | 
							val = po->tp_reserve;
 | 
				
			||||||
 | 
							data = &val;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return -ENOPROTOOPT;
 | 
							return -ENOPROTOOPT;
 | 
				
			||||||
| 
						 | 
					@ -1790,7 +1812,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
 | 
							if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		if (unlikely(req->tp_frame_size < po->tp_hdrlen))
 | 
							if (unlikely(req->tp_frame_size < po->tp_hdrlen +
 | 
				
			||||||
 | 
											  po->tp_reserve))
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
 | 
							if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue