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 --- 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 */ @@ -48,6 +50,7 @@ struct sockaddr_ll #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 @@ struct packet_sock { unsigned int tp_reserve; unsigned int tp_loss:1; #endif + unsigned int pkt_type; }; struct packet_skb_cb { @@ -342,6 +343,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 @@ -349,6 +351,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 @@ -361,7 +364,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)) @@ -545,12 +548,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; @@ -667,12 +670,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; @@ -1381,6 +1384,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; @@ -1728,6 +1732,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: @@ -1873,6 +1887,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))