diff options
Diffstat (limited to 'net/ieee802154/netlink.c')
-rw-r--r-- | net/ieee802154/netlink.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c new file mode 100644 index 00000000..c8097ae2 --- /dev/null +++ b/net/ieee802154/netlink.c @@ -0,0 +1,139 @@ +/* + * Netlink inteface for IEEE 802.15.4 stack + * + * Copyright 2007, 2008 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin <slapin@ossfans.org> + * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> + * Maxim Osipov <maxim.osipov@siemens.com> + */ + +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <net/genetlink.h> +#include <linux/nl802154.h> + +#include "ieee802154.h" + +static unsigned int ieee802154_seq_num; +static DEFINE_SPINLOCK(ieee802154_seq_lock); + +struct genl_family nl802154_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = IEEE802154_NL_NAME, + .version = 1, + .maxattr = IEEE802154_ATTR_MAX, +}; + +/* Requests to userspace */ +struct sk_buff *ieee802154_nl_create(int flags, u8 req) +{ + void *hdr; + struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + unsigned long f; + + if (!msg) + return NULL; + + spin_lock_irqsave(&ieee802154_seq_lock, f); + hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, + &nl802154_family, flags, req); + spin_unlock_irqrestore(&ieee802154_seq_lock, f); + if (!hdr) { + nlmsg_free(msg); + return NULL; + } + + return msg; +} + +int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group) +{ + /* XXX: nlh is right at the start of msg */ + void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); + + if (genlmsg_end(msg, hdr) < 0) + goto out; + + return genlmsg_multicast(msg, 0, group, GFP_ATOMIC); +out: + nlmsg_free(msg); + return -ENOBUFS; +} + +struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, + int flags, u8 req) +{ + void *hdr; + struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); + + if (!msg) + return NULL; + + hdr = genlmsg_put_reply(msg, info, + &nl802154_family, flags, req); + if (!hdr) { + nlmsg_free(msg); + return NULL; + } + + return msg; +} + +int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info) +{ + /* XXX: nlh is right at the start of msg */ + void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); + + if (genlmsg_end(msg, hdr) < 0) + goto out; + + return genlmsg_reply(msg, info); +out: + nlmsg_free(msg); + return -ENOBUFS; +} + +int __init ieee802154_nl_init(void) +{ + int rc; + + rc = genl_register_family(&nl802154_family); + if (rc) + goto fail; + + rc = nl802154_mac_register(); + if (rc) + goto fail; + + rc = nl802154_phy_register(); + if (rc) + goto fail; + + return 0; + +fail: + genl_unregister_family(&nl802154_family); + return rc; +} + +void __exit ieee802154_nl_exit(void) +{ + genl_unregister_family(&nl802154_family); +} + |