aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.6/patches-2.6.32/240-packet_socket_type.patch
blob: a03d699575f50ec7905d3b0df38183916b97ddd7 (plain)
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
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@openwrt.org>

--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -31,6 +31,8 @@
 /* These ones are invisible by user level */
 #define PACKET_LOOPBACK		5		/* MC/BRD frame looped back */
 #define PACKET_FASTROUTE	6		/* Fastrouted frame	*/
+#define PACKET_MASK_ANY		0xffffffff	/* mask for packet type bits */
+
 
 /* Packet socket options */
 
@@ -48,6 +50,7 @@
 #define PACKET_RESERVE			12
 #define PACKET_TX_RING			13
 #define PACKET_LOSS			14
+#define PACKET_RECV_TYPE		15
 
 struct tpacket_stats
 {
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -204,6 +204,7 @@
 	unsigned int		tp_reserve;
 	unsigned int		tp_loss:1;
 #endif
+	unsigned int		pkt_type;
 };
 
 struct packet_skb_cb {
@@ -342,6 +343,7 @@
 {
 	struct sock *sk;
 	struct sockaddr_pkt *spkt;
+	struct packet_sock *po;
 
 	/*
 	 *	When we registered the protocol we saved the socket in the data
@@ -349,6 +351,7 @@
 	 */
 
 	sk = pt->af_packet_priv;
+	po = pkt_sk(sk);
 
 	/*
 	 *	Yank back the headers [hope the device set this
@@ -361,7 +364,7 @@
 	 *	so that this procedure is noop.
 	 */
 
-	if (skb->pkt_type == PACKET_LOOPBACK)
+	if (!(po->pkt_type & (1 << skb->pkt_type)))
 		goto out;
 
 	if (dev_net(dev) != sock_net(sk))
@@ -545,12 +548,12 @@
 	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 (dev_net(dev) != sock_net(sk))
 		goto drop;
 
@@ -667,12 +670,12 @@
 	struct timeval tv;
 	struct timespec ts;
 
-	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 (dev_net(dev) != sock_net(sk))
 		goto drop;
 
@@ -1390,6 +1393,7 @@
 	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;
@@ -1737,6 +1741,16 @@
 			ret = packet_mc_drop(sk, &mreq);
 		return ret;
 	}
+	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 & ~PACKET_LOOPBACK;
+		return 0;
+	}
 
 #ifdef CONFIG_PACKET_MMAP
 	case PACKET_RX_RING:
@@ -1882,6 +1896,13 @@
 
 		data = &val;
 		break;
+	case PACKET_RECV_TYPE:
+		if (len > sizeof(unsigned int))
+			len = sizeof(unsigned int);
+		val = po->pkt_type;
+
+		data = &val;
+		break;
 #ifdef CONFIG_PACKET_MMAP
 	case PACKET_VERSION:
 		if (len > sizeof(int))