kernel: add missing patch
[oweals/openwrt.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