1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018. 4 */ 5 6 #include <linux/module.h> 7 #include <linux/kernel.h> 8 #include <linux/if_arp.h> 9 #include <linux/rtnetlink.h> 10 #include <linux/etherdevice.h> 11 #include <net/genetlink.h> 12 #include <net/ncsi.h> 13 #include <linux/skbuff.h> 14 #include <net/sock.h> 15 #include <uapi/linux/ncsi.h> 16 17 #include "internal.h" 18 #include "ncsi-pkt.h" 19 #include "ncsi-netlink.h" 20 21 static struct genl_family ncsi_genl_family; 22 23 static const struct nla_policy ncsi_genl_policy[NCSI_ATTR_MAX + 1] = { 24 [NCSI_ATTR_IFINDEX] = { .type = NLA_U32 }, 25 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED }, 26 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 }, 27 [NCSI_ATTR_CHANNEL_ID] = { .type = NLA_U32 }, 28 [NCSI_ATTR_DATA] = { .type = NLA_BINARY, .len = 2048 }, 29 [NCSI_ATTR_MULTI_FLAG] = { .type = NLA_FLAG }, 30 [NCSI_ATTR_PACKAGE_MASK] = { .type = NLA_U32 }, 31 [NCSI_ATTR_CHANNEL_MASK] = { .type = NLA_U32 }, 32 }; 33 34 static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex) 35 { 36 struct ncsi_dev_priv *ndp; 37 struct net_device *dev; 38 struct ncsi_dev *nd; 39 struct ncsi_dev; 40 41 if (!net) 42 return NULL; 43 44 dev = dev_get_by_index(net, ifindex); 45 if (!dev) { 46 pr_err("NCSI netlink: No device for ifindex %u\n", ifindex); 47 return NULL; 48 } 49 50 nd = ncsi_find_dev(dev); 51 ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL; 52 53 dev_put(dev); 54 return ndp; 55 } 56 57 static int ncsi_write_channel_info(struct sk_buff *skb, 58 struct ncsi_dev_priv *ndp, 59 struct ncsi_channel *nc) 60 { 61 struct ncsi_channel_vlan_filter *ncf; 62 struct ncsi_channel_mode *m; 63 struct nlattr *vid_nest; 64 int i; 65 66 nla_put_u32(skb, NCSI_CHANNEL_ATTR_ID, nc->id); 67 m = &nc->modes[NCSI_MODE_LINK]; 68 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]); 69 if (nc->state == NCSI_CHANNEL_ACTIVE) 70 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE); 71 if (nc == nc->package->preferred_channel) 72 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED); 73 74 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.major); 75 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.minor); 76 nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name); 77 78 vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST); 79 if (!vid_nest) 80 return -ENOMEM; 81 ncf = &nc->vlan_filter; 82 i = -1; 83 while ((i = find_next_bit((void *)&ncf->bitmap, ncf->n_vids, 84 i + 1)) < ncf->n_vids) { 85 if (ncf->vids[i]) 86 nla_put_u16(skb, NCSI_CHANNEL_ATTR_VLAN_ID, 87 ncf->vids[i]); 88 } 89 nla_nest_end(skb, vid_nest); 90 91 return 0; 92 } 93 94 static int ncsi_write_package_info(struct sk_buff *skb, 95 struct ncsi_dev_priv *ndp, unsigned int id) 96 { 97 struct nlattr *pnest, *cnest, *nest; 98 struct ncsi_package *np; 99 struct ncsi_channel *nc; 100 bool found; 101 int rc; 102 103 if (id > ndp->package_num - 1) { 104 netdev_info(ndp->ndev.dev, "NCSI: No package with id %u\n", id); 105 return -ENODEV; 106 } 107 108 found = false; 109 NCSI_FOR_EACH_PACKAGE(ndp, np) { 110 if (np->id != id) 111 continue; 112 pnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR); 113 if (!pnest) 114 return -ENOMEM; 115 rc = nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id); 116 if (rc) { 117 nla_nest_cancel(skb, pnest); 118 return rc; 119 } 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 if (nca.payload > len - sizeof(*hdr)) { 465 ret = -EINVAL; 466 goto out_netlink; 467 } 468 nca.data = data + sizeof(*hdr); 469 470 ret = ncsi_xmit_cmd(&nca); 471 out_netlink: 472 if (ret != 0) { 473 netdev_err(ndp->ndev.dev, 474 "NCSI: Error %d sending command\n", 475 ret); 476 ncsi_send_netlink_err(ndp->ndev.dev, 477 info->snd_seq, 478 info->snd_portid, 479 info->nlhdr, 480 ret); 481 } 482 out: 483 return ret; 484 } 485 486 int ncsi_send_netlink_rsp(struct ncsi_request *nr, 487 struct ncsi_package *np, 488 struct ncsi_channel *nc) 489 { 490 struct sk_buff *skb; 491 struct net *net; 492 void *hdr; 493 int rc; 494 495 net = dev_net(nr->rsp->dev); 496 497 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 498 if (!skb) 499 return -ENOMEM; 500 501 hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq, 502 &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD); 503 if (!hdr) { 504 kfree_skb(skb); 505 return -EMSGSIZE; 506 } 507 508 nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->rsp->dev->ifindex); 509 if (np) 510 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id); 511 if (nc) 512 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id); 513 else 514 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL); 515 516 rc = nla_put(skb, NCSI_ATTR_DATA, nr->rsp->len, (void *)nr->rsp->data); 517 if (rc) 518 goto err; 519 520 genlmsg_end(skb, hdr); 521 return genlmsg_unicast(net, skb, nr->snd_portid); 522 523 err: 524 kfree_skb(skb); 525 return rc; 526 } 527 528 int ncsi_send_netlink_timeout(struct ncsi_request *nr, 529 struct ncsi_package *np, 530 struct ncsi_channel *nc) 531 { 532 struct sk_buff *skb; 533 struct net *net; 534 void *hdr; 535 536 skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 537 if (!skb) 538 return -ENOMEM; 539 540 hdr = genlmsg_put(skb, nr->snd_portid, nr->snd_seq, 541 &ncsi_genl_family, 0, NCSI_CMD_SEND_CMD); 542 if (!hdr) { 543 kfree_skb(skb); 544 return -EMSGSIZE; 545 } 546 547 net = dev_net(nr->cmd->dev); 548 549 nla_put_u32(skb, NCSI_ATTR_IFINDEX, nr->cmd->dev->ifindex); 550 551 if (np) 552 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, np->id); 553 else 554 nla_put_u32(skb, NCSI_ATTR_PACKAGE_ID, 555 NCSI_PACKAGE_INDEX((((struct ncsi_pkt_hdr *) 556 nr->cmd->data)->channel))); 557 558 if (nc) 559 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, nc->id); 560 else 561 nla_put_u32(skb, NCSI_ATTR_CHANNEL_ID, NCSI_RESERVED_CHANNEL); 562 563 genlmsg_end(skb, hdr); 564 return genlmsg_unicast(net, skb, nr->snd_portid); 565 } 566 567 int ncsi_send_netlink_err(struct net_device *dev, 568 u32 snd_seq, 569 u32 snd_portid, 570 const struct nlmsghdr *nlhdr, 571 int err) 572 { 573 struct nlmsghdr *nlh; 574 struct nlmsgerr *nle; 575 struct sk_buff *skb; 576 struct net *net; 577 578 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 579 if (!skb) 580 return -ENOMEM; 581 582 net = dev_net(dev); 583 584 nlh = nlmsg_put(skb, snd_portid, snd_seq, 585 NLMSG_ERROR, sizeof(*nle), 0); 586 nle = (struct nlmsgerr *)nlmsg_data(nlh); 587 nle->error = err; 588 memcpy(&nle->msg, nlhdr, sizeof(*nlh)); 589 590 nlmsg_end(skb, nlh); 591 592 return nlmsg_unicast(net->genl_sock, skb, snd_portid); 593 } 594 595 static int ncsi_set_package_mask_nl(struct sk_buff *msg, 596 struct genl_info *info) 597 { 598 struct ncsi_dev_priv *ndp; 599 unsigned long flags; 600 int rc; 601 602 if (!info || !info->attrs) 603 return -EINVAL; 604 605 if (!info->attrs[NCSI_ATTR_IFINDEX]) 606 return -EINVAL; 607 608 if (!info->attrs[NCSI_ATTR_PACKAGE_MASK]) 609 return -EINVAL; 610 611 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 612 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 613 if (!ndp) 614 return -ENODEV; 615 616 spin_lock_irqsave(&ndp->lock, flags); 617 if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) { 618 if (ndp->flags & NCSI_DEV_HWA) { 619 ndp->multi_package = true; 620 rc = 0; 621 } else { 622 netdev_err(ndp->ndev.dev, 623 "NCSI: Can't use multiple packages without HWA\n"); 624 rc = -EPERM; 625 } 626 } else { 627 ndp->multi_package = false; 628 rc = 0; 629 } 630 631 if (!rc) 632 ndp->package_whitelist = 633 nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_MASK]); 634 spin_unlock_irqrestore(&ndp->lock, flags); 635 636 if (!rc) { 637 /* Update channel configuration */ 638 if (!(ndp->flags & NCSI_DEV_RESET)) 639 ncsi_reset_dev(&ndp->ndev); 640 } 641 642 return rc; 643 } 644 645 static int ncsi_set_channel_mask_nl(struct sk_buff *msg, 646 struct genl_info *info) 647 { 648 struct ncsi_package *np, *package; 649 struct ncsi_channel *nc, *channel; 650 u32 package_id, channel_id; 651 struct ncsi_dev_priv *ndp; 652 unsigned long flags; 653 654 if (!info || !info->attrs) 655 return -EINVAL; 656 657 if (!info->attrs[NCSI_ATTR_IFINDEX]) 658 return -EINVAL; 659 660 if (!info->attrs[NCSI_ATTR_PACKAGE_ID]) 661 return -EINVAL; 662 663 if (!info->attrs[NCSI_ATTR_CHANNEL_MASK]) 664 return -EINVAL; 665 666 ndp = ndp_from_ifindex(get_net(sock_net(msg->sk)), 667 nla_get_u32(info->attrs[NCSI_ATTR_IFINDEX])); 668 if (!ndp) 669 return -ENODEV; 670 671 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]); 672 package = NULL; 673 NCSI_FOR_EACH_PACKAGE(ndp, np) 674 if (np->id == package_id) { 675 package = np; 676 break; 677 } 678 if (!package) 679 return -ERANGE; 680 681 spin_lock_irqsave(&package->lock, flags); 682 683 channel = NULL; 684 if (info->attrs[NCSI_ATTR_CHANNEL_ID]) { 685 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]); 686 NCSI_FOR_EACH_CHANNEL(np, nc) 687 if (nc->id == channel_id) { 688 channel = nc; 689 break; 690 } 691 if (!channel) { 692 spin_unlock_irqrestore(&package->lock, flags); 693 return -ERANGE; 694 } 695 netdev_dbg(ndp->ndev.dev, 696 "NCSI: Channel %u set as preferred channel\n", 697 channel->id); 698 } 699 700 package->channel_whitelist = 701 nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_MASK]); 702 if (package->channel_whitelist == 0) 703 netdev_dbg(ndp->ndev.dev, 704 "NCSI: Package %u set to all channels disabled\n", 705 package->id); 706 707 package->preferred_channel = channel; 708 709 if (nla_get_flag(info->attrs[NCSI_ATTR_MULTI_FLAG])) { 710 package->multi_channel = true; 711 netdev_info(ndp->ndev.dev, 712 "NCSI: Multi-channel enabled on package %u\n", 713 package_id); 714 } else { 715 package->multi_channel = false; 716 } 717 718 spin_unlock_irqrestore(&package->lock, flags); 719 720 /* Update channel configuration */ 721 if (!(ndp->flags & NCSI_DEV_RESET)) 722 ncsi_reset_dev(&ndp->ndev); 723 724 return 0; 725 } 726 727 static const struct genl_small_ops ncsi_ops[] = { 728 { 729 .cmd = NCSI_CMD_PKG_INFO, 730 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 731 .doit = ncsi_pkg_info_nl, 732 .dumpit = ncsi_pkg_info_all_nl, 733 .flags = 0, 734 }, 735 { 736 .cmd = NCSI_CMD_SET_INTERFACE, 737 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 738 .doit = ncsi_set_interface_nl, 739 .flags = GENL_ADMIN_PERM, 740 }, 741 { 742 .cmd = NCSI_CMD_CLEAR_INTERFACE, 743 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 744 .doit = ncsi_clear_interface_nl, 745 .flags = GENL_ADMIN_PERM, 746 }, 747 { 748 .cmd = NCSI_CMD_SEND_CMD, 749 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 750 .doit = ncsi_send_cmd_nl, 751 .flags = GENL_ADMIN_PERM, 752 }, 753 { 754 .cmd = NCSI_CMD_SET_PACKAGE_MASK, 755 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 756 .doit = ncsi_set_package_mask_nl, 757 .flags = GENL_ADMIN_PERM, 758 }, 759 { 760 .cmd = NCSI_CMD_SET_CHANNEL_MASK, 761 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, 762 .doit = ncsi_set_channel_mask_nl, 763 .flags = GENL_ADMIN_PERM, 764 }, 765 }; 766 767 static struct genl_family ncsi_genl_family __ro_after_init = { 768 .name = "NCSI", 769 .version = 0, 770 .maxattr = NCSI_ATTR_MAX, 771 .policy = ncsi_genl_policy, 772 .module = THIS_MODULE, 773 .small_ops = ncsi_ops, 774 .n_small_ops = ARRAY_SIZE(ncsi_ops), 775 .resv_start_op = NCSI_CMD_SET_CHANNEL_MASK + 1, 776 }; 777 778 static int __init ncsi_init_netlink(void) 779 { 780 return genl_register_family(&ncsi_genl_family); 781 } 782 subsys_initcall(ncsi_init_netlink); 783