From patchwork Thu Oct 7 12:46:58 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Felix Fietkau X-Patchwork-Id: 238151 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o97Cl8oC011098 for ; Thu, 7 Oct 2010 12:47:11 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755296Ab0JGMrF (ORCPT ); Thu, 7 Oct 2010 08:47:05 -0400 Received: from nbd.name ([88.198.39.176]:57345 "EHLO ds10.nbd.name" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760471Ab0JGMrF (ORCPT ); Thu, 7 Oct 2010 08:47:05 -0400 Message-ID: <4CADC142.7010709@openwrt.org> Date: Thu, 07 Oct 2010 14:46:58 +0200 From: Felix Fietkau User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.9) Gecko/20100915 Thunderbird/3.1.4 MIME-Version: 1.0 To: "Luis R. Rodriguez" CC: linux-wireless Subject: [PATCH v2] compat: backport netlink changes used in the nl80211 cleanup References: <4CADB60C.6040105@openwrt.org> In-Reply-To: <4CADB60C.6040105@openwrt.org> X-Enigmail-Version: 1.1.1 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Thu, 07 Oct 2010 12:47:12 +0000 (UTC) --- a/include/linux/compat-2.6.37.h +++ b/include/linux/compat-2.6.37.h @@ -45,6 +45,68 @@ static inline void skb_checksum_none_ass #define pcmcia_enable_device(link) pcmcia_request_configuration(link, &link->conf) +#include + +struct compat_genl_info { + struct genl_info *info; + + u32 snd_seq; + u32 snd_pid; + struct genlmsghdr *genlhdr; + struct nlattr **attrs; + void *user_ptr[2]; +}; +#define genl_info compat_genl_info + +struct compat_genl_ops { + struct genl_ops 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); +}; +#define genl_ops compat_genl_ops + +struct compat_genl_family { + struct genl_family family; + + struct list_head list; + + unsigned int id, hdrsize, version, maxattr; + const char *name; + bool netnsok; + + struct nlattr **attrbuf; + + int (*pre_doit)(struct genl_ops *ops, struct sk_buff *skb, + struct genl_info *info); + + 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 + +int genl_unregister_family(struct genl_family *family); + +#define genl_info_net(_info) genl_info_net((_info)->info) +#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 /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)) */ #endif /* LINUX_26_37_COMPAT_H */ --- a/compat/compat-2.6.37.c +++ b/compat/compat-2.6.37.c @@ -42,4 +42,114 @@ 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 + 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(compat_genl_register_family_with_ops); + +int compat_genl_unregister_family(struct genl_family *family) +{ + list_del(&family->list); + return genl_unregister_family(&family->family); +} +EXPORT_SYMBOL(compat_genl_unregister_family); + #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) */