2000-03-31 04:00:42 +08:00
|
|
|
/*
|
|
|
|
* BIRD -- OSPF
|
|
|
|
*
|
2004-06-05 00:30:04 +08:00
|
|
|
* (c) 2000-2004 Ondrej Filip <feela@network.cz>
|
2000-03-31 04:00:42 +08:00
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ospf.h"
|
|
|
|
|
2004-06-05 00:30:04 +08:00
|
|
|
char *s_queue[]={ "direct", "delayed" };
|
2000-04-18 09:06:16 +08:00
|
|
|
|
2004-06-05 00:30:04 +08:00
|
|
|
/*
|
|
|
|
* =====================================
|
|
|
|
* Note, that h is in network endianity!
|
|
|
|
* =====================================
|
|
|
|
*/
|
2000-04-18 09:06:16 +08:00
|
|
|
void
|
2004-06-05 00:30:04 +08:00
|
|
|
ospf_lsack_enqueue(struct ospf_neighbor *n,struct ospf_lsa_header *h,
|
|
|
|
struct proto *p, int queue)
|
2000-04-18 09:06:16 +08:00
|
|
|
{
|
|
|
|
struct lsah_n *no;
|
|
|
|
|
2004-06-01 21:12:10 +08:00
|
|
|
no=mb_alloc(n->pool,sizeof(struct lsah_n));
|
2000-04-18 09:06:16 +08:00
|
|
|
memcpy(&no->lsa,h,sizeof(struct ospf_lsa_header));
|
2004-06-05 00:30:04 +08:00
|
|
|
add_tail(&n->ackl[queue], NODE no);
|
|
|
|
DBG("Adding (%s) ack for %I, ID: %I, RT: %I, Type: %u\n", s_queue[queue], n->rid,
|
2000-04-19 01:36:46 +08:00
|
|
|
ntohl(h->id), ntohl(h->rt),h->type);
|
2000-04-18 09:06:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-06-05 00:30:04 +08:00
|
|
|
ospf_lsack_send(struct ospf_neighbor *n, int queue)
|
2000-04-18 09:06:16 +08:00
|
|
|
{
|
|
|
|
struct ospf_packet *op;
|
|
|
|
struct ospf_lsack_packet *pk;
|
|
|
|
sock *sk;
|
|
|
|
u16 len,i=0;
|
|
|
|
struct ospf_lsa_header *h;
|
|
|
|
struct lsah_n *no;
|
|
|
|
struct ospf_iface *ifa=n->ifa;
|
2000-06-06 10:32:14 +08:00
|
|
|
struct proto *p=&n->ifa->proto->proto;
|
2000-04-18 09:06:16 +08:00
|
|
|
|
2004-06-05 00:30:04 +08:00
|
|
|
if(EMPTY_LIST(n->ackl[queue])) return;
|
|
|
|
|
|
|
|
OSPF_TRACE(D_PACKETS, "LS ack sent to %I (%s)", n->ip, s_queue[queue]);
|
2000-04-19 01:00:56 +08:00
|
|
|
|
2000-04-18 09:06:16 +08:00
|
|
|
if(ifa->type==OSPF_IT_BCAST)
|
|
|
|
{
|
|
|
|
sk=ifa->hello_sk;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sk=ifa->ip_sk;
|
|
|
|
}
|
|
|
|
|
|
|
|
pk=(struct ospf_lsack_packet *)sk->tbuf;
|
|
|
|
op=(struct ospf_packet *)sk->tbuf;
|
|
|
|
|
2000-06-03 09:29:00 +08:00
|
|
|
fill_ospf_pkt_hdr(n->ifa, pk, LSACK_P);
|
2000-04-18 09:06:16 +08:00
|
|
|
h=(struct ospf_lsa_header *)(pk+1);
|
|
|
|
|
2004-06-05 00:30:04 +08:00
|
|
|
while(!EMPTY_LIST(n->ackl[queue]))
|
2000-04-18 09:06:16 +08:00
|
|
|
{
|
2004-06-05 00:30:04 +08:00
|
|
|
no=(struct lsah_n *)HEAD(n->ackl[queue]);
|
2000-04-18 09:06:16 +08:00
|
|
|
memcpy(h+i,&no->lsa, sizeof(struct ospf_lsa_header));
|
|
|
|
i++;
|
2000-04-19 01:00:56 +08:00
|
|
|
DBG("Iter %u ID: %I, RT: %I, Type: %u\n",i, ntohl((h+i)->id),
|
|
|
|
ntohl((h+i)->rt),(h+i)->type);
|
|
|
|
rem_node(NODE no);
|
2000-04-19 01:36:46 +08:00
|
|
|
mb_free(no);
|
2000-04-19 01:00:56 +08:00
|
|
|
if((i*sizeof(struct ospf_lsa_header)+sizeof(struct ospf_lsack_packet)+SIPH)>
|
2000-04-18 09:06:16 +08:00
|
|
|
n->ifa->iface->mtu)
|
|
|
|
{
|
2004-06-05 00:30:04 +08:00
|
|
|
if(!EMPTY_LIST(n->ackl[queue]))
|
2000-04-18 09:06:16 +08:00
|
|
|
{
|
|
|
|
len=sizeof(struct ospf_lsack_packet)+i*sizeof(struct ospf_lsa_header);
|
|
|
|
op->length=htons(len);
|
|
|
|
ospf_pkt_finalize(n->ifa, op);
|
2000-06-08 06:10:46 +08:00
|
|
|
DBG("Sending and continuing! Len=%u\n",len);
|
2000-04-18 09:06:16 +08:00
|
|
|
if(ifa->type==OSPF_IT_BCAST)
|
|
|
|
{
|
|
|
|
if((ifa->state==OSPF_IS_DR)||(ifa->state==OSPF_IS_BACKUP))
|
|
|
|
{
|
|
|
|
sk_send_to(sk ,len, AllSPFRouters, OSPF_PROTO);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sk_send_to(sk ,len, AllDRouters, OSPF_PROTO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-06-06 08:08:27 +08:00
|
|
|
if((ifa->state==OSPF_IS_DR)||(ifa->state==OSPF_IS_BACKUP))
|
|
|
|
{
|
|
|
|
sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sk_send_to_bdr(sk, len, ifa);
|
|
|
|
}
|
2000-04-18 09:06:16 +08:00
|
|
|
}
|
2000-04-19 01:36:46 +08:00
|
|
|
|
2000-06-03 09:29:00 +08:00
|
|
|
fill_ospf_pkt_hdr(n->ifa, pk, LSACK_P);
|
2000-04-18 09:06:16 +08:00
|
|
|
i=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
len=sizeof(struct ospf_lsack_packet)+i*sizeof(struct ospf_lsa_header);
|
|
|
|
op->length=htons(len);
|
|
|
|
ospf_pkt_finalize(n->ifa, op);
|
2000-04-19 01:00:56 +08:00
|
|
|
DBG("Sending! Len=%u\n",len);
|
2000-04-18 09:06:16 +08:00
|
|
|
if(ifa->type==OSPF_IT_BCAST)
|
|
|
|
{
|
|
|
|
if((ifa->state==OSPF_IS_DR)||(ifa->state==OSPF_IS_BACKUP))
|
|
|
|
{
|
2004-06-05 00:30:04 +08:00
|
|
|
sk_send_to(sk, len, AllSPFRouters, OSPF_PROTO);
|
2000-04-18 09:06:16 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-06-05 00:30:04 +08:00
|
|
|
sk_send_to(sk, len, AllDRouters, OSPF_PROTO);
|
2000-04-18 09:06:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE);
|
|
|
|
}
|
2000-03-31 04:00:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2004-06-05 00:30:04 +08:00
|
|
|
ospf_lsack_receive(struct ospf_lsack_packet *ps, struct proto *p,
|
2000-03-31 04:00:42 +08:00
|
|
|
struct ospf_iface *ifa, u16 size)
|
|
|
|
{
|
|
|
|
u32 nrid, myrid;
|
|
|
|
struct ospf_neighbor *n;
|
2000-04-12 23:20:13 +08:00
|
|
|
struct ospf_lsa_header lsa,*plsa;
|
2000-03-31 04:00:42 +08:00
|
|
|
int length;
|
2000-04-12 23:20:13 +08:00
|
|
|
u16 nolsa,i;
|
|
|
|
struct top_hash_entry *en;
|
2000-05-12 06:00:16 +08:00
|
|
|
u16 lenn=ntohs(ps->ospf_packet.length);
|
2000-03-31 04:00:42 +08:00
|
|
|
|
|
|
|
nrid=ntohl(ps->ospf_packet.routerid);
|
|
|
|
|
|
|
|
myrid=p->cf->global->router_id;
|
|
|
|
|
|
|
|
if((n=find_neigh(ifa, nrid))==NULL)
|
|
|
|
{
|
2000-06-06 10:32:14 +08:00
|
|
|
OSPF_TRACE(D_PACKETS, "Received LS ack from unknown neigbor! (%I)",
|
2000-03-31 04:00:42 +08:00
|
|
|
nrid);
|
|
|
|
return ;
|
|
|
|
}
|
2000-04-12 23:37:52 +08:00
|
|
|
|
2000-06-06 10:32:14 +08:00
|
|
|
OSPF_TRACE(D_PACKETS, "Received LS ack from %I", n->ip);
|
2000-06-06 03:45:06 +08:00
|
|
|
ospf_neigh_sm(n, INM_HELLOREC);
|
2000-05-10 02:17:34 +08:00
|
|
|
|
2000-05-12 06:00:16 +08:00
|
|
|
if(n->state<NEIGHBOR_EXCHANGE) return;
|
2000-05-10 02:17:34 +08:00
|
|
|
|
2000-05-12 06:00:16 +08:00
|
|
|
nolsa=(lenn-sizeof(struct ospf_lsack_packet))/
|
2000-04-12 23:20:13 +08:00
|
|
|
sizeof(struct ospf_lsa_header);
|
2000-05-12 06:00:16 +08:00
|
|
|
|
|
|
|
if((nolsa<1)||((lenn-sizeof(struct ospf_lsack_packet))!=
|
|
|
|
(nolsa*sizeof(struct ospf_lsa_header))))
|
|
|
|
{
|
2000-06-05 03:56:06 +08:00
|
|
|
log("%s: Received corrupted LS ack from %I", p->name, n->ip);
|
2000-05-12 06:00:16 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
plsa=(struct ospf_lsa_header *)(ps+1);
|
2000-04-12 23:20:13 +08:00
|
|
|
|
|
|
|
for(i=0;i<nolsa;i++)
|
|
|
|
{
|
|
|
|
ntohlsah(plsa+i,&lsa);
|
|
|
|
if((en=ospf_hash_find_header(n->lsrth,&lsa))==NULL) continue;
|
|
|
|
|
|
|
|
if(lsa_comp(&lsa,&en->lsa)!=CMP_SAME)
|
|
|
|
{
|
2000-06-01 02:21:42 +08:00
|
|
|
if((lsa.sn==LSA_MAXSEQNO)&&(lsa.age==LSA_MAXAGE)) continue;
|
|
|
|
|
2000-06-06 10:32:14 +08:00
|
|
|
OSPF_TRACE(D_PACKETS, "Strange LS acknoledgement from %I",n->ip);
|
|
|
|
OSPF_TRACE(D_PACKETS, "Id: %I, Rt: %I, Type: %u",
|
|
|
|
lsa.id,lsa.rt,lsa.type);
|
|
|
|
OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seqno: 0x%08x, Sum: %u",
|
|
|
|
en->lsa.age, en->lsa.sn, en->lsa.checksum);
|
|
|
|
OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seqno: 0x%08x, Sum: %u",
|
|
|
|
lsa.age,lsa.sn,lsa.checksum);
|
2000-04-12 23:20:13 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2000-04-12 23:37:52 +08:00
|
|
|
DBG("Deleting LS Id: %I RT: %I Type: %u from LS Retl for neighbor %I\n",
|
2000-04-12 23:20:13 +08:00
|
|
|
lsa.id,lsa.rt,lsa.type,n->rid);
|
|
|
|
s_rem_node(SNODE en);
|
2004-06-01 21:12:10 +08:00
|
|
|
if(en->lsa_body!=NULL) mb_free(en->lsa_body);
|
|
|
|
en->lsa_body=NULL;
|
2000-04-12 23:20:13 +08:00
|
|
|
ospf_hash_delete(n->lsrth,en);
|
|
|
|
}
|
2000-03-31 04:00:42 +08:00
|
|
|
}
|