linux/generic: refresh 2.6.37 patches
[openwrt.git] / target / linux / generic / patches-2.6.37 / 240-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/linux/if_packet.h
9 +++ b/include/linux/if_packet.h
10 @@ -29,6 +29,8 @@ struct sockaddr_ll {
11  /* These ones are invisible by user level */
12  #define PACKET_LOOPBACK                5               /* MC/BRD frame looped back */
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 @@ -49,6 +51,7 @@ struct sockaddr_ll {
20  #define PACKET_VNET_HDR                        15
21  #define PACKET_TX_TIMESTAMP            16
22  #define PACKET_TIMESTAMP               17
23 +#define PACKET_RECV_TYPE               18
24  
25  struct tpacket_stats {
26         unsigned int    tp_packets;
27 --- a/net/packet/af_packet.c
28 +++ b/net/packet/af_packet.c
29 @@ -205,6 +205,7 @@ struct packet_sock {
30         unsigned int            tp_loss:1;
31         unsigned int            tp_tstamp;
32         struct packet_type      prot_hook ____cacheline_aligned_in_smp;
33 +       unsigned int            pkt_type;
34  };
35  
36  struct packet_skb_cb {
37 @@ -341,6 +342,7 @@ static int packet_rcv_spkt(struct sk_buf
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 @@ -348,6 +350,7 @@ static int packet_rcv_spkt(struct sk_buf
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 @@ -360,7 +363,7 @@ static int packet_rcv_spkt(struct sk_buf
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 @@ -539,12 +542,12 @@ static int packet_rcv(struct sk_buff *sk
63         int skb_len = skb->len;
64         unsigned int snaplen, res;
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 @@ -660,12 +663,12 @@ static int tpacket_rcv(struct sk_buff *s
79         struct timespec ts;
80         struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
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 @@ -1488,6 +1491,7 @@ static int packet_create(struct net *net
95         spin_lock_init(&po->bind_lock);
96         mutex_init(&po->pg_vec_lock);
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 @@ -2057,6 +2061,16 @@ packet_setsockopt(struct socket *sock, i
103                 po->tp_tstamp = val;
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 & ~PACKET_LOOPBACK;
114 +                return 0;
115 +        }
116         default:
117                 return -ENOPROTOOPT;
118         }
119 @@ -2114,6 +2128,13 @@ static int packet_getsockopt(struct sock
120  
121                 data = &val;
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                 if (len > sizeof(int))
132                         len = sizeof(int);