diff options
Diffstat (limited to 'include/net/genetlink.h')
| -rw-r--r-- | include/net/genetlink.h | 145 | 
1 files changed, 103 insertions, 42 deletions
diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 8e0b6c856a1..93695f0e22a 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -10,16 +10,9 @@  /**   * struct genl_multicast_group - generic netlink multicast group   * @name: name of the multicast group, names are per-family - * @id: multicast group ID, assigned by the core, to use with - *      genlmsg_multicast(). - * @list: list entry for linking - * @family: pointer to family, need not be set before registering   */  struct genl_multicast_group { -	struct genl_family	*family;	/* private */ -	struct list_head	list;		/* private */  	char			name[GENL_NAMSIZ]; -	u32			id;  };  struct genl_ops; @@ -39,9 +32,12 @@ struct genl_info;   * @post_doit: called after an operation's doit callback, it may   *	undo operations done by pre_doit, for example release locks   * @attrbuf: buffer to store parsed attributes - * @ops_list: list of all assigned operations   * @family_list: family list - * @mcast_groups: multicast groups list + * @mcgrps: multicast groups used by this family (private) + * @n_mcgrps: number of multicast groups (private) + * @mcgrp_offset: starting number of multicast group IDs in this family + * @ops: the operations supported by this family (private) + * @n_ops: number of operations supported by this family (private)   */  struct genl_family {  	unsigned int		id; @@ -51,16 +47,19 @@ struct genl_family {  	unsigned int		maxattr;  	bool			netnsok;  	bool			parallel_ops; -	int			(*pre_doit)(struct genl_ops *ops, +	int			(*pre_doit)(const struct genl_ops *ops,  					    struct sk_buff *skb,  					    struct genl_info *info); -	void			(*post_doit)(struct genl_ops *ops, +	void			(*post_doit)(const struct genl_ops *ops,  					     struct sk_buff *skb,  					     struct genl_info *info);  	struct nlattr **	attrbuf;	/* private */ -	struct list_head	ops_list;	/* private */ +	const struct genl_ops *	ops;		/* private */ +	const struct genl_multicast_group *mcgrps; /* private */ +	unsigned int		n_ops;		/* private */ +	unsigned int		n_mcgrps;	/* private */ +	unsigned int		mcgrp_offset;	/* private */  	struct list_head	family_list;	/* private */ -	struct list_head	mcast_groups;	/* private */  	struct module		*module;  }; @@ -74,6 +73,7 @@ struct genl_family {   * @attrs: netlink attributes   * @_net: network namespace   * @user_ptr: user pointers + * @dst_sk: destination socket   */  struct genl_info {  	u32			snd_seq; @@ -86,6 +86,7 @@ struct genl_info {  	struct net *		_net;  #endif  	void *			user_ptr[2]; +	struct sock *		dst_sk;  };  static inline struct net *genl_info_net(struct genl_info *info) @@ -110,19 +111,18 @@ static inline void genl_info_net_set(struct genl_info *info, struct net *net)   * @ops_list: operations list   */  struct genl_ops { -	u8			cmd; -	u8			internal_flags; -	unsigned int		flags;  	const struct nla_policy	*policy;  	int		       (*doit)(struct sk_buff *skb,  				       struct genl_info *info);  	int		       (*dumpit)(struct sk_buff *skb,  					 struct netlink_callback *cb);  	int		       (*done)(struct netlink_callback *cb); -	struct list_head	ops_list; +	u8			cmd; +	u8			internal_flags; +	u8			flags;  }; -extern int __genl_register_family(struct genl_family *family); +int __genl_register_family(struct genl_family *family);  static inline int genl_register_family(struct genl_family *family)  { @@ -130,28 +130,59 @@ static inline int genl_register_family(struct genl_family *family)  	return __genl_register_family(family);  } -extern int __genl_register_family_with_ops(struct genl_family *family, -	struct genl_ops *ops, size_t n_ops); - -static inline int genl_register_family_with_ops(struct genl_family *family, -	struct genl_ops *ops, size_t n_ops) +/** + * genl_register_family_with_ops - register a generic netlink family with ops + * @family: generic netlink family + * @ops: operations to be registered + * @n_ops: number of elements to register + * + * Registers the specified family and operations from the specified table. + * 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. + * + * Either a doit or dumpit callback must be specified for every registered + * operation or the function will fail. Only one operation structure per + * command identifier may be registered. + * + * See include/net/genetlink.h for more documenation on the operations + * structure. + * + * Return 0 on success or a negative error code. + */ +static inline int +_genl_register_family_with_ops_grps(struct genl_family *family, +				    const struct genl_ops *ops, size_t n_ops, +				    const struct genl_multicast_group *mcgrps, +				    size_t n_mcgrps)  {  	family->module = THIS_MODULE; -	return __genl_register_family_with_ops(family, ops, n_ops); +	family->ops = ops; +	family->n_ops = n_ops; +	family->mcgrps = mcgrps; +	family->n_mcgrps = n_mcgrps; +	return __genl_register_family(family);  } -extern int genl_unregister_family(struct genl_family *family); -extern int genl_register_ops(struct genl_family *, struct genl_ops *ops); -extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); -extern int genl_register_mc_group(struct genl_family *family, -				  struct genl_multicast_group *grp); -extern void genl_unregister_mc_group(struct genl_family *family, -				     struct genl_multicast_group *grp); -extern void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, -			u32 group, struct nlmsghdr *nlh, gfp_t flags); - +#define genl_register_family_with_ops(family, ops)			\ +	_genl_register_family_with_ops_grps((family),			\ +					    (ops), ARRAY_SIZE(ops),	\ +					    NULL, 0) +#define genl_register_family_with_ops_groups(family, ops, grps)	\ +	_genl_register_family_with_ops_grps((family),			\ +					    (ops), ARRAY_SIZE(ops),	\ +					    (grps), ARRAY_SIZE(grps)) + +int genl_unregister_family(struct genl_family *family); +void genl_notify(struct genl_family *family, +		 struct sk_buff *skb, struct net *net, u32 portid, +		 u32 group, struct nlmsghdr *nlh, gfp_t flags); + +struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info, +				    gfp_t flags);  void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, -				struct genl_family *family, int flags, u8 cmd); +		  struct genl_family *family, int flags, u8 cmd);  /**   * genlmsg_nlhdr - Obtain netlink header from user specified header @@ -227,41 +258,51 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)  /**   * genlmsg_multicast_netns - multicast a netlink message to a specific netns + * @family: the generic netlink family   * @net: the net namespace   * @skb: netlink message as socket buffer   * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id + * @group: offset of multicast group in groups array   * @flags: allocation flags   */ -static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb, +static inline int genlmsg_multicast_netns(struct genl_family *family, +					  struct net *net, struct sk_buff *skb,  					  u32 portid, unsigned int group, gfp_t flags)  { +	if (WARN_ON_ONCE(group >= family->n_mcgrps)) +		return -EINVAL; +	group = family->mcgrp_offset + group;  	return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);  }  /**   * genlmsg_multicast - multicast a netlink message to the default netns + * @family: the generic netlink family   * @skb: netlink message as socket buffer   * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id + * @group: offset of multicast group in groups array   * @flags: allocation flags   */ -static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid, +static inline int genlmsg_multicast(struct genl_family *family, +				    struct sk_buff *skb, u32 portid,  				    unsigned int group, gfp_t flags)  { -	return genlmsg_multicast_netns(&init_net, skb, portid, group, flags); +	return genlmsg_multicast_netns(family, &init_net, skb, +				       portid, group, flags);  }  /**   * genlmsg_multicast_allns - multicast a netlink message to all net namespaces + * @family: the generic netlink family   * @skb: netlink message as socket buffer   * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id + * @group: offset of multicast group in groups array   * @flags: allocation flags   *   * This function must hold the RTNL or rcu_read_lock().   */ -int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid, +int genlmsg_multicast_allns(struct genl_family *family, +			    struct sk_buff *skb, u32 portid,  			    unsigned int group, gfp_t flags);  /** @@ -332,5 +373,25 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags)  	return nlmsg_new(genlmsg_total_size(payload), flags);  } +/** + * genl_set_err - report error to genetlink broadcast listeners + * @family: the generic netlink family + * @net: the network namespace to report the error to + * @portid: the PORTID of a process that we want to skip (if any) + * @group: the broadcast group that will notice the error + * 	(this is the offset of the multicast group in the groups array) + * @code: error code, must be negative (as usual in kernelspace) + * + * This function returns the number of broadcast listeners that have set the + * NETLINK_RECV_NO_ENOBUFS socket option. + */ +static inline int genl_set_err(struct genl_family *family, struct net *net, +			       u32 portid, u32 group, int code) +{ +	if (WARN_ON_ONCE(group >= family->n_mcgrps)) +		return -EINVAL; +	group = family->mcgrp_offset + group; +	return netlink_set_err(net->genl_sock, portid, group, code); +}  #endif	/* __NET_GENERIC_NETLINK_H */  | 
