Commit 8913336a authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3ca4095f
...@@ -45,6 +45,7 @@ struct sockaddr_ll ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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, ...@@ -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 ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment