summaryrefslogtreecommitdiff
path: root/proto/ospf/dbdes.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/dbdes.c')
-rw-r--r--proto/ospf/dbdes.c652
1 files changed, 351 insertions, 301 deletions
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
index 6b291344..65bdb3ec 100644
--- a/proto/ospf/dbdes.c
+++ b/proto/ospf/dbdes.c
@@ -2,6 +2,8 @@
* BIRD -- OSPF
*
* (c) 1999--2004 Ondrej Filip <feela@network.cz>
+ * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2009--2014 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -9,422 +11,470 @@
#include "ospf.h"
-#ifdef OSPFv2
-struct ospf_dbdes_packet
+struct ospf_dbdes2_packet
{
- struct ospf_packet ospf_packet;
+ struct ospf_packet hdr;
+ union ospf_auth auth;
+
u16 iface_mtu;
u8 options;
- union imms imms; /* I, M, MS bits */
+ u8 imms; /* I, M, MS bits */
u32 ddseq;
-};
-
-#define hton_opt(X) X
-#define ntoh_opt(X) X
-#endif
+ struct ospf_lsa_header lsas[];
+};
-#ifdef OSPFv3
-struct ospf_dbdes_packet
+struct ospf_dbdes3_packet
{
- struct ospf_packet ospf_packet;
+ struct ospf_packet hdr;
+
u32 options;
u16 iface_mtu;
u8 padding;
- union imms imms; /* I, M, MS bits */
+ u8 imms; /* I, M, MS bits */
u32 ddseq;
+
+ struct ospf_lsa_header lsas[];
};
-#define hton_opt(X) htonl(X)
-#define ntoh_opt(X) ntohl(X)
-#endif
-
-static void ospf_dump_dbdes(struct proto *p, struct ospf_dbdes_packet *pkt)
+static inline uint
+ospf_dbdes_hdrlen(struct ospf_proto *p)
{
- struct ospf_packet *op = &pkt->ospf_packet;
+ return ospf_is_v2(p) ?
+ sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
+}
- ASSERT(op->type == DBDES_P);
- ospf_dump_common(p, op);
- log(L_TRACE "%s: imms %s%s%s",
- p->name, pkt->imms.bit.ms ? "MS " : "",
- pkt->imms.bit.m ? "M " : "",
- pkt->imms.bit.i ? "I " : "" );
- log(L_TRACE "%s: ddseq %u", p->name, ntohl(pkt->ddseq));
- struct ospf_lsa_header *plsa = (void *) (pkt + 1);
- unsigned int i, j;
+static void
+ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
+ struct ospf_lsa_header **body, uint *count)
+{
+ uint plen = ntohs(pkt->length);
+ uint hlen = ospf_dbdes_hdrlen(p);
- j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
- sizeof(struct ospf_lsa_header);
+ *body = ((void *) pkt) + hlen;
+ *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
+}
- for (i = 0; i < j; i++)
- ospf_dump_lsahdr(p, plsa + i);
+static void
+ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
+{
+ struct ospf_lsa_header *lsas;
+ uint i, lsa_count;
+ u32 pkt_ddseq;
+ u16 pkt_iface_mtu;
+ u8 pkt_imms;
+
+ ASSERT(pkt->type == DBDES_P);
+ ospf_dump_common(p, pkt);
+
+ if (ospf_is_v2(p))
+ {
+ struct ospf_dbdes2_packet *ps = (void *) pkt;
+ pkt_iface_mtu = ntohs(ps->iface_mtu);
+ pkt_imms = ps->imms;
+ pkt_ddseq = ntohl(ps->ddseq);
+ }
+ else /* OSPFv3 */
+ {
+ struct ospf_dbdes3_packet *ps = (void *) pkt;
+ pkt_iface_mtu = ntohs(ps->iface_mtu);
+ pkt_imms = ps->imms;
+ pkt_ddseq = ntohl(ps->ddseq);
+ }
+
+ log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
+ log(L_TRACE "%s: imms %s%s%s", p->p.name,
+ (pkt_imms & DBDES_I) ? "I " : "",
+ (pkt_imms & DBDES_M) ? "M " : "",
+ (pkt_imms & DBDES_MS) ? "MS" : "");
+ log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
+
+ ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
+ for (i = 0; i < lsa_count; i++)
+ ospf_dump_lsahdr(p, lsas + i);
}
-/**
- * ospf_dbdes_send - transmit database description packet
- * @n: neighbor
- * @next: whether to send a next packet in a sequence (1) or to retransmit the old one (0)
- *
- * Sending of a database description packet is described in 10.8 of RFC 2328.
- * Reception of each packet is acknowledged in the sequence number of another.
- * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
- * does not reply, I don't create a new packet but just send the content
- * of the buffer.
- */
-void
-ospf_dbdes_send(struct ospf_neighbor *n, int next)
+static void
+ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
- struct ospf_dbdes_packet *pkt;
- struct ospf_packet *op;
struct ospf_iface *ifa = n->ifa;
- struct ospf_area *oa = ifa->oa;
- struct proto_ospf *po = oa->po;
- struct proto *p = &po->proto;
- u16 length, i, j;
+ struct ospf_packet *pkt;
+ uint length;
- /* FIXME ??? */
- if ((oa->rt == NULL) || (EMPTY_LIST(po->lsal)))
- update_rt_lsa(oa);
+ u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
- switch (n->state)
+ /* Update DBDES buffer */
+ if (n->ldd_bsize != ifa->tx_length)
{
- case NEIGHBOR_EXSTART: /* Send empty packets */
- n->myimms.bit.i = 1;
- pkt = ospf_tx_buffer(ifa);
- op = &pkt->ospf_packet;
- ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
- pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
- pkt->options = hton_opt(oa->options);
- pkt->imms = n->myimms;
- pkt->ddseq = htonl(n->dds);
- length = sizeof(struct ospf_dbdes_packet);
- op->length = htons(length);
-
- OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
- ospf_send_to(ifa, n->ip);
- break;
-
- case NEIGHBOR_EXCHANGE:
- n->myimms.bit.i = 0;
+ mb_free(n->ldd_buffer);
+ n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
+ n->ldd_bsize = ifa->tx_length;
+ }
- if (next)
- {
- snode *sn;
- struct ospf_lsa_header *lsa;
+ pkt = n->ldd_buffer;
+ ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
- if (n->ldd_bsize != ifa->tx_length)
- {
- mb_free(n->ldd_buffer);
- n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
- n->ldd_bsize = ifa->tx_length;
- }
+ if (ospf_is_v2(p))
+ {
+ struct ospf_dbdes2_packet *ps = (void *) pkt;
+ ps->iface_mtu = htons(iface_mtu);
+ ps->options = ifa->oa->options;
+ ps->imms = 0; /* Will be set later */
+ ps->ddseq = htonl(n->dds);
+ length = sizeof(struct ospf_dbdes2_packet);
+ }
+ else /* OSPFv3 */
+ {
+ struct ospf_dbdes3_packet *ps = (void *) pkt;
+ ps->options = htonl(ifa->oa->options);
+ ps->iface_mtu = htons(iface_mtu);
+ ps->padding = 0;
+ ps->imms = 0; /* Will be set later */
+ ps->ddseq = htonl(n->dds);
+ length = sizeof(struct ospf_dbdes3_packet);
+ }
- pkt = n->ldd_buffer;
- op = (struct ospf_packet *) pkt;
+ /* Prepare DBDES body */
+ if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
+ {
+ struct ospf_lsa_header *lsas;
+ struct top_hash_entry *en;
+ uint i = 0, lsa_max;
- ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
- pkt->iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : htons(ifa->iface->mtu);
- pkt->ddseq = htonl(n->dds);
- pkt->options = hton_opt(oa->options);
+ ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
+ en = (void *) s_get(&(n->dbsi));
- j = i = (ospf_pkt_maxsize(ifa) - sizeof(struct ospf_dbdes_packet)) / sizeof(struct ospf_lsa_header); /* Number of possible lsaheaders to send */
- lsa = (n->ldd_buffer + sizeof(struct ospf_dbdes_packet));
+ while (i < lsa_max)
+ {
+ if (!SNODE_VALID(en))
+ {
+ n->myimms &= ~DBDES_M; /* Unset More bit */
+ break;
+ }
- if (n->myimms.bit.m)
+ if ((en->lsa.age < LSA_MAXAGE) &&
+ lsa_flooding_allowed(en->lsa_type, en->domain, ifa))
{
- sn = s_get(&(n->dbsi));
-
- DBG("Number of LSA: %d\n", j);
- for (; i > 0; i--)
- {
- struct top_hash_entry *en= (struct top_hash_entry *) sn;
-
- if (ospf_lsa_flooding_allowed(&en->lsa, en->domain, ifa))
- {
- htonlsah(&(en->lsa), lsa);
- DBG("Working on: %d\n", i);
- DBG("\tX%01x %-1R %-1R %p\n", en->lsa.type, en->lsa.id, en->lsa.rt, en->lsa_body);
-
- lsa++;
- }
- else i++; /* No lsa added */
-
- if (sn == STAIL(po->lsal))
- {
- i--;
- break;
- }
-
- sn = sn->next;
- }
-
- if (sn == STAIL(po->lsal))
- {
- DBG("Number of LSA NOT sent: %d\n", i);
- DBG("M bit unset.\n");
- n->myimms.bit.m = 0; /* Unset more bit */
- }
-
- s_put(&(n->dbsi), sn);
+ lsa_hton_hdr(&(en->lsa), lsas + i);
+ i++;
}
- pkt->imms.byte = n->myimms.byte;
+ en = SNODE_NEXT(en);
+ }
- length = (j - i) * sizeof(struct ospf_lsa_header) +
- sizeof(struct ospf_dbdes_packet);
- op->length = htons(length);
+ s_put(&(n->dbsi), SNODE en);
- DBG("%s: DB_DES (M) prepared for %I.\n", p->name, n->ip);
- }
+ length += i * sizeof(struct ospf_lsa_header);
+ }
- case NEIGHBOR_LOADING:
- case NEIGHBOR_FULL:
- length = n->ldd_buffer ? ntohs(((struct ospf_packet *) n->ldd_buffer)->length) : 0;
+ if (ospf_is_v2(p))
+ ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
+ else
+ ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
- if (!length)
- {
- OSPF_TRACE(D_PACKETS, "No packet in my buffer for repeating");
- ospf_neigh_sm(n, INM_KILLNBR);
- return;
- }
+ pkt->length = htons(length);
+}
- /* Send last packet from ldd buffer */
+static void
+ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
- OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer, "DBDES packet sent to %I via %s", n->ip, ifa->ifname);
+ OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
+ "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
+ sk_set_tbuf(ifa->sk, n->ldd_buffer);
+ ospf_send_to(ifa, n->ip);
+ sk_set_tbuf(ifa->sk, NULL);
+}
- sk_set_tbuf(ifa->sk, n->ldd_buffer);
- ospf_send_to(ifa, n->ip);
- sk_set_tbuf(ifa->sk, NULL);
+/**
+ * ospf_send_dbdes - transmit database description packet
+ * @n: neighbor
+ *
+ * Sending of a database description packet is described in 10.8 of RFC 2328.
+ * Reception of each packet is acknowledged in the sequence number of another.
+ * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
+ * does not reply, I don't create a new packet but just send the content
+ * of the buffer.
+ */
+void
+ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
+{
+ /* RFC 2328 10.8 */
- if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */
+ ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
- if (!n->myimms.bit.ms)
- {
- if ((n->myimms.bit.m == 0) && (n->imms.bit.m == 0) &&
- (n->state == NEIGHBOR_EXCHANGE))
- {
- ospf_neigh_sm(n, INM_EXDONE);
- }
- }
- break;
+ if (n->ifa->oa->rt == NULL)
+ return;
- default: /* Ignore it */
- break;
- }
+ ospf_prepare_dbdes(p, n);
+ ospf_do_send_dbdes(p, n);
}
-static void
-ospf_dbdes_reqladd(struct ospf_dbdes_packet *ps, struct ospf_neighbor *n)
+void
+ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
- struct ospf_lsa_header *plsa, lsa;
- struct top_hash_entry *he, *sn;
- struct ospf_area *oa = n->ifa->oa;
- struct top_graph *gr = oa->po->gr;
- struct ospf_packet *op;
- int i, j;
+ ASSERT(n->state > NEIGHBOR_EXSTART);
- op = (struct ospf_packet *) ps;
+ if (!n->ldd_buffer)
+ {
+ log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
+ ospf_neigh_sm(n, INM_SEQMIS);
+ return;
+ }
- plsa = (void *) (ps + 1);
+ /* Send last packet */
+ ospf_do_send_dbdes(p, n);
+}
- j = (ntohs(op->length) - sizeof(struct ospf_dbdes_packet)) /
- sizeof(struct ospf_lsa_header);
+static int
+ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
+{
+ struct ospf_iface *ifa = n->ifa;
+ struct ospf_lsa_header *lsas, lsa;
+ struct top_hash_entry *en, *req;
+ const char *err_dsc = NULL;
+ u32 lsa_type, lsa_domain;
+ uint i, lsa_count;
- for (i = 0; i < j; i++)
+ ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
+
+ for (i = 0; i < lsa_count; i++)
{
- ntohlsah(plsa + i, &lsa);
- u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
- if (((he = ospf_hash_find_header(gr, dom, &lsa)) == NULL) ||
- (lsa_comp(&lsa, &(he->lsa)) == 1))
+ lsa_ntoh_hdr(lsas + i, &lsa);
+ lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
+
+ /* RFC 2328 10.6 and RFC 5340 4.2.2 */
+
+ if (!lsa_type)
+ DROP1("LSA of unknown type");
+
+ if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
+ DROP1("LSA with AS scope in stub area");
+
+ /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
+ if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
+ DROP1("rt-summary-LSA in stub area");
+
+ /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
+ if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
+ DROP1("LSA with invalid scope");
+
+ en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
+ if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
{
- /* Is this condition necessary? */
- if (ospf_hash_find_header(n->lsrqh, dom, &lsa) == NULL)
- {
- sn = ospf_hash_get_header(n->lsrqh, dom, &lsa);
- ntohlsah(plsa + i, &(sn->lsa));
- s_add_tail(&(n->lsrql), SNODE sn);
- }
+ /* This should be splitted to ospf_lsa_lsrq_up() */
+ req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
+
+ if (!SNODE_VALID(req))
+ s_add_tail(&n->lsrql, SNODE req);
+
+ if (!SNODE_VALID(n->lsrqi))
+ n->lsrqi = req;
+
+ req->lsa = lsa;
+ req->lsa_body = LSA_BODY_DUMMY;
+
+ if (!tm_active(n->lsrq_timer))
+ tm_start(n->lsrq_timer, 0);
}
}
+
+ return 0;
+
+drop:
+ LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
+ LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
+
+ ospf_neigh_sm(n, INM_SEQMIS);
+ return -1;
}
void
-ospf_dbdes_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
+ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
- struct proto_ospf *po = ifa->oa->po;
- struct proto *p = &po->proto;
+ struct ospf_proto *p = ifa->oa->po;
+ const char *err_dsc = NULL;
+ u32 rcv_ddseq, rcv_options;
+ u16 rcv_iface_mtu;
+ u8 rcv_imms;
+ uint plen, err_val = 0;
+
+ /* RFC 2328 10.6 */
- unsigned int size = ntohs(ps_i->length);
- if (size < sizeof(struct ospf_dbdes_packet))
+ plen = ntohs(pkt->length);
+ if (plen < ospf_dbdes_hdrlen(p))
{
- log(L_ERR "Bad OSPF DBDES packet from %I - too short (%u B)", n->ip, size);
+ LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
return;
}
- struct ospf_dbdes_packet *ps = (void *) ps_i;
- u32 ps_ddseq = ntohl(ps->ddseq);
- u32 ps_options = ntoh_opt(ps->options);
- u16 ps_iface_mtu = ntohs(ps->iface_mtu);
-
- OSPF_PACKET(ospf_dump_dbdes, ps, "DBDES packet received from %I via %s", n->ip, ifa->ifname);
+ OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
ospf_neigh_sm(n, INM_HELLOREC);
+ if (ospf_is_v2(p))
+ {
+ struct ospf_dbdes2_packet *ps = (void *) pkt;
+ rcv_iface_mtu = ntohs(ps->iface_mtu);
+ rcv_options = ps->options;
+ rcv_imms = ps->imms;
+ rcv_ddseq = ntohl(ps->ddseq);
+ }
+ else /* OSPFv3 */
+ {
+ struct ospf_dbdes3_packet *ps = (void *) pkt;
+ rcv_options = ntohl(ps->options);
+ rcv_iface_mtu = ntohs(ps->iface_mtu);
+ rcv_imms = ps->imms;
+ rcv_ddseq = ntohl(ps->ddseq);
+ }
+
switch (n->state)
{
case NEIGHBOR_DOWN:
case NEIGHBOR_ATTEMPT:
case NEIGHBOR_2WAY:
+ OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
return;
- break;
+
case NEIGHBOR_INIT:
ospf_neigh_sm(n, INM_2WAYREC);
if (n->state != NEIGHBOR_EXSTART)
return;
- case NEIGHBOR_EXSTART:
-
- if ((ifa->type != OSPF_IT_VLINK) && (ps_iface_mtu != ifa->iface->mtu)
- && (ps_iface_mtu != 0) && (ifa->iface->mtu != 0))
- log(L_WARN "OSPF: MTU mismatch with neighbour %I on interface %s (remote %d, local %d)",
- n->ip, ifa->ifname, ps_iface_mtu, ifa->iface->mtu);
- if ((ps->imms.bit.m && ps->imms.bit.ms && ps->imms.bit.i)
- && (n->rid > po->router_id) && (size == sizeof(struct ospf_dbdes_packet)))
+ case NEIGHBOR_EXSTART:
+ if ((ifa->type != OSPF_IT_VLINK) &&
+ (rcv_iface_mtu != ifa->iface->mtu) &&
+ (rcv_iface_mtu != 0) &&
+ (ifa->iface->mtu != 0))
+ LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
+ n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
+
+ if ((rcv_imms == DBDES_IMMS) &&
+ (n->rid > p->router_id) &&
+ (plen == ospf_dbdes_hdrlen(p)))
{
/* I'm slave! */
- n->dds = ps_ddseq;
- n->ddr = ps_ddseq;
- n->options = ps_options;
- n->myimms.bit.ms = 0;
- n->imms.byte = ps->imms.byte;
- OSPF_TRACE(D_PACKETS, "I'm slave to %I.", n->ip);
+ n->dds = rcv_ddseq;
+ n->ddr = rcv_ddseq;
+ n->options = rcv_options;
+ n->myimms &= ~DBDES_MS;
+ n->imms = rcv_imms;
+ tm_stop(n->dbdes_timer);
ospf_neigh_sm(n, INM_NEGDONE);
- ospf_dbdes_send(n, 1);
+ ospf_send_dbdes(p, n);
break;
}
- if (((ps->imms.bit.i == 0) && (ps->imms.bit.ms == 0)) &&
- (n->rid < po->router_id) && (n->dds == ps_ddseq))
+ if (!(rcv_imms & DBDES_I) &&
+ !(rcv_imms & DBDES_MS) &&
+ (n->rid < p->router_id) &&
+ (n->dds == rcv_ddseq))
{
/* I'm master! */
- n->options = ps_options;
- n->ddr = ps_ddseq - 1; /* It will be set corectly a few lines down */
- n->imms.byte = ps->imms.byte;
- OSPF_TRACE(D_PACKETS, "I'm master to %I.", n->ip);
+ n->options = rcv_options;
+ n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
+ n->imms = rcv_imms;
ospf_neigh_sm(n, INM_NEGDONE);
+ /* Continue to the NEIGHBOR_EXCHANGE case */
}
else
{
- DBG("%s: Nothing happend to %I (imms=%u)\n", p->name, n->ip,
- ps->imms.byte);
+ DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
break;
}
+
case NEIGHBOR_EXCHANGE:
- if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options) &&
- (ps_ddseq == n->ddr))
- {
- /* Duplicate packet */
- OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
- if (n->myimms.bit.ms == 0)
- {
- /* Slave should retransmit dbdes packet */
- ospf_dbdes_send(n, 0);
- }
- return;
- }
+ if ((rcv_imms == n->imms) &&
+ (rcv_options == n->options) &&
+ (rcv_ddseq == n->ddr))
+ goto duplicate;
- n->ddr = ps_ddseq;
+ if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
+ DROP("MS-bit mismatch", rcv_imms);
- if (ps->imms.bit.ms != n->imms.bit.ms) /* M/S bit differs */
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit MS)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
+ if (rcv_imms & DBDES_I)
+ DROP("I-bit mismatch", rcv_imms);
- if (ps->imms.bit.i) /* I bit is set */
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (bit I)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
+ if (rcv_options != n->options)
+ DROP("options mismatch", rcv_options);
- n->imms.byte = ps->imms.byte;
+ n->ddr = rcv_ddseq;
+ n->imms = rcv_imms;
- if (ps_options != n->options) /* Options differs */
+ if (n->myimms & DBDES_MS)
{
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (options)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
+ /* MASTER */
+
+ if (rcv_ddseq != n->dds)
+ DROP("DD sequence number mismatch", rcv_ddseq);
- if (n->myimms.bit.ms)
- {
- if (ps_ddseq != n->dds) /* MASTER */
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (master)",
- n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
n->dds++;
- DBG("Incrementing dds\n");
- ospf_dbdes_reqladd(ps, n);
- if ((n->myimms.bit.m == 0) && (ps->imms.bit.m == 0))
+
+ if (ospf_process_dbdes(p, pkt, n) < 0)
+ return;
+
+ if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
{
+ tm_stop(n->dbdes_timer);
ospf_neigh_sm(n, INM_EXDONE);
- }
- else
- {
- ospf_dbdes_send(n, 1);
+ break;
}
+ ospf_send_dbdes(p, n);
+ tm_start(n->dbdes_timer, n->ifa->rxmtint);
}
else
{
- if (ps_ddseq != (n->dds + 1)) /* SLAVE */
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (slave)", n->ip);
- ospf_neigh_sm(n, INM_SEQMIS);
- break;
- }
- n->ddr = ps_ddseq;
- n->dds = ps_ddseq;
- ospf_dbdes_reqladd(ps, n);
- ospf_dbdes_send(n, 1);
- }
+ /* SLAVE */
+
+ if (rcv_ddseq != (n->dds + 1))
+ DROP("DD sequence number mismatch", rcv_ddseq);
+
+ n->ddr = rcv_ddseq;
+ n->dds = rcv_ddseq;
+ if (ospf_process_dbdes(p, pkt, n) < 0)
+ return;
+
+ ospf_send_dbdes(p, n);
+
+ if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
+ ospf_neigh_sm(n, INM_EXDONE);
+ }
break;
+
case NEIGHBOR_LOADING:
case NEIGHBOR_FULL:
- if ((ps->imms.byte == n->imms.byte) && (ps_options == n->options)
- && (ps_ddseq == n->ddr))
- /* Only duplicate are accepted */
- {
- OSPF_TRACE(D_PACKETS, "Received duplicate dbdes from %I.", n->ip);
- if (n->myimms.bit.ms == 0)
- {
- /* Slave should retransmit dbdes packet */
- ospf_dbdes_send(n, 0);
- }
- return;
- }
- else
- {
- OSPF_TRACE(D_PACKETS, "dbdes - sequence mismatch neighbor %I (full)",
- n->ip);
- DBG("PS=%u, DDR=%u, DDS=%u\n", ps_ddseq, n->ddr, n->dds);
- ospf_neigh_sm(n, INM_SEQMIS);
- }
- break;
+ if ((rcv_imms == n->imms) &&
+ (rcv_options == n->options) &&
+ (rcv_ddseq == n->ddr))
+ goto duplicate;
+
+ DROP("too late for DD exchange", n->state);
+
default:
- bug("Received dbdes from %I in undefined state.", n->ip);
+ bug("Undefined interface state");
}
+ return;
+
+duplicate:
+ OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
+
+ /* Slave should retransmit DBDES packet */
+ if (!(n->myimms & DBDES_MS))
+ ospf_rxmt_dbdes(p, n);
+ return;
+
+drop:
+ LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
+ n->rid, ifa->ifname, err_dsc, err_val);
+
+ ospf_neigh_sm(n, INM_SEQMIS);
+ return;
}