aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-07-18 21:05:19 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-18 21:05:19 -0400
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 a630295b255f..18db0668065a 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -45,6 +45,7 @@ struct sockaddr_ll
45#define PACKET_ORIGDEV 9 45#define PACKET_ORIGDEV 9
46#define PACKET_VERSION 10 46#define PACKET_VERSION 10
47#define PACKET_HDRLEN 11 47#define PACKET_HDRLEN 11
48#define PACKET_RESERVE 12
48 49
49struct tpacket_stats 50struct tpacket_stats
50{ 51{
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index db792e02a37f..de73bcb5235a 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -188,6 +188,7 @@ struct packet_sock {
188 unsigned int pg_vec_len; 188 unsigned int pg_vec_len;
189 enum tpacket_versions tp_version; 189 enum tpacket_versions tp_version;
190 unsigned int tp_hdrlen; 190 unsigned int tp_hdrlen;
191 unsigned int tp_reserve;
191#endif 192#endif
192}; 193};
193 194
@@ -635,11 +636,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
635 snaplen = res; 636 snaplen = res;
636 637
637 if (sk->sk_type == SOCK_DGRAM) { 638 if (sk->sk_type == SOCK_DGRAM) {
638 macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16; 639 macoff = netoff = TPACKET_ALIGN(po->tp_hdrlen) + 16 +
640 po->tp_reserve;
639 } else { 641 } else {
640 unsigned maclen = skb_network_offset(skb); 642 unsigned maclen = skb_network_offset(skb);
641 netoff = TPACKET_ALIGN(po->tp_hdrlen + 643 netoff = TPACKET_ALIGN(po->tp_hdrlen +
642 (maclen < 16 ? 16 : maclen)); 644 (maclen < 16 ? 16 : maclen)) +
645 po->tp_reserve;
643 macoff = netoff - maclen; 646 macoff = netoff - maclen;
644 } 647 }
645 648
@@ -1448,6 +1451,19 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
1448 return -EINVAL; 1451 return -EINVAL;
1449 } 1452 }
1450 } 1453 }
1454 case PACKET_RESERVE:
1455 {
1456 unsigned int val;
1457
1458 if (optlen != sizeof(val))
1459 return -EINVAL;
1460 if (po->pg_vec)
1461 return -EBUSY;
1462 if (copy_from_user(&val, optval, sizeof(val)))
1463 return -EFAULT;
1464 po->tp_reserve = val;
1465 return 0;
1466 }
1451#endif 1467#endif
1452 case PACKET_AUXDATA: 1468 case PACKET_AUXDATA:
1453 { 1469 {
@@ -1547,6 +1563,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
1547 } 1563 }
1548 data = &val; 1564 data = &val;
1549 break; 1565 break;
1566 case PACKET_RESERVE:
1567 if (len > sizeof(unsigned int))
1568 len = sizeof(unsigned int);
1569 val = po->tp_reserve;
1570 data = &val;
1571 break;
1550#endif 1572#endif
1551 default: 1573 default:
1552 return -ENOPROTOOPT; 1574 return -ENOPROTOOPT;
@@ -1790,7 +1812,8 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
1790 return -EINVAL; 1812 return -EINVAL;
1791 if (unlikely(req->tp_block_size & (PAGE_SIZE - 1))) 1813 if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
1792 return -EINVAL; 1814 return -EINVAL;
1793 if (unlikely(req->tp_frame_size < po->tp_hdrlen)) 1815 if (unlikely(req->tp_frame_size < po->tp_hdrlen +
1816 po->tp_reserve))
1794 return -EINVAL; 1817 return -EINVAL;
1795 if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1))) 1818 if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
1796 return -EINVAL; 1819 return -EINVAL;