LiteX: driver for SPI Flash (mtd) device
[linux/fpc-iii.git] / net / netlabel / netlabel_mgmt.c
blobdf1b41ed73fd9f732eadc12e6e9d125944a916a0
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * NetLabel Management Support
5 * This file defines the management functions for the NetLabel system. The
6 * NetLabel system manages static and dynamic label mappings for network
7 * protocols such as CIPSO and RIPSO.
9 * Author: Paul Moore <paul@paul-moore.com>
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
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>
33 #include "netlabel_calipso.h"
34 #include "netlabel_domainhash.h"
35 #include "netlabel_user.h"
36 #include "netlabel_mgmt.h"
38 /* NetLabel configured protocol counter */
39 atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
41 /* Argument struct for netlbl_domhsh_walk() */
42 struct netlbl_domhsh_walk_arg {
43 struct netlink_callback *nl_cb;
44 struct sk_buff *skb;
45 u32 seq;
48 /* NetLabel Generic NETLINK CIPSOv4 family */
49 static struct genl_family netlbl_mgmt_gnl_family;
51 /* NetLabel Netlink attribute policy */
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 },
62 * Helper Functions
65 /**
66 * netlbl_mgmt_add - Handle an ADD message
67 * @info: the Generic NETLINK info block
68 * @audit_info: NetLabel audit information
70 * Description:
71 * Helper function for the ADD and ADDDEF messages to add the domain mappings
72 * from the message to the hash table. See netlabel.h for a description of the
73 * message format. Returns zero on success, negative values on failure.
76 static int netlbl_mgmt_add_common(struct genl_info *info,
77 struct netlbl_audit *audit_info)
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);
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;
98 nla_strscpy(entry->domain,
99 info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
102 /* NOTE: internally we allow/use a entry->def.type value of
103 * NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
104 * to pass that as a protocol value because we need to know the
105 * "real" protocol */
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;
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;
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 /* IPv6 */
139 default:
140 goto add_free_domain;
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;
147 if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
148 struct in_addr *addr;
149 struct in_addr *mask;
150 struct netlbl_domaddr4_map *map;
152 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
153 if (addrmap == NULL) {
154 ret_val = -ENOMEM;
155 goto add_doi_put_def;
157 INIT_LIST_HEAD(&addrmap->list4);
158 INIT_LIST_HEAD(&addrmap->list6);
160 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
161 sizeof(struct in_addr)) {
162 ret_val = -EINVAL;
163 goto add_free_addrmap;
165 if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
166 sizeof(struct in_addr)) {
167 ret_val = -EINVAL;
168 goto add_free_addrmap;
170 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
171 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
173 map = kzalloc(sizeof(*map), GFP_KERNEL);
174 if (map == NULL) {
175 ret_val = -ENOMEM;
176 goto add_free_addrmap;
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;
185 ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
186 if (ret_val != 0) {
187 kfree(map);
188 goto add_free_addrmap;
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;
200 addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
201 if (addrmap == NULL) {
202 ret_val = -ENOMEM;
203 goto add_doi_put_def;
205 INIT_LIST_HEAD(&addrmap->list4);
206 INIT_LIST_HEAD(&addrmap->list6);
208 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
209 sizeof(struct in6_addr)) {
210 ret_val = -EINVAL;
211 goto add_free_addrmap;
213 if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
214 sizeof(struct in6_addr)) {
215 ret_val = -EINVAL;
216 goto add_free_addrmap;
218 addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
219 mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
221 map = kzalloc(sizeof(*map), GFP_KERNEL);
222 if (map == NULL) {
223 ret_val = -ENOMEM;
224 goto add_free_addrmap;
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;
237 ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
238 if (ret_val != 0) {
239 kfree(map);
240 goto add_free_addrmap;
243 entry->family = AF_INET6;
244 entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
245 entry->def.addrsel = addrmap;
246 #endif /* IPv6 */
249 ret_val = netlbl_domhsh_add(entry, audit_info);
250 if (ret_val != 0)
251 goto add_free_addrmap;
253 return 0;
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;
270 * netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
271 * @skb: the NETLINK buffer
272 * @entry: the map entry
274 * Description:
275 * This function is a helper function used by the LISTALL and LISTDEF command
276 * handlers. The caller is responsible for ensuring that the RCU read lock
277 * is held. Returns zero on success, negative values on failure.
280 static int netlbl_mgmt_listentry(struct sk_buff *skb,
281 struct netlbl_dom_map *entry)
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
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;
298 ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
299 if (ret_val != 0)
300 return ret_val;
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;
308 netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
309 struct netlbl_domaddr4_map *map4;
310 struct in_addr addr_struct;
312 nla_b = nla_nest_start_noflag(skb,
313 NLBL_MGMT_A_ADDRSELECTOR);
314 if (nla_b == NULL)
315 return -ENOMEM;
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;
341 nla_nest_end(skb, nla_b);
343 #if IS_ENABLED(CONFIG_IPV6)
344 netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
345 struct netlbl_domaddr6_map *map6;
347 nla_b = nla_nest_start_noflag(skb,
348 NLBL_MGMT_A_ADDRSELECTOR);
349 if (nla_b == NULL)
350 return -ENOMEM;
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;
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;
375 nla_nest_end(skb, nla_b);
377 #endif /* IPv6 */
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;
403 return ret_val;
407 * NetLabel Command Handlers
411 * netlbl_mgmt_add - Handle an ADD message
412 * @skb: the NETLINK buffer
413 * @info: the Generic NETLINK info block
415 * Description:
416 * Process a user generated ADD message and add the domains from the message
417 * to the hash table. See netlabel.h for a description of the message format.
418 * Returns zero on success, negative values on failure.
421 static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
423 struct netlbl_audit audit_info;
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;
437 netlbl_netlink_auditinfo(skb, &audit_info);
439 return netlbl_mgmt_add_common(info, &audit_info);
443 * netlbl_mgmt_remove - Handle a REMOVE message
444 * @skb: the NETLINK buffer
445 * @info: the Generic NETLINK info block
447 * Description:
448 * Process a user generated REMOVE message and remove the specified domain
449 * mappings. Returns zero on success, negative values on failure.
452 static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
454 char *domain;
455 struct netlbl_audit audit_info;
457 if (!info->attrs[NLBL_MGMT_A_DOMAIN])
458 return -EINVAL;
460 netlbl_netlink_auditinfo(skb, &audit_info);
462 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
463 return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
467 * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
468 * @entry: the domain mapping hash table entry
469 * @arg: the netlbl_domhsh_walk_arg structure
471 * Description:
472 * This function is designed to be used as a callback to the
473 * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
474 * message. Returns the size of the message on success, negative values on
475 * failure.
478 static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
480 int ret_val = -ENOMEM;
481 struct netlbl_domhsh_walk_arg *cb_arg = arg;
482 void *data;
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;
490 ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
491 if (ret_val != 0)
492 goto listall_cb_failure;
494 cb_arg->seq++;
495 genlmsg_end(cb_arg->skb, data);
496 return 0;
498 listall_cb_failure:
499 genlmsg_cancel(cb_arg->skb, data);
500 return ret_val;
504 * netlbl_mgmt_listall - Handle a LISTALL message
505 * @skb: the NETLINK buffer
506 * @cb: the NETLINK callback
508 * Description:
509 * Process a user generated LISTALL message and dumps the domain hash table in
510 * a form suitable for use in a kernel generated LISTALL message. Returns zero
511 * on success, negative values on failure.
514 static int netlbl_mgmt_listall(struct sk_buff *skb,
515 struct netlink_callback *cb)
517 struct netlbl_domhsh_walk_arg cb_arg;
518 u32 skip_bkt = cb->args[0];
519 u32 skip_chain = cb->args[1];
521 cb_arg.nl_cb = cb;
522 cb_arg.skb = skb;
523 cb_arg.seq = cb->nlh->nlmsg_seq;
525 netlbl_domhsh_walk(&skip_bkt,
526 &skip_chain,
527 netlbl_mgmt_listall_cb,
528 &cb_arg);
530 cb->args[0] = skip_bkt;
531 cb->args[1] = skip_chain;
532 return skb->len;
536 * netlbl_mgmt_adddef - Handle an ADDDEF message
537 * @skb: the NETLINK buffer
538 * @info: the Generic NETLINK info block
540 * Description:
541 * Process a user generated ADDDEF message and respond accordingly. Returns
542 * zero on success, negative values on failure.
545 static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
547 struct netlbl_audit audit_info;
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;
560 netlbl_netlink_auditinfo(skb, &audit_info);
562 return netlbl_mgmt_add_common(info, &audit_info);
566 * netlbl_mgmt_removedef - Handle a REMOVEDEF message
567 * @skb: the NETLINK buffer
568 * @info: the Generic NETLINK info block
570 * Description:
571 * Process a user generated REMOVEDEF message and remove the default domain
572 * mapping. Returns zero on success, negative values on failure.
575 static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
577 struct netlbl_audit audit_info;
579 netlbl_netlink_auditinfo(skb, &audit_info);
581 return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
585 * netlbl_mgmt_listdef - Handle a LISTDEF message
586 * @skb: the NETLINK buffer
587 * @info: the Generic NETLINK info block
589 * Description:
590 * Process a user generated LISTDEF message and dumps the default domain
591 * mapping in a form suitable for use in a kernel generated LISTDEF message.
592 * Returns zero on success, negative values on failure.
595 static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
597 int ret_val = -ENOMEM;
598 struct sk_buff *ans_skb = NULL;
599 void *data;
600 struct netlbl_dom_map *entry;
601 u16 family;
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;
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;
616 rcu_read_lock();
617 entry = netlbl_domhsh_getentry(NULL, family);
618 if (entry == NULL) {
619 ret_val = -ENOENT;
620 goto listdef_failure_lock;
622 ret_val = netlbl_mgmt_listentry(ans_skb, entry);
623 rcu_read_unlock();
624 if (ret_val != 0)
625 goto listdef_failure;
627 genlmsg_end(ans_skb, data);
628 return genlmsg_reply(ans_skb, info);
630 listdef_failure_lock:
631 rcu_read_unlock();
632 listdef_failure:
633 kfree_skb(ans_skb);
634 return ret_val;
638 * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
639 * @skb: the skb to write to
640 * @cb: the NETLINK callback
641 * @protocol: the NetLabel protocol to use in the message
643 * Description:
644 * This function is to be used in conjunction with netlbl_mgmt_protocols() to
645 * answer a application's PROTOCOLS message. Returns the size of the message
646 * on success, negative values on failure.
649 static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
650 struct netlink_callback *cb,
651 u32 protocol)
653 int ret_val = -ENOMEM;
654 void *data;
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;
662 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
663 if (ret_val != 0)
664 goto protocols_cb_failure;
666 genlmsg_end(skb, data);
667 return 0;
669 protocols_cb_failure:
670 genlmsg_cancel(skb, data);
671 return ret_val;
675 * netlbl_mgmt_protocols - Handle a PROTOCOLS message
676 * @skb: the NETLINK buffer
677 * @cb: the NETLINK callback
679 * Description:
680 * Process a user generated PROTOCOLS message and respond accordingly.
683 static int netlbl_mgmt_protocols(struct sk_buff *skb,
684 struct netlink_callback *cb)
686 u32 protos_sent = cb->args[0];
688 if (protos_sent == 0) {
689 if (netlbl_mgmt_protocols_cb(skb,
691 NETLBL_NLTYPE_UNLABELED) < 0)
692 goto protocols_return;
693 protos_sent++;
695 if (protos_sent == 1) {
696 if (netlbl_mgmt_protocols_cb(skb,
698 NETLBL_NLTYPE_CIPSOV4) < 0)
699 goto protocols_return;
700 protos_sent++;
702 #if IS_ENABLED(CONFIG_IPV6)
703 if (protos_sent == 2) {
704 if (netlbl_mgmt_protocols_cb(skb,
706 NETLBL_NLTYPE_CALIPSO) < 0)
707 goto protocols_return;
708 protos_sent++;
710 #endif
712 protocols_return:
713 cb->args[0] = protos_sent;
714 return skb->len;
718 * netlbl_mgmt_version - Handle a VERSION message
719 * @skb: the NETLINK buffer
720 * @info: the Generic NETLINK info block
722 * Description:
723 * Process a user generated VERSION message and respond accordingly. Returns
724 * zero on success, negative values on failure.
727 static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
729 int ret_val = -ENOMEM;
730 struct sk_buff *ans_skb = NULL;
731 void *data;
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;
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;
747 genlmsg_end(ans_skb, data);
748 return genlmsg_reply(ans_skb, info);
750 version_failure:
751 kfree_skb(ans_skb);
752 return ret_val;
757 * NetLabel Generic NETLINK Command Definitions
760 static const struct genl_small_ops netlbl_mgmt_genl_ops[] = {
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,
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,
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,
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,
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,
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,
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,
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,
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 .small_ops = netlbl_mgmt_genl_ops,
827 .n_small_ops = ARRAY_SIZE(netlbl_mgmt_genl_ops),
831 * NetLabel Generic NETLINK Protocol Functions
835 * netlbl_mgmt_genl_init - Register the NetLabel management component
837 * Description:
838 * Register the NetLabel management component with the Generic NETLINK
839 * mechanism. Returns zero on success, negative values on failure.
842 int __init netlbl_mgmt_genl_init(void)
844 return genl_register_family(&netlbl_mgmt_gnl_family);