"Fossies" - the Fresh Open Source Software Archive

Member "ospfd/interface.c" (5 Jun 2009, 21258 Bytes) of package /linux/privat/old/openospfd-4.6.tgz:


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 "interface.c" see the Fossies "Dox" file reference documentation.

    1 /*  $OpenBSD: interface.c,v 1.63 2009/06/05 04:12:52 claudio Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
    5  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include <sys/types.h>
   21 #include <sys/ioctl.h>
   22 #include <sys/time.h>
   23 #include <sys/socket.h>
   24 #include <netinet/in.h>
   25 #include <arpa/inet.h>
   26 #include <net/if.h>
   27 #include <net/if_types.h>
   28 #include <ctype.h>
   29 #include <err.h>
   30 #include <stdio.h>
   31 #include <stdlib.h>
   32 #include <unistd.h>
   33 #include <string.h>
   34 #include <event.h>
   35 
   36 #include "ospfd.h"
   37 #include "ospf.h"
   38 #include "log.h"
   39 #include "ospfe.h"
   40 
   41 void         if_hello_timer(int, short, void *);
   42 void         if_start_hello_timer(struct iface *);
   43 void         if_stop_hello_timer(struct iface *);
   44 void         if_stop_wait_timer(struct iface *);
   45 void         if_wait_timer(int, short, void *);
   46 void         if_start_wait_timer(struct iface *);
   47 void         if_stop_wait_timer(struct iface *);
   48 struct nbr  *if_elect(struct nbr *, struct nbr *);
   49 
   50 struct {
   51     int         state;
   52     enum iface_event    event;
   53     enum iface_action   action;
   54     int         new_state;
   55 } iface_fsm[] = {
   56     /* current state    event that happened action to take  resulting state */
   57     {IF_STA_DOWN,   IF_EVT_UP,      IF_ACT_STRT,    0},
   58     {IF_STA_WAITING,    IF_EVT_BACKUP_SEEN, IF_ACT_ELECT,   0},
   59     {IF_STA_WAITING,    IF_EVT_WTIMER,      IF_ACT_ELECT,   0},
   60     {IF_STA_ANY,    IF_EVT_WTIMER,      IF_ACT_NOTHING, 0},
   61     {IF_STA_WAITING,    IF_EVT_NBR_CHNG,    IF_ACT_NOTHING, 0},
   62     {IF_STA_MULTI,  IF_EVT_NBR_CHNG,    IF_ACT_ELECT,   0},
   63     {IF_STA_ANY,    IF_EVT_NBR_CHNG,    IF_ACT_NOTHING, 0},
   64     {IF_STA_ANY,    IF_EVT_DOWN,        IF_ACT_RST, IF_STA_DOWN},
   65     {IF_STA_ANY,    IF_EVT_LOOP,        IF_ACT_RST, IF_STA_LOOPBACK},
   66     {IF_STA_LOOPBACK,   IF_EVT_UNLOOP,      IF_ACT_NOTHING, IF_STA_DOWN},
   67     {-1,        IF_EVT_NOTHING,     IF_ACT_NOTHING, 0},
   68 };
   69 
   70 static int vlink_cnt = 0;
   71 
   72 const char * const if_event_names[] = {
   73     "NOTHING",
   74     "UP",
   75     "WAITTIMER",
   76     "BACKUPSEEN",
   77     "NEIGHBORCHANGE",
   78     "LOOP",
   79     "UNLOOP",
   80     "DOWN"
   81 };
   82 
   83 const char * const if_action_names[] = {
   84     "NOTHING",
   85     "START",
   86     "ELECT",
   87     "RESET"
   88 };
   89 
   90 int
   91 if_fsm(struct iface *iface, enum iface_event event)
   92 {
   93     int old_state;
   94     int new_state = 0;
   95     int i, ret = 0;
   96 
   97     old_state = iface->state;
   98 
   99     for (i = 0; iface_fsm[i].state != -1; i++)
  100         if ((iface_fsm[i].state & old_state) &&
  101             (iface_fsm[i].event == event)) {
  102             new_state = iface_fsm[i].new_state;
  103             break;
  104         }
  105 
  106     if (iface_fsm[i].state == -1) {
  107         /* event outside of the defined fsm, ignore it. */
  108         log_debug("if_fsm: interface %s, "
  109             "event %s not expected in state %s", iface->name,
  110             if_event_names[event], if_state_name(old_state));
  111         return (0);
  112     }
  113 
  114     switch (iface_fsm[i].action) {
  115     case IF_ACT_STRT:
  116         ret = if_act_start(iface);
  117         break;
  118     case IF_ACT_ELECT:
  119         ret = if_act_elect(iface);
  120         break;
  121     case IF_ACT_RST:
  122         ret = if_act_reset(iface);
  123         break;
  124     case IF_ACT_NOTHING:
  125         /* do nothing */
  126         break;
  127     }
  128 
  129     if (ret) {
  130         log_debug("if_fsm: error changing state for interface %s, "
  131             "event %s, state %s", iface->name, if_event_names[event],
  132             if_state_name(old_state));
  133         return (-1);
  134     }
  135 
  136     if (new_state != 0)
  137         iface->state = new_state;
  138 
  139     if (iface->state != old_state)
  140         orig_rtr_lsa(iface->area);
  141 
  142     if (old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT) &&
  143         (iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
  144         ospfe_demote_iface(iface, 0);
  145     if ((old_state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0 &&
  146         iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT))
  147         ospfe_demote_iface(iface, 1);
  148 
  149     log_debug("if_fsm: event %s resulted in action %s and changing "
  150         "state for interface %s from %s to %s",
  151         if_event_names[event], if_action_names[iface_fsm[i].action],
  152         iface->name, if_state_name(old_state), if_state_name(iface->state));
  153 
  154     return (ret);
  155 }
  156 
  157 struct iface *
  158 if_new(struct kif *kif, struct kif_addr *ka)
  159 {
  160     struct iface        *iface;
  161 
  162     if ((iface = calloc(1, sizeof(*iface))) == NULL)
  163         err(1, "if_new: calloc");
  164 
  165     iface->state = IF_STA_DOWN;
  166 
  167     LIST_INIT(&iface->nbr_list);
  168     TAILQ_INIT(&iface->ls_ack_list);
  169     TAILQ_INIT(&iface->auth_md_list);
  170 
  171     iface->crypt_seq_num = arc4random() & 0x0fffffff;
  172 
  173     if (kif == NULL) {
  174         iface->type = IF_TYPE_VIRTUALLINK;
  175         snprintf(iface->name, sizeof(iface->name), "vlink%d",
  176             vlink_cnt++);
  177         iface->flags |= IFF_UP;
  178         iface->mtu = IP_MSS;
  179         return (iface);
  180     }
  181 
  182     strlcpy(iface->name, kif->ifname, sizeof(iface->name));
  183 
  184     /* get type */
  185     if (kif->flags & IFF_POINTOPOINT)
  186         iface->type = IF_TYPE_POINTOPOINT;
  187     if (kif->flags & IFF_BROADCAST &&
  188         kif->flags & IFF_MULTICAST)
  189         iface->type = IF_TYPE_BROADCAST;
  190     if (kif->flags & IFF_LOOPBACK) {
  191         iface->type = IF_TYPE_POINTOPOINT;
  192         iface->state = IF_STA_LOOPBACK;
  193     }
  194 
  195     /* get mtu, index and flags */
  196     iface->mtu = kif->mtu;
  197     iface->ifindex = kif->ifindex;
  198     iface->flags = kif->flags;
  199     iface->linkstate = kif->link_state;
  200     iface->media_type = kif->media_type;
  201     iface->baudrate = kif->baudrate;
  202 
  203     /* set address, mask and p2p addr */
  204     iface->addr = ka->addr;
  205     iface->mask = ka->mask;
  206     if (kif->flags & IFF_POINTOPOINT) {
  207         iface->dst = ka->dstbrd;
  208     }
  209 
  210     return (iface);
  211 }
  212 
  213 void
  214 if_del(struct iface *iface)
  215 {
  216     struct nbr  *nbr = NULL;
  217 
  218     /* revert the demotion when the interface is deleted */
  219     if ((iface->state & (IF_STA_MULTI | IF_STA_POINTTOPOINT)) == 0)
  220         ospfe_demote_iface(iface, 1);
  221 
  222     /* clear lists etc */
  223     while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL)
  224         nbr_del(nbr);
  225 
  226     if (evtimer_pending(&iface->hello_timer, NULL))
  227         evtimer_del(&iface->hello_timer);
  228     if (evtimer_pending(&iface->wait_timer, NULL))
  229         evtimer_del(&iface->wait_timer);
  230     if (evtimer_pending(&iface->lsack_tx_timer, NULL))
  231         evtimer_del(&iface->lsack_tx_timer);
  232 
  233     ls_ack_list_clr(iface);
  234     md_list_clr(&iface->auth_md_list);
  235     free(iface);
  236 }
  237 
  238 void
  239 if_init(struct ospfd_conf *xconf, struct iface *iface)
  240 {
  241     struct ifreq    ifr;
  242     u_int       rdomain;
  243 
  244     /* init the dummy local neighbor */
  245     iface->self = nbr_new(ospfe_router_id(), iface, 1);
  246 
  247     /* set event handlers for interface */
  248     evtimer_set(&iface->lsack_tx_timer, ls_ack_tx_timer, iface);
  249     evtimer_set(&iface->hello_timer, if_hello_timer, iface);
  250     evtimer_set(&iface->wait_timer, if_wait_timer, iface);
  251 
  252     iface->fd = xconf->ospf_socket;
  253 
  254     strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
  255     if (ioctl(iface->fd, SIOCGIFRTABLEID, (caddr_t)&ifr) == -1)
  256         rdomain = 0;
  257     else {
  258         rdomain = ifr.ifr_rdomainid;
  259         if (setsockopt(iface->fd, IPPROTO_IP, SO_RDOMAIN,
  260             &rdomain, sizeof(rdomain)) == -1)
  261             fatal("failed to set rdomain");
  262     }
  263     if (rdomain != xconf->rdomain)
  264         fatalx("interface rdomain mismatch");
  265 
  266     ospfe_demote_iface(iface, 0);
  267 }
  268 
  269 /* timers */
  270 /* ARGSUSED */
  271 void
  272 if_hello_timer(int fd, short event, void *arg)
  273 {
  274     struct iface *iface = arg;
  275     struct timeval tv;
  276 
  277     send_hello(iface);
  278 
  279     /* reschedule hello_timer */
  280     timerclear(&tv);
  281     tv.tv_sec = iface->hello_interval;
  282     if (evtimer_add(&iface->hello_timer, &tv) == -1)
  283         fatal("if_hello_timer");
  284 }
  285 
  286 void
  287 if_start_hello_timer(struct iface *iface)
  288 {
  289     struct timeval tv;
  290 
  291     timerclear(&tv);
  292     if (evtimer_add(&iface->hello_timer, &tv) == -1)
  293         fatal("if_start_hello_timer");
  294 }
  295 
  296 void
  297 if_stop_hello_timer(struct iface *iface)
  298 {
  299     if (evtimer_del(&iface->hello_timer) == -1)
  300         fatal("if_stop_hello_timer");
  301 }
  302 
  303 /* ARGSUSED */
  304 void
  305 if_wait_timer(int fd, short event, void *arg)
  306 {
  307     struct iface *iface = arg;
  308 
  309     if_fsm(iface, IF_EVT_WTIMER);
  310 }
  311 
  312 void
  313 if_start_wait_timer(struct iface *iface)
  314 {
  315     struct timeval  tv;
  316 
  317     timerclear(&tv);
  318     tv.tv_sec = iface->dead_interval;
  319     if (evtimer_add(&iface->wait_timer, &tv) == -1)
  320         fatal("if_start_wait_timer");
  321 }
  322 
  323 void
  324 if_stop_wait_timer(struct iface *iface)
  325 {
  326     if (evtimer_del(&iface->wait_timer) == -1)
  327         fatal("if_stop_wait_timer");
  328 }
  329 
  330 /* actions */
  331 int
  332 if_act_start(struct iface *iface)
  333 {
  334     struct in_addr       addr;
  335     struct timeval       now;
  336 
  337     if (!((iface->flags & IFF_UP) &&
  338         (LINK_STATE_IS_UP(iface->linkstate) ||
  339         (iface->linkstate == LINK_STATE_UNKNOWN &&
  340         iface->media_type != IFT_CARP))))
  341         return (0);
  342 
  343     if (iface->media_type == IFT_CARP && iface->passive == 0) {
  344         /* force passive mode on carp interfaces */
  345         log_warnx("if_act_start: forcing interface %s to passive",
  346             iface->name);
  347         iface->passive = 1;
  348     }
  349 
  350     if (iface->passive) {
  351         /* for an update of stub network entries */
  352         orig_rtr_lsa(iface->area);
  353         return (0);
  354     }
  355 
  356     gettimeofday(&now, NULL);
  357     iface->uptime = now.tv_sec;
  358 
  359     switch (iface->type) {
  360     case IF_TYPE_POINTOPOINT:
  361         inet_aton(AllSPFRouters, &addr);
  362         if (if_join_group(iface, &addr))
  363             return (-1);
  364         iface->state = IF_STA_POINTTOPOINT;
  365         break;
  366     case IF_TYPE_VIRTUALLINK:
  367         iface->state = IF_STA_POINTTOPOINT;
  368         break;
  369     case IF_TYPE_POINTOMULTIPOINT:
  370     case IF_TYPE_NBMA:
  371         log_debug("if_act_start: type %s not supported, interface %s",
  372             if_type_name(iface->type), iface->name);
  373         return (-1);
  374     case IF_TYPE_BROADCAST:
  375         inet_aton(AllSPFRouters, &addr);
  376         if (if_join_group(iface, &addr))
  377             return (-1);
  378         if (iface->priority == 0) {
  379             iface->state = IF_STA_DROTHER;
  380         } else {
  381             iface->state = IF_STA_WAITING;
  382             if_start_wait_timer(iface);
  383         }
  384         break;
  385     default:
  386         fatalx("if_act_start: unknown interface type");
  387     }
  388 
  389     /* hello timer needs to be started in any case */
  390     if_start_hello_timer(iface);
  391     return (0);
  392 }
  393 
  394 struct nbr *
  395 if_elect(struct nbr *a, struct nbr *b)
  396 {
  397     if (a->priority > b->priority)
  398         return (a);
  399     if (a->priority < b->priority)
  400         return (b);
  401     if (ntohl(a->id.s_addr) > ntohl(b->id.s_addr))
  402         return (a);
  403     return (b);
  404 }
  405 
  406 int
  407 if_act_elect(struct iface *iface)
  408 {
  409     struct in_addr   addr;
  410     struct nbr  *nbr, *bdr = NULL, *dr = NULL;
  411     int      round = 0;
  412     int      changed = 0;
  413     int      old_state;
  414     char         b1[16], b2[16], b3[16], b4[16];
  415 
  416 start:
  417     /* elect backup designated router */
  418     LIST_FOREACH(nbr, &iface->nbr_list, entry) {
  419         if (nbr->priority == 0 || nbr == dr ||  /* not electable */
  420             nbr->state & NBR_STA_PRELIM ||  /* not available */
  421             nbr->dr.s_addr == nbr->addr.s_addr) /* don't elect DR */
  422             continue;
  423         if (bdr != NULL) {
  424             /*
  425              * routers announcing themselves as BDR have higher
  426              * precedence over those routers announcing a
  427              * different BDR.
  428              */
  429             if (nbr->bdr.s_addr == nbr->addr.s_addr) {
  430                 if (bdr->bdr.s_addr == bdr->addr.s_addr)
  431                     bdr = if_elect(bdr, nbr);
  432                 else
  433                     bdr = nbr;
  434             } else if (bdr->bdr.s_addr != bdr->addr.s_addr)
  435                     bdr = if_elect(bdr, nbr);
  436         } else
  437             bdr = nbr;
  438     }
  439 
  440     /* elect designated router */
  441     LIST_FOREACH(nbr, &iface->nbr_list, entry) {
  442         if (nbr->priority == 0 || nbr->state & NBR_STA_PRELIM ||
  443             (nbr != dr && nbr->dr.s_addr != nbr->addr.s_addr))
  444             /* only DR may be elected check priority too */
  445             continue;
  446         if (dr == NULL)
  447             dr = nbr;
  448         else
  449             dr = if_elect(dr, nbr);
  450     }
  451 
  452     if (dr == NULL) {
  453         /* no designated router found use backup DR */
  454         dr = bdr;
  455         bdr = NULL;
  456     }
  457 
  458     /*
  459      * if we are involved in the election (e.g. new DR or no
  460      * longer BDR) redo the election
  461      */
  462     if (round == 0 &&
  463         ((iface->self == dr && iface->self != iface->dr) ||
  464         (iface->self != dr && iface->self == iface->dr) ||
  465         (iface->self == bdr && iface->self != iface->bdr) ||
  466         (iface->self != bdr && iface->self == iface->bdr))) {
  467         /*
  468          * Reset announced DR/BDR to calculated one, so
  469          * that we may get elected in the second round.
  470          * This is needed to drop from a DR to a BDR.
  471          */
  472         iface->self->dr.s_addr = dr->addr.s_addr;
  473         if (bdr)
  474             iface->self->bdr.s_addr = bdr->addr.s_addr;
  475         round = 1;
  476         goto start;
  477     }
  478 
  479     log_debug("if_act_elect: interface %s old dr %s new dr %s, "
  480         "old bdr %s new bdr %s", iface->name,
  481         iface->dr ? inet_ntop(AF_INET, &iface->dr->addr, b1, sizeof(b1)) :
  482         "none", dr ? inet_ntop(AF_INET, &dr->addr, b2, sizeof(b2)) : "none",
  483         iface->bdr ? inet_ntop(AF_INET, &iface->bdr->addr, b3, sizeof(b3)) :
  484         "none", bdr ? inet_ntop(AF_INET, &bdr->addr, b4, sizeof(b4)) :
  485         "none");
  486 
  487     /*
  488      * After the second round still DR or BDR change state to DR or BDR,
  489      * etc.
  490      */
  491     old_state = iface->state;
  492     if (dr == iface->self)
  493         iface->state = IF_STA_DR;
  494     else if (bdr == iface->self)
  495         iface->state = IF_STA_BACKUP;
  496     else
  497         iface->state = IF_STA_DROTHER;
  498 
  499     /* TODO if iface is NBMA send all non eligible neighbors event Start */
  500 
  501     /*
  502      * if DR or BDR changed issue a AdjOK? event for all neighbors > 2-Way
  503      */
  504     if (iface->dr != dr || iface->bdr != bdr)
  505         changed = 1;
  506 
  507     iface->dr = dr;
  508     iface->bdr = bdr;
  509 
  510     if (changed) {
  511         inet_aton(AllDRouters, &addr);
  512         if (old_state & IF_STA_DRORBDR &&
  513             (iface->state & IF_STA_DRORBDR) == 0) {
  514             if (if_leave_group(iface, &addr))
  515                 return (-1);
  516         } else if ((old_state & IF_STA_DRORBDR) == 0 &&
  517             iface->state & IF_STA_DRORBDR) {
  518             if (if_join_group(iface, &addr))
  519                 return (-1);
  520         }
  521 
  522         LIST_FOREACH(nbr, &iface->nbr_list, entry) {
  523             if (nbr->state & NBR_STA_BIDIR)
  524                 nbr_fsm(nbr, NBR_EVT_ADJ_OK);
  525         }
  526 
  527         orig_rtr_lsa(iface->area);
  528         if (iface->state & IF_STA_DR || old_state & IF_STA_DR)
  529             orig_net_lsa(iface);
  530     }
  531 
  532     if_start_hello_timer(iface);
  533     return (0);
  534 }
  535 
  536 int
  537 if_act_reset(struct iface *iface)
  538 {
  539     struct nbr      *nbr = NULL;
  540     struct in_addr       addr;
  541 
  542     if (iface->passive) {
  543         /* for an update of stub network entries */
  544         orig_rtr_lsa(iface->area);
  545         return (0);
  546     }
  547 
  548     switch (iface->type) {
  549     case IF_TYPE_POINTOPOINT:
  550     case IF_TYPE_BROADCAST:
  551         inet_aton(AllSPFRouters, &addr);
  552         if (if_leave_group(iface, &addr)) {
  553             log_warnx("if_act_reset: error leaving group %s, "
  554                 "interface %s", inet_ntoa(addr), iface->name);
  555         }
  556         if (iface->state & IF_STA_DRORBDR) {
  557             inet_aton(AllDRouters, &addr);
  558             if (if_leave_group(iface, &addr)) {
  559                 log_warnx("if_act_reset: "
  560                     "error leaving group %s, interface %s",
  561                     inet_ntoa(addr), iface->name);
  562             }
  563         }
  564         break;
  565     case IF_TYPE_VIRTUALLINK:
  566         /* nothing */
  567         break;
  568     case IF_TYPE_NBMA:
  569     case IF_TYPE_POINTOMULTIPOINT:
  570         log_debug("if_act_reset: type %s not supported, interface %s",
  571             if_type_name(iface->type), iface->name);
  572         return (-1);
  573     default:
  574         fatalx("if_act_reset: unknown interface type");
  575     }
  576 
  577     LIST_FOREACH(nbr, &iface->nbr_list, entry) {
  578         if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
  579             log_debug("if_act_reset: error killing neighbor %s",
  580                 inet_ntoa(nbr->id));
  581         }
  582     }
  583 
  584     iface->dr = NULL;
  585     iface->bdr = NULL;
  586 
  587     ls_ack_list_clr(iface);
  588     stop_ls_ack_tx_timer(iface);
  589     if_stop_hello_timer(iface);
  590     if_stop_wait_timer(iface);
  591 
  592     /* send empty hello to tell everybody that we are going down */
  593     send_hello(iface);
  594 
  595     return (0);
  596 }
  597 
  598 struct ctl_iface *
  599 if_to_ctl(struct iface *iface)
  600 {
  601     static struct ctl_iface  ictl;
  602     struct timeval       tv, now, res;
  603     struct nbr      *nbr;
  604 
  605     memcpy(ictl.name, iface->name, sizeof(ictl.name));
  606     memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
  607     memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
  608     ictl.rtr_id.s_addr = ospfe_router_id();
  609     memcpy(&ictl.area, &iface->area->id, sizeof(ictl.area));
  610     if (iface->dr) {
  611         memcpy(&ictl.dr_id, &iface->dr->id, sizeof(ictl.dr_id));
  612         memcpy(&ictl.dr_addr, &iface->dr->addr, sizeof(ictl.dr_addr));
  613     } else {
  614         bzero(&ictl.dr_id, sizeof(ictl.dr_id));
  615         bzero(&ictl.dr_addr, sizeof(ictl.dr_addr));
  616     }
  617     if (iface->bdr) {
  618         memcpy(&ictl.bdr_id, &iface->bdr->id, sizeof(ictl.bdr_id));
  619         memcpy(&ictl.bdr_addr, &iface->bdr->addr,
  620             sizeof(ictl.bdr_addr));
  621     } else {
  622         bzero(&ictl.bdr_id, sizeof(ictl.bdr_id));
  623         bzero(&ictl.bdr_addr, sizeof(ictl.bdr_addr));
  624     }
  625     ictl.ifindex = iface->ifindex;
  626     ictl.state = iface->state;
  627     ictl.mtu = iface->mtu;
  628     ictl.nbr_cnt = 0;
  629     ictl.adj_cnt = 0;
  630     ictl.baudrate = iface->baudrate;
  631     ictl.dead_interval = iface->dead_interval;
  632     ictl.transmit_delay = iface->transmit_delay;
  633     ictl.hello_interval = iface->hello_interval;
  634     ictl.flags = iface->flags;
  635     ictl.metric = iface->metric;
  636     ictl.rxmt_interval = iface->rxmt_interval;
  637     ictl.type = iface->type;
  638     ictl.linkstate = iface->linkstate;
  639     ictl.mediatype = iface->media_type;
  640     ictl.priority = iface->priority;
  641     ictl.passive = iface->passive;
  642     ictl.auth_type = iface->auth_type;
  643     ictl.auth_keyid = iface->auth_keyid;
  644 
  645     gettimeofday(&now, NULL);
  646     if (evtimer_pending(&iface->hello_timer, &tv)) {
  647         timersub(&tv, &now, &res);
  648         ictl.hello_timer = res.tv_sec;
  649     } else
  650         ictl.hello_timer = -1;
  651 
  652     if (iface->state != IF_STA_DOWN) {
  653         ictl.uptime = now.tv_sec - iface->uptime;
  654     } else
  655         ictl.uptime = 0;
  656 
  657     LIST_FOREACH(nbr, &iface->nbr_list, entry) {
  658         if (nbr == iface->self)
  659             continue;
  660         ictl.nbr_cnt++;
  661         if (nbr->state & NBR_STA_ADJFORM)
  662             ictl.adj_cnt++;
  663     }
  664 
  665     return (&ictl);
  666 }
  667 
  668 /* misc */
  669 int
  670 if_set_recvif(int fd, int enable)
  671 {
  672     if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
  673         sizeof(enable)) < 0) {
  674         log_warn("if_set_recvif: error setting IP_RECVIF");
  675         return (-1);
  676     }
  677     return (0);
  678 }
  679 
  680 void
  681 if_set_recvbuf(int fd)
  682 {
  683     int bsize;
  684 
  685     bsize = 65535;
  686     while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
  687         sizeof(bsize)) == -1)
  688         bsize /= 2;
  689 }
  690 
  691 /*
  692  * only one JOIN or DROP per interface and address is allowed so we need
  693  * to keep track of what is added and removed.
  694  */
  695 struct if_group_count {
  696     LIST_ENTRY(if_group_count)  entry;
  697     struct in_addr          addr;
  698     unsigned int            ifindex;
  699     int             count;
  700 };
  701 
  702 LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
  703 
  704 int
  705 if_join_group(struct iface *iface, struct in_addr *addr)
  706 {
  707     struct ip_mreq       mreq;
  708     struct if_group_count   *ifg;
  709 
  710     switch (iface->type) {
  711     case IF_TYPE_POINTOPOINT:
  712     case IF_TYPE_BROADCAST:
  713         LIST_FOREACH(ifg, &ifglist, entry)
  714             if (iface->ifindex == ifg->ifindex &&
  715                 addr->s_addr == ifg->addr.s_addr)
  716                 break;
  717         if (ifg == NULL) {
  718             if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
  719                 fatal("if_join_group");
  720             ifg->addr.s_addr = addr->s_addr;
  721             ifg->ifindex = iface->ifindex;
  722             LIST_INSERT_HEAD(&ifglist, ifg, entry);
  723         }
  724 
  725         if (ifg->count++ != 0)
  726             /* already joined */
  727             return (0);
  728 
  729         mreq.imr_multiaddr.s_addr = addr->s_addr;
  730         mreq.imr_interface.s_addr = iface->addr.s_addr;
  731 
  732         if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  733             (void *)&mreq, sizeof(mreq)) < 0) {
  734             log_warn("if_join_group: error IP_ADD_MEMBERSHIP, "
  735                 "interface %s address %s", iface->name,
  736                 inet_ntoa(*addr));
  737             return (-1);
  738         }
  739         break;
  740     case IF_TYPE_POINTOMULTIPOINT:
  741     case IF_TYPE_VIRTUALLINK:
  742     case IF_TYPE_NBMA:
  743         log_debug("if_join_group: type %s not supported, interface %s",
  744             if_type_name(iface->type), iface->name);
  745         return (-1);
  746     default:
  747         fatalx("if_join_group: unknown interface type");
  748     }
  749 
  750     return (0);
  751 }
  752 
  753 int
  754 if_leave_group(struct iface *iface, struct in_addr *addr)
  755 {
  756     struct ip_mreq       mreq;
  757     struct if_group_count   *ifg;
  758 
  759     switch (iface->type) {
  760     case IF_TYPE_POINTOPOINT:
  761     case IF_TYPE_BROADCAST:
  762         LIST_FOREACH(ifg, &ifglist, entry)
  763             if (iface->ifindex == ifg->ifindex &&
  764                 addr->s_addr == ifg->addr.s_addr)
  765                 break;
  766 
  767         /* if interface is not found just try to drop membership */
  768         if (ifg && --ifg->count != 0)
  769             /* others still joined */
  770             return (0);
  771 
  772         mreq.imr_multiaddr.s_addr = addr->s_addr;
  773         mreq.imr_interface.s_addr = iface->addr.s_addr;
  774 
  775         if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
  776             (void *)&mreq, sizeof(mreq)) < 0) {
  777             log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, "
  778                 "interface %s address %s", iface->name,
  779                 inet_ntoa(*addr));
  780             return (-1);
  781         }
  782 
  783         if (ifg) {
  784             LIST_REMOVE(ifg, entry);
  785             free(ifg);
  786         }
  787         break;
  788     case IF_TYPE_POINTOMULTIPOINT:
  789     case IF_TYPE_VIRTUALLINK:
  790     case IF_TYPE_NBMA:
  791         log_debug("if_leave_group: type %s not supported, interface %s",
  792             if_type_name(iface->type), iface->name);
  793         return (-1);
  794     default:
  795         fatalx("if_leave_group: unknown interface type");
  796     }
  797 
  798     return (0);
  799 }
  800 
  801 int
  802 if_set_mcast(struct iface *iface)
  803 {
  804     switch (iface->type) {
  805     case IF_TYPE_POINTOPOINT:
  806     case IF_TYPE_BROADCAST:
  807         if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
  808             &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) {
  809             log_debug("if_set_mcast: error setting "
  810                 "IP_MULTICAST_IF, interface %s", iface->name);
  811             return (-1);
  812         }
  813         break;
  814     case IF_TYPE_POINTOMULTIPOINT:
  815     case IF_TYPE_VIRTUALLINK:
  816     case IF_TYPE_NBMA:
  817         log_debug("if_set_mcast: type %s not supported, interface %s",
  818             if_type_name(iface->type), iface->name);
  819         return (-1);
  820     default:
  821         fatalx("if_set_mcast: unknown interface type");
  822     }
  823 
  824     return (0);
  825 }
  826 
  827 int
  828 if_set_mcast_loop(int fd)
  829 {
  830     u_int8_t    loop = 0;
  831 
  832     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
  833         (char *)&loop, sizeof(loop)) < 0) {
  834         log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
  835         return (-1);
  836     }
  837 
  838     return (0);
  839 }
  840 
  841 int
  842 if_set_ip_hdrincl(int fd)
  843 {
  844     int hincl = 1;
  845 
  846     if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) {
  847         log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL");
  848         return (-1);
  849     }
  850 
  851     return (0);
  852 }