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