1/* 2 * Netlink inteface for IEEE 802.15.4 stack 3 * 4 * Copyright 2007, 2008 Siemens AG 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 8 * as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Written by: 20 * Sergey Lapin <slapin@ossfans.org> 21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 22 * Maxim Osipov <maxim.osipov@siemens.com> 23 */ 24 25#include <linux/kernel.h> 26#include <linux/gfp.h> 27#include <net/genetlink.h> 28#include <linux/nl802154.h> 29 30#include "ieee802154.h" 31 32static unsigned int ieee802154_seq_num; 33static DEFINE_SPINLOCK(ieee802154_seq_lock); 34 35struct genl_family nl802154_family = { 36 .id = GENL_ID_GENERATE, 37 .hdrsize = 0, 38 .name = IEEE802154_NL_NAME, 39 .version = 1, 40 .maxattr = IEEE802154_ATTR_MAX, 41}; 42 43/* Requests to userspace */ 44struct sk_buff *ieee802154_nl_create(int flags, u8 req) 45{ 46 void *hdr; 47 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 48 unsigned long f; 49 50 if (!msg) 51 return NULL; 52 53 spin_lock_irqsave(&ieee802154_seq_lock, f); 54 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, 55 &nl802154_family, flags, req); 56 spin_unlock_irqrestore(&ieee802154_seq_lock, f); 57 if (!hdr) { 58 nlmsg_free(msg); 59 return NULL; 60 } 61 62 return msg; 63} 64 65int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group) 66{ 67 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 68 69 if (genlmsg_end(msg, hdr) < 0) 70 goto out; 71 72 return genlmsg_multicast(msg, 0, group, GFP_ATOMIC); 73out: 74 nlmsg_free(msg); 75 return -ENOBUFS; 76} 77 78struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info, 79 int flags, u8 req) 80{ 81 void *hdr; 82 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 83 84 if (!msg) 85 return NULL; 86 87 hdr = genlmsg_put_reply(msg, info, 88 &nl802154_family, flags, req); 89 if (!hdr) { 90 nlmsg_free(msg); 91 return NULL; 92 } 93 94 return msg; 95} 96 97int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info) 98{ 99 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 100 101 if (genlmsg_end(msg, hdr) < 0) 102 goto out; 103 104 return genlmsg_reply(msg, info); 105out: 106 nlmsg_free(msg); 107 return -ENOBUFS; 108} 109 110int __init ieee802154_nl_init(void) 111{ 112 int rc; 113 114 rc = genl_register_family(&nl802154_family); 115 if (rc) 116 goto fail; 117 118 rc = nl802154_mac_register(); 119 if (rc) 120 goto fail; 121 122 rc = nl802154_phy_register(); 123 if (rc) 124 goto fail; 125 126 return 0; 127 128fail: 129 genl_unregister_family(&nl802154_family); 130 return rc; 131} 132 133void __exit ieee802154_nl_exit(void) 134{ 135 genl_unregister_family(&nl802154_family); 136} 137