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 <net/genetlink.h> 27 #include <linux/nl802154.h> 28 29 #include "ieee802154.h" 30 31 static unsigned int ieee802154_seq_num; 32 static DEFINE_SPINLOCK(ieee802154_seq_lock); 33 34 struct genl_family nl802154_family = { 35 .id = GENL_ID_GENERATE, 36 .hdrsize = 0, 37 .name = IEEE802154_NL_NAME, 38 .version = 1, 39 .maxattr = IEEE802154_ATTR_MAX, 40 }; 41 42 /* Requests to userspace */ 43 struct sk_buff *ieee802154_nl_create(int flags, u8 req) 44 { 45 void *hdr; 46 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 47 unsigned long f; 48 49 if (!msg) 50 return NULL; 51 52 spin_lock_irqsave(&ieee802154_seq_lock, f); 53 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, 54 &nl802154_family, flags, req); 55 spin_unlock_irqrestore(&ieee802154_seq_lock, f); 56 if (!hdr) { 57 nlmsg_free(msg); 58 return NULL; 59 } 60 61 return msg; 62 } 63 64 int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group) 65 { 66 /* XXX: nlh is right at the start of msg */ 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); 73 out: 74 nlmsg_free(msg); 75 return -ENOBUFS; 76 } 77 78 struct 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 97 int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info) 98 { 99 /* XXX: nlh is right at the start of msg */ 100 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 101 102 if (genlmsg_end(msg, hdr) < 0) 103 goto out; 104 105 return genlmsg_reply(msg, info); 106 out: 107 nlmsg_free(msg); 108 return -ENOBUFS; 109 } 110 111 int __init ieee802154_nl_init(void) 112 { 113 int rc; 114 115 rc = genl_register_family(&nl802154_family); 116 if (rc) 117 goto fail; 118 119 rc = nl802154_mac_register(); 120 if (rc) 121 goto fail; 122 123 rc = nl802154_phy_register(); 124 if (rc) 125 goto fail; 126 127 return 0; 128 129 fail: 130 genl_unregister_family(&nl802154_family); 131 return rc; 132 } 133 134 void __exit ieee802154_nl_exit(void) 135 { 136 genl_unregister_family(&nl802154_family); 137 } 138 139