Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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