xfrm: Use __skb_queue_tail in xfrm_trans_queue
[pandora-kernel.git] / net / netlabel / netlabel_domainhash.c
1 /*
2  * NetLabel Domain Hash Table
3  *
4  * This file manages the domain hash table that NetLabel uses to determine
5  * which network labeling protocol to use for a given domain.  The NetLabel
6  * system manages static and dynamic label mappings for network protocols such
7  * as CIPSO and RIPSO.
8  *
9  * Author: Paul Moore <paul@paul-moore.com>
10  *
11  */
12
13 /*
14  * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
15  *
16  * This program is free software;  you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
24  * the GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program;  if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29  *
30  */
31
32 #include <linux/types.h>
33 #include <linux/rculist.h>
34 #include <linux/skbuff.h>
35 #include <linux/spinlock.h>
36 #include <linux/string.h>
37 #include <linux/audit.h>
38 #include <linux/slab.h>
39 #include <net/netlabel.h>
40 #include <net/cipso_ipv4.h>
41 #include <asm/bug.h>
42
43 #include "netlabel_mgmt.h"
44 #include "netlabel_addrlist.h"
45 #include "netlabel_domainhash.h"
46 #include "netlabel_user.h"
47
48 struct netlbl_domhsh_tbl {
49         struct list_head *tbl;
50         u32 size;
51 };
52
53 /* Domain hash table */
54 /* updates should be so rare that having one spinlock for the entire hash table
55  * should be okay */
56 static DEFINE_SPINLOCK(netlbl_domhsh_lock);
57 #define netlbl_domhsh_rcu_deref(p) \
58         rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
59 static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
60 static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
61
62 /*
63  * Domain Hash Table Helper Functions
64  */
65
66 /**
67  * netlbl_domhsh_free_entry - Frees a domain hash table entry
68  * @entry: the entry's RCU field
69  *
70  * Description:
71  * This function is designed to be used as a callback to the call_rcu()
72  * function so that the memory allocated to a hash table entry can be released
73  * safely.
74  *
75  */
76 static void netlbl_domhsh_free_entry(struct rcu_head *entry)
77 {
78         struct netlbl_dom_map *ptr;
79         struct netlbl_af4list *iter4;
80         struct netlbl_af4list *tmp4;
81 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
82         struct netlbl_af6list *iter6;
83         struct netlbl_af6list *tmp6;
84 #endif /* IPv6 */
85
86         ptr = container_of(entry, struct netlbl_dom_map, rcu);
87         if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
88                 netlbl_af4list_foreach_safe(iter4, tmp4,
89                                             &ptr->type_def.addrsel->list4) {
90                         netlbl_af4list_remove_entry(iter4);
91                         kfree(netlbl_domhsh_addr4_entry(iter4));
92                 }
93 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
94                 netlbl_af6list_foreach_safe(iter6, tmp6,
95                                             &ptr->type_def.addrsel->list6) {
96                         netlbl_af6list_remove_entry(iter6);
97                         kfree(netlbl_domhsh_addr6_entry(iter6));
98                 }
99 #endif /* IPv6 */
100         }
101         kfree(ptr->domain);
102         kfree(ptr);
103 }
104
105 /**
106  * netlbl_domhsh_hash - Hashing function for the domain hash table
107  * @domain: the domain name to hash
108  *
109  * Description:
110  * This is the hashing function for the domain hash table, it returns the
111  * correct bucket number for the domain.  The caller is responsible for
112  * ensuring that the hash table is protected with either a RCU read lock or the
113  * hash table lock.
114  *
115  */
116 static u32 netlbl_domhsh_hash(const char *key)
117 {
118         u32 iter;
119         u32 val;
120         u32 len;
121
122         /* This is taken (with slight modification) from
123          * security/selinux/ss/symtab.c:symhash() */
124
125         for (iter = 0, val = 0, len = strlen(key); iter < len; iter++)
126                 val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter];
127         return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
128 }
129
130 /**
131  * netlbl_domhsh_search - Search for a domain entry
132  * @domain: the domain
133  *
134  * Description:
135  * Searches the domain hash table and returns a pointer to the hash table
136  * entry if found, otherwise NULL is returned.  The caller is responsible for
137  * ensuring that the hash table is protected with either a RCU read lock or the
138  * hash table lock.
139  *
140  */
141 static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
142 {
143         u32 bkt;
144         struct list_head *bkt_list;
145         struct netlbl_dom_map *iter;
146
147         if (domain != NULL) {
148                 bkt = netlbl_domhsh_hash(domain);
149                 bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
150                 list_for_each_entry_rcu(iter, bkt_list, list)
151                         if (iter->valid && strcmp(iter->domain, domain) == 0)
152                                 return iter;
153         }
154
155         return NULL;
156 }
157
158 /**
159  * netlbl_domhsh_search_def - Search for a domain entry
160  * @domain: the domain
161  * @def: return default if no match is found
162  *
163  * Description:
164  * Searches the domain hash table and returns a pointer to the hash table
165  * entry if an exact match is found, if an exact match is not present in the
166  * hash table then the default entry is returned if valid otherwise NULL is
167  * returned.  The caller is responsible ensuring that the hash table is
168  * protected with either a RCU read lock or the hash table lock.
169  *
170  */
171 static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
172 {
173         struct netlbl_dom_map *entry;
174
175         entry = netlbl_domhsh_search(domain);
176         if (entry == NULL) {
177                 entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def);
178                 if (entry != NULL && !entry->valid)
179                         entry = NULL;
180         }
181
182         return entry;
183 }
184
185 /**
186  * netlbl_domhsh_audit_add - Generate an audit entry for an add event
187  * @entry: the entry being added
188  * @addr4: the IPv4 address information
189  * @addr6: the IPv6 address information
190  * @result: the result code
191  * @audit_info: NetLabel audit information
192  *
193  * Description:
194  * Generate an audit record for adding a new NetLabel/LSM mapping entry with
195  * the given information.  Caller is responsible for holding the necessary
196  * locks.
197  *
198  */
199 static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
200                                     struct netlbl_af4list *addr4,
201                                     struct netlbl_af6list *addr6,
202                                     int result,
203                                     struct netlbl_audit *audit_info)
204 {
205         struct audit_buffer *audit_buf;
206         struct cipso_v4_doi *cipsov4 = NULL;
207         u32 type;
208
209         audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
210         if (audit_buf != NULL) {
211                 audit_log_format(audit_buf, " nlbl_domain=%s",
212                                  entry->domain ? entry->domain : "(default)");
213                 if (addr4 != NULL) {
214                         struct netlbl_domaddr4_map *map4;
215                         map4 = netlbl_domhsh_addr4_entry(addr4);
216                         type = map4->type;
217                         cipsov4 = map4->type_def.cipsov4;
218                         netlbl_af4list_audit_addr(audit_buf, 0, NULL,
219                                                   addr4->addr, addr4->mask);
220 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
221                 } else if (addr6 != NULL) {
222                         struct netlbl_domaddr6_map *map6;
223                         map6 = netlbl_domhsh_addr6_entry(addr6);
224                         type = map6->type;
225                         netlbl_af6list_audit_addr(audit_buf, 0, NULL,
226                                                   &addr6->addr, &addr6->mask);
227 #endif /* IPv6 */
228                 } else {
229                         type = entry->type;
230                         cipsov4 = entry->type_def.cipsov4;
231                 }
232                 switch (type) {
233                 case NETLBL_NLTYPE_UNLABELED:
234                         audit_log_format(audit_buf, " nlbl_protocol=unlbl");
235                         break;
236                 case NETLBL_NLTYPE_CIPSOV4:
237                         BUG_ON(cipsov4 == NULL);
238                         audit_log_format(audit_buf,
239                                          " nlbl_protocol=cipsov4 cipso_doi=%u",
240                                          cipsov4->doi);
241                         break;
242                 }
243                 audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
244                 audit_log_end(audit_buf);
245         }
246 }
247
248 /**
249  * netlbl_domhsh_validate - Validate a new domain mapping entry
250  * @entry: the entry to validate
251  *
252  * This function validates the new domain mapping entry to ensure that it is
253  * a valid entry.  Returns zero on success, negative values on failure.
254  *
255  */
256 static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
257 {
258         struct netlbl_af4list *iter4;
259         struct netlbl_domaddr4_map *map4;
260 #if IS_ENABLED(CONFIG_IPV6)
261         struct netlbl_af6list *iter6;
262         struct netlbl_domaddr6_map *map6;
263 #endif /* IPv6 */
264
265         if (entry == NULL)
266                 return -EINVAL;
267
268         switch (entry->type) {
269         case NETLBL_NLTYPE_UNLABELED:
270                 if (entry->type_def.cipsov4 != NULL ||
271                     entry->type_def.addrsel != NULL)
272                         return -EINVAL;
273                 break;
274         case NETLBL_NLTYPE_CIPSOV4:
275                 if (entry->type_def.cipsov4 == NULL)
276                         return -EINVAL;
277                 break;
278         case NETLBL_NLTYPE_ADDRSELECT:
279                 netlbl_af4list_foreach(iter4, &entry->type_def.addrsel->list4) {
280                         map4 = netlbl_domhsh_addr4_entry(iter4);
281                         switch (map4->type) {
282                         case NETLBL_NLTYPE_UNLABELED:
283                                 if (map4->type_def.cipsov4 != NULL)
284                                         return -EINVAL;
285                                 break;
286                         case NETLBL_NLTYPE_CIPSOV4:
287                                 if (map4->type_def.cipsov4 == NULL)
288                                         return -EINVAL;
289                                 break;
290                         default:
291                                 return -EINVAL;
292                         }
293                 }
294 #if IS_ENABLED(CONFIG_IPV6)
295                 netlbl_af6list_foreach(iter6, &entry->type_def.addrsel->list6) {
296                         map6 = netlbl_domhsh_addr6_entry(iter6);
297                         switch (map6->type) {
298                         case NETLBL_NLTYPE_UNLABELED:
299                                 break;
300                         default:
301                                 return -EINVAL;
302                         }
303                 }
304 #endif /* IPv6 */
305                 break;
306         default:
307                 return -EINVAL;
308         }
309
310         return 0;
311 }
312
313 /*
314  * Domain Hash Table Functions
315  */
316
317 /**
318  * netlbl_domhsh_init - Init for the domain hash
319  * @size: the number of bits to use for the hash buckets
320  *
321  * Description:
322  * Initializes the domain hash table, should be called only by
323  * netlbl_user_init() during initialization.  Returns zero on success, non-zero
324  * values on error.
325  *
326  */
327 int __init netlbl_domhsh_init(u32 size)
328 {
329         u32 iter;
330         struct netlbl_domhsh_tbl *hsh_tbl;
331
332         if (size == 0)
333                 return -EINVAL;
334
335         hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
336         if (hsh_tbl == NULL)
337                 return -ENOMEM;
338         hsh_tbl->size = 1 << size;
339         hsh_tbl->tbl = kcalloc(hsh_tbl->size,
340                                sizeof(struct list_head),
341                                GFP_KERNEL);
342         if (hsh_tbl->tbl == NULL) {
343                 kfree(hsh_tbl);
344                 return -ENOMEM;
345         }
346         for (iter = 0; iter < hsh_tbl->size; iter++)
347                 INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
348
349         spin_lock(&netlbl_domhsh_lock);
350         rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
351         spin_unlock(&netlbl_domhsh_lock);
352
353         return 0;
354 }
355
356 /**
357  * netlbl_domhsh_add - Adds a entry to the domain hash table
358  * @entry: the entry to add
359  * @audit_info: NetLabel audit information
360  *
361  * Description:
362  * Adds a new entry to the domain hash table and handles any updates to the
363  * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
364  * negative on failure.
365  *
366  */
367 int netlbl_domhsh_add(struct netlbl_dom_map *entry,
368                       struct netlbl_audit *audit_info)
369 {
370         int ret_val = 0;
371         struct netlbl_dom_map *entry_old;
372         struct netlbl_af4list *iter4;
373         struct netlbl_af4list *tmp4;
374 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
375         struct netlbl_af6list *iter6;
376         struct netlbl_af6list *tmp6;
377 #endif /* IPv6 */
378
379         ret_val = netlbl_domhsh_validate(entry);
380         if (ret_val != 0)
381                 return ret_val;
382
383         /* XXX - we can remove this RCU read lock as the spinlock protects the
384          *       entire function, but before we do we need to fixup the
385          *       netlbl_af[4,6]list RCU functions to do "the right thing" with
386          *       respect to rcu_dereference() when only a spinlock is held. */
387         rcu_read_lock();
388         spin_lock(&netlbl_domhsh_lock);
389         if (entry->domain != NULL)
390                 entry_old = netlbl_domhsh_search(entry->domain);
391         else
392                 entry_old = netlbl_domhsh_search_def(entry->domain);
393         if (entry_old == NULL) {
394                 entry->valid = 1;
395
396                 if (entry->domain != NULL) {
397                         u32 bkt = netlbl_domhsh_hash(entry->domain);
398                         list_add_tail_rcu(&entry->list,
399                                     &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
400                 } else {
401                         INIT_LIST_HEAD(&entry->list);
402                         rcu_assign_pointer(netlbl_domhsh_def, entry);
403                 }
404
405                 if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
406                         netlbl_af4list_foreach_rcu(iter4,
407                                                &entry->type_def.addrsel->list4)
408                                 netlbl_domhsh_audit_add(entry, iter4, NULL,
409                                                         ret_val, audit_info);
410 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
411                         netlbl_af6list_foreach_rcu(iter6,
412                                                &entry->type_def.addrsel->list6)
413                                 netlbl_domhsh_audit_add(entry, NULL, iter6,
414                                                         ret_val, audit_info);
415 #endif /* IPv6 */
416                 } else
417                         netlbl_domhsh_audit_add(entry, NULL, NULL,
418                                                 ret_val, audit_info);
419         } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
420                    entry->type == NETLBL_NLTYPE_ADDRSELECT) {
421                 struct list_head *old_list4;
422                 struct list_head *old_list6;
423
424                 old_list4 = &entry_old->type_def.addrsel->list4;
425                 old_list6 = &entry_old->type_def.addrsel->list6;
426
427                 /* we only allow the addition of address selectors if all of
428                  * the selectors do not exist in the existing domain map */
429                 netlbl_af4list_foreach_rcu(iter4,
430                                            &entry->type_def.addrsel->list4)
431                         if (netlbl_af4list_search_exact(iter4->addr,
432                                                         iter4->mask,
433                                                         old_list4)) {
434                                 ret_val = -EEXIST;
435                                 goto add_return;
436                         }
437 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
438                 netlbl_af6list_foreach_rcu(iter6,
439                                            &entry->type_def.addrsel->list6)
440                         if (netlbl_af6list_search_exact(&iter6->addr,
441                                                         &iter6->mask,
442                                                         old_list6)) {
443                                 ret_val = -EEXIST;
444                                 goto add_return;
445                         }
446 #endif /* IPv6 */
447
448                 netlbl_af4list_foreach_safe(iter4, tmp4,
449                                             &entry->type_def.addrsel->list4) {
450                         netlbl_af4list_remove_entry(iter4);
451                         iter4->valid = 1;
452                         ret_val = netlbl_af4list_add(iter4, old_list4);
453                         netlbl_domhsh_audit_add(entry_old, iter4, NULL,
454                                                 ret_val, audit_info);
455                         if (ret_val != 0)
456                                 goto add_return;
457                 }
458 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
459                 netlbl_af6list_foreach_safe(iter6, tmp6,
460                                             &entry->type_def.addrsel->list6) {
461                         netlbl_af6list_remove_entry(iter6);
462                         iter6->valid = 1;
463                         ret_val = netlbl_af6list_add(iter6, old_list6);
464                         netlbl_domhsh_audit_add(entry_old, NULL, iter6,
465                                                 ret_val, audit_info);
466                         if (ret_val != 0)
467                                 goto add_return;
468                 }
469 #endif /* IPv6 */
470         } else
471                 ret_val = -EINVAL;
472
473 add_return:
474         spin_unlock(&netlbl_domhsh_lock);
475         rcu_read_unlock();
476         return ret_val;
477 }
478
479 /**
480  * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
481  * @entry: the entry to add
482  * @audit_info: NetLabel audit information
483  *
484  * Description:
485  * Adds a new default entry to the domain hash table and handles any updates
486  * to the lower level protocol handler (i.e. CIPSO).  Returns zero on success,
487  * negative on failure.
488  *
489  */
490 int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
491                               struct netlbl_audit *audit_info)
492 {
493         return netlbl_domhsh_add(entry, audit_info);
494 }
495
496 /**
497  * netlbl_domhsh_remove_entry - Removes a given entry from the domain table
498  * @entry: the entry to remove
499  * @audit_info: NetLabel audit information
500  *
501  * Description:
502  * Removes an entry from the domain hash table and handles any updates to the
503  * lower level protocol handler (i.e. CIPSO).  Caller is responsible for
504  * ensuring that the RCU read lock is held.  Returns zero on success, negative
505  * on failure.
506  *
507  */
508 int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
509                                struct netlbl_audit *audit_info)
510 {
511         int ret_val = 0;
512         struct audit_buffer *audit_buf;
513
514         if (entry == NULL)
515                 return -ENOENT;
516
517         spin_lock(&netlbl_domhsh_lock);
518         if (entry->valid) {
519                 entry->valid = 0;
520                 if (entry != rcu_dereference(netlbl_domhsh_def))
521                         list_del_rcu(&entry->list);
522                 else
523                         RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
524         } else
525                 ret_val = -ENOENT;
526         spin_unlock(&netlbl_domhsh_lock);
527
528         audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
529         if (audit_buf != NULL) {
530                 audit_log_format(audit_buf,
531                                  " nlbl_domain=%s res=%u",
532                                  entry->domain ? entry->domain : "(default)",
533                                  ret_val == 0 ? 1 : 0);
534                 audit_log_end(audit_buf);
535         }
536
537         if (ret_val == 0) {
538                 struct netlbl_af4list *iter4;
539                 struct netlbl_domaddr4_map *map4;
540
541                 switch (entry->type) {
542                 case NETLBL_NLTYPE_ADDRSELECT:
543                         netlbl_af4list_foreach_rcu(iter4,
544                                              &entry->type_def.addrsel->list4) {
545                                 map4 = netlbl_domhsh_addr4_entry(iter4);
546                                 cipso_v4_doi_putdef(map4->type_def.cipsov4);
547                         }
548                         /* no need to check the IPv6 list since we currently
549                          * support only unlabeled protocols for IPv6 */
550                         break;
551                 case NETLBL_NLTYPE_CIPSOV4:
552                         cipso_v4_doi_putdef(entry->type_def.cipsov4);
553                         break;
554                 }
555                 call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
556         }
557
558         return ret_val;
559 }
560
561 /**
562  * netlbl_domhsh_remove_af4 - Removes an address selector entry
563  * @domain: the domain
564  * @addr: IPv4 address
565  * @mask: IPv4 address mask
566  * @audit_info: NetLabel audit information
567  *
568  * Description:
569  * Removes an individual address selector from a domain mapping and potentially
570  * the entire mapping if it is empty.  Returns zero on success, negative values
571  * on failure.
572  *
573  */
574 int netlbl_domhsh_remove_af4(const char *domain,
575                              const struct in_addr *addr,
576                              const struct in_addr *mask,
577                              struct netlbl_audit *audit_info)
578 {
579         struct netlbl_dom_map *entry_map;
580         struct netlbl_af4list *entry_addr;
581         struct netlbl_af4list *iter4;
582 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
583         struct netlbl_af6list *iter6;
584 #endif /* IPv6 */
585         struct netlbl_domaddr4_map *entry;
586
587         rcu_read_lock();
588
589         if (domain)
590                 entry_map = netlbl_domhsh_search(domain);
591         else
592                 entry_map = netlbl_domhsh_search_def(domain);
593         if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
594                 goto remove_af4_failure;
595
596         spin_lock(&netlbl_domhsh_lock);
597         entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
598                                            &entry_map->type_def.addrsel->list4);
599         spin_unlock(&netlbl_domhsh_lock);
600
601         if (entry_addr == NULL)
602                 goto remove_af4_failure;
603         netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
604                 goto remove_af4_single_addr;
605 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
606         netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
607                 goto remove_af4_single_addr;
608 #endif /* IPv6 */
609         /* the domain mapping is empty so remove it from the mapping table */
610         netlbl_domhsh_remove_entry(entry_map, audit_info);
611
612 remove_af4_single_addr:
613         rcu_read_unlock();
614         /* yick, we can't use call_rcu here because we don't have a rcu head
615          * pointer but hopefully this should be a rare case so the pause
616          * shouldn't be a problem */
617         synchronize_rcu();
618         entry = netlbl_domhsh_addr4_entry(entry_addr);
619         cipso_v4_doi_putdef(entry->type_def.cipsov4);
620         kfree(entry);
621         return 0;
622
623 remove_af4_failure:
624         rcu_read_unlock();
625         return -ENOENT;
626 }
627
628 /**
629  * netlbl_domhsh_remove - Removes an entry from the domain hash table
630  * @domain: the domain to remove
631  * @audit_info: NetLabel audit information
632  *
633  * Description:
634  * Removes an entry from the domain hash table and handles any updates to the
635  * lower level protocol handler (i.e. CIPSO).  Returns zero on success,
636  * negative on failure.
637  *
638  */
639 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
640 {
641         int ret_val;
642         struct netlbl_dom_map *entry;
643
644         rcu_read_lock();
645         if (domain)
646                 entry = netlbl_domhsh_search(domain);
647         else
648                 entry = netlbl_domhsh_search_def(domain);
649         ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
650         rcu_read_unlock();
651
652         return ret_val;
653 }
654
655 /**
656  * netlbl_domhsh_remove_default - Removes the default entry from the table
657  * @audit_info: NetLabel audit information
658  *
659  * Description:
660  * Removes/resets the default entry for the domain hash table and handles any
661  * updates to the lower level protocol handler (i.e. CIPSO).  Returns zero on
662  * success, non-zero on failure.
663  *
664  */
665 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
666 {
667         return netlbl_domhsh_remove(NULL, audit_info);
668 }
669
670 /**
671  * netlbl_domhsh_getentry - Get an entry from the domain hash table
672  * @domain: the domain name to search for
673  *
674  * Description:
675  * Look through the domain hash table searching for an entry to match @domain,
676  * return a pointer to a copy of the entry or NULL.  The caller is responsible
677  * for ensuring that rcu_read_[un]lock() is called.
678  *
679  */
680 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
681 {
682         return netlbl_domhsh_search_def(domain);
683 }
684
685 /**
686  * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
687  * @domain: the domain name to search for
688  * @addr: the IP address to search for
689  *
690  * Description:
691  * Look through the domain hash table searching for an entry to match @domain
692  * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
693  * responsible for ensuring that rcu_read_[un]lock() is called.
694  *
695  */
696 struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
697                                                        __be32 addr)
698 {
699         struct netlbl_dom_map *dom_iter;
700         struct netlbl_af4list *addr_iter;
701
702         dom_iter = netlbl_domhsh_search_def(domain);
703         if (dom_iter == NULL)
704                 return NULL;
705         if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
706                 return NULL;
707
708         addr_iter = netlbl_af4list_search(addr,
709                                           &dom_iter->type_def.addrsel->list4);
710         if (addr_iter == NULL)
711                 return NULL;
712
713         return netlbl_domhsh_addr4_entry(addr_iter);
714 }
715
716 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
717 /**
718  * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
719  * @domain: the domain name to search for
720  * @addr: the IP address to search for
721  *
722  * Description:
723  * Look through the domain hash table searching for an entry to match @domain
724  * and @addr, return a pointer to a copy of the entry or NULL.  The caller is
725  * responsible for ensuring that rcu_read_[un]lock() is called.
726  *
727  */
728 struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
729                                                    const struct in6_addr *addr)
730 {
731         struct netlbl_dom_map *dom_iter;
732         struct netlbl_af6list *addr_iter;
733
734         dom_iter = netlbl_domhsh_search_def(domain);
735         if (dom_iter == NULL)
736                 return NULL;
737         if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
738                 return NULL;
739
740         addr_iter = netlbl_af6list_search(addr,
741                                           &dom_iter->type_def.addrsel->list6);
742         if (addr_iter == NULL)
743                 return NULL;
744
745         return netlbl_domhsh_addr6_entry(addr_iter);
746 }
747 #endif /* IPv6 */
748
749 /**
750  * netlbl_domhsh_walk - Iterate through the domain mapping hash table
751  * @skip_bkt: the number of buckets to skip at the start
752  * @skip_chain: the number of entries to skip in the first iterated bucket
753  * @callback: callback for each entry
754  * @cb_arg: argument for the callback function
755  *
756  * Description:
757  * Interate over the domain mapping hash table, skipping the first @skip_bkt
758  * buckets and @skip_chain entries.  For each entry in the table call
759  * @callback, if @callback returns a negative value stop 'walking' through the
760  * table and return.  Updates the values in @skip_bkt and @skip_chain on
761  * return.  Returns zero on success, negative values on failure.
762  *
763  */
764 int netlbl_domhsh_walk(u32 *skip_bkt,
765                      u32 *skip_chain,
766                      int (*callback) (struct netlbl_dom_map *entry, void *arg),
767                      void *cb_arg)
768 {
769         int ret_val = -ENOENT;
770         u32 iter_bkt;
771         struct list_head *iter_list;
772         struct netlbl_dom_map *iter_entry;
773         u32 chain_cnt = 0;
774
775         rcu_read_lock();
776         for (iter_bkt = *skip_bkt;
777              iter_bkt < rcu_dereference(netlbl_domhsh)->size;
778              iter_bkt++, chain_cnt = 0) {
779                 iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
780                 list_for_each_entry_rcu(iter_entry, iter_list, list)
781                         if (iter_entry->valid) {
782                                 if (chain_cnt++ < *skip_chain)
783                                         continue;
784                                 ret_val = callback(iter_entry, cb_arg);
785                                 if (ret_val < 0) {
786                                         chain_cnt--;
787                                         goto walk_return;
788                                 }
789                         }
790         }
791
792 walk_return:
793         rcu_read_unlock();
794         *skip_bkt = iter_bkt;
795         *skip_chain = chain_cnt;
796         return ret_val;
797 }