netlink.c revision 932c1329acebc03ef5efa3647c9c3a967b59d0c4
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 */ 23 24#include <linux/kernel.h> 25#include <linux/if_arp.h> 26#include <linux/netdevice.h> 27#include <net/netlink.h> 28#include <net/genetlink.h> 29#include <linux/nl802154.h> 30#include <net/ieee802154/af_ieee802154.h> 31#include <net/ieee802154/nl802154.h> 32#include <net/ieee802154/netdevice.h> 33 34static unsigned int ieee802154_seq_num; 35 36static struct genl_family ieee802154_coordinator_family = { 37 .id = GENL_ID_GENERATE, 38 .hdrsize = 0, 39 .name = IEEE802154_NL_NAME, 40 .version = 1, 41 .maxattr = IEEE802154_ATTR_MAX, 42}; 43 44static struct genl_multicast_group ieee802154_coord_mcgrp = { 45 .name = IEEE802154_MCAST_COORD_NAME, 46}; 47 48static struct genl_multicast_group ieee802154_beacon_mcgrp = { 49 .name = IEEE802154_MCAST_BEACON_NAME, 50}; 51 52/* Requests to userspace */ 53static struct sk_buff *ieee802154_nl_create(int flags, u8 req) 54{ 55 void *hdr; 56 struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 57 58 if (!msg) 59 return NULL; 60 61 hdr = genlmsg_put(msg, 0, ieee802154_seq_num++, 62 &ieee802154_coordinator_family, flags, req); 63 if (!hdr) { 64 nlmsg_free(msg); 65 return NULL; 66 } 67 68 return msg; 69} 70 71static int ieee802154_nl_finish(struct sk_buff *msg) 72{ 73 /* XXX: nlh is right at the start of msg */ 74 void *hdr = genlmsg_data(NLMSG_DATA(msg->data)); 75 76 if (!genlmsg_end(msg, hdr)) 77 goto out; 78 79 return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id, 80 GFP_ATOMIC); 81out: 82 nlmsg_free(msg); 83 return -ENOBUFS; 84} 85 86int ieee802154_nl_assoc_indic(struct net_device *dev, 87 struct ieee802154_addr *addr, u8 cap) 88{ 89 struct sk_buff *msg; 90 91 pr_debug("%s\n", __func__); 92 93 if (addr->addr_type != IEEE802154_ADDR_LONG) { 94 pr_err("%s: received non-long source address!\n", __func__); 95 return -EINVAL; 96 } 97 98 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC); 99 if (!msg) 100 return -ENOBUFS; 101 102 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 103 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 104 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 105 dev->dev_addr); 106 107 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 108 addr->hwaddr); 109 110 NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap); 111 112 return ieee802154_nl_finish(msg); 113 114nla_put_failure: 115 nlmsg_free(msg); 116 return -ENOBUFS; 117} 118EXPORT_SYMBOL(ieee802154_nl_assoc_indic); 119 120int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, 121 u8 status) 122{ 123 struct sk_buff *msg; 124 125 pr_debug("%s\n", __func__); 126 127 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF); 128 if (!msg) 129 return -ENOBUFS; 130 131 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 132 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 133 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 134 dev->dev_addr); 135 136 NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr); 137 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 138 139 return ieee802154_nl_finish(msg); 140 141nla_put_failure: 142 nlmsg_free(msg); 143 return -ENOBUFS; 144} 145EXPORT_SYMBOL(ieee802154_nl_assoc_confirm); 146 147int ieee802154_nl_disassoc_indic(struct net_device *dev, 148 struct ieee802154_addr *addr, u8 reason) 149{ 150 struct sk_buff *msg; 151 152 pr_debug("%s\n", __func__); 153 154 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC); 155 if (!msg) 156 return -ENOBUFS; 157 158 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 159 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 160 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 161 dev->dev_addr); 162 163 if (addr->addr_type == IEEE802154_ADDR_LONG) 164 NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, 165 addr->hwaddr); 166 else 167 NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, 168 addr->short_addr); 169 170 NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason); 171 172 return ieee802154_nl_finish(msg); 173 174nla_put_failure: 175 nlmsg_free(msg); 176 return -ENOBUFS; 177} 178EXPORT_SYMBOL(ieee802154_nl_disassoc_indic); 179 180int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) 181{ 182 struct sk_buff *msg; 183 184 pr_debug("%s\n", __func__); 185 186 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF); 187 if (!msg) 188 return -ENOBUFS; 189 190 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 191 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 192 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 193 dev->dev_addr); 194 195 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 196 197 return ieee802154_nl_finish(msg); 198 199nla_put_failure: 200 nlmsg_free(msg); 201 return -ENOBUFS; 202} 203EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); 204 205int ieee802154_nl_beacon_indic(struct net_device *dev, 206 u16 panid, u16 coord_addr) 207{ 208 struct sk_buff *msg; 209 210 pr_debug("%s\n", __func__); 211 212 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC); 213 if (!msg) 214 return -ENOBUFS; 215 216 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 217 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 218 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 219 dev->dev_addr); 220 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr); 221 NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid); 222 223 return ieee802154_nl_finish(msg); 224 225nla_put_failure: 226 nlmsg_free(msg); 227 return -ENOBUFS; 228} 229EXPORT_SYMBOL(ieee802154_nl_beacon_indic); 230 231int ieee802154_nl_scan_confirm(struct net_device *dev, 232 u8 status, u8 scan_type, u32 unscanned, 233 u8 *edl/* , struct list_head *pan_desc_list */) 234{ 235 struct sk_buff *msg; 236 237 pr_debug("%s\n", __func__); 238 239 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF); 240 if (!msg) 241 return -ENOBUFS; 242 243 NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 244 NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex); 245 NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, 246 dev->dev_addr); 247 248 NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status); 249 NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type); 250 NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned); 251 252 if (edl) 253 NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl); 254 255 return ieee802154_nl_finish(msg); 256 257nla_put_failure: 258 nlmsg_free(msg); 259 return -ENOBUFS; 260} 261EXPORT_SYMBOL(ieee802154_nl_scan_confirm); 262 263/* Requests from userspace */ 264static struct net_device *ieee802154_nl_get_dev(struct genl_info *info) 265{ 266 struct net_device *dev; 267 268 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 269 char name[IFNAMSIZ + 1]; 270 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME], 271 sizeof(name)); 272 dev = dev_get_by_name(&init_net, name); 273 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX]) 274 dev = dev_get_by_index(&init_net, 275 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX])); 276 else 277 return NULL; 278 279 if (!dev) 280 return NULL; 281 282 if (dev->type != ARPHRD_IEEE802154) { 283 dev_put(dev); 284 return NULL; 285 } 286 287 return dev; 288} 289 290static int ieee802154_associate_req(struct sk_buff *skb, 291 struct genl_info *info) 292{ 293 struct net_device *dev; 294 struct ieee802154_addr addr; 295 int ret = -EINVAL; 296 297 if (!info->attrs[IEEE802154_ATTR_CHANNEL] || 298 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 299 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] && 300 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) || 301 !info->attrs[IEEE802154_ATTR_CAPABILITY]) 302 return -EINVAL; 303 304 dev = ieee802154_nl_get_dev(info); 305 if (!dev) 306 return -ENODEV; 307 308 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { 309 addr.addr_type = IEEE802154_ADDR_LONG; 310 nla_memcpy(addr.hwaddr, 311 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], 312 IEEE802154_ADDR_LEN); 313 } else { 314 addr.addr_type = IEEE802154_ADDR_SHORT; 315 addr.short_addr = nla_get_u16( 316 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 317 } 318 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 319 320 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr, 321 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]), 322 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY])); 323 324 dev_put(dev); 325 return ret; 326} 327 328static int ieee802154_associate_resp(struct sk_buff *skb, 329 struct genl_info *info) 330{ 331 struct net_device *dev; 332 struct ieee802154_addr addr; 333 int ret = -EINVAL; 334 335 if (!info->attrs[IEEE802154_ATTR_STATUS] || 336 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] || 337 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) 338 return -EINVAL; 339 340 dev = ieee802154_nl_get_dev(info); 341 if (!dev) 342 return -ENODEV; 343 344 addr.addr_type = IEEE802154_ADDR_LONG; 345 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 346 IEEE802154_ADDR_LEN); 347 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 348 349 350 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, 351 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]), 352 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS])); 353 354 dev_put(dev); 355 return ret; 356} 357 358static int ieee802154_disassociate_req(struct sk_buff *skb, 359 struct genl_info *info) 360{ 361 struct net_device *dev; 362 struct ieee802154_addr addr; 363 int ret = -EINVAL; 364 365 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] && 366 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) || 367 !info->attrs[IEEE802154_ATTR_REASON]) 368 return -EINVAL; 369 370 dev = ieee802154_nl_get_dev(info); 371 if (!dev) 372 return -ENODEV; 373 374 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { 375 addr.addr_type = IEEE802154_ADDR_LONG; 376 nla_memcpy(addr.hwaddr, 377 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], 378 IEEE802154_ADDR_LEN); 379 } else { 380 addr.addr_type = IEEE802154_ADDR_SHORT; 381 addr.short_addr = nla_get_u16( 382 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); 383 } 384 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 385 386 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr, 387 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON])); 388 389 dev_put(dev); 390 return ret; 391} 392 393/* 394 * PANid, channel, beacon_order = 15, superframe_order = 15, 395 * PAN_coordinator, battery_life_extension = 0, 396 * coord_realignment = 0, security_enable = 0 397*/ 398static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info) 399{ 400 struct net_device *dev; 401 struct ieee802154_addr addr; 402 403 u8 channel, bcn_ord, sf_ord; 404 int pan_coord, blx, coord_realign; 405 int ret; 406 407 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] || 408 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] || 409 !info->attrs[IEEE802154_ATTR_CHANNEL] || 410 !info->attrs[IEEE802154_ATTR_BCN_ORD] || 411 !info->attrs[IEEE802154_ATTR_SF_ORD] || 412 !info->attrs[IEEE802154_ATTR_PAN_COORD] || 413 !info->attrs[IEEE802154_ATTR_BAT_EXT] || 414 !info->attrs[IEEE802154_ATTR_COORD_REALIGN] 415 ) 416 return -EINVAL; 417 418 dev = ieee802154_nl_get_dev(info); 419 if (!dev) 420 return -ENODEV; 421 422 addr.addr_type = IEEE802154_ADDR_SHORT; 423 addr.short_addr = nla_get_u16( 424 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 425 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]); 426 427 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]); 428 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); 429 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]); 430 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]); 431 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]); 432 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]); 433 434 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, 435 bcn_ord, sf_ord, pan_coord, blx, coord_realign); 436 437 dev_put(dev); 438 return ret; 439} 440 441static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info) 442{ 443 struct net_device *dev; 444 int ret; 445 u8 type; 446 u32 channels; 447 u8 duration; 448 449 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] || 450 !info->attrs[IEEE802154_ATTR_CHANNELS] || 451 !info->attrs[IEEE802154_ATTR_DURATION]) 452 return -EINVAL; 453 454 dev = ieee802154_nl_get_dev(info); 455 if (!dev) 456 return -ENODEV; 457 458 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]); 459 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]); 460 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]); 461 462 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, 463 duration); 464 465 dev_put(dev); 466 return ret; 467} 468 469#define IEEE802154_OP(_cmd, _func) \ 470 { \ 471 .cmd = _cmd, \ 472 .policy = ieee802154_policy, \ 473 .doit = _func, \ 474 .dumpit = NULL, \ 475 .flags = GENL_ADMIN_PERM, \ 476 } 477 478static struct genl_ops ieee802154_coordinator_ops[] = { 479 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req), 480 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp), 481 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req), 482 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req), 483 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req), 484}; 485 486static int __init ieee802154_nl_init(void) 487{ 488 int rc; 489 int i; 490 491 rc = genl_register_family(&ieee802154_coordinator_family); 492 if (rc) 493 goto fail; 494 495 rc = genl_register_mc_group(&ieee802154_coordinator_family, 496 &ieee802154_coord_mcgrp); 497 if (rc) 498 goto fail; 499 500 rc = genl_register_mc_group(&ieee802154_coordinator_family, 501 &ieee802154_beacon_mcgrp); 502 if (rc) 503 goto fail; 504 505 506 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) { 507 rc = genl_register_ops(&ieee802154_coordinator_family, 508 &ieee802154_coordinator_ops[i]); 509 if (rc) 510 goto fail; 511 } 512 513 return 0; 514 515fail: 516 genl_unregister_family(&ieee802154_coordinator_family); 517 return rc; 518} 519module_init(ieee802154_nl_init); 520 521static void __exit ieee802154_nl_exit(void) 522{ 523 genl_unregister_family(&ieee802154_coordinator_family); 524} 525module_exit(ieee802154_nl_exit); 526 527