#endif
/* Packet Type String. */
-const struct message ospf_packet_type_str[] =
-{
- { OSPF_MSG_HELLO, "Hello" },
- { OSPF_MSG_DB_DESC, "Database Description" },
- { OSPF_MSG_LS_REQ, "Link State Request" },
- { OSPF_MSG_LS_UPD, "Link State Update" },
- { OSPF_MSG_LS_ACK, "Link State Acknowledgment" },
- { 0 }
-};
+const struct message ospf_packet_type_str[] = {
+ {OSPF_MSG_HELLO, "Hello"},
+ {OSPF_MSG_DB_DESC, "Database Description"},
+ {OSPF_MSG_LS_REQ, "Link State Request"},
+ {OSPF_MSG_LS_UPD, "Link State Update"},
+ {OSPF_MSG_LS_ACK, "Link State Acknowledgment"},
+ {0}};
/* Minimum (besides OSPF_HEADER_SIZE) lengths for OSPF packets of
particular types, offset is the "type" field of a packet. */
-static const u_int16_t ospf_packet_minlen[] =
-{
- 0,
- OSPF_HELLO_MIN_SIZE,
- OSPF_DB_DESC_MIN_SIZE,
- OSPF_LS_REQ_MIN_SIZE,
- OSPF_LS_UPD_MIN_SIZE,
- OSPF_LS_ACK_MIN_SIZE,
+static const u_int16_t ospf_packet_minlen[] = {
+ 0,
+ OSPF_HELLO_MIN_SIZE,
+ OSPF_DB_DESC_MIN_SIZE,
+ OSPF_LS_REQ_MIN_SIZE,
+ OSPF_LS_UPD_MIN_SIZE,
+ OSPF_LS_ACK_MIN_SIZE,
};
/* Minimum (besides OSPF_LSA_HEADER_SIZE) lengths for LSAs of particular
types, offset is the "LSA type" field. */
-static const u_int16_t ospf_lsa_minlen[] =
-{
- 0,
- OSPF_ROUTER_LSA_MIN_SIZE,
- OSPF_NETWORK_LSA_MIN_SIZE,
- OSPF_SUMMARY_LSA_MIN_SIZE,
- OSPF_SUMMARY_LSA_MIN_SIZE,
- OSPF_AS_EXTERNAL_LSA_MIN_SIZE,
- 0,
- OSPF_AS_EXTERNAL_LSA_MIN_SIZE,
- 0,
- 0,
- 0,
- 0,
+static const u_int16_t ospf_lsa_minlen[] = {
+ 0,
+ OSPF_ROUTER_LSA_MIN_SIZE,
+ OSPF_NETWORK_LSA_MIN_SIZE,
+ OSPF_SUMMARY_LSA_MIN_SIZE,
+ OSPF_SUMMARY_LSA_MIN_SIZE,
+ OSPF_AS_EXTERNAL_LSA_MIN_SIZE,
+ 0,
+ OSPF_AS_EXTERNAL_LSA_MIN_SIZE,
+ 0,
+ 0,
+ 0,
+ 0,
};
/* for ospf_check_auth() */
-static int ospf_check_sum (struct ospf_header *);
+static int ospf_check_sum(struct ospf_header *);
/* OSPF authentication checking function */
-static int
-ospf_auth_type (struct ospf_interface *oi)
+static int ospf_auth_type(struct ospf_interface *oi)
{
- int auth_type;
+ int auth_type;
- if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET)
- auth_type = oi->area->auth_type;
- else
- auth_type = OSPF_IF_PARAM (oi, auth_type);
+ if (OSPF_IF_PARAM(oi, auth_type) == OSPF_AUTH_NOTSET)
+ auth_type = oi->area->auth_type;
+ else
+ auth_type = OSPF_IF_PARAM(oi, auth_type);
- /* Handle case where MD5 key list is not configured aka Cisco */
- if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC &&
- list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
- return OSPF_AUTH_NULL;
-
- return auth_type;
+ /* Handle case where MD5 key list is not configured aka Cisco */
+ if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC
+ && list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
+ return OSPF_AUTH_NULL;
+ return auth_type;
}
-struct ospf_packet *
-ospf_packet_new (size_t size)
+struct ospf_packet *ospf_packet_new(size_t size)
{
- struct ospf_packet *new;
+ struct ospf_packet *new;
- new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet));
- new->s = stream_new (size);
+ new = XCALLOC(MTYPE_OSPF_PACKET, sizeof(struct ospf_packet));
+ new->s = stream_new(size);
- return new;
+ return new;
}
-void
-ospf_packet_free (struct ospf_packet *op)
+void ospf_packet_free(struct ospf_packet *op)
{
- if (op->s)
- stream_free (op->s);
+ if (op->s)
+ stream_free(op->s);
- XFREE (MTYPE_OSPF_PACKET, op);
+ XFREE(MTYPE_OSPF_PACKET, op);
- op = NULL;
+ op = NULL;
}
-struct ospf_fifo *
-ospf_fifo_new ()
+struct ospf_fifo *ospf_fifo_new()
{
- struct ospf_fifo *new;
+ struct ospf_fifo *new;
- new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo));
- return new;
+ new = XCALLOC(MTYPE_OSPF_FIFO, sizeof(struct ospf_fifo));
+ return new;
}
/* Add new packet to fifo. */
-void
-ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op)
+void ospf_fifo_push(struct ospf_fifo *fifo, struct ospf_packet *op)
{
- if (fifo->tail)
- fifo->tail->next = op;
- else
- fifo->head = op;
+ if (fifo->tail)
+ fifo->tail->next = op;
+ else
+ fifo->head = op;
- fifo->tail = op;
+ fifo->tail = op;
- fifo->count++;
+ fifo->count++;
}
/* Add new packet to head of fifo. */
-static void
-ospf_fifo_push_head (struct ospf_fifo *fifo, struct ospf_packet *op)
+static void ospf_fifo_push_head(struct ospf_fifo *fifo, struct ospf_packet *op)
{
- op->next = fifo->head;
-
- if (fifo->tail == NULL)
- fifo->tail = op;
-
- fifo->head = op;
-
- fifo->count++;
+ op->next = fifo->head;
+
+ if (fifo->tail == NULL)
+ fifo->tail = op;
+
+ fifo->head = op;
+
+ fifo->count++;
}
/* Delete first packet from fifo. */
-struct ospf_packet *
-ospf_fifo_pop (struct ospf_fifo *fifo)
+struct ospf_packet *ospf_fifo_pop(struct ospf_fifo *fifo)
{
- struct ospf_packet *op;
+ struct ospf_packet *op;
- op = fifo->head;
+ op = fifo->head;
- if (op)
- {
- fifo->head = op->next;
+ if (op) {
+ fifo->head = op->next;
- if (fifo->head == NULL)
- fifo->tail = NULL;
+ if (fifo->head == NULL)
+ fifo->tail = NULL;
- fifo->count--;
- }
+ fifo->count--;
+ }
- return op;
+ return op;
}
/* Return first fifo entry. */
-struct ospf_packet *
-ospf_fifo_head (struct ospf_fifo *fifo)
+struct ospf_packet *ospf_fifo_head(struct ospf_fifo *fifo)
{
- return fifo->head;
+ return fifo->head;
}
/* Flush ospf packet fifo. */
-void
-ospf_fifo_flush (struct ospf_fifo *fifo)
+void ospf_fifo_flush(struct ospf_fifo *fifo)
{
- struct ospf_packet *op;
- struct ospf_packet *next;
+ struct ospf_packet *op;
+ struct ospf_packet *next;
- for (op = fifo->head; op; op = next)
- {
- next = op->next;
- ospf_packet_free (op);
- }
- fifo->head = fifo->tail = NULL;
- fifo->count = 0;
+ for (op = fifo->head; op; op = next) {
+ next = op->next;
+ ospf_packet_free(op);
+ }
+ fifo->head = fifo->tail = NULL;
+ fifo->count = 0;
}
/* Free ospf packet fifo. */
-void
-ospf_fifo_free (struct ospf_fifo *fifo)
+void ospf_fifo_free(struct ospf_fifo *fifo)
{
- ospf_fifo_flush (fifo);
+ ospf_fifo_flush(fifo);
- XFREE (MTYPE_OSPF_FIFO, fifo);
+ XFREE(MTYPE_OSPF_FIFO, fifo);
}
-void
-ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
+void ospf_packet_add(struct ospf_interface *oi, struct ospf_packet *op)
{
- if (!oi->obuf)
- {
- zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, "
- "destination %s) called with NULL obuf, ignoring "
- "(please report this bug)!\n",
- IF_NAME(oi), oi->state, lookup_msg(ospf_ism_state_msg, oi->state, NULL),
- lookup_msg(ospf_packet_type_str, stream_getc_from(op->s, 1), NULL),
- inet_ntoa (op->dst));
- return;
- }
+ if (!oi->obuf) {
+ zlog_err(
+ "ospf_packet_add(interface %s in state %d [%s], packet type %s, "
+ "destination %s) called with NULL obuf, ignoring "
+ "(please report this bug)!\n",
+ IF_NAME(oi), oi->state,
+ lookup_msg(ospf_ism_state_msg, oi->state, NULL),
+ lookup_msg(ospf_packet_type_str,
+ stream_getc_from(op->s, 1), NULL),
+ inet_ntoa(op->dst));
+ return;
+ }
- /* Add packet to end of queue. */
- ospf_fifo_push (oi->obuf, op);
+ /* Add packet to end of queue. */
+ ospf_fifo_push(oi->obuf, op);
- /* Debug of packet fifo*/
- /* ospf_fifo_debug (oi->obuf); */
+ /* Debug of packet fifo*/
+ /* ospf_fifo_debug (oi->obuf); */
}
-static void
-ospf_packet_add_top (struct ospf_interface *oi, struct ospf_packet *op)
+static void ospf_packet_add_top(struct ospf_interface *oi,
+ struct ospf_packet *op)
{
- if (!oi->obuf)
- {
- zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, "
- "destination %s) called with NULL obuf, ignoring "
- "(please report this bug)!\n",
- IF_NAME(oi), oi->state, lookup_msg(ospf_ism_state_msg, oi->state, NULL),
- lookup_msg(ospf_packet_type_str, stream_getc_from(op->s, 1), NULL),
- inet_ntoa (op->dst));
- return;
- }
+ if (!oi->obuf) {
+ zlog_err(
+ "ospf_packet_add(interface %s in state %d [%s], packet type %s, "
+ "destination %s) called with NULL obuf, ignoring "
+ "(please report this bug)!\n",
+ IF_NAME(oi), oi->state,
+ lookup_msg(ospf_ism_state_msg, oi->state, NULL),
+ lookup_msg(ospf_packet_type_str,
+ stream_getc_from(op->s, 1), NULL),
+ inet_ntoa(op->dst));
+ return;
+ }
- /* Add packet to head of queue. */
- ospf_fifo_push_head (oi->obuf, op);
+ /* Add packet to head of queue. */
+ ospf_fifo_push_head(oi->obuf, op);
- /* Debug of packet fifo*/
- /* ospf_fifo_debug (oi->obuf); */
+ /* Debug of packet fifo*/
+ /* ospf_fifo_debug (oi->obuf); */
}
-void
-ospf_packet_delete (struct ospf_interface *oi)
+void ospf_packet_delete(struct ospf_interface *oi)
{
- struct ospf_packet *op;
-
- op = ospf_fifo_pop (oi->obuf);
+ struct ospf_packet *op;
+
+ op = ospf_fifo_pop(oi->obuf);
- if (op)
- ospf_packet_free (op);
+ if (op)
+ ospf_packet_free(op);
}
-struct ospf_packet *
-ospf_packet_dup (struct ospf_packet *op)
+struct ospf_packet *ospf_packet_dup(struct ospf_packet *op)
{
- struct ospf_packet *new;
+ struct ospf_packet *new;
- if (stream_get_endp(op->s) != op->length)
- /* XXX size_t */
- zlog_warn ("ospf_packet_dup stream %lu ospf_packet %u size mismatch",
- (u_long)STREAM_SIZE(op->s), op->length);
+ if (stream_get_endp(op->s) != op->length)
+ /* XXX size_t */
+ zlog_warn(
+ "ospf_packet_dup stream %lu ospf_packet %u size mismatch",
+ (u_long)STREAM_SIZE(op->s), op->length);
- /* Reserve space for MD5 authentication that may be added later. */
- new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);
- stream_copy (new->s, op->s);
+ /* Reserve space for MD5 authentication that may be added later. */
+ new = ospf_packet_new(stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);
+ stream_copy(new->s, op->s);
- new->dst = op->dst;
- new->length = op->length;
+ new->dst = op->dst;
+ new->length = op->length;
- return new;
+ return new;
}
/* XXX inline */
-static unsigned int
-ospf_packet_authspace (struct ospf_interface *oi)
+static unsigned int ospf_packet_authspace(struct ospf_interface *oi)
{
- int auth = 0;
+ int auth = 0;
- if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
- auth = OSPF_AUTH_MD5_SIZE;
+ if (ospf_auth_type(oi) == OSPF_AUTH_CRYPTOGRAPHIC)
+ auth = OSPF_AUTH_MD5_SIZE;
- return auth;
+ return auth;
}
-static unsigned int
-ospf_packet_max (struct ospf_interface *oi)
+static unsigned int ospf_packet_max(struct ospf_interface *oi)
{
- int max;
+ int max;
- max = oi->ifp->mtu - ospf_packet_authspace(oi);
+ max = oi->ifp->mtu - ospf_packet_authspace(oi);
- max -= (OSPF_HEADER_SIZE + sizeof (struct ip));
+ max -= (OSPF_HEADER_SIZE + sizeof(struct ip));
- return max;
+ return max;
}
-static int
-ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh)
+static int ospf_check_md5_digest(struct ospf_interface *oi,
+ struct ospf_header *ospfh)
{
- MD5_CTX ctx;
- unsigned char digest[OSPF_AUTH_MD5_SIZE];
- struct crypt_key *ck;
- struct ospf_neighbor *nbr;
- u_int16_t length = ntohs (ospfh->length);
-
- /* Get secret key. */
- ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt),
- ospfh->u.crypt.key_id);
- if (ck == NULL)
- {
- zlog_warn ("interface %s: ospf_check_md5 no key %d",
- IF_NAME (oi), ospfh->u.crypt.key_id);
- return 0;
- }
+ MD5_CTX ctx;
+ unsigned char digest[OSPF_AUTH_MD5_SIZE];
+ struct crypt_key *ck;
+ struct ospf_neighbor *nbr;
+ u_int16_t length = ntohs(ospfh->length);
+
+ /* Get secret key. */
+ ck = ospf_crypt_key_lookup(OSPF_IF_PARAM(oi, auth_crypt),
+ ospfh->u.crypt.key_id);
+ if (ck == NULL) {
+ zlog_warn("interface %s: ospf_check_md5 no key %d", IF_NAME(oi),
+ ospfh->u.crypt.key_id);
+ return 0;
+ }
- /* check crypto seqnum. */
- nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id);
+ /* check crypto seqnum. */
+ nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &ospfh->router_id);
- if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum))
- {
- zlog_warn ("interface %s: ospf_check_md5 bad sequence %d (expect %d)",
- IF_NAME (oi),
- ntohl(ospfh->u.crypt.crypt_seqnum),
- ntohl(nbr->crypt_seqnum));
- return 0;
- }
-
- /* Generate a digest for the ospf packet - their digest + our digest. */
- memset(&ctx, 0, sizeof(ctx));
- MD5Init(&ctx);
- MD5Update(&ctx, ospfh, length);
- MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
- MD5Final(digest, &ctx);
+ if (nbr
+ && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) {
+ zlog_warn(
+ "interface %s: ospf_check_md5 bad sequence %d (expect %d)",
+ IF_NAME(oi), ntohl(ospfh->u.crypt.crypt_seqnum),
+ ntohl(nbr->crypt_seqnum));
+ return 0;
+ }
- /* compare the two */
- if (memcmp ((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE))
- {
- zlog_warn ("interface %s: ospf_check_md5 checksum mismatch",
- IF_NAME (oi));
- return 0;
- }
+ /* Generate a digest for the ospf packet - their digest + our digest. */
+ memset(&ctx, 0, sizeof(ctx));
+ MD5Init(&ctx);
+ MD5Update(&ctx, ospfh, length);
+ MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
+ MD5Final(digest, &ctx);
+
+ /* compare the two */
+ if (memcmp((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) {
+ zlog_warn("interface %s: ospf_check_md5 checksum mismatch",
+ IF_NAME(oi));
+ return 0;
+ }
- /* save neighbor's crypt_seqnum */
- if (nbr)
- nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
- return 1;
+ /* save neighbor's crypt_seqnum */
+ if (nbr)
+ nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
+ return 1;
}
/* This function is called from ospf_write(), it will detect the
authentication scheme and if it is MD5, it will change the sequence
and update the MD5 digest. */
-static int
-ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
-{
- struct ospf_header *ospfh;
- unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0};
- MD5_CTX ctx;
- void *ibuf;
- u_int32_t t;
- struct crypt_key *ck;
- const u_int8_t *auth_key;
-
- ibuf = STREAM_DATA (op->s);
- ospfh = (struct ospf_header *) ibuf;
-
- if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
- return 0;
-
- /* We do this here so when we dup a packet, we don't have to
- waste CPU rewriting other headers.
-
- Note that quagga_time /deliberately/ is not used here */
- t = (time(NULL) & 0xFFFFFFFF);
- if (t > oi->crypt_seqnum)
- oi->crypt_seqnum = t;
- else
- oi->crypt_seqnum++;
-
- ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum);
-
- /* Get MD5 Authentication key from auth_key list. */
- if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
- auth_key = (const u_int8_t *) digest;
- else
- {
- ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt)));
- auth_key = ck->auth_key;
- }
+static int ospf_make_md5_digest(struct ospf_interface *oi,
+ struct ospf_packet *op)
+{
+ struct ospf_header *ospfh;
+ unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0};
+ MD5_CTX ctx;
+ void *ibuf;
+ u_int32_t t;
+ struct crypt_key *ck;
+ const u_int8_t *auth_key;
+
+ ibuf = STREAM_DATA(op->s);
+ ospfh = (struct ospf_header *)ibuf;
+
+ if (ntohs(ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+ return 0;
+
+ /* We do this here so when we dup a packet, we don't have to
+ waste CPU rewriting other headers.
+
+ Note that quagga_time /deliberately/ is not used here */
+ t = (time(NULL) & 0xFFFFFFFF);
+ if (t > oi->crypt_seqnum)
+ oi->crypt_seqnum = t;
+ else
+ oi->crypt_seqnum++;
+
+ ospfh->u.crypt.crypt_seqnum = htonl(oi->crypt_seqnum);
+
+ /* Get MD5 Authentication key from auth_key list. */
+ if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt)))
+ auth_key = (const u_int8_t *)digest;
+ else {
+ ck = listgetdata(listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+ auth_key = ck->auth_key;
+ }
- /* Generate a digest for the entire packet + our secret key. */
- memset(&ctx, 0, sizeof(ctx));
- MD5Init(&ctx);
- MD5Update(&ctx, ibuf, ntohs (ospfh->length));
- MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
- MD5Final(digest, &ctx);
+ /* Generate a digest for the entire packet + our secret key. */
+ memset(&ctx, 0, sizeof(ctx));
+ MD5Init(&ctx);
+ MD5Update(&ctx, ibuf, ntohs(ospfh->length));
+ MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+ MD5Final(digest, &ctx);
- /* Append md5 digest to the end of the stream. */
- stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE);
+ /* Append md5 digest to the end of the stream. */
+ stream_put(op->s, digest, OSPF_AUTH_MD5_SIZE);
- /* We do *NOT* increment the OSPF header length. */
- op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE;
+ /* We do *NOT* increment the OSPF header length. */
+ op->length = ntohs(ospfh->length) + OSPF_AUTH_MD5_SIZE;
- if (stream_get_endp(op->s) != op->length)
- /* XXX size_t */
- zlog_warn("ospf_make_md5_digest: length mismatch stream %lu ospf_packet %u",
- (u_long)stream_get_endp(op->s), op->length);
+ if (stream_get_endp(op->s) != op->length)
+ /* XXX size_t */
+ zlog_warn(
+ "ospf_make_md5_digest: length mismatch stream %lu ospf_packet %u",
+ (u_long)stream_get_endp(op->s), op->length);
- return OSPF_AUTH_MD5_SIZE;
+ return OSPF_AUTH_MD5_SIZE;
}
-static int
-ospf_ls_req_timer (struct thread *thread)
+static int ospf_ls_req_timer(struct thread *thread)
{
- struct ospf_neighbor *nbr;
+ struct ospf_neighbor *nbr;
- nbr = THREAD_ARG (thread);
- nbr->t_ls_req = NULL;
+ nbr = THREAD_ARG(thread);
+ nbr->t_ls_req = NULL;
- /* Send Link State Request. */
- if (ospf_ls_request_count (nbr))
- ospf_ls_req_send (nbr);
+ /* Send Link State Request. */
+ if (ospf_ls_request_count(nbr))
+ ospf_ls_req_send(nbr);
- /* Set Link State Request retransmission timer. */
- OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
+ /* Set Link State Request retransmission timer. */
+ OSPF_NSM_TIMER_ON(nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
- return 0;
+ return 0;
}
-void
-ospf_ls_req_event (struct ospf_neighbor *nbr)
+void ospf_ls_req_event(struct ospf_neighbor *nbr)
{
- if (nbr->t_ls_req)
- {
- thread_cancel (nbr->t_ls_req);
- nbr->t_ls_req = NULL;
- }
- nbr->t_ls_req = NULL;
- thread_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req);
+ if (nbr->t_ls_req) {
+ thread_cancel(nbr->t_ls_req);
+ nbr->t_ls_req = NULL;
+ }
+ nbr->t_ls_req = NULL;
+ thread_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req);
}
/* Cyclic timer function. Fist registered in ospf_nbr_new () in
ospf_neighbor.c */
-int
-ospf_ls_upd_timer (struct thread *thread)
-{
- struct ospf_neighbor *nbr;
-
- nbr = THREAD_ARG (thread);
- nbr->t_ls_upd = NULL;
-
- /* Send Link State Update. */
- if (ospf_ls_retransmit_count (nbr) > 0)
- {
- struct list *update;
- struct ospf_lsdb *lsdb;
- int i;
- int retransmit_interval;
-
- retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval);
-
- lsdb = &nbr->ls_rxmt;
- update = list_new ();
+int ospf_ls_upd_timer(struct thread *thread)
+{
+ struct ospf_neighbor *nbr;
+
+ nbr = THREAD_ARG(thread);
+ nbr->t_ls_upd = NULL;
+
+ /* Send Link State Update. */
+ if (ospf_ls_retransmit_count(nbr) > 0) {
+ struct list *update;
+ struct ospf_lsdb *lsdb;
+ int i;
+ int retransmit_interval;
+
+ retransmit_interval =
+ OSPF_IF_PARAM(nbr->oi, retransmit_interval);
+
+ lsdb = &nbr->ls_rxmt;
+ update = list_new();
+
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
+ struct route_table *table = lsdb->type[i].db;
+ struct route_node *rn;
+
+ for (rn = route_top(table); rn; rn = route_next(rn)) {
+ struct ospf_lsa *lsa;
+
+ if ((lsa = rn->info) != NULL) {
+ /* Don't retransmit an LSA if we
+ received it within
+ the last RxmtInterval seconds - this
+ is to allow the
+ neighbour a chance to acknowledge the
+ LSA as it may
+ have ben just received before the
+ retransmit timer
+ fired. This is a small tweak to what
+ is in the RFC,
+ but it will cut out out a lot of
+ retransmit traffic
+ - MAG */
+ if (monotime_since(&lsa->tv_recv, NULL)
+ >= retransmit_interval * 1000000LL)
+ listnode_add(update, rn->info);
+ }
+ }
+ }
- for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
- {
- struct route_table *table = lsdb->type[i].db;
- struct route_node *rn;
-
- for (rn = route_top (table); rn; rn = route_next (rn))
- {
- struct ospf_lsa *lsa;
-
- if ((lsa = rn->info) != NULL)
- {
- /* Don't retransmit an LSA if we received it within
- the last RxmtInterval seconds - this is to allow the
- neighbour a chance to acknowledge the LSA as it may
- have ben just received before the retransmit timer
- fired. This is a small tweak to what is in the RFC,
- but it will cut out out a lot of retransmit traffic
- - MAG */
- if (monotime_since (&lsa->tv_recv, NULL)
- >= retransmit_interval * 1000000LL)
- listnode_add (update, rn->info);
- }
- }
+ if (listcount(update) > 0)
+ ospf_ls_upd_send(nbr, update, OSPF_SEND_PACKET_DIRECT);
+ list_delete(update);
}
- if (listcount (update) > 0)
- ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT);
- list_delete (update);
- }
+ /* Set LS Update retransmission timer. */
+ OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
- /* Set LS Update retransmission timer. */
- OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
-
- return 0;
+ return 0;
}
-int
-ospf_ls_ack_timer (struct thread *thread)
+int ospf_ls_ack_timer(struct thread *thread)
{
- struct ospf_interface *oi;
+ struct ospf_interface *oi;
- oi = THREAD_ARG (thread);
- oi->t_ls_ack = NULL;
+ oi = THREAD_ARG(thread);
+ oi->t_ls_ack = NULL;
- /* Send Link State Acknowledgment. */
- if (listcount (oi->ls_ack) > 0)
- ospf_ls_ack_send_delayed (oi);
+ /* Send Link State Acknowledgment. */
+ if (listcount(oi->ls_ack) > 0)
+ ospf_ls_ack_send_delayed(oi);
- /* Set LS Ack timer. */
- OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
+ /* Set LS Ack timer. */
+ OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
- return 0;
+ return 0;
}
#ifdef WANT_OSPF_WRITE_FRAGMENT
-static void
-ospf_write_frags (int fd, struct ospf_packet *op, struct ip *iph,
- struct msghdr *msg, unsigned int maxdatasize,
- unsigned int mtu, int flags, u_char type)
+static void ospf_write_frags(int fd, struct ospf_packet *op, struct ip *iph,
+ struct msghdr *msg, unsigned int maxdatasize,
+ unsigned int mtu, int flags, u_char type)
{
#define OSPF_WRITE_FRAG_SHIFT 3
- u_int16_t offset;
- struct iovec *iovp;
- int ret;
-
- assert ( op->length == stream_get_endp(op->s) );
- assert (msg->msg_iovlen == 2);
-
- /* we can but try.
- *
- * SunOS, BSD and BSD derived kernels likely will clear ip_id, as
- * well as the IP_MF flag, making this all quite pointless.
- *
- * However, for a system on which IP_MF is left alone, and ip_id left
- * alone or else which sets same ip_id for each fragment this might
- * work, eg linux.
- *
- * XXX-TODO: It would be much nicer to have the kernel's use their
- * existing fragmentation support to do this for us. Bugs/RFEs need to
- * be raised against the various kernels.
- */
-
- /* set More Frag */
- iph->ip_off |= IP_MF;
-
- /* ip frag offset is expressed in units of 8byte words */
- offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT;
-
- iovp = &msg->msg_iov[1];
-
- while ( (stream_get_endp(op->s) - stream_get_getp (op->s))
- > maxdatasize )
- {
- /* data length of this frag is to next offset value */
- iovp->iov_len = offset << OSPF_WRITE_FRAG_SHIFT;
- iph->ip_len = iovp->iov_len + sizeof (struct ip);
- assert (iph->ip_len <= mtu);
-
- sockopt_iphdrincl_swab_htosys (iph);
-
- ret = sendmsg (fd, msg, flags);
-
- sockopt_iphdrincl_swab_systoh (iph);
-
- if (ret < 0)
- zlog_warn ("*** ospf_write_frags: sendmsg failed to %s,"
- " id %d, off %d, len %d, mtu %u failed with %s",
- inet_ntoa (iph->ip_dst),
- iph->ip_id,
- iph->ip_off,
- iph->ip_len,
- mtu,
- safe_strerror (errno));
-
- if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
- {
- zlog_debug ("ospf_write_frags: sent id %d, off %d, len %d to %s\n",
- iph->ip_id, iph->ip_off, iph->ip_len,
- inet_ntoa (iph->ip_dst));
- if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
- {
- zlog_debug ("-----------------IP Header Dump----------------------");
- ospf_ip_header_dump (iph);
- zlog_debug ("-----------------------------------------------------");
- }
- }
-
- iph->ip_off += offset;
- stream_forward_getp (op->s, iovp->iov_len);
- iovp->iov_base = STREAM_PNT (op->s);
- }
-
- /* setup for final fragment */
- iovp->iov_len = stream_get_endp(op->s) - stream_get_getp (op->s);
- iph->ip_len = iovp->iov_len + sizeof (struct ip);
- iph->ip_off &= (~IP_MF);
+ u_int16_t offset;
+ struct iovec *iovp;
+ int ret;
+
+ assert(op->length == stream_get_endp(op->s));
+ assert(msg->msg_iovlen == 2);
+
+ /* we can but try.
+ *
+ * SunOS, BSD and BSD derived kernels likely will clear ip_id, as
+ * well as the IP_MF flag, making this all quite pointless.
+ *
+ * However, for a system on which IP_MF is left alone, and ip_id left
+ * alone or else which sets same ip_id for each fragment this might
+ * work, eg linux.
+ *
+ * XXX-TODO: It would be much nicer to have the kernel's use their
+ * existing fragmentation support to do this for us. Bugs/RFEs need to
+ * be raised against the various kernels.
+ */
+
+ /* set More Frag */
+ iph->ip_off |= IP_MF;
+
+ /* ip frag offset is expressed in units of 8byte words */
+ offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT;
+
+ iovp = &msg->msg_iov[1];
+
+ while ((stream_get_endp(op->s) - stream_get_getp(op->s))
+ > maxdatasize) {
+ /* data length of this frag is to next offset value */
+ iovp->iov_len = offset << OSPF_WRITE_FRAG_SHIFT;
+ iph->ip_len = iovp->iov_len + sizeof(struct ip);
+ assert(iph->ip_len <= mtu);
+
+ sockopt_iphdrincl_swab_htosys(iph);
+
+ ret = sendmsg(fd, msg, flags);
+
+ sockopt_iphdrincl_swab_systoh(iph);
+
+ if (ret < 0)
+ zlog_warn(
+ "*** ospf_write_frags: sendmsg failed to %s,"
+ " id %d, off %d, len %d, mtu %u failed with %s",
+ inet_ntoa(iph->ip_dst), iph->ip_id, iph->ip_off,
+ iph->ip_len, mtu, safe_strerror(errno));
+
+ if (IS_DEBUG_OSPF_PACKET(type - 1, SEND)) {
+ zlog_debug(
+ "ospf_write_frags: sent id %d, off %d, len %d to %s\n",
+ iph->ip_id, iph->ip_off, iph->ip_len,
+ inet_ntoa(iph->ip_dst));
+ if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL)) {
+ zlog_debug(
+ "-----------------IP Header Dump----------------------");
+ ospf_ip_header_dump(iph);
+ zlog_debug(
+ "-----------------------------------------------------");
+ }
+ }
+
+ iph->ip_off += offset;
+ stream_forward_getp(op->s, iovp->iov_len);
+ iovp->iov_base = STREAM_PNT(op->s);
+ }
+
+ /* setup for final fragment */
+ iovp->iov_len = stream_get_endp(op->s) - stream_get_getp(op->s);
+ iph->ip_len = iovp->iov_len + sizeof(struct ip);
+ iph->ip_off &= (~IP_MF);
}
#endif /* WANT_OSPF_WRITE_FRAGMENT */
-static int
-ospf_write (struct thread *thread)
-{
- struct ospf *ospf = THREAD_ARG (thread);
- struct ospf_interface *oi;
- struct ospf_interface *last_serviced_oi = NULL;
- struct ospf_packet *op;
- struct sockaddr_in sa_dst;
- struct ip iph;
- struct msghdr msg;
- struct iovec iov[2];
- u_char type;
- int ret;
- int flags = 0;
- struct listnode *node;
+static int ospf_write(struct thread *thread)
+{
+ struct ospf *ospf = THREAD_ARG(thread);
+ struct ospf_interface *oi;
+ struct ospf_interface *last_serviced_oi = NULL;
+ struct ospf_packet *op;
+ struct sockaddr_in sa_dst;
+ struct ip iph;
+ struct msghdr msg;
+ struct iovec iov[2];
+ u_char type;
+ int ret;
+ int flags = 0;
+ struct listnode *node;
#ifdef WANT_OSPF_WRITE_FRAGMENT
- static u_int16_t ipid = 0;
- u_int16_t maxdatasize;
+ static u_int16_t ipid = 0;
+ u_int16_t maxdatasize;
#endif /* WANT_OSPF_WRITE_FRAGMENT */
+ /* $FRR indent$ */
+ /* clang-format off */
#define OSPF_WRITE_IPHL_SHIFT 2
- int pkt_count = 0;
-
- ospf->t_write = NULL;
+ int pkt_count = 0;
+
+ ospf->t_write = NULL;
- node = listhead (ospf->oi_write_q);
- assert (node);
- oi = listgetdata (node);
- assert (oi);
+ node = listhead(ospf->oi_write_q);
+ assert(node);
+ oi = listgetdata(node);
+ assert(oi);
#ifdef WANT_OSPF_WRITE_FRAGMENT
- /* seed ipid static with low order bits of time */
- if (ipid == 0)
- ipid = (time(NULL) & 0xffff);
+ /* seed ipid static with low order bits of time */
+ if (ipid == 0)
+ ipid = (time(NULL) & 0xffff);
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- while ((pkt_count < ospf->write_oi_count) && oi && (last_serviced_oi != oi))
- {
- /* If there is only packet in the queue, the oi is removed from
- write-q, so fix up the last interface that was serviced */
- if (last_serviced_oi == NULL) {
- last_serviced_oi = oi;
- }
- pkt_count++;
+ while ((pkt_count < ospf->write_oi_count) && oi
+ && (last_serviced_oi != oi)) {
+ /* If there is only packet in the queue, the oi is removed from
+ write-q, so fix up the last interface that was serviced */
+ if (last_serviced_oi == NULL) {
+ last_serviced_oi = oi;
+ }
+ pkt_count++;
#ifdef WANT_OSPF_WRITE_FRAGMENT
- /* convenience - max OSPF data per packet */
- maxdatasize = oi->ifp->mtu - sizeof (struct ip);
+ /* convenience - max OSPF data per packet */
+ maxdatasize = oi->ifp->mtu - sizeof(struct ip);
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- /* Get one packet from queue. */
- op = ospf_fifo_head (oi->obuf);
- assert (op);
- assert (op->length >= OSPF_HEADER_SIZE);
-
- if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS)
- || op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
- ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
-
- /* Rewrite the md5 signature & update the seq */
- ospf_make_md5_digest (oi, op);
-
- /* Retrieve OSPF packet type. */
- stream_set_getp (op->s, 1);
- type = stream_getc (op->s);
-
- /* reset get pointer */
- stream_set_getp (op->s, 0);
-
- memset (&iph, 0, sizeof (struct ip));
- memset (&sa_dst, 0, sizeof (sa_dst));
-
- sa_dst.sin_family = AF_INET;
+ /* Get one packet from queue. */
+ op = ospf_fifo_head(oi->obuf);
+ assert(op);
+ assert(op->length >= OSPF_HEADER_SIZE);
+
+ if (op->dst.s_addr == htonl(OSPF_ALLSPFROUTERS)
+ || op->dst.s_addr == htonl(OSPF_ALLDROUTERS))
+ ospf_if_ipmulticast(ospf, oi->address,
+ oi->ifp->ifindex);
+
+ /* Rewrite the md5 signature & update the seq */
+ ospf_make_md5_digest(oi, op);
+
+ /* Retrieve OSPF packet type. */
+ stream_set_getp(op->s, 1);
+ type = stream_getc(op->s);
+
+ /* reset get pointer */
+ stream_set_getp(op->s, 0);
+
+ memset(&iph, 0, sizeof(struct ip));
+ memset(&sa_dst, 0, sizeof(sa_dst));
+
+ sa_dst.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- sa_dst.sin_len = sizeof(sa_dst);
+ sa_dst.sin_len = sizeof(sa_dst);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- sa_dst.sin_addr = op->dst;
- sa_dst.sin_port = htons (0);
-
- /* Set DONTROUTE flag if dst is unicast. */
- if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
- if (!IN_MULTICAST (htonl (op->dst.s_addr)))
- flags = MSG_DONTROUTE;
-
- iph.ip_hl = sizeof (struct ip) >> OSPF_WRITE_IPHL_SHIFT;
- /* it'd be very strange for header to not be 4byte-word aligned but.. */
- if ( sizeof (struct ip)
- > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) )
- iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */
-
- iph.ip_v = IPVERSION;
- iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
- iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
+ sa_dst.sin_addr = op->dst;
+ sa_dst.sin_port = htons(0);
+
+ /* Set DONTROUTE flag if dst is unicast. */
+ if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ if (!IN_MULTICAST(htonl(op->dst.s_addr)))
+ flags = MSG_DONTROUTE;
+
+ iph.ip_hl = sizeof(struct ip) >> OSPF_WRITE_IPHL_SHIFT;
+ /* it'd be very strange for header to not be 4byte-word aligned
+ * but.. */
+ if (sizeof(struct ip)
+ > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT))
+ iph.ip_hl++; /* we presume sizeof struct ip cant
+ overflow ip_hl.. */
+
+ iph.ip_v = IPVERSION;
+ iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
+ iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
#if defined(__DragonFly__)
- /*
- * DragonFly's raw socket expects ip_len/ip_off in network byte order.
- */
- iph.ip_len = htons(iph.ip_len);
+ /*
+ * DragonFly's raw socket expects ip_len/ip_off in network byte
+ * order.
+ */
+ iph.ip_len = htons(iph.ip_len);
#endif
#ifdef WANT_OSPF_WRITE_FRAGMENT
- /* XXX-MT: not thread-safe at all..
- * XXX: this presumes this is only programme sending OSPF packets
- * otherwise, no guarantee ipid will be unique
- */
- iph.ip_id = ++ipid;
+ /* XXX-MT: not thread-safe at all..
+ * XXX: this presumes this is only programme sending OSPF
+ * packets
+ * otherwise, no guarantee ipid will be unique
+ */
+ iph.ip_id = ++ipid;
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- iph.ip_off = 0;
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- iph.ip_ttl = OSPF_VL_IP_TTL;
- else
- iph.ip_ttl = OSPF_IP_TTL;
- iph.ip_p = IPPROTO_OSPFIGP;
- iph.ip_sum = 0;
- iph.ip_src.s_addr = oi->address->u.prefix4.s_addr;
- iph.ip_dst.s_addr = op->dst.s_addr;
-
- memset (&msg, 0, sizeof (msg));
- msg.msg_name = (caddr_t) &sa_dst;
- msg.msg_namelen = sizeof (sa_dst);
- msg.msg_iov = iov;
- msg.msg_iovlen = 2;
- iov[0].iov_base = (char*)&iph;
- iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT;
- iov[1].iov_base = STREAM_PNT (op->s);
- iov[1].iov_len = op->length;
-
- /* Sadly we can not rely on kernels to fragment packets because of either
- * IP_HDRINCL and/or multicast destination being set.
- */
+ iph.ip_off = 0;
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ iph.ip_ttl = OSPF_VL_IP_TTL;
+ else
+ iph.ip_ttl = OSPF_IP_TTL;
+ iph.ip_p = IPPROTO_OSPFIGP;
+ iph.ip_sum = 0;
+ iph.ip_src.s_addr = oi->address->u.prefix4.s_addr;
+ iph.ip_dst.s_addr = op->dst.s_addr;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (caddr_t)&sa_dst;
+ msg.msg_namelen = sizeof(sa_dst);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ iov[0].iov_base = (char *)&iph;
+ iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT;
+ iov[1].iov_base = STREAM_PNT(op->s);
+ iov[1].iov_len = op->length;
+
+/* Sadly we can not rely on kernels to fragment packets because of either
+ * IP_HDRINCL and/or multicast destination being set.
+ */
#ifdef WANT_OSPF_WRITE_FRAGMENT
- if ( op->length > maxdatasize )
- ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize,
- oi->ifp->mtu, flags, type);
+ if (op->length > maxdatasize)
+ ospf_write_frags(ospf->fd, op, &iph, &msg, maxdatasize,
+ oi->ifp->mtu, flags, type);
#endif /* WANT_OSPF_WRITE_FRAGMENT */
- /* send final fragment (could be first) */
- sockopt_iphdrincl_swab_htosys (&iph);
- ret = sendmsg (ospf->fd, &msg, flags);
- sockopt_iphdrincl_swab_systoh (&iph);
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_write to %s, "
- "id %d, off %d, len %d, interface %s, mtu %u:",
- inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len,
- oi->ifp->name, oi->ifp->mtu);
-
- if (ret < 0)
- zlog_warn ("*** sendmsg in ospf_write failed to %s, "
- "id %d, off %d, len %d, interface %s, mtu %u: %s",
- inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len,
- oi->ifp->name, oi->ifp->mtu, safe_strerror (errno));
-
- /* Show debug sending packet. */
- if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
- {
- if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
- {
- zlog_debug ("-----------------------------------------------------");
- ospf_ip_header_dump (&iph);
- stream_set_getp (op->s, 0);
- ospf_packet_dump (op->s);
- }
-
- zlog_debug ("%s sent to [%s] via [%s].",
- lookup_msg(ospf_packet_type_str, type, NULL),
- inet_ntoa (op->dst),
- IF_NAME (oi));
-
- if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
- zlog_debug ("-----------------------------------------------------");
- }
-
- /* Now delete packet from queue. */
- ospf_packet_delete (oi);
-
- /* Move this interface to the tail of write_q to
- serve everyone in a round robin fashion */
- list_delete_node (ospf->oi_write_q, node);
- if (ospf_fifo_head (oi->obuf) == NULL)
- {
- oi->on_write_q = 0;
- last_serviced_oi = NULL;
- oi = NULL;
- }
- else
- {
- listnode_add (ospf->oi_write_q, oi);
- }
-
- /* Setup to service from the head of the queue again */
- if (!list_isempty (ospf->oi_write_q))
- {
- node = listhead (ospf->oi_write_q);
- assert (node);
- oi = listgetdata (node);
- assert (oi);
+ /* send final fragment (could be first) */
+ sockopt_iphdrincl_swab_htosys(&iph);
+ ret = sendmsg(ospf->fd, &msg, flags);
+ sockopt_iphdrincl_swab_systoh(&iph);
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "ospf_write to %s, "
+ "id %d, off %d, len %d, interface %s, mtu %u:",
+ inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off,
+ iph.ip_len, oi->ifp->name, oi->ifp->mtu);
+
+ if (ret < 0)
+ zlog_warn(
+ "*** sendmsg in ospf_write failed to %s, "
+ "id %d, off %d, len %d, interface %s, mtu %u: %s",
+ inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off,
+ iph.ip_len, oi->ifp->name, oi->ifp->mtu,
+ safe_strerror(errno));
+
+ /* Show debug sending packet. */
+ if (IS_DEBUG_OSPF_PACKET(type - 1, SEND)) {
+ if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL)) {
+ zlog_debug(
+ "-----------------------------------------------------");
+ ospf_ip_header_dump(&iph);
+ stream_set_getp(op->s, 0);
+ ospf_packet_dump(op->s);
+ }
+
+ zlog_debug("%s sent to [%s] via [%s].",
+ lookup_msg(ospf_packet_type_str, type, NULL),
+ inet_ntoa(op->dst), IF_NAME(oi));
+
+ if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL))
+ zlog_debug(
+ "-----------------------------------------------------");
+ }
+
+ /* Now delete packet from queue. */
+ ospf_packet_delete(oi);
+
+ /* Move this interface to the tail of write_q to
+ serve everyone in a round robin fashion */
+ list_delete_node(ospf->oi_write_q, node);
+ if (ospf_fifo_head(oi->obuf) == NULL) {
+ oi->on_write_q = 0;
+ last_serviced_oi = NULL;
+ oi = NULL;
+ } else {
+ listnode_add(ospf->oi_write_q, oi);
}
+
+ /* Setup to service from the head of the queue again */
+ if (!list_isempty(ospf->oi_write_q)) {
+ node = listhead(ospf->oi_write_q);
+ assert(node);
+ oi = listgetdata(node);
+ assert(oi);
+ }
+ }
+
+ /* If packets still remain in queue, call write thread. */
+ if (!list_isempty(ospf->oi_write_q)) {
+ ospf->t_write = NULL;
+ thread_add_write(master, ospf_write, ospf, ospf->fd,
+ &ospf->t_write);
}
-
- /* If packets still remain in queue, call write thread. */
- if (!list_isempty (ospf->oi_write_q)) {
- ospf->t_write = NULL;
- thread_add_write(master, ospf_write, ospf, ospf->fd, &ospf->t_write);
- }
- return 0;
+ return 0;
}
/* OSPF Hello message read -- RFC2328 Section 10.5. */
-static void
-ospf_hello (struct ip *iph, struct ospf_header *ospfh,
- struct stream * s, struct ospf_interface *oi, int size)
-{
- struct ospf_hello *hello;
- struct ospf_neighbor *nbr;
- int old_state;
- struct prefix p;
-
- /* increment statistics. */
- oi->hello_in++;
-
- hello = (struct ospf_hello *) STREAM_PNT (s);
-
- /* If Hello is myself, silently discard. */
- if (IPV4_ADDR_SAME (&ospfh->router_id, &oi->ospf->router_id))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- {
- zlog_debug ("ospf_header[%s/%s]: selforiginated, "
- "dropping.",
- lookup_msg(ospf_packet_type_str, ospfh->type, NULL),
- inet_ntoa (iph->ip_src));
- }
- return;
- }
-
- /* get neighbor prefix. */
- p.family = AF_INET;
- p.prefixlen = ip_masklen (hello->network_mask);
- p.u.prefix4 = iph->ip_src;
-
- /* Compare network mask. */
- /* Checking is ignored for Point-to-Point and Virtual link. */
- if (oi->type != OSPF_IFTYPE_POINTOPOINT
- && oi->type != OSPF_IFTYPE_VIRTUALLINK)
- if (oi->address->prefixlen != p.prefixlen)
- {
- zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch on %s (configured prefix length is %d, but hello packet indicates %d).",
- inet_ntoa(ospfh->router_id), IF_NAME(oi),
- (int)oi->address->prefixlen, (int)p.prefixlen);
- return;
- }
-
- /* Compare Router Dead Interval. */
- if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval))
- {
- zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch "
- "(expected %u, but received %u).",
- inet_ntoa(ospfh->router_id),
- OSPF_IF_PARAM(oi, v_wait), ntohl(hello->dead_interval));
- return;
- }
-
- /* Compare Hello Interval - ignored if fast-hellos are set. */
- if (OSPF_IF_PARAM (oi, fast_hello) == 0)
- {
- if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
- {
- zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch "
- "(expected %u, but received %u).",
- inet_ntoa(ospfh->router_id),
- OSPF_IF_PARAM(oi, v_hello), ntohs(hello->hello_interval));
- return;
- }
- }
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Packet %s [Hello:RECV]: Options %s",
- inet_ntoa (ospfh->router_id),
- ospf_options_dump (hello->options));
-
- /* Compare options. */
+static void ospf_hello(struct ip *iph, struct ospf_header *ospfh,
+ struct stream *s, struct ospf_interface *oi, int size)
+{
+ struct ospf_hello *hello;
+ struct ospf_neighbor *nbr;
+ int old_state;
+ struct prefix p;
+
+ /* increment statistics. */
+ oi->hello_in++;
+
+ hello = (struct ospf_hello *)STREAM_PNT(s);
+
+ /* If Hello is myself, silently discard. */
+ if (IPV4_ADDR_SAME(&ospfh->router_id, &oi->ospf->router_id)) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) {
+ zlog_debug(
+ "ospf_header[%s/%s]: selforiginated, "
+ "dropping.",
+ lookup_msg(ospf_packet_type_str, ospfh->type,
+ NULL),
+ inet_ntoa(iph->ip_src));
+ }
+ return;
+ }
+
+ /* get neighbor prefix. */
+ p.family = AF_INET;
+ p.prefixlen = ip_masklen(hello->network_mask);
+ p.u.prefix4 = iph->ip_src;
+
+ /* Compare network mask. */
+ /* Checking is ignored for Point-to-Point and Virtual link. */
+ if (oi->type != OSPF_IFTYPE_POINTOPOINT
+ && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ if (oi->address->prefixlen != p.prefixlen) {
+ zlog_warn(
+ "Packet %s [Hello:RECV]: NetworkMask mismatch on %s (configured prefix length is %d, but hello packet indicates %d).",
+ inet_ntoa(ospfh->router_id), IF_NAME(oi),
+ (int)oi->address->prefixlen, (int)p.prefixlen);
+ return;
+ }
+
+ /* Compare Router Dead Interval. */
+ if (OSPF_IF_PARAM(oi, v_wait) != ntohl(hello->dead_interval)) {
+ zlog_warn(
+ "Packet %s [Hello:RECV]: RouterDeadInterval mismatch "
+ "(expected %u, but received %u).",
+ inet_ntoa(ospfh->router_id), OSPF_IF_PARAM(oi, v_wait),
+ ntohl(hello->dead_interval));
+ return;
+ }
+
+ /* Compare Hello Interval - ignored if fast-hellos are set. */
+ if (OSPF_IF_PARAM(oi, fast_hello) == 0) {
+ if (OSPF_IF_PARAM(oi, v_hello)
+ != ntohs(hello->hello_interval)) {
+ zlog_warn(
+ "Packet %s [Hello:RECV]: HelloInterval mismatch "
+ "(expected %u, but received %u).",
+ inet_ntoa(ospfh->router_id),
+ OSPF_IF_PARAM(oi, v_hello),
+ ntohs(hello->hello_interval));
+ return;
+ }
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("Packet %s [Hello:RECV]: Options %s",
+ inet_ntoa(ospfh->router_id),
+ ospf_options_dump(hello->options));
+
+/* Compare options. */
#define REJECT_IF_TBIT_ON 1 /* XXX */
#ifdef REJECT_IF_TBIT_ON
- if (CHECK_FLAG (hello->options, OSPF_OPTION_MT))
- {
- /*
- * This router does not support non-zero TOS.
- * Drop this Hello packet not to establish neighbor relationship.
- */
- zlog_warn ("Packet %s [Hello:RECV]: T-bit on, drop it.",
- inet_ntoa (ospfh->router_id));
- return;
- }
+ if (CHECK_FLAG(hello->options, OSPF_OPTION_MT)) {
+ /*
+ * This router does not support non-zero TOS.
+ * Drop this Hello packet not to establish neighbor
+ * relationship.
+ */
+ zlog_warn("Packet %s [Hello:RECV]: T-bit on, drop it.",
+ inet_ntoa(ospfh->router_id));
+ return;
+ }
#endif /* REJECT_IF_TBIT_ON */
- if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)
- && CHECK_FLAG (hello->options, OSPF_OPTION_O))
- {
- /*
- * This router does know the correct usage of O-bit
- * the bit should be set in DD packet only.
- */
- zlog_warn ("Packet %s [Hello:RECV]: O-bit abuse?",
- inet_ntoa (ospfh->router_id));
+ if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)
+ && CHECK_FLAG(hello->options, OSPF_OPTION_O)) {
+ /*
+ * This router does know the correct usage of O-bit
+ * the bit should be set in DD packet only.
+ */
+ zlog_warn("Packet %s [Hello:RECV]: O-bit abuse?",
+ inet_ntoa(ospfh->router_id));
#ifdef STRICT_OBIT_USAGE_CHECK
- return; /* Reject this packet. */
-#else /* STRICT_OBIT_USAGE_CHECK */
- UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */
-#endif /* STRICT_OBIT_USAGE_CHECK */
- }
+ return; /* Reject this packet. */
+#else /* STRICT_OBIT_USAGE_CHECK */
+ UNSET_FLAG(hello->options, OSPF_OPTION_O); /* Ignore O-bit. */
+#endif /* STRICT_OBIT_USAGE_CHECK */
+ }
- /* new for NSSA is to ensure that NP is on and E is off */
+ /* new for NSSA is to ensure that NP is on and E is off */
+
+ if (oi->area->external_routing == OSPF_AREA_NSSA) {
+ if (!(CHECK_FLAG(OPTIONS(oi), OSPF_OPTION_NP)
+ && CHECK_FLAG(hello->options, OSPF_OPTION_NP)
+ && !CHECK_FLAG(OPTIONS(oi), OSPF_OPTION_E)
+ && !CHECK_FLAG(hello->options, OSPF_OPTION_E))) {
+ zlog_warn(
+ "NSSA-Packet-%s[Hello:RECV]: my options: %x, his options %x",
+ inet_ntoa(ospfh->router_id), OPTIONS(oi),
+ hello->options);
+ return;
+ }
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_debug("NSSA-Hello:RECV:Packet from %s:",
+ inet_ntoa(ospfh->router_id));
+ } else
+ /* The setting of the E-bit found in the Hello Packet's Options
+ field must match this area's ExternalRoutingCapability A
+ mismatch causes processing to stop and the packet to be
+ dropped. The setting of the rest of the bits in the Hello
+ Packet's Options field should be ignored. */
+ if (CHECK_FLAG(OPTIONS(oi), OSPF_OPTION_E)
+ != CHECK_FLAG(hello->options, OSPF_OPTION_E)) {
+ zlog_warn(
+ "Packet %s [Hello:RECV]: my options: %x, his options %x",
+ inet_ntoa(ospfh->router_id), OPTIONS(oi),
+ hello->options);
+ return;
+ }
- if (oi->area->external_routing == OSPF_AREA_NSSA)
- {
- if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP)
- && CHECK_FLAG (hello->options, OSPF_OPTION_NP)
- && ! CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E)
- && ! CHECK_FLAG (hello->options, OSPF_OPTION_E)))
- {
- zlog_warn ("NSSA-Packet-%s[Hello:RECV]: my options: %x, his options %x", inet_ntoa (ospfh->router_id), OPTIONS (oi), hello->options);
- return;
- }
- if (IS_DEBUG_OSPF_NSSA)
- zlog_debug ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id));
- }
- else
- /* The setting of the E-bit found in the Hello Packet's Options
- field must match this area's ExternalRoutingCapability A
- mismatch causes processing to stop and the packet to be
- dropped. The setting of the rest of the bits in the Hello
- Packet's Options field should be ignored. */
- if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) !=
- CHECK_FLAG (hello->options, OSPF_OPTION_E))
- {
- zlog_warn ("Packet %s [Hello:RECV]: my options: %x, his options %x",
- inet_ntoa(ospfh->router_id), OPTIONS (oi), hello->options);
- return;
- }
-
- /* get neighbour struct */
- nbr = ospf_nbr_get (oi, ospfh, iph, &p);
-
- /* neighbour must be valid, ospf_nbr_get creates if none existed */
- assert (nbr);
-
- old_state = nbr->state;
-
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
-
- /* RFC2328 Section 9.5.1
- If the router is not eligible to become Designated Router,
- (snip) It must also send an Hello Packet in reply to an
- Hello Packet received from any eligible neighbor (other than
- the current Designated Router and Backup Designated Router). */
- if (oi->type == OSPF_IFTYPE_NBMA)
- if (PRIORITY(oi) == 0 && hello->priority > 0
- && IPV4_ADDR_CMP(&DR(oi), &iph->ip_src)
- && IPV4_ADDR_CMP(&BDR(oi), &iph->ip_src))
- OSPF_NSM_TIMER_ON (nbr->t_hello_reply, ospf_hello_reply_timer,
- OSPF_HELLO_REPLY_DELAY);
-
- /* on NBMA network type, it happens to receive bidirectional Hello packet
- without advance 1-Way Received event.
- To avoid incorrect DR-seletion, raise 1-Way Received event.*/
- if (oi->type == OSPF_IFTYPE_NBMA &&
- (old_state == NSM_Down || old_state == NSM_Attempt))
- {
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived);
- nbr->priority = hello->priority;
- nbr->d_router = hello->d_router;
- nbr->bd_router = hello->bd_router;
- return;
- }
-
- if (ospf_nbr_bidirectional (&oi->ospf->router_id, hello->neighbors,
- size - OSPF_HELLO_MIN_SIZE))
- {
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_TwoWayReceived);
- nbr->options |= hello->options;
- }
- else
- {
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived);
- /* Set neighbor information. */
- nbr->priority = hello->priority;
- nbr->d_router = hello->d_router;
- nbr->bd_router = hello->bd_router;
- return;
- }
-
- /* If neighbor itself declares DR and no BDR exists,
- cause event BackupSeen */
- if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router))
- if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting)
- OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen);
-
- /* neighbor itself declares BDR. */
- if (oi->state == ISM_Waiting &&
- IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router))
- OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen);
-
- /* had not previously. */
- if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router) &&
- IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->d_router)) ||
- (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->d_router) &&
- IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router)))
- OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
-
- /* had not previously. */
- if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router) &&
- IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->bd_router)) ||
- (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->bd_router) &&
- IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router)))
- OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
-
- /* Neighbor priority check. */
- if (nbr->priority >= 0 && nbr->priority != hello->priority)
- OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange);
-
- /* Set neighbor information. */
- nbr->priority = hello->priority;
- nbr->d_router = hello->d_router;
- nbr->bd_router = hello->bd_router;
+ /* get neighbour struct */
+ nbr = ospf_nbr_get(oi, ospfh, iph, &p);
+
+ /* neighbour must be valid, ospf_nbr_get creates if none existed */
+ assert(nbr);
+
+ old_state = nbr->state;
+
+ /* Add event to thread. */
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
+
+ /* RFC2328 Section 9.5.1
+ If the router is not eligible to become Designated Router,
+ (snip) It must also send an Hello Packet in reply to an
+ Hello Packet received from any eligible neighbor (other than
+ the current Designated Router and Backup Designated Router). */
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ if (PRIORITY(oi) == 0 && hello->priority > 0
+ && IPV4_ADDR_CMP(&DR(oi), &iph->ip_src)
+ && IPV4_ADDR_CMP(&BDR(oi), &iph->ip_src))
+ OSPF_NSM_TIMER_ON(nbr->t_hello_reply,
+ ospf_hello_reply_timer,
+ OSPF_HELLO_REPLY_DELAY);
+
+ /* on NBMA network type, it happens to receive bidirectional Hello
+ packet
+ without advance 1-Way Received event.
+ To avoid incorrect DR-seletion, raise 1-Way Received event.*/
+ if (oi->type == OSPF_IFTYPE_NBMA
+ && (old_state == NSM_Down || old_state == NSM_Attempt)) {
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_OneWayReceived);
+ nbr->priority = hello->priority;
+ nbr->d_router = hello->d_router;
+ nbr->bd_router = hello->bd_router;
+ return;
+ }
+
+ if (ospf_nbr_bidirectional(&oi->ospf->router_id, hello->neighbors,
+ size - OSPF_HELLO_MIN_SIZE)) {
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_TwoWayReceived);
+ nbr->options |= hello->options;
+ } else {
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_OneWayReceived);
+ /* Set neighbor information. */
+ nbr->priority = hello->priority;
+ nbr->d_router = hello->d_router;
+ nbr->bd_router = hello->bd_router;
+ return;
+ }
+
+ /* If neighbor itself declares DR and no BDR exists,
+ cause event BackupSeen */
+ if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router))
+ if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting)
+ OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen);
+
+ /* neighbor itself declares BDR. */
+ if (oi->state == ISM_Waiting
+ && IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->bd_router))
+ OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen);
+
+ /* had not previously. */
+ if ((IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router)
+ && IPV4_ADDR_CMP(&nbr->address.u.prefix4, &nbr->d_router))
+ || (IPV4_ADDR_CMP(&nbr->address.u.prefix4, &hello->d_router)
+ && IPV4_ADDR_SAME(&nbr->address.u.prefix4, &nbr->d_router)))
+ OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange);
+
+ /* had not previously. */
+ if ((IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->bd_router)
+ && IPV4_ADDR_CMP(&nbr->address.u.prefix4, &nbr->bd_router))
+ || (IPV4_ADDR_CMP(&nbr->address.u.prefix4, &hello->bd_router)
+ && IPV4_ADDR_SAME(&nbr->address.u.prefix4, &nbr->bd_router)))
+ OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange);
+
+ /* Neighbor priority check. */
+ if (nbr->priority >= 0 && nbr->priority != hello->priority)
+ OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange);
+
+ /* Set neighbor information. */
+ nbr->priority = hello->priority;
+ nbr->d_router = hello->d_router;
+ nbr->bd_router = hello->bd_router;
}
/* Save DD flags/options/Seqnum received. */
-static void
-ospf_db_desc_save_current (struct ospf_neighbor *nbr,
- struct ospf_db_desc *dd)
+static void ospf_db_desc_save_current(struct ospf_neighbor *nbr,
+ struct ospf_db_desc *dd)
{
- nbr->last_recv.flags = dd->flags;
- nbr->last_recv.options = dd->options;
- nbr->last_recv.dd_seqnum = ntohl (dd->dd_seqnum);
+ nbr->last_recv.flags = dd->flags;
+ nbr->last_recv.options = dd->options;
+ nbr->last_recv.dd_seqnum = ntohl(dd->dd_seqnum);
}
/* Process rest of DD packet. */
-static void
-ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
- struct ospf_neighbor *nbr, struct ospf_db_desc *dd,
- u_int16_t size)
-{
- struct ospf_lsa *new, *find;
- struct lsa_header *lsah;
-
- stream_forward_getp (s, OSPF_DB_DESC_MIN_SIZE);
- for (size -= OSPF_DB_DESC_MIN_SIZE;
- size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE)
- {
- lsah = (struct lsa_header *) STREAM_PNT (s);
- stream_forward_getp (s, OSPF_LSA_HEADER_SIZE);
-
- /* Unknown LS type. */
- if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA)
- {
- zlog_warn ("Packet [DD:RECV]: Unknown LS type %d.", lsah->type);
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- return;
- }
-
- if (IS_OPAQUE_LSA (lsah->type)
- && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O))
- {
- zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id));
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- return;
- }
-
- switch (lsah->type)
- {
- case OSPF_AS_EXTERNAL_LSA:
- case OSPF_OPAQUE_AS_LSA:
- /* Check for stub area. Reject if AS-External from stub but
- allow if from NSSA. */
- if (oi->area->external_routing == OSPF_AREA_STUB)
- {
- zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.",
- lsah->type, inet_ntoa (lsah->id),
- (oi->area->external_routing == OSPF_AREA_STUB) ?\
- "STUB" : "NSSA");
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- return;
- }
- break;
- default:
- break;
- }
-
- /* Create LS-request object. */
- new = ospf_ls_request_new (lsah);
-
- /* Lookup received LSA, then add LS request list. */
- find = ospf_lsa_lookup_by_header (oi->area, lsah);
-
- /* ospf_lsa_more_recent is fine with NULL pointers */
- switch (ospf_lsa_more_recent (find, new))
- {
- case -1:
- /* Neighbour has a more recent LSA, we must request it */
- ospf_ls_request_add (nbr, new);
- /* fallthru */
- case 0:
- /* If we have a copy of this LSA, it's either less recent
- * and we're requesting it from neighbour (the case above), or
- * it's as recent and we both have same copy (this case).
- *
- * In neither of these two cases is there any point in
- * describing our copy of the LSA to the neighbour in a
- * DB-Summary packet, if we're still intending to do so.
- *
- * See: draft-ogier-ospf-dbex-opt-00.txt, describing the
- * backward compatible optimisation to OSPF DB Exchange /
- * DB Description process implemented here.
- */
- if (find)
- ospf_lsdb_delete (&nbr->db_sum, find);
- ospf_lsa_discard (new);
- break;
- default:
- /* We have the more recent copy, nothing specific to do:
- * - no need to request neighbours stale copy
- * - must leave DB summary list copy alone
- */
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Packet [DD:RECV]: LSA received Type %d, "
- "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id));
- ospf_lsa_discard (new);
- }
- }
-
- /* Master */
- if (IS_SET_DD_MS (nbr->dd_flags))
- {
- nbr->dd_seqnum++;
-
- /* Both sides have no More, then we're done with Exchange */
- if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags))
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
- else
- ospf_db_desc_send (nbr);
- }
- /* Slave */
- else
- {
- nbr->dd_seqnum = ntohl (dd->dd_seqnum);
-
- /* Send DD packet in reply.
- *
- * Must be done to acknowledge the Master's DD, regardless of
- * whether we have more LSAs ourselves to describe.
- *
- * This function will clear the 'More' bit, if after this DD
- * we have no more LSAs to describe to the master..
- */
- ospf_db_desc_send (nbr);
-
- /* Slave can raise ExchangeDone now, if master is also done */
- if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags))
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
- }
-
- /* Save received neighbor values from DD. */
- ospf_db_desc_save_current (nbr, dd);
-
- if (!nbr->t_ls_req)
- ospf_ls_req_send (nbr);
-}
-
-static int
-ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr)
-{
- /* Is DD duplicated? */
- if (dd->options == nbr->last_recv.options &&
- dd->flags == nbr->last_recv.flags &&
- dd->dd_seqnum == htonl (nbr->last_recv.dd_seqnum))
- return 1;
-
- return 0;
+static void ospf_db_desc_proc(struct stream *s, struct ospf_interface *oi,
+ struct ospf_neighbor *nbr,
+ struct ospf_db_desc *dd, u_int16_t size)
+{
+ struct ospf_lsa *new, *find;
+ struct lsa_header *lsah;
+
+ stream_forward_getp(s, OSPF_DB_DESC_MIN_SIZE);
+ for (size -= OSPF_DB_DESC_MIN_SIZE; size >= OSPF_LSA_HEADER_SIZE;
+ size -= OSPF_LSA_HEADER_SIZE) {
+ lsah = (struct lsa_header *)STREAM_PNT(s);
+ stream_forward_getp(s, OSPF_LSA_HEADER_SIZE);
+
+ /* Unknown LS type. */
+ if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) {
+ zlog_warn("Packet [DD:RECV]: Unknown LS type %d.",
+ lsah->type);
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ return;
+ }
+
+ if (IS_OPAQUE_LSA(lsah->type)
+ && !CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
+ zlog_warn("LSA[Type%d:%s]: Opaque capability mismatch?",
+ lsah->type, inet_ntoa(lsah->id));
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ return;
+ }
+
+ switch (lsah->type) {
+ case OSPF_AS_EXTERNAL_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ /* Check for stub area. Reject if AS-External from stub
+ but
+ allow if from NSSA. */
+ if (oi->area->external_routing == OSPF_AREA_STUB) {
+ zlog_warn(
+ "Packet [DD:RECV]: LSA[Type%d:%s] from %s area.",
+ lsah->type, inet_ntoa(lsah->id),
+ (oi->area->external_routing
+ == OSPF_AREA_STUB)
+ ? "STUB"
+ : "NSSA");
+ OSPF_NSM_EVENT_SCHEDULE(nbr,
+ NSM_SeqNumberMismatch);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Create LS-request object. */
+ new = ospf_ls_request_new(lsah);
+
+ /* Lookup received LSA, then add LS request list. */
+ find = ospf_lsa_lookup_by_header(oi->area, lsah);
+
+ /* ospf_lsa_more_recent is fine with NULL pointers */
+ switch (ospf_lsa_more_recent(find, new)) {
+ case -1:
+ /* Neighbour has a more recent LSA, we must request it
+ */
+ ospf_ls_request_add(nbr, new);
+ /* fallthru */
+ case 0:
+ /* If we have a copy of this LSA, it's either less
+ * recent
+ * and we're requesting it from neighbour (the case
+ * above), or
+ * it's as recent and we both have same copy (this
+ * case).
+ *
+ * In neither of these two cases is there any point in
+ * describing our copy of the LSA to the neighbour in a
+ * DB-Summary packet, if we're still intending to do so.
+ *
+ * See: draft-ogier-ospf-dbex-opt-00.txt, describing the
+ * backward compatible optimisation to OSPF DB Exchange
+ * /
+ * DB Description process implemented here.
+ */
+ if (find)
+ ospf_lsdb_delete(&nbr->db_sum, find);
+ ospf_lsa_discard(new);
+ break;
+ default:
+ /* We have the more recent copy, nothing specific to do:
+ * - no need to request neighbours stale copy
+ * - must leave DB summary list copy alone
+ */
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "Packet [DD:RECV]: LSA received Type %d, "
+ "ID %s is not recent.",
+ lsah->type, inet_ntoa(lsah->id));
+ ospf_lsa_discard(new);
+ }
+ }
+
+ /* Master */
+ if (IS_SET_DD_MS(nbr->dd_flags)) {
+ nbr->dd_seqnum++;
+
+ /* Both sides have no More, then we're done with Exchange */
+ if (!IS_SET_DD_M(dd->flags) && !IS_SET_DD_M(nbr->dd_flags))
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_ExchangeDone);
+ else
+ ospf_db_desc_send(nbr);
+ }
+ /* Slave */
+ else {
+ nbr->dd_seqnum = ntohl(dd->dd_seqnum);
+
+ /* Send DD packet in reply.
+ *
+ * Must be done to acknowledge the Master's DD, regardless of
+ * whether we have more LSAs ourselves to describe.
+ *
+ * This function will clear the 'More' bit, if after this DD
+ * we have no more LSAs to describe to the master..
+ */
+ ospf_db_desc_send(nbr);
+
+ /* Slave can raise ExchangeDone now, if master is also done */
+ if (!IS_SET_DD_M(dd->flags) && !IS_SET_DD_M(nbr->dd_flags))
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_ExchangeDone);
+ }
+
+ /* Save received neighbor values from DD. */
+ ospf_db_desc_save_current(nbr, dd);
+
+ if (!nbr->t_ls_req)
+ ospf_ls_req_send(nbr);
+}
+
+static int ospf_db_desc_is_dup(struct ospf_db_desc *dd,
+ struct ospf_neighbor *nbr)
+{
+ /* Is DD duplicated? */
+ if (dd->options == nbr->last_recv.options
+ && dd->flags == nbr->last_recv.flags
+ && dd->dd_seqnum == htonl(nbr->last_recv.dd_seqnum))
+ return 1;
+
+ return 0;
}
/* OSPF Database Description message read -- RFC2328 Section 10.6. */
-static void
-ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
- struct stream *s, struct ospf_interface *oi, u_int16_t size)
-{
- struct ospf_db_desc *dd;
- struct ospf_neighbor *nbr;
-
- /* Increment statistics. */
- oi->db_desc_in++;
-
- dd = (struct ospf_db_desc *) STREAM_PNT (s);
-
- nbr = ospf_nbr_lookup (oi, iph, ospfh);
- if (nbr == NULL)
- {
- zlog_warn ("Packet[DD]: Unknown Neighbor %s",
- inet_ntoa (ospfh->router_id));
- return;
- }
-
- /* Check MTU. */
- if ((OSPF_IF_PARAM (oi, mtu_ignore) == 0) &&
- (ntohs (dd->mtu) > oi->ifp->mtu))
- {
- zlog_warn ("Packet[DD]: Neighbor %s MTU %u is larger than [%s]'s MTU %u",
- inet_ntoa (nbr->router_id), ntohs (dd->mtu),
- IF_NAME (oi), oi->ifp->mtu);
- return;
- }
-
- /*
- * XXX HACK by Hasso Tepper. Setting N/P bit in NSSA area DD packets is not
- * required. In fact at least JunOS sends DD packets with P bit clear.
- * Until proper solution is developped, this hack should help.
- *
- * Update: According to the RFCs, N bit is specified /only/ for Hello
- * options, unfortunately its use in DD options is not specified. Hence some
- * implementations follow E-bit semantics and set it in DD options, and some
- * treat it as unspecified and hence follow the directive "default for
- * options is clear", ie unset.
- *
- * Reset the flag, as ospfd follows E-bit semantics.
- */
- if ( (oi->area->external_routing == OSPF_AREA_NSSA)
- && (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
- && (!CHECK_FLAG (dd->options, OSPF_OPTION_NP)) )
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options",
- inet_ntoa (nbr->router_id) );
- SET_FLAG (dd->options, OSPF_OPTION_NP);
- }
+static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh,
+ struct stream *s, struct ospf_interface *oi,
+ u_int16_t size)
+{
+ struct ospf_db_desc *dd;
+ struct ospf_neighbor *nbr;
-#ifdef REJECT_IF_TBIT_ON
- if (CHECK_FLAG (dd->options, OSPF_OPTION_MT))
- {
- /*
- * In Hello protocol, optional capability must have checked
- * to prevent this T-bit enabled router be my neighbor.
- */
- zlog_warn ("Packet[DD]: Neighbor %s: T-bit on?", inet_ntoa (nbr->router_id));
- return;
- }
-#endif /* REJECT_IF_TBIT_ON */
+ /* Increment statistics. */
+ oi->db_desc_in++;
- if (CHECK_FLAG (dd->options, OSPF_OPTION_O)
- && !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE))
- {
- /*
- * This node is not configured to handle O-bit, for now.
- * Clear it to ignore unsupported capability proposed by neighbor.
- */
- UNSET_FLAG (dd->options, OSPF_OPTION_O);
- }
-
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
-
- /* Process DD packet by neighbor status. */
- switch (nbr->state)
- {
- case NSM_Down:
- case NSM_Attempt:
- case NSM_TwoWay:
- zlog_warn ("Packet[DD]: Neighbor %s state is %s, packet discarded.",
- inet_ntoa(nbr->router_id),
- lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
- break;
- case NSM_Init:
- OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived);
- /* If the new state is ExStart, the processing of the current
- packet should then continue in this new state by falling
- through to case ExStart below. */
- if (nbr->state != NSM_ExStart)
- break;
- /* fallthru */
- case NSM_ExStart:
- /* Initial DBD */
- if ((IS_SET_DD_ALL (dd->flags) == OSPF_DD_FLAG_ALL) &&
- (size == OSPF_DB_DESC_MIN_SIZE))
- {
- if (IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) > 0)
- {
- /* We're Slave---obey */
- zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Slave).",
- inet_ntoa(nbr->router_id));
- nbr->dd_seqnum = ntohl (dd->dd_seqnum);
-
- /* Reset I/MS */
- UNSET_FLAG (nbr->dd_flags, (OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I));
- }
- else
- {
- /* We're Master, ignore the initial DBD from Slave */
- zlog_info ("Packet[DD]: Neighbor %s: Initial DBD from Slave, "
- "ignoring.", inet_ntoa(nbr->router_id));
- break;
- }
- }
- /* Ack from the Slave */
- else if (!IS_SET_DD_MS (dd->flags) && !IS_SET_DD_I (dd->flags) &&
- ntohl (dd->dd_seqnum) == nbr->dd_seqnum &&
- IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) < 0)
- {
- zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Master).",
- inet_ntoa(nbr->router_id));
- /* Reset I, leaving MS */
- UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_I);
+ dd = (struct ospf_db_desc *)STREAM_PNT(s);
+
+ nbr = ospf_nbr_lookup(oi, iph, ospfh);
+ if (nbr == NULL) {
+ zlog_warn("Packet[DD]: Unknown Neighbor %s",
+ inet_ntoa(ospfh->router_id));
+ return;
}
- else
- {
- zlog_warn ("Packet[DD]: Neighbor %s Negotiation fails.",
- inet_ntoa(nbr->router_id));
- break;
- }
-
- /* This is where the real Options are saved */
- nbr->options = dd->options;
-
- if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE))
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Neighbor[%s] is %sOpaque-capable.",
- inet_ntoa (nbr->router_id),
- CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT ");
-
- if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O)
- && IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4))
- {
- zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; "
- "Opaque-LSAs cannot be reliably advertised "
- "in this network.",
- inet_ntoa (nbr->router_id));
- /* This situation is undesirable, but not a real error. */
- }
- }
-
- OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone);
-
- /* continue processing rest of packet. */
- ospf_db_desc_proc (s, oi, nbr, dd, size);
- break;
- case NSM_Exchange:
- if (ospf_db_desc_is_dup (dd, nbr))
- {
- if (IS_SET_DD_MS (nbr->dd_flags))
- /* Master: discard duplicated DD packet. */
- zlog_info ("Packet[DD] (Master): Neighbor %s packet duplicated.",
- inet_ntoa (nbr->router_id));
- else
- /* Slave: cause to retransmit the last Database Description. */
- {
- zlog_info ("Packet[DD] [Slave]: Neighbor %s packet duplicated.",
- inet_ntoa (nbr->router_id));
- ospf_db_desc_resend (nbr);
- }
- break;
- }
-
- /* Otherwise DD packet should be checked. */
- /* Check Master/Slave bit mismatch */
- if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags))
- {
- zlog_warn ("Packet[DD]: Neighbor %s MS-bit mismatch.",
- inet_ntoa(nbr->router_id));
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
- dd->flags, nbr->dd_flags);
- break;
+
+ /* Check MTU. */
+ if ((OSPF_IF_PARAM(oi, mtu_ignore) == 0)
+ && (ntohs(dd->mtu) > oi->ifp->mtu)) {
+ zlog_warn(
+ "Packet[DD]: Neighbor %s MTU %u is larger than [%s]'s MTU %u",
+ inet_ntoa(nbr->router_id), ntohs(dd->mtu), IF_NAME(oi),
+ oi->ifp->mtu);
+ return;
}
- /* Check initialize bit is set. */
- if (IS_SET_DD_I (dd->flags))
- {
- zlog_info ("Packet[DD]: Neighbor %s I-bit set.",
- inet_ntoa(nbr->router_id));
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- break;
+ /*
+ * XXX HACK by Hasso Tepper. Setting N/P bit in NSSA area DD packets is
+ * not
+ * required. In fact at least JunOS sends DD packets with P bit clear.
+ * Until proper solution is developped, this hack should help.
+ *
+ * Update: According to the RFCs, N bit is specified /only/ for Hello
+ * options, unfortunately its use in DD options is not specified. Hence
+ * some
+ * implementations follow E-bit semantics and set it in DD options, and
+ * some
+ * treat it as unspecified and hence follow the directive "default for
+ * options is clear", ie unset.
+ *
+ * Reset the flag, as ospfd follows E-bit semantics.
+ */
+ if ((oi->area->external_routing == OSPF_AREA_NSSA)
+ && (CHECK_FLAG(nbr->options, OSPF_OPTION_NP))
+ && (!CHECK_FLAG(dd->options, OSPF_OPTION_NP))) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options",
+ inet_ntoa(nbr->router_id));
+ SET_FLAG(dd->options, OSPF_OPTION_NP);
}
- /* Check DD Options. */
- if (dd->options != nbr->options)
- {
+#ifdef REJECT_IF_TBIT_ON
+ if (CHECK_FLAG(dd->options, OSPF_OPTION_MT)) {
+ /*
+ * In Hello protocol, optional capability must have checked
+ * to prevent this T-bit enabled router be my neighbor.
+ */
+ zlog_warn("Packet[DD]: Neighbor %s: T-bit on?",
+ inet_ntoa(nbr->router_id));
+ return;
+ }
+#endif /* REJECT_IF_TBIT_ON */
+
+ if (CHECK_FLAG(dd->options, OSPF_OPTION_O)
+ && !CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) {
+ /*
+ * This node is not configured to handle O-bit, for now.
+ * Clear it to ignore unsupported capability proposed by
+ * neighbor.
+ */
+ UNSET_FLAG(dd->options, OSPF_OPTION_O);
+ }
+
+ /* Add event to thread. */
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
+
+ /* Process DD packet by neighbor status. */
+ switch (nbr->state) {
+ case NSM_Down:
+ case NSM_Attempt:
+ case NSM_TwoWay:
+ zlog_warn(
+ "Packet[DD]: Neighbor %s state is %s, packet discarded.",
+ inet_ntoa(nbr->router_id),
+ lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
+ break;
+ case NSM_Init:
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_TwoWayReceived);
+ /* If the new state is ExStart, the processing of the current
+ packet should then continue in this new state by falling
+ through to case ExStart below. */
+ if (nbr->state != NSM_ExStart)
+ break;
+ /* fallthru */
+ case NSM_ExStart:
+ /* Initial DBD */
+ if ((IS_SET_DD_ALL(dd->flags) == OSPF_DD_FLAG_ALL)
+ && (size == OSPF_DB_DESC_MIN_SIZE)) {
+ if (IPV4_ADDR_CMP(&nbr->router_id, &oi->ospf->router_id)
+ > 0) {
+ /* We're Slave---obey */
+ zlog_info(
+ "Packet[DD]: Neighbor %s Negotiation done (Slave).",
+ inet_ntoa(nbr->router_id));
+ nbr->dd_seqnum = ntohl(dd->dd_seqnum);
+
+ /* Reset I/MS */
+ UNSET_FLAG(nbr->dd_flags,
+ (OSPF_DD_FLAG_MS | OSPF_DD_FLAG_I));
+ } else {
+ /* We're Master, ignore the initial DBD from
+ * Slave */
+ zlog_info(
+ "Packet[DD]: Neighbor %s: Initial DBD from Slave, "
+ "ignoring.",
+ inet_ntoa(nbr->router_id));
+ break;
+ }
+ }
+ /* Ack from the Slave */
+ else if (!IS_SET_DD_MS(dd->flags) && !IS_SET_DD_I(dd->flags)
+ && ntohl(dd->dd_seqnum) == nbr->dd_seqnum
+ && IPV4_ADDR_CMP(&nbr->router_id, &oi->ospf->router_id)
+ < 0) {
+ zlog_info(
+ "Packet[DD]: Neighbor %s Negotiation done (Master).",
+ inet_ntoa(nbr->router_id));
+ /* Reset I, leaving MS */
+ UNSET_FLAG(nbr->dd_flags, OSPF_DD_FLAG_I);
+ } else {
+ zlog_warn("Packet[DD]: Neighbor %s Negotiation fails.",
+ inet_ntoa(nbr->router_id));
+ break;
+ }
+
+ /* This is where the real Options are saved */
+ nbr->options = dd->options;
+
+ if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "Neighbor[%s] is %sOpaque-capable.",
+ inet_ntoa(nbr->router_id),
+ CHECK_FLAG(nbr->options, OSPF_OPTION_O)
+ ? ""
+ : "NOT ");
+
+ if (!CHECK_FLAG(nbr->options, OSPF_OPTION_O)
+ && IPV4_ADDR_SAME(&DR(oi),
+ &nbr->address.u.prefix4)) {
+ zlog_warn(
+ "DR-neighbor[%s] is NOT opaque-capable; "
+ "Opaque-LSAs cannot be reliably advertised "
+ "in this network.",
+ inet_ntoa(nbr->router_id));
+ /* This situation is undesirable, but not a real
+ * error. */
+ }
+ }
+
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_NegotiationDone);
+
+ /* continue processing rest of packet. */
+ ospf_db_desc_proc(s, oi, nbr, dd, size);
+ break;
+ case NSM_Exchange:
+ if (ospf_db_desc_is_dup(dd, nbr)) {
+ if (IS_SET_DD_MS(nbr->dd_flags))
+ /* Master: discard duplicated DD packet. */
+ zlog_info(
+ "Packet[DD] (Master): Neighbor %s packet duplicated.",
+ inet_ntoa(nbr->router_id));
+ else
+ /* Slave: cause to retransmit the last Database
+ Description. */
+ {
+ zlog_info(
+ "Packet[DD] [Slave]: Neighbor %s packet duplicated.",
+ inet_ntoa(nbr->router_id));
+ ospf_db_desc_resend(nbr);
+ }
+ break;
+ }
+
+ /* Otherwise DD packet should be checked. */
+ /* Check Master/Slave bit mismatch */
+ if (IS_SET_DD_MS(dd->flags)
+ != IS_SET_DD_MS(nbr->last_recv.flags)) {
+ zlog_warn("Packet[DD]: Neighbor %s MS-bit mismatch.",
+ inet_ntoa(nbr->router_id));
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
+ dd->flags, nbr->dd_flags);
+ break;
+ }
+
+ /* Check initialize bit is set. */
+ if (IS_SET_DD_I(dd->flags)) {
+ zlog_info("Packet[DD]: Neighbor %s I-bit set.",
+ inet_ntoa(nbr->router_id));
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ break;
+ }
+
+ /* Check DD Options. */
+ if (dd->options != nbr->options) {
#ifdef ORIGINAL_CODING
- /* Save the new options for debugging */
- nbr->options = dd->options;
+ /* Save the new options for debugging */
+ nbr->options = dd->options;
#endif /* ORIGINAL_CODING */
- zlog_warn ("Packet[DD]: Neighbor %s options mismatch.",
- inet_ntoa(nbr->router_id));
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- break;
- }
+ zlog_warn("Packet[DD]: Neighbor %s options mismatch.",
+ inet_ntoa(nbr->router_id));
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ break;
+ }
- /* Check DD sequence number. */
- if ((IS_SET_DD_MS (nbr->dd_flags) &&
- ntohl (dd->dd_seqnum) != nbr->dd_seqnum) ||
- (!IS_SET_DD_MS (nbr->dd_flags) &&
- ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1))
- {
- zlog_warn ("Packet[DD]: Neighbor %s sequence number mismatch.",
- inet_ntoa(nbr->router_id));
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- break;
- }
-
- /* Continue processing rest of packet. */
- ospf_db_desc_proc (s, oi, nbr, dd, size);
- break;
- case NSM_Loading:
- case NSM_Full:
- if (ospf_db_desc_is_dup (dd, nbr))
- {
- if (IS_SET_DD_MS (nbr->dd_flags))
- {
- /* Master should discard duplicate DD packet. */
- zlog_info ("Packet[DD]: Neighbor %s duplicated, "
- "packet discarded.",
- inet_ntoa(nbr->router_id));
- break;
- }
- else
- {
- if (monotime_since (&nbr->last_send_ts, NULL)
- < nbr->v_inactivity * 1000000LL)
- {
- /* In states Loading and Full the slave must resend
- its last Database Description packet in response to
- duplicate Database Description packets received
- from the master. For this reason the slave must
- wait RouterDeadInterval seconds before freeing the
- last Database Description packet. Reception of a
- Database Description packet from the master after
- this interval will generate a SeqNumberMismatch
- neighbor event. RFC2328 Section 10.8 */
- ospf_db_desc_resend (nbr);
- break;
+ /* Check DD sequence number. */
+ if ((IS_SET_DD_MS(nbr->dd_flags)
+ && ntohl(dd->dd_seqnum) != nbr->dd_seqnum)
+ || (!IS_SET_DD_MS(nbr->dd_flags)
+ && ntohl(dd->dd_seqnum) != nbr->dd_seqnum + 1)) {
+ zlog_warn(
+ "Packet[DD]: Neighbor %s sequence number mismatch.",
+ inet_ntoa(nbr->router_id));
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ break;
+ }
+
+ /* Continue processing rest of packet. */
+ ospf_db_desc_proc(s, oi, nbr, dd, size);
+ break;
+ case NSM_Loading:
+ case NSM_Full:
+ if (ospf_db_desc_is_dup(dd, nbr)) {
+ if (IS_SET_DD_MS(nbr->dd_flags)) {
+ /* Master should discard duplicate DD packet. */
+ zlog_info(
+ "Packet[DD]: Neighbor %s duplicated, "
+ "packet discarded.",
+ inet_ntoa(nbr->router_id));
+ break;
+ } else {
+ if (monotime_since(&nbr->last_send_ts, NULL)
+ < nbr->v_inactivity * 1000000LL) {
+ /* In states Loading and Full the slave
+ must resend
+ its last Database Description packet
+ in response to
+ duplicate Database Description
+ packets received
+ from the master. For this reason the
+ slave must
+ wait RouterDeadInterval seconds
+ before freeing the
+ last Database Description packet.
+ Reception of a
+ Database Description packet from the
+ master after
+ this interval will generate a
+ SeqNumberMismatch
+ neighbor event. RFC2328 Section 10.8
+ */
+ ospf_db_desc_resend(nbr);
+ break;
+ }
+ }
}
- }
- }
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
- break;
- default:
- zlog_warn ("Packet[DD]: Neighbor %s NSM illegal status %u.",
- inet_ntoa(nbr->router_id), nbr->state);
- break;
- }
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
+ break;
+ default:
+ zlog_warn("Packet[DD]: Neighbor %s NSM illegal status %u.",
+ inet_ntoa(nbr->router_id), nbr->state);
+ break;
+ }
}
#define OSPF_LSA_KEY_SIZE 12 /* type(4) + id(4) + ar(4) */
/* OSPF Link State Request Read -- RFC2328 Section 10.7. */
-static void
-ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
- struct stream *s, struct ospf_interface *oi, u_int16_t size)
-{
- struct ospf_neighbor *nbr;
- u_int32_t ls_type;
- struct in_addr ls_id;
- struct in_addr adv_router;
- struct ospf_lsa *find;
- struct list *ls_upd;
- unsigned int length;
-
- /* Increment statistics. */
- oi->ls_req_in++;
-
- nbr = ospf_nbr_lookup (oi, iph, ospfh);
- if (nbr == NULL)
- {
- zlog_warn ("Link State Request: Unknown Neighbor %s.",
- inet_ntoa (ospfh->router_id));
- return;
- }
-
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
-
- /* Neighbor State should be Exchange or later. */
- if (nbr->state != NSM_Exchange &&
- nbr->state != NSM_Loading &&
- nbr->state != NSM_Full)
- {
- zlog_warn ("Link State Request received from %s: "
- "Neighbor state is %s, packet discarded.",
- inet_ntoa (ospfh->router_id),
- lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
- return;
- }
-
- /* Send Link State Update for ALL requested LSAs. */
- ls_upd = list_new ();
- length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE;
-
- while (size >= OSPF_LSA_KEY_SIZE)
- {
- /* Get one slice of Link State Request. */
- ls_type = stream_getl (s);
- ls_id.s_addr = stream_get_ipv4 (s);
- adv_router.s_addr = stream_get_ipv4 (s);
-
- /* Verify LSA type. */
- if (ls_type < OSPF_MIN_LSA || ls_type >= OSPF_MAX_LSA)
- {
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
- list_delete (ls_upd);
- return;
+static void ospf_ls_req(struct ip *iph, struct ospf_header *ospfh,
+ struct stream *s, struct ospf_interface *oi,
+ u_int16_t size)
+{
+ struct ospf_neighbor *nbr;
+ u_int32_t ls_type;
+ struct in_addr ls_id;
+ struct in_addr adv_router;
+ struct ospf_lsa *find;
+ struct list *ls_upd;
+ unsigned int length;
+
+ /* Increment statistics. */
+ oi->ls_req_in++;
+
+ nbr = ospf_nbr_lookup(oi, iph, ospfh);
+ if (nbr == NULL) {
+ zlog_warn("Link State Request: Unknown Neighbor %s.",
+ inet_ntoa(ospfh->router_id));
+ return;
}
- /* Search proper LSA in LSDB. */
- find = ospf_lsa_lookup (oi->area, ls_type, ls_id, adv_router);
- if (find == NULL)
- {
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
- list_delete (ls_upd);
- return;
+ /* Add event to thread. */
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
+
+ /* Neighbor State should be Exchange or later. */
+ if (nbr->state != NSM_Exchange && nbr->state != NSM_Loading
+ && nbr->state != NSM_Full) {
+ zlog_warn(
+ "Link State Request received from %s: "
+ "Neighbor state is %s, packet discarded.",
+ inet_ntoa(ospfh->router_id),
+ lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
+ return;
}
- /* Packet overflows MTU size, send immediately. */
- if (length + ntohs (find->data->length) > ospf_packet_max (oi))
- {
- if (oi->type == OSPF_IFTYPE_NBMA)
- ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
- else
- ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT);
+ /* Send Link State Update for ALL requested LSAs. */
+ ls_upd = list_new();
+ length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE;
+
+ while (size >= OSPF_LSA_KEY_SIZE) {
+ /* Get one slice of Link State Request. */
+ ls_type = stream_getl(s);
+ ls_id.s_addr = stream_get_ipv4(s);
+ adv_router.s_addr = stream_get_ipv4(s);
+
+ /* Verify LSA type. */
+ if (ls_type < OSPF_MIN_LSA || ls_type >= OSPF_MAX_LSA) {
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_BadLSReq);
+ list_delete(ls_upd);
+ return;
+ }
- /* Only remove list contents. Keep ls_upd. */
- list_delete_all_node (ls_upd);
+ /* Search proper LSA in LSDB. */
+ find = ospf_lsa_lookup(oi->area, ls_type, ls_id, adv_router);
+ if (find == NULL) {
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_BadLSReq);
+ list_delete(ls_upd);
+ return;
+ }
- length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE;
- }
+ /* Packet overflows MTU size, send immediately. */
+ if (length + ntohs(find->data->length) > ospf_packet_max(oi)) {
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ ospf_ls_upd_send(nbr, ls_upd,
+ OSPF_SEND_PACKET_DIRECT);
+ else
+ ospf_ls_upd_send(nbr, ls_upd,
+ OSPF_SEND_PACKET_INDIRECT);
+
+ /* Only remove list contents. Keep ls_upd. */
+ list_delete_all_node(ls_upd);
- /* Append LSA to update list. */
- listnode_add (ls_upd, find);
- length += ntohs (find->data->length);
+ length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE;
+ }
+
+ /* Append LSA to update list. */
+ listnode_add(ls_upd, find);
+ length += ntohs(find->data->length);
- size -= OSPF_LSA_KEY_SIZE;
- }
+ size -= OSPF_LSA_KEY_SIZE;
+ }
- /* Send rest of Link State Update. */
- if (listcount (ls_upd) > 0)
- {
- if (oi->type == OSPF_IFTYPE_NBMA)
- ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
- else
- ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT);
+ /* Send rest of Link State Update. */
+ if (listcount(ls_upd) > 0) {
+ if (oi->type == OSPF_IFTYPE_NBMA)
+ ospf_ls_upd_send(nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
+ else
+ ospf_ls_upd_send(nbr, ls_upd,
+ OSPF_SEND_PACKET_INDIRECT);
- list_delete (ls_upd);
- }
- else
- list_free (ls_upd);
+ list_delete(ls_upd);
+ } else
+ list_free(ls_upd);
}
/* Get the list of LSAs from Link State Update packet.
And process some validation -- RFC2328 Section 13. (1)-(2). */
-static struct list *
-ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
- struct ospf_interface *oi, size_t size)
-{
- u_int16_t count, sum;
- u_int32_t length;
- struct lsa_header *lsah;
- struct ospf_lsa *lsa;
- struct list *lsas;
+static struct list *ospf_ls_upd_list_lsa(struct ospf_neighbor *nbr,
+ struct stream *s,
+ struct ospf_interface *oi, size_t size)
+{
+ u_int16_t count, sum;
+ u_int32_t length;
+ struct lsa_header *lsah;
+ struct ospf_lsa *lsa;
+ struct list *lsas;
+
+ lsas = list_new();
+
+ count = stream_getl(s);
+ size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */
+
+ for (; size >= OSPF_LSA_HEADER_SIZE && count > 0;
+ size -= length, stream_forward_getp(s, length), count--) {
+ lsah = (struct lsa_header *)STREAM_PNT(s);
+ length = ntohs(lsah->length);
+
+ if (length > size) {
+ zlog_warn(
+ "Link State Update: LSA length exceeds packet size.");
+ break;
+ }
- lsas = list_new ();
+ /* Validate the LSA's LS checksum. */
+ sum = lsah->checksum;
+ if (!ospf_lsa_checksum_valid(lsah)) {
+ /* (bug #685) more details in a one-line message make it
+ * possible
+ * to identify problem source on the one hand and to
+ * have a better
+ * chance to compress repeated messages in syslog on the
+ * other */
+ zlog_warn(
+ "Link State Update: LSA checksum error %x/%x, ID=%s from: nbr %s, router ID %s, adv router %s",
+ sum, lsah->checksum, inet_ntoa(lsah->id),
+ inet_ntoa(nbr->src), inet_ntoa(nbr->router_id),
+ inet_ntoa(lsah->adv_router));
+ continue;
+ }
- count = stream_getl (s);
- size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */
+ /* Examine the LSA's LS type. */
+ if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) {
+ zlog_warn("Link State Update: Unknown LS type %d",
+ lsah->type);
+ continue;
+ }
- for (; size >= OSPF_LSA_HEADER_SIZE && count > 0;
- size -= length, stream_forward_getp (s, length), count--)
- {
- lsah = (struct lsa_header *) STREAM_PNT (s);
- length = ntohs (lsah->length);
+ /*
+ * What if the received LSA's age is greater than MaxAge?
+ * Treat it as a MaxAge case -- endo.
+ */
+ if (ntohs(lsah->ls_age) > OSPF_LSA_MAXAGE)
+ lsah->ls_age = htons(OSPF_LSA_MAXAGE);
- if (length > size)
- {
- zlog_warn ("Link State Update: LSA length exceeds packet size.");
- break;
- }
+ if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
+#ifdef STRICT_OBIT_USAGE_CHECK
+ if ((IS_OPAQUE_LSA(lsah->type)
+ && !CHECK_FLAG(lsah->options, OSPF_OPTION_O))
+ || (!IS_OPAQUE_LSA(lsah->type)
+ && CHECK_FLAG(lsah->options, OSPF_OPTION_O))) {
+ /*
+ * This neighbor must know the exact usage of
+ * O-bit;
+ * the bit will be set in Type-9,10,11 LSAs
+ * only.
+ */
+ zlog_warn("LSA[Type%d:%s]: O-bit abuse?",
+ lsah->type, inet_ntoa(lsah->id));
+ continue;
+ }
+#endif /* STRICT_OBIT_USAGE_CHECK */
- /* Validate the LSA's LS checksum. */
- sum = lsah->checksum;
- if (! ospf_lsa_checksum_valid (lsah))
- {
- /* (bug #685) more details in a one-line message make it possible
- * to identify problem source on the one hand and to have a better
- * chance to compress repeated messages in syslog on the other */
- zlog_warn ("Link State Update: LSA checksum error %x/%x, ID=%s from: nbr %s, router ID %s, adv router %s",
- sum, lsah->checksum, inet_ntoa (lsah->id),
- inet_ntoa (nbr->src), inet_ntoa (nbr->router_id),
- inet_ntoa (lsah->adv_router));
- continue;
- }
-
- /* Examine the LSA's LS type. */
- if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA)
- {
- zlog_warn ("Link State Update: Unknown LS type %d", lsah->type);
- continue;
- }
+ /* Do not take in AS External Opaque-LSAs if we are a
+ * stub. */
+ if (lsah->type == OSPF_OPAQUE_AS_LSA
+ && nbr->oi->area->external_routing
+ != OSPF_AREA_DEFAULT) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "LSA[Type%d:%s]: We are a stub, don't take this LSA.",
+ lsah->type,
+ inet_ntoa(lsah->id));
+ continue;
+ }
+ } else if (IS_OPAQUE_LSA(lsah->type)) {
+ zlog_warn("LSA[Type%d:%s]: Opaque capability mismatch?",
+ lsah->type, inet_ntoa(lsah->id));
+ continue;
+ }
- /*
- * What if the received LSA's age is greater than MaxAge?
- * Treat it as a MaxAge case -- endo.
- */
- if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE)
- lsah->ls_age = htons (OSPF_LSA_MAXAGE);
+ /* Create OSPF LSA instance. */
+ lsa = ospf_lsa_new();
+
+ /* We may wish to put some error checking if type NSSA comes in
+ and area not in NSSA mode */
+ switch (lsah->type) {
+ case OSPF_AS_EXTERNAL_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ lsa->area = NULL;
+ break;
+ case OSPF_OPAQUE_LINK_LSA:
+ lsa->oi = oi; /* Remember incoming interface for
+ flooding control. */
+ /* Fallthrough */
+ default:
+ lsa->area = oi->area;
+ break;
+ }
- if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
- {
-#ifdef STRICT_OBIT_USAGE_CHECK
- if ((IS_OPAQUE_LSA(lsah->type) &&
- ! CHECK_FLAG (lsah->options, OSPF_OPTION_O))
- || (! IS_OPAQUE_LSA(lsah->type) &&
- CHECK_FLAG (lsah->options, OSPF_OPTION_O)))
- {
- /*
- * This neighbor must know the exact usage of O-bit;
- * the bit will be set in Type-9,10,11 LSAs only.
- */
- zlog_warn ("LSA[Type%d:%s]: O-bit abuse?", lsah->type, inet_ntoa (lsah->id));
- continue;
- }
-#endif /* STRICT_OBIT_USAGE_CHECK */
+ lsa->data = ospf_lsa_data_new(length);
+ memcpy(lsa->data, lsah, length);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "LSA[Type%d:%s]: %p new LSA created with Link State Update",
+ lsa->data->type, inet_ntoa(lsa->data->id),
+ (void *)lsa);
+ listnode_add(lsas, lsa);
+ }
- /* Do not take in AS External Opaque-LSAs if we are a stub. */
- if (lsah->type == OSPF_OPAQUE_AS_LSA
- && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT)
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id));
- continue;
- }
- }
- else if (IS_OPAQUE_LSA(lsah->type))
- {
- zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id));
- continue;
- }
-
- /* Create OSPF LSA instance. */
- lsa = ospf_lsa_new ();
-
- /* We may wish to put some error checking if type NSSA comes in
- and area not in NSSA mode */
- switch (lsah->type)
- {
- case OSPF_AS_EXTERNAL_LSA:
- case OSPF_OPAQUE_AS_LSA:
- lsa->area = NULL;
- break;
- case OSPF_OPAQUE_LINK_LSA:
- lsa->oi = oi; /* Remember incoming interface for flooding control. */
- /* Fallthrough */
- default:
- lsa->area = oi->area;
- break;
- }
-
- lsa->data = ospf_lsa_data_new (length);
- memcpy (lsa->data, lsah, length);
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update",
- lsa->data->type, inet_ntoa (lsa->data->id), (void *)lsa);
- listnode_add (lsas, lsa);
- }
-
- return lsas;
+ return lsas;
}
/* Cleanup Update list. */
-static void
-ospf_upd_list_clean (struct list *lsas)
+static void ospf_upd_list_clean(struct list *lsas)
{
- struct listnode *node, *nnode;
- struct ospf_lsa *lsa;
+ struct listnode *node, *nnode;
+ struct ospf_lsa *lsa;
- for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
- ospf_lsa_discard (lsa);
+ for (ALL_LIST_ELEMENTS(lsas, node, nnode, lsa))
+ ospf_lsa_discard(lsa);
- list_delete (lsas);
+ list_delete(lsas);
}
/* OSPF Link State Update message read -- RFC2328 Section 13. */
-static void
-ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh,
- struct stream *s, struct ospf_interface *oi, u_int16_t size)
-{
- struct ospf_neighbor *nbr;
- struct list *lsas;
- struct listnode *node, *nnode;
- struct ospf_lsa *lsa = NULL;
- /* unsigned long ls_req_found = 0; */
-
- /* Dis-assemble the stream, update each entry, re-encapsulate for flooding */
-
- /* Increment statistics. */
- oi->ls_upd_in++;
-
- /* Check neighbor. */
- nbr = ospf_nbr_lookup (oi, iph, ospfh);
- if (nbr == NULL)
- {
- zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s",
- inet_ntoa (ospfh->router_id), IF_NAME (oi));
- return;
- }
-
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
-
- /* Check neighbor state. */
- if (nbr->state < NSM_Exchange)
- {
- if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
- zlog_debug ("Link State Update: "
- "Neighbor[%s] state %s is less than Exchange",
- inet_ntoa (ospfh->router_id),
- lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
- return;
- }
-
- /* Get list of LSAs from Link State Update packet. - Also perorms Stages
- * 1 (validate LSA checksum) and 2 (check for LSA consistent type)
- * of section 13.
- */
- lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size);
-
-#define DISCARD_LSA(L,N) {\
- if (IS_DEBUG_OSPF_EVENT) \
- zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p" \
- " Type-%d", N, (void *)lsa, (int) lsa->data->type); \
- ospf_lsa_discard (L); \
- continue; }
-
- /* Process each LSA received in the one packet.
- *
- * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding
- * text below are from the steps in RFC 2328, Section 13.
- */
- for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
- {
- struct ospf_lsa *ls_ret, *current;
- int ret = 1;
-
- if (IS_DEBUG_OSPF_NSSA)
- {
- char buf1[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
- char buf3[INET_ADDRSTRLEN];
-
- zlog_debug("LSA Type-%d from %s, ID: %s, ADV: %s",
- lsa->data->type,
- inet_ntop (AF_INET, &ospfh->router_id,
- buf1, INET_ADDRSTRLEN),
- inet_ntop (AF_INET, &lsa->data->id,
- buf2, INET_ADDRSTRLEN),
- inet_ntop (AF_INET, &lsa->data->adv_router,
- buf3, INET_ADDRSTRLEN));
- }
-
- listnode_delete (lsas, lsa); /* We don't need it in list anymore */
-
- /* (1) Validate Checksum - Done above by ospf_ls_upd_list_lsa() */
-
- /* (2) LSA Type - Done above by ospf_ls_upd_list_lsa() */
-
- /* (3) Do not take in AS External LSAs if we are a stub or NSSA. */
-
- /* Do not take in AS NSSA if this neighbor and we are not NSSA */
-
- /* Do take in Type-7's if we are an NSSA */
-
- /* If we are also an ABR, later translate them to a Type-5 packet */
-
- /* Later, an NSSA Re-fresh can Re-fresh Type-7's and an ABR will
- translate them to a separate Type-5 packet. */
-
- if (lsa->data->type == OSPF_AS_EXTERNAL_LSA)
- /* Reject from STUB or NSSA */
- if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT)
- {
- if (IS_DEBUG_OSPF_NSSA)
- zlog_debug("Incoming External LSA Discarded: We are NSSA/STUB Area");
- DISCARD_LSA (lsa, 1);
- }
-
- if (lsa->data->type == OSPF_AS_NSSA_LSA)
- if (nbr->oi->area->external_routing != OSPF_AREA_NSSA)
- {
- if (IS_DEBUG_OSPF_NSSA)
- zlog_debug("Incoming NSSA LSA Discarded: Not NSSA Area");
- DISCARD_LSA (lsa,2);
- }
-
- /* VU229804: Router-LSA Adv-ID must be equal to LS-ID */
- if (lsa->data->type == OSPF_ROUTER_LSA)
- if (!IPV4_ADDR_SAME(&lsa->data->id, &lsa->data->adv_router))
- {
- char buf1[INET_ADDRSTRLEN];
- char buf2[INET_ADDRSTRLEN];
- char buf3[INET_ADDRSTRLEN];
-
- zlog_err("Incoming Router-LSA from %s with "
- "Adv-ID[%s] != LS-ID[%s]",
- inet_ntop (AF_INET, &ospfh->router_id,
- buf1, INET_ADDRSTRLEN),
- inet_ntop (AF_INET, &lsa->data->id,
- buf2, INET_ADDRSTRLEN),
- inet_ntop (AF_INET, &lsa->data->adv_router,
- buf3, INET_ADDRSTRLEN));
- zlog_err("OSPF domain compromised by attack or corruption. "
- "Verify correct operation of -ALL- OSPF routers.");
- DISCARD_LSA (lsa, 0);
- }
-
- /* Find the LSA in the current database. */
-
- current = ospf_lsa_lookup_by_header (oi->area, lsa->data);
-
- /* (4) If the LSA's LS age is equal to MaxAge, and there is currently
- no instance of the LSA in the router's link state database,
- and none of router's neighbors are in states Exchange or Loading,
- then take the following actions: */
-
- if (IS_LSA_MAXAGE (lsa) && !current &&
- ospf_check_nbr_status(oi->ospf))
- {
- /* (4a) Response Link State Acknowledgment. */
- ospf_ls_ack_send (nbr, lsa);
-
- /* (4b) Discard LSA. */
- if (IS_DEBUG_OSPF (lsa, LSA))
- {
- zlog_debug ("Link State Update[%s]: LS age is equal to MaxAge.",
- dump_lsa_key(lsa));
- }
- DISCARD_LSA (lsa, 3);
- }
-
- if (IS_OPAQUE_LSA (lsa->data->type)
- && IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id))
- {
- /*
- * Even if initial flushing seems to be completed, there might
- * be a case that self-originated LSA with MaxAge still remain
- * in the routing domain.
- * Just send an LSAck message to cease retransmission.
- */
- if (IS_LSA_MAXAGE (lsa))
- {
- zlog_warn ("LSA[%s]: Boomerang effect?", dump_lsa_key (lsa));
- ospf_ls_ack_send (nbr, lsa);
- ospf_lsa_discard (lsa);
-
- if (current != NULL && ! IS_LSA_MAXAGE (current))
- ospf_opaque_lsa_refresh_schedule (current);
- continue;
- }
-
- /*
- * If an instance of self-originated Opaque-LSA is not found
- * in the LSDB, there are some possible cases here.
- *
- * 1) This node lost opaque-capability after restart.
- * 2) Else, a part of opaque-type is no more supported.
- * 3) Else, a part of opaque-id is no more supported.
- *
- * Anyway, it is still this node's responsibility to flush it.
- * Otherwise, the LSA instance remains in the routing domain
- * until its age reaches to MaxAge.
- */
- /* XXX: We should deal with this for *ALL* LSAs, not just opaque */
- if (current == NULL)
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("LSA[%s]: Previously originated Opaque-LSA,"
- "not found in the LSDB.", dump_lsa_key (lsa));
-
- SET_FLAG (lsa->flags, OSPF_LSA_SELF);
-
- ospf_opaque_self_originated_lsa_received (nbr, lsa);
- ospf_ls_ack_send (nbr, lsa);
-
- continue;
- }
- }
-
- /* It might be happen that received LSA is self-originated network LSA, but
- * router ID is changed. So, we should check if LSA is a network-LSA whose
- * Link State ID is one of the router's own IP interface addresses but whose
- * Advertising Router is not equal to the router's own Router ID
- * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed.
- */
-
- if(lsa->data->type == OSPF_NETWORK_LSA)
- {
- struct listnode *oinode, *oinnode;
- struct ospf_interface *out_if;
- int Flag = 0;
-
- for (ALL_LIST_ELEMENTS (oi->ospf->oiflist, oinode, oinnode, out_if))
- {
- if(out_if == NULL)
- break;
-
- if((IPV4_ADDR_SAME(&out_if->address->u.prefix4, &lsa->data->id)) &&
- (!(IPV4_ADDR_SAME(&oi->ospf->router_id, &lsa->data->adv_router))))
- {
- if(out_if->network_lsa_self)
- {
- ospf_lsa_flush_area(lsa,out_if->area);
- if(IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d",
- (void *)lsa, (int) lsa->data->type);
- ospf_lsa_discard (lsa);
- Flag = 1;
- }
- break;
- }
- }
- if(Flag)
- continue;
- }
-
- /* (5) Find the instance of this LSA that is currently contained
- in the router's link state database. If there is no
- database copy, or the received LSA is more recent than
- the database copy the following steps must be performed.
- (The sub steps from RFC 2328 section 13 step (5) will be performed in
- ospf_flood() ) */
-
- if (current == NULL ||
- (ret = ospf_lsa_more_recent (current, lsa)) < 0)
- {
- /* Actual flooding procedure. */
- if (ospf_flood (oi->ospf, nbr, current, lsa) < 0) /* Trap NSSA later. */
- DISCARD_LSA (lsa, 4);
- continue;
+static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
+ struct ospf_header *ospfh, struct stream *s,
+ struct ospf_interface *oi, u_int16_t size)
+{
+ struct ospf_neighbor *nbr;
+ struct list *lsas;
+ struct listnode *node, *nnode;
+ struct ospf_lsa *lsa = NULL;
+ /* unsigned long ls_req_found = 0; */
+
+ /* Dis-assemble the stream, update each entry, re-encapsulate for
+ * flooding */
+
+ /* Increment statistics. */
+ oi->ls_upd_in++;
+
+ /* Check neighbor. */
+ nbr = ospf_nbr_lookup(oi, iph, ospfh);
+ if (nbr == NULL) {
+ zlog_warn("Link State Update: Unknown Neighbor %s on int: %s",
+ inet_ntoa(ospfh->router_id), IF_NAME(oi));
+ return;
}
- /* (6) Else, If there is an instance of the LSA on the sending
- neighbor's Link state request list, an error has occurred in
- the Database Exchange process. In this case, restart the
- Database Exchange process by generating the neighbor event
- BadLSReq for the sending neighbor and stop processing the
- Link State Update packet. */
-
- if (ospf_ls_request_lookup (nbr, lsa))
- {
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
- zlog_warn("LSA[%s] instance exists on Link state request list",
- dump_lsa_key(lsa));
+ /* Add event to thread. */
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
+
+ /* Check neighbor state. */
+ if (nbr->state < NSM_Exchange) {
+ if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
+ zlog_debug(
+ "Link State Update: "
+ "Neighbor[%s] state %s is less than Exchange",
+ inet_ntoa(ospfh->router_id),
+ lookup_msg(ospf_nsm_state_msg, nbr->state,
+ NULL));
+ return;
+ }
- /* Clean list of LSAs. */
- ospf_upd_list_clean (lsas);
- /* this lsa is not on lsas list already. */
- ospf_lsa_discard (lsa);
- return;
+ /* Get list of LSAs from Link State Update packet. - Also perorms Stages
+ * 1 (validate LSA checksum) and 2 (check for LSA consistent type)
+ * of section 13.
+ */
+ lsas = ospf_ls_upd_list_lsa(nbr, s, oi, size);
+
+#define DISCARD_LSA(L, N) \
+ { \
+ if (IS_DEBUG_OSPF_EVENT) \
+ zlog_debug( \
+ "ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p" \
+ " Type-%d", \
+ N, (void *)lsa, (int)lsa->data->type); \
+ ospf_lsa_discard(L); \
+ continue; \
}
- /* If the received LSA is the same instance as the database copy
- (i.e., neither one is more recent) the following two steps
- should be performed: */
+ /* Process each LSA received in the one packet.
+ *
+ * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding
+ * text below are from the steps in RFC 2328, Section 13.
+ */
+ for (ALL_LIST_ELEMENTS(lsas, node, nnode, lsa)) {
+ struct ospf_lsa *ls_ret, *current;
+ int ret = 1;
+
+ if (IS_DEBUG_OSPF_NSSA) {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+ char buf3[INET_ADDRSTRLEN];
+
+ zlog_debug("LSA Type-%d from %s, ID: %s, ADV: %s",
+ lsa->data->type,
+ inet_ntop(AF_INET, &ospfh->router_id, buf1,
+ INET_ADDRSTRLEN),
+ inet_ntop(AF_INET, &lsa->data->id, buf2,
+ INET_ADDRSTRLEN),
+ inet_ntop(AF_INET, &lsa->data->adv_router,
+ buf3, INET_ADDRSTRLEN));
+ }
- if (ret == 0)
- {
- /* If the LSA is listed in the Link state retransmission list
- for the receiving adjacency, the router itself is expecting
- an acknowledgment for this LSA. The router should treat the
- received LSA as an acknowledgment by removing the LSA from
- the Link state retransmission list. This is termed an
- "implied acknowledgment". */
-
- ls_ret = ospf_ls_retransmit_lookup (nbr, lsa);
-
- if (ls_ret != NULL)
- {
- ospf_ls_retransmit_delete (nbr, ls_ret);
-
- /* Delayed acknowledgment sent if advertisement received
- from Designated Router, otherwise do nothing. */
- if (oi->state == ISM_Backup)
- if (NBR_IS_DR (nbr))
- listnode_add (oi->ls_ack, ospf_lsa_lock (lsa));
-
- DISCARD_LSA (lsa, 5);
- }
- else
- /* Acknowledge the receipt of the LSA by sending a
- Link State Acknowledgment packet back out the receiving
- interface. */
- {
- ospf_ls_ack_send (nbr, lsa);
- DISCARD_LSA (lsa, 6);
- }
- }
-
- /* The database copy is more recent. If the database copy
- has LS age equal to MaxAge and LS sequence number equal to
- MaxSequenceNumber, simply discard the received LSA without
- acknowledging it. (In this case, the LSA's LS sequence number is
- wrapping, and the MaxSequenceNumber LSA must be completely
- flushed before any new LSA instance can be introduced). */
-
- else if (ret > 0) /* Database copy is more recent */
- {
- if (IS_LSA_MAXAGE (current) &&
- current->data->ls_seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER))
- {
- DISCARD_LSA (lsa, 7);
- }
- /* Otherwise, as long as the database copy has not been sent in a
- Link State Update within the last MinLSArrival seconds, send the
- database copy back to the sending neighbor, encapsulated within
- a Link State Update Packet. The Link State Update Packet should
- be sent directly to the neighbor. In so doing, do not put the
- database copy of the LSA on the neighbor's link state
- retransmission list, and do not acknowledge the received (less
- recent) LSA instance. */
- else
- {
- if (monotime_since (¤t->tv_orig, NULL)
- >= ospf->min_ls_arrival * 1000LL)
- /* Trap NSSA type later.*/
- ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT);
- DISCARD_LSA (lsa, 8);
- }
- }
- }
+ listnode_delete(lsas,
+ lsa); /* We don't need it in list anymore */
+
+ /* (1) Validate Checksum - Done above by ospf_ls_upd_list_lsa()
+ */
+
+ /* (2) LSA Type - Done above by ospf_ls_upd_list_lsa() */
+
+ /* (3) Do not take in AS External LSAs if we are a stub or NSSA.
+ */
+
+ /* Do not take in AS NSSA if this neighbor and we are not NSSA
+ */
+
+ /* Do take in Type-7's if we are an NSSA */
+
+ /* If we are also an ABR, later translate them to a Type-5
+ * packet */
+
+ /* Later, an NSSA Re-fresh can Re-fresh Type-7's and an ABR will
+ translate them to a separate Type-5 packet. */
+
+ if (lsa->data->type == OSPF_AS_EXTERNAL_LSA)
+ /* Reject from STUB or NSSA */
+ if (nbr->oi->area->external_routing
+ != OSPF_AREA_DEFAULT) {
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_debug(
+ "Incoming External LSA Discarded: We are NSSA/STUB Area");
+ DISCARD_LSA(lsa, 1);
+ }
+
+ if (lsa->data->type == OSPF_AS_NSSA_LSA)
+ if (nbr->oi->area->external_routing != OSPF_AREA_NSSA) {
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_debug(
+ "Incoming NSSA LSA Discarded: Not NSSA Area");
+ DISCARD_LSA(lsa, 2);
+ }
+
+ /* VU229804: Router-LSA Adv-ID must be equal to LS-ID */
+ if (lsa->data->type == OSPF_ROUTER_LSA)
+ if (!IPV4_ADDR_SAME(&lsa->data->id,
+ &lsa->data->adv_router)) {
+ char buf1[INET_ADDRSTRLEN];
+ char buf2[INET_ADDRSTRLEN];
+ char buf3[INET_ADDRSTRLEN];
+
+ zlog_err(
+ "Incoming Router-LSA from %s with "
+ "Adv-ID[%s] != LS-ID[%s]",
+ inet_ntop(AF_INET, &ospfh->router_id,
+ buf1, INET_ADDRSTRLEN),
+ inet_ntop(AF_INET, &lsa->data->id, buf2,
+ INET_ADDRSTRLEN),
+ inet_ntop(AF_INET,
+ &lsa->data->adv_router, buf3,
+ INET_ADDRSTRLEN));
+ zlog_err(
+ "OSPF domain compromised by attack or corruption. "
+ "Verify correct operation of -ALL- OSPF routers.");
+ DISCARD_LSA(lsa, 0);
+ }
+
+ /* Find the LSA in the current database. */
+
+ current = ospf_lsa_lookup_by_header(oi->area, lsa->data);
+
+ /* (4) If the LSA's LS age is equal to MaxAge, and there is
+ currently
+ no instance of the LSA in the router's link state database,
+ and none of router's neighbors are in states Exchange or
+ Loading,
+ then take the following actions: */
+
+ if (IS_LSA_MAXAGE(lsa) && !current
+ && ospf_check_nbr_status(oi->ospf)) {
+ /* (4a) Response Link State Acknowledgment. */
+ ospf_ls_ack_send(nbr, lsa);
+
+ /* (4b) Discard LSA. */
+ if (IS_DEBUG_OSPF(lsa, LSA)) {
+ zlog_debug(
+ "Link State Update[%s]: LS age is equal to MaxAge.",
+ dump_lsa_key(lsa));
+ }
+ DISCARD_LSA(lsa, 3);
+ }
+
+ if (IS_OPAQUE_LSA(lsa->data->type)
+ && IPV4_ADDR_SAME(&lsa->data->adv_router,
+ &oi->ospf->router_id)) {
+ /*
+ * Even if initial flushing seems to be completed, there
+ * might
+ * be a case that self-originated LSA with MaxAge still
+ * remain
+ * in the routing domain.
+ * Just send an LSAck message to cease retransmission.
+ */
+ if (IS_LSA_MAXAGE(lsa)) {
+ zlog_warn("LSA[%s]: Boomerang effect?",
+ dump_lsa_key(lsa));
+ ospf_ls_ack_send(nbr, lsa);
+ ospf_lsa_discard(lsa);
+
+ if (current != NULL && !IS_LSA_MAXAGE(current))
+ ospf_opaque_lsa_refresh_schedule(
+ current);
+ continue;
+ }
+
+ /*
+ * If an instance of self-originated Opaque-LSA is not
+ * found
+ * in the LSDB, there are some possible cases here.
+ *
+ * 1) This node lost opaque-capability after restart.
+ * 2) Else, a part of opaque-type is no more supported.
+ * 3) Else, a part of opaque-id is no more supported.
+ *
+ * Anyway, it is still this node's responsibility to
+ * flush it.
+ * Otherwise, the LSA instance remains in the routing
+ * domain
+ * until its age reaches to MaxAge.
+ */
+ /* XXX: We should deal with this for *ALL* LSAs, not
+ * just opaque */
+ if (current == NULL) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "LSA[%s]: Previously originated Opaque-LSA,"
+ "not found in the LSDB.",
+ dump_lsa_key(lsa));
+
+ SET_FLAG(lsa->flags, OSPF_LSA_SELF);
+
+ ospf_opaque_self_originated_lsa_received(nbr,
+ lsa);
+ ospf_ls_ack_send(nbr, lsa);
+
+ continue;
+ }
+ }
+
+ /* It might be happen that received LSA is self-originated
+ * network LSA, but
+ * router ID is changed. So, we should check if LSA is a
+ * network-LSA whose
+ * Link State ID is one of the router's own IP interface
+ * addresses but whose
+ * Advertising Router is not equal to the router's own Router ID
+ * According to RFC 2328 12.4.2 and 13.4 this LSA should be
+ * flushed.
+ */
+
+ if (lsa->data->type == OSPF_NETWORK_LSA) {
+ struct listnode *oinode, *oinnode;
+ struct ospf_interface *out_if;
+ int Flag = 0;
+
+ for (ALL_LIST_ELEMENTS(oi->ospf->oiflist, oinode,
+ oinnode, out_if)) {
+ if (out_if == NULL)
+ break;
+
+ if ((IPV4_ADDR_SAME(&out_if->address->u.prefix4,
+ &lsa->data->id))
+ && (!(IPV4_ADDR_SAME(
+ &oi->ospf->router_id,
+ &lsa->data->adv_router)))) {
+ if (out_if->network_lsa_self) {
+ ospf_lsa_flush_area(
+ lsa, out_if->area);
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d",
+ (void *)lsa,
+ (int)lsa->data
+ ->type);
+ ospf_lsa_discard(lsa);
+ Flag = 1;
+ }
+ break;
+ }
+ }
+ if (Flag)
+ continue;
+ }
+
+ /* (5) Find the instance of this LSA that is currently contained
+ in the router's link state database. If there is no
+ database copy, or the received LSA is more recent than
+ the database copy the following steps must be performed.
+ (The sub steps from RFC 2328 section 13 step (5) will be
+ performed in
+ ospf_flood() ) */
+
+ if (current == NULL
+ || (ret = ospf_lsa_more_recent(current, lsa)) < 0) {
+ /* Actual flooding procedure. */
+ if (ospf_flood(oi->ospf, nbr, current, lsa)
+ < 0) /* Trap NSSA later. */
+ DISCARD_LSA(lsa, 4);
+ continue;
+ }
+
+ /* (6) Else, If there is an instance of the LSA on the sending
+ neighbor's Link state request list, an error has occurred in
+ the Database Exchange process. In this case, restart the
+ Database Exchange process by generating the neighbor event
+ BadLSReq for the sending neighbor and stop processing the
+ Link State Update packet. */
+
+ if (ospf_ls_request_lookup(nbr, lsa)) {
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_BadLSReq);
+ zlog_warn(
+ "LSA[%s] instance exists on Link state request list",
+ dump_lsa_key(lsa));
+
+ /* Clean list of LSAs. */
+ ospf_upd_list_clean(lsas);
+ /* this lsa is not on lsas list already. */
+ ospf_lsa_discard(lsa);
+ return;
+ }
+
+ /* If the received LSA is the same instance as the database copy
+ (i.e., neither one is more recent) the following two steps
+ should be performed: */
+
+ if (ret == 0) {
+ /* If the LSA is listed in the Link state retransmission
+ list
+ for the receiving adjacency, the router itself is
+ expecting
+ an acknowledgment for this LSA. The router should
+ treat the
+ received LSA as an acknowledgment by removing the LSA
+ from
+ the Link state retransmission list. This is termed
+ an
+ "implied acknowledgment". */
+
+ ls_ret = ospf_ls_retransmit_lookup(nbr, lsa);
+
+ if (ls_ret != NULL) {
+ ospf_ls_retransmit_delete(nbr, ls_ret);
+
+ /* Delayed acknowledgment sent if advertisement
+ received
+ from Designated Router, otherwise do nothing.
+ */
+ if (oi->state == ISM_Backup)
+ if (NBR_IS_DR(nbr))
+ listnode_add(
+ oi->ls_ack,
+ ospf_lsa_lock(lsa));
+
+ DISCARD_LSA(lsa, 5);
+ } else
+ /* Acknowledge the receipt of the LSA by sending a
+ Link State Acknowledgment packet back out the
+ receiving
+ interface. */
+ {
+ ospf_ls_ack_send(nbr, lsa);
+ DISCARD_LSA(lsa, 6);
+ }
+ }
+
+ /* The database copy is more recent. If the database copy
+ has LS age equal to MaxAge and LS sequence number equal to
+ MaxSequenceNumber, simply discard the received LSA without
+ acknowledging it. (In this case, the LSA's LS sequence number
+ is
+ wrapping, and the MaxSequenceNumber LSA must be completely
+ flushed before any new LSA instance can be introduced). */
+
+ else if (ret > 0) /* Database copy is more recent */
+ {
+ if (IS_LSA_MAXAGE(current)
+ && current->data->ls_seqnum
+ == htonl(OSPF_MAX_SEQUENCE_NUMBER)) {
+ DISCARD_LSA(lsa, 7);
+ }
+ /* Otherwise, as long as the database copy has not been
+ sent in a
+ Link State Update within the last MinLSArrival
+ seconds, send the
+ database copy back to the sending neighbor,
+ encapsulated within
+ a Link State Update Packet. The Link State Update
+ Packet should
+ be sent directly to the neighbor. In so doing, do not
+ put the
+ database copy of the LSA on the neighbor's link state
+ retransmission list, and do not acknowledge the
+ received (less
+ recent) LSA instance. */
+ else {
+ if (monotime_since(¤t->tv_orig, NULL)
+ >= ospf->min_ls_arrival * 1000LL)
+ /* Trap NSSA type later.*/
+ ospf_ls_upd_send_lsa(
+ nbr, current,
+ OSPF_SEND_PACKET_DIRECT);
+ DISCARD_LSA(lsa, 8);
+ }
+ }
+ }
#undef DISCARD_LSA
- assert (listcount (lsas) == 0);
- list_delete (lsas);
+ assert(listcount(lsas) == 0);
+ list_delete(lsas);
}
/* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */
-static void
-ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
- struct stream *s, struct ospf_interface *oi, u_int16_t size)
-{
- struct ospf_neighbor *nbr;
-
- /* increment statistics. */
- oi->ls_ack_in++;
-
- nbr = ospf_nbr_lookup (oi, iph, ospfh);
- if (nbr == NULL)
- {
- zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.",
- inet_ntoa (ospfh->router_id));
- return;
- }
-
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
-
- if (nbr->state < NSM_Exchange)
- {
- if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
- zlog_debug ("Link State Acknowledgment: "
- "Neighbor[%s] state %s is less than Exchange",
- inet_ntoa (ospfh->router_id),
- lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
- return;
- }
-
- while (size >= OSPF_LSA_HEADER_SIZE)
- {
- struct ospf_lsa *lsa, *lsr;
-
- lsa = ospf_lsa_new ();
- lsa->data = (struct lsa_header *) STREAM_PNT (s);
-
- /* lsah = (struct lsa_header *) STREAM_PNT (s); */
- size -= OSPF_LSA_HEADER_SIZE;
- stream_forward_getp (s, OSPF_LSA_HEADER_SIZE);
-
- if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA)
+static void ospf_ls_ack(struct ip *iph, struct ospf_header *ospfh,
+ struct stream *s, struct ospf_interface *oi,
+ u_int16_t size)
+{
+ struct ospf_neighbor *nbr;
+
+ /* increment statistics. */
+ oi->ls_ack_in++;
+
+ nbr = ospf_nbr_lookup(oi, iph, ospfh);
+ if (nbr == NULL) {
+ zlog_warn("Link State Acknowledgment: Unknown Neighbor %s.",
+ inet_ntoa(ospfh->router_id));
+ return;
+ }
+
+ /* Add event to thread. */
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
+
+ if (nbr->state < NSM_Exchange) {
+ if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
+ zlog_debug(
+ "Link State Acknowledgment: "
+ "Neighbor[%s] state %s is less than Exchange",
+ inet_ntoa(ospfh->router_id),
+ lookup_msg(ospf_nsm_state_msg, nbr->state,
+ NULL));
+ return;
+ }
+
+ while (size >= OSPF_LSA_HEADER_SIZE) {
+ struct ospf_lsa *lsa, *lsr;
+
+ lsa = ospf_lsa_new();
+ lsa->data = (struct lsa_header *)STREAM_PNT(s);
+
+ /* lsah = (struct lsa_header *) STREAM_PNT (s); */
+ size -= OSPF_LSA_HEADER_SIZE;
+ stream_forward_getp(s, OSPF_LSA_HEADER_SIZE);
+
+ if (lsa->data->type < OSPF_MIN_LSA
+ || lsa->data->type >= OSPF_MAX_LSA) {
+ lsa->data = NULL;
+ ospf_lsa_discard(lsa);
+ continue;
+ }
+
+ lsr = ospf_ls_retransmit_lookup(nbr, lsa);
+
+ if (lsr != NULL && ospf_lsa_more_recent(lsr, lsa) == 0)
+ ospf_ls_retransmit_delete(nbr, lsr);
+
+ lsa->data = NULL;
+ ospf_lsa_discard(lsa);
+ }
+
+ return;
+}
+
+static struct stream *ospf_recv_packet(int fd, struct interface **ifp,
+ struct stream *ibuf)
+{
+ int ret;
+ struct ip *iph;
+ u_int16_t ip_len;
+ ifindex_t ifindex = 0;
+ struct iovec iov;
+ /* Header and data both require alignment. */
+ char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
+ struct msghdr msgh;
+
+ memset(&msgh, 0, sizeof(struct msghdr));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = (caddr_t)buff;
+ msgh.msg_controllen = sizeof(buff);
+
+ ret = stream_recvmsg(ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE + 1);
+ if (ret < 0) {
+ zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
+ return NULL;
+ }
+ if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
{
- lsa->data = NULL;
- ospf_lsa_discard (lsa);
- continue;
- }
-
- lsr = ospf_ls_retransmit_lookup (nbr, lsa);
-
- if (lsr != NULL && ospf_lsa_more_recent (lsr, lsa) == 0)
- ospf_ls_retransmit_delete (nbr, lsr);
-
- lsa->data = NULL;
- ospf_lsa_discard (lsa);
- }
-
- return;
-}
-
-static struct stream *
-ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
-{
- int ret;
- struct ip *iph;
- u_int16_t ip_len;
- ifindex_t ifindex = 0;
- struct iovec iov;
- /* Header and data both require alignment. */
- char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
- struct msghdr msgh;
-
- memset (&msgh, 0, sizeof (struct msghdr));
- msgh.msg_iov = &iov;
- msgh.msg_iovlen = 1;
- msgh.msg_control = (caddr_t) buff;
- msgh.msg_controllen = sizeof (buff);
-
- ret = stream_recvmsg (ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE+1);
- if (ret < 0)
- {
- zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
- return NULL;
- }
- if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
- {
- zlog_warn("ospf_recv_packet: discarding runt packet of length %d "
- "(ip header size is %u)",
- ret, (u_int)sizeof(iph));
- return NULL;
- }
-
- /* Note that there should not be alignment problems with this assignment
- because this is at the beginning of the stream data buffer. */
- iph = (struct ip *) STREAM_DATA(ibuf);
- sockopt_iphdrincl_swab_systoh (iph);
-
- ip_len = iph->ip_len;
-
+ zlog_warn(
+ "ospf_recv_packet: discarding runt packet of length %d "
+ "(ip header size is %u)",
+ ret, (u_int)sizeof(iph));
+ return NULL;
+ }
+
+ /* Note that there should not be alignment problems with this assignment
+ because this is at the beginning of the stream data buffer. */
+ iph = (struct ip *)STREAM_DATA(ibuf);
+ sockopt_iphdrincl_swab_systoh(iph);
+
+ ip_len = iph->ip_len;
+
#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
- /*
- * Kernel network code touches incoming IP header parameters,
- * before protocol specific processing.
- *
- * 1) Convert byteorder to host representation.
- * --> ip_len, ip_id, ip_off
- *
- * 2) Adjust ip_len to strip IP header size!
- * --> If user process receives entire IP packet via RAW
- * socket, it must consider adding IP header size to
- * the "ip_len" field of "ip" structure.
- *
- * For more details, see <netinet/ip_input.c>.
- */
- ip_len = ip_len + (iph->ip_hl << 2);
+ /*
+ * Kernel network code touches incoming IP header parameters,
+ * before protocol specific processing.
+ *
+ * 1) Convert byteorder to host representation.
+ * --> ip_len, ip_id, ip_off
+ *
+ * 2) Adjust ip_len to strip IP header size!
+ * --> If user process receives entire IP packet via RAW
+ * socket, it must consider adding IP header size to
+ * the "ip_len" field of "ip" structure.
+ *
+ * For more details, see <netinet/ip_input.c>.
+ */
+ ip_len = ip_len + (iph->ip_hl << 2);
#endif
-
+
#if defined(__DragonFly__)
- /*
- * in DragonFly's raw socket, ip_len/ip_off are read
- * in network byte order.
- * As OpenBSD < 200311 adjust ip_len to strip IP header size!
- */
- ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
+ /*
+ * in DragonFly's raw socket, ip_len/ip_off are read
+ * in network byte order.
+ * As OpenBSD < 200311 adjust ip_len to strip IP header size!
+ */
+ ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
#endif
- ifindex = getsockopt_ifindex (AF_INET, &msgh);
-
- *ifp = if_lookup_by_index (ifindex, VRF_DEFAULT);
+ ifindex = getsockopt_ifindex(AF_INET, &msgh);
+
+ *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+
+ if (ret != ip_len) {
+ zlog_warn(
+ "ospf_recv_packet read length mismatch: ip_len is %d, "
+ "but recvmsg returned %d",
+ ip_len, ret);
+ return NULL;
+ }
- if (ret != ip_len)
- {
- zlog_warn ("ospf_recv_packet read length mismatch: ip_len is %d, "
- "but recvmsg returned %d", ip_len, ret);
- return NULL;
- }
-
- return ibuf;
+ return ibuf;
}
static struct ospf_interface *
-ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp,
- struct ip *iph, struct ospf_header *ospfh)
-{
- struct ospf_interface *rcv_oi;
- struct ospf_vl_data *vl_data;
- struct ospf_area *vl_area;
- struct listnode *node;
-
- if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) ||
- !OSPF_IS_AREA_BACKBONE (ospfh))
- return NULL;
-
- /* look for local OSPF interface matching the destination
- * to determine Area ID. We presume therefore the destination address
- * is unique, or at least (for "unnumbered" links), not used in other
- * areas
- */
- if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, NULL,
- iph->ip_dst)) == NULL)
- return NULL;
-
- for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data))
- {
- vl_area = ospf_area_lookup_by_area_id (ospf, vl_data->vl_area_id);
- if (!vl_area)
- continue;
-
- if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) &&
- IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id))
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("associating packet with %s",
- IF_NAME (vl_data->vl_oi));
- if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP))
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("This VL is not up yet, sorry");
- return NULL;
- }
-
- return vl_data->vl_oi;
+ospf_associate_packet_vl(struct ospf *ospf, struct interface *ifp,
+ struct ip *iph, struct ospf_header *ospfh)
+{
+ struct ospf_interface *rcv_oi;
+ struct ospf_vl_data *vl_data;
+ struct ospf_area *vl_area;
+ struct listnode *node;
+
+ if (IN_MULTICAST(ntohl(iph->ip_dst.s_addr))
+ || !OSPF_IS_AREA_BACKBONE(ospfh))
+ return NULL;
+
+ /* look for local OSPF interface matching the destination
+ * to determine Area ID. We presume therefore the destination address
+ * is unique, or at least (for "unnumbered" links), not used in other
+ * areas
+ */
+ if ((rcv_oi = ospf_if_lookup_by_local_addr(ospf, NULL, iph->ip_dst))
+ == NULL)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(ospf->vlinks, node, vl_data)) {
+ vl_area =
+ ospf_area_lookup_by_area_id(ospf, vl_data->vl_area_id);
+ if (!vl_area)
+ continue;
+
+ if (OSPF_AREA_SAME(&vl_area, &rcv_oi->area)
+ && IPV4_ADDR_SAME(&vl_data->vl_peer, &ospfh->router_id)) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("associating packet with %s",
+ IF_NAME(vl_data->vl_oi));
+ if (!CHECK_FLAG(vl_data->vl_oi->ifp->flags, IFF_UP)) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "This VL is not up yet, sorry");
+ return NULL;
+ }
+
+ return vl_data->vl_oi;
+ }
}
- }
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("couldn't find any VL to associate the packet with");
-
- return NULL;
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("couldn't find any VL to associate the packet with");
+
+ return NULL;
}
-static int
-ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
+static int ospf_check_area_id(struct ospf_interface *oi,
+ struct ospf_header *ospfh)
{
- /* Check match the Area ID of the receiving interface. */
- if (OSPF_AREA_SAME (&oi->area, &ospfh))
- return 1;
+ /* Check match the Area ID of the receiving interface. */
+ if (OSPF_AREA_SAME(&oi->area, &ospfh))
+ return 1;
- return 0;
+ return 0;
}
/* Unbound socket will accept any Raw IP packets if proto is matched.
To prevent it, compare src IP address and i/f address with masking
i/f network mask. */
-static int
-ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
+static int ospf_check_network_mask(struct ospf_interface *oi,
+ struct in_addr ip_src)
{
- struct in_addr mask, me, him;
+ struct in_addr mask, me, him;
- if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
- oi->type == OSPF_IFTYPE_VIRTUALLINK)
- return 1;
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT
+ || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ return 1;
- masklen2ip (oi->address->prefixlen, &mask);
+ masklen2ip(oi->address->prefixlen, &mask);
- me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
- him.s_addr = ip_src.s_addr & mask.s_addr;
+ me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+ him.s_addr = ip_src.s_addr & mask.s_addr;
- if (IPV4_ADDR_SAME (&me, &him))
- return 1;
+ if (IPV4_ADDR_SAME(&me, &him))
+ return 1;
- return 0;
+ return 0;
}
/* Return 1, if the packet is properly authenticated and checksummed,
0 otherwise. In particular, check that AuType header field is valid and
matches the locally configured AuType, and that D.5 requirements are met. */
-static int
-ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
-{
- struct crypt_key *ck;
- u_int16_t iface_auth_type;
- u_int16_t pkt_auth_type = ntohs (ospfh->auth_type);
-
- switch (pkt_auth_type)
- {
- case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */
- if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type (oi)))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null",
- IF_NAME (oi), lookup_msg(ospf_auth_type_str, iface_auth_type, NULL));
- return 0;
- }
- if (! ospf_check_sum (ospfh))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: Null auth OK, but checksum error, Router-ID %s",
- IF_NAME (oi), inet_ntoa (ospfh->router_id));
- return 0;
- }
- return 1;
- case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */
- if (OSPF_AUTH_SIMPLE != (iface_auth_type = ospf_auth_type (oi)))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Simple",
- IF_NAME (oi), lookup_msg(ospf_auth_type_str, iface_auth_type, NULL));
- return 0;
- }
- if (memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: Simple auth failed", IF_NAME (oi));
- return 0;
- }
- if (! ospf_check_sum (ospfh))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: Simple auth OK, checksum error, Router-ID %s",
- IF_NAME (oi), inet_ntoa (ospfh->router_id));
- return 0;
- }
- return 1;
- case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */
- if (OSPF_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf_auth_type (oi)))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic",
- IF_NAME (oi), lookup_msg(ospf_auth_type_str, iface_auth_type, NULL));
- return 0;
- }
- if (ospfh->checksum)
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: OSPF header checksum is not 0", IF_NAME (oi));
- return 0;
- }
- /* only MD5 crypto method can pass ospf_packet_examin() */
- if
- (
- NULL == (ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) ||
- ospfh->u.crypt.key_id != ck->key_id ||
- /* Condition above uses the last key ID on the list, which is
- different from what ospf_crypt_key_lookup() does. A bug? */
- ! ospf_check_md5_digest (oi, ospfh)
- )
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: MD5 auth failed", IF_NAME (oi));
- return 0;
- }
- return 1;
- default:
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- zlog_warn ("interface %s: invalid packet auth-type (%02x)",
- IF_NAME (oi), pkt_auth_type);
- return 0;
- }
-}
-
-static int
-ospf_check_sum (struct ospf_header *ospfh)
-{
- u_int32_t ret;
- u_int16_t sum;
-
- /* clear auth_data for checksum. */
- memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
-
- /* keep checksum and clear. */
- sum = ospfh->checksum;
- memset (&ospfh->checksum, 0, sizeof (u_int16_t));
-
- /* calculate checksum. */
- ret = in_cksum (ospfh, ntohs (ospfh->length));
-
- if (ret != sum)
- {
- zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X",
- ret, sum);
- return 0;
- }
-
- return 1;
+static int ospf_check_auth(struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+ struct crypt_key *ck;
+ u_int16_t iface_auth_type;
+ u_int16_t pkt_auth_type = ntohs(ospfh->auth_type);
+
+ switch (pkt_auth_type) {
+ case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */
+ if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type(oi))) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: auth-type mismatch, local %s, rcvd Null",
+ IF_NAME(oi),
+ lookup_msg(ospf_auth_type_str,
+ iface_auth_type, NULL));
+ return 0;
+ }
+ if (!ospf_check_sum(ospfh)) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: Null auth OK, but checksum error, Router-ID %s",
+ IF_NAME(oi),
+ inet_ntoa(ospfh->router_id));
+ return 0;
+ }
+ return 1;
+ case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */
+ if (OSPF_AUTH_SIMPLE
+ != (iface_auth_type = ospf_auth_type(oi))) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: auth-type mismatch, local %s, rcvd Simple",
+ IF_NAME(oi),
+ lookup_msg(ospf_auth_type_str,
+ iface_auth_type, NULL));
+ return 0;
+ }
+ if (memcmp(OSPF_IF_PARAM(oi, auth_simple), ospfh->u.auth_data,
+ OSPF_AUTH_SIMPLE_SIZE)) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn("interface %s: Simple auth failed",
+ IF_NAME(oi));
+ return 0;
+ }
+ if (!ospf_check_sum(ospfh)) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: Simple auth OK, checksum error, Router-ID %s",
+ IF_NAME(oi),
+ inet_ntoa(ospfh->router_id));
+ return 0;
+ }
+ return 1;
+ case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */
+ if (OSPF_AUTH_CRYPTOGRAPHIC
+ != (iface_auth_type = ospf_auth_type(oi))) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: auth-type mismatch, local %s, rcvd Cryptographic",
+ IF_NAME(oi),
+ lookup_msg(ospf_auth_type_str,
+ iface_auth_type, NULL));
+ return 0;
+ }
+ if (ospfh->checksum) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: OSPF header checksum is not 0",
+ IF_NAME(oi));
+ return 0;
+ }
+ /* only MD5 crypto method can pass ospf_packet_examin() */
+ if (
+ NULL == (ck = listgetdata(listtail(
+ OSPF_IF_PARAM(oi, auth_crypt))))
+ || ospfh->u.crypt.key_id != ck->key_id ||
+ /* Condition above uses the last key ID on the list,
+ which is
+ different from what ospf_crypt_key_lookup() does. A
+ bug? */
+ !ospf_check_md5_digest(oi, ospfh)) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn("interface %s: MD5 auth failed",
+ IF_NAME(oi));
+ return 0;
+ }
+ return 1;
+ default:
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV))
+ zlog_warn(
+ "interface %s: invalid packet auth-type (%02x)",
+ IF_NAME(oi), pkt_auth_type);
+ return 0;
+ }
+}
+
+static int ospf_check_sum(struct ospf_header *ospfh)
+{
+ u_int32_t ret;
+ u_int16_t sum;
+
+ /* clear auth_data for checksum. */
+ memset(ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+
+ /* keep checksum and clear. */
+ sum = ospfh->checksum;
+ memset(&ospfh->checksum, 0, sizeof(u_int16_t));
+
+ /* calculate checksum. */
+ ret = in_cksum(ospfh, ntohs(ospfh->length));
+
+ if (ret != sum) {
+ zlog_info("ospf_check_sum(): checksum mismatch, my %X, his %X",
+ ret, sum);
+ return 0;
+ }
+
+ return 1;
}
/* Verify, that given link/TOS records are properly sized/aligned and match
Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */
-static unsigned
-ospf_router_lsa_links_examin
-(
- struct router_lsa_link * link,
- u_int16_t linkbytes,
- const u_int16_t num_links
-)
-{
- unsigned counted_links = 0, thislinklen;
-
- while (linkbytes)
- {
- thislinklen = OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count;
- if (thislinklen > linkbytes)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: length error in link block #%u", __func__, counted_links);
- return MSG_NG;
- }
- link = (struct router_lsa_link *)((caddr_t) link + thislinklen);
- linkbytes -= thislinklen;
- counted_links++;
- }
- if (counted_links != num_links)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: %u link blocks declared, %u present",
- __func__, num_links, counted_links);
- return MSG_NG;
- }
- return MSG_OK;
+static unsigned ospf_router_lsa_links_examin(struct router_lsa_link *link,
+ u_int16_t linkbytes,
+ const u_int16_t num_links)
+{
+ unsigned counted_links = 0, thislinklen;
+
+ while (linkbytes) {
+ thislinklen =
+ OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count;
+ if (thislinklen > linkbytes) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: length error in link block #%u",
+ __func__, counted_links);
+ return MSG_NG;
+ }
+ link = (struct router_lsa_link *)((caddr_t)link + thislinklen);
+ linkbytes -= thislinklen;
+ counted_links++;
+ }
+ if (counted_links != num_links) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: %u link blocks declared, %u present",
+ __func__, num_links, counted_links);
+ return MSG_NG;
+ }
+ return MSG_OK;
}
/* Verify, that the given LSA is properly sized/aligned (including type-specific
minimum length constraint). */
-static unsigned
-ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char headeronly)
-{
- unsigned ret;
- struct router_lsa * rlsa;
- if
- (
- lsah->type < OSPF_MAX_LSA &&
- ospf_lsa_minlen[lsah->type] &&
- lsalen < OSPF_LSA_HEADER_SIZE + ospf_lsa_minlen[lsah->type]
- )
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: undersized (%u B) %s",
- __func__, lsalen, lookup_msg(ospf_lsa_type_msg, lsah->type, NULL));
- return MSG_NG;
- }
- switch (lsah->type)
- {
- case OSPF_ROUTER_LSA:
- /* RFC2328 A.4.2, LSA header + 4 bytes followed by N>=1 (12+)-byte link blocks */
- if (headeronly)
- {
- ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE) % 4 ? MSG_NG : MSG_OK;
- break;
- }
- rlsa = (struct router_lsa *) lsah;
- ret = ospf_router_lsa_links_examin
- (
- (struct router_lsa_link *) rlsa->link,
- lsalen - OSPF_LSA_HEADER_SIZE - 4, /* skip: basic header, "flags", 0, "# links" */
- ntohs (rlsa->links) /* 16 bits */
- );
- break;
- case OSPF_AS_EXTERNAL_LSA:
- /* RFC2328 A.4.5, LSA header + 4 bytes followed by N>=1 12-bytes long blocks */
- case OSPF_AS_NSSA_LSA:
- /* RFC3101 C, idem */
- ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_AS_EXTERNAL_LSA_MIN_SIZE) % 12 ? MSG_NG : MSG_OK;
- break;
- /* Following LSA types are considered OK length-wise as soon as their minimum
- * length constraint is met and length of the whole LSA is a multiple of 4
- * (basic LSA header size is already a multiple of 4). */
- case OSPF_NETWORK_LSA:
- /* RFC2328 A.4.3, LSA header + 4 bytes followed by N>=1 router-IDs */
- case OSPF_SUMMARY_LSA:
- case OSPF_ASBR_SUMMARY_LSA:
- /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */
- case OSPF_OPAQUE_LINK_LSA:
- case OSPF_OPAQUE_AREA_LSA:
- case OSPF_OPAQUE_AS_LSA:
- /* RFC5250 A.2, "some number of octets (of application-specific
- * data) padded to 32-bit alignment." This is considered equivalent
- * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt
- * file for the detailed analysis of this passage. */
- ret = lsalen % 4 ? MSG_NG : MSG_OK;
- break;
- default:
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: unsupported LSA type 0x%02x", __func__, lsah->type);
- return MSG_NG;
- }
- if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: alignment error in %s",
- __func__, lookup_msg(ospf_lsa_type_msg, lsah->type, NULL));
- return ret;
+static unsigned ospf_lsa_examin(struct lsa_header *lsah, const u_int16_t lsalen,
+ const u_char headeronly)
+{
+ unsigned ret;
+ struct router_lsa *rlsa;
+ if (lsah->type < OSPF_MAX_LSA && ospf_lsa_minlen[lsah->type]
+ && lsalen < OSPF_LSA_HEADER_SIZE + ospf_lsa_minlen[lsah->type]) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: undersized (%u B) %s", __func__, lsalen,
+ lookup_msg(ospf_lsa_type_msg, lsah->type,
+ NULL));
+ return MSG_NG;
+ }
+ switch (lsah->type) {
+ case OSPF_ROUTER_LSA:
+ /* RFC2328 A.4.2, LSA header + 4 bytes followed by N>=1
+ * (12+)-byte link blocks */
+ if (headeronly) {
+ ret = (lsalen - OSPF_LSA_HEADER_SIZE
+ - OSPF_ROUTER_LSA_MIN_SIZE)
+ % 4
+ ? MSG_NG
+ : MSG_OK;
+ break;
+ }
+ rlsa = (struct router_lsa *)lsah;
+ ret = ospf_router_lsa_links_examin(
+ (struct router_lsa_link *)rlsa->link,
+ lsalen - OSPF_LSA_HEADER_SIZE - 4, /* skip: basic
+ header, "flags",
+ 0, "# links" */
+ ntohs(rlsa->links) /* 16 bits */
+ );
+ break;
+ case OSPF_AS_EXTERNAL_LSA:
+ /* RFC2328 A.4.5, LSA header + 4 bytes followed by N>=1 12-bytes long
+ * blocks */
+ case OSPF_AS_NSSA_LSA:
+ /* RFC3101 C, idem */
+ ret = (lsalen - OSPF_LSA_HEADER_SIZE
+ - OSPF_AS_EXTERNAL_LSA_MIN_SIZE)
+ % 12
+ ? MSG_NG
+ : MSG_OK;
+ break;
+ /* Following LSA types are considered OK length-wise as soon as their
+ * minimum
+ * length constraint is met and length of the whole LSA is a multiple of
+ * 4
+ * (basic LSA header size is already a multiple of 4). */
+ case OSPF_NETWORK_LSA:
+ /* RFC2328 A.4.3, LSA header + 4 bytes followed by N>=1 router-IDs */
+ case OSPF_SUMMARY_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+ /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS
+ * blocks */
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ /* RFC5250 A.2, "some number of octets (of application-specific
+ * data) padded to 32-bit alignment." This is considered
+ * equivalent
+ * to 4-byte alignment of all other LSA types, see
+ * OSPF-ALIGNMENT.txt
+ * file for the detailed analysis of this passage. */
+ ret = lsalen % 4 ? MSG_NG : MSG_OK;
+ break;
+ default:
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: unsupported LSA type 0x%02x", __func__,
+ lsah->type);
+ return MSG_NG;
+ }
+ if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: alignment error in %s", __func__,
+ lookup_msg(ospf_lsa_type_msg, lsah->type, NULL));
+ return ret;
}
/* Verify if the provided input buffer is a valid sequence of LSAs. This
includes verification of LSA blocks length/alignment and dispatching
of deeper-level checks. */
static unsigned
-ospf_lsaseq_examin
-(
- struct lsa_header *lsah, /* start of buffered data */
- size_t length,
- const u_char headeronly,
- /* When declared_num_lsas is not 0, compare it to the real number of LSAs
- and treat the difference as an error. */
- const u_int32_t declared_num_lsas
-)
-{
- u_int32_t counted_lsas = 0;
-
- while (length)
- {
- u_int16_t lsalen;
- if (length < OSPF_LSA_HEADER_SIZE)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header",
- __func__, length, counted_lsas);
- return MSG_NG;
- }
- /* save on ntohs() calls here and in the LSA validator */
- lsalen = ntohs (lsah->length);
- if (lsalen < OSPF_LSA_HEADER_SIZE)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: malformed LSA header #%u, declared length is %u B",
- __func__, counted_lsas, lsalen);
- return MSG_NG;
- }
- if (headeronly)
- {
- /* less checks here and in ospf_lsa_examin() */
- if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 1))
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: malformed header-only LSA #%u", __func__, counted_lsas);
- return MSG_NG;
- }
- lsah = (struct lsa_header *) ((caddr_t) lsah + OSPF_LSA_HEADER_SIZE);
- length -= OSPF_LSA_HEADER_SIZE;
- }
- else
- {
- /* make sure the input buffer is deep enough before further checks */
- if (lsalen > length)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: anomaly in LSA #%u: declared length is %u B, buffered length is %zu B",
- __func__, counted_lsas, lsalen, length);
- return MSG_NG;
- }
- if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 0))
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: malformed LSA #%u", __func__, counted_lsas);
- return MSG_NG;
- }
- lsah = (struct lsa_header *) ((caddr_t) lsah + lsalen);
- length -= lsalen;
- }
- counted_lsas++;
- }
-
- if (declared_num_lsas && counted_lsas != declared_num_lsas)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)",
- __func__, declared_num_lsas, counted_lsas);
- return MSG_NG;
- }
- return MSG_OK;
+ospf_lsaseq_examin(struct lsa_header *lsah, /* start of buffered data */
+ size_t length, const u_char headeronly,
+ /* When declared_num_lsas is not 0, compare it to the real
+ number of LSAs
+ and treat the difference as an error. */
+ const u_int32_t declared_num_lsas)
+{
+ u_int32_t counted_lsas = 0;
+
+ while (length) {
+ u_int16_t lsalen;
+ if (length < OSPF_LSA_HEADER_SIZE) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: undersized (%zu B) trailing (#%u) LSA header",
+ __func__, length, counted_lsas);
+ return MSG_NG;
+ }
+ /* save on ntohs() calls here and in the LSA validator */
+ lsalen = ntohs(lsah->length);
+ if (lsalen < OSPF_LSA_HEADER_SIZE) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: malformed LSA header #%u, declared length is %u B",
+ __func__, counted_lsas, lsalen);
+ return MSG_NG;
+ }
+ if (headeronly) {
+ /* less checks here and in ospf_lsa_examin() */
+ if (MSG_OK != ospf_lsa_examin(lsah, lsalen, 1)) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: malformed header-only LSA #%u",
+ __func__, counted_lsas);
+ return MSG_NG;
+ }
+ lsah = (struct lsa_header *)((caddr_t)lsah
+ + OSPF_LSA_HEADER_SIZE);
+ length -= OSPF_LSA_HEADER_SIZE;
+ } else {
+ /* make sure the input buffer is deep enough before
+ * further checks */
+ if (lsalen > length) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: anomaly in LSA #%u: declared length is %u B, buffered length is %zu B",
+ __func__, counted_lsas, lsalen,
+ length);
+ return MSG_NG;
+ }
+ if (MSG_OK != ospf_lsa_examin(lsah, lsalen, 0)) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: malformed LSA #%u",
+ __func__, counted_lsas);
+ return MSG_NG;
+ }
+ lsah = (struct lsa_header *)((caddr_t)lsah + lsalen);
+ length -= lsalen;
+ }
+ counted_lsas++;
+ }
+
+ if (declared_num_lsas && counted_lsas != declared_num_lsas) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: #LSAs declared (%u) does not match actual (%u)",
+ __func__, declared_num_lsas, counted_lsas);
+ return MSG_NG;
+ }
+ return MSG_OK;
}
/* Verify a complete OSPF packet for proper sizing/alignment. */
-static unsigned
-ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire)
-{
- u_int16_t bytesdeclared, bytesauth;
- unsigned ret;
- struct ospf_ls_update * lsupd;
-
- /* Length, 1st approximation. */
- if (bytesonwire < OSPF_HEADER_SIZE)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire);
- return MSG_NG;
- }
- /* Now it is safe to access header fields. Performing length check, allow
- * for possible extra bytes of crypto auth/padding, which are not counted
- * in the OSPF header "length" field. */
- if (oh->version != OSPF_VERSION)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version);
- return MSG_NG;
- }
- bytesdeclared = ntohs (oh->length);
- if (ntohs (oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
- bytesauth = 0;
- else
- {
- if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: unsupported crypto auth length (%u B)",
- __func__, oh->u.crypt.auth_data_len);
- return MSG_NG;
- }
- bytesauth = OSPF_AUTH_MD5_SIZE;
- }
- if (bytesdeclared + bytesauth > bytesonwire)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: packet length error (%u real, %u+%u declared)",
- __func__, bytesonwire, bytesdeclared, bytesauth);
- return MSG_NG;
- }
- /* Length, 2nd approximation. The type-specific constraint is checked
- against declared length, not amount of bytes on wire. */
- if
- (
- oh->type >= OSPF_MSG_HELLO &&
- oh->type <= OSPF_MSG_LS_ACK &&
- bytesdeclared < OSPF_HEADER_SIZE + ospf_packet_minlen[oh->type]
- )
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: undersized (%u B) %s packet", __func__,
- bytesdeclared, lookup_msg(ospf_packet_type_str, oh->type, NULL));
- return MSG_NG;
- }
- switch (oh->type)
- {
- case OSPF_MSG_HELLO:
- /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes followed
- by N>=0 router-IDs. */
- ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK;
- break;
- case OSPF_MSG_DB_DESC:
- /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes followed
- by N>=0 header-only LSAs. */
- ret = ospf_lsaseq_examin
- (
- (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE),
- bytesdeclared - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE,
- 1, /* header-only LSAs */
- 0
- );
- break;
- case OSPF_MSG_LS_REQ:
- /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes request blocks. */
- ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) %
- OSPF_LSA_KEY_SIZE ? MSG_NG : MSG_OK;
- break;
- case OSPF_MSG_LS_UPD:
- /* RFC2328 A.3.5, packet header + OSPF_LS_UPD_MIN_SIZE bytes followed
- by N>=0 full LSAs (with N declared beforehand). */
- lsupd = (struct ospf_ls_update *) ((caddr_t) oh + OSPF_HEADER_SIZE);
- ret = ospf_lsaseq_examin
- (
- (struct lsa_header *) ((caddr_t) lsupd + OSPF_LS_UPD_MIN_SIZE),
- bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE,
- 0, /* full LSAs */
- ntohl (lsupd->num_lsas) /* 32 bits */
- );
- break;
- case OSPF_MSG_LS_ACK:
- /* RFC2328 A.3.6, packet header followed by N>=0 header-only LSAs. */
- ret = ospf_lsaseq_examin
- (
- (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_LS_ACK_MIN_SIZE),
- bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE,
- 1, /* header-only LSAs */
- 0
- );
- break;
- default:
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: invalid packet type 0x%02x", __func__, oh->type);
- return MSG_NG;
- }
- if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("%s: malformed %s packet", __func__, lookup_msg(ospf_packet_type_str, oh->type, NULL));
- return ret;
+static unsigned ospf_packet_examin(struct ospf_header *oh,
+ const unsigned bytesonwire)
+{
+ u_int16_t bytesdeclared, bytesauth;
+ unsigned ret;
+ struct ospf_ls_update *lsupd;
+
+ /* Length, 1st approximation. */
+ if (bytesonwire < OSPF_HEADER_SIZE) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: undersized (%u B) packet", __func__,
+ bytesonwire);
+ return MSG_NG;
+ }
+ /* Now it is safe to access header fields. Performing length check,
+ * allow
+ * for possible extra bytes of crypto auth/padding, which are not
+ * counted
+ * in the OSPF header "length" field. */
+ if (oh->version != OSPF_VERSION) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: invalid (%u) protocol version",
+ __func__, oh->version);
+ return MSG_NG;
+ }
+ bytesdeclared = ntohs(oh->length);
+ if (ntohs(oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+ bytesauth = 0;
+ else {
+ if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: unsupported crypto auth length (%u B)",
+ __func__, oh->u.crypt.auth_data_len);
+ return MSG_NG;
+ }
+ bytesauth = OSPF_AUTH_MD5_SIZE;
+ }
+ if (bytesdeclared + bytesauth > bytesonwire) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "%s: packet length error (%u real, %u+%u declared)",
+ __func__, bytesonwire, bytesdeclared,
+ bytesauth);
+ return MSG_NG;
+ }
+ /* Length, 2nd approximation. The type-specific constraint is checked
+ against declared length, not amount of bytes on wire. */
+ if (oh->type >= OSPF_MSG_HELLO && oh->type <= OSPF_MSG_LS_ACK
+ && bytesdeclared
+ < OSPF_HEADER_SIZE + ospf_packet_minlen[oh->type]) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: undersized (%u B) %s packet", __func__,
+ bytesdeclared,
+ lookup_msg(ospf_packet_type_str, oh->type,
+ NULL));
+ return MSG_NG;
+ }
+ switch (oh->type) {
+ case OSPF_MSG_HELLO:
+ /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes
+ followed
+ by N>=0 router-IDs. */
+ ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE)
+ % 4
+ ? MSG_NG
+ : MSG_OK;
+ break;
+ case OSPF_MSG_DB_DESC:
+ /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes
+ followed
+ by N>=0 header-only LSAs. */
+ ret = ospf_lsaseq_examin(
+ (struct lsa_header *)((caddr_t)oh + OSPF_HEADER_SIZE
+ + OSPF_DB_DESC_MIN_SIZE),
+ bytesdeclared - OSPF_HEADER_SIZE
+ - OSPF_DB_DESC_MIN_SIZE,
+ 1, /* header-only LSAs */
+ 0);
+ break;
+ case OSPF_MSG_LS_REQ:
+ /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes
+ * request blocks. */
+ ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE)
+ % OSPF_LSA_KEY_SIZE
+ ? MSG_NG
+ : MSG_OK;
+ break;
+ case OSPF_MSG_LS_UPD:
+ /* RFC2328 A.3.5, packet header + OSPF_LS_UPD_MIN_SIZE bytes
+ followed
+ by N>=0 full LSAs (with N declared beforehand). */
+ lsupd = (struct ospf_ls_update *)((caddr_t)oh
+ + OSPF_HEADER_SIZE);
+ ret = ospf_lsaseq_examin(
+ (struct lsa_header *)((caddr_t)lsupd
+ + OSPF_LS_UPD_MIN_SIZE),
+ bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE,
+ 0, /* full LSAs */
+ ntohl(lsupd->num_lsas) /* 32 bits */
+ );
+ break;
+ case OSPF_MSG_LS_ACK:
+ /* RFC2328 A.3.6, packet header followed by N>=0 header-only
+ * LSAs. */
+ ret = ospf_lsaseq_examin(
+ (struct lsa_header *)((caddr_t)oh + OSPF_HEADER_SIZE
+ + OSPF_LS_ACK_MIN_SIZE),
+ bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE,
+ 1, /* header-only LSAs */
+ 0);
+ break;
+ default:
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: invalid packet type 0x%02x", __func__,
+ oh->type);
+ return MSG_NG;
+ }
+ if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug("%s: malformed %s packet", __func__,
+ lookup_msg(ospf_packet_type_str, oh->type, NULL));
+ return ret;
}
/* OSPF Header verification. */
-static int
-ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
- struct ip *iph, struct ospf_header *ospfh)
-{
- /* Check Area ID. */
- if (!ospf_check_area_id (oi, ospfh))
- {
- zlog_warn ("interface %s: ospf_read invalid Area ID %s.",
- IF_NAME (oi), inet_ntoa (ospfh->area_id));
- return -1;
- }
+static int ospf_verify_header(struct stream *ibuf, struct ospf_interface *oi,
+ struct ip *iph, struct ospf_header *ospfh)
+{
+ /* Check Area ID. */
+ if (!ospf_check_area_id(oi, ospfh)) {
+ zlog_warn("interface %s: ospf_read invalid Area ID %s.",
+ IF_NAME(oi), inet_ntoa(ospfh->area_id));
+ return -1;
+ }
- /* Check network mask, Silently discarded. */
- if (! ospf_check_network_mask (oi, iph->ip_src))
- {
- zlog_warn ("interface %s: ospf_read network address is not same [%s]",
- IF_NAME (oi), inet_ntoa (iph->ip_src));
- return -1;
- }
+ /* Check network mask, Silently discarded. */
+ if (!ospf_check_network_mask(oi, iph->ip_src)) {
+ zlog_warn(
+ "interface %s: ospf_read network address is not same [%s]",
+ IF_NAME(oi), inet_ntoa(iph->ip_src));
+ return -1;
+ }
- /* Check authentication. The function handles logging actions, where required. */
- if (! ospf_check_auth (oi, ospfh))
- return -1;
+ /* Check authentication. The function handles logging actions, where
+ * required. */
+ if (!ospf_check_auth(oi, ospfh))
+ return -1;
- return 0;
+ return 0;
}
/* Starting point of packet process function. */
-int
-ospf_read (struct thread *thread)
-{
- int ret;
- struct stream *ibuf;
- struct ospf *ospf;
- struct ospf_interface *oi;
- struct ip *iph;
- struct ospf_header *ospfh;
- u_int16_t length;
- struct interface *ifp;
- struct connected *c;
-
- /* first of all get interface pointer. */
- ospf = THREAD_ARG (thread);
-
- /* prepare for next packet. */
- ospf->t_read = NULL;
- thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read);
-
- stream_reset(ospf->ibuf);
- if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf)))
- return -1;
- /* This raw packet is known to be at least as big as its IP header. */
-
- /* Note that there should not be alignment problems with this assignment
- because this is at the beginning of the stream data buffer. */
- iph = (struct ip *) STREAM_DATA (ibuf);
- /* Note that sockopt_iphdrincl_swab_systoh was called in ospf_recv_packet. */
-
- if (ifp == NULL)
- {
- /* Handle cases where the platform does not support retrieving the ifindex,
- and also platforms (such as Solaris 8) that claim to support ifindex
- retrieval but do not. */
- c = if_lookup_address ((void *)&iph->ip_src, AF_INET, VRF_DEFAULT);
- if (c)
- ifp = c->ifp;
- if (ifp == NULL)
+int ospf_read(struct thread *thread)
+{
+ int ret;
+ struct stream *ibuf;
+ struct ospf *ospf;
+ struct ospf_interface *oi;
+ struct ip *iph;
+ struct ospf_header *ospfh;
+ u_int16_t length;
+ struct interface *ifp;
+ struct connected *c;
+
+ /* first of all get interface pointer. */
+ ospf = THREAD_ARG(thread);
+
+ /* prepare for next packet. */
+ ospf->t_read = NULL;
+ thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read);
+
+ stream_reset(ospf->ibuf);
+ if (!(ibuf = ospf_recv_packet(ospf->fd, &ifp, ospf->ibuf)))
+ return -1;
+ /* This raw packet is known to be at least as big as its IP header. */
+
+ /* Note that there should not be alignment problems with this assignment
+ because this is at the beginning of the stream data buffer. */
+ iph = (struct ip *)STREAM_DATA(ibuf);
+ /* Note that sockopt_iphdrincl_swab_systoh was called in
+ * ospf_recv_packet. */
+
+ if (ifp == NULL) {
+ /* Handle cases where the platform does not support retrieving
+ the ifindex,
+ and also platforms (such as Solaris 8) that claim to support
+ ifindex
+ retrieval but do not. */
+ c = if_lookup_address((void *)&iph->ip_src, AF_INET,
+ VRF_DEFAULT);
+ if (c)
+ ifp = c->ifp;
+ if (ifp == NULL)
+ return 0;
+ }
+
+ /* IP Header dump. */
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ ospf_ip_header_dump(iph);
+
+ /* Self-originated packet should be discarded silently. */
+ if (ospf_if_lookup_by_local_addr(ospf, NULL, iph->ip_src)) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV)) {
+ zlog_debug(
+ "ospf_read[%s]: Dropping self-originated packet",
+ inet_ntoa(iph->ip_src));
+ }
+ return 0;
+ }
+
+ /* Advance from IP header to OSPF header (iph->ip_hl has been verified
+ by ospf_recv_packet() to be correct). */
+ stream_forward_getp(ibuf, iph->ip_hl * 4);
+
+ ospfh = (struct ospf_header *)STREAM_PNT(ibuf);
+ if (MSG_OK
+ != ospf_packet_examin(
+ ospfh, stream_get_endp(ibuf) - stream_get_getp(ibuf)))
+ return -1;
+ /* Now it is safe to access all fields of OSPF packet header. */
+
+ /* associate packet with ospf interface */
+ oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp);
+
+ /* ospf_verify_header() relies on a valid "oi" and thus can be called
+ only
+ after the passive/backbone/other checks below are passed. These
+ checks
+ in turn access the fields of unverified "ospfh" structure for their
+ own
+ purposes and must remain very accurate in doing this. */
+
+ /* If incoming interface is passive one, ignore it. */
+ if (oi && OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) {
+ char buf[3][INET_ADDRSTRLEN];
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "ignoring packet from router %s sent to %s, "
+ "received on a passive interface, %s",
+ inet_ntop(AF_INET, &ospfh->router_id, buf[0],
+ sizeof(buf[0])),
+ inet_ntop(AF_INET, &iph->ip_dst, buf[1],
+ sizeof(buf[1])),
+ inet_ntop(AF_INET, &oi->address->u.prefix4,
+ buf[2], sizeof(buf[2])));
+
+ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) {
+ /* Try to fix multicast membership.
+ * Some OS:es may have problems in this area,
+ * make sure it is removed.
+ */
+ OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
+ ospf_if_set_multicast(oi);
+ }
+ return 0;
+ }
+
+
+ /* if no local ospf_interface,
+ * or header area is backbone but ospf_interface is not
+ * check for VLINK interface
+ */
+ if ((oi == NULL) || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
+ && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) {
+ if ((oi = ospf_associate_packet_vl(ospf, ifp, iph, ospfh))
+ == NULL) {
+ if (!ospf->instance && IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "Packet from [%s] received on link %s"
+ " but no ospf_interface",
+ inet_ntoa(iph->ip_src), ifp->name);
+ return 0;
+ }
+ }
+
+ /* else it must be a local ospf interface, check it was received on
+ * correct link
+ */
+ else if (oi->ifp != ifp) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_warn("Packet from [%s] received on wrong link %s",
+ inet_ntoa(iph->ip_src), ifp->name);
+ return 0;
+ } else if (oi->state == ISM_Down) {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_warn(
+ "Ignoring packet from %s to %s received on interface that is "
+ "down [%s]; interface flags are %s",
+ inet_ntop(AF_INET, &iph->ip_src, buf[0],
+ sizeof(buf[0])),
+ inet_ntop(AF_INET, &iph->ip_dst, buf[1],
+ sizeof(buf[1])),
+ ifp->name, if_flag_dump(ifp->flags));
+ /* Fix multicast memberships? */
+ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
+ OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
+ else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
+ OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
+ if (oi->multicast_memberships)
+ ospf_if_set_multicast(oi);
+ return 0;
+ }
+
+ /*
+ * If the received packet is destined for AllDRouters, the packet
+ * should be accepted only if the received ospf interface state is
+ * either DR or Backup -- endo.
+ */
+ if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS)
+ && (oi->state != ISM_DR && oi->state != ISM_Backup)) {
+ zlog_warn(
+ "Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)",
+ inet_ntoa(iph->ip_src), IF_NAME(oi),
+ lookup_msg(ospf_ism_state_msg, oi->state, NULL));
+ /* Try to fix multicast membership. */
+ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+ ospf_if_set_multicast(oi);
+ return 0;
+ }
+
+ /* Verify more OSPF header fields. */
+ ret = ospf_verify_header(ibuf, oi, iph, ospfh);
+ if (ret < 0) {
+ if (IS_DEBUG_OSPF_PACKET(0, RECV))
+ zlog_debug(
+ "ospf_read[%s]: Header check failed, "
+ "dropping.",
+ inet_ntoa(iph->ip_src));
+ return ret;
+ }
+
+ /* Show debug receiving packet. */
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, RECV)) {
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, DETAIL)) {
+ zlog_debug(
+ "-----------------------------------------------------");
+ ospf_packet_dump(ibuf);
+ }
+
+ zlog_debug("%s received from [%s] via [%s]",
+ lookup_msg(ospf_packet_type_str, ospfh->type, NULL),
+ inet_ntoa(ospfh->router_id), IF_NAME(oi));
+ zlog_debug(" src [%s],", inet_ntoa(iph->ip_src));
+ zlog_debug(" dst [%s]", inet_ntoa(iph->ip_dst));
+
+ if (IS_DEBUG_OSPF_PACKET(ospfh->type - 1, DETAIL))
+ zlog_debug(
+ "-----------------------------------------------------");
+ }
+
+ stream_forward_getp(ibuf, OSPF_HEADER_SIZE);
+
+ /* Adjust size to message length. */
+ length = ntohs(ospfh->length) - OSPF_HEADER_SIZE;
+
+ /* Read rest of the packet and call each sort of packet routine. */
+ switch (ospfh->type) {
+ case OSPF_MSG_HELLO:
+ ospf_hello(iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_DB_DESC:
+ ospf_db_desc(iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_LS_REQ:
+ ospf_ls_req(iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_LS_UPD:
+ ospf_ls_upd(ospf, iph, ospfh, ibuf, oi, length);
+ break;
+ case OSPF_MSG_LS_ACK:
+ ospf_ls_ack(iph, ospfh, ibuf, oi, length);
+ break;
+ default:
+ zlog_warn("interface %s: OSPF packet header type %d is illegal",
+ IF_NAME(oi), ospfh->type);
+ break;
+ }
+
return 0;
- }
-
- /* IP Header dump. */
- if (IS_DEBUG_OSPF_PACKET(0, RECV))
- ospf_ip_header_dump (iph);
-
- /* Self-originated packet should be discarded silently. */
- if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src))
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- {
- zlog_debug ("ospf_read[%s]: Dropping self-originated packet",
- inet_ntoa (iph->ip_src));
- }
- return 0;
- }
-
- /* Advance from IP header to OSPF header (iph->ip_hl has been verified
- by ospf_recv_packet() to be correct). */
- stream_forward_getp (ibuf, iph->ip_hl * 4);
-
- ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
- if (MSG_OK != ospf_packet_examin (ospfh, stream_get_endp (ibuf) - stream_get_getp (ibuf)))
- return -1;
- /* Now it is safe to access all fields of OSPF packet header. */
-
- /* associate packet with ospf interface */
- oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp);
-
- /* ospf_verify_header() relies on a valid "oi" and thus can be called only
- after the passive/backbone/other checks below are passed. These checks
- in turn access the fields of unverified "ospfh" structure for their own
- purposes and must remain very accurate in doing this. */
-
- /* If incoming interface is passive one, ignore it. */
- if (oi && OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
- {
- char buf[3][INET_ADDRSTRLEN];
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ignoring packet from router %s sent to %s, "
- "received on a passive interface, %s",
- inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])),
- inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
- inet_ntop(AF_INET, &oi->address->u.prefix4,
- buf[2], sizeof(buf[2])));
-
- if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
- {
- /* Try to fix multicast membership.
- * Some OS:es may have problems in this area,
- * make sure it is removed.
- */
- OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
- ospf_if_set_multicast(oi);
- }
- return 0;
- }
-
-
- /* if no local ospf_interface,
- * or header area is backbone but ospf_interface is not
- * check for VLINK interface
- */
- if ( (oi == NULL) ||
- (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
- && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))
- )
- {
- if ((oi = ospf_associate_packet_vl (ospf, ifp, iph, ospfh)) == NULL)
- {
- if (!ospf->instance && IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Packet from [%s] received on link %s"
- " but no ospf_interface",
- inet_ntoa (iph->ip_src), ifp->name);
- return 0;
- }
- }
-
- /* else it must be a local ospf interface, check it was received on
- * correct link
- */
- else if (oi->ifp != ifp)
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_warn ("Packet from [%s] received on wrong link %s",
- inet_ntoa (iph->ip_src), ifp->name);
- return 0;
- }
- else if (oi->state == ISM_Down)
- {
- char buf[2][INET_ADDRSTRLEN];
- zlog_warn ("Ignoring packet from %s to %s received on interface that is "
- "down [%s]; interface flags are %s",
- inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])),
- inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
- ifp->name, if_flag_dump(ifp->flags));
- /* Fix multicast memberships? */
- if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
- OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
- else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
- OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
- if (oi->multicast_memberships)
- ospf_if_set_multicast(oi);
- return 0;
- }
-
- /*
- * If the received packet is destined for AllDRouters, the packet
- * should be accepted only if the received ospf interface state is
- * either DR or Backup -- endo.
- */
- if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS)
- && (oi->state != ISM_DR && oi->state != ISM_Backup))
- {
- zlog_warn ("Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)",
- inet_ntoa (iph->ip_src), IF_NAME (oi),
- lookup_msg(ospf_ism_state_msg, oi->state, NULL));
- /* Try to fix multicast membership. */
- SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
- ospf_if_set_multicast(oi);
- return 0;
- }
-
- /* Verify more OSPF header fields. */
- ret = ospf_verify_header (ibuf, oi, iph, ospfh);
- if (ret < 0)
- {
- if (IS_DEBUG_OSPF_PACKET (0, RECV))
- zlog_debug ("ospf_read[%s]: Header check failed, "
- "dropping.",
- inet_ntoa (iph->ip_src));
- return ret;
- }
-
- /* Show debug receiving packet. */
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
- {
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
- {
- zlog_debug ("-----------------------------------------------------");
- ospf_packet_dump (ibuf);
- }
-
- zlog_debug ("%s received from [%s] via [%s]",
- lookup_msg(ospf_packet_type_str, ospfh->type, NULL),
- inet_ntoa (ospfh->router_id), IF_NAME (oi));
- zlog_debug (" src [%s],", inet_ntoa (iph->ip_src));
- zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst));
-
- if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
- zlog_debug ("-----------------------------------------------------");
- }
-
- stream_forward_getp (ibuf, OSPF_HEADER_SIZE);
-
- /* Adjust size to message length. */
- length = ntohs (ospfh->length) - OSPF_HEADER_SIZE;
-
- /* Read rest of the packet and call each sort of packet routine. */
- switch (ospfh->type)
- {
- case OSPF_MSG_HELLO:
- ospf_hello (iph, ospfh, ibuf, oi, length);
- break;
- case OSPF_MSG_DB_DESC:
- ospf_db_desc (iph, ospfh, ibuf, oi, length);
- break;
- case OSPF_MSG_LS_REQ:
- ospf_ls_req (iph, ospfh, ibuf, oi, length);
- break;
- case OSPF_MSG_LS_UPD:
- ospf_ls_upd (ospf, iph, ospfh, ibuf, oi, length);
- break;
- case OSPF_MSG_LS_ACK:
- ospf_ls_ack (iph, ospfh, ibuf, oi, length);
- break;
- default:
- zlog_warn("interface %s: OSPF packet header type %d is illegal",
- IF_NAME(oi), ospfh->type);
- break;
- }
-
- return 0;
}
/* Make OSPF header. */
-static void
-ospf_make_header (int type, struct ospf_interface *oi, struct stream *s)
+static void ospf_make_header(int type, struct ospf_interface *oi,
+ struct stream *s)
{
- struct ospf_header *ospfh;
+ struct ospf_header *ospfh;
- ospfh = (struct ospf_header *) STREAM_DATA (s);
+ ospfh = (struct ospf_header *)STREAM_DATA(s);
- ospfh->version = (u_char) OSPF_VERSION;
- ospfh->type = (u_char) type;
+ ospfh->version = (u_char)OSPF_VERSION;
+ ospfh->type = (u_char)type;
- ospfh->router_id = oi->ospf->router_id;
+ ospfh->router_id = oi->ospf->router_id;
- ospfh->checksum = 0;
- ospfh->area_id = oi->area->area_id;
- ospfh->auth_type = htons (ospf_auth_type (oi));
+ ospfh->checksum = 0;
+ ospfh->area_id = oi->area->area_id;
+ ospfh->auth_type = htons(ospf_auth_type(oi));
- memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
+ memset(ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
- stream_forward_endp (s, OSPF_HEADER_SIZE);
+ stream_forward_endp(s, OSPF_HEADER_SIZE);
}
/* Make Authentication Data. */
-static int
-ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
-{
- struct crypt_key *ck;
-
- switch (ospf_auth_type (oi))
- {
- case OSPF_AUTH_NULL:
- /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */
- break;
- case OSPF_AUTH_SIMPLE:
- memcpy (ospfh->u.auth_data, OSPF_IF_PARAM (oi, auth_simple),
- OSPF_AUTH_SIMPLE_SIZE);
- break;
- case OSPF_AUTH_CRYPTOGRAPHIC:
- /* If key is not set, then set 0. */
- if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
- {
- ospfh->u.crypt.zero = 0;
- ospfh->u.crypt.key_id = 0;
- ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
- }
- else
- {
- ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt)));
- ospfh->u.crypt.zero = 0;
- ospfh->u.crypt.key_id = ck->key_id;
- ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+static int ospf_make_auth(struct ospf_interface *oi, struct ospf_header *ospfh)
+{
+ struct crypt_key *ck;
+
+ switch (ospf_auth_type(oi)) {
+ case OSPF_AUTH_NULL:
+ /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data));
+ */
+ break;
+ case OSPF_AUTH_SIMPLE:
+ memcpy(ospfh->u.auth_data, OSPF_IF_PARAM(oi, auth_simple),
+ OSPF_AUTH_SIMPLE_SIZE);
+ break;
+ case OSPF_AUTH_CRYPTOGRAPHIC:
+ /* If key is not set, then set 0. */
+ if (list_isempty(OSPF_IF_PARAM(oi, auth_crypt))) {
+ ospfh->u.crypt.zero = 0;
+ ospfh->u.crypt.key_id = 0;
+ ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+ } else {
+ ck = listgetdata(
+ listtail(OSPF_IF_PARAM(oi, auth_crypt)));
+ ospfh->u.crypt.zero = 0;
+ ospfh->u.crypt.key_id = ck->key_id;
+ ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
+ }
+ /* note: the seq is done in ospf_make_md5_digest() */
+ break;
+ default:
+ /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data));
+ */
+ break;
}
- /* note: the seq is done in ospf_make_md5_digest() */
- break;
- default:
- /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */
- break;
- }
- return 0;
+ return 0;
}
/* Fill rest of OSPF header. */
-static void
-ospf_fill_header (struct ospf_interface *oi,
- struct stream *s, u_int16_t length)
-{
- struct ospf_header *ospfh;
-
- ospfh = (struct ospf_header *) STREAM_DATA (s);
-
- /* Fill length. */
- ospfh->length = htons (length);
-
- /* Calculate checksum. */
- if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
- ospfh->checksum = in_cksum (ospfh, length);
- else
- ospfh->checksum = 0;
-
- /* Add Authentication Data. */
- ospf_make_auth (oi, ospfh);
-}
-
-static int
-ospf_make_hello (struct ospf_interface *oi, struct stream *s)
-{
- struct ospf_neighbor *nbr;
- struct route_node *rn;
- u_int16_t length = OSPF_HELLO_MIN_SIZE;
- struct in_addr mask;
- unsigned long p;
- int flag = 0;
-
- /* Set netmask of interface. */
- if (!(CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED) &&
- oi->type == OSPF_IFTYPE_POINTOPOINT) &&
- oi->type != OSPF_IFTYPE_VIRTUALLINK)
- masklen2ip (oi->address->prefixlen, &mask);
- else
- memset ((char *) &mask, 0, sizeof (struct in_addr));
- stream_put_ipv4 (s, mask.s_addr);
-
- /* Set Hello Interval. */
- if (OSPF_IF_PARAM (oi, fast_hello) == 0)
- stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
- else
- stream_putw (s, 0); /* hello-interval of 0 for fast-hellos */
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("make_hello: options: %x, int: %s",
- OPTIONS(oi), IF_NAME (oi));
-
- /* Set Options. */
- stream_putc (s, OPTIONS (oi));
-
- /* Set Router Priority. */
- stream_putc (s, PRIORITY (oi));
-
- /* Set Router Dead Interval. */
- stream_putl (s, OSPF_IF_PARAM (oi, v_wait));
-
- /* Set Designated Router. */
- stream_put_ipv4 (s, DR (oi).s_addr);
-
- p = stream_get_endp (s);
-
- /* Set Backup Designated Router. */
- stream_put_ipv4 (s, BDR (oi).s_addr);
-
- /* Add neighbor seen. */
- for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
- if ((nbr = rn->info))
- if (nbr->router_id.s_addr != 0) /* Ignore 0.0.0.0 node. */
- if (nbr->state != NSM_Attempt) /* Ignore Down neighbor. */
- if (nbr->state != NSM_Down) /* This is myself for DR election. */
- if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id))
- {
- /* Check neighbor is sane? */
- if (nbr->d_router.s_addr != 0
- && IPV4_ADDR_SAME (&nbr->d_router, &oi->address->u.prefix4)
- && IPV4_ADDR_SAME (&nbr->bd_router, &oi->address->u.prefix4))
- flag = 1;
-
- stream_put_ipv4 (s, nbr->router_id.s_addr);
- length += 4;
- }
-
- /* Let neighbor generate BackupSeen. */
- if (flag == 1)
- stream_putl_at (s, p, 0); /* ipv4 address, normally */
-
- return length;
-}
-
-static int
-ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
- struct stream *s)
-{
- struct ospf_lsa *lsa;
- u_int16_t length = OSPF_DB_DESC_MIN_SIZE;
- u_char options;
- unsigned long pp;
- int i;
- struct ospf_lsdb *lsdb;
-
- /* Set Interface MTU. */
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- stream_putw (s, 0);
- else
- stream_putw (s, oi->ifp->mtu);
-
- /* Set Options. */
- options = OPTIONS (oi);
- if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE))
- SET_FLAG (options, OSPF_OPTION_O);
- stream_putc (s, options);
-
- /* DD flags */
- pp = stream_get_endp (s);
- stream_putc (s, nbr->dd_flags);
-
- /* Set DD Sequence Number. */
- stream_putl (s, nbr->dd_seqnum);
-
- /* shortcut unneeded walk of (empty) summary LSDBs */
- if (ospf_db_summary_isempty (nbr))
- goto empty;
-
- /* Describe LSA Header from Database Summary List. */
- lsdb = &nbr->db_sum;
-
- for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
- {
- struct route_table *table = lsdb->type[i].db;
- struct route_node *rn;
-
- for (rn = route_top (table); rn; rn = route_next (rn))
- if ((lsa = rn->info) != NULL)
- {
- if (IS_OPAQUE_LSA (lsa->data->type)
- && (! CHECK_FLAG (options, OSPF_OPTION_O)))
- {
- /* Suppress advertising opaque-informations. */
- /* Remove LSA from DB summary list. */
- ospf_lsdb_delete (lsdb, lsa);
- continue;
- }
-
- if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD))
- {
- struct lsa_header *lsah;
- u_int16_t ls_age;
-
- /* DD packet overflows interface MTU. */
- if (length + OSPF_LSA_HEADER_SIZE > ospf_packet_max (oi))
- break;
-
- /* Keep pointer to LS age. */
- lsah = (struct lsa_header *) (STREAM_DATA (s) +
- stream_get_endp (s));
-
- /* Proceed stream pointer. */
- stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
- length += OSPF_LSA_HEADER_SIZE;
-
- /* Set LS age. */
- ls_age = LS_AGE (lsa);
- lsah->ls_age = htons (ls_age);
-
- }
-
- /* Remove LSA from DB summary list. */
- ospf_lsdb_delete (lsdb, lsa);
- }
- }
-
- /* Update 'More' bit */
- if (ospf_db_summary_isempty (nbr))
- {
-empty:
- if (nbr->state >= NSM_Exchange)
- {
- UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_M);
- /* Rewrite DD flags */
- stream_putc_at (s, pp, nbr->dd_flags);
- }
- else
- {
- assert (IS_SET_DD_M(nbr->dd_flags));
- }
- }
- return length;
-}
-
-static int
-ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
- unsigned long delta, struct ospf_neighbor *nbr,
- struct ospf_lsa *lsa)
-{
- struct ospf_interface *oi;
-
- oi = nbr->oi;
-
- /* LS Request packet overflows interface MTU. */
- if (*length + delta > ospf_packet_max(oi))
- return 0;
-
- stream_putl (s, lsa->data->type);
- stream_put_ipv4 (s, lsa->data->id.s_addr);
- stream_put_ipv4 (s, lsa->data->adv_router.s_addr);
-
- ospf_lsa_unlock (&nbr->ls_req_last);
- nbr->ls_req_last = ospf_lsa_lock (lsa);
-
- *length += 12;
- return 1;
-}
-
-static int
-ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s)
-{
- struct ospf_lsa *lsa;
- u_int16_t length = OSPF_LS_REQ_MIN_SIZE;
- unsigned long delta = stream_get_endp(s)+12;
- struct route_table *table;
- struct route_node *rn;
- int i;
- struct ospf_lsdb *lsdb;
-
- lsdb = &nbr->ls_req;
-
- for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
- {
- table = lsdb->type[i].db;
- for (rn = route_top (table); rn; rn = route_next (rn))
- if ((lsa = (rn->info)) != NULL)
- if (ospf_make_ls_req_func (s, &length, delta, nbr, lsa) == 0)
- {
- route_unlock_node (rn);
- break;
- }
- }
- return length;
-}
-
-static int
-ls_age_increment (struct ospf_lsa *lsa, int delay)
-{
- int age;
-
- age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay;
-
- return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
-}
-
-static int
-ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream *s)
-{
- struct ospf_lsa *lsa;
- struct listnode *node;
- u_int16_t length = 0;
- unsigned int size_noauth;
- unsigned long delta = stream_get_endp (s);
- unsigned long pp;
- int count = 0;
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_make_ls_upd: Start");
-
- pp = stream_get_endp (s);
- stream_forward_endp (s, OSPF_LS_UPD_MIN_SIZE);
- length += OSPF_LS_UPD_MIN_SIZE;
+static void ospf_fill_header(struct ospf_interface *oi, struct stream *s,
+ u_int16_t length)
+{
+ struct ospf_header *ospfh;
+
+ ospfh = (struct ospf_header *)STREAM_DATA(s);
+
+ /* Fill length. */
+ ospfh->length = htons(length);
+
+ /* Calculate checksum. */
+ if (ntohs(ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC)
+ ospfh->checksum = in_cksum(ospfh, length);
+ else
+ ospfh->checksum = 0;
+
+ /* Add Authentication Data. */
+ ospf_make_auth(oi, ospfh);
+}
+
+static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
+{
+ struct ospf_neighbor *nbr;
+ struct route_node *rn;
+ u_int16_t length = OSPF_HELLO_MIN_SIZE;
+ struct in_addr mask;
+ unsigned long p;
+ int flag = 0;
+
+ /* Set netmask of interface. */
+ if (!(CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)
+ && oi->type == OSPF_IFTYPE_POINTOPOINT)
+ && oi->type != OSPF_IFTYPE_VIRTUALLINK)
+ masklen2ip(oi->address->prefixlen, &mask);
+ else
+ memset((char *)&mask, 0, sizeof(struct in_addr));
+ stream_put_ipv4(s, mask.s_addr);
+
+ /* Set Hello Interval. */
+ if (OSPF_IF_PARAM(oi, fast_hello) == 0)
+ stream_putw(s, OSPF_IF_PARAM(oi, v_hello));
+ else
+ stream_putw(s, 0); /* hello-interval of 0 for fast-hellos */
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("make_hello: options: %x, int: %s", OPTIONS(oi),
+ IF_NAME(oi));
+
+ /* Set Options. */
+ stream_putc(s, OPTIONS(oi));
+
+ /* Set Router Priority. */
+ stream_putc(s, PRIORITY(oi));
+
+ /* Set Router Dead Interval. */
+ stream_putl(s, OSPF_IF_PARAM(oi, v_wait));
+
+ /* Set Designated Router. */
+ stream_put_ipv4(s, DR(oi).s_addr);
+
+ p = stream_get_endp(s);
+
+ /* Set Backup Designated Router. */
+ stream_put_ipv4(s, BDR(oi).s_addr);
+
+ /* Add neighbor seen. */
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
+ if ((nbr = rn->info))
+ if (nbr->router_id.s_addr
+ != 0) /* Ignore 0.0.0.0 node. */
+ if (nbr->state
+ != NSM_Attempt) /* Ignore Down neighbor. */
+ if (nbr->state
+ != NSM_Down) /* This is myself for
+ DR election. */
+ if (!IPV4_ADDR_SAME(
+ &nbr->router_id,
+ &oi->ospf->router_id)) {
+ /* Check neighbor is
+ * sane? */
+ if (nbr->d_router.s_addr
+ != 0
+ && IPV4_ADDR_SAME(
+ &nbr->d_router,
+ &oi->address
+ ->u
+ .prefix4)
+ && IPV4_ADDR_SAME(
+ &nbr->bd_router,
+ &oi->address
+ ->u
+ .prefix4))
+ flag = 1;
+
+ stream_put_ipv4(
+ s,
+ nbr->router_id
+ .s_addr);
+ length += 4;
+ }
+
+ /* Let neighbor generate BackupSeen. */
+ if (flag == 1)
+ stream_putl_at(s, p, 0); /* ipv4 address, normally */
+
+ return length;
+}
+
+static int ospf_make_db_desc(struct ospf_interface *oi,
+ struct ospf_neighbor *nbr, struct stream *s)
+{
+ struct ospf_lsa *lsa;
+ u_int16_t length = OSPF_DB_DESC_MIN_SIZE;
+ u_char options;
+ unsigned long pp;
+ int i;
+ struct ospf_lsdb *lsdb;
+
+ /* Set Interface MTU. */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ stream_putw(s, 0);
+ else
+ stream_putw(s, oi->ifp->mtu);
+
+ /* Set Options. */
+ options = OPTIONS(oi);
+ if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE))
+ SET_FLAG(options, OSPF_OPTION_O);
+ stream_putc(s, options);
+
+ /* DD flags */
+ pp = stream_get_endp(s);
+ stream_putc(s, nbr->dd_flags);
+
+ /* Set DD Sequence Number. */
+ stream_putl(s, nbr->dd_seqnum);
+
+ /* shortcut unneeded walk of (empty) summary LSDBs */
+ if (ospf_db_summary_isempty(nbr))
+ goto empty;
+
+ /* Describe LSA Header from Database Summary List. */
+ lsdb = &nbr->db_sum;
+
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
+ struct route_table *table = lsdb->type[i].db;
+ struct route_node *rn;
+
+ for (rn = route_top(table); rn; rn = route_next(rn))
+ if ((lsa = rn->info) != NULL) {
+ if (IS_OPAQUE_LSA(lsa->data->type)
+ && (!CHECK_FLAG(options, OSPF_OPTION_O))) {
+ /* Suppress advertising
+ * opaque-informations. */
+ /* Remove LSA from DB summary list. */
+ ospf_lsdb_delete(lsdb, lsa);
+ continue;
+ }
+
+ if (!CHECK_FLAG(lsa->flags, OSPF_LSA_DISCARD)) {
+ struct lsa_header *lsah;
+ u_int16_t ls_age;
+
+ /* DD packet overflows interface MTU. */
+ if (length + OSPF_LSA_HEADER_SIZE
+ > ospf_packet_max(oi))
+ break;
+
+ /* Keep pointer to LS age. */
+ lsah = (struct lsa_header
+ *)(STREAM_DATA(s)
+ + stream_get_endp(
+ s));
+
+ /* Proceed stream pointer. */
+ stream_put(s, lsa->data,
+ OSPF_LSA_HEADER_SIZE);
+ length += OSPF_LSA_HEADER_SIZE;
+
+ /* Set LS age. */
+ ls_age = LS_AGE(lsa);
+ lsah->ls_age = htons(ls_age);
+ }
+
+ /* Remove LSA from DB summary list. */
+ ospf_lsdb_delete(lsdb, lsa);
+ }
+ }
- /* Calculate amount of packet usable for data. */
- size_noauth = stream_get_size(s) - ospf_packet_authspace(oi);
+ /* Update 'More' bit */
+ if (ospf_db_summary_isempty(nbr)) {
+ empty:
+ if (nbr->state >= NSM_Exchange) {
+ UNSET_FLAG(nbr->dd_flags, OSPF_DD_FLAG_M);
+ /* Rewrite DD flags */
+ stream_putc_at(s, pp, nbr->dd_flags);
+ } else {
+ assert(IS_SET_DD_M(nbr->dd_flags));
+ }
+ }
+ return length;
+}
- while ((node = listhead (update)) != NULL)
- {
- struct lsa_header *lsah;
- u_int16_t ls_age;
+static int ospf_make_ls_req_func(struct stream *s, u_int16_t *length,
+ unsigned long delta, struct ospf_neighbor *nbr,
+ struct ospf_lsa *lsa)
+{
+ struct ospf_interface *oi;
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_make_ls_upd: List Iteration %d", count);
+ oi = nbr->oi;
- lsa = listgetdata (node);
+ /* LS Request packet overflows interface MTU. */
+ if (*length + delta > ospf_packet_max(oi))
+ return 0;
- assert (lsa->data);
+ stream_putl(s, lsa->data->type);
+ stream_put_ipv4(s, lsa->data->id.s_addr);
+ stream_put_ipv4(s, lsa->data->adv_router.s_addr);
- /* Will it fit? */
- if (length + delta + ntohs (lsa->data->length) > size_noauth)
- break;
+ ospf_lsa_unlock(&nbr->ls_req_last);
+ nbr->ls_req_last = ospf_lsa_lock(lsa);
- /* Keep pointer to LS age. */
- lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_endp (s));
+ *length += 12;
+ return 1;
+}
- /* Put LSA to Link State Request. */
- stream_put (s, lsa->data, ntohs (lsa->data->length));
+static int ospf_make_ls_req(struct ospf_neighbor *nbr, struct stream *s)
+{
+ struct ospf_lsa *lsa;
+ u_int16_t length = OSPF_LS_REQ_MIN_SIZE;
+ unsigned long delta = stream_get_endp(s) + 12;
+ struct route_table *table;
+ struct route_node *rn;
+ int i;
+ struct ospf_lsdb *lsdb;
- /* Set LS age. */
- /* each hop must increment an lsa_age by transmit_delay
- of OSPF interface */
- ls_age = ls_age_increment (lsa, OSPF_IF_PARAM (oi, transmit_delay));
- lsah->ls_age = htons (ls_age);
+ lsdb = &nbr->ls_req;
- length += ntohs (lsa->data->length);
- count++;
+ for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
+ table = lsdb->type[i].db;
+ for (rn = route_top(table); rn; rn = route_next(rn))
+ if ((lsa = (rn->info)) != NULL)
+ if (ospf_make_ls_req_func(s, &length, delta,
+ nbr, lsa)
+ == 0) {
+ route_unlock_node(rn);
+ break;
+ }
+ }
+ return length;
+}
- list_delete_node (update, node);
- ospf_lsa_unlock (&lsa); /* oi->ls_upd_queue */
- }
+static int ls_age_increment(struct ospf_lsa *lsa, int delay)
+{
+ int age;
- /* Now set #LSAs. */
- stream_putl_at (s, pp, count);
+ age = IS_LSA_MAXAGE(lsa) ? OSPF_LSA_MAXAGE : LS_AGE(lsa) + delay;
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_make_ls_upd: Stop");
- return length;
+ return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
}
-static int
-ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s)
+static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update,
+ struct stream *s)
{
- struct listnode *node, *nnode;
- u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
- unsigned long delta = stream_get_endp(s) + 24;
- struct ospf_lsa *lsa;
+ struct ospf_lsa *lsa;
+ struct listnode *node;
+ u_int16_t length = 0;
+ unsigned int size_noauth;
+ unsigned long delta = stream_get_endp(s);
+ unsigned long pp;
+ int count = 0;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("ospf_make_ls_upd: Start");
+
+ pp = stream_get_endp(s);
+ stream_forward_endp(s, OSPF_LS_UPD_MIN_SIZE);
+ length += OSPF_LS_UPD_MIN_SIZE;
+
+ /* Calculate amount of packet usable for data. */
+ size_noauth = stream_get_size(s) - ospf_packet_authspace(oi);
+
+ while ((node = listhead(update)) != NULL) {
+ struct lsa_header *lsah;
+ u_int16_t ls_age;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("ospf_make_ls_upd: List Iteration %d",
+ count);
+
+ lsa = listgetdata(node);
+
+ assert(lsa->data);
+
+ /* Will it fit? */
+ if (length + delta + ntohs(lsa->data->length) > size_noauth)
+ break;
+
+ /* Keep pointer to LS age. */
+ lsah = (struct lsa_header *)(STREAM_DATA(s)
+ + stream_get_endp(s));
+
+ /* Put LSA to Link State Request. */
+ stream_put(s, lsa->data, ntohs(lsa->data->length));
- for (ALL_LIST_ELEMENTS (ack, node, nnode, lsa))
- {
- assert (lsa);
-
- if (length + delta > ospf_packet_max (oi))
- break;
-
- stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
- length += OSPF_LSA_HEADER_SIZE;
-
- listnode_delete (ack, lsa);
- ospf_lsa_unlock (&lsa); /* oi->ls_ack_direct.ls_ack */
- }
-
- return length;
+ /* Set LS age. */
+ /* each hop must increment an lsa_age by transmit_delay
+ of OSPF interface */
+ ls_age = ls_age_increment(lsa,
+ OSPF_IF_PARAM(oi, transmit_delay));
+ lsah->ls_age = htons(ls_age);
+
+ length += ntohs(lsa->data->length);
+ count++;
+
+ list_delete_node(update, node);
+ ospf_lsa_unlock(&lsa); /* oi->ls_upd_queue */
+ }
+
+ /* Now set #LSAs. */
+ stream_putl_at(s, pp, count);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("ospf_make_ls_upd: Stop");
+ return length;
}
-static void
-ospf_hello_send_sub (struct ospf_interface *oi, in_addr_t addr)
+static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack,
+ struct stream *s)
{
- struct ospf_packet *op;
- u_int16_t length = OSPF_HEADER_SIZE;
+ struct listnode *node, *nnode;
+ u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
+ unsigned long delta = stream_get_endp(s) + 24;
+ struct ospf_lsa *lsa;
- op = ospf_packet_new (oi->ifp->mtu);
+ for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) {
+ assert(lsa);
- /* Prepare OSPF common header. */
- ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
+ if (length + delta > ospf_packet_max(oi))
+ break;
- /* Prepare OSPF Hello body. */
- length += ospf_make_hello (oi, op->s);
+ stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE);
+ length += OSPF_LSA_HEADER_SIZE;
+
+ listnode_delete(ack, lsa);
+ ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */
+ }
+
+ return length;
+}
+
+static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr)
+{
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
- /* Fill OSPF header. */
- ospf_fill_header (oi, op->s, length);
+ op = ospf_packet_new(oi->ifp->mtu);
- /* Set packet length. */
- op->length = length;
+ /* Prepare OSPF common header. */
+ ospf_make_header(OSPF_MSG_HELLO, oi, op->s);
- op->dst.s_addr = addr;
+ /* Prepare OSPF Hello body. */
+ length += ospf_make_hello(oi, op->s);
- /* Add packet to the top of the interface output queue, so that they
- * can't get delayed by things like long queues of LS Update packets
- */
- ospf_packet_add_top (oi, op);
+ /* Fill OSPF header. */
+ ospf_fill_header(oi, op->s, length);
- /* Hook thread to write packet. */
- OSPF_ISM_WRITE_ON (oi->ospf);
+ /* Set packet length. */
+ op->length = length;
+
+ op->dst.s_addr = addr;
+
+ /* Add packet to the top of the interface output queue, so that they
+ * can't get delayed by things like long queues of LS Update packets
+ */
+ ospf_packet_add_top(oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON(oi->ospf);
}
-static void
-ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
+static void ospf_poll_send(struct ospf_nbr_nbma *nbr_nbma)
{
- struct ospf_interface *oi;
+ struct ospf_interface *oi;
- oi = nbr_nbma->oi;
- assert(oi);
+ oi = nbr_nbma->oi;
+ assert(oi);
- /* If this is passive interface, do not send OSPF Hello. */
- if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
- return;
+ /* If this is passive interface, do not send OSPF Hello. */
+ if (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE)
+ return;
- if (oi->type != OSPF_IFTYPE_NBMA)
- return;
+ if (oi->type != OSPF_IFTYPE_NBMA)
+ return;
- if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down)
- return;
+ if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down)
+ return;
- if (PRIORITY(oi) == 0)
- return;
+ if (PRIORITY(oi) == 0)
+ return;
- if (nbr_nbma->priority == 0
- && oi->state != ISM_DR && oi->state != ISM_Backup)
- return;
+ if (nbr_nbma->priority == 0 && oi->state != ISM_DR
+ && oi->state != ISM_Backup)
+ return;
- ospf_hello_send_sub (oi, nbr_nbma->addr.s_addr);
+ ospf_hello_send_sub(oi, nbr_nbma->addr.s_addr);
}
-int
-ospf_poll_timer (struct thread *thread)
+int ospf_poll_timer(struct thread *thread)
{
- struct ospf_nbr_nbma *nbr_nbma;
+ struct ospf_nbr_nbma *nbr_nbma;
- nbr_nbma = THREAD_ARG (thread);
- nbr_nbma->t_poll = NULL;
+ nbr_nbma = THREAD_ARG(thread);
+ nbr_nbma->t_poll = NULL;
- if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
- zlog_debug("NSM[%s:%s]: Timer (Poll timer expire)", IF_NAME(nbr_nbma->oi),
- inet_ntoa(nbr_nbma->addr));
+ if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
+ zlog_debug("NSM[%s:%s]: Timer (Poll timer expire)",
+ IF_NAME(nbr_nbma->oi), inet_ntoa(nbr_nbma->addr));
- ospf_poll_send (nbr_nbma);
+ ospf_poll_send(nbr_nbma);
- if (nbr_nbma->v_poll > 0)
- OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
- nbr_nbma->v_poll);
+ if (nbr_nbma->v_poll > 0)
+ OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer,
+ nbr_nbma->v_poll);
- return 0;
+ return 0;
}
-int
-ospf_hello_reply_timer (struct thread *thread)
+int ospf_hello_reply_timer(struct thread *thread)
{
- struct ospf_neighbor *nbr;
+ struct ospf_neighbor *nbr;
- nbr = THREAD_ARG (thread);
- nbr->t_hello_reply = NULL;
+ nbr = THREAD_ARG(thread);
+ nbr->t_hello_reply = NULL;
- assert (nbr->oi);
+ assert(nbr->oi);
- if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
- zlog_debug("NSM[%s:%s]: Timer (hello-reply timer expire)",
- IF_NAME(nbr->oi), inet_ntoa(nbr->router_id));
+ if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
+ zlog_debug("NSM[%s:%s]: Timer (hello-reply timer expire)",
+ IF_NAME(nbr->oi), inet_ntoa(nbr->router_id));
- ospf_hello_send_sub (nbr->oi, nbr->address.u.prefix4.s_addr);
+ ospf_hello_send_sub(nbr->oi, nbr->address.u.prefix4.s_addr);
- return 0;
+ return 0;
}
/* Send OSPF Hello. */
-void
-ospf_hello_send (struct ospf_interface *oi)
-{
- /* If this is passive interface, do not send OSPF Hello. */
- if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
- return;
-
- if (oi->type == OSPF_IFTYPE_NBMA)
- {
- struct ospf_neighbor *nbr;
- struct route_node *rn;
-
- for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
- if ((nbr = rn->info))
- if (nbr != oi->nbr_self)
- if (nbr->state != NSM_Down)
- {
- /* RFC 2328 Section 9.5.1
- If the router is not eligible to become Designated Router,
- it must periodically send Hello Packets to both the
- Designated Router and the Backup Designated Router (if they
- exist). */
- if (PRIORITY(oi) == 0 &&
- IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) &&
- IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4))
- continue;
-
- /* If the router is eligible to become Designated Router, it
- must periodically send Hello Packets to all neighbors that
- are also eligible. In addition, if the router is itself the
- Designated Router or Backup Designated Router, it must also
- send periodic Hello Packets to all other neighbors. */
-
- if (nbr->priority == 0 && oi->state == ISM_DROther)
- continue;
- /* if oi->state == Waiting, send hello to all neighbors */
- ospf_hello_send_sub (oi, nbr->address.u.prefix4.s_addr);
- }
- }
- else
- {
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- ospf_hello_send_sub (oi, oi->vl_data->peer_addr.s_addr);
- else
- ospf_hello_send_sub (oi, htonl (OSPF_ALLSPFROUTERS));
- }
+void ospf_hello_send(struct ospf_interface *oi)
+{
+ /* If this is passive interface, do not send OSPF Hello. */
+ if (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE)
+ return;
+
+ if (oi->type == OSPF_IFTYPE_NBMA) {
+ struct ospf_neighbor *nbr;
+ struct route_node *rn;
+
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
+ if ((nbr = rn->info))
+ if (nbr != oi->nbr_self)
+ if (nbr->state != NSM_Down) {
+ /* RFC 2328 Section 9.5.1
+ If the router is not
+ eligible to become Designated
+ Router,
+ it must periodically send
+ Hello Packets to both the
+ Designated Router and the
+ Backup Designated Router (if
+ they
+ exist). */
+ if (PRIORITY(oi) == 0
+ && IPV4_ADDR_CMP(
+ &DR(oi),
+ &nbr->address.u
+ .prefix4)
+ && IPV4_ADDR_CMP(
+ &BDR(oi),
+ &nbr->address.u
+ .prefix4))
+ continue;
+
+ /* If the router is eligible to
+ become Designated Router, it
+ must periodically send Hello
+ Packets to all neighbors that
+ are also eligible. In
+ addition, if the router is
+ itself the
+ Designated Router or Backup
+ Designated Router, it must
+ also
+ send periodic Hello Packets
+ to all other neighbors. */
+
+ if (nbr->priority == 0
+ && oi->state == ISM_DROther)
+ continue;
+ /* if oi->state == Waiting, send
+ * hello to all neighbors */
+ ospf_hello_send_sub(
+ oi,
+ nbr->address.u.prefix4
+ .s_addr);
+ }
+ } else {
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ ospf_hello_send_sub(oi, oi->vl_data->peer_addr.s_addr);
+ else
+ ospf_hello_send_sub(oi, htonl(OSPF_ALLSPFROUTERS));
+ }
}
/* Send OSPF Database Description. */
-void
-ospf_db_desc_send (struct ospf_neighbor *nbr)
+void ospf_db_desc_send(struct ospf_neighbor *nbr)
{
- struct ospf_interface *oi;
- struct ospf_packet *op;
- u_int16_t length = OSPF_HEADER_SIZE;
+ struct ospf_interface *oi;
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
- oi = nbr->oi;
- op = ospf_packet_new (oi->ifp->mtu);
+ oi = nbr->oi;
+ op = ospf_packet_new(oi->ifp->mtu);
- /* Prepare OSPF common header. */
- ospf_make_header (OSPF_MSG_DB_DESC, oi, op->s);
+ /* Prepare OSPF common header. */
+ ospf_make_header(OSPF_MSG_DB_DESC, oi, op->s);
- /* Prepare OSPF Database Description body. */
- length += ospf_make_db_desc (oi, nbr, op->s);
+ /* Prepare OSPF Database Description body. */
+ length += ospf_make_db_desc(oi, nbr, op->s);
- /* Fill OSPF header. */
- ospf_fill_header (oi, op->s, length);
+ /* Fill OSPF header. */
+ ospf_fill_header(oi, op->s, length);
- /* Set packet length. */
- op->length = length;
+ /* Set packet length. */
+ op->length = length;
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else
- op->dst = nbr->address.u.prefix4;
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ op->dst = nbr->address.u.prefix4;
- /* Add packet to the interface output queue. */
- ospf_packet_add (oi, op);
+ /* Add packet to the interface output queue. */
+ ospf_packet_add(oi, op);
- /* Hook thread to write packet. */
- OSPF_ISM_WRITE_ON (oi->ospf);
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON(oi->ospf);
- /* Remove old DD packet, then copy new one and keep in neighbor structure. */
- if (nbr->last_send)
- ospf_packet_free (nbr->last_send);
- nbr->last_send = ospf_packet_dup (op);
- monotime(&nbr->last_send_ts);
+ /* Remove old DD packet, then copy new one and keep in neighbor
+ * structure. */
+ if (nbr->last_send)
+ ospf_packet_free(nbr->last_send);
+ nbr->last_send = ospf_packet_dup(op);
+ monotime(&nbr->last_send_ts);
}
/* Re-send Database Description. */
-void
-ospf_db_desc_resend (struct ospf_neighbor *nbr)
+void ospf_db_desc_resend(struct ospf_neighbor *nbr)
{
- struct ospf_interface *oi;
+ struct ospf_interface *oi;
- oi = nbr->oi;
+ oi = nbr->oi;
- /* Add packet to the interface output queue. */
- ospf_packet_add (oi, ospf_packet_dup (nbr->last_send));
+ /* Add packet to the interface output queue. */
+ ospf_packet_add(oi, ospf_packet_dup(nbr->last_send));
- /* Hook thread to write packet. */
- OSPF_ISM_WRITE_ON (oi->ospf);
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON(oi->ospf);
}
/* Send Link State Request. */
-void
-ospf_ls_req_send (struct ospf_neighbor *nbr)
+void ospf_ls_req_send(struct ospf_neighbor *nbr)
{
- struct ospf_interface *oi;
- struct ospf_packet *op;
- u_int16_t length = OSPF_HEADER_SIZE;
+ struct ospf_interface *oi;
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
- oi = nbr->oi;
- op = ospf_packet_new (oi->ifp->mtu);
+ oi = nbr->oi;
+ op = ospf_packet_new(oi->ifp->mtu);
- /* Prepare OSPF common header. */
- ospf_make_header (OSPF_MSG_LS_REQ, oi, op->s);
+ /* Prepare OSPF common header. */
+ ospf_make_header(OSPF_MSG_LS_REQ, oi, op->s);
- /* Prepare OSPF Link State Request body. */
- length += ospf_make_ls_req (nbr, op->s);
- if (length == OSPF_HEADER_SIZE)
- {
- ospf_packet_free (op);
- return;
- }
+ /* Prepare OSPF Link State Request body. */
+ length += ospf_make_ls_req(nbr, op->s);
+ if (length == OSPF_HEADER_SIZE) {
+ ospf_packet_free(op);
+ return;
+ }
- /* Fill OSPF header. */
- ospf_fill_header (oi, op->s, length);
+ /* Fill OSPF header. */
+ ospf_fill_header(oi, op->s, length);
- /* Set packet length. */
- op->length = length;
+ /* Set packet length. */
+ op->length = length;
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else
- op->dst = nbr->address.u.prefix4;
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ op->dst = nbr->address.u.prefix4;
- /* Add packet to the interface output queue. */
- ospf_packet_add (oi, op);
+ /* Add packet to the interface output queue. */
+ ospf_packet_add(oi, op);
- /* Hook thread to write packet. */
- OSPF_ISM_WRITE_ON (oi->ospf);
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON(oi->ospf);
- /* Add Link State Request Retransmission Timer. */
- OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
+ /* Add Link State Request Retransmission Timer. */
+ OSPF_NSM_TIMER_ON(nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req);
}
/* Send Link State Update with an LSA. */
-void
-ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
- int flag)
+void ospf_ls_upd_send_lsa(struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
+ int flag)
{
- struct list *update;
+ struct list *update;
- update = list_new ();
+ update = list_new();
- listnode_add (update, lsa);
- ospf_ls_upd_send (nbr, update, flag);
+ listnode_add(update, lsa);
+ ospf_ls_upd_send(nbr, update, flag);
- list_delete (update);
+ list_delete(update);
}
/* Determine size for packet. Must be at least big enough to accomodate next
* NULL if we can not allocate, eg because LSA is bigger than imposed limit
* on packet sizes (in which case offending LSA is deleted from update list)
*/
-static struct ospf_packet *
-ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi)
-{
- struct ospf_lsa *lsa;
- struct listnode *ln;
- size_t size;
- static char warned = 0;
-
- lsa = listgetdata((ln = listhead (update)));
- assert (lsa->data);
-
- if ((OSPF_LS_UPD_MIN_SIZE + ntohs (lsa->data->length))
- > ospf_packet_max (oi))
- {
- if (!warned)
- {
- zlog_warn ("ospf_ls_upd_packet_new: oversized LSA encountered!"
- "will need to fragment. Not optimal. Try divide up"
- " your network with areas. Use 'debug ospf packet send'"
- " to see details, or look at 'show ip ospf database ..'");
- warned = 1;
- }
-
- if (IS_DEBUG_OSPF_PACKET (0, SEND))
- zlog_debug ("ospf_ls_upd_packet_new: oversized LSA id:%s,"
- " %d bytes originated by %s, will be fragmented!",
- inet_ntoa (lsa->data->id),
- ntohs (lsa->data->length),
- inet_ntoa (lsa->data->adv_router));
-
- /*
- * Allocate just enough to fit this LSA only, to avoid including other
- * LSAs in fragmented LSA Updates.
- */
- size = ntohs (lsa->data->length) + (oi->ifp->mtu - ospf_packet_max (oi))
- + OSPF_LS_UPD_MIN_SIZE;
- }
- else
- size = oi->ifp->mtu;
-
- if (size > OSPF_MAX_PACKET_SIZE)
- {
- zlog_warn ("ospf_ls_upd_packet_new: oversized LSA id:%s too big,"
- " %d bytes, packet size %ld, dropping it completely."
- " OSPF routing is broken!",
- inet_ntoa (lsa->data->id), ntohs (lsa->data->length),
- (long int) size);
- list_delete_node (update, ln);
- return NULL;
- }
-
- /* IP header is built up separately by ospf_write(). This means, that we must
- * reduce the "affordable" size just calculated by length of an IP header.
- * This makes sure, that even if we manage to fill the payload with LSA data
- * completely, the final packet (our data plus IP header) still fits into
- * outgoing interface MTU. This correction isn't really meaningful for an
- * oversized LSA, but for consistency the correction is done for both cases.
- *
- * P.S. OSPF_MAX_PACKET_SIZE above already includes IP header size
- */
- return ospf_packet_new (size - sizeof (struct ip));
-}
-
-static void
-ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update,
- struct in_addr addr)
-{
- struct ospf_packet *op;
- u_int16_t length = OSPF_HEADER_SIZE;
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("listcount = %d, [%s]dst %s", listcount (update), IF_NAME(oi),
- inet_ntoa(addr));
-
- op = ospf_ls_upd_packet_new (update, oi);
-
- /* Prepare OSPF common header. */
- ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s);
-
- /* Prepare OSPF Link State Update body.
- * Includes Type-7 translation.
- */
- length += ospf_make_ls_upd (oi, update, op->s);
-
- /* Fill OSPF header. */
- ospf_fill_header (oi, op->s, length);
-
- /* Set packet length. */
- op->length = length;
-
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else
- op->dst.s_addr = addr.s_addr;
-
- /* Add packet to the interface output queue. */
- ospf_packet_add (oi, op);
-
- /* Hook thread to write packet. */
- OSPF_ISM_WRITE_ON (oi->ospf);
-}
-
-static int
-ospf_ls_upd_send_queue_event (struct thread *thread)
-{
- struct ospf_interface *oi = THREAD_ARG(thread);
- struct route_node *rn;
- struct route_node *rnext;
- struct list *update;
- char again = 0;
-
- oi->t_ls_upd_event = NULL;
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_ls_upd_send_queue start");
-
- for (rn = route_top (oi->ls_upd_queue); rn; rn = rnext)
- {
- rnext = route_next (rn);
-
- if (rn->info == NULL)
- continue;
-
- update = (struct list *)rn->info;
-
- ospf_ls_upd_queue_send (oi, update, rn->p.u.prefix4);
-
- /* list might not be empty. */
- if (listcount(update) == 0)
- {
- list_delete (rn->info);
- rn->info = NULL;
- route_unlock_node (rn);
- }
- else
- again = 1;
- }
-
- if (again != 0)
- {
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_ls_upd_send_queue: update lists not cleared,"
- " %d nodes to try again, raising new event", again);
- oi->t_ls_upd_event = NULL;
- thread_add_event(master, ospf_ls_upd_send_queue_event, oi, 0,
- &oi->t_ls_upd_event);
- }
-
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("ospf_ls_upd_send_queue stop");
-
- return 0;
-}
-
-void
-ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag)
-{
- struct ospf_interface *oi;
- struct ospf_lsa *lsa;
- struct prefix_ipv4 p;
- struct route_node *rn;
- struct listnode *node;
-
- oi = nbr->oi;
-
- p.family = AF_INET;
- p.prefixlen = IPV4_MAX_BITLEN;
-
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- p.prefix = oi->vl_data->peer_addr;
- else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else if (flag == OSPF_SEND_PACKET_DIRECT)
- p.prefix = nbr->address.u.prefix4;
- else if (oi->state == ISM_DR || oi->state == ISM_Backup)
- p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
- p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else
- p.prefix.s_addr = htonl (OSPF_ALLDROUTERS);
-
- if (oi->type == OSPF_IFTYPE_NBMA)
- {
- if (flag == OSPF_SEND_PACKET_INDIRECT)
- zlog_warn ("* LS-Update is directly sent on NBMA network.");
- if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr))
- zlog_warn ("* LS-Update is sent to myself.");
- }
-
- rn = route_node_get (oi->ls_upd_queue, (struct prefix *) &p);
-
- if (rn->info == NULL)
- rn->info = list_new ();
- else
- route_unlock_node (rn);
-
- for (ALL_LIST_ELEMENTS_RO (update, node, lsa))
- listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */
-
- thread_add_event(master, ospf_ls_upd_send_queue_event, oi, 0,
- &oi->t_ls_upd_event);
-}
-
-static void
-ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack,
- struct in_addr dst)
-{
- struct ospf_packet *op;
- u_int16_t length = OSPF_HEADER_SIZE;
-
- op = ospf_packet_new (oi->ifp->mtu);
-
- /* Prepare OSPF common header. */
- ospf_make_header (OSPF_MSG_LS_ACK, oi, op->s);
-
- /* Prepare OSPF Link State Acknowledgment body. */
- length += ospf_make_ls_ack (oi, ack, op->s);
-
- /* Fill OSPF header. */
- ospf_fill_header (oi, op->s, length);
-
- /* Set packet length. */
- op->length = length;
-
- /* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else
- op->dst.s_addr = dst.s_addr;
-
- /* Add packet to the interface output queue. */
- ospf_packet_add (oi, op);
+static struct ospf_packet *ospf_ls_upd_packet_new(struct list *update,
+ struct ospf_interface *oi)
+{
+ struct ospf_lsa *lsa;
+ struct listnode *ln;
+ size_t size;
+ static char warned = 0;
+
+ lsa = listgetdata((ln = listhead(update)));
+ assert(lsa->data);
+
+ if ((OSPF_LS_UPD_MIN_SIZE + ntohs(lsa->data->length))
+ > ospf_packet_max(oi)) {
+ if (!warned) {
+ zlog_warn(
+ "ospf_ls_upd_packet_new: oversized LSA encountered!"
+ "will need to fragment. Not optimal. Try divide up"
+ " your network with areas. Use 'debug ospf packet send'"
+ " to see details, or look at 'show ip ospf database ..'");
+ warned = 1;
+ }
+
+ if (IS_DEBUG_OSPF_PACKET(0, SEND))
+ zlog_debug(
+ "ospf_ls_upd_packet_new: oversized LSA id:%s,"
+ " %d bytes originated by %s, will be fragmented!",
+ inet_ntoa(lsa->data->id),
+ ntohs(lsa->data->length),
+ inet_ntoa(lsa->data->adv_router));
+
+ /*
+ * Allocate just enough to fit this LSA only, to avoid including
+ * other
+ * LSAs in fragmented LSA Updates.
+ */
+ size = ntohs(lsa->data->length)
+ + (oi->ifp->mtu - ospf_packet_max(oi))
+ + OSPF_LS_UPD_MIN_SIZE;
+ } else
+ size = oi->ifp->mtu;
+
+ if (size > OSPF_MAX_PACKET_SIZE) {
+ zlog_warn(
+ "ospf_ls_upd_packet_new: oversized LSA id:%s too big,"
+ " %d bytes, packet size %ld, dropping it completely."
+ " OSPF routing is broken!",
+ inet_ntoa(lsa->data->id), ntohs(lsa->data->length),
+ (long int)size);
+ list_delete_node(update, ln);
+ return NULL;
+ }
- /* Hook thread to write packet. */
- OSPF_ISM_WRITE_ON (oi->ospf);
+ /* IP header is built up separately by ospf_write(). This means, that we
+ * must
+ * reduce the "affordable" size just calculated by length of an IP
+ * header.
+ * This makes sure, that even if we manage to fill the payload with LSA
+ * data
+ * completely, the final packet (our data plus IP header) still fits
+ * into
+ * outgoing interface MTU. This correction isn't really meaningful for
+ * an
+ * oversized LSA, but for consistency the correction is done for both
+ * cases.
+ *
+ * P.S. OSPF_MAX_PACKET_SIZE above already includes IP header size
+ */
+ return ospf_packet_new(size - sizeof(struct ip));
}
-static int
-ospf_ls_ack_send_event (struct thread *thread)
+static void ospf_ls_upd_queue_send(struct ospf_interface *oi,
+ struct list *update, struct in_addr addr)
{
- struct ospf_interface *oi = THREAD_ARG (thread);
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("listcount = %d, [%s]dst %s", listcount(update),
+ IF_NAME(oi), inet_ntoa(addr));
+
+ op = ospf_ls_upd_packet_new(update, oi);
- oi->t_ls_ack_direct = NULL;
-
- while (listcount (oi->ls_ack_direct.ls_ack))
- ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack,
- oi->ls_ack_direct.dst);
+ /* Prepare OSPF common header. */
+ ospf_make_header(OSPF_MSG_LS_UPD, oi, op->s);
- return 0;
+ /* Prepare OSPF Link State Update body.
+ * Includes Type-7 translation.
+ */
+ length += ospf_make_ls_upd(oi, update, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header(oi, op->s, length);
+
+ /* Set packet length. */
+ op->length = length;
+
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ op->dst.s_addr = addr.s_addr;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add(oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON(oi->ospf);
+}
+
+static int ospf_ls_upd_send_queue_event(struct thread *thread)
+{
+ struct ospf_interface *oi = THREAD_ARG(thread);
+ struct route_node *rn;
+ struct route_node *rnext;
+ struct list *update;
+ char again = 0;
+
+ oi->t_ls_upd_event = NULL;
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("ospf_ls_upd_send_queue start");
+
+ for (rn = route_top(oi->ls_upd_queue); rn; rn = rnext) {
+ rnext = route_next(rn);
+
+ if (rn->info == NULL)
+ continue;
+
+ update = (struct list *)rn->info;
+
+ ospf_ls_upd_queue_send(oi, update, rn->p.u.prefix4);
+
+ /* list might not be empty. */
+ if (listcount(update) == 0) {
+ list_delete(rn->info);
+ rn->info = NULL;
+ route_unlock_node(rn);
+ } else
+ again = 1;
+ }
+
+ if (again != 0) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "ospf_ls_upd_send_queue: update lists not cleared,"
+ " %d nodes to try again, raising new event",
+ again);
+ oi->t_ls_upd_event = NULL;
+ thread_add_event(master, ospf_ls_upd_send_queue_event, oi, 0,
+ &oi->t_ls_upd_event);
+ }
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("ospf_ls_upd_send_queue stop");
+
+ return 0;
+}
+
+void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag)
+{
+ struct ospf_interface *oi;
+ struct ospf_lsa *lsa;
+ struct prefix_ipv4 p;
+ struct route_node *rn;
+ struct listnode *node;
+
+ oi = nbr->oi;
+
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ p.prefix = oi->vl_data->peer_addr;
+ else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ p.prefix.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else if (flag == OSPF_SEND_PACKET_DIRECT)
+ p.prefix = nbr->address.u.prefix4;
+ else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+ p.prefix.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ p.prefix.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ p.prefix.s_addr = htonl(OSPF_ALLDROUTERS);
+
+ if (oi->type == OSPF_IFTYPE_NBMA) {
+ if (flag == OSPF_SEND_PACKET_INDIRECT)
+ zlog_warn(
+ "* LS-Update is directly sent on NBMA network.");
+ if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr))
+ zlog_warn("* LS-Update is sent to myself.");
+ }
+
+ rn = route_node_get(oi->ls_upd_queue, (struct prefix *)&p);
+
+ if (rn->info == NULL)
+ rn->info = list_new();
+ else
+ route_unlock_node(rn);
+
+ for (ALL_LIST_ELEMENTS_RO(update, node, lsa))
+ listnode_add(rn->info,
+ ospf_lsa_lock(lsa)); /* oi->ls_upd_queue */
+
+ thread_add_event(master, ospf_ls_upd_send_queue_event, oi, 0,
+ &oi->t_ls_upd_event);
}
-void
-ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack,
+ struct in_addr dst)
{
- struct ospf_interface *oi = nbr->oi;
+ struct ospf_packet *op;
+ u_int16_t length = OSPF_HEADER_SIZE;
+
+ op = ospf_packet_new(oi->ifp->mtu);
+
+ /* Prepare OSPF common header. */
+ ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s);
+
+ /* Prepare OSPF Link State Acknowledgment body. */
+ length += ospf_make_ls_ack(oi, ack, op->s);
+
+ /* Fill OSPF header. */
+ ospf_fill_header(oi, op->s, length);
- if (listcount (oi->ls_ack_direct.ls_ack) == 0)
- oi->ls_ack_direct.dst = nbr->address.u.prefix4;
-
- listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa));
-
- thread_add_event(master, ospf_ls_ack_send_event, oi, 0,
- &oi->t_ls_ack_direct);
+ /* Set packet length. */
+ op->length = length;
+
+ /* Decide destination address. */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ op->dst.s_addr = dst.s_addr;
+
+ /* Add packet to the interface output queue. */
+ ospf_packet_add(oi, op);
+
+ /* Hook thread to write packet. */
+ OSPF_ISM_WRITE_ON(oi->ospf);
+}
+
+static int ospf_ls_ack_send_event(struct thread *thread)
+{
+ struct ospf_interface *oi = THREAD_ARG(thread);
+
+ oi->t_ls_ack_direct = NULL;
+
+ while (listcount(oi->ls_ack_direct.ls_ack))
+ ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack,
+ oi->ls_ack_direct.dst);
+
+ return 0;
+}
+
+void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
+{
+ struct ospf_interface *oi = nbr->oi;
+
+ if (listcount(oi->ls_ack_direct.ls_ack) == 0)
+ oi->ls_ack_direct.dst = nbr->address.u.prefix4;
+
+ listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa));
+
+ thread_add_event(master, ospf_ls_ack_send_event, oi, 0,
+ &oi->t_ls_ack_direct);
}
/* Send Link State Acknowledgment delayed. */
-void
-ospf_ls_ack_send_delayed (struct ospf_interface *oi)
-{
- struct in_addr dst;
-
- /* Decide destination address. */
- /* RFC2328 Section 13.5 On non-broadcast
- networks, delayed Link State Acknowledgment packets must be
- unicast separately over each adjacency (i.e., neighbor whose
- state is >= Exchange). */
- if (oi->type == OSPF_IFTYPE_NBMA)
- {
- struct ospf_neighbor *nbr;
- struct route_node *rn;
-
- for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
- if ((nbr = rn->info) != NULL)
- if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange)
- while (listcount (oi->ls_ack))
- ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4);
- return;
- }
- if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
- dst.s_addr = oi->vl_data->peer_addr.s_addr;
- else if (oi->state == ISM_DR || oi->state == ISM_Backup)
- dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
- dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
- dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
- else
- dst.s_addr = htonl (OSPF_ALLDROUTERS);
-
- while (listcount (oi->ls_ack))
- ospf_ls_ack_send_list (oi, oi->ls_ack, dst);
+void ospf_ls_ack_send_delayed(struct ospf_interface *oi)
+{
+ struct in_addr dst;
+
+ /* Decide destination address. */
+ /* RFC2328 Section 13.5 On non-broadcast
+ networks, delayed Link State Acknowledgment packets must be
+ unicast separately over each adjacency (i.e., neighbor whose
+ state is >= Exchange). */
+ if (oi->type == OSPF_IFTYPE_NBMA) {
+ struct ospf_neighbor *nbr;
+ struct route_node *rn;
+
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
+ if ((nbr = rn->info) != NULL)
+ if (nbr != oi->nbr_self
+ && nbr->state >= NSM_Exchange)
+ while (listcount(oi->ls_ack))
+ ospf_ls_ack_send_list(
+ oi, oi->ls_ack,
+ nbr->address.u.prefix4);
+ return;
+ }
+ if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
+ dst.s_addr = oi->vl_data->peer_addr.s_addr;
+ else if (oi->state == ISM_DR || oi->state == ISM_Backup)
+ dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+ dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
+ else
+ dst.s_addr = htonl(OSPF_ALLDROUTERS);
+
+ while (listcount(oi->ls_ack))
+ ospf_ls_ack_send_list(oi, oi->ls_ack, dst);
}
/*
* can be avoided if the MAC was known apriori.
*/
#define OSPF_PING_NBR_STR_MAX (8 + 40 + 20)
-void
-ospf_proactively_arp (struct ospf_neighbor *nbr)
-{
- char ping_nbr[OSPF_PING_NBR_STR_MAX];
- char *str_ptr;
- int ret;
-
- if (!nbr || !nbr->oi || !nbr->oi->ifp)
- return;
-
- str_ptr = strcpy (ping_nbr, "ping -c 1 -I ");
- str_ptr = strcat (str_ptr, nbr->oi->ifp->name);
- str_ptr = strcat (str_ptr, " ");
- str_ptr = strcat (str_ptr, inet_ntoa (nbr->address.u.prefix4));
- str_ptr = strcat (str_ptr, " > /dev/null 2>&1 &");
- ret = system (ping_nbr);
- if (IS_DEBUG_OSPF_EVENT)
- zlog_debug ("Executed %s %s", ping_nbr,
- ((ret == 0) ? "successfully" : "but failed"));
+void ospf_proactively_arp(struct ospf_neighbor *nbr)
+{
+ char ping_nbr[OSPF_PING_NBR_STR_MAX];
+ char *str_ptr;
+ int ret;
+
+ if (!nbr || !nbr->oi || !nbr->oi->ifp)
+ return;
+
+ str_ptr = strcpy(ping_nbr, "ping -c 1 -I ");
+ str_ptr = strcat(str_ptr, nbr->oi->ifp->name);
+ str_ptr = strcat(str_ptr, " ");
+ str_ptr = strcat(str_ptr, inet_ntoa(nbr->address.u.prefix4));
+ str_ptr = strcat(str_ptr, " > /dev/null 2>&1 &");
+ ret = system(ping_nbr);
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("Executed %s %s", ping_nbr,
+ ((ret == 0) ? "successfully" : "but failed"));
}