File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ospfd / ospf_api.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:12 2016 UTC (7 years, 8 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    1: /*
    2:  * API message handling module for OSPF daemon and client.
    3:  * Copyright (C) 2001, 2002 Ralph Keller
    4:  *
    5:  * This file is part of GNU Zebra.
    6:  * 
    7:  * GNU Zebra is free software; you can redistribute it and/or modify
    8:  * it under the terms of the GNU General Public License as published
    9:  * by the Free Software Foundation; either version 2, or (at your
   10:  * option) any later version.
   11:  *
   12:  * GNU Zebra is distributed in the hope that it will be useful, but
   13:  * WITHOUT ANY WARRANTY; without even the implied warranty of
   14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15:  * General Public License for more details.
   16:  *
   17:  * You should have received a copy of the GNU General Public License
   18:  * along with GNU Zebra; see the file COPYING.  If not, write to the
   19:  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   20:  * Boston, MA 02111-1307, USA.
   21:  */
   22: 
   23: #include <zebra.h>
   24: 
   25: #ifdef SUPPORT_OSPF_API
   26: 
   27: #include "linklist.h"
   28: #include "prefix.h"
   29: #include "if.h"
   30: #include "table.h"
   31: #include "memory.h"
   32: #include "command.h"
   33: #include "vty.h"
   34: #include "stream.h"
   35: #include "log.h"
   36: #include "thread.h"
   37: #include "hash.h"
   38: #include "sockunion.h"		/* for inet_aton() */
   39: #include "buffer.h"
   40: #include "network.h"
   41: 
   42: #include "ospfd/ospfd.h"
   43: #include "ospfd/ospf_interface.h"
   44: #include "ospfd/ospf_ism.h"
   45: #include "ospfd/ospf_asbr.h"
   46: #include "ospfd/ospf_lsa.h"
   47: #include "ospfd/ospf_lsdb.h"
   48: #include "ospfd/ospf_neighbor.h"
   49: #include "ospfd/ospf_nsm.h"
   50: #include "ospfd/ospf_flood.h"
   51: #include "ospfd/ospf_packet.h"
   52: #include "ospfd/ospf_spf.h"
   53: #include "ospfd/ospf_dump.h"
   54: #include "ospfd/ospf_route.h"
   55: #include "ospfd/ospf_ase.h"
   56: #include "ospfd/ospf_zebra.h"
   57: 
   58: #include "ospfd/ospf_api.h"
   59: 
   60: 
   61: /* For debugging only, will be removed */
   62: void
   63: api_opaque_lsa_print (struct lsa_header *data)
   64: {
   65:   struct opaque_lsa
   66:   {
   67:     struct lsa_header header;
   68:     u_char mydata[];
   69:   };
   70: 
   71:   struct opaque_lsa *olsa;
   72:   int opaquelen;
   73:   int i;
   74: 
   75:   ospf_lsa_header_dump (data);
   76: 
   77:   olsa = (struct opaque_lsa *) data;
   78: 
   79:   opaquelen = ntohs (data->length) - OSPF_LSA_HEADER_SIZE;
   80:   zlog_debug ("apiserver_lsa_print: opaquelen=%d\n", opaquelen);
   81: 
   82:   for (i = 0; i < opaquelen; i++)
   83:     {
   84:       zlog_debug ("0x%x ", olsa->mydata[i]);
   85:     }
   86:   zlog_debug ("\n");
   87: }
   88: 
   89: /* -----------------------------------------------------------
   90:  * Generic messages
   91:  * -----------------------------------------------------------
   92:  */
   93: 
   94: struct msg *
   95: msg_new (u_char msgtype, void *msgbody, u_int32_t seqnum, u_int16_t msglen)
   96: {
   97:   struct msg *new;
   98: 
   99:   new = XCALLOC (MTYPE_OSPF_API_MSG, sizeof (struct msg));
  100: 
  101:   new->hdr.version = OSPF_API_VERSION;
  102:   new->hdr.msgtype = msgtype;
  103:   new->hdr.msglen = htons (msglen);
  104:   new->hdr.msgseq = htonl (seqnum);
  105: 
  106:   new->s = stream_new (msglen);
  107:   assert (new->s);
  108:   stream_put (new->s, msgbody, msglen);
  109: 
  110:   return new;
  111: }
  112: 
  113: 
  114: /* Duplicate a message by copying content. */
  115: struct msg *
  116: msg_dup (struct msg *msg)
  117: {
  118:   struct msg *new;
  119: 
  120:   assert (msg);
  121: 
  122:   new = msg_new (msg->hdr.msgtype, STREAM_DATA (msg->s),
  123: 		 ntohl (msg->hdr.msgseq), ntohs (msg->hdr.msglen));
  124:   return new;
  125: }
  126: 
  127: 
  128: /* XXX only for testing, will be removed */
  129: 
  130: struct nametab {
  131:   int value;
  132:   const char *name;
  133: };
  134: 
  135: const char *
  136: ospf_api_typename (int msgtype)
  137: {
  138:   struct nametab NameTab[] = {
  139:     { MSG_REGISTER_OPAQUETYPE,   "Register opaque-type",   },
  140:     { MSG_UNREGISTER_OPAQUETYPE, "Unregister opaque-type", },
  141:     { MSG_REGISTER_EVENT,        "Register event",         },
  142:     { MSG_SYNC_LSDB,             "Sync LSDB",              },
  143:     { MSG_ORIGINATE_REQUEST,     "Originate request",      },
  144:     { MSG_DELETE_REQUEST,        "Delete request",         },
  145:     { MSG_REPLY,                 "Reply",                  },
  146:     { MSG_READY_NOTIFY,          "Ready notify",           },
  147:     { MSG_LSA_UPDATE_NOTIFY,     "LSA update notify",      },
  148:     { MSG_LSA_DELETE_NOTIFY,     "LSA delete notify",      },
  149:     { MSG_NEW_IF,                "New interface",          },
  150:     { MSG_DEL_IF,                "Del interface",          },
  151:     { MSG_ISM_CHANGE,            "ISM change",             },
  152:     { MSG_NSM_CHANGE,            "NSM change",             },
  153:   };
  154: 
  155:   int i, n = array_size(NameTab);
  156:   const char *name = NULL;
  157: 
  158:   for (i = 0; i < n; i++)
  159:     {
  160:       if (NameTab[i].value == msgtype)
  161:         {
  162:           name = NameTab[i].name;
  163:           break;
  164:         }
  165:     }
  166: 
  167:   return name ? name : "?";
  168: }
  169: 
  170: const char *
  171: ospf_api_errname (int errcode)
  172: {
  173:   struct nametab NameTab[] = {
  174:     { OSPF_API_OK,                      "OK",                         },
  175:     { OSPF_API_NOSUCHINTERFACE,         "No such interface",          },
  176:     { OSPF_API_NOSUCHAREA,              "No such area",               },
  177:     { OSPF_API_NOSUCHLSA,               "No such LSA",                },
  178:     { OSPF_API_ILLEGALLSATYPE,          "Illegal LSA type",           },
  179:     { OSPF_API_OPAQUETYPEINUSE,         "Opaque type in use",         },
  180:     { OSPF_API_OPAQUETYPENOTREGISTERED, "Opaque type not registered", },
  181:     { OSPF_API_NOTREADY,                "Not ready",                  },
  182:     { OSPF_API_NOMEMORY,                "No memory",                  },
  183:     { OSPF_API_ERROR,                   "Other error",                },
  184:     { OSPF_API_UNDEF,                   "Undefined",                  },
  185:   };
  186: 
  187:   int i, n = array_size(NameTab);
  188:   const char *name = NULL;
  189: 
  190:   for (i = 0; i < n; i++)
  191:     {
  192:       if (NameTab[i].value == errcode)
  193:         {
  194:           name = NameTab[i].name;
  195:           break;
  196:         }
  197:     }
  198: 
  199:   return name ? name : "?";
  200: }
  201: 
  202: void
  203: msg_print (struct msg *msg)
  204: {
  205:   if (!msg)
  206:     {
  207:       zlog_debug ("msg_print msg=NULL!\n");
  208:       return;
  209:     }
  210: 
  211: #ifdef ORIGINAL_CODING
  212:   zlog_debug
  213:     ("msg=%p msgtype=%d msglen=%d msgseq=%d streamdata=%p streamsize=%lu\n",
  214:      msg, msg->hdr.msgtype, ntohs (msg->hdr.msglen), ntohl (msg->hdr.msgseq),
  215:      STREAM_DATA (msg->s), STREAM_SIZE (msg->s));
  216: #else /* ORIGINAL_CODING */
  217:   /* API message common header part. */
  218:   zlog_debug
  219:     ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)",
  220:      ospf_api_typename (msg->hdr.msgtype), msg->hdr.msgtype, 
  221:      ntohs (msg->hdr.msglen), (unsigned long) ntohl (msg->hdr.msgseq),
  222:      STREAM_DATA (msg->s), STREAM_SIZE (msg->s));
  223: 
  224:   /* API message body part. */
  225: #ifdef ndef
  226:   /* Generic Hex/Ascii dump */
  227:   DumpBuf (STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); /* Sorry, deleted! */
  228: #else /* ndef */
  229:   /* Message-type dependent dump function. */
  230: #endif /* ndef */
  231: 
  232:   return;
  233: #endif /* ORIGINAL_CODING */
  234: }
  235: 
  236: void
  237: msg_free (struct msg *msg)
  238: {
  239:   if (msg->s)
  240:     stream_free (msg->s);
  241: 
  242:   XFREE (MTYPE_OSPF_API_MSG, msg);
  243: }
  244: 
  245: 
  246: /* Set sequence number of message */
  247: void
  248: msg_set_seq (struct msg *msg, u_int32_t seqnr)
  249: {
  250:   assert (msg);
  251:   msg->hdr.msgseq = htonl (seqnr);
  252: }
  253: 
  254: /* Get sequence number of message */
  255: u_int32_t
  256: msg_get_seq (struct msg *msg)
  257: {
  258:   assert (msg);
  259:   return ntohl (msg->hdr.msgseq);
  260: }
  261: 
  262: /* -----------------------------------------------------------
  263:  * Message fifo queues
  264:  * -----------------------------------------------------------
  265:  */
  266: 
  267: struct msg_fifo *
  268: msg_fifo_new ()
  269: {
  270:   return XCALLOC (MTYPE_OSPF_API_FIFO, sizeof (struct msg_fifo));
  271: }
  272: 
  273: /* Add new message to fifo. */
  274: void
  275: msg_fifo_push (struct msg_fifo *fifo, struct msg *msg)
  276: {
  277:   if (fifo->tail)
  278:     fifo->tail->next = msg;
  279:   else
  280:     fifo->head = msg;
  281: 
  282:   fifo->tail = msg;
  283:   fifo->count++;
  284: }
  285: 
  286: 
  287: /* Remove first message from fifo. */
  288: struct msg *
  289: msg_fifo_pop (struct msg_fifo *fifo)
  290: {
  291:   struct msg *msg;
  292: 
  293:   msg = fifo->head;
  294:   if (msg)
  295:     {
  296:       fifo->head = msg->next;
  297: 
  298:       if (fifo->head == NULL)
  299: 	fifo->tail = NULL;
  300: 
  301:       fifo->count--;
  302:     }
  303:   return msg;
  304: }
  305: 
  306: /* Return first fifo entry but do not remove it. */
  307: struct msg *
  308: msg_fifo_head (struct msg_fifo *fifo)
  309: {
  310:   return fifo->head;
  311: }
  312: 
  313: /* Flush message fifo. */
  314: void
  315: msg_fifo_flush (struct msg_fifo *fifo)
  316: {
  317:   struct msg *op;
  318:   struct msg *next;
  319: 
  320:   for (op = fifo->head; op; op = next)
  321:     {
  322:       next = op->next;
  323:       msg_free (op);
  324:     }
  325: 
  326:   fifo->head = fifo->tail = NULL;
  327:   fifo->count = 0;
  328: }
  329: 
  330: /* Free API message fifo. */
  331: void
  332: msg_fifo_free (struct msg_fifo *fifo)
  333: {
  334:   msg_fifo_flush (fifo);
  335: 
  336:   XFREE (MTYPE_OSPF_API_FIFO, fifo);
  337: }
  338: 
  339: struct msg *
  340: msg_read (int fd)
  341: {
  342:   struct msg *msg;
  343:   struct apimsghdr hdr;
  344:   u_char buf[OSPF_API_MAX_MSG_SIZE];
  345:   int bodylen;
  346:   int rlen;
  347: 
  348:   /* Read message header */
  349:   rlen = readn (fd, (u_char *) &hdr, sizeof (struct apimsghdr));
  350: 
  351:   if (rlen < 0)
  352:     {
  353:       zlog_warn ("msg_read: readn %s", safe_strerror (errno));
  354:       return NULL;
  355:     }
  356:   else if (rlen == 0)
  357:     {
  358:       zlog_warn ("msg_read: Connection closed by peer");
  359:       return NULL;
  360:     }
  361:   else if (rlen != sizeof (struct apimsghdr))
  362:     {
  363:       zlog_warn ("msg_read: Cannot read message header!");
  364:       return NULL;
  365:     }
  366: 
  367:   /* Check version of API protocol */
  368:   if (hdr.version != OSPF_API_VERSION)
  369:     {
  370:       zlog_warn ("msg_read: OSPF API protocol version mismatch");
  371:       return NULL;
  372:     }
  373: 
  374:   /* Determine body length. */
  375:   bodylen = ntohs (hdr.msglen);
  376:   if (bodylen > 0)
  377:     {
  378: 
  379:       /* Read message body */
  380:       rlen = readn (fd, buf, bodylen);
  381:       if (rlen < 0)
  382: 	{
  383: 	  zlog_warn ("msg_read: readn %s", safe_strerror (errno));
  384: 	  return NULL;
  385: 	}
  386:       else if (rlen == 0)
  387: 	{
  388: 	  zlog_warn ("msg_read: Connection closed by peer");
  389: 	  return NULL;
  390: 	}
  391:       else if (rlen != bodylen)
  392: 	{
  393: 	  zlog_warn ("msg_read: Cannot read message body!");
  394: 	  return NULL;
  395: 	}
  396:     }
  397: 
  398:   /* Allocate new message */
  399:   msg = msg_new (hdr.msgtype, buf, ntohl (hdr.msgseq), ntohs (hdr.msglen));
  400: 
  401:   return msg;
  402: }
  403: 
  404: int
  405: msg_write (int fd, struct msg *msg)
  406: {
  407:   u_char buf[OSPF_API_MAX_MSG_SIZE];
  408:   int l;
  409:   int wlen;
  410: 
  411:   assert (msg);
  412:   assert (msg->s);
  413: 
  414:   /* Length of message including header */
  415:   l = sizeof (struct apimsghdr) + ntohs (msg->hdr.msglen);
  416: 
  417:   /* Make contiguous memory buffer for message */
  418:   memcpy (buf, &msg->hdr, sizeof (struct apimsghdr));
  419:   memcpy (buf + sizeof (struct apimsghdr), STREAM_DATA (msg->s),
  420: 	  ntohs (msg->hdr.msglen));
  421: 
  422:   wlen = writen (fd, buf, l);
  423:   if (wlen < 0)
  424:     {
  425:       zlog_warn ("msg_write: writen %s", safe_strerror (errno));
  426:       return -1;
  427:     }
  428:   else if (wlen == 0)
  429:     {
  430:       zlog_warn ("msg_write: Connection closed by peer");
  431:       return -1;
  432:     }
  433:   else if (wlen != l)
  434:     {
  435:       zlog_warn ("msg_write: Cannot write API message");
  436:       return -1;
  437:     }
  438:   return 0;
  439: }
  440: 
  441: /* -----------------------------------------------------------
  442:  * Specific messages
  443:  * -----------------------------------------------------------
  444:  */
  445: 
  446: struct msg *
  447: new_msg_register_opaque_type (u_int32_t seqnum, u_char ltype, u_char otype)
  448: {
  449:   struct msg_register_opaque_type rmsg;
  450: 
  451:   rmsg.lsatype = ltype;
  452:   rmsg.opaquetype = otype;
  453:   memset (&rmsg.pad, 0, sizeof (rmsg.pad));
  454: 
  455:   return msg_new (MSG_REGISTER_OPAQUETYPE, &rmsg, seqnum,
  456: 		  sizeof (struct msg_register_opaque_type));
  457: }
  458: 
  459: struct msg *
  460: new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter)
  461: {
  462:   u_char buf[OSPF_API_MAX_MSG_SIZE];
  463:   struct msg_register_event *emsg;
  464:   size_t len;
  465: 
  466:   emsg = (struct msg_register_event *) buf;
  467:   len = sizeof (struct msg_register_event) +
  468:     filter->num_areas * sizeof (struct in_addr);
  469:   emsg->filter.typemask = htons (filter->typemask);
  470:   emsg->filter.origin = filter->origin;
  471:   emsg->filter.num_areas = filter->num_areas;
  472:   if (len > sizeof (buf))
  473:     len = sizeof(buf);
  474:   /* API broken - missing memcpy to fill data */
  475:   return msg_new (MSG_REGISTER_EVENT, emsg, seqnum, len);
  476: }
  477: 
  478: struct msg *
  479: new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter)
  480: {
  481:   u_char buf[OSPF_API_MAX_MSG_SIZE];
  482:   struct msg_sync_lsdb *smsg;
  483:   size_t len;
  484: 
  485:   smsg = (struct msg_sync_lsdb *) buf;
  486:   len = sizeof (struct msg_sync_lsdb) +
  487:     filter->num_areas * sizeof (struct in_addr);
  488:   smsg->filter.typemask = htons (filter->typemask);
  489:   smsg->filter.origin = filter->origin;
  490:   smsg->filter.num_areas = filter->num_areas;
  491:   if (len > sizeof (buf))
  492:     len = sizeof(buf);
  493:   /* API broken - missing memcpy to fill data */
  494:   return msg_new (MSG_SYNC_LSDB, smsg, seqnum, len);
  495: }
  496: 
  497: 
  498: struct msg *
  499: new_msg_originate_request (u_int32_t seqnum,
  500: 			   struct in_addr ifaddr,
  501: 			   struct in_addr area_id, struct lsa_header *data)
  502: {
  503:   struct msg_originate_request *omsg;
  504:   size_t omsglen;
  505:   char buf[OSPF_API_MAX_MSG_SIZE];
  506: 
  507:   omsg = (struct msg_originate_request *) buf;
  508:   omsg->ifaddr = ifaddr;
  509:   omsg->area_id = area_id;
  510: 
  511:   omsglen = ntohs (data->length);
  512:   if (omsglen > sizeof (buf) - offsetof (struct msg_originate_request, data))
  513:     omsglen = sizeof (buf) - offsetof (struct msg_originate_request, data);
  514:   memcpy (&omsg->data, data, omsglen);
  515:   omsglen += sizeof (struct msg_originate_request) - sizeof (struct lsa_header);
  516: 
  517:   return msg_new (MSG_ORIGINATE_REQUEST, omsg, seqnum, omsglen);
  518: }
  519: 
  520: struct msg *
  521: new_msg_delete_request (u_int32_t seqnum,
  522: 			struct in_addr area_id, u_char lsa_type,
  523: 			u_char opaque_type, u_int32_t opaque_id)
  524: {
  525:   struct msg_delete_request dmsg;
  526:   dmsg.area_id = area_id;
  527:   dmsg.lsa_type = lsa_type;
  528:   dmsg.opaque_type = opaque_type;
  529:   dmsg.opaque_id = htonl (opaque_id);
  530:   memset (&dmsg.pad, 0, sizeof (dmsg.pad));
  531: 
  532:   return msg_new (MSG_DELETE_REQUEST, &dmsg, seqnum,
  533: 		  sizeof (struct msg_delete_request));
  534: }
  535: 
  536: 
  537: struct msg *
  538: new_msg_reply (u_int32_t seqnr, u_char rc)
  539: {
  540:   struct msg *msg;
  541:   struct msg_reply rmsg;
  542: 
  543:   /* Set return code */
  544:   rmsg.errcode = rc;
  545:   memset (&rmsg.pad, 0, sizeof (rmsg.pad));
  546: 
  547:   msg = msg_new (MSG_REPLY, &rmsg, seqnr, sizeof (struct msg_reply));
  548: 
  549:   return msg;
  550: }
  551: 
  552: struct msg *
  553: new_msg_ready_notify (u_int32_t seqnr, u_char lsa_type,
  554: 		      u_char opaque_type, struct in_addr addr)
  555: {
  556:   struct msg_ready_notify rmsg;
  557: 
  558:   rmsg.lsa_type = lsa_type;
  559:   rmsg.opaque_type = opaque_type;
  560:   memset (&rmsg.pad, 0, sizeof (rmsg.pad));
  561:   rmsg.addr = addr;
  562: 
  563:   return msg_new (MSG_READY_NOTIFY, &rmsg, seqnr,
  564: 		  sizeof (struct msg_ready_notify));
  565: }
  566: 
  567: struct msg *
  568: new_msg_new_if (u_int32_t seqnr,
  569: 		struct in_addr ifaddr, struct in_addr area_id)
  570: {
  571:   struct msg_new_if nmsg;
  572: 
  573:   nmsg.ifaddr = ifaddr;
  574:   nmsg.area_id = area_id;
  575: 
  576:   return msg_new (MSG_NEW_IF, &nmsg, seqnr, sizeof (struct msg_new_if));
  577: }
  578: 
  579: struct msg *
  580: new_msg_del_if (u_int32_t seqnr, struct in_addr ifaddr)
  581: {
  582:   struct msg_del_if dmsg;
  583: 
  584:   dmsg.ifaddr = ifaddr;
  585: 
  586:   return msg_new (MSG_DEL_IF, &dmsg, seqnr, sizeof (struct msg_del_if));
  587: }
  588: 
  589: struct msg *
  590: new_msg_ism_change (u_int32_t seqnr, struct in_addr ifaddr,
  591: 		    struct in_addr area_id, u_char status)
  592: {
  593:   struct msg_ism_change imsg;
  594: 
  595:   imsg.ifaddr = ifaddr;
  596:   imsg.area_id = area_id;
  597:   imsg.status = status;
  598:   memset (&imsg.pad, 0, sizeof (imsg.pad));
  599: 
  600:   return msg_new (MSG_ISM_CHANGE, &imsg, seqnr,
  601: 		  sizeof (struct msg_ism_change));
  602: }
  603: 
  604: struct msg *
  605: new_msg_nsm_change (u_int32_t seqnr, struct in_addr ifaddr,
  606: 		    struct in_addr nbraddr,
  607: 		    struct in_addr router_id, u_char status)
  608: {
  609:   struct msg_nsm_change nmsg;
  610: 
  611:   nmsg.ifaddr = ifaddr;
  612:   nmsg.nbraddr = nbraddr;
  613:   nmsg.router_id = router_id;
  614:   nmsg.status = status;
  615:   memset (&nmsg.pad, 0, sizeof (nmsg.pad));
  616: 
  617:   return msg_new (MSG_NSM_CHANGE, &nmsg, seqnr,
  618: 		  sizeof (struct msg_nsm_change));
  619: }
  620: 
  621: struct msg *
  622: new_msg_lsa_change_notify (u_char msgtype,
  623: 			   u_int32_t seqnum,
  624: 			   struct in_addr ifaddr,
  625: 			   struct in_addr area_id,
  626: 			   u_char is_self_originated, struct lsa_header *data)
  627: {
  628:   u_char buf[OSPF_API_MAX_MSG_SIZE];
  629:   struct msg_lsa_change_notify *nmsg;
  630:   size_t len;
  631: 
  632:   assert (data);
  633: 
  634:   nmsg = (struct msg_lsa_change_notify *) buf;
  635:   nmsg->ifaddr = ifaddr;
  636:   nmsg->area_id = area_id;
  637:   nmsg->is_self_originated = is_self_originated;
  638:   memset (&nmsg->pad, 0, sizeof (nmsg->pad));
  639: 
  640:   len = ntohs (data->length);
  641:   if (len > sizeof (buf) - offsetof (struct msg_lsa_change_notify, data))
  642:     len = sizeof (buf) - offsetof (struct msg_lsa_change_notify, data);
  643:   memcpy (&nmsg->data, data, len);
  644:   len += sizeof (struct msg_lsa_change_notify) - sizeof (struct lsa_header);
  645: 
  646:   return msg_new (msgtype, nmsg, seqnum, len);
  647: }
  648: 
  649: #endif /* SUPPORT_OSPF_API */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>