From 508e53e2eef3eefba4c1aa771529027fd4486ea8 Mon Sep 17 00:00:00 2001 From: hasso Date: Tue, 18 May 2004 18:57:06 +0000 Subject: Ospf6d merge from Zebra repository with added privs stuff and merged zclient changes. --- ospf6d/ospf6_message.c | 3174 +++++++++++++++++++++++++----------------------- 1 file changed, 1638 insertions(+), 1536 deletions(-) (limited to 'ospf6d/ospf6_message.c') diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 0e74b651..21b799e0 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999 Yasuhiro Ohara + * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * @@ -19,1954 +19,2056 @@ * Boston, MA 02111-1307, USA. */ +#include + +#include "log.h" +#include "vty.h" +#include "command.h" +#include "thread.h" +#include "linklist.h" + #include "ospf6d.h" +#include "ospf6_proto.h" +#include "ospf6_lsa.h" +#include "ospf6_lsdb.h" +#include "ospf6_network.h" +#include "ospf6_message.h" -int -is_ospf6_message_dump (u_char type) -{ - if (type > OSPF6_MESSAGE_TYPE_LSACK) - type = OSPF6_MESSAGE_TYPE_UNKNOWN; +#include "ospf6_top.h" +#include "ospf6_area.h" +#include "ospf6_neighbor.h" +#include "ospf6_interface.h" - switch (type) - { - case OSPF6_MESSAGE_TYPE_UNKNOWN: - return 1; - break; - case OSPF6_MESSAGE_TYPE_HELLO: - if (IS_OSPF6_DUMP_HELLO) - return 1; - break; - case OSPF6_MESSAGE_TYPE_DBDESC: - if (IS_OSPF6_DUMP_DBDESC) - return 1; - break; - case OSPF6_MESSAGE_TYPE_LSREQ: - if (IS_OSPF6_DUMP_LSREQ) - return 1; - break; - case OSPF6_MESSAGE_TYPE_LSUPDATE: - if (IS_OSPF6_DUMP_LSUPDATE) - return 1; - break; - case OSPF6_MESSAGE_TYPE_LSACK: - if (IS_OSPF6_DUMP_LSACK) - return 1; - break; - default: - break; - } - return 0; -} -#define IS_OSPF6_DUMP_MESSAGE(x) (is_ospf6_message_dump(x)) +#include "ospf6_flood.h" -char *ospf6_message_type_string[] = -{ - "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck", NULL -}; +unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; +char *ospf6_message_type_str[] = + { "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck" }; -void -ospf6_message_log_lsa_header (struct ospf6_lsa_header *lsa_header) -{ - char buf_id[16], buf_router[16], typebuf[32]; - - inet_ntop (AF_INET, &lsa_header->advrtr, buf_router, sizeof (buf_router)); - inet_ntop (AF_INET, &lsa_header->ls_id, buf_id, sizeof (buf_id)); - zlog_info (" [%s ID=%s Adv=%s]", - ospf6_lsa_type_string (lsa_header->type, typebuf, - sizeof (typebuf)), - buf_id, buf_router); - zlog_info (" Age=%hu SeqNum=%#lx Cksum=%#hx Len=%hu", - ntohs (lsa_header->age), (u_long)ntohl (lsa_header->seqnum), - ntohs (lsa_header->checksum), ntohs (lsa_header->length)); -} +/* print functions */ static void -ospf6_message_log_unknown (struct iovec *message) +ospf6_header_print (struct ospf6_header *oh) { - zlog_info ("Message: Unknown"); + char router_id[16], area_id[16]; + inet_ntop (AF_INET, &oh->router_id, router_id, sizeof (router_id)); + inet_ntop (AF_INET, &oh->area_id, area_id, sizeof (area_id)); + + zlog_info (" OSPFv%d Type:%d Len:%hu Router-ID:%s", + oh->version, oh->type, ntohs (oh->length), router_id); + zlog_info (" Area-ID:%s Cksum:%hx Instance-ID:%d", + area_id, ntohs (oh->checksum), oh->instance_id); } -static void -ospf6_message_log_hello (struct iovec *message) +void +ospf6_hello_print (struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length_left; struct ospf6_hello *hello; - char dr_str[16], bdr_str[16]; - char *start, *end, *current; + char options[16]; + char drouter[16], bdrouter[16], neighbor[16]; + char *p; - /* calculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? - length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_HELLO); - hello = (struct ospf6_hello *) message[1].iov_base; + hello = (struct ospf6_hello *) + ((caddr_t) oh + sizeof (struct ospf6_header)); - inet_ntop (AF_INET, &hello->dr, dr_str, sizeof (dr_str)); - inet_ntop (AF_INET, &hello->bdr, bdr_str, sizeof (bdr_str)); + inet_ntop (AF_INET, &hello->drouter, drouter, sizeof (drouter)); + inet_ntop (AF_INET, &hello->bdrouter, bdrouter, sizeof (bdrouter)); + ospf6_options_printbuf (hello->options, options, sizeof (options)); - zlog_info (" IFID:%ld Priority:%d Option:%s", - (u_long)ntohl (hello->interface_id), hello->rtr_pri, "xxx"); - zlog_info (" HelloInterval:%hu Deadinterval:%hu", - ntohs (hello->hello_interval), - ntohs (hello->router_dead_interval)); - zlog_info (" DR:%s BDR:%s", dr_str, bdr_str); + zlog_info (" I/F-Id:%ld Priority:%d Option:%s", + (u_long) ntohl (hello->interface_id), hello->priority, options); + zlog_info (" HelloInterval:%hu DeadInterval:%hu", + ntohs (hello->hello_interval), ntohs (hello->dead_interval)); + zlog_info (" DR:%s BDR:%s", drouter, bdrouter); - start = (char *) (hello + 1); - if (start >= (char *) message[1].iov_base + message[1].iov_len) - start = message[2].iov_base; - end = (char *) start + (length_left - sizeof (struct ospf6_hello)); - - for (current = start; current < end; current += sizeof (u_int32_t)) + for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); + p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); + p += sizeof (u_int32_t)) { - char neighbor[16]; - inet_ntop (AF_INET, current, neighbor, sizeof (neighbor)); + inet_ntop (AF_INET, (void *) p, neighbor, sizeof (neighbor)); zlog_info (" Neighbor: %s", neighbor); } + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); } -static void -ospf6_message_log_dbdesc (struct iovec *message) +void +ospf6_dbdesc_print (struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length_left; struct ospf6_dbdesc *dbdesc; - int i; - char buffer[16]; - struct ospf6_lsa_header *lsa_header; - - /* calculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? - length_left : iov_totallen (message) - sizeof (struct ospf6_header)); - - dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; - ospf6_options_string (dbdesc->options, buffer, sizeof (buffer)); - - zlog_info (" Option:%s IFMTU:%hu", buffer, ntohs (dbdesc->ifmtu)); - zlog_info (" Bits:%s%s%s SeqNum:%#lx", - (DD_IS_IBIT_SET (dbdesc->bits) ? "I" : "-"), - (DD_IS_MBIT_SET (dbdesc->bits) ? "M" : "-"), - (DD_IS_MSBIT_SET (dbdesc->bits) ? "m" : "s"), - (u_long)ntohl (dbdesc->seqnum)); - - for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1); - (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + message[1].iov_len) && - (char *)(lsa_header + 1) <= (char *)dbdesc + length_left; - lsa_header++) - ospf6_message_log_lsa_header (lsa_header); - - length_left -= message[1].iov_len; - for (i = 2; message[i].iov_base; i++) - { - for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base; - (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + - message[i].iov_len) && - (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left); - lsa_header++) - ospf6_message_log_lsa_header (lsa_header); - length_left -= message[i].iov_len; - } + char options[16]; + char *p; + + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_DBDESC); + + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + ospf6_options_printbuf (dbdesc->options, options, sizeof (options)); + + zlog_info (" MBZ: %#x Option: %s IfMTU: %hu", + dbdesc->reserved1, options, ntohs (dbdesc->ifmtu)); + zlog_info (" MBZ: %#x Bits: %s%s%s SeqNum: %#lx", + dbdesc->reserved2, + (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) ? "I" : "-"), + (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) ? "M" : "-"), + (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"), + (u_long) ntohl (dbdesc->seqnum)); + + for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); } -static void -ospf6_message_log_lsreq (struct iovec *message) +void +ospf6_lsreq_print (struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length_left; - int i; - struct ospf6_lsreq *lsreq; - char buf_router[16], buf_id[16], buf_type[16]; + char id[16], adv_router[16]; + char *p; - /* calculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? - length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_LSREQ); - for (i = 1; message[i].iov_base; i++) + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsreq_entry)) { - for (lsreq = (struct ospf6_lsreq *) message[i].iov_base; - (char *)(lsreq + 1) <= (char *) (message[i].iov_base + message[i].iov_len) && - (char *)(lsreq + 1) <= (char *) (message[i].iov_base + length_left); - lsreq++) - { - inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router)); - inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id)); - zlog_info (" [%s ID=%s Adv=%s]", - ospf6_lsa_type_string (lsreq->type, buf_type, - sizeof (buf_type)), - buf_id, buf_router); - } - length_left -= message[i].iov_len; + struct ospf6_lsreq_entry *e = (struct ospf6_lsreq_entry *) p; + inet_ntop (AF_INET, &e->adv_router, adv_router, sizeof (adv_router)); + inet_ntop (AF_INET, &e->id, id, sizeof (id)); + zlog_info (" [%s Id:%s Adv:%s]", + OSPF6_LSTYPE_NAME (e->type), id, adv_router); } + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); } -static void -ospf6_message_log_lsupdate (struct iovec *message) +void +ospf6_lsupdate_print (struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length_left; - int i, lsanum; struct ospf6_lsupdate *lsupdate; - struct ospf6_lsa_header *lsa_header; + u_long num; + char *p; - /* calculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? - length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_LSUPDATE); - lsupdate = (struct ospf6_lsupdate *) message[1].iov_base; - lsanum = ntohl (lsupdate->lsupdate_num); + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); - zlog_info (" Number of LSA: #%d", lsanum); + num = ntohl (lsupdate->lsa_number); + zlog_info (" Number of LSA: %ld", num); - for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1); - (char *)lsa_header < (char *)(message[1].iov_base + message[1].iov_len) && - (char *)lsa_header < (char *)(message[1].iov_base + length_left); - lsa_header = OSPF6_LSA_NEXT (lsa_header)) - ospf6_message_log_lsa_header (lsa_header); - length_left -= message[1].iov_len; + for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + p < OSPF6_MESSAGE_END (oh) && + p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); + p += OSPF6_LSA_SIZE (p)) + { + ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); + if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header)) + { + zlog_info (" Malformed LSA length, quit printing"); + break; + } + } - for (i = 2; message[i].iov_base; i++) + if (p != OSPF6_MESSAGE_END (oh)) { + char buf[32]; + + int num = 0; + memset (buf, 0, sizeof (buf)); - for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base; - (char *)lsa_header < (char *) (message[i].iov_base + message[i].iov_len) && - (char *)lsa_header < (char *) (message[i].iov_base + length_left); - lsa_header = OSPF6_LSA_NEXT (lsa_header)) - ospf6_message_log_lsa_header (lsa_header); - length_left -= message[i].iov_len; + zlog_info (" Trailing garbage exists"); + while (p < OSPF6_MESSAGE_END (oh)) + { + snprintf (buf, sizeof (buf), "%s %2x", buf, *p++); + num++; + if (num == 8) + { + zlog_info (" %s", buf); + memset (buf, 0, sizeof (buf)); + num = 0; + } + } + if (num) + zlog_info (" %s", buf); } } -static void -ospf6_message_log_lsack (struct iovec *message) +void +ospf6_lsack_print (struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length_left; - struct ospf6_lsa_header *lsa_header; - int i; + char *p; - /* calculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ? - length_left : iov_totallen (message) - sizeof (struct ospf6_header)); + ospf6_header_print (oh); + assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); - for (i = 1; message[i].iov_base; i++) - { - for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base; - (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + - message[i].iov_len) && - (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left); - lsa_header++) - ospf6_message_log_lsa_header (lsa_header); - length_left -= message[i].iov_len; - } + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); + + if (p != OSPF6_MESSAGE_END (oh)) + zlog_info ("Trailing garbage exists"); } -struct { - void (*message_log) (struct iovec *); -} ospf6_message_log_body [] = +/* Receive function */ +#define MSG_OK 0 +#define MSG_NG 1 +static int +ospf6_header_examin (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) { - {ospf6_message_log_unknown}, - {ospf6_message_log_hello}, - {ospf6_message_log_dbdesc}, - {ospf6_message_log_lsreq}, - {ospf6_message_log_lsupdate}, - {ospf6_message_log_lsack}, -}; - -static void -ospf6_message_log (struct iovec *message) -{ - struct ospf6_header *o6h; - char router_id[16], area_id[16]; u_char type; + type = OSPF6_MESSAGE_TYPE_CANONICAL (oh->type); - assert (message[0].iov_len == sizeof (struct ospf6_header)); - o6h = (struct ospf6_header *) message[0].iov_base; + /* version check */ + if (oh->version != OSPFV3_VERSION) + { + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Message with unknown version"); + return MSG_NG; + } - inet_ntop (AF_INET, &o6h->router_id, router_id, sizeof (router_id)); - inet_ntop (AF_INET, &o6h->area_id, area_id, sizeof (area_id)); + /* Area-ID check */ + if (oh->area_id != oi->area->area_id) + { + if (oh->area_id == 0) + { + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Message may be via Virtual Link: not supported"); + return MSG_NG; + } - zlog_info (" OSPFv%d Type:%d Len:%hu RouterID:%s", - o6h->version, o6h->type, ntohs (o6h->len), router_id); - zlog_info (" AreaID:%s Cksum:%hx InstanceID:%d", - area_id, ntohs (o6h->cksum), o6h->instance_id); + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Area-ID mismatch"); + return MSG_NG; + } - type = (OSPF6_MESSAGE_TYPE_UNKNOWN < o6h->type && - o6h->type <= OSPF6_MESSAGE_TYPE_LSACK ? - o6h->type : OSPF6_MESSAGE_TYPE_UNKNOWN); - (* ospf6_message_log_body[type].message_log) (&message[0]); -} + /* Instance-ID check */ + if (oh->instance_id != oi->instance_id) + { + if (IS_OSPF6_DEBUG_MESSAGE (type, RECV)) + zlog_info ("Instance-ID mismatch"); + return MSG_NG; + } -int -ospf6_opt_is_mismatch (unsigned char opt, char *options1, char *options2) -{ - return (OSPF6_OPT_ISSET (options1, opt) ^ OSPF6_OPT_ISSET (options2, opt)); -} + /* Router-ID check */ + if (oh->router_id == oi->area->ospf6->router_id) + zlog_warn ("Detect duplicate Router-ID"); - -void -ospf6_process_unknown (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i, - u_int32_t router_id) -{ - zlog_warn ("unknown message type, drop"); + return MSG_OK; } void -ospf6_process_hello (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i, - u_int32_t router_id) +ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length; struct ospf6_hello *hello; - char changes = 0; -#define CHANGE_RTRPRI (1 << 0) -#define CHANGE_DR (1 << 1) -#define CHANGE_BDR (1 << 2) - int twoway = 0, backupseen = 0, nbchange = 0; - u_int32_t *router_id_ptr; - int i, seenrtrnum = 0, router_id_space = 0; - char strbuf[64]; - struct ospf6_neighbor *o6n = NULL; - - /* assert interface */ - assert (o6i); - - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); - - /* set hello pointer */ - hello = (struct ospf6_hello *) message[1].iov_base; - - /* find neighbor. if cannot be found, create */ - o6n = ospf6_neighbor_lookup (router_id, o6i); - if (!o6n) - { - o6n = ospf6_neighbor_create (router_id, o6i); - o6n->ifid = ntohl (hello->interface_id); - o6n->prevdr = o6n->dr = hello->dr; - o6n->prevbdr = o6n->bdr = hello->bdr; - o6n->priority = hello->rtr_pri; - memcpy (&o6n->hisaddr, src, sizeof (struct in6_addr)); - } + struct ospf6_neighbor *on; + char *p; + int twoway = 0; + int neighborchange = 0; + int backupseen = 0; + + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + hello = (struct ospf6_hello *) + ((caddr_t) oh + sizeof (struct ospf6_header)); /* HelloInterval check */ - if (ntohs (hello->hello_interval) != o6i->hello_interval) + if (ntohs (hello->hello_interval) != oi->hello_interval) { - zlog_warn ("HelloInterval mismatch with %s", o6n->str); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("HelloInterval mismatch"); return; } /* RouterDeadInterval check */ - if (ntohs (hello->router_dead_interval) - != o6i->dead_interval) + if (ntohs (hello->dead_interval) != oi->dead_interval) { - zlog_warn ("RouterDeadInterval mismatch with %s", o6n->str); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("RouterDeadInterval mismatch"); return; } - /* check options */ - /* Ebit */ - if (ospf6_opt_is_mismatch (OSPF6_OPT_E, hello->options, o6i->area->options)) + /* E-bit check */ + if (OSPF6_OPT_ISSET (hello->options, OSPF6_OPT_E) != + OSPF6_OPT_ISSET (oi->area->options, OSPF6_OPT_E)) { - zlog_warn ("Ebit mismatch with %s", o6n->str); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("E-bit mismatch"); return; } - /* RouterPriority set */ - if (o6n->priority != hello->rtr_pri) + /* Find neighbor, create if not exist */ + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) { - o6n->priority = hello->rtr_pri; - if (IS_OSPF6_DUMP_HELLO) - zlog_info ("%s: RouterPriority changed", o6n->str); - changes |= CHANGE_RTRPRI; + on = ospf6_neighbor_create (oh->router_id, oi); + on->prev_drouter = on->drouter = hello->drouter; + on->prev_bdrouter = on->bdrouter = hello->bdrouter; + on->priority = hello->priority; + on->ifindex = ntohl (hello->interface_id); + memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); } - /* DR set */ - if (o6n->dr != hello->dr) + /* TwoWay check */ + for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); + p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); + p += sizeof (u_int32_t)) { - /* save previous dr, set current */ - o6n->prevdr = o6n->dr; - o6n->dr = hello->dr; - inet_ntop (AF_INET, &o6n->dr, strbuf, sizeof (strbuf)); - if (IS_OSPF6_DUMP_HELLO) - zlog_info ("%s declare %s as DR", o6n->str, strbuf); - changes |= CHANGE_DR; + u_int32_t *router_id = (u_int32_t *) p; + + if (*router_id == oi->area->ospf6->router_id) + twoway++; } - /* BDR set */ - if (o6n->bdr != hello->bdr) + if (p != OSPF6_MESSAGE_END (oh)) { - /* save previous bdr, set current */ - o6n->prevbdr = o6n->bdr; - o6n->bdr = hello->bdr; - inet_ntop (AF_INET, &o6n->bdr, strbuf, sizeof (strbuf)); - if (IS_OSPF6_DUMP_HELLO) - zlog_info ("%s declare %s as BDR", o6n->str, strbuf); - changes |= CHANGE_BDR; + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); } - /* TwoWay check */ - router_id_space = length - sizeof (struct ospf6_hello); - seenrtrnum = router_id_space / sizeof (u_int32_t); - router_id_ptr = (u_int32_t *) (hello + 1); - for (i = 0; i < seenrtrnum; i++) + /* RouterPriority check */ + if (on->priority != hello->priority) { - if (*router_id_ptr == o6i->area->ospf6->router_id) - twoway++; - router_id_ptr++; + on->priority = hello->priority; + neighborchange++; } - /* execute neighbor events */ - thread_execute (master, hello_received, o6n, 0); - if (twoway) - thread_execute (master, twoway_received, o6n, 0); - else - thread_execute (master, oneway_received, o6n, 0); + /* DR check */ + if (on->drouter != hello->drouter) + { + on->prev_drouter = on->drouter; + on->drouter = hello->drouter; + if (on->prev_drouter == on->router_id || on->drouter == on->router_id) + neighborchange++; + } - /* BackupSeen check */ - if (o6i->state == IFS_WAITING) + /* BDR check */ + if (on->bdrouter != hello->bdrouter) { - if (hello->dr == hello->bdr && - hello->dr == o6n->router_id) - zlog_warn ("*** DR Election of %s is illegal", o6n->str); + on->prev_bdrouter = on->bdrouter; + on->bdrouter = hello->bdrouter; + if (on->prev_bdrouter == on->router_id || on->bdrouter == on->router_id) + neighborchange++; + } - if (hello->bdr == o6n->router_id) + /* BackupSeen check */ + if (oi->state == OSPF6_INTERFACE_WAITING) + { + if (hello->bdrouter == on->router_id) backupseen++; - else if (hello->dr == o6n->router_id && hello->bdr == 0) + else if (hello->drouter == on->router_id && hello->bdrouter == htonl (0)) backupseen++; } - /* NeighborChange check */ - if (changes & CHANGE_RTRPRI) - nbchange++; - if (changes & CHANGE_DR) - if (o6n->prevdr == o6n->router_id || o6n->dr == o6n->router_id) - nbchange++; - if (changes & CHANGE_BDR) - if (o6n->prevbdr == o6n->router_id || o6n->bdr == o6n->router_id) - nbchange++; + /* Execute neighbor events */ + thread_execute (master, hello_received, on, 0); + if (twoway) + thread_execute (master, twoway_received, on, 0); + else + thread_execute (master, oneway_received, on, 0); - /* schedule interface events */ + /* Schedule interface events */ if (backupseen) - thread_add_event (master, backup_seen, o6i, 0); - if (nbchange) - thread_add_event (master, neighbor_change, o6i, 0); - - return; + thread_add_event (master, backup_seen, oi, 0); + if (neighborchange) + thread_add_event (master, neighbor_change, oi, 0); } -int -ospf6_dbdesc_is_master (struct ospf6_neighbor *o6n) +static void +ospf6_dbdesc_recv_master (struct ospf6_header *oh, + struct ospf6_neighbor *on) { - char buf[128]; + struct ospf6_dbdesc *dbdesc; + char *p; - if (o6n->router_id == ospf6->router_id) + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + if (on->state < OSPF6_NEIGHBOR_INIT) { - inet_ntop (AF_INET6, &o6n->hisaddr, buf, sizeof (buf)); - zlog_warn ("Message: Neighbor router-id conflicts: %s: %s", - o6n->str, buf); - return -1; + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Init, ignore"); + return; } - else if (ntohl (o6n->router_id) > ntohl (ospf6->router_id)) - return 0; - return 1; -} -int -ospf6_dbdesc_is_duplicate (struct ospf6_dbdesc *received, - struct ospf6_dbdesc *last_received) -{ - if (memcmp (received->options, last_received->options, 3) != 0) - return 0; - if (received->ifmtu != last_received->ifmtu) - return 0; - if (received->bits != last_received->bits) - return 0; - if (received->seqnum != last_received->seqnum) - return 0; - return 1; -} + switch (on->state) + { + case OSPF6_NEIGHBOR_TWOWAY: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is 2-Way, ignore"); + return; -void -ospf6_process_dbdesc_master (struct iovec *message, struct ospf6_neighbor *o6n) -{ - struct ospf6_header *ospf6_header; - u_int16_t length, lsa_count; - struct ospf6_dbdesc *dbdesc; - struct ospf6_lsa_header *lsa_header; - - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); - - /* set database description pointer */ - dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; - - switch (o6n->state) - { - case NBS_DOWN: - case NBS_ATTEMPT: - case NBS_TWOWAY: - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("DbDesc from %s Ignored: state less than Init", - o6n->str); - return; - - case NBS_INIT: - thread_execute (master, twoway_received, o6n, 0); - if (o6n->state != NBS_EXSTART) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("DbDesc from %s Ignored: state less than ExStart", - o6n->str); - return; - } - /* else fall through to ExStart */ - case NBS_EXSTART: - if (DDBIT_IS_SLAVE (dbdesc->bits) && - !DDBIT_IS_INITIAL (dbdesc->bits) && - ntohl (dbdesc->seqnum) == o6n->dbdesc_seqnum) - { - ospf6_neighbor_dbex_init (o6n); - - if (o6n->thread_rxmt_dbdesc) - thread_cancel (o6n->thread_rxmt_dbdesc); - o6n->thread_rxmt_dbdesc = (struct thread *) NULL; - - thread_add_event (master, negotiation_done, o6n, 0); - } - else - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" negotiation failed with %s", o6n->str); - return; - } - break; + case OSPF6_NEIGHBOR_INIT: + thread_execute (master, twoway_received, on, 0); + if (on->state != OSPF6_NEIGHBOR_EXSTART) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is not ExStart, ignore"); + return; + } + /* else fall through to ExStart */ + + case OSPF6_NEIGHBOR_EXSTART: + /* if neighbor obeys us as our slave, schedule negotiation_done + and process LSA Headers. Otherwise, ignore this message */ + if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) && + ! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) && + ntohl (dbdesc->seqnum) == on->dbdesc_seqnum) + { + /* execute NegotiationDone */ + thread_execute (master, negotiation_done, on, 0); - case NBS_EXCHANGE: - /* duplicate dbdesc dropped by master */ - if (!memcmp (dbdesc, &o6n->last_dd, - sizeof (struct ospf6_dbdesc))) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" duplicate dbdesc, drop"); - return; - } - - /* check Initialize bit and Master/Slave bit */ - if (DDBIT_IS_INITIAL (dbdesc->bits)) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("Initialize bit mismatch"); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - if (DDBIT_IS_MASTER (dbdesc->bits)) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("Master/Slave bit mismatch"); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - - /* dbdesc option check */ - if (memcmp (dbdesc->options, o6n->last_dd.options, - sizeof (dbdesc->options))) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("dbdesc option field changed"); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - - /* dbdesc sequence number check */ - if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_warn ("*** dbdesc seqnumber mismatch: %d expected", - o6n->dbdesc_seqnum); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - break; + /* Record neighbor options */ + memcpy (on->options, dbdesc->options, sizeof (on->options)); + } + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Negotiation failed"); + return; + } + /* fall through to exchange */ - case NBS_LOADING: - case NBS_FULL: - /* duplicate dbdesc dropped by master */ - if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd)) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" duplicate dbdesc, drop"); - return; - } - else - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" not duplicate dbdesc in state %s", - ospf6_neighbor_state_string[o6n->state]); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - break; /* not reached */ + case OSPF6_NEIGHBOR_EXCHANGE: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription is dropped by master */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc discarded by Master, ignore"); + return; + } - default: - assert (0); - break; /* not reached */ + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Master/Slave bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Initialize bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (memcmp (on->options, dbdesc->options, sizeof (on->options))) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Option field mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Sequence number mismatch (%#lx expected)", + (u_long) on->dbdesc_seqnum); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + break; + + case OSPF6_NEIGHBOR_LOADING: + case OSPF6_NEIGHBOR_FULL: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription is dropped by master */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc discarded by Master, ignore"); + return; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Not duplicate dbdesc in state %s", + ospf6_neighbor_state_str[on->state]); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + + default: + assert (0); + break; } - /* process LSA headers */ - lsa_count = 0; - for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1); - (char *)(lsa_header + 1) <= (char *)dbdesc + length; - lsa_header++) + /* Process LSA headers */ + for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) { - if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0) + struct ospf6_lsa *his, *mine; + struct ospf6_lsdb *lsdb = NULL; + + his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); + his->scope = ospf6_get_lsa_scope (his->header->type, on); + lsdb = ospf6_get_scoped_lsdb (his->header->type, his->scope); + if (lsdb == NULL) + { + zlog_warn ("Can't decide scoped LSDB"); + ospf6_lsa_delete (his); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (ntohs (his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && + ospf6_area_is_stub (on->ospf6_if->area)) { - thread_add_event (master, seqnumber_mismatch, o6n, 0); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("E-bit mismatch with LSA Headers"); + ospf6_lsa_delete (his); + thread_add_event (master, seqnumber_mismatch, on, 0); return; } - lsa_count ++; + + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, lsdb); + if (mine == NULL || ospf6_lsa_compare (his, mine) < 0) + { + if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (DATABASE)) + zlog_info ("Add %s's request-list: %s", on->name, his->name); + ospf6_lsdb_add (his, on->request_list); + } + else + ospf6_lsa_delete (his); } - /* increment dbdesc seqnum */ - o6n->dbdesc_seqnum++; + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } - /* cancel transmission/retransmission thread */ - if (o6n->thread_send_dbdesc) - thread_cancel (o6n->thread_send_dbdesc); - o6n->thread_send_dbdesc = (struct thread *) NULL; - if (o6n->thread_rxmt_dbdesc) - thread_cancel (o6n->thread_rxmt_dbdesc); - o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + /* Increment sequence number */ + on->dbdesc_seqnum ++; - /* more bit check */ - if (!DD_IS_MBIT_SET (dbdesc->bits) && !DD_IS_MBIT_SET (o6n->dbdesc_bits)) - thread_add_event (master, exchange_done, o6n, 0); - else - o6n->thread_send_dbdesc = - thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + /* schedule send lsreq */ + if (on->thread_send_lsreq == NULL) + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); - /* save last received dbdesc */ - memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc)); + THREAD_OFF (on->thread_send_dbdesc); - /* statistics */ - o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count; + /* More bit check */ + if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) && + ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) + thread_add_event (master, exchange_done, on, 0); + else + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send_newone, on, 0); - return; + /* save last received dbdesc */ + memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc)); } -void -ospf6_process_dbdesc_slave (struct iovec *message, struct ospf6_neighbor *o6n) +static void +ospf6_dbdesc_recv_slave (struct ospf6_header *oh, + struct ospf6_neighbor *on) { - struct ospf6_header *ospf6_header; - u_int16_t length, lsa_count; struct ospf6_dbdesc *dbdesc; - struct ospf6_lsa_header *lsa_header; - - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); - - /* set database description pointer */ - dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; - - switch (o6n->state) - { - case NBS_DOWN: - case NBS_ATTEMPT: - case NBS_TWOWAY: - return; - case NBS_INIT: - thread_execute (master, twoway_received, o6n, 0); - if (o6n->state != NBS_EXSTART) - { - return; - } - /* else fall through to ExStart */ - case NBS_EXSTART: - if (DD_IS_IBIT_SET (dbdesc->bits) && - DD_IS_MBIT_SET (dbdesc->bits) && - DD_IS_MSBIT_SET (dbdesc->bits)) - { - /* Master/Slave bit set to slave */ - DD_MSBIT_CLEAR (o6n->dbdesc_bits); - /* Initialize bit clear */ - DD_IBIT_CLEAR (o6n->dbdesc_bits); - /* sequence number set to master's */ - o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum); - ospf6_neighbor_dbex_init (o6n); - - if (o6n->thread_rxmt_dbdesc) - thread_cancel (o6n->thread_rxmt_dbdesc); - o6n->thread_rxmt_dbdesc = (struct thread *) NULL; - - thread_add_event (master, negotiation_done, o6n, 0); - } - else - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("negotiation failed"); - return; - } - break; + char *p; - case NBS_EXCHANGE: - /* duplicate dbdesc dropped by master */ - if (!memcmp (dbdesc, &o6n->last_dd, - sizeof (struct ospf6_dbdesc))) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" duplicate dbdesc, retransmit dbdesc"); - - if (o6n->thread_rxmt_dbdesc) - thread_cancel (o6n->thread_rxmt_dbdesc); - o6n->thread_rxmt_dbdesc = - thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0); - - return; - } - - /* check Initialize bit and Master/Slave bit */ - if (DDBIT_IS_INITIAL (dbdesc->bits)) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("Initialize bit mismatch"); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - if (DDBIT_IS_SLAVE (dbdesc->bits)) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("Master/Slave bit mismatch"); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - - /* dbdesc option check */ - if (memcmp (dbdesc->options, o6n->last_dd.options, - sizeof (dbdesc->options))) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("dbdesc option field changed"); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - - /* dbdesc sequence number check */ - if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum + 1) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_warn ("*** dbdesc seqnumber mismatch: %d expected", - o6n->dbdesc_seqnum + 1); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - break; + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); + + if (on->state < OSPF6_NEIGHBOR_INIT) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Init, ignore"); + return; + } - case NBS_LOADING: - case NBS_FULL: - /* duplicate dbdesc cause slave to retransmit */ - if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd)) - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" duplicate dbdesc, retransmit"); - - if (o6n->thread_rxmt_dbdesc) - thread_cancel (o6n->thread_rxmt_dbdesc); - o6n->thread_rxmt_dbdesc = - thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0); - - return; - } - else - { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info (" not duplicate dbdesc in state %s", - ospf6_neighbor_state_string[o6n->state]); - thread_add_event (master, seqnumber_mismatch, o6n, 0); - return; - } - break; /* not reached */ + switch (on->state) + { + case OSPF6_NEIGHBOR_TWOWAY: + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is 2-Way, ignore"); + return; - default: - assert (0); - break; /* not reached */ + case OSPF6_NEIGHBOR_INIT: + thread_execute (master, twoway_received, on, 0); + if (on->state != OSPF6_NEIGHBOR_EXSTART) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state is not ExStart, ignore"); + return; + } + /* else fall through to ExStart */ + + case OSPF6_NEIGHBOR_EXSTART: + /* If the neighbor is Master, act as Slave. Schedule negotiation_done + and process LSA Headers. Otherwise, ignore this message */ + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) && + CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) && + CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) && + ntohs (oh->length) == sizeof (struct ospf6_header) + + sizeof (struct ospf6_dbdesc)) + { + /* set the master/slave bit to slave */ + UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); + + /* set the DD sequence number to one specified by master */ + on->dbdesc_seqnum = ntohl (dbdesc->seqnum); + + /* schedule NegotiationDone */ + thread_execute (master, negotiation_done, on, 0); + + /* Record neighbor options */ + memcpy (on->options, dbdesc->options, sizeof (on->options)); + } + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Negotiation failed"); + return; + } + break; + + case OSPF6_NEIGHBOR_EXCHANGE: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription causes slave to retransmit */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc causes retransmit"); + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + return; + } + + if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Master/Slave bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Initialize bit mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (memcmp (on->options, dbdesc->options, sizeof (on->options))) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Option field mismatch"); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum + 1) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Sequence number mismatch (%#lx expected)", + (u_long) on->dbdesc_seqnum + 1); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + break; + + case OSPF6_NEIGHBOR_LOADING: + case OSPF6_NEIGHBOR_FULL: + if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) + { + /* Duplicated DatabaseDescription causes slave to retransmit */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Duplicated dbdesc causes retransmit"); + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send, on, 0); + return; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Not duplicate dbdesc in state %s", + ospf6_neighbor_state_str[on->state]); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + + default: + assert (0); + break; } - /* process LSA headers */ - lsa_count = 0; - for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1); - (char *)(lsa_header + 1) <= (char *)dbdesc + length; - lsa_header++) + /* Process LSA headers */ + for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) { - if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0) + struct ospf6_lsa *his, *mine; + struct ospf6_lsdb *lsdb = NULL; + + his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); + his->scope = ospf6_get_lsa_scope (his->header->type, on); + lsdb = ospf6_get_scoped_lsdb (his->header->type, his->scope); + if (lsdb == NULL) + { + zlog_warn ("Can't decide scoped LSDB"); + ospf6_lsa_delete (his); + thread_add_event (master, seqnumber_mismatch, on, 0); + return; + } + + if (ntohs (his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && + ospf6_area_is_stub (on->ospf6_if->area)) { - thread_add_event (master, seqnumber_mismatch, o6n, 0); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("E-bit mismatch with LSA Headers"); + ospf6_lsa_delete (his); + thread_add_event (master, seqnumber_mismatch, on, 0); return; } - lsa_count ++; + + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, lsdb); + if (mine == NULL || ospf6_lsa_compare (his, mine) < 0) + { + if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (DATABASE)) + zlog_info ("Add %s to request-list of %s", his->name, on->name); + ospf6_lsdb_add (his, on->request_list); + } + else + ospf6_lsa_delete (his); } - /* set dbdesc seqnum to master's */ - o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum); + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } - if (o6n->thread_send_dbdesc) - thread_cancel (o6n->thread_send_dbdesc); - o6n->thread_send_dbdesc = - thread_add_event (master, ospf6_send_dbdesc, o6n, 0); + /* Set sequence number to Master's */ + on->dbdesc_seqnum = ntohl (dbdesc->seqnum); - /* save last received dbdesc */ - memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc)); + /* schedule send lsreq */ + if (on->thread_send_lsreq == NULL) + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); - /* statistics */ - o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count; + THREAD_OFF (on->thread_send_dbdesc); + on->thread_send_dbdesc = + thread_add_event (master, ospf6_dbdesc_send_newone, on, 0); - return; + /* save last received dbdesc */ + memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc)); } void -ospf6_process_dbdesc (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i, - u_int32_t router_id) +ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length; - struct ospf6_neighbor *o6n; + struct ospf6_neighbor *on; struct ospf6_dbdesc *dbdesc; - int Im_master = 0; - - /* assert interface */ - assert (o6i); - - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); - /* set database description pointer */ - dbdesc = (struct ospf6_dbdesc *) message[1].iov_base; + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; - /* find neighbor. if cannot be found, reject this message */ - o6n = ospf6_neighbor_lookup (router_id, o6i); - if (!o6n) + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) { - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("neighbor not found, reject"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); return; } - if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + if (memcmp (src, &on->linklocal_addr, sizeof (struct in6_addr))) { - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("From Secondary I/F of the neighbor: ignore"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore"); return; } - /* interface mtu check */ - /* xxx */ + dbdesc = (struct ospf6_dbdesc *) + ((caddr_t) oh + sizeof (struct ospf6_header)); - /* check am I master */ - Im_master = ospf6_dbdesc_is_master (o6n); - if (Im_master < 0) + /* Interface MTU check */ + if (ntohs (dbdesc->ifmtu) != oi->ifmtu) { - return; /* can't decide which is master, return */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("I/F MTU mismatch"); + return; } - if (Im_master) - ospf6_process_dbdesc_master (message, o6n); - else - ospf6_process_dbdesc_slave (message, o6n); + if (dbdesc->reserved1 || dbdesc->reserved2) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Non-0 reserved field in %s's DbDesc, correct", + on->name); + dbdesc->reserved1 = 0; + dbdesc->reserved2 = 0; + } - return; + if (ntohl (oh->router_id) < ntohl (ospf6->router_id)) + ospf6_dbdesc_recv_master (oh, on); + else if (ntohl (ospf6->router_id) < ntohl (oh->router_id)) + ospf6_dbdesc_recv_slave (oh, on); + else + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Can't decide which is master, ignore"); + } } void -ospf6_process_lsreq (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i, - u_int32_t router_id) +ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length; - struct ospf6_neighbor *o6n; - struct ospf6_lsreq *lsreq; - struct iovec response[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_neighbor *on; + char *p; + struct ospf6_lsreq_entry *e; + void *scope = NULL; + struct ospf6_lsdb *lsdb = NULL; struct ospf6_lsa *lsa; - unsigned long lsanum = 0; - struct ospf6_lsupdate lsupdate; - char buf_id[16], buf_router[16], buf_type[16]; - - /* assert interface */ - assert (o6i); - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; - /* find neighbor. if cannot be found, reject this message */ - o6n = ospf6_neighbor_lookup (router_id, o6i); - if (!o6n) + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) { - if (IS_OSPF6_DUMP_LSREQ) - zlog_info (" neighbor not found, reject"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); return; } - if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + if (memcmp (src, &on->linklocal_addr, sizeof (struct in6_addr))) { - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("From Secondary I/F of the neighbor: ignore"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore"); return; } - /* In states other than ExChange, Loading, or Full, the packet - should be ignored. */ - if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING - && o6n->state != NBS_FULL) + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING && + on->state != OSPF6_NEIGHBOR_FULL) { - if (IS_OSPF6_DUMP_LSREQ) - zlog_info (" neighbor state less than Exchange, reject"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Exchange, ignore"); return; } - /* Initialize response LSUpdate packet */ - OSPF6_MESSAGE_CLEAR (response); - memset (&lsupdate, 0, sizeof (struct ospf6_lsupdate)); - OSPF6_MESSAGE_ATTACH (response, &lsupdate, sizeof (struct ospf6_lsupdate)); - - /* process each request */ - lsanum = 0; - for (lsreq = (struct ospf6_lsreq *) message[1].iov_base; - (char *)(lsreq + 1) <= (char *)(message[1].iov_base + length); - lsreq++) + /* Process each request */ + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsreq_entry)) { - inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router)); - inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id)); - - /* find instance of database copy */ - lsa = ospf6_lsdb_lookup (lsreq->type, lsreq->id, lsreq->adv_router, - ospf6_lsa_get_scope (lsreq->type, o6i)); + e = (struct ospf6_lsreq_entry *) p; + scope = ospf6_get_lsa_scope (e->type, on); + lsdb = ospf6_get_scoped_lsdb (e->type, scope); - if (!lsa) + /* Find database copy */ + lsa = ospf6_lsdb_lookup (e->type, e->id, e->adv_router, lsdb); + if (lsa == NULL) { - if (IS_OSPF6_DUMP_LSREQ) - zlog_info ("BadLSReq: %s requests [%s ID=%s Adv=%s] not found", - o6n->str, ospf6_lsa_type_string (lsreq->type, buf_type, - sizeof (buf_type)), - buf_id, buf_router); - thread_add_event (master, bad_lsreq, o6n, 0); + char id[16], adv_router[16]; + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + { + inet_ntop (AF_INET, &e->id, id, sizeof (id)); + inet_ntop (AF_INET, &e->adv_router, adv_router, + sizeof (adv_router)); + zlog_info ("Can't find requested [%s Id:%s Adv:%s]", + OSPF6_LSTYPE_NAME (e->type), id, adv_router); + } + thread_add_event (master, bad_lsreq, on, 0); return; } - /* I/F MTU check */ - if (sizeof (struct ospf6_header) + sizeof (struct ospf6_lsupdate) - + iov_totallen (response) + ntohs (lsa->header->length) - > o6i->ifmtu) - break; - - OSPF6_MESSAGE_ATTACH (response, lsa->header, ntohs (lsa->header->length)); - lsanum++; + if (IS_OSPF6_DEBUG_LSA (DATABASE)) + zlog_info ("Add copy of %s to lsupdate_list of %s", + lsa->name, on->name); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->lsupdate_list); } - /* send response LSUpdate to this request */ - if (lsanum) + if (p != OSPF6_MESSAGE_END (oh)) { - lsupdate.lsupdate_num = htonl (lsanum); - - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, response, - &o6n->hisaddr, o6i->if_id); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); } - /* statistics */ - o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ] - += length / sizeof (struct ospf6_lsreq); + /* schedule send lsupdate */ + THREAD_OFF (on->thread_send_lsupdate); + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } void -ospf6_process_lsupdate (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i, - u_int32_t router_id) +ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length; + struct ospf6_neighbor *on; struct ospf6_lsupdate *lsupdate; - struct ospf6_neighbor *o6n; - unsigned long lsanum; - struct ospf6_lsa_header *lsa_header; - - /* assert interface */ - assert (o6i); + unsigned long num; + char *p; - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; - /* find neighbor. if cannot be found, reject this message */ - o6n = ospf6_neighbor_lookup (router_id, o6i); - if (! o6n) + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) { - if (IS_OSPF6_DUMP_LSUPDATE) - zlog_info (" neighbor not found, reject"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); return; } - if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) + if (memcmp (src, &on->linklocal_addr, sizeof (struct in6_addr))) { - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("From Secondary I/F of the neighbor: ignore"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore"); return; } - /* if neighbor state less than ExChange, reject this message */ - if (o6n->state < NBS_EXCHANGE) + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING && + on->state != OSPF6_NEIGHBOR_FULL) { - if (IS_OSPF6_DUMP_LSUPDATE) - zlog_info (" neighbor state less than Exchange, reject"); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Exchange, ignore"); return; } - /* set linkstate update pointer */ - lsupdate = (struct ospf6_lsupdate *) message[1].iov_base; + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); - /* save linkstate update info */ - lsanum = ntohl (lsupdate->lsupdate_num); + num = ntohl (lsupdate->lsa_number); - /* statistics */ - o6n->ospf6_stat_received_lsa += lsanum; - o6n->ospf6_stat_received_lsupdate++; + /* Process LSAs */ + for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + p < OSPF6_MESSAGE_END (oh) && + p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); + p += OSPF6_LSA_SIZE (p)) + { + if (num == 0) + break; + if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Malformed LSA length, quit processing"); + break; + } + + ospf6_receive_lsa ((struct ospf6_lsa_header *) p, on); + num--; + } + + if (num != 0) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Malformed LSA number or LSA length"); + } + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } /* RFC2328 Section 10.9: When the neighbor responds to these requests with the proper Link State Update packet(s), the Link state request list is truncated and a new Link State Request packet is sent. */ + /* send new Link State Request packet if this LS Update packet + can be recognized as a response to our previous LS Request */ + if (! IN6_IS_ADDR_MULTICAST (dst) && + (on->state == OSPF6_NEIGHBOR_EXCHANGE || + on->state == OSPF6_NEIGHBOR_LOADING)) + { + THREAD_OFF (on->thread_send_lsreq); + on->thread_send_lsreq = + thread_add_event (master, ospf6_lsreq_send, on, 0); + } +} + +void +ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) +{ + struct ospf6_neighbor *on; + char *p; + struct ospf6_lsa *his, *mine; + struct ospf6_lsdb *lsdb = NULL; + + assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); + if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK) + return; + + on = ospf6_neighbor_lookup (oh->router_id, oi); + if (on == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor not found, ignore"); + return; + } + + if (memcmp (src, &on->linklocal_addr, sizeof (struct in6_addr))) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore"); + return; + } - /* process LSAs */ - for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1); - lsanum && (char *)lsa_header < (char *)lsupdate + length; - lsanum--) + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING && + on->state != OSPF6_NEIGHBOR_FULL) { - ospf6_dbex_receive_lsa (lsa_header, o6n); - lsa_header = OSPF6_LSA_NEXT (lsa_header); + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Neighbor state less than Exchange, ignore"); + return; } - /* send new Link State Request packet if this LS Update packet - can be recognized as a response to our previous LS request */ - if (! IN6_IS_ADDR_MULTICAST(dst) && - (o6n->state == NBS_EXCHANGE || o6n->state == NBS_LOADING)) - thread_add_event (master, ospf6_send_lsreq, o6n, 0); + for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); + p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); + p += sizeof (struct ospf6_lsa_header)) + { + his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); + his->scope = ospf6_get_lsa_scope (his->header->type, on); + lsdb = ospf6_get_scoped_lsdb (his->header->type, his->scope); + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV) || + IS_OSPF6_DEBUG_LSA (SEND)) + zlog_info ("%s acknowledged by %s", his->name, on->name); + + /* Find database copy */ + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, lsdb); + if (mine == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("No database copy"); + ospf6_lsa_delete (his); + continue; + } + + /* Check if the LSA is on his retrans-list */ + mine = ospf6_lsdb_lookup (his->header->type, his->header->id, + his->header->adv_router, on->retrans_list); + if (mine == NULL) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Not on %s's retrans-list", on->name); + ospf6_lsa_delete (his); + continue; + } + + if (ospf6_lsa_compare (his, mine) != 0) + { + /* Log this questionable acknowledgement, + and examine the next one. */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Questionable acknowledgement"); + ospf6_lsa_delete (his); + continue; + } + + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV) || + IS_OSPF6_DEBUG_LSA (SEND)) + zlog_info ("Acknowledged, remove from %s's retrans-list", + on->name); + + if (OSPF6_LSA_IS_MAXAGE (mine)) + ospf6_maxage_remove (on->ospf6_if->area->ospf6); + + if (IS_OSPF6_DEBUG_LSA (DATABASE)) + zlog_info ("remove %s from retrans_list of %s", + mine->name, on->name); + ospf6_lsdb_remove (mine, on->retrans_list); + ospf6_lsa_delete (his); + } + + if (p != OSPF6_MESSAGE_END (oh)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Trailing garbage ignored"); + } +} + +char recvbuf[OSPF6_MESSAGE_BUFSIZ]; +char sendbuf[OSPF6_MESSAGE_BUFSIZ]; + +int +ospf6_receive (struct thread *thread) +{ + int sockfd, len; + char srcname[64], dstname[64]; + struct in6_addr src, dst; + unsigned int ifindex; + struct iovec iovector[2]; + struct ospf6_interface *oi; + struct ospf6_header *oh; + + /* add next read thread */ + sockfd = THREAD_FD (thread); + thread_add_read (master, ospf6_receive, NULL, sockfd); + + /* initialize */ + memset (recvbuf, 0, sizeof (recvbuf)); + iovector[0].iov_base = recvbuf; + iovector[0].iov_len = sizeof (recvbuf); + iovector[1].iov_base = NULL; + iovector[1].iov_len = 0; + + /* receive message */ + len = ospf6_recvmsg (&src, &dst, &ifindex, iovector); + if (len > sizeof (recvbuf)) + { + zlog_err ("Excess message read"); + return 0; + } + else if (len < sizeof (struct ospf6_header)) + { + zlog_err ("Deficient message read"); + return 0; + } + + oi = ospf6_interface_lookup_by_ifindex (ifindex); + if (oi == NULL || oi->area == NULL) + { + zlog_info ("Message received on disabled interface"); + return 0; + } + + oh = (struct ospf6_header *) recvbuf; + + /* Log */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + { + inet_ntop (AF_INET6, &src, srcname, sizeof (srcname)); + inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname)); + zlog_info ("%s received on %s", + OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name); + zlog_info (" src: %s", srcname); + zlog_info (" dst: %s", dstname); + if (len != ntohs (oh->length)) + zlog_info ("Message length does not match actually received: %d", len); + + switch (oh->type) + { + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_print (oh); + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_print (oh); + break; + default: + zlog_info ("Unknown message"); + break; + } + } + + if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) + { + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) + zlog_info ("Ignore message on passive interface %s", + oi->interface->name); + return 0; + } + + switch (oh->type) + { + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_recv (&src, &dst, oi, oh); + break; + + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_recv (&src, &dst, oi, oh); + break; + + default: + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + zlog_info ("Unknown message"); + break; + } - return; + return 0; } void -ospf6_process_lsack (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i, - u_int32_t router_id) +ospf6_send (struct in6_addr *src, struct in6_addr *dst, + struct ospf6_interface *oi, struct ospf6_header *oh) { - struct ospf6_header *ospf6_header; - u_int16_t length; - struct ospf6_neighbor *o6n; - struct ospf6_lsa_header *lsa_header; - struct ospf6_lsa *lsa, *copy, *rem; - - /* assert interface */ - assert (o6i); - - /* caluculate length */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; - length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header); - length = (length < message[1].iov_len ? length : message[1].iov_len); - - /* find neighbor. if cannot be found, reject this message */ - o6n = ospf6_neighbor_lookup (router_id, o6i); - if (!o6n) - { - if (IS_OSPF6_DUMP_LSACK) - zlog_info ("LSACK: neighbor not found, reject"); - return; - } - - if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr))) - { - if (IS_OSPF6_DUMP_LSACK) - zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore"); - return; - } + int len; + char srcname[64], dstname[64]; + struct iovec iovector[2]; - /* if neighbor state less than ExChange, reject this message */ - if (o6n->state < NBS_EXCHANGE) - { - if (IS_OSPF6_DUMP_LSACK) - zlog_info ("LSACK: neighbor state less than Exchange, reject"); - return; - } + /* initialize */ + iovector[0].iov_base = (caddr_t) oh; + iovector[0].iov_len = ntohs (oh->length); + iovector[1].iov_base = NULL; + iovector[1].iov_len = 0; + + /* fill OSPF header */ + oh->version = OSPFV3_VERSION; + /* message type must be set before */ + /* message length must be set before */ + oh->router_id = oi->area->ospf6->router_id; + oh->area_id = oi->area->area_id; + /* checksum is calculated by kernel */ + oh->instance_id = oi->instance_id; + oh->reserved = 0; - /* process each LSA header */ - for (lsa_header = (struct ospf6_lsa_header *) message[1].iov_base; - (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + length); - lsa_header++) + /* Log */ + if (IS_OSPF6_DEBUG_MESSAGE (oh->type, SEND)) { - /* find database copy */ - copy = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id, - lsa_header->advrtr, - ospf6_lsa_get_scope (lsa_header->type, o6i)); - - /* if no database copy */ - if (!copy) - { - if (IS_OSPF6_DUMP_LSACK) - zlog_info ("LSACK: no database copy, ignore"); - continue; - } - - /* if not on his retrans list */ - rem = ospf6_lsdb_lookup_lsdb (copy->header->type, copy->header->id, - copy->header->adv_router, - o6n->retrans_list); - if (rem == NULL) - { - if (IS_OSPF6_DUMP_LSACK) - zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str); - continue; - } - - /* create temporary LSA from Ack message */ - lsa = ospf6_lsa_summary_create ((struct ospf6_lsa_header__ *) lsa_header); - - /* if the same instance, remove from retrans list. - else, log and ignore */ - if (ospf6_lsa_check_recent (lsa, copy) == 0) - ospf6_neighbor_retrans_remove (rem, o6n); + inet_ntop (AF_INET6, dst, dstname, sizeof (dstname)); + if (src) + inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); else + memset (srcname, 0, sizeof (srcname)); + zlog_info ("%s send on %s", + OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name); + zlog_info (" src: %s", srcname); + zlog_info (" dst: %s", dstname); + + switch (oh->type) { - /* Log the questionable acknowledgement, - and examine the next one. */ - zlog_info ("LSACK: questionable acknowledge: %s", copy->str); - zlog_info ("LSACK: received: seq: %#x age: %hu", - ntohl (lsa->header->seqnum), - ntohs (lsa->header->age)); - zlog_info ("LSACK: instance: seq: %#x age: %hu", - ntohl (copy->header->seqnum), - ospf6_lsa_age_current (copy)); + case OSPF6_MESSAGE_TYPE_HELLO: + ospf6_hello_print (oh); + break; + case OSPF6_MESSAGE_TYPE_DBDESC: + ospf6_dbdesc_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSREQ: + ospf6_lsreq_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSUPDATE: + ospf6_lsupdate_print (oh); + break; + case OSPF6_MESSAGE_TYPE_LSACK: + ospf6_lsack_print (oh); + break; + default: + zlog_info ("Unknown message"); + assert (0); + break; } - - /* release temporary LSA from Ack message */ - ospf6_lsa_delete (lsa); } - ospf6_maxage_remover (); - return; + /* send message */ + len = ospf6_sendmsg (src, dst, &oi->interface->ifindex, iovector); + if (len != ntohs (oh->length)) + zlog_err ("Could not send entire message"); } -struct { - void (*process) (struct iovec *, struct in6_addr *, struct in6_addr *, - struct ospf6_interface *, u_int32_t); -} ospf6_message_process_type [] = -{ - {ospf6_process_unknown}, - {ospf6_process_hello}, - {ospf6_process_dbdesc}, - {ospf6_process_lsreq}, - {ospf6_process_lsupdate}, - {ospf6_process_lsack} -}; - -/* process ospf6 protocol header. then, call next process function - for each message type */ -static void -ospf6_message_process (struct iovec *message, - struct in6_addr *src, - struct in6_addr *dst, - struct ospf6_interface *o6i) +int +ospf6_hello_send (struct thread *thread) { - struct ospf6_header *ospf6_header = NULL; - u_char type; - u_int32_t router_id; - char srcname[64]; - - assert (o6i); - assert (src); - assert (dst); + struct ospf6_interface *oi; + struct ospf6_header *oh; + struct ospf6_hello *hello; + char *p; + listnode node; + struct ospf6_neighbor *on; - /* set ospf6_hdr pointer to head of buffer */ - ospf6_header = (struct ospf6_header *) message[0].iov_base; + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_send_hello = (struct thread *) NULL; - /* version check */ - if (ospf6_header->version != OSPF6_VERSION) + if (oi->state <= OSPF6_INTERFACE_DOWN) { - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("version mismatch, drop"); - return; + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) + zlog_info ("Unable to send Hello on down interface %s", + oi->interface->name); + return 0; } - /* area id check */ - if (ospf6_header->area_id != o6i->area->area_id) - { - if (ospf6_header->area_id == 0) - { - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("virtual link not yet, drop"); - return; - } + /* set next thread */ + oi->thread_send_hello = thread_add_timer (master, ospf6_hello_send, + oi, oi->hello_interval); - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("area id mismatch, drop"); - return; - } + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; + hello = (struct ospf6_hello *)((caddr_t) oh + sizeof (struct ospf6_header)); - /* instance id check */ - if (ospf6_header->instance_id != o6i->instance_id) - { - if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type)) - zlog_info ("instance id mismatch, drop"); - return; - } + hello->interface_id = htonl (oi->interface->ifindex); + hello->priority = oi->priority; + hello->options[0] = oi->area->options[0]; + hello->options[1] = oi->area->options[1]; + hello->options[2] = oi->area->options[2]; + hello->hello_interval = htons (oi->hello_interval); + hello->dead_interval = htons (oi->dead_interval); + hello->drouter = oi->drouter; + hello->bdrouter = oi->bdrouter; - /* message type check */ - type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ? - OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type); + p = (char *)((caddr_t) hello + sizeof (struct ospf6_hello)); - /* log */ - if (IS_OSPF6_DUMP_MESSAGE (type)) + for (node = listhead (oi->neighbor_list); node; nextnode (node)) { - char srcname[64], dstname[64]; - inet_ntop (AF_INET6, dst, dstname, sizeof (dstname)); - inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); - zlog_info ("Receive %s on %s", - ospf6_message_type_string[type], o6i->interface->name); - zlog_info (" %s -> %s", srcname, dstname); - ospf6_message_log (message); - } + on = (struct ospf6_neighbor *) getdata (node); - /* router id check */ - router_id = ospf6_header->router_id; - if (ospf6_header->router_id == o6i->area->ospf6->router_id) - { - inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); - zlog_warn ("*** Router-ID mismatch: from %s on %s", - srcname, o6i->interface->name); - return; - } + if (on->state < OSPF6_NEIGHBOR_INIT) + continue; + + if (p - sendbuf + sizeof (u_int32_t) > oi->ifmtu) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) + zlog_info ("sending Hello message: exceeds I/F MTU"); + break; + } - /* octet statistics relies on some asumption: - on ethernet, no IPv6 Extention header, etc */ -#define OSPF6_IP6_HEADER_SIZE 40 -#define OSPF6_ETHER_HEADER_SIZE 14 - o6i->message_stat[type].recv++; - o6i->message_stat[type].recv_octet += ntohs (ospf6_header->len) - + OSPF6_IP6_HEADER_SIZE + OSPF6_ETHER_HEADER_SIZE; + memcpy (p, &on->router_id, sizeof (u_int32_t)); + p += sizeof (u_int32_t); + } - /* futher process */ - (*ospf6_message_process_type[type].process) (&message[0], src, dst, o6i, router_id); + oh->type = OSPF6_MESSAGE_TYPE_HELLO; + oh->length = htons (p - sendbuf); - return; + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + return 0; } int -ospf6_receive (struct thread *thread) +ospf6_dbdesc_send (struct thread *thread) { - int sockfd; - struct in6_addr src, dst; - unsigned int ifindex; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_header ospf6_header; - char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE]; - struct ospf6_interface *o6i; - unsigned char type; + struct ospf6_neighbor *on; + struct ospf6_header *oh; + struct ospf6_dbdesc *dbdesc; + char *p; + struct ospf6_lsa *lsa; - /* get socket */ - sockfd = THREAD_FD (thread); + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_dbdesc = (struct thread *) NULL; - /* add next read thread */ - thread_add_read (master, ospf6_receive, NULL, sockfd); + if (on->state < OSPF6_NEIGHBOR_EXSTART) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_DBDESC, SEND)) + zlog_info ("Quit to send DbDesc to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); + return 0; + } - /* initialize */ - OSPF6_MESSAGE_CLEAR (message); - memset (&ospf6_header, 0, sizeof (struct ospf6_header)); + /* set next thread if master */ + if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) + on->thread_send_dbdesc = + thread_add_timer (master, ospf6_dbdesc_send, on, + on->ospf6_if->rxmt_interval); - OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header)); - OSPF6_MESSAGE_ATTACH (message, buffer, OSPF6_MESSAGE_RECEIVE_BUFSIZE); + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; + dbdesc = (struct ospf6_dbdesc *)((caddr_t) oh + + sizeof (struct ospf6_header)); - /* receive message */ - ospf6_recvmsg (&src, &dst, &ifindex, message); + /* if this is initial one, initialize sequence number for DbDesc */ + if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT)) + { + struct timeval tv; + if (gettimeofday (&tv, (struct timezone *) NULL) < 0) + tv.tv_sec = 1; + on->dbdesc_seqnum = tv.tv_sec; + } + + dbdesc->options[0] = on->ospf6_if->area->options[0]; + dbdesc->options[1] = on->ospf6_if->area->options[1]; + dbdesc->options[2] = on->ospf6_if->area->options[2]; + dbdesc->ifmtu = htons (on->ospf6_if->ifmtu); + dbdesc->bits = on->dbdesc_bits; + dbdesc->seqnum = htonl (on->dbdesc_seqnum); - type = (OSPF6_MESSAGE_TYPE_UNKNOWN < ospf6_header.type && - ospf6_header.type <= OSPF6_MESSAGE_TYPE_LSACK ? - ospf6_header.type : OSPF6_MESSAGE_TYPE_UNKNOWN); - o6i = ospf6_interface_lookup_by_index (ifindex); - if (!o6i || !o6i->area) + /* if this is not initial one, set LSA headers in dbdesc */ + p = (char *)((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); + if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT)) { - //zlog_warn ("*** received interface ospf6 disabled"); - return 0; + for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > + on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; + } + memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); + p += sizeof (struct ospf6_lsa_header); + } } - /* if not passive, process message */ - if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE)) - ospf6_message_process (message, &src, &dst, o6i); - else if (IS_OSPF6_DUMP_MESSAGE (type)) - zlog_info ("Ignore message on passive interface %s", - o6i->interface->name); + oh->type = OSPF6_MESSAGE_TYPE_DBDESC; + oh->length = htons (p - sendbuf); + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); return 0; } - -/* send section */ int -ospf6_message_length (struct iovec *message) +ospf6_dbdesc_send_newone (struct thread *thread) { - int i, length = 0; - for (i = 0; i < OSPF6_MESSAGE_IOVEC_SIZE; i++) + struct ospf6_neighbor *on; + struct ospf6_lsa *lsa; + unsigned int size = 0; + + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + if (IS_OSPF6_DEBUG_LSA (DATABASE)) + zlog_info ("Remove entire dbdesc_list of %s: sending newone", on->name); + ospf6_lsdb_remove_all (on->dbdesc_list); + + /* move LSAs from summary_list to dbdesc_list (within neighbor structure) + so that ospf6_send_dbdesc () can send those LSAs */ + size = sizeof (struct ospf6_lsa_header) + sizeof (struct ospf6_dbdesc); + for (lsa = ospf6_lsdb_head (on->summary_list); lsa; + lsa = ospf6_lsdb_next (lsa)) { - if (message[i].iov_base == NULL && message[i].iov_len == 0) - break; - length += message[i].iov_len; - } - return length; -} -#define OSPF6_MESSAGE_LENGTH(msg) \ -(ospf6_message_length (msg)) - -void -ospf6_message_send (unsigned char type, struct iovec *msg, - struct in6_addr *dst, u_int ifindex) -{ - struct ospf6_interface *o6i; - struct ospf6_header ospf6_header; - char dst_name[64], src_name[64]; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - int msg_len; - - /* ospf6 interface lookup */ - o6i = ospf6_interface_lookup_by_index (ifindex); - assert (o6i); - - msg_len = OSPF6_MESSAGE_LENGTH (msg); - - /* I/F MTU check */ -#if 0 - if (msg_len + sizeof (struct ospf6_header) >= o6i->interface->mtu) -#else - if (msg_len + sizeof (struct ospf6_header) >= o6i->ifmtu) -#endif - { - /* If Interface MTU is 0, save the case - since zebra had been failed to get MTU from Kernel */ - if (o6i->interface->mtu != 0) - { - zlog_warn ("Message: Send failed on %s: exceeds I/F MTU", - o6i->interface->name); - zlog_warn ("Message: while sending %s: Len:%d MTU:%d", - ospf6_message_type_string[type], - msg_len + sizeof (struct ospf6_header), - o6i->ifmtu); - return; - } - else + if (size + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu) { - zlog_warn ("Message: I/F MTU check ignored on %s", - o6i->interface->name); + ospf6_lsa_unlock (lsa); + break; } + + if (IS_OSPF6_DEBUG_LSA (DATABASE)) + zlog_info ("Move %s from summary_list to dbdesc_list of %s", + lsa->name, on->name); + ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->dbdesc_list); + ospf6_lsdb_remove (lsa, on->summary_list); + size += sizeof (struct ospf6_lsa_header); } - /* Initialize */ - OSPF6_MESSAGE_CLEAR (message); + if (on->summary_list->count == 0) + UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); - /* set OSPF header */ - memset (&ospf6_header, 0, sizeof (ospf6_header)); - ospf6_header.version = OSPF6_VERSION; - ospf6_header.type = type; - ospf6_header.len = htons (msg_len + sizeof (struct ospf6_header)); - ospf6_header.router_id = ospf6->router_id; - ospf6_header.area_id = o6i->area->area_id; - /* checksum is calculated by kernel */ - ospf6_header.instance_id = o6i->instance_id; - ospf6_header.reserved = 0; - OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header)); + /* If slave, More bit check must be done here */ + if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */ + ! CHECK_FLAG (on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) && + ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) + thread_add_event (master, exchange_done, on, 0); - /* Attach rest to message */ - OSPF6_MESSAGE_JOIN (message, msg); + thread_execute (master, ospf6_dbdesc_send, on, 0); + return 0; +} - /* statistics */ - if (type >= OSPF6_MESSAGE_TYPE_MAX) - type = OSPF6_MESSAGE_TYPE_UNKNOWN; - o6i->message_stat[type].send++; - o6i->message_stat[type].send_octet += ntohs (ospf6_header.len); +int +ospf6_lsreq_send (struct thread *thread) +{ + struct ospf6_neighbor *on; + struct ospf6_header *oh; + struct ospf6_lsreq_entry *e; + char *p; + struct ospf6_lsa *lsa; - /* log */ - if (IS_OSPF6_DUMP_MESSAGE (type)) + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_lsreq = (struct thread *) NULL; + + /* LSReq will be sent only in ExStart or Loading */ + if (on->state != OSPF6_NEIGHBOR_EXCHANGE && + on->state != OSPF6_NEIGHBOR_LOADING) { - inet_ntop (AF_INET6, dst, dst_name, sizeof (dst_name)); - if (o6i->lladdr) - inet_ntop (AF_INET6, o6i->lladdr, src_name, sizeof (src_name)); - else - strcpy (src_name, "Unknown"); - zlog_info ("Send %s on %s", - ospf6_message_type_string[type], o6i->interface->name); - zlog_info (" %s -> %s", src_name, dst_name); - ospf6_message_log (message); + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSREQ, SEND)) + zlog_info ("Quit to send LSReq to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); + return 0; } - /* send message */ - ospf6_sendmsg (o6i->lladdr, dst, &ifindex, message); -} - - -int -ospf6_send_hello (struct thread *thread) -{ - listnode n; - struct ospf6_interface *o6i; - struct ospf6_neighbor *o6n; - struct in6_addr dst; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_hello hello; - char router_buffer[1024]; /* xxx */ - u_int router_size; - - /* which ospf6 interface to send */ - o6i = (struct ospf6_interface *) THREAD_ARG (thread); - o6i->thread_send_hello = (struct thread *) NULL; - - /* assure interface is up */ - if (o6i->state <= IFS_DOWN) - { - if (IS_OSPF6_DUMP_HELLO) - zlog_warn ("Send HELLO Failed: Interface not enabled: %s", - o6i->interface->name); + /* schedule loading_done if request list is empty */ + if (on->request_list->count == 0) + { + thread_add_event (master, loading_done, on, 0); return 0; } - /* clear message buffer */ - OSPF6_MESSAGE_CLEAR (message); + /* set next thread */ + on->thread_send_lsreq = + thread_add_timer (master, ospf6_lsreq_send, on, + on->ospf6_if->rxmt_interval); - /* set Hello fields */ - hello.interface_id = htonl (o6i->if_id); - hello.rtr_pri = o6i->priority; - memcpy (hello.options, o6i->area->options, sizeof (hello.options)); - hello.hello_interval = htons (o6i->hello_interval); - hello.router_dead_interval = htons (o6i->dead_interval); - hello.dr = o6i->dr; - hello.bdr = o6i->bdr; - OSPF6_MESSAGE_ATTACH (message, &hello, sizeof (struct ospf6_hello)); + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; - /* set neighbor router id */ - router_size = 0; - for (n = listhead (o6i->neighbor_list); n; nextnode (n)) + /* set Request entries in lsreq */ + p = (char *)((caddr_t) oh + sizeof (struct ospf6_header)); + for (lsa = ospf6_lsdb_head (on->request_list); lsa; + lsa = ospf6_lsdb_next (lsa)) { - o6n = (struct ospf6_neighbor *) getdata (n); - - if (o6n->state < NBS_INIT) - continue; - - if (router_size + sizeof (o6n->router_id) > sizeof (router_buffer)) + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > on->ospf6_if->ifmtu) { - zlog_warn ("Send HELLO: Buffer shortage on %s", - o6i->interface->name); + ospf6_lsa_unlock (lsa); break; } - /* Copy Router-ID to Buffer */ - memcpy (router_buffer + router_size, &o6n->router_id, - sizeof (o6n->router_id)); - router_size += sizeof (o6n->router_id); + e = (struct ospf6_lsreq_entry *) p; + e->type = lsa->header->type; + e->id = lsa->header->id; + e->adv_router = lsa->header->adv_router; + p += sizeof (struct ospf6_lsreq_entry); } - OSPF6_MESSAGE_ATTACH (message, router_buffer, router_size); - /* set destionation */ - inet_pton (AF_INET6, ALLSPFROUTERS6, &dst); - - /* send hello */ - ospf6_message_send (OSPF6_MESSAGE_TYPE_HELLO, message, &dst, - o6i->interface->ifindex); - - /* set next timer thread */ - o6i->thread_send_hello = thread_add_timer (master, ospf6_send_hello, - o6i, o6i->hello_interval); + oh->type = OSPF6_MESSAGE_TYPE_LSREQ; + oh->length = htons (p - sendbuf); + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); return 0; } -void -ospf6_dbdesc_seqnum_init (struct ospf6_neighbor *o6n) -{ - struct timeval tv; - - if (gettimeofday (&tv, (struct timezone *) NULL) < 0) - tv.tv_sec = 1; - - o6n->dbdesc_seqnum = tv.tv_sec; - - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("set dbdesc seqnum %d for %s", o6n->dbdesc_seqnum, o6n->str); -} - int -ospf6_send_dbdesc_rxmt (struct thread *thread) +ospf6_lsupdate_send_neighbor (struct thread *thread) { - struct ospf6_lsdb_node node; - struct ospf6_neighbor *o6n; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_neighbor *on; + struct ospf6_header *oh; + struct ospf6_lsupdate *lsupdate; + char *p; + int num; struct ospf6_lsa *lsa; - struct ospf6_lsa_header *lsa_header; - struct ospf6_dbdesc dbdesc; - o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); - assert (o6n); + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_lsupdate = (struct thread *) NULL; - /* clear thread */ - o6n->thread_rxmt_dbdesc = (struct thread *) NULL; + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_info ("Quit to send LSUpdate to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); + return 0; + } - /* if state less than ExStart, do nothing */ - if (o6n->state < NBS_EXSTART) + /* if we have nothing to send, return */ + if (on->lsupdate_list->count == 0 && + on->retrans_list->count == 0) return 0; - OSPF6_MESSAGE_CLEAR (message); + if (IS_OSPF6_DEBUG_LSA (SEND)) + zlog_info ("LSA Send to %s", on->name); + + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; + lsupdate = (struct ospf6_lsupdate *) + ((caddr_t) oh + sizeof (struct ospf6_header)); - /* set dbdesc */ - memcpy (dbdesc.options, o6n->ospf6_interface->area->options, - sizeof (dbdesc.options)); - dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu); - dbdesc.bits = o6n->dbdesc_bits; - dbdesc.seqnum = htonl (o6n->dbdesc_seqnum); - OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc)); + p = (char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + num = 0; - /* if this is not initial, set LSA summary to dbdesc */ - if (! DD_IS_IBIT_SET (o6n->dbdesc_bits)) + /* lsupdate_list lists those LSA which doesn't need to be + retransmitted. remove those from the list */ + for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; + lsa = ospf6_lsdb_next (lsa)) { - for (ospf6_lsdb_head (&node, o6n->dbdesc_list); - ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) + /* MTU check */ + if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > on->ospf6_if->ifmtu) { - lsa = node.lsa; + ospf6_lsa_unlock (lsa); + break; + } - /* xxx, no MTU check: no support for Dynamic MTU change */ + if (IS_OSPF6_DEBUG_LSA (SEND)) + ospf6_lsa_header_print (lsa); - /* set age and add InfTransDelay */ - ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); + p += OSPF6_LSA_SIZE (lsa->header); + num++; - /* set LSA summary to send buffer */ - lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr; - OSPF6_MESSAGE_ATTACH (message, lsa_header, - sizeof (struct ospf6_lsa_header)); + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, on->lsupdate_list); + } + + for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > on->ospf6_if->ifmtu) + { + ospf6_lsa_unlock (lsa); + break; } + + if (IS_OSPF6_DEBUG_LSA (SEND)) + ospf6_lsa_header_print (lsa); + + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); + p += OSPF6_LSA_SIZE (lsa->header); + num++; } - /* send dbdesc */ - ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr, - o6n->ospf6_interface->interface->ifindex); + lsupdate->lsa_number = htonl (num); + + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); - /* if master, set futher retransmission */ - if (DD_IS_MSBIT_SET (o6n->dbdesc_bits)) - o6n->thread_rxmt_dbdesc = - thread_add_timer (master, ospf6_send_dbdesc_rxmt, - o6n, o6n->ospf6_interface->rxmt_interval); + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); - /* statistics */ - o6n->ospf6_stat_retrans_dbdesc++; + if (on->lsupdate_list->count != 0 || + on->retrans_list->count != 0) + { + if (on->lsupdate_list->count != 0) + on->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); + else + on->thread_send_lsupdate = + thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, + on->ospf6_if->rxmt_interval); + } return 0; } int -ospf6_send_dbdesc (struct thread *thread) +ospf6_lsupdate_send_interface (struct thread *thread) { - struct ospf6_neighbor *o6n; + struct ospf6_interface *oi; + struct ospf6_header *oh; + struct ospf6_lsupdate *lsupdate; + char *p; + int num; struct ospf6_lsa *lsa; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_dbdesc dbdesc; - struct ospf6_lsdb_node node; - o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); - assert (o6n); + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_send_lsupdate = (struct thread *) NULL; - /* clear thread */ - o6n->thread_send_dbdesc = (struct thread *) NULL; - if (o6n->thread_rxmt_dbdesc) - thread_cancel (o6n->thread_rxmt_dbdesc); - o6n->thread_rxmt_dbdesc = (struct thread *) NULL; - - /* if state less than ExStart, do nothing */ - if (o6n->state < NBS_EXSTART) - return 0; - - OSPF6_MESSAGE_CLEAR (message); - OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc)); - - /* clear previous LSA summary sent */ - ospf6_lsdb_remove_all (o6n->dbdesc_list); - assert (o6n->dbdesc_list->count == 0); - - /* if this is not initial, set LSA summary to dbdesc */ - if (! DD_IS_IBIT_SET (o6n->dbdesc_bits)) + if (oi->state <= OSPF6_INTERFACE_WAITING) { - for (ospf6_lsdb_head (&node, o6n->summary_list); - ! ospf6_lsdb_is_end (&node); - ospf6_lsdb_next (&node)) - { - lsa = node.lsa; - - /* MTU check */ - if (OSPF6_MESSAGE_LENGTH (message) - + sizeof (struct ospf6_lsa_header) - + sizeof (struct ospf6_header) - > o6n->ospf6_interface->ifmtu) - break; + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) + zlog_info ("Quit to send LSUpdate to interface %s state %s", + oi->interface->name, ospf6_interface_state_str[oi->state]); + return 0; + } - /* debug */ - if (IS_OSPF6_DUMP_DBDESC) - zlog_info ("Include DbDesc: %s", lsa->str); + /* if we have nothing to send, return */ + if (oi->lsupdate_list->count == 0) + return 0; - /* attach to dbdesclist */ - ospf6_neighbor_dbdesc_add (lsa, o6n); - /* detach from summarylist */ - ospf6_neighbor_summary_remove (lsa, o6n); + if (IS_OSPF6_DEBUG_LSA (SEND)) + zlog_info ("LSA Send to %s", oi->interface->name); - /* set age and add InfTransDelay */ - ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; + lsupdate = (struct ospf6_lsupdate *)((caddr_t) oh + + sizeof (struct ospf6_header)); - /* set LSA summary to send buffer */ - OSPF6_MESSAGE_ATTACH (message, lsa->header, - sizeof (struct ospf6_lsa_header)); - } + p = (char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); + num = 0; - if (o6n->summary_list->count == 0) + for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > oi->ifmtu) { - /* Clear more bit */ - DD_MBIT_CLEAR (o6n->dbdesc_bits); - - /* slave must schedule ExchangeDone on sending, here */ - if (! DD_IS_MSBIT_SET (o6n->dbdesc_bits)) - { - if (! DD_IS_MBIT_SET (o6n->dbdesc_bits) && - ! DD_IS_MBIT_SET (o6n->last_dd.bits)) - thread_add_event (master, exchange_done, o6n, 0); - } + ospf6_lsa_unlock (lsa); + break; } - } - - /* if this is initial, set seqnum */ - if (DDBIT_IS_INITIAL (o6n->dbdesc_bits)) - ospf6_dbdesc_seqnum_init (o6n); - /* set dbdesc */ - memcpy (dbdesc.options, o6n->ospf6_interface->area->options, - sizeof (dbdesc.options)); - dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu); - dbdesc.bits = o6n->dbdesc_bits; - dbdesc.seqnum = htonl (o6n->dbdesc_seqnum); + if (IS_OSPF6_DEBUG_LSA (SEND)) + ospf6_lsa_header_print (lsa); - /* send dbdesc */ - ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr, - o6n->ospf6_interface->interface->ifindex); + ospf6_lsa_age_update_to_send (lsa, oi->transdelay); + memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); + p += OSPF6_LSA_SIZE (lsa->header); + num++; - /* if master, set retransmission */ - if (DD_IS_MSBIT_SET (o6n->dbdesc_bits)) - o6n->thread_rxmt_dbdesc = - thread_add_timer (master, ospf6_send_dbdesc_rxmt, - o6n, o6n->ospf6_interface->rxmt_interval); + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, oi->lsupdate_list); + } - /* statistics */ - o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC] += o6n->dbdesc_list->count; + lsupdate->lsa_number = htonl (num); - return 0; -} + oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; + oh->length = htons (p - sendbuf); -int -ospf6_send_lsreq_rxmt (struct thread *thread) -{ - struct ospf6_neighbor *o6n; + if (oi->state == OSPF6_INTERFACE_DR || + oi->state == OSPF6_INTERFACE_BDR) + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + else + ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); - o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); - assert (o6n); + if (oi->lsupdate_list->count > 0) + { + oi->thread_send_lsupdate = + thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); + } - o6n->thread_rxmt_lsreq = (struct thread *) NULL; - o6n->thread_send_lsreq = thread_add_event (master, ospf6_send_lsreq, o6n, 0); return 0; } int -ospf6_send_lsreq (struct thread *thread) +ospf6_lsack_send_neighbor (struct thread *thread) { - struct ospf6_neighbor *o6n; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_lsreq lsreq[OSPF6_MESSAGE_IOVEC_SIZE]; + struct ospf6_neighbor *on; + struct ospf6_header *oh; + char *p; struct ospf6_lsa *lsa; - struct ospf6_lsdb_node node; - int i; - - o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); - assert (o6n); - - /* LSReq will be send only in ExStart or Loading */ - if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING) - return 0; - /* clear thread */ - o6n->thread_send_lsreq = (struct thread *) NULL; - if (o6n->thread_rxmt_lsreq) - thread_cancel (o6n->thread_rxmt_lsreq); - o6n->thread_rxmt_lsreq = (struct thread *) NULL; + on = (struct ospf6_neighbor *) THREAD_ARG (thread); + on->thread_send_lsack = (struct thread *) NULL; - /* schedule loading_done if request list is empty */ - if (o6n->request_list->count == 0) + if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { - thread_add_event (master, loading_done, o6n, 0); + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) + zlog_info ("Quit to send LSAck to neighbor %s state %s", + on->name, ospf6_neighbor_state_str[on->state]); return 0; } - /* clear message buffer */ - OSPF6_MESSAGE_CLEAR (message); - - i = 0; - for (ospf6_lsdb_head (&node, o6n->request_list); - ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node)) - { - lsa = node.lsa; + /* if we have nothing to send, return */ + if (on->lsack_list->count == 0) + return 0; - /* Buffer Overflow */ - if (i >= OSPF6_MESSAGE_IOVEC_SIZE) - break; + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; - /* I/F MTU check */ - if (OSPF6_MESSAGE_LENGTH (message) - + sizeof (struct ospf6_lsreq) - + sizeof (struct ospf6_header) - > o6n->ospf6_interface->ifmtu) - break; + p = (char *)((caddr_t) oh + sizeof (struct ospf6_header)); - lsreq[i].mbz = 0; - lsreq[i].type = lsa->header->type; - lsreq[i].id = lsa->header->id; - lsreq[i].adv_router = lsa->header->adv_router; + for (lsa = ospf6_lsdb_head (on->lsack_list); lsa; + lsa = ospf6_lsdb_next (lsa)) + { + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu) + { + /* if we run out of packet size/space here, + better to try again soon. */ + THREAD_OFF (on->thread_send_lsack); + on->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); - OSPF6_MESSAGE_ATTACH (message, &lsreq[i], sizeof (struct ospf6_lsreq)); - i++; - } + ospf6_lsa_unlock (lsa); + break; + } - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSREQ, message, &o6n->hisaddr, - o6n->ospf6_interface->interface->ifindex); + ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); + memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); + p += sizeof (struct ospf6_lsa_header); - /* set retransmit thread */ - o6n->thread_rxmt_lsreq = - thread_add_timer (master, ospf6_send_lsreq_rxmt, - o6n, o6n->ospf6_interface->rxmt_interval); + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, on->lsack_list); + } - /* statistics */ - o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ] += i; + oh->type = OSPF6_MESSAGE_TYPE_LSACK; + oh->length = htons (p - sendbuf); + ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, + on->ospf6_if, oh); return 0; } -/* Send LSUpdate directly to the neighbor, from his retransmission list */ int -ospf6_send_lsupdate_rxmt (struct thread *thread) +ospf6_lsack_send_interface (struct thread *thread) { - struct ospf6_neighbor *o6n; - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_lsupdate lsupdate; + struct ospf6_interface *oi; + struct ospf6_header *oh; + char *p; struct ospf6_lsa *lsa; - struct ospf6_lsdb_node node; - o6n = (struct ospf6_neighbor *) THREAD_ARG (thread); - assert (o6n); + oi = (struct ospf6_interface *) THREAD_ARG (thread); + oi->thread_send_lsack = (struct thread *) NULL; - o6n->send_update = (struct thread *) NULL; + if (oi->state <= OSPF6_INTERFACE_WAITING) + { + if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) + zlog_info ("Quit to send LSAck to interface %s state %s", + oi->interface->name, ospf6_interface_state_str[oi->state]); + return 0; + } - if (o6n->ospf6_interface->state <= IFS_WAITING) - return -1; + /* if we have nothing to send, return */ + if (oi->lsack_list->count == 0) + return 0; - /* clear message buffer */ - OSPF6_MESSAGE_CLEAR (message); + memset (sendbuf, 0, sizeof (sendbuf)); + oh = (struct ospf6_header *) sendbuf; - /* set lsupdate header */ - lsupdate.lsupdate_num = 0; /* set gradually */ - OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate)); + p = (char *)((caddr_t) oh + sizeof (struct ospf6_header)); - /* for each LSA listed on retransmission-list */ - for (ospf6_lsdb_head (&node, o6n->retrans_list); - ! ospf6_lsdb_is_end (&node); - ospf6_lsdb_next (&node)) + for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa; + lsa = ospf6_lsdb_next (lsa)) { - lsa = node.lsa; + /* MTU check */ + if (p - sendbuf + sizeof (struct ospf6_lsa_header) > oi->ifmtu) + { + /* if we run out of packet size/space here, + better to try again soon. */ + THREAD_OFF (oi->thread_send_lsack); + oi->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_interface, oi, 0); - /* I/F MTU check */ - if (OSPF6_MESSAGE_LENGTH (message) - + sizeof (struct ospf6_lsupdate) - + sizeof (struct ospf6_header) - + ntohs (lsa->header->length) - > o6n->ospf6_interface->ifmtu) - break; + ospf6_lsa_unlock (lsa); + break; + } - ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); - OSPF6_MESSAGE_ATTACH (message, lsa->header, ntohs (lsa->header->length)); - lsupdate.lsupdate_num++; - } + ospf6_lsa_age_update_to_send (lsa, oi->transdelay); + memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); + p += sizeof (struct ospf6_lsa_header); - /* check and correct lsupdate */ - if (lsupdate.lsupdate_num == 0) - return 0; - lsupdate.lsupdate_num = htonl (lsupdate.lsupdate_num); + assert (lsa->lock == 2); + ospf6_lsdb_remove (lsa, oi->lsack_list); + } - if (IS_OSPF6_DUMP_LSUPDATE) - zlog_info ("MESSAGE: retrsnsmit LSUpdate to %s", o6n->str); + oh->type = OSPF6_MESSAGE_TYPE_LSACK; + oh->length = htons (p - sendbuf); - /* statistics */ - o6n->ospf6_stat_retrans_lsupdate++; + if (oi->state == OSPF6_INTERFACE_DR || + oi->state == OSPF6_INTERFACE_BDR) + ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); + else + ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, - &o6n->hisaddr, o6n->ospf6_interface->if_id); + if (oi->thread_send_lsack == NULL && oi->lsack_list->count > 0) + { + oi->thread_send_lsack = + thread_add_event (master, ospf6_lsack_send_interface, oi, 0); + } - o6n->send_update = thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n, - o6n->ospf6_interface->rxmt_interval); return 0; } -/* Send LSUpdate containing one LSA directly to the neighbor. - This is "implied acknowledgement" */ -void -ospf6_send_lsupdate_direct (struct ospf6_lsa *lsa, struct ospf6_neighbor *o6n) + +/* Commands */ +DEFUN (debug_ospf6_message, + debug_ospf6_message_cmd, + "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + ) { - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_lsupdate lsupdate; - int lsa_len; - - /* clear message buffer */ - OSPF6_MESSAGE_CLEAR (message); + unsigned char level = 0; + int type = 0; + int i; - /* set lsupdate header */ - lsupdate.lsupdate_num = ntohl (1); - OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate)); + assert (argc > 0); - /* set one LSA */ - lsa_len = ntohs (lsa->lsa_hdr->lsh_len); - ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay); - OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len); + /* check type */ + if (! strncmp (argv[0], "u", 1)) + type = OSPF6_MESSAGE_TYPE_UNKNOWN; + else if (! strncmp (argv[0], "h", 1)) + type = OSPF6_MESSAGE_TYPE_HELLO; + else if (! strncmp (argv[0], "d", 1)) + type = OSPF6_MESSAGE_TYPE_DBDESC; + else if (! strncmp (argv[0], "lsr", 3)) + type = OSPF6_MESSAGE_TYPE_LSREQ; + else if (! strncmp (argv[0], "lsu", 3)) + type = OSPF6_MESSAGE_TYPE_LSUPDATE; + else if (! strncmp (argv[0], "lsa", 3)) + type = OSPF6_MESSAGE_TYPE_LSACK; + else if (! strncmp (argv[0], "a", 1)) + type = OSPF6_MESSAGE_TYPE_ALL; + + if (argc == 1) + level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; + else if (! strncmp (argv[1], "s", 1)) + level = OSPF6_DEBUG_MESSAGE_SEND; + else if (! strncmp (argv[1], "r", 1)) + level = OSPF6_DEBUG_MESSAGE_RECV; + + if (type == OSPF6_MESSAGE_TYPE_ALL) + { + for (i = 0; i < 6; i++) + OSPF6_DEBUG_MESSAGE_ON (i, level); + } + else + OSPF6_DEBUG_MESSAGE_ON (type, level); - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &o6n->hisaddr, - o6n->ospf6_interface->if_id); + return CMD_SUCCESS; } -/* Send LSUpdate containing one LSA by multicast. - On non-broadcast link, send it to each neighbor by unicast. - This is ordinary flooding */ -void -ospf6_send_lsupdate_flood (struct ospf6_lsa *lsa, struct ospf6_interface *o6i) -{ - struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE]; - struct ospf6_lsupdate lsupdate; - struct in6_addr dst; - int lsa_len; - - /* clear message buffer */ - OSPF6_MESSAGE_CLEAR (message); +ALIAS (debug_ospf6_message, + debug_ospf6_message_sendrecv_cmd, + "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + "Debug only sending message\n" + "Debug only receiving message\n" + ); - /* set lsupdate header */ - lsupdate.lsupdate_num = ntohl (1); - OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate)); + +DEFUN (no_debug_ospf6_message, + no_debug_ospf6_message_cmd, + "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + ) +{ + unsigned char level = 0; + int type = 0; + int i; - /* set one LSA */ - lsa_len = ntohs (lsa->lsa_hdr->lsh_len); - ospf6_lsa_age_update_to_send (lsa, o6i->transdelay); - OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len); + assert (argc > 0); - if (if_is_broadcast (o6i->interface)) + /* check type */ + if (! strncmp (argv[0], "u", 1)) + type = OSPF6_MESSAGE_TYPE_UNKNOWN; + else if (! strncmp (argv[0], "h", 1)) + type = OSPF6_MESSAGE_TYPE_HELLO; + else if (! strncmp (argv[0], "d", 1)) + type = OSPF6_MESSAGE_TYPE_DBDESC; + else if (! strncmp (argv[0], "lsr", 3)) + type = OSPF6_MESSAGE_TYPE_LSREQ; + else if (! strncmp (argv[0], "lsu", 3)) + type = OSPF6_MESSAGE_TYPE_LSUPDATE; + else if (! strncmp (argv[0], "lsa", 3)) + type = OSPF6_MESSAGE_TYPE_LSACK; + else if (! strncmp (argv[0], "a", 1)) + type = OSPF6_MESSAGE_TYPE_ALL; + + if (argc == 1) + level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; + else if (! strncmp (argv[1], "s", 1)) + level = OSPF6_DEBUG_MESSAGE_SEND; + else if (! strncmp (argv[1], "r", 1)) + level = OSPF6_DEBUG_MESSAGE_RECV; + + if (type == OSPF6_MESSAGE_TYPE_ALL) { - /* set destination */ - if (o6i->state == IFS_DR || o6i->state == IFS_BDR) - inet_pton (AF_INET6, ALLSPFROUTERS6, &dst); - else - inet_pton (AF_INET6, ALLDROUTERS6, &dst); + for (i = 0; i < 6; i++) + OSPF6_DEBUG_MESSAGE_OFF (i, level); } else - { - /* IPv6 relies on link local multicast */ - inet_pton (AF_INET6, ALLSPFROUTERS6, &dst); - } + OSPF6_DEBUG_MESSAGE_OFF (type, level); - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &dst, - o6i->if_id); + return CMD_SUCCESS; } +ALIAS (no_debug_ospf6_message, + no_debug_ospf6_message_sendrecv_cmd, + "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug OSPFv3 message\n" + "Debug Unknown message\n" + "Debug Hello message\n" + "Debug Database Description message\n" + "Debug Link State Request message\n" + "Debug Link State Update message\n" + "Debug Link State Acknowledgement message\n" + "Debug All message\n" + "Debug only sending message\n" + "Debug only receiving message\n" + ); + int -ospf6_send_lsack_delayed (struct thread *thread) +config_write_ospf6_debug_message (struct vty *vty) { - struct ospf6_interface *o6i; - struct iovec message[MAXIOVLIST]; - struct ospf6_lsa *lsa; - struct ospf6_lsdb_node node; - - o6i = THREAD_ARG (thread); - assert (o6i); - - if (IS_OSPF6_DUMP_LSACK) - zlog_info ("LSACK: Delayed LSAck for %s\n", o6i->interface->name); - - o6i->thread_send_lsack_delayed = (struct thread *) NULL; - - if (o6i->state <= IFS_WAITING) - return 0; - - if (o6i->ack_list->count == 0) - return 0; + char *type_str[] = {"unknown", "hello", "dbdesc", + "lsreq", "lsupdate", "lsack"}; + unsigned char s = 0, r = 0; + int i; - iov_clear (message, MAXIOVLIST); + for (i = 0; i < 6; i++) + { + if (IS_OSPF6_DEBUG_MESSAGE (i, SEND)) + s |= 1 << i; + if (IS_OSPF6_DEBUG_MESSAGE (i, RECV)) + r |= 1 << i; + } - for (ospf6_lsdb_head (&node, o6i->ack_list); - ! ospf6_lsdb_is_end (&node); - ospf6_lsdb_next (&node)) + if (s == 0x3f && r == 0x3f) { - lsa = node.lsa; - if (IS_OVER_MTU (message, o6i->ifmtu, sizeof (struct ospf6_lsa_hdr))) - break; + vty_out (vty, "debug ospf6 message all%s", VTY_NEWLINE); + return 0; + } - OSPF6_MESSAGE_ATTACH (message, lsa->header, - sizeof (struct ospf6_lsa_header)); - ospf6_interface_delayed_ack_remove (lsa, o6i); + if (s == 0x3f && r == 0) + { + vty_out (vty, "debug ospf6 message all send%s", VTY_NEWLINE); + return 0; + } + else if (s == 0 && r == 0x3f) + { + vty_out (vty, "debug ospf6 message all recv%s", VTY_NEWLINE); + return 0; } - /* statistics */ - o6i->ospf6_stat_delayed_lsack++; + /* Unknown message is logged by default */ + if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND) && + ! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + vty_out (vty, "no debug ospf6 message unknown%s", VTY_NEWLINE); + else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND)) + vty_out (vty, "no debug ospf6 message unknown send%s", VTY_NEWLINE); + else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) + vty_out (vty, "no debug ospf6 message unknown recv%s", VTY_NEWLINE); - switch (o6i->state) + for (i = 1; i < 6; i++) { - case IFS_DR: - case IFS_BDR: - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message, - &allspfrouters6.sin6_addr, o6i->if_id); - break; - default: - ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message, - &alldrouters6.sin6_addr, o6i->if_id); - break; + if (IS_OSPF6_DEBUG_MESSAGE (i, SEND) && + IS_OSPF6_DEBUG_MESSAGE (i, RECV)) + vty_out (vty, "debug ospf6 message %s%s", type_str[i], VTY_NEWLINE); + else if (IS_OSPF6_DEBUG_MESSAGE (i, SEND)) + vty_out (vty, "debug ospf6 message %s send%s", type_str[i], + VTY_NEWLINE); + else if (IS_OSPF6_DEBUG_MESSAGE (i, RECV)) + vty_out (vty, "debug ospf6 message %s recv%s", type_str[i], + VTY_NEWLINE); } - iov_clear (message, MAXIOVLIST); return 0; } +void +install_element_ospf6_debug_message () +{ + install_element (ENABLE_NODE, &debug_ospf6_message_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd); + install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd); + install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd); + install_element (CONFIG_NODE, &debug_ospf6_message_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd); + install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd); + install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd); +} + + -- cgit v1.2.1