]> bbs.cooldavid.org Git - net-next-2.6.git/blob - net/netlabel/netlabel_cipso_v4.c
[GENL]: Add genlmsg_put_reply() to simplify building reply headers
[net-next-2.6.git] / net / netlabel / netlabel_cipso_v4.c
1 /*
2  * NetLabel CIPSO/IPv4 Support
3  *
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.
7  *
8  * Author: Paul Moore <paul.moore@hp.com>
9  *
10  */
11
12 /*
13  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14  *
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.
19  *
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.
24  *
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
28  *
29  */
30
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>
41
42 #include "netlabel_user.h"
43 #include "netlabel_cipso_v4.h"
44
45 /* Argument struct for cipso_v4_doi_walk() */
46 struct netlbl_cipsov4_doiwalk_arg {
47         struct netlink_callback *nl_cb;
48         struct sk_buff *skb;
49         u32 seq;
50 };
51
52 /* NetLabel Generic NETLINK CIPSOv4 family */
53 static struct genl_family netlbl_cipsov4_gnl_family = {
54         .id = GENL_ID_GENERATE,
55         .hdrsize = 0,
56         .name = NETLBL_NLTYPE_CIPSOV4_NAME,
57         .version = NETLBL_PROTO_VERSION,
58         .maxattr = NLBL_CIPSOV4_A_MAX,
59 };
60
61 /* NetLabel Netlink attribute policy */
62 static struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
63         [NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
64         [NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
65         [NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
66         [NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
67         [NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
68         [NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
69         [NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
70         [NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
71         [NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
72         [NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
73         [NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
74         [NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
75 };
76
77 /*
78  * Helper Functions
79  */
80
81 /**
82  * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
83  * @entry: the entry's RCU field
84  *
85  * Description:
86  * This function is designed to be used as a callback to the call_rcu()
87  * function so that the memory allocated to the DOI definition can be released
88  * safely.
89  *
90  */
91 static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
92 {
93         struct cipso_v4_doi *ptr;
94
95         ptr = container_of(entry, struct cipso_v4_doi, rcu);
96         switch (ptr->type) {
97         case CIPSO_V4_MAP_STD:
98                 kfree(ptr->map.std->lvl.cipso);
99                 kfree(ptr->map.std->lvl.local);
100                 kfree(ptr->map.std->cat.cipso);
101                 kfree(ptr->map.std->cat.local);
102                 break;
103         }
104         kfree(ptr);
105 }
106
107 /**
108  * netlbl_cipsov4_add_common - Parse the common sections of a ADD message
109  * @info: the Generic NETLINK info block
110  * @doi_def: the CIPSO V4 DOI definition
111  *
112  * Description:
113  * Parse the common sections of a ADD message and fill in the related values
114  * in @doi_def.  Returns zero on success, negative values on failure.
115  *
116  */
117 static int netlbl_cipsov4_add_common(struct genl_info *info,
118                                      struct cipso_v4_doi *doi_def)
119 {
120         struct nlattr *nla;
121         int nla_rem;
122         u32 iter = 0;
123
124         doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
125
126         if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
127                                 NLBL_CIPSOV4_A_MAX,
128                                 netlbl_cipsov4_genl_policy) != 0)
129                 return -EINVAL;
130
131         nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
132                 if (nla->nla_type == NLBL_CIPSOV4_A_TAG) {
133                         if (iter > CIPSO_V4_TAG_MAXCNT)
134                                 return -EINVAL;
135                         doi_def->tags[iter++] = nla_get_u8(nla);
136                 }
137         if (iter < CIPSO_V4_TAG_MAXCNT)
138                 doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
139
140         return 0;
141 }
142
143 /*
144  * NetLabel Command Handlers
145  */
146
147 /**
148  * netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
149  * @info: the Generic NETLINK info block
150  *
151  * Description:
152  * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
153  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
154  * error.
155  *
156  */
157 static int netlbl_cipsov4_add_std(struct genl_info *info)
158 {
159         int ret_val = -EINVAL;
160         struct cipso_v4_doi *doi_def = NULL;
161         struct nlattr *nla_a;
162         struct nlattr *nla_b;
163         int nla_a_rem;
164         int nla_b_rem;
165
166         if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
167             !info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
168                 return -EINVAL;
169
170         if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
171                                 NLBL_CIPSOV4_A_MAX,
172                                 netlbl_cipsov4_genl_policy) != 0)
173                 return -EINVAL;
174
175         doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
176         if (doi_def == NULL)
177                 return -ENOMEM;
178         doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
179         if (doi_def->map.std == NULL) {
180                 ret_val = -ENOMEM;
181                 goto add_std_failure;
182         }
183         doi_def->type = CIPSO_V4_MAP_STD;
184
185         ret_val = netlbl_cipsov4_add_common(info, doi_def);
186         if (ret_val != 0)
187                 goto add_std_failure;
188
189         nla_for_each_nested(nla_a,
190                             info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
191                             nla_a_rem)
192                 if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
193                         nla_for_each_nested(nla_b, nla_a, nla_b_rem)
194                                 switch (nla_b->nla_type) {
195                                 case NLBL_CIPSOV4_A_MLSLVLLOC:
196                                         if (nla_get_u32(nla_b) >=
197                                             doi_def->map.std->lvl.local_size)
198                                              doi_def->map.std->lvl.local_size =
199                                                      nla_get_u32(nla_b) + 1;
200                                         break;
201                                 case NLBL_CIPSOV4_A_MLSLVLREM:
202                                         if (nla_get_u32(nla_b) >=
203                                             doi_def->map.std->lvl.cipso_size)
204                                              doi_def->map.std->lvl.cipso_size =
205                                                      nla_get_u32(nla_b) + 1;
206                                         break;
207                                 }
208                 }
209         if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS ||
210             doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
211                 goto add_std_failure;
212         doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
213                                               sizeof(u32),
214                                               GFP_KERNEL);
215         if (doi_def->map.std->lvl.local == NULL) {
216                 ret_val = -ENOMEM;
217                 goto add_std_failure;
218         }
219         doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
220                                               sizeof(u32),
221                                               GFP_KERNEL);
222         if (doi_def->map.std->lvl.cipso == NULL) {
223                 ret_val = -ENOMEM;
224                 goto add_std_failure;
225         }
226         nla_for_each_nested(nla_a,
227                             info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
228                             nla_a_rem)
229                 if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
230                         struct nlattr *lvl_loc;
231                         struct nlattr *lvl_rem;
232
233                         if (nla_validate_nested(nla_a,
234                                               NLBL_CIPSOV4_A_MAX,
235                                               netlbl_cipsov4_genl_policy) != 0)
236                                 goto add_std_failure;
237
238                         lvl_loc = nla_find_nested(nla_a,
239                                                   NLBL_CIPSOV4_A_MLSLVLLOC);
240                         lvl_rem = nla_find_nested(nla_a,
241                                                   NLBL_CIPSOV4_A_MLSLVLREM);
242                         if (lvl_loc == NULL || lvl_rem == NULL)
243                                 goto add_std_failure;
244                         doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
245                                 nla_get_u32(lvl_rem);
246                         doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
247                                 nla_get_u32(lvl_loc);
248                 }
249
250         if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
251                 if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
252                                         NLBL_CIPSOV4_A_MAX,
253                                         netlbl_cipsov4_genl_policy) != 0)
254                         goto add_std_failure;
255
256                 nla_for_each_nested(nla_a,
257                                     info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
258                                     nla_a_rem)
259                         if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
260                                 if (nla_validate_nested(nla_a,
261                                               NLBL_CIPSOV4_A_MAX,
262                                               netlbl_cipsov4_genl_policy) != 0)
263                                         goto add_std_failure;
264                                 nla_for_each_nested(nla_b, nla_a, nla_b_rem)
265                                         switch (nla_b->nla_type) {
266                                         case NLBL_CIPSOV4_A_MLSCATLOC:
267                                                 if (nla_get_u32(nla_b) >=
268                                               doi_def->map.std->cat.local_size)
269                                              doi_def->map.std->cat.local_size =
270                                                      nla_get_u32(nla_b) + 1;
271                                                 break;
272                                         case NLBL_CIPSOV4_A_MLSCATREM:
273                                                 if (nla_get_u32(nla_b) >=
274                                               doi_def->map.std->cat.cipso_size)
275                                              doi_def->map.std->cat.cipso_size =
276                                                      nla_get_u32(nla_b) + 1;
277                                                 break;
278                                         }
279                         }
280                 if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS ||
281                     doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
282                         goto add_std_failure;
283                 doi_def->map.std->cat.local = kcalloc(
284                                               doi_def->map.std->cat.local_size,
285                                               sizeof(u32),
286                                               GFP_KERNEL);
287                 if (doi_def->map.std->cat.local == NULL) {
288                         ret_val = -ENOMEM;
289                         goto add_std_failure;
290                 }
291                 doi_def->map.std->cat.cipso = kcalloc(
292                                               doi_def->map.std->cat.cipso_size,
293                                               sizeof(u32),
294                                               GFP_KERNEL);
295                 if (doi_def->map.std->cat.cipso == NULL) {
296                         ret_val = -ENOMEM;
297                         goto add_std_failure;
298                 }
299                 nla_for_each_nested(nla_a,
300                                     info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
301                                     nla_a_rem)
302                         if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSCAT) {
303                                 struct nlattr *cat_loc;
304                                 struct nlattr *cat_rem;
305
306                                 cat_loc = nla_find_nested(nla_a,
307                                                      NLBL_CIPSOV4_A_MLSCATLOC);
308                                 cat_rem = nla_find_nested(nla_a,
309                                                      NLBL_CIPSOV4_A_MLSCATREM);
310                                 if (cat_loc == NULL || cat_rem == NULL)
311                                         goto add_std_failure;
312                                 doi_def->map.std->cat.local[
313                                                         nla_get_u32(cat_loc)] =
314                                         nla_get_u32(cat_rem);
315                                 doi_def->map.std->cat.cipso[
316                                                         nla_get_u32(cat_rem)] =
317                                         nla_get_u32(cat_loc);
318                         }
319         }
320
321         ret_val = cipso_v4_doi_add(doi_def);
322         if (ret_val != 0)
323                 goto add_std_failure;
324         return 0;
325
326 add_std_failure:
327         if (doi_def)
328                 netlbl_cipsov4_doi_free(&doi_def->rcu);
329         return ret_val;
330 }
331
332 /**
333  * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
334  * @info: the Generic NETLINK info block
335  *
336  * Description:
337  * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
338  * and add it to the CIPSO V4 engine.  Return zero on success and non-zero on
339  * error.
340  *
341  */
342 static int netlbl_cipsov4_add_pass(struct genl_info *info)
343 {
344         int ret_val;
345         struct cipso_v4_doi *doi_def = NULL;
346
347         if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
348                 return -EINVAL;
349
350         doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
351         if (doi_def == NULL)
352                 return -ENOMEM;
353         doi_def->type = CIPSO_V4_MAP_PASS;
354
355         ret_val = netlbl_cipsov4_add_common(info, doi_def);
356         if (ret_val != 0)
357                 goto add_pass_failure;
358
359         ret_val = cipso_v4_doi_add(doi_def);
360         if (ret_val != 0)
361                 goto add_pass_failure;
362         return 0;
363
364 add_pass_failure:
365         netlbl_cipsov4_doi_free(&doi_def->rcu);
366         return ret_val;
367 }
368
369 /**
370  * netlbl_cipsov4_add - Handle an ADD message
371  * @skb: the NETLINK buffer
372  * @info: the Generic NETLINK info block
373  *
374  * Description:
375  * Create a new DOI definition based on the given ADD message and add it to the
376  * CIPSO V4 engine.  Returns zero on success, negative values on failure.
377  *
378  */
379 static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
380
381 {
382         int ret_val = -EINVAL;
383         u32 type;
384         u32 doi;
385         const char *type_str = "(unknown)";
386         struct audit_buffer *audit_buf;
387         struct netlbl_audit audit_info;
388
389         if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
390             !info->attrs[NLBL_CIPSOV4_A_MTYPE])
391                 return -EINVAL;
392
393         doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
394         netlbl_netlink_auditinfo(skb, &audit_info);
395
396         type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
397         switch (type) {
398         case CIPSO_V4_MAP_STD:
399                 type_str = "std";
400                 ret_val = netlbl_cipsov4_add_std(info);
401                 break;
402         case CIPSO_V4_MAP_PASS:
403                 type_str = "pass";
404                 ret_val = netlbl_cipsov4_add_pass(info);
405                 break;
406         }
407
408         audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
409                                               &audit_info);
410         audit_log_format(audit_buf,
411                          " cipso_doi=%u cipso_type=%s res=%u",
412                          doi,
413                          type_str,
414                          ret_val == 0 ? 1 : 0);
415         audit_log_end(audit_buf);
416
417         return ret_val;
418 }
419
420 /**
421  * netlbl_cipsov4_list - Handle a LIST message
422  * @skb: the NETLINK buffer
423  * @info: the Generic NETLINK info block
424  *
425  * Description:
426  * Process a user generated LIST message and respond accordingly.  While the
427  * response message generated by the kernel is straightforward, determining
428  * before hand the size of the buffer to allocate is not (we have to generate
429  * the message to know the size).  In order to keep this function sane what we
430  * do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
431  * that size, if we fail then we restart with a larger buffer and try again.
432  * We continue in this manner until we hit a limit of failed attempts then we
433  * give up and just send an error message.  Returns zero on success and
434  * negative values on error.
435  *
436  */
437 static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
438 {
439         int ret_val;
440         struct sk_buff *ans_skb = NULL;
441         u32 nlsze_mult = 1;
442         void *data;
443         u32 doi;
444         struct nlattr *nla_a;
445         struct nlattr *nla_b;
446         struct cipso_v4_doi *doi_def;
447         u32 iter;
448
449         if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
450                 ret_val = -EINVAL;
451                 goto list_failure;
452         }
453
454 list_start:
455         ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
456         if (ans_skb == NULL) {
457                 ret_val = -ENOMEM;
458                 goto list_failure;
459         }
460         data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
461                                  0, NLBL_CIPSOV4_C_LIST);
462         if (data == NULL) {
463                 ret_val = -ENOMEM;
464                 goto list_failure;
465         }
466
467         doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
468
469         rcu_read_lock();
470         doi_def = cipso_v4_doi_getdef(doi);
471         if (doi_def == NULL) {
472                 ret_val = -EINVAL;
473                 goto list_failure;
474         }
475
476         ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
477         if (ret_val != 0)
478                 goto list_failure_lock;
479
480         nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
481         if (nla_a == NULL) {
482                 ret_val = -ENOMEM;
483                 goto list_failure_lock;
484         }
485         for (iter = 0;
486              iter < CIPSO_V4_TAG_MAXCNT &&
487                doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
488              iter++) {
489                 ret_val = nla_put_u8(ans_skb,
490                                      NLBL_CIPSOV4_A_TAG,
491                                      doi_def->tags[iter]);
492                 if (ret_val != 0)
493                         goto list_failure_lock;
494         }
495         nla_nest_end(ans_skb, nla_a);
496
497         switch (doi_def->type) {
498         case CIPSO_V4_MAP_STD:
499                 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
500                 if (nla_a == NULL) {
501                         ret_val = -ENOMEM;
502                         goto list_failure_lock;
503                 }
504                 for (iter = 0;
505                      iter < doi_def->map.std->lvl.local_size;
506                      iter++) {
507                         if (doi_def->map.std->lvl.local[iter] ==
508                             CIPSO_V4_INV_LVL)
509                                 continue;
510
511                         nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
512                         if (nla_b == NULL) {
513                                 ret_val = -ENOMEM;
514                                 goto list_retry;
515                         }
516                         ret_val = nla_put_u32(ans_skb,
517                                               NLBL_CIPSOV4_A_MLSLVLLOC,
518                                               iter);
519                         if (ret_val != 0)
520                                 goto list_retry;
521                         ret_val = nla_put_u32(ans_skb,
522                                             NLBL_CIPSOV4_A_MLSLVLREM,
523                                             doi_def->map.std->lvl.local[iter]);
524                         if (ret_val != 0)
525                                 goto list_retry;
526                         nla_nest_end(ans_skb, nla_b);
527                 }
528                 nla_nest_end(ans_skb, nla_a);
529
530                 nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
531                 if (nla_a == NULL) {
532                         ret_val = -ENOMEM;
533                         goto list_retry;
534                 }
535                 for (iter = 0;
536                      iter < doi_def->map.std->cat.local_size;
537                      iter++) {
538                         if (doi_def->map.std->cat.local[iter] ==
539                             CIPSO_V4_INV_CAT)
540                                 continue;
541
542                         nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
543                         if (nla_b == NULL) {
544                                 ret_val = -ENOMEM;
545                                 goto list_retry;
546                         }
547                         ret_val = nla_put_u32(ans_skb,
548                                               NLBL_CIPSOV4_A_MLSCATLOC,
549                                               iter);
550                         if (ret_val != 0)
551                                 goto list_retry;
552                         ret_val = nla_put_u32(ans_skb,
553                                             NLBL_CIPSOV4_A_MLSCATREM,
554                                             doi_def->map.std->cat.local[iter]);
555                         if (ret_val != 0)
556                                 goto list_retry;
557                         nla_nest_end(ans_skb, nla_b);
558                 }
559                 nla_nest_end(ans_skb, nla_a);
560
561                 break;
562         }
563         rcu_read_unlock();
564
565         genlmsg_end(ans_skb, data);
566
567         ret_val = genlmsg_reply(ans_skb, info);
568         if (ret_val != 0)
569                 goto list_failure;
570
571         return 0;
572
573 list_retry:
574         /* XXX - this limit is a guesstimate */
575         if (nlsze_mult < 4) {
576                 rcu_read_unlock();
577                 kfree_skb(ans_skb);
578                 nlsze_mult++;
579                 goto list_start;
580         }
581 list_failure_lock:
582         rcu_read_unlock();
583 list_failure:
584         kfree_skb(ans_skb);
585         return ret_val;
586 }
587
588 /**
589  * netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
590  * @doi_def: the CIPSOv4 DOI definition
591  * @arg: the netlbl_cipsov4_doiwalk_arg structure
592  *
593  * Description:
594  * This function is designed to be used as a callback to the
595  * cipso_v4_doi_walk() function for use in generating a response for a LISTALL
596  * message.  Returns the size of the message on success, negative values on
597  * failure.
598  *
599  */
600 static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
601 {
602         int ret_val = -ENOMEM;
603         struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
604         void *data;
605
606         data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,
607                            cb_arg->seq, &netlbl_cipsov4_gnl_family,
608                            NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
609         if (data == NULL)
610                 goto listall_cb_failure;
611
612         ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
613         if (ret_val != 0)
614                 goto listall_cb_failure;
615         ret_val = nla_put_u32(cb_arg->skb,
616                               NLBL_CIPSOV4_A_MTYPE,
617                               doi_def->type);
618         if (ret_val != 0)
619                 goto listall_cb_failure;
620
621         return genlmsg_end(cb_arg->skb, data);
622
623 listall_cb_failure:
624         genlmsg_cancel(cb_arg->skb, data);
625         return ret_val;
626 }
627
628 /**
629  * netlbl_cipsov4_listall - Handle a LISTALL message
630  * @skb: the NETLINK buffer
631  * @cb: the NETLINK callback
632  *
633  * Description:
634  * Process a user generated LISTALL message and respond accordingly.  Returns
635  * zero on success and negative values on error.
636  *
637  */
638 static int netlbl_cipsov4_listall(struct sk_buff *skb,
639                                   struct netlink_callback *cb)
640 {
641         struct netlbl_cipsov4_doiwalk_arg cb_arg;
642         int doi_skip = cb->args[0];
643
644         cb_arg.nl_cb = cb;
645         cb_arg.skb = skb;
646         cb_arg.seq = cb->nlh->nlmsg_seq;
647
648         cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
649
650         cb->args[0] = doi_skip;
651         return skb->len;
652 }
653
654 /**
655  * netlbl_cipsov4_remove - Handle a REMOVE message
656  * @skb: the NETLINK buffer
657  * @info: the Generic NETLINK info block
658  *
659  * Description:
660  * Process a user generated REMOVE message and respond accordingly.  Returns
661  * zero on success, negative values on failure.
662  *
663  */
664 static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
665 {
666         int ret_val = -EINVAL;
667         u32 doi = 0;
668         struct audit_buffer *audit_buf;
669         struct netlbl_audit audit_info;
670
671         if (!info->attrs[NLBL_CIPSOV4_A_DOI])
672                 return -EINVAL;
673
674         doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
675         netlbl_netlink_auditinfo(skb, &audit_info);
676
677         ret_val = cipso_v4_doi_remove(doi,
678                                       &audit_info,
679                                       netlbl_cipsov4_doi_free);
680
681         audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
682                                               &audit_info);
683         audit_log_format(audit_buf,
684                          " cipso_doi=%u res=%u",
685                          doi,
686                          ret_val == 0 ? 1 : 0);
687         audit_log_end(audit_buf);
688
689         return ret_val;
690 }
691
692 /*
693  * NetLabel Generic NETLINK Command Definitions
694  */
695
696 static struct genl_ops netlbl_cipsov4_genl_c_add = {
697         .cmd = NLBL_CIPSOV4_C_ADD,
698         .flags = GENL_ADMIN_PERM,
699         .policy = netlbl_cipsov4_genl_policy,
700         .doit = netlbl_cipsov4_add,
701         .dumpit = NULL,
702 };
703
704 static struct genl_ops netlbl_cipsov4_genl_c_remove = {
705         .cmd = NLBL_CIPSOV4_C_REMOVE,
706         .flags = GENL_ADMIN_PERM,
707         .policy = netlbl_cipsov4_genl_policy,
708         .doit = netlbl_cipsov4_remove,
709         .dumpit = NULL,
710 };
711
712 static struct genl_ops netlbl_cipsov4_genl_c_list = {
713         .cmd = NLBL_CIPSOV4_C_LIST,
714         .flags = 0,
715         .policy = netlbl_cipsov4_genl_policy,
716         .doit = netlbl_cipsov4_list,
717         .dumpit = NULL,
718 };
719
720 static struct genl_ops netlbl_cipsov4_genl_c_listall = {
721         .cmd = NLBL_CIPSOV4_C_LISTALL,
722         .flags = 0,
723         .policy = netlbl_cipsov4_genl_policy,
724         .doit = NULL,
725         .dumpit = netlbl_cipsov4_listall,
726 };
727
728 /*
729  * NetLabel Generic NETLINK Protocol Functions
730  */
731
732 /**
733  * netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
734  *
735  * Description:
736  * Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
737  * mechanism.  Returns zero on success, negative values on failure.
738  *
739  */
740 int netlbl_cipsov4_genl_init(void)
741 {
742         int ret_val;
743
744         ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
745         if (ret_val != 0)
746                 return ret_val;
747
748         ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
749                                     &netlbl_cipsov4_genl_c_add);
750         if (ret_val != 0)
751                 return ret_val;
752         ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
753                                     &netlbl_cipsov4_genl_c_remove);
754         if (ret_val != 0)
755                 return ret_val;
756         ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
757                                     &netlbl_cipsov4_genl_c_list);
758         if (ret_val != 0)
759                 return ret_val;
760         ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
761                                     &netlbl_cipsov4_genl_c_listall);
762         if (ret_val != 0)
763                 return ret_val;
764
765         return 0;
766 }