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.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c
new file mode 100644
index 00000000..85d2a3bc
--- /dev/null
+++ b/proto/ospf/dbdes.c
@@ -0,0 +1,203 @@
+/*
+ * BIRD -- OSPF
+ *
+ * (c) 1999 Ondrej Filip <feela@network.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "ospf.h"
+
+void
+ospf_dbdes_tx(struct ospf_neighbor *n)
+{
+ struct ospf_dbdes_packet *pkt;
+ struct ospf_packet *op;
+ struct ospf_iface *ifa;
+ u16 length;
+ struct proto *p;
+
+ ifa=n->ifa;
+
+ p=(struct proto *)(ifa->proto);
+
+ switch(n->state)
+ {
+ case NEIGHBOR_EXSTART: /* Send empty packets */
+ pkt=(struct ospf_dbdes_packet *)(ifa->ip_sk->tbuf);
+ op=(struct ospf_packet *)pkt;
+
+ fill_ospf_pkt_hdr(ifa, pkt, DBDES);
+ pkt->iface_mtu= ((struct iface *)ifa)->mtu;
+ pkt->options= ifa->options;
+ pkt->imms=n->myimms;
+ pkt->ddseq=n->dds;
+ length=sizeof(struct ospf_dbdes_packet);
+ op->length=htons(length);
+ ospf_pkt_finalize(ifa, op);
+ sk_send_to(ifa->ip_sk,length, n->ip, OSPF_PROTO);
+ debug("%s: DB_DES sent for %u.\n", p->name, n->rid);
+
+ /*case NEIGHBOR_EXCHANGE: */
+ default: /* Ignore it */
+ break;
+ }
+}
+
+void
+rxmt_timer_hook(timer *timer)
+{
+ struct ospf_iface *ifa;
+ struct proto *p;
+ struct ospf_neighbor *n;
+
+ ifa=(struct ospf_iface *)timer->data;
+ p=(struct proto *)(ifa->proto);
+ debug("%s: RXMT timer fired on interface %s.\n",
+ p->name, ifa->iface->name);
+ WALK_LIST (n, ifa->neigh_list) /* Try to send db_des */
+ {
+ ospf_dbdes_tx(n);
+ }
+}
+
+void
+ospf_dbdes_rx(struct ospf_dbdes_packet *ps, struct proto *p,
+ struct ospf_iface *ifa, u16 size)
+{
+ u32 nrid, myrid;
+ struct ospf_neighbor *n;
+ u8 i;
+
+ nrid=ntohl(((struct ospf_packet *)ps)->routerid);
+
+ myrid=p->cf->global->router_id;
+
+ if((n=find_neigh(ifa, nrid))==NULL)
+ {
+ debug("%s: Received dbdes from unknown neigbor! (%u)\n", p->name,
+ nrid);
+ return ;
+ }
+
+ if(ifa->iface->mtu<size)
+ {
+ debug("%s: Received dbdes larger than MTU from (%u)!\n", p->name, nrid);
+ return ;
+ }
+
+ switch(n->state)
+ {
+ case NEIGHBOR_DOWN:
+ case NEIGHBOR_ATTEMPT:
+ case NEIGHBOR_2WAY:
+ debug("%s: Received dbdes from %u in bad state. (%u)\n", p->name, nrid);
+ return;
+ break;
+ case NEIGHBOR_INIT:
+ ospf_neigh_sm(n, INM_2WAYREC);
+ if(n->state!=NEIGHBOR_EXSTART) return;
+ case NEIGHBOR_EXSTART:
+ if(ps->imms==(DBDES_I|DBDES_M|DBDES_MS) && (n->rid > myrid) &&
+ (size == sizeof(struct ospf_dbdes_packet)))
+ {
+ /* I'm slave! */
+ n->dds=ps->ddseq;
+ n->options=ps->options;
+ n->myimms=(n->myimms && DBDES_M);
+ n->ddr=ps->ddseq;
+ n->imms=ps->imms;
+ debug("%s: I'm slave to %u. \n", p->name, nrid);
+ ospf_neigh_sm(n, INM_NEGDONE);
+ }
+ else
+ {
+ if(((ps->imms & (DBDES_I|DBDES_MS))== 0) && (n->rid < myrid) &&
+ (n->dds == ps->ddseq))
+ {
+ /* I'm master! */
+ n->options=ps->options;
+ n->ddr=ps->ddseq;
+ n->imms=ps->imms;
+ debug("%s: I'm master to %u. \n", p->name, nrid);
+ ospf_neigh_sm(n, INM_NEGDONE);
+ }
+ else
+ {
+ debug("%s: Nothing happend to %u (imms=%u)", p->name, nrid,
+ ps->imms);
+ break;
+ }
+ }
+ break; /* I should probably continue processing packet */
+
+ case NEIGHBOR_EXCHANGE:
+ if((ps->imms==n->imms) && (ps->options=n->options) &&
+ (ps->ddseq==n->dds))
+ {
+ /* Duplicate packet */
+ debug("%s: Received duplicate dbdes from (%u)!\n", p->name, nrid);
+ if(!IAMMASTER(n->imms))
+ {
+ ospf_dbdes_tx(n);
+ }
+ return;
+ }
+
+ if(IAMMASTER(ps->imms)!=IAMMASTER(n->myimms)) /* M/S bit differs */
+ {
+ ospf_neigh_sm(n, INM_SEQMIS);
+ break;
+ }
+
+ if(INISET(ps->imms)) /* I bit is set */
+ {
+ ospf_neigh_sm(n, INM_SEQMIS);
+ break;
+ }
+
+ if(ps->options!=n->options) /* Options differs */
+ {
+ ospf_neigh_sm(n, INM_SEQMIS);
+ break;
+ }
+
+ if(IAMMASTER(n->myimms))
+ {
+ if(ps->ddseq!=n->dds)
+ {
+ ospf_neigh_sm(n, INM_SEQMIS);
+ break;
+ }
+ }
+ else
+ {
+ if(ps->ddseq!=(n->dds+1))
+ {
+ ospf_neigh_sm(n, INM_SEQMIS);
+ break;
+ }
+ }
+
+ /* FIXME: Packet accepted, go on */
+
+ break;
+ case NEIGHBOR_LOADING:
+ case NEIGHBOR_FULL:
+ if((ps->imms==n->imms) && (ps->options=n->options) &&
+ (ps->ddseq==n->dds)) /* Only duplicate are accepted */
+ {
+ debug("%s: Received duplicate dbdes from (%u)!\n", p->name, nrid);
+ return;
+ }
+ else
+ {
+ ospf_neigh_sm(n, INM_SEQMIS);
+ }
+ break;
+ defaut:
+ die("%s: Received dbdes from %u in unknown state. (%u)\n", p->name, nrid);
+ break;
+ }
+}
+