hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/net/ncsi/ncsi-netlink.c
....@@ -1,10 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * 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.
84 */
95
106 #include <linux/module.h>
....@@ -12,7 +8,6 @@
128 #include <linux/if_arp.h>
139 #include <linux/rtnetlink.h>
1410 #include <linux/etherdevice.h>
15
-#include <linux/module.h>
1611 #include <net/genetlink.h>
1712 #include <net/ncsi.h>
1813 #include <linux/skbuff.h>
....@@ -20,6 +15,7 @@
2015 #include <uapi/linux/ncsi.h>
2116
2217 #include "internal.h"
18
+#include "ncsi-pkt.h"
2319 #include "ncsi-netlink.h"
2420
2521 static struct genl_family ncsi_genl_family;
....@@ -29,6 +25,10 @@
2925 [NCSI_ATTR_PACKAGE_LIST] = { .type = NLA_NESTED },
3026 [NCSI_ATTR_PACKAGE_ID] = { .type = NLA_U32 },
3127 [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 },
3232 };
3333
3434 static struct ncsi_dev_priv *ndp_from_ifindex(struct net *net, u32 ifindex)
....@@ -68,14 +68,14 @@
6868 nla_put_u32(skb, NCSI_CHANNEL_ATTR_LINK_STATE, m->data[2]);
6969 if (nc->state == NCSI_CHANNEL_ACTIVE)
7070 nla_put_flag(skb, NCSI_CHANNEL_ATTR_ACTIVE);
71
- if (ndp->force_channel == nc)
71
+ if (nc == nc->package->preferred_channel)
7272 nla_put_flag(skb, NCSI_CHANNEL_ATTR_FORCED);
7373
7474 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MAJOR, nc->version.version);
7575 nla_put_u32(skb, NCSI_CHANNEL_ATTR_VERSION_MINOR, nc->version.alpha2);
7676 nla_put_string(skb, NCSI_CHANNEL_ATTR_VERSION_STR, nc->version.fw_name);
7777
78
- vid_nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
78
+ vid_nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR_VLAN_LIST);
7979 if (!vid_nest)
8080 return -ENOMEM;
8181 ncf = &nc->vlan_filter;
....@@ -109,19 +109,23 @@
109109 NCSI_FOR_EACH_PACKAGE(ndp, np) {
110110 if (np->id != id)
111111 continue;
112
- pnest = nla_nest_start(skb, NCSI_PKG_ATTR);
112
+ pnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR);
113113 if (!pnest)
114114 return -ENOMEM;
115
- nla_put_u32(skb, NCSI_PKG_ATTR_ID, np->id);
116
- if (ndp->force_package == np)
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)
117121 nla_put_flag(skb, NCSI_PKG_ATTR_FORCED);
118
- cnest = nla_nest_start(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
122
+ cnest = nla_nest_start_noflag(skb, NCSI_PKG_ATTR_CHANNEL_LIST);
119123 if (!cnest) {
120124 nla_nest_cancel(skb, pnest);
121125 return -ENOMEM;
122126 }
123127 NCSI_FOR_EACH_CHANNEL(np, nc) {
124
- nest = nla_nest_start(skb, NCSI_CHANNEL_ATTR);
128
+ nest = nla_nest_start_noflag(skb, NCSI_CHANNEL_ATTR);
125129 if (!nest) {
126130 nla_nest_cancel(skb, cnest);
127131 nla_nest_cancel(skb, pnest);
....@@ -183,7 +187,7 @@
183187
184188 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
185189
186
- attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST);
190
+ attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST);
187191 if (!attr) {
188192 kfree_skb(skb);
189193 return -EMSGSIZE;
....@@ -216,8 +220,8 @@
216220 void *hdr;
217221 int rc;
218222
219
- rc = genlmsg_parse(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX,
220
- ncsi_genl_policy, NULL);
223
+ rc = genlmsg_parse_deprecated(cb->nlh, &ncsi_genl_family, attrs, NCSI_ATTR_MAX,
224
+ ncsi_genl_policy, NULL);
221225 if (rc)
222226 return rc;
223227
....@@ -246,7 +250,11 @@
246250 goto err;
247251 }
248252
249
- attr = nla_nest_start(skb, NCSI_ATTR_PACKAGE_LIST);
253
+ attr = nla_nest_start_noflag(skb, NCSI_ATTR_PACKAGE_LIST);
254
+ if (!attr) {
255
+ rc = -EMSGSIZE;
256
+ goto err;
257
+ }
250258 rc = ncsi_write_package_info(skb, ndp, package->id);
251259 if (rc) {
252260 nla_nest_cancel(skb, attr);
....@@ -289,49 +297,58 @@
289297 package_id = nla_get_u32(info->attrs[NCSI_ATTR_PACKAGE_ID]);
290298 package = NULL;
291299
292
- spin_lock_irqsave(&ndp->lock, flags);
293
-
294300 NCSI_FOR_EACH_PACKAGE(ndp, np)
295301 if (np->id == package_id)
296302 package = np;
297303 if (!package) {
298304 /* The user has set a package that does not exist */
299
- spin_unlock_irqrestore(&ndp->lock, flags);
300305 return -ERANGE;
301306 }
302307
303308 channel = NULL;
304
- if (!info->attrs[NCSI_ATTR_CHANNEL_ID]) {
305
- /* Allow any channel */
306
- channel_id = NCSI_RESERVED_CHANNEL;
307
- } else {
309
+ if (info->attrs[NCSI_ATTR_CHANNEL_ID]) {
308310 channel_id = nla_get_u32(info->attrs[NCSI_ATTR_CHANNEL_ID]);
309311 NCSI_FOR_EACH_CHANNEL(package, nc)
310
- if (nc->id == channel_id)
312
+ if (nc->id == channel_id) {
311313 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
+ }
312322 }
313323
314
- if (channel_id != NCSI_RESERVED_CHANNEL && !channel) {
315
- /* The user has set a channel that does not exist on this
316
- * package
317
- */
318
- spin_unlock_irqrestore(&ndp->lock, flags);
319
- netdev_info(ndp->ndev.dev, "NCSI: Channel %u does not exist!\n",
320
- channel_id);
321
- return -ERANGE;
322
- }
323
-
324
- ndp->force_package = package;
325
- ndp->force_channel = channel;
324
+ spin_lock_irqsave(&ndp->lock, flags);
325
+ ndp->package_whitelist = 0x1 << package->id;
326
+ ndp->multi_package = false;
326327 spin_unlock_irqrestore(&ndp->lock, flags);
327328
328
- netdev_info(ndp->ndev.dev, "Set package 0x%x, channel 0x%x%s as preferred\n",
329
- package_id, channel_id,
330
- channel_id == NCSI_RESERVED_CHANNEL ? " (any)" : "");
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);
331340
332
- /* Bounce the NCSI channel to set changes */
333
- ncsi_stop_dev(&ndp->ndev);
334
- ncsi_start_dev(&ndp->ndev);
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);
335352
336353 return 0;
337354 }
....@@ -339,6 +356,7 @@
339356 static int ncsi_clear_interface_nl(struct sk_buff *msg, struct genl_info *info)
340357 {
341358 struct ncsi_dev_priv *ndp;
359
+ struct ncsi_package *np;
342360 unsigned long flags;
343361
344362 if (!info || !info->attrs)
....@@ -352,38 +370,392 @@
352370 if (!ndp)
353371 return -ENODEV;
354372
355
- /* Clear any override */
373
+ /* Reset any whitelists and disable multi mode */
356374 spin_lock_irqsave(&ndp->lock, flags);
357
- ndp->force_package = NULL;
358
- ndp->force_channel = NULL;
375
+ ndp->package_whitelist = UINT_MAX;
376
+ ndp->multi_package = false;
359377 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
+ }
360386 netdev_info(ndp->ndev.dev, "NCSI: Cleared preferred package/channel\n");
361387
362
- /* Bounce the NCSI channel to set changes */
363
- ncsi_stop_dev(&ndp->ndev);
364
- ncsi_start_dev(&ndp->ndev);
388
+ /* Update channel configuration */
389
+ if (!(ndp->flags & NCSI_DEV_RESET))
390
+ ncsi_reset_dev(&ndp->ndev);
365391
366392 return 0;
367393 }
368394
369
-static const struct genl_ops ncsi_ops[] = {
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_small_ops ncsi_ops[] = {
370724 {
371725 .cmd = NCSI_CMD_PKG_INFO,
372
- .policy = ncsi_genl_policy,
726
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
373727 .doit = ncsi_pkg_info_nl,
374728 .dumpit = ncsi_pkg_info_all_nl,
375729 .flags = 0,
376730 },
377731 {
378732 .cmd = NCSI_CMD_SET_INTERFACE,
379
- .policy = ncsi_genl_policy,
733
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
380734 .doit = ncsi_set_interface_nl,
381735 .flags = GENL_ADMIN_PERM,
382736 },
383737 {
384738 .cmd = NCSI_CMD_CLEAR_INTERFACE,
385
- .policy = ncsi_genl_policy,
739
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
386740 .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,
387759 .flags = GENL_ADMIN_PERM,
388760 },
389761 };
....@@ -392,9 +764,10 @@
392764 .name = "NCSI",
393765 .version = 0,
394766 .maxattr = NCSI_ATTR_MAX,
767
+ .policy = ncsi_genl_policy,
395768 .module = THIS_MODULE,
396
- .ops = ncsi_ops,
397
- .n_ops = ARRAY_SIZE(ncsi_ops),
769
+ .small_ops = ncsi_ops,
770
+ .n_small_ops = ARRAY_SIZE(ncsi_ops),
398771 };
399772
400773 static int __init ncsi_init_netlink(void)