"Fossies" - the Fresh Open Source Software Archive

Member "mrouted-3.9.8/rsrr.c" (1 Jan 2017, 14907 Bytes) of package /linux/misc/mrouted-3.9.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rsrr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.9.7_vs_3.9.8.

    1 /*
    2  * Copyright (c) 1993, 1998-2001.
    3  * The University of Southern California/Information Sciences Institute.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. Neither the name of the project nor the names of its contributors
   15  *    may be used to endorse or promote products derived from this software
   16  *    without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /* RSRR code written by Daniel Zappala, USC Information Sciences Institute,
   32  * April 1995.
   33  */
   34 
   35 /* May 1995 -- Added support for Route Change Notification */
   36 
   37 #ifdef RSRR
   38 
   39 #include "defs.h"
   40 #include <sys/param.h>
   41 #ifdef HAVE_SA_LEN
   42 #include <stddef.h>     /* for offsetof */
   43 #endif
   44 
   45 /* 
   46  * Local RSRR variables.
   47  */
   48 static int rsrr_socket;     /* interface to reservation protocol */
   49 static char *rsrr_recv_buf;     /* RSRR receive buffer */
   50 static char *rsrr_send_buf;     /* RSRR send buffer */
   51 
   52 static struct sockaddr_un client_addr;
   53 static socklen_t client_length = sizeof(client_addr);
   54 
   55 /*
   56  * Procedure definitions needed internally.
   57  */
   58 static void rsrr_accept(size_t recvlen);
   59 static void rsrr_accept_iq(void);
   60 static int  rsrr_accept_rq(struct rsrr_rq *route_query, uint8_t flags, struct gtable *gt_notify);
   61 static void rsrr_read(int);
   62 static int  rsrr_send(int sendlen);
   63 static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query);
   64 
   65 /* Initialize RSRR socket */
   66 void rsrr_init(void)
   67 {
   68     int servlen;
   69     struct sockaddr_un serv_addr;
   70 
   71     rsrr_recv_buf = malloc(RSRR_MAX_LEN);
   72     rsrr_send_buf = malloc(RSRR_MAX_LEN);
   73     if (!rsrr_recv_buf || !rsrr_send_buf) {
   74     logit(LOG_ERR, errno, "Failed allocating memory in %s:%s()", __FILE__, __func__);
   75     return;
   76     }
   77 
   78     rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
   79     if (rsrr_socket < 0) {
   80     logit(LOG_ERR, errno, "Failed creating RSRR socket");
   81     return;
   82     }
   83 
   84     unlink(RSRR_SERV_PATH);
   85     memset(&serv_addr, 0, sizeof(serv_addr));
   86     serv_addr.sun_family = AF_UNIX;
   87     strlcpy(serv_addr.sun_path, RSRR_SERV_PATH, sizeof(serv_addr.sun_path));
   88 #ifdef HAVE_SA_LEN
   89     servlen = offsetof(struct sockaddr_un, sun_path) + strlen(serv_addr.sun_path);
   90     serv_addr.sun_len = servlen;
   91 #else
   92     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
   93 #endif
   94  
   95     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
   96     logit(LOG_ERR, errno, "Cannot bind RSRR socket");
   97 
   98     if (register_input_handler(rsrr_socket, rsrr_read) < 0)
   99     logit(LOG_ERR, 0, "Could not register RSRR as an input handler");
  100 }
  101 
  102 /* Read a message from the RSRR socket */
  103 static void rsrr_read(int fd)
  104 {
  105     ssize_t rsrr_recvlen;
  106     
  107     memset(&client_addr, 0, sizeof(client_addr));
  108     rsrr_recvlen = recvfrom(fd, rsrr_recv_buf, RSRR_MAX_LEN,
  109                 0, (struct sockaddr *)&client_addr, &client_length);
  110     if (rsrr_recvlen < 0) { 
  111     if (errno != EINTR)
  112         logit(LOG_ERR, errno, "RSRR recvfrom");
  113     return;
  114     }
  115     rsrr_accept(rsrr_recvlen);
  116 }
  117 
  118 /* Accept a message from the reservation protocol and take
  119  * appropriate action.
  120  */
  121 static void rsrr_accept(size_t recvlen)
  122 {
  123     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_recv_buf;
  124     struct rsrr_rq *route_query;
  125     
  126     if (recvlen < RSRR_HEADER_LEN) {
  127     logit(LOG_WARNING, 0, "Received RSRR packet of %d bytes, which is less than MIN size %d.",
  128           recvlen, RSRR_HEADER_LEN);
  129     return;
  130     }
  131     
  132     if (rsrr->version > RSRR_MAX_VERSION || rsrr->version != 1) {
  133     logit(LOG_WARNING, 0, "Received RSRR packet version %d, which I don't understand",
  134           rsrr->version);
  135     return;
  136     }
  137 
  138     switch (rsrr->type) {
  139     case RSRR_INITIAL_QUERY:
  140         /* Send Initial Reply to client */
  141         IF_DEBUG(DEBUG_RSRR) {
  142         logit(LOG_DEBUG, 0, "Received Initial Query\n");
  143         }
  144         rsrr_accept_iq();
  145         break;
  146 
  147     case RSRR_ROUTE_QUERY:
  148         /* Check size */
  149         if (recvlen < RSRR_RQ_LEN) {
  150         logit(LOG_WARNING, 0, "Received Route Query of %d bytes, which is too small", recvlen);
  151         break;
  152         }
  153         /* Get the query */
  154         route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN);
  155         IF_DEBUG(DEBUG_RSRR) {
  156         logit(LOG_DEBUG, 0,
  157               "Received Route Query for src %s grp %s notification %d",
  158               inet_fmt(route_query->source_addr.s_addr, s1, sizeof(s1)),
  159               inet_fmt(route_query->dest_addr.s_addr, s2, sizeof(s2)),
  160               BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
  161         }
  162         /* Send Route Reply to client */
  163         rsrr_accept_rq(route_query, rsrr->flags, NULL);
  164         break;
  165 
  166     default:
  167         logit(LOG_WARNING, 0, "Received RSRR packet type %d, which I don't handle", rsrr->type);
  168         break;
  169     }
  170 }
  171 
  172 /* Send an Initial Reply to the reservation protocol. */
  173 static void rsrr_accept_iq(void)
  174 {
  175     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
  176     struct rsrr_vif *vif_list;
  177     struct uvif *v;
  178     int vifi, sendlen;
  179     
  180     /* Check for space.  There should be room for plenty of vifs,
  181      * but we should check anyway.
  182      */
  183     if (numvifs > RSRR_MAX_VIFS) {
  184     logit(LOG_WARNING, 0,
  185         "Cannot send RSRR Route Reply because %d is too many vifs %d",
  186         numvifs);
  187     return;
  188     }
  189     
  190     /* Set up message */
  191     rsrr->version = 1;
  192     rsrr->type = RSRR_INITIAL_REPLY;
  193     rsrr->flags = 0;
  194     rsrr->num = numvifs;
  195     
  196     vif_list = (struct rsrr_vif *)(rsrr_send_buf + RSRR_HEADER_LEN);
  197     
  198     /* Include the vif list. */
  199     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
  200     vif_list[vifi].id = vifi;
  201     vif_list[vifi].status = 0;
  202     if (v->uv_flags & VIFF_DISABLED)
  203         BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT);
  204     vif_list[vifi].threshold = v->uv_threshold;
  205     vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr;
  206     }
  207     
  208     /* Get the size. */
  209     sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN;
  210     
  211     /* Send it. */
  212     IF_DEBUG(DEBUG_RSRR) {
  213     logit(LOG_DEBUG, 0, "Send RSRR Initial Reply");
  214     }
  215     rsrr_send(sendlen);
  216 }
  217 
  218 /* Send a Route Reply to the reservation protocol.  The Route Query
  219  * contains the query to which we are responding.  The flags contain
  220  * the incoming flags from the query or, for route change
  221  * notification, the flags that should be set for the reply.  The
  222  * kernel table entry contains the routing info to use for a route
  223  * change notification.
  224  */
  225 /* XXX: must modify if your routing table structure/search is different */
  226 static int rsrr_accept_rq(struct rsrr_rq *route_query, uint8_t flags, struct gtable *gt_notify)
  227 {
  228     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
  229     struct rsrr_rr *route_reply;
  230     struct gtable *gt,local_g;
  231     struct rtentry *r;
  232     int sendlen;
  233     uint32_t mcastgrp;
  234     
  235     /* Set up message */
  236     rsrr->version = 1;
  237     rsrr->type = RSRR_ROUTE_REPLY;
  238     rsrr->flags = 0;
  239     rsrr->num = 0;
  240     
  241     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
  242     route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr;
  243     route_reply->source_addr.s_addr = route_query->source_addr.s_addr;
  244     route_reply->query_id = route_query->query_id;
  245     
  246     /* Blank routing entry for error. */
  247     route_reply->in_vif = 0;
  248     route_reply->reserved = 0;
  249     route_reply->out_vif_bm = 0;
  250     
  251     /* Get the size. */
  252     sendlen = RSRR_RR_LEN;
  253 
  254     /* If kernel table entry is defined, then we are sending a Route Reply
  255      * due to a Route Change Notification event.  Use the kernel table entry
  256      * to supply the routing info.
  257      */
  258     if (gt_notify && gt_notify->gt_route) {
  259     /* Set flags */
  260     rsrr->flags = flags;
  261 
  262     /* Include the routing entry. */
  263     route_reply->in_vif = gt_notify->gt_route->rt_parent;
  264 
  265     if (BIT_TST(flags, RSRR_NOTIFICATION_BIT))
  266         route_reply->out_vif_bm = gt_notify->gt_grpmems;
  267     else
  268         route_reply->out_vif_bm = 0;
  269 
  270     } else if (find_src_grp(route_query->source_addr.s_addr, 0, route_query->dest_addr.s_addr)) {
  271 
  272     /* Found kernel entry. Code taken from add_table_entry() */
  273     gt = gtp ? gtp->gt_gnext : kernel_table;
  274     
  275     /* Include the routing entry. */
  276     if (gt && gt->gt_route) {
  277         route_reply->in_vif     = gt->gt_route->rt_parent;
  278         route_reply->out_vif_bm = gt->gt_grpmems;
  279 
  280         /* Cache reply if using route change notification. */
  281         if (BIT_TST(flags, RSRR_NOTIFICATION_BIT)) {
  282         /* TODO: XXX: Originally the rsrr_cache() call was first, but
  283          * I think this is incorrect, because rsrr_cache() checks the
  284          * rsrr_send_buf "flag" first.
  285          */
  286         BIT_SET(rsrr->flags, RSRR_NOTIFICATION_BIT);
  287         rsrr_cache(gt, route_query);
  288         }
  289     }
  290     } else {
  291 
  292     /* No kernel entry; use routing table. */
  293     r = determine_route(route_query->source_addr.s_addr);
  294     if (r) {
  295         /* We need to mimic what will happen if a data packet
  296          * is forwarded by multicast routing -- the kernel will
  297          * make an upcall and mrouted will install a route in the kernel.
  298          * Our outgoing vif bitmap should reflect what that table
  299          * will look like.  Grab code from add_table_entry().
  300          * This is gross, but it's probably better to be accurate.
  301          */
  302         
  303         gt = &local_g;
  304         mcastgrp = route_query->dest_addr.s_addr;
  305         
  306         gt->gt_mcastgrp     = mcastgrp;
  307         gt->gt_grpmems  = 0;
  308         gt->gt_scope    = 0;
  309         gt->gt_route        = r;
  310         
  311         /* obtain the multicast group membership list */
  312         determine_forwvifs(gt);
  313         
  314         /* Include the routing entry. */
  315         route_reply->in_vif = gt->gt_route->rt_parent;
  316         route_reply->out_vif_bm = gt->gt_grpmems;
  317     } else {
  318         /* Set error bit. */
  319         BIT_SET(rsrr->flags, RSRR_ERROR_BIT);
  320     }
  321     }
  322     
  323     IF_DEBUG(DEBUG_RSRR) {
  324     logit(LOG_DEBUG, 0, "%sSend RSRR Route Reply for src %s dst %s in vif %d out vif %d\n",
  325           gt_notify ? "Route Change: " : "",
  326           inet_fmt(route_reply->source_addr.s_addr, s1, sizeof(s1)),
  327           inet_fmt(route_reply->dest_addr.s_addr, s2, sizeof(s2)),
  328           route_reply->in_vif,route_reply->out_vif_bm);
  329     }
  330 
  331     /* Send it. */
  332     return rsrr_send(sendlen);
  333 }
  334 
  335 /* Send an RSRR message. */
  336 static int rsrr_send(int sendlen)
  337 {
  338     int error;
  339     
  340     /* Send it. */
  341     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
  342            (struct sockaddr *)&client_addr, client_length);
  343     
  344     /* Check for errors. */
  345     if (error < 0) {
  346     logit(LOG_WARNING, errno, "Failed send on RSRR socket");
  347     } else if (error != sendlen) {
  348     logit(LOG_WARNING, 0,
  349         "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
  350     }
  351 
  352     return error;
  353 }
  354 
  355 /* TODO: need to sort the rsrr_cache entries for faster access */
  356 /* Cache a message being sent to a client.  Currently only used for
  357  * caching Route Reply messages for route change notification.
  358  */
  359 static void rsrr_cache(struct gtable *gt, struct rsrr_rq *route_query)
  360 {
  361     struct rsrr_cache *rc, **rcnp;
  362     struct rsrr_header *rsrr = (struct rsrr_header *)rsrr_send_buf;
  363 
  364     rcnp = &gt->gt_rsrr_cache;
  365     while ((rc = *rcnp)) {
  366     if ((rc->route_query.source_addr.s_addr == route_query->source_addr.s_addr) &&
  367         (rc->route_query.dest_addr.s_addr == route_query->dest_addr.s_addr) &&
  368         (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
  369         /* Cache entry already exists.
  370          * Check if route notification bit has been cleared.
  371          */
  372         if (!BIT_TST(rsrr->flags, RSRR_NOTIFICATION_BIT)) {
  373         /* Delete cache entry. */
  374         *rcnp = rc->next;
  375         free(rc);
  376         } else {
  377         /* Update */
  378         /* TODO: XXX: No need to update iif, oifs, flags */
  379         rc->route_query.query_id = route_query->query_id;
  380         IF_DEBUG(DEBUG_RSRR) {
  381             logit(LOG_DEBUG, 0,
  382               "Update cached query id %ld from client %s\n",
  383               rc->route_query.query_id, rc->client_addr.sun_path);
  384         }
  385         }
  386 
  387         return;
  388     }
  389 
  390     rcnp = &rc->next;
  391     }
  392 
  393     /* Cache entry doesn't already exist.  Create one and insert at
  394      * front of list.
  395      */
  396     rc = malloc(sizeof(struct rsrr_cache));
  397     if (!rc) {
  398     logit(LOG_ERR, errno, "Failed allocating memory in %s:%s()", __FILE__, __func__);
  399     return;
  400     }
  401 
  402     rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
  403     rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
  404     rc->route_query.query_id = route_query->query_id;
  405     strlcpy(rc->client_addr.sun_path, client_addr.sun_path, sizeof(rc->client_addr.sun_path));
  406     rc->client_length = client_length;
  407     rc->next = gt->gt_rsrr_cache;
  408     gt->gt_rsrr_cache = rc;
  409 
  410     IF_DEBUG(DEBUG_RSRR) {
  411     logit(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
  412           rc->route_query.query_id, rc->client_addr.sun_path);
  413     }
  414 }
  415 
  416 /* Send all the messages in the cache for particular routing entry.
  417  * Currently this is used to send all the cached Route Reply messages
  418  * for route change notification.
  419  */
  420 void rsrr_cache_send(struct gtable *gt, int notify)
  421 {
  422     struct rsrr_cache *rc, **rcnp;
  423     uint8_t flags = 0;
  424 
  425     if (notify) {
  426     BIT_SET(flags, RSRR_NOTIFICATION_BIT);
  427     }
  428 
  429     rcnp = &gt->gt_rsrr_cache;
  430     while ((rc = *rcnp)) {
  431     if (rsrr_accept_rq(&rc->route_query, flags, gt) < 0) {
  432         IF_DEBUG(DEBUG_RSRR) {
  433         logit(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
  434               rc->route_query.query_id, rc->client_addr.sun_path);
  435         }
  436         /* Delete cache entry. */
  437         *rcnp = rc->next;
  438         free(rc);
  439     } else {
  440         rcnp = &rc->next;
  441     }
  442     }
  443 }
  444 
  445 /* Clean the cache by deleting all entries. */
  446 void rsrr_cache_clean(struct gtable *gt)
  447 {
  448     struct rsrr_cache *rc, *rc_next;
  449 
  450     IF_DEBUG(DEBUG_RSRR) {
  451     logit(LOG_DEBUG, 0, "cleaning cache for group %s\n",
  452           inet_fmt(gt->gt_mcastgrp, s1, sizeof(s1)));
  453     }
  454     rc = gt->gt_rsrr_cache;
  455     while (rc) {
  456     rc_next = rc->next;
  457     free(rc);
  458     rc = rc_next;
  459     }
  460     gt->gt_rsrr_cache = NULL;
  461 }
  462 
  463 void rsrr_clean(void)
  464 {
  465     unlink(RSRR_SERV_PATH);
  466 }
  467 
  468 #endif /* RSRR */
  469 
  470 /**
  471  * Local Variables:
  472  *  version-control: t
  473  *  indent-tabs-mode: t
  474  *  c-file-style: "ellemtel"
  475  *  c-basic-offset: 4
  476  * End:
  477  */