diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 87113e86b328..34de326b4f09 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1497,6 +1497,8 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po) | |||
1497 | f->arr[f->num_members] = sk; | 1497 | f->arr[f->num_members] = sk; |
1498 | smp_wmb(); | 1498 | smp_wmb(); |
1499 | f->num_members++; | 1499 | f->num_members++; |
1500 | if (f->num_members == 1) | ||
1501 | dev_add_pack(&f->prot_hook); | ||
1500 | spin_unlock(&f->lock); | 1502 | spin_unlock(&f->lock); |
1501 | } | 1503 | } |
1502 | 1504 | ||
@@ -1513,6 +1515,8 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po) | |||
1513 | BUG_ON(i >= f->num_members); | 1515 | BUG_ON(i >= f->num_members); |
1514 | f->arr[i] = f->arr[f->num_members - 1]; | 1516 | f->arr[i] = f->arr[f->num_members - 1]; |
1515 | f->num_members--; | 1517 | f->num_members--; |
1518 | if (f->num_members == 0) | ||
1519 | __dev_remove_pack(&f->prot_hook); | ||
1516 | spin_unlock(&f->lock); | 1520 | spin_unlock(&f->lock); |
1517 | } | 1521 | } |
1518 | 1522 | ||
@@ -1693,7 +1697,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) | |||
1693 | match->prot_hook.func = packet_rcv_fanout; | 1697 | match->prot_hook.func = packet_rcv_fanout; |
1694 | match->prot_hook.af_packet_priv = match; | 1698 | match->prot_hook.af_packet_priv = match; |
1695 | match->prot_hook.id_match = match_fanout_group; | 1699 | match->prot_hook.id_match = match_fanout_group; |
1696 | dev_add_pack(&match->prot_hook); | ||
1697 | list_add(&match->list, &fanout_list); | 1700 | list_add(&match->list, &fanout_list); |
1698 | } | 1701 | } |
1699 | err = -EINVAL; | 1702 | err = -EINVAL; |
@@ -1718,7 +1721,12 @@ out: | |||
1718 | return err; | 1721 | return err; |
1719 | } | 1722 | } |
1720 | 1723 | ||
1721 | static void fanout_release(struct sock *sk) | 1724 | /* If pkt_sk(sk)->fanout->sk_ref is zero, this function removes |
1725 | * pkt_sk(sk)->fanout from fanout_list and returns pkt_sk(sk)->fanout. | ||
1726 | * It is the responsibility of the caller to call fanout_release_data() and | ||
1727 | * free the returned packet_fanout (after synchronize_net()) | ||
1728 | */ | ||
1729 | static struct packet_fanout *fanout_release(struct sock *sk) | ||
1722 | { | 1730 | { |
1723 | struct packet_sock *po = pkt_sk(sk); | 1731 | struct packet_sock *po = pkt_sk(sk); |
1724 | struct packet_fanout *f; | 1732 | struct packet_fanout *f; |
@@ -1728,17 +1736,17 @@ static void fanout_release(struct sock *sk) | |||
1728 | if (f) { | 1736 | if (f) { |
1729 | po->fanout = NULL; | 1737 | po->fanout = NULL; |
1730 | 1738 | ||
1731 | if (atomic_dec_and_test(&f->sk_ref)) { | 1739 | if (atomic_dec_and_test(&f->sk_ref)) |
1732 | list_del(&f->list); | 1740 | list_del(&f->list); |
1733 | dev_remove_pack(&f->prot_hook); | 1741 | else |
1734 | fanout_release_data(f); | 1742 | f = NULL; |
1735 | kfree(f); | ||
1736 | } | ||
1737 | 1743 | ||
1738 | if (po->rollover) | 1744 | if (po->rollover) |
1739 | kfree_rcu(po->rollover, rcu); | 1745 | kfree_rcu(po->rollover, rcu); |
1740 | } | 1746 | } |
1741 | mutex_unlock(&fanout_mutex); | 1747 | mutex_unlock(&fanout_mutex); |
1748 | |||
1749 | return f; | ||
1742 | } | 1750 | } |
1743 | 1751 | ||
1744 | static bool packet_extra_vlan_len_allowed(const struct net_device *dev, | 1752 | static bool packet_extra_vlan_len_allowed(const struct net_device *dev, |
@@ -2970,6 +2978,7 @@ static int packet_release(struct socket *sock) | |||
2970 | { | 2978 | { |
2971 | struct sock *sk = sock->sk; | 2979 | struct sock *sk = sock->sk; |
2972 | struct packet_sock *po; | 2980 | struct packet_sock *po; |
2981 | struct packet_fanout *f; | ||
2973 | struct net *net; | 2982 | struct net *net; |
2974 | union tpacket_req_u req_u; | 2983 | union tpacket_req_u req_u; |
2975 | 2984 | ||
@@ -3009,9 +3018,14 @@ static int packet_release(struct socket *sock) | |||
3009 | packet_set_ring(sk, &req_u, 1, 1); | 3018 | packet_set_ring(sk, &req_u, 1, 1); |
3010 | } | 3019 | } |
3011 | 3020 | ||
3012 | fanout_release(sk); | 3021 | f = fanout_release(sk); |
3013 | 3022 | ||
3014 | synchronize_net(); | 3023 | synchronize_net(); |
3024 | |||
3025 | if (f) { | ||
3026 | fanout_release_data(f); | ||
3027 | kfree(f); | ||
3028 | } | ||
3015 | /* | 3029 | /* |
3016 | * Now the socket is dead. No more input will appear. | 3030 | * Now the socket is dead. No more input will appear. |
3017 | */ | 3031 | */ |
@@ -3963,7 +3977,6 @@ static int packet_notifier(struct notifier_block *this, | |||
3963 | } | 3977 | } |
3964 | if (msg == NETDEV_UNREGISTER) { | 3978 | if (msg == NETDEV_UNREGISTER) { |
3965 | packet_cached_dev_reset(po); | 3979 | packet_cached_dev_reset(po); |
3966 | fanout_release(sk); | ||
3967 | po->ifindex = -1; | 3980 | po->ifindex = -1; |
3968 | if (po->prot_hook.dev) | 3981 | if (po->prot_hook.dev) |
3969 | dev_put(po->prot_hook.dev); | 3982 | dev_put(po->prot_hook.dev); |