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_U32, }, 213 [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, }, 214 215 [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, }, 216 217 [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, }, 218 [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 }, 219 [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, }, 220 221 [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, }, 222 [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, }, 223 [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, }, 224 225 [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, }, 226 227 [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, }, 228 }; 229 230 /* message building helper */ 231 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, 232 int flags, u8 cmd) 233 { 234 /* since there is no private header just add the generic one */ 235 return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd); 236 } 237 238 static int 239 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev, 240 struct sk_buff *msg) 241 { 242 struct nlattr *nl_page; 243 unsigned long page; 244 245 nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED); 246 if (!nl_page) 247 return -ENOBUFS; 248 249 for (page = 0; page <= IEEE802154_MAX_PAGE; page++) { 250 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL, 251 rdev->wpan_phy.channels_supported[page])) 252 return -ENOBUFS; 253 } 254 nla_nest_end(msg, nl_page); 255 256 return 0; 257 } 258 259 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, 260 enum nl802154_commands cmd, 261 struct sk_buff *msg, u32 portid, u32 seq, 262 int flags) 263 { 264 void *hdr; 265 266 hdr = nl802154hdr_put(msg, portid, seq, flags, cmd); 267 if (!hdr) 268 return -ENOBUFS; 269 270 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || 271 nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME, 272 wpan_phy_name(&rdev->wpan_phy)) || 273 nla_put_u32(msg, NL802154_ATTR_GENERATION, 274 cfg802154_rdev_list_generation)) 275 goto nla_put_failure; 276 277 if (cmd != NL802154_CMD_NEW_WPAN_PHY) 278 goto finish; 279 280 /* DUMP PHY PIB */ 281 282 /* current channel settings */ 283 if (nla_put_u8(msg, NL802154_ATTR_PAGE, 284 rdev->wpan_phy.current_page) || 285 nla_put_u8(msg, NL802154_ATTR_CHANNEL, 286 rdev->wpan_phy.current_channel)) 287 goto nla_put_failure; 288 289 /* supported channels array */ 290 if (nl802154_send_wpan_phy_channels(rdev, msg)) 291 goto nla_put_failure; 292 293 /* cca mode */ 294 if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE, 295 rdev->wpan_phy.cca.mode)) 296 goto nla_put_failure; 297 298 if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) { 299 if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT, 300 rdev->wpan_phy.cca.opt)) 301 goto nla_put_failure; 302 } 303 304 if (nla_put_s8(msg, NL802154_ATTR_TX_POWER, 305 rdev->wpan_phy.transmit_power)) 306 goto nla_put_failure; 307 308 finish: 309 genlmsg_end(msg, hdr); 310 return 0; 311 312 nla_put_failure: 313 genlmsg_cancel(msg, hdr); 314 return -EMSGSIZE; 315 } 316 317 struct nl802154_dump_wpan_phy_state { 318 s64 filter_wpan_phy; 319 long start; 320 321 }; 322 323 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb, 324 struct netlink_callback *cb, 325 struct nl802154_dump_wpan_phy_state *state) 326 { 327 struct nlattr **tb = nl802154_fam.attrbuf; 328 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize, 329 tb, nl802154_fam.maxattr, nl802154_policy); 330 331 /* TODO check if we can handle error here, 332 * we have no backward compatibility 333 */ 334 if (ret) 335 return 0; 336 337 if (tb[NL802154_ATTR_WPAN_PHY]) 338 state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]); 339 if (tb[NL802154_ATTR_WPAN_DEV]) 340 state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32; 341 if (tb[NL802154_ATTR_IFINDEX]) { 342 struct net_device *netdev; 343 struct cfg802154_registered_device *rdev; 344 int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]); 345 346 /* TODO netns */ 347 netdev = __dev_get_by_index(&init_net, ifidx); 348 if (!netdev) 349 return -ENODEV; 350 if (netdev->ieee802154_ptr) { 351 rdev = wpan_phy_to_rdev( 352 netdev->ieee802154_ptr->wpan_phy); 353 state->filter_wpan_phy = rdev->wpan_phy_idx; 354 } 355 } 356 357 return 0; 358 } 359 360 static int 361 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb) 362 { 363 int idx = 0, ret; 364 struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0]; 365 struct cfg802154_registered_device *rdev; 366 367 rtnl_lock(); 368 if (!state) { 369 state = kzalloc(sizeof(*state), GFP_KERNEL); 370 if (!state) { 371 rtnl_unlock(); 372 return -ENOMEM; 373 } 374 state->filter_wpan_phy = -1; 375 ret = nl802154_dump_wpan_phy_parse(skb, cb, state); 376 if (ret) { 377 kfree(state); 378 rtnl_unlock(); 379 return ret; 380 } 381 cb->args[0] = (long)state; 382 } 383 384 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 385 /* TODO net ns compare */ 386 if (++idx <= state->start) 387 continue; 388 if (state->filter_wpan_phy != -1 && 389 state->filter_wpan_phy != rdev->wpan_phy_idx) 390 continue; 391 /* attempt to fit multiple wpan_phy data chunks into the skb */ 392 ret = nl802154_send_wpan_phy(rdev, 393 NL802154_CMD_NEW_WPAN_PHY, 394 skb, 395 NETLINK_CB(cb->skb).portid, 396 cb->nlh->nlmsg_seq, NLM_F_MULTI); 397 if (ret < 0) { 398 if ((ret == -ENOBUFS || ret == -EMSGSIZE) && 399 !skb->len && cb->min_dump_alloc < 4096) { 400 cb->min_dump_alloc = 4096; 401 rtnl_unlock(); 402 return 1; 403 } 404 idx--; 405 break; 406 } 407 break; 408 } 409 rtnl_unlock(); 410 411 state->start = idx; 412 413 return skb->len; 414 } 415 416 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb) 417 { 418 kfree((void *)cb->args[0]); 419 return 0; 420 } 421 422 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info) 423 { 424 struct sk_buff *msg; 425 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 426 427 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 428 if (!msg) 429 return -ENOMEM; 430 431 if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg, 432 info->snd_portid, info->snd_seq, 0) < 0) { 433 nlmsg_free(msg); 434 return -ENOBUFS; 435 } 436 437 return genlmsg_reply(msg, info); 438 } 439 440 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev) 441 { 442 return (u64)wpan_dev->identifier | 443 ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32); 444 } 445 446 static int 447 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, 448 struct cfg802154_registered_device *rdev, 449 struct wpan_dev *wpan_dev) 450 { 451 struct net_device *dev = wpan_dev->netdev; 452 void *hdr; 453 454 hdr = nl802154hdr_put(msg, portid, seq, flags, 455 NL802154_CMD_NEW_INTERFACE); 456 if (!hdr) 457 return -1; 458 459 if (dev && 460 (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) || 461 nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name))) 462 goto nla_put_failure; 463 464 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) || 465 nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) || 466 nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) || 467 nla_put_u32(msg, NL802154_ATTR_GENERATION, 468 rdev->devlist_generation ^ 469 (cfg802154_rdev_list_generation << 2))) 470 goto nla_put_failure; 471 472 /* address settings */ 473 if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR, 474 wpan_dev->extended_addr) || 475 nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR, 476 wpan_dev->short_addr) || 477 nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id)) 478 goto nla_put_failure; 479 480 /* ARET handling */ 481 if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES, 482 wpan_dev->frame_retries) || 483 nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) || 484 nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS, 485 wpan_dev->csma_retries) || 486 nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be)) 487 goto nla_put_failure; 488 489 /* listen before transmit */ 490 if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt)) 491 goto nla_put_failure; 492 493 genlmsg_end(msg, hdr); 494 return 0; 495 496 nla_put_failure: 497 genlmsg_cancel(msg, hdr); 498 return -EMSGSIZE; 499 } 500 501 static int 502 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) 503 { 504 int wp_idx = 0; 505 int if_idx = 0; 506 int wp_start = cb->args[0]; 507 int if_start = cb->args[1]; 508 struct cfg802154_registered_device *rdev; 509 struct wpan_dev *wpan_dev; 510 511 rtnl_lock(); 512 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 513 /* TODO netns compare */ 514 if (wp_idx < wp_start) { 515 wp_idx++; 516 continue; 517 } 518 if_idx = 0; 519 520 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { 521 if (if_idx < if_start) { 522 if_idx++; 523 continue; 524 } 525 if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid, 526 cb->nlh->nlmsg_seq, NLM_F_MULTI, 527 rdev, wpan_dev) < 0) { 528 goto out; 529 } 530 if_idx++; 531 } 532 533 wp_idx++; 534 } 535 out: 536 rtnl_unlock(); 537 538 cb->args[0] = wp_idx; 539 cb->args[1] = if_idx; 540 541 return skb->len; 542 } 543 544 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info) 545 { 546 struct sk_buff *msg; 547 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 548 struct wpan_dev *wdev = info->user_ptr[1]; 549 550 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 551 if (!msg) 552 return -ENOMEM; 553 554 if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0, 555 rdev, wdev) < 0) { 556 nlmsg_free(msg); 557 return -ENOBUFS; 558 } 559 560 return genlmsg_reply(msg, info); 561 } 562 563 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) 564 { 565 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 566 enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC; 567 __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL); 568 569 /* TODO avoid failing a new interface 570 * creation due to pending removal? 571 */ 572 573 if (!info->attrs[NL802154_ATTR_IFNAME]) 574 return -EINVAL; 575 576 if (info->attrs[NL802154_ATTR_IFTYPE]) { 577 type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]); 578 if (type > NL802154_IFTYPE_MAX) 579 return -EINVAL; 580 } 581 582 /* TODO add nla_get_le64 to netlink */ 583 if (info->attrs[NL802154_ATTR_EXTENDED_ADDR]) 584 extended_addr = (__force __le64)nla_get_u64( 585 info->attrs[NL802154_ATTR_EXTENDED_ADDR]); 586 587 if (!rdev->ops->add_virtual_intf) 588 return -EOPNOTSUPP; 589 590 return rdev_add_virtual_intf(rdev, 591 nla_data(info->attrs[NL802154_ATTR_IFNAME]), 592 type, extended_addr); 593 } 594 595 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info) 596 { 597 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 598 struct wpan_dev *wpan_dev = info->user_ptr[1]; 599 600 if (!rdev->ops->del_virtual_intf) 601 return -EOPNOTSUPP; 602 603 /* If we remove a wpan device without a netdev then clear 604 * user_ptr[1] so that nl802154_post_doit won't dereference it 605 * to check if it needs to do dev_put(). Otherwise it crashes 606 * since the wpan_dev has been freed, unlike with a netdev where 607 * we need the dev_put() for the netdev to really be freed. 608 */ 609 if (!wpan_dev->netdev) 610 info->user_ptr[1] = NULL; 611 612 return rdev_del_virtual_intf(rdev, wpan_dev); 613 } 614 615 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info) 616 { 617 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 618 u8 channel, page; 619 620 if (!info->attrs[NL802154_ATTR_PAGE] || 621 !info->attrs[NL802154_ATTR_CHANNEL]) 622 return -EINVAL; 623 624 page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]); 625 channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]); 626 627 /* check 802.15.4 constraints */ 628 if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL) 629 return -EINVAL; 630 631 return rdev_set_channel(rdev, page, channel); 632 } 633 634 static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info) 635 { 636 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 637 struct wpan_phy_cca cca; 638 639 if (!info->attrs[NL802154_ATTR_CCA_MODE]) 640 return -EINVAL; 641 642 cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]); 643 /* checking 802.15.4 constraints */ 644 if (cca.mode < NL802154_CCA_ENERGY || cca.mode > NL802154_CCA_ATTR_MAX) 645 return -EINVAL; 646 647 if (cca.mode == NL802154_CCA_ENERGY_CARRIER) { 648 if (!info->attrs[NL802154_ATTR_CCA_OPT]) 649 return -EINVAL; 650 651 cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]); 652 if (cca.opt > NL802154_CCA_OPT_ATTR_MAX) 653 return -EINVAL; 654 } 655 656 return rdev_set_cca_mode(rdev, &cca); 657 } 658 659 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info) 660 { 661 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 662 struct net_device *dev = info->user_ptr[1]; 663 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 664 __le16 pan_id; 665 666 /* conflict here while tx/rx calls */ 667 if (netif_running(dev)) 668 return -EBUSY; 669 670 /* don't change address fields on monitor */ 671 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) 672 return -EINVAL; 673 674 if (!info->attrs[NL802154_ATTR_PAN_ID]) 675 return -EINVAL; 676 677 pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); 678 679 return rdev_set_pan_id(rdev, wpan_dev, pan_id); 680 } 681 682 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info) 683 { 684 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 685 struct net_device *dev = info->user_ptr[1]; 686 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 687 __le16 short_addr; 688 689 /* conflict here while tx/rx calls */ 690 if (netif_running(dev)) 691 return -EBUSY; 692 693 /* don't change address fields on monitor */ 694 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR) 695 return -EINVAL; 696 697 if (!info->attrs[NL802154_ATTR_SHORT_ADDR]) 698 return -EINVAL; 699 700 short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]); 701 702 return rdev_set_short_addr(rdev, wpan_dev, short_addr); 703 } 704 705 static int 706 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info) 707 { 708 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 709 struct net_device *dev = info->user_ptr[1]; 710 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 711 u8 min_be, max_be; 712 713 /* should be set on netif open inside phy settings */ 714 if (netif_running(dev)) 715 return -EBUSY; 716 717 if (!info->attrs[NL802154_ATTR_MIN_BE] || 718 !info->attrs[NL802154_ATTR_MAX_BE]) 719 return -EINVAL; 720 721 min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]); 722 max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]); 723 724 /* check 802.15.4 constraints */ 725 if (max_be < 3 || max_be > 8 || min_be > max_be) 726 return -EINVAL; 727 728 return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be); 729 } 730 731 static int 732 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info) 733 { 734 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 735 struct net_device *dev = info->user_ptr[1]; 736 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 737 u8 max_csma_backoffs; 738 739 /* conflict here while other running iface settings */ 740 if (netif_running(dev)) 741 return -EBUSY; 742 743 if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]) 744 return -EINVAL; 745 746 max_csma_backoffs = nla_get_u8( 747 info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]); 748 749 /* check 802.15.4 constraints */ 750 if (max_csma_backoffs > 5) 751 return -EINVAL; 752 753 return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs); 754 } 755 756 static int 757 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info) 758 { 759 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 760 struct net_device *dev = info->user_ptr[1]; 761 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 762 s8 max_frame_retries; 763 764 if (netif_running(dev)) 765 return -EBUSY; 766 767 if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]) 768 return -EINVAL; 769 770 max_frame_retries = nla_get_s8( 771 info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]); 772 773 /* check 802.15.4 constraints */ 774 if (max_frame_retries < -1 || max_frame_retries > 7) 775 return -EINVAL; 776 777 return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries); 778 } 779 780 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) 781 { 782 struct cfg802154_registered_device *rdev = info->user_ptr[0]; 783 struct net_device *dev = info->user_ptr[1]; 784 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 785 bool mode; 786 787 if (netif_running(dev)) 788 return -EBUSY; 789 790 if (!info->attrs[NL802154_ATTR_LBT_MODE]) 791 return -EINVAL; 792 793 mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]); 794 return rdev_set_lbt_mode(rdev, wpan_dev, mode); 795 } 796 797 #define NL802154_FLAG_NEED_WPAN_PHY 0x01 798 #define NL802154_FLAG_NEED_NETDEV 0x02 799 #define NL802154_FLAG_NEED_RTNL 0x04 800 #define NL802154_FLAG_CHECK_NETDEV_UP 0x08 801 #define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\ 802 NL802154_FLAG_CHECK_NETDEV_UP) 803 #define NL802154_FLAG_NEED_WPAN_DEV 0x10 804 #define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\ 805 NL802154_FLAG_CHECK_NETDEV_UP) 806 807 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb, 808 struct genl_info *info) 809 { 810 struct cfg802154_registered_device *rdev; 811 struct wpan_dev *wpan_dev; 812 struct net_device *dev; 813 bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL; 814 815 if (rtnl) 816 rtnl_lock(); 817 818 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) { 819 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info); 820 if (IS_ERR(rdev)) { 821 if (rtnl) 822 rtnl_unlock(); 823 return PTR_ERR(rdev); 824 } 825 info->user_ptr[0] = rdev; 826 } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV || 827 ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) { 828 ASSERT_RTNL(); 829 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info), 830 info->attrs); 831 if (IS_ERR(wpan_dev)) { 832 if (rtnl) 833 rtnl_unlock(); 834 return PTR_ERR(wpan_dev); 835 } 836 837 dev = wpan_dev->netdev; 838 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy); 839 840 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) { 841 if (!dev) { 842 if (rtnl) 843 rtnl_unlock(); 844 return -EINVAL; 845 } 846 847 info->user_ptr[1] = dev; 848 } else { 849 info->user_ptr[1] = wpan_dev; 850 } 851 852 if (dev) { 853 if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP && 854 !netif_running(dev)) { 855 if (rtnl) 856 rtnl_unlock(); 857 return -ENETDOWN; 858 } 859 860 dev_hold(dev); 861 } 862 863 info->user_ptr[0] = rdev; 864 } 865 866 return 0; 867 } 868 869 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb, 870 struct genl_info *info) 871 { 872 if (info->user_ptr[1]) { 873 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) { 874 struct wpan_dev *wpan_dev = info->user_ptr[1]; 875 876 if (wpan_dev->netdev) 877 dev_put(wpan_dev->netdev); 878 } else { 879 dev_put(info->user_ptr[1]); 880 } 881 } 882 883 if (ops->internal_flags & NL802154_FLAG_NEED_RTNL) 884 rtnl_unlock(); 885 } 886 887 static const struct genl_ops nl802154_ops[] = { 888 { 889 .cmd = NL802154_CMD_GET_WPAN_PHY, 890 .doit = nl802154_get_wpan_phy, 891 .dumpit = nl802154_dump_wpan_phy, 892 .done = nl802154_dump_wpan_phy_done, 893 .policy = nl802154_policy, 894 /* can be retrieved by unprivileged users */ 895 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 896 NL802154_FLAG_NEED_RTNL, 897 }, 898 { 899 .cmd = NL802154_CMD_GET_INTERFACE, 900 .doit = nl802154_get_interface, 901 .dumpit = nl802154_dump_interface, 902 .policy = nl802154_policy, 903 /* can be retrieved by unprivileged users */ 904 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | 905 NL802154_FLAG_NEED_RTNL, 906 }, 907 { 908 .cmd = NL802154_CMD_NEW_INTERFACE, 909 .doit = nl802154_new_interface, 910 .policy = nl802154_policy, 911 .flags = GENL_ADMIN_PERM, 912 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 913 NL802154_FLAG_NEED_RTNL, 914 }, 915 { 916 .cmd = NL802154_CMD_DEL_INTERFACE, 917 .doit = nl802154_del_interface, 918 .policy = nl802154_policy, 919 .flags = GENL_ADMIN_PERM, 920 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV | 921 NL802154_FLAG_NEED_RTNL, 922 }, 923 { 924 .cmd = NL802154_CMD_SET_CHANNEL, 925 .doit = nl802154_set_channel, 926 .policy = nl802154_policy, 927 .flags = GENL_ADMIN_PERM, 928 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 929 NL802154_FLAG_NEED_RTNL, 930 }, 931 { 932 .cmd = NL802154_CMD_SET_CCA_MODE, 933 .doit = nl802154_set_cca_mode, 934 .policy = nl802154_policy, 935 .flags = GENL_ADMIN_PERM, 936 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY | 937 NL802154_FLAG_NEED_RTNL, 938 }, 939 { 940 .cmd = NL802154_CMD_SET_PAN_ID, 941 .doit = nl802154_set_pan_id, 942 .policy = nl802154_policy, 943 .flags = GENL_ADMIN_PERM, 944 .internal_flags = NL802154_FLAG_NEED_NETDEV | 945 NL802154_FLAG_NEED_RTNL, 946 }, 947 { 948 .cmd = NL802154_CMD_SET_SHORT_ADDR, 949 .doit = nl802154_set_short_addr, 950 .policy = nl802154_policy, 951 .flags = GENL_ADMIN_PERM, 952 .internal_flags = NL802154_FLAG_NEED_NETDEV | 953 NL802154_FLAG_NEED_RTNL, 954 }, 955 { 956 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT, 957 .doit = nl802154_set_backoff_exponent, 958 .policy = nl802154_policy, 959 .flags = GENL_ADMIN_PERM, 960 .internal_flags = NL802154_FLAG_NEED_NETDEV | 961 NL802154_FLAG_NEED_RTNL, 962 }, 963 { 964 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS, 965 .doit = nl802154_set_max_csma_backoffs, 966 .policy = nl802154_policy, 967 .flags = GENL_ADMIN_PERM, 968 .internal_flags = NL802154_FLAG_NEED_NETDEV | 969 NL802154_FLAG_NEED_RTNL, 970 }, 971 { 972 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES, 973 .doit = nl802154_set_max_frame_retries, 974 .policy = nl802154_policy, 975 .flags = GENL_ADMIN_PERM, 976 .internal_flags = NL802154_FLAG_NEED_NETDEV | 977 NL802154_FLAG_NEED_RTNL, 978 }, 979 { 980 .cmd = NL802154_CMD_SET_LBT_MODE, 981 .doit = nl802154_set_lbt_mode, 982 .policy = nl802154_policy, 983 .flags = GENL_ADMIN_PERM, 984 .internal_flags = NL802154_FLAG_NEED_NETDEV | 985 NL802154_FLAG_NEED_RTNL, 986 }, 987 }; 988 989 /* initialisation/exit functions */ 990 int nl802154_init(void) 991 { 992 return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops, 993 nl802154_mcgrps); 994 } 995 996 void nl802154_exit(void) 997 { 998 genl_unregister_family(&nl802154_fam); 999 } 1000