⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 genetlink.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * NETLINK      Generic Netlink Family * * 		Authors:	Jamal Hadi Salim * 				Thomas Graf <tgraf@suug.ch> *				Johannes Berg <johannes@sipsolutions.net> */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/mutex.h>#include <linux/bitmap.h>#include <net/sock.h>#include <net/genetlink.h>struct sock *genl_sock = NULL;static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */static inline void genl_lock(void){	mutex_lock(&genl_mutex);}static inline void genl_unlock(void){	mutex_unlock(&genl_mutex);}#define GENL_FAM_TAB_SIZE	16#define GENL_FAM_TAB_MASK	(GENL_FAM_TAB_SIZE - 1)static struct list_head family_ht[GENL_FAM_TAB_SIZE];/* * Bitmap of multicast groups that are currently in use. * * To avoid an allocation at boot of just one unsigned long, * declare it global instead. * Bit 0 is marked as already used since group 0 is invalid. */static unsigned long mc_group_start = 0x1;static unsigned long *mc_groups = &mc_group_start;static unsigned long mc_groups_longs = 1;static int genl_ctrl_event(int event, void *data);static inline unsigned int genl_family_hash(unsigned int id){	return id & GENL_FAM_TAB_MASK;}static inline struct list_head *genl_family_chain(unsigned int id){	return &family_ht[genl_family_hash(id)];}static struct genl_family *genl_family_find_byid(unsigned int id){	struct genl_family *f;	list_for_each_entry(f, genl_family_chain(id), family_list)		if (f->id == id)			return f;	return NULL;}static struct genl_family *genl_family_find_byname(char *name){	struct genl_family *f;	int i;	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)		list_for_each_entry(f, genl_family_chain(i), family_list)			if (strcmp(f->name, name) == 0)				return f;	return NULL;}static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family){	struct genl_ops *ops;	list_for_each_entry(ops, &family->ops_list, ops_list)		if (ops->cmd == cmd)			return ops;	return NULL;}/* Of course we are going to have problems once we hit * 2^16 alive types, but that can only happen by year 2K*/static inline u16 genl_generate_id(void){	static u16 id_gen_idx;	int overflowed = 0;	do {		if (id_gen_idx == 0)			id_gen_idx = GENL_MIN_ID;		if (++id_gen_idx > GENL_MAX_ID) {			if (!overflowed) {				overflowed = 1;				id_gen_idx = 0;				continue;			} else				return 0;		}	} while (genl_family_find_byid(id_gen_idx));	return id_gen_idx;}static struct genl_multicast_group notify_grp;/** * genl_register_mc_group - register a multicast group * * Registers the specified multicast group and notifies userspace * about the new group. * * Returns 0 on success or a negative error code. * * @family: The generic netlink family the group shall be registered for. * @grp: The group to register, must have a name. */int genl_register_mc_group(struct genl_family *family,			   struct genl_multicast_group *grp){	int id;	unsigned long *new_groups;	int err;	BUG_ON(grp->name[0] == '\0');	genl_lock();	/* special-case our own group */	if (grp == &notify_grp)		id = GENL_ID_CTRL;	else		id = find_first_zero_bit(mc_groups,					 mc_groups_longs * BITS_PER_LONG);	if (id >= mc_groups_longs * BITS_PER_LONG) {		size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);		if (mc_groups == &mc_group_start) {			new_groups = kzalloc(nlen, GFP_KERNEL);			if (!new_groups) {				err = -ENOMEM;				goto out;			}			mc_groups = new_groups;			*mc_groups = mc_group_start;		} else {			new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);			if (!new_groups) {				err = -ENOMEM;				goto out;			}			mc_groups = new_groups;			mc_groups[mc_groups_longs] = 0;		}		mc_groups_longs++;	}	err = netlink_change_ngroups(genl_sock,				     mc_groups_longs * BITS_PER_LONG);	if (err)		goto out;	grp->id = id;	set_bit(id, mc_groups);	list_add_tail(&grp->list, &family->mcast_groups);	grp->family = family;	genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp); out:	genl_unlock();	return err;}EXPORT_SYMBOL(genl_register_mc_group);static void __genl_unregister_mc_group(struct genl_family *family,				       struct genl_multicast_group *grp){	BUG_ON(grp->family != family);	netlink_clear_multicast_users(genl_sock, grp->id);	clear_bit(grp->id, mc_groups);	list_del(&grp->list);	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);	grp->id = 0;	grp->family = NULL;}/** * genl_unregister_mc_group - unregister a multicast group * * Unregisters the specified multicast group and notifies userspace * about it. All current listeners on the group are removed. * * Note: It is not necessary to unregister all multicast groups before *       unregistering the family, unregistering the family will cause *       all assigned multicast groups to be unregistered automatically. * * @family: Generic netlink family the group belongs to. * @grp: The group to unregister, must have been registered successfully *	 previously. */void genl_unregister_mc_group(struct genl_family *family,			      struct genl_multicast_group *grp){	genl_lock();	__genl_unregister_mc_group(family, grp);	genl_unlock();}static void genl_unregister_mc_groups(struct genl_family *family){	struct genl_multicast_group *grp, *tmp;	genl_lock();	list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)		__genl_unregister_mc_group(family, grp);	genl_unlock();}/** * genl_register_ops - register generic netlink operations * @family: generic netlink family * @ops: operations to be registered * * Registers the specified operations and assigns them to the specified * family. Either a doit or dumpit callback must be specified or the * operation will fail. Only one operation structure per command * identifier may be registered. * * See include/net/genetlink.h for more documenation on the operations * structure. * * Returns 0 on success or a negative error code. */int genl_register_ops(struct genl_family *family, struct genl_ops *ops){	int err = -EINVAL;	if (ops->dumpit == NULL && ops->doit == NULL)		goto errout;	if (genl_get_cmd(ops->cmd, family)) {		err = -EEXIST;		goto errout;	}	if (ops->dumpit)		ops->flags |= GENL_CMD_CAP_DUMP;	if (ops->doit)		ops->flags |= GENL_CMD_CAP_DO;	if (ops->policy)		ops->flags |= GENL_CMD_CAP_HASPOL;	genl_lock();	list_add_tail(&ops->ops_list, &family->ops_list);	genl_unlock();	genl_ctrl_event(CTRL_CMD_NEWOPS, ops);	err = 0;errout:	return err;}/** * genl_unregister_ops - unregister generic netlink operations * @family: generic netlink family * @ops: operations to be unregistered * * Unregisters the specified operations and unassigns them from the * specified family. The operation blocks until the current message * processing has finished and doesn't start again until the * unregister process has finished. * * Note: It is not necessary to unregister all operations before *       unregistering the family, unregistering the family will cause *       all assigned operations to be unregistered automatically. * * Returns 0 on success or a negative error code. */int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops){	struct genl_ops *rc;	genl_lock();	list_for_each_entry(rc, &family->ops_list, ops_list) {		if (rc == ops) {			list_del(&ops->ops_list);			genl_unlock();			genl_ctrl_event(CTRL_CMD_DELOPS, ops);			return 0;		}	}	genl_unlock();	return -ENOENT;}/** * genl_register_family - register a generic netlink family * @family: generic netlink family * * Registers the specified family after validating it first. Only one * family may be registered with the same family name or identifier. * The family id may equal GENL_ID_GENERATE causing an unique id to * be automatically generated and assigned. * * Return 0 on success or a negative error code. */int genl_register_family(struct genl_family *family){	int err = -EINVAL;	if (family->id && family->id < GENL_MIN_ID)		goto errout;	if (family->id > GENL_MAX_ID)		goto errout;	INIT_LIST_HEAD(&family->ops_list);	INIT_LIST_HEAD(&family->mcast_groups);	genl_lock();	if (genl_family_find_byname(family->name)) {		err = -EEXIST;		goto errout_locked;	}	if (genl_family_find_byid(family->id)) {		err = -EEXIST;		goto errout_locked;	}	if (family->id == GENL_ID_GENERATE) {		u16 newid = genl_generate_id();		if (!newid) {			err = -ENOMEM;			goto errout_locked;		}		family->id = newid;	}	if (family->maxattr) {		family->attrbuf = kmalloc((family->maxattr+1) *					sizeof(struct nlattr *), GFP_KERNEL);		if (family->attrbuf == NULL) {			err = -ENOMEM;			goto errout_locked;		}	} else		family->attrbuf = NULL;	list_add_tail(&family->family_list, genl_family_chain(family->id));	genl_unlock();	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);	return 0;errout_locked:	genl_unlock();errout:	return err;}/** * genl_unregister_family - unregister generic netlink family * @family: generic netlink family * * Unregisters the specified family. * * Returns 0 on success or a negative error code. */int genl_unregister_family(struct genl_family *family){	struct genl_family *rc;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -