openwrt/target/linux/generic/patches-3.10/630-packet_socket_type.patch

135 lines
3.6 KiB
Diff

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/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -29,6 +29,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 */
@@ -51,6 +53,7 @@ struct sockaddr_ll {
#define PACKET_TIMESTAMP 17
#define PACKET_FANOUT 18
#define PACKET_TX_HAS_OFF 19
+#define PACKET_RECV_TYPE 20
#define PACKET_FANOUT_HASH 0
#define PACKET_FANOUT_LB 1
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1403,6 +1403,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
@@ -1410,6 +1411,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
@@ -1422,7 +1424,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)))
@@ -1629,12 +1631,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;
@@ -1747,12 +1749,12 @@ static int tpacket_rcv(struct sk_buff *s
struct timespec ts;
__u32 ts_status;
- 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;
@@ -2641,6 +2643,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;
@@ -3251,6 +3254,16 @@ packet_setsockopt(struct socket *sock, i
po->tp_tx_has_off = !!val;
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;
}
@@ -3302,6 +3315,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
@@ -115,6 +115,7 @@ struct packet_sock {
unsigned int tp_tstamp;
struct net_device __rcu *cached_dev;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
+ unsigned int pkt_type;
};
static struct packet_sock *pkt_sk(struct sock *sk)