"Fossies" - the Fresh Open Source Software Archive

Member "ospfd/database.c" (31 Jan 2009, 10396 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 "database.c" see the Fossies "Dox" file reference documentation.

    1 /*  $OpenBSD: database.c,v 1.26 2009/01/31 11:44:49 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/socket.h>
   22 #include <netinet/in.h>
   23 #include <netinet/in_systm.h>
   24 #include <netinet/ip.h>
   25 #include <arpa/inet.h>
   26 #include <stdlib.h>
   27 #include <string.h>
   28 #include <unistd.h>
   29 
   30 #include "ospfd.h"
   31 #include "ospf.h"
   32 #include "log.h"
   33 #include "ospfe.h"
   34 
   35 extern struct ospfd_conf    *oeconf;
   36 
   37 void    db_sum_list_next(struct nbr *);
   38 
   39 /* database description packet handling */
   40 int
   41 send_db_description(struct nbr *nbr)
   42 {
   43     struct sockaddr_in   dst;
   44     struct db_dscrp_hdr  dd_hdr;
   45     struct lsa_entry    *le, *nle;
   46     struct buf      *buf;
   47     int          ret = 0;
   48     u_int8_t         bits = 0;
   49 
   50     if ((buf = buf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL)
   51         fatal("send_db_description");
   52 
   53     /* OSPF header */
   54     if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
   55         goto fail;
   56 
   57     /* reserve space for database description header */
   58     if (buf_reserve(buf, sizeof(dd_hdr)) == NULL)
   59         goto fail;
   60 
   61     switch (nbr->state) {
   62     case NBR_STA_DOWN:
   63     case NBR_STA_ATTEMPT:
   64     case NBR_STA_INIT:
   65     case NBR_STA_2_WAY:
   66     case NBR_STA_SNAP:
   67         log_debug("send_db_description: cannot send packet in state %s,"
   68             " neighbor ID %s", nbr_state_name(nbr->state),
   69             inet_ntoa(nbr->id));
   70         ret = -1;
   71         goto done;
   72     case NBR_STA_XSTRT:
   73         bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
   74         nbr->dd_more = 1;
   75         break;
   76     case NBR_STA_XCHNG:
   77         if (nbr->dd_master)
   78             bits |= OSPF_DBD_MS;
   79         else
   80             bits &= ~OSPF_DBD_MS;
   81 
   82         if (TAILQ_EMPTY(&nbr->db_sum_list)) {
   83             bits &= ~OSPF_DBD_M;
   84             nbr->dd_more = 0;
   85         } else {
   86             bits |= OSPF_DBD_M;
   87             nbr->dd_more = 1;
   88         }
   89 
   90         bits &= ~OSPF_DBD_I;
   91 
   92         /* build LSA list, keep space for a possible md5 sum */
   93         for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
   94             buf_left(buf) >= MD5_DIGEST_LENGTH + sizeof(struct lsa_hdr);
   95             le = nle) {
   96             nbr->dd_end = nle = TAILQ_NEXT(le, entry);
   97             if (buf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
   98                 goto fail;
   99         }
  100         break;
  101     case NBR_STA_LOAD:
  102     case NBR_STA_FULL:
  103         if (nbr->dd_master)
  104             bits |= OSPF_DBD_MS;
  105         else
  106             bits &= ~OSPF_DBD_MS;
  107         bits &= ~OSPF_DBD_M;
  108         bits &= ~OSPF_DBD_I;
  109 
  110         nbr->dd_more = 0;
  111         break;
  112     default:
  113         fatalx("send_db_description: unknown neighbor state");
  114     }
  115 
  116     /* set destination */
  117     dst.sin_family = AF_INET;
  118     dst.sin_len = sizeof(struct sockaddr_in);
  119 
  120     switch (nbr->iface->type) {
  121     case IF_TYPE_POINTOPOINT:
  122         inet_aton(AllSPFRouters, &dst.sin_addr);
  123         dd_hdr.iface_mtu = htons(nbr->iface->mtu);
  124         break;
  125     case IF_TYPE_BROADCAST:
  126         dst.sin_addr = nbr->addr;
  127         dd_hdr.iface_mtu = htons(nbr->iface->mtu);
  128         break;
  129     case IF_TYPE_NBMA:
  130     case IF_TYPE_POINTOMULTIPOINT:
  131         /* XXX not supported */
  132         break;
  133     case IF_TYPE_VIRTUALLINK:
  134         dst.sin_addr = nbr->iface->dst;
  135         dd_hdr.iface_mtu = 0;
  136         break;
  137     default:
  138         fatalx("send_db_description: unknown interface type");
  139     }
  140 
  141     dd_hdr.opts = area_ospf_options(nbr->iface->area);
  142     dd_hdr.bits = bits;
  143     dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
  144 
  145     memcpy(buf_seek(buf, sizeof(struct ospf_hdr), sizeof(dd_hdr)),
  146         &dd_hdr, sizeof(dd_hdr));
  147 
  148     /* update authentication and calculate checksum */
  149     if (auth_gen(buf, nbr->iface))
  150         goto fail;
  151 
  152     /* transmit packet */
  153     ret = send_packet(nbr->iface, buf, &dst);
  154 done:
  155     buf_free(buf);
  156     return (ret);
  157 fail:
  158     log_warn("send_db_description");
  159     buf_free(buf);
  160     return (-1);
  161 }
  162 
  163 void
  164 recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
  165 {
  166     struct db_dscrp_hdr  dd_hdr;
  167     int          dupe = 0;
  168 
  169     if (len < sizeof(dd_hdr)) {
  170         log_warnx("recv_db_description: "
  171             "bad packet size, neighbor ID %s", inet_ntoa(nbr->id));
  172         return;
  173     }
  174     memcpy(&dd_hdr, buf, sizeof(dd_hdr));
  175     buf += sizeof(dd_hdr);
  176     len -= sizeof(dd_hdr);
  177 
  178     /* db description packet sanity checks */
  179     if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
  180         log_warnx("recv_db_description: invalid MTU %d sent by "
  181             "neighbor ID %s, expected %d", ntohs(dd_hdr.iface_mtu),
  182             inet_ntoa(nbr->id), nbr->iface->mtu);
  183         return;
  184     }
  185 
  186     if (nbr->last_rx_options == dd_hdr.opts &&
  187         nbr->last_rx_bits == dd_hdr.bits &&
  188         ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
  189         1 : 0) {
  190             log_debug("recv_db_description: dupe from ID %s",
  191                 inet_ntoa(nbr->id));
  192             dupe = 1;
  193     }
  194 
  195     switch (nbr->state) {
  196     case NBR_STA_DOWN:
  197     case NBR_STA_ATTEMPT:
  198     case NBR_STA_2_WAY:
  199     case NBR_STA_SNAP:
  200         log_debug("recv_db_description: packet ignored in state %s, "
  201             "neighbor ID %s", nbr_state_name(nbr->state),
  202             inet_ntoa(nbr->id));
  203         return;
  204     case NBR_STA_INIT:
  205         /* evaluate dr and bdr after issuing a 2-Way event */
  206         nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
  207         if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
  208         if (nbr->state != NBR_STA_XSTRT)
  209             return;
  210         /* FALLTHROUGH */
  211     case NBR_STA_XSTRT:
  212         if (dupe)
  213             return;
  214         /*
  215          * check bits: either I,M,MS or only M
  216          */
  217         if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
  218             /* if nbr Router ID is larger than own -> slave */
  219             if ((ntohl(nbr->id.s_addr)) >
  220                 ntohl(ospfe_router_id())) {
  221                 /* slave */
  222                 nbr->dd_master = 0;
  223                 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
  224 
  225                 /* event negotiation done */
  226                 nbr_fsm(nbr, NBR_EVT_NEG_DONE);
  227             }
  228         } else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
  229             /* M only case: we are master */
  230             if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
  231                 log_warnx("recv_db_description: invalid "
  232                     "seq num, mine %x his %x",
  233                     nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
  234                 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
  235                 return;
  236             }
  237             nbr->dd_seq_num++;
  238 
  239             /* event negotiation done */
  240             nbr_fsm(nbr, NBR_EVT_NEG_DONE);
  241 
  242             /* this packet may already have data so pass it on */
  243             if (len > 0) {
  244                 nbr->dd_pending++;
  245                 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
  246                     0, buf, len);
  247             }
  248         } else {
  249             /* ignore packet */
  250             log_debug("recv_db_description: packet ignored in "
  251                 "state %s (bad flags), neighbor ID %s",
  252                 nbr_state_name(nbr->state), inet_ntoa(nbr->id));
  253         }
  254         break;
  255     case NBR_STA_XCHNG:
  256     case NBR_STA_LOAD:
  257     case NBR_STA_FULL:
  258         if (dd_hdr.bits & OSPF_DBD_I ||
  259             !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
  260             log_warnx("recv_db_description: seq num mismatch, "
  261                 "bad flags");
  262             nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
  263             return;
  264         }
  265 
  266         if (nbr->last_rx_options != dd_hdr.opts) {
  267             log_warnx("recv_db_description: seq num mismatch, "
  268                 "bad options");
  269             nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
  270             return;
  271         }
  272 
  273         if (dupe) {
  274             if (!nbr->dd_master)
  275                 /* retransmit */
  276                 start_db_tx_timer(nbr);
  277             return;
  278         }
  279 
  280         if (nbr->state != NBR_STA_XCHNG) {
  281             log_warnx("recv_db_description: invalid "
  282                 "seq num, mine %x his %x",
  283                 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
  284             nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
  285             return;
  286         }
  287 
  288         /* sanity check dd seq number */
  289         if (nbr->dd_master) {
  290             /* master */
  291             if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
  292                 log_warnx("recv_db_description: invalid "
  293                     "seq num, mine %x his %x",
  294                     nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
  295                 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
  296                 return;
  297             }
  298             nbr->dd_seq_num++;
  299         } else {
  300             /* slave */
  301             if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
  302                 log_warnx("recv_db_description: invalid "
  303                     "seq num, mine %x his %x",
  304                     nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
  305                 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
  306                 return;
  307             }
  308             nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
  309         }
  310 
  311         /* forward to RDE and let it decide which LSAs to request */
  312         if (len > 0) {
  313             nbr->dd_pending++;
  314             ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
  315                 buf, len);
  316         }
  317 
  318         /* next packet */
  319         db_sum_list_next(nbr);
  320         start_db_tx_timer(nbr);
  321 
  322         if (!(dd_hdr.bits & OSPF_DBD_M) &&
  323             TAILQ_EMPTY(&nbr->db_sum_list))
  324             if (!nbr->dd_master || !nbr->dd_more)
  325                 nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
  326         break;
  327     default:
  328         fatalx("recv_db_description: unknown neighbor state");
  329     }
  330 
  331     nbr->last_rx_options = dd_hdr.opts;
  332     nbr->last_rx_bits = dd_hdr.bits;
  333 }
  334 
  335 void
  336 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
  337 {
  338     struct lsa_entry    *le;
  339 
  340     if ((le = calloc(1, sizeof(*le))) == NULL)
  341         fatal("db_sum_list_add");
  342 
  343     TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
  344     le->le_lsa = lsa;
  345 }
  346 
  347 void
  348 db_sum_list_next(struct nbr *nbr)
  349 {
  350     struct lsa_entry    *le;
  351 
  352     while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
  353         TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
  354         free(le->le_lsa);
  355         free(le);
  356     }
  357 }
  358 
  359 void
  360 db_sum_list_clr(struct nbr *nbr)
  361 {
  362     nbr->dd_end = NULL;
  363     db_sum_list_next(nbr);
  364 }
  365 
  366 /* timers */
  367 /* ARGSUSED */
  368 void
  369 db_tx_timer(int fd, short event, void *arg)
  370 {
  371     struct nbr *nbr = arg;
  372     struct timeval tv;
  373 
  374     switch (nbr->state) {
  375     case NBR_STA_DOWN:
  376     case NBR_STA_ATTEMPT:
  377     case NBR_STA_INIT:
  378     case NBR_STA_2_WAY:
  379     case NBR_STA_SNAP:
  380         return ;
  381     case NBR_STA_XSTRT:
  382     case NBR_STA_XCHNG:
  383     case NBR_STA_LOAD:
  384     case NBR_STA_FULL:
  385         send_db_description(nbr);
  386         break;
  387     default:
  388         log_debug("db_tx_timer: unknown neighbor state, "
  389             "neighbor ID %s", inet_ntoa(nbr->id));
  390         break;
  391     }
  392 
  393     /* reschedule db_tx_timer but only in master mode */
  394     if (nbr->dd_master) {
  395         timerclear(&tv);
  396         tv.tv_sec = nbr->iface->rxmt_interval;
  397         if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
  398             fatal("db_tx_timer");
  399     }
  400 }
  401 
  402 void
  403 start_db_tx_timer(struct nbr *nbr)
  404 {
  405     struct timeval  tv;
  406 
  407     if (nbr == nbr->iface->self)
  408         return;
  409 
  410     timerclear(&tv);
  411     if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
  412         fatal("start_db_tx_timer");
  413 }
  414 
  415 void
  416 stop_db_tx_timer(struct nbr *nbr)
  417 {
  418     if (nbr == nbr->iface->self)
  419         return;
  420 
  421     if (evtimer_del(&nbr->db_tx_timer) == -1)
  422         fatal("stop_db_tx_timer");
  423 }