back to topotato report
topotato coverage report
Current view: top level - ospf6d - ospf6_message.c (source / functions) Hit Total Coverage
Test: test_ospf6_p2xp.py::PtMPBasic Lines: 988 1746 56.6 %
Date: 2023-02-24 18:38:14 Functions: 55 68 80.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2003 Yasuhiro Ohara
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "memory.h"
      24             : #include "log.h"
      25             : #include "vty.h"
      26             : #include "command.h"
      27             : #include "thread.h"
      28             : #include "linklist.h"
      29             : #include "lib_errors.h"
      30             : #include "checksum.h"
      31             : #include "network.h"
      32             : 
      33             : #include "ospf6_proto.h"
      34             : #include "ospf6_lsa.h"
      35             : #include "ospf6_lsdb.h"
      36             : #include "ospf6_top.h"
      37             : #include "ospf6_network.h"
      38             : #include "ospf6_message.h"
      39             : 
      40             : #include "ospf6_area.h"
      41             : #include "ospf6_neighbor.h"
      42             : #include "ospf6_interface.h"
      43             : #include "ospf6_vlink.h"
      44             : 
      45             : /* for structures and macros ospf6_lsa_examin() needs */
      46             : #include "ospf6_abr.h"
      47             : #include "ospf6_asbr.h"
      48             : #include "ospf6_intra.h"
      49             : 
      50             : #include "ospf6_flood.h"
      51             : #include "ospf6d.h"
      52             : #include "ospf6_gr.h"
      53             : #include <netinet/ip6.h>
      54             : #include "lib/libospf.h"
      55             : #include "lib/keychain.h"
      56             : #include "ospf6_auth_trailer.h"
      57             : 
      58          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
      59          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet");
      60          12 : DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6  FIFO queue");
      61             : 
      62             : unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
      63             : 
      64           0 : const char *ospf6_message_type(int type)
      65             : {
      66           0 :         switch (type) {
      67             :         case OSPF6_MESSAGE_TYPE_HELLO:
      68             :                 return "Hello";
      69           0 :         case OSPF6_MESSAGE_TYPE_DBDESC:
      70           0 :                 return "DbDesc";
      71           0 :         case OSPF6_MESSAGE_TYPE_LSREQ:
      72           0 :                 return "LSReq";
      73           0 :         case OSPF6_MESSAGE_TYPE_LSUPDATE:
      74           0 :                 return "LSUpdate";
      75           0 :         case OSPF6_MESSAGE_TYPE_LSACK:
      76           0 :                 return "LSAck";
      77           0 :         case OSPF6_MESSAGE_TYPE_UNKNOWN:
      78             :         default:
      79           0 :                 return "unknown";
      80             :         }
      81             : }
      82             : 
      83             : /* Minimum (besides the standard OSPF packet header) lengths for OSPF
      84             :    packets of particular types, offset is the "type" field. */
      85             : const uint16_t ospf6_packet_minlen[OSPF6_MESSAGE_TYPE_ALL] = {
      86             :         0,
      87             :         OSPF6_HELLO_MIN_SIZE,
      88             :         OSPF6_DB_DESC_MIN_SIZE,
      89             :         OSPF6_LS_REQ_MIN_SIZE,
      90             :         OSPF6_LS_UPD_MIN_SIZE,
      91             :         OSPF6_LS_ACK_MIN_SIZE};
      92             : 
      93             : /* Minimum (besides the standard LSA header) lengths for LSAs of particular
      94             :    types, offset is the "LSA function code" portion of "LSA type" field. */
      95             : const uint16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = {
      96             :         0,
      97             :         /* 0x2001 */ OSPF6_ROUTER_LSA_MIN_SIZE,
      98             :         /* 0x2002 */ OSPF6_NETWORK_LSA_MIN_SIZE,
      99             :         /* 0x2003 */ OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
     100             :         /* 0x2004 */ OSPF6_INTER_ROUTER_LSA_FIX_SIZE,
     101             :         /* 0x4005 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
     102             :         /* 0x2006 */ 0,
     103             :         /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE,
     104             :         /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE,
     105             :         /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
     106             :         /* 0x200a */ 0,
     107             :         /* 0x000b */ OSPF6_GRACE_LSA_MIN_SIZE};
     108             : 
     109             : /* quick helpers */
     110         306 : static inline uint32_t on_transdelay(struct ospf6_neighbor *on)
     111             : {
     112         306 :         return on->vlink ? on->vlink->transmit_delay : on->ospf6_if->transdelay;
     113             : }
     114             : 
     115             : /* print functions */
     116             : 
     117           0 : static void ospf6_header_print(struct ospf6_header *oh)
     118             : {
     119           0 :         zlog_debug("    OSPFv%d Type:%d Len:%hu Router-ID:%pI4", oh->version,
     120             :                    oh->type, ntohs(oh->length), &oh->router_id);
     121           0 :         zlog_debug("    Area-ID:%pI4 Cksum:%hx Instance-ID:%d", &oh->area_id,
     122             :                    ntohs(oh->checksum), oh->instance_id);
     123           0 : }
     124             : 
     125           0 : void ospf6_hello_print(struct ospf6_header *oh, int action)
     126             : {
     127           0 :         struct ospf6_hello *hello;
     128           0 :         char options[32];
     129           0 :         char *p;
     130             : 
     131           0 :         ospf6_header_print(oh);
     132           0 :         assert(oh->type == OSPF6_MESSAGE_TYPE_HELLO);
     133             : 
     134           0 :         hello = (struct ospf6_hello *)((caddr_t)oh
     135             :                                        + sizeof(struct ospf6_header));
     136             : 
     137           0 :         ospf6_options_printbuf(hello->options, options, sizeof(options));
     138             : 
     139           0 :         zlog_debug("    I/F-Id:%ld Priority:%d Option:%s",
     140             :                    (unsigned long)ntohl(hello->interface_id), hello->priority,
     141             :                    options);
     142           0 :         zlog_debug("    HelloInterval:%hu DeadInterval:%hu",
     143             :                    ntohs(hello->hello_interval), ntohs(hello->dead_interval));
     144           0 :         zlog_debug("    DR:%pI4 BDR:%pI4", &hello->drouter, &hello->bdrouter);
     145             : 
     146           0 :         if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
     147           0 :              && action == OSPF6_ACTION_RECV)
     148           0 :             || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
     149           0 :                 && action == OSPF6_ACTION_SEND)) {
     150             : 
     151           0 :                 for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello));
     152           0 :                      p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh);
     153           0 :                      p += sizeof(uint32_t))
     154           0 :                         zlog_debug("    Neighbor: %pI4", (in_addr_t *)p);
     155             : 
     156           0 :                 assert(p == OSPF6_MESSAGE_END(oh));
     157             :         }
     158           0 : }
     159             : 
     160           0 : void ospf6_dbdesc_print(struct ospf6_header *oh, int action)
     161             : {
     162           0 :         struct ospf6_dbdesc *dbdesc;
     163           0 :         char options[32];
     164           0 :         char *p;
     165             : 
     166           0 :         ospf6_header_print(oh);
     167           0 :         assert(oh->type == OSPF6_MESSAGE_TYPE_DBDESC);
     168             : 
     169           0 :         dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
     170             :                                          + sizeof(struct ospf6_header));
     171             : 
     172           0 :         ospf6_options_printbuf(dbdesc->options, options, sizeof(options));
     173             : 
     174           0 :         zlog_debug("    MBZ: %#x Option: %s IfMTU: %hu", dbdesc->reserved1,
     175             :                    options, ntohs(dbdesc->ifmtu));
     176           0 :         zlog_debug("    MBZ: %#x Bits: %s%s%s SeqNum: %#lx", dbdesc->reserved2,
     177             :                    (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT) ? "I" : "-"),
     178             :                    (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT) ? "M" : "-"),
     179             :                    (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"),
     180             :                    (unsigned long)ntohl(dbdesc->seqnum));
     181             : 
     182           0 :         if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
     183           0 :              && action == OSPF6_ACTION_RECV)
     184           0 :             || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
     185           0 :                 && action == OSPF6_ACTION_SEND)) {
     186             : 
     187           0 :                 for (p = (char *)((caddr_t)dbdesc
     188             :                                   + sizeof(struct ospf6_dbdesc));
     189           0 :                      p + sizeof(struct ospf6_lsa_header)
     190           0 :                      <= OSPF6_MESSAGE_END(oh);
     191           0 :                      p += sizeof(struct ospf6_lsa_header))
     192           0 :                         ospf6_lsa_header_print_raw(
     193             :                                 (struct ospf6_lsa_header *)p);
     194             : 
     195           0 :                 assert(p == OSPF6_MESSAGE_END(oh));
     196             :         }
     197           0 : }
     198             : 
     199           0 : void ospf6_lsreq_print(struct ospf6_header *oh, int action)
     200             : {
     201           0 :         char *p;
     202             : 
     203           0 :         ospf6_header_print(oh);
     204           0 :         assert(oh->type == OSPF6_MESSAGE_TYPE_LSREQ);
     205             : 
     206           0 :         if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
     207           0 :              && action == OSPF6_ACTION_RECV)
     208           0 :             || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
     209           0 :                 && action == OSPF6_ACTION_SEND)) {
     210             : 
     211           0 :                 for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
     212           0 :                      p + sizeof(struct ospf6_lsreq_entry)
     213           0 :                      <= OSPF6_MESSAGE_END(oh);
     214           0 :                      p += sizeof(struct ospf6_lsreq_entry)) {
     215           0 :                         struct ospf6_lsreq_entry *e =
     216             :                                 (struct ospf6_lsreq_entry *)p;
     217             : 
     218           0 :                         zlog_debug("    [%s Id:%pI4 Adv:%pI4]",
     219             :                                    ospf6_lstype_name(e->type), &e->id,
     220             :                                    &e->adv_router);
     221             :                 }
     222             : 
     223           0 :                 assert(p == OSPF6_MESSAGE_END(oh));
     224             :         }
     225           0 : }
     226             : 
     227           0 : void ospf6_lsupdate_print(struct ospf6_header *oh, int action)
     228             : {
     229           0 :         struct ospf6_lsupdate *lsupdate;
     230           0 :         unsigned long num;
     231           0 :         char *p;
     232             : 
     233           0 :         ospf6_header_print(oh);
     234           0 :         assert(oh->type == OSPF6_MESSAGE_TYPE_LSUPDATE);
     235             : 
     236           0 :         lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
     237             :                                              + sizeof(struct ospf6_header));
     238             : 
     239           0 :         num = ntohl(lsupdate->lsa_number);
     240           0 :         zlog_debug("    Number of LSA: %ld", num);
     241             : 
     242           0 :         if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
     243           0 :              && action == OSPF6_ACTION_RECV)
     244           0 :             || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
     245           0 :                 && action == OSPF6_ACTION_SEND)) {
     246             : 
     247           0 :                 for (p = (char *)((caddr_t)lsupdate
     248             :                                   + sizeof(struct ospf6_lsupdate));
     249           0 :                      p < OSPF6_MESSAGE_END(oh)
     250           0 :                      && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh);
     251           0 :                      p += OSPF6_LSA_SIZE(p)) {
     252           0 :                         ospf6_lsa_header_print_raw(
     253             :                                 (struct ospf6_lsa_header *)p);
     254             :                 }
     255             : 
     256           0 :                 assert(p == OSPF6_MESSAGE_END(oh));
     257             :         }
     258           0 : }
     259             : 
     260           0 : void ospf6_lsack_print(struct ospf6_header *oh, int action)
     261             : {
     262           0 :         char *p;
     263             : 
     264           0 :         ospf6_header_print(oh);
     265           0 :         assert(oh->type == OSPF6_MESSAGE_TYPE_LSACK);
     266             : 
     267           0 :         if ((IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)
     268           0 :              && action == OSPF6_ACTION_RECV)
     269           0 :             || (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)
     270           0 :                 && action == OSPF6_ACTION_SEND)) {
     271             : 
     272           0 :                 for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
     273           0 :                      p + sizeof(struct ospf6_lsa_header)
     274           0 :                      <= OSPF6_MESSAGE_END(oh);
     275           0 :                      p += sizeof(struct ospf6_lsa_header))
     276           0 :                         ospf6_lsa_header_print_raw(
     277             :                                 (struct ospf6_lsa_header *)p);
     278             : 
     279           0 :                 assert(p == OSPF6_MESSAGE_END(oh));
     280             :         }
     281           0 : }
     282             : 
     283         239 : static struct ospf6_packet *ospf6_packet_new(size_t size)
     284             : {
     285         239 :         struct ospf6_packet *new;
     286             : 
     287         239 :         new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
     288         239 :         new->s = stream_new(size);
     289             : 
     290         239 :         return new;
     291             : }
     292             : 
     293           0 : static struct ospf6_packet *ospf6_packet_dup(struct ospf6_packet *old)
     294             : {
     295           0 :         struct ospf6_packet *new;
     296             : 
     297           0 :         new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
     298           0 :         new->s = stream_dup(old->s);
     299           0 :         new->dst = old->dst;
     300           0 :         new->length = old->length;
     301             : 
     302           0 :         return new;
     303             : }
     304             : 
     305         239 : static void ospf6_packet_free(struct ospf6_packet *op)
     306             : {
     307         239 :         if (op->s)
     308         239 :                 stream_free(op->s);
     309             : 
     310         239 :         XFREE(MTYPE_OSPF6_PACKET, op);
     311         239 : }
     312             : 
     313           5 : struct ospf6_fifo *ospf6_fifo_new(void)
     314             : {
     315           5 :         struct ospf6_fifo *new;
     316             : 
     317           5 :         new = XCALLOC(MTYPE_OSPF6_FIFO, sizeof(struct ospf6_fifo));
     318           5 :         return new;
     319             : }
     320             : 
     321             : /* Add new packet to fifo. */
     322         159 : static void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op)
     323             : {
     324         159 :         if (fifo->tail)
     325          53 :                 fifo->tail->next = op;
     326             :         else
     327         106 :                 fifo->head = op;
     328             : 
     329         159 :         fifo->tail = op;
     330             : 
     331         159 :         fifo->count++;
     332             : }
     333             : 
     334             : /* Add new packet to head of fifo. */
     335          60 : static void ospf6_fifo_push_head(struct ospf6_fifo *fifo,
     336             :                                  struct ospf6_packet *op)
     337             : {
     338          60 :         op->next = fifo->head;
     339             : 
     340          60 :         if (fifo->tail == NULL)
     341          59 :                 fifo->tail = op;
     342             : 
     343          60 :         fifo->head = op;
     344             : 
     345          60 :         fifo->count++;
     346             : }
     347             : 
     348             : /* Delete first packet from fifo. */
     349         219 : static struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo)
     350             : {
     351         219 :         struct ospf6_packet *op;
     352             : 
     353         219 :         op = fifo->head;
     354             : 
     355         219 :         if (op) {
     356         219 :                 fifo->head = op->next;
     357             : 
     358         219 :                 if (fifo->head == NULL)
     359         165 :                         fifo->tail = NULL;
     360             : 
     361         219 :                 fifo->count--;
     362             :         }
     363             : 
     364         219 :         return op;
     365             : }
     366             : 
     367             : /* Return first fifo entry. */
     368         438 : static struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo)
     369             : {
     370         438 :         return fifo->head;
     371             : }
     372             : 
     373             : /* Flush ospf packet fifo. */
     374          32 : void ospf6_fifo_flush(struct ospf6_fifo *fifo)
     375             : {
     376          32 :         struct ospf6_packet *op;
     377          32 :         struct ospf6_packet *next;
     378             : 
     379          32 :         for (op = fifo->head; op; op = next) {
     380           0 :                 next = op->next;
     381           0 :                 ospf6_packet_free(op);
     382             :         }
     383          32 :         fifo->head = fifo->tail = NULL;
     384          32 :         fifo->count = 0;
     385          32 : }
     386             : 
     387             : /* Free ospf packet fifo. */
     388           5 : void ospf6_fifo_free(struct ospf6_fifo *fifo)
     389             : {
     390           5 :         ospf6_fifo_flush(fifo);
     391             : 
     392           5 :         XFREE(MTYPE_OSPF6_FIFO, fifo);
     393           5 : }
     394             : 
     395         159 : static void ospf6_packet_add(struct ospf6_interface *oi,
     396             :                              struct ospf6_packet *op)
     397             : {
     398             :         /* Add packet to end of queue. */
     399         159 :         ospf6_fifo_push(oi->obuf, op);
     400             : 
     401             :         /* Debug of packet fifo*/
     402             :         /* ospf_fifo_debug (oi->obuf); */
     403         159 : }
     404             : 
     405          60 : static void ospf6_packet_add_top(struct ospf6_interface *oi,
     406             :                                  struct ospf6_packet *op)
     407             : {
     408             :         /* Add packet to head of queue. */
     409          60 :         ospf6_fifo_push_head(oi->obuf, op);
     410             : 
     411             :         /* Debug of packet fifo*/
     412             :         /* ospf_fifo_debug (oi->obuf); */
     413          60 : }
     414             : 
     415         219 : static void ospf6_packet_delete(struct ospf6_interface *oi)
     416             : {
     417         219 :         struct ospf6_packet *op;
     418             : 
     419         219 :         op = ospf6_fifo_pop(oi->obuf);
     420             : 
     421         219 :         if (op)
     422         219 :                 ospf6_packet_free(op);
     423         219 : }
     424             : 
     425             : 
     426          90 : static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
     427             :                              struct ospf6_interface *oi,
     428             :                              struct ospf6_header *oh)
     429             : {
     430          90 :         struct ospf6_hello *hello;
     431          90 :         struct ospf6_neighbor *on;
     432          90 :         struct ospf6_virtual_link *vlink = NULL;
     433          90 :         char *p;
     434          90 :         int twoway = 0;
     435          90 :         int neighborchange = 0;
     436          90 :         int neighbor_ifindex_change = 0;
     437          90 :         int backupseen = 0;
     438          90 :         int64_t latency = 0;
     439          90 :         struct timeval timestamp;
     440          90 :         uint32_t expect_hello, expect_dead;
     441             : 
     442          90 :         monotime(&timestamp);
     443          90 :         hello = (struct ospf6_hello *)((caddr_t)oh
     444             :                                        + sizeof(struct ospf6_header));
     445             : 
     446          90 :         if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT
     447          90 :              || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT)
     448          67 :             && oi->p2xp_only_cfg_neigh) {
     449             :                 /* NEVER, never, ever, do this on broadcast (or NBMA)!
     450             :                  * DR/BDR election requires everyone to talk to everyone else
     451             :                  * only for PtP/PtMP we can be selective in adjacencies!
     452             :                  */
     453           0 :                 struct ospf6_if_p2xp_neighcfg *p2xp_cfg;
     454             : 
     455           0 :                 p2xp_cfg = ospf6_if_p2xp_find(oi, src);
     456           0 :                 if (!p2xp_cfg) {
     457           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     458           0 :                                 zlog_debug(
     459             :                                         "ignoring PtP/PtMP hello from %pI6, neighbor not configured",
     460             :                                         src);
     461           0 :                         return;
     462             :                 }
     463             :         }
     464             : 
     465             :         /* Find neighbor, create if not exist */
     466          90 :         on = ospf6_neighbor_lookup(oh->router_id, oi);
     467          90 :         if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
     468           0 :                 if (!on) {
     469           0 :                         zlog_warn(
     470             :                                 "VRF %s: virtual link hello from %pI6 (%pI4): not configured",
     471             :                                 oi->interface->vrf->name, src,
     472             :                                 &oh->router_id);
     473           0 :                         return;
     474             :                 }
     475           0 :                 vlink = on->vlink;
     476           0 :                 expect_hello = vlink->hello_interval;
     477           0 :                 expect_dead = vlink->dead_interval;
     478             :         } else {
     479          90 :                 expect_hello = oi->hello_interval;
     480          90 :                 expect_dead = oi->dead_interval;
     481             :         }
     482             : 
     483             :         /* HelloInterval check */
     484          90 :         if (ntohs(hello->hello_interval) != expect_hello) {
     485           0 :                 zlog_warn(
     486             :                         "VRF %s: I/F %pOI HelloInterval mismatch: (my %d, rcvd %d)",
     487             :                         oi->interface->vrf->name, oi,
     488             :                         expect_hello, ntohs(hello->hello_interval));
     489           0 :                 return;
     490             :         }
     491             : 
     492             :         /* RouterDeadInterval check */
     493          90 :         if (ntohs(hello->dead_interval) != expect_dead) {
     494           0 :                 zlog_warn(
     495             :                         "VRF %s: I/F %pOI DeadInterval mismatch: (my %d, rcvd %d)",
     496             :                         oi->interface->vrf->name, oi,
     497             :                         expect_dead, ntohs(hello->dead_interval));
     498           0 :                 return;
     499             :         }
     500             : 
     501             :         /* E-bit check */
     502          90 :         if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_E)
     503          90 :             != OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_E)) {
     504           0 :                 zlog_warn("VRF %s: IF %pOI E-bit mismatch",
     505             :                           oi->interface->vrf->name, oi);
     506           0 :                 return;
     507             :         }
     508             : 
     509             :         /* N-bit check */
     510          90 :         if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_N)
     511             :             != OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_N)) {
     512           0 :                 zlog_warn("VRF %s: IF %pOI N-bit mismatch",
     513             :                           oi->interface->vrf->name, oi);
     514           0 :                 return;
     515             :         }
     516             : 
     517          90 :         if (((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) ==
     518           0 :               OSPF6_OPT_AT) &&
     519          90 :              (oi->at_data.flags == 0)) ||
     520             :             ((OSPF6_OPT_ISSET_EXT(hello->options, OSPF6_OPT_AT) !=
     521          90 :               OSPF6_OPT_AT) &&
     522          90 :              (oi->at_data.flags != 0))) {
     523           0 :                 if (IS_OSPF6_DEBUG_AUTH_RX)
     524           0 :                         zlog_warn(
     525             :                                 "VRF %s: IF %pOI AT-bit mismatch in hello packet",
     526             :                                 oi->interface->vrf->name, oi);
     527           0 :                 oi->at_data.rx_drop++;
     528           0 :                 return;
     529             :         }
     530             : 
     531          90 :         if (on == NULL) {
     532           8 :                 on = ospf6_neighbor_create(oh->router_id, oi);
     533           8 :                 on->prev_drouter = on->drouter = hello->drouter;
     534           8 :                 on->prev_bdrouter = on->bdrouter = hello->bdrouter;
     535           8 :                 on->priority = hello->priority;
     536             :         }
     537             : 
     538             :         /* check latency against hello period */
     539          90 :         if (on->hello_in)
     540          82 :                 latency = monotime_since(&on->last_hello, NULL)
     541          82 :                           - ((int64_t)oi->hello_interval * 1000000);
     542             :         /* log if latency exceeds the hello period */
     543          90 :         if (latency > ((int64_t)oi->hello_interval * 1000000))
     544           0 :                 zlog_warn("%s RX %pI4 high latency %" PRId64 "us.", __func__,
     545             :                           &on->router_id, latency);
     546          90 :         on->last_hello = timestamp;
     547          90 :         on->hello_in++;
     548             : 
     549             :         /* Always override neighbor's source address */
     550          90 :         ospf6_neighbor_lladdr_set(on, src);
     551             : 
     552             :         /* Neighbor ifindex check */
     553          90 :         if (on->ifindex != (ifindex_t)ntohl(hello->interface_id)) {
     554           8 :                 on->ifindex = ntohl(hello->interface_id);
     555           8 :                 neighbor_ifindex_change++;
     556             :         }
     557             : 
     558             :         /* TwoWay check */
     559          90 :         for (p = (char *)((caddr_t)hello + sizeof(struct ospf6_hello));
     560         240 :              p + sizeof(uint32_t) <= OSPF6_MESSAGE_END(oh);
     561             :              p += sizeof(uint32_t)) {
     562         150 :                 uint32_t *router_id = (uint32_t *)p;
     563             : 
     564         150 :                 if (*router_id == oi->area->ospf6->router_id)
     565          86 :                         twoway++;
     566             :         }
     567             : 
     568          90 :         assert(p == OSPF6_MESSAGE_END(oh));
     569             : 
     570             :         /* RouterPriority check */
     571          90 :         if (on->priority != hello->priority) {
     572           0 :                 on->priority = hello->priority;
     573           0 :                 neighborchange++;
     574             :         }
     575             : 
     576             :         /* DR check */
     577          90 :         if (on->drouter != hello->drouter) {
     578           2 :                 on->prev_drouter = on->drouter;
     579           2 :                 on->drouter = hello->drouter;
     580           2 :                 if (on->prev_drouter == on->router_id
     581           2 :                     || on->drouter == on->router_id)
     582           1 :                         neighborchange++;
     583             :         }
     584             : 
     585             :         /* BDR check */
     586          90 :         if (on->bdrouter != hello->bdrouter) {
     587           2 :                 on->prev_bdrouter = on->bdrouter;
     588           2 :                 on->bdrouter = hello->bdrouter;
     589           2 :                 if (on->prev_bdrouter == on->router_id
     590           2 :                     || on->bdrouter == on->router_id)
     591           1 :                         neighborchange++;
     592             :         }
     593             : 
     594             :         /* BackupSeen check */
     595          90 :         if (oi->state == OSPF6_INTERFACE_WAITING) {
     596           4 :                 if (hello->bdrouter == on->router_id)
     597             :                         backupseen++;
     598           4 :                 else if (hello->drouter == on->router_id
     599           1 :                          && hello->bdrouter == htonl(0))
     600           0 :                         backupseen++;
     601             :         }
     602             : 
     603          90 :         oi->hello_in++;
     604             : 
     605             :         /* Execute neighbor events */
     606          90 :         thread_execute(master, hello_received, on, 0);
     607          90 :         if (twoway)
     608          86 :                 thread_execute(master, twoway_received, on, 0);
     609             :         else {
     610           4 :                 if (OSPF6_GR_IS_ACTIVE_HELPER(on)) {
     611           0 :                         if (IS_DEBUG_OSPF6_GR)
     612           0 :                                 zlog_debug(
     613             :                                         "%s, Received oneway hello from RESTARTER so ignore here.",
     614             :                                         __PRETTY_FUNCTION__);
     615             :                 } else {
     616             :                         /* If the router is DR_OTHER, RESTARTER will not wait
     617             :                          * until it receives the hello from it if it receives
     618             :                          * from DR and BDR.
     619             :                          * So, helper might receives ONE_WAY hello from
     620             :                          * RESTARTER. So not allowing to change the state if it
     621             :                          * receives one_way hellow when it acts as HELPER for
     622             :                          * that specific neighbor.
     623             :                          */
     624           4 :                         thread_execute(master, oneway_received, on, 0);
     625             :                 }
     626             :         }
     627             : 
     628          90 :         if (OSPF6_GR_IS_ACTIVE_HELPER(on)) {
     629             :                 /* As per the GR Conformance Test Case 7.2. Section 3
     630             :                  * "Also, if X was the Designated Router on network segment S
     631             :                  * when the helping relationship began, Y maintains X as the
     632             :                  * Designated Router until the helping relationship is
     633             :                  * terminated."
     634             :                  * When it is a helper for this neighbor, It should not trigger
     635             :                  * the ISM Events. Also Intentionally not setting the priority
     636             :                  * and other fields so that when the neighbor exits the Grace
     637             :                  * period, it can handle if there is any change before GR and
     638             :                  * after GR.
     639             :                  */
     640           0 :                 if (IS_DEBUG_OSPF6_GR)
     641           0 :                         zlog_debug(
     642             :                                 "%s, Neighbor is under GR Restart, hence ignoring the ISM Events",
     643             :                                 __PRETTY_FUNCTION__);
     644             : 
     645           0 :                 return;
     646             :         }
     647             : 
     648             :         /*
     649             :          * RFC 3623 - Section 2:
     650             :          * "If the restarting router determines that it was the Designated
     651             :          * Router on a given segment prior to the restart, it elects
     652             :          * itself as the Designated Router again.  The restarting router
     653             :          * knows that it was the Designated Router if, while the
     654             :          * associated interface is in Waiting state, a Hello packet is
     655             :          * received from a neighbor listing the router as the Designated
     656             :          * Router".
     657             :          */
     658          90 :         if (oi->area->ospf6->gr_info.restart_in_progress
     659           0 :             && oi->state == OSPF6_INTERFACE_WAITING
     660           0 :             && hello->drouter == oi->area->ospf6->router_id)
     661           0 :                 oi->drouter = hello->drouter;
     662             : 
     663             :         /* Schedule interface events */
     664          90 :         if (backupseen)
     665           0 :                 thread_add_event(master, backup_seen, oi, 0, NULL);
     666          90 :         if (neighborchange)
     667           2 :                 thread_add_event(master, neighbor_change, oi, 0, NULL);
     668             : 
     669          90 :         if (neighbor_ifindex_change && on->state == OSPF6_NEIGHBOR_FULL)
     670          90 :                 OSPF6_ROUTER_LSA_SCHEDULE(oi->area);
     671             : }
     672             : 
     673          11 : static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
     674             :                                      struct ospf6_neighbor *on)
     675             : {
     676          11 :         struct ospf6_dbdesc *dbdesc;
     677          11 :         char *p;
     678             : 
     679          11 :         dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
     680             :                                          + sizeof(struct ospf6_header));
     681             : 
     682          11 :         if (on->state < OSPF6_NEIGHBOR_INIT) {
     683           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     684           0 :                         zlog_debug("Neighbor state less than Init, ignore");
     685           0 :                 return;
     686             :         }
     687             : 
     688          11 :         switch (on->state) {
     689           0 :         case OSPF6_NEIGHBOR_TWOWAY:
     690           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     691           0 :                         zlog_debug("Neighbor state is 2-Way, ignore");
     692             :                 return;
     693             : 
     694           2 :         case OSPF6_NEIGHBOR_INIT:
     695           2 :                 thread_execute(master, twoway_received, on, 0);
     696           2 :                 if (on->state != OSPF6_NEIGHBOR_EXSTART) {
     697           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     698           0 :                                 zlog_debug(
     699             :                                         "Neighbor state is not ExStart, ignore");
     700           0 :                         return;
     701             :                 }
     702             :         /* else fall through to ExStart */
     703             :         /* fallthru */
     704             :         case OSPF6_NEIGHBOR_EXSTART:
     705             :                 /* if neighbor obeys us as our slave, schedule negotiation_done
     706             :                    and process LSA Headers. Otherwise, ignore this message */
     707           7 :                 if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)
     708             :                     && !CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)
     709           4 :                     && ntohl(dbdesc->seqnum) == on->dbdesc_seqnum) {
     710             :                         /* execute NegotiationDone */
     711           4 :                         thread_execute(master, negotiation_done, on, 0);
     712             : 
     713             :                         /* Record neighbor options */
     714           4 :                         memcpy(on->options, dbdesc->options,
     715             :                                sizeof(on->options));
     716             :                 } else {
     717           3 :                         zlog_warn("VRF %s: Nbr %s: Negotiation failed",
     718             :                                   on->ospf6_if->interface->vrf->name, on->name);
     719           3 :                         return;
     720             :                 }
     721             :         /* fall through to exchange */
     722             : 
     723             :         case OSPF6_NEIGHBOR_EXCHANGE:
     724           8 :                 if (!memcmp(dbdesc, &on->dbdesc_last,
     725             :                             sizeof(struct ospf6_dbdesc))) {
     726             :                         /* Duplicated DatabaseDescription is dropped by master
     727             :                          */
     728           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     729           0 :                                 zlog_debug(
     730             :                                         "Duplicated dbdesc discarded by Master, ignore");
     731           0 :                         return;
     732             :                 }
     733             : 
     734           8 :                 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
     735           0 :                         zlog_warn(
     736             :                                 "DbDesc recv: Master/Slave bit mismatch Nbr %s",
     737             :                                 on->name);
     738           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     739             :                                          NULL);
     740           0 :                         return;
     741             :                 }
     742             : 
     743           8 :                 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
     744           0 :                         zlog_warn("DbDesc recv: Initialize bit mismatch Nbr %s",
     745             :                                   on->name);
     746           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     747             :                                          NULL);
     748           0 :                         return;
     749             :                 }
     750             : 
     751           8 :                 if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
     752           0 :                         zlog_warn("DbDesc recv: Option field mismatch Nbr %s",
     753             :                                   on->name);
     754           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     755             :                                          NULL);
     756           0 :                         return;
     757             :                 }
     758             : 
     759           8 :                 if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) {
     760           0 :                         zlog_warn(
     761             :                                 "DbDesc recv: Sequence number mismatch Nbr %s (%#lx expected)",
     762             :                                 on->name, (unsigned long)on->dbdesc_seqnum);
     763           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     764             :                                          NULL);
     765           0 :                         return;
     766             :                 }
     767           8 :                 break;
     768             : 
     769           0 :         case OSPF6_NEIGHBOR_LOADING:
     770             :         case OSPF6_NEIGHBOR_FULL:
     771           0 :                 if (!memcmp(dbdesc, &on->dbdesc_last,
     772             :                             sizeof(struct ospf6_dbdesc))) {
     773             :                         /* Duplicated DatabaseDescription is dropped by master
     774             :                          */
     775           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     776           0 :                                 zlog_debug(
     777             :                                         "Duplicated dbdesc discarded by Master, ignore");
     778           0 :                         return;
     779             :                 }
     780             : 
     781           0 :                 zlog_warn(
     782             :                         "DbDesc recv: Not duplicate dbdesc in state %s Nbr %s",
     783             :                         ospf6_neighbor_state_str[on->state], on->name);
     784           0 :                 thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
     785           0 :                 return;
     786             : 
     787             :         default:
     788           0 :                 assert(0);
     789             :                 break;
     790             :         }
     791             : 
     792             :         /* Process LSA headers */
     793           8 :         for (p = (char *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
     794          25 :              p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
     795             :              p += sizeof(struct ospf6_lsa_header)) {
     796          17 :                 struct ospf6_lsa *his, *mine;
     797          17 :                 struct ospf6_lsdb *lsdb = NULL;
     798             : 
     799          17 :                 his = ospf6_lsa_create_headeronly((struct ospf6_lsa_header *)p);
     800             : 
     801          17 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     802           0 :                         zlog_debug("%s", his->name);
     803             : 
     804          17 :                 switch (OSPF6_LSA_SCOPE(his->header->type)) {
     805           6 :                 case OSPF6_SCOPE_LINKLOCAL:
     806           6 :                         if (on->ospf6_if->type == OSPF_IFTYPE_VIRTUALLINK) {
     807           0 :                                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     808           0 :                                         zlog_debug("Link-scoped LSA on Virtual link");
     809           0 :                                 ospf6_lsa_delete(his);
     810           0 :                                 continue;
     811             :                         }
     812           6 :                         lsdb = on->ospf6_if->lsdb;
     813           6 :                         break;
     814          11 :                 case OSPF6_SCOPE_AREA:
     815          11 :                         lsdb = on->ospf6_if->area->lsdb;
     816          11 :                         break;
     817           0 :                 case OSPF6_SCOPE_AS:
     818           0 :                         lsdb = on->ospf6_if->area->ospf6->lsdb;
     819           0 :                         break;
     820           0 :                 case OSPF6_SCOPE_RESERVED:
     821           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     822           0 :                                 zlog_debug("Ignoring LSA of reserved scope");
     823           0 :                         ospf6_lsa_delete(his);
     824           0 :                         continue;
     825             :                 }
     826             : 
     827          17 :                 if (ntohs(his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
     828           0 :                     && (IS_AREA_STUB(on->ospf6_if->area)
     829             :                         || IS_AREA_NSSA(on->ospf6_if->area))) {
     830           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     831           0 :                                 zlog_debug(
     832             :                                         "SeqNumMismatch (E-bit mismatch), discard");
     833           0 :                         ospf6_lsa_delete(his);
     834           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     835             :                                          NULL);
     836           0 :                         return;
     837             :                 }
     838             : 
     839          17 :                 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
     840             :                                          his->header->adv_router, lsdb);
     841          17 :                 if (mine == NULL) {
     842           8 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     843           0 :                                 zlog_debug("Add request (No database copy)");
     844           8 :                         ospf6_lsdb_add(ospf6_lsa_copy(his), on->request_list);
     845           9 :                 } else if (ospf6_lsa_compare(his, mine) < 0) {
     846           2 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     847           0 :                                 zlog_debug("Add request (Received MoreRecent)");
     848           2 :                         ospf6_lsdb_add(ospf6_lsa_copy(his), on->request_list);
     849             :                 } else {
     850           7 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
     851           0 :                                 zlog_debug("Discard (Existing MoreRecent)");
     852             :                 }
     853          17 :                 ospf6_lsa_delete(his);
     854             :         }
     855             : 
     856           8 :         assert(p == OSPF6_MESSAGE_END(oh));
     857             : 
     858             :         /* Increment sequence number */
     859           8 :         on->dbdesc_seqnum++;
     860             : 
     861             :         /* schedule send lsreq */
     862           8 :         if (on->request_list->count)
     863           5 :                 thread_add_event(master, ospf6_lsreq_send, on, 0,
     864             :                                  &on->thread_send_lsreq);
     865             : 
     866           8 :         THREAD_OFF(on->thread_send_dbdesc);
     867             : 
     868             :         /* More bit check */
     869           8 :         if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT)
     870           8 :             && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
     871           4 :                 thread_add_event(master, exchange_done, on, 0,
     872             :                                  &on->thread_exchange_done);
     873             :         else {
     874           4 :                 thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
     875             :                                  &on->thread_send_dbdesc);
     876             :         }
     877             : 
     878             :         /* save last received dbdesc */
     879           8 :         memcpy(&on->dbdesc_last, dbdesc, sizeof(struct ospf6_dbdesc));
     880             : }
     881             : 
     882           9 : static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
     883             :                                     struct ospf6_neighbor *on)
     884             : {
     885           9 :         struct ospf6_dbdesc *dbdesc;
     886           9 :         char *p;
     887             : 
     888           9 :         dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
     889             :                                          + sizeof(struct ospf6_header));
     890             : 
     891           9 :         if (on->state < OSPF6_NEIGHBOR_INIT) {
     892           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     893           0 :                         zlog_debug("Neighbor state less than Init, ignore");
     894           0 :                 return;
     895             :         }
     896             : 
     897           9 :         switch (on->state) {
     898           1 :         case OSPF6_NEIGHBOR_TWOWAY:
     899           1 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     900           0 :                         zlog_debug("Neighbor state is 2-Way, ignore");
     901             :                 return;
     902             : 
     903           1 :         case OSPF6_NEIGHBOR_INIT:
     904           1 :                 thread_execute(master, twoway_received, on, 0);
     905           1 :                 if (on->state != OSPF6_NEIGHBOR_EXSTART) {
     906           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     907           0 :                                 zlog_debug(
     908             :                                         "Neighbor state is not ExStart, ignore");
     909           0 :                         return;
     910             :                 }
     911             :         /* else fall through to ExStart */
     912             :         /* fallthru */
     913             :         case OSPF6_NEIGHBOR_EXSTART:
     914             :                 /* If the neighbor is Master, act as Slave. Schedule
     915             :                    negotiation_done
     916             :                    and process LSA Headers. Otherwise, ignore this message */
     917           4 :                 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)
     918             :                     && CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT)
     919           4 :                     && CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)
     920           4 :                     && ntohs(oh->length)
     921             :                                == sizeof(struct ospf6_header)
     922             :                                           + sizeof(struct ospf6_dbdesc)) {
     923             :                         /* set the master/slave bit to slave */
     924           4 :                         UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
     925             : 
     926             :                         /* set the DD sequence number to one specified by master
     927             :                          */
     928           4 :                         on->dbdesc_seqnum = ntohl(dbdesc->seqnum);
     929             : 
     930             :                         /* schedule NegotiationDone */
     931           4 :                         thread_execute(master, negotiation_done, on, 0);
     932             : 
     933             :                         /* Record neighbor options */
     934           4 :                         memcpy(on->options, dbdesc->options,
     935             :                                sizeof(on->options));
     936             :                 } else {
     937           0 :                         zlog_warn("VRF %s: Nbr %s Negotiation failed",
     938             :                                   on->ospf6_if->interface->vrf->name, on->name);
     939           0 :                         return;
     940             :                 }
     941           4 :                 break;
     942             : 
     943           4 :         case OSPF6_NEIGHBOR_EXCHANGE:
     944           4 :                 if (!memcmp(dbdesc, &on->dbdesc_last,
     945             :                             sizeof(struct ospf6_dbdesc))) {
     946             :                         /* Duplicated DatabaseDescription causes slave to
     947             :                          * retransmit */
     948           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
     949           0 :                                 zlog_debug(
     950             :                                         "Duplicated dbdesc causes retransmit");
     951           0 :                         THREAD_OFF(on->thread_send_dbdesc);
     952           0 :                         thread_add_event(master, ospf6_dbdesc_send, on, 0,
     953             :                                          &on->thread_send_dbdesc);
     954           0 :                         return;
     955             :                 }
     956             : 
     957           4 :                 if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
     958           0 :                         zlog_warn(
     959             :                                 "DbDesc slave recv: Master/Slave bit mismatch Nbr %s",
     960             :                                 on->name);
     961           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     962             :                                          NULL);
     963           0 :                         return;
     964             :                 }
     965             : 
     966           4 :                 if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
     967           0 :                         zlog_warn(
     968             :                                 "DbDesc slave recv: Initialize bit mismatch Nbr %s",
     969             :                                 on->name);
     970           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     971             :                                          NULL);
     972           0 :                         return;
     973             :                 }
     974             : 
     975           4 :                 if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
     976           0 :                         zlog_warn(
     977             :                                 "DbDesc slave recv: Option field mismatch Nbr %s",
     978             :                                 on->name);
     979           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     980             :                                          NULL);
     981           0 :                         return;
     982             :                 }
     983             : 
     984           4 :                 if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) {
     985           0 :                         zlog_warn(
     986             :                                 "DbDesc slave recv: Sequence number mismatch Nbr %s (%#lx expected)",
     987             :                                 on->name, (unsigned long)on->dbdesc_seqnum + 1);
     988           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
     989             :                                          NULL);
     990           0 :                         return;
     991             :                 }
     992             :                 break;
     993             : 
     994           0 :         case OSPF6_NEIGHBOR_LOADING:
     995             :         case OSPF6_NEIGHBOR_FULL:
     996           0 :                 if (!memcmp(dbdesc, &on->dbdesc_last,
     997             :                             sizeof(struct ospf6_dbdesc))) {
     998             :                         /* Duplicated DatabaseDescription causes slave to
     999             :                          * retransmit */
    1000           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1001           0 :                                 zlog_debug(
    1002             :                                         "Duplicated dbdesc causes retransmit");
    1003           0 :                         THREAD_OFF(on->thread_send_dbdesc);
    1004           0 :                         thread_add_event(master, ospf6_dbdesc_send, on, 0,
    1005             :                                          &on->thread_send_dbdesc);
    1006           0 :                         return;
    1007             :                 }
    1008             : 
    1009           0 :                 zlog_warn(
    1010             :                         "DbDesc slave recv: Not duplicate dbdesc in state %s Nbr %s",
    1011             :                         ospf6_neighbor_state_str[on->state], on->name);
    1012           0 :                 thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
    1013           0 :                 return;
    1014             : 
    1015             :         default:
    1016           0 :                 assert(0);
    1017             :                 break;
    1018             :         }
    1019             : 
    1020             :         /* Process LSA headers */
    1021           8 :         for (p = (char *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
    1022          30 :              p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
    1023             :              p += sizeof(struct ospf6_lsa_header)) {
    1024          22 :                 struct ospf6_lsa *his, *mine;
    1025          22 :                 struct ospf6_lsdb *lsdb = NULL;
    1026             : 
    1027          22 :                 his = ospf6_lsa_create_headeronly((struct ospf6_lsa_header *)p);
    1028             : 
    1029          22 :                 switch (OSPF6_LSA_SCOPE(his->header->type)) {
    1030           6 :                 case OSPF6_SCOPE_LINKLOCAL:
    1031           6 :                         if (on->ospf6_if->type == OSPF_IFTYPE_VIRTUALLINK) {
    1032           0 :                                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1033           0 :                                         zlog_debug("Link-scoped LSA on Virtual link");
    1034           0 :                                 ospf6_lsa_delete(his);
    1035           0 :                                 continue;
    1036             :                         }
    1037           6 :                         lsdb = on->ospf6_if->lsdb;
    1038           6 :                         break;
    1039          16 :                 case OSPF6_SCOPE_AREA:
    1040          16 :                         lsdb = on->ospf6_if->area->lsdb;
    1041          16 :                         break;
    1042           0 :                 case OSPF6_SCOPE_AS:
    1043           0 :                         lsdb = on->ospf6_if->area->ospf6->lsdb;
    1044           0 :                         break;
    1045           0 :                 case OSPF6_SCOPE_RESERVED:
    1046           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1047           0 :                                 zlog_debug("Ignoring LSA of reserved scope");
    1048           0 :                         ospf6_lsa_delete(his);
    1049           0 :                         continue;
    1050             :                 }
    1051             : 
    1052          22 :                 if (OSPF6_LSA_SCOPE(his->header->type) == OSPF6_SCOPE_AS
    1053           0 :                     && (IS_AREA_STUB(on->ospf6_if->area)
    1054             :                         || IS_AREA_NSSA(on->ospf6_if->area))) {
    1055           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1056           0 :                                 zlog_debug("E-bit mismatch with LSA Headers");
    1057           0 :                         ospf6_lsa_delete(his);
    1058           0 :                         thread_add_event(master, seqnumber_mismatch, on, 0,
    1059             :                                          NULL);
    1060           0 :                         return;
    1061             :                 }
    1062             : 
    1063          22 :                 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
    1064             :                                          his->header->adv_router, lsdb);
    1065          22 :                 if (mine == NULL || ospf6_lsa_compare(his, mine) < 0) {
    1066          15 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1067           0 :                                 zlog_debug("Add request-list: %s", his->name);
    1068          15 :                         ospf6_lsdb_add(ospf6_lsa_copy(his), on->request_list);
    1069             :                 }
    1070          22 :                 ospf6_lsa_delete(his);
    1071             :         }
    1072             : 
    1073           8 :         assert(p == OSPF6_MESSAGE_END(oh));
    1074             : 
    1075             :         /* Set sequence number to Master's */
    1076           8 :         on->dbdesc_seqnum = ntohl(dbdesc->seqnum);
    1077             : 
    1078             :         /* schedule send lsreq */
    1079           8 :         if (on->request_list->count)
    1080           4 :                 thread_add_event(master, ospf6_lsreq_send, on, 0,
    1081             :                                  &on->thread_send_lsreq);
    1082             : 
    1083           8 :         THREAD_OFF(on->thread_send_dbdesc);
    1084           8 :         thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
    1085             :                          &on->thread_send_dbdesc);
    1086             : 
    1087             :         /* save last received dbdesc */
    1088           8 :         memcpy(&on->dbdesc_last, dbdesc, sizeof(struct ospf6_dbdesc));
    1089             : }
    1090             : 
    1091          20 : static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst,
    1092             :                               struct ospf6_interface *oi,
    1093             :                               struct ospf6_header *oh)
    1094             : {
    1095          20 :         struct ospf6_neighbor *on;
    1096          20 :         struct ospf6_dbdesc *dbdesc;
    1097             : 
    1098          20 :         on = ospf6_neighbor_lookup(oh->router_id, oi);
    1099          20 :         if (on == NULL) {
    1100           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1101           0 :                         zlog_debug("Neighbor not found, ignore");
    1102           0 :                 return;
    1103             :         }
    1104             : 
    1105          20 :         dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
    1106             :                                          + sizeof(struct ospf6_header));
    1107             : 
    1108          20 :         if (((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) ==
    1109           0 :               OSPF6_OPT_AT) &&
    1110          20 :              (oi->at_data.flags == 0)) ||
    1111             :             ((OSPF6_OPT_ISSET_EXT(dbdesc->options, OSPF6_OPT_AT) !=
    1112          20 :               OSPF6_OPT_AT) &&
    1113          20 :              (oi->at_data.flags != 0))) {
    1114           0 :                 if (IS_OSPF6_DEBUG_AUTH_RX)
    1115           0 :                         zlog_warn(
    1116             :                                 "VRF %s: IF %pOI AT-bit mismatch in dbdesc packet",
    1117             :                                 oi->interface->vrf->name, oi);
    1118           0 :                 oi->at_data.rx_drop++;
    1119           0 :                 return;
    1120             :         }
    1121             : 
    1122             :         /* Interface MTU check */
    1123          20 :         if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) {
    1124           0 :                 zlog_warn("VRF %s: I/F %pOI MTU mismatch (my %d rcvd %d)",
    1125             :                           oi->interface->vrf->name, oi,
    1126             :                           oi->ifmtu, ntohs(dbdesc->ifmtu));
    1127           0 :                 return;
    1128             :         }
    1129             : 
    1130          20 :         if (dbdesc->reserved1 || dbdesc->reserved2) {
    1131           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1132           0 :                         zlog_debug(
    1133             :                                 "Non-0 reserved field in %s's DbDesc, correct",
    1134             :                                 on->name);
    1135           0 :                 dbdesc->reserved1 = 0;
    1136           0 :                 dbdesc->reserved2 = 0;
    1137             :         }
    1138             : 
    1139          20 :         oi->db_desc_in++;
    1140             : 
    1141          20 :         if (ntohl(oh->router_id) < ntohl(oi->area->ospf6->router_id))
    1142          11 :                 ospf6_dbdesc_recv_master(oh, on);
    1143           9 :         else if (ntohl(oi->area->ospf6->router_id) < ntohl(oh->router_id))
    1144           9 :                 ospf6_dbdesc_recv_slave(oh, on);
    1145             :         else {
    1146           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1147           0 :                         zlog_debug("Can't decide which is master, ignore");
    1148             :         }
    1149             : }
    1150             : 
    1151           8 : static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
    1152             :                              struct ospf6_interface *oi,
    1153             :                              struct ospf6_header *oh)
    1154             : {
    1155           8 :         struct ospf6_neighbor *on;
    1156           8 :         char *p;
    1157           8 :         struct ospf6_lsreq_entry *e;
    1158           8 :         struct ospf6_lsdb *lsdb = NULL;
    1159           8 :         struct ospf6_lsa *lsa;
    1160             : 
    1161           8 :         on = ospf6_neighbor_lookup(oh->router_id, oi);
    1162           8 :         if (on == NULL) {
    1163           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1164           0 :                         zlog_debug("Neighbor not found, ignore");
    1165           0 :                 return;
    1166             :         }
    1167             : 
    1168           8 :         if (on->state != OSPF6_NEIGHBOR_EXCHANGE
    1169             :             && on->state != OSPF6_NEIGHBOR_LOADING
    1170           8 :             && on->state != OSPF6_NEIGHBOR_FULL) {
    1171           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1172           0 :                         zlog_debug("Neighbor state less than Exchange, ignore");
    1173           0 :                 return;
    1174             :         }
    1175             : 
    1176           8 :         oi->ls_req_in++;
    1177             : 
    1178             :         /* Process each request */
    1179           8 :         for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
    1180          33 :              p + sizeof(struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END(oh);
    1181             :              p += sizeof(struct ospf6_lsreq_entry)) {
    1182          25 :                 e = (struct ospf6_lsreq_entry *)p;
    1183             : 
    1184          25 :                 switch (OSPF6_LSA_SCOPE(e->type)) {
    1185           6 :                 case OSPF6_SCOPE_LINKLOCAL:
    1186           6 :                         if (on->ospf6_if->type == OSPF_IFTYPE_VIRTUALLINK) {
    1187           0 :                                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1188           0 :                                         zlog_debug("Link-scoped LSA on Virtual link");
    1189           0 :                                 continue;
    1190             :                         }
    1191           6 :                         lsdb = on->ospf6_if->lsdb;
    1192           6 :                         break;
    1193          19 :                 case OSPF6_SCOPE_AREA:
    1194          19 :                         lsdb = on->ospf6_if->area->lsdb;
    1195          19 :                         break;
    1196           0 :                 case OSPF6_SCOPE_AS:
    1197           0 :                         lsdb = on->ospf6_if->area->ospf6->lsdb;
    1198           0 :                         break;
    1199           0 :                 default:
    1200           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1201           0 :                                 zlog_debug("Ignoring LSA of reserved scope");
    1202           0 :                         continue;
    1203             :                 }
    1204             : 
    1205             :                 /* Find database copy */
    1206          25 :                 lsa = ospf6_lsdb_lookup(e->type, e->id, e->adv_router, lsdb);
    1207          25 :                 if (lsa == NULL) {
    1208           0 :                         zlog_warn(
    1209             :                                 "Can't find requested lsa [%s Id:%pI4 Adv:%pI4] send badLSReq",
    1210             :                                 ospf6_lstype_name(e->type), &e->id,
    1211             :                                 &e->adv_router);
    1212           0 :                         thread_add_event(master, bad_lsreq, on, 0, NULL);
    1213           0 :                         return;
    1214             :                 }
    1215             : 
    1216          25 :                 ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->lsupdate_list);
    1217             :         }
    1218             : 
    1219           8 :         assert(p == OSPF6_MESSAGE_END(oh));
    1220             : 
    1221             :         /* schedule send lsupdate */
    1222           8 :         THREAD_OFF(on->thread_send_lsupdate);
    1223           8 :         thread_add_event(master, ospf6_lsupdate_send_neighbor, on, 0,
    1224             :                          &on->thread_send_lsupdate);
    1225             : }
    1226             : 
    1227             : /* Verify, that the specified memory area contains exactly N valid IPv6
    1228             :    prefixes as specified by RFC5340, A.4.1. */
    1229         114 : static unsigned ospf6_prefixes_examin(
    1230             :         struct ospf6_prefix *current, /* start of buffer    */
    1231             :         unsigned length,
    1232             :         const uint32_t req_num_pfxs /* always compared with the actual number
    1233             :                                         of prefixes */
    1234             : )
    1235             : {
    1236         114 :         uint8_t requested_pfx_bytes;
    1237         114 :         uint32_t real_num_pfxs = 0;
    1238             : 
    1239         261 :         while (length) {
    1240         147 :                 if (length < OSPF6_PREFIX_MIN_SIZE) {
    1241           0 :                         zlog_warn("%s: undersized IPv6 prefix header",
    1242             :                                   __func__);
    1243           0 :                         return MSG_NG;
    1244             :                 }
    1245             :                 /* safe to look deeper */
    1246         147 :                 if (current->prefix_length > IPV6_MAX_BITLEN) {
    1247           0 :                         zlog_warn("%s: invalid PrefixLength (%u bits)",
    1248             :                                   __func__, current->prefix_length);
    1249           0 :                         return MSG_NG;
    1250             :                 }
    1251             :                 /* covers both fixed- and variable-sized fields */
    1252         147 :                 requested_pfx_bytes =
    1253             :                         OSPF6_PREFIX_MIN_SIZE
    1254         147 :                         + OSPF6_PREFIX_SPACE(current->prefix_length);
    1255         147 :                 if (requested_pfx_bytes > length) {
    1256           0 :                         zlog_warn("%s: undersized IPv6 prefix", __func__);
    1257           0 :                         return MSG_NG;
    1258             :                 }
    1259             :                 /* next prefix */
    1260         147 :                 length -= requested_pfx_bytes;
    1261         147 :                 current = (struct ospf6_prefix *)((caddr_t)current
    1262             :                                                   + requested_pfx_bytes);
    1263         147 :                 real_num_pfxs++;
    1264             :         }
    1265         114 :         if (real_num_pfxs != req_num_pfxs) {
    1266           0 :                 zlog_warn(
    1267             :                         "%s: IPv6 prefix number mismatch (%u required, %u real)",
    1268             :                         __func__, req_num_pfxs, real_num_pfxs);
    1269           0 :                 return MSG_NG;
    1270             :         }
    1271             :         return MSG_OK;
    1272             : }
    1273             : 
    1274             : /* Verify an LSA to have a valid length and dispatch further (where
    1275             :    appropriate) to check if the contents, including nested IPv6 prefixes,
    1276             :    is properly sized/aligned within the LSA. Note that this function gets
    1277             :    LSA type in network byte order, uses in host byte order and passes to
    1278             :    ospf6_lstype_name() in network byte order again. */
    1279         309 : static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
    1280             :                                  const uint16_t lsalen,
    1281             :                                  const uint8_t headeronly)
    1282             : {
    1283         309 :         struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
    1284         309 :         struct ospf6_as_external_lsa *as_external_lsa;
    1285         309 :         struct ospf6_link_lsa *link_lsa;
    1286         309 :         unsigned exp_length;
    1287         309 :         uint8_t ltindex;
    1288         309 :         uint16_t lsatype;
    1289             : 
    1290             :         /* In case an additional minimum length constraint is defined for
    1291             :            current
    1292             :            LSA type, make sure that this constraint is met. */
    1293         309 :         lsatype = ntohs(lsah->type);
    1294         309 :         ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
    1295         309 :         if (ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex]
    1296         309 :             && lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE) {
    1297           0 :                 zlog_warn("%s: undersized (%u B) LSA", __func__, lsalen);
    1298           0 :                 return MSG_NG;
    1299             :         }
    1300         309 :         switch (lsatype) {
    1301         124 :         case OSPF6_LSTYPE_ROUTER:
    1302             :                 /* RFC5340 A.4.3, LSA header + OSPF6_ROUTER_LSA_MIN_SIZE bytes
    1303             :                    followed
    1304             :                    by N>=0 interface descriptions. */
    1305         124 :                 if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE)
    1306         124 :                     % OSPF6_ROUTER_LSDESC_FIX_SIZE) {
    1307           0 :                         zlog_warn(
    1308             :                                 "%s: Router LSA interface description alignment error",
    1309             :                                 __func__);
    1310           0 :                         return MSG_NG;
    1311             :                 }
    1312             :                 break;
    1313          15 :         case OSPF6_LSTYPE_NETWORK:
    1314             :                 /* RFC5340 A.4.4, LSA header + OSPF6_NETWORK_LSA_MIN_SIZE bytes
    1315             :                    followed by N>=0 attached router descriptions. */
    1316          15 :                 if ((lsalen - OSPF6_LSA_HEADER_SIZE
    1317             :                      - OSPF6_NETWORK_LSA_MIN_SIZE)
    1318             :                     % OSPF6_NETWORK_LSDESC_FIX_SIZE) {
    1319           0 :                         zlog_warn(
    1320             :                                 "%s: Network LSA router description alignment error",
    1321             :                                 __func__);
    1322           0 :                         return MSG_NG;
    1323             :                 }
    1324             :                 break;
    1325           0 :         case OSPF6_LSTYPE_INTER_PREFIX:
    1326             :                 /* RFC5340 A.4.5, LSA header + OSPF6_INTER_PREFIX_LSA_MIN_SIZE
    1327             :                    bytes
    1328             :                    followed by 3-4 fields of a single IPv6 prefix. */
    1329           0 :                 if (headeronly)
    1330             :                         break;
    1331           0 :                 return ospf6_prefixes_examin(
    1332             :                         (struct ospf6_prefix
    1333             :                                  *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE
    1334             :                                     + OSPF6_INTER_PREFIX_LSA_MIN_SIZE),
    1335             :                         lsalen - OSPF6_LSA_HEADER_SIZE
    1336             :                                 - OSPF6_INTER_PREFIX_LSA_MIN_SIZE,
    1337             :                         1);
    1338           0 :         case OSPF6_LSTYPE_INTER_ROUTER:
    1339             :                 /* RFC5340 A.4.6, fixed-size LSA. */
    1340           0 :                 if (lsalen
    1341             :                     > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) {
    1342           0 :                         zlog_warn("%s: Inter Router LSA oversized (%u B) LSA",
    1343             :                                   __func__, lsalen);
    1344           0 :                         return MSG_NG;
    1345             :                 }
    1346             :                 break;
    1347           0 :         case OSPF6_LSTYPE_AS_EXTERNAL: /* RFC5340 A.4.7, same as A.4.8. */
    1348             :         case OSPF6_LSTYPE_TYPE_7:
    1349             :                 /* RFC5340 A.4.8, LSA header + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE
    1350             :                    bytes
    1351             :                    followed by 3-4 fields of IPv6 prefix and 3 conditional LSA
    1352             :                    fields:
    1353             :                    16 bytes of forwarding address, 4 bytes of external route
    1354             :                    tag,
    1355             :                    4 bytes of referenced link state ID. */
    1356           0 :                 if (headeronly)
    1357             :                         break;
    1358           0 :                 as_external_lsa =
    1359             :                         (struct ospf6_as_external_lsa
    1360             :                                  *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE);
    1361           0 :                 exp_length =
    1362             :                         OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE;
    1363             :                 /* To find out if the last optional field (Referenced Link State
    1364             :                    ID) is
    1365             :                    assumed in this LSA, we need to access fixed fields of the
    1366             :                    IPv6
    1367             :                    prefix before ospf6_prefix_examin() confirms its sizing. */
    1368           0 :                 if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) {
    1369           0 :                         zlog_warn(
    1370             :                                 "%s: AS External undersized (%u B) LSA header",
    1371             :                                 __func__, lsalen);
    1372           0 :                         return MSG_NG;
    1373             :                 }
    1374             :                 /* forwarding address */
    1375           0 :                 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F))
    1376           0 :                         exp_length += 16;
    1377             :                 /* external route tag */
    1378           0 :                 if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T))
    1379           0 :                         exp_length += 4;
    1380             :                 /* referenced link state ID */
    1381           0 :                 if (as_external_lsa->prefix.u._prefix_referenced_lstype)
    1382           0 :                         exp_length += 4;
    1383             :                 /* All the fixed-size fields (mandatory and optional) must fit.
    1384             :                    I.e.,
    1385             :                    this check does not include any IPv6 prefix fields. */
    1386           0 :                 if (exp_length > lsalen) {
    1387           0 :                         zlog_warn(
    1388             :                                 "%s: AS External undersized (%u B) LSA header",
    1389             :                                 __func__, lsalen);
    1390           0 :                         return MSG_NG;
    1391             :                 }
    1392             :                 /* The last call completely covers the remainder (IPv6 prefix).
    1393             :                  */
    1394           0 :                 return ospf6_prefixes_examin(
    1395             :                         (struct ospf6_prefix
    1396             :                                  *)((caddr_t)as_external_lsa
    1397             :                                     + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE),
    1398             :                         lsalen - exp_length, 1);
    1399          48 :         case OSPF6_LSTYPE_LINK:
    1400             :                 /* RFC5340 A.4.9, LSA header + OSPF6_LINK_LSA_MIN_SIZE bytes
    1401             :                    followed
    1402             :                    by N>=0 IPv6 prefix blocks (with N declared beforehand). */
    1403          48 :                 if (headeronly)
    1404             :                         break;
    1405          28 :                 link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsah
    1406             :                                                      + OSPF6_LSA_HEADER_SIZE);
    1407          28 :                 return ospf6_prefixes_examin(
    1408             :                         (struct ospf6_prefix *)((caddr_t)link_lsa
    1409             :                                                 + OSPF6_LINK_LSA_MIN_SIZE),
    1410             :                         lsalen - OSPF6_LSA_HEADER_SIZE
    1411             :                                 - OSPF6_LINK_LSA_MIN_SIZE,
    1412             :                         ntohl(link_lsa->prefix_num) /* 32 bits */
    1413             :                         );
    1414         122 :         case OSPF6_LSTYPE_INTRA_PREFIX:
    1415             :                 /* RFC5340 A.4.10, LSA header + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE
    1416             :                    bytes
    1417             :                    followed by N>=0 IPv6 prefixes (with N declared beforehand).
    1418             :                    */
    1419         122 :                 if (headeronly)
    1420             :                         break;
    1421          86 :                 intra_prefix_lsa =
    1422             :                         (struct ospf6_intra_prefix_lsa
    1423             :                                  *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE);
    1424          86 :                 return ospf6_prefixes_examin(
    1425             :                         (struct ospf6_prefix
    1426             :                                  *)((caddr_t)intra_prefix_lsa
    1427             :                                     + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE),
    1428             :                         lsalen - OSPF6_LSA_HEADER_SIZE
    1429             :                                 - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE,
    1430          86 :                         ntohs(intra_prefix_lsa->prefix_num) /* 16 bits */
    1431             :                 );
    1432           0 :         case OSPF6_LSTYPE_GRACE_LSA:
    1433           0 :                 if (lsalen < OSPF6_LSA_HEADER_SIZE + GRACE_PERIOD_TLV_SIZE
    1434             :                                      + GRACE_RESTART_REASON_TLV_SIZE) {
    1435           0 :                         if (IS_DEBUG_OSPF6_GR)
    1436           0 :                                 zlog_debug("%s: Undersized GraceLSA.",
    1437             :                                            __func__);
    1438           0 :                         return MSG_NG;
    1439             :                 }
    1440             :         }
    1441             :         /* No additional validation is possible for unknown LSA types, which are
    1442             :            themselves valid in OPSFv3, hence the default decision is to accept.
    1443             :            */
    1444             :         return MSG_OK;
    1445             : }
    1446             : 
    1447             : /* Verify if the provided input buffer is a valid sequence of LSAs. This
    1448             :    includes verification of LSA blocks length/alignment and dispatching
    1449             :    of deeper-level checks. */
    1450             : static unsigned
    1451         132 : ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
    1452             :                     size_t length, const uint8_t headeronly,
    1453             :                     /* When declared_num_lsas is not 0, compare it to the real
    1454             :                        number of LSAs
    1455             :                        and treat the difference as an error. */
    1456             :                     const uint32_t declared_num_lsas)
    1457             : {
    1458         132 :         uint32_t counted_lsas = 0;
    1459             : 
    1460         441 :         while (length) {
    1461         309 :                 uint16_t lsalen;
    1462         309 :                 if (length < OSPF6_LSA_HEADER_SIZE) {
    1463           0 :                         zlog_warn(
    1464             :                                 "%s: undersized (%zu B) trailing (#%u) LSA header",
    1465             :                                 __func__, length, counted_lsas);
    1466           0 :                         return MSG_NG;
    1467             :                 }
    1468             :                 /* save on ntohs() calls here and in the LSA validator */
    1469         309 :                 lsalen = OSPF6_LSA_SIZE(lsah);
    1470         309 :                 if (lsalen < OSPF6_LSA_HEADER_SIZE) {
    1471           0 :                         zlog_warn(
    1472             :                                 "%s: malformed LSA header #%u, declared length is %u B",
    1473             :                                 __func__, counted_lsas, lsalen);
    1474           0 :                         return MSG_NG;
    1475             :                 }
    1476         309 :                 if (headeronly) {
    1477             :                         /* less checks here and in ospf6_lsa_examin() */
    1478          98 :                         if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 1)) {
    1479           0 :                                 zlog_warn(
    1480             :                                         "%s: anomaly in header-only %s LSA #%u",
    1481             :                                         __func__, ospf6_lstype_name(lsah->type),
    1482             :                                         counted_lsas);
    1483           0 :                                 return MSG_NG;
    1484             :                         }
    1485          98 :                         lsah = (struct ospf6_lsa_header
    1486             :                                         *)((caddr_t)lsah
    1487             :                                            + OSPF6_LSA_HEADER_SIZE);
    1488          98 :                         length -= OSPF6_LSA_HEADER_SIZE;
    1489             :                 } else {
    1490             :                         /* make sure the input buffer is deep enough before
    1491             :                          * further checks */
    1492         211 :                         if (lsalen > length) {
    1493           0 :                                 zlog_warn(
    1494             :                                         "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
    1495             :                                         __func__, ospf6_lstype_name(lsah->type),
    1496             :                                         counted_lsas, lsalen, length);
    1497           0 :                                 return MSG_NG;
    1498             :                         }
    1499         211 :                         if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 0)) {
    1500           0 :                                 zlog_warn("%s: anomaly in %s LSA #%u", __func__,
    1501             :                                           ospf6_lstype_name(lsah->type),
    1502             :                                           counted_lsas);
    1503           0 :                                 return MSG_NG;
    1504             :                         }
    1505         211 :                         lsah = (struct ospf6_lsa_header *)((caddr_t)lsah
    1506             :                                                            + lsalen);
    1507         211 :                         length -= lsalen;
    1508             :                 }
    1509         309 :                 counted_lsas++;
    1510             :         }
    1511             : 
    1512         132 :         if (declared_num_lsas && counted_lsas != declared_num_lsas) {
    1513           0 :                 zlog_warn("%s: #LSAs declared (%u) does not match actual (%u)",
    1514             :                           __func__, declared_num_lsas, counted_lsas);
    1515           0 :                 return MSG_NG;
    1516             :         }
    1517             :         return MSG_OK;
    1518             : }
    1519             : 
    1520             : /* Verify a complete OSPF packet for proper sizing/alignment. */
    1521         230 : static unsigned ospf6_packet_examin(struct ospf6_header *oh,
    1522             :                                     const unsigned bytesonwire)
    1523             : {
    1524         230 :         struct ospf6_lsupdate *lsupd;
    1525         230 :         unsigned test;
    1526             : 
    1527             :         /* length, 1st approximation */
    1528         230 :         if (bytesonwire < OSPF6_HEADER_SIZE) {
    1529           0 :                 zlog_warn("%s: undersized (%u B) packet", __func__,
    1530             :                           bytesonwire);
    1531           0 :                 return MSG_NG;
    1532             :         }
    1533             : 
    1534             :         /* Now it is safe to access header fields. */
    1535         230 :         if (bytesonwire != ntohs(oh->length)) {
    1536           0 :                 zlog_warn("%s: %s packet length error (%u real, %u declared)",
    1537             :                           __func__, ospf6_message_type(oh->type), bytesonwire,
    1538             :                           ntohs(oh->length));
    1539           0 :                 return MSG_NG;
    1540             :         }
    1541             : 
    1542             :         /* version check */
    1543         230 :         if (oh->version != OSPFV3_VERSION) {
    1544           0 :                 zlog_warn("%s: invalid (%u) protocol version", __func__,
    1545             :                           oh->version);
    1546           0 :                 return MSG_NG;
    1547             :         }
    1548             :         /* length, 2nd approximation */
    1549         230 :         if (oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type]
    1550         196 :             && bytesonwire
    1551         196 :                        < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) {
    1552           0 :                 zlog_warn("%s: undersized (%u B) %s packet", __func__,
    1553             :                           bytesonwire, ospf6_message_type(oh->type));
    1554           0 :                 return MSG_NG;
    1555             :         }
    1556             :         /* type-specific deeper validation */
    1557         230 :         switch (oh->type) {
    1558          90 :         case OSPF6_MESSAGE_TYPE_HELLO:
    1559             :                 /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes
    1560             :                    followed
    1561             :                    by N>=0 router-IDs. */
    1562          90 :                 if (0
    1563             :                     == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE)
    1564          90 :                                % 4)
    1565             :                         return MSG_OK;
    1566           0 :                 zlog_warn("%s: alignment error in %s packet", __func__,
    1567             :                           ospf6_message_type(oh->type));
    1568           0 :                 return MSG_NG;
    1569          20 :         case OSPF6_MESSAGE_TYPE_DBDESC:
    1570             :                 /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes
    1571             :                    followed
    1572             :                    by N>=0 header-only LSAs. */
    1573          20 :                 test = ospf6_lsaseq_examin(
    1574             :                         (struct ospf6_lsa_header *)((caddr_t)oh
    1575             :                                                     + OSPF6_HEADER_SIZE
    1576             :                                                     + OSPF6_DB_DESC_MIN_SIZE),
    1577             :                         bytesonwire - OSPF6_HEADER_SIZE
    1578          20 :                                 - OSPF6_DB_DESC_MIN_SIZE,
    1579             :                         1, 0);
    1580          20 :                 break;
    1581           8 :         case OSPF6_MESSAGE_TYPE_LSREQ:
    1582             :                 /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */
    1583           8 :                 if (0
    1584           8 :                     == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE)
    1585           8 :                                % OSPF6_LSREQ_LSDESC_FIX_SIZE)
    1586             :                         return MSG_OK;
    1587           0 :                 zlog_warn("%s: alignment error in %s packet", __func__,
    1588             :                           ospf6_message_type(oh->type));
    1589           0 :                 return MSG_NG;
    1590          86 :         case OSPF6_MESSAGE_TYPE_LSUPDATE:
    1591             :                 /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes
    1592             :                    followed
    1593             :                    by N>=0 full LSAs (with N declared beforehand). */
    1594          86 :                 lsupd = (struct ospf6_lsupdate *)((caddr_t)oh
    1595             :                                                   + OSPF6_HEADER_SIZE);
    1596          86 :                 test = ospf6_lsaseq_examin(
    1597             :                         (struct ospf6_lsa_header *)((caddr_t)lsupd
    1598             :                                                     + OSPF6_LS_UPD_MIN_SIZE),
    1599          86 :                         bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE,
    1600             :                         0, ntohl(lsupd->lsa_number) /* 32 bits */
    1601             :                         );
    1602          86 :                 break;
    1603          26 :         case OSPF6_MESSAGE_TYPE_LSACK:
    1604             :                 /* RFC5340 A.3.6, packet header + N>=0 header-only LSAs. */
    1605          26 :                 test = ospf6_lsaseq_examin(
    1606             :                         (struct ospf6_lsa_header *)((caddr_t)oh
    1607             :                                                     + OSPF6_HEADER_SIZE
    1608             :                                                     + OSPF6_LS_ACK_MIN_SIZE),
    1609          26 :                         bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE,
    1610             :                         1, 0);
    1611          26 :                 break;
    1612           0 :         default:
    1613           0 :                 zlog_warn("%s: invalid (%u) message type", __func__, oh->type);
    1614           0 :                 return MSG_NG;
    1615             :         }
    1616         132 :         if (test != MSG_OK)
    1617           0 :                 zlog_warn("%s: anomaly in %s packet", __func__,
    1618             :                           ospf6_message_type(oh->type));
    1619             :         return test;
    1620             : }
    1621             : 
    1622             : /* Verify particular fields of otherwise correct received OSPF packet to
    1623             :    meet the requirements of RFC. */
    1624         230 : static int ospf6_rxpacket_examin(struct ospf6_interface *oi,
    1625             :                                  struct ospf6_header *oh,
    1626             :                                  const unsigned bytesonwire)
    1627             : {
    1628             : 
    1629         230 :         if (MSG_OK != ospf6_packet_examin(oh, bytesonwire))
    1630             :                 return MSG_NG;
    1631             : 
    1632             :         /* Area-ID check */
    1633         230 :         if (oh->area_id != oi->area->area_id) {
    1634           0 :                 if (oh->area_id == OSPF_AREA_BACKBONE)
    1635           0 :                         zlog_warn(
    1636             :                                 "VRF %s: I/F %pOI Message may be via Virtual Link: not supported",
    1637             :                                 oi->interface->vrf->name, oi);
    1638             :                 else
    1639           0 :                         zlog_warn(
    1640             :                                 "VRF %s: I/F %pOI Area-ID mismatch (my %pI4, rcvd %pI4)",
    1641             :                                 oi->interface->vrf->name, oi,
    1642             :                                 &oi->area->area_id, &oh->area_id);
    1643           0 :                 return MSG_NG;
    1644             :         }
    1645             : 
    1646             :         /* Instance-ID check */
    1647         230 :         if (oh->instance_id != oi->instance_id) {
    1648           0 :                 zlog_warn(
    1649             :                         "VRF %s: I/F %pOI Instance-ID mismatch (my %u, rcvd %u)",
    1650             :                         oi->interface->vrf->name, oi,
    1651             :                         oi->instance_id, oh->instance_id);
    1652           0 :                 return MSG_NG;
    1653             :         }
    1654             : 
    1655             :         /* Router-ID check */
    1656         230 :         if (oh->router_id == oi->area->ospf6->router_id) {
    1657           0 :                 zlog_warn("VRF %s: I/F %pOI Duplicate Router-ID (%pI4)",
    1658             :                           oi->interface->vrf->name, oi,
    1659             :                           &oh->router_id);
    1660           0 :                 return MSG_NG;
    1661             :         }
    1662             :         return MSG_OK;
    1663             : }
    1664             : 
    1665          86 : static void ospf6_lsupdate_recv(struct in6_addr *src, struct in6_addr *dst,
    1666             :                                 struct ospf6_interface *oi,
    1667             :                                 struct ospf6_header *oh)
    1668             : {
    1669          86 :         struct ospf6_neighbor *on;
    1670          86 :         struct ospf6_lsupdate *lsupdate;
    1671          86 :         char *p;
    1672             : 
    1673          86 :         on = ospf6_neighbor_lookup(oh->router_id, oi);
    1674          86 :         if (on == NULL) {
    1675           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1676           0 :                         zlog_debug("Neighbor not found, ignore");
    1677           0 :                 return;
    1678             :         }
    1679             : 
    1680          86 :         if (on->state != OSPF6_NEIGHBOR_EXCHANGE
    1681             :             && on->state != OSPF6_NEIGHBOR_LOADING
    1682          86 :             && on->state != OSPF6_NEIGHBOR_FULL) {
    1683           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1684           0 :                         zlog_debug("Neighbor state less than Exchange, ignore");
    1685           0 :                 return;
    1686             :         }
    1687             : 
    1688          86 :         lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
    1689             :                                              + sizeof(struct ospf6_header));
    1690             : 
    1691          86 :         oi->ls_upd_in++;
    1692             : 
    1693             :         /* Process LSAs */
    1694          86 :         for (p = (char *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
    1695         297 :              p < OSPF6_MESSAGE_END(oh)
    1696         297 :              && p + OSPF6_LSA_SIZE(p) <= OSPF6_MESSAGE_END(oh);
    1697         211 :              p += OSPF6_LSA_SIZE(p)) {
    1698         211 :                 ospf6_receive_lsa(on, (struct ospf6_lsa_header *)p);
    1699             :         }
    1700             : 
    1701          86 :         assert(p == OSPF6_MESSAGE_END(oh));
    1702             : }
    1703             : 
    1704          26 : static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst,
    1705             :                              struct ospf6_interface *oi,
    1706             :                              struct ospf6_header *oh)
    1707             : {
    1708          26 :         struct ospf6_neighbor *on;
    1709          26 :         char *p;
    1710          26 :         struct ospf6_lsa *his, *mine;
    1711          26 :         struct ospf6_lsdb *lsdb = NULL;
    1712             : 
    1713          26 :         assert(oh->type == OSPF6_MESSAGE_TYPE_LSACK);
    1714             : 
    1715          26 :         on = ospf6_neighbor_lookup(oh->router_id, oi);
    1716          26 :         if (on == NULL) {
    1717           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1718           0 :                         zlog_debug("Neighbor not found, ignore");
    1719           0 :                 return;
    1720             :         }
    1721             : 
    1722          26 :         if (on->state != OSPF6_NEIGHBOR_EXCHANGE
    1723             :             && on->state != OSPF6_NEIGHBOR_LOADING
    1724          26 :             && on->state != OSPF6_NEIGHBOR_FULL) {
    1725           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
    1726           0 :                         zlog_debug("Neighbor state less than Exchange, ignore");
    1727           0 :                 return;
    1728             :         }
    1729             : 
    1730          26 :         oi->ls_ack_in++;
    1731             : 
    1732          26 :         for (p = (char *)((caddr_t)oh + sizeof(struct ospf6_header));
    1733          85 :              p + sizeof(struct ospf6_lsa_header) <= OSPF6_MESSAGE_END(oh);
    1734             :              p += sizeof(struct ospf6_lsa_header)) {
    1735          59 :                 his = ospf6_lsa_create_headeronly((struct ospf6_lsa_header *)p);
    1736             : 
    1737          59 :                 switch (OSPF6_LSA_SCOPE(his->header->type)) {
    1738           8 :                 case OSPF6_SCOPE_LINKLOCAL:
    1739           8 :                         if (on->ospf6_if->type == OSPF_IFTYPE_VIRTUALLINK) {
    1740           0 :                                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1741           0 :                                         zlog_debug("Link-scoped LSA on Virtual link");
    1742           0 :                                 ospf6_lsa_delete(his);
    1743           0 :                                 continue;
    1744             :                         }
    1745           8 :                         lsdb = on->ospf6_if->lsdb;
    1746           8 :                         break;
    1747          51 :                 case OSPF6_SCOPE_AREA:
    1748          51 :                         lsdb = on->ospf6_if->area->lsdb;
    1749          51 :                         break;
    1750           0 :                 case OSPF6_SCOPE_AS:
    1751           0 :                         lsdb = on->ospf6_if->area->ospf6->lsdb;
    1752           0 :                         break;
    1753           0 :                 case OSPF6_SCOPE_RESERVED:
    1754           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1755           0 :                                 zlog_debug("Ignoring LSA of reserved scope");
    1756           0 :                         ospf6_lsa_delete(his);
    1757           0 :                         continue;
    1758             :                 }
    1759             : 
    1760          59 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1761           0 :                         zlog_debug("%s acknowledged by %s", his->name,
    1762             :                                    on->name);
    1763             : 
    1764             :                 /* Find database copy */
    1765         118 :                 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
    1766          59 :                                          his->header->adv_router, lsdb);
    1767          59 :                 if (mine == NULL) {
    1768           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1769           0 :                                 zlog_debug("No database copy");
    1770           0 :                         ospf6_lsa_delete(his);
    1771           0 :                         continue;
    1772             :                 }
    1773             : 
    1774             :                 /* Check if the LSA is on his retrans-list */
    1775         118 :                 mine = ospf6_lsdb_lookup(his->header->type, his->header->id,
    1776          59 :                                          his->header->adv_router,
    1777             :                                          on->retrans_list);
    1778          59 :                 if (mine == NULL) {
    1779          14 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1780           0 :                                 zlog_debug("Not on %s's retrans-list",
    1781             :                                            on->name);
    1782          14 :                         ospf6_lsa_delete(his);
    1783          14 :                         continue;
    1784             :                 }
    1785             : 
    1786          45 :                 if (ospf6_lsa_compare(his, mine) != 0) {
    1787             :                         /* Log this questionable acknowledgement,
    1788             :                            and examine the next one. */
    1789           4 :                         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1790           0 :                                 zlog_debug("Questionable acknowledgement");
    1791           4 :                         ospf6_lsa_delete(his);
    1792           4 :                         continue;
    1793             :                 }
    1794             : 
    1795          41 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
    1796           0 :                         zlog_debug(
    1797             :                                 "Acknowledged, remove from %s's retrans-list",
    1798             :                                 on->name);
    1799             : 
    1800          41 :                 ospf6_decrement_retrans_count(mine);
    1801          41 :                 if (OSPF6_LSA_IS_MAXAGE(mine))
    1802           0 :                         ospf6_maxage_remove(on->ospf6_if->area->ospf6);
    1803          41 :                 ospf6_lsdb_remove(mine, on->retrans_list);
    1804          41 :                 ospf6_lsa_delete(his);
    1805             :         }
    1806             : 
    1807          26 :         assert(p == OSPF6_MESSAGE_END(oh));
    1808             : }
    1809             : 
    1810             : static uint8_t *recvbuf = NULL;
    1811             : static uint8_t *sendbuf = NULL;
    1812             : static unsigned int iobuflen = 0;
    1813             : 
    1814          10 : int ospf6_iobuf_size(unsigned int size)
    1815             : {
    1816             :         /* NB: there was previously code here that tried to dynamically size
    1817             :          * the buffer for whatever we see in MTU on interfaces.  Which is
    1818             :          * _unconditionally wrong_ - we can always receive fragmented IPv6
    1819             :          * up to the regular 64k length limit.  (No jumbograms, thankfully.)
    1820             :          */
    1821             : 
    1822          10 :         if (!iobuflen) {
    1823             :                 /* the + 128 is to have some runway at the end */
    1824           4 :                 size_t alloc_size = 65536 + 128;
    1825             : 
    1826           4 :                 assert(!recvbuf && !sendbuf);
    1827             : 
    1828           4 :                 recvbuf = XMALLOC(MTYPE_OSPF6_MESSAGE, alloc_size);
    1829           4 :                 sendbuf = XMALLOC(MTYPE_OSPF6_MESSAGE, alloc_size);
    1830           4 :                 iobuflen = alloc_size;
    1831             :         }
    1832             : 
    1833          10 :         return iobuflen;
    1834             : }
    1835             : 
    1836           4 : void ospf6_message_terminate(void)
    1837             : {
    1838           4 :         XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
    1839           4 :         XFREE(MTYPE_OSPF6_MESSAGE, sendbuf);
    1840             : 
    1841           4 :         iobuflen = 0;
    1842           4 : }
    1843             : 
    1844             : enum ospf6_read_return_enum {
    1845             :         OSPF6_READ_ERROR,
    1846             :         OSPF6_READ_CONTINUE,
    1847             : };
    1848             : 
    1849             : static int ospf6_rxpacket_process(struct in6_addr *src, struct in6_addr *dst,
    1850             :                                   struct ospf6_interface *oi,
    1851             :                                   struct ospf6_header *oh, int len,
    1852             :                                   uint32_t at_len, uint32_t lls_len);
    1853             : 
    1854           0 : static int ospf6_rxpacket_vlink(struct in6_addr *src, struct in6_addr *dst,
    1855             :                                 struct ospf6 *ospf6, int ifindex, int len,
    1856             :                                 uint32_t at_len, uint32_t lls_len)
    1857             : {
    1858           0 :         struct ospf6_interface *oi = ospf6->vlink_oi;
    1859           0 :         struct ospf6_header *oh;
    1860           0 :         struct interface *ifp;
    1861             : 
    1862             :         /*
    1863             :          * Drop packet destined to another VRF.
    1864             :          * This happens when raw_l3mdev_accept is set to 1.
    1865             :          */
    1866           0 :         ifp = if_lookup_by_index(ifindex, ospf6->vrf_id);
    1867           0 :         if (!ifp || ospf6->vrf_id != ifp->vrf->vrf_id)
    1868             :                 return OSPF6_READ_CONTINUE;
    1869             : 
    1870           0 :         oh = (struct ospf6_header *)recvbuf;
    1871           0 :         if (MSG_OK != ospf6_packet_examin(oh, len))
    1872             :                 return OSPF6_READ_ERROR;
    1873             : 
    1874             :         /* Area-ID check */
    1875           0 :         if (oh->area_id != INADDR_ANY || !oi) {
    1876           0 :                 zlog_warn(
    1877             :                         "VRF %s: OSPFv3 packet to invalid destination %pI6",
    1878             :                         vrf_id_to_name(ospf6->vrf_id), dst);
    1879           0 :                 return OSPF6_READ_ERROR;
    1880             :         }
    1881             : 
    1882             :         /* Instance-ID check */
    1883           0 :         if (oh->instance_id != oi->instance_id) {
    1884           0 :                 zlog_warn(
    1885             :                         "VRF %s: %pI6%%%s Instance-ID mismatch (my %u, rcvd %u)",
    1886             :                         vrf_id_to_name(ospf6->vrf_id), src, ifp->name,
    1887             :                         oi->instance_id, oh->instance_id);
    1888           0 :                 return MSG_NG;
    1889             :         }
    1890             : 
    1891             :         /* Router-ID check */
    1892           0 :         if (oh->router_id == ospf6->router_id) {
    1893           0 :                 zlog_warn("VRF %s: %pI6%%%s Duplicate Router-ID (%pI4)",
    1894             :                           vrf_id_to_name(ospf6->vrf_id), src, ifp->name,
    1895             :                           &oh->router_id);
    1896           0 :                 return MSG_NG;
    1897             :         }
    1898             : 
    1899           0 :         return ospf6_rxpacket_process(src, dst, oi, oh, len, at_len, lls_len);
    1900             : }
    1901             : 
    1902         409 : static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6)
    1903             : {
    1904         409 :         int len;
    1905         409 :         struct in6_addr src, dst;
    1906         409 :         ifindex_t ifindex;
    1907         409 :         struct iovec iovector[2];
    1908         409 :         struct ospf6_interface *oi;
    1909         409 :         struct ospf6_header *oh;
    1910         409 :         enum ospf6_auth_err ret = OSPF6_AUTH_PROCESS_NORMAL;
    1911         409 :         uint32_t at_len = 0;
    1912         409 :         uint32_t lls_len = 0;
    1913             : 
    1914             :         /* initialize */
    1915         409 :         memset(&src, 0, sizeof(src));
    1916         409 :         memset(&dst, 0, sizeof(dst));
    1917         409 :         ifindex = 0;
    1918         409 :         iovector[0].iov_base = recvbuf;
    1919         409 :         iovector[0].iov_len = iobuflen;
    1920         409 :         iovector[1].iov_base = NULL;
    1921         409 :         iovector[1].iov_len = 0;
    1922             : 
    1923             :         /* receive message */
    1924         409 :         len = ospf6_recvmsg(&src, &dst, &ifindex, iovector, sockfd);
    1925         409 :         if (len < 0)
    1926             :                 return OSPF6_READ_ERROR;
    1927             : 
    1928         230 :         if ((uint)len > iobuflen) {
    1929           0 :                 flog_err(EC_LIB_DEVELOPMENT, "Excess message read");
    1930           0 :                 return OSPF6_READ_ERROR;
    1931             :         }
    1932             : 
    1933             :         /* ensure some zeroes past the end, just as a security precaution */
    1934         230 :         memset(recvbuf + len, 0, MIN(128, iobuflen - len));
    1935             : 
    1936         230 :         if (!IN6_IS_ADDR_LINKLOCAL(&dst) && !IN6_IS_ADDR_MULTICAST(&dst))
    1937           0 :                 return ospf6_rxpacket_vlink(&src, &dst, ospf6, ifindex, len,
    1938             :                                             at_len, lls_len);
    1939             : 
    1940         230 :         oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
    1941         230 :         if (oi == NULL || oi->area == NULL
    1942         230 :             || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
    1943           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
    1944             :                                            RECV_HDR))
    1945           0 :                         zlog_debug("Message received on disabled interface");
    1946           0 :                 return OSPF6_READ_CONTINUE;
    1947             :         }
    1948         230 :         if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) {
    1949           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
    1950             :                                            RECV_HDR))
    1951           0 :                         zlog_debug("%s: Ignore message on passive interface %pOI",
    1952             :                                    __func__, oi);
    1953           0 :                 return OSPF6_READ_CONTINUE;
    1954             :         }
    1955             : 
    1956             :         /*
    1957             :          * Drop packet destined to another VRF.
    1958             :          * This happens when raw_l3mdev_accept is set to 1.
    1959             :          */
    1960         230 :         if (ospf6->vrf_id != oi->interface->vrf->vrf_id)
    1961             :                 return OSPF6_READ_CONTINUE;
    1962             : 
    1963         230 :         oh = (struct ospf6_header *)recvbuf;
    1964         230 :         ret = ospf6_auth_validate_pkt(oi, (uint32_t *)&len, oh, &at_len,
    1965             :                                       &lls_len);
    1966         230 :         if (ret == OSPF6_AUTH_VALIDATE_SUCCESS) {
    1967           0 :                 ret = ospf6_auth_check_digest(oh, oi, &src, lls_len);
    1968           0 :                 if (ret == OSPF6_AUTH_VALIDATE_FAILURE) {
    1969           0 :                         if (IS_OSPF6_DEBUG_AUTH_RX)
    1970           0 :                                 zlog_err(
    1971             :                                         "RECV[%pOI]: OSPF packet auth digest miss-match on %s",
    1972             :                                         oi, ospf6_message_type(oh->type));
    1973           0 :                         oi->at_data.rx_drop++;
    1974           0 :                         return OSPF6_READ_CONTINUE;
    1975             :                 }
    1976         230 :         } else if (ret == OSPF6_AUTH_VALIDATE_FAILURE) {
    1977           0 :                 oi->at_data.rx_drop++;
    1978           0 :                 return OSPF6_READ_CONTINUE;
    1979             :         }
    1980             : 
    1981         230 :         if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK)
    1982             :                 return OSPF6_READ_CONTINUE;
    1983         230 :         return ospf6_rxpacket_process(&src, &dst, oi, oh, len, at_len, lls_len);
    1984             : }
    1985             : 
    1986         230 : static int ospf6_rxpacket_process(struct in6_addr *src, struct in6_addr *dst,
    1987             :                                   struct ospf6_interface *oi,
    1988             :                                   struct ospf6_header *oh, int len,
    1989             :                                   uint32_t at_len, uint32_t lls_len)
    1990             : {
    1991             :         /* Being here means, that no sizing/alignment issues were detected in
    1992             :            the input packet. This renders the additional checks performed below
    1993             :            and also in the type-specific dispatching functions a dead code,
    1994             :            which can be dismissed in a cleanup-focused review round later. */
    1995             : 
    1996             :         /* Log */
    1997         230 :         if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR)) {
    1998           0 :                 zlog_debug("%s received on %pOI", ospf6_message_type(oh->type),
    1999             :                            oi);
    2000           0 :                 zlog_debug("    src: %pI6", src);
    2001           0 :                 zlog_debug("    dst: %pI6", dst);
    2002             : 
    2003           0 :                 switch (oh->type) {
    2004           0 :                 case OSPF6_MESSAGE_TYPE_HELLO:
    2005           0 :                         ospf6_hello_print(oh, OSPF6_ACTION_RECV);
    2006           0 :                         break;
    2007           0 :                 case OSPF6_MESSAGE_TYPE_DBDESC:
    2008           0 :                         ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV);
    2009           0 :                         break;
    2010           0 :                 case OSPF6_MESSAGE_TYPE_LSREQ:
    2011           0 :                         ospf6_lsreq_print(oh, OSPF6_ACTION_RECV);
    2012           0 :                         break;
    2013           0 :                 case OSPF6_MESSAGE_TYPE_LSUPDATE:
    2014           0 :                         ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV);
    2015           0 :                         break;
    2016           0 :                 case OSPF6_MESSAGE_TYPE_LSACK:
    2017           0 :                         ospf6_lsack_print(oh, OSPF6_ACTION_RECV);
    2018           0 :                         break;
    2019             :                 default:
    2020           0 :                         assert(0);
    2021             :                 }
    2022             : 
    2023           0 :                 if ((at_len != 0) && IS_OSPF6_DEBUG_AUTH_RX)
    2024           0 :                         ospf6_auth_hdr_dump_recv(oh, (len + at_len + lls_len),
    2025             :                                                  lls_len);
    2026             :         }
    2027             : 
    2028         230 :         switch (oh->type) {
    2029          90 :         case OSPF6_MESSAGE_TYPE_HELLO:
    2030          90 :                 ospf6_hello_recv(src, dst, oi, oh);
    2031          90 :                 break;
    2032             : 
    2033          20 :         case OSPF6_MESSAGE_TYPE_DBDESC:
    2034          20 :                 ospf6_dbdesc_recv(src, dst, oi, oh);
    2035          20 :                 break;
    2036             : 
    2037           8 :         case OSPF6_MESSAGE_TYPE_LSREQ:
    2038           8 :                 ospf6_lsreq_recv(src, dst, oi, oh);
    2039           8 :                 break;
    2040             : 
    2041          86 :         case OSPF6_MESSAGE_TYPE_LSUPDATE:
    2042          86 :                 ospf6_lsupdate_recv(src, dst, oi, oh);
    2043          86 :                 break;
    2044             : 
    2045          26 :         case OSPF6_MESSAGE_TYPE_LSACK:
    2046          26 :                 ospf6_lsack_recv(src, dst, oi, oh);
    2047          26 :                 break;
    2048             : 
    2049             :         default:
    2050           0 :                 assert(0);
    2051             :         }
    2052             : 
    2053         230 :         return OSPF6_READ_CONTINUE;
    2054             : }
    2055             : 
    2056         179 : void ospf6_receive(struct thread *thread)
    2057             : {
    2058         179 :         int sockfd;
    2059         179 :         struct ospf6 *ospf6;
    2060         179 :         int count = 0;
    2061             : 
    2062             :         /* add next read thread */
    2063         179 :         ospf6 = THREAD_ARG(thread);
    2064         179 :         sockfd = THREAD_FD(thread);
    2065             : 
    2066         179 :         thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
    2067             :                         &ospf6->t_ospf6_receive);
    2068             : 
    2069         409 :         while (count < ospf6->write_oi_count) {
    2070         409 :                 count++;
    2071         409 :                 switch (ospf6_read_helper(sockfd, ospf6)) {
    2072             :                 case OSPF6_READ_ERROR:
    2073             :                         return;
    2074             :                 case OSPF6_READ_CONTINUE:
    2075             :                         break;
    2076             :                 }
    2077             :         }
    2078             : }
    2079             : 
    2080         159 : static void ospf6_fill_hdr_checksum(struct ospf6_interface *oi,
    2081             :                                     struct ospf6_packet *op)
    2082             : {
    2083         159 :         struct ipv6_ph ph = {};
    2084         159 :         struct ospf6_header *oh;
    2085         159 :         void *offset = NULL;
    2086             : 
    2087         159 :         if (oi->at_data.flags != 0)
    2088           0 :                 return;
    2089             : 
    2090         159 :         memcpy(&ph.src, oi->linklocal_addr, sizeof(struct in6_addr));
    2091         159 :         memcpy(&ph.dst, &op->dst, sizeof(struct in6_addr));
    2092         159 :         ph.ulpl = htonl(op->length);
    2093         159 :         ph.next_hdr = IPPROTO_OSPFIGP;
    2094             : 
    2095             :         /* Suppress static analysis warnings about accessing icmp6 oob */
    2096         159 :         oh = (struct ospf6_header *)STREAM_DATA(op->s);
    2097         159 :         offset = oh;
    2098         159 :         oh->checksum = in_cksum_with_ph6(&ph, offset, op->length);
    2099             : }
    2100             : 
    2101         311 : static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi,
    2102             :                               struct stream *s)
    2103             : {
    2104         311 :         struct ospf6_header *oh;
    2105             : 
    2106         311 :         oh = (struct ospf6_header *)STREAM_DATA(s);
    2107             : 
    2108         311 :         oh->version = (uint8_t)OSPFV3_VERSION;
    2109         311 :         oh->type = type;
    2110         311 :         oh->length = 0;
    2111             : 
    2112         311 :         oh->router_id = oi->area->ospf6->router_id;
    2113         311 :         oh->area_id = oi->area->area_id;
    2114         311 :         oh->checksum = 0;
    2115         311 :         oh->instance_id = oi->instance_id;
    2116         311 :         oh->reserved = 0;
    2117             : 
    2118         311 :         stream_forward_endp(s, OSPF6_HEADER_SIZE);
    2119         311 : }
    2120             : 
    2121         219 : static void ospf6_fill_header(struct ospf6_interface *oi, struct stream *s,
    2122             :                               uint16_t length)
    2123             : {
    2124         219 :         struct ospf6_header *oh;
    2125             : 
    2126         219 :         oh = (struct ospf6_header *)STREAM_DATA(s);
    2127             : 
    2128         219 :         oh->length = htons(length);
    2129             : }
    2130             : 
    2131         102 : static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num)
    2132             : {
    2133         102 :         struct ospf6_header *oh;
    2134         102 :         struct ospf6_lsupdate *lsu;
    2135             : 
    2136         102 :         oh = (struct ospf6_header *)STREAM_DATA(s);
    2137             : 
    2138         102 :         lsu = (struct ospf6_lsupdate *)((caddr_t)oh
    2139             :                                         + sizeof(struct ospf6_header));
    2140         102 :         lsu->lsa_number = htonl(lsa_num);
    2141             : }
    2142             : 
    2143           0 : static void ospf6_auth_trailer_copy_keychain_key(struct ospf6_interface *oi)
    2144             : {
    2145           0 :         char *keychain_name = NULL;
    2146           0 :         struct keychain *keychain = NULL;
    2147           0 :         struct key *key = NULL;
    2148             : 
    2149           0 :         keychain_name = oi->at_data.keychain;
    2150           0 :         keychain = keychain_lookup(keychain_name);
    2151           0 :         if (keychain) {
    2152           0 :                 key = key_lookup_for_send(keychain);
    2153           0 :                 if (key && key->string &&
    2154           0 :                     key->hash_algo != KEYCHAIN_ALGO_NULL) {
    2155             :                         /* storing the values so that further
    2156             :                          * lookup can be avoided. after
    2157             :                          * processing the digest need to reset
    2158             :                          * these values
    2159             :                          */
    2160           0 :                         oi->at_data.hash_algo = key->hash_algo;
    2161           0 :                         if (oi->at_data.auth_key)
    2162           0 :                                 XFREE(MTYPE_OSPF6_AUTH_MANUAL_KEY,
    2163             :                                       oi->at_data.auth_key);
    2164           0 :                         oi->at_data.auth_key = XSTRDUP(
    2165             :                                 MTYPE_OSPF6_AUTH_MANUAL_KEY, key->string);
    2166           0 :                         oi->at_data.key_id = key->index;
    2167           0 :                         SET_FLAG(oi->at_data.flags,
    2168             :                                  OSPF6_AUTH_TRAILER_KEYCHAIN_VALID);
    2169             :                 }
    2170             :         }
    2171           0 : }
    2172             : 
    2173         468 : static uint16_t ospf6_packet_max(struct ospf6_interface *oi)
    2174             : {
    2175         468 :         uint16_t at_len = 0;
    2176             : 
    2177         468 :         assert(oi->ifmtu > sizeof(struct ip6_hdr));
    2178             : 
    2179         468 :         if (oi->at_data.flags != 0) {
    2180           0 :                 if (CHECK_FLAG(oi->at_data.flags, OSPF6_AUTH_TRAILER_KEYCHAIN))
    2181           0 :                         ospf6_auth_trailer_copy_keychain_key(oi);
    2182             : 
    2183           0 :                 at_len += OSPF6_AUTH_HDR_MIN_SIZE;
    2184           0 :                 at_len += keychain_get_hash_len(oi->at_data.hash_algo);
    2185           0 :                 return oi->ifmtu - (sizeof(struct ip6_hdr)) - at_len;
    2186             :         }
    2187             : 
    2188         468 :         return oi->ifmtu - (sizeof(struct ip6_hdr));
    2189             : }
    2190             : 
    2191          60 : static uint16_t ospf6_make_hello(struct ospf6_interface *oi,
    2192             :                                  struct ospf6_virtual_link *vlink,
    2193             :                                  struct stream *s)
    2194             : {
    2195          60 :         struct listnode *node, *nnode;
    2196          60 :         struct ospf6_neighbor *on;
    2197          60 :         uint16_t length = OSPF6_HELLO_MIN_SIZE;
    2198          60 :         uint8_t options1 = oi->area->options[1];
    2199             : 
    2200          60 :         if (oi->at_data.flags != 0)
    2201           0 :                 options1 |= OSPF6_OPT_AT;
    2202             : 
    2203          60 :         stream_putl(s, vlink ? vlink->v_ifindex : oi->interface->ifindex);
    2204          60 :         stream_putc(s, oi->priority);
    2205          60 :         stream_putc(s, oi->area->options[0]);
    2206          60 :         stream_putc(s, options1);
    2207          60 :         stream_putc(s, oi->area->options[2]);
    2208          60 :         stream_putw(s, vlink ? vlink->hello_interval : oi->hello_interval);
    2209          60 :         stream_putw(s, vlink ? vlink->dead_interval : oi->dead_interval);
    2210          60 :         stream_put_ipv4(s, oi->drouter);
    2211          60 :         stream_put_ipv4(s, oi->bdrouter);
    2212             : 
    2213          60 :         if (vlink) {
    2214           0 :                 on = vlink->nbr;
    2215           0 :                 if (on->state >= OSPF6_NEIGHBOR_INIT) {
    2216           0 :                         stream_put_ipv4(s, on->router_id);
    2217           0 :                         length += sizeof(uint32_t);
    2218             :                 }
    2219           0 :                 return length;
    2220             :         }
    2221             : 
    2222         206 :         for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
    2223          86 :                 if (on->state < OSPF6_NEIGHBOR_INIT)
    2224           0 :                         continue;
    2225             : 
    2226         172 :                 if ((length + sizeof(uint32_t) + OSPF6_HEADER_SIZE)
    2227          86 :                     > ospf6_packet_max(oi)) {
    2228           0 :                         if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
    2229             :                                                    SEND))
    2230           0 :                                 zlog_debug(
    2231             :                                         "sending Hello message: exceeds I/F MTU");
    2232             :                         break;
    2233             :                 }
    2234             : 
    2235          86 :                 stream_put_ipv4(s, on->router_id);
    2236          86 :                 length += sizeof(uint32_t);
    2237             :         }
    2238             : 
    2239             :         return length;
    2240             : }
    2241             : 
    2242         159 : static void ospf6_write(struct thread *thread)
    2243             : {
    2244         159 :         struct ospf6 *ospf6 = THREAD_ARG(thread);
    2245         159 :         struct ospf6_interface *oi;
    2246         159 :         struct ospf6_header *oh;
    2247         159 :         struct ospf6_packet *op;
    2248         159 :         struct listnode *node;
    2249         159 :         struct iovec iovector[2];
    2250         159 :         int pkt_count = 0;
    2251         159 :         int len;
    2252         159 :         int64_t latency = 0;
    2253         159 :         struct timeval timestamp;
    2254         159 :         uint16_t at_len = 0;
    2255             : 
    2256         159 :         if (ospf6->fd < 0) {
    2257           0 :                 zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd);
    2258           0 :                 return;
    2259             :         }
    2260             : 
    2261         159 :         node = listhead(ospf6->oi_write_q);
    2262         159 :         assert(node);
    2263         159 :         oi = listgetdata(node);
    2264             : 
    2265         378 :         while ((pkt_count < ospf6->write_oi_count) && oi) {
    2266         219 :                 op = ospf6_fifo_head(oi->obuf);
    2267         219 :                 assert(op);
    2268         219 :                 assert(op->length >= OSPF6_HEADER_SIZE);
    2269             : 
    2270         219 :                 iovector[0].iov_base = (caddr_t)stream_pnt(op->s);
    2271         219 :                 iovector[0].iov_len = op->length;
    2272         219 :                 iovector[1].iov_base = NULL;
    2273         219 :                 iovector[1].iov_len = 0;
    2274             : 
    2275         219 :                 oh = (struct ospf6_header *)STREAM_DATA(op->s);
    2276             : 
    2277         219 :                 if (oi->at_data.flags != 0) {
    2278           0 :                         at_len = ospf6_auth_len_get(oi);
    2279           0 :                         if (at_len) {
    2280           0 :                                 iovector[0].iov_len =
    2281           0 :                                         ntohs(oh->length) + at_len;
    2282           0 :                                 ospf6_auth_digest_send(oi->linklocal_addr, oi,
    2283             :                                                        oh, at_len,
    2284             :                                                        iovector[0].iov_len);
    2285             :                         } else {
    2286           0 :                                 iovector[0].iov_len = ntohs(oh->length);
    2287             :                         }
    2288             :                 } else {
    2289         219 :                         iovector[0].iov_len = ntohs(oh->length);
    2290             :                 }
    2291             : 
    2292         438 :                 len = ospf6_sendmsg(oi->linklocal_addr, &op->dst,
    2293         219 :                                     oi->interface->ifindex, iovector,
    2294             :                                     ospf6->fd);
    2295             : 
    2296         219 :                 if (len != (op->length + (int)at_len))
    2297           0 :                         flog_err(EC_LIB_DEVELOPMENT,
    2298             :                                  "Could not send entire message");
    2299             : 
    2300         219 :                 if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) {
    2301           0 :                         zlog_debug("%s send on %pOI",
    2302             :                                    ospf6_message_type(oh->type), oi);
    2303           0 :                         zlog_debug("    src: %pI6", oi->linklocal_addr);
    2304           0 :                         zlog_debug("    dst: %pI6", &op->dst);
    2305           0 :                         switch (oh->type) {
    2306           0 :                         case OSPF6_MESSAGE_TYPE_HELLO:
    2307           0 :                                 ospf6_hello_print(oh, OSPF6_ACTION_SEND);
    2308           0 :                                 break;
    2309           0 :                         case OSPF6_MESSAGE_TYPE_DBDESC:
    2310           0 :                                 ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND);
    2311           0 :                                 break;
    2312           0 :                         case OSPF6_MESSAGE_TYPE_LSREQ:
    2313           0 :                                 ospf6_lsreq_print(oh, OSPF6_ACTION_SEND);
    2314           0 :                                 break;
    2315           0 :                         case OSPF6_MESSAGE_TYPE_LSUPDATE:
    2316           0 :                                 ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND);
    2317           0 :                                 break;
    2318           0 :                         case OSPF6_MESSAGE_TYPE_LSACK:
    2319           0 :                                 ospf6_lsack_print(oh, OSPF6_ACTION_SEND);
    2320           0 :                                 break;
    2321           0 :                         default:
    2322           0 :                                 zlog_debug("Unknown message");
    2323           0 :                                 assert(0);
    2324             :                                 break;
    2325             :                         }
    2326             :                 }
    2327         219 :                 switch (oh->type) {
    2328          60 :                 case OSPF6_MESSAGE_TYPE_HELLO:
    2329          60 :                         monotime(&timestamp);
    2330          60 :                         if (oi->hello_out)
    2331          55 :                                 latency = monotime_since(&oi->last_hello, NULL)
    2332          55 :                                           - ((int64_t)oi->hello_interval
    2333          55 :                                              * 1000000);
    2334             : 
    2335             :                         /* log if latency exceeds the hello period */
    2336          60 :                         if (latency > ((int64_t)oi->hello_interval * 1000000))
    2337           0 :                                 zlog_warn("%s hello TX high latency %" PRId64
    2338             :                                           "us.",
    2339             :                                           __func__, latency);
    2340          60 :                         oi->last_hello = timestamp;
    2341          60 :                         oi->hello_out++;
    2342          60 :                         break;
    2343          20 :                 case OSPF6_MESSAGE_TYPE_DBDESC:
    2344          20 :                         oi->db_desc_out++;
    2345          20 :                         break;
    2346           8 :                 case OSPF6_MESSAGE_TYPE_LSREQ:
    2347           8 :                         oi->ls_req_out++;
    2348           8 :                         break;
    2349         102 :                 case OSPF6_MESSAGE_TYPE_LSUPDATE:
    2350         102 :                         oi->ls_upd_out++;
    2351         102 :                         break;
    2352          29 :                 case OSPF6_MESSAGE_TYPE_LSACK:
    2353          29 :                         oi->ls_ack_out++;
    2354          29 :                         break;
    2355           0 :                 default:
    2356           0 :                         zlog_debug("Unknown message");
    2357           0 :                         assert(0);
    2358             :                         break;
    2359             :                 }
    2360             : 
    2361         219 :                 if ((oi->at_data.flags != 0) &&
    2362           0 :                     (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) &&
    2363           0 :                     (IS_OSPF6_DEBUG_AUTH_TX))
    2364           0 :                         ospf6_auth_hdr_dump_send(oh, iovector[0].iov_len);
    2365             : 
    2366             :                 /* initialize at_len to 0 for next packet */
    2367         219 :                 at_len = 0;
    2368             : 
    2369             :                 /* Now delete packet from queue. */
    2370         219 :                 ospf6_packet_delete(oi);
    2371             : 
    2372             :                 /* Move this interface to the tail of write_q to
    2373             :                        serve everyone in a round robin fashion */
    2374         219 :                 list_delete_node(ospf6->oi_write_q, node);
    2375         219 :                 if (ospf6_fifo_head(oi->obuf) == NULL) {
    2376         165 :                         oi->on_write_q = 0;
    2377         165 :                         oi = NULL;
    2378             :                 } else {
    2379          54 :                         listnode_add(ospf6->oi_write_q, oi);
    2380             :                 }
    2381             : 
    2382             :                 /* Setup to service from the head of the queue again */
    2383         219 :                 if (!list_isempty(ospf6->oi_write_q)) {
    2384          60 :                         node = listhead(ospf6->oi_write_q);
    2385          60 :                         oi = listgetdata(node);
    2386             :                 }
    2387             :         }
    2388             : 
    2389             :         /* If packets still remain in queue, call write thread. */
    2390         159 :         if (!list_isempty(ospf6->oi_write_q))
    2391           0 :                 thread_add_write(master, ospf6_write, ospf6, ospf6->fd,
    2392             :                                  &ospf6->t_write);
    2393             : }
    2394             : 
    2395          60 : void ospf6_hello_send(struct thread *thread)
    2396             : {
    2397          60 :         struct ospf6_interface *oi;
    2398             : 
    2399          60 :         oi = (struct ospf6_interface *)THREAD_ARG(thread);
    2400             : 
    2401          60 :         if (oi->state <= OSPF6_INTERFACE_DOWN) {
    2402           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO, SEND_HDR))
    2403           0 :                         zlog_debug("Unable to send Hello on down interface %pOI",
    2404             :                                    oi);
    2405           0 :                 return;
    2406             :         }
    2407             : 
    2408          60 :         thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
    2409             :                          &oi->thread_send_hello);
    2410             : 
    2411          60 :         ospf6_hello_send_addr(oi, NULL, NULL);
    2412             : }
    2413             : 
    2414             : /* used to send polls for PtP/PtMP too */
    2415          60 : void ospf6_hello_send_addr(struct ospf6_interface *oi,
    2416             :                            struct ospf6_virtual_link *vlink,
    2417             :                            const struct in6_addr *addr)
    2418             : {
    2419          60 :         struct ospf6_packet *op;
    2420          60 :         uint16_t length = OSPF6_HEADER_SIZE;
    2421          60 :         bool anything = false;
    2422             : 
    2423          60 :         op = ospf6_packet_new(oi->ifmtu);
    2424             : 
    2425          60 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
    2426             : 
    2427             :         /* Prepare OSPF Hello body */
    2428          60 :         length += ospf6_make_hello(oi, vlink, op->s);
    2429          60 :         if (length == OSPF6_HEADER_SIZE) {
    2430             :                 /* Hello overshooting MTU */
    2431           0 :                 ospf6_packet_free(op);
    2432           0 :                 return;
    2433             :         }
    2434             : 
    2435             :         /* Fill OSPF header. */
    2436          60 :         ospf6_fill_header(oi, op->s, length);
    2437             : 
    2438             :         /* Set packet length. */
    2439          60 :         op->length = length;
    2440             : 
    2441          60 :         if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT
    2442          60 :              || oi->state == OSPF6_INTERFACE_POINTTOMULTIPOINT)
    2443          36 :             && !addr && oi->p2xp_no_multicast_hello) {
    2444           0 :                 struct listnode *node;
    2445           0 :                 struct ospf6_neighbor *on;
    2446           0 :                 struct ospf6_packet *opdup;
    2447             : 
    2448           0 :                 for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, node, on)) {
    2449           0 :                         if (on->state < OSPF6_NEIGHBOR_INIT)
    2450             :                                 /* poll-interval for these */
    2451           0 :                                 continue;
    2452             : 
    2453           0 :                         opdup = ospf6_packet_dup(op);
    2454           0 :                         opdup->dst = on->linklocal_addr;
    2455           0 :                         ospf6_packet_add_top(oi, opdup);
    2456           0 :                         anything = true;
    2457             :                 }
    2458             : 
    2459           0 :                 ospf6_packet_free(op);
    2460             :         } else {
    2461          60 :                 op->dst = addr ? *addr : allspfrouters6;
    2462             : 
    2463             :                 /* Add packet to the top of the interface output queue, so that
    2464             :                  * they can't get delayed by things like long queues of LS
    2465             :                  * Update packets
    2466             :                  */
    2467          60 :                 ospf6_packet_add_top(oi, op);
    2468          60 :                 anything = true;
    2469             :         }
    2470             : 
    2471          60 :         if (anything)
    2472          61 :                 OSPF6_MESSAGE_WRITE_ON(oi);
    2473             : }
    2474             : 
    2475          20 : static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
    2476             : {
    2477          20 :         uint16_t length = OSPF6_DB_DESC_MIN_SIZE;
    2478          20 :         struct ospf6_lsa *lsa, *lsanext;
    2479          20 :         uint8_t options1 = on->ospf6_if->area->options[1];
    2480             : 
    2481          20 :         if (on->ospf6_if->at_data.flags != 0)
    2482           0 :                 options1 |= OSPF6_OPT_AT;
    2483             : 
    2484             :         /* if this is initial one, initialize sequence number for DbDesc */
    2485          20 :         if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
    2486           8 :             && (on->dbdesc_seqnum == 0)) {
    2487           7 :                 on->dbdesc_seqnum = frr_sequence32_next();
    2488             :         }
    2489             : 
    2490             :         /* reserved */
    2491          20 :         stream_putc(s, 0); /* reserved 1 */
    2492          20 :         stream_putc(s, on->ospf6_if->area->options[0]);
    2493          20 :         stream_putc(s, options1);
    2494          20 :         stream_putc(s, on->ospf6_if->area->options[2]);
    2495          20 :         stream_putw(s, on->vlink ? 0 : on->ospf6_if->ifmtu);
    2496          20 :         stream_putc(s, 0); /* reserved 2 */
    2497          20 :         stream_putc(s, on->dbdesc_bits);
    2498          20 :         stream_putl(s, on->dbdesc_seqnum);
    2499             : 
    2500             :         /* if this is not initial one, set LSA headers in dbdesc */
    2501          20 :         if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)) {
    2502          51 :                 for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) {
    2503          78 :                         ospf6_lsa_age_update_to_send(lsa, on_transdelay(on));
    2504             : 
    2505             :                         /* MTU check */
    2506          78 :                         if ((length + sizeof(struct ospf6_lsa_header)
    2507          39 :                              + OSPF6_HEADER_SIZE)
    2508          39 :                             > ospf6_packet_max(on->ospf6_if)) {
    2509           0 :                                 ospf6_lsa_unlock(lsa);
    2510           0 :                                 if (lsanext)
    2511           0 :                                         ospf6_lsa_unlock(lsanext);
    2512             :                                 break;
    2513             :                         }
    2514          39 :                         stream_put(s, lsa->header,
    2515             :                                    sizeof(struct ospf6_lsa_header));
    2516          39 :                         length += sizeof(struct ospf6_lsa_header);
    2517             :                 }
    2518             :         }
    2519          20 :         return length;
    2520             : }
    2521             : 
    2522          20 : void ospf6_dbdesc_send(struct thread *thread)
    2523             : {
    2524          20 :         struct ospf6_neighbor *on;
    2525          20 :         uint16_t length = OSPF6_HEADER_SIZE;
    2526          20 :         struct ospf6_packet *op;
    2527             : 
    2528          20 :         on = (struct ospf6_neighbor *)THREAD_ARG(thread);
    2529             : 
    2530          20 :         if (on->state < OSPF6_NEIGHBOR_EXSTART) {
    2531           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND))
    2532           0 :                         zlog_debug(
    2533             :                                 "Quit to send DbDesc to neighbor %s state %s",
    2534             :                                 on->name, ospf6_neighbor_state_str[on->state]);
    2535           0 :                 return;
    2536             :         }
    2537             : 
    2538             :         /* set next thread if master */
    2539          20 :         if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
    2540          12 :                 thread_add_timer(master, ospf6_dbdesc_send, on,
    2541             :                                  on->vlink ? on->vlink->retransmit_interval
    2542             :                                            : on->ospf6_if->rxmt_interval,
    2543             :                                  &on->thread_send_dbdesc);
    2544             : 
    2545          20 :         op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2546          20 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_DBDESC, on->ospf6_if, op->s);
    2547             : 
    2548          20 :         length += ospf6_make_dbdesc(on, op->s);
    2549          20 :         ospf6_fill_header(on->ospf6_if, op->s, length);
    2550             : 
    2551             :         /* Set packet length. */
    2552          20 :         op->length = length;
    2553             : 
    2554          20 :         if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
    2555           0 :                 op->dst = allspfrouters6;
    2556             :         else
    2557          20 :                 op->dst = on->linklocal_addr;
    2558             : 
    2559          20 :         ospf6_fill_hdr_checksum(on->ospf6_if, op);
    2560             : 
    2561          20 :         ospf6_packet_add(on->ospf6_if, op);
    2562             : 
    2563          29 :         OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
    2564             : }
    2565             : 
    2566          12 : void ospf6_dbdesc_send_newone(struct thread *thread)
    2567             : {
    2568          12 :         struct ospf6_neighbor *on;
    2569          12 :         struct ospf6_lsa *lsa, *lsanext;
    2570          12 :         unsigned int size = 0;
    2571             : 
    2572          12 :         on = (struct ospf6_neighbor *)THREAD_ARG(thread);
    2573          12 :         ospf6_lsdb_remove_all(on->dbdesc_list);
    2574             : 
    2575             :         /* move LSAs from summary_list to dbdesc_list (within neighbor
    2576             :            structure)
    2577             :            so that ospf6_send_dbdesc () can send those LSAs */
    2578          12 :         size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc);
    2579          51 :         for (ALL_LSDB(on->summary_list, lsa, lsanext)) {
    2580             :                 /* if stub area then don't advertise AS-External LSAs */
    2581          39 :                 if ((IS_AREA_STUB(on->ospf6_if->area)
    2582             :                      || IS_AREA_NSSA(on->ospf6_if->area))
    2583           0 :                     && ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
    2584           0 :                         ospf6_lsdb_remove(lsa, on->summary_list);
    2585           0 :                         continue;
    2586             :                 }
    2587             :                 /* no as-scope entirely for virtual links */
    2588          39 :                 if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AS
    2589           0 :                     && on->vlink) {
    2590           0 :                         ospf6_lsdb_remove(lsa, on->summary_list);
    2591           0 :                         continue;
    2592             :                 }
    2593             : 
    2594          78 :                 if (size + sizeof(struct ospf6_lsa_header)
    2595          39 :                     > ospf6_packet_max(on->ospf6_if)) {
    2596           0 :                         ospf6_lsa_unlock(lsa);
    2597           0 :                         if (lsanext)
    2598           0 :                                 ospf6_lsa_unlock(lsanext);
    2599             :                         break;
    2600             :                 }
    2601             : 
    2602          39 :                 ospf6_lsdb_add(ospf6_lsa_copy(lsa), on->dbdesc_list);
    2603          39 :                 ospf6_lsdb_remove(lsa, on->summary_list);
    2604          39 :                 size += sizeof(struct ospf6_lsa_header);
    2605             :         }
    2606             : 
    2607          12 :         if (on->summary_list->count == 0)
    2608          12 :                 UNSET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
    2609             : 
    2610             :         /* If slave, More bit check must be done here */
    2611          12 :         if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */
    2612           8 :             !CHECK_FLAG(on->dbdesc_last.bits, OSPF6_DBDESC_MBIT)
    2613           4 :             && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
    2614           4 :                 thread_add_event(master, exchange_done, on, 0,
    2615             :                                  &on->thread_exchange_done);
    2616             : 
    2617          12 :         thread_execute(master, ospf6_dbdesc_send, on, 0);
    2618          12 : }
    2619             : 
    2620           8 : static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
    2621             : {
    2622           8 :         uint16_t length = 0;
    2623           8 :         struct ospf6_lsa *lsa, *lsanext, *last_req = NULL;
    2624             : 
    2625          33 :         for (ALL_LSDB(on->request_list, lsa, lsanext)) {
    2626          50 :                 if ((length + OSPF6_HEADER_SIZE)
    2627          25 :                     > ospf6_packet_max(on->ospf6_if)) {
    2628           0 :                         ospf6_lsa_unlock(lsa);
    2629           0 :                         if (lsanext)
    2630           0 :                                 ospf6_lsa_unlock(lsanext);
    2631             :                         break;
    2632             :                 }
    2633          25 :                 stream_putw(s, 0); /* reserved */
    2634          25 :                 stream_putw(s, ntohs(lsa->header->type));
    2635          25 :                 stream_putl(s, ntohl(lsa->header->id));
    2636          25 :                 stream_putl(s, ntohl(lsa->header->adv_router));
    2637          25 :                 length += sizeof(struct ospf6_lsreq_entry);
    2638          25 :                 last_req = lsa;
    2639             :         }
    2640             : 
    2641           8 :         if (last_req != NULL) {
    2642           8 :                 if (on->last_ls_req != NULL)
    2643           0 :                         on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
    2644             : 
    2645           8 :                 ospf6_lsa_lock(last_req);
    2646           8 :                 on->last_ls_req = last_req;
    2647             :         }
    2648             : 
    2649           8 :         return length;
    2650             : }
    2651             : 
    2652          22 : static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on,
    2653             :                                           struct ospf6_packet **op)
    2654             : {
    2655          22 :         uint16_t length = 0;
    2656          22 :         struct ospf6_lsa *lsa, *lsanext;
    2657          22 :         int lsa_cnt = 0;
    2658             : 
    2659          67 :         for (ALL_LSDB(on->lsack_list, lsa, lsanext)) {
    2660          90 :                 if ((length + sizeof(struct ospf6_lsa_header)
    2661          45 :                      + OSPF6_HEADER_SIZE)
    2662          45 :                     > ospf6_packet_max(on->ospf6_if)) {
    2663             :                         /* if we run out of packet size/space here,
    2664             :                            better to try again soon. */
    2665           0 :                         if (lsa_cnt) {
    2666           0 :                                 ospf6_fill_header(on->ospf6_if, (*op)->s,
    2667           0 :                                                   length + OSPF6_HEADER_SIZE);
    2668             : 
    2669           0 :                                 (*op)->length = length + OSPF6_HEADER_SIZE;
    2670           0 :                                 (*op)->dst = on->linklocal_addr;
    2671           0 :                                 ospf6_fill_hdr_checksum(on->ospf6_if, *op);
    2672           0 :                                 ospf6_packet_add(on->ospf6_if, *op);
    2673           0 :                                 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
    2674             :                                 /* new packet */
    2675           0 :                                 *op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2676           0 :                                 ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK,
    2677             :                                                   on->ospf6_if, (*op)->s);
    2678           0 :                                 length = 0;
    2679           0 :                                 lsa_cnt = 0;
    2680             :                         }
    2681             :                 }
    2682          90 :                 ospf6_lsa_age_update_to_send(lsa, on_transdelay(on));
    2683          45 :                 stream_put((*op)->s, lsa->header,
    2684             :                            sizeof(struct ospf6_lsa_header));
    2685          45 :                 length += sizeof(struct ospf6_lsa_header);
    2686             : 
    2687          45 :                 assert(lsa->lock == 2);
    2688          45 :                 ospf6_lsdb_remove(lsa, on->lsack_list);
    2689          45 :                 lsa_cnt++;
    2690             :         }
    2691          22 :         return length;
    2692             : }
    2693             : 
    2694          16 : void ospf6_lsreq_send(struct thread *thread)
    2695             : {
    2696          16 :         struct ospf6_neighbor *on;
    2697          16 :         struct ospf6_packet *op;
    2698          16 :         uint16_t length = OSPF6_HEADER_SIZE;
    2699             : 
    2700          16 :         on = (struct ospf6_neighbor *)THREAD_ARG(thread);
    2701             : 
    2702             :         /* LSReq will be sent only in ExStart or Loading */
    2703          16 :         if (on->state != OSPF6_NEIGHBOR_EXCHANGE
    2704          16 :             && on->state != OSPF6_NEIGHBOR_LOADING) {
    2705           8 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSREQ, SEND_HDR))
    2706           0 :                         zlog_debug("Quit to send LSReq to neighbor %s state %s",
    2707             :                                    on->name,
    2708             :                                    ospf6_neighbor_state_str[on->state]);
    2709           8 :                 return;
    2710             :         }
    2711             : 
    2712             :         /* schedule loading_done if request list is empty */
    2713           8 :         if (on->request_list->count == 0) {
    2714           0 :                 thread_add_event(master, loading_done, on, 0, NULL);
    2715           0 :                 return;
    2716             :         }
    2717             : 
    2718           8 :         op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2719           8 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSREQ, on->ospf6_if, op->s);
    2720             : 
    2721           8 :         length += ospf6_make_lsreq(on, op->s);
    2722             : 
    2723           8 :         if (length == OSPF6_HEADER_SIZE) {
    2724             :                 /* Hello overshooting MTU */
    2725           0 :                 ospf6_packet_free(op);
    2726           0 :                 return;
    2727             :         }
    2728             : 
    2729             :         /* Fill OSPF header. */
    2730           8 :         ospf6_fill_header(on->ospf6_if, op->s, length);
    2731             : 
    2732             :         /* Set packet length */
    2733           8 :         op->length = length;
    2734             : 
    2735           8 :         if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
    2736           0 :                 op->dst = allspfrouters6;
    2737             :         else
    2738           8 :                 op->dst = on->linklocal_addr;
    2739             : 
    2740           8 :         ospf6_fill_hdr_checksum(on->ospf6_if, op);
    2741           8 :         ospf6_packet_add(on->ospf6_if, op);
    2742             : 
    2743          12 :         OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
    2744             : 
    2745             :         /* set next thread */
    2746           8 :         if (on->request_list->count != 0) {
    2747           8 :                 thread_add_timer(master, ospf6_lsreq_send, on,
    2748             :                                  on->vlink ? on->vlink->retransmit_interval
    2749             :                                            : on->ospf6_if->rxmt_interval,
    2750             :                                  &on->thread_send_lsreq);
    2751             :         }
    2752             : }
    2753             : 
    2754          41 : static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
    2755             :                                 struct ospf6_interface *oi,
    2756             :                                 struct ospf6_packet *op)
    2757             : {
    2758             : 
    2759          41 :         if (on) {
    2760             : 
    2761          35 :                 if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
    2762          35 :                     || (on->ospf6_if->state == OSPF6_INTERFACE_DR)
    2763          30 :                     || (on->ospf6_if->state == OSPF6_INTERFACE_BDR))
    2764           8 :                         op->dst = allspfrouters6;
    2765             :                 else
    2766          27 :                         op->dst = on->linklocal_addr;
    2767             :                 oi = on->ospf6_if;
    2768           6 :         } else if (oi) {
    2769           6 :                 if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
    2770           6 :                     || (oi->state == OSPF6_INTERFACE_DR)
    2771           1 :                     || (oi->state == OSPF6_INTERFACE_BDR))
    2772           6 :                         op->dst = allspfrouters6;
    2773             :                 else
    2774           0 :                         op->dst = alldrouters6;
    2775             :         }
    2776          41 :         if (oi) {
    2777          41 :                 ospf6_fill_hdr_checksum(oi, op);
    2778          41 :                 ospf6_packet_add(oi, op);
    2779             :                 /* If ospf instance is being deleted, send the packet
    2780             :                  * immediately
    2781             :                  */
    2782          41 :                 if ((oi->area == NULL) || (oi->area->ospf6 == NULL))
    2783             :                         return;
    2784          41 :                 if (oi->area->ospf6->inst_shutdown) {
    2785          26 :                         if (oi->on_write_q == 0) {
    2786          26 :                                 listnode_add(oi->area->ospf6->oi_write_q, oi);
    2787          26 :                                 oi->on_write_q = 1;
    2788             :                         }
    2789          26 :                         thread_execute(master, ospf6_write, oi->area->ospf6, 0);
    2790             :                 } else
    2791          22 :                         OSPF6_MESSAGE_WRITE_ON(oi);
    2792             :         }
    2793             : }
    2794             : 
    2795          81 : static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on,
    2796             :                                          struct ospf6_packet **op, int *lsa_cnt)
    2797             : {
    2798          81 :         uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
    2799          81 :         struct ospf6_lsa *lsa, *lsanext;
    2800             : 
    2801             :         /* skip over fixed header */
    2802          81 :         stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
    2803             : 
    2804         108 :         for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) {
    2805          27 :                 if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) >
    2806          27 :                     ospf6_packet_max(on->ospf6_if)) {
    2807           0 :                         ospf6_fill_header(on->ospf6_if, (*op)->s,
    2808           0 :                                           length + OSPF6_HEADER_SIZE);
    2809           0 :                         (*op)->length = length + OSPF6_HEADER_SIZE;
    2810           0 :                         ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
    2811           0 :                         ospf6_send_lsupdate(on, NULL, *op);
    2812             : 
    2813             :                         /* refresh packet */
    2814           0 :                         *op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2815           0 :                         length = OSPF6_LS_UPD_MIN_SIZE;
    2816           0 :                         *lsa_cnt = 0;
    2817           0 :                         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
    2818             :                                           on->ospf6_if, (*op)->s);
    2819           0 :                         stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
    2820             :                 }
    2821          54 :                 ospf6_lsa_age_update_to_send(lsa, on_transdelay(on));
    2822          27 :                 stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
    2823          27 :                 (*lsa_cnt)++;
    2824          27 :                 length += OSPF6_LSA_SIZE(lsa->header);
    2825          27 :                 assert(lsa->lock == 2);
    2826          27 :                 ospf6_lsdb_remove(lsa, on->lsupdate_list);
    2827             :         }
    2828          81 :         return length;
    2829             : }
    2830             : 
    2831          81 : static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on,
    2832             :                                            struct ospf6_packet **op,
    2833             :                                            int *lsa_cnt)
    2834             : {
    2835          81 :         uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
    2836          81 :         struct ospf6_lsa *lsa, *lsanext;
    2837             : 
    2838             :         /* skip over fixed header */
    2839          81 :         stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
    2840             : 
    2841         250 :         for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
    2842         169 :                 if ((length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE) >
    2843         169 :                     ospf6_packet_max(on->ospf6_if)) {
    2844           0 :                         ospf6_fill_header(on->ospf6_if, (*op)->s,
    2845           0 :                                           length + OSPF6_HEADER_SIZE);
    2846           0 :                         (*op)->length = length + OSPF6_HEADER_SIZE;
    2847           0 :                         ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
    2848           0 :                         if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
    2849           0 :                                 (*op)->dst = allspfrouters6;
    2850             :                         else
    2851           0 :                                 (*op)->dst = on->linklocal_addr;
    2852             : 
    2853           0 :                         ospf6_fill_hdr_checksum(on->ospf6_if, *op);
    2854           0 :                         ospf6_packet_add(on->ospf6_if, *op);
    2855           0 :                         OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
    2856             : 
    2857             :                         /* refresh packet */
    2858           0 :                         *op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2859           0 :                         length = OSPF6_LS_UPD_MIN_SIZE;
    2860           0 :                         *lsa_cnt = 0;
    2861           0 :                         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
    2862             :                                           on->ospf6_if, (*op)->s);
    2863           0 :                         stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
    2864             :                 }
    2865         338 :                 ospf6_lsa_age_update_to_send(lsa, on_transdelay(on));
    2866         169 :                 stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
    2867         169 :                 (*lsa_cnt)++;
    2868         169 :                 length += OSPF6_LSA_SIZE(lsa->header);
    2869             :         }
    2870          81 :         return length;
    2871             : }
    2872             : 
    2873          82 : void ospf6_lsupdate_send_neighbor(struct thread *thread)
    2874             : {
    2875          82 :         struct ospf6_neighbor *on;
    2876          82 :         struct ospf6_packet *op;
    2877          82 :         uint16_t length = OSPF6_HEADER_SIZE;
    2878          82 :         int lsa_cnt = 0;
    2879             : 
    2880          82 :         on = (struct ospf6_neighbor *)THREAD_ARG(thread);
    2881             : 
    2882          82 :         if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
    2883           0 :                 zlog_debug("LSUpdate to neighbor %s", on->name);
    2884             : 
    2885          82 :         if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
    2886           1 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE,
    2887             :                                            SEND_HDR))
    2888           0 :                         zlog_debug("Quit to send (neighbor state %s)",
    2889             :                                    ospf6_neighbor_state_str[on->state]);
    2890           1 :                 return;
    2891             :         }
    2892             : 
    2893             :         /* first do lsupdate_list */
    2894          81 :         op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2895          81 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
    2896          81 :         length += ospf6_make_lsupdate_list(on, &op, &lsa_cnt);
    2897          81 :         if (lsa_cnt) {
    2898             :                 /* Fill OSPF header. */
    2899           9 :                 ospf6_fill_header(on->ospf6_if, op->s, length);
    2900           9 :                 ospf6_fill_lsupdate_header(op->s, lsa_cnt);
    2901           9 :                 op->length = length;
    2902           9 :                 ospf6_send_lsupdate(on, NULL, op);
    2903             : 
    2904             :                 /* prepare new packet */
    2905           9 :                 op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2906           9 :                 length = OSPF6_HEADER_SIZE;
    2907           9 :                 lsa_cnt = 0;
    2908             :         } else {
    2909          72 :                 stream_reset(op->s);
    2910          72 :                 length = OSPF6_HEADER_SIZE;
    2911             :         }
    2912             : 
    2913          81 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
    2914             :         /* now do retransmit list */
    2915          81 :         length += ospf6_make_ls_retrans_list(on, &op, &lsa_cnt);
    2916          81 :         if (lsa_cnt) {
    2917          61 :                 ospf6_fill_header(on->ospf6_if, op->s, length);
    2918          61 :                 ospf6_fill_lsupdate_header(op->s, lsa_cnt);
    2919          61 :                 op->length = length;
    2920          61 :                 if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
    2921           0 :                         op->dst = allspfrouters6;
    2922             :                 else
    2923          61 :                         op->dst = on->linklocal_addr;
    2924          61 :                 ospf6_fill_hdr_checksum(on->ospf6_if, op);
    2925          61 :                 ospf6_packet_add(on->ospf6_if, op);
    2926          94 :                 OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
    2927             :         } else
    2928          20 :                 ospf6_packet_free(op);
    2929             : 
    2930          81 :         if (on->lsupdate_list->count != 0) {
    2931           0 :                 thread_add_event(master, ospf6_lsupdate_send_neighbor, on, 0,
    2932             :                                  &on->thread_send_lsupdate);
    2933          81 :         } else if (on->retrans_list->count != 0) {
    2934          61 :                 thread_add_timer(master, ospf6_lsupdate_send_neighbor, on,
    2935             :                                  on->vlink ? on->vlink->retransmit_interval
    2936             :                                            : on->ospf6_if->rxmt_interval,
    2937             :                                  &on->thread_send_lsupdate);
    2938             :         }
    2939             : }
    2940             : 
    2941          26 : int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
    2942             :                                      struct ospf6_lsa *lsa)
    2943             : {
    2944          26 :         struct ospf6_packet *op;
    2945          26 :         uint16_t length = OSPF6_HEADER_SIZE;
    2946             : 
    2947          26 :         op = ospf6_packet_new(on->ospf6_if->ifmtu);
    2948          26 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
    2949             : 
    2950             :         /* skip over fixed header */
    2951          26 :         stream_forward_endp(op->s, OSPF6_LS_UPD_MIN_SIZE);
    2952          52 :         ospf6_lsa_age_update_to_send(lsa, on_transdelay(on));
    2953          26 :         stream_put(op->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
    2954          26 :         length = OSPF6_HEADER_SIZE + OSPF6_LS_UPD_MIN_SIZE
    2955          26 :                  + OSPF6_LSA_SIZE(lsa->header);
    2956          26 :         ospf6_fill_header(on->ospf6_if, op->s, length);
    2957          26 :         ospf6_fill_lsupdate_header(op->s, 1);
    2958          26 :         op->length = length;
    2959             : 
    2960          26 :         if (IS_OSPF6_DEBUG_FLOODING
    2961          26 :             || IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
    2962           0 :                 zlog_debug("%s: Send lsupdate with lsa %s (age %u)", __func__,
    2963             :                            lsa->name, ntohs(lsa->header->age));
    2964             : 
    2965          26 :         ospf6_send_lsupdate(on, NULL, op);
    2966             : 
    2967          26 :         return 0;
    2968             : }
    2969             : 
    2970           6 : static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi,
    2971             :                                               struct ospf6_packet **op,
    2972             :                                               int *lsa_cnt)
    2973             : {
    2974           6 :         uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
    2975           6 :         struct ospf6_lsa *lsa, *lsanext;
    2976             : 
    2977             :         /* skip over fixed header */
    2978           6 :         stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
    2979             : 
    2980          16 :         for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) {
    2981          10 :                 if (length + OSPF6_LSA_SIZE(lsa->header) + OSPF6_HEADER_SIZE >
    2982          10 :                     ospf6_packet_max(oi)) {
    2983           0 :                         ospf6_fill_header(oi, (*op)->s,
    2984           0 :                                           length + OSPF6_HEADER_SIZE);
    2985           0 :                         (*op)->length = length + OSPF6_HEADER_SIZE;
    2986           0 :                         ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
    2987           0 :                         ospf6_send_lsupdate(NULL, oi, *op);
    2988             : 
    2989             :                         /* refresh packet */
    2990           0 :                         *op = ospf6_packet_new(oi->ifmtu);
    2991           0 :                         length = OSPF6_LS_UPD_MIN_SIZE;
    2992           0 :                         *lsa_cnt = 0;
    2993           0 :                         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi,
    2994             :                                           (*op)->s);
    2995           0 :                         stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
    2996             :                 }
    2997             : 
    2998          10 :                 ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
    2999          10 :                 stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
    3000          10 :                 (*lsa_cnt)++;
    3001          10 :                 length += OSPF6_LSA_SIZE(lsa->header);
    3002             : 
    3003          10 :                 assert(lsa->lock == 2);
    3004          10 :                 ospf6_lsdb_remove(lsa, oi->lsupdate_list);
    3005             :         }
    3006           6 :         return length;
    3007             : }
    3008             : 
    3009           6 : void ospf6_lsupdate_send_interface(struct thread *thread)
    3010             : {
    3011           6 :         struct ospf6_interface *oi;
    3012           6 :         struct ospf6_packet *op;
    3013           6 :         uint16_t length = OSPF6_HEADER_SIZE;
    3014           6 :         int lsa_cnt = 0;
    3015             : 
    3016           6 :         oi = (struct ospf6_interface *)THREAD_ARG(thread);
    3017             : 
    3018           6 :         if (oi->state <= OSPF6_INTERFACE_WAITING) {
    3019           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE,
    3020             :                                            SEND_HDR))
    3021           0 :                         zlog_debug(
    3022             :                                 "Quit to send LSUpdate to interface %pOI state %s",
    3023             :                                 oi, ospf6_interface_state_str[oi->state]);
    3024           0 :                 return;
    3025             :         }
    3026             : 
    3027             :         /* if we have nothing to send, return */
    3028           6 :         if (oi->lsupdate_list->count == 0)
    3029             :                 return;
    3030             : 
    3031           6 :         op = ospf6_packet_new(oi->ifmtu);
    3032           6 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi, op->s);
    3033           6 :         length += ospf6_make_lsupdate_interface(oi, &op, &lsa_cnt);
    3034           6 :         if (lsa_cnt) {
    3035             :                 /* Fill OSPF header. */
    3036           6 :                 ospf6_fill_header(oi, op->s, length);
    3037           6 :                 ospf6_fill_lsupdate_header(op->s, lsa_cnt);
    3038           6 :                 op->length = length;
    3039           6 :                 ospf6_send_lsupdate(NULL, oi, op);
    3040             :         } else
    3041           0 :                 ospf6_packet_free(op);
    3042             : 
    3043           6 :         if (oi->lsupdate_list->count > 0) {
    3044           0 :                 thread_add_event(master, ospf6_lsupdate_send_interface, oi, 0,
    3045             :                                  &oi->thread_send_lsupdate);
    3046             :         }
    3047             : }
    3048             : 
    3049          22 : void ospf6_lsack_send_neighbor(struct thread *thread)
    3050             : {
    3051          22 :         struct ospf6_neighbor *on;
    3052          22 :         struct ospf6_packet *op;
    3053          22 :         uint16_t length = OSPF6_HEADER_SIZE;
    3054             : 
    3055          22 :         on = (struct ospf6_neighbor *)THREAD_ARG(thread);
    3056             : 
    3057          22 :         if (on->state < OSPF6_NEIGHBOR_EXCHANGE) {
    3058           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND_HDR))
    3059           0 :                         zlog_debug("Quit to send LSAck to neighbor %s state %s",
    3060             :                                    on->name,
    3061             :                                    ospf6_neighbor_state_str[on->state]);
    3062           0 :                 return;
    3063             :         }
    3064             : 
    3065             :         /* if we have nothing to send, return */
    3066          22 :         if (on->lsack_list->count == 0)
    3067             :                 return;
    3068             : 
    3069          22 :         op = ospf6_packet_new(on->ospf6_if->ifmtu);
    3070          22 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, on->ospf6_if, op->s);
    3071             : 
    3072          22 :         length += ospf6_make_lsack_neighbor(on, &op);
    3073             : 
    3074          22 :         if (length == OSPF6_HEADER_SIZE) {
    3075           0 :                 ospf6_packet_free(op);
    3076           0 :                 return;
    3077             :         }
    3078             : 
    3079             :         /* Fill OSPF header. */
    3080          22 :         ospf6_fill_header(on->ospf6_if, op->s, length);
    3081             : 
    3082             :         /* Set packet length, dst and queue to FIFO. */
    3083          22 :         op->length = length;
    3084          22 :         op->dst = on->linklocal_addr;
    3085          22 :         ospf6_fill_hdr_checksum(on->ospf6_if, op);
    3086          22 :         ospf6_packet_add(on->ospf6_if, op);
    3087          26 :         OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
    3088             : 
    3089          22 :         if (on->lsack_list->count > 0)
    3090           0 :                 thread_add_event(master, ospf6_lsack_send_neighbor, on, 0,
    3091             :                                  &on->thread_send_lsack);
    3092             : }
    3093             : 
    3094           7 : static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi,
    3095             :                                            struct ospf6_packet *op)
    3096             : {
    3097           7 :         uint16_t length = 0;
    3098           7 :         struct ospf6_lsa *lsa, *lsanext;
    3099             : 
    3100          35 :         for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) {
    3101          56 :                 if ((length + sizeof(struct ospf6_lsa_header)
    3102          28 :                      + OSPF6_HEADER_SIZE)
    3103          28 :                     > ospf6_packet_max(oi)) {
    3104             :                         /* if we run out of packet size/space here,
    3105             :                            better to try again soon. */
    3106           0 :                         THREAD_OFF(oi->thread_send_lsack);
    3107           0 :                         thread_add_event(master, ospf6_lsack_send_interface, oi,
    3108             :                                          0, &oi->thread_send_lsack);
    3109             : 
    3110           0 :                         ospf6_lsa_unlock(lsa);
    3111           0 :                         if (lsanext)
    3112           0 :                                 ospf6_lsa_unlock(lsanext);
    3113             :                         break;
    3114             :                 }
    3115          28 :                 ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
    3116          28 :                 stream_put(op->s, lsa->header, sizeof(struct ospf6_lsa_header));
    3117          28 :                 length += sizeof(struct ospf6_lsa_header);
    3118             : 
    3119          28 :                 assert(lsa->lock == 2);
    3120          28 :                 ospf6_lsdb_remove(lsa, oi->lsack_list);
    3121             :         }
    3122           7 :         return length;
    3123             : }
    3124             : 
    3125           7 : void ospf6_lsack_send_interface(struct thread *thread)
    3126             : {
    3127           7 :         struct ospf6_interface *oi;
    3128           7 :         struct ospf6_packet *op;
    3129           7 :         uint16_t length = OSPF6_HEADER_SIZE;
    3130             : 
    3131           7 :         oi = (struct ospf6_interface *)THREAD_ARG(thread);
    3132             : 
    3133           7 :         if (oi->state <= OSPF6_INTERFACE_WAITING) {
    3134           0 :                 if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSACK, SEND_HDR))
    3135           0 :                         zlog_debug(
    3136             :                                 "Quit to send LSAck to interface %pOI state %s",
    3137             :                                 oi, ospf6_interface_state_str[oi->state]);
    3138           0 :                 return;
    3139             :         }
    3140             : 
    3141             :         /* if we have nothing to send, return */
    3142           7 :         if (oi->lsack_list->count == 0)
    3143             :                 return;
    3144             : 
    3145           7 :         op = ospf6_packet_new(oi->ifmtu);
    3146           7 :         ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, oi, op->s);
    3147             : 
    3148           7 :         length += ospf6_make_lsack_interface(oi, op);
    3149             : 
    3150           7 :         if (length == OSPF6_HEADER_SIZE) {
    3151           0 :                 ospf6_packet_free(op);
    3152           0 :                 return;
    3153             :         }
    3154             :         /* Fill OSPF header. */
    3155           7 :         ospf6_fill_header(oi, op->s, length);
    3156             : 
    3157             :         /* Set packet length, dst and queue to FIFO. */
    3158           7 :         op->length = length;
    3159           7 :         if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
    3160           7 :             || (oi->state == OSPF6_INTERFACE_DR)
    3161           5 :             || (oi->state == OSPF6_INTERFACE_BDR))
    3162           4 :                 op->dst = allspfrouters6;
    3163             :         else
    3164           3 :                 op->dst = alldrouters6;
    3165             : 
    3166           7 :         ospf6_fill_hdr_checksum(oi, op);
    3167           7 :         ospf6_packet_add(oi, op);
    3168           9 :         OSPF6_MESSAGE_WRITE_ON(oi);
    3169             : 
    3170           7 :         if (oi->lsack_list->count > 0)
    3171           0 :                 thread_add_event(master, ospf6_lsack_send_interface, oi, 0,
    3172             :                                  &oi->thread_send_lsack);
    3173             : }
    3174             : 
    3175             : /* Commands */
    3176           0 : DEFUN(debug_ospf6_message, debug_ospf6_message_cmd,
    3177             :       "debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
    3178             :       DEBUG_STR OSPF6_STR
    3179             :       "Debug OSPFv3 message\n"
    3180             :       "Debug Unknown message\n"
    3181             :       "Debug Hello message\n"
    3182             :       "Debug Database Description message\n"
    3183             :       "Debug Link State Request message\n"
    3184             :       "Debug Link State Update message\n"
    3185             :       "Debug Link State Acknowledgement message\n"
    3186             :       "Debug All message\n"
    3187             :       "Debug only sending message, entire packet\n"
    3188             :       "Debug only receiving message, entire packet\n"
    3189             :       "Debug only sending message, header only\n"
    3190             :       "Debug only receiving message, header only\n")
    3191             : {
    3192           0 :         int idx_packet = 3;
    3193           0 :         int idx_send_recv = 4;
    3194           0 :         unsigned char level = 0;
    3195           0 :         int type = 0;
    3196           0 :         int i;
    3197             : 
    3198             :         /* check type */
    3199           0 :         if (!strncmp(argv[idx_packet]->arg, "u", 1))
    3200             :                 type = OSPF6_MESSAGE_TYPE_UNKNOWN;
    3201           0 :         else if (!strncmp(argv[idx_packet]->arg, "h", 1))
    3202             :                 type = OSPF6_MESSAGE_TYPE_HELLO;
    3203           0 :         else if (!strncmp(argv[idx_packet]->arg, "d", 1))
    3204             :                 type = OSPF6_MESSAGE_TYPE_DBDESC;
    3205           0 :         else if (!strncmp(argv[idx_packet]->arg, "lsr", 3))
    3206             :                 type = OSPF6_MESSAGE_TYPE_LSREQ;
    3207           0 :         else if (!strncmp(argv[idx_packet]->arg, "lsu", 3))
    3208             :                 type = OSPF6_MESSAGE_TYPE_LSUPDATE;
    3209           0 :         else if (!strncmp(argv[idx_packet]->arg, "lsa", 3))
    3210             :                 type = OSPF6_MESSAGE_TYPE_LSACK;
    3211           0 :         else if (!strncmp(argv[idx_packet]->arg, "a", 1))
    3212           0 :                 type = OSPF6_MESSAGE_TYPE_ALL;
    3213             : 
    3214           0 :         if (argc == 4)
    3215             :                 level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV;
    3216           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "send-h", 6))
    3217             :                 level = OSPF6_DEBUG_MESSAGE_SEND_HDR;
    3218           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "s", 1))
    3219             :                 level = OSPF6_DEBUG_MESSAGE_SEND;
    3220           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "recv-h", 6))
    3221             :                 level = OSPF6_DEBUG_MESSAGE_RECV_HDR;
    3222           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "r", 1))
    3223           0 :                 level = OSPF6_DEBUG_MESSAGE_RECV;
    3224             : 
    3225           0 :         if (type == OSPF6_MESSAGE_TYPE_ALL) {
    3226           0 :                 for (i = 0; i < 6; i++)
    3227           0 :                         OSPF6_DEBUG_MESSAGE_ON(i, level);
    3228             :         } else
    3229           0 :                 OSPF6_DEBUG_MESSAGE_ON(type, level);
    3230             : 
    3231           0 :         return CMD_SUCCESS;
    3232             : }
    3233             : 
    3234           0 : DEFUN(no_debug_ospf6_message, no_debug_ospf6_message_cmd,
    3235             :       "no debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
    3236             :       NO_STR DEBUG_STR OSPF6_STR
    3237             :       "Debug OSPFv3 message\n"
    3238             :       "Debug Unknown message\n"
    3239             :       "Debug Hello message\n"
    3240             :       "Debug Database Description message\n"
    3241             :       "Debug Link State Request message\n"
    3242             :       "Debug Link State Update message\n"
    3243             :       "Debug Link State Acknowledgement message\n"
    3244             :       "Debug All message\n"
    3245             :       "Debug only sending message, entire pkt\n"
    3246             :       "Debug only receiving message, entire pkt\n"
    3247             :       "Debug only sending message, header only\n"
    3248             :       "Debug only receiving message, header only\n")
    3249             : {
    3250           0 :         int idx_packet = 4;
    3251           0 :         int idx_send_recv = 5;
    3252           0 :         unsigned char level = 0;
    3253           0 :         int type = 0;
    3254           0 :         int i;
    3255             : 
    3256             :         /* check type */
    3257           0 :         if (!strncmp(argv[idx_packet]->arg, "u", 1))
    3258             :                 type = OSPF6_MESSAGE_TYPE_UNKNOWN;
    3259           0 :         else if (!strncmp(argv[idx_packet]->arg, "h", 1))
    3260             :                 type = OSPF6_MESSAGE_TYPE_HELLO;
    3261           0 :         else if (!strncmp(argv[idx_packet]->arg, "d", 1))
    3262             :                 type = OSPF6_MESSAGE_TYPE_DBDESC;
    3263           0 :         else if (!strncmp(argv[idx_packet]->arg, "lsr", 3))
    3264             :                 type = OSPF6_MESSAGE_TYPE_LSREQ;
    3265           0 :         else if (!strncmp(argv[idx_packet]->arg, "lsu", 3))
    3266             :                 type = OSPF6_MESSAGE_TYPE_LSUPDATE;
    3267           0 :         else if (!strncmp(argv[idx_packet]->arg, "lsa", 3))
    3268             :                 type = OSPF6_MESSAGE_TYPE_LSACK;
    3269           0 :         else if (!strncmp(argv[idx_packet]->arg, "a", 1))
    3270           0 :                 type = OSPF6_MESSAGE_TYPE_ALL;
    3271             : 
    3272           0 :         if (argc == 5)
    3273             :                 level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV
    3274             :                         | OSPF6_DEBUG_MESSAGE_SEND_HDR
    3275             :                         | OSPF6_DEBUG_MESSAGE_RECV_HDR;
    3276           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "send-h", 6))
    3277             :                 level = OSPF6_DEBUG_MESSAGE_SEND_HDR;
    3278           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "s", 1))
    3279             :                 level = OSPF6_DEBUG_MESSAGE_SEND;
    3280           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "recv-h", 6))
    3281             :                 level = OSPF6_DEBUG_MESSAGE_RECV_HDR;
    3282           0 :         else if (!strncmp(argv[idx_send_recv]->arg, "r", 1))
    3283           0 :                 level = OSPF6_DEBUG_MESSAGE_RECV;
    3284             : 
    3285           0 :         if (type == OSPF6_MESSAGE_TYPE_ALL) {
    3286           0 :                 for (i = 0; i < 6; i++)
    3287           0 :                         OSPF6_DEBUG_MESSAGE_OFF(i, level);
    3288             :         } else
    3289           0 :                 OSPF6_DEBUG_MESSAGE_OFF(type, level);
    3290             : 
    3291           0 :         return CMD_SUCCESS;
    3292             : }
    3293             : 
    3294             : 
    3295           0 : int config_write_ospf6_debug_message(struct vty *vty)
    3296             : {
    3297           0 :         const char *type_str[] = {"unknown", "hello",    "dbdesc",
    3298             :                                   "lsreq",   "lsupdate", "lsack"};
    3299           0 :         unsigned char s = 0, r = 0, sh = 0, rh = 0;
    3300           0 :         int i;
    3301             : 
    3302           0 :         for (i = 0; i < 6; i++) {
    3303           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND))
    3304           0 :                         s |= 1 << i;
    3305           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
    3306           0 :                         r |= 1 << i;
    3307             :         }
    3308             : 
    3309           0 :         for (i = 0; i < 6; i++) {
    3310           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR))
    3311           0 :                         sh |= 1 << i;
    3312           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
    3313           0 :                         rh |= 1 << i;
    3314             :         }
    3315             : 
    3316           0 :         if (s == 0x3f && r == 0x3f) {
    3317           0 :                 vty_out(vty, "debug ospf6 message all\n");
    3318           0 :                 return 0;
    3319             :         }
    3320             : 
    3321           0 :         if (s == 0x3f && r == 0) {
    3322           0 :                 vty_out(vty, "debug ospf6 message all send\n");
    3323           0 :                 return 0;
    3324           0 :         } else if (s == 0 && r == 0x3f) {
    3325           0 :                 vty_out(vty, "debug ospf6 message all recv\n");
    3326           0 :                 return 0;
    3327             :         }
    3328             : 
    3329           0 :         if (sh == 0x3f && rh == 0) {
    3330           0 :                 vty_out(vty, "debug ospf6 message all send-hdr\n");
    3331           0 :                 return 0;
    3332           0 :         } else if (sh == 0 && rh == 0x3f) {
    3333           0 :                 vty_out(vty, "debug ospf6 message all recv-hdr\n");
    3334           0 :                 return 0;
    3335             :         }
    3336             : 
    3337             :         /* Unknown message is logged by default */
    3338           0 :         if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, SEND)
    3339             :             && !IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
    3340           0 :                 vty_out(vty, "no debug ospf6 message unknown\n");
    3341           0 :         else if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, SEND))
    3342           0 :                 vty_out(vty, "no debug ospf6 message unknown send\n");
    3343           0 :         else if (!IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
    3344           0 :                 vty_out(vty, "no debug ospf6 message unknown recv\n");
    3345             : 
    3346           0 :         for (i = 1; i < 6; i++) {
    3347           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND)
    3348             :                     && IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV)) {
    3349           0 :                         vty_out(vty, "debug ospf6 message %s\n", type_str[i]);
    3350           0 :                         continue;
    3351             :                 }
    3352             : 
    3353           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND))
    3354           0 :                         vty_out(vty, "debug ospf6 message %s send\n",
    3355             :                                 type_str[i]);
    3356           0 :                 else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, SEND_HDR))
    3357           0 :                         vty_out(vty, "debug ospf6 message %s send-hdr\n",
    3358             :                                 type_str[i]);
    3359             : 
    3360           0 :                 if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV))
    3361           0 :                         vty_out(vty, "debug ospf6 message %s recv\n",
    3362             :                                 type_str[i]);
    3363           0 :                 else if (IS_OSPF6_DEBUG_MESSAGE_ENABLED(i, RECV_HDR))
    3364           0 :                         vty_out(vty, "debug ospf6 message %s recv-hdr\n",
    3365             :                                 type_str[i]);
    3366             :         }
    3367             : 
    3368             :         return 0;
    3369             : }
    3370             : 
    3371           4 : void install_element_ospf6_debug_message(void)
    3372             : {
    3373           4 :         install_element(ENABLE_NODE, &debug_ospf6_message_cmd);
    3374           4 :         install_element(ENABLE_NODE, &no_debug_ospf6_message_cmd);
    3375           4 :         install_element(CONFIG_NODE, &debug_ospf6_message_cmd);
    3376           4 :         install_element(CONFIG_NODE, &no_debug_ospf6_message_cmd);
    3377           4 : }

Generated by: LCOV version v1.16-topotato