5afee1e3cff1b758fea24ff6fed469da74874b7b
[openwrt/staging/wigyori.git] / target / linux / generic / pending-4.9 / 630-packet_socket_type.patch
1 From: Felix Fietkau <nbd@nbd.name>
2 Subject: net: add an optimization for dealing with raw sockets
3
4 lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6
5 Signed-off-by: Felix Fietkau <nbd@nbd.name>
6 ---
7 include/uapi/linux/if_packet.h | 3 +++
8 net/packet/af_packet.c | 34 +++++++++++++++++++++++++++-------
9 net/packet/internal.h | 1 +
10 3 files changed, 31 insertions(+), 7 deletions(-)
11
12 diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
13 index 9e7edfd8141e..40fdf8907900 100644
14 --- a/include/uapi/linux/if_packet.h
15 +++ b/include/uapi/linux/if_packet.h
16 @@ -31,6 +31,8 @@ struct sockaddr_ll {
17 #define PACKET_KERNEL 7 /* To kernel space */
18 /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
19 #define PACKET_FASTROUTE 6 /* Fastrouted frame */
20 +#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */
21 +
22
23 /* Packet socket options */
24
25 @@ -56,6 +58,7 @@ struct sockaddr_ll {
26 #define PACKET_QDISC_BYPASS 20
27 #define PACKET_ROLLOVER_STATS 21
28 #define PACKET_FANOUT_DATA 22
29 +#define PACKET_RECV_TYPE 23
30
31 #define PACKET_FANOUT_HASH 0
32 #define PACKET_FANOUT_LB 1
33 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
34 index 6a563e6e24de..e412c5a4f6d4 100644
35 --- a/net/packet/af_packet.c
36 +++ b/net/packet/af_packet.c
37 @@ -1772,6 +1772,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
38 {
39 struct sock *sk;
40 struct sockaddr_pkt *spkt;
41 + struct packet_sock *po;
42
43 /*
44 * When we registered the protocol we saved the socket in the data
45 @@ -1779,6 +1780,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
46 */
47
48 sk = pt->af_packet_priv;
49 + po = pkt_sk(sk);
50
51 /*
52 * Yank back the headers [hope the device set this
53 @@ -1791,7 +1793,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
54 * so that this procedure is noop.
55 */
56
57 - if (skb->pkt_type == PACKET_LOOPBACK)
58 + if (!(po->pkt_type & (1 << skb->pkt_type)))
59 goto out;
60
61 if (!net_eq(dev_net(dev), sock_net(sk)))
62 @@ -2029,12 +2031,12 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
63 unsigned int snaplen, res;
64 bool is_drop_n_account = false;
65
66 - if (skb->pkt_type == PACKET_LOOPBACK)
67 - goto drop;
68 -
69 sk = pt->af_packet_priv;
70 po = pkt_sk(sk);
71
72 + if (!(po->pkt_type & (1 << skb->pkt_type)))
73 + goto drop;
74 +
75 if (!net_eq(dev_net(dev), sock_net(sk)))
76 goto drop;
77
78 @@ -2159,12 +2161,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
79 BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
80 BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
81
82 - if (skb->pkt_type == PACKET_LOOPBACK)
83 - goto drop;
84 -
85 sk = pt->af_packet_priv;
86 po = pkt_sk(sk);
87
88 + if (!(po->pkt_type & (1 << skb->pkt_type)))
89 + goto drop;
90 +
91 if (!net_eq(dev_net(dev), sock_net(sk)))
92 goto drop;
93
94 @@ -3234,6 +3236,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
95 mutex_init(&po->pg_vec_lock);
96 po->rollover = NULL;
97 po->prot_hook.func = packet_rcv;
98 + po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
99
100 if (sock->type == SOCK_PACKET)
101 po->prot_hook.func = packet_rcv_spkt;
102 @@ -3815,6 +3818,16 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
103 po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
104 return 0;
105 }
106 + case PACKET_RECV_TYPE:
107 + {
108 + unsigned int val;
109 + if (optlen != sizeof(val))
110 + return -EINVAL;
111 + if (copy_from_user(&val, optval, sizeof(val)))
112 + return -EFAULT;
113 + po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
114 + return 0;
115 + }
116 default:
117 return -ENOPROTOOPT;
118 }
119 @@ -3867,6 +3880,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
120 case PACKET_VNET_HDR:
121 val = po->has_vnet_hdr;
122 break;
123 + case PACKET_RECV_TYPE:
124 + if (len > sizeof(unsigned int))
125 + len = sizeof(unsigned int);
126 + val = po->pkt_type;
127 +
128 + data = &val;
129 + break;
130 case PACKET_VERSION:
131 val = po->tp_version;
132 break;
133 diff --git a/net/packet/internal.h b/net/packet/internal.h
134 index 9ee46314b7d7..76c895fcf22f 100644
135 --- a/net/packet/internal.h
136 +++ b/net/packet/internal.h
137 @@ -129,6 +129,7 @@ struct packet_sock {
138 struct net_device __rcu *cached_dev;
139 int (*xmit)(struct sk_buff *skb);
140 struct packet_type prot_hook ____cacheline_aligned_in_smp;
141 + unsigned int pkt_type;
142 };
143
144 static struct packet_sock *pkt_sk(struct sock *sk)
145 --
146 2.11.0
147