天天看点

NS2下AODV协议aodv.cc源码分析

修改aodv协议心得 在修改完协议后一定要记得在\ns-allinone-2.xx\ns-2.xx目录下make编译,否则没用,步骤如下:
1、首先,要修改你的协议,如果修改的是.h文件,一定要记得再修改一下调用这个.h文件的.cc文件(感谢SeaSon的指导)
2、记得修改\ns-allinone-2.xx\ns-2.xx目录下的Makefile.in和Makefile文件(修改Makefile的时间一定要比Makefile.in晚)。(感谢自己:lol )
3、然后  make clean
         make
4、OK,等编译完成吧
           
感谢原作者 http://blog.csdn.net/ise_gaoyue1990/article/details/7610522/
           
//#include <ip.h>  
  
#include <aodv/aodv.h>  
#include <aodv/aodv_packet.h>  
#include <random.h>  
#include <cmu-trace.h>  
//#include <energy-model.h>  
  
#define max(a,b)        ( (a) > (b) ? (a) : (b) )  
#define CURRENT_TIME    Scheduler::instance().clock()  
  
//#define DEBUG  
//#define ERROR  
  
#ifdef DEBUG  
static int extra_route_reply = 0;  
static int limit_route_request = 0;  
static int route_request = 0;  
#endif  
  
  
/* 
  TCL Hooks 
*/  
  
  
int hdr_aodv::offset_;  
static class AODVHeaderClass : public PacketHeaderClass {  
public:  
        AODVHeaderClass() : PacketHeaderClass("PacketHeader/AODV",  
                                              sizeof(hdr_all_aodv)) {  
      bind_offset(&hdr_aodv::offset_);  
    }   
} class_rtProtoAODV_hdr;  
/*AODVclass 只有两个函数,构造函数和creat函数*/  
static class AODVclass : public TclClass {  
public:  
        AODVclass() : TclClass("Agent/AODV") {}  
        TclObject* create(int argc, const char*const* argv) {  
          assert(argc == 5);  
          //return (new AODV((nsaddr_t) atoi(argv[4])));  
      return (new AODV((nsaddr_t) Address::instance().str2addr(argv[4])));  
        }  
} class_rtProtoAODV;  
  
/*command函数实现了命令的分发*/  
int  
AODV::command(int argc, const char*const* argv) {  
  if(argc == 2) {//命令的参数个数是2  
  Tcl& tcl = Tcl::instance();  
      
    if(strncasecmp(argv[1], "id", 2) == 0) {//命令所要求的操作为id  
      tcl.resultf("%d", index);  
      return TCL_OK;  
    }  
      
    if(strncasecmp(argv[1], "start", 2) == 0) {//命令所要求的操作为start  
      btimer.handle((Event*) 0);  
  
#ifndef AODV_LINK_LAYER_DETECTION  
      htimer.handle((Event*) 0);  
      ntimer.handle((Event*) 0);  
#endif // LINK LAYER DETECTION  
  
      rtimer.handle((Event*) 0);  
      return TCL_OK;  
     }                 
  }  
  else if(argc == 3) {//命令参数个数等于3  
    if(strcmp(argv[1], "index") == 0) {//命令所要求的操作为index  
      index = atoi(argv[2]);  
      return TCL_OK;  
    }  
//命令所要求的操作为log-target或者tracetarget  
    else if(strcmp(argv[1], "log-target") == 0 || strcmp(argv[1], "tracetarget") == 0) {  
      logtarget = (Trace*) TclObject::lookup(argv[2]);  
      if(logtarget == 0)  
    return TCL_ERROR;  
      return TCL_OK;  
    }  
    else if(strcmp(argv[1], "drop-target") == 0)   
    {  
    //命令所要求的操作为drop-target  
    int stat = rqueue.command(argc,argv);  
      if (stat != TCL_OK) return stat;  
      return Agent::command(argc, argv);  
    }  
  
    //命令所要求的操作if-queue  
    else if(strcmp(argv[1], "if-queue") == 0) {  
    ifqueue = (PriQueue*) TclObject::lookup(argv[2]);  
        
      if(ifqueue == 0)  
    return TCL_ERROR;  
      return TCL_OK;  
    }  
    //命令所要求的操作为port-dmux  
    else if (strcmp(argv[1], "port-dmux") == 0) {  
        dmux_ = (PortClassifier *)TclObject::lookup(argv[2]);  
    if (dmux_ == 0) {  
        fprintf (stderr, "%s: %s lookup of %s failed\n", __FILE__,  
        argv[1], argv[2]);  
        return TCL_ERROR;  
    }  
    return TCL_OK;  
    }  
  }  
  return Agent::command(argc, argv);  
}  
  
/*  
   Constructor 
*/  
  
AODV::AODV(nsaddr_t id) : Agent(PT_AODV),  
              btimer(this), htimer(this), ntimer(this),   
              rtimer(this), lrtimer(this), rqueue() {  
   
                  
  index = id;  
  seqno = 2;  
  bid = 1;  
  
  LIST_INIT(&nbhead);  
  LIST_INIT(&bihead);  
  
  logtarget = 0;  
  ifqueue = 0;  
}  
  
/* 
  Timers 
*/  
//广播定时器  
void  
BroadcastTimer::handle(Event*) {  
  agent->id_purge();  
  Scheduler::instance().schedule(this, &intr, BCAST_ID_SAVE);  
}  
//hello报文定时器  
void  
HelloTimer::handle(Event*) {  
   agent->sendHello();  
   double interval = MinHelloInterval +   
                 ((MaxHelloInterval - MinHelloInterval) * Random::uniform());  
   assert(interval >= 0);  
   Scheduler::instance().schedule(this, &intr, interval);  
}  
//邻居定时器  
void  
NeighborTimer::handle(Event*) {  
  agent->nb_purge();  
  Scheduler::instance().schedule(this, &intr, HELLO_INTERVAL);  
}  
路由缓存定时器  
void  
RouteCacheTimer::handle(Event*) {  
  agent->rt_purge();  
#define FREQUENCY 0.5 // sec  
  Scheduler::instance().schedule(this, &intr, FREQUENCY);  
}  
//路由缓存定时器  
void  
LocalRepairTimer::handle(Event* p)  {  // SRD: 5/4/99  
aodv_rt_entry *rt;  
struct hdr_ip *ih = HDR_IP( (Packet *)p);  
  
   /* you get here after the timeout in a local repair attempt */  
   /*   fprintf(stderr, "%s\n", __FUNCTION__); */  
  
  
    rt = agent->rtable.rt_lookup(ih->daddr());  
      
    if (rt && rt->rt_flags != RTF_UP) {  
    // route is yet to be repaired  
    // I will be conservative and bring down the route  
    // and send route errors upstream.  
    /* The following assert fails, not sure why */  
    /* assert (rt->rt_flags == RTF_IN_REPAIR); */  
          
      //rt->rt_seqno++;  
      agent->rt_down(rt);  
      // send RERR  
#ifdef DEBUG  
      fprintf(stderr,"Node %d: Dst - %d, failed local repair\n",index, rt->rt_dst);  
#endif        
    }  
    Packet::free((Packet *)p);  
}  
  
  
/* 
   Broadcast ID Management  Functions 
*/  
  
  
void  
AODV::id_insert(nsaddr_t id, u_int32_t bid) {  
BroadcastID *b = new BroadcastID(id, bid);  
  
 assert(b);  
 b->expire = CURRENT_TIME + BCAST_ID_SAVE;  
 LIST_INSERT_HEAD(&bihead, b, link);  
}  
  
/* SRD */  
bool  
AODV::id_lookup(nsaddr_t id, u_int32_t bid) {  
BroadcastID *b = bihead.lh_first;  
   
 // Search the list for a match of source and bid  
 for( ; b; b = b->link.le_next) {  
   if ((b->src == id) && (b->id == bid))  
     return true;       
 }  
 return false;  
}  
  
void  
AODV::id_purge() {  
BroadcastID *b = bihead.lh_first;  
BroadcastID *bn;  
double now = CURRENT_TIME;  
  
 for(; b; b = bn) {  
   bn = b->link.le_next;  
   if(b->expire <= now) {  
     LIST_REMOVE(b,link);  
     delete b;  
   }  
 }  
}  
  
/* 
  Helper Functions 
*/  
  
double  
AODV::PerHopTime(aodv_rt_entry *rt) {  
int num_non_zero = 0, i;  
double total_latency = 0.0;  
  
 if (!rt)  
   return ((double) NODE_TRAVERSAL_TIME );  
      
 for (i=0; i < MAX_HISTORY; i++) {  
   if (rt->rt_disc_latency[i] > 0.0) {  
      num_non_zero++;  
      total_latency += rt->rt_disc_latency[i];  
   }  
 }  
 if (num_non_zero > 0)  
   return(total_latency / (double) num_non_zero);  
 else  
   return((double) NODE_TRAVERSAL_TIME);  
  
}  
  
/* 
  Link Failure Management Functions 
*/  
  
static void  
aodv_rt_failed_callback(Packet *p, void *arg) {  
  ((AODV*) arg)->rt_ll_failed(p);  
}  
  
/* 
 * This routine is invoked when the link-layer reports a route failed. 
 */  
 /*邻居链路down掉,处理*/  
void  
AODV::rt_ll_failed(Packet *p) {  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
aodv_rt_entry *rt;  
nsaddr_t broken_nbr = ch->next_hop_;//记录下一跳邻居的地址  
  
#ifndef AODV_LINK_LAYER_DETECTION  
 drop(p, DROP_RTR_MAC_CALLBACK);  
#else   
  
 /* 
  * Non-data packets and Broadcast Packets can be dropped. 
  */  
  //如果是非数据或者广播报文,则可以直接丢弃  
  if(! DATA_PACKET(ch->ptype()) ||  
     (u_int32_t) ih->daddr() == IP_BROADCAST) {  
    drop(p, DROP_RTR_MAC_CALLBACK);  
    return;  
  }  
  log_link_broke(p);  
  //如果不存在到达目的节点的路径,丢弃报文  
    if((rt = rtable.rt_lookup(ih->daddr())) == 0) {  
    drop(p, DROP_RTR_MAC_CALLBACK);  
    return;  
  }  
  log_link_del(ch->next_hop_);  
  
#ifdef AODV_LOCAL_REPAIR  
  /* if the broken link is closer to the dest than source,  
     attempt a local repair. Otherwise, bring down the route. */  
  
//如果转发的跳数大于到达目的节点的跳数,则进行路由修复;否则丢弃通过此邻居的  
//数据并且删除此邻居  
  if (ch->num_forwards() > rt->rt_hops) {  
    local_rt_repair(rt, p); // local repair  
    // retrieve all the packets in the ifq using this link,  
    // queue the packets for which local repair is done,   
    return;  
  }  
  else    
#endif // LOCAL REPAIR    
  
  {  
    drop(p, DROP_RTR_MAC_CALLBACK);  
    // Do the same thing for other packets in the interface queue using the  
    // broken link -Mahesh  
while((p = ifqueue->filter(broken_nbr))) {  
     drop(p, DROP_RTR_MAC_CALLBACK);  
    }     
    nb_delete(broken_nbr);  
  }  
  
#endif // LINK LAYER DETECTION  
}  
/*当发现邻居失效的时候,就会调用此函数*/  
void  
AODV::handle_link_failure(nsaddr_t id) {  
aodv_rt_entry *rt, *rtn;  
Packet *rerr = Packet::alloc();  
struct hdr_aodv_error *re = HDR_AODV_ERROR(rerr);  
  
 re->DestCount = 0;  
 //查找通过此邻居节点到达目的的路由,  
 for(rt = rtable.head(); rt; rt = rtn) {  // for each rt entry  
   rtn = rt->rt_link.le_next;   
   //如果跳数不是无限大并且下一跳就是失效的邻居  
   if ((rt->rt_hops != INFINITY2) && (rt->rt_nexthop == id) ) {  
     assert (rt->rt_flags == RTF_UP);  
     assert((rt->rt_seqno%2) == 0);  
     rt->rt_seqno++;  
     re->unreachable_dst[re->DestCount] = rt->rt_dst;  
     re->unreachable_dst_seqno[re->DestCount] = rt->rt_seqno;  
#ifdef DEBUG  
     fprintf(stderr, "%s(%f): %d\t(%d\t%u\t%d)\n", __FUNCTION__, CURRENT_TIME,  
             index, re->unreachable_dst[re->DestCount],  
             re->unreachable_dst_seqno[re->DestCount], rt->rt_nexthop);  
#endif // DEBUG  
     re->DestCount += 1;  
     rt_down(rt);//将此路由down掉  
   }  
   // remove the lost neighbor from all the precursor lists  
   rt->pc_delete(id);//删除此路由的前缀列表  
 }     
/*如果存在通过此邻居到达目的节点的路由,则发送错误报文*/  
 if (re->DestCount > 0) {  
#ifdef DEBUG  
   fprintf(stderr, "%s(%f): %d\tsending RERR...\n", __FUNCTION__, CURRENT_TIME, index);  
#endif // DEBUG  
   sendError(rerr, false);  
 }  
 else {  
   Packet::free(rerr);  
 }  
}  
  
void  
AODV::local_rt_repair(aodv_rt_entry *rt, Packet *p) {  
#ifdef DEBUG  
  fprintf(stderr,"%s: Dst - %d\n", __FUNCTION__, rt->rt_dst);   
#endif    
  // Buffer the packet   
  rqueue.enque(p);  
  
  // mark the route as under repair   
  rt->rt_flags = RTF_IN_REPAIR;  
  
  sendRequest(rt->rt_dst);  
  
  // set up a timer interrupt  
  Scheduler::instance().schedule(&lrtimer, p->copy(), rt->rt_req_timeout);  
}  
/*更新路由条目*/  
void  
AODV::rt_update(aodv_rt_entry *rt, u_int32_t seqnum, u_int16_t metric,  
            nsaddr_t nexthop, double expire_time) {  
  
     rt->rt_seqno = seqnum;  
     rt->rt_hops = metric;  
     rt->rt_flags = RTF_UP;  
     rt->rt_nexthop = nexthop;  
     rt->rt_expire = expire_time;  
}  
/*将此路由条目down掉*/  
void  
AODV::rt_down(aodv_rt_entry *rt) {  
  /* 
   *  Make sure that you don't "down" a route more than once. 
   */  
  
  if(rt->rt_flags == RTF_DOWN) {  
    return;  
  }  
  
  // assert (rt->rt_seqno%2); // is the seqno odd?  
  rt->rt_last_hop_count = rt->rt_hops;  
  rt->rt_hops = INFINITY2;  
  rt->rt_flags = RTF_DOWN;  
  rt->rt_nexthop = 0;  
  rt->rt_expire = 0;  
  
} /* rt_down function */  
  
/* 
  Route Handling Functions 
*/  
  
void  
AODV::rt_resolve(Packet *p) {  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
aodv_rt_entry *rt;  
  
 /* 
  *  Set the transmit failure callback.  That 
  *  won't change. 
  */  
  //这是一个指针,具体请看另一篇博客  
 ch->xmit_failure_ = aodv_rt_failed_callback;  
 ch->xmit_failure_data_ = (void*) this;  
    rt = rtable.rt_lookup(ih->daddr());  
 if(rt == 0) {  
      rt = rtable.rt_add(ih->daddr());  
 }  
  
 /* 
  * If the route is up, forward the packet  
  */  
    //如果存在路由,则转发  
 if(rt->rt_flags == RTF_UP) {  
   assert(rt->rt_hops != INFINITY2);  
   forward(rt, p, NO_DELAY);  
 }  
 /* 
  *  if I am the source of the packet, then do a Route Request. 
  */  
    else if(ih->saddr() == index)   
    // {  
    //如果是源节点且没有到达目的节点的路由,缓存数分组  
    //发送路由请求  
   rqueue.enque(p);  
   sendRequest(rt->rt_dst);  
 }  
 /* 
  * A local repair is in progress. Buffer the packet.  
  */  
  //如果此路由处于修复状态,则缓存分组  
 else if (rt->rt_flags == RTF_IN_REPAIR) {  
   rqueue.enque(p);  
 }  
  
 /* 
  * I am trying to forward a packet for someone else to which 
  * I don't have a route. 
  */  
  //否则发送错误报文  
 else {  
 Packet *rerr = Packet::alloc();  
 struct hdr_aodv_error *re = HDR_AODV_ERROR(rerr);  
 /*  
  * For now, drop the packet and send error upstream. 
  * Now the route errors are broadcast to upstream 
  * neighbors - Mahesh 09/11/99 
  */      
   
   assert (rt->rt_flags == RTF_DOWN);  
   re->DestCount = 0;  
   re->unreachable_dst[re->DestCount] = rt->rt_dst;  
   re->unreachable_dst_seqno[re->DestCount] = rt->rt_seqno;  
   re->DestCount += 1;  
#ifdef DEBUG  
   fprintf(stderr, "%s: sending RERR...\n", __FUNCTION__);  
#endif  
   sendError(rerr, false);  
  
   drop(p, DROP_RTR_NO_ROUTE);  
 }  
  
}  
/*定时查看路由缓存条目*/  
void  
AODV::rt_purge() {  
aodv_rt_entry *rt, *rtn;  
double now = CURRENT_TIME;  
double delay = 0.0;  
Packet *p;  
  
 for(rt = rtable.head(); rt; rt = rtn) {  // for each rt entry  
   rtn = rt->rt_link.le_next;  
   //如果此路由条目标注为有效,但是生存时间为0  
   //丢弃前往目的分组,并且将此路由条目down掉  
   if ((rt->rt_flags == RTF_UP) && (rt->rt_expire < now)) {  
   // if a valid route has expired, purge all packets from   
   // send buffer and invalidate the route.                      
    assert(rt->rt_hops != INFINITY2);  
     while((p = rqueue.deque(rt->rt_dst))) {  
#ifdef DEBUG  
       fprintf(stderr, "%s: calling drop()\n",  
                       __FUNCTION__);  
#endif // DEBUG  
       drop(p, DROP_RTR_NO_ROUTE);  
     }  
     rt->rt_seqno++;  
     assert (rt->rt_seqno%2);  
     rt_down(rt);  
   }  
   //如果此路由条目并没有过期,则可以发送分组  
   else if (rt->rt_flags == RTF_UP) {  
   // If the route is not expired,  
   // and there are packets in the sendbuffer waiting,  
   // forward them. This should not be needed, but this extra   
   // check does no harm.  
     assert(rt->rt_hops != INFINITY2);  
     while((p = rqueue.deque(rt->rt_dst))) {  
       forward (rt, p, delay);  
       delay += ARP_DELAY;  
     }  
   }   
   //如果此路由条目已经down掉,但是有前往目的的分组,则发送路由请求  
   else if (rqueue.find(rt->rt_dst))  
   // If the route is down and   
   // if there is a packet for this destination waiting in  
   // the sendbuffer, then send out route request. sendRequest  
   // will check whether it is time to really send out request  
   // or not.  
   // This may not be crucial to do it here, as each generated   
   // packet will do a sendRequest anyway.  
  
     sendRequest(rt->rt_dst);   
   }  
  
}  
  
/* 
  Packet Reception Routines 
*/  
  
void  
AODV::recv(Packet *p, Handler*) {  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
  
 assert(initialized());  
 //assert(p->incoming == 0);  
 // XXXXX NOTE: use of incoming flag has been depracated; In order to track direction of pkt flow, direction_ in hdr_cmn is used instead. see packet.h for details.  
//如果分组类型是AODV类型,则交给recvAodv函数  
 if(ch->ptype() == PT_AODV) {  
   ih->ttl_ -= 1;  
   recvAODV(p);  
   return;  
 }  
  
  
 /* 
  *  Must be a packet I'm originating... 
  */  
  //如果是我发送的报文,加上包头,ch->num_forward()是转发的跳数  
if((ih->saddr() == index) && (ch->num_forwards() == 0)) {  
 /* 
  * Add the IP Header 
  */  
   ch->size() += IP_HDR_LEN;  
   // Added by Parag Dadhania && John Novatnack to handle broadcasting  
   if ( (u_int32_t)ih->daddr() != IP_BROADCAST)  
     ih->ttl_ = NETWORK_DIAMETER;  
}  
 /* 
  *  I received a packet that I sent.  Probably 
  *  a routing loop. 
  */  
  //出现路由环路,丢弃  
else if(ih->saddr() == index) {  
   drop(p, DROP_RTR_ROUTE_LOOP);  
   return;  
 }  
 /* 
  *  Packet I'm forwarding... 
  */  
 else {  
 /* 
  *  Check the TTL.  If it is zero, then discard. 
  */  
  //如果ttl值为零,丢弃  
   if(--ih->ttl_ == 0) {  
     drop(p, DROP_RTR_TTL);  
     return;  
   }  
 }  
// Added by Parag Dadhania && John Novatnack to handle broadcasting  
//如果不是广播报文,交给re_resolve函数处理;如果是广播报文,则转发  
 if ( (u_int32_t)ih->daddr() != IP_BROADCAST)  
   rt_resolve(p);  
 else  
   forward((aodv_rt_entry*) 0, p, NO_DELAY);  
}  
  
  
void  
AODV::recvAODV(Packet *p) {  
struct hdr_aodv *ah = HDR_AODV(p);  
struct hdr_ip *ih = HDR_IP(p);  
  
 assert(ih->sport() == RT_PORT);  
 assert(ih->dport() == RT_PORT);  
  
 /* 
  * Incoming Packets. 
  */  
 switch(ah->ah_type) {  
  
 case AODVTYPE_RREQ:  
   recvRequest(p);  
   break;  
  
 case AODVTYPE_RREP:  
   recvReply(p);  
   break;  
  
 case AODVTYPE_RERR:  
   recvError(p);  
   break;  
  
 case AODVTYPE_HELLO:  
   recvHello(p);  
   break;  
          
 default:  
   fprintf(stderr, "Invalid AODV type (%x)\n", ah->ah_type);  
   exit(1);  
 }  
  
}  
  
  
void  
AODV::recvRequest(Packet *p) {  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p);  
aodv_rt_entry *rt;  
  
  /* 
   * Drop if: 
   *      - I'm the source 
   *      - I recently heard this request. 
   */  
/*如果此节点就是源节点,出现环路,丢弃路由请求报文*/  
  if(rq->rq_src == index) {  
#ifdef DEBUG  
    fprintf(stderr, "%s: got my own REQUEST\n", __FUNCTION__);  
#endif // DEBUG  
    Packet::free(p);  
    return;  
  }   
/*如果已经收到了源地址和请求序列号相等的请求报文,丢弃*/  
 if (id_lookup(rq->rq_src, rq->rq_bcast_id)) {  
  
#ifdef DEBUG  
   fprintf(stderr, "%s: discarding request\n", __FUNCTION__);  
#endif // DEBUG  
   
   Packet::free(p);  
   return;  
 }  
  
 /* 
  * Cache the broadcast ID 
  */  
  /*缓存此路由请求*/  
 id_insert(rq->rq_src, rq->rq_bcast_id);  
  
  
  
 /*  
  * We are either going to forward the REQUEST or generate a 
  * REPLY. Before we do anything, we make sure that the REVERSE 
  * route is in the route table. 
  */  
  //建立反向路径  
 aodv_rt_entry *rt0; // rt0 is the reverse route   
     
   rt0 = rtable.rt_lookup(rq->rq_src);  
   if(rt0 == 0) { /* if not in the route table */  
   // create an entry for the reverse route.  
     rt0 = rtable.rt_add(rq->rq_src);  
   }  
  //更新此路由条目的生存时间  
   rt0->rt_expire = max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE));  
/*如果请求序列号大于路由序列号或者两者序列号相等但是跳数 
比源路由跳数小,则更新*/  
   if ( (rq->rq_src_seqno > rt0->rt_seqno ) ||  
        ((rq->rq_src_seqno == rt0->rt_seqno) &&   
     (rq->rq_hop_count < rt0->rt_hops)) ) {  
   // If we have a fresher seq no. or lesser #hops for the   
   // same seq no., update the rt entry. Else don't bother.  
rt_update(rt0, rq->rq_src_seqno, rq->rq_hop_count, ih->saddr(),  
               max(rt0->rt_expire, (CURRENT_TIME + REV_ROUTE_LIFE)) );  
   /*如果此前请求过该路由条目,则更新信息*/  
     if (rt0->rt_req_timeout > 0.0) {  
     // Reset the soft state and   
     // Set expiry time to CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT  
     // This is because route is used in the forward direction,  
     // but only sources get benefited by this change  
       rt0->rt_req_cnt = 0;  
       rt0->rt_req_timeout = 0.0;   
       rt0->rt_req_last_ttl = rq->rq_hop_count;  
       rt0->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT;  
     }  
  
     /* Find out whether any buffered packet can benefit from the  
      * reverse route. 
      * May need some change in the following code - Mahesh 09/11/99 
      */  
      /*如果有到反向路径的分组报文,则发送*/  
     assert (rt0->rt_flags == RTF_UP);  
     Packet *buffered_pkt;  
     while ((buffered_pkt = rqueue.deque(rt0->rt_dst))) {  
       if (rt0 && (rt0->rt_flags == RTF_UP)) {  
    assert(rt0->rt_hops != INFINITY2);  
         forward(rt0, buffered_pkt, NO_DELAY);  
       }  
     }  
   }   
   // End for putting reverse route in rt table  
  
  
 /* 
  * We have taken care of the reverse route stuff. 
  * Now see whether we can send a route reply.  
  */  
//寻找到目的节点的路由  
 rt = rtable.rt_lookup(rq->rq_dst);  
  
 // First check if I am the destination ..  
/*如果本节点就是目的节点,直接发送路由应答报文*/  
 if(rq->rq_dst == index) {  
  
#ifdef DEBUG  
   fprintf(stderr, "%d - %s: destination sending reply\n",  
                   index, __FUNCTION__);  
#endif // DEBUG  
  
                 
   // Just to be safe, I use the max. Somebody may have  
   // incremented the dst seqno.  
   seqno = max(seqno, rq->rq_dst_seqno)+1;  
   if (seqno%2) seqno++;  
  
   sendReply(rq->rq_src,           // IP Destination  
             1,                    // Hop Count  
             index,                // Dest IP Address  
             seqno,                // Dest Sequence Num  
             MY_ROUTE_TIMEOUT,     // Lifetime  
             rq->rq_timestamp);    // timestamp  
   
   Packet::free(p);  
 }  
  
 // I am not the destination, but I may have a fresh enough route.  
/*如果不是目的节点,但是有到目的节点的路径,也发送路由应答报文*/  
 else if (rt && (rt->rt_hops != INFINITY2) &&   
        (rt->rt_seqno >= rq->rq_dst_seqno) ) {  
  
   //assert (rt->rt_flags == RTF_UP);  
   assert(rq->rq_dst == rt->rt_dst);  
   //assert ((rt->rt_seqno%2) == 0); // is the seqno even?  
   sendReply(rq->rq_src,  
             rt->rt_hops + 1,  
             rq->rq_dst,  
             rt->rt_seqno,  
         (u_int32_t) (rt->rt_expire - CURRENT_TIME),  
         //             rt->rt_expire - CURRENT_TIME,  
             rq->rq_timestamp);  
   // Insert nexthops to RREQ source and RREQ destination in the  
   // precursor lists of destination and source respectively  
   rt->pc_insert(rt0->rt_nexthop); // 加入前缀列表  
   rt0->pc_insert(rt->rt_nexthop); // 加入前缀列表  
  
#ifdef RREQ_GRAT_RREP    
  
   sendReply(rq->rq_dst,  
             rq->rq_hop_count,  
             rq->rq_src,  
             rq->rq_src_seqno,  
         (u_int32_t) (rt->rt_expire - CURRENT_TIME),  
         //             rt->rt_expire - CURRENT_TIME,  
             rq->rq_timestamp);  
#endif  
     
// TODO: send grat RREP to dst if G flag set in RREQ using rq->rq_src_seqno, rq->rq_hop_counT  
     
// DONE: Included gratuitous replies to be sent as per IETF aodv draft specification. As of now, G flag has not been dynamically used and is always set or reset in aodv-packet.h --- Anant Utgikar, 09/16/02.  
  
    Packet::free(p);  
 }  
 /* 
  * Can't reply. So forward the  Route Request 
  */  
  //不能应答此报文,则继续广播  
 else {  
   ih->saddr() = index;  
   ih->daddr() = IP_BROADCAST;  
   rq->rq_hop_count += 1;  
   // Maximum sequence number seen en route  
   if (rt) rq->rq_dst_seqno = max(rt->rt_seqno, rq->rq_dst_seqno);  
   forward((aodv_rt_entry*) 0, p, DELAY);  
 }  
  
}  
  
  
void  
AODV::recvReply(Packet *p) {  
//struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);  
aodv_rt_entry *rt;  
char suppress_reply = 0;  
double delay = 0.0;  
      
#ifdef DEBUG  
 fprintf(stderr, "%d - %s: received a REPLY\n", index, __FUNCTION__);  
#endif // DEBUG  
  
  
 /* 
  *  Got a reply. So reset the "soft state" maintained for  
  *  route requests in the request table. We don't really have 
  *  have a separate request table. It is just a part of the 
  *  routing table itself.  
  */  
 // Note that rp_dst is the dest of the data packets, not the  
 // the dest of the reply, which is the src of the data packets.  
  
 rt = rtable.rt_lookup(rp->rp_dst);//建立反向路径  
          
 /* 
  *  If I don't have a rt entry to this host... adding 
  */  
 if(rt == 0) {  
   rt = rtable.rt_add(rp->rp_dst);  
 }  
  
 /* 
  * Add a forward route table entry... here I am following  
  * Perkins-Royer AODV paper almost literally - SRD 5/99 
  */  
/*如果应答报文中目的序列号大于路由序列号或者 
 两者序列号相等但是跳数较小,则更新路由表*/  
 if ( (rt->rt_seqno < rp->rp_dst_seqno) ||   // newer route   
      ((rt->rt_seqno == rp->rp_dst_seqno) &&    
       (rt->rt_hops > rp->rp_hop_count)) ) { // shorter or better route  
      
  // Update the rt entry   
  rt_update(rt, rp->rp_dst_seqno, rp->rp_hop_count,  
        rp->rp_src, CURRENT_TIME + rp->rp_lifetime);  
  
  // reset the soft state  
  rt->rt_req_cnt = 0;//路由请求次数归零  
  rt->rt_req_timeout = 0.0; //路由请求剩余时间归零  
  rt->rt_req_last_ttl = rp->rp_hop_count;  
  /*如果此节点是目的节点*/  
if (ih->daddr() == index) { // If I am the original source  
  // Update the route discovery latency statistics  
  // rp->rp_timestamp is the time of request origination  
          
    rt->rt_disc_latency[rt->hist_indx] = (CURRENT_TIME - rp->rp_timestamp)  
                                         / (double) rp->rp_hop_count;  
    // increment indx for next time  
    rt->hist_indx = (rt->hist_indx + 1) % MAX_HISTORY;  
  }   
  
  /* 
   * Send all packets queued in the sendbuffer destined for 
   * this destination.  
   * XXX - observe the "second" use of p. 
   */  
   /*如果有到反向路径的数据包,则发送*/  
  Packet *buf_pkt;  
  while((buf_pkt = rqueue.deque(rt->rt_dst))) {  
    if(rt->rt_hops != INFINITY2) {  
          assert (rt->rt_flags == RTF_UP);  
    // Delay them a little to help ARP. Otherwise ARP   
    // may drop packets. -SRD 5/23/99  
      forward(rt, buf_pkt, delay);  
      delay += ARP_DELAY;  
    }  
  }  
 }  
 else {  
  suppress_reply = 1;//序列号过小且没有更小的跳数  
 }  
  
 /* 
  * If reply is for me, discard it. 
  */  
  
if(ih->daddr() == index || suppress_reply)   
 {//如果此节点是源节点或者应答报文不够新且没有更小的跳数  
   Packet::free(p);  
 }  
 /* 
  * Otherwise, forward the Route Reply. 
  */  
 else {  
 // Find the rt entry  
aodv_rt_entry *rt0 = rtable.rt_lookup(ih->daddr());  
   // If the rt is up, forward  
   if(rt0 && (rt0->rt_hops != INFINITY2))   
    {  
   //如果存在到源节点的路径,则转发应答报文,否则丢弃应答报文  
        assert (rt0->rt_flags == RTF_UP);  
     rp->rp_hop_count += 1;  
     rp->rp_src = index;  
     forward(rt0, p, NO_DELAY);  
     // Insert the nexthop towards the RREQ source to   
     // the precursor list of the RREQ destination  
     rt->pc_insert(rt0->rt_nexthop); // nexthop to RREQ source  
       
   }  
   else {//  
   // I don't know how to forward .. drop the reply.   
#ifdef DEBUG  
     fprintf(stderr, "%s: dropping Route Reply\n", __FUNCTION__);  
#endif // DEBUG  
     drop(p, DROP_RTR_NO_ROUTE);  
   }  
 }  
}  
  
/*从邻居那里收到错误分组,检查自己路由表是否有通过此邻居到达目的地的 
路由条目,如果有,则将此路由删除,并继续向邻居广播错误分组*/  
void  
AODV::recvError(Packet *p) {  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_error *re = HDR_AODV_ERROR(p);  
aodv_rt_entry *rt;  
u_int8_t i;  
Packet *rerr = Packet::alloc();  
struct hdr_aodv_error *nre = HDR_AODV_ERROR(rerr);  
  
 nre->DestCount = 0;  
/*遍历错误分组中每一个不可达路由*/  
 for (i=0; i<re->DestCount; i++) {  
 // For each unreachable destination  
   rt = rtable.rt_lookup(re->unreachable_dst[i]);  
 /*是否存在经过发送错误分组的邻居的路由*/  
   if ( rt && (rt->rt_hops != INFINITY2) &&  
    (rt->rt_nexthop == ih->saddr()) &&  
        (rt->rt_seqno <= re->unreachable_dst_seqno[i]) ) {  
    assert(rt->rt_flags == RTF_UP);  
    assert((rt->rt_seqno%2) == 0); // 奇数代表无穷大,无效的意思  
#ifdef DEBUG  
     fprintf(stderr, "%s(%f): %d\t(%d\t%u\t%d)\t(%d\t%u\t%d)\n", __FUNCTION__,CURRENT_TIME,  
             index, rt->rt_dst, rt->rt_seqno, rt->rt_nexthop,  
             re->unreachable_dst[i],re->unreachable_dst_seqno[i],  
                 ih->saddr());  
#endif // DEBUG  
        rt->rt_seqno = re->unreachable_dst_seqno[i];  
        rt_down(rt);//将此路由down掉  
  
   // Not sure whether this is the right thing to do  
   /*查看队列中是否有下一跳是此邻居的分组 
   若有的话,直接丢包;具体请看queue/priqueue.cc的filter函数*/  
   Packet *pkt;  
    while((pkt = ifqueue->filter(ih->saddr()))) {  
            drop(pkt, DROP_RTR_MAC_CALLBACK);  
        }  
  
     // if precursor list non-empty add to RERR and delete the precursor list  
     /*如果此路由的前缀列表非空,将此节点不可达的目的地记录在新的路由分组中 
     并且删除此路由的前缀列表*/  
        if (!rt->pc_empty()) {  
            nre->unreachable_dst[nre->DestCount] = rt->rt_dst;  
            nre->unreachable_dst_seqno[nre->DestCount] = rt->rt_seqno;  
            nre->DestCount += 1;  
        rt->pc_delete();  
        }  
   }  
 }   
/*如果此节点有不可达路由,则继续广播错误分组*/  
 if (nre->DestCount > 0) {  
#ifdef DEBUG  
   fprintf(stderr, "%s(%f): %d\t sending RERR...\n", __FUNCTION__, CURRENT_TIME, index);  
#endif // DEBUG  
   sendError(rerr);  
 }  
 else {  
   Packet::free(rerr);  
 }  
  
 Packet::free(p);  
}  
  
  
/* 
   Packet Transmission Routines 
*/  
  
void  
AODV::forward(aodv_rt_entry *rt, Packet *p, double delay) {  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
/*如果跳数为零,直接丢弃*/  
 if(ih->ttl_ == 0) {  
  
#ifdef DEBUG  
  fprintf(stderr, "%s: calling drop()\n", __PRETTY_FUNCTION__);  
#endif // DEBUG  
   
  drop(p, DROP_RTR_TTL);  
  return;  
 }  
/*如果不是AODV数据包并且链路方向是上行并且是广播包或者此节点就是目的地址*/  
 if (ch->ptype() != PT_AODV && ch->direction() == hdr_cmn::UP &&  
    ((u_int32_t)ih->daddr() == IP_BROADCAST)  
        || ((u_int32_t)ih->daddr() == here_.addr_)) {  
    dmux_->recv(p,0);//交给分类器  
    return;  
 }  
  
 if (rt) {//如果存在去往目的的路由,设置一系列参数  
   assert(rt->rt_flags == RTF_UP);  
   rt->rt_expire = CURRENT_TIME + ACTIVE_ROUTE_TIMEOUT;  
   ch->next_hop_ = rt->rt_nexthop;  
   ch->addr_type() = NS_AF_INET;  
   ch->direction() = hdr_cmn::DOWN;       //important: change the packet's direction  
 }  
 else { // if it is a broadcast packet  
   // assert(ch->ptype() == PT_AODV); // maybe a diff pkt type like gaf  
   assert(ih->daddr() == (nsaddr_t) IP_BROADCAST);//如果这是一个广播报文  
   ch->addr_type() = NS_AF_NONE;  
   ch->direction() = hdr_cmn::DOWN;       //important: change the packet's direction  
 }  
  
if (ih->daddr() == (nsaddr_t) IP_BROADCAST) {//广播报文  
 // If it is a broadcast packet  
   assert(rt == 0);  
   /* 
    *  Jitter the sending of broadcast packets by 10ms 
    */  
   Scheduler::instance().schedule(target_, p,  
                       0.01 * Random::uniform());//加入定时器  
 }  
 else { // 非广播报文  
   if(delay > 0.0) {  
     Scheduler::instance().schedule(target_, p, delay);  
   }  
   else {  
   // Not a broadcast packet, no delay, send immediately  
     Scheduler::instance().schedule(target_, p, 0.);  
   }  
 }  
  
}  
  
  
void  
AODV::sendRequest(nsaddr_t dst) {  
// Allocate a RREQ packet   
Packet *p = Packet::alloc();  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_request *rq = HDR_AODV_REQUEST(p);  
aodv_rt_entry *rt = rtable.rt_lookup(dst);  
  
 assert(rt);  
  
 /* 
  *  Rate limit sending of Route Requests. We are very conservative 
  *  about sending out route requests.  
  */  
 //如果有到目的节点的路由,则终止请求  
 if (rt->rt_flags == RTF_UP) {  
   assert(rt->rt_hops != INFINITY2);  
   Packet::free((Packet *)p);  
   return;  
 }  
//如果请求时间还有到,则不发送  
 if (rt->rt_req_timeout > CURRENT_TIME) {  
   Packet::free((Packet *)p);  
   return;  
 }  
  
 // rt_req_cnt is the no. of times we did network-wide broadcast  
 // RREQ_RETRIES is the maximum number we will allow before   
 // going to a long timeout.  
//如果请求次数大于最大的发送请求次数,则丢掉分组,不发送请求  
 if (rt->rt_req_cnt > RREQ_RETRIES) {  
   rt->rt_req_timeout = CURRENT_TIME + MAX_RREQ_TIMEOUT;  
   rt->rt_req_cnt = 0;  
 Packet *buf_pkt;  
   while ((buf_pkt = rqueue.deque(rt->rt_dst))) {  
       drop(buf_pkt, DROP_RTR_NO_ROUTE);  
   }  
   Packet::free((Packet *)p);  
   return;  
 }  
  
#ifdef DEBUG  
   fprintf(stderr, "(%2d) - %2d sending Route Request, dst: %d\n",  
                    ++route_request, index, rt->rt_dst);  
#endif // DEBUG  
  
 // Determine the TTL to be used this time.   
 // Dynamic TTL evaluation - SRD  
  
 rt->rt_req_last_ttl = max(rt->rt_req_last_ttl,rt->rt_last_hop_count);  
//路由请求的环搜索  
//第一次广播请求,选择初始跳数;随后逐渐扩大  
 if (0 == rt->rt_req_last_ttl) {  
 // first time query broadcast  
   ih->ttl_ = TTL_START;  
 }  
 else {  
 // Expanding ring search.  
   if (rt->rt_req_last_ttl < TTL_THRESHOLD)  
     ih->ttl_ = rt->rt_req_last_ttl + TTL_INCREMENT;  
   else {  
   // network-wide broadcast  
     ih->ttl_ = NETWORK_DIAMETER;  
     rt->rt_req_cnt += 1;  
   }  
 }  
  
 // remember the TTL used  for the next time  
 rt->rt_req_last_ttl = ih->ttl_;//为下次使用做记录  
  
 // PerHopTime is the roundtrip time per hop for route requests.  
 // The factor 2.0 is just to be safe .. SRD 5/22/99  
 // Also note that we are making timeouts to be larger if we have   
 // done network wide broadcast before.   
  
 rt->rt_req_timeout = 2.0 * (double) ih->ttl_ * PerHopTime(rt);   
 if (rt->rt_req_cnt > 0)  
   rt->rt_req_timeout *= rt->rt_req_cnt;  
 rt->rt_req_timeout += CURRENT_TIME;  
  
 // Don't let the timeout to be too large, however .. SRD 6/8/99  
 if (rt->rt_req_timeout > CURRENT_TIME + MAX_RREQ_TIMEOUT)  
   rt->rt_req_timeout = CURRENT_TIME + MAX_RREQ_TIMEOUT;  
 rt->rt_expire = 0;  
  
#ifdef DEBUG  
 fprintf(stderr, "(%2d) - %2d sending Route Request, dst: %d, tout %f ms\n",  
             ++route_request,   
         index, rt->rt_dst,   
         rt->rt_req_timeout - CURRENT_TIME);  
#endif  // DEBUG  
      
  
 // Fill out the RREQ packet   
 // ch->uid() = 0;  
 ch->ptype() = PT_AODV;  
 ch->size() = IP_HDR_LEN + rq->size();  
 ch->iface() = -2;  
 ch->error() = 0;  
 ch->addr_type() = NS_AF_NONE;  
 ch->prev_hop_ = index;          // AODV hack  
  
 ih->saddr() = index;  
 ih->daddr() = IP_BROADCAST;  
 ih->sport() = RT_PORT;  
 ih->dport() = RT_PORT;  
  
 // Fill up some more fields.   
 rq->rq_type = AODVTYPE_RREQ;  
 rq->rq_hop_count = 1;  
 rq->rq_bcast_id = bid++;  
 rq->rq_dst = dst;  
 rq->rq_dst_seqno = (rt ? rt->rt_seqno : 0);  
 rq->rq_src = index;  
 seqno += 2;  
 assert ((seqno%2) == 0);  
 rq->rq_src_seqno = seqno;  
 rq->rq_timestamp = CURRENT_TIME;  
  
 Scheduler::instance().schedule(target_, p, 0.);  
  
}  
  
void  
AODV::sendReply(nsaddr_t ipdst, u_int32_t hop_count, nsaddr_t rpdst,  
                u_int32_t rpseq, u_int32_t lifetime, double timestamp) {  
Packet *p = Packet::alloc();  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);  
aodv_rt_entry *rt = rtable.rt_lookup(ipdst);  
  
#ifdef DEBUG  
fprintf(stderr, "sending Reply from %d at %.2f\n", index, Scheduler::instance().clock());  
#endif // DEBUG  
 assert(rt);  
  
 rp->rp_type = AODVTYPE_RREP;  
 //rp->rp_flags = 0x00;  
 rp->rp_hop_count = hop_count;  
 rp->rp_dst = rpdst;  
 rp->rp_dst_seqno = rpseq;  
 rp->rp_src = index;  
 rp->rp_lifetime = lifetime;  
 rp->rp_timestamp = timestamp;  
     
 // ch->uid() = 0;  
 ch->ptype() = PT_AODV;  
 ch->size() = IP_HDR_LEN + rp->size();  
 ch->iface() = -2;  
 ch->error() = 0;  
 ch->addr_type() = NS_AF_INET;  
 ch->next_hop_ = rt->rt_nexthop;  
 ch->prev_hop_ = index;          // AODV hack  
 ch->direction() = hdr_cmn::DOWN;  
  
 ih->saddr() = index;  
 ih->daddr() = ipdst;  
 ih->sport() = RT_PORT;  
 ih->dport() = RT_PORT;  
 ih->ttl_ = NETWORK_DIAMETER;  
  
 Scheduler::instance().schedule(target_, p, 0.);  
  
}  
  
void  
AODV::sendError(Packet *p, bool jitter) {  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_error *re = HDR_AODV_ERROR(p);  
      
#ifdef ERROR  
fprintf(stderr, "sending Error from %d at %.2f\n", index, Scheduler::instance().clock());  
#endif // DEBUG  
  
 re->re_type = AODVTYPE_RERR;  
 //re->reserved[0] = 0x00; re->reserved[1] = 0x00;  
 // DestCount and list of unreachable destinations are already filled  
  
 // ch->uid() = 0;  
 ch->ptype() = PT_AODV;  
 ch->size() = IP_HDR_LEN + re->size();  
 ch->iface() = -2;  
 ch->error() = 0;  
 ch->addr_type() = NS_AF_NONE;  
 ch->next_hop_ = 0;  
 ch->prev_hop_ = index;          // AODV hack  
 ch->direction() = hdr_cmn::DOWN;       //important: change the packet's direction  
  
 ih->saddr() = index;  
 ih->daddr() = IP_BROADCAST;  
 ih->sport() = RT_PORT;  
 ih->dport() = RT_PORT;  
 ih->ttl_ = 1;  
  
 // Do we need any jitter? Yes  
 if (jitter)  
    Scheduler::instance().schedule(target_, p, 0.01*Random::uniform());  
 else  
    Scheduler::instance().schedule(target_, p, 0.0);  
  
}  
  
  
/* 
   Neighbor Management Functions 
*/  
  
void  
AODV::sendHello() {  
Packet *p = Packet::alloc();  
struct hdr_cmn *ch = HDR_CMN(p);  
struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_reply *rh = HDR_AODV_REPLY(p);  
  
#ifdef DEBUG  
fprintf(stderr, "sending Hello from %d at %.2f\n", index, Scheduler::instance().clock());  
#endif // DEBUG  
  
 rh->rp_type = AODVTYPE_HELLO;  
 //rh->rp_flags = 0x00;  
 rh->rp_hop_count = 1;  
 rh->rp_dst = index;  
 rh->rp_dst_seqno = seqno;  
 rh->rp_lifetime = (1 + ALLOWED_HELLO_LOSS) * HELLO_INTERVAL;  
  
 // ch->uid() = 0;  
 ch->ptype() = PT_AODV;  
 ch->size() = IP_HDR_LEN + rh->size();  
 ch->iface() = -2;  
 ch->error() = 0;  
 ch->addr_type() = NS_AF_NONE;  
 ch->prev_hop_ = index;          // AODV hack  
  
 ih->saddr() = index;  
 ih->daddr() = IP_BROADCAST;  
 ih->sport() = RT_PORT;  
 ih->dport() = RT_PORT;  
 ih->ttl_ = 1;  
  
 Scheduler::instance().schedule(target_, p, 0.0);  
}  
  
  
void  
AODV::recvHello(Packet *p) {  
//struct hdr_ip *ih = HDR_IP(p);  
struct hdr_aodv_reply *rp = HDR_AODV_REPLY(p);  
AODV_Neighbor *nb;  
  
 nb = nb_lookup(rp->rp_dst);  
 if(nb == 0) {  
   nb_insert(rp->rp_dst);  
 }  
 else {  
   nb->nb_expire = CURRENT_TIME +  
                   (1.5 * ALLOWED_HELLO_LOSS * HELLO_INTERVAL);  
 }  
  
 Packet::free(p);  
}  
  
void  
AODV::nb_insert(nsaddr_t id) {  
AODV_Neighbor *nb = new AODV_Neighbor(id);  
  
 assert(nb);  
 nb->nb_expire = CURRENT_TIME +  
                (1.5 * ALLOWED_HELLO_LOSS * HELLO_INTERVAL);  
 LIST_INSERT_HEAD(&nbhead, nb, nb_link);  
 seqno += 2;             // set of neighbors changed  
 assert ((seqno%2) == 0);  
}  
  
  
AODV_Neighbor*  
AODV::nb_lookup(nsaddr_t id) {  
AODV_Neighbor *nb = nbhead.lh_first;  
  
 for(; nb; nb = nb->nb_link.le_next) {  
   if(nb->nb_addr == id) break;  
 }  
 return nb;  
}  
  
  
/* 
 * Called when we receive *explicit* notification that a Neighbor 
 * is no longer reachable. 
 */  
void  
AODV::nb_delete(nsaddr_t id) {  
AODV_Neighbor *nb = nbhead.lh_first;  
  
 log_link_del(id);  
 seqno += 2;     // Set of neighbors changed  
 assert ((seqno%2) == 0);  
  
 for(; nb; nb = nb->nb_link.le_next) {  
   if(nb->nb_addr == id) {  
     LIST_REMOVE(nb,nb_link);  
     delete nb;  
     break;  
   }  
 }  
  
 handle_link_failure(id);  
  
}  
  
  
/* 
 * Purges all timed-out Neighbor Entries - runs every 
 * HELLO_INTERVAL * 1.5 seconds. 
 */  
void  
AODV::nb_purge() {  
AODV_Neighbor *nb = nbhead.lh_first;  
AODV_Neighbor *nbn;  
double now = CURRENT_TIME;  
  
 for(; nb; nb = nbn) {  
   nbn = nb->nb_link.le_next;  
   if(nb->nb_expire <= now) {  
     nb_delete(nb->nb_addr);  
   }  
 }  
  
}  
           
NS2