diff options
Diffstat (limited to 'net/netlabel/netlabel_domainhash.c')
-rw-r--r-- | net/netlabel/netlabel_domainhash.c | 393 |
1 files changed, 304 insertions, 89 deletions
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 643c032a3a57..5fadf10e5ddf 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 | 14 | * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 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 | 17 | * it under the terms of the GNU General Public License as published by |
@@ -40,6 +40,7 @@ | |||
40 | #include <asm/bug.h> | 40 | #include <asm/bug.h> |
41 | 41 | ||
42 | #include "netlabel_mgmt.h" | 42 | #include "netlabel_mgmt.h" |
43 | #include "netlabel_addrlist.h" | ||
43 | #include "netlabel_domainhash.h" | 44 | #include "netlabel_domainhash.h" |
44 | #include "netlabel_user.h" | 45 | #include "netlabel_user.h" |
45 | 46 | ||
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL; | |||
72 | static void netlbl_domhsh_free_entry(struct rcu_head *entry) | 73 | static void netlbl_domhsh_free_entry(struct rcu_head *entry) |
73 | { | 74 | { |
74 | struct netlbl_dom_map *ptr; | 75 | struct netlbl_dom_map *ptr; |
76 | struct netlbl_af4list *iter4; | ||
77 | struct netlbl_af4list *tmp4; | ||
78 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
79 | struct netlbl_af6list *iter6; | ||
80 | struct netlbl_af6list *tmp6; | ||
81 | #endif /* IPv6 */ | ||
75 | 82 | ||
76 | ptr = container_of(entry, struct netlbl_dom_map, rcu); | 83 | ptr = container_of(entry, struct netlbl_dom_map, rcu); |
84 | if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) { | ||
85 | netlbl_af4list_foreach_safe(iter4, tmp4, | ||
86 | &ptr->type_def.addrsel->list4) { | ||
87 | netlbl_af4list_remove_entry(iter4); | ||
88 | kfree(netlbl_domhsh_addr4_entry(iter4)); | ||
89 | } | ||
90 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
91 | netlbl_af6list_foreach_safe(iter6, tmp6, | ||
92 | &ptr->type_def.addrsel->list6) { | ||
93 | netlbl_af6list_remove_entry(iter6); | ||
94 | kfree(netlbl_domhsh_addr6_entry(iter6)); | ||
95 | } | ||
96 | #endif /* IPv6 */ | ||
97 | } | ||
77 | kfree(ptr->domain); | 98 | kfree(ptr->domain); |
78 | kfree(ptr); | 99 | kfree(ptr); |
79 | } | 100 | } |
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key) | |||
115 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) | 136 | static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain) |
116 | { | 137 | { |
117 | u32 bkt; | 138 | u32 bkt; |
139 | struct list_head *bkt_list; | ||
118 | struct netlbl_dom_map *iter; | 140 | struct netlbl_dom_map *iter; |
119 | 141 | ||
120 | if (domain != NULL) { | 142 | if (domain != NULL) { |
121 | bkt = netlbl_domhsh_hash(domain); | 143 | bkt = netlbl_domhsh_hash(domain); |
122 | list_for_each_entry_rcu(iter, | 144 | bkt_list = &rcu_dereference(netlbl_domhsh)->tbl[bkt]; |
123 | &rcu_dereference(netlbl_domhsh)->tbl[bkt], | 145 | list_for_each_entry_rcu(iter, bkt_list, list) |
124 | list) | ||
125 | if (iter->valid && strcmp(iter->domain, domain) == 0) | 146 | if (iter->valid && strcmp(iter->domain, domain) == 0) |
126 | return iter; | 147 | return iter; |
127 | } | 148 | } |
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) | |||
156 | return entry; | 177 | return entry; |
157 | } | 178 | } |
158 | 179 | ||
180 | /** | ||
181 | * netlbl_domhsh_audit_add - Generate an audit entry for an add event | ||
182 | * @entry: the entry being added | ||
183 | * @addr4: the IPv4 address information | ||
184 | * @addr6: the IPv6 address information | ||
185 | * @result: the result code | ||
186 | * @audit_info: NetLabel audit information | ||
187 | * | ||
188 | * Description: | ||
189 | * Generate an audit record for adding a new NetLabel/LSM mapping entry with | ||
190 | * the given information. Caller is responsibile for holding the necessary | ||
191 | * locks. | ||
192 | * | ||
193 | */ | ||
194 | static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry, | ||
195 | struct netlbl_af4list *addr4, | ||
196 | struct netlbl_af6list *addr6, | ||
197 | int result, | ||
198 | struct netlbl_audit *audit_info) | ||
199 | { | ||
200 | struct audit_buffer *audit_buf; | ||
201 | struct cipso_v4_doi *cipsov4 = NULL; | ||
202 | u32 type; | ||
203 | |||
204 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); | ||
205 | if (audit_buf != NULL) { | ||
206 | audit_log_format(audit_buf, " nlbl_domain=%s", | ||
207 | entry->domain ? entry->domain : "(default)"); | ||
208 | if (addr4 != NULL) { | ||
209 | struct netlbl_domaddr4_map *map4; | ||
210 | map4 = netlbl_domhsh_addr4_entry(addr4); | ||
211 | type = map4->type; | ||
212 | cipsov4 = map4->type_def.cipsov4; | ||
213 | netlbl_af4list_audit_addr(audit_buf, 0, NULL, | ||
214 | addr4->addr, addr4->mask); | ||
215 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
216 | } else if (addr6 != NULL) { | ||
217 | struct netlbl_domaddr6_map *map6; | ||
218 | map6 = netlbl_domhsh_addr6_entry(addr6); | ||
219 | type = map6->type; | ||
220 | netlbl_af6list_audit_addr(audit_buf, 0, NULL, | ||
221 | &addr6->addr, &addr6->mask); | ||
222 | #endif /* IPv6 */ | ||
223 | } else { | ||
224 | type = entry->type; | ||
225 | cipsov4 = entry->type_def.cipsov4; | ||
226 | } | ||
227 | switch (type) { | ||
228 | case NETLBL_NLTYPE_UNLABELED: | ||
229 | audit_log_format(audit_buf, " nlbl_protocol=unlbl"); | ||
230 | break; | ||
231 | case NETLBL_NLTYPE_CIPSOV4: | ||
232 | BUG_ON(cipsov4 == NULL); | ||
233 | audit_log_format(audit_buf, | ||
234 | " nlbl_protocol=cipsov4 cipso_doi=%u", | ||
235 | cipsov4->doi); | ||
236 | break; | ||
237 | } | ||
238 | audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0); | ||
239 | audit_log_end(audit_buf); | ||
240 | } | ||
241 | } | ||
242 | |||
159 | /* | 243 | /* |
160 | * Domain Hash Table Functions | 244 | * Domain Hash Table Functions |
161 | */ | 245 | */ |
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size) | |||
213 | int netlbl_domhsh_add(struct netlbl_dom_map *entry, | 297 | int netlbl_domhsh_add(struct netlbl_dom_map *entry, |
214 | struct netlbl_audit *audit_info) | 298 | struct netlbl_audit *audit_info) |
215 | { | 299 | { |
216 | int ret_val; | 300 | int ret_val = 0; |
217 | u32 bkt; | 301 | struct netlbl_dom_map *entry_old; |
218 | struct audit_buffer *audit_buf; | 302 | struct netlbl_af4list *iter4; |
219 | 303 | struct netlbl_af4list *tmp4; | |
220 | switch (entry->type) { | 304 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
221 | case NETLBL_NLTYPE_UNLABELED: | 305 | struct netlbl_af6list *iter6; |
222 | ret_val = 0; | 306 | struct netlbl_af6list *tmp6; |
223 | break; | 307 | #endif /* IPv6 */ |
224 | case NETLBL_NLTYPE_CIPSOV4: | ||
225 | ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4, | ||
226 | entry->domain); | ||
227 | break; | ||
228 | default: | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | if (ret_val != 0) | ||
232 | return ret_val; | ||
233 | |||
234 | entry->valid = 1; | ||
235 | INIT_RCU_HEAD(&entry->rcu); | ||
236 | 308 | ||
237 | rcu_read_lock(); | 309 | rcu_read_lock(); |
310 | |||
238 | spin_lock(&netlbl_domhsh_lock); | 311 | spin_lock(&netlbl_domhsh_lock); |
239 | if (entry->domain != NULL) { | 312 | if (entry->domain != NULL) |
240 | bkt = netlbl_domhsh_hash(entry->domain); | 313 | entry_old = netlbl_domhsh_search(entry->domain); |
241 | if (netlbl_domhsh_search(entry->domain) == NULL) | 314 | else |
315 | entry_old = netlbl_domhsh_search_def(entry->domain); | ||
316 | if (entry_old == NULL) { | ||
317 | entry->valid = 1; | ||
318 | INIT_RCU_HEAD(&entry->rcu); | ||
319 | |||
320 | if (entry->domain != NULL) { | ||
321 | u32 bkt = netlbl_domhsh_hash(entry->domain); | ||
242 | list_add_tail_rcu(&entry->list, | 322 | list_add_tail_rcu(&entry->list, |
243 | &rcu_dereference(netlbl_domhsh)->tbl[bkt]); | 323 | &rcu_dereference(netlbl_domhsh)->tbl[bkt]); |
244 | else | 324 | } else { |
245 | ret_val = -EEXIST; | 325 | INIT_LIST_HEAD(&entry->list); |
246 | } else { | ||
247 | INIT_LIST_HEAD(&entry->list); | ||
248 | if (rcu_dereference(netlbl_domhsh_def) == NULL) | ||
249 | rcu_assign_pointer(netlbl_domhsh_def, entry); | 326 | rcu_assign_pointer(netlbl_domhsh_def, entry); |
250 | else | ||
251 | ret_val = -EEXIST; | ||
252 | } | ||
253 | spin_unlock(&netlbl_domhsh_lock); | ||
254 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); | ||
255 | if (audit_buf != NULL) { | ||
256 | audit_log_format(audit_buf, | ||
257 | " nlbl_domain=%s", | ||
258 | entry->domain ? entry->domain : "(default)"); | ||
259 | switch (entry->type) { | ||
260 | case NETLBL_NLTYPE_UNLABELED: | ||
261 | audit_log_format(audit_buf, " nlbl_protocol=unlbl"); | ||
262 | break; | ||
263 | case NETLBL_NLTYPE_CIPSOV4: | ||
264 | audit_log_format(audit_buf, | ||
265 | " nlbl_protocol=cipsov4 cipso_doi=%u", | ||
266 | entry->type_def.cipsov4->doi); | ||
267 | break; | ||
268 | } | 327 | } |
269 | audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0); | ||
270 | audit_log_end(audit_buf); | ||
271 | } | ||
272 | rcu_read_unlock(); | ||
273 | 328 | ||
274 | if (ret_val != 0) { | 329 | if (entry->type == NETLBL_NLTYPE_ADDRSELECT) { |
275 | switch (entry->type) { | 330 | netlbl_af4list_foreach_rcu(iter4, |
276 | case NETLBL_NLTYPE_CIPSOV4: | 331 | &entry->type_def.addrsel->list4) |
277 | if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, | 332 | netlbl_domhsh_audit_add(entry, iter4, NULL, |
278 | entry->domain) != 0) | 333 | ret_val, audit_info); |
279 | BUG(); | 334 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
280 | break; | 335 | netlbl_af6list_foreach_rcu(iter6, |
336 | &entry->type_def.addrsel->list6) | ||
337 | netlbl_domhsh_audit_add(entry, NULL, iter6, | ||
338 | ret_val, audit_info); | ||
339 | #endif /* IPv6 */ | ||
340 | } else | ||
341 | netlbl_domhsh_audit_add(entry, NULL, NULL, | ||
342 | ret_val, audit_info); | ||
343 | } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT && | ||
344 | entry->type == NETLBL_NLTYPE_ADDRSELECT) { | ||
345 | struct list_head *old_list4; | ||
346 | struct list_head *old_list6; | ||
347 | |||
348 | old_list4 = &entry_old->type_def.addrsel->list4; | ||
349 | old_list6 = &entry_old->type_def.addrsel->list6; | ||
350 | |||
351 | /* we only allow the addition of address selectors if all of | ||
352 | * the selectors do not exist in the existing domain map */ | ||
353 | netlbl_af4list_foreach_rcu(iter4, | ||
354 | &entry->type_def.addrsel->list4) | ||
355 | if (netlbl_af4list_search_exact(iter4->addr, | ||
356 | iter4->mask, | ||
357 | old_list4)) { | ||
358 | ret_val = -EEXIST; | ||
359 | goto add_return; | ||
360 | } | ||
361 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
362 | netlbl_af6list_foreach_rcu(iter6, | ||
363 | &entry->type_def.addrsel->list6) | ||
364 | if (netlbl_af6list_search_exact(&iter6->addr, | ||
365 | &iter6->mask, | ||
366 | old_list6)) { | ||
367 | ret_val = -EEXIST; | ||
368 | goto add_return; | ||
369 | } | ||
370 | #endif /* IPv6 */ | ||
371 | |||
372 | netlbl_af4list_foreach_safe(iter4, tmp4, | ||
373 | &entry->type_def.addrsel->list4) { | ||
374 | netlbl_af4list_remove_entry(iter4); | ||
375 | iter4->valid = 1; | ||
376 | ret_val = netlbl_af4list_add(iter4, old_list4); | ||
377 | netlbl_domhsh_audit_add(entry_old, iter4, NULL, | ||
378 | ret_val, audit_info); | ||
379 | if (ret_val != 0) | ||
380 | goto add_return; | ||
281 | } | 381 | } |
282 | } | 382 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
383 | netlbl_af6list_foreach_safe(iter6, tmp6, | ||
384 | &entry->type_def.addrsel->list6) { | ||
385 | netlbl_af6list_remove_entry(iter6); | ||
386 | iter6->valid = 1; | ||
387 | ret_val = netlbl_af6list_add(iter6, old_list6); | ||
388 | netlbl_domhsh_audit_add(entry_old, NULL, iter6, | ||
389 | ret_val, audit_info); | ||
390 | if (ret_val != 0) | ||
391 | goto add_return; | ||
392 | } | ||
393 | #endif /* IPv6 */ | ||
394 | } else | ||
395 | ret_val = -EINVAL; | ||
283 | 396 | ||
397 | add_return: | ||
398 | spin_unlock(&netlbl_domhsh_lock); | ||
399 | rcu_read_unlock(); | ||
284 | return ret_val; | 400 | return ret_val; |
285 | } | 401 | } |
286 | 402 | ||
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry, | |||
302 | } | 418 | } |
303 | 419 | ||
304 | /** | 420 | /** |
305 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | 421 | * netlbl_domhsh_remove_entry - Removes a given entry from the domain table |
306 | * @domain: the domain to remove | 422 | * @entry: the entry to remove |
307 | * @audit_info: NetLabel audit information | 423 | * @audit_info: NetLabel audit information |
308 | * | 424 | * |
309 | * Description: | 425 | * Description: |
310 | * Removes an entry from the domain hash table and handles any updates to the | 426 | * Removes an entry from the domain hash table and handles any updates to the |
311 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | 427 | * lower level protocol handler (i.e. CIPSO). Caller is responsible for |
312 | * negative on failure. | 428 | * ensuring that the RCU read lock is held. Returns zero on success, negative |
429 | * on failure. | ||
313 | * | 430 | * |
314 | */ | 431 | */ |
315 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | 432 | int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry, |
433 | struct netlbl_audit *audit_info) | ||
316 | { | 434 | { |
317 | int ret_val = -ENOENT; | 435 | int ret_val = 0; |
318 | struct netlbl_dom_map *entry; | ||
319 | struct audit_buffer *audit_buf; | 436 | struct audit_buffer *audit_buf; |
320 | 437 | ||
321 | rcu_read_lock(); | ||
322 | if (domain) | ||
323 | entry = netlbl_domhsh_search(domain); | ||
324 | else | ||
325 | entry = netlbl_domhsh_search_def(domain); | ||
326 | if (entry == NULL) | 438 | if (entry == NULL) |
327 | goto remove_return; | 439 | return -ENOENT; |
328 | switch (entry->type) { | 440 | |
329 | case NETLBL_NLTYPE_CIPSOV4: | ||
330 | cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4, | ||
331 | entry->domain); | ||
332 | break; | ||
333 | } | ||
334 | spin_lock(&netlbl_domhsh_lock); | 441 | spin_lock(&netlbl_domhsh_lock); |
335 | if (entry->valid) { | 442 | if (entry->valid) { |
336 | entry->valid = 0; | 443 | entry->valid = 0; |
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | |||
338 | list_del_rcu(&entry->list); | 445 | list_del_rcu(&entry->list); |
339 | else | 446 | else |
340 | rcu_assign_pointer(netlbl_domhsh_def, NULL); | 447 | rcu_assign_pointer(netlbl_domhsh_def, NULL); |
341 | ret_val = 0; | 448 | } else |
342 | } | 449 | ret_val = -ENOENT; |
343 | spin_unlock(&netlbl_domhsh_lock); | 450 | spin_unlock(&netlbl_domhsh_lock); |
344 | 451 | ||
345 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); | 452 | audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); |
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | |||
351 | audit_log_end(audit_buf); | 458 | audit_log_end(audit_buf); |
352 | } | 459 | } |
353 | 460 | ||
354 | remove_return: | 461 | if (ret_val == 0) { |
355 | rcu_read_unlock(); | 462 | struct netlbl_af4list *iter4; |
356 | if (ret_val == 0) | 463 | struct netlbl_domaddr4_map *map4; |
464 | |||
465 | switch (entry->type) { | ||
466 | case NETLBL_NLTYPE_ADDRSELECT: | ||
467 | netlbl_af4list_foreach_rcu(iter4, | ||
468 | &entry->type_def.addrsel->list4) { | ||
469 | map4 = netlbl_domhsh_addr4_entry(iter4); | ||
470 | cipso_v4_doi_putdef(map4->type_def.cipsov4); | ||
471 | } | ||
472 | /* no need to check the IPv6 list since we currently | ||
473 | * support only unlabeled protocols for IPv6 */ | ||
474 | break; | ||
475 | case NETLBL_NLTYPE_CIPSOV4: | ||
476 | cipso_v4_doi_putdef(entry->type_def.cipsov4); | ||
477 | break; | ||
478 | } | ||
357 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); | 479 | call_rcu(&entry->rcu, netlbl_domhsh_free_entry); |
480 | } | ||
481 | |||
482 | return ret_val; | ||
483 | } | ||
484 | |||
485 | /** | ||
486 | * netlbl_domhsh_remove - Removes an entry from the domain hash table | ||
487 | * @domain: the domain to remove | ||
488 | * @audit_info: NetLabel audit information | ||
489 | * | ||
490 | * Description: | ||
491 | * Removes an entry from the domain hash table and handles any updates to the | ||
492 | * lower level protocol handler (i.e. CIPSO). Returns zero on success, | ||
493 | * negative on failure. | ||
494 | * | ||
495 | */ | ||
496 | int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) | ||
497 | { | ||
498 | int ret_val; | ||
499 | struct netlbl_dom_map *entry; | ||
500 | |||
501 | rcu_read_lock(); | ||
502 | if (domain) | ||
503 | entry = netlbl_domhsh_search(domain); | ||
504 | else | ||
505 | entry = netlbl_domhsh_search_def(domain); | ||
506 | ret_val = netlbl_domhsh_remove_entry(entry, audit_info); | ||
507 | rcu_read_unlock(); | ||
508 | |||
358 | return ret_val; | 509 | return ret_val; |
359 | } | 510 | } |
360 | 511 | ||
@@ -389,6 +540,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) | |||
389 | } | 540 | } |
390 | 541 | ||
391 | /** | 542 | /** |
543 | * netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table | ||
544 | * @domain: the domain name to search for | ||
545 | * @addr: the IP address to search for | ||
546 | * | ||
547 | * Description: | ||
548 | * Look through the domain hash table searching for an entry to match @domain | ||
549 | * and @addr, return a pointer to a copy of the entry or NULL. The caller is | ||
550 | * responsible for ensuring that rcu_read_[un]lock() is called. | ||
551 | * | ||
552 | */ | ||
553 | struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain, | ||
554 | __be32 addr) | ||
555 | { | ||
556 | struct netlbl_dom_map *dom_iter; | ||
557 | struct netlbl_af4list *addr_iter; | ||
558 | |||
559 | dom_iter = netlbl_domhsh_search_def(domain); | ||
560 | if (dom_iter == NULL) | ||
561 | return NULL; | ||
562 | if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) | ||
563 | return NULL; | ||
564 | |||
565 | addr_iter = netlbl_af4list_search(addr, | ||
566 | &dom_iter->type_def.addrsel->list4); | ||
567 | if (addr_iter == NULL) | ||
568 | return NULL; | ||
569 | |||
570 | return netlbl_domhsh_addr4_entry(addr_iter); | ||
571 | } | ||
572 | |||
573 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
574 | /** | ||
575 | * netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table | ||
576 | * @domain: the domain name to search for | ||
577 | * @addr: the IP address to search for | ||
578 | * | ||
579 | * Description: | ||
580 | * Look through the domain hash table searching for an entry to match @domain | ||
581 | * and @addr, return a pointer to a copy of the entry or NULL. The caller is | ||
582 | * responsible for ensuring that rcu_read_[un]lock() is called. | ||
583 | * | ||
584 | */ | ||
585 | struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain, | ||
586 | const struct in6_addr *addr) | ||
587 | { | ||
588 | struct netlbl_dom_map *dom_iter; | ||
589 | struct netlbl_af6list *addr_iter; | ||
590 | |||
591 | dom_iter = netlbl_domhsh_search_def(domain); | ||
592 | if (dom_iter == NULL) | ||
593 | return NULL; | ||
594 | if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT) | ||
595 | return NULL; | ||
596 | |||
597 | addr_iter = netlbl_af6list_search(addr, | ||
598 | &dom_iter->type_def.addrsel->list6); | ||
599 | if (addr_iter == NULL) | ||
600 | return NULL; | ||
601 | |||
602 | return netlbl_domhsh_addr6_entry(addr_iter); | ||
603 | } | ||
604 | #endif /* IPv6 */ | ||
605 | |||
606 | /** | ||
392 | * netlbl_domhsh_walk - Iterate through the domain mapping hash table | 607 | * netlbl_domhsh_walk - Iterate through the domain mapping hash table |
393 | * @skip_bkt: the number of buckets to skip at the start | 608 | * @skip_bkt: the number of buckets to skip at the start |
394 | * @skip_chain: the number of entries to skip in the first iterated bucket | 609 | * @skip_chain: the number of entries to skip in the first iterated bucket |
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt, | |||
410 | { | 625 | { |
411 | int ret_val = -ENOENT; | 626 | int ret_val = -ENOENT; |
412 | u32 iter_bkt; | 627 | u32 iter_bkt; |
628 | struct list_head *iter_list; | ||
413 | struct netlbl_dom_map *iter_entry; | 629 | struct netlbl_dom_map *iter_entry; |
414 | u32 chain_cnt = 0; | 630 | u32 chain_cnt = 0; |
415 | 631 | ||
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt, | |||
417 | for (iter_bkt = *skip_bkt; | 633 | for (iter_bkt = *skip_bkt; |
418 | iter_bkt < rcu_dereference(netlbl_domhsh)->size; | 634 | iter_bkt < rcu_dereference(netlbl_domhsh)->size; |
419 | iter_bkt++, chain_cnt = 0) { | 635 | iter_bkt++, chain_cnt = 0) { |
420 | list_for_each_entry_rcu(iter_entry, | 636 | iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt]; |
421 | &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt], | 637 | list_for_each_entry_rcu(iter_entry, iter_list, list) |
422 | list) | ||
423 | if (iter_entry->valid) { | 638 | if (iter_entry->valid) { |
424 | if (chain_cnt++ < *skip_chain) | 639 | if (chain_cnt++ < *skip_chain) |
425 | continue; | 640 | continue; |