LCOV - code coverage report
Current view: top level - vnsw/agent/services/multicast/grpmgmt - gmp_router.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 98 402 24.4 %
Date: 2026-08-03 02:19:58 Functions: 12 42 28.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $Id: gmp_router.c 514187 2012-05-06 12:25:25Z ib-builder $
       2             :  *
       3             :  * gmp_router.c - IGMP/MLD Router-Side Support
       4             :  *
       5             :  * Dave Katz, March 2008
       6             :  *
       7             :  * Copyright (c) 2008, Juniper Networks, Inc.
       8             :  * All rights reserved.
       9             :  *
      10             :  * This module defines the top-level routines for the router-side support
      11             :  * for GMP.
      12             :  */
      13             : #include "gmpx_basic_types.h"
      14             : #include "gmp.h"
      15             : #include "gmpx_environment.h"
      16             : #include "gmp_externs.h"
      17             : #include "gmp_private.h"
      18             : #include "gmp_router.h"
      19             : #include "gmpr_private.h"
      20             : #include "gmp_trace.h"
      21             : #include "gmpr_trace.h"
      22             : 
      23             : /*
      24             :  * Global storage.  There should be very little here.
      25             : */
      26             : gmpx_block_tag gmpr_instance_tag;
      27             : gmpx_block_tag gmpr_client_tag;
      28             : gmpx_block_tag gmpr_intf_tag;
      29             : gmpx_block_tag gmpr_host_tag;
      30             : gmpx_block_tag gmpr_host_group_tag;
      31             : gmpx_block_tag gmpr_host_group_addr_tag;
      32             : gmpx_block_tag gmpr_group_tag;
      33             : gmpx_block_tag gmpr_ogroup_tag;
      34             : gmpx_block_tag gmpr_group_addr_entry_tag;
      35             : gmpx_block_tag gmpr_ogroup_addr_entry_tag;
      36             : gmpx_block_tag gmpr_notification_tag;
      37             : gmpx_block_tag gmpr_host_notification_tag;
      38             : gmpx_block_tag gmpr_global_group_tag;
      39             : gmpx_block_tag gmpr_intf_list_tag;
      40             : gmpx_block_tag gmpr_intf_group_tag;
      41             : gmpx_block_tag gmpr_intf_host_tag;
      42             : 
      43             : static boolean gr_initialized;          /* TRUE if we've initialized */
      44             : 
      45             : 
      46             : /*
      47             :  * gmpr_init
      48             :  *
      49             :  * Initialize GMP Router code
      50             :  *
      51             :  * Called when the first instance is created.
      52             :  *
      53             :  * Returns 0 if all OK, or -1 if out of memory.
      54             :  */
      55             : static int
      56         125 : gmpr_init (void)
      57             : {
      58             :     gmp_proto proto;
      59             : 
      60             :     /* Initialize the interface tree. */
      61             : 
      62         375 :     for (proto = 0; proto < GMP_NUM_PROTOS; proto++) {
      63         250 :         gmpr_global_intf_tree[proto] =
      64         250 :             gmpx_patroot_init(sizeof(gmpx_intf_id),
      65             :                               GMPX_PATRICIA_OFFSET(gmpr_intf,
      66             :                                                    rintf_global_patnode,
      67             :                                                    rintf_id));
      68         250 :         if (!gmpr_global_intf_tree[proto])
      69           0 :             return -1;                  /* Out of memory. */
      70             :     }
      71             : 
      72         125 :     gr_initialized = TRUE;
      73             : 
      74             :     /* Do common initialization. */
      75             : 
      76         125 :     gmp_common_init();
      77             : 
      78             :     /* Create the instance thread. */
      79             : 
      80         125 :     thread_new_circular_thread(&gmpr_global_instance_thread);
      81             : 
      82             :     /* Create memory blocks. */
      83             : 
      84         125 :     gmpr_instance_tag = gmpx_malloc_block_create(sizeof(gmpr_instance),
      85             :                                                  "GMP router instance");
      86         125 :     gmpr_client_tag = gmpx_malloc_block_create(sizeof(gmpr_client),
      87             :                                                "GMP router client");
      88         125 :     gmpr_intf_tag = gmpx_malloc_block_create(sizeof(gmpr_intf),
      89             :                                              "GMP router intf");
      90         125 :     gmpr_host_tag = gmpx_malloc_block_create(sizeof(gmpr_host),
      91             :                                              "GMP router host");
      92         125 :     gmpr_host_group_tag = gmpx_malloc_block_create(sizeof(gmpr_host_group),
      93             :                                                    "GMP router host group");
      94         125 :     gmpr_host_group_addr_tag =
      95         125 :         gmpx_malloc_block_create(sizeof(gmpr_host_group_addr),
      96             :                                  "GMP router host group address");
      97         125 :     gmpr_group_tag = gmpx_malloc_block_create(sizeof(gmpr_group),
      98             :                                               "GMP router group");
      99         125 :     gmpr_ogroup_tag = gmpx_malloc_block_create(sizeof(gmpr_ogroup),
     100             :                                                "GMP router output group");
     101         125 :     gmpr_group_addr_entry_tag =
     102         125 :         gmpx_malloc_block_create(sizeof(gmpr_group_addr_entry),
     103             :                                  "GMP router group address entry");
     104         125 :     gmpr_ogroup_addr_entry_tag =
     105         125 :         gmpx_malloc_block_create(sizeof(gmpr_ogroup_addr_entry),
     106             :                                  "GMP router output group address entry");
     107         125 :     gmpr_notification_tag =
     108         125 :         gmpx_malloc_block_create(sizeof(gmpr_client_notification),
     109             :                                  "GMP router notification");
     110         125 :     gmpr_host_notification_tag =
     111         125 :         gmpx_malloc_block_create(sizeof(gmpr_client_host_notification),
     112             :                                  "GMP router host notification");
     113         125 :     gmpr_global_group_tag =
     114         125 :         gmpx_malloc_block_create(sizeof(gmpr_global_group),
     115             :                                  "GMP router global group");
     116         125 :     gmpr_intf_list_tag =
     117         125 :         gmpx_malloc_block_create(sizeof(gmpr_client_intf_list),
     118             :                                  "GMP router interface list");
     119         125 :     gmpr_intf_group_tag =
     120         125 :         gmpx_malloc_block_create(sizeof(gmpr_intf_group_entry),
     121             :                                  "GMP router interface group");
     122         125 :     gmpr_intf_host_tag =
     123         125 :         gmpx_malloc_block_create(sizeof(gmpr_intf_host_entry),
     124             :                                  "GMP router interface host");
     125         125 :     return 0;
     126             : }
     127             : 
     128             : 
     129             : /*
     130             :  * gmpr_create_instance
     131             :  *
     132             :  * Create a router-side GMP instance.
     133             :  *
     134             :  * Returns an instance ID (really a pointer), or zero if out of memory.
     135             :  */
     136             : gmp_instance_id
     137         125 : gmpr_create_instance (gmp_proto proto, void *inst_context,
     138             :                       gmpr_instance_context *cb_context)
     139             : {
     140             :     gmpr_instance *instance;
     141             : 
     142             :     /* If we're not initialized yet, do it now. */
     143             : 
     144         125 :     if (!gr_initialized) {
     145         125 :         if (gmpr_init() < 0)
     146           0 :             return NULL;                /* Out of memory. */
     147             :     }
     148             : 
     149         125 :     gr_initialized = TRUE;
     150             : 
     151             :     /* Create the instance. */
     152             : 
     153         125 :     instance = gmpr_instance_create(proto, inst_context);
     154             : 
     155             :     /* Copy over the context block. */
     156             : 
     157         125 :     if (cb_context) {
     158         125 :         memmove(&instance->rinst_cb_context, cb_context,
     159             :             sizeof(gmpr_instance_context));
     160             :     }
     161             : 
     162         125 :     return instance;
     163             : }
     164             : 
     165             : 
     166             : /*
     167             :  * gmpr_destroy_instance
     168             :  *
     169             :  * Destroy an instance and all things associated with it.
     170             :  */
     171             : void
     172         125 : gmpr_destroy_instance (gmp_instance_id instance_id)
     173             : {
     174             :     gmpr_instance *instance;
     175             : 
     176             :     /* Get the instance block. */
     177             : 
     178         125 :     instance = gmpr_get_instance(instance_id);
     179             : 
     180             :     /* Destroy it. */
     181             : 
     182         125 :     gmpr_instance_destroy(instance);
     183         125 : }
     184             : 
     185             : 
     186             : /*
     187             :  * gmpr_register
     188             :  *
     189             :  * Register a router-side client with GMP.
     190             :  *
     191             :  * Returns a client ID for the client to identify itself with, or 0 if
     192             :  * we're maxed out on clients.
     193             :  */
     194             : gmp_client_id
     195         125 : gmpr_register (gmp_instance_id instance_id, void *client_context,
     196             :                gmpr_client_context *cb_context)
     197             : {
     198             :     gmpr_client *client;
     199             :     gmpr_instance *instance;
     200             : 
     201             :     /* Get the instance. */
     202             : 
     203         125 :     instance = gmpr_get_instance(instance_id);
     204             : 
     205             :     /* Create a client. */
     206             : 
     207         125 :     client = gmpr_create_client(instance);
     208         125 :     client->rclient_context = client_context;
     209             : 
     210             :     /* Copy over the context block. */
     211             : 
     212         125 :     memmove(&client->rclient_cb_context, cb_context,
     213             :         sizeof(gmpr_client_context));
     214             : 
     215             :     /* If the client supplied a host callback, turn on host tracking. */
     216             : 
     217         125 :     if (cb_context->rctx_host_notif_cb)
     218         125 :         instance->rinst_host_tracking = TRUE;
     219             : 
     220         125 :     return client;
     221             : }
     222             : 
     223             : 
     224             : /*
     225             :  * gmpr_detach
     226             :  *
     227             :  * A client is going away.  Clean up.
     228             :  */
     229             : void
     230         125 : gmpr_detach (gmp_client_id client_id)
     231             : {
     232             :     gmpr_client *client;
     233             : 
     234             :     /* Get the client. */
     235             : 
     236         125 :     client = gmpr_get_client(client_id);
     237             : 
     238             :     /* Get rid of it. */
     239             : 
     240         125 :     gmpr_destroy_client(client);
     241         125 : }
     242             : 
     243             : 
     244             : /*
     245             :  * gmpr_refresh
     246             :  *
     247             :  * Refresh all group state.  This enqueues all state for the client.
     248             :  *
     249             :  * If flush is TRUE, we first flush out all source notifications, which
     250             :  * has the effect of getting rid of any pending source deletions.
     251             :  */
     252             : void
     253           0 : gmpr_refresh (gmp_client_id client_id, boolean flush)
     254             : {
     255             :     gmpr_client *client;
     256             :     gmpr_instance *instance;
     257             : 
     258             :     /* Get the client. */
     259             : 
     260           0 :     client = gmpr_get_client(client_id);
     261           0 :     instance = client->rclient_instance;
     262             : 
     263             :     /* Trace it. */
     264             : 
     265           0 :     gmpr_trace(instance, GMPR_TRACE_CLIENT_NOTIFY,
     266             :                "Client %u refresh", client->rclient_ordinal);
     267             : 
     268             :     /* Enqueue everything. */
     269             : 
     270           0 :     gmpr_client_enqueue_all_groups(client, flush);
     271             : 
     272             :     /* Enqueue the end-of-refresh marker. */
     273             : 
     274           0 :     gmpr_enqueue_refresh_end(client);
     275             : 
     276             :     /* Kick the clients. */
     277             : 
     278           0 :     gmpr_alert_clients(client->rclient_instance);
     279           0 : }
     280             : 
     281             : 
     282             : /*
     283             :  * gmpr_refresh_intf
     284             :  *
     285             :  * Refresh all group state for a single interface.  This enqueues all
     286             :  * state for the client.
     287             :  *
     288             :  * If flush is TRUE, we first flush out any pending source notifications,
     289             :  * which has the effect of getting rid of any pending source deletions.
     290             :  */
     291             : void
     292           0 : gmpr_refresh_intf (gmp_client_id client_id, gmpx_intf_id intf_id,
     293             :                    boolean flush)
     294             : {
     295             :     gmpr_intf *intf;
     296             :     gmpr_client *client;
     297             : 
     298             :     /* Get the client. */
     299             : 
     300           0 :     client = gmpr_get_client(client_id);
     301             : 
     302             :     /* Look up the interface. */
     303             : 
     304           0 :     intf = gmpr_intf_lookup(client->rclient_instance, intf_id);
     305           0 :     if (!intf)
     306           0 :         return;
     307             : 
     308             :     /* Enqueue everything. */
     309             : 
     310           0 :     gmpr_client_enqueue_all_intf_groups(client, intf, flush);
     311           0 :     gmpr_alert_clients(client->rclient_instance);
     312             : }
     313             : 
     314             : 
     315             : /*
     316             :  * gmpr_refresh_host_state
     317             :  *
     318             :  * Refresh all host group state.  This enqueues all state for the client.
     319             :  */
     320             : void
     321           0 : gmpr_refresh_host_state (gmp_client_id client_id)
     322             : {
     323             :     gmpr_client *client;
     324             : 
     325             :     /* Get the client. */
     326             : 
     327           0 :     client = gmpr_get_client(client_id);
     328             : 
     329             :     /* Enqueue everything. */
     330             : 
     331           0 :     gmpr_client_enqueue_all_host_groups(client);
     332           0 :     gmpr_alert_host_clients(client->rclient_instance);
     333           0 : }
     334             : 
     335             : 
     336             : /*
     337             :  * gmpr_set_intf_params
     338             :  *
     339             :  * Set parameters for an interface.
     340             :  *
     341             :  * Returns 0 if OK, -1 if out of memory, or 1 if the interface hasn't
     342             :  * been attached.
     343             :  */
     344             : int
     345        1708 : gmpr_set_intf_params (gmp_instance_id instance_id, gmpx_intf_id intf_id,
     346             :                       gmpr_intf_params *params)
     347             : {
     348             :     gmpr_instance *instance;
     349             : 
     350             :     /* Get the instance. */
     351             : 
     352        1708 :     instance = gmpr_get_instance(instance_id);
     353             : 
     354             :     /* Go do the work. */
     355             : 
     356        1708 :     return gmpr_intf_set_params(instance, intf_id, params);
     357             : }
     358             : 
     359             : void 
     360           0 : gmpr_chk_grp_limit (gmp_instance_id instance_id, 
     361             :                     gmpx_intf_id intf_id)
     362             : {
     363             :    gmpr_intf *intf;
     364             :    // gmpr_instance *instance;
     365             :  
     366             :    // instance = gmpr_get_instance(instance_id);
     367           0 :    intf = gmpr_intf_lookup(instance_id, intf_id);
     368           0 :    gmpr_check_grp_limit(intf, FALSE);
     369           0 : }
     370             : 
     371             : /*
     372             :  * gmpr_immediate_leave_intf_count
     373             :  */
     374             : static int
     375           0 : gmpr_immediate_leave_intf_count (gmpr_instance *instance)
     376             : {
     377           0 :     int intf_count = 0;
     378           0 :     gmpr_intf *intf = NULL;
     379             :     
     380           0 :     intf = gmpr_next_instance_intf(instance, NULL);
     381           0 :     while (intf) {
     382           0 :         if (intf->rintf_fast_leaves) {
     383           0 :             intf_count++;
     384             :         }
     385           0 :         intf = gmpr_next_instance_intf(instance, intf);
     386             :     }
     387           0 :     return intf_count;
     388             : }
     389             : 
     390             : /*
     391             :  * gmpr_intf_disable_host_tracking
     392             :  *
     393             :  * Disable host tracking for an interface
     394             :  *
     395             :  * Returns 0 if OK, or 1 if the interface hasn't
     396             :  * been attached.
     397             :  */
     398             : int
     399           0 : gmpr_disable_host_tracking (gmp_instance_id instance_id,
     400             :                             gmpx_intf_id intf_id)
     401             : {
     402             :     gmpr_instance *instance;
     403             :     gmpr_intf *intf;
     404             : 
     405             :     /* Get the instance. */
     406           0 :     instance = gmpr_get_instance(instance_id);
     407           0 :     intf = gmpr_intf_lookup(instance, intf_id);
     408             :     
     409             :     /* If interface doesn't exist. */
     410           0 :     if (!intf)
     411           0 :         return 1;
     412             : 
     413             :     /* Blast all of the hosts on the interface. */
     414           0 :     gmpr_destroy_intf_hosts(intf);
     415             :     
     416             :     /* Disable host tracking if this is the last interface */
     417           0 :     if (gmpr_immediate_leave_intf_count(instance) == 0)
     418           0 :         instance->rinst_host_tracking = FALSE;
     419             :     
     420           0 :     return 0;
     421             : }
     422             : 
     423             : /*
     424             :  * gmpr_attach_intf
     425             :  *
     426             :  * Bind to an interface, in preparation for later interest.
     427             :  *
     428             :  * Returns 0 if OK, -1 if out of memory, or 1 if the interface already
     429             :  * is bound.
     430             :  */
     431             : int
     432        1708 : gmpr_attach_intf (gmp_instance_id instance_id, gmpx_intf_id intf_id)
     433             : {
     434             :     gmpr_instance *instance;
     435             : 
     436             :     /* Go do the work. */
     437             : 
     438        1708 :     instance = gmpr_get_instance(instance_id);
     439        1708 :     return gmpr_attach_intf_internal(instance, intf_id);
     440             : }
     441             : 
     442             : 
     443             : /*
     444             :  * gmpr_detach_intf
     445             :  *
     446             :  * Unbind an interface.  This flushes all previous listen requests
     447             :  * on the interface.
     448             :  *
     449             :  * Returns 0 if all OK, or 1 if the interface doesn't exist.
     450             :  */
     451             : int
     452        1708 : gmpr_detach_intf (gmp_instance_id instance_id, gmpx_intf_id intf_id)
     453             : {
     454             :     gmpr_instance *instance;
     455             : 
     456             :     /* Go do the work. */
     457             : 
     458        1708 :     instance = gmpr_get_instance(instance_id);
     459        1708 :     return gmpr_detach_intf_internal(instance, intf_id);
     460             : }
     461             : 
     462             : 
     463             : /*
     464             :  * gmpr_get_notification
     465             :  *
     466             :  * Get the next notification for this client.
     467             :  *
     468             :  * Returns a pointer to the notification block, or NULL if no more
     469             :  * notifications.
     470             :  *
     471             :  * If last_notification isn't NULL, the client is returning a previous
     472             :  * notification block, which we can re-use if we like.
     473             :  */
     474             : gmpr_client_notification *
     475         272 : gmpr_get_notification (gmp_client_id client_id,
     476             :                        gmpr_client_notification *last_notification)
     477             : {
     478             :     gmpr_client *client;
     479             : 
     480             :      /* Get the client. */
     481             : 
     482         272 :     client = gmpr_get_client(client_id);
     483             : 
     484             :     /* Do the work. */
     485             : 
     486         272 :     return gmpr_client_get_notification(client, last_notification);
     487             : }
     488             : 
     489             : 
     490             : /*
     491             :  * gmpr_get_host_notification
     492             :  *
     493             :  * Get the next host notification for this client.
     494             :  *
     495             :  * Returns a pointer to the notification block, or NULL if no more
     496             :  * notifications.
     497             :  *
     498             :  * If last_notification isn't NULL, the client is returning a previous
     499             :  * notification block, which we can re-use if we like.
     500             :  */
     501             : gmpr_client_host_notification *
     502         350 : gmpr_get_host_notification (gmp_client_id client_id,
     503             :                             gmpr_client_host_notification *last_notification)
     504             : {
     505             :     gmpr_client *client;
     506             : 
     507             :      /* Get the client. */
     508             : 
     509         350 :     client = gmpr_get_client(client_id);
     510             : 
     511             :     /* Do the work. */
     512             : 
     513         350 :     return gmpr_client_get_host_notification(client, last_notification);
     514             : }
     515             : 
     516             : 
     517             : /*
     518             :  * gmpr_return_notification
     519             :  *
     520             :  * Free up a previously-delivered notification.
     521             :  */
     522             : void
     523           0 : gmpr_return_notification (gmpr_client_notification *notification)
     524             : {
     525             : 
     526             :     /* Do the work. */
     527             : 
     528           0 :     gmpr_free_notification(notification);
     529           0 : }
     530             : 
     531             : 
     532             : /*
     533             :  * gmpr_return_host_notification
     534             :  * 
     535             :  * Free up a previously-delivered host notification.
     536             :  */
     537             : void
     538           0 : gmpr_return_host_notification (gmpr_client_host_notification *host_notif)
     539             : {
     540             : 
     541             :     /* No-brainer. */
     542             : 
     543           0 :     gmpr_client_free_host_notification(host_notif);
     544           0 : }
     545             : 
     546             : 
     547             : /*
     548             :  * gmpr_notification_last_sg
     549             :  *
     550             :  * Return the value of notif_last_sg given a notification.
     551             :  */
     552             : boolean
     553           0 : gmpr_notification_last_sg (gmpr_client_notification *notification)
     554             : {
     555           0 :     if (notification && notification->notif_last_sg) {
     556           0 :         return TRUE;
     557             :     } else {
     558           0 :         return FALSE;
     559             :     }
     560             : }
     561             : 
     562             : /*
     563             :  * gmpr_add_intf_list_entry
     564             :  *
     565             :  * Add an interface index to an interface list.
     566             :  *
     567             :  * May allocate further entries as necessary.
     568             :  *
     569             :  * Returns a pointer to the current list entry, or NULL if out of memory.
     570             :  */
     571             : static gmpr_client_intf_list *
     572           0 : gmpr_add_intf_list_entry(gmpr_client_intf_list *cur_intf_list,
     573             :                          gmpx_intf_id intf_id)
     574             : {
     575             :     gmpr_client_intf_list *next_list;
     576             : 
     577             :     /* See if the entry will fit in the current entry. */
     578             : 
     579           0 :     if (cur_intf_list->gci_intf_count >= GMPR_INTF_LIST_SIZE) {
     580             : 
     581             :         /* Entry is full.  Allocate a new one and link 'em. */
     582             : 
     583           0 :         next_list = gmpx_malloc_block(gmpr_intf_list_tag);
     584           0 :         if (!next_list)
     585           0 :             return NULL;                /* Out of memory */
     586             : 
     587           0 :         cur_intf_list->gci_next = next_list;
     588           0 :         cur_intf_list = next_list;
     589             :     }
     590             : 
     591             :     /* Add the entry to the array. */
     592             : 
     593           0 :     cur_intf_list->gci_intfs[cur_intf_list->gci_intf_count++] = intf_id;
     594             : 
     595           0 :     return cur_intf_list;
     596             : }
     597             : 
     598             : 
     599             : /*
     600             :  * gmpr_get_intf_list
     601             :  *
     602             :  * Get the list of interfaces corresponding to a (S,G) or (*,G).
     603             :  *
     604             :  * If a (*,G) is specified (by virtue of a NULL source address pointer)
     605             :  * we will return an interface only if its state is Exclude{}.  If an (S,G)
     606             :  * is specified, we return an interface if either the source is included in
     607             :  * an Include list, or is not listed in an Exclude list.
     608             :  *
     609             :  * If the search type is LOOSE, we will match a (*,G) for any group in
     610             :  * Exclude mode, whether or not there are any sources.
     611             :  *
     612             :  * Returns a pointer to an interface list, or NULL if out of memory.
     613             :  */
     614             : gmpr_client_intf_list *
     615           0 : gmpr_get_intf_list (gmp_instance_id instance_id, uint8_t *group_addr,
     616             :                     uint8_t *source_addr, gmpr_intf_list_match match_type)
     617             : {
     618             :     gmpr_instance *instance;
     619             :     gmpr_global_group *global_group;
     620             :     gmpr_client_intf_list *intf_list_head, *cur_intf_list;
     621             :     task_thread *thread_ptr;
     622             :     gmpr_ogroup *group;
     623             :     gmp_addr_cat_entry *cat_entry;
     624             : 
     625             :     /* Allocate the block we're returning. */
     626             : 
     627           0 :     intf_list_head = gmpx_malloc_block(gmpr_intf_list_tag);
     628           0 :     if (!intf_list_head)
     629           0 :         return NULL;                    /* Out of memory */
     630           0 :     cur_intf_list = intf_list_head;
     631             : 
     632             :     /* Get the instance. */
     633             : 
     634           0 :     instance = gmpr_get_instance(instance_id);
     635             : 
     636             :     /* Look up the global group entry. */
     637             : 
     638           0 :     global_group = gmpr_lookup_global_group(instance, group_addr);
     639             : 
     640             :     /* Bail if we don't know of the group. */
     641             : 
     642           0 :     if (!global_group)
     643           0 :         return intf_list_head;
     644             : 
     645             :     /*
     646             :      * Look up the address catalog entry for the source address.  It may
     647             :      * or may not be there.
     648             :      */
     649           0 :     cat_entry = NULL;
     650           0 :     if (source_addr) {
     651           0 :         cat_entry = gmp_lookup_addr_cat_entry(&instance->rinst_addr_cat,
     652             :                                               source_addr);
     653             :     }
     654             : 
     655             :     /* Walk the group thread. */
     656             : 
     657           0 :     thread_ptr = NULL;
     658             :     while (TRUE) {
     659           0 :         thread_ptr = thread_circular_thread_next(
     660             :                          &global_group->global_group_head, thread_ptr);
     661           0 :         group = gmpr_global_thread_to_group(thread_ptr);
     662           0 :         if (!group)
     663           0 :             break;
     664             : 
     665             :         /*
     666             :          * Found a group.  See if there was no source address
     667             :          * specified (we're looking for a (*,G) entry).
     668             :          */
     669           0 :         if (!source_addr) {
     670             : 
     671             :             /*
     672             :              * No source address--we're looking for (*,G).  Bail if the
     673             :              * group isn't in Exclude mode.
     674             :              */
     675           0 :             if ((group->rogroup_filter_mode != GMP_FILTER_MODE_EXCLUDE)) {
     676           0 :                 continue;
     677             :             }
     678             : 
     679             :             /*
     680             :              * Exclude mode.  Bail if there are sources present,
     681             :              * unless we're doing a loose search.
     682             :              */
     683           0 :             if (!gmp_addr_list_empty(&group->rogroup_excl_src_addr) &&
     684             :                 (match_type == INTF_LIST_STRICT)) {
     685           0 :                 continue;
     686             :             }
     687             : 
     688             :         } else {
     689             : 
     690             :             /* (S,G) specified.  Skip if the source isn't active. */
     691             : 
     692           0 :             if (!cat_entry ||
     693           0 :                 !gmpr_source_ord_is_active(group, cat_entry->adcat_ent_ord)) {
     694           0 :                 continue;
     695             :             }
     696             :         }
     697             : 
     698             :         /* Looks like we should report the interface.  Add it to the list. */
     699             : 
     700             :         cur_intf_list =
     701           0 :             gmpr_add_intf_list_entry(cur_intf_list,
     702           0 :                                      group->rogroup_intf->rintf_id);
     703             :     }
     704             : 
     705           0 :     return intf_list_head;
     706             : }
     707             : 
     708             : 
     709             : /*
     710             :  * gmpr_free_intf_list
     711             :  *
     712             :  * Free a previously-allocated interface list.
     713             :  */
     714             : void
     715           0 : gmpr_free_intf_list (gmpr_client_intf_list *intf_list)
     716             : {
     717             :     gmpr_client_intf_list *next;
     718             : 
     719             :     /* Simple linked list traversal. */
     720             : 
     721           0 :     while (intf_list) {
     722           0 :         next = intf_list->gci_next;
     723           0 :         gmpx_free_block(gmpr_intf_list_tag, intf_list);
     724           0 :         intf_list = next;
     725             :     }
     726           0 : }
     727             : 
     728             : 
     729             : /*
     730             :  * gmpr_is_forwarding_channel
     731             :  *
     732             :  * Returns TRUE if GMP is recommending forwarding of the specified (S,G)
     733             :  * channel on the interface, or FALSE if not.  If the source pointer is
     734             :  * NULL, we test for (*,G).
     735             :  *
     736             :  * If "exact" is TRUE, we return TRUE only if the channel as specified is
     737             :  * to be forwarded.  If FALSE, we return TRUE if *any* (S,G) is being
     738             :  * forwarded when a (*,G) request is made.
     739             :  */
     740             : boolean
     741           0 : gmpr_is_forwarding_channel (gmp_instance_id instance_id, gmpx_intf_id intf_id,
     742             :                             const uint8_t *source_addr,
     743             :                             const uint8_t *group_addr, boolean exact)
     744             : {
     745             :     gmpr_instance *instance;
     746             :     gmpr_intf *intf;
     747             :     gmpr_ogroup *group;
     748             : 
     749             :     /* Get the instance and interface. */
     750             : 
     751           0 :     instance = gmpr_get_instance(instance_id);
     752           0 :     intf = gmpr_intf_lookup(instance, intf_id);
     753           0 :     if (!intf)
     754           0 :         return FALSE;
     755             : 
     756             :     /* Get the group. */
     757             : 
     758           0 :     group = gmpr_ogroup_lookup(intf, group_addr);
     759           0 :     if (!group)
     760           0 :         return FALSE;
     761             : 
     762             :     /* If the group is a (*,G) join, we match anything. */
     763             : 
     764           0 :     if (gmpr_group_forwards_all_sources(group))
     765           0 :         return TRUE;
     766             : 
     767             :     /*
     768             :      * If we're doing an inexact (*,G) match and any part of the group
     769             :      * is being forwarded, we have a match.
     770             :      */
     771           0 :     if (!exact && !source_addr && gmpr_ogroup_is_active(group))
     772           0 :         return TRUE;
     773             : 
     774             :     /* If we're doing a (*,G) test, we didn't match. */
     775             : 
     776           0 :     if (!source_addr)
     777           0 :         return FALSE;
     778             : 
     779             :     /* See if we're forwarding the specified source. */
     780             : 
     781           0 :     return gmpr_group_forwards_source(group, source_addr);
     782             : }
     783             : 
     784             : 
     785             : /*
     786             :  * gmpr_update_intf_state
     787             :  *
     788             :  * Update the interface state.  If the address is NULL, the interface
     789             :  * is going down.
     790             :  */
     791             : void
     792        3416 : gmpr_update_intf_state (gmp_instance_id instance_id, gmpx_intf_id intf_id,
     793             :                         const uint8_t *intf_addr)
     794             : {
     795             :     gmpr_instance *instance;
     796             :     gmpr_intf *intf;
     797             :     boolean was_up;
     798             : 
     799             :     /* Get the instance and interface. */
     800             : 
     801        3416 :     instance = gmpr_get_instance(instance_id);
     802        3416 :     intf = gmpr_intf_lookup(instance, intf_id);
     803        3416 :     if (!intf)
     804           0 :         return;
     805             : 
     806             :     /*
     807             :      * If the address is there, mark the interface up.  Store the new
     808             :      * address and make ourselves querier if the address has changed
     809             :      * or the interface has just come up.
     810             :      */
     811        3416 :     was_up = intf->rintf_up;
     812        3416 :     if (intf_addr) {
     813        1708 :         intf->rintf_up = TRUE;
     814             : 
     815        1708 :         if (!was_up || memcmp(intf_addr, intf->rintf_local_addr.gmp_addr,
     816           0 :             instance->rinst_addrlen)) {
     817             : 
     818             :             /* Make ourselves querier. */
     819             : 
     820        1708 :             memmove(intf->rintf_local_addr.gmp_addr, intf_addr, instance->rinst_addrlen);
     821        1708 :             gmpr_update_querier(intf, &intf->rintf_local_addr, TRUE);
     822             :         }
     823             : 
     824             :     } else {
     825             :         /* No address.  Mark the interface down and zap the querier address */
     826             : 
     827        1708 :         intf->rintf_up = FALSE;
     828        1708 :         intf->rintf_querier = FALSE;
     829        1708 :         memset(intf->rintf_local_addr.gmp_addr, 0, instance->rinst_addrlen);
     830             :     }
     831             : 
     832             :     /* If the up/down status changed, update any associated output groups. */
     833             : 
     834        3416 :     if (was_up != intf->rintf_up)
     835        3416 :         gmpr_update_intf_output_groups(intf);
     836             : 
     837             :     /*
     838             :      * If the interface went down, blast any input groups on the
     839             :      * interface, and note that we no longer have any transmissions
     840             :      * pending.
     841             :      */
     842             : 
     843        3416 :     if (was_up && !intf->rintf_up) {
     844        1708 :         gmpr_flush_intf_input_groups(intf);
     845        1708 :         intf->rintf_xmit_pending = FALSE;
     846             :     }
     847             : 
     848             :     /*
     849             :      * If the interface came up, kick the transmitter in case
     850             :      * something is waiting to go.  Also send out startup queries,
     851             :      * since the interface just came back up.
     852             :      */
     853        3416 :     if (!was_up && intf->rintf_up) {
     854        1708 :         gmpr_setup_initial_query_timer(intf);
     855        1708 :         gmpr_kick_xmit(intf);
     856             :     }
     857             : }
     858             : 
     859             : 
     860             : /*
     861             :  * Context structure for gmpr_build_group_cb
     862             :  */
     863             : typedef struct gmpr_build_group_cb_context_ {
     864             :     gmpr_instance *gbg_instance;        /* Instance pointer */
     865             :     gmpr_ogroup *gbg_ogroup;            /* Output group */
     866             :     gmpr_intf_group_entry *gbg_group_ent; /* Group entry */
     867             : } gmpr_build_group_cb_context;
     868             : 
     869             : 
     870             : /*
     871             :  * gmpr_build_group_cb
     872             :  *
     873             :  * Callback from vector walk to build a list of sources for a group.
     874             :  */
     875             : static boolean
     876           0 : gmpr_build_group_cb (void *context, bv_bitnum_t bitnum,
     877             :                      boolean new_val GMPX_UNUSED,
     878             :                      boolean old_val GMPX_UNUSED)
     879             : {
     880             :     gmpr_instance *instance;
     881             :     gmpr_build_group_cb_context *ctx;
     882             :     gmpr_intf_group_entry *group_entry;
     883             :     gmp_addr_cat_entry *cat_entry;
     884             :     gmpr_ogroup *group;
     885             : 
     886           0 :     ctx = context;
     887           0 :     instance = ctx->gbg_instance;
     888           0 :     group_entry = ctx->gbg_group_ent;
     889           0 :     group = ctx->gbg_ogroup;
     890             : 
     891             :     /* Look up the address catalog entry. */
     892             : 
     893           0 :     cat_entry = gmp_get_addr_cat_by_ordinal(&instance->rinst_addr_cat, bitnum);
     894           0 :     gmpx_assert(cat_entry);
     895             : 
     896             :     /* Bail if the source isn't active. */
     897             : 
     898           0 :     if (!gmpr_source_ord_is_active(group, bitnum))
     899           0 :         return FALSE;
     900             : 
     901             :     /* Stick the source address into the address thread. */
     902             : 
     903           0 :     gmp_enqueue_addr_thread_addr(group_entry->gig_sources,
     904           0 :                                  cat_entry->adcat_ent_addr.gmp_addr,
     905             :                                  instance->rinst_addrlen);
     906             : 
     907           0 :     return FALSE;
     908             : }
     909             : 
     910             : 
     911             : /*
     912             :  * gmpr_get_intf_groups
     913             :  *
     914             :  * Get a list of all groups and sources on an interface.  Returns a pointer
     915             :  * to a group entry, to which other group entries are linked.  Returns NULL
     916             :  * if there are no groups on the interface.
     917             :  *
     918             :  * The pointer should be returned via gmpr_destroy_intf_group() when the
     919             :  * caller is done.
     920             :  *
     921             :  * **** THIS IS NONSCALABLE AND HEINOUS AND SHOULD BE REMOVED AS SOON
     922             :  * **** AS PIM WORKS REASONABLY!!!!
     923             :  */
     924             : gmpr_intf_group_entry *
     925           0 : gmpr_get_intf_groups (gmp_instance_id instance_id, gmpx_intf_id intf_id)
     926             : {
     927             :     gmpr_instance *instance;
     928             :     gmpr_intf *intf;
     929             :     gmpr_ogroup *group;
     930             :     gmpr_intf_group_entry *group_list;
     931             :     gmpr_intf_group_entry *cur_group;
     932             :     gmp_addr_list *addr_list;
     933             :     gmpr_build_group_cb_context ctx;
     934             : 
     935             :     /* Get the instance and interface. */
     936             : 
     937           0 :     instance = gmpr_get_instance(instance_id);
     938           0 :     intf = gmpr_intf_lookup(instance, intf_id);
     939           0 :     if (!intf)
     940           0 :         return NULL;
     941             : 
     942             :     /* Walk all groups on the interface. */
     943             : 
     944           0 :     group_list = NULL;
     945           0 :     group = NULL;
     946             :     while (TRUE) {
     947             : 
     948             :         /* Get the next one.  Bail out if done. */
     949             : 
     950           0 :         group = gmpr_next_oif_group(intf, group);
     951           0 :         if (!group)
     952           0 :             break;
     953             : 
     954             :         /* Got a group.  Allocate an entry. */
     955             : 
     956           0 :         cur_group = gmpx_malloc_block(gmpr_intf_group_tag);
     957           0 :         if (!cur_group)
     958           0 :             break;                      /* Out of memory */
     959             : 
     960             :         /* Set the group address and filter mode. */
     961             : 
     962           0 :         memmove(cur_group->gig_group_addr.gmp_addr, group->rogroup_addr.gmp_addr,
     963           0 :             instance->rinst_addrlen);
     964           0 :         cur_group->gig_filter_mode = group->rogroup_filter_mode;
     965             : 
     966             :         /* If there are sources, copy them in as well. */
     967             : 
     968           0 :         addr_list = gmpr_ogroup_source_list(group);
     969           0 :         if (!gmp_addr_list_empty(addr_list)) {
     970             : 
     971             :             /* Got sources.  Create the address thread. */
     972             : 
     973           0 :             cur_group->gig_sources = gmp_alloc_addr_thread();
     974           0 :             ctx.gbg_instance = instance;
     975           0 :             ctx.gbg_group_ent = cur_group;
     976           0 :             ctx.gbg_ogroup = group;
     977           0 :             gmp_addr_vect_walk(&addr_list->addr_vect, gmpr_build_group_cb,
     978             :                                &ctx);
     979             :         }
     980             : 
     981             :         /* Link the new entry to the list. */
     982             : 
     983           0 :         if (group_list)
     984           0 :             cur_group->gig_next = group_list;
     985           0 :         group_list = cur_group;
     986             :     }
     987             : 
     988           0 :     return group_list;
     989             : }
     990             : 
     991             : 
     992             : /*
     993             :  * gmpr_get_host_groups
     994             :  *
     995             :  * Get a list of all groups and sources on an interface for the specified
     996             :  * host.  Returns a pointer to a group entry, to which other group entries
     997             :  * are linked.  Returns NULL if there are no groups on the interface.
     998             :  *
     999             :  * The pointer should be returned via gmpr_destroy_intf_group() when the
    1000             :  * caller is done.
    1001             :  *
    1002             :  * While the per-interface version of this code does not scale and is 
    1003             :  * considered to be heinous, a single host should not have too much join
    1004             :  * state, so this should be OK.
    1005             :  */
    1006             : gmpr_intf_group_entry *
    1007           0 : gmpr_get_host_groups (gmp_instance_id instance_id,
    1008             :                       gmpx_intf_id intf_id,
    1009             :                       const uint8_t *host_addr)
    1010             : {
    1011             :     gmpr_instance *instance;
    1012             :     gmpr_intf *intf;
    1013             :     gmpr_intf_group_entry *group_list;
    1014             :     gmpr_intf_group_entry *cur_group;
    1015             :     gmp_addr_list *addr_list;
    1016             :     gmpr_host *host;
    1017             :     gmpx_patnode *host_group_node;
    1018             :     gmpr_host_group *host_group;
    1019             :     gmp_addr_cat_entry *cat_entry;
    1020             :     gmpr_host_group_addr *host_group_addr;
    1021             :     gmp_addr_list_entry *addr_entry;
    1022             : 
    1023             :     /* Get the instance. */
    1024             : 
    1025           0 :     instance = gmpr_get_instance(instance_id);
    1026             : 
    1027             :     /* If no matching interface, return NULL */
    1028             : 
    1029           0 :     intf = gmpr_intf_lookup(instance, intf_id);
    1030           0 :     if (!intf)
    1031           0 :         return NULL;
    1032             : 
    1033             :     /* If no matching host, return NULL */
    1034             : 
    1035           0 :     host = gmpr_lookup_host(intf, host_addr);
    1036           0 :     if (!host)
    1037           0 :         return NULL;
    1038             : 
    1039             :     /* Got a host.  Walk all host groups on the host. */
    1040             : 
    1041           0 :     group_list = NULL;
    1042           0 :     host_group_node = NULL;
    1043             :     
    1044             :     while (TRUE) {
    1045           0 :         host_group_node = gmpx_patricia_get_next(host->rhost_group_root,
    1046             :                                                  host_group_node);
    1047           0 :         host_group = gmpr_patnode_to_host_group(host_group_node);
    1048             : 
    1049             :         /* Bail if done. */
    1050             : 
    1051           0 :         if (!host_group)
    1052           0 :             break;
    1053             : 
    1054             :         /* Only want the active ones */
    1055             : 
    1056           0 :         if (!gmpr_host_group_active(host_group))
    1057           0 :             continue;
    1058             : 
    1059             :         /* Got a group.  Allocate an entry. */
    1060             : 
    1061           0 :         cur_group = gmpx_malloc_block(gmpr_intf_group_tag);
    1062           0 :         if (!cur_group)
    1063           0 :             break;                      /* Out of memory */
    1064             : 
    1065             :         /* Set the group address. */
    1066             : 
    1067           0 :         memmove(cur_group->gig_group_addr.gmp_addr,
    1068           0 :             host_group->rhgroup_addr.gmp_addr,
    1069           0 :             instance->rinst_addrlen);
    1070             : 
    1071             :         /* If there are sources, copy them in as well. */
    1072             : 
    1073           0 :         addr_list = &host_group->rhgroup_addrs;
    1074           0 :         if (!gmp_addr_list_empty(addr_list)) {
    1075             :             /* Walk address list */
    1076             : 
    1077             :             /* Got sources.  Create the address thread. */
    1078             : 
    1079           0 :             cur_group->gig_sources = gmp_alloc_addr_thread();
    1080             : 
    1081           0 :             addr_entry = NULL;
    1082             :             while (TRUE) {
    1083           0 :                 addr_entry = gmp_addr_list_next_entry(addr_list, addr_entry);
    1084             :                 host_group_addr =
    1085           0 :                     gmpr_addr_entry_to_host_group_entry(addr_entry);
    1086           0 :                 if (!host_group_addr || !host_group_addr->rhga_source)
    1087             :                     break;
    1088             : 
    1089             :                 cat_entry =
    1090           0 :                     gmp_get_addr_cat_by_ordinal(&instance->rinst_addr_cat,
    1091           0 :                                                 host_group_addr->rhga_source->
    1092             :                                                 rgroup_addr_entry.addr_ent_ord);
    1093           0 :                 gmpx_assert(cat_entry);
    1094             : 
    1095           0 :                 gmp_enqueue_addr_thread_addr(cur_group->gig_sources,
    1096           0 :                                              cat_entry->adcat_ent_addr.gmp_addr,
    1097             :                                              instance->rinst_addrlen);
    1098             :             }
    1099             :         }
    1100             : 
    1101             :         /* Link the new entry to the list. */
    1102             : 
    1103           0 :         if (group_list)
    1104           0 :             cur_group->gig_next = group_list;
    1105           0 :         group_list = cur_group;
    1106             :     }
    1107             : 
    1108           0 :     return group_list;
    1109             : }
    1110             : 
    1111             : 
    1112             : /*
    1113             :  * gmpr_host_is_active
    1114             :  *
    1115             :  * Determine if a host has active groups.
    1116             :  */
    1117             : static boolean
    1118           0 : gmpr_host_is_active (gmpr_host *host)
    1119             : {
    1120             :     gmpx_patnode *host_group_node;
    1121             :     gmpr_host_group *host_group;
    1122             : 
    1123             :     /* Walk all host groups on the host. */
    1124           0 :     host_group_node = NULL;
    1125             : 
    1126             :     while (TRUE) {
    1127           0 :         host_group_node = gmpx_patricia_get_next(host->rhost_group_root,
    1128             :                                                  host_group_node);
    1129           0 :         host_group = gmpr_patnode_to_host_group(host_group_node);
    1130             : 
    1131             :         /* Bail if done. */
    1132             : 
    1133           0 :         if (!host_group)
    1134           0 :             break;
    1135             : 
    1136             :         /* Found an active one, so the host is active */
    1137             : 
    1138           0 :         if (gmpr_host_group_active(host_group))
    1139           0 :             return TRUE;
    1140             :     }
    1141             : 
    1142             :     /* Host has no active groups */
    1143             : 
    1144           0 :     return FALSE;
    1145             : }
    1146             : 
    1147             : 
    1148             : /*
    1149             :  * gmpr_get_intf_hosts
    1150             :  *
    1151             :  * Get a list of all active hosts on the specified interface.  Returns a
    1152             :  * pointer  to a host entry, to which other host entries are linked.  
    1153             :  * Returns NULL* if there are no active hosts on the interface.
    1154             :  *
    1155             :  * The pointer should be returned via gmpr_destroy_host_group() when the
    1156             :  * caller is done.
    1157             :  *
    1158             :  * This could be heinous and does not scale if there are lots of hosts
    1159             :  * on the interface.
    1160             :  */
    1161             : gmpr_intf_host_entry *
    1162           0 : gmpr_get_intf_hosts (gmp_instance_id instance_id, gmpx_intf_id intf_id)
    1163             : {
    1164             :     gmpr_instance *instance;
    1165             :     gmpr_host *host;
    1166             :     gmpr_intf *intf;
    1167             :     gmpr_intf_host_entry *host_list;
    1168             :     gmpr_intf_host_entry *cur_host;
    1169             :     gmpx_patnode *host_node;
    1170             : 
    1171             :     /* Get the instance. */
    1172             : 
    1173           0 :     instance = gmpr_get_instance(instance_id);
    1174             : 
    1175             :     /* If no matching interface, return NULL */
    1176             : 
    1177           0 :     intf = gmpr_intf_lookup(instance, intf_id);
    1178           0 :     if (!intf)
    1179           0 :         return NULL;
    1180             : 
    1181             :     /* Walk all hosts on the interface */
    1182           0 :     host_list = NULL;
    1183           0 :     host_node = NULL;
    1184             : 
    1185             :     while (TRUE) {
    1186           0 :         host_node = gmpx_patricia_get_next(intf->rintf_host_root, host_node);
    1187           0 :         host = gmpr_patnode_to_host(host_node);
    1188             : 
    1189             :         /* Bail if done. */
    1190             : 
    1191           0 :         if (!host)
    1192           0 :             break;
    1193             : 
    1194             :         /* Ignore hosts that are not active. */
    1195             : 
    1196           0 :         if (!gmpr_host_is_active(host)) {
    1197           0 :             continue;
    1198             :         }
    1199             :         
    1200             :         /* Got an active host.  Allocate an entry. */
    1201             : 
    1202           0 :         cur_host = gmpx_malloc_block(gmpr_intf_host_tag);
    1203           0 :         if (!cur_host)
    1204           0 :             break;                      /* Out of memory */
    1205             : 
    1206             :         /* Set the host address */
    1207             : 
    1208           0 :         memmove(cur_host->gih_host_addr.gmp_addr, host->rhost_addr.gmp_addr,
    1209           0 :             instance->rinst_addrlen);
    1210             : 
    1211             :         /*
    1212             :          * Link the new entry to the list.
    1213             :          */
    1214           0 :         if (host_list) 
    1215           0 :             cur_host->gih_next = host_list;
    1216           0 :         host_list = cur_host;
    1217             :     }
    1218             : 
    1219           0 :     return host_list;
    1220             : }
    1221             : 
    1222             : 
    1223             : /*
    1224             :  * gmpr_destroy_intf_host
    1225             :  *
    1226             :  * Destroy the structure returned by gmpr_get_intf_hosts.
    1227             :  *
    1228             :  * Tolerates NULL pointers.
    1229             :  */
    1230             : void
    1231           0 : gmpr_destroy_intf_host (gmpr_intf_host_entry *host_list)
    1232             : {
    1233             :     gmpr_intf_host_entry *next;
    1234             : 
    1235             :     /* Walk the list. */
    1236             : 
    1237           0 :     while (host_list) {
    1238           0 :         next = host_list->gih_next;
    1239             : 
    1240             :         /* Free the entry. */
    1241             : 
    1242           0 :         gmpx_free_block(gmpr_intf_host_tag, host_list);
    1243             : 
    1244           0 :         host_list = next;
    1245             :     }
    1246           0 : }
    1247             : 
    1248             : 
    1249             : /*
    1250             :  * gmpr_destroy_intf_group
    1251             :  *
    1252             :  * Destroy the structure returned by gmpr_get_intf_groups.
    1253             :  *
    1254             :  * Tolerates NULL pointers.
    1255             :  */
    1256             : void
    1257           0 : gmpr_destroy_intf_group (gmpr_intf_group_entry *group_list)
    1258             : {
    1259             :     gmpr_intf_group_entry *next;
    1260             : 
    1261             :     /* Walk the list. */
    1262             : 
    1263           0 :     while (group_list) {
    1264           0 :         next = group_list->gig_next;
    1265             : 
    1266             :         /* Destroy the address thread, if there. */
    1267             : 
    1268           0 :         gmp_destroy_addr_thread(group_list->gig_sources);
    1269             : 
    1270             :         /* Free the entry. */
    1271             : 
    1272           0 :         gmpx_free_block(gmpr_intf_group_tag, group_list);
    1273             : 
    1274           0 :         group_list = next;
    1275             :     }
    1276           0 : }
    1277             : 
    1278             : 
    1279             : /*
    1280             :  * gmpr_is_initialized
    1281             :  *
    1282             :  * Returns TRUE if GMP router support has been initialized, or FALSE if not.
    1283             :  *
    1284             :  * This lets external callbacks know if it's safe to do stuff in here.
    1285             :  */
    1286             : boolean
    1287           0 : gmpr_is_initialized (void)
    1288             : {
    1289           0 :     return gr_initialized;
    1290             : }
    1291             : 
    1292             : 
    1293             : /*
    1294             :  * gmpr_timeout_group_range
    1295             :  *
    1296             :  * Prematurely age a range of groups on an interface.
    1297             :  *
    1298             :  * send_query is TRUE if we should immediately send a general query on the
    1299             :  * interface.
    1300             :  */
    1301             : void
    1302           0 : gmpr_timeout_group_range (gmp_instance_id instance_id, gmpx_intf_id intf_id,
    1303             :                           const uint8_t *group_addr, uint32_t pfx_len,
    1304             :                           boolean send_query)
    1305             : {
    1306             :     gmpr_instance *instance;
    1307             :     gmpr_intf *intf;
    1308             :     gmpr_group *group;
    1309             :     gmpr_group *next_group;
    1310             :     uint8_t last_byte_mask;
    1311             :     uint32_t pfx_full_bytes;
    1312             :     uint32_t pfx_len_bytes;
    1313             :     uint32_t extra_bits;
    1314             :     uint32_t bit_ix;
    1315             : 
    1316             :     /* Get the instance and interface. */
    1317             : 
    1318           0 :     instance = gmpr_get_instance(instance_id);
    1319           0 :     intf = gmpr_intf_lookup(instance, intf_id);
    1320           0 :     if (!intf)
    1321           0 :         return;
    1322             : 
    1323             :     /* Normalize the prefix length to bytes. */
    1324             : 
    1325           0 :     pfx_len_bytes = (pfx_len + 7) / 8;
    1326           0 :     gmpx_assert(pfx_len_bytes <= instance->rinst_addrlen);
    1327           0 :     pfx_full_bytes = pfx_len / 8;
    1328             : 
    1329             :     /* If the last byte isn't full, set up a mask for it. */
    1330             : 
    1331           0 :     extra_bits = pfx_len % 8;
    1332           0 :     last_byte_mask = 0;
    1333           0 :     if (extra_bits) {
    1334           0 :         for (bit_ix = 0; bit_ix < extra_bits; bit_ix++) {
    1335           0 :             last_byte_mask |= (0x80 >> bit_ix);
    1336             :         }
    1337             :     }
    1338             : 
    1339             :     /* Walk all groups on the interface. */
    1340             : 
    1341           0 :     group = gmpr_next_intf_group(intf, NULL);
    1342           0 :     while (group) {
    1343           0 :         next_group = gmpr_next_intf_group(intf, group);
    1344             : 
    1345             :         /* Compare the full bytes. */
    1346             : 
    1347           0 :         if (!memcmp(group_addr, group->rgroup_addr.gmp_addr, pfx_full_bytes)) {
    1348             : 
    1349             :             /* The full bytes match.  If there's a partial byte, try that. */
    1350             : 
    1351           0 :             if (!extra_bits ||
    1352           0 :                 (group_addr[pfx_full_bytes] ==
    1353           0 :                  (group->rgroup_addr.gmp_addr[pfx_full_bytes] &
    1354             :                  last_byte_mask))) {
    1355             : 
    1356             :                 /* If we got here, we've got a match.  Blast the timers. */
    1357             : 
    1358           0 :                 gmpr_timeout_group(group);
    1359             :             }
    1360             :         }
    1361             : 
    1362           0 :         group = next_group;
    1363             :     }
    1364             : 
    1365             :     /* If we're supposed to send an immediate query, whack the timer. */
    1366             : 
    1367           0 :     if (send_query)
    1368           0 :         gmpx_start_timer(intf->rintf_query_timer, 0, 0);
    1369             : }
    1370             : 
    1371             : 
    1372             : /*
    1373             :  * gmpr_sg_is_excluded
    1374             :  *
    1375             :  * Returns TRUE if the (intf, s, g) tuple is on an Exclude list, or FALSE
    1376             :  * if not.
    1377             :  */
    1378             : boolean
    1379           0 : gmpr_sg_is_excluded (gmp_instance_id instance_id, gmpx_intf_id intf_id,
    1380             :                      const uint8_t *group_addr, const uint8_t *source_addr)
    1381             : {
    1382             :     gmpr_instance *instance;
    1383             :     gmpr_intf *intf;
    1384             :     gmpr_group *group;
    1385             :     gmp_addr_cat_entry *cat_entry;
    1386             : 
    1387             :     /* Get the instance and interface. */
    1388             : 
    1389           0 :     instance = gmpr_get_instance(instance_id);
    1390           0 :     intf = gmpr_intf_lookup(instance, intf_id);
    1391           0 :     if (!intf)
    1392           0 :         return FALSE;
    1393             : 
    1394             :     /* Look up the address catalog entry for the source address. */
    1395             : 
    1396           0 :     cat_entry = gmp_lookup_addr_cat_entry(&instance->rinst_addr_cat,
    1397             :                                           source_addr);
    1398           0 :     if (!cat_entry)
    1399           0 :         return FALSE;
    1400             : 
    1401             :     /* Look up the group. */
    1402             : 
    1403           0 :     group = gmpr_group_lookup(intf, group_addr);
    1404           0 :     if (!group)
    1405           0 :         return FALSE;
    1406             : 
    1407             :     /* If the source is in the stopped-timer list, it is being excluded. */
    1408             : 
    1409           0 :     return gmp_addr_in_list(&group->rgroup_src_addr_stopped,
    1410             :                             cat_entry->adcat_ent_ord);
    1411             : }
    1412             : 
    1413             : 
    1414             : /*
    1415             :  * gmpr_update_trace_flags
    1416             :  *
    1417             :  * Update trace flags for an instance.
    1418             :  */
    1419             : void
    1420         125 : gmpr_update_trace_flags (gmp_instance_id instance_id, uint32_t trace_flags)
    1421             : {
    1422             :     gmpr_instance *instance;
    1423             : 
    1424             :     /* Get the instance. */
    1425             : 
    1426         125 :     instance = gmpr_get_instance(instance_id);
    1427             : 
    1428             :     /* Update the trace flags. */
    1429             : 
    1430         125 :     instance->rinst_traceflags = trace_flags;
    1431         125 : }
    1432             : 
    1433             : 
    1434             : /*
    1435             :  * gmpr_query_sequence_internal
    1436             :  *
    1437             :  * Trigger an initial query sequence.  "force" is TRUE if we should force
    1438             :  * the queries even if query transmission is suppressed.
    1439             :  */
    1440             : static void
    1441           0 : gmpr_query_sequence_internal (gmp_instance_id instance_id, gmpx_intf_id intf_id,
    1442             :                               boolean force)
    1443             : {
    1444             :     gmpr_instance *instance;
    1445             :     gmpr_intf *intf;
    1446             : 
    1447             :     /* Get the instance and interface. */
    1448             : 
    1449           0 :     instance = gmpr_get_instance(instance_id);
    1450           0 :     intf = gmpr_intf_lookup(instance, intf_id);
    1451           0 :     if (intf) {
    1452             : 
    1453             :         /*
    1454             :          * Set the flag that overrides query suppression according to
    1455             :          * the force parameter.
    1456             :          */
    1457           0 :         intf->rintf_gen_query_requested = force;
    1458             : 
    1459             :         /* Launch the queries. */
    1460             : 
    1461           0 :         gmpr_setup_initial_query_timer(intf);
    1462             :     }
    1463           0 : }
    1464             : 
    1465             : 
    1466             : /*
    1467             :  * gmpr_force_general_queries
    1468             :  *
    1469             :  * Trigger a sequence of general queries to be sent on an interface.
    1470             :  * The queries are sent regardless of whether queries are normally
    1471             :  * suppressed on the interface.  This is typically only used when
    1472             :  * general queries are otherwise suppressed.
    1473             :  */
    1474             : void
    1475           0 : gmpr_force_general_queries (gmp_instance_id instance_id, gmpx_intf_id intf_id)
    1476             : {
    1477           0 :     gmpr_query_sequence_internal(instance_id, intf_id, TRUE);
    1478           0 : }
    1479             : 
    1480             : 
    1481             : /*
    1482             :  * gmpr_request_general_queries
    1483             :  *
    1484             :  * Trigger a general query sequence on an interface.  The queries will
    1485             :  * not be sent if queries are suppressed on the interface.
    1486             :  */
    1487             : void
    1488           0 : gmpr_request_general_queries (gmp_instance_id instance_id, gmpx_intf_id intf_id)
    1489             : {
    1490           0 :     gmpr_query_sequence_internal(instance_id, intf_id, FALSE);
    1491           0 : }
    1492             : 
    1493             : 
    1494             : /*
    1495             :  * gmpr_one_query_internal
    1496             :  *
    1497             :  * Trigger the transmission of a single general query on an interface.
    1498             :  * "force" is TRUE if we should force the query even if query
    1499             :  * transmission is suppressed.
    1500             :  */
    1501             : static void
    1502           0 : gmpr_one_query_internal (gmp_instance_id instance_id, gmpx_intf_id intf_id,
    1503             :                          boolean force)
    1504             : {
    1505             :     gmpr_instance *instance;
    1506             :     gmpr_intf *intf;
    1507             : 
    1508             :     /* Get the instance and interface. */
    1509             : 
    1510           0 :     instance = gmpr_get_instance(instance_id);
    1511           0 :     intf = gmpr_intf_lookup(instance, intf_id);
    1512           0 :     if (intf) {
    1513             : 
    1514             :         /* Set the flag and trigger the transmission. */
    1515             : 
    1516           0 :         intf->rintf_gen_query_requested = force;
    1517           0 :         gmpr_trigger_one_query(intf);
    1518             :     }
    1519           0 : }
    1520             : 
    1521             : 
    1522             : /*
    1523             :  * gmpr_force_one_general_query
    1524             :  *
    1525             :  * Trigger the transmission of a single general query on an interface.
    1526             :  * The query is sent regardless of whether queries are normally
    1527             :  * suppressed on the interface.  This is typically only used when
    1528             :  * general queries are otherwise suppressed.
    1529             :  */
    1530             : void
    1531           0 : gmpr_force_one_general_query (gmp_instance_id instance_id, gmpx_intf_id intf_id)
    1532             : {
    1533           0 :     gmpr_one_query_internal(instance_id, intf_id, TRUE);
    1534           0 : }
    1535             : 
    1536             : 
    1537             : /*
    1538             :  * gmpr_request_one_general_query
    1539             :  *
    1540             :  * Trigger the transmission of a single general query on an interface.
    1541             :  * The query will not be sent if queries are suppressed on the
    1542             :  * interface.
    1543             :  */
    1544             : void
    1545           0 : gmpr_request_one_general_query (gmp_instance_id instance_id,
    1546             :                                 gmpx_intf_id intf_id)
    1547             : {
    1548           0 :     gmpr_one_query_internal(instance_id, intf_id, FALSE);
    1549           0 : }
    1550             : 
    1551             : 
    1552             : /*
    1553             :  * gmpr_notify_oif_map_change
    1554             :  *
    1555             :  * Update the OIF mappings for an input interface.  This is done when the
    1556             :  * OIF map for that interface changes, or any other circumstance where
    1557             :  * the input->output interface mapping needs to be updated.
    1558             :  */
    1559             : void
    1560           0 : gmpr_notify_oif_map_change (gmp_proto proto, gmpx_intf_id intf_id)
    1561             : {
    1562             :     gmpr_intf *intf;
    1563             : 
    1564             :     /* Get the interface. */
    1565             : 
    1566           0 :     intf = gmpr_intf_lookup_global(proto, intf_id);
    1567             : 
    1568             :     /* Bail if there's no interface. */
    1569             : 
    1570           0 :     if (!intf)
    1571           0 :         return;
    1572             : 
    1573             :     /* Do the deed. */
    1574             : 
    1575           0 :     gmpr_notify_oif_map_change_internal(intf);
    1576             : }

Generated by: LCOV version 1.14