From 3686ec5e84977eddc796903177e7e0a122585c11 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:43 +0100 Subject: genetlink: remove genl_register_ops/genl_unregister_ops genl_register_ops() is still needed for internal registration, but is no longer available to users of the API. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 9b787b62cf16..617d718524b0 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -141,8 +141,6 @@ static inline int genl_register_family_with_ops(struct genl_family *family, } int genl_unregister_family(struct genl_family *family); -int genl_register_ops(struct genl_family *, struct genl_ops *ops); -int genl_unregister_ops(struct genl_family *, struct genl_ops *ops); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); void genl_unregister_mc_group(struct genl_family *family, -- cgit v1.2.3 From d91824c08fbcb265ec930d863fa905e8daa836a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:44 +0100 Subject: genetlink: register family ops as array Instead of using a linked list, use an array. This reduces the data size needed by the users of genetlink, for example in wireless (net/wireless/nl80211.c) on 64-bit it frees up over 1K of data space. Remove the attempted sending of CTRL_CMD_NEWOPS ctrl event since genl_ctrl_event(CTRL_CMD_NEWOPS, ...) only returns -EINVAL anyway, therefore no such event could ever be sent. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 7 +++-- net/netlink/genetlink.c | 78 +++++++++++++++++++++---------------------------- 2 files changed, 37 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 617d718524b0..d4802af1a8b3 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -39,9 +39,10 @@ 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 + * @ops: the operations supported by this family (private) + * @n_ops: number of operations supported by this family (private) */ struct genl_family { unsigned int id; @@ -58,7 +59,8 @@ struct genl_family { struct sk_buff *skb, struct genl_info *info); struct nlattr ** attrbuf; /* private */ - struct list_head ops_list; /* private */ + struct genl_ops * ops; /* private */ + unsigned int n_ops; /* private */ struct list_head family_list; /* private */ struct list_head mcast_groups; /* private */ struct module *module; @@ -119,7 +121,6 @@ struct genl_ops { int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb); int (*done)(struct netlink_callback *cb); - struct list_head ops_list; }; int __genl_register_family(struct genl_family *family); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index fbccb45e8cc1..d8273b057763 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -108,11 +108,11 @@ static struct genl_family *genl_family_find_byname(char *name) static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) { - struct genl_ops *ops; + int i; - list_for_each_entry(ops, &family->ops_list, ops_list) - if (ops->cmd == cmd) - return ops; + for (i = 0; i < family->n_ops; i++) + if (family->ops[i].cmd == cmd) + return &family->ops[i]; return NULL; } @@ -283,33 +283,30 @@ static void genl_unregister_mc_groups(struct genl_family *family) __genl_unregister_mc_group(family, grp); } -static int genl_register_ops(struct genl_family *family, struct genl_ops *ops) +static int genl_validate_add_ops(struct genl_family *family, struct genl_ops *ops, + unsigned int n_ops) { - int err = -EINVAL; - - if (ops->dumpit == NULL && ops->doit == NULL) - goto errout; - - if (genl_get_cmd(ops->cmd, family)) { - err = -EEXIST; - goto errout; + int i, j; + + for (i = 0; i < n_ops; i++) { + if (ops[i].dumpit == NULL && ops[i].doit == NULL) + return -EINVAL; + for (j = i + 1; j < n_ops; j++) + if (ops[i].cmd == ops[j].cmd) + return -EINVAL; + if (ops[i].dumpit) + ops[i].flags |= GENL_CMD_CAP_DUMP; + if (ops[i].doit) + ops[i].flags |= GENL_CMD_CAP_DO; + if (ops[i].policy) + ops[i].flags |= GENL_CMD_CAP_HASPOL; } - 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_all(); - list_add_tail(&ops->ops_list, &family->ops_list); - genl_unlock_all(); + /* family is not registered yet, so no locking needed */ + family->ops = ops; + family->n_ops = n_ops; - genl_ctrl_event(CTRL_CMD_NEWOPS, ops); - err = 0; -errout: - return err; + return 0; } /** @@ -333,7 +330,6 @@ int __genl_register_family(struct genl_family *family) if (family->id > GENL_MAX_ID) goto errout; - INIT_LIST_HEAD(&family->ops_list); INIT_LIST_HEAD(&family->mcast_groups); genl_lock_all(); @@ -405,21 +401,13 @@ EXPORT_SYMBOL(__genl_register_family); int __genl_register_family_with_ops(struct genl_family *family, struct genl_ops *ops, size_t n_ops) { - int err, i; + int err; - err = __genl_register_family(family); + err = genl_validate_add_ops(family, ops, n_ops); if (err) return err; - for (i = 0; i < n_ops; ++i, ++ops) { - err = genl_register_ops(family, ops); - if (err) - goto err_out; - } - return 0; -err_out: - genl_unregister_family(family); - return err; + return __genl_register_family(family); } EXPORT_SYMBOL(__genl_register_family_with_ops); @@ -444,7 +432,7 @@ int genl_unregister_family(struct genl_family *family) continue; list_del(&rc->family_list); - INIT_LIST_HEAD(&family->ops_list); + family->n_ops = 0; genl_unlock_all(); kfree(family->attrbuf); @@ -671,19 +659,19 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr)) goto nla_put_failure; - if (!list_empty(&family->ops_list)) { + if (family->n_ops) { struct nlattr *nla_ops; - struct genl_ops *ops; - int idx = 1; + int i; nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); if (nla_ops == NULL) goto nla_put_failure; - list_for_each_entry(ops, &family->ops_list, ops_list) { + for (i = 0; i < family->n_ops; i++) { struct nlattr *nest; + struct genl_ops *ops = &family->ops[i]; - nest = nla_nest_start(skb, idx++); + nest = nla_nest_start(skb, i + 1); if (nest == NULL) goto nla_put_failure; -- cgit v1.2.3 From f84f771d942182e39a56ec2989d6a67d3ca33a13 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:45 +0100 Subject: genetlink: allow making ops const Allow making the ops array const by not modifying the ops flags on registration but rather only when ops are sent out in the family information. No users are updated yet except for the pre_doit/post_doit calls in wireless (the only ones that exist now.) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 10 +++++----- net/netlink/genetlink.c | 36 +++++++++++++++++++++--------------- net/wireless/nl80211.c | 8 ++++---- 3 files changed, 30 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d4802af1a8b3..d87486aa0611 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -52,14 +52,14 @@ 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 genl_ops * ops; /* private */ + const struct genl_ops * ops; /* private */ unsigned int n_ops; /* private */ struct list_head family_list; /* private */ struct list_head mcast_groups; /* private */ @@ -132,10 +132,10 @@ static inline int genl_register_family(struct genl_family *family) } int __genl_register_family_with_ops(struct genl_family *family, - struct genl_ops *ops, size_t n_ops); + const 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) + const struct genl_ops *ops, size_t n_ops) { family->module = THIS_MODULE; return __genl_register_family_with_ops(family, ops, n_ops); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index d8273b057763..a7c62d3d05a1 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -106,7 +106,7 @@ static struct genl_family *genl_family_find_byname(char *name) return NULL; } -static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) +static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) { int i; @@ -283,7 +283,8 @@ static void genl_unregister_mc_groups(struct genl_family *family) __genl_unregister_mc_group(family, grp); } -static int genl_validate_add_ops(struct genl_family *family, struct genl_ops *ops, +static int genl_validate_add_ops(struct genl_family *family, + const struct genl_ops *ops, unsigned int n_ops) { int i, j; @@ -294,12 +295,6 @@ static int genl_validate_add_ops(struct genl_family *family, struct genl_ops *op for (j = i + 1; j < n_ops; j++) if (ops[i].cmd == ops[j].cmd) return -EINVAL; - if (ops[i].dumpit) - ops[i].flags |= GENL_CMD_CAP_DUMP; - if (ops[i].doit) - ops[i].flags |= GENL_CMD_CAP_DO; - if (ops[i].policy) - ops[i].flags |= GENL_CMD_CAP_HASPOL; } /* family is not registered yet, so no locking needed */ @@ -399,7 +394,7 @@ EXPORT_SYMBOL(__genl_register_family); * Return 0 on success or a negative error code. */ int __genl_register_family_with_ops(struct genl_family *family, - struct genl_ops *ops, size_t n_ops) + const struct genl_ops *ops, size_t n_ops) { int err; @@ -479,7 +474,8 @@ EXPORT_SYMBOL(genlmsg_put); static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) { - struct genl_ops *ops = cb->data; + /* our ops are always const - netlink API doesn't propagate that */ + const struct genl_ops *ops = cb->data; int rc; genl_lock(); @@ -490,7 +486,8 @@ static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) static int genl_lock_done(struct netlink_callback *cb) { - struct genl_ops *ops = cb->data; + /* our ops are always const - netlink API doesn't propagate that */ + const struct genl_ops *ops = cb->data; int rc = 0; if (ops->done) { @@ -505,7 +502,7 @@ static int genl_family_rcv_msg(struct genl_family *family, struct sk_buff *skb, struct nlmsghdr *nlh) { - struct genl_ops *ops; + const struct genl_ops *ops; struct net *net = sock_net(skb->sk); struct genl_info info; struct genlmsghdr *hdr = nlmsg_data(nlh); @@ -537,7 +534,8 @@ static int genl_family_rcv_msg(struct genl_family *family, if (!family->parallel_ops) { struct netlink_dump_control c = { .module = family->module, - .data = ops, + /* we have const, but the netlink API doesn't */ + .data = (void *)ops, .dump = genl_lock_dumpit, .done = genl_lock_done, }; @@ -669,14 +667,22 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, for (i = 0; i < family->n_ops; i++) { struct nlattr *nest; - struct genl_ops *ops = &family->ops[i]; + const struct genl_ops *ops = &family->ops[i]; + u32 flags = ops->flags; + + if (ops->dumpit) + flags |= GENL_CMD_CAP_DUMP; + if (ops->doit) + flags |= GENL_CMD_CAP_DO; + if (ops->policy) + flags |= GENL_CMD_CAP_HASPOL; nest = nla_nest_start(skb, i + 1); if (nest == NULL) goto nla_put_failure; if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) || - nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, ops->flags)) + nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, flags)) goto nla_put_failure; nla_nest_end(skb, nest); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a7f4e7902104..3fef55958e98 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -30,9 +30,9 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, struct cfg80211_crypto_settings *settings, int cipher_limit); -static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, +static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); -static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, +static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); /* the netlink family */ @@ -8851,7 +8851,7 @@ static int nl80211_crit_protocol_stop(struct sk_buff *skb, #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ NL80211_FLAG_CHECK_NETDEV_UP) -static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, +static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; @@ -8920,7 +8920,7 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, return 0; } -static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, +static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { if (info->user_ptr[1]) { -- cgit v1.2.3 From 3f5ccd06aecd0eb1651dd451439d5cb365170854 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Nov 2013 17:14:47 +0100 Subject: genetlink: make genl_ops flags a u8 and move to end To save some space in the struct on 32-bit systems, make the flags a u8 (only 4 bits are used) and also move them to the end of the struct. This has no impact on 64-bit systems as alignment of the struct in an array uses up the space anyway. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d87486aa0611..0b6a144468c6 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -112,15 +112,15 @@ 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); + u8 cmd; + u8 internal_flags; + u8 flags; }; int __genl_register_family(struct genl_family *family); -- cgit v1.2.3 From be9eac48274a2d9b142d6dd8567b9b2362939346 Mon Sep 17 00:00:00 2001 From: Michal Kubeček Date: Fri, 15 Nov 2013 06:18:40 +0100 Subject: macvlan: introduce macvlan_dev_real_dev() helper function Introduce helper function macvlan_dev_real_dev which returns the underlying device of a macvlan device, similar to vlan_dev_real_dev() for 802.1q VLAN devices. v2: IFF_MACVLAN flag and equivalent of is_macvlan_dev() were introduced in the meantime v3: do BUG() if compiled without macvlan support Signed-off-by: Michal Kubecek Signed-off-by: David S. Miller --- include/linux/if_macvlan.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'include') diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index c2702856295e..84ba5ac39e03 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -119,4 +119,21 @@ extern int macvlan_link_register(struct rtnl_link_ops *ops); extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev); +#if IS_ENABLED(CONFIG_MACVLAN) +static inline struct net_device * +macvlan_dev_real_dev(const struct net_device *dev) +{ + struct macvlan_dev *macvlan = netdev_priv(dev); + + return macvlan->lowerdev; +} +#else +static inline struct net_device * +macvlan_dev_real_dev(const struct net_device *dev) +{ + BUG(); + return NULL; +} +#endif + #endif /* _LINUX_IF_MACVLAN_H */ -- cgit v1.2.3 From 568508aa0724cc39bcf7d3d8001bd27a45609800 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Nov 2013 14:19:08 +0100 Subject: genetlink: unify registration functions Now that the ops assignment is just two variables rather than a long list iteration etc., there's no reason to separately export __genl_register_family() and __genl_register_family_with_ops(). Unify the two functions into __genl_register_family() and make genl_register_family_with_ops() call it after assigning the ops. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 28 ++++++++++++++++++++++---- net/netlink/genetlink.c | 53 +++++++++++++++---------------------------------- 2 files changed, 40 insertions(+), 41 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 0b6a144468c6..e96385d46b48 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -131,14 +131,34 @@ static inline int genl_register_family(struct genl_family *family) return __genl_register_family(family); } -int __genl_register_family_with_ops(struct genl_family *family, - const 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(struct genl_family *family, const struct genl_ops *ops, size_t n_ops) { family->module = THIS_MODULE; - return __genl_register_family_with_ops(family, ops, n_ops); + family->ops = ops; + family->n_ops = n_ops; + return __genl_register_family(family); } int genl_unregister_family(struct genl_family *family); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index a7c62d3d05a1..f07eb568a1db 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -283,12 +283,18 @@ static void genl_unregister_mc_groups(struct genl_family *family) __genl_unregister_mc_group(family, grp); } -static int genl_validate_add_ops(struct genl_family *family, - const struct genl_ops *ops, - unsigned int n_ops) +static int genl_validate_ops(struct genl_family *family) { + const struct genl_ops *ops = family->ops; + unsigned int n_ops = family->n_ops; int i, j; + if (WARN_ON(n_ops && !ops)) + return -EINVAL; + + if (!n_ops) + return 0; + for (i = 0; i < n_ops; i++) { if (ops[i].dumpit == NULL && ops[i].doit == NULL) return -EINVAL; @@ -313,6 +319,9 @@ static int genl_validate_add_ops(struct genl_family *family, * The family id may equal GENL_ID_GENERATE causing an unique id to * be automatically generated and assigned. * + * The family's ops array must already be assigned, you can use the + * genl_register_family_with_ops() helper function. + * * Return 0 on success or a negative error code. */ int __genl_register_family(struct genl_family *family) @@ -325,6 +334,10 @@ int __genl_register_family(struct genl_family *family) if (family->id > GENL_MAX_ID) goto errout; + err = genl_validate_ops(family); + if (err) + return err; + INIT_LIST_HEAD(&family->mcast_groups); genl_lock_all(); @@ -372,40 +385,6 @@ errout: } EXPORT_SYMBOL(__genl_register_family); -/** - * __genl_register_family_with_ops - register a generic netlink family - * @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. - */ -int __genl_register_family_with_ops(struct genl_family *family, - const struct genl_ops *ops, size_t n_ops) -{ - int err; - - err = genl_validate_add_ops(family, ops, n_ops); - if (err) - return err; - - return __genl_register_family(family); -} -EXPORT_SYMBOL(__genl_register_family_with_ops); - /** * genl_unregister_family - unregister generic netlink family * @family: generic netlink family -- cgit v1.2.3 From 65c5189a2b57b9aa1d89e4b79da39928257c9505 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 Nov 2013 08:57:26 -0800 Subject: pkt_sched: fq: warn users using defrate Commit 7eec4174ff29 ("pkt_sched: fq: fix non TCP flows pacing") obsoleted TCA_FQ_FLOW_DEFAULT_RATE without notice for the users. Suggested by David Miller Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/uapi/linux/pkt_sched.h | 4 +--- net/sched/sch_fq.c | 10 ++++------ 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 307f293477e8..885001b62c83 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -763,9 +763,7 @@ enum { TCA_FQ_RATE_ENABLE, /* enable/disable rate limiting */ - TCA_FQ_FLOW_DEFAULT_RATE,/* for sockets with unspecified sk_rate, - * use the following rate - */ + TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */ TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */ diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index d4fa38e4af80..26906ab51c52 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -88,7 +88,6 @@ struct fq_sched_data { struct fq_flow internal; /* for non classified or high prio packets */ u32 quantum; u32 initial_quantum; - u32 flow_default_rate;/* rate per flow : bytes per second */ u32 flow_max_rate; /* optional max rate per flow */ u32 flow_plimit; /* max packets per flow */ struct rb_root *fq_root; @@ -650,7 +649,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) q->initial_quantum = nla_get_u32(tb[TCA_FQ_INITIAL_QUANTUM]); if (tb[TCA_FQ_FLOW_DEFAULT_RATE]) - q->flow_default_rate = nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]); + pr_warn_ratelimited("sch_fq: defrate %u ignored.\n", + nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE])); if (tb[TCA_FQ_FLOW_MAX_RATE]) q->flow_max_rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]); @@ -699,7 +699,6 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt) q->flow_plimit = 100; q->quantum = 2 * psched_mtu(qdisc_dev(sch)); q->initial_quantum = 10 * psched_mtu(qdisc_dev(sch)); - q->flow_default_rate = 0; q->flow_max_rate = ~0U; q->rate_enable = 1; q->new_flows.first = NULL; @@ -726,9 +725,8 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb) if (opts == NULL) goto nla_put_failure; - /* TCA_FQ_FLOW_DEFAULT_RATE is not used anymore, - * do not bother giving its value - */ + /* TCA_FQ_FLOW_DEFAULT_RATE is not used anymore */ + if (nla_put_u32(skb, TCA_FQ_PLIMIT, sch->limit) || nla_put_u32(skb, TCA_FQ_FLOW_PLIMIT, q->flow_plimit) || nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) || -- cgit v1.2.3 From f52ed89971adbe79b6438c459814034707b8ab91 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 15 Nov 2013 08:58:14 -0800 Subject: pkt_sched: fq: fix pacing for small frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For performance reasons, sch_fq tried hard to not setup timers for every sent packet, using a quantum based heuristic : A delay is setup only if the flow exhausted its credit. Problem is that application limited flows can refill their credit for every queued packet, and they can evade pacing. This problem can also be triggered when TCP flows use small MSS values, as TSO auto sizing builds packets that are smaller than the default fq quantum (3028 bytes) This patch adds a 40 ms delay to guard flow credit refill. Fixes: afe4fd062416 ("pkt_sched: fq: Fair Queue packet scheduler") Signed-off-by: Eric Dumazet Cc: Maciej Żenczykowski Cc: Willem de Bruijn Cc: Yuchung Cheng Cc: Neal Cardwell Signed-off-by: David S. Miller --- include/uapi/linux/pkt_sched.h | 3 +++ net/sched/sch_fq.c | 22 ++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 885001b62c83..a806687ad98f 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -768,6 +768,9 @@ enum { TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */ TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */ + + TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */ + __TCA_FQ_MAX }; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 26906ab51c52..95d843961907 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -88,6 +88,7 @@ struct fq_sched_data { struct fq_flow internal; /* for non classified or high prio packets */ u32 quantum; u32 initial_quantum; + u32 flow_refill_delay; u32 flow_max_rate; /* optional max rate per flow */ u32 flow_plimit; /* max packets per flow */ struct rb_root *fq_root; @@ -114,6 +115,7 @@ static struct fq_flow detached, throttled; static void fq_flow_set_detached(struct fq_flow *f) { f->next = &detached; + f->age = jiffies; } static bool fq_flow_is_detached(const struct fq_flow *f) @@ -366,17 +368,20 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch) } f->qlen++; - flow_queue_add(f, skb); if (skb_is_retransmit(skb)) q->stat_tcp_retrans++; sch->qstats.backlog += qdisc_pkt_len(skb); if (fq_flow_is_detached(f)) { fq_flow_add_tail(&q->new_flows, f); - if (q->quantum > f->credit) - f->credit = q->quantum; + if (time_after(jiffies, f->age + q->flow_refill_delay)) + f->credit = max_t(u32, f->credit, q->quantum); q->inactive_flows--; qdisc_unthrottled(sch); } + + /* Note: this overwrites f->age */ + flow_queue_add(f, skb); + if (unlikely(f == &q->internal)) { q->stat_internal_packets++; qdisc_unthrottled(sch); @@ -454,7 +459,6 @@ begin: fq_flow_add_tail(&q->old_flows, f); } else { fq_flow_set_detached(f); - f->age = jiffies; q->inactive_flows++; } goto begin; @@ -608,6 +612,7 @@ static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = { [TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NLA_U32 }, [TCA_FQ_FLOW_MAX_RATE] = { .type = NLA_U32 }, [TCA_FQ_BUCKETS_LOG] = { .type = NLA_U32 }, + [TCA_FQ_FLOW_REFILL_DELAY] = { .type = NLA_U32 }, }; static int fq_change(struct Qdisc *sch, struct nlattr *opt) @@ -664,6 +669,12 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) err = -EINVAL; } + if (tb[TCA_FQ_FLOW_REFILL_DELAY]) { + u32 usecs_delay = nla_get_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]) ; + + q->flow_refill_delay = usecs_to_jiffies(usecs_delay); + } + if (!err) err = fq_resize(q, fq_log); @@ -699,6 +710,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt) q->flow_plimit = 100; q->quantum = 2 * psched_mtu(qdisc_dev(sch)); q->initial_quantum = 10 * psched_mtu(qdisc_dev(sch)); + q->flow_refill_delay = msecs_to_jiffies(40); q->flow_max_rate = ~0U; q->rate_enable = 1; q->new_flows.first = NULL; @@ -733,6 +745,8 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb) nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) || nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) || nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) || + nla_put_u32(skb, TCA_FQ_FLOW_REFILL_DELAY, + jiffies_to_usecs(q->flow_refill_delay)) || nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log)) goto nla_put_failure; -- cgit v1.2.3 From 018c5bba052b3a383d83cf0c756da0e7bc748397 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 15 Nov 2013 21:11:16 -0500 Subject: net: Handle CHECKSUM_COMPLETE more adequately in pskb_trim_rcsum(). Currently pskb_trim_rcsum() just balks on CHECKSUM_COMPLETE packets and remarks them as CHECKSUM_NONE, forcing a software checksum validation later. We have all of the mechanics available to fixup the skb->csum value, even for complicated fragmented packets, via the helpers skb_checksum() and csum_sub(). So just use them. Based upon a suggestion by Herbert Xu. Signed-off-by: David S. Miller --- include/linux/skbuff.h | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 215b5ea1cb30..bec1cc7d5e3c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2263,24 +2263,6 @@ static inline void skb_postpull_rcsum(struct sk_buff *skb, unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len); -/** - * pskb_trim_rcsum - trim received skb and update checksum - * @skb: buffer to trim - * @len: new length - * - * This is exactly the same as pskb_trim except that it ensures the - * checksum of received packets are still valid after the operation. - */ - -static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) -{ - if (likely(len >= skb->len)) - return 0; - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - return __pskb_trim(skb, len); -} - #define skb_queue_walk(queue, skb) \ for (skb = (queue)->next; \ skb != (struct sk_buff *)(queue); \ @@ -2378,6 +2360,27 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, __wsum csum); +/** + * pskb_trim_rcsum - trim received skb and update checksum + * @skb: buffer to trim + * @len: new length + * + * This is exactly the same as pskb_trim except that it ensures the + * checksum of received packets are still valid after the operation. + */ + +static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) +{ + if (likely(len >= skb->len)) + return 0; + if (skb->ip_summed == CHECKSUM_COMPLETE) { + __wsum adj = skb_checksum(skb, len, skb->len - len, 0); + + skb->csum = csum_sub(skb->csum, adj); + } + return __pskb_trim(skb, len); +} + static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) { -- cgit v1.2.3 From c53ed7423619b4e8108914a9f31b426dd58ad591 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:31 +0100 Subject: genetlink: only pass array to genl_register_family_with_ops() As suggested by David Miller, make genl_register_family_with_ops() a macro and pass only the array, evaluating ARRAY_SIZE() in the macro, this is a little safer. The openvswitch has some indirection, assing ops/n_ops directly in that code. This might ultimately just assign the pointers in the family initializations, saving the struct genl_family_and_ops and code (once mcast groups are handled differently.) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/net/team/team.c | 3 +-- drivers/net/wireless/mac80211_hwsim.c | 3 +-- fs/dlm/netlink.c | 10 ++++++---- include/linux/genl_magic_func.h | 3 +-- include/net/genetlink.h | 8 ++++++-- kernel/taskstats.c | 3 +-- net/core/drop_monitor.c | 3 +-- net/hsr/hsr_netlink.c | 3 +-- net/ieee802154/netlink.c | 3 +-- net/ipv4/tcp_metrics.c | 3 +-- net/irda/irnetlink.c | 3 +-- net/l2tp/l2tp_netlink.c | 7 +------ net/netfilter/ipvs/ip_vs_ctl.c | 2 +- net/netlabel/netlabel_cipso_v4.c | 2 +- net/netlabel/netlabel_mgmt.c | 2 +- net/netlabel/netlabel_unlabeled.c | 2 +- net/netlink/genetlink.c | 14 ++++++++------ net/nfc/netlink.c | 3 +-- net/openvswitch/datapath.c | 5 +++-- net/tipc/netlink.c | 11 ++++++----- net/wimax/stack.c | 4 ++-- net/wireless/nl80211.c | 3 +-- 22 files changed, 47 insertions(+), 53 deletions(-) (limited to 'include') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 6390254beb7d..f55758b0840e 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2699,8 +2699,7 @@ static int team_nl_init(void) { int err; - err = genl_register_family_with_ops(&team_nl_family, team_nl_ops, - ARRAY_SIZE(team_nl_ops)); + err = genl_register_family_with_ops(&team_nl_family, team_nl_ops); if (err) return err; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index cfc3fda79a2d..9df7bc91a26f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2148,8 +2148,7 @@ static int hwsim_init_netlink(void) printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); - rc = genl_register_family_with_ops(&hwsim_genl_family, - hwsim_ops, ARRAY_SIZE(hwsim_ops)); + rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops); if (rc) goto failure; diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c index 60a327863b11..e7cfbaf8d0e2 100644 --- a/fs/dlm/netlink.c +++ b/fs/dlm/netlink.c @@ -74,14 +74,16 @@ static int user_cmd(struct sk_buff *skb, struct genl_info *info) return 0; } -static struct genl_ops dlm_nl_ops = { - .cmd = DLM_CMD_HELLO, - .doit = user_cmd, +static struct genl_ops dlm_nl_ops[] = { + { + .cmd = DLM_CMD_HELLO, + .doit = user_cmd, + }, }; int __init dlm_netlink_init(void) { - return genl_register_family_with_ops(&family, &dlm_nl_ops, 1); + return genl_register_family_with_ops(&family, dlm_nl_ops); } void dlm_netlink_exit(void) diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h index 023bc346b877..47086030ab31 100644 --- a/include/linux/genl_magic_func.h +++ b/include/linux/genl_magic_func.h @@ -293,8 +293,7 @@ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void) { - int err = genl_register_family_with_ops(&ZZZ_genl_family, - ZZZ_genl_ops, ARRAY_SIZE(ZZZ_genl_ops)); + int err = genl_register_family_with_ops(&ZZZ_genl_family, ZZZ_genl_ops); if (err) return err; #undef GENL_mc_group diff --git a/include/net/genetlink.h b/include/net/genetlink.h index e96385d46b48..9bd52a4c5e17 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -152,8 +152,9 @@ static inline int genl_register_family(struct genl_family *family) * * Return 0 on success or a negative error code. */ -static inline int genl_register_family_with_ops(struct genl_family *family, - const struct genl_ops *ops, size_t n_ops) +static inline int _genl_register_family_with_ops(struct genl_family *family, + const struct genl_ops *ops, + size_t n_ops) { family->module = THIS_MODULE; family->ops = ops; @@ -161,6 +162,9 @@ static inline int genl_register_family_with_ops(struct genl_family *family, return __genl_register_family(family); } +#define genl_register_family_with_ops(family, ops) \ + _genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops)) + int genl_unregister_family(struct genl_family *family); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 76595cd9d211..13d2f7cd65db 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -703,8 +703,7 @@ static int __init taskstats_init(void) { int rc; - rc = genl_register_family_with_ops(&family, taskstats_ops, - ARRAY_SIZE(taskstats_ops)); + rc = genl_register_family_with_ops(&family, taskstats_ops); if (rc) return rc; diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index f9fe2f22d20b..0efc5028ba9d 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -365,8 +365,7 @@ static int __init init_net_drop_monitor(void) } rc = genl_register_family_with_ops(&net_drop_monitor_family, - dropmon_ops, - ARRAY_SIZE(dropmon_ops)); + dropmon_ops); if (rc) { pr_err("Could not create drop monitor netlink family\n"); return rc; diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 3b9205d2afc4..f182260be76d 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -414,8 +414,7 @@ int __init hsr_netlink_init(void) if (rc) goto fail_rtnl_link_register; - rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops, - ARRAY_SIZE(hsr_ops)); + rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops); if (rc) goto fail_genl_register_family; diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 3ffcdbb56aab..1a81709a4717 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -129,8 +129,7 @@ int __init ieee802154_nl_init(void) { int rc; - rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops, - ARRAY_SIZE(ieee8021154_ops)); + rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops); if (rc) return rc; diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 8c121b523eee..06493736fbc8 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -1082,8 +1082,7 @@ void __init tcp_metrics_init(void) if (ret < 0) goto cleanup; ret = genl_register_family_with_ops(&tcp_metrics_nl_family, - tcp_metrics_nl_ops, - ARRAY_SIZE(tcp_metrics_nl_ops)); + tcp_metrics_nl_ops); if (ret < 0) goto cleanup_subsys; return; diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index bf5d7d476dae..a37b81fe0479 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -149,8 +149,7 @@ static const struct genl_ops irda_nl_ops[] = { int irda_nl_register(void) { - return genl_register_family_with_ops(&irda_nl_family, - irda_nl_ops, ARRAY_SIZE(irda_nl_ops)); + return genl_register_family_with_ops(&irda_nl_family, irda_nl_ops); } void irda_nl_unregister(void) diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 57db66e24f1f..4cfd722e9153 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -887,13 +887,8 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops); static int l2tp_nl_init(void) { - int err; - pr_info("L2TP netlink interface\n"); - err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops, - ARRAY_SIZE(l2tp_nl_ops)); - - return err; + return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops); } static void l2tp_nl_cleanup(void) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index fc8a04ed8854..393498704691 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3666,7 +3666,7 @@ static const struct genl_ops ip_vs_genl_ops[] __read_mostly = { static int __init ip_vs_genl_register(void) { return genl_register_family_with_ops(&ip_vs_genl_family, - ip_vs_genl_ops, ARRAY_SIZE(ip_vs_genl_ops)); + ip_vs_genl_ops); } static void ip_vs_genl_unregister(void) diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index 706691739b99..69345cebe3a3 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -783,5 +783,5 @@ static const struct genl_ops netlbl_cipsov4_ops[] = { int __init netlbl_cipsov4_genl_init(void) { return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family, - netlbl_cipsov4_ops, ARRAY_SIZE(netlbl_cipsov4_ops)); + netlbl_cipsov4_ops); } diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 7de6f660b80a..8ef83ee97c6a 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -779,5 +779,5 @@ static const struct genl_ops netlbl_mgmt_genl_ops[] = { int __init netlbl_mgmt_genl_init(void) { return genl_register_family_with_ops(&netlbl_mgmt_gnl_family, - netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops)); + netlbl_mgmt_genl_ops); } diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 76ee9252daa7..43817d73ccf9 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1397,7 +1397,7 @@ static const struct genl_ops netlbl_unlabel_genl_ops[] = { int __init netlbl_unlabel_genl_init(void) { return genl_register_family_with_ops(&netlbl_unlabel_gnl_family, - netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops)); + netlbl_unlabel_genl_ops); } /* diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index f54215d7b8f3..c68ce73619b5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -906,11 +906,13 @@ static int genl_ctrl_event(int event, void *data) return 0; } -static struct genl_ops genl_ctrl_ops = { - .cmd = CTRL_CMD_GETFAMILY, - .doit = ctrl_getfamily, - .dumpit = ctrl_dumpfamily, - .policy = ctrl_policy, +static struct genl_ops genl_ctrl_ops[] = { + { + .cmd = CTRL_CMD_GETFAMILY, + .doit = ctrl_getfamily, + .dumpit = ctrl_dumpfamily, + .policy = ctrl_policy, + }, }; static struct genl_multicast_group notify_grp = { @@ -954,7 +956,7 @@ static int __init genl_init(void) for (i = 0; i < GENL_FAM_TAB_SIZE; i++) INIT_LIST_HEAD(&family_ht[i]); - err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1); + err = genl_register_family_with_ops(&genl_ctrl, genl_ctrl_ops); if (err < 0) goto problem; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f5585611c098..fe6760d328a0 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -1536,8 +1536,7 @@ int __init nfc_genl_init(void) { int rc; - rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops, - ARRAY_SIZE(nfc_genl_ops)); + rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops); if (rc) return rc; diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 91e1c927a465..8ec8b73033e0 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1817,8 +1817,9 @@ static int dp_register_genl(void) for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) { const struct genl_family_and_ops *f = &dp_genl_families[i]; - err = genl_register_family_with_ops(f->family, f->ops, - f->n_ops); + f->family->ops = f->ops; + f->family->n_ops = f->n_ops; + err = genl_register_family(f->family); if (err) goto error; n_registered++; diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 8bcd4985d0fb..9f72a6376362 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -76,9 +76,11 @@ static struct genl_family tipc_genl_family = { .maxattr = 0, }; -static struct genl_ops tipc_genl_ops = { - .cmd = TIPC_GENL_CMD, - .doit = handle_cmd, +static struct genl_ops tipc_genl_ops[] = { + { + .cmd = TIPC_GENL_CMD, + .doit = handle_cmd, + }, }; static int tipc_genl_family_registered; @@ -87,8 +89,7 @@ int tipc_netlink_start(void) { int res; - res = genl_register_family_with_ops(&tipc_genl_family, - &tipc_genl_ops, 1); + res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops); if (res) { pr_err("Failed to register netlink interface\n"); return res; diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 47170c9495f1..6328afe90319 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -597,8 +597,8 @@ int __init wimax_subsys_init(void) snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), "WiMAX"); - result = genl_register_family_with_ops(&wimax_gnl_family, wimax_gnl_ops, - ARRAY_SIZE(wimax_gnl_ops)); + result = genl_register_family_with_ops(&wimax_gnl_family, + wimax_gnl_ops); if (unlikely(result < 0)) { printk(KERN_ERR "cannot register generic netlink family: %d\n", result); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 58c43c8e149f..1b6c5dd4dccf 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -11329,8 +11329,7 @@ int nl80211_init(void) { int err; - err = genl_register_family_with_ops(&nl80211_fam, - nl80211_ops, ARRAY_SIZE(nl80211_ops)); + err = genl_register_family_with_ops(&nl80211_fam, nl80211_ops); if (err) return err; -- cgit v1.2.3 From 2ecf7536b2787580616d23b6507005d930975ca0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:33 +0100 Subject: quota/genetlink: use proper genetlink multicast APIs The quota code is abusing the genetlink API and is using its family ID as the multicast group ID, which is invalid and may belong to somebody else (and likely will.) Make the quota code use the correct API, but since this is already used as-is by userspace, reserve a family ID for this code and also reserve that group ID to not break userspace assumptions. Acked-by: Jan Kara Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- fs/quota/netlink.c | 17 +++++++++++++++-- include/uapi/linux/genetlink.h | 1 + net/netlink/genetlink.c | 10 ++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index 16e8abb7709b..aa22fe03b76c 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c @@ -11,13 +11,23 @@ /* Netlink family structure for quota */ static struct genl_family quota_genl_family = { - .id = GENL_ID_GENERATE, + /* + * Needed due to multicast group ID abuse - old code assumed + * the family ID was also a valid multicast group ID (which + * isn't true) and userspace might thus rely on it. Assign a + * static ID for this group to make dealing with that easier. + */ + .id = GENL_ID_VFS_DQUOT, .hdrsize = 0, .name = "VFS_DQUOT", .version = 1, .maxattr = QUOTA_NL_A_MAX, }; +static struct genl_multicast_group quota_mcgrp = { + .name = "events", +}; + /** * quota_send_warning - Send warning to userspace about exceeded quota * @type: The quota type: USRQQUOTA, GRPQUOTA,... @@ -78,7 +88,7 @@ void quota_send_warning(struct kqid qid, dev_t dev, goto attr_err_out; genlmsg_end(skb, msg_head); - genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); + genlmsg_multicast(skb, 0, quota_mcgrp.id, GFP_NOFS); return; attr_err_out: printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); @@ -92,6 +102,9 @@ static int __init quota_init(void) if (genl_register_family("a_genl_family) != 0) printk(KERN_ERR "VFS: Failed to create quota netlink interface.\n"); + if (genl_register_mc_group("a_genl_family, "a_mcgrp)) + printk(KERN_ERR + "VFS: Failed to register quota mcast group.\n"); return 0; }; diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h index c880a417d8a9..1af72d8228e0 100644 --- a/include/uapi/linux/genetlink.h +++ b/include/uapi/linux/genetlink.h @@ -27,6 +27,7 @@ struct genlmsghdr { */ #define GENL_ID_GENERATE 0 #define GENL_ID_CTRL NLMSG_MIN_TYPE +#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) /************************************************************************** * Controller diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 353909d46dda..bee91a7527a5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -69,8 +69,11 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE]; * abuses the API and thinks it can statically use group 1. * That group will typically conflict with other groups that * any proper users use. + * Bit 17 is marked as already used since the VFS quota code + * also abused this API and relied on family == group ID, we + * cater to that by giving it a static family and group ID. */ -static unsigned long mc_group_start = 0x3; +static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT); static unsigned long *mc_groups = &mc_group_start; static unsigned long mc_groups_longs = 1; @@ -130,7 +133,8 @@ static u16 genl_generate_id(void) int i; for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { - if (!genl_family_find_byid(id_gen_idx)) + if (id_gen_idx != GENL_ID_VFS_DQUOT && + !genl_family_find_byid(id_gen_idx)) return id_gen_idx; if (++id_gen_idx > GENL_MAX_ID) id_gen_idx = GENL_MIN_ID; @@ -169,6 +173,8 @@ int genl_register_mc_group(struct genl_family *family, id = GENL_ID_CTRL; else if (strcmp(family->name, "NET_DM") == 0) id = 1; + else if (strcmp(family->name, "VFS_DQUOT") == 0) + id = GENL_ID_VFS_DQUOT; else id = find_first_zero_bit(mc_groups, mc_groups_longs * BITS_PER_LONG); -- cgit v1.2.3 From 06fb555a273dc8ef0d876f4e864ad11cfcea63e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:35 +0100 Subject: genetlink: remove genl_unregister_mc_group() There are no users of this API remaining, and we'll soon change group registration to be static (like ops are now) Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 -- net/netlink/genetlink.c | 23 ----------------------- 2 files changed, 25 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 9bd52a4c5e17..067569d1bc99 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -168,8 +168,6 @@ static inline int _genl_register_family_with_ops(struct genl_family *family, int genl_unregister_family(struct genl_family *family); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); -void genl_unregister_mc_group(struct genl_family *family, - struct genl_multicast_group *grp); void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index bee91a7527a5..6efb0e9036b5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -265,29 +265,6 @@ static void __genl_unregister_mc_group(struct genl_family *family, 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_all(); - __genl_unregister_mc_group(family, grp); - genl_unlock_all(); -} -EXPORT_SYMBOL(genl_unregister_mc_group); - static void genl_unregister_mc_groups(struct genl_family *family) { struct genl_multicast_group *grp, *tmp; -- cgit v1.2.3 From c2ebb908469d507ff400dad94efc755e6c799672 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:36 +0100 Subject: genetlink: remove family pointer from genl_multicast_group There's no reason to have the family pointer there since it can just be passed internally where needed, so remove it. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 2 -- net/netlink/genetlink.c | 38 ++++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 067569d1bc99..d8a8b1fd96c4 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -13,10 +13,8 @@ * @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; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 6efb0e9036b5..e9ef640200b4 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -77,7 +77,8 @@ static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT); 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 int genl_ctrl_event(int event, struct genl_family *family, + struct genl_multicast_group *grp); static inline unsigned int genl_family_hash(unsigned int id) { @@ -235,9 +236,8 @@ int genl_register_mc_group(struct genl_family *family, 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); + genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, grp); out: genl_unlock_all(); return err; @@ -248,7 +248,6 @@ static void __genl_unregister_mc_group(struct genl_family *family, struct genl_multicast_group *grp) { struct net *net; - BUG_ON(grp->family != family); netlink_table_grab(); rcu_read_lock(); @@ -260,9 +259,8 @@ static void __genl_unregister_mc_group(struct genl_family *family, if (grp->id != 1) clear_bit(grp->id, mc_groups); list_del(&grp->list); - genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp); + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, grp); grp->id = 0; - grp->family = NULL; } static void genl_unregister_mc_groups(struct genl_family *family) @@ -364,7 +362,7 @@ int __genl_register_family(struct genl_family *family) list_add_tail(&family->family_list, genl_family_chain(family->id)); genl_unlock_all(); - genl_ctrl_event(CTRL_CMD_NEWFAMILY, family); + genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL); return 0; @@ -400,7 +398,7 @@ int genl_unregister_family(struct genl_family *family) genl_unlock_all(); kfree(family->attrbuf); - genl_ctrl_event(CTRL_CMD_DELFAMILY, family); + genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL); return 0; } @@ -693,7 +691,8 @@ nla_put_failure: return -EMSGSIZE; } -static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid, +static int ctrl_fill_mcgrp_info(struct genl_family *family, + struct genl_multicast_group *grp, u32 portid, u32 seq, u32 flags, struct sk_buff *skb, u8 cmd) { @@ -705,8 +704,8 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid, if (hdr == NULL) return -1; - if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name) || - nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id)) + if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) || + nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id)) goto nla_put_failure; nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); @@ -783,7 +782,8 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, return skb; } -static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp, +static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_family *family, + struct genl_multicast_group *grp, u32 portid, int seq, u8 cmd) { struct sk_buff *skb; @@ -793,7 +793,7 @@ static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp, if (skb == NULL) return ERR_PTR(-ENOBUFS); - err = ctrl_fill_mcgrp_info(grp, portid, seq, 0, skb, cmd); + err = ctrl_fill_mcgrp_info(family, grp, portid, seq, 0, skb, cmd); if (err < 0) { nlmsg_free(skb); return ERR_PTR(err); @@ -855,11 +855,10 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) return genlmsg_reply(msg, info); } -static int genl_ctrl_event(int event, void *data) +static int genl_ctrl_event(int event, struct genl_family *family, + struct genl_multicast_group *grp) { struct sk_buff *msg; - struct genl_family *family; - struct genl_multicast_group *grp; /* genl is still initialising */ if (!init_net.genl_sock) @@ -868,14 +867,13 @@ static int genl_ctrl_event(int event, void *data) switch (event) { case CTRL_CMD_NEWFAMILY: case CTRL_CMD_DELFAMILY: - family = data; + WARN_ON(grp); msg = ctrl_build_family_msg(family, 0, 0, event); break; case CTRL_CMD_NEWMCAST_GRP: case CTRL_CMD_DELMCAST_GRP: - grp = data; - family = grp->family; - msg = ctrl_build_mcgrp_msg(data, 0, 0, event); + BUG_ON(!grp); + msg = ctrl_build_mcgrp_msg(family, grp, 0, 0, event); break; default: return -EINVAL; -- cgit v1.2.3 From 62b68e99faa802352e9cb2ae91adecd8dfddf1b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:37 +0100 Subject: genetlink: add and use genl_set_err() Add a static inline to generic netlink to wrap netlink_set_err() to make it easier to use here - use it in openvswitch (the only generic netlink user of netlink_set_err()). Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- include/net/genetlink.h | 14 ++++++++++++++ net/openvswitch/datapath.c | 8 ++++---- net/openvswitch/dp_notify.c | 6 +++--- 3 files changed, 21 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/net/genetlink.h b/include/net/genetlink.h index d8a8b1fd96c4..11ac77f6180c 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -351,5 +351,19 @@ 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 + * @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 + * @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 net *net, u32 portid, u32 group, int code) +{ + return netlink_set_err(net->genl_sock, portid, group, code); +} #endif /* __NET_GENERIC_NETLINK_H */ diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 8ec8b73033e0..3e2bb15fd717 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -879,8 +879,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) if (!IS_ERR(reply)) ovs_notify(reply, info, &ovs_dp_flow_multicast_group); else - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, - ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); + genl_set_err(sock_net(skb->sk), 0, + ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); return 0; err_flow_free: @@ -1326,8 +1326,8 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) info->snd_seq, OVS_DP_CMD_NEW); if (IS_ERR(reply)) { err = PTR_ERR(reply); - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, - ovs_dp_datapath_multicast_group.id, err); + genl_set_err(sock_net(skb->sk), 0, + ovs_dp_datapath_multicast_group.id, err); err = 0; goto unlock; } diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index 5c2dab276109..3d55ead6095c 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -34,9 +34,9 @@ static void dp_detach_port_notify(struct vport *vport) OVS_VPORT_CMD_DEL); ovs_dp_detach_port(vport); if (IS_ERR(notify)) { - netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0, - ovs_dp_vport_multicast_group.id, - PTR_ERR(notify)); + genl_set_err(ovs_dp_get_net(dp), 0, + ovs_dp_vport_multicast_group.id, + PTR_ERR(notify)); return; } -- cgit v1.2.3 From 68eb55031da7c967d954e5f9415cd05f4abdb692 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:38 +0100 Subject: genetlink: pass family to functions using groups This doesn't really change anything, but prepares for the next patch that will change the APIs to pass the group ID within the family, rather than the global group ID. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/acpi/event.c | 3 +- drivers/net/team/team.c | 5 +-- drivers/scsi/pmcraid.c | 3 +- drivers/thermal/thermal_core.c | 3 +- fs/quota/netlink.c | 2 +- include/linux/genl_magic_func.h | 3 +- include/net/genetlink.h | 22 +++++++++---- net/core/drop_monitor.c | 3 +- net/hsr/hsr_netlink.c | 6 ++-- net/ieee802154/netlink.c | 2 +- net/netlink/genetlink.c | 12 ++++--- net/nfc/netlink.c | 39 +++++++++++++++-------- net/openvswitch/datapath.c | 35 +++++++++++++-------- net/openvswitch/datapath.h | 1 + net/openvswitch/dp_notify.c | 5 +-- net/wimax/op-msg.c | 3 +- net/wimax/stack.c | 3 +- net/wireless/nl80211.c | 70 ++++++++++++++++++++--------------------- 18 files changed, 133 insertions(+), 87 deletions(-) (limited to 'include') diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 8247fcdde079..68a8755202ec 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -146,7 +146,8 @@ int acpi_bus_generate_netlink_event(const char *device_class, return result; } - genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&acpi_event_genl_family, + skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC); return 0; } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index f55758b0840e..2721e29935a6 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2677,8 +2677,9 @@ static struct genl_multicast_group team_change_event_mcgrp = { static int team_nl_send_multicast(struct sk_buff *skb, struct team *team, u32 portid) { - return genlmsg_multicast_netns(dev_net(team->dev), skb, 0, - team_change_event_mcgrp.id, GFP_KERNEL); + return genlmsg_multicast_netns(&team_nl_family, dev_net(team->dev), + skb, 0, team_change_event_mcgrp.id, + GFP_KERNEL); } static int team_nl_send_event_options_get(struct team *team, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 1eb7b0280a45..2775441111ff 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -1512,7 +1512,8 @@ static int pmcraid_notify_aen( } result = - genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC); + genlmsg_multicast(&pmcraid_event_family, skb, 0, + pmcraid_event_family.id, GFP_ATOMIC); /* If there are no listeners, genlmsg_multicast may return non-zero * value. diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 4962a6aaf295..2570a944fffc 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1675,7 +1675,8 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz, return result; } - result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC); + result = genlmsg_multicast(&thermal_event_genl_family, skb, 0, + thermal_event_mcgrp.id, GFP_ATOMIC); if (result) dev_err(&tz->device, "Failed to send netlink event:%d", result); diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index aa22fe03b76c..a5b5eddf6603 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c @@ -88,7 +88,7 @@ void quota_send_warning(struct kqid qid, dev_t dev, goto attr_err_out; genlmsg_end(skb, msg_head); - genlmsg_multicast(skb, 0, quota_mcgrp.id, GFP_NOFS); + genlmsg_multicast("a_genl_family, skb, 0, quota_mcgrp.id, GFP_NOFS); return; attr_err_out: printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h index 47086030ab31..5b9b8ae6748b 100644 --- a/include/linux/genl_magic_func.h +++ b/include/linux/genl_magic_func.h @@ -286,7 +286,8 @@ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id; \ if (!group_id) \ return -EINVAL; \ - return genlmsg_multicast(skb, 0, group_id, flags); \ + return genlmsg_multicast(&ZZZ_genl_family, skb, 0, \ + group_id, flags); \ } #include GENL_MAGIC_INCLUDE_FILE diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 11ac77f6180c..60aef0df386b 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -166,7 +166,8 @@ static inline int _genl_register_family_with_ops(struct genl_family *family, int genl_unregister_family(struct genl_family *family); int genl_register_mc_group(struct genl_family *family, struct genl_multicast_group *grp); -void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, +void genl_notify(struct genl_family *family, + struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags); void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, @@ -246,13 +247,15 @@ 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 * @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) { return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); @@ -260,19 +263,23 @@ static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb, /** * 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 * @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 @@ -280,7 +287,8 @@ static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid, * * 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); /** @@ -353,6 +361,7 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t 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 @@ -361,7 +370,8 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) * 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 net *net, u32 portid, u32 group, int code) +static inline int genl_set_err(struct genl_family *family, struct net *net, + u32 portid, u32 group, int code) { return netlink_set_err(net->genl_sock, portid, group, code); } diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 46ee488c0015..1eab1dc48821 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -120,7 +120,8 @@ static void send_dm_alert(struct work_struct *work) skb = reset_per_cpu_data(data); if (skb) - genlmsg_multicast(skb, 0, dm_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&net_drop_monitor_family, skb, 0, + dm_mcgrp.id, GFP_KERNEL); } /* diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 908e335dcdc9..0009416c08c2 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -129,7 +129,8 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_multicast(skb, 0, hsr_network_genl_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&hsr_genl_family, skb, 0, + hsr_network_genl_mcgrp.id, GFP_ATOMIC); return; @@ -163,7 +164,8 @@ void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]) goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_multicast(skb, 0, hsr_network_genl_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&hsr_genl_family, skb, 0, + hsr_network_genl_mcgrp.id, GFP_ATOMIC); return; diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 1a81709a4717..5172f467a383 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -70,7 +70,7 @@ int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group) if (genlmsg_end(msg, hdr) < 0) goto out; - return genlmsg_multicast(msg, 0, group, GFP_ATOMIC); + return genlmsg_multicast(&nl802154_family, msg, 0, group, GFP_ATOMIC); out: nlmsg_free(msg); return -ENOBUFS; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index e9ef640200b4..36e3a86cacf6 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -883,11 +883,12 @@ static int genl_ctrl_event(int event, struct genl_family *family, return PTR_ERR(msg); if (!family->netnsok) { - genlmsg_multicast_netns(&init_net, msg, 0, + genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0, GENL_ID_CTRL, GFP_KERNEL); } else { rcu_read_lock(); - genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC); + genlmsg_multicast_allns(&genl_ctrl, msg, 0, + GENL_ID_CTRL, GFP_ATOMIC); rcu_read_unlock(); } @@ -993,14 +994,15 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, return err; } -int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid, unsigned int group, - gfp_t flags) +int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, + u32 portid, unsigned int group, gfp_t flags) { return genlmsg_mcast(skb, portid, group, flags); } EXPORT_SYMBOL(genlmsg_multicast_allns); -void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group, +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 sock *sk = net->genl_sock; diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index fe6760d328a0..3092df313fb1 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -194,7 +194,8 @@ int nfc_genl_targets_found(struct nfc_dev *dev) genlmsg_end(msg, hdr); - return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + return genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_ATOMIC); nla_put_failure: genlmsg_cancel(msg, hdr); @@ -223,7 +224,8 @@ int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -255,7 +257,8 @@ int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -285,7 +288,8 @@ int nfc_genl_tm_deactivated(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -318,7 +322,8 @@ int nfc_genl_device_added(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -348,7 +353,8 @@ int nfc_genl_device_removed(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -414,7 +420,8 @@ int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list) genlmsg_end(msg, hdr); - return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + return genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_ATOMIC); nla_put_failure: genlmsg_cancel(msg, hdr); @@ -448,7 +455,8 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -479,7 +487,8 @@ int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -600,7 +609,8 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, dev->dep_link_up = true; - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_ATOMIC); return 0; @@ -632,7 +642,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_ATOMIC); return 0; @@ -1137,7 +1148,8 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name, genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); return 0; @@ -1308,7 +1320,8 @@ static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err) genlmsg_end(msg, hdr); - genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, + nfc_genl_event_mcgrp.id, GFP_KERNEL); kfree(ctx); diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 3e2bb15fd717..5c19846b1d2a 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -61,10 +61,11 @@ int ovs_net_id __read_mostly; -static void ovs_notify(struct sk_buff *skb, struct genl_info *info, +static void ovs_notify(struct genl_family *family, + struct sk_buff *skb, struct genl_info *info, struct genl_multicast_group *grp) { - genl_notify(skb, genl_info_net(info), info->snd_portid, + genl_notify(family, skb, genl_info_net(info), info->snd_portid, grp->id, info->nlhdr, GFP_KERNEL); } @@ -877,9 +878,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); if (!IS_ERR(reply)) - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, reply, info, + &ovs_dp_flow_multicast_group); else - genl_set_err(sock_net(skb->sk), 0, + genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0, ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); return 0; @@ -990,7 +992,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) ovs_flow_free(flow, true); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, reply, info, + &ovs_dp_flow_multicast_group); return 0; unlock: ovs_unlock(); @@ -1237,7 +1240,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info, + &ovs_dp_datapath_multicast_group); return 0; err_destroy_local_port: @@ -1302,7 +1306,8 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) __dp_destroy(dp); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info, + &ovs_dp_datapath_multicast_group); return 0; unlock: @@ -1326,14 +1331,15 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) info->snd_seq, OVS_DP_CMD_NEW); if (IS_ERR(reply)) { err = PTR_ERR(reply); - genl_set_err(sock_net(skb->sk), 0, + genl_set_err(&dp_datapath_genl_family, sock_net(skb->sk), 0, ovs_dp_datapath_multicast_group.id, err); err = 0; goto unlock; } ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info, + &ovs_dp_datapath_multicast_group); return 0; unlock: @@ -1425,7 +1431,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, }; -static struct genl_family dp_vport_genl_family = { +struct genl_family dp_vport_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = sizeof(struct ovs_header), .name = OVS_VPORT_FAMILY, @@ -1595,7 +1601,8 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) goto exit_unlock; } - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info, + &ovs_dp_vport_multicast_group); exit_unlock: ovs_unlock(); @@ -1642,7 +1649,8 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) BUG_ON(err < 0); ovs_unlock(); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info, + &ovs_dp_vport_multicast_group); return 0; exit_free: @@ -1679,7 +1687,8 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) err = 0; ovs_dp_detach_port(vport); - ovs_notify(reply, info, &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info, + &ovs_dp_vport_multicast_group); exit_unlock: ovs_unlock(); diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index d3d14a58aa91..4067ea41be28 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -177,6 +177,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n } extern struct notifier_block ovs_dp_device_notifier; +extern struct genl_family dp_vport_genl_family; extern struct genl_multicast_group ovs_dp_vport_multicast_group; void ovs_dp_process_received_packet(struct vport *, struct sk_buff *); diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index 3d55ead6095c..f4b66c84ea0b 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -34,13 +34,14 @@ static void dp_detach_port_notify(struct vport *vport) OVS_VPORT_CMD_DEL); ovs_dp_detach_port(vport); if (IS_ERR(notify)) { - genl_set_err(ovs_dp_get_net(dp), 0, + genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0, ovs_dp_vport_multicast_group.id, PTR_ERR(notify)); return; } - genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0, + genlmsg_multicast_netns(&dp_vport_genl_family, + ovs_dp_get_net(dp), notify, 0, ovs_dp_vport_multicast_group.id, GFP_KERNEL); } diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index ff19cbeaf607..f37dd3c5576d 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c @@ -279,7 +279,8 @@ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); d_dump(2, dev, msg, size); - genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL); + genlmsg_multicast(&wimax_gnl_family, skb, 0, + wimax_gnl_mcg.id, GFP_KERNEL); d_printf(1, dev, "CTX: genl multicast done\n"); return 0; } diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 6328afe90319..18888748e699 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -177,7 +177,8 @@ int wimax_gnl_re_state_change_send( goto out; } genlmsg_end(report_skb, header); - genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL); + genlmsg_multicast(&wimax_gnl_family, report_skb, 0, + wimax_gnl_mcg.id, GFP_KERNEL); out: d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n", wimax_dev, report_skb, result); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1b6c5dd4dccf..f20edfd2e1f0 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6868,7 +6868,7 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) nla_nest_end(skb, data); genlmsg_end(skb, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, nl80211_testmode_mcgrp.id, gfp); } EXPORT_SYMBOL(cfg80211_testmode_event); @@ -9597,7 +9597,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); } @@ -9707,7 +9707,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); } @@ -9726,7 +9726,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); } @@ -9745,7 +9745,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); } @@ -9764,7 +9764,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); } @@ -9782,7 +9782,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL); } @@ -9837,8 +9837,8 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) genlmsg_end(msg, hdr); rcu_read_lock(); - genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, - GFP_ATOMIC); + genlmsg_multicast_allns(&nl80211_fam, msg, 0, + nl80211_regulatory_mcgrp.id, GFP_ATOMIC); rcu_read_unlock(); return; @@ -9873,7 +9873,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -9961,7 +9961,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10017,7 +10017,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10056,7 +10056,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10094,7 +10094,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); return; @@ -10128,7 +10128,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10169,7 +10169,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10208,7 +10208,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10261,8 +10261,8 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, genlmsg_end(msg, hdr); rcu_read_lock(); - genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id, - GFP_ATOMIC); + genlmsg_multicast_allns(&nl80211_fam, msg, 0, + nl80211_regulatory_mcgrp.id, GFP_ATOMIC); rcu_read_unlock(); return; @@ -10307,7 +10307,7 @@ static void nl80211_send_remain_on_chan_event( genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10362,7 +10362,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, return; } - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); } EXPORT_SYMBOL(cfg80211_new_sta); @@ -10392,7 +10392,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10428,7 +10428,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10590,7 +10590,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10639,7 +10639,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10684,7 +10684,7 @@ static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10742,7 +10742,7 @@ nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10789,7 +10789,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10866,7 +10866,7 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10915,7 +10915,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -10962,7 +10962,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -11002,7 +11002,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -11154,7 +11154,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -11196,7 +11196,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, gfp); return; @@ -11279,7 +11279,7 @@ void cfg80211_ft_event(struct net_device *netdev, genlmsg_end(msg, hdr); - genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); } EXPORT_SYMBOL(cfg80211_ft_event); -- cgit v1.2.3 From 2a94fe48f32ccf7321450a2cc07f2b724a444e5b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Nov 2013 15:19:39 +0100 Subject: genetlink: make multicast groups const, prevent abuse Register generic netlink multicast groups as an array with the family and give them contiguous group IDs. Then instead of passing the global group ID to the various functions that send messages, pass the ID relative to the family - for most families that's just 0 because the only have one group. This avoids the list_head and ID in each group, adding a new field for the mcast group ID offset to the family. At the same time, this allows us to prevent abusing groups again like the quota and dropmon code did, since we can now check that a family only uses a group it owns. Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- drivers/acpi/event.c | 26 ++-- drivers/net/team/team.c | 25 +--- drivers/thermal/thermal_core.c | 24 ++-- fs/quota/netlink.c | 15 +-- include/linux/genl_magic_func.h | 49 +++---- include/net/genetlink.h | 48 ++++--- net/core/drop_monitor.c | 18 +-- net/hsr/hsr_netlink.c | 19 +-- net/ieee802154/ieee802154.h | 6 +- net/ieee802154/netlink.c | 26 ++-- net/ieee802154/nl-mac.c | 22 +--- net/netlink/genetlink.c | 278 ++++++++++++++++++++++++---------------- net/nfc/netlink.c | 51 +++----- net/openvswitch/datapath.c | 43 +++---- net/openvswitch/dp_notify.c | 6 +- net/wimax/op-msg.c | 3 +- net/wimax/stack.c | 21 ++- net/wimax/wimax-internal.h | 1 - net/wireless/nl80211.c | 129 ++++++++----------- 19 files changed, 377 insertions(+), 433 deletions(-) (limited to 'include') diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 68a8755202ec..aeb5aa6ce068 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -78,15 +78,17 @@ enum { #define ACPI_GENL_VERSION 0x01 #define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group" +static const struct genl_multicast_group acpi_event_mcgrps[] = { + { .name = ACPI_GENL_MCAST_GROUP_NAME, }, +}; + static struct genl_family acpi_event_genl_family = { .id = GENL_ID_GENERATE, .name = ACPI_GENL_FAMILY_NAME, .version = ACPI_GENL_VERSION, .maxattr = ACPI_GENL_ATTR_MAX, -}; - -static struct genl_multicast_group acpi_event_mcgrp = { - .name = ACPI_GENL_MCAST_GROUP_NAME, + .mcgrps = acpi_event_mcgrps, + .n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps), }; int acpi_bus_generate_netlink_event(const char *device_class, @@ -146,8 +148,7 @@ int acpi_bus_generate_netlink_event(const char *device_class, return result; } - genlmsg_multicast(&acpi_event_genl_family, - skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC); return 0; } @@ -155,18 +156,7 @@ EXPORT_SYMBOL(acpi_bus_generate_netlink_event); static int acpi_event_genetlink_init(void) { - int result; - - result = genl_register_family(&acpi_event_genl_family); - if (result) - return result; - - result = genl_register_mc_group(&acpi_event_genl_family, - &acpi_event_mcgrp); - if (result) - genl_unregister_family(&acpi_event_genl_family); - - return result; + return genl_register_family(&acpi_event_genl_family); } #else diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 2721e29935a6..0715de50b3dc 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2670,16 +2670,15 @@ static const struct genl_ops team_nl_ops[] = { }, }; -static struct genl_multicast_group team_change_event_mcgrp = { - .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, +static const struct genl_multicast_group team_nl_mcgrps[] = { + { .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, }, }; static int team_nl_send_multicast(struct sk_buff *skb, struct team *team, u32 portid) { return genlmsg_multicast_netns(&team_nl_family, dev_net(team->dev), - skb, 0, team_change_event_mcgrp.id, - GFP_KERNEL); + skb, 0, 0, GFP_KERNEL); } static int team_nl_send_event_options_get(struct team *team, @@ -2698,22 +2697,8 @@ static int team_nl_send_event_port_get(struct team *team, static int team_nl_init(void) { - int err; - - err = genl_register_family_with_ops(&team_nl_family, team_nl_ops); - if (err) - return err; - - err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp); - if (err) - goto err_change_event_grp_reg; - - return 0; - -err_change_event_grp_reg: - genl_unregister_family(&team_nl_family); - - return err; + return genl_register_family_with_ops_groups(&team_nl_family, team_nl_ops, + team_nl_mcgrps); } static void team_nl_fini(void) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 2570a944fffc..19edd6124ca3 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1606,15 +1606,17 @@ exit: EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); #ifdef CONFIG_NET +static const struct genl_multicast_group thermal_event_mcgrps[] = { + { .name = THERMAL_GENL_MCAST_GROUP_NAME, }, +}; + static struct genl_family thermal_event_genl_family = { .id = GENL_ID_GENERATE, .name = THERMAL_GENL_FAMILY_NAME, .version = THERMAL_GENL_VERSION, .maxattr = THERMAL_GENL_ATTR_MAX, -}; - -static struct genl_multicast_group thermal_event_mcgrp = { - .name = THERMAL_GENL_MCAST_GROUP_NAME, + .mcgrps = thermal_event_mcgrps, + .n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps), }; int thermal_generate_netlink_event(struct thermal_zone_device *tz, @@ -1676,7 +1678,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz, } result = genlmsg_multicast(&thermal_event_genl_family, skb, 0, - thermal_event_mcgrp.id, GFP_ATOMIC); + 0, GFP_ATOMIC); if (result) dev_err(&tz->device, "Failed to send netlink event:%d", result); @@ -1686,17 +1688,7 @@ EXPORT_SYMBOL_GPL(thermal_generate_netlink_event); static int genetlink_init(void) { - int result; - - result = genl_register_family(&thermal_event_genl_family); - if (result) - return result; - - result = genl_register_mc_group(&thermal_event_genl_family, - &thermal_event_mcgrp); - if (result) - genl_unregister_family(&thermal_event_genl_family); - return result; + return genl_register_family(&thermal_event_genl_family); } static void genetlink_exit(void) diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index a5b5eddf6603..72d29177998e 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c @@ -9,6 +9,10 @@ #include #include +static const struct genl_multicast_group quota_mcgrps[] = { + { .name = "events", }, +}; + /* Netlink family structure for quota */ static struct genl_family quota_genl_family = { /* @@ -22,10 +26,8 @@ static struct genl_family quota_genl_family = { .name = "VFS_DQUOT", .version = 1, .maxattr = QUOTA_NL_A_MAX, -}; - -static struct genl_multicast_group quota_mcgrp = { - .name = "events", + .mcgrps = quota_mcgrps, + .n_mcgrps = ARRAY_SIZE(quota_mcgrps), }; /** @@ -88,7 +90,7 @@ void quota_send_warning(struct kqid qid, dev_t dev, goto attr_err_out; genlmsg_end(skb, msg_head); - genlmsg_multicast("a_genl_family, skb, 0, quota_mcgrp.id, GFP_NOFS); + genlmsg_multicast("a_genl_family, skb, 0, 0, GFP_NOFS); return; attr_err_out: printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); @@ -102,9 +104,6 @@ static int __init quota_init(void) if (genl_register_family("a_genl_family) != 0) printk(KERN_ERR "VFS: Failed to create quota netlink interface.\n"); - if (genl_register_mc_group("a_genl_family, "a_mcgrp)) - printk(KERN_ERR - "VFS: Failed to register quota mcast group.\n"); return 0; }; diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h index 5b9b8ae6748b..c0894dd8827b 100644 --- a/include/linux/genl_magic_func.h +++ b/include/linux/genl_magic_func.h @@ -273,49 +273,40 @@ static struct genl_family ZZZ_genl_family __read_mostly = { * Magic: define multicast groups * Magic: define multicast group registration helper */ +#define ZZZ_genl_mcgrps CONCAT_(GENL_MAGIC_FAMILY, _genl_mcgrps) +static const struct genl_multicast_group ZZZ_genl_mcgrps[] = { +#undef GENL_mc_group +#define GENL_mc_group(group) { .name = #group, }, +#include GENL_MAGIC_INCLUDE_FILE +}; + +enum CONCAT_(GENL_MAGIC_FAMILY, group_ids) { +#undef GENL_mc_group +#define GENL_mc_group(group) CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group), +#include GENL_MAGIC_INCLUDE_FILE +}; + #undef GENL_mc_group #define GENL_mc_group(group) \ -static struct genl_multicast_group \ -CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group) __read_mostly = { \ - .name = #group, \ -}; \ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)( \ struct sk_buff *skb, gfp_t flags) \ { \ unsigned int group_id = \ - CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id; \ - if (!group_id) \ - return -EINVAL; \ + CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group); \ return genlmsg_multicast(&ZZZ_genl_family, skb, 0, \ group_id, flags); \ } #include GENL_MAGIC_INCLUDE_FILE -int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void) -{ - int err = genl_register_family_with_ops(&ZZZ_genl_family, ZZZ_genl_ops); - if (err) - return err; -#undef GENL_mc_group -#define GENL_mc_group(group) \ - err = genl_register_mc_group(&ZZZ_genl_family, \ - &CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group)); \ - if (err) \ - goto fail; \ - else \ - pr_info("%s: mcg %s: %u\n", #group, \ - __stringify(GENL_MAGIC_FAMILY), \ - CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id); - -#include GENL_MAGIC_INCLUDE_FILE - #undef GENL_mc_group #define GENL_mc_group(group) - return 0; -fail: - genl_unregister_family(&ZZZ_genl_family); - return err; + +int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void) +{ + return genl_register_family_with_ops_groups(&ZZZ_genl_family, \ + ZZZ_genl_ops, \ + ZZZ_genl_mcgrps); } void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 60aef0df386b..ace4abf118d7 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -10,14 +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 */ struct genl_multicast_group { - struct list_head list; /* private */ char name[GENL_NAMSIZ]; - u32 id; }; struct genl_ops; @@ -38,7 +33,9 @@ struct genl_info; * undo operations done by pre_doit, for example release locks * @attrbuf: buffer to store parsed attributes * @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) */ @@ -58,9 +55,11 @@ struct genl_family { struct genl_info *info); struct nlattr ** attrbuf; /* 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; }; @@ -150,22 +149,30 @@ static inline int genl_register_family(struct genl_family *family) * * Return 0 on success or a negative error code. */ -static inline int _genl_register_family_with_ops(struct genl_family *family, - const struct genl_ops *ops, - size_t n_ops) +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; family->ops = ops; family->n_ops = n_ops; + family->mcgrps = mcgrps; + family->n_mcgrps = n_mcgrps; return __genl_register_family(family); } -#define genl_register_family_with_ops(family, ops) \ - _genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops)) +#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); -int genl_register_mc_group(struct genl_family *family, - struct genl_multicast_group *grp); void genl_notify(struct genl_family *family, struct sk_buff *skb, struct net *net, u32 portid, u32 group, struct nlmsghdr *nlh, gfp_t flags); @@ -251,13 +258,16 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) * @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 genl_family *family, struct net *net, struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { + if (group >= family->n_mcgrps) + return -EINVAL; + group = family->mcgrp_offset + group; return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); } @@ -266,13 +276,16 @@ static inline int genlmsg_multicast_netns(struct genl_family *family, * @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 genl_family *family, struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { + if (group >= family->n_mcgrps) + return -EINVAL; + group = family->mcgrp_offset + group; return genlmsg_multicast_netns(family, &init_net, skb, portid, group, flags); } @@ -282,7 +295,7 @@ static inline int genlmsg_multicast(struct genl_family *family, * @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(). @@ -365,6 +378,7 @@ static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) * @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 diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 1eab1dc48821..95897183226e 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -106,8 +106,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data) return skb; } -static struct genl_multicast_group dm_mcgrp = { - .name = "events", +static struct genl_multicast_group dropmon_mcgrps[] = { + { .name = "events", }, }; static void send_dm_alert(struct work_struct *work) @@ -121,7 +121,7 @@ static void send_dm_alert(struct work_struct *work) if (skb) genlmsg_multicast(&net_drop_monitor_family, skb, 0, - dm_mcgrp.id, GFP_KERNEL); + 0, GFP_KERNEL); } /* @@ -369,19 +369,13 @@ static int __init init_net_drop_monitor(void) return -ENOSPC; } - rc = genl_register_family_with_ops(&net_drop_monitor_family, - dropmon_ops); + rc = genl_register_family_with_ops_groups(&net_drop_monitor_family, + dropmon_ops, dropmon_mcgrps); if (rc) { pr_err("Could not create drop monitor netlink family\n"); return rc; } - - rc = genl_register_mc_group(&net_drop_monitor_family, &dm_mcgrp); - if (rc) { - pr_err("Failed to register drop monitor mcast group\n"); - goto out_unreg; - } - WARN_ON(dm_mcgrp.id != NET_DM_GRP_ALERT); + WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT); rc = register_netdevice_notifier(&dropmon_net_notifier); if (rc < 0) { diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 0009416c08c2..5325af85eea6 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c @@ -90,8 +90,8 @@ static struct genl_family hsr_genl_family = { .maxattr = HSR_A_MAX, }; -static struct genl_multicast_group hsr_network_genl_mcgrp = { - .name = "hsr-network", +static const struct genl_multicast_group hsr_mcgrps[] = { + { .name = "hsr-network", }, }; @@ -129,8 +129,7 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN], goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_multicast(&hsr_genl_family, skb, 0, - hsr_network_genl_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC); return; @@ -164,8 +163,7 @@ void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN]) goto nla_put_failure; genlmsg_end(skb, msg_head); - genlmsg_multicast(&hsr_genl_family, skb, 0, - hsr_network_genl_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC); return; @@ -416,18 +414,13 @@ int __init hsr_netlink_init(void) if (rc) goto fail_rtnl_link_register; - rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops); + rc = genl_register_family_with_ops_groups(&hsr_genl_family, hsr_ops, + hsr_mcgrps); if (rc) goto fail_genl_register_family; - rc = genl_register_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp); - if (rc) - goto fail_genl_register_mc_group; - return 0; -fail_genl_register_mc_group: - genl_unregister_family(&hsr_genl_family); fail_genl_register_family: rtnl_link_unregister(&hsr_link_ops); fail_rtnl_link_register: diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 14d5dab4436f..cee4425b9956 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h @@ -54,8 +54,10 @@ int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb); int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info); int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info); -extern struct genl_multicast_group ieee802154_coord_mcgrp; -extern struct genl_multicast_group ieee802154_beacon_mcgrp; +enum ieee802154_mcgrp_ids { + IEEE802154_COORD_MCGRP, + IEEE802154_BEACON_MCGRP, +}; int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info); int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info); diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 5172f467a383..43f1b2bf469f 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c @@ -125,25 +125,17 @@ static const struct genl_ops ieee8021154_ops[] = { ieee802154_dump_iface), }; -int __init ieee802154_nl_init(void) -{ - int rc; - - rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops); - if (rc) - return rc; +static const struct genl_multicast_group ieee802154_mcgrps[] = { + [IEEE802154_COORD_MCGRP] = { .name = IEEE802154_MCAST_COORD_NAME, }, + [IEEE802154_BEACON_MCGRP] = { .name = IEEE802154_MCAST_BEACON_NAME, }, +}; - rc = genl_register_mc_group(&nl802154_family, &ieee802154_coord_mcgrp); - if (rc) - goto fail; - rc = genl_register_mc_group(&nl802154_family, &ieee802154_beacon_mcgrp); - if (rc) - goto fail; - return 0; -fail: - genl_unregister_family(&nl802154_family); - return rc; +int __init ieee802154_nl_init(void) +{ + return genl_register_family_with_ops_groups(&nl802154_family, + ieee8021154_ops, + ieee802154_mcgrps); } void __exit ieee802154_nl_exit(void) diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index 28d493032132..ba5c1e002f37 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c @@ -39,14 +39,6 @@ #include "ieee802154.h" -struct genl_multicast_group ieee802154_coord_mcgrp = { - .name = IEEE802154_MCAST_COORD_NAME, -}; - -struct genl_multicast_group ieee802154_beacon_mcgrp = { - .name = IEEE802154_MCAST_BEACON_NAME, -}; - int ieee802154_nl_assoc_indic(struct net_device *dev, struct ieee802154_addr *addr, u8 cap) { @@ -72,7 +64,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -98,7 +90,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -133,7 +125,7 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev, } if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -157,7 +149,7 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) dev->dev_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -183,7 +175,7 @@ int ieee802154_nl_beacon_indic(struct net_device *dev, nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) || nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -214,7 +206,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, (edl && nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl))) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); @@ -238,7 +230,7 @@ int ieee802154_nl_start_confirm(struct net_device *dev, u8 status) dev->dev_addr) || nla_put_u8(msg, IEEE802154_ATTR_STATUS, status)) goto nla_put_failure; - return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id); + return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); nla_put_failure: nlmsg_free(msg); diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 36e3a86cacf6..7dbc4f732c75 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -69,16 +69,20 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE]; * abuses the API and thinks it can statically use group 1. * That group will typically conflict with other groups that * any proper users use. + * Bit 16 is marked as used since it's used for generic netlink + * and the code no longer marks pre-reserved IDs as used. * Bit 17 is marked as already used since the VFS quota code * also abused this API and relied on family == group ID, we * cater to that by giving it a static family and group ID. */ -static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT); +static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) | + BIT(GENL_ID_VFS_DQUOT); static unsigned long *mc_groups = &mc_group_start; static unsigned long mc_groups_longs = 1; static int genl_ctrl_event(int event, struct genl_family *family, - struct genl_multicast_group *grp); + const struct genl_multicast_group *grp, + int grp_id); static inline unsigned int genl_family_hash(unsigned int id) { @@ -144,66 +148,110 @@ static u16 genl_generate_id(void) return 0; } -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) +static int genl_allocate_reserve_groups(int n_groups, int *first_id) { - int id; unsigned long *new_groups; - int err = 0; + int start = 0; + int i; + int id; + bool fits; + + do { + if (start == 0) + id = find_first_zero_bit(mc_groups, + mc_groups_longs * + BITS_PER_LONG); + else + id = find_next_zero_bit(mc_groups, + mc_groups_longs * BITS_PER_LONG, + start); + + fits = true; + for (i = id; + i < min_t(int, id + n_groups, + mc_groups_longs * BITS_PER_LONG); + i++) { + if (test_bit(i, mc_groups)) { + start = i; + fits = false; + break; + } + } - BUG_ON(grp->name[0] == '\0'); - BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL); + if (id >= mc_groups_longs * BITS_PER_LONG) { + unsigned long new_longs = mc_groups_longs + + BITS_TO_LONGS(n_groups); + size_t nlen = new_longs * sizeof(unsigned long); + + if (mc_groups == &mc_group_start) { + new_groups = kzalloc(nlen, GFP_KERNEL); + if (!new_groups) + return -ENOMEM; + mc_groups = new_groups; + *mc_groups = mc_group_start; + } else { + new_groups = krealloc(mc_groups, nlen, + GFP_KERNEL); + if (!new_groups) + return -ENOMEM; + mc_groups = new_groups; + for (i = 0; i < BITS_TO_LONGS(n_groups); i++) + mc_groups[mc_groups_longs + i] = 0; + } + mc_groups_longs = new_longs; + } + } while (!fits); - genl_lock_all(); + for (i = id; i < id + n_groups; i++) + set_bit(i, mc_groups); + *first_id = id; + return 0; +} + +static struct genl_family genl_ctrl; + +static int genl_validate_assign_mc_groups(struct genl_family *family) +{ + int first_id; + int n_groups = family->n_mcgrps; + int err, i; + bool groups_allocated = false; + + if (!n_groups) + return 0; + + for (i = 0; i < n_groups; i++) { + const struct genl_multicast_group *grp = &family->mcgrps[i]; + + if (WARN_ON(grp->name[0] == '\0')) + return -EINVAL; + if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL)) + return -EINVAL; + } /* special-case our own group and hacks */ - if (grp == ¬ify_grp) - id = GENL_ID_CTRL; - else if (strcmp(family->name, "NET_DM") == 0) - id = 1; - else if (strcmp(family->name, "VFS_DQUOT") == 0) - id = GENL_ID_VFS_DQUOT; - 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++; + if (family == &genl_ctrl) { + first_id = GENL_ID_CTRL; + BUG_ON(n_groups != 1); + } else if (strcmp(family->name, "NET_DM") == 0) { + first_id = 1; + BUG_ON(n_groups != 1); + } else if (strcmp(family->name, "VFS_DQUOT") == 0) { + first_id = GENL_ID_VFS_DQUOT; + BUG_ON(n_groups != 1); + } else { + groups_allocated = true; + err = genl_allocate_reserve_groups(n_groups, &first_id); + if (err) + return err; } + family->mcgrp_offset = first_id; + + /* if still initializing, can't and don't need to to realloc bitmaps */ + if (!init_net.genl_sock) + return 0; + if (family->netnsok) { struct net *net; @@ -219,9 +267,7 @@ int genl_register_mc_group(struct genl_family *family, * number of _possible_ groups has been * increased on some sockets which is ok. */ - rcu_read_unlock(); - netlink_table_ungrab(); - goto out; + break; } } rcu_read_unlock(); @@ -229,46 +275,39 @@ int genl_register_mc_group(struct genl_family *family, } else { err = netlink_change_ngroups(init_net.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); + if (groups_allocated && err) { + for (i = 0; i < family->n_mcgrps; i++) + clear_bit(family->mcgrp_offset + i, mc_groups); + } - genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, grp); - out: - genl_unlock_all(); return err; } -EXPORT_SYMBOL(genl_register_mc_group); -static void __genl_unregister_mc_group(struct genl_family *family, - struct genl_multicast_group *grp) +static void genl_unregister_mc_groups(struct genl_family *family) { struct net *net; + int i; netlink_table_grab(); rcu_read_lock(); - for_each_net_rcu(net) - __netlink_clear_multicast_users(net->genl_sock, grp->id); + for_each_net_rcu(net) { + for (i = 0; i < family->n_mcgrps; i++) + __netlink_clear_multicast_users( + net->genl_sock, family->mcgrp_offset + i); + } rcu_read_unlock(); netlink_table_ungrab(); - if (grp->id != 1) - clear_bit(grp->id, mc_groups); - list_del(&grp->list); - genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, grp); - grp->id = 0; -} - -static void genl_unregister_mc_groups(struct genl_family *family) -{ - struct genl_multicast_group *grp, *tmp; + for (i = 0; i < family->n_mcgrps; i++) { + int grp_id = family->mcgrp_offset + i; - list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) - __genl_unregister_mc_group(family, grp); + if (grp_id != 1) + clear_bit(grp_id, mc_groups); + genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, + &family->mcgrps[i], grp_id); + } } static int genl_validate_ops(struct genl_family *family) @@ -314,7 +353,7 @@ static int genl_validate_ops(struct genl_family *family) */ int __genl_register_family(struct genl_family *family) { - int err = -EINVAL; + int err = -EINVAL, i; if (family->id && family->id < GENL_MIN_ID) goto errout; @@ -326,8 +365,6 @@ int __genl_register_family(struct genl_family *family) if (err) return err; - INIT_LIST_HEAD(&family->mcast_groups); - genl_lock_all(); if (genl_family_find_byname(family->name)) { @@ -359,10 +396,18 @@ int __genl_register_family(struct genl_family *family) } else family->attrbuf = NULL; + err = genl_validate_assign_mc_groups(family); + if (err) + goto errout_locked; + list_add_tail(&family->family_list, genl_family_chain(family->id)); genl_unlock_all(); - genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL); + /* send all events */ + genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0); + for (i = 0; i < family->n_mcgrps; i++) + genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, + &family->mcgrps[i], family->mcgrp_offset + i); return 0; @@ -398,7 +443,7 @@ int genl_unregister_family(struct genl_family *family) genl_unlock_all(); kfree(family->attrbuf); - genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL); + genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); return 0; } @@ -658,23 +703,26 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, nla_nest_end(skb, nla_ops); } - if (!list_empty(&family->mcast_groups)) { - struct genl_multicast_group *grp; + if (family->n_mcgrps) { struct nlattr *nla_grps; - int idx = 1; + int i; nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); if (nla_grps == NULL) goto nla_put_failure; - list_for_each_entry(grp, &family->mcast_groups, list) { + for (i = 0; i < family->n_mcgrps; i++) { struct nlattr *nest; + const struct genl_multicast_group *grp; - nest = nla_nest_start(skb, idx++); + grp = &family->mcgrps[i]; + + nest = nla_nest_start(skb, i + 1); if (nest == NULL) goto nla_put_failure; - if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id) || + if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, + family->mcgrp_offset + i) || nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME, grp->name)) goto nla_put_failure; @@ -692,9 +740,9 @@ nla_put_failure: } static int ctrl_fill_mcgrp_info(struct genl_family *family, - struct genl_multicast_group *grp, u32 portid, - u32 seq, u32 flags, struct sk_buff *skb, - u8 cmd) + const struct genl_multicast_group *grp, + int grp_id, u32 portid, u32 seq, u32 flags, + struct sk_buff *skb, u8 cmd) { void *hdr; struct nlattr *nla_grps; @@ -716,7 +764,7 @@ static int ctrl_fill_mcgrp_info(struct genl_family *family, if (nest == NULL) goto nla_put_failure; - if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id) || + if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) || nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME, grp->name)) goto nla_put_failure; @@ -782,9 +830,10 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, return skb; } -static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_family *family, - struct genl_multicast_group *grp, - u32 portid, int seq, u8 cmd) +static struct sk_buff * +ctrl_build_mcgrp_msg(struct genl_family *family, + const struct genl_multicast_group *grp, + int grp_id, u32 portid, int seq, u8 cmd) { struct sk_buff *skb; int err; @@ -793,7 +842,8 @@ static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_family *family, if (skb == NULL) return ERR_PTR(-ENOBUFS); - err = ctrl_fill_mcgrp_info(family, grp, portid, seq, 0, skb, cmd); + err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid, + seq, 0, skb, cmd); if (err < 0) { nlmsg_free(skb); return ERR_PTR(err); @@ -856,7 +906,8 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) } static int genl_ctrl_event(int event, struct genl_family *family, - struct genl_multicast_group *grp) + const struct genl_multicast_group *grp, + int grp_id) { struct sk_buff *msg; @@ -873,7 +924,7 @@ static int genl_ctrl_event(int event, struct genl_family *family, case CTRL_CMD_NEWMCAST_GRP: case CTRL_CMD_DELMCAST_GRP: BUG_ON(!grp); - msg = ctrl_build_mcgrp_msg(family, grp, 0, 0, event); + msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event); break; default: return -EINVAL; @@ -884,11 +935,11 @@ static int genl_ctrl_event(int event, struct genl_family *family, if (!family->netnsok) { genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0, - GENL_ID_CTRL, GFP_KERNEL); + 0, GFP_KERNEL); } else { rcu_read_lock(); genlmsg_multicast_allns(&genl_ctrl, msg, 0, - GENL_ID_CTRL, GFP_ATOMIC); + 0, GFP_ATOMIC); rcu_read_unlock(); } @@ -904,8 +955,8 @@ static struct genl_ops genl_ctrl_ops[] = { }, }; -static struct genl_multicast_group notify_grp = { - .name = "notify", +static struct genl_multicast_group genl_ctrl_groups[] = { + { .name = "notify", }, }; static int __net_init genl_pernet_init(struct net *net) @@ -945,7 +996,8 @@ static int __init genl_init(void) for (i = 0; i < GENL_FAM_TAB_SIZE; i++) INIT_LIST_HEAD(&family_ht[i]); - err = genl_register_family_with_ops(&genl_ctrl, genl_ctrl_ops); + err = genl_register_family_with_ops_groups(&genl_ctrl, genl_ctrl_ops, + genl_ctrl_groups); if (err < 0) goto problem; @@ -953,10 +1005,6 @@ static int __init genl_init(void) if (err) goto problem; - err = genl_register_mc_group(&genl_ctrl, ¬ify_grp); - if (err < 0) - goto problem; - return 0; problem: @@ -997,6 +1045,9 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, u32 portid, unsigned int group, gfp_t flags) { + if (group >= family->n_mcgrps) + return -EINVAL; + group = family->mcgrp_offset + group; return genlmsg_mcast(skb, portid, group, flags); } EXPORT_SYMBOL(genlmsg_multicast_allns); @@ -1011,6 +1062,9 @@ void genl_notify(struct genl_family *family, if (nlh) report = nlmsg_report(nlh); + if (group >= family->n_mcgrps) + return; + group = family->mcgrp_offset + group; nlmsg_notify(sk, skb, portid, group, report, flags); } EXPORT_SYMBOL(genl_notify); diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 3092df313fb1..a9b2342d5253 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -30,8 +30,8 @@ #include "nfc.h" #include "llcp.h" -static struct genl_multicast_group nfc_genl_event_mcgrp = { - .name = NFC_GENL_MCAST_EVENT_NAME, +static const struct genl_multicast_group nfc_genl_mcgrps[] = { + { .name = NFC_GENL_MCAST_EVENT_NAME, }, }; static struct genl_family nfc_genl_family = { @@ -194,8 +194,7 @@ int nfc_genl_targets_found(struct nfc_dev *dev) genlmsg_end(msg, hdr); - return genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_ATOMIC); + return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); nla_put_failure: genlmsg_cancel(msg, hdr); @@ -224,8 +223,7 @@ int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -257,8 +255,7 @@ int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -288,8 +285,7 @@ int nfc_genl_tm_deactivated(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -322,8 +318,7 @@ int nfc_genl_device_added(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -353,8 +348,7 @@ int nfc_genl_device_removed(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -420,8 +414,7 @@ int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list) genlmsg_end(msg, hdr); - return genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_ATOMIC); + return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); nla_put_failure: genlmsg_cancel(msg, hdr); @@ -455,8 +448,7 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -487,8 +479,7 @@ int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -609,8 +600,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx, dev->dep_link_up = true; - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); return 0; @@ -642,8 +632,7 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_ATOMIC); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC); return 0; @@ -1148,8 +1137,7 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name, genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); return 0; @@ -1320,8 +1308,7 @@ static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err) genlmsg_end(msg, hdr); - genlmsg_multicast(&nfc_genl_family, msg, 0, - nfc_genl_event_mcgrp.id, GFP_KERNEL); + genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL); kfree(ctx); @@ -1549,15 +1536,15 @@ int __init nfc_genl_init(void) { int rc; - rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops); + rc = genl_register_family_with_ops_groups(&nfc_genl_family, + nfc_genl_ops, + nfc_genl_mcgrps); if (rc) return rc; - rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp); - netlink_register_notifier(&nl_notifier); - return rc; + return 0; } /** diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 5c19846b1d2a..1de4d281e3f1 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -62,11 +62,10 @@ int ovs_net_id __read_mostly; static void ovs_notify(struct genl_family *family, - struct sk_buff *skb, struct genl_info *info, - struct genl_multicast_group *grp) + struct sk_buff *skb, struct genl_info *info) { genl_notify(family, skb, genl_info_net(info), info->snd_portid, - grp->id, info->nlhdr, GFP_KERNEL); + 0, info->nlhdr, GFP_KERNEL); } /** @@ -878,11 +877,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); if (!IS_ERR(reply)) - ovs_notify(&dp_flow_genl_family, reply, info, - &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, reply, info); else genl_set_err(&dp_flow_genl_family, sock_net(skb->sk), 0, - ovs_dp_flow_multicast_group.id, PTR_ERR(reply)); + 0, PTR_ERR(reply)); return 0; err_flow_free: @@ -992,8 +990,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) ovs_flow_free(flow, true); ovs_unlock(); - ovs_notify(&dp_flow_genl_family, reply, info, - &ovs_dp_flow_multicast_group); + ovs_notify(&dp_flow_genl_family, reply, info); return 0; unlock: ovs_unlock(); @@ -1240,8 +1237,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) ovs_unlock(); - ovs_notify(&dp_datapath_genl_family, reply, info, - &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info); return 0; err_destroy_local_port: @@ -1306,8 +1302,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) __dp_destroy(dp); ovs_unlock(); - ovs_notify(&dp_datapath_genl_family, reply, info, - &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info); return 0; unlock: @@ -1332,14 +1327,13 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(reply)) { err = PTR_ERR(reply); genl_set_err(&dp_datapath_genl_family, sock_net(skb->sk), 0, - ovs_dp_datapath_multicast_group.id, err); + 0, err); err = 0; goto unlock; } ovs_unlock(); - ovs_notify(&dp_datapath_genl_family, reply, info, - &ovs_dp_datapath_multicast_group); + ovs_notify(&dp_datapath_genl_family, reply, info); return 0; unlock: @@ -1601,8 +1595,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) goto exit_unlock; } - ovs_notify(&dp_vport_genl_family, reply, info, - &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info); exit_unlock: ovs_unlock(); @@ -1649,8 +1642,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) BUG_ON(err < 0); ovs_unlock(); - ovs_notify(&dp_vport_genl_family, reply, info, - &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info); return 0; exit_free: @@ -1687,8 +1679,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) err = 0; ovs_dp_detach_port(vport); - ovs_notify(&dp_vport_genl_family, reply, info, - &ovs_dp_vport_multicast_group); + ovs_notify(&dp_vport_genl_family, reply, info); exit_unlock: ovs_unlock(); @@ -1790,7 +1781,7 @@ struct genl_family_and_ops { struct genl_family *family; const struct genl_ops *ops; int n_ops; - struct genl_multicast_group *group; + const struct genl_multicast_group *group; }; static const struct genl_family_and_ops dp_genl_families[] = { @@ -1828,16 +1819,12 @@ static int dp_register_genl(void) f->family->ops = f->ops; f->family->n_ops = f->n_ops; + f->family->mcgrps = f->group; + f->family->n_mcgrps = f->group ? 1 : 0; err = genl_register_family(f->family); if (err) goto error; n_registered++; - - if (f->group) { - err = genl_register_mc_group(f->family, f->group); - if (err) - goto error; - } } return 0; diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index f4b66c84ea0b..2c631fe76be1 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -35,15 +35,13 @@ static void dp_detach_port_notify(struct vport *vport) ovs_dp_detach_port(vport); if (IS_ERR(notify)) { genl_set_err(&dp_vport_genl_family, ovs_dp_get_net(dp), 0, - ovs_dp_vport_multicast_group.id, - PTR_ERR(notify)); + 0, PTR_ERR(notify)); return; } genlmsg_multicast_netns(&dp_vport_genl_family, ovs_dp_get_net(dp), notify, 0, - ovs_dp_vport_multicast_group.id, - GFP_KERNEL); + 0, GFP_KERNEL); } void ovs_dp_notify_wq(struct work_struct *work) diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c index f37dd3c5576d..c278b3356f75 100644 --- a/net/wimax/op-msg.c +++ b/net/wimax/op-msg.c @@ -279,8 +279,7 @@ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); d_dump(2, dev, msg, size); - genlmsg_multicast(&wimax_gnl_family, skb, 0, - wimax_gnl_mcg.id, GFP_KERNEL); + genlmsg_multicast(&wimax_gnl_family, skb, 0, 0, GFP_KERNEL); d_printf(1, dev, "CTX: genl multicast done\n"); return 0; } diff --git a/net/wimax/stack.c b/net/wimax/stack.c index 18888748e699..ef2191b969a7 100644 --- a/net/wimax/stack.c +++ b/net/wimax/stack.c @@ -116,8 +116,9 @@ struct sk_buff *wimax_gnl_re_state_change_alloc( dev_err(dev, "RE_STCH: can't create message\n"); goto error_new; } - data = genlmsg_put(report_skb, 0, wimax_gnl_mcg.id, &wimax_gnl_family, - 0, WIMAX_GNL_RE_STATE_CHANGE); + /* FIXME: sending a group ID as the seq is wrong */ + data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset, + &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE); if (data == NULL) { dev_err(dev, "RE_STCH: can't put data into message\n"); goto error_put; @@ -177,8 +178,7 @@ int wimax_gnl_re_state_change_send( goto out; } genlmsg_end(report_skb, header); - genlmsg_multicast(&wimax_gnl_family, report_skb, 0, - wimax_gnl_mcg.id, GFP_KERNEL); + genlmsg_multicast(&wimax_gnl_family, report_skb, 0, 0, GFP_KERNEL); out: d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n", wimax_dev, report_skb, result); @@ -580,8 +580,8 @@ struct genl_family wimax_gnl_family = { .maxattr = WIMAX_GNL_ATTR_MAX, }; -struct genl_multicast_group wimax_gnl_mcg = { - .name = "msg", +static const struct genl_multicast_group wimax_gnl_mcgrps[] = { + { .name = "msg", }, }; @@ -598,21 +598,18 @@ int __init wimax_subsys_init(void) snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name), "WiMAX"); - result = genl_register_family_with_ops(&wimax_gnl_family, - wimax_gnl_ops); + result = genl_register_family_with_ops_groups(&wimax_gnl_family, + wimax_gnl_ops, + wimax_gnl_mcgrps); if (unlikely(result < 0)) { printk(KERN_ERR "cannot register generic netlink family: %d\n", result); goto error_register_family; } - result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg); - if (result < 0) - goto error_mc_group; d_fnend(4, NULL, "() = 0\n"); return 0; -error_mc_group: genl_unregister_family(&wimax_gnl_family); error_register_family: d_fnend(4, NULL, "() = %d\n", result); diff --git a/net/wimax/wimax-internal.h b/net/wimax/wimax-internal.h index 8567d3079a83..b445b82020a8 100644 --- a/net/wimax/wimax-internal.h +++ b/net/wimax/wimax-internal.h @@ -86,7 +86,6 @@ void wimax_rfkill_rm(struct wimax_dev *); /* generic netlink */ extern struct genl_family wimax_gnl_family; -extern struct genl_multicast_group wimax_gnl_mcg; /* ops */ int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f20edfd2e1f0..a1eb21073176 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -47,6 +47,25 @@ static struct genl_family nl80211_fam = { .post_doit = nl80211_post_doit, }; +/* multicast groups */ +enum nl80211_multicast_groups { + NL80211_MCGRP_CONFIG, + NL80211_MCGRP_SCAN, + NL80211_MCGRP_REGULATORY, + NL80211_MCGRP_MLME, + NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ +}; + +static const struct genl_multicast_group nl80211_mcgrps[] = { + [NL80211_MCGRP_CONFIG] = { .name = "config", }, + [NL80211_MCGRP_SCAN] = { .name = "scan", }, + [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, + [NL80211_MCGRP_MLME] = { .name = "mlme", }, +#ifdef CONFIG_NL80211_TESTMODE + [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } +#endif +}; + /* returns ERR_PTR values */ static struct wireless_dev * __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) @@ -6656,10 +6675,6 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info) #ifdef CONFIG_NL80211_TESTMODE -static struct genl_multicast_group nl80211_testmode_mcgrp = { - .name = "testmode", -}; - static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -6869,7 +6884,7 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) nla_nest_end(skb, data); genlmsg_end(skb, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, - nl80211_testmode_mcgrp.id, gfp); + NL80211_MCGRP_TESTMODE, gfp); } EXPORT_SYMBOL(cfg80211_testmode_event); #endif @@ -9566,21 +9581,6 @@ static const struct genl_ops nl80211_ops[] = { }, }; -static struct genl_multicast_group nl80211_mlme_mcgrp = { - .name = "mlme", -}; - -/* multicast groups */ -static struct genl_multicast_group nl80211_config_mcgrp = { - .name = "config", -}; -static struct genl_multicast_group nl80211_scan_mcgrp = { - .name = "scan", -}; -static struct genl_multicast_group nl80211_regulatory_mcgrp = { - .name = "regulatory", -}; - /* notification functions */ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) @@ -9598,7 +9598,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_config_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_CONFIG, GFP_KERNEL); } static int nl80211_add_scan_req(struct sk_buff *msg, @@ -9708,7 +9708,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, @@ -9727,7 +9727,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, @@ -9746,7 +9746,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, @@ -9765,7 +9765,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_SCAN, GFP_KERNEL); } void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, @@ -9783,7 +9783,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_scan_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_SCAN, GFP_KERNEL); } /* @@ -9838,7 +9838,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) rcu_read_lock(); genlmsg_multicast_allns(&nl80211_fam, msg, 0, - nl80211_regulatory_mcgrp.id, GFP_ATOMIC); + NL80211_MCGRP_REGULATORY, GFP_ATOMIC); rcu_read_unlock(); return; @@ -9874,7 +9874,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -9962,7 +9962,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10018,7 +10018,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10057,7 +10057,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10095,7 +10095,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_MLME, GFP_KERNEL); return; nla_put_failure: @@ -10129,7 +10129,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10170,7 +10170,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10209,7 +10209,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10262,7 +10262,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy, rcu_read_lock(); genlmsg_multicast_allns(&nl80211_fam, msg, 0, - nl80211_regulatory_mcgrp.id, GFP_ATOMIC); + NL80211_MCGRP_REGULATORY, GFP_ATOMIC); rcu_read_unlock(); return; @@ -10308,7 +10308,7 @@ static void nl80211_send_remain_on_chan_event( genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10363,7 +10363,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, } genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); } EXPORT_SYMBOL(cfg80211_new_sta); @@ -10393,7 +10393,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp) genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10429,7 +10429,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10591,7 +10591,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10640,7 +10640,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10685,7 +10685,7 @@ static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10743,7 +10743,7 @@ nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10790,7 +10790,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10867,7 +10867,7 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10916,7 +10916,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -10963,7 +10963,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -11003,7 +11003,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -11155,7 +11155,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; free_msg: @@ -11197,7 +11197,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, gfp); + NL80211_MCGRP_MLME, gfp); return; nla_put_failure: @@ -11280,7 +11280,7 @@ void cfg80211_ft_event(struct net_device *netdev, genlmsg_end(msg, hdr); genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, - nl80211_mlme_mcgrp.id, GFP_KERNEL); + NL80211_MCGRP_MLME, GFP_KERNEL); } EXPORT_SYMBOL(cfg80211_ft_event); @@ -11329,32 +11329,11 @@ int nl80211_init(void) { int err; - err = genl_register_family_with_ops(&nl80211_fam, nl80211_ops); + err = genl_register_family_with_ops_groups(&nl80211_fam, nl80211_ops, + nl80211_mcgrps); if (err) return err; - err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); - if (err) - goto err_out; - - err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp); - if (err) - goto err_out; - - err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp); - if (err) - goto err_out; - - err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); - if (err) - goto err_out; - -#ifdef CONFIG_NL80211_TESTMODE - err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp); - if (err) - goto err_out; -#endif - err = netlink_register_notifier(&nl80211_netlink_notifier); if (err) goto err_out; -- cgit v1.2.3