x86: 64-bit, add the new split_large_page() function
[wrt350n-kernel.git] / net / netlabel / netlabel_cipso_v4.c
blobba0ca8d3f77d49720358da39e1988797b487e9e1
1 /*
2 * NetLabel CIPSO/IPv4 Support
4 * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
5 * NetLabel system manages static and dynamic label mappings for network
6 * protocols such as CIPSO and RIPSO.
8 * Author: Paul Moore <paul.moore@hp.com>
13 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 * the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <linux/types.h>
32 #include <linux/socket.h>
33 #include <linux/string.h>
34 #include <linux/skbuff.h>
35 #include <linux/audit.h>
36 #include <net/sock.h>
37 #include <net/netlink.h>
38 #include <net/genetlink.h>
39 #include <net/netlabel.h>
40 #include <net/cipso_ipv4.h>
42 #include "netlabel_user.h"
43 #include "netlabel_cipso_v4.h"
44 #include "netlabel_mgmt.h"
46 /* Argument struct for cipso_v4_doi_walk() */
47 struct netlbl_cipsov4_doiwalk_arg {
48 struct netlink_callback *nl_cb;
49 struct sk_buff *skb;
50 u32 seq;
53 /* NetLabel Generic NETLINK CIPSOv4 family */
54 static struct genl_family netlbl_cipsov4_gnl_family = {
55 .id = GENL_ID_GENERATE,
56 .hdrsize = 0,
57 .name = NETLBL_NLTYPE_CIPSOV4_NAME,
58 .version = NETLBL_PROTO_VERSION,
59 .maxattr = NLBL_CIPSOV4_A_MAX,
62 /* NetLabel Netlink attribute policy */
63 static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
64 [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
65 [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
66 [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
67 [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
68 [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
69 [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
70 [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
71 [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
72 [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
73 [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
74 [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
75 [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
79 * Helper Functions
82 /**
83 * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
84 * @entry: the entry's RCU field
86 * Description:
87 * This function is designed to be used as a callback to the call_rcu()
88 * function so that the memory allocated to the DOI definition can be released
89 * safely.
92 static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
94 struct cipso_v4_doi *ptr;
96 ptr = container_of(entry, struct cipso_v4_doi, rcu);
97 switch (ptr->type) {
98 case CIPSO_V4_MAP_STD:
99 kfree(ptr->map.std->lvl.cipso);
100 kfree(ptr->map.std->lvl.local);
101 kfree(ptr->map.std->cat.cipso);
102 kfree(ptr->map.std->cat.local);
103 break;
105 kfree(ptr);
109 * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
110 * @info: the Generic NETLINK info block
111 * @doi_def: the CIPSO V4 DOI definition
113 * Description:
114 * Parse the common sections of a ADD message and fill in the related values
115 * in @doi_def. Returns zero on success, negative values on failure.
118 static int netlbl_cipsov4_add_common(struct genl_info *info,
119 struct cipso_v4_doi *doi_def)
121 struct nlattr *nla;
122 int nla_rem;
123 u32 iter = 0;
125 doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
127 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
128 NLBL_CIPSOV4_A_MAX,
129 netlbl_cipsov4_genl_policy) != 0)
130 return -EINVAL;
132 nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
133 if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
134 if (iter >= CIPSO_V4_TAG_MAXCNT)
135 return -EINVAL;
136 doi_def->tags[iter++] = nla_get_u8(nla);
138 while (iter < CIPSO_V4_TAG_MAXCNT)
139 doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
141 return 0;
145 * NetLabel Command Handlers
149 * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
150 * @info: the Generic NETLINK info block
152 * Description:
153 * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
154 * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
155 * error.
158 static int netlbl_cipsov4_add_std(struct genl_info *info)
160 int ret_val = -EINVAL;
161 struct cipso_v4_doi *doi_def = NULL;
162 struct nlattr *nla_a;
163 struct nlattr *nla_b;
164 int nla_a_rem;
165 int nla_b_rem;
166 u32 iter;
168 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
169 !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
170 return -EINVAL;
172 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
173 NLBL_CIPSOV4_A_MAX,
174 netlbl_cipsov4_genl_policy) != 0)
175 return -EINVAL;
177 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
178 if (doi_def == NULL)
179 return -ENOMEM;
180 doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
181 if (doi_def->map.std == NULL) {
182 ret_val = -ENOMEM;
183 goto add_std_failure;
185 doi_def->type = CIPSO_V4_MAP_STD;
187 ret_val = netlbl_cipsov4_add_common(info, doi_def);
188 if (ret_val != 0)
189 goto add_std_failure;
190 ret_val = -EINVAL;
192 nla_for_each_nested(nla_a,
193 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
194 nla_a_rem)
195 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
196 if (nla_validate_nested(nla_a,
197 NLBL_CIPSOV4_A_MAX,
198 netlbl_cipsov4_genl_policy) != 0)
199 goto add_std_failure;
200 nla_for_each_nested(nla_b, nla_a, nla_b_rem)
201 switch (nla_type(nla_b)) {
202 case NLBL_CIPSOV4_A_MLSLVLLOC:
203 if (nla_get_u32(nla_b) >
204 CIPSO_V4_MAX_LOC_LVLS)
205 goto add_std_failure;
206 if (nla_get_u32(nla_b) >=
207 doi_def->map.std->lvl.local_size)
208 doi_def->map.std->lvl.local_size =
209 nla_get_u32(nla_b) + 1;
210 break;
211 case NLBL_CIPSOV4_A_MLSLVLREM:
212 if (nla_get_u32(nla_b) >
213 CIPSO_V4_MAX_REM_LVLS)
214 goto add_std_failure;
215 if (nla_get_u32(nla_b) >=
216 doi_def->map.std->lvl.cipso_size)
217 doi_def->map.std->lvl.cipso_size =
218 nla_get_u32(nla_b) + 1;
219 break;
222 doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
223 sizeof(u32),
224 GFP_KERNEL);
225 if (doi_def->map.std->lvl.local == NULL) {
226 ret_val = -ENOMEM;
227 goto add_std_failure;
229 doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
230 sizeof(u32),
231 GFP_KERNEL);
232 if (doi_def->map.std->lvl.cipso == NULL) {
233 ret_val = -ENOMEM;
234 goto add_std_failure;
236 for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
237 doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
238 for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
239 doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
240 nla_for_each_nested(nla_a,
241 info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
242 nla_a_rem)
243 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
244 struct nlattr *lvl_loc;
245 struct nlattr *lvl_rem;
247 lvl_loc = nla_find_nested(nla_a,
248 NLBL_CIPSOV4_A_MLSLVLLOC);
249 lvl_rem = nla_find_nested(nla_a,
250 NLBL_CIPSOV4_A_MLSLVLREM);
251 if (lvl_loc == NULL || lvl_rem == NULL)
252 goto add_std_failure;
253 doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
254 nla_get_u32(lvl_rem);
255 doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
256 nla_get_u32(lvl_loc);
259 if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
260 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
261 NLBL_CIPSOV4_A_MAX,
262 netlbl_cipsov4_genl_policy) != 0)
263 goto add_std_failure;
265 nla_for_each_nested(nla_a,
266 info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
267 nla_a_rem)
268 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
269 if (nla_validate_nested(nla_a,
270 NLBL_CIPSOV4_A_MAX,
271 netlbl_cipsov4_genl_policy) != 0)
272 goto add_std_failure;
273 nla_for_each_nested(nla_b, nla_a, nla_b_rem)
274 switch (nla_type(nla_b)) {
275 case NLBL_CIPSOV4_A_MLSCATLOC:
276 if (nla_get_u32(nla_b) >
277 CIPSO_V4_MAX_LOC_CATS)
278 goto add_std_failure;
279 if (nla_get_u32(nla_b) >=
280 doi_def->map.std->cat.local_size)
281 doi_def->map.std->cat.local_size =
282 nla_get_u32(nla_b) + 1;
283 break;
284 case NLBL_CIPSOV4_A_MLSCATREM:
285 if (nla_get_u32(nla_b) >
286 CIPSO_V4_MAX_REM_CATS)
287 goto add_std_failure;
288 if (nla_get_u32(nla_b) >=
289 doi_def->map.std->cat.cipso_size)
290 doi_def->map.std->cat.cipso_size =
291 nla_get_u32(nla_b) + 1;
292 break;
295 doi_def->map.std->cat.local = kcalloc(
296 doi_def->map.std->cat.local_size,
297 sizeof(u32),
298 GFP_KERNEL);
299 if (doi_def->map.std->cat.local == NULL) {
300 ret_val = -ENOMEM;
301 goto add_std_failure;
303 doi_def->map.std->cat.cipso = kcalloc(
304 doi_def->map.std->cat.cipso_size,
305 sizeof(u32),
306 GFP_KERNEL);
307 if (doi_def->map.std->cat.cipso == NULL) {
308 ret_val = -ENOMEM;
309 goto add_std_failure;
311 for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
312 doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
313 for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
314 doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
315 nla_for_each_nested(nla_a,
316 info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
317 nla_a_rem)
318 if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
319 struct nlattr *cat_loc;
320 struct nlattr *cat_rem;
322 cat_loc = nla_find_nested(nla_a,
323 NLBL_CIPSOV4_A_MLSCATLOC);
324 cat_rem = nla_find_nested(nla_a,
325 NLBL_CIPSOV4_A_MLSCATREM);
326 if (cat_loc == NULL || cat_rem == NULL)
327 goto add_std_failure;
328 doi_def->map.std->cat.local[
329 nla_get_u32(cat_loc)] =
330 nla_get_u32(cat_rem);
331 doi_def->map.std->cat.cipso[
332 nla_get_u32(cat_rem)] =
333 nla_get_u32(cat_loc);
337 ret_val = cipso_v4_doi_add(doi_def);
338 if (ret_val != 0)
339 goto add_std_failure;
340 return 0;
342 add_std_failure:
343 if (doi_def)
344 netlbl_cipsov4_doi_free(&doi_def->rcu);
345 return ret_val;
349 * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
350 * @info: the Generic NETLINK info block
352 * Description:
353 * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
354 * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
355 * error.
358 static int netlbl_cipsov4_add_pass(struct genl_info *info)
360 int ret_val;
361 struct cipso_v4_doi *doi_def = NULL;
363 if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
364 return -EINVAL;
366 doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
367 if (doi_def == NULL)
368 return -ENOMEM;
369 doi_def->type = CIPSO_V4_MAP_PASS;
371 ret_val = netlbl_cipsov4_add_common(info, doi_def);
372 if (ret_val != 0)
373 goto add_pass_failure;
375 ret_val = cipso_v4_doi_add(doi_def);
376 if (ret_val != 0)
377 goto add_pass_failure;
378 return 0;
380 add_pass_failure:
381 netlbl_cipsov4_doi_free(&doi_def->rcu);
382 return ret_val;
386 * netlbl_cipsov4_add - Handle an ADD message
387 * @skb: the NETLINK buffer
388 * @info: the Generic NETLINK info block
390 * Description:
391 * Create a new DOI definition based on the given ADD message and add it to the
392 * CIPSO V4 engine. Returns zero on success, negative values on failure.
395 static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
398 int ret_val = -EINVAL;
399 u32 type;
400 u32 doi;
401 const char *type_str = "(unknown)";
402 struct audit_buffer *audit_buf;
403 struct netlbl_audit audit_info;
405 if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
406 !info->attrs[NLBL_CIPSOV4_A_MTYPE])
407 return -EINVAL;
409 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
410 netlbl_netlink_auditinfo(skb, &audit_info);
412 type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
413 switch (type) {
414 case CIPSO_V4_MAP_STD:
415 type_str = "std";
416 ret_val = netlbl_cipsov4_add_std(info);
417 break;
418 case CIPSO_V4_MAP_PASS:
419 type_str = "pass";
420 ret_val = netlbl_cipsov4_add_pass(info);
421 break;
423 if (ret_val == 0)
424 netlbl_mgmt_protocount_inc();
426 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
427 &audit_info);
428 if (audit_buf != NULL) {
429 audit_log_format(audit_buf,
430 " cipso_doi=%u cipso_type=%s res=%u",
431 doi,
432 type_str,
433 ret_val == 0 ? 1 : 0);
434 audit_log_end(audit_buf);
437 return ret_val;
441 * netlbl_cipsov4_list - Handle a LIST message
442 * @skb: the NETLINK buffer
443 * @info: the Generic NETLINK info block
445 * Description:
446 * Process a user generated LIST message and respond accordingly. While the
447 * response message generated by the kernel is straightforward, determining
448 * before hand the size of the buffer to allocate is not (we have to generate
449 * the message to know the size). In order to keep this function sane what we
450 * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
451 * that size, if we fail then we restart with a larger buffer and try again.
452 * We continue in this manner until we hit a limit of failed attempts then we
453 * give up and just send an error message. Returns zero on success and
454 * negative values on error.
457 static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
459 int ret_val;
460 struct sk_buff *ans_skb = NULL;
461 u32 nlsze_mult = 1;
462 void *data;
463 u32 doi;
464 struct nlattr *nla_a;
465 struct nlattr *nla_b;
466 struct cipso_v4_doi *doi_def;
467 u32 iter;
469 if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
470 ret_val = -EINVAL;
471 goto list_failure;
474 list_start:
475 ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
476 if (ans_skb == NULL) {
477 ret_val = -ENOMEM;
478 goto list_failure;
480 data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
481 0, NLBL_CIPSOV4_C_LIST);
482 if (data == NULL) {
483 ret_val = -ENOMEM;
484 goto list_failure;
487 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
489 rcu_read_lock();
490 doi_def = cipso_v4_doi_getdef(doi);
491 if (doi_def == NULL) {
492 ret_val = -EINVAL;
493 goto list_failure;
496 ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
497 if (ret_val != 0)
498 goto list_failure_lock;
500 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
501 if (nla_a == NULL) {
502 ret_val = -ENOMEM;
503 goto list_failure_lock;
505 for (iter = 0;
506 iter < CIPSO_V4_TAG_MAXCNT &&
507 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
508 iter++) {
509 ret_val = nla_put_u8(ans_skb,
510 NLBL_CIPSOV4_A_TAG,
511 doi_def->tags[iter]);
512 if (ret_val != 0)
513 goto list_failure_lock;
515 nla_nest_end(ans_skb, nla_a);
517 switch (doi_def->type) {
518 case CIPSO_V4_MAP_STD:
519 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
520 if (nla_a == NULL) {
521 ret_val = -ENOMEM;
522 goto list_failure_lock;
524 for (iter = 0;
525 iter < doi_def->map.std->lvl.local_size;
526 iter++) {
527 if (doi_def->map.std->lvl.local[iter] ==
528 CIPSO_V4_INV_LVL)
529 continue;
531 nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
532 if (nla_b == NULL) {
533 ret_val = -ENOMEM;
534 goto list_retry;
536 ret_val = nla_put_u32(ans_skb,
537 NLBL_CIPSOV4_A_MLSLVLLOC,
538 iter);
539 if (ret_val != 0)
540 goto list_retry;
541 ret_val = nla_put_u32(ans_skb,
542 NLBL_CIPSOV4_A_MLSLVLREM,
543 doi_def->map.std->lvl.local[iter]);
544 if (ret_val != 0)
545 goto list_retry;
546 nla_nest_end(ans_skb, nla_b);
548 nla_nest_end(ans_skb, nla_a);
550 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
551 if (nla_a == NULL) {
552 ret_val = -ENOMEM;
553 goto list_retry;
555 for (iter = 0;
556 iter < doi_def->map.std->cat.local_size;
557 iter++) {
558 if (doi_def->map.std->cat.local[iter] ==
559 CIPSO_V4_INV_CAT)
560 continue;
562 nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
563 if (nla_b == NULL) {
564 ret_val = -ENOMEM;
565 goto list_retry;
567 ret_val = nla_put_u32(ans_skb,
568 NLBL_CIPSOV4_A_MLSCATLOC,
569 iter);
570 if (ret_val != 0)
571 goto list_retry;
572 ret_val = nla_put_u32(ans_skb,
573 NLBL_CIPSOV4_A_MLSCATREM,
574 doi_def->map.std->cat.local[iter]);
575 if (ret_val != 0)
576 goto list_retry;
577 nla_nest_end(ans_skb, nla_b);
579 nla_nest_end(ans_skb, nla_a);
581 break;
583 rcu_read_unlock();
585 genlmsg_end(ans_skb, data);
587 ret_val = genlmsg_reply(ans_skb, info);
588 if (ret_val != 0)
589 goto list_failure;
591 return 0;
593 list_retry:
594 /* XXX - this limit is a guesstimate */
595 if (nlsze_mult < 4) {
596 rcu_read_unlock();
597 kfree_skb(ans_skb);
598 nlsze_mult++;
599 goto list_start;
601 list_failure_lock:
602 rcu_read_unlock();
603 list_failure:
604 kfree_skb(ans_skb);
605 return ret_val;
609 * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
610 * @doi_def: the CIPSOv4 DOI definition
611 * @arg: the netlbl_cipsov4_doiwalk_arg structure
613 * Description:
614 * This function is designed to be used as a callback to the
615 * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
616 * message. Returns the size of the message on success, negative values on
617 * failure.
620 static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
622 int ret_val = -ENOMEM;
623 struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
624 void *data;
626 data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
627 cb_arg->seq, &netlbl_cipsov4_gnl_family,
628 NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
629 if (data == NULL)
630 goto listall_cb_failure;
632 ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
633 if (ret_val != 0)
634 goto listall_cb_failure;
635 ret_val = nla_put_u32(cb_arg->skb,
636 NLBL_CIPSOV4_A_MTYPE,
637 doi_def->type);
638 if (ret_val != 0)
639 goto listall_cb_failure;
641 return genlmsg_end(cb_arg->skb, data);
643 listall_cb_failure:
644 genlmsg_cancel(cb_arg->skb, data);
645 return ret_val;
649 * netlbl_cipsov4_listall - Handle a LISTALL message
650 * @skb: the NETLINK buffer
651 * @cb: the NETLINK callback
653 * Description:
654 * Process a user generated LISTALL message and respond accordingly. Returns
655 * zero on success and negative values on error.
658 static int netlbl_cipsov4_listall(struct sk_buff *skb,
659 struct netlink_callback *cb)
661 struct netlbl_cipsov4_doiwalk_arg cb_arg;
662 int doi_skip = cb->args[0];
664 cb_arg.nl_cb = cb;
665 cb_arg.skb = skb;
666 cb_arg.seq = cb->nlh->nlmsg_seq;
668 cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
670 cb->args[0] = doi_skip;
671 return skb->len;
675 * netlbl_cipsov4_remove - Handle a REMOVE message
676 * @skb: the NETLINK buffer
677 * @info: the Generic NETLINK info block
679 * Description:
680 * Process a user generated REMOVE message and respond accordingly. Returns
681 * zero on success, negative values on failure.
684 static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
686 int ret_val = -EINVAL;
687 u32 doi = 0;
688 struct audit_buffer *audit_buf;
689 struct netlbl_audit audit_info;
691 if (!info->attrs[NLBL_CIPSOV4_A_DOI])
692 return -EINVAL;
694 doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
695 netlbl_netlink_auditinfo(skb, &audit_info);
697 ret_val = cipso_v4_doi_remove(doi,
698 &audit_info,
699 netlbl_cipsov4_doi_free);
700 if (ret_val == 0)
701 netlbl_mgmt_protocount_dec();
703 audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
704 &audit_info);
705 if (audit_buf != NULL) {
706 audit_log_format(audit_buf,
707 " cipso_doi=%u res=%u",
708 doi,
709 ret_val == 0 ? 1 : 0);
710 audit_log_end(audit_buf);
713 return ret_val;
717 * NetLabel Generic NETLINK Command Definitions
720 static struct genl_ops netlbl_cipsov4_genl_c_add = {
721 .cmd = NLBL_CIPSOV4_C_ADD,
722 .flags = GENL_ADMIN_PERM,
723 .policy = netlbl_cipsov4_genl_policy,
724 .doit = netlbl_cipsov4_add,
725 .dumpit = NULL,
728 static struct genl_ops netlbl_cipsov4_genl_c_remove = {
729 .cmd = NLBL_CIPSOV4_C_REMOVE,
730 .flags = GENL_ADMIN_PERM,
731 .policy = netlbl_cipsov4_genl_policy,
732 .doit = netlbl_cipsov4_remove,
733 .dumpit = NULL,
736 static struct genl_ops netlbl_cipsov4_genl_c_list = {
737 .cmd = NLBL_CIPSOV4_C_LIST,
738 .flags = 0,
739 .policy = netlbl_cipsov4_genl_policy,
740 .doit = netlbl_cipsov4_list,
741 .dumpit = NULL,
744 static struct genl_ops netlbl_cipsov4_genl_c_listall = {
745 .cmd = NLBL_CIPSOV4_C_LISTALL,
746 .flags = 0,
747 .policy = netlbl_cipsov4_genl_policy,
748 .doit = NULL,
749 .dumpit = netlbl_cipsov4_listall,
753 * NetLabel Generic NETLINK Protocol Functions
757 * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
759 * Description:
760 * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
761 * mechanism. Returns zero on success, negative values on failure.
764 int netlbl_cipsov4_genl_init(void)
766 int ret_val;
768 ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
769 if (ret_val != 0)
770 return ret_val;
772 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
773 &netlbl_cipsov4_genl_c_add);
774 if (ret_val != 0)
775 return ret_val;
776 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
777 &netlbl_cipsov4_genl_c_remove);
778 if (ret_val != 0)
779 return ret_val;
780 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
781 &netlbl_cipsov4_genl_c_list);
782 if (ret_val != 0)
783 return ret_val;
784 ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
785 &netlbl_cipsov4_genl_c_listall);
786 if (ret_val != 0)
787 return ret_val;
789 return 0;