1 /* This program is free software; you can redistribute it and/or modify 2 * it under the terms of the GNU General Public License version 2 3 * as published by the Free Software Foundation. 4 * 5 * This program is distributed in the hope that it will be useful, 6 * but WITHOUT ANY WARRANTY; without even the implied warranty of 7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8 * GNU General Public License for more details. 9 * 10 * Authors: 11 * Alexander Aring <aar@pengutronix.de> 12 * 13 * Based on: net/wireless/nl80211.c 14 */ 15 16 #include <linux/rtnetlink.h> 17 18 #include <net/cfg802154.h> 19 #include <net/genetlink.h> 20 #include <net/mac802154.h> 21 #include <net/netlink.h> 22 #include <net/nl802154.h> 23 #include <net/sock.h> 24 25 #include "nl802154.h" 26 #include "rdev-ops.h" 27 #include "core.h" 28 29 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, 30 struct genl_info *info); 31 32 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, 33 struct genl_info *info); 34 35 /* the netlink family */ 36 static struct genl_family nl802154_fam = { 37 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ 38 .name = NL802154_GENL_NAME, /* have users key off the name instead */ 39 .hdrsize = 0, /* no private header */ 40 .version = 1, /* no particular meaning now */ 41 .maxattr = NL802154_ATTR_MAX, 42 .netnsok = true, 43 .pre_doit = nl802154_pre_doit, 44 .post_doit = nl802154_post_doit, 45 }; 46 47 /* multicast groups */ 48 enum nl802154_multicast_groups { 49 NL802154_MCGRP_CONFIG, 50 }; 51 52 static const struct genl_multicast_group nl802154_mcgrps[] = { 53 [NL802154_MCGRP_CONFIG] = { .name = "config", }, 54 }; 55 56 /* returns ERR_PTR values */ 57 static struct wpan_dev * 58 __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs) 59 { 60 struct cfg802154_registered_device *rdev; 61 struct wpan_dev *result = NULL; 62 bool have_ifidx = attrs[NL802154_ATTR_IFINDEX]; 63 bool have_wpan_dev_id = attrs[NL802154_ATTR_WPAN_DEV]; 64 u64 wpan_dev_id; 65 int wpan_phy_idx = -1; 66 int ifidx = -1; 67 68 ASSERT_RTNL(); 69 70 if (!have_ifidx && !have_wpan_dev_id) 71 return ERR_PTR(-EINVAL); 72 73 if (have_ifidx) 74 ifidx = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]); 75 if (have_wpan_dev_id) { 76 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]); 77 wpan_phy_idx = wpan_dev_id >> 32; 78 } 79 80 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 81 struct wpan_dev *wpan_dev; 82 83 /* TODO netns compare */ 84 85 if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx) 86 continue; 87 88 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { 89 if (have_ifidx && wpan_dev->netdev && 90 wpan_dev->netdev->ifindex == ifidx) { 91 result = wpan_dev; 92 break; 93 } 94 if (have_wpan_dev_id && 95 wpan_dev->identifier == (u32)wpan_dev_id) { 96 result = wpan_dev; 97 break; 98 } 99 } 100 101 if (result) 102 break; 103 } 104 105 if (result) 106 return result; 107 108 return ERR_PTR(-ENODEV); 109 } 110 111 static struct cfg802154_registered_device * 112 __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs) 113 { 114 struct cfg802154_registered_device *rdev = NULL, *tmp; 115 struct net_device *netdev; 116 117 ASSERT_RTNL(); 118 119 if (!attrs[NL802154_ATTR_WPAN_PHY] && 120 !attrs[NL802154_ATTR_IFINDEX] && 121 !attrs[NL802154_ATTR_WPAN_DEV]) 122 return ERR_PTR(-EINVAL); 123 124 if (attrs[NL802154_ATTR_WPAN_PHY]) 125 rdev = cfg802154_rdev_by_wpan_phy_idx( 126 nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY])); 127 128 if (attrs[NL802154_ATTR_WPAN_DEV]) { 129 u64 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]); 130 struct wpan_dev *wpan_dev; 131 bool found = false; 132 133 tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32); 134 if (tmp) { 135 /* make sure wpan_dev exists */ 136 list_for_each_entry(wpan_dev, &tmp->wpan_dev_list, list) { 137 if (wpan_dev->identifier != (u32)wpan_dev_id) 138 continue; 139 found = true; 140 break; 141 } 142 143 if (!found) 144 tmp = NULL; 145 146 if (rdev && tmp != rdev) 147 return ERR_PTR(-EINVAL); 148 rdev = tmp; 149 } 150 } 151 152 if (attrs[NL802154_ATTR_IFINDEX]) { 153 int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]); 154 155 netdev = __dev_get_by_index(netns, ifindex); 156 if (netdev) { 157 if (netdev->ieee802154_ptr) 158 tmp = wpan_phy_to_rdev( 159 netdev->ieee802154_ptr->wpan_phy); 160 else 161 tmp = NULL; 162 163 /* not wireless device -- return error */ 164 if (!tmp) 165 return ERR_PTR(-EINVAL); 166 167 /* mismatch -- return error */ 168 if (rdev && tmp != rdev) 169 return ERR_PTR(-EINVAL); 170 171 rdev = tmp; 172 } 173 } 174 175 if (!rdev) 176 return ERR_PTR(-ENODEV); 177 178 /* TODO netns compare */ 179 180 return rdev; 181 } 182 183 /* This function returns a pointer to the driver 184 * that the genl_info item that is passed refers to. 185 * 186 * The result of this can be a PTR_ERR and hence must 187 * be checked with IS_ERR() for errors. 188 */ 189 static struct cfg802154_registered_device * 190 cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info) 191 { 192 return __cfg802154_rdev_from_attrs(netns, info->attrs); 193 } 194 195 /* policy for the attributes */ 196 static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { 197 [NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 }, 198 [NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING, 199 .len = 20-1 }, 200 201 [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 }, 202 [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 }, 203 [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, 204 205 [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 }, 206 207 [NL802154_ATTR_PAGE] = { .type = NLA_U8, }, 208 [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, }, 209 210 [NL802154_ATTR_TX_POWER] = { .type = NLA_S8, }, 211 212 [NL802154_ATTR_CCA_MODE] = { .type = NLA_U8, }, 213 214 [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, }, 215 216 [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, }, 217 [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 }, 218 [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, 219 220 [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, }, 221 [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, }, 222 [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, }, 223 224 [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, }, 225 226 [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, }, 227 }; 228 229 /* message building helper */ 230 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, 231 int flags, u8 cmd) 232 { 233 /* since there is no private header just add the generic one */ 234 return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd); 235 } 236 237 static int 238 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, 239 struct sk_buff *msg) 240 { 241 struct nlattr *nl_page; 242 unsigned long page; 243 244 nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED); 245 if (!nl_page) 246 return -ENOBUFS; 247 248 for (page = 0; page <= IEEE802154_MAX_PAGE; page++) { 249 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL, 250 rdev->wpan_phy.channels_supported[page])) 251 return -ENOBUFS; 252 } 253 nla_nest_end(msg, nl_page); 254 255 return 0; 256 } 257 258 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, 259 enum nl802154_commands cmd, 260 struct sk_buff *msg, u32 portid, u32 seq, 261 int flags) 262 { 263 void *hdr; 264 265 hdr = nl802154hdr_put(msg, portid, seq, flags, cmd); 266 if (!hdr) 267 return -ENOBUFS; 268 269 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || 270 nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME, 271 wpan_phy_name(&rdev->wpan_phy)) || 272 nla_put_u32(msg, NL802154_ATTR_GENERATION, 273 cfg802154_rdev_list_generation)) 274 goto nla_put_failure; 275 276 if (cmd != NL802154_CMD_NEW_WPAN_PHY) 277 goto finish; 278 279 /* DUMP PHY PIB */ 280 281 /* current channel settings */ 282 if (nla_put_u8(msg, NL802154_ATTR_PAGE, 283 rdev->wpan_phy.current_page) || 284 nla_put_u8(msg, NL802154_ATTR_CHANNEL, 285 rdev->wpan_phy.current_channel)) 286 goto nla_put_failure; 287 288 /* supported channels array */ 289 if (nl802154_send_wpan_phy_channels(rdev, msg)) 290 goto nla_put_failure; 291 292 /* cca mode */ 293 if (nla_put_u8(msg, NL802154_ATTR_CCA_MODE, 294 rdev->wpan_phy.cca_mode)) 295 goto nla_put_failure; 296 297 if (nla_put_s8(msg, NL802154_ATTR_TX_POWER, 298 rdev->wpan_phy.transmit_power)) 299 goto nla_put_failure; 300 301 finish: 302 return genlmsg_end(msg, hdr); 303 304 nla_put_failure: 305 genlmsg_cancel(msg, hdr); 306 return -EMSGSIZE; 307 } 308 309 struct nl802154_dump_wpan_phy_state { 310 s64 filter_wpan_phy; 311 long start; 312 313 }; 314 315 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb, 316 struct netlink_callback *cb, 317 struct nl802154_dump_wpan_phy_state *state) 318 { 319 struct nlattr **tb = nl802154_fam.attrbuf; 320 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize, 321 tb, nl802154_fam.maxattr, nl802154_policy); 322 323 /* TODO check if we can handle error here, 324 * we have no backward compatibility 325 */ 326 if (ret) 327 return 0; 328 329 if (tb[NL802154_ATTR_WPAN_PHY]) 330 state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]); 331 if (tb[NL802154_ATTR_WPAN_DEV]) 332 state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32; 333 if (tb[NL802154_ATTR_IFINDEX]) { 334 struct net_device *netdev; 335 struct cfg802154_registered_device *rdev; 336 int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]); 337 338 /* TODO netns */ 339 netdev = __dev_get_by_index(&init_net, ifidx); 340 if (!netdev) 341 return -ENODEV; 342 if (netdev->ieee802154_ptr) { 343 rdev = wpan_phy_to_rdev( 344 netdev->ieee802154_ptr->wpan_phy); 345 state->filter_wpan_phy = rdev->wpan_phy_idx; 346 } 347 } 348 349 return 0; 350 } 351 352 static int 353 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb) 354 { 355 int idx = 0, ret; 356 struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0]; 357 struct cfg802154_registered_device *rdev; 358 359 rtnl_lock(); 360 if (!state) { 361 state = kzalloc(sizeof(*state), GFP_KERNEL); 362 if (!state) { 363 rtnl_unlock(); 364 return -ENOMEM; 365 } 366 state->filter_wpan_phy = -1; 367 ret = nl802154_dump_wpan_phy_parse(skb, cb, state); 368 if (ret) { 369 kfree(state); 370 rtnl_unlock(); 371 return ret; 372 } 373 cb->args[0] = (long)state; 374 } 375 376 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 377 /* TODO net ns compare */ 378 if (++idx <= state->start) 379 continue; 380 if (state->filter_wpan_phy != -1 && 381 state->filter_wpan_phy != rdev->wpan_phy_idx) 382 continue; 383 /* attempt to fit multiple wpan_phy data chunks into the skb */ 384 ret = nl802154_send_wpan_phy(rdev, 385 NL802154_CMD_NEW_WPAN_PHY, 386 skb, 387 NETLINK_CB(cb->skb).portid, 388 cb->nlh->nlmsg_seq, NLM_F_MULTI); 389 if (ret < 0) { 390 if ((ret == -ENOBUFS || ret == -EMSGSIZE) && 391 !skb->len && cb->min_dump_alloc < 4096) { 392 cb->min_dump_alloc = 4096; 393 rtnl_unlock(); 394 return 1; 395 } 396 idx--; 397 break; 398 } 399 break; 400 } 401 rtnl_unlock(); 402 403 state->start = idx; 404 405 return skb->len; 406 } 407 408 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb) 409 { 410 kfree((void *)cb->args[0]); 411 return 0; 412 } 413 414 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info) 415 { 416 struct sk_buff *msg; 417 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 418 419 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 420 if (!msg) 421 return -ENOMEM; 422 423 if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg, 424 info->snd_portid, info->snd_seq, 0) < 0) { 425 nlmsg_free(msg); 426 return -ENOBUFS; 427 } 428 429 return genlmsg_reply(msg, info); 430 } 431 432 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev) 433 { 434 return (u64)wpan_dev->identifier | 435 ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32); 436 } 437 438 static int 439 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, 440 struct cfg802154_registered_device *rdev, 441 struct wpan_dev *wpan_dev) 442 { 443 struct net_device *dev = wpan_dev->netdev; 444 void *hdr; 445 446 hdr = nl802154hdr_put(msg, portid, seq, flags, 447 NL802154_CMD_NEW_INTERFACE); 448 if (!hdr) 449 return -1; 450 451 if (dev && 452 (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) || 453 nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name))) 454 goto nla_put_failure; 455 456 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || 457 nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) || 458 nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) || 459 nla_put_u32(msg, NL802154_ATTR_GENERATION, 460 rdev->devlist_generation ^ 461 (cfg802154_rdev_list_generation << 2))) 462 goto nla_put_failure; 463 464 /* address settings */ 465 if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR, 466 wpan_dev->extended_addr) || 467 nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR, 468 wpan_dev->short_addr) || 469 nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id)) 470 goto nla_put_failure; 471 472 /* ARET handling */ 473 if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES, 474 wpan_dev->frame_retries) || 475 nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) || 476 nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS, 477 wpan_dev->csma_retries) || 478 nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be)) 479 goto nla_put_failure; 480 481 /* listen before transmit */ 482 if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt)) 483 goto nla_put_failure; 484 485 return genlmsg_end(msg, hdr); 486 487 nla_put_failure: 488 genlmsg_cancel(msg, hdr); 489 return -EMSGSIZE; 490 } 491 492 static int 493 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) 494 { 495 int wp_idx = 0; 496 int if_idx = 0; 497 int wp_start = cb->args[0]; 498 int if_start = cb->args[1]; 499 struct cfg802154_registered_device *rdev; 500 struct wpan_dev *wpan_dev; 501 502 rtnl_lock(); 503 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 504 /* TODO netns compare */ 505 if (wp_idx < wp_start) { 506 wp_idx++; 507 continue; 508 } 509 if_idx = 0; 510 511 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { 512 if (if_idx < if_start) { 513 if_idx++; 514 continue; 515 } 516 if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid, 517 cb->nlh->nlmsg_seq, NLM_F_MULTI, 518 rdev, wpan_dev) < 0) { 519 goto out; 520 } 521 if_idx++; 522 } 523 524 wp_idx++; 525 } 526 out: 527 rtnl_unlock(); 528 529 cb->args[0] = wp_idx; 530 cb->args[1] = if_idx; 531 532 return skb->len; 533 } 534 535 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info) 536 { 537 struct sk_buff *msg; 538 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 539 struct wpan_dev *wdev = info->user_ptr[1]; 540 541 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 542 if (!msg) 543 return -ENOMEM; 544 545 if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0, 546 rdev, wdev) < 0) { 547 nlmsg_free(msg); 548 return -ENOBUFS; 549 } 550 551 return genlmsg_reply(msg, info); 552 } 553 554 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) 555 { 556 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 557 enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC; 558 __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL); 559 560 /* TODO avoid failing a new interface 561 * creation due to pending removal? 562 */ 563 564 if (!info->attrs[NL802154_ATTR_IFNAME]) 565 return -EINVAL; 566 567 if (info->attrs[NL802154_ATTR_IFTYPE]) { 568 type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]); 569 if (type > NL802154_IFTYPE_MAX) 570 return -EINVAL; 571 } 572 573 /* TODO add nla_get_le64 to netlink */ 574 if (info->attrs[NL802154_ATTR_EXTENDED_ADDR]) 575 extended_addr = (__force __le64)nla_get_u64( 576 info->attrs[NL802154_ATTR_EXTENDED_ADDR]); 577 578 if (!rdev->ops->add_virtual_intf) 579 return -EOPNOTSUPP; 580 581 return rdev_add_virtual_intf(rdev, 582 nla_data(info->attrs[NL802154_ATTR_IFNAME]), 583 type, extended_addr); 584 } 585 586 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info) 587 { 588 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 589 struct wpan_dev *wpan_dev = info->user_ptr[1]; 590 591 if (!rdev->ops->del_virtual_intf) 592 return -EOPNOTSUPP; 593 594 /* If we remove a wpan device without a netdev then clear 595 * user_ptr[1] so that nl802154_post_doit won't dereference it 596 * to check if it needs to do dev_put(). Otherwise it crashes 597 * since the wpan_dev has been freed, unlike with a netdev where 598 * we need the dev_put() for the netdev to really be freed. 599 */ 600 if (!wpan_dev->netdev) 601 info->user_ptr[1] = NULL; 602 603 return rdev_del_virtual_intf(rdev, wpan_dev); 604 } 605 606 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) 607 { 608 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 609 u8 channel, page; 610 611 if (!info->attrs[NL802154_ATTR_PAGE] || 612 !info->attrs[NL802154_ATTR_CHANNEL]) 613 return -EINVAL; 614 615 page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]); 616 channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]); 617 618 /* check 802.15.4 constraints */ 619 if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL) 620 return -EINVAL; 621 622 return rdev_set_channel(rdev, page, channel); 623 } 624 625 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) 626 { 627 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 628 struct net_device *dev = info->user_ptr[1]; 629 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 630 __le16 pan_id; 631 632 /* conflict here while tx/rx calls */ 633 if (netif_running(dev)) 634 return -EBUSY; 635 636 /* don't change address fields on monitor */ 637 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) 638 return -EINVAL; 639 640 if (!info->attrs[NL802154_ATTR_PAN_ID]) 641 return -EINVAL; 642 643 pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); 644 645 return rdev_set_pan_id(rdev, wpan_dev, pan_id); 646 } 647 648 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info) 649 { 650 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 651 struct net_device *dev = info->user_ptr[1]; 652 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 653 __le16 short_addr; 654 655 /* conflict here while tx/rx calls */ 656 if (netif_running(dev)) 657 return -EBUSY; 658 659 /* don't change address fields on monitor */ 660 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) 661 return -EINVAL; 662 663 if (!info->attrs[NL802154_ATTR_SHORT_ADDR]) 664 return -EINVAL; 665 666 short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]); 667 668 return rdev_set_short_addr(rdev, wpan_dev, short_addr); 669 } 670 671 static int 672 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info) 673 { 674 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 675 struct net_device *dev = info->user_ptr[1]; 676 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 677 u8 min_be, max_be; 678 679 /* should be set on netif open inside phy settings */ 680 if (netif_running(dev)) 681 return -EBUSY; 682 683 if (!info->attrs[NL802154_ATTR_MIN_BE] || 684 !info->attrs[NL802154_ATTR_MAX_BE]) 685 return -EINVAL; 686 687 min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]); 688 max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]); 689 690 /* check 802.15.4 constraints */ 691 if (max_be < 3 || max_be > 8 || min_be > max_be) 692 return -EINVAL; 693 694 return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be); 695 } 696 697 static int 698 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info) 699 { 700 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 701 struct net_device *dev = info->user_ptr[1]; 702 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 703 u8 max_csma_backoffs; 704 705 /* conflict here while other running iface settings */ 706 if (netif_running(dev)) 707 return -EBUSY; 708 709 if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]) 710 return -EINVAL; 711 712 max_csma_backoffs = nla_get_u8( 713 info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]); 714 715 /* check 802.15.4 constraints */ 716 if (max_csma_backoffs > 5) 717 return -EINVAL; 718 719 return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs); 720 } 721 722 static int 723 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info) 724 { 725 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 726 struct net_device *dev = info->user_ptr[1]; 727 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 728 s8 max_frame_retries; 729 730 if (netif_running(dev)) 731 return -EBUSY; 732 733 if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]) 734 return -EINVAL; 735 736 max_frame_retries = nla_get_s8( 737 info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]); 738 739 /* check 802.15.4 constraints */ 740 if (max_frame_retries < -1 || max_frame_retries > 7) 741 return -EINVAL; 742 743 return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries); 744 } 745 746 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) 747 { 748 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 749 struct net_device *dev = info->user_ptr[1]; 750 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 751 bool mode; 752 753 if (netif_running(dev)) 754 return -EBUSY; 755 756 if (!info->attrs[NL802154_ATTR_LBT_MODE]) 757 return -EINVAL; 758 759 mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]); 760 return rdev_set_lbt_mode(rdev, wpan_dev, mode); 761 } 762 763 #define NL802154_FLAG_NEED_WPAN_PHY 0x01 764 #define NL802154_FLAG_NEED_NETDEV 0x02 765 #define NL802154_FLAG_NEED_RTNL 0x04 766 #define NL802154_FLAG_CHECK_NETDEV_UP 0x08 767 #define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\ 768 NL802154_FLAG_CHECK_NETDEV_UP) 769 #define NL802154_FLAG_NEED_WPAN_DEV 0x10 770 #define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\ 771 NL802154_FLAG_CHECK_NETDEV_UP) 772 773 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, 774 struct genl_info *info) 775 { 776 struct cfg802154_registered_device *rdev; 777 struct wpan_dev *wpan_dev; 778 struct net_device *dev; 779 bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL; 780 781 if (rtnl) 782 rtnl_lock(); 783 784 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) { 785 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info); 786 if (IS_ERR(rdev)) { 787 if (rtnl) 788 rtnl_unlock(); 789 return PTR_ERR(rdev); 790 } 791 info->user_ptr[0] = rdev; 792 } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV || 793 ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) { 794 ASSERT_RTNL(); 795 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info), 796 info->attrs); 797 if (IS_ERR(wpan_dev)) { 798 if (rtnl) 799 rtnl_unlock(); 800 return PTR_ERR(wpan_dev); 801 } 802 803 dev = wpan_dev->netdev; 804 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy); 805 806 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) { 807 if (!dev) { 808 if (rtnl) 809 rtnl_unlock(); 810 return -EINVAL; 811 } 812 813 info->user_ptr[1] = dev; 814 } else { 815 info->user_ptr[1] = wpan_dev; 816 } 817 818 if (dev) { 819 if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP && 820 !netif_running(dev)) { 821 if (rtnl) 822 rtnl_unlock(); 823 return -ENETDOWN; 824 } 825 826 dev_hold(dev); 827 } 828 829 info->user_ptr[0] = rdev; 830 } 831 832 return 0; 833 } 834 835 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, 836 struct genl_info *info) 837 { 838 if (info->user_ptr[1]) { 839 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) { 840 struct wpan_dev *wpan_dev = info->user_ptr[1]; 841 842 if (wpan_dev->netdev) 843 dev_put(wpan_dev->netdev); 844 } else { 845 dev_put(info->user_ptr[1]); 846 } 847 } 848 849 if (ops->internal_flags & NL802154_FLAG_NEED_RTNL) 850 rtnl_unlock(); 851 } 852 853 static const struct genl_ops nl802154_ops[] = { 854 { 855 .cmd = NL802154_CMD_GET_WPAN_PHY, 856 .doit = nl802154_get_wpan_phy, 857 .dumpit = nl802154_dump_wpan_phy, 858 .done = nl802154_dump_wpan_phy_done, 859 .policy = nl802154_policy, 860 /* can be retrieved by unprivileged users */ 861 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 862 NL802154_FLAG_NEED_RTNL, 863 }, 864 { 865 .cmd = NL802154_CMD_GET_INTERFACE, 866 .doit = nl802154_get_interface, 867 .dumpit = nl802154_dump_interface, 868 .policy = nl802154_policy, 869 /* can be retrieved by unprivileged users */ 870 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | 871 NL802154_FLAG_NEED_RTNL, 872 }, 873 { 874 .cmd = NL802154_CMD_NEW_INTERFACE, 875 .doit = nl802154_new_interface, 876 .policy = nl802154_policy, 877 .flags = GENL_ADMIN_PERM, 878 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 879 NL802154_FLAG_NEED_RTNL, 880 }, 881 { 882 .cmd = NL802154_CMD_DEL_INTERFACE, 883 .doit = nl802154_del_interface, 884 .policy = nl802154_policy, 885 .flags = GENL_ADMIN_PERM, 886 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | 887 NL802154_FLAG_NEED_RTNL, 888 }, 889 { 890 .cmd = NL802154_CMD_SET_CHANNEL, 891 .doit = nl802154_set_channel, 892 .policy = nl802154_policy, 893 .flags = GENL_ADMIN_PERM, 894 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 895 NL802154_FLAG_NEED_RTNL, 896 }, 897 { 898 .cmd = NL802154_CMD_SET_PAN_ID, 899 .doit = nl802154_set_pan_id, 900 .policy = nl802154_policy, 901 .flags = GENL_ADMIN_PERM, 902 .internal_flags = NL802154_FLAG_NEED_NETDEV | 903 NL802154_FLAG_NEED_RTNL, 904 }, 905 { 906 .cmd = NL802154_CMD_SET_SHORT_ADDR, 907 .doit = nl802154_set_short_addr, 908 .policy = nl802154_policy, 909 .flags = GENL_ADMIN_PERM, 910 .internal_flags = NL802154_FLAG_NEED_NETDEV | 911 NL802154_FLAG_NEED_RTNL, 912 }, 913 { 914 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT, 915 .doit = nl802154_set_backoff_exponent, 916 .policy = nl802154_policy, 917 .flags = GENL_ADMIN_PERM, 918 .internal_flags = NL802154_FLAG_NEED_NETDEV | 919 NL802154_FLAG_NEED_RTNL, 920 }, 921 { 922 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS, 923 .doit = nl802154_set_max_csma_backoffs, 924 .policy = nl802154_policy, 925 .flags = GENL_ADMIN_PERM, 926 .internal_flags = NL802154_FLAG_NEED_NETDEV | 927 NL802154_FLAG_NEED_RTNL, 928 }, 929 { 930 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES, 931 .doit = nl802154_set_max_frame_retries, 932 .policy = nl802154_policy, 933 .flags = GENL_ADMIN_PERM, 934 .internal_flags = NL802154_FLAG_NEED_NETDEV | 935 NL802154_FLAG_NEED_RTNL, 936 }, 937 { 938 .cmd = NL802154_CMD_SET_LBT_MODE, 939 .doit = nl802154_set_lbt_mode, 940 .policy = nl802154_policy, 941 .flags = GENL_ADMIN_PERM, 942 .internal_flags = NL802154_FLAG_NEED_NETDEV | 943 NL802154_FLAG_NEED_RTNL, 944 }, 945 }; 946 947 /* initialisation/exit functions */ 948 int nl802154_init(void) 949 { 950 return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops, 951 nl802154_mcgrps); 952 } 953 954 void nl802154_exit(void) 955 { 956 genl_unregister_family(&nl802154_fam); 957 } 958