diff options
author | Eyal Birger <eyal.birger@gmail.com> | 2015-03-01 07:58:28 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-02 00:19:29 -0500 |
commit | 2472d7613bd3bae40a7dc75539c0858d5b9e795a (patch) | |
tree | 0c08b919ed13050fef72a0e2f1f8552157d833ea | |
parent | 2cfdf9fcb85bf6c0bb4556384ba800b9f443f601 (diff) |
net: packet: use sockaddr_ll fields as storage for skb original length in recvmsg path
As part of an effort to move skb->dropcount to skb->cb[], 4 bytes
of additional room are needed in skb->cb[] in packet sockets.
Store the skb original length in the first two fields of sockaddr_ll
(sll_family and sll_protocol) as they can be derived from the skb when
needed.
Signed-off-by: Eyal Birger <eyal.birger@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/packet/af_packet.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 9c28cec1a083..7eea30b9c8e5 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -216,10 +216,16 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *, | |||
216 | static void packet_flush_mclist(struct sock *sk); | 216 | static void packet_flush_mclist(struct sock *sk); |
217 | 217 | ||
218 | struct packet_skb_cb { | 218 | struct packet_skb_cb { |
219 | unsigned int origlen; | ||
220 | union { | 219 | union { |
221 | struct sockaddr_pkt pkt; | 220 | struct sockaddr_pkt pkt; |
222 | struct sockaddr_ll ll; | 221 | union { |
222 | /* Trick: alias skb original length with | ||
223 | * ll.sll_family and ll.protocol in order | ||
224 | * to save room. | ||
225 | */ | ||
226 | unsigned int origlen; | ||
227 | struct sockaddr_ll ll; | ||
228 | }; | ||
223 | } sa; | 229 | } sa; |
224 | }; | 230 | }; |
225 | 231 | ||
@@ -1814,9 +1820,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, | |||
1814 | sizeof(skb->cb)); | 1820 | sizeof(skb->cb)); |
1815 | 1821 | ||
1816 | sll = &PACKET_SKB_CB(skb)->sa.ll; | 1822 | sll = &PACKET_SKB_CB(skb)->sa.ll; |
1817 | sll->sll_family = AF_PACKET; | ||
1818 | sll->sll_hatype = dev->type; | 1823 | sll->sll_hatype = dev->type; |
1819 | sll->sll_protocol = skb->protocol; | ||
1820 | sll->sll_pkttype = skb->pkt_type; | 1824 | sll->sll_pkttype = skb->pkt_type; |
1821 | if (unlikely(po->origdev)) | 1825 | if (unlikely(po->origdev)) |
1822 | sll->sll_ifindex = orig_dev->ifindex; | 1826 | sll->sll_ifindex = orig_dev->ifindex; |
@@ -1825,7 +1829,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, | |||
1825 | 1829 | ||
1826 | sll->sll_halen = dev_parse_header(skb, sll->sll_addr); | 1830 | sll->sll_halen = dev_parse_header(skb, sll->sll_addr); |
1827 | 1831 | ||
1828 | PACKET_SKB_CB(skb)->origlen = skb->len; | 1832 | /* sll->sll_family and sll->sll_protocol are set in packet_recvmsg(). |
1833 | * Use their space for storing the original skb length. | ||
1834 | */ | ||
1835 | PACKET_SKB_CB(skb)->sa.origlen = skb->len; | ||
1829 | 1836 | ||
1830 | if (pskb_trim(skb, snaplen)) | 1837 | if (pskb_trim(skb, snaplen)) |
1831 | goto drop_n_acct; | 1838 | goto drop_n_acct; |
@@ -2883,6 +2890,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
2883 | struct sk_buff *skb; | 2890 | struct sk_buff *skb; |
2884 | int copied, err; | 2891 | int copied, err; |
2885 | int vnet_hdr_len = 0; | 2892 | int vnet_hdr_len = 0; |
2893 | unsigned int origlen = 0; | ||
2886 | 2894 | ||
2887 | err = -EINVAL; | 2895 | err = -EINVAL; |
2888 | if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT|MSG_ERRQUEUE)) | 2896 | if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT|MSG_ERRQUEUE)) |
@@ -2982,6 +2990,15 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
2982 | if (err) | 2990 | if (err) |
2983 | goto out_free; | 2991 | goto out_free; |
2984 | 2992 | ||
2993 | if (sock->type != SOCK_PACKET) { | ||
2994 | struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; | ||
2995 | |||
2996 | /* Original length was stored in sockaddr_ll fields */ | ||
2997 | origlen = PACKET_SKB_CB(skb)->sa.origlen; | ||
2998 | sll->sll_family = AF_PACKET; | ||
2999 | sll->sll_protocol = skb->protocol; | ||
3000 | } | ||
3001 | |||
2985 | sock_recv_ts_and_drops(msg, sk, skb); | 3002 | sock_recv_ts_and_drops(msg, sk, skb); |
2986 | 3003 | ||
2987 | if (msg->msg_name) { | 3004 | if (msg->msg_name) { |
@@ -2993,6 +3010,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
2993 | msg->msg_namelen = sizeof(struct sockaddr_pkt); | 3010 | msg->msg_namelen = sizeof(struct sockaddr_pkt); |
2994 | } else { | 3011 | } else { |
2995 | struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; | 3012 | struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; |
3013 | |||
2996 | msg->msg_namelen = sll->sll_halen + | 3014 | msg->msg_namelen = sll->sll_halen + |
2997 | offsetof(struct sockaddr_ll, sll_addr); | 3015 | offsetof(struct sockaddr_ll, sll_addr); |
2998 | } | 3016 | } |
@@ -3006,7 +3024,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
3006 | aux.tp_status = TP_STATUS_USER; | 3024 | aux.tp_status = TP_STATUS_USER; |
3007 | if (skb->ip_summed == CHECKSUM_PARTIAL) | 3025 | if (skb->ip_summed == CHECKSUM_PARTIAL) |
3008 | aux.tp_status |= TP_STATUS_CSUMNOTREADY; | 3026 | aux.tp_status |= TP_STATUS_CSUMNOTREADY; |
3009 | aux.tp_len = PACKET_SKB_CB(skb)->origlen; | 3027 | aux.tp_len = origlen; |
3010 | aux.tp_snaplen = skb->len; | 3028 | aux.tp_snaplen = skb->len; |
3011 | aux.tp_mac = 0; | 3029 | aux.tp_mac = 0; |
3012 | aux.tp_net = skb_network_offset(skb); | 3030 | aux.tp_net = skb_network_offset(skb); |