--- zzzz-none-000/linux-4.4.60/net/packet/af_packet.c 2017-04-08 07:53:53.000000000 +0000 +++ hawkeye-5590-729/linux-4.4.60/net/packet/af_packet.c 2022-03-30 14:21:53.000000000 +0000 @@ -1652,10 +1652,6 @@ mutex_lock(&fanout_mutex); - err = -EINVAL; - if (!po->running) - goto out; - err = -EALREADY; if (po->fanout) goto out; @@ -1694,7 +1690,7 @@ match->flags = flags; INIT_LIST_HEAD(&match->list); spin_lock_init(&match->lock); - atomic_set(&match->sk_ref, 0); + refcount_set(&match->sk_ref, 0); fanout_init_data(match); match->prot_hook.type = po->prot_hook.type; match->prot_hook.dev = po->prot_hook.dev; @@ -1704,18 +1700,28 @@ list_add(&match->list, &fanout_list); } err = -EINVAL; - if (match->type == type && + + spin_lock(&po->bind_lock); + if (po->running && + match->type == type && match->prot_hook.type == po->prot_hook.type && match->prot_hook.dev == po->prot_hook.dev) { err = -ENOSPC; - if (atomic_read(&match->sk_ref) < PACKET_FANOUT_MAX) { + if (refcount_read(&match->sk_ref) < PACKET_FANOUT_MAX) { __dev_remove_pack(&po->prot_hook); po->fanout = match; - atomic_inc(&match->sk_ref); + refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1); __fanout_link(sk, po); err = 0; } } + spin_unlock(&po->bind_lock); + + if (err && !refcount_read(&match->sk_ref)) { + list_del(&match->list); + kfree(match); + } + out: if (err && rollover) { kfree(rollover); @@ -1740,7 +1746,7 @@ if (f) { po->fanout = NULL; - if (atomic_dec_and_test(&f->sk_ref)) + if (refcount_dec_and_test(&f->sk_ref)) list_del(&f->list); else f = NULL; @@ -1776,6 +1782,7 @@ { struct sock *sk; struct sockaddr_pkt *spkt; + struct packet_sock *po; /* * When we registered the protocol we saved the socket in the data @@ -1783,6 +1790,7 @@ */ sk = pt->af_packet_priv; + po = pkt_sk(sk); /* * Yank back the headers [hope the device set this @@ -1795,7 +1803,7 @@ * 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))) @@ -1998,12 +2006,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 (!net_eq(dev_net(dev), sock_net(sk))) goto drop; @@ -2123,12 +2131,12 @@ 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; @@ -3115,6 +3123,7 @@ 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; @@ -3737,6 +3746,16 @@ 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; } @@ -3789,6 +3808,13 @@ 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;