Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c380d9a7 authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller
Browse files

genetlink: pass multicast bind/unbind to families



In order to make the newly fixed multicast bind/unbind
functionality in generic netlink, pass them down to the
appropriate family.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7d68536b
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ struct genl_info;
 *	do additional, common, filtering and return an error
 * @post_doit: called after an operation's doit callback, it may
 *	undo operations done by pre_doit, for example release locks
 * @mcast_bind: a socket bound to the given multicast group (which
 *	is given as the offset into the groups array)
 * @mcast_unbind: a socket was unbound from the given multicast group
 * @attrbuf: buffer to store parsed attributes
 * @family_list: family list
 * @mcgrps: multicast groups used by this family (private)
@@ -53,6 +56,8 @@ struct genl_family {
	void			(*post_doit)(const struct genl_ops *ops,
					     struct sk_buff *skb,
					     struct genl_info *info);
	int			(*mcast_bind)(int group);
	void			(*mcast_unbind)(int group);
	struct nlattr **	attrbuf;	/* private */
	const struct genl_ops *	ops;		/* private */
	const struct genl_multicast_group *mcgrps; /* private */
+59 −0
Original line number Diff line number Diff line
@@ -983,11 +983,70 @@ static struct genl_multicast_group genl_ctrl_groups[] = {
	{ .name = "notify", },
};

static int genl_bind(int group)
{
	int i, err;
	bool found = false;

	down_read(&cb_lock);
	for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
		struct genl_family *f;

		list_for_each_entry(f, genl_family_chain(i), family_list) {
			if (group >= f->mcgrp_offset &&
			    group < f->mcgrp_offset + f->n_mcgrps) {
				int fam_grp = group - f->mcgrp_offset;

				if (f->mcast_bind)
					err = f->mcast_bind(fam_grp);
				else
					err = 0;
				found = true;
				break;
			}
		}
	}
	up_read(&cb_lock);

	if (WARN_ON(!found))
		err = 0;

	return err;
}

static void genl_unbind(int group)
{
	int i;
	bool found = false;

	down_read(&cb_lock);
	for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
		struct genl_family *f;

		list_for_each_entry(f, genl_family_chain(i), family_list) {
			if (group >= f->mcgrp_offset &&
			    group < f->mcgrp_offset + f->n_mcgrps) {
				int fam_grp = group - f->mcgrp_offset;

				if (f->mcast_unbind)
					f->mcast_unbind(fam_grp);
				found = true;
				break;
			}
		}
	}
	up_read(&cb_lock);

	WARN_ON(!found);
}

static int __net_init genl_pernet_init(struct net *net)
{
	struct netlink_kernel_cfg cfg = {
		.input		= genl_rcv,
		.flags		= NL_CFG_F_NONROOT_RECV,
		.bind		= genl_bind,
		.unbind		= genl_unbind,
	};

	/* we'll bump the group number right afterwards */