summaryrefslogtreecommitdiff
path: root/backport
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-11-21 20:51:23 +0100
committerHauke Mehrtens <hauke@hauke-m.de>2013-11-21 23:34:44 +0100
commitd7a42dd40dfb09fa980c7492f469f8a525f7df8c (patch)
tree40971930b58aeabf64af01ad2a9c10de48fab82b /backport
parentc38da7cf931df4f26692b6fe1d93131d8898aab7 (diff)
backports: support new generic netlink APIs
I recently changed the generic netlink registration and multicast group APIs to be safer. Backport these changes by implementing all the new APIs in terms of what was in the kernel before. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Diffstat (limited to 'backport')
-rw-r--r--backport/backport-include/net/genetlink.h192
-rw-r--r--backport/compat/backport-3.13.c140
-rw-r--r--backport/compat/compat-2.6.37.c115
3 files changed, 290 insertions, 157 deletions
diff --git a/backport/backport-include/net/genetlink.h b/backport/backport-include/net/genetlink.h
index 4458a10d..d1ae143f 100644
--- a/backport/backport-include/net/genetlink.h
+++ b/backport/backport-include/net/genetlink.h
@@ -13,12 +13,8 @@
#define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN)
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
-#define genl_dump_check_consistent(cb, user_hdr, family)
-#endif
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
-struct compat_genl_info {
+struct backport_genl_info {
struct genl_info *info;
u32 snd_seq;
@@ -27,9 +23,13 @@ struct compat_genl_info {
struct nlattr **attrs;
void *user_ptr[2];
};
-#define genl_info compat_genl_info
+#define genl_info LINUX_BACKPORT(genl_info)
-struct compat_genl_ops {
+/* if info gets overridden, so will family below */
+#define genlmsg_put_reply(_skb, _info, _fam, _flags, _cmd) \
+ genlmsg_put_reply(_skb, (_info)->info, &(_fam)->family, _flags, _cmd)
+
+struct backport_genl_ops {
struct genl_ops ops;
u8 cmd;
@@ -41,16 +41,50 @@ struct compat_genl_ops {
int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb);
int (*done)(struct netlink_callback *cb);
};
-#define genl_ops compat_genl_ops
+#define genl_ops LINUX_BACKPORT(genl_ops)
+
+#define genlmsg_reply(_msg, _info) genlmsg_reply(_msg, (_info)->info)
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
+#define genl_info_net(_info) genl_info_net((_info)->info)
+#endif
+#endif /* 2.6.37 */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+/*
+ * struct genl_multicast_group was made netns aware through
+ * patch "genetlink: make netns aware" by johannes, we just
+ * force this to always use the default init_net
+ */
+#define genl_info_net(x) &init_net
+/* Just use init_net for older kernels */
+#define get_net_ns_by_pid(x) &init_net
+/* net namespace is lost */
+#define genlmsg_unicast(net, skb, pid) genlmsg_unicast(skb, pid)
+#endif
-struct compat_genl_family {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,1,0)
+#define genl_dump_check_consistent(cb, user_hdr, family)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+static inline int __real_genl_register_family(struct genl_family *family)
+{
+ return genl_register_family(family);
+}
+
+/* Needed for the mcgrps pointer */
+struct backport_genl_family {
struct genl_family family;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
struct list_head list;
+#endif
unsigned int id, hdrsize, version, maxattr;
- const char *name;
+ char name[GENL_NAMSIZ];
bool netnsok;
+ bool parallel_ops;
struct nlattr **attrbuf;
@@ -59,43 +93,119 @@ struct compat_genl_family {
void (*post_doit)(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info);
-};
-
-#define genl_family compat_genl_family
-
-#define genl_register_family_with_ops compat_genl_register_family_with_ops
-
-int genl_register_family_with_ops(struct genl_family *family,
- struct genl_ops *ops, size_t n_ops);
-#define genl_unregister_family compat_genl_unregister_family
+ struct genl_multicast_group *mcgrps;
+ struct genl_ops *ops;
+ unsigned int n_mcgrps, n_ops;
+ struct module *module;
+};
+#define genl_family LINUX_BACKPORT(genl_family)
+
+int __backport_genl_register_family(struct genl_family *family);
+
+#define genl_register_family LINUX_BACKPORT(genl_register_family)
+static inline int
+genl_register_family(struct genl_family *family)
+{
+ family->module = THIS_MODULE;
+ return __backport_genl_register_family(family);
+}
+
+#define _genl_register_family_with_ops_grps \
+ _backport_genl_register_family_with_ops_grps
+static inline int
+_genl_register_family_with_ops_grps(struct genl_family *family,
+ struct genl_ops *ops, size_t n_ops,
+ struct genl_multicast_group *mcgrps,
+ size_t n_mcgrps)
+{
+ 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_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))
+
+#define genl_unregister_family backport_genl_unregister_family
int genl_unregister_family(struct genl_family *family);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
-#define genl_info_net(_info) genl_info_net((_info)->info)
+#define genl_notify(_fam, _skb, _net, _portid, _group, _nlh, _flags) \
+ genl_notify(_skb, _net, _portid, (_fam)->mcgrps[_group].id, \
+ _nlh, _flags)
+#define genlmsg_put(_skb, _pid, _seq, _fam, _flags, _cmd) \
+ genlmsg_put(_skb, _pid, _seq, &(_fam)->family, _flags, _cmd)
+#define genlmsg_nlhdr(_hdr, _fam) \
+ genlmsg_nlhdr(_hdr, &(_fam)->family)
+#ifndef genl_dump_check_consistent
+#define genl_dump_check_consistent(_cb, _hdr, _fam) \
+ genl_dump_check_consistent(_cb, _hdr, &(_fam)->family)
#endif
-
-#define genlmsg_reply(_msg, _info) genlmsg_reply(_msg, (_info)->info)
-#define genlmsg_put(_skb, _pid, _seq, _fam, _flags, _cmd) genlmsg_put(_skb, _pid, _seq, &(_fam)->family, _flags, _cmd)
-#define genl_register_mc_group(_fam, _grp) genl_register_mc_group(&(_fam)->family, _grp)
-#define genl_unregister_mc_group(_fam, _grp) genl_unregister_mc_group(&(_fam)->family, _grp)
-#endif /* < 2.6.37 */
-
+#ifndef genlmsg_put_reply /* might already be there from _info override above */
+#define genlmsg_put_reply(_skb, _info, _fam, _flags, _cmd) \
+ genlmsg_put_reply(_skb, _info, &(_fam)->family, _flags, _cmd)
+#endif
+#define genlmsg_multicast_netns LINUX_BACKPORT(genlmsg_multicast_netns)
+static inline int genlmsg_multicast_netns(struct genl_family *family,
+ struct net *net, struct sk_buff *skb,
+ u32 portid, unsigned int group,
+ gfp_t flags)
+{
+ if (WARN_ON_ONCE(group >= family->n_mcgrps))
+ return -EINVAL;
+ group = family->mcgrps[group].id;
+ return nlmsg_multicast(
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-/*
- * struct genl_multicast_group was made netns aware through
- * patch "genetlink: make netns aware" by johannes, we just
- * force this to always use the default init_net
- */
-#define genl_info_net(x) &init_net
-/* Just use init_net for older kernels */
-#define get_net_ns_by_pid(x) &init_net
-
-/* net namespace is lost */
-#define genlmsg_multicast_netns(a, b, c, d, e) genlmsg_multicast(b, c, d, e)
-#define genlmsg_multicast_allns(a, b, c, d) genlmsg_multicast(a, b, c, d)
-#define genlmsg_unicast(net, skb, pid) genlmsg_unicast(skb, pid)
+ genl_sock,
+#else
+ net->genl_sock,
#endif
+ skb, portid, group, flags);
+}
+#define genlmsg_multicast LINUX_BACKPORT(genlmsg_multicast)
+static inline int genlmsg_multicast(struct genl_family *family,
+ struct sk_buff *skb, u32 portid,
+ unsigned int group, gfp_t flags)
+{
+ if (WARN_ON_ONCE(group >= family->n_mcgrps))
+ return -EINVAL;
+ group = family->mcgrps[group].id;
+ return nlmsg_multicast(
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+ genl_sock,
+#else
+ init_net.genl_sock,
+#endif
+ skb, portid, group, flags);
+}
+static inline int
+backport_genlmsg_multicast_allns(struct genl_family *family,
+ struct sk_buff *skb, u32 portid,
+ unsigned int group, gfp_t flags)
+{
+ if (WARN_ON_ONCE(group >= family->n_mcgrps))
+ return -EINVAL;
+ group = family->mcgrps[group].id;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
+ return nlmsg_multicast(genl_sock, skb, portid, group, flags);
+#else
+ return genlmsg_multicast_allns(skb, portid, group, flags);
+#endif
+}
+#define genlmsg_multicast_allns LINUX_BACKPORT(genlmsg_multicast_allns)
+
+#define __genl_const
+#else /* < 3.13 */
+#define __genl_const const
+#endif /* < 3.13 */
#endif /* __BACKPORT_NET_GENETLINK_H */
diff --git a/backport/compat/backport-3.13.c b/backport/compat/backport-3.13.c
index 91fb4804..77eefef9 100644
--- a/backport/compat/backport-3.13.c
+++ b/backport/compat/backport-3.13.c
@@ -8,10 +8,11 @@
* published by the Free Software Foundation.
*/
#include <linux/version.h>
+#include <linux/kernel.h>
+#include <net/genetlink.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0))
#ifdef CONFIG_REGULATOR
-#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regulator/driver.h>
#include <linux/device.h>
@@ -83,3 +84,140 @@ void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(devm_regulator_unregister);
#endif /* CONFIG_REGULATOR */
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)) */
+
+/************* generic netlink backport *****************/
+
+#undef genl_register_family
+#undef genl_unregister_family
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#undef genl_info
+static LIST_HEAD(backport_nl_fam);
+
+static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
+{
+ struct genl_ops *ops;
+
+ list_for_each_entry(ops, &family->family.ops_list, ops.ops_list)
+ if (ops->cmd == cmd)
+ return ops;
+
+ return NULL;
+}
+
+static int nl_doit_wrapper(struct sk_buff *skb, struct genl_info *info)
+{
+ struct backport_genl_info backport_info;
+ struct genl_family *family;
+ struct genl_ops *ops;
+ int err;
+
+ list_for_each_entry(family, &backport_nl_fam, list) {
+ if (family->id == info->nlhdr->nlmsg_type)
+ goto found;
+ }
+ return -ENOENT;
+
+found:
+ ops = genl_get_cmd(info->genlhdr->cmd, family);
+ if (!ops)
+ return -ENOENT;
+
+ memset(&backport_info.user_ptr, 0, sizeof(backport_info.user_ptr));
+ backport_info.info = info;
+#define __copy(_field) backport_info._field = info->_field
+ __copy(snd_seq);
+ __copy(snd_pid);
+ __copy(genlhdr);
+ __copy(attrs);
+#undef __copy
+ if (family->pre_doit) {
+ err = family->pre_doit(ops, skb, &backport_info);
+ if (err)
+ return err;
+ }
+
+ err = ops->doit(skb, &backport_info);
+
+ if (family->post_doit)
+ family->post_doit(ops, skb, &backport_info);
+
+ return err;
+}
+#endif /* < 2.6.37 */
+
+int __backport_genl_register_family(struct genl_family *family)
+{
+ int i, ret;
+
+#define __copy(_field) family->family._field = family->_field
+ __copy(id);
+ __copy(hdrsize);
+ __copy(version);
+ __copy(maxattr);
+ strncpy(family->family.name, family->name, sizeof(family->family.name));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+ __copy(netnsok);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ __copy(parallel_ops);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
+ __copy(module);
+#endif
+#undef __copy
+
+ ret = genl_register_family(&family->family);
+ if (ret < 0)
+ return ret;
+
+ family->attrbuf = family->family.attrbuf;
+ family->id = family->family.id;
+
+ for (i = 0; i < family->n_ops; i++) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+#define __copy(_field) family->ops[i].ops._field = family->ops[i]._field
+ __copy(cmd);
+ __copy(flags);
+ __copy(policy);
+ __copy(dumpit);
+ __copy(done);
+#undef __copy
+ if (family->ops[i].doit)
+ family->ops[i].ops.doit = nl_doit_wrapper;
+ ret = genl_register_ops(&family->family, &family->ops[i].ops);
+#else
+ ret = genl_register_ops(&family->family, &family->ops[i]);
+#endif
+ if (ret < 0)
+ goto error;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+ list_add(&family->list, &backport_nl_fam);
+#endif
+
+ for (i = 0; i < family->n_mcgrps; i++) {
+ ret = genl_register_mc_group(&family->family,
+ &family->mcgrps[i]);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+ error:
+ backport_genl_unregister_family(family);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__backport_genl_register_family);
+
+int backport_genl_unregister_family(struct genl_family *family)
+{
+ int err;
+ err = genl_unregister_family(&family->family);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
+ list_del(&family->list);
+#endif
+ return err;
+}
+EXPORT_SYMBOL_GPL(backport_genl_unregister_family);
diff --git a/backport/compat/compat-2.6.37.c b/backport/compat/compat-2.6.37.c
index 078912a4..8d401e18 100644
--- a/backport/compat/compat-2.6.37.c
+++ b/backport/compat/compat-2.6.37.c
@@ -13,7 +13,6 @@
#include <net/sock.h>
#include <linux/nsproxy.h>
#include <linux/vmalloc.h>
-#include <net/genetlink.h>
#include <linux/leds.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
@@ -39,122 +38,8 @@ struct kobj_ns_type_operations net_ns_type_operations = {
.initial_ns = net_initial_ns,
};
EXPORT_SYMBOL_GPL(net_ns_type_operations);
-
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)*/
-#undef genl_info
-#undef genl_unregister_family
-
-static LIST_HEAD(compat_nl_fam);
-
-static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family)
-{
- struct genl_ops *ops;
-
- list_for_each_entry(ops, &family->family.ops_list, ops.ops_list)
- if (ops->cmd == cmd)
- return ops;
-
- return NULL;
-}
-
-
-static int nl_doit_wrapper(struct sk_buff *skb, struct genl_info *info)
-{
- struct compat_genl_info compat_info;
- struct genl_family *family;
- struct genl_ops *ops;
- int err;
-
- list_for_each_entry(family, &compat_nl_fam, list) {
- if (family->id == info->nlhdr->nlmsg_type)
- goto found;
- }
- return -ENOENT;
-
-found:
- ops = genl_get_cmd(info->genlhdr->cmd, family);
- if (!ops)
- return -ENOENT;
-
- memset(&compat_info.user_ptr, 0, sizeof(compat_info.user_ptr));
- compat_info.info = info;
-#define __copy(_field) compat_info._field = info->_field
- __copy(snd_seq);
- __copy(snd_pid);
- __copy(genlhdr);
- __copy(attrs);
-#undef __copy
- if (family->pre_doit) {
- err = family->pre_doit(ops, skb, &compat_info);
- if (err)
- return err;
- }
-
- err = ops->doit(skb, &compat_info);
-
- if (family->post_doit)
- family->post_doit(ops, skb, &compat_info);
-
- return err;
-}
-
-int compat_genl_register_family_with_ops(struct genl_family *family,
- struct genl_ops *ops, size_t n_ops)
-{
- int i, ret;
-
-#define __copy(_field) family->family._field = family->_field
- __copy(id);
- __copy(hdrsize);
- __copy(version);
- __copy(maxattr);
- strncpy(family->family.name, family->name, sizeof(family->family.name));
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
- __copy(netnsok);
-#endif
-#undef __copy
-
- ret = genl_register_family(&family->family);
- if (ret < 0)
- return ret;
-
- family->attrbuf = family->family.attrbuf;
- family->id = family->family.id;
-
- for (i = 0; i < n_ops; i++) {
-#define __copy(_field) ops[i].ops._field = ops[i]._field
- __copy(cmd);
- __copy(flags);
- __copy(policy);
- __copy(dumpit);
- __copy(done);
-#undef __copy
- if (ops[i].doit)
- ops[i].ops.doit = nl_doit_wrapper;
- ret = genl_register_ops(&family->family, &ops[i].ops);
- if (ret < 0)
- goto error_ops;
- }
- list_add(&family->list, &compat_nl_fam);
-
- return ret;
-
-error_ops:
- compat_genl_unregister_family(family);
- return ret;
-}
-EXPORT_SYMBOL_GPL(compat_genl_register_family_with_ops);
-
-int compat_genl_unregister_family(struct genl_family *family)
-{
- int err;
- err = genl_unregister_family(&family->family);
- list_del(&family->list);
- return err;
-}
-EXPORT_SYMBOL_GPL(compat_genl_unregister_family);
-
#if IS_ENABLED(CONFIG_LEDS_CLASS) && !defined(CPTCFG_BACKPORT_BUILD_LEDS)
#undef led_brightness_set