/* * BIRD -- OSPF * * (c) 2000 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ #include "ospf.h" /* Note, that h is in network endianity! */ void ospf_lsack_direct_tx(struct ospf_neighbor *n,struct ospf_lsa_header *h) { struct ospf_packet *op; struct ospf_lsack_packet *pk; sock *sk=n->ifa->ip_sk; struct proto *p=&n->ifa->proto->proto; u16 len; DBG("Sending direct ACK to %I for Type: %u, ID: %I, RT: %I\n",n->rid, h->type, ntohl(h->id), ntohl(h->rt)); pk=(struct ospf_lsack_packet *)sk->tbuf; op=(struct ospf_packet *)sk->tbuf; fill_ospf_pkt_hdr(n->ifa, pk, LSACK); memcpy(pk+1,h,sizeof(struct ospf_lsa_header)); len=sizeof(struct ospf_lsack_packet)+sizeof(struct ospf_lsa_header); op->length=htons(len); ospf_pkt_finalize(n->ifa, op); sk_send_to(sk,len, n->ip, OSPF_PROTO); debug("%s: LS ack sent to %I\n", p->name, n->ip); } void ospf_lsa_delay(struct ospf_neighbor *n,struct ospf_lsa_header *h, struct proto *p) { struct lsah_n *no; no=mb_alloc(p->pool,sizeof(struct lsah_n)); memcpy(&no->lsa,h,sizeof(struct ospf_lsa_header)); add_tail(&n->ackl, NODE no); DBG("Adding delay ack for %I, ID: %I, RT: %I, Type: %u\n",n->rid, ntohl(h->id), ntohl(h->rt),h->type); } void ackd_timer_hook(timer *t) { struct ospf_neighbor *n=t->data; if(!EMPTY_LIST(n->ackl)) ospf_lsack_delay_tx(n); } void ospf_lsack_delay_tx(struct ospf_neighbor *n) { 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; debug("%s: LS ack sent to %I (delayed)\n",n->ifa->proto->proto.name,n->ip); 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; fill_ospf_pkt_hdr(n->ifa, pk, LSACK); h=(struct ospf_lsa_header *)(pk+1); while(!EMPTY_LIST(n->ackl)) { no=(struct lsah_n *)HEAD(n->ackl); memcpy(h+i,&no->lsa, sizeof(struct ospf_lsa_header)); i++; 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); mb_free(no); if((i*sizeof(struct ospf_lsa_header)+sizeof(struct ospf_lsack_packet)+SIPH)> n->ifa->iface->mtu) { if(!EMPTY_LIST(n->ackl)) { len=sizeof(struct ospf_lsack_packet)+i*sizeof(struct ospf_lsa_header); op->length=htons(len); ospf_pkt_finalize(n->ifa, op); DBG("Sending and continueing! Len=%u\n",len); 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 { sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); } fill_ospf_pkt_hdr(n->ifa, pk, LSACK); i=0; } } } len=sizeof(struct ospf_lsack_packet)+i*sizeof(struct ospf_lsa_header); op->length=htons(len); ospf_pkt_finalize(n->ifa, op); DBG("Sending! Len=%u\n",len); 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 { sk_send_to_agt(sk, len, ifa, NEIGHBOR_EXCHANGE); } } void ospf_lsack_rx(struct ospf_lsack_packet *ps, struct proto *p, struct ospf_iface *ifa, u16 size) { u32 nrid, myrid; struct ospf_neighbor *n; struct ospf_lsa_header lsa,*plsa; int length; u16 nolsa,i; struct top_hash_entry *en; u16 lenn=ntohs(ps->ospf_packet.length); nrid=ntohl(ps->ospf_packet.routerid); myrid=p->cf->global->router_id; if((n=find_neigh(ifa, nrid))==NULL) { debug("%s: Received LS ack from unknown neigbor! (%I)\n", p->name, nrid); return ; } debug("%s: Received LS ack from %I\n", p->name, n->ip); if(n->statename, n->ip); return; } plsa=(struct ospf_lsa_header *)(ps+1); for(i=0;ilsrth,&lsa))==NULL) continue; if(lsa_comp(&lsa,&en->lsa)!=CMP_SAME) { debug("%s: Strange LS acknoledgement from %I\n",p->name,n->ip); debug("%s: Id: %I, Rt: %I, Type: %u\n",p->name,lsa.id,lsa.rt,lsa.type); debug("%s: I have: Age: %4u, Seqno: 0x%08x\n",p->name,en->lsa.age, en->lsa.sn); debug("%s: He has: Age: %4u, Seqno: 0x%08x\n",p->name,lsa.age,lsa.sn); continue; } DBG("Deleting LS Id: %I RT: %I Type: %u from LS Retl for neighbor %I\n", lsa.id,lsa.rt,lsa.type,n->rid); s_rem_node(SNODE en); ospf_hash_delete(n->lsrth,en); } }