treewide: fix replace nbd@openwrt.org with nbd@nbd.name
[openwrt.org/openwrt.git] / target / linux / generic / patches-3.18 / 630-packet_socket_type.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
This patch allows the user to specify desired packet types (outgoing,
broadcast, unicast, etc.) on packet sockets via setsockopt.
This can reduce the load in situations where only a limited number
of packet types are necessary
 
Signed-off-by: Felix Fietkau <nbd@nbd.name>
 
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -31,6 +31,8 @@ struct sockaddr_ll {
 #define PACKET_KERNEL          7               /* To kernel space      */
 /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
 #define PACKET_FASTROUTE       6               /* Fastrouted frame     */
+#define PACKET_MASK_ANY                0xffffffff      /* mask for packet type bits */
+
 
 /* Packet socket options */
 
@@ -54,6 +56,7 @@ struct sockaddr_ll {
 #define PACKET_FANOUT                  18
 #define PACKET_TX_HAS_OFF              19
 #define PACKET_QDISC_BYPASS            20
+#define PACKET_RECV_TYPE               21
 
 #define PACKET_FANOUT_HASH             0
 #define PACKET_FANOUT_LB               1
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1530,6 +1530,7 @@ static int packet_rcv_spkt(struct sk_buf
 {
        struct sock *sk;
        struct sockaddr_pkt *spkt;
+       struct packet_sock *po;
 
        /*
         *      When we registered the protocol we saved the socket in the data
@@ -1537,6 +1538,7 @@ static int packet_rcv_spkt(struct sk_buf
         */
 
        sk = pt->af_packet_priv;
+       po = pkt_sk(sk);
 
        /*
         *      Yank back the headers [hope the device set this
@@ -1549,7 +1551,7 @@ static int packet_rcv_spkt(struct sk_buf
         *      so that this procedure is noop.
         */
 
-       if (skb->pkt_type == PACKET_LOOPBACK)
+       if (!(po->pkt_type & (1 << skb->pkt_type)))
                goto out;
 
        if (!net_eq(dev_net(dev), sock_net(sk)))
@@ -1748,12 +1750,12 @@ static int packet_rcv(struct sk_buff *sk
        int skb_len = skb->len;
        unsigned int snaplen, res;
 
-       if (skb->pkt_type == PACKET_LOOPBACK)
-               goto drop;
-
        sk = pt->af_packet_priv;
        po = pkt_sk(sk);
 
+       if (!(po->pkt_type & (1 << skb->pkt_type)))
+               goto drop;
+
        if (!net_eq(dev_net(dev), sock_net(sk)))
                goto drop;
 
@@ -1873,12 +1875,12 @@ static int tpacket_rcv(struct sk_buff *s
        BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
        BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
 
-       if (skb->pkt_type == PACKET_LOOPBACK)
-               goto drop;
-
        sk = pt->af_packet_priv;
        po = pkt_sk(sk);
 
+       if (!(po->pkt_type & (1 << skb->pkt_type)))
+               goto drop;
+
        if (!net_eq(dev_net(dev), sock_net(sk)))
                goto drop;
 
@@ -2828,6 +2830,7 @@ static int packet_create(struct net *net
        spin_lock_init(&po->bind_lock);
        mutex_init(&po->pg_vec_lock);
        po->prot_hook.func = packet_rcv;
+       po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
 
        if (sock->type == SOCK_PACKET)
                po->prot_hook.func = packet_rcv_spkt;
@@ -3408,6 +3411,16 @@ packet_setsockopt(struct socket *sock, i
                po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
                return 0;
        }
+        case PACKET_RECV_TYPE:
+        {
+                unsigned int val;
+                if (optlen != sizeof(val))
+                        return -EINVAL;
+                if (copy_from_user(&val, optval, sizeof(val)))
+                        return -EFAULT;
+                po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
+                return 0;
+        }
        default:
                return -ENOPROTOOPT;
        }
@@ -3459,6 +3472,13 @@ static int packet_getsockopt(struct sock
        case PACKET_VNET_HDR:
                val = po->has_vnet_hdr;
                break;
+       case PACKET_RECV_TYPE:
+               if (len > sizeof(unsigned int))
+                       len = sizeof(unsigned int);
+               val = po->pkt_type;
+
+               data = &val;
+               break;
        case PACKET_VERSION:
                val = po->tp_version;
                break;
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -117,6 +117,7 @@ struct packet_sock {
        struct net_device __rcu *cached_dev;
        int                     (*xmit)(struct sk_buff *skb);
        struct packet_type      prot_hook ____cacheline_aligned_in_smp;
+       unsigned int            pkt_type;
 };
 
 static struct packet_sock *pkt_sk(struct sock *sk)
 
comments