diff options
Diffstat (limited to 'net/netlabel/netlabel_domainhash.c')
-rw-r--r-- | net/netlabel/netlabel_domainhash.c | 183 |
1 files changed, 37 insertions, 146 deletions
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 0489a1378101..f56d7a8ac7b7 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c | |||
@@ -354,160 +354,51 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) | |||
354 | } | 354 | } |
355 | 355 | ||
356 | /** | 356 | /** |
357 | * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff | 357 | * netlbl_domhsh_walk - Iterate through the domain mapping hash table |
358 | * @skip_bkt: the number of buckets to skip at the start | ||
359 | * @skip_chain: the number of entries to skip in the first iterated bucket | ||
360 | * @callback: callback for each entry | ||
361 | * @cb_arg: argument for the callback function | ||
358 | * | 362 | * |
359 | * Description: | 363 | * Description: |
360 | * Dump the domain hash table into a buffer suitable for returning to an | 364 | * Interate over the domain mapping hash table, skipping the first @skip_bkt |
361 | * application in response to a NetLabel management DOMAIN message. This | 365 | * buckets and @skip_chain entries. For each entry in the table call |
362 | * function may fail if another process is growing the hash table at the same | 366 | * @callback, if @callback returns a negative value stop 'walking' through the |
363 | * time. The returned sk_buff has room at the front of the sk_buff for | 367 | * table and return. Updates the values in @skip_bkt and @skip_chain on |
364 | * @headroom bytes. See netlabel.h for the DOMAIN message format. Returns a | 368 | * return. Returns zero on succcess, negative values on failure. |
365 | * pointer to a sk_buff on success, NULL on error. | ||
366 | * | 369 | * |
367 | */ | 370 | */ |
368 | struct sk_buff *netlbl_domhsh_dump(size_t headroom) | 371 | int netlbl_domhsh_walk(u32 *skip_bkt, |
372 | u32 *skip_chain, | ||
373 | int (*callback) (struct netlbl_dom_map *entry, void *arg), | ||
374 | void *cb_arg) | ||
369 | { | 375 | { |
370 | struct sk_buff *skb = NULL; | 376 | int ret_val = -ENOENT; |
371 | ssize_t buf_len; | 377 | u32 iter_bkt; |
372 | u32 bkt_iter; | 378 | struct netlbl_dom_map *iter_entry; |
373 | u32 dom_cnt = 0; | 379 | u32 chain_cnt = 0; |
374 | struct netlbl_domhsh_tbl *hsh_tbl; | ||
375 | struct netlbl_dom_map *list_iter; | ||
376 | ssize_t tmp_len; | ||
377 | 380 | ||
378 | buf_len = NETLBL_LEN_U32; | ||
379 | rcu_read_lock(); | 381 | rcu_read_lock(); |
380 | hsh_tbl = rcu_dereference(netlbl_domhsh); | 382 | for (iter_bkt = *skip_bkt; |
381 | for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++) | 383 | iter_bkt < rcu_dereference(netlbl_domhsh)->size; |
382 | list_for_each_entry_rcu(list_iter, | 384 | iter_bkt++, chain_cnt = 0) { |
383 | &hsh_tbl->tbl[bkt_iter], list) { | 385 | list_for_each_entry_rcu(iter_entry, |
384 | buf_len += NETLBL_LEN_U32 + | 386 | &netlbl_domhsh->tbl[iter_bkt], |
385 | nla_total_size(strlen(list_iter->domain) + 1); | 387 | list) |
386 | switch (list_iter->type) { | 388 | if (iter_entry->valid) { |
387 | case NETLBL_NLTYPE_UNLABELED: | 389 | if (chain_cnt++ < *skip_chain) |
388 | break; | 390 | continue; |
389 | case NETLBL_NLTYPE_CIPSOV4: | 391 | ret_val = callback(iter_entry, cb_arg); |
390 | buf_len += 2 * NETLBL_LEN_U32; | 392 | if (ret_val < 0) { |
391 | break; | 393 | chain_cnt--; |
392 | } | 394 | goto walk_return; |
393 | dom_cnt++; | 395 | } |
394 | } | ||
395 | |||
396 | skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); | ||
397 | if (skb == NULL) | ||
398 | goto dump_failure; | ||
399 | |||
400 | if (nla_put_u32(skb, NLA_U32, dom_cnt) != 0) | ||
401 | goto dump_failure; | ||
402 | buf_len -= NETLBL_LEN_U32; | ||
403 | hsh_tbl = rcu_dereference(netlbl_domhsh); | ||
404 | for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++) | ||
405 | list_for_each_entry_rcu(list_iter, | ||
406 | &hsh_tbl->tbl[bkt_iter], list) { | ||
407 | tmp_len = nla_total_size(strlen(list_iter->domain) + | ||
408 | 1); | ||
409 | if (buf_len < NETLBL_LEN_U32 + tmp_len) | ||
410 | goto dump_failure; | ||
411 | if (nla_put_string(skb, | ||
412 | NLA_STRING, | ||
413 | list_iter->domain) != 0) | ||
414 | goto dump_failure; | ||
415 | if (nla_put_u32(skb, NLA_U32, list_iter->type) != 0) | ||
416 | goto dump_failure; | ||
417 | buf_len -= NETLBL_LEN_U32 + tmp_len; | ||
418 | switch (list_iter->type) { | ||
419 | case NETLBL_NLTYPE_UNLABELED: | ||
420 | break; | ||
421 | case NETLBL_NLTYPE_CIPSOV4: | ||
422 | if (buf_len < 2 * NETLBL_LEN_U32) | ||
423 | goto dump_failure; | ||
424 | if (nla_put_u32(skb, | ||
425 | NLA_U32, | ||
426 | list_iter->type_def.cipsov4->type) != 0) | ||
427 | goto dump_failure; | ||
428 | if (nla_put_u32(skb, | ||
429 | NLA_U32, | ||
430 | list_iter->type_def.cipsov4->doi) != 0) | ||
431 | goto dump_failure; | ||
432 | buf_len -= 2 * NETLBL_LEN_U32; | ||
433 | break; | ||
434 | } | 396 | } |
435 | } | 397 | } |
436 | rcu_read_unlock(); | ||
437 | |||
438 | return skb; | ||
439 | |||
440 | dump_failure: | ||
441 | rcu_read_unlock(); | ||
442 | kfree_skb(skb); | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff | ||
448 | * | ||
449 | * Description: | ||
450 | * Dump the default domain mapping into a buffer suitable for returning to an | ||
451 | * application in response to a NetLabel management DEFDOMAIN message. This | ||
452 | * function may fail if another process is changing the default domain mapping | ||
453 | * at the same time. The returned sk_buff has room at the front of the | ||
454 | * skb_buff for @headroom bytes. See netlabel.h for the DEFDOMAIN message | ||
455 | * format. Returns a pointer to a sk_buff on success, NULL on error. | ||
456 | * | ||
457 | */ | ||
458 | struct sk_buff *netlbl_domhsh_dump_default(size_t headroom) | ||
459 | { | ||
460 | struct sk_buff *skb; | ||
461 | ssize_t buf_len; | ||
462 | struct netlbl_dom_map *entry; | ||
463 | |||
464 | buf_len = NETLBL_LEN_U32; | ||
465 | rcu_read_lock(); | ||
466 | entry = rcu_dereference(netlbl_domhsh_def); | ||
467 | if (entry != NULL) | ||
468 | switch (entry->type) { | ||
469 | case NETLBL_NLTYPE_UNLABELED: | ||
470 | break; | ||
471 | case NETLBL_NLTYPE_CIPSOV4: | ||
472 | buf_len += 2 * NETLBL_LEN_U32; | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC); | ||
477 | if (skb == NULL) | ||
478 | goto dump_default_failure; | ||
479 | |||
480 | if (entry != rcu_dereference(netlbl_domhsh_def)) | ||
481 | goto dump_default_failure; | ||
482 | if (entry != NULL) { | ||
483 | if (nla_put_u32(skb, NLA_U32, entry->type) != 0) | ||
484 | goto dump_default_failure; | ||
485 | buf_len -= NETLBL_LEN_U32; | ||
486 | switch (entry->type) { | ||
487 | case NETLBL_NLTYPE_UNLABELED: | ||
488 | break; | ||
489 | case NETLBL_NLTYPE_CIPSOV4: | ||
490 | if (buf_len < 2 * NETLBL_LEN_U32) | ||
491 | goto dump_default_failure; | ||
492 | if (nla_put_u32(skb, | ||
493 | NLA_U32, | ||
494 | entry->type_def.cipsov4->type) != 0) | ||
495 | goto dump_default_failure; | ||
496 | if (nla_put_u32(skb, | ||
497 | NLA_U32, | ||
498 | entry->type_def.cipsov4->doi) != 0) | ||
499 | goto dump_default_failure; | ||
500 | buf_len -= 2 * NETLBL_LEN_U32; | ||
501 | break; | ||
502 | } | ||
503 | } else | ||
504 | nla_put_u32(skb, NLA_U32, NETLBL_NLTYPE_NONE); | ||
505 | rcu_read_unlock(); | ||
506 | |||
507 | return skb; | ||
508 | 398 | ||
509 | dump_default_failure: | 399 | walk_return: |
510 | rcu_read_unlock(); | 400 | rcu_read_unlock(); |
511 | kfree_skb(skb); | 401 | *skip_bkt = iter_bkt; |
512 | return NULL; | 402 | *skip_chain = chain_cnt; |
403 | return ret_val; | ||
513 | } | 404 | } |