summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-18 18:05:19 -0700
committerDavid S. Miller <davem@davemloft.net>2008-07-18 18:05:19 -0700
commit8913336a7e8d56e984109a3137d6c0e3362596a4 (patch)
tree16e2ad819112b59a759daff79651955e9bfab1dd
parent3ca4095f246c21c285d9e4be2ea4d3ee7fbacebd (diff)
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>
-rw-r--r--include/linux/if_packet.h1
-rw-r--r--net/packet/af_packet.c29
2 files changed, 27 insertions, 3 deletions
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index a630295b255..18db0668065 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -45,6 +45,7 @@ struct sockaddr_ll
#define PACKET_ORIGDEV 9
#define PACKET_VERSION 10
#define PACKET_HDRLEN 11
+#define PACKET_RESERVE 12
struct tpacket_stats
{
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index db792e02a37..de73bcb5235 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -188,6 +188,7 @@ struct packet_sock {
unsigned int pg_vec_len;
enum tpacket_versions tp_version;
unsigned int tp_hdrlen;
+ unsigned int tp_reserve;
#endif
};
@@ -635,11 +636,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
snaplen = res;
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 {
unsigned maclen = skb_network_offset(skb);
netoff = TPACKET_ALIGN(po->tp_hdrlen +
- (maclen < 16 ? 16 : maclen));
+ (maclen < 16 ? 16 : maclen)) +
+ po->tp_reserve;
macoff = netoff - maclen;
}
@@ -1448,6 +1451,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
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
case PACKET_AUXDATA:
{
@@ -1547,6 +1563,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
}
data = &val;
break;
+ case PACKET_RESERVE:
+ if (len > sizeof(unsigned int))
+ len = sizeof(unsigned int);
+ val = po->tp_reserve;
+ data = &val;
+ break;
#endif
default:
return -ENOPROTOOPT;
@@ -1790,7 +1812,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
return -EINVAL;
if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
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;
if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
return -EINVAL;