LCOV - code coverage report
Current view: top level - vnsw/agent/services/multicast/grpmgmt - gmp_addrlist.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 253 328 77.1 %
Date: 2026-08-03 02:19:58 Functions: 41 50 82.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $Id: gmp_addrlist.c 346474 2009-11-14 10:18:58Z ssiano $
       2             :  *
       3             :  * gmp_addrlist.c - IGMP/MLD address list management
       4             :  *
       5             :  * Dave Katz, March 2008
       6             :  *
       7             :  * Copyright (c) 2008, Juniper Networks, Inc.
       8             :  * All rights reserved.
       9             :  *
      10             :  * This file defines manipulations of Address Lists, which are the key
      11             :  * data structure in the GMP toolkit.  An address list is, conceptually,
      12             :  * a list of addresses (!).  The reality is much more complex, however,
      13             :  * as the address lists are subject to set operations (union, intersection,
      14             :  * etc.)  See gmp_private.h for details.
      15             :  */
      16             : #include "gmpx_basic_types.h"
      17             : #include "gmp.h"
      18             : #include "gmpx_environment.h"
      19             : #include "gmp_externs.h"
      20             : #include "gmp_private.h"
      21             : 
      22             : static gmpx_block_tag gmp_addr_list_tag;
      23             : static gmpx_block_tag gmp_addr_list_entry_tag;
      24             : static gmpx_block_tag gmp_adcat_entry_tag;
      25             : static gmpx_block_tag gmp_addr_thread_tag;
      26             : static gmpx_block_tag gmp_addr_thread_entry_tag;
      27             : static boolean ga_initialized;
      28             : 
      29             : static gmp_addr_string zero_addr;
      30             : 
      31             : /*
      32             :  * gmp_addr_is_zero
      33             :  *
      34             :  * Returns TRUE if the address is all zero, or FALSE if not.
      35             :  */
      36             : boolean
      37           0 : gmp_addr_is_zero (gmp_addr_string *addr, uint32_t addr_len)
      38             : {
      39           0 :     return !memcmp(addr->gmp_addr, zero_addr.gmp_addr, addr_len);
      40             : }
      41             : 
      42             : 
      43             : /*
      44             :  * Address thread manipulation.
      45             :  *
      46             :  * Address threads are used to carry lists of addresses in explicit
      47             :  * form (the actual address bytes.)  Much of this code uses ordinals
      48             :  * to represent addresses, but ordinals are not visible outside of
      49             :  * this module, so we need to have a generic representation of a list
      50             :  * of addresses to pass in and out.
      51             :  */
      52             : 
      53             : /*
      54             :  * gmp_init_addr_thread
      55             :  *
      56             :  * Initialize an address thread.
      57             :  */
      58             : static void
      59          59 : gmp_init_addr_thread (gmp_addr_thread *addr_thread)
      60             : {
      61          59 :     thread_new_circular_thread(&addr_thread->gmp_addr_thread_head);
      62          59 :     addr_thread->gmp_addr_thread_count = 0;
      63          59 : }
      64             : 
      65             : 
      66             : /*
      67             :  * gmp_addr_thread_count
      68             :  *
      69             :  * Returns the count of entries in an address thread.
      70             :  *
      71             :  * Tolerates null pointers.
      72             :  */
      73             : uint32_t
      74           0 : gmp_addr_thread_count (gmp_addr_thread *addr_thread)
      75             : {
      76           0 :     if (!addr_thread)
      77           0 :         return 0;
      78             : 
      79           0 :     return addr_thread->gmp_addr_thread_count;
      80             : }
      81             : 
      82             : 
      83             : /*
      84             :  * gmp_alloc_addr_thread
      85             :  *
      86             :  * Allocate and initialize an address thread.
      87             :  *
      88             :  * Returns a pointer to the address thread, or NULL if out of memory.
      89             :  */
      90             : gmp_addr_thread *
      91          59 : gmp_alloc_addr_thread (void)
      92             : {
      93             :     gmp_addr_thread *addr_thread;
      94             : 
      95          59 :     addr_thread = gmpx_malloc_block(gmp_addr_thread_tag);
      96          59 :     if (addr_thread)
      97          59 :         gmp_init_addr_thread(addr_thread);
      98             : 
      99          59 :     return addr_thread;
     100             : }
     101             : 
     102             : 
     103             : /*
     104             :  * gmp_enqueue_addr_thread_addr
     105             :  *
     106             :  * Enqueue an address on an address thread.
     107             :  *
     108             :  * Returns 0 if all OK, or -1 if out of memory.
     109             :  */
     110             : int
     111         134 : gmp_enqueue_addr_thread_addr(gmp_addr_thread *addr_thread,
     112             :                              uint8_t *addr, uint32_t addr_len)
     113             : {
     114             :     gmp_addr_thread_entry *thread_entry;
     115             : 
     116             :     /* Allocate an address thread entry. */
     117             : 
     118         134 :     thread_entry = gmpx_malloc_block(gmp_addr_thread_entry_tag);
     119         134 :     if (!thread_entry)
     120           0 :         return -1;                      /* Out of memory */
     121             : 
     122             :     /* Copy in the address. */
     123             : 
     124         134 :     memmove(thread_entry->gmp_adth_addr.gmp_addr, addr, addr_len);
     125             : 
     126             :     /* Enqueue the entry. */
     127             : 
     128         134 :     thread_circular_add_bottom(&addr_thread->gmp_addr_thread_head,
     129             :                                &thread_entry->gmp_adth_thread);
     130             : 
     131             :     /* Bump the count. */
     132             : 
     133         134 :     addr_thread->gmp_addr_thread_count++;
     134             : 
     135         134 :     return 0;
     136             : }
     137             : 
     138             : 
     139             : /*
     140             :  * gmp_next_addr_thread_addr
     141             :  *
     142             :  * Get the next address thread address, given a pointer to the last one.
     143             :  * If the last one was NULL, get the first one.
     144             :  *
     145             :  * Returns a pointer to the address string in the entry, or NULL if there
     146             :  * are no more entries.
     147             :  *
     148             :  * Updates the pointer.
     149             :  *
     150             :  * Tolerates null pointers.
     151             :  */
     152             : gmp_addr_string *
     153         193 : gmp_next_addr_thread_addr (gmp_addr_thread *addr_thread,
     154             :                            gmp_addr_thread_entry **entry_ptr)
     155             : {
     156             :     task_thread *thread_ptr;
     157             :     gmp_addr_thread_entry *thread_entry;
     158             : 
     159             :     /* Bail if there's no thread. */
     160             : 
     161         193 :     if (!addr_thread)
     162           0 :         return NULL;
     163             : 
     164             :     /* Pick up the current position. */
     165             : 
     166         193 :     thread_ptr = NULL;
     167         193 :     if (*entry_ptr)
     168         134 :         thread_ptr = &((*entry_ptr)->gmp_adth_thread);
     169             : 
     170             :     /* Fetch the next entry. */
     171             : 
     172             :     thread_ptr =
     173         193 :         thread_circular_thread_next(&addr_thread->gmp_addr_thread_head,
     174             :                                     thread_ptr);
     175         193 :     thread_entry = gmp_adth_thread_to_thread_entry(thread_ptr);
     176         193 :     *entry_ptr = thread_entry;
     177             : 
     178             :     /* Return a pointer to the address string, if it's there. */
     179             : 
     180         193 :     if (thread_entry) {
     181         134 :         return &thread_entry->gmp_adth_addr;
     182             :     } else {
     183          59 :         return NULL;
     184             :     }
     185             : }
     186             : 
     187             : 
     188             : /*
     189             :  * gmp_destroy_addr_thread
     190             :  *
     191             :  * Destroy an address thread
     192             :  *
     193             :  * Flushes the thread and frees the entries and the thread head.
     194             :  */
     195             : void
     196        1239 : gmp_destroy_addr_thread (gmp_addr_thread *addr_thread)
     197             : {
     198             :     gmp_addr_thread_entry *thread_entry;
     199             :     task_thread *thread_ptr;
     200             : 
     201             :     /* Tolerate NULL pointers. */
     202             : 
     203        1239 :     if (!addr_thread)
     204        1180 :         return;
     205             : 
     206             :     /* Pull entries off the thread until it is empty. */
     207             : 
     208             :     while (TRUE) {
     209         134 :         thread_ptr =
     210         193 :             thread_circular_dequeue_top(&addr_thread->gmp_addr_thread_head);
     211         193 :         thread_entry = gmp_adth_thread_to_thread_entry(thread_ptr);
     212         193 :         if (!thread_entry)
     213          59 :             break;
     214         134 :         gmpx_free_block(gmp_addr_thread_entry_tag, thread_entry);
     215             :     }
     216             : 
     217             :     /* Free the thread head. */
     218             : 
     219          59 :     gmpx_free_block(gmp_addr_thread_tag, addr_thread);
     220             : }
     221             : 
     222             : 
     223             : /*
     224             :  * gmp_alloc_generic_addr_list_entry
     225             :  *
     226             :  * Allocate memory for a generic (non-embedded) address list entry.
     227             :  *
     228             :  * Returns a pointer to the entry, or NULL if out of memory.
     229             :  */
     230             : gmp_addr_list_entry *
     231          36 : gmp_alloc_generic_addr_list_entry (void *context GMPX_UNUSED)
     232             : {
     233             :     gmp_addr_list_entry *addr_entry;
     234             : 
     235          36 :     addr_entry = gmpx_malloc_block(gmp_addr_list_entry_tag);
     236          36 :     return addr_entry;
     237             : }
     238             : 
     239             : 
     240             : 
     241             : /*
     242             :  * Address catalog manipulation.
     243             :  *
     244             :  * An address catalog maps addresses to ordinals.  The ordinals are
     245             :  * then used both as shorthand for addresses (for IPv6) and as bit
     246             :  * positions in address vectors (for vector set operations.)
     247             :  *
     248             :  * The catalog maps in each direction between ordinal and address.  A
     249             :  * refcount is kept, and the catalog entry is freed when the last
     250             :  * reference is deleted.
     251             :  *
     252             :  * One must be *very* careful with the lock/unlock pairings; in
     253             :  * particular, if an entry is unlocked when it shouldn't be, this
     254             :  * could free the ordinal, which in turn will either cause a crash (an
     255             :  * ordinal without a matching catalog entry) or worse, the ordinal
     256             :  * could be reassigned, making much mischief with addresses.
     257             :  */
     258             : 
     259             : /*
     260             :  * gmp_destroy_addr_catalog
     261             :  *
     262             :  * Destroy an address catalog.  Cleans out its contents.
     263             :  */
     264             : void
     265         125 : gmp_destroy_addr_catalog (gmp_addr_catalog *catalog)
     266             : {
     267             :     /* The catalog better be empty! */
     268             : 
     269         125 :     gmpx_assert(!(gmpx_patricia_lookup_least(catalog->adcat_addr_root)));
     270         125 :     gmpx_assert(!(gmpx_patricia_lookup_least(catalog->adcat_ord_root)));
     271             : 
     272             :     /* Destroy the patricia trees. */
     273             : 
     274         125 :     gmpx_patroot_destroy(catalog->adcat_addr_root);
     275         125 :     catalog->adcat_addr_root = NULL;
     276         125 :     gmpx_patroot_destroy(catalog->adcat_ord_root);
     277         125 :     catalog->adcat_ord_root = NULL;
     278             : 
     279             :     /* Free the ordinal space. */
     280             : 
     281         125 :     ord_destroy_context(catalog->adcat_ord_handle);
     282         125 :     catalog->adcat_ord_handle = NULL;
     283         125 : }
     284             : 
     285             : 
     286             : /*
     287             :  * gmp_init_addr_catalog
     288             :  *
     289             :  * Initialize an address catalog header.
     290             :  *
     291             :  * Returns 0 if all OK, or -1 if out of memory.
     292             :  */
     293             : int
     294         125 : gmp_init_addr_catalog (gmp_addr_catalog *catalog, uint32_t addr_len)
     295             : {
     296             :     /* Create the tree roots. */
     297             : 
     298         125 :     catalog->adcat_addr_root =
     299         125 :         gmpx_patroot_init(addr_len, GMPX_PATRICIA_OFFSET(gmp_addr_cat_entry,
     300             :                                                          adcat_ent_addr_node,
     301             :                                                          adcat_ent_addr));
     302         125 :     if (!catalog->adcat_addr_root)
     303           0 :         return -1;                      /* Out of memory */
     304             : 
     305         125 :     catalog->adcat_ord_root =
     306         125 :         gmpx_patroot_init(sizeof(ordinal_t),
     307             :                           GMPX_PATRICIA_OFFSET(gmp_addr_cat_entry,
     308             :                                                adcat_ent_ord_node,
     309             :                                                adcat_ent_ord));
     310         125 :     if (!catalog->adcat_ord_root) {
     311           0 :         gmpx_patroot_destroy(catalog->adcat_addr_root);
     312           0 :         catalog->adcat_addr_root = NULL;
     313           0 :         return -1;                      /* Out of memory */
     314             :     }
     315             : 
     316             :     /* Allocate ordinal space. */
     317             : 
     318         125 :     catalog->adcat_ord_handle = ord_create_context(ORD_PERFORMANCE);
     319         125 :     if (!catalog->adcat_ord_handle) {
     320           0 :         gmpx_patroot_destroy(catalog->adcat_addr_root);
     321           0 :         catalog->adcat_addr_root = NULL;
     322           0 :         gmpx_patroot_destroy(catalog->adcat_ord_root);
     323           0 :         catalog->adcat_ord_root = NULL;
     324           0 :         return -1;                      /* Out of memory */
     325             :     }
     326             : 
     327             :     /* Set the address length. */
     328             : 
     329         125 :     catalog->adcat_addrlen = addr_len;
     330             : 
     331         125 :     return 0;
     332             : }
     333             : 
     334             : 
     335             : /*
     336             :  * gmp_addr_list_copy_cb
     337             :  *
     338             :  * Bit vector callback to copy an address list entry.
     339             :  *
     340             :  * If an entry is already present in the destination list, it is left there.
     341             :  */
     342             : boolean
     343           0 : gmp_addr_list_copy_cb (void *context, bv_bitnum_t bitnum,
     344             :                        boolean new_val GMPX_UNUSED,
     345             :                        boolean old_val GMPX_UNUSED)
     346             : {
     347             :     gmp_addr_list *dest;
     348             : 
     349           0 :     dest = context;
     350             : 
     351             :     /* See if the entry is already present in the destination list. */
     352             : 
     353           0 :     if (!gmp_addr_in_list(dest, bitnum)) {
     354             : 
     355             :         /* Not present.  Create a new entry. */
     356             : 
     357           0 :         gmp_create_addr_list_entry(dest, bitnum);
     358             :     }
     359             : 
     360           0 :     return FALSE;
     361             : }
     362             : 
     363             : 
     364             : /*
     365             :  * gmp_get_addr_cat_by_ordinal
     366             :  *
     367             :  * Look up an address catalog entry by its ordinal.
     368             :  *
     369             :  * Returns a pointer to the catalog entry, or NULL if not found.
     370             :  */
     371             : gmp_addr_cat_entry *
     372         813 : gmp_get_addr_cat_by_ordinal (gmp_addr_catalog *catalog, ordinal_t ordinal)
     373             : {
     374             :     gmp_addr_cat_entry *cat_entry;
     375             :     gmpx_patnode *node;
     376             : 
     377             :     /* Look it up. */
     378             : 
     379         813 :     node = gmpx_patricia_lookup(catalog->adcat_ord_root, &ordinal);
     380         813 :     cat_entry = gmp_ord_patnode_to_addr_cat_entry(node);
     381             : 
     382         813 :     return cat_entry;
     383             : }
     384             : 
     385             : 
     386             : /*
     387             :  * gmp_unlock_adcat_entry
     388             :  *
     389             :  * Unlock an address catalog entry.
     390             :  *
     391             :  * If the refcount has gone to zero, release the entry.
     392             :  */
     393             : void
     394         283 : gmp_unlock_adcat_entry (gmp_addr_catalog *catalog, ordinal_t ordinal)
     395             : {
     396             :     gmp_addr_cat_entry *cat_entry;
     397             : 
     398             :     /* Look up the catalog entry by ordinal. */
     399             : 
     400         283 :     cat_entry = gmp_get_addr_cat_by_ordinal(catalog, ordinal);
     401         283 :     gmpx_assert(cat_entry);
     402             : 
     403         283 :     cat_entry->adcat_ent_refcount--;
     404         283 :     gmpx_assert(cat_entry->adcat_ent_refcount >= 0);
     405             : 
     406             :     /* Free the entry and its ordinal if the refcount has gone to zero. */
     407             : 
     408         283 :     if (cat_entry->adcat_ent_refcount == 0) {
     409          34 :         ord_free_ordinal(catalog->adcat_ord_handle, ordinal);
     410          34 :         gmpx_assert(gmpx_patricia_delete(catalog->adcat_addr_root,
     411             :                                          &cat_entry->adcat_ent_addr_node));
     412          34 :         gmpx_assert(gmpx_patricia_delete(catalog->adcat_ord_root,
     413             :                                          &cat_entry->adcat_ent_ord_node));
     414          34 :         gmpx_free_block(gmp_adcat_entry_tag, cat_entry);
     415             :     }
     416         283 : }
     417             : 
     418             : 
     419             : /*
     420             :  * gmp_lock_adcat_entry
     421             :  *
     422             :  * Lock an address catalog entry.  Just bump the refcount.
     423             :  */
     424             : void
     425         283 : gmp_lock_adcat_entry (gmp_addr_catalog *catalog, ordinal_t ordinal)
     426             : {
     427             :     gmp_addr_cat_entry *cat_entry;
     428             : 
     429             :     /* Look up the catalog entry by ordinal. */
     430             : 
     431         283 :     cat_entry = gmp_get_addr_cat_by_ordinal(catalog, ordinal);
     432         283 :     gmpx_assert(cat_entry);
     433             : 
     434         283 :     cat_entry->adcat_ent_refcount++;
     435         283 : }
     436             : 
     437             : 
     438             : /*
     439             :  * gmp_lookup_addr_cat_entry
     440             :  *
     441             :  * Look up an address catalog entry by address.
     442             :  * 
     443             :  * Returns a pointer to the entry, or NULL if not found.
     444             :  */
     445             : gmp_addr_cat_entry *
     446         122 : gmp_lookup_addr_cat_entry (gmp_addr_catalog *catalog, const uint8_t *addr)
     447             : {
     448             :     gmpx_patnode *node;
     449             :     gmp_addr_cat_entry *cat_entry;
     450             : 
     451             :     /* Look up the entry. */
     452             : 
     453         122 :     node = gmpx_patricia_lookup(catalog->adcat_addr_root, addr);
     454         122 :     cat_entry = gmp_addr_patnode_to_addr_cat_entry(node);
     455             : 
     456         122 :     return cat_entry;
     457             : }
     458             : 
     459             : 
     460             : /*
     461             :  * gmp_lookup_create_addr_cat_entry
     462             :  *
     463             :  * Look up an address catalog entry by address, and create an entry if one
     464             :  * isn't there.
     465             :  *
     466             :  * Returns the ordinal of the entry, or ORD_BAD_ORDINAL if out of memory.
     467             :  *
     468             :  * Note that the caller is responsible for locking the entry!
     469             :  */
     470             : ordinal_t
     471         122 : gmp_lookup_create_addr_cat_entry (gmp_addr_catalog *catalog,
     472             :                                   uint8_t *addr)
     473             : {
     474             :     gmp_addr_cat_entry *cat_entry;
     475             : 
     476             :     /* Look up the entry. */
     477             : 
     478         122 :     cat_entry = gmp_lookup_addr_cat_entry(catalog, addr);
     479             : 
     480         122 :     if (!cat_entry) {
     481             : 
     482             :         /* No entry found.  Create a new one. */
     483             : 
     484          34 :         cat_entry = gmpx_malloc_block(gmp_adcat_entry_tag);
     485          34 :         if (!cat_entry)
     486           0 :             return ORD_BAD_ORDINAL;     /* Out of memory */
     487             : 
     488             :         /* Got one.  Initialize it. */
     489             : 
     490          34 :         memmove(cat_entry->adcat_ent_addr.gmp_addr, addr,
     491          34 :             catalog->adcat_addrlen);
     492          34 :         cat_entry->adcat_ent_ord = ord_get_ordinal(catalog->adcat_ord_handle);
     493          34 :         if (cat_entry->adcat_ent_ord == ORD_BAD_ORDINAL) {
     494           0 :             free(cat_entry);
     495           0 :             return ORD_BAD_ORDINAL;     /* Out of memory */
     496             :         }
     497             : 
     498             :         /* Add it to the patricia trees. */
     499             : 
     500          34 :         gmpx_assert(gmpx_patricia_add(catalog->adcat_addr_root,
     501             :                           &cat_entry->adcat_ent_addr_node));
     502          34 :         gmpx_assert(gmpx_patricia_add(catalog->adcat_ord_root,
     503             :                           &cat_entry->adcat_ent_ord_node));
     504             :     }
     505             : 
     506         122 :     return cat_entry->adcat_ent_ord;
     507             : }
     508             : 
     509             : 
     510             : /*
     511             :  * Generic address list entry routines.  Generic address list entries
     512             :  * are used when no additional information needs to be associated with
     513             :  * the entry--the semantics are just an address.  These routines
     514             :  * allocate and deallocate naked address list entries for those who
     515             :  * need them.  When other information needs to be associated with an
     516             :  * address, a more specific structure is created with an address list
     517             :  * entry embedded therein; those users provide their own alloc and
     518             :  * free routines.
     519             :  */
     520             : 
     521             : /*
     522             :  * gmp_free_generic_addr_list_entry
     523             :  *
     524             :  * Callback to free a generic address list entry.
     525             :  */
     526             : void
     527          36 : gmp_free_generic_addr_list_entry (gmp_addr_list_entry *addr_entry)
     528             : {
     529             :     /* Simply free the block. */
     530             : 
     531          36 :     gmpx_free_block(gmp_addr_list_entry_tag, addr_entry);
     532          36 : }
     533             : 
     534             : 
     535             : /*
     536             :  * gmp_addr_list_empty
     537             :  * 
     538             :  * Returns TRUE if the address list is empty, or FALSE if not.
     539             :  */
     540             : boolean
     541        1752 : gmp_addr_list_empty (gmp_addr_list *list)
     542             : {
     543        1752 :     return (!list->addr_count);
     544             : }
     545             : 
     546             : 
     547             : /*
     548             :  * gmp_addr_list_next_entry
     549             :  *
     550             :  * Returns the next entry in an address list, given a pointer to the
     551             :  * previous one.  If the provided pointer is NULL, returns the first
     552             :  * entry on the list.
     553             :  *
     554             :  * Returns NULL when there are no more entries on the list.
     555             :  *
     556             :  * The entries are *not* returned in any particular lexicographic order.
     557             :  */
     558             : gmp_addr_list_entry *
     559        1085 : gmp_addr_list_next_entry (gmp_addr_list *list, gmp_addr_list_entry *prev)
     560             : {
     561             :     task_thread *new_thread;
     562             :     task_thread *cur_thread;
     563             : 
     564             :     /* Get the current position. */
     565             : 
     566        1085 :     if (prev) {
     567          60 :         cur_thread = &prev->addr_ent_thread;
     568             :     } else {
     569        1025 :         cur_thread = NULL;
     570             :     }
     571             : 
     572             :     /* Get the next entry. */
     573             : 
     574        1085 :     new_thread = thread_circular_thread_next(&list->addr_list_head,
     575             :                                              cur_thread);
     576        1085 :     return gmp_thread_to_addr_list_entry(new_thread);
     577             : }
     578             : 
     579             : 
     580             : /*
     581             :  * gmp_addr_list_init
     582             :  *
     583             :  * Initialize an address list header.  We leave the patricia tree root
     584             :  * empty unless we actually get sources to work with.
     585             :  */
     586             : void
     587         405 : gmp_addr_list_init (gmp_addr_list *list, gmp_addr_catalog *catalog,
     588             :                     gmp_addr_list_alloc_func alloc_func,
     589             :                     gmp_addr_list_free_func free_func,
     590             :                     void *context)
     591             : {
     592             :     /* Zero it out. */
     593             : 
     594         405 :     memset(list, 0, sizeof(gmp_addr_list));
     595             : 
     596             :     /* Initialize the threads. */
     597             : 
     598         405 :     thread_new_circular_thread(&list->addr_list_head);
     599         405 :     thread_new_circular_thread(&list->addr_list_xmit_head);
     600             : 
     601             :     /* Initialize the address vector. */
     602             : 
     603         405 :     gmp_init_addr_vector(&list->addr_vect, catalog);
     604             : 
     605             :     /* Initialize the allocation/free pointers. */
     606             : 
     607         405 :     list->addr_alloc = alloc_func;
     608         405 :     list->addr_free = free_func;
     609         405 :     list->addr_context = context;
     610         405 : }
     611             : 
     612             : 
     613             : 
     614             : /*
     615             :  * Transmit list manipulations.  These routines operate on the transmit
     616             :  * thread of an address list.
     617             :  */
     618             : 
     619             : /*
     620             :  * gmp_flush_xmit_list
     621             :  *
     622             :  * Flush the transmit list of an address list.
     623             :  */
     624             : void
     625          69 : gmp_flush_xmit_list (gmp_addr_list *addr_list)
     626             : {
     627             :     task_thread *thread_ptr;
     628             : 
     629          69 :     if (!addr_list)
     630          69 :         return;                         /* Tolerate NULL pointers */
     631             : 
     632             :     /* Just walk the list, deleting everything. */
     633             : 
     634             :     while (TRUE) {
     635           0 :         thread_ptr = thread_circular_top(&addr_list->addr_list_xmit_head);
     636           0 :         if (!thread_ptr)
     637           0 :             break;
     638           0 :         thread_remove(thread_ptr);
     639             :     }
     640           0 :     addr_list->xmit_addr_count = 0;
     641             : }
     642             : 
     643             : 
     644             : /*
     645             :  * gmp_enqueue_xmit_addr_entry
     646             :  *
     647             :  * Enqueue an address entry on its owning address list transmit thread
     648             :  * if it is not already enqueued.
     649             :  */
     650             : void
     651          36 : gmp_enqueue_xmit_addr_entry (gmp_addr_list_entry *addr_entry)
     652             : { 
     653             :     gmp_addr_list *addr_list;
     654             : 
     655             :    /* Enqueue it if it's not already on a queue. */
     656             : 
     657          36 :     if(!thread_node_on_thread(&addr_entry->addr_ent_xmit_thread)) {
     658          36 :         addr_list = addr_entry->addr_ent_list;
     659          36 :         thread_circular_add_bottom(&addr_list->addr_list_xmit_head,
     660             :                                    &addr_entry->addr_ent_xmit_thread);
     661          36 :         addr_list->xmit_addr_count++;
     662             :     }
     663          36 : }
     664             : 
     665             : 
     666             : /*
     667             :  * gmp_dequeue_xmit_addr_entry
     668             :  *
     669             :  * Dequeue an address entry from its owning address list transmit thread.
     670             :  */
     671             : void
     672         283 : gmp_dequeue_xmit_addr_entry (gmp_addr_list_entry *addr_entry)
     673             : {
     674             :     gmp_addr_list *addr_list;    
     675         283 :     if (thread_node_on_thread(&addr_entry->addr_ent_xmit_thread)) {
     676          36 :         addr_list = addr_entry->addr_ent_list;
     677          36 :         thread_remove(&addr_entry->addr_ent_xmit_thread);
     678          36 :         addr_list->xmit_addr_count--;
     679          36 :         gmpx_assert(addr_list->xmit_addr_count >= 0);
     680             :     }
     681         283 : }
     682             : 
     683             : 
     684             : /*
     685             :  * gmp_xmit_addr_list_empty
     686             :  * 
     687             :  * Returns TRUE if the transmit thread on an address list is empty, or
     688             :  * FALSE if not.
     689             :  */
     690             : boolean
     691         139 : gmp_xmit_addr_list_empty (gmp_addr_list *list)
     692             : {
     693         139 :     return (list->xmit_addr_count == 0);
     694             : }
     695             : 
     696             : 
     697             : /*
     698             :  * gmp_first_xmit_addr_entry
     699             :  *
     700             :  * Returns a pointer to the first address entry on an address list
     701             :  * transmit thread, or NULL if the thread is empty.
     702             :  */
     703             : gmp_addr_list_entry *
     704          53 : gmp_first_xmit_addr_entry (gmp_addr_list *addr_list)
     705             : {
     706             :     task_thread *entry_thread;
     707             : 
     708          53 :     entry_thread = thread_circular_top(&addr_list->addr_list_xmit_head);
     709          53 :     return gmp_xmit_thread_to_addr_list_entry(entry_thread);
     710             : }
     711             : 
     712             : 
     713             : /*
     714             :  * gmp_enqueue_xmit_addr_list
     715             :  *
     716             :  * Thread all entries in an address list onto the list transmit
     717             :  * thread.  We traverse the address list thread for speed.
     718             :  */
     719             : void
     720           0 : gmp_enqueue_xmit_addr_list (gmp_addr_list *addr_list)
     721             : {
     722             :     gmp_addr_list_entry *addr_entry;
     723             : 
     724             :     /* Walk everything on the address list. */
     725             : 
     726           0 :     addr_entry = NULL;
     727             :     while (TRUE) {
     728           0 :         addr_entry = gmp_addr_list_next_entry(addr_list, addr_entry);
     729             : 
     730             :         /* Bail if nothing left. */
     731             : 
     732           0 :         if (!addr_entry)
     733           0 :             break;
     734             : 
     735             :         /* Enqueue the entry. */
     736             : 
     737           0 :         gmp_enqueue_xmit_addr_entry(addr_entry);
     738             :     }
     739           0 : }
     740             : 
     741             : 
     742             : /*
     743             :  * gmp_remove_addr_list_entry
     744             :  *
     745             :  * Remove an address list entry from an address list (but don't free it.)
     746             :  *
     747             :  * Note that we do NOT unlock the corresponding catalog entry.
     748             :  *
     749             :  */
     750             : static void
     751         247 : gmp_remove_addr_list_entry (gmp_addr_list_entry *addr_entry)
     752             : {
     753             :     gmp_addr_list *addr_list;
     754             : 
     755             :     /* Delete the entry from the tree. */
     756             : 
     757         247 :     addr_list = addr_entry->addr_ent_list;
     758         247 :     gmpx_assert(gmpx_patricia_delete(addr_list->addr_list_root,
     759             :                                      &addr_entry->addr_ent_patnode));
     760             : 
     761             :     /* Clear the corresponding vector bit.  Better have been set. */
     762             : 
     763         247 :     gmpx_assert(bv_clear_bit(&addr_list->addr_vect.av_vector,
     764             :                              addr_entry->addr_ent_ord));
     765             : 
     766             :     /* Remove it from the threads if it is there. */
     767             : 
     768         247 :     thread_remove(&addr_entry->addr_ent_thread);
     769         247 :     gmp_dequeue_xmit_addr_entry(addr_entry);
     770         247 :     addr_entry->addr_ent_list = NULL;
     771             : 
     772             :     /* Drop the entry count. */
     773             : 
     774         247 :     addr_list->addr_count--;
     775         247 :     gmpx_assert(addr_list->addr_count >= 0);
     776         247 : }
     777             : 
     778             : 
     779             : /*
     780             :  * gmp_delete_addr_list_entry
     781             :  *
     782             :  * Remove an address entry from a list and free it.
     783             :  *
     784             :  * Clears the vector bit and unlocks the corresponding catalog entry.
     785             :  */
     786             : void
     787         161 : gmp_delete_addr_list_entry (gmp_addr_list_entry *addr_entry)
     788             : {
     789             :     gmp_addr_list *addr_list;
     790             : 
     791         161 :     addr_list = addr_entry->addr_ent_list;
     792             : 
     793             :     /* Remove the entry from its list. */
     794             : 
     795         161 :     gmp_remove_addr_list_entry(addr_entry);
     796             : 
     797             :     /* Unlock the address catalog entry. */
     798             : 
     799         161 :     gmp_unlock_adcat_entry(addr_list->addr_vect.av_catalog,
     800             :                            addr_entry->addr_ent_ord);
     801             : 
     802             :     /* Free the entry. */
     803             : 
     804         161 :     (*addr_list->addr_free)(addr_entry);
     805         161 : }
     806             : 
     807             : 
     808             : /*
     809             :  * gmp_lookup_addr_entry
     810             :  *
     811             :  * Look up an address in an address list.
     812             :  *
     813             :  * Returns a pointer to the address entry, or NULL if not there.
     814             :  */
     815             : gmp_addr_list_entry *
     816         290 : gmp_lookup_addr_entry (gmp_addr_list *addr_list, ordinal_t ordinal)
     817             : {
     818             :     gmpx_patnode *node;
     819             :     gmp_addr_list_entry *addr_entry;
     820             : 
     821             :     /* Bail if the list is empty. */
     822             : 
     823         290 :     if (gmp_addr_list_empty(addr_list))
     824          60 :         return NULL;
     825             : 
     826             :     /* Look up the address entry. */
     827             : 
     828         230 :     node = gmpx_patricia_lookup(addr_list->addr_list_root, &ordinal);
     829         230 :     addr_entry = gmp_patnode_to_addr_list_entry(node);
     830             : 
     831         230 :     return addr_entry;
     832             : }
     833             : 
     834             : 
     835             : /*
     836             :  * gmp_flush_addr_list
     837             :  *
     838             :  * Flush an address list.  The address list header (including the
     839             :  * patrica root) is not freed, but all of the list entries are.
     840             :  *
     841             :  * Calls back to the callback pointer to actually free each entry.
     842             :  *
     843             :  * Tolerates a null address list tree.
     844             :  */
     845             : void
     846         700 : gmp_flush_addr_list (gmp_addr_list *addr_list)
     847             : {
     848             :     gmp_addr_list_entry *addr_entry;
     849             : 
     850             :     /* Just pull entries out of the thread until it's empty. */
     851             : 
     852             :     while (TRUE) {
     853             : 
     854             :         /* Get the first entry. */
     855             : 
     856         700 :         addr_entry = gmp_addr_list_next_entry(addr_list, NULL);
     857         700 :         if (!addr_entry)                /* All done */
     858         652 :             break;
     859             : 
     860             :         /* Remove it from the address list and free it. */
     861             : 
     862          48 :         gmp_delete_addr_list_entry(addr_entry);
     863             :     }
     864         652 : }
     865             : 
     866             : 
     867             : /*
     868             :  * gmp_add_addr_list_tree
     869             :  *
     870             :  * Add the patricia tree to an address list.  We try not to do this unless
     871             :  * we have to (to save memory.)
     872             :  *
     873             :  * Returns 0 if all OK, or -1 if no memory.
     874             :  */
     875             : static int
     876         109 : gmp_add_addr_list_tree (gmp_addr_list *addr_list)
     877             : {
     878             :     /* Be extra paranoid that there are no addresses there now. */
     879             : 
     880         109 :     gmpx_assert((addr_list->addr_list_root == NULL) &&
     881             :                 gmp_addr_list_empty(addr_list));
     882             : 
     883             :     /* Create the patricia tree. */
     884             : 
     885         109 :     addr_list->addr_list_root =
     886         109 :         gmpx_patroot_init(sizeof(ordinal_t),
     887             :                           GMPX_PATRICIA_OFFSET(gmp_addr_list_entry,
     888             :                                                addr_ent_patnode,
     889             :                                                addr_ent_ord));
     890         109 :     if (!addr_list->addr_list_root)
     891           0 :         return -1;                      /* Out of memory */
     892             : 
     893         109 :     return 0;
     894             : }
     895             : 
     896             : 
     897             : /*
     898             :  * gmp_add_addr_list_entry
     899             :  *
     900             :  * Add an address list entry to an address list.  Creates an address tree
     901             :  * if one does not exist.
     902             :  *
     903             :  * Assumes that the corresponding address catalog entry has already been
     904             :  * locked, and does *NOT* do so here.
     905             :  *
     906             :  * Returns 0 if all OK, or -1 if out of memory.
     907             :  */
     908             : int
     909         247 : gmp_add_addr_list_entry (gmp_addr_list *addr_list,
     910             :                          gmp_addr_list_entry *addr_entry)
     911             : {
     912             :     int retval;
     913             : 
     914             :     /* If there's no patricia tree there, create one. */
     915             : 
     916         247 :     if (addr_list->addr_list_root == NULL) {
     917         109 :         if (gmp_add_addr_list_tree(addr_list) < 0)
     918           0 :             return -1;                  /* Out of memory */
     919             :     }
     920             : 
     921             :     /* Add the entry to the patricia tree. */
     922             : 
     923         247 :     gmpx_assert(gmpx_patricia_add(addr_list->addr_list_root,
     924             :                                   &addr_entry->addr_ent_patnode));
     925             : 
     926             :     /* Put the entry on the address list thread. */
     927             : 
     928         247 :     addr_list->addr_count++;
     929         247 :     gmpx_assert(!thread_node_on_thread(&addr_entry->addr_ent_thread));
     930         247 :     gmpx_assert(!thread_node_on_thread(&addr_entry->addr_ent_xmit_thread));
     931         247 :     thread_circular_add_bottom(&addr_list->addr_list_head,
     932             :                                &addr_entry->addr_ent_thread);
     933         247 :     addr_entry->addr_ent_list = addr_list;
     934             : 
     935             :     /* Set the vector bit. */
     936             : 
     937         247 :     retval = bv_set_bit(&addr_list->addr_vect.av_vector,
     938             :                         addr_entry->addr_ent_ord);
     939         247 :     gmpx_assert(retval != 1);           /* Better not have been set */
     940             : 
     941         247 :     return retval;
     942             : }
     943             : 
     944             : 
     945             : /*
     946             :  * gmp_move_addr_list_entry
     947             :  *
     948             :  * Move an address list entry from its current list to another.
     949             :  */
     950             : void
     951          86 : gmp_move_addr_list_entry (gmp_addr_list *to_list,
     952             :                           gmp_addr_list_entry *addr_entry)
     953             : {
     954             :     gmp_addr_list *from_list;
     955             : 
     956          86 :     from_list = addr_entry->addr_ent_list;
     957             : 
     958             :     /*
     959             :      * Ensure that the lists have the same allocation and free pointers.
     960             :      * This makes sure that the lists are compatible.
     961             :      */
     962          86 :     gmpx_assert(from_list->addr_alloc == to_list->addr_alloc &&
     963             :                 from_list->addr_free == to_list->addr_free);
     964             : 
     965             :     /* Remove the entry from the from list. */
     966             : 
     967          86 :     gmp_remove_addr_list_entry(addr_entry);
     968             : 
     969             :     /* Stick it onto the to list. */
     970             : 
     971          86 :     gmp_add_addr_list_entry(to_list, addr_entry);
     972          86 : }
     973             : 
     974             : 
     975             : /*
     976             :  * gmp_create_addr_list_entry
     977             :  *
     978             :  * Create and enqueue an address list entry, given the list and the address
     979             :  * ordinal.
     980             :  *
     981             :  * The entry is allocated via the allocation pointer in the address list.
     982             :  *
     983             :  * The catalog entry corresponding to the ordinal is locked.
     984             :  *
     985             :  * Returns a pointer to the new entry, or NULL if out of memory or the
     986             :  * allocation routine declined to create an entry.
     987             :  */
     988             : gmp_addr_list_entry *
     989         161 : gmp_create_addr_list_entry (gmp_addr_list *addr_list, ordinal_t ordinal)
     990             : {
     991             :     gmp_addr_list_entry *addr_entry;
     992             : 
     993             :     /* Allocate the entry. */
     994             : 
     995         161 :     addr_entry = (*addr_list->addr_alloc)(addr_list->addr_context);
     996         161 :     if (!addr_entry)
     997           0 :         return NULL;                    /* Out of memory */
     998             : 
     999         161 :     addr_entry->addr_ent_ord = ordinal;
    1000             : 
    1001             :     /* Add it to the list. */
    1002             : 
    1003         161 :     gmp_add_addr_list_entry(addr_list, addr_entry);
    1004             : 
    1005             :     /* Lock the catalog entry. */
    1006             : 
    1007         161 :     gmp_lock_adcat_entry(addr_list->addr_vect.av_catalog, ordinal);
    1008             : 
    1009         161 :     return addr_entry;
    1010             : }
    1011             : 
    1012             : 
    1013             : /*
    1014             :  * gmp_init_addr_vector
    1015             :  *
    1016             :  * Initialize an address vector.
    1017             :  *
    1018             :  * If no catalog pointer is supplied, it's a scratch vector and catalog
    1019             :  * entries will not be locked and unlocked as the vector is manipulated.
    1020             :  */
    1021             : void
    1022         541 : gmp_init_addr_vector (gmp_addr_vect *vector, gmp_addr_catalog *catalog)
    1023             : {
    1024             :     /* Initialize the bit vector.  We always use fast vector operations. */
    1025             : 
    1026         541 :     bv_init_vector(&vector->av_vector, TRUE);
    1027             : 
    1028             :     /* Stash the catalog pointer. */
    1029             : 
    1030         541 :     vector->av_catalog = catalog;
    1031         541 : }
    1032             : 
    1033             : 
    1034             : /*
    1035             :  * gmp_addr_vect_clean_cb
    1036             :  *
    1037             :  * Callback from the bit vector code when cleaning out a vector entry.
    1038             :  *
    1039             :  * We decrement the catalog refcount and release the entry if the
    1040             :  * refcount has gone to zero.
    1041             :  */
    1042             : static boolean
    1043         122 : gmp_addr_vect_clean_cb (void *context GMPX_UNUSED, uint32_t bitnum,
    1044             :                         boolean new_bitval, boolean old_bitval GMPX_UNUSED)
    1045             : {
    1046             :     gmp_addr_catalog *catalog;
    1047             : 
    1048         122 :     catalog = context;
    1049             : 
    1050         122 :     gmpx_assert(new_bitval == 0);       /* Better be turning off the bit! */
    1051             : 
    1052         122 :     gmp_unlock_adcat_entry(catalog, bitnum);
    1053             : 
    1054         122 :     return FALSE;
    1055             : }
    1056             : 
    1057             : 
    1058             : /*
    1059             :  * gmp_addr_vect_set
    1060             :  *
    1061             :  * Add an address to an address vector, by creating an address catalog
    1062             :  * entry for it and setting the bit in the vector.
    1063             :  *
    1064             :  * This routine tolerates duplicate addresses.
    1065             :  *
    1066             :  * Returns 0 if all OK, or -1 if no memory.
    1067             :  *
    1068             :  * The address catalog entry is locked, but only once when duplicate
    1069             :  * addresses are present.
    1070             :  */
    1071             : int
    1072         122 : gmp_addr_vect_set(gmp_addr_vect *addr_vect, gmp_addr_string *addr)
    1073             : {
    1074             :     int set_result;
    1075             :     ordinal_t ordinal;
    1076             : 
    1077             :     /* Look up or create an address catalog entry. */
    1078             : 
    1079         122 :     ordinal = gmp_lookup_create_addr_cat_entry(addr_vect->av_catalog,
    1080         122 :                                                addr->gmp_addr);
    1081         122 :     if (ordinal == ORD_BAD_ORDINAL)     /* No memory */
    1082           0 :         return -1;
    1083             : 
    1084             :     /* Got the entry.  Set the bit in the vector. */
    1085             : 
    1086         122 :     set_result = bv_set_bit(&addr_vect->av_vector, ordinal);
    1087         122 :     if (set_result < 0)
    1088           0 :         return -1;                      /* Out of memory */
    1089             : 
    1090             :     /*
    1091             :      * If the bit wasn't already set (not a duplicate), lock the
    1092             :      * catalog entry.
    1093             :      */
    1094         122 :     if (set_result == 0)
    1095         122 :         gmp_lock_adcat_entry(addr_vect->av_catalog, ordinal);
    1096             : 
    1097         122 :     return 0;
    1098             : }
    1099             : 
    1100             : 
    1101             : /*
    1102             :  * gmp_addr_vect_clean
    1103             :  *
    1104             :  * Clean out an address vector.  Clears all of the vector bits and drops
    1105             :  * the refcounts as necessary.  Address catalog entries may be freed as a
    1106             :  * side effect.
    1107             :  *
    1108             :  * The catalog pointer can be NULL if the vector is not persistent.
    1109             :  */
    1110             : void
    1111         140 : gmp_addr_vect_clean (gmp_addr_vect *vector)
    1112             : {
    1113             :     /*
    1114             :      * Call the bit vector routine to do the work.  If a catalog
    1115             :      * pointer is provided, pass a pointer to the callback routine
    1116             :      * above to unlock each address.
    1117             :      */
    1118         140 :     bv_clear_all_bits(&vector->av_vector, vector->av_catalog ?
    1119         140 :                       gmp_addr_vect_clean_cb : NULL, vector->av_catalog,
    1120             :                       BV_CALL_CHANGE);
    1121         140 : }
    1122             : 
    1123             : 
    1124             : /*
    1125             :  * gmp_addr_vect_empty
    1126             :  *
    1127             :  * Returns TRUE if an address vector is empty (has no set bits), or FALSE
    1128             :  * if not.
    1129             :  */
    1130             : boolean
    1131         199 : gmp_addr_vect_empty (gmp_addr_vect *vector)
    1132             : {
    1133         199 :     return bv_empty(&vector->av_vector);
    1134             : }
    1135             : 
    1136             : 
    1137             : /*
    1138             :  * gmp_build_addr_cb
    1139             :  *
    1140             :  * Callback from bit vector routines for gmp_build_addr_list().
    1141             :  *
    1142             :  * This routine is called for each bit that is different between the
    1143             :  * two vectors.
    1144             :  *
    1145             :  * New entries are allocated, and departing entries are freed, as
    1146             :  * appropriate.
    1147             :  */
    1148             : static boolean
    1149           0 : gmp_build_addr_cb (void *context, bv_bitnum_t bitnum,
    1150             :                    boolean new_bit GMPX_UNUSED, boolean old_bit GMPX_UNUSED)
    1151             : {
    1152             :     gmp_addr_list *addr_list;
    1153             :     gmp_addr_list_entry *addr_entry;
    1154             : 
    1155           0 :     addr_list = context;
    1156             : 
    1157             :     /* If we're creating a new entry, add it to the list. */
    1158             : 
    1159           0 :     if (!gmp_addr_in_list(addr_list, bitnum)) {
    1160           0 :         addr_entry = gmp_create_addr_list_entry(addr_list, bitnum);
    1161             : 
    1162             :     } else {
    1163             : 
    1164             :         /* Getting rid of an old entry.  Trash it. */
    1165             : 
    1166           0 :         addr_entry = gmp_lookup_addr_entry(addr_list, bitnum);
    1167           0 :         gmpx_assert(addr_entry);        /* Better be there! */
    1168           0 :         gmp_delete_addr_list_entry(addr_entry);
    1169             :     }
    1170             : 
    1171           0 :     return FALSE;
    1172             : }
    1173             : 
    1174             : 
    1175             : /*
    1176             :  * gmp_build_addr_list
    1177             :  *
    1178             :  * Builds an address list from an address vector.
    1179             :  *
    1180             :  * Returns 0 if all OK, or -1 if out of memory.
    1181             :  *
    1182             :  * The contents of the address list are changed to match the new vector.
    1183             :  * Any existing entries not on the new vector are deleted, and any
    1184             :  * existing entries that are on the new vector are left untouched.
    1185             :  */
    1186             : int
    1187           0 : gmp_build_addr_list (gmp_addr_list *addr_list, gmp_addr_vect *vector)
    1188             : {
    1189             :     /*
    1190             :      * Compare the two vectors;  we'll be called back for any bits that
    1191             :      * are different, and the callback routine will make the appropriate
    1192             :      * adjustments.
    1193             :      */
    1194           0 :     return gmp_addr_vect_compare(vector, &addr_list->addr_vect,
    1195             :                                  gmp_build_addr_cb, addr_list);
    1196             : }
    1197             : 
    1198             : 
    1199             : /*
    1200             :  * gmp_addr_vect_fill
    1201             :  *
    1202             :  * Fill an address list vector from an address thread.
    1203             :  *
    1204             :  * Returns 0 if all OK, or -1 if no memory.
    1205             :  *
    1206             :  * Address catalog entries for each address are locked.
    1207             :  */
    1208             : int
    1209           0 : gmp_addr_vect_fill (gmp_addr_vect *addr_vect, gmp_addr_thread *addr_thread)
    1210             : {
    1211             :     int set_result;
    1212             :     ordinal_t ordinal;
    1213             :     gmp_addr_thread_entry *thread_entry;
    1214             :     gmp_addr_string *addr;
    1215             : 
    1216             :     /* Walk each of the source addresses, if any. */
    1217             : 
    1218           0 :     thread_entry = NULL;
    1219             :     while (TRUE) {
    1220           0 :         addr = gmp_next_addr_thread_addr(addr_thread, &thread_entry);
    1221           0 :         if (!addr)
    1222           0 :             break;
    1223             :         
    1224             :         /* Look up or create an address catalog entry. */
    1225             : 
    1226           0 :         ordinal = gmp_lookup_create_addr_cat_entry(addr_vect->av_catalog,
    1227           0 :                                                    addr->gmp_addr);
    1228           0 :         if (ordinal == ORD_BAD_ORDINAL) { /* No memory */
    1229           0 :             gmp_addr_vect_clean(addr_vect);
    1230           0 :             return -1;
    1231             :         }
    1232             : 
    1233             :         /* Got the entry.  Lock it. */
    1234             : 
    1235           0 :         gmp_lock_adcat_entry(addr_vect->av_catalog, ordinal);
    1236             : 
    1237             :         /* Set the bit in the vector. */
    1238             : 
    1239           0 :         set_result = bv_set_bit(&addr_vect->av_vector, ordinal);
    1240           0 :         gmpx_assert(set_result != 1);   /* Better not have been set! */
    1241           0 :         if (set_result < 0) {
    1242           0 :             gmp_unlock_adcat_entry(addr_vect->av_catalog, ordinal);
    1243           0 :             gmp_addr_vect_clean(addr_vect);
    1244           0 :             return -1;                  /* Out of memory */
    1245             :         }
    1246             :     }
    1247             : 
    1248           0 :     return 0;
    1249             : }
    1250             : 
    1251             : 
    1252             : /*
    1253             :  * gmp_addr_list_clean
    1254             :  *
    1255             :  * Flush an address list and then free the patricia tree root.
    1256             :  *
    1257             :  * The address list structure itself is left intact but empty.
    1258             :  *
    1259             :  * Calls back to free each entry.
    1260             :  */
    1261             : void
    1262         405 : gmp_addr_list_clean (gmp_addr_list *addr_list)
    1263             : {
    1264             :     /* Flush the addresses. */
    1265             : 
    1266         405 :     gmp_flush_addr_list(addr_list);
    1267             : 
    1268             :     /* Clean the bit vector. */
    1269             : 
    1270         405 :     bv_clean(&addr_list->addr_vect.av_vector);
    1271             : 
    1272             :     /* Free the patricia tree root. */
    1273             : 
    1274         405 :     if (addr_list->addr_list_root) {
    1275         109 :         gmpx_assert(gmpx_patricia_lookup_least(addr_list->addr_list_root) ==
    1276             :                     NULL);
    1277         109 :         gmpx_patroot_destroy(addr_list->addr_list_root);
    1278         109 :         addr_list->addr_list_root = NULL;
    1279             :     }
    1280         405 : }
    1281             : 
    1282             : 
    1283             : /*
    1284             :  * gmp_addr_vect_inter
    1285             :  *
    1286             :  * Form an intersection of two address vectors, storing the result in
    1287             :  * the third vector.  Typically, the caller will supply a callback and
    1288             :  * context, and most of the real work will be done there.
    1289             :  *
    1290             :  * If a callback is provided, it will be called for each bit set or
    1291             :  * changed in the intersection of the two vectors according to cb_opt.
    1292             :  * 
    1293             :  * The destination may be NULL, or may be one of the two parameters.
    1294             :  *
    1295             :  * Returns 0 if all OK, or -1 if out of memory.
    1296             :  */
    1297          59 : int gmp_addr_vect_inter (gmp_addr_vect *src1, gmp_addr_vect *src2,
    1298             :                          gmp_addr_vect *dest, bv_callback callback,
    1299             :                          void *context, bv_callback_option cb_opt)
    1300             : {
    1301          59 :     return bv_and_vectors(gmp_addr_vector(src1), gmp_addr_vector(src2),
    1302             :                           gmp_addr_vector(dest), callback, context, cb_opt);
    1303             : }
    1304             : 
    1305             : 
    1306             : /*
    1307             :  * gmp_addr_vect_union
    1308             :  *
    1309             :  * Form a union of two address vectors, storing the result in the
    1310             :  * third vector.  Typically, the caller will supply a callback and
    1311             :  * context, and most of the real work will be done there.
    1312             :  *
    1313             :  * If a callback is provided, it will be called for each bit set or
    1314             :  * changed in the union of the two vectors according to cb_opt.
    1315             :  * 
    1316             :  * The destination may be NULL, or may be one of the two parameters.
    1317             :  *
    1318             :  * Returns 0 if all OK, or -1 if out of memory.
    1319             :  */
    1320           0 : int gmp_addr_vect_union (gmp_addr_vect *src1, gmp_addr_vect *src2,
    1321             :                          gmp_addr_vect *dest, bv_callback callback,
    1322             :                          void *context, bv_callback_option cb_opt)
    1323             : {
    1324           0 :     return bv_or_vectors(gmp_addr_vector(src1), gmp_addr_vector(src2),
    1325             :                          gmp_addr_vector(dest), callback, context, cb_opt);
    1326             : }
    1327             : 
    1328             : 
    1329             : /*
    1330             :  * gmp_addr_vect_minus
    1331             :  *
    1332             :  * Clear all bits set in the second vector from those set in the first
    1333             :  * storing the result in the third vector.  Typically, the caller will
    1334             :  * supply a callback and context, and most of the real work will be
    1335             :  * done there.
    1336             :  *
    1337             :  * If a callback is provided, it will be called for each bit set or
    1338             :  * changed in the result according to cb_opt.
    1339             :  *
    1340             :  * The destination may be NULL or may be one of the two parameters.
    1341             :  *
    1342             :  * Returns 0 if all OK, or -1 if out of memory.
    1343             :  */
    1344         152 : int gmp_addr_vect_minus (gmp_addr_vect *src1, gmp_addr_vect *src2,
    1345             :                          gmp_addr_vect *dest, bv_callback callback,
    1346             :                          void *context, bv_callback_option cb_opt)
    1347             : {
    1348         152 :     return bv_clear_vectors(gmp_addr_vector(src1), gmp_addr_vector(src2),
    1349             :                             gmp_addr_vector(dest), callback, context, cb_opt);
    1350             : }
    1351             : 
    1352             : 
    1353             : /*
    1354             :  * gmp_addr_vect_compare
    1355             :  *
    1356             :  * Compare all bits in the two vectors.  A callback will be made for
    1357             :  * every bit that is different between the two.
    1358             :  *
    1359             :  * The destination may be NULL or may be one of the two parameters.
    1360             :  *
    1361             :  * Returns 0 if all OK, or -1 if out of memory.
    1362             :  */
    1363           0 : int gmp_addr_vect_compare (gmp_addr_vect *src1, gmp_addr_vect *src2,
    1364             :                            bv_callback callback, void *context)
    1365             : {
    1366           0 :     return bv_xor_vectors(gmp_addr_vector(src1), gmp_addr_vector(src2),
    1367             :                           NULL, callback, context, BV_CALL_SET);
    1368             : }
    1369             : 
    1370             : 
    1371             : /*
    1372             :  * gmp_addr_vect_walk
    1373             :  *
    1374             :  * Walk all bits set in the vector, calling the callback for each set
    1375             :  * bit.
    1376             : 
    1377             :  * Returns 0 if all OK, or -1 if out of memory.
    1378             :  */
    1379         144 : int gmp_addr_vect_walk (gmp_addr_vect *src, bv_callback callback,
    1380             :                         void *context)
    1381             : {
    1382         144 :     gmpx_assert(src);
    1383         144 :     return bv_walk_vector(&src->av_vector, callback, context);
    1384             : }
    1385             : 
    1386             : 
    1387             : /*
    1388             :  * gmp_addrlist_init
    1389             :  *
    1390             :  * Initialize address list management.
    1391             :  */
    1392             : static void
    1393         125 : gmp_addrlist_init (void)
    1394             : {
    1395             :     /* Set up memory blocks. */
    1396             : 
    1397         125 :     gmp_addr_list_entry_tag =
    1398         125 :         gmpx_malloc_block_create(sizeof(gmp_addr_list_entry),
    1399             :                                  "GMP generic address list entry");
    1400         125 :     gmp_addr_list_tag =
    1401         125 :         gmpx_malloc_block_create(sizeof(gmp_addr_list),
    1402             :                                  "GMP address list");
    1403         125 :     gmp_adcat_entry_tag =
    1404         125 :         gmpx_malloc_block_create(sizeof(gmp_addr_cat_entry),
    1405             :                                  "GMP address catalog entry");
    1406         125 :     gmp_addr_thread_tag =
    1407         125 :         gmpx_malloc_block_create(sizeof(gmp_addr_thread),
    1408             :                                  "GMP address thread");
    1409         125 :     gmp_addr_thread_entry_tag =
    1410         125 :         gmpx_malloc_block_create(sizeof(gmp_addr_thread_entry),
    1411             :                                  "GMP address thread entry");
    1412         125 : }
    1413             : 
    1414             : 
    1415             : /*
    1416             :  * gmp_common_init
    1417             :  *
    1418             :  * Initialize common GMP code.
    1419             :  *
    1420             :  * If both host and router support are compiled in, this routine will be
    1421             :  * called twice, so it exits silently after the first call.
    1422             :  */
    1423             : void
    1424         125 : gmp_common_init (void)
    1425             : {
    1426             :     /* Bail if we've already been called. */
    1427             : 
    1428         125 :     if (ga_initialized)
    1429           0 :         return;
    1430         125 :     ga_initialized = TRUE;
    1431             : 
    1432             :     /* Initialize address list support. */
    1433             : 
    1434         125 :     gmp_addrlist_init();
    1435             : 
    1436             :     /* Initialize generic packet support. */
    1437             : 
    1438         125 :     gmpp_init();
    1439             : }

Generated by: LCOV version 1.14