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 : }
|