This source file includes following definitions.
- netlbl_mgmt_add_common
- netlbl_mgmt_listentry
- netlbl_mgmt_add
- netlbl_mgmt_remove
- netlbl_mgmt_listall_cb
- netlbl_mgmt_listall
- netlbl_mgmt_adddef
- netlbl_mgmt_removedef
- netlbl_mgmt_listdef
- netlbl_mgmt_protocols_cb
- netlbl_mgmt_protocols
- netlbl_mgmt_version
- netlbl_mgmt_genl_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #include <linux/types.h>
17 #include <linux/socket.h>
18 #include <linux/string.h>
19 #include <linux/skbuff.h>
20 #include <linux/in.h>
21 #include <linux/in6.h>
22 #include <linux/slab.h>
23 #include <net/sock.h>
24 #include <net/netlink.h>
25 #include <net/genetlink.h>
26 #include <net/ip.h>
27 #include <net/ipv6.h>
28 #include <net/netlabel.h>
29 #include <net/cipso_ipv4.h>
30 #include <net/calipso.h>
31 #include <linux/atomic.h>
32
33 #include "netlabel_calipso.h"
34 #include "netlabel_domainhash.h"
35 #include "netlabel_user.h"
36 #include "netlabel_mgmt.h"
37
38
39 atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
40
41
42 struct netlbl_domhsh_walk_arg {
43 struct netlink_callback *nl_cb;
44 struct sk_buff *skb;
45 u32 seq;
46 };
47
48
49 static struct genl_family netlbl_mgmt_gnl_family;
50
51
52 static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
53 [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
54 [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
55 [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
56 [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
57 [NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
58 [NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
59 };
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 static int netlbl_mgmt_add_common(struct genl_info *info,
77 struct netlbl_audit *audit_info)
78 {
79 int ret_val = -EINVAL;
80 struct netlbl_domaddr_map *addrmap = NULL;
81 struct cipso_v4_doi *cipsov4 = NULL;
82 #if IS_ENABLED(CONFIG_IPV6)
83 struct calipso_doi *calipso = NULL;
84 #endif
85 u32 tmp_val;
86 struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
87
88 if (!entry)
89 return -ENOMEM;
90 entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
91 if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
92 size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
93 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
94 if (entry->domain == NULL) {
95 ret_val = -ENOMEM;
96 goto add_free_entry;
97 }
98 nla_strlcpy(entry->domain,
99 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
100 }
101
102
103
104
105
106
107 switch (entry->def.type) {
108 case NETLBL_NLTYPE_UNLABELED:
109 if (info->attrs[NLBL_MGMT_A_FAMILY])
110 entry->family =
111 nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
112 else
113 entry->family = AF_UNSPEC;
114 break;
115 case NETLBL_NLTYPE_CIPSOV4:
116 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
117 goto add_free_domain;
118
119 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
120 cipsov4 = cipso_v4_doi_getdef(tmp_val);
121 if (cipsov4 == NULL)
122 goto add_free_domain;
123 entry->family = AF_INET;
124 entry->def.cipso = cipsov4;
125 break;
126 #if IS_ENABLED(CONFIG_IPV6)
127 case NETLBL_NLTYPE_CALIPSO:
128 if (!info->attrs[NLBL_MGMT_A_CLPDOI])
129 goto add_free_domain;
130
131 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
132 calipso = calipso_doi_getdef(tmp_val);
133 if (calipso == NULL)
134 goto add_free_domain;
135 entry->family = AF_INET6;
136 entry->def.calipso = calipso;
137 break;
138 #endif
139 default:
140 goto add_free_domain;
141 }
142
143 if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
144 (entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
145 goto add_doi_put_def;
146
147 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
148 struct in_addr *addr;
149 struct in_addr *mask;
150 struct netlbl_domaddr4_map *map;
151
152 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
153 if (addrmap == NULL) {
154 ret_val = -ENOMEM;
155 goto add_doi_put_def;
156 }
157 INIT_LIST_HEAD(&addrmap->list4);
158 INIT_LIST_HEAD(&addrmap->list6);
159
160 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
161 sizeof(struct in_addr)) {
162 ret_val = -EINVAL;
163 goto add_free_addrmap;
164 }
165 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
166 sizeof(struct in_addr)) {
167 ret_val = -EINVAL;
168 goto add_free_addrmap;
169 }
170 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
171 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
172
173 map = kzalloc(sizeof(*map), GFP_KERNEL);
174 if (map == NULL) {
175 ret_val = -ENOMEM;
176 goto add_free_addrmap;
177 }
178 map->list.addr = addr->s_addr & mask->s_addr;
179 map->list.mask = mask->s_addr;
180 map->list.valid = 1;
181 map->def.type = entry->def.type;
182 if (cipsov4)
183 map->def.cipso = cipsov4;
184
185 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
186 if (ret_val != 0) {
187 kfree(map);
188 goto add_free_addrmap;
189 }
190
191 entry->family = AF_INET;
192 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
193 entry->def.addrsel = addrmap;
194 #if IS_ENABLED(CONFIG_IPV6)
195 } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
196 struct in6_addr *addr;
197 struct in6_addr *mask;
198 struct netlbl_domaddr6_map *map;
199
200 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
201 if (addrmap == NULL) {
202 ret_val = -ENOMEM;
203 goto add_doi_put_def;
204 }
205 INIT_LIST_HEAD(&addrmap->list4);
206 INIT_LIST_HEAD(&addrmap->list6);
207
208 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
209 sizeof(struct in6_addr)) {
210 ret_val = -EINVAL;
211 goto add_free_addrmap;
212 }
213 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
214 sizeof(struct in6_addr)) {
215 ret_val = -EINVAL;
216 goto add_free_addrmap;
217 }
218 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
219 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
220
221 map = kzalloc(sizeof(*map), GFP_KERNEL);
222 if (map == NULL) {
223 ret_val = -ENOMEM;
224 goto add_free_addrmap;
225 }
226 map->list.addr = *addr;
227 map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
228 map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
229 map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
230 map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
231 map->list.mask = *mask;
232 map->list.valid = 1;
233 map->def.type = entry->def.type;
234 if (calipso)
235 map->def.calipso = calipso;
236
237 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
238 if (ret_val != 0) {
239 kfree(map);
240 goto add_free_addrmap;
241 }
242
243 entry->family = AF_INET6;
244 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
245 entry->def.addrsel = addrmap;
246 #endif
247 }
248
249 ret_val = netlbl_domhsh_add(entry, audit_info);
250 if (ret_val != 0)
251 goto add_free_addrmap;
252
253 return 0;
254
255 add_free_addrmap:
256 kfree(addrmap);
257 add_doi_put_def:
258 cipso_v4_doi_putdef(cipsov4);
259 #if IS_ENABLED(CONFIG_IPV6)
260 calipso_doi_putdef(calipso);
261 #endif
262 add_free_domain:
263 kfree(entry->domain);
264 add_free_entry:
265 kfree(entry);
266 return ret_val;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280 static int netlbl_mgmt_listentry(struct sk_buff *skb,
281 struct netlbl_dom_map *entry)
282 {
283 int ret_val = 0;
284 struct nlattr *nla_a;
285 struct nlattr *nla_b;
286 struct netlbl_af4list *iter4;
287 #if IS_ENABLED(CONFIG_IPV6)
288 struct netlbl_af6list *iter6;
289 #endif
290
291 if (entry->domain != NULL) {
292 ret_val = nla_put_string(skb,
293 NLBL_MGMT_A_DOMAIN, entry->domain);
294 if (ret_val != 0)
295 return ret_val;
296 }
297
298 ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
299 if (ret_val != 0)
300 return ret_val;
301
302 switch (entry->def.type) {
303 case NETLBL_NLTYPE_ADDRSELECT:
304 nla_a = nla_nest_start_noflag(skb, NLBL_MGMT_A_SELECTORLIST);
305 if (nla_a == NULL)
306 return -ENOMEM;
307
308 netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
309 struct netlbl_domaddr4_map *map4;
310 struct in_addr addr_struct;
311
312 nla_b = nla_nest_start_noflag(skb,
313 NLBL_MGMT_A_ADDRSELECTOR);
314 if (nla_b == NULL)
315 return -ENOMEM;
316
317 addr_struct.s_addr = iter4->addr;
318 ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4ADDR,
319 addr_struct.s_addr);
320 if (ret_val != 0)
321 return ret_val;
322 addr_struct.s_addr = iter4->mask;
323 ret_val = nla_put_in_addr(skb, NLBL_MGMT_A_IPV4MASK,
324 addr_struct.s_addr);
325 if (ret_val != 0)
326 return ret_val;
327 map4 = netlbl_domhsh_addr4_entry(iter4);
328 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
329 map4->def.type);
330 if (ret_val != 0)
331 return ret_val;
332 switch (map4->def.type) {
333 case NETLBL_NLTYPE_CIPSOV4:
334 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
335 map4->def.cipso->doi);
336 if (ret_val != 0)
337 return ret_val;
338 break;
339 }
340
341 nla_nest_end(skb, nla_b);
342 }
343 #if IS_ENABLED(CONFIG_IPV6)
344 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
345 struct netlbl_domaddr6_map *map6;
346
347 nla_b = nla_nest_start_noflag(skb,
348 NLBL_MGMT_A_ADDRSELECTOR);
349 if (nla_b == NULL)
350 return -ENOMEM;
351
352 ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6ADDR,
353 &iter6->addr);
354 if (ret_val != 0)
355 return ret_val;
356 ret_val = nla_put_in6_addr(skb, NLBL_MGMT_A_IPV6MASK,
357 &iter6->mask);
358 if (ret_val != 0)
359 return ret_val;
360 map6 = netlbl_domhsh_addr6_entry(iter6);
361 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
362 map6->def.type);
363 if (ret_val != 0)
364 return ret_val;
365
366 switch (map6->def.type) {
367 case NETLBL_NLTYPE_CALIPSO:
368 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
369 map6->def.calipso->doi);
370 if (ret_val != 0)
371 return ret_val;
372 break;
373 }
374
375 nla_nest_end(skb, nla_b);
376 }
377 #endif
378
379 nla_nest_end(skb, nla_a);
380 break;
381 case NETLBL_NLTYPE_UNLABELED:
382 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
383 entry->def.type);
384 break;
385 case NETLBL_NLTYPE_CIPSOV4:
386 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
387 entry->def.type);
388 if (ret_val != 0)
389 return ret_val;
390 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
391 entry->def.cipso->doi);
392 break;
393 case NETLBL_NLTYPE_CALIPSO:
394 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
395 entry->def.type);
396 if (ret_val != 0)
397 return ret_val;
398 ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
399 entry->def.calipso->doi);
400 break;
401 }
402
403 return ret_val;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
422 {
423 struct netlbl_audit audit_info;
424
425 if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
426 (!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
427 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
428 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
429 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
430 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
431 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
432 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
433 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
434 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
435 return -EINVAL;
436
437 netlbl_netlink_auditinfo(skb, &audit_info);
438
439 return netlbl_mgmt_add_common(info, &audit_info);
440 }
441
442
443
444
445
446
447
448
449
450
451
452 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
453 {
454 char *domain;
455 struct netlbl_audit audit_info;
456
457 if (!info->attrs[NLBL_MGMT_A_DOMAIN])
458 return -EINVAL;
459
460 netlbl_netlink_auditinfo(skb, &audit_info);
461
462 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
463 return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
464 }
465
466
467
468
469
470
471
472
473
474
475
476
477
478 static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
479 {
480 int ret_val = -ENOMEM;
481 struct netlbl_domhsh_walk_arg *cb_arg = arg;
482 void *data;
483
484 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
485 cb_arg->seq, &netlbl_mgmt_gnl_family,
486 NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
487 if (data == NULL)
488 goto listall_cb_failure;
489
490 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
491 if (ret_val != 0)
492 goto listall_cb_failure;
493
494 cb_arg->seq++;
495 genlmsg_end(cb_arg->skb, data);
496 return 0;
497
498 listall_cb_failure:
499 genlmsg_cancel(cb_arg->skb, data);
500 return ret_val;
501 }
502
503
504
505
506
507
508
509
510
511
512
513
514 static int netlbl_mgmt_listall(struct sk_buff *skb,
515 struct netlink_callback *cb)
516 {
517 struct netlbl_domhsh_walk_arg cb_arg;
518 u32 skip_bkt = cb->args[0];
519 u32 skip_chain = cb->args[1];
520
521 cb_arg.nl_cb = cb;
522 cb_arg.skb = skb;
523 cb_arg.seq = cb->nlh->nlmsg_seq;
524
525 netlbl_domhsh_walk(&skip_bkt,
526 &skip_chain,
527 netlbl_mgmt_listall_cb,
528 &cb_arg);
529
530 cb->args[0] = skip_bkt;
531 cb->args[1] = skip_chain;
532 return skb->len;
533 }
534
535
536
537
538
539
540
541
542
543
544
545 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
546 {
547 struct netlbl_audit audit_info;
548
549 if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
550 (info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
551 info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
552 (info->attrs[NLBL_MGMT_A_IPV4MASK] &&
553 info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
554 ((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
555 (info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
556 ((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
557 (info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
558 return -EINVAL;
559
560 netlbl_netlink_auditinfo(skb, &audit_info);
561
562 return netlbl_mgmt_add_common(info, &audit_info);
563 }
564
565
566
567
568
569
570
571
572
573
574
575 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
576 {
577 struct netlbl_audit audit_info;
578
579 netlbl_netlink_auditinfo(skb, &audit_info);
580
581 return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
596 {
597 int ret_val = -ENOMEM;
598 struct sk_buff *ans_skb = NULL;
599 void *data;
600 struct netlbl_dom_map *entry;
601 u16 family;
602
603 if (info->attrs[NLBL_MGMT_A_FAMILY])
604 family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
605 else
606 family = AF_INET;
607
608 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
609 if (ans_skb == NULL)
610 return -ENOMEM;
611 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
612 0, NLBL_MGMT_C_LISTDEF);
613 if (data == NULL)
614 goto listdef_failure;
615
616 rcu_read_lock();
617 entry = netlbl_domhsh_getentry(NULL, family);
618 if (entry == NULL) {
619 ret_val = -ENOENT;
620 goto listdef_failure_lock;
621 }
622 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
623 rcu_read_unlock();
624 if (ret_val != 0)
625 goto listdef_failure;
626
627 genlmsg_end(ans_skb, data);
628 return genlmsg_reply(ans_skb, info);
629
630 listdef_failure_lock:
631 rcu_read_unlock();
632 listdef_failure:
633 kfree_skb(ans_skb);
634 return ret_val;
635 }
636
637
638
639
640
641
642
643
644
645
646
647
648
649 static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
650 struct netlink_callback *cb,
651 u32 protocol)
652 {
653 int ret_val = -ENOMEM;
654 void *data;
655
656 data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
657 &netlbl_mgmt_gnl_family, NLM_F_MULTI,
658 NLBL_MGMT_C_PROTOCOLS);
659 if (data == NULL)
660 goto protocols_cb_failure;
661
662 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
663 if (ret_val != 0)
664 goto protocols_cb_failure;
665
666 genlmsg_end(skb, data);
667 return 0;
668
669 protocols_cb_failure:
670 genlmsg_cancel(skb, data);
671 return ret_val;
672 }
673
674
675
676
677
678
679
680
681
682
683 static int netlbl_mgmt_protocols(struct sk_buff *skb,
684 struct netlink_callback *cb)
685 {
686 u32 protos_sent = cb->args[0];
687
688 if (protos_sent == 0) {
689 if (netlbl_mgmt_protocols_cb(skb,
690 cb,
691 NETLBL_NLTYPE_UNLABELED) < 0)
692 goto protocols_return;
693 protos_sent++;
694 }
695 if (protos_sent == 1) {
696 if (netlbl_mgmt_protocols_cb(skb,
697 cb,
698 NETLBL_NLTYPE_CIPSOV4) < 0)
699 goto protocols_return;
700 protos_sent++;
701 }
702 #if IS_ENABLED(CONFIG_IPV6)
703 if (protos_sent == 2) {
704 if (netlbl_mgmt_protocols_cb(skb,
705 cb,
706 NETLBL_NLTYPE_CALIPSO) < 0)
707 goto protocols_return;
708 protos_sent++;
709 }
710 #endif
711
712 protocols_return:
713 cb->args[0] = protos_sent;
714 return skb->len;
715 }
716
717
718
719
720
721
722
723
724
725
726
727 static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
728 {
729 int ret_val = -ENOMEM;
730 struct sk_buff *ans_skb = NULL;
731 void *data;
732
733 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
734 if (ans_skb == NULL)
735 return -ENOMEM;
736 data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
737 0, NLBL_MGMT_C_VERSION);
738 if (data == NULL)
739 goto version_failure;
740
741 ret_val = nla_put_u32(ans_skb,
742 NLBL_MGMT_A_VERSION,
743 NETLBL_PROTO_VERSION);
744 if (ret_val != 0)
745 goto version_failure;
746
747 genlmsg_end(ans_skb, data);
748 return genlmsg_reply(ans_skb, info);
749
750 version_failure:
751 kfree_skb(ans_skb);
752 return ret_val;
753 }
754
755
756
757
758
759
760 static const struct genl_ops netlbl_mgmt_genl_ops[] = {
761 {
762 .cmd = NLBL_MGMT_C_ADD,
763 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
764 .flags = GENL_ADMIN_PERM,
765 .doit = netlbl_mgmt_add,
766 .dumpit = NULL,
767 },
768 {
769 .cmd = NLBL_MGMT_C_REMOVE,
770 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
771 .flags = GENL_ADMIN_PERM,
772 .doit = netlbl_mgmt_remove,
773 .dumpit = NULL,
774 },
775 {
776 .cmd = NLBL_MGMT_C_LISTALL,
777 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
778 .flags = 0,
779 .doit = NULL,
780 .dumpit = netlbl_mgmt_listall,
781 },
782 {
783 .cmd = NLBL_MGMT_C_ADDDEF,
784 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
785 .flags = GENL_ADMIN_PERM,
786 .doit = netlbl_mgmt_adddef,
787 .dumpit = NULL,
788 },
789 {
790 .cmd = NLBL_MGMT_C_REMOVEDEF,
791 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
792 .flags = GENL_ADMIN_PERM,
793 .doit = netlbl_mgmt_removedef,
794 .dumpit = NULL,
795 },
796 {
797 .cmd = NLBL_MGMT_C_LISTDEF,
798 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
799 .flags = 0,
800 .doit = netlbl_mgmt_listdef,
801 .dumpit = NULL,
802 },
803 {
804 .cmd = NLBL_MGMT_C_PROTOCOLS,
805 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
806 .flags = 0,
807 .doit = NULL,
808 .dumpit = netlbl_mgmt_protocols,
809 },
810 {
811 .cmd = NLBL_MGMT_C_VERSION,
812 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
813 .flags = 0,
814 .doit = netlbl_mgmt_version,
815 .dumpit = NULL,
816 },
817 };
818
819 static struct genl_family netlbl_mgmt_gnl_family __ro_after_init = {
820 .hdrsize = 0,
821 .name = NETLBL_NLTYPE_MGMT_NAME,
822 .version = NETLBL_PROTO_VERSION,
823 .maxattr = NLBL_MGMT_A_MAX,
824 .policy = netlbl_mgmt_genl_policy,
825 .module = THIS_MODULE,
826 .ops = netlbl_mgmt_genl_ops,
827 .n_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
828 };
829
830
831
832
833
834
835
836
837
838
839
840
841
842 int __init netlbl_mgmt_genl_init(void)
843 {
844 return genl_register_family(&netlbl_mgmt_gnl_family);
845 }