bird/proto/ospf/dbdes.c

264 lines
6.2 KiB
C

/*
* BIRD -- OSPF
*
* (c) 1999-2000 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;
u16 i,j;
u8 *aa,*bb;
ifa=n->ifa;
p=(struct proto *)(ifa->proto);
pkt=(struct ospf_dbdes_packet *)(ifa->ip_sk->tbuf);
op=(struct ospf_packet *)pkt;
switch(n->state)
{
case NEIGHBOR_EXSTART: /* Send empty packets */
fill_ospf_pkt_hdr(ifa, pkt, DBDES);
pkt->iface_mtu=ifa->iface->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);
break;
case NEIGHBOR_EXCHANGE:
if(! ((IAMMASTER(n->myimms) && (n->dds==n->ddr+1)) || ((!IAMMASTER(n->myimms)) && (n->dds==n->ddr))))
{
snode *sn; /* Send next */
struct ospf_lsaheader *lsa;
fill_ospf_pkt_hdr(ifa, pkt, DBDES);
pkt->iface_mtu= ifa->iface->mtu;
pkt->options= ifa->options;
pkt->ddseq=n->dds;
sn=s_get(&(n->dbsi));
j=i=(pkt->iface_mtu-sizeof(struct ospf_dbdes_packet))/sizeof(struct ospf_lsaheader); /* Number of lsaheaders */
lsa=(n->ldbdes+sizeof(struct ospf_dbdes_packet));
for(;i>0;i--)
{
struct top_hash_entry *en;
en=(struct top_hash_entry *)sn;
lsa->lsage=htons(en->lsage);
lsa->options=htons(en->options);
lsa->lstype=htons(en->lsa_type);
lsa->lsid=htons(en->lsa_id);
lsa->advr=htons(en->rtr_id);
lsa->lssn=htons(en->lsseqno);
lsa->length=htons(en->length);
lsa->checksum=htons(en->checksum);
if(sn->next==NULL)
{
break; /* Should set some flag? */
}
sn=sn->next;
}
s_put(&(n->dbsi),sn);
if(sn->next==NULL)
{
n->myimms=(n->myimms-DBDES_M); /* Unset more bit */
}
pkt->imms=n->myimms;
length=j*sizeof(struct ospf_lsaheader)+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);
}
aa=ifa->ip_sk->tbuf;
bb=n->ldbdes;
length=ntohs(op->length);
for(i=0; i<ifa->iface->mtu; i++)
{
*(aa+i)=*(bb+i); /* Copy last sent packet again */
}
sk_send_to(ifa->ip_sk,length, n->ip, OSPF_PROTO);
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;
}
}