1 /* 2 * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/if_arp.h> 13 #include <linux/rtnetlink.h> 14 #include <linux/etherdevice.h> 15 #include <net/genetlink.h> 16 #include <net/ncsi.h> 17 #include <linux/skbuff.h> 18 #include <net/sock.h> 19 #include <uapi/linux/ncsi.h> 20 21 #include "internal.h" 22 #include "ncsi-pkt.h" 23 #include "ncsi-netlink.h" 24 25 static struct genl_family ncsi_genl_family; 26 27 static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = { 28 [NCSI_ATTR_IFINDEX] = { .type = NLA_U32 }, 29 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, 30 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, 31 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, 32 [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 }, 33 [NCSI_ATTR_MULTI_FLAG] = { .type = NLA_FLAG }, 34 [NCSI_ATTR_PACKAGE_MASK] = { .type = NLA_U32 }, 35 [NCSI_ATTR_CHANNEL_MASK] = { .type = NLA_U32 }, 36 }; 37 38 static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 39 { 40 struct ncsi_dev_priv *ndp; 41 struct net_device *dev; 42 struct ncsi_dev *nd; 43 struct ncsi_dev; 44 45 if (!net) 46 return NULL; 47 48 dev = dev_get_by_index(net, ifindex); 49 if (!dev) { 50 pr_err("NCSI netlink: No device for ifindex %u\n", ifindex); 51 return NULL; 52 } 53 54 nd = ncsi_find_dev(dev); 55 ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL; 56 57 dev_put(dev); 58 return ndp; 59 } 60 61 static int ncsi_write_channel_info(struct sk_buff *skb, 62 struct ncsi_dev_priv *ndp, 63 struct ncsi_channel *nc) 64 { 65 struct ncsi_channel_vlan_filter *ncf; 66 struct ncsi_channel_mode *m; 67 struct nlattr *vid_nest; 68 int i; 69 70 nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id); 71 m = &nc->modes[NCSI_MODE_LINK]; 72 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]); 73 if (nc->state == NCSI_CHANNEL_ACTIVE) 74 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE); 75 if (nc == nc->package->preferred_channel) 76 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); 77 78 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version); 79 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2); 80 nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); 81 82 vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); 83 if (!vid_nest) 84 return -ENOMEM; 85 ncf = &nc->vlan_filter; 86 i = -1; 87 while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids, 88 i + 1)) < ncf->n_vids) { 89 if (ncf->vids[i]) 90 nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID, 91 ncf->vids[i]); 92 } 93 nla_nest_end(skb, vid_nest); 94 95 return 0; 96 } 97 98 static int ncsi_write_package_info(struct sk_buff *skb, 99 struct ncsi_dev_priv *ndp, unsigned int id) 100 { 101 struct nlattr *pnest, *cnest, *nest; 102 struct ncsi_package *np; 103 struct ncsi_channel *nc; 104 bool found; 105 int rc; 106 107 if (id > ndp->package_num - 1) { 108 netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id); 109 return -ENODEV; 110 } 111 112 found = false; 113 NCSI_FOR_EACH_PACKAGE(ndp, np) { 114 if (np->id != id) 115 continue; 116 pnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR); 117 if (!pnest) 118 return -ENOMEM; 119 nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id); 120 if ((0x1 << np->id) == ndp->package_whitelist) 121 nla_put_flag(skb, NCSI_PKG_ATTR_FORCED); 122 cnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR_CHANNEL_LIST); 123 if (!cnest) { 124 nla_nest_cancel(skb, pnest); 125 return -ENOMEM; 126 } 127 NCSI_FOR_EACH_CHANNEL(np, nc) { 128 nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR); 129 if (!nest) { 130 nla_nest_cancel(skb, cnest); 131 nla_nest_cancel(skb, pnest); 132 return -ENOMEM; 133 } 134 rc = ncsi_write_channel_info(skb, ndp, nc); 135 if (rc) { 136 nla_nest_cancel(skb, nest); 137 nla_nest_cancel(skb, cnest); 138 nla_nest_cancel(skb, pnest); 139 return rc; 140 } 141 nla_nest_end(skb, nest); 142 } 143 nla_nest_end(skb, cnest); 144 nla_nest_end(skb, pnest); 145 found = true; 146 } 147 148 if (!found) 149 return -ENODEV; 150 151 return 0; 152 } 153 154 static int ncsi_pkg_info_nl(struct sk_buff *msg, struct genl_info *info) 155 { 156 struct ncsi_dev_priv *ndp; 157 unsigned int package_id; 158 struct sk_buff *skb; 159 struct nlattr *attr; 160 void *hdr; 161 int rc; 162 163 if (!info || !info->attrs) 164 return -EINVAL; 165 166 if (!info->attrs[NCSI_ATTR_IFINDEX]) 167 return -EINVAL; 168 169 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 170 return -EINVAL; 171 172 ndp = ndp_from_ifindex(genl_info_net(info), 173 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 174 if (!ndp) 175 return -ENODEV; 176 177 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 178 if (!skb) 179 return -ENOMEM; 180 181 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, 182 &ncsi_genl_family, 0, NCSI_CMD_PKG_INFO); 183 if (!hdr) { 184 kfree_skb(skb); 185 return -EMSGSIZE; 186 } 187 188 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 189 190 attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST); 191 if (!attr) { 192 kfree_skb(skb); 193 return -EMSGSIZE; 194 } 195 rc = ncsi_write_package_info(skb, ndp, package_id); 196 197 if (rc) { 198 nla_nest_cancel(skb, attr); 199 goto err; 200 } 201 202 nla_nest_end(skb, attr); 203 204 genlmsg_end(skb, hdr); 205 return genlmsg_reply(skb, info); 206 207 err: 208 kfree_skb(skb); 209 return rc; 210 } 211 212 static int ncsi_pkg_info_all_nl(struct sk_buff *skb, 213 struct netlink_callback *cb) 214 { 215 struct nlattr *attrs[NCSI_ATTR_MAX + 1]; 216 struct ncsi_package *np, *package; 217 struct ncsi_dev_priv *ndp; 218 unsigned int package_id; 219 struct nlattr *attr; 220 void *hdr; 221 int rc; 222 223 rc = genlmsg_parse_deprecated(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX, 224 ncsi_genl_policy, NULL); 225 if (rc) 226 return rc; 227 228 if (!attrs[NCSI_ATTR_IFINDEX]) 229 return -EINVAL; 230 231 ndp = ndp_from_ifindex(get_net(sock_net(skb->sk)), 232 nla_get_u32(attrs[NCSI_ATTR_IFINDEX])); 233 234 if (!ndp) 235 return -ENODEV; 236 237 package_id = cb->args[0]; 238 package = NULL; 239 NCSI_FOR_EACH_PACKAGE(ndp, np) 240 if (np->id == package_id) 241 package = np; 242 243 if (!package) 244 return 0; /* done */ 245 246 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 247 &ncsi_genl_family, NLM_F_MULTI, NCSI_CMD_PKG_INFO); 248 if (!hdr) { 249 rc = -EMSGSIZE; 250 goto err; 251 } 252 253 attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST); 254 if (!attr) { 255 rc = -EMSGSIZE; 256 goto err; 257 } 258 rc = ncsi_write_package_info(skb, ndp, package->id); 259 if (rc) { 260 nla_nest_cancel(skb, attr); 261 goto err; 262 } 263 264 nla_nest_end(skb, attr); 265 genlmsg_end(skb, hdr); 266 267 cb->args[0] = package_id + 1; 268 269 return skb->len; 270 err: 271 genlmsg_cancel(skb, hdr); 272 return rc; 273 } 274 275 static int ncsi_set_interface_nl(struct sk_buff *msg, struct genl_info *info) 276 { 277 struct ncsi_package *np, *package; 278 struct ncsi_channel *nc, *channel; 279 u32 package_id, channel_id; 280 struct ncsi_dev_priv *ndp; 281 unsigned long flags; 282 283 if (!info || !info->attrs) 284 return -EINVAL; 285 286 if (!info->attrs[NCSI_ATTR_IFINDEX]) 287 return -EINVAL; 288 289 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 290 return -EINVAL; 291 292 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 293 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 294 if (!ndp) 295 return -ENODEV; 296 297 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 298 package = NULL; 299 300 NCSI_FOR_EACH_PACKAGE(ndp, np) 301 if (np->id == package_id) 302 package = np; 303 if (!package) { 304 /* The user has set a package that does not exist */ 305 return -ERANGE; 306 } 307 308 channel = NULL; 309 if (info->attrs[NCSI_ATTR_CHANNEL_ID]) { 310 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 311 NCSI_FOR_EACH_CHANNEL(package, nc) 312 if (nc->id == channel_id) { 313 channel = nc; 314 break; 315 } 316 if (!channel) { 317 netdev_info(ndp->ndev.dev, 318 "NCSI: Channel %u does not exist!\n", 319 channel_id); 320 return -ERANGE; 321 } 322 } 323 324 spin_lock_irqsave(&ndp->lock, flags); 325 ndp->package_whitelist = 0x1 << package->id; 326 ndp->multi_package = false; 327 spin_unlock_irqrestore(&ndp->lock, flags); 328 329 spin_lock_irqsave(&package->lock, flags); 330 package->multi_channel = false; 331 if (channel) { 332 package->channel_whitelist = 0x1 << channel->id; 333 package->preferred_channel = channel; 334 } else { 335 /* Allow any channel */ 336 package->channel_whitelist = UINT_MAX; 337 package->preferred_channel = NULL; 338 } 339 spin_unlock_irqrestore(&package->lock, flags); 340 341 if (channel) 342 netdev_info(ndp->ndev.dev, 343 "Set package 0x%x, channel 0x%x as preferred\n", 344 package_id, channel_id); 345 else 346 netdev_info(ndp->ndev.dev, "Set package 0x%x as preferred\n", 347 package_id); 348 349 /* Update channel configuration */ 350 if (!(ndp->flags & NCSI_DEV_RESET)) 351 ncsi_reset_dev(&ndp->ndev); 352 353 return 0; 354 } 355 356 static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info) 357 { 358 struct ncsi_dev_priv *ndp; 359 struct ncsi_package *np; 360 unsigned long flags; 361 362 if (!info || !info->attrs) 363 return -EINVAL; 364 365 if (!info->attrs[NCSI_ATTR_IFINDEX]) 366 return -EINVAL; 367 368 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 369 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 370 if (!ndp) 371 return -ENODEV; 372 373 /* Reset any whitelists and disable multi mode */ 374 spin_lock_irqsave(&ndp->lock, flags); 375 ndp->package_whitelist = UINT_MAX; 376 ndp->multi_package = false; 377 spin_unlock_irqrestore(&ndp->lock, flags); 378 379 NCSI_FOR_EACH_PACKAGE(ndp, np) { 380 spin_lock_irqsave(&np->lock, flags); 381 np->multi_channel = false; 382 np->channel_whitelist = UINT_MAX; 383 np->preferred_channel = NULL; 384 spin_unlock_irqrestore(&np->lock, flags); 385 } 386 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n"); 387 388 /* Update channel configuration */ 389 if (!(ndp->flags & NCSI_DEV_RESET)) 390 ncsi_reset_dev(&ndp->ndev); 391 392 return 0; 393 } 394 395 static int ncsi_send_cmd_nl(struct sk_buff *msg, struct genl_info *info) 396 { 397 struct ncsi_dev_priv *ndp; 398 struct ncsi_pkt_hdr *hdr; 399 struct ncsi_cmd_arg nca; 400 unsigned char *data; 401 u32 package_id; 402 u32 channel_id; 403 int len, ret; 404 405 if (!info || !info->attrs) { 406 ret = -EINVAL; 407 goto out; 408 } 409 410 if (!info->attrs[NCSI_ATTR_IFINDEX]) { 411 ret = -EINVAL; 412 goto out; 413 } 414 415 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) { 416 ret = -EINVAL; 417 goto out; 418 } 419 420 if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) { 421 ret = -EINVAL; 422 goto out; 423 } 424 425 if (!info->attrs[NCSI_ATTR_DATA]) { 426 ret = -EINVAL; 427 goto out; 428 } 429 430 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 431 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 432 if (!ndp) { 433 ret = -ENODEV; 434 goto out; 435 } 436 437 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 438 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 439 440 if (package_id >= NCSI_MAX_PACKAGE || channel_id >= NCSI_MAX_CHANNEL) { 441 ret = -ERANGE; 442 goto out_netlink; 443 } 444 445 len = nla_len(info->attrs[NCSI_ATTR_DATA]); 446 if (len < sizeof(struct ncsi_pkt_hdr)) { 447 netdev_info(ndp->ndev.dev, "NCSI: no command to send %u\n", 448 package_id); 449 ret = -EINVAL; 450 goto out_netlink; 451 } else { 452 data = (unsigned char *)nla_data(info->attrs[NCSI_ATTR_DATA]); 453 } 454 455 hdr = (struct ncsi_pkt_hdr *)data; 456 457 nca.ndp = ndp; 458 nca.package = (unsigned char)package_id; 459 nca.channel = (unsigned char)channel_id; 460 nca.type = hdr->type; 461 nca.req_flags = NCSI_REQ_FLAG_NETLINK_DRIVEN; 462 nca.info = info; 463 nca.payload = ntohs(hdr->length); 464 nca.data = data + sizeof(*hdr); 465 466 ret = ncsi_xmit_cmd(&nca); 467 out_netlink: 468 if (ret != 0) { 469 netdev_err(ndp->ndev.dev, 470 "NCSI: Error %d sending command\n", 471 ret); 472 ncsi_send_netlink_err(ndp->ndev.dev, 473 info->snd_seq, 474 info->snd_portid, 475 info->nlhdr, 476 ret); 477 } 478 out: 479 return ret; 480 } 481 482 int ncsi_send_netlink_rsp(struct ncsi_request *nr, 483 struct ncsi_package *np, 484 struct ncsi_channel *nc) 485 { 486 struct sk_buff *skb; 487 struct net *net; 488 void *hdr; 489 int rc; 490 491 net = dev_net(nr->rsp->dev); 492 493 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 494 if (!skb) 495 return -ENOMEM; 496 497 hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq, 498 &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD); 499 if (!hdr) { 500 kfree_skb(skb); 501 return -EMSGSIZE; 502 } 503 504 nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex); 505 if (np) 506 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id); 507 if (nc) 508 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id); 509 else 510 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL); 511 512 rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data); 513 if (rc) 514 goto err; 515 516 genlmsg_end(skb, hdr); 517 return genlmsg_unicast(net, skb, nr->snd_portid); 518 519 err: 520 kfree_skb(skb); 521 return rc; 522 } 523 524 int ncsi_send_netlink_timeout(struct ncsi_request *nr, 525 struct ncsi_package *np, 526 struct ncsi_channel *nc) 527 { 528 struct sk_buff *skb; 529 struct net *net; 530 void *hdr; 531 532 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 533 if (!skb) 534 return -ENOMEM; 535 536 hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq, 537 &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD); 538 if (!hdr) { 539 kfree_skb(skb); 540 return -EMSGSIZE; 541 } 542 543 net = dev_net(nr->cmd->dev); 544 545 nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex); 546 547 if (np) 548 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id); 549 else 550 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, 551 NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *) 552 nr->cmd->data)->channel))); 553 554 if (nc) 555 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id); 556 else 557 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL); 558 559 genlmsg_end(skb, hdr); 560 return genlmsg_unicast(net, skb, nr->snd_portid); 561 } 562 563 int ncsi_send_netlink_err(struct net_device *dev, 564 u32 snd_seq, 565 u32 snd_portid, 566 struct nlmsghdr *nlhdr, 567 int err) 568 { 569 struct nlmsghdr *nlh; 570 struct nlmsgerr *nle; 571 struct sk_buff *skb; 572 struct net *net; 573 574 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 575 if (!skb) 576 return -ENOMEM; 577 578 net = dev_net(dev); 579 580 nlh = nlmsg_put(skb, snd_portid, snd_seq, 581 NLMSG_ERROR, sizeof(*nle), 0); 582 nle = (struct nlmsgerr *)nlmsg_data(nlh); 583 nle->error = err; 584 memcpy(&nle->msg, nlhdr, sizeof(*nlh)); 585 586 nlmsg_end(skb, nlh); 587 588 return nlmsg_unicast(net->genl_sock, skb, snd_portid); 589 } 590 591 static int ncsi_set_package_mask_nl(struct sk_buff *msg, 592 struct genl_info *info) 593 { 594 struct ncsi_dev_priv *ndp; 595 unsigned long flags; 596 int rc; 597 598 if (!info || !info->attrs) 599 return -EINVAL; 600 601 if (!info->attrs[NCSI_ATTR_IFINDEX]) 602 return -EINVAL; 603 604 if (!info->attrs[NCSI_ATTR_PACKAGE_MASK]) 605 return -EINVAL; 606 607 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 608 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 609 if (!ndp) 610 return -ENODEV; 611 612 spin_lock_irqsave(&ndp->lock, flags); 613 if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) { 614 if (ndp->flags & NCSI_DEV_HWA) { 615 ndp->multi_package = true; 616 rc = 0; 617 } else { 618 netdev_err(ndp->ndev.dev, 619 "NCSI: Can't use multiple packages without HWA\n"); 620 rc = -EPERM; 621 } 622 } else { 623 ndp->multi_package = false; 624 rc = 0; 625 } 626 627 if (!rc) 628 ndp->package_whitelist = 629 nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_MASK]); 630 spin_unlock_irqrestore(&ndp->lock, flags); 631 632 if (!rc) { 633 /* Update channel configuration */ 634 if (!(ndp->flags & NCSI_DEV_RESET)) 635 ncsi_reset_dev(&ndp->ndev); 636 } 637 638 return rc; 639 } 640 641 static int ncsi_set_channel_mask_nl(struct sk_buff *msg, 642 struct genl_info *info) 643 { 644 struct ncsi_package *np, *package; 645 struct ncsi_channel *nc, *channel; 646 u32 package_id, channel_id; 647 struct ncsi_dev_priv *ndp; 648 unsigned long flags; 649 650 if (!info || !info->attrs) 651 return -EINVAL; 652 653 if (!info->attrs[NCSI_ATTR_IFINDEX]) 654 return -EINVAL; 655 656 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 657 return -EINVAL; 658 659 if (!info->attrs[NCSI_ATTR_CHANNEL_MASK]) 660 return -EINVAL; 661 662 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 663 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 664 if (!ndp) 665 return -ENODEV; 666 667 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 668 package = NULL; 669 NCSI_FOR_EACH_PACKAGE(ndp, np) 670 if (np->id == package_id) { 671 package = np; 672 break; 673 } 674 if (!package) 675 return -ERANGE; 676 677 spin_lock_irqsave(&package->lock, flags); 678 679 channel = NULL; 680 if (info->attrs[NCSI_ATTR_CHANNEL_ID]) { 681 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 682 NCSI_FOR_EACH_CHANNEL(np, nc) 683 if (nc->id == channel_id) { 684 channel = nc; 685 break; 686 } 687 if (!channel) { 688 spin_unlock_irqrestore(&package->lock, flags); 689 return -ERANGE; 690 } 691 netdev_dbg(ndp->ndev.dev, 692 "NCSI: Channel %u set as preferred channel\n", 693 channel->id); 694 } 695 696 package->channel_whitelist = 697 nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_MASK]); 698 if (package->channel_whitelist == 0) 699 netdev_dbg(ndp->ndev.dev, 700 "NCSI: Package %u set to all channels disabled\n", 701 package->id); 702 703 package->preferred_channel = channel; 704 705 if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) { 706 package->multi_channel = true; 707 netdev_info(ndp->ndev.dev, 708 "NCSI: Multi-channel enabled on package %u\n", 709 package_id); 710 } else { 711 package->multi_channel = false; 712 } 713 714 spin_unlock_irqrestore(&package->lock, flags); 715 716 /* Update channel configuration */ 717 if (!(ndp->flags & NCSI_DEV_RESET)) 718 ncsi_reset_dev(&ndp->ndev); 719 720 return 0; 721 } 722 723 static const struct genl_ops ncsi_ops[] = { 724 { 725 .cmd = NCSI_CMD_PKG_INFO, 726 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 727 .doit = ncsi_pkg_info_nl, 728 .dumpit = ncsi_pkg_info_all_nl, 729 .flags = 0, 730 }, 731 { 732 .cmd = NCSI_CMD_SET_INTERFACE, 733 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 734 .doit = ncsi_set_interface_nl, 735 .flags = GENL_ADMIN_PERM, 736 }, 737 { 738 .cmd = NCSI_CMD_CLEAR_INTERFACE, 739 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 740 .doit = ncsi_clear_interface_nl, 741 .flags = GENL_ADMIN_PERM, 742 }, 743 { 744 .cmd = NCSI_CMD_SEND_CMD, 745 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 746 .doit = ncsi_send_cmd_nl, 747 .flags = GENL_ADMIN_PERM, 748 }, 749 { 750 .cmd = NCSI_CMD_SET_PACKAGE_MASK, 751 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 752 .doit = ncsi_set_package_mask_nl, 753 .flags = GENL_ADMIN_PERM, 754 }, 755 { 756 .cmd = NCSI_CMD_SET_CHANNEL_MASK, 757 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 758 .doit = ncsi_set_channel_mask_nl, 759 .flags = GENL_ADMIN_PERM, 760 }, 761 }; 762 763 static struct genl_family ncsi_genl_family __ro_after_init = { 764 .name = "NCSI", 765 .version = 0, 766 .maxattr = NCSI_ATTR_MAX, 767 .policy = ncsi_genl_policy, 768 .module = THIS_MODULE, 769 .ops = ncsi_ops, 770 .n_ops = ARRAY_SIZE(ncsi_ops), 771 }; 772 773 int ncsi_init_netlink(struct net_device *dev) 774 { 775 int rc; 776 777 rc = genl_register_family(&ncsi_genl_family); 778 if (rc) 779 netdev_err(dev, "ncsi: failed to register netlink family\n"); 780 781 return rc; 782 } 783 784 int ncsi_unregister_netlink(struct net_device *dev) 785 { 786 int rc; 787 788 rc = genl_unregister_family(&ncsi_genl_family); 789 if (rc) 790 netdev_err(dev, "ncsi: failed to unregister netlink family\n"); 791 792 return rc; 793 } 794