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