diff options
Diffstat (limited to 'proto/ospf/dbdes.c')
-rw-r--r-- | proto/ospf/dbdes.c | 203 |
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; + } +} + |