aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-openmoko-2.6.30.4/240-packet_socket_type.patch
blob: d86fcf3bc24718639e99c552dbba80d3655a814c (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 @@ struct sockaddr_ll
 /* 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 */
 
@@ -46,6 +48,7 @@ struct sockaddr_ll
 #define PACKET_VERSION			10
 #define PACKET_HDRLEN			11
 #define PACKET_RESERVE			12
+#define PACKET_RECV_TYPE		13
 
 struct tpacket_stats
 {
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -192,6 +192,7 @@ struct packet_sock {
 	unsigned int		tp_hdrlen;
 	unsigned int		tp_reserve;
 #endif
+	unsigned int		pkt_type;
 };
 
 struct packet_skb_cb {
@@ -282,6 +283,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
@@ -289,6 +291,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
@@ -301,7 +304,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 (dev_net(dev) != sock_net(sk))
@@ -486,12 +489,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 (dev_net(dev) != sock_net(sk))
 		goto drop;
 
@@ -608,12 +611,12 @@ static int tpacket_rcv(struct sk_buff *s
 	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;
 
@@ -1072,6 +1075,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;
@@ -1412,6 +1416,16 @@ packet_setsockopt(struct socket *sock, i
 			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:
@@ -1543,6 +1557,13 @@ static int packet_getsockopt(struct sock
 
 		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))