diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index 9e7edfd8141e5dea69129807f46b89b2b637ead9..40fdf8907900ed754554c7a3fe6cb3df02c6ff7f 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -31,6 +31,8 @@ struct sockaddr_ll { #define PACKET_KERNEL 7 /* To kernel space */ /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ #define PACKET_FASTROUTE 6 /* Fastrouted frame */ +#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ + /* Packet socket options */ @@ -56,6 +58,7 @@ struct sockaddr_ll { #define PACKET_QDISC_BYPASS 20 #define PACKET_ROLLOVER_STATS 21 #define PACKET_FANOUT_DATA 22 +#define PACKET_RECV_TYPE 23 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 2c4a47f29f361e09dd5debe9f9da22930cb00697..116cd146a538d41552c5b22f75488da70e0a9aee 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1780,6 +1780,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, { struct sock *sk; struct sockaddr_pkt *spkt; + struct packet_sock *po; /* * When we registered the protocol we saved the socket in the data @@ -1787,6 +1788,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, */ sk = pt->af_packet_priv; + po = pkt_sk(sk); /* * Yank back the headers [hope the device set this @@ -1799,7 +1801,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, * 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))) @@ -2037,12 +2039,12 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, unsigned int snaplen, res; bool is_drop_n_account = false; - 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; @@ -2168,12 +2170,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); - 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; @@ -3262,6 +3264,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, mutex_init(&po->pg_vec_lock); po->rollover = NULL; 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; @@ -3875,6 +3878,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv po->xmit = val ? packet_direct_xmit : dev_queue_xmit; 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; } @@ -3927,6 +3941,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, 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; diff --git a/net/packet/internal.h b/net/packet/internal.h index 1309e2a7baad48224a6f32d5048a7744b60fd2cd..743d605881639d0990c9ac603ea885ae6b77885c 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -128,6 +128,7 @@ struct packet_sock { struct net_device __rcu *cached_dev; int (*xmit)(struct sk_buff *skb); struct packet_type prot_hook ____cacheline_aligned_in_smp; + unsigned int pkt_type; }; static struct packet_sock *pkt_sk(struct sock *sk)