diff options
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 29 |
1 files changed, 26 insertions, 3 deletions
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; |