imep.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  * Copyright (c) 1997 Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the Computer Systems
00017  *      Engineering Group at Lawrence Berkeley Laboratory.
00018  * 4. Neither the name of the University nor of the Laboratory may be used
00019  *    to endorse or promote products derived from this software without
00020  *    specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * Ported from CMU/Monarch's code 
00035  *
00036  * $Header: /nfs/jade/vint/CVSROOT/ns-2/imep/imep.cc,v 1.11 2002/03/21 22:44:38 haldar Exp $
00037  */
00038 
00039 #include <packet.h>
00040 #include <ip.h>
00041 #include <random.h>
00042 
00043 #include <cmu-trace.h>
00044 #include <imep/imep.h>
00045 
00046 #define CURRENT_TIME    Scheduler::instance().clock()
00047 
00048 static const int verbose = 0;
00049 static const int imep_use_mac_callback = 1;
00050 
00051 // ======================================================================
00052 //   TCL Hooks
00053 // ======================================================================
00054 
00055 int hdr_imep::offset_;
00056 static class IMEPHeaderClass : public PacketHeaderClass {
00057 public:
00058         IMEPHeaderClass() : PacketHeaderClass("PacketHeader/IMEP",
00059                           IMEP_HDR_LEN) { 
00060         bind_offset(&hdr_imep::offset_);
00061     } 
00062 } class_imep_hdr;
00063 
00064 static class agentIMEPclass : public TclClass {
00065 public:
00066     agentIMEPclass() : TclClass("Agent/IMEP") {}
00067     TclObject* create(int argc, const char*const* argv) {
00068         assert(argc == 5);
00069         return (new imepAgent((nsaddr_t) atoi(argv[4])));
00070     }
00071 } class_imepAgent;
00072 
00073 
00074 // ======================================================================
00075 // ======================================================================
00076 
00077 // MAC layer callback
00078 static void
00079 imep_failed_callback(Packet *p, void *arg)
00080 {
00081     if(imep_use_mac_callback)
00082         ((imepAgent*) arg)->imepPacketUndeliverable(p);
00083     else {
00084         Packet::free(p);
00085         // XXX: Should probably call a "drop" agent here
00086     }
00087 }
00088 
00089 imepAgent::imepAgent(nsaddr_t index) :
00090     Agent(PT_TORA),
00091     beaconTimer(this, BEACON_TIMER),
00092     controlTimer(this, CONTROL_TIMER),
00093     rexmitTimer(this, REXMIT_TIMER),
00094     incomingTimer(this, INCOMING_TIMER),
00095     ipaddr(index),
00096     incomingQ(this, index)
00097 {
00098     controlSequence = 0;
00099     recvtarget_ = sendtarget_ = 0;
00100     logtarget_ = 0;
00101     rtagent_ = 0;
00102     LIST_INIT(&imepLinkHead);
00103     bzero(&stats, sizeof(stats));
00104 }
00105 
00106 int
00107 imepAgent::command(int argc, const char*const* argv)
00108 {
00109     if(argc == 2) {
00110         if(strcmp(argv[1], "start") == 0) {
00111             beaconTimer.start(BEACON_PERIOD);
00112             return TCL_OK;
00113         } 
00114         else if(strcmp(argv[1], "reset") == 0) {
00115                 Terminate();
00116             return TCL_OK;
00117         }
00118     } else if (argc == 3) {
00119         if (strcmp(argv[1], "recvtarget") == 0) {
00120             recvtarget_ = (NsObject*) TclObject::lookup(argv[2]);
00121                         assert(recvtarget_);
00122             return (TCL_OK);
00123         }
00124         else if (strcmp(argv[1], "sendtarget") == 0) {
00125             sendtarget_ = (NsObject*) TclObject::lookup(argv[2]);
00126                         assert(sendtarget_);
00127             return (TCL_OK);
00128         }
00129         else if (strcmp(argv[1], "rtagent") == 0) {
00130             rtagent_ = (rtAgent*) TclObject::lookup(argv[2]);
00131             assert(rtagent_);
00132             return (TCL_OK);
00133         }
00134         else if(strcmp(argv[1], "log-target") == 0) {
00135             logtarget_ = (Trace*) TclObject::lookup(argv[2]);
00136             assert(logtarget_);
00137             return (TCL_OK);
00138         }
00139     }
00140     return Agent::command(argc, argv);
00141 }
00142 
00143 
00144 imepLink*
00145 imepAgent::findLink(nsaddr_t index)
00146 {
00147     imepLink *l;
00148 
00149     for(l = imepLinkHead.lh_first; l; l = l->link.le_next) {
00150         if(l->index() == index)
00151             return l;
00152     }
00153     return 0;
00154 }
00155 
00156 Packet*
00157 imepAgent::findObjectSequence(u_int8_t seqno)
00158 {
00159         Packet *p;  
00160     ReXmitQIter iter = rexmitq.iter();
00161     struct imep_object_block *ob;
00162     
00163     while ((p = iter.next())) {
00164         ob = findObjectBlock(p);
00165 
00166         if(ob == 0) continue;
00167         // no OBJECT block
00168 
00169         if(ob->ob_sequence != seqno) continue;
00170         // wrong SEQUENCE number
00171 
00172         if(ob->ob_num_responses <=0) {
00173             fprintf(stderr,
00174                 "imepAgent::findObjectSequence: "
00175                 "Object Block without response list\n");
00176             abort();
00177         }
00178 
00179         return p;
00180     }
00181 
00182     /*  abort();
00183         this isn't an abort condition.  consider an ack arriving 
00184         for a pkt after it's timed out from the rexmit q -dam */
00185 
00186     return NULL;
00187 }
00188 
00189 
00190 void
00191 imepAgent::removeObjectResponse(Packet *p, nsaddr_t index)
00192 {
00193     struct imep_object_block *ob = findObjectBlock(p);
00194     struct imep_response *r = findResponseList(p);
00195     struct imep_response *r0;
00196     struct hdr_cmn *ch = HDR_CMN(p);
00197     int i;
00198 
00199     assert(ob && r);
00200 
00201     for(i = 0, r0 = r; i < ob->ob_num_responses; i++, r0++) {
00202         if(INT32_T(r0->resp_ipaddr) == index)
00203             break;
00204     }
00205 
00206     if(INT32_T(r0->resp_ipaddr) != index) {
00207       if (verbose) 
00208         trace("T %.9f _%d_ dup ack(?) from %d", CURRENT_TIME, ipaddr, index);
00209       return;
00210     }
00211 
00212     if(ob->ob_num_responses == 1) {
00213             if (verbose) 
00214                trace("T %.9f _%d_ remove from reXq pkt %d", 
00215                  CURRENT_TIME, ipaddr, ch->uid());
00216             rexmitq.remove(p);
00217             Packet::free(p);
00218         stats.num_rexmitable_fully_acked++;
00219     } else {
00220         // find the last "response"
00221             r += (ob->ob_num_responses - 1);
00222 
00223         if(r != r0) {
00224             INT32_T(r0->resp_ipaddr) = INT32_T(r->resp_ipaddr);
00225         }
00226         
00227         ob->ob_num_responses -= 1;          
00228 
00229             if (verbose) 
00230                trace("T %.9f _%d_ remove %d from resp list %d (%d left) RL %s", 
00231                  CURRENT_TIME, ipaddr, index, ch->uid(), ob->ob_num_responses, 
00232              dumpResponseList(p));
00233 
00234         struct hdr_imep *im = HDR_IMEP(p);
00235         ch->size() -= sizeof(struct imep_response);
00236         U_INT16_T(im->imep_length) -= sizeof(struct imep_response);
00237     }
00238 }
00239 
00240 
00241 void 
00242 imepAgent::purgeReXmitQ(nsaddr_t index)
00243   // remove index from any response lists in the rexmit q
00244 {
00245   Packet *p;    
00246   ReXmitQIter iter = rexmitq.iter();
00247   struct imep_object_block *ob;
00248   struct imep_response *r,*r0;
00249   struct hdr_cmn *ch;
00250   int i;
00251 
00252   if (verbose)
00253     trace("T %.9f _%d_ purge %d from reXmit Q", 
00254       CURRENT_TIME, ipaddr, index);
00255 
00256   while ((p = iter.next())) {
00257     ob = findObjectBlock(p);
00258     if(ob == 0) assert(0); // should always be an object block
00259 
00260     r = findResponseList(p);
00261     ch = HDR_CMN(p);
00262 
00263     assert(ob && r);
00264 
00265     for(i = 0, r0 = r; i < ob->ob_num_responses; i++, r0++) {
00266       if(INT32_T(r0->resp_ipaddr) == index)
00267     break;
00268     }
00269 
00270     if(INT32_T(r0->resp_ipaddr) != index) {
00271       continue; // index not in this response list
00272     }
00273 
00274     if(ob->ob_num_responses == 1) {
00275       if (verbose) 
00276     trace("T %.9f _%d_ remove from reXq pkt %d",
00277           CURRENT_TIME, ipaddr, ch->uid());
00278       rexmitq.remove(p);
00279       drop(p, DROP_RTR_QTIMEOUT);
00280       stats.num_rexmitable_fully_acked++;
00281     } else {
00282       // find the last "response"
00283       r += (ob->ob_num_responses - 1);
00284 
00285       if(r != r0) {
00286     INT32_T(r0->resp_ipaddr) = INT32_T(r->resp_ipaddr);
00287       }
00288         
00289       ob->ob_num_responses -= 1;            
00290 
00291       if (verbose) 
00292     trace("T %.9f _%d_ purge %d from resp list %d (%d left) RL %s", 
00293           CURRENT_TIME, ipaddr, index, ch->uid(), ob->ob_num_responses, 
00294           dumpResponseList(p));
00295 
00296       struct hdr_imep *im = HDR_IMEP(p);
00297       ch->size() -= sizeof(struct imep_response);
00298       U_INT16_T(im->imep_length) -= sizeof(struct imep_response);
00299     }
00300   }
00301 }
00302 
00303 
00304 // ======================================================================
00305 // ======================================================================
00306 // Timer Handling Functions
00307 
00308 void
00309 imepAgent::handlerTimer(imepTimerType t)
00310 {
00311     switch(t) {
00312     case BEACON_TIMER:
00313         handlerBeaconTimer();
00314         break;
00315     case CONTROL_TIMER:
00316         handlerControlTimer();
00317         break;
00318     case REXMIT_TIMER:
00319             handlerReXmitTimer();
00320         break;
00321     case INCOMING_TIMER:
00322         handlerIncomingTimer();
00323         break;
00324     default:
00325         abort();
00326     }
00327 }
00328 
00329 void
00330 imepAgent::handlerBeaconTimer(void)
00331 {
00332   imepLink *l;
00333 
00334   // garbage collect old links
00335   purgeLink();
00336 
00337   if (verbose) log_neighbor_list();
00338 
00339   /* aside from the debugging asserts, handleControlTimer will generate a
00340    ``beacon'' packet if there are no objects pending, so we could
00341    just call it.  Since we have sendBeacon() laying around, though, 
00342    I'll call it and leave the debugging asserts in handleControlTimer()
00343 
00344    The packet generated by handlerControlTimer is a beacon equivelent, 
00345    so we don't need to generate a beacon. */
00346 
00347   if (controlTimer.busy() || helloQueue.length() > 0)
00348     { // a control timer is pending or there's left over Hello's in the queue, 
00349       // but we're about to service all pending acks, hellos, and objects now, 
00350       // so cancel the timer
00351       if (controlTimer.busy()) controlTimer.cancel();
00352       handlerControlTimer();
00353     }
00354   else 
00355     { // all the Hellos we had to send out during the last BEACON_PERIOD
00356       // went out.  Assuming there were some, they were beacon equivelent,
00357       // and we don't need to send a beacon now.  If there were none, beacon
00358       if (NULL == imepLinkHead.lh_first) sendBeacon();
00359       // this is a touch conservative, since if there were hellos that went out
00360       // but their links were down'd by purgeLink, we'll still beacon.
00361       // But, if we *have*no* adjacencies, we should do something to get some
00362     }
00363 
00364   /* Send a hello to all our IN adjacencies (everyone we've heard a
00365      packet from). This loads up the helloQueue with all the hellos that
00366      that need to go out sometime in the next BEACON_PERIOD before the
00367      beaconTimer goes off, but doesn't start the controlTimer.  If a
00368      control packet is sent for some other reason, the hellos will ride out
00369      for free, otherwise they'll go out when the beacon timer goes off.
00370      */
00371   int busy_before_hello_load = controlTimer.busy();
00372   for(l = imepLinkHead.lh_first; l; l = l->link.le_next) 
00373     {
00374       if (l->status() & LINK_IN) sendHello(l->index());
00375     }
00376   if (!busy_before_hello_load && controlTimer.busy()) controlTimer.cancel();
00377 
00378   // restart the beacon timer
00379   beaconTimer.start(BEACON_PERIOD);
00380 }
00381 
00382 
00383 // transmit all queued ACKs, HELLOs, and OBJECTs.
00384 void
00385 imepAgent::handlerControlTimer(void)
00386 {
00387     Packet *p;
00388 
00389     int num_acks = ackQueue.length();
00390     int num_hellos = helloQueue.length();
00391     int num_objects = objectQueue.length();
00392 
00393 MAKE_PACKET:
00394     assert(num_acks + num_hellos + num_objects > 0);
00395 
00396     // now have to aggregate multiple control packets
00397 
00398     p = Packet::alloc();
00399     
00400     struct hdr_cmn *ch = HDR_CMN(p);
00401     struct hdr_ip *ih = HDR_IP(p);
00402     struct hdr_imep *im = HDR_IMEP(p);
00403 
00404     ch->uid() = uidcnt_++;
00405     ch->ptype() = PT_IMEP;
00406     ch->size() = BEACON_HDR_LEN;
00407     ch->iface() = -2;
00408     ch->error() = 0;
00409     ch->addr_type() = NS_AF_NONE;
00410         ch->prev_hop_ = ipaddr;
00411 
00412     ih->saddr() = ipaddr;
00413     ih->daddr() = IP_BROADCAST;
00414     ih->sport() = RT_PORT;
00415     ih->dport() = RT_PORT;
00416     ih->ttl_ = 1;
00417 
00418     im->imep_version = IMEP_VERSION;
00419     im->imep_block_flags = 0x00;
00420     U_INT16_T(im->imep_length) = sizeof(struct hdr_imep);
00421 
00422     aggregateAckBlock(p);
00423     aggregateHelloBlock(p);
00424     aggregateObjectBlock(p);
00425 
00426     imep_output(p);
00427 
00428     num_acks = ackQueue.length();
00429     num_hellos = helloQueue.length();
00430     num_objects = objectQueue.length();
00431     if (num_acks + num_hellos + num_objects > 0)
00432       { // not done yet...
00433         if (verbose) 
00434           trace("T %.9f _%d_ imep pkt overflow %d %d %d leftover",
00435             CURRENT_TIME, ipaddr, num_acks, num_hellos, num_objects);
00436         goto MAKE_PACKET;
00437       }
00438 
00439     // don't need to restart the controlTimer because the arrival of
00440     // the next packet from an ULP will start it.
00441 }
00442 
00443 void
00444 imepAgent::handlerReXmitTimer() 
00445 {
00446   Packet *p;
00447   Time rexat;
00448   int num_xmits_left;
00449 
00450   rexmitq.peekHead(&rexat, &p, &num_xmits_left);
00451 
00452   if (NULL == p) return;  //  no more pkts on queue
00453   struct hdr_cmn *ch = HDR_CMN(p);
00454 
00455   if (0 == num_xmits_left)
00456     {
00457       if (verbose) 
00458     {
00459       trace("T %.9f _%d_ rexmit timed out %d RL:%s",
00460         CURRENT_TIME, ipaddr, ch->uid(), dumpResponseList(p));
00461     }
00462 
00463         struct imep_object_block *ob = findObjectBlock(p);
00464     struct imep_response *r = findResponseList(p);
00465     int i;
00466 
00467     for(i = 0; i < ob->ob_num_responses; i++, r++) 
00468       {
00469         if (verbose) trace("T %.9f _%d_ punting neighbor %d",
00470                    CURRENT_TIME, ipaddr, INT32_T(r->resp_ipaddr));
00471         imepSetLinkDownStatus(INT32_T(r->resp_ipaddr));
00472       }
00473 
00474       stats.num_rexmitable_retired++;
00475       stats.sum_rexmitable_retired_response_sz += ob->ob_num_responses;
00476 
00477 
00478       // don't need to explicitly remove p from q and drop it, since
00479       // by downing all the links on it's response list, it'll have bee
00480       // dropped anyway
00481       // rexmitq.removeHead();
00482       // drop(p, DROP_RTR_QTIMEOUT);
00483     }
00484   else if (rexat <= CURRENT_TIME) 
00485     {
00486       if (verbose) 
00487     trace("T %.9f _%d_ rexmit %d as %d",
00488           CURRENT_TIME, ipaddr, ch->uid(), uidcnt_);
00489       ch->uid() = uidcnt_++;
00490       imep_output(p->copy());
00491 
00492       num_xmits_left--;
00493       rexmitq.removeHead(); // take it off the queue and reinsert it
00494       rexmitq.insert(CURRENT_TIME + RETRANS_PERIOD, p, num_xmits_left);
00495 
00496       stats.num_rexmits++;
00497     }  
00498   
00499   // reschedule the timer
00500   rexmitq.peekHead(&rexat, &p, &num_xmits_left);
00501   if (NULL == p) return;  //  no more pkts on queue
00502   if (verbose) trace("T %.9f _%d_ rexmit trigger again for %d at %.9f (in %.9f)",
00503              CURRENT_TIME, ipaddr, ch->uid(), rexat, rexat - CURRENT_TIME );
00504   rexmitTimer.start(rexat - CURRENT_TIME);
00505 }
00506 
00507 
00508 void
00509 imepAgent::handlerIncomingTimer()
00510 {
00511     Packet *p;
00512     u_int32_t s;
00513     double expire;
00514     int index;
00515 
00516     if (verbose) trace("T %.9f _%d_ inorder - timer expired",
00517           CURRENT_TIME, ipaddr);
00518 
00519     incomingQ.dumpAll();
00520 
00521     while((p = incomingQ.getNextPacket(s))) {
00522         stats.num_holes_retired++;
00523         
00524         index = HDR_IP(p)->saddr();
00525         imepLink *l = findLink(index);      
00526         assert(l);  // if there's no link entry, then the incoming
00527         // q should have been cleared, when the link entry was destroyed
00528 
00529         if(verbose) 
00530           trace("T %.9f _%d_ inorder - src %d hole retired seq %d -> %d",
00531             CURRENT_TIME, ipaddr, index, l->lastSeq(), s);
00532 
00533         /* tell ULP that we've effectively broken our link to 
00534            neighbor by retiring the hole and accepting the deletion.
00535            since we don't do this till at least MAX_REXMIT_TIME after
00536            receiving the out of seq packet, we're sure the packet's sender
00537            must have timed us out when we didn't ack their packet.
00538            can't call imepLinkDown b/c it'll purge the reseq q */
00539         rtagent_->rtNotifyLinkDN(index);
00540         stats.delete_neighbor3++;
00541         rtagent_->rtNotifyLinkUP(index);
00542         stats.new_neighbor++;
00543 
00544         if (verbose)
00545           trace("T %.9f _%d_ inorder - src %d seq %d (timer delivery)",
00546             CURRENT_TIME, ipaddr, index, s);
00547 
00548         l->lastSeq() = s;  // advance sequence number for this neighbor
00549         
00550         stats.num_recvd_from_queue++;
00551         imep_object_process(p);
00552         Packet::free(p);
00553 
00554         // now deliver as many in sequence packets to ULP as possible
00555         Packet *p0;
00556         while((p0 = incomingQ.getPacket(index, l->lastSeq() + 1)))
00557           {
00558             if (verbose)
00559               trace("T %.9f _%d_ inorder - src %d seq %d (chain" 
00560                 " timer delivery)", CURRENT_TIME, ipaddr, 
00561                 HDR_IP(p0)->saddr(), l->lastSeq() + 1);
00562             l->lastSeq() += 1;
00563             stats.num_recvd_from_queue++;
00564             imep_object_process(p0);
00565             Packet::free(p0);
00566           }     
00567     }
00568 
00569     if((expire = incomingQ.getNextExpire()) != 0.0) {
00570         assert(expire > CURRENT_TIME);
00571         if (verbose)
00572           trace("T %.9f _%d_ inorder - timer started (delay %.9f)",
00573             CURRENT_TIME, ipaddr, expire - CURRENT_TIME);
00574             incomingTimer.start(expire - CURRENT_TIME);
00575     }
00576 }
00577 
00578 
00580 
00581 void
00582 imepAgent::scheduleReXmit(Packet *p)
00583 {
00584   rexmitq.insert(CURRENT_TIME + RETRANS_PERIOD, p, MAX_REXMITS);
00585   
00586   // start the timer
00587   if (!rexmitTimer.busy()) rexmitTimer.start(RETRANS_PERIOD);    
00588 }
00589 
00590 void
00591 imepAgent::scheduleIncoming(Packet *p, u_int32_t s)
00592 {
00593     struct hdr_ip *ip = HDR_IP(p);
00594 
00595     incomingQ.addEntry(ip->saddr(), CURRENT_TIME + MAX_RETRANS_TIME, s, p);
00596   
00597     // start the timer
00598     if (!incomingTimer.busy()) {
00599         if (verbose) 
00600           trace("T %.9f _%d_ inorder - timer started",
00601             CURRENT_TIME, ipaddr);
00602         incomingTimer.start(MAX_RETRANS_TIME);
00603     }
00604 }
00605 
00606 
00607 // ======================================================================
00608 // Packet Processing Functions
00609 
00610 void
00611 imepAgent::recv(Packet *p, Handler *)
00612 {
00613     //struct hdr_ip *ih = HDR_IP(p);
00614     struct hdr_cmn *ch = HDR_CMN(p);
00615 
00616     assert(initialized());
00617 
00618     if(ch->prev_hop_ == ipaddr) {
00619       // I hate all uses of prev_hop, but the only other way to
00620       // do this test is by checking for a nonNULL handler (like 
00621       // mac-801_11.cc does), which would
00622       // require changing tora to send out pkts with a non 0 hndler
00623       // -dam
00624         recv_outgoing(p);
00625     } else {
00626             recv_incoming(p);
00627     }
00628 }
00629 
00630 void
00631 imepAgent::recv_outgoing(Packet *p)
00632 {
00633     struct hdr_cmn *ch = HDR_CMN(p);
00634     struct hdr_ip *ip = HDR_IP(p);
00635 
00636     if(DATA_PACKET(ch->ptype())) {
00637         imep_output(p);
00638         return;
00639     }
00640 
00641     if(ip->daddr() != (nsaddr_t) IP_BROADCAST) {
00642         fprintf(stderr, "IP dst is unicast - not encapsulating\n");
00643         imep_output(p);
00644         return;
00645     }
00646 
00647     assert(ch->ptype() == PT_TORA);
00648     // XXX: for debugging purposes - IMEP supports other object types
00649 
00650     objectQueue.enque(p);
00651     // this queue is a queue of "packets" passed down from the 
00652     // upper layer routing protocols that IMEP will buffer and try
00653     // to aggregate before transmitting.  Although these are valid
00654     // packets, they must not be transmitted before encaspulating
00655     // them in an IMEP packet to ensure reliability.
00656 
00657     double send_delay = MIN_TRANSMIT_WAIT_TIME_HIGHP
00658       + ((MAX_TRANSMIT_WAIT_TIME_HIGHP - MIN_TRANSMIT_WAIT_TIME_HIGHP)
00659          * Random::uniform());
00660     if (controlTimer.busy() == 0) 
00661       {
00662         controlTimer.start(send_delay);
00663       } 
00664     else if (controlTimer.timeLeft() > send_delay) 
00665       {
00666         controlTimer.cancel();
00667         controlTimer.start(send_delay);
00668       }
00669 }
00670 
00671 void
00672 imepAgent::recv_incoming(Packet *p)
00673 {
00674     struct hdr_cmn *ch = HDR_CMN(p);
00675     struct hdr_ip *ih = HDR_IP(p);
00676     struct hdr_imep *im = HDR_IMEP(p);
00677 
00678     if(DATA_PACKET(ch->ptype())) {
00679         imep_input(p);
00680         return;
00681     }
00682 
00683     // if it's a data packet, the ip->src could be from far away,
00684     // so we can't use it for link indications.  If we RARPd the 
00685     // MAC source addr, we could use that...
00686 
00687     imepSetLinkInStatus(ih->saddr());
00688     // XXX: this could be done at the MAC layer.  In fact, I will 
00689     // augment the IEEE 802.11 layer so that the receipt of an
00690     // ACK confirms bidirectional status. -josh
00691     // hasn't actually be done. seems unlikely to be of help, and is
00692     // fairly hard to do. -dam 8/19/98
00693         assert(ch->ptype() == PT_IMEP);
00694     assert(im->imep_version == IMEP_VERSION);
00695 
00696     if(im->imep_block_flags == 0) {
00697         imep_beacon_input(p);
00698         Packet::free(p);
00699         return;
00700     }
00701 
00702     if(im->imep_block_flags & BLOCK_FLAG_ACK)
00703         imep_ack_input(p);
00704 
00705     if(im->imep_block_flags & BLOCK_FLAG_HELLO)
00706         imep_hello_input(p);
00707 
00708     if(im->imep_block_flags & BLOCK_FLAG_OBJECT) {
00709         imep_object_input(p);
00710         // each upper layer object will be decapsulated and
00711         // placed into its own packet before being passed
00712         // to the upper layer.  This provides total transparency
00713         // to the upper layer.
00714     }
00715 
00716     Packet::free(p);
00717 }
00718 
00719 void
00720 imepAgent::imep_beacon_input(Packet *p)
00721 {
00722     struct hdr_ip *ip = HDR_IP(p);
00723 
00724     sendHello(ip->saddr());
00725 }
00726 
00727 
00728 // If there is an ACK for us we need to (1) removed the sender
00729 // of the ACK from the "ack list", and we need to update the
00730 // status of this neighbor to "BIDIRECTIONAL".
00731 void
00732 imepAgent::imep_ack_input(Packet *p)
00733 {
00734     struct hdr_ip *ih = HDR_IP(p);
00735     struct imep_ack_block *ab = findAckBlock(p);
00736     struct imep_ack *ack;
00737 
00738     assert(ab);
00739     ack = (struct imep_ack*) (ab + 1);
00740 
00741     // According to the IMEP specs, the ACK block (if it exists)
00742     // immediately follows the 3-byte IMEP header.
00743 
00744     for(int i = 0; i < ab->ab_num_acks; i++, ack++) {
00745         if(INT32_T(ack->ack_ipaddr) == ipaddr) {
00746 
00747             Packet *p0 = findObjectSequence(ack->ack_seqno);
00748             if (NULL == p0)
00749               {
00750                 if(verbose) 
00751                   trace("T %.9f _%d_ %d acks seq %d : no obj"
00752                     " block", CURRENT_TIME, ipaddr, 
00753                     ih->saddr(), ack->ack_seqno);
00754                 stats.num_unexpected_acks++;
00755                 continue;
00756               }
00757 
00758             removeObjectResponse(p0, ih->saddr());
00759 
00760             imepSetLinkBiStatus(ih->saddr());
00761         }
00762     }
00763 }
00764 
00765 void
00766 imepAgent::imep_hello_input(Packet *p)
00767 {
00768     struct hdr_ip *ip = HDR_IP(p);
00769     struct imep_hello_block *hb = findHelloBlock(p);
00770     struct imep_hello *hello;
00771 
00772     assert(hb);
00773     hello = (struct imep_hello*) (hb + 1);
00774 
00775     for(int i = 0; i < hb->hb_num_hellos; i++, hello++) {
00776         if(INT32_T(hello->hello_ipaddr) == ipaddr) {
00777 
00778             imepSetLinkBiStatus(ip->saddr());
00779 
00780             break;
00781         }
00782     }
00783 }
00784 
00785 void
00786 imepAgent::imep_object_input(Packet *p)
00787 {
00788     struct imep_object_block *ob;
00789 
00790     // First, send an ack for the object
00791     imep_ack_object(p);
00792 
00793     // now see what to do with the object
00794     ob = findObjectBlock(p);
00795     assert(ob);
00796 
00797     struct hdr_ip *iph = HDR_IP(p);
00798     imepLink *l = findLink(iph->saddr());
00799     assert(l);  // if we have an object, a link entry should already exist
00800 
00801     if (!l->lastSeqValid()) 
00802       { // first object we've heard from this node
00803         l->lastSeqValid() = 1;
00804         l->lastSeq() = ob->ob_sequence - 1;
00805         if (verbose)
00806           trace("T %.9f _d_ first object from neighbor %d seq %d",
00807             CURRENT_TIME, ipaddr, iph->saddr(), ob->ob_sequence);
00808       }
00809 
00810     // This calc requires sequence number SEQ_GT() semantics
00811     // Life will be very bad if this calc isn't actually done in 
00812     // a register the size of the sequence number space
00813     int8_t reg = (int8_t) ob->ob_sequence - (int8_t) l->lastSeq();
00814 
00815     if(reg <= 0)
00816       { // already passed this pkt up to ULP or declared it a permenant
00817         // hole
00818         if (verbose)
00819           trace("T %.9f _%d_ from %d ignored seq %d (already heard)",
00820             CURRENT_TIME, ipaddr, iph->saddr(), ob->ob_sequence);
00821         stats.num_out_of_window_objs++;
00822         return;
00823       }
00824 
00825     if (verbose && reg > 1)
00826       { // found a hole in the sequence number space...
00827         trace("T %.9f _%d_ inorder - src %d seq %d out of order (%d expected)",
00828           CURRENT_TIME, ipaddr, iph->saddr(),
00829           ob->ob_sequence, l->lastSeq()+1);
00830       }
00831 
00832     if (1 == reg)
00833       { // ``fast path''
00834         // got the expected next seq num
00835 
00836         if (verbose)
00837           trace("T %.9f _%d_ inorder - fastpath src %d seq %d (delivering)",
00838             CURRENT_TIME, ipaddr, HDR_IP(p)->saddr(), ob->ob_sequence);
00839         stats.num_in_order_objs++;
00840 
00841         imep_object_process(p);
00842         assert((u_int8_t)(l->lastSeq() + 1) == ob->ob_sequence);
00843         l->lastSeq() = ob->ob_sequence;
00844       }
00845     else
00846       {
00847         // put this packet on the resequencing queue
00848         scheduleIncoming(p->copy(), ob->ob_sequence);
00849         stats.num_out_of_order_objs++;
00850       }
00851 
00852     // now deliver as many in-sequence packets to ULP as possible
00853     Packet *p0;
00854     while((p0 = incomingQ.getPacket(iph->saddr(), l->lastSeq() + 1)))
00855       {
00856         stats.num_recvd_from_queue++;
00857         if (verbose)
00858           trace("T %.9f _%d_ inorder - src %d seq %d (delivering)",
00859             CURRENT_TIME, ipaddr, HDR_IP(p0)->saddr(), l->lastSeq() + 1);
00860         l->lastSeq() += 1;
00861         imep_object_process(p0);
00862         Packet::free(p0);
00863       }
00864 }
00865 
00866 void
00867 imepAgent::imep_object_process(Packet *p)
00868   // hand the conents of any object in the pkt to the respective ULP
00869 {
00870   struct imep_object_block *ob;
00871   struct imep_object *object;
00872   int i;
00873 
00874   stats.num_object_pkts_recvd++;
00875 
00876   ob = findObjectBlock(p);
00877   assert(ob);
00878   assert(ob->ob_protocol_type == PROTO_TORA); // XXX: more general later
00879 
00880   object = (struct imep_object*) (ob + 1);
00881 
00882   for(i = 0; i < ob->ob_num_objects; i++)
00883     {
00884       Packet *p0 = p->copy();
00885         
00886       assert(object->o_length > 0); // sanity check
00887         
00888       toraCreateHeader(p0,
00889                ((char*) object) + sizeof(struct imep_object),
00890                object->o_length);
00891         
00892       imep_input(p0);
00893         
00894       object = (struct imep_object*) ((char*) object + 
00895              sizeof(struct imep_object) + object->o_length);
00896     }
00897 }
00898 
00899 
00900 void
00901 imepAgent::imep_ack_object(Packet *p)
00902   // send an ack for the object in p, if any
00903 {
00904   struct hdr_ip *iph = HDR_IP(p);
00905   struct imep_object_block *ob;
00906   struct imep_object *object;
00907   int i;
00908 
00909   ob = findObjectBlock(p);
00910   if (!ob) return;
00911 
00912   if (0 == ob->ob_num_responses) 
00913     return;
00914 
00915   if (31 == ob->ob_num_responses) 
00916     { // a ``broadcast'' response list to which everyone replies
00917       sendAck(iph->saddr(), ob->ob_sequence);
00918       return;
00919     }
00920 
00921   object = (struct imep_object*) (ob + 1);
00922 
00923   // walk the objects to find the response list
00924   for(i = 0; i < ob->ob_num_objects; i++)
00925     {       
00926       object = (struct imep_object*) ((char*) object + 
00927              sizeof(struct imep_object) + object->o_length);
00928     }
00929 
00930   struct imep_response *r = (struct imep_response*) object;
00931   for (i = 0; i < ob->ob_num_responses; i++)
00932     {
00933       if (INT32_T(r->resp_ipaddr) == ipaddr)
00934     {
00935       sendAck(iph->saddr(), ob->ob_sequence);
00936       break;
00937     }
00938       r = r + 1;
00939     }
00940 }
00941 
00942 // ======================================================================
00943 // ======================================================================
00944 // Routines by which packets leave the IMEP object
00945 
00946 void
00947 imepAgent::imep_input(Packet *p)
00948 {
00949     recvtarget_->recv(p, (Handler*) 0);
00950 }
00951 
00952 void
00953 imepAgent::imep_output(Packet *p)
00954 {
00955     struct hdr_cmn *ch = HDR_CMN(p);
00956 
00957     if(imep_use_mac_callback) {
00958         ch->xmit_failure_ = imep_failed_callback;
00959         ch->xmit_failure_data_ = (void*) this;
00960     } else {
00961         ch->xmit_failure_ = 0;
00962         ch->xmit_failure_data_ = 0;
00963     }
00964     ch->xmit_reason_ = 0;
00965 
00966     sendtarget_->recv(p, (Handler*) 0);
00967 }
00968 
00969 // ======================================================================
00970 // ======================================================================
00971 // Debugging routines
00972 
00973 void
00974 imepAgent::imep_dump_header(Packet *p)
00975 {
00976     struct hdr_imep *im = HDR_IMEP(p);
00977 
00978     fprintf(stderr,
00979         "imep_version: 0x%x\n", im->imep_version);
00980     fprintf(stderr,
00981         "imep_block_flags: 0x%x\n", im->imep_block_flags);
00982     fprintf(stderr,
00983         "imep_length: 0x%04x\n", U_INT16_T(im->imep_length));
00984 
00985     Packet::dump_header(p, hdr_imep::offset_, 64);
00986 }
00987 
00988 void
00989 imepAgent::log_neighbor_list()
00990 {
00991     imepLink *l;
00992     int offset = 0;
00993 
00994         if(! verbose ) return;
00995     
00996         sprintf(logtarget_->pt_->buffer(),
00997                 "T %.9f _%d_ neighbors: ", CURRENT_TIME, ipaddr);
00998 
00999     for(l = imepLinkHead.lh_first; l; l = l->link.le_next) {
01000       offset = strlen(logtarget_->pt_->buffer());
01001       sprintf(logtarget_->pt_->buffer() + offset,
01002           "%d%c ", l->index(),
01003           l->status() == LINK_BI ? '+' : 
01004             (l->status() == LINK_IN ? '-' : 
01005              (l->status() == LINK_OUT ? '|' : 'X')));
01006     }
01007         logtarget_->pt_->dump();
01008 }
01009 
01010 void
01011 imepAgent::trace(char* fmt, ...)
01012 {
01013   va_list ap;
01014   
01015   if (!logtarget_) return;
01016 
01017   va_start(ap, fmt);
01018   vsprintf(logtarget_->pt_->buffer(), fmt, ap);
01019   logtarget_->pt_->dump();
01020   va_end(ap);
01021 }
01022 
01023 
01024 char *
01025 imepAgent::dumpResponseList(Packet *p)
01026 {
01027   static char buf[512];
01028   char *ptr = buf;
01029   struct imep_object_block *ob = findObjectBlock(p);
01030   struct imep_response *r = findResponseList(p);
01031   struct imep_response *r0;
01032   int i;
01033 
01034   for(i = 0, r0 = r; i < ob->ob_num_responses; i++, r0++) 
01035     {
01036       ptr += (int)sprintf(ptr,"%d ", INT32_T(r0->resp_ipaddr));
01037     }
01038   return buf;
01039 }
01040 
01041 
01042 void
01043 imepAgent::Terminate()
01044 {
01045   trace("IL %.9f _%d_ Add-Adj: %d New-Neigh: %d Del-Neigh1: %d Del-Neigh2: %d Del-Neigh3: %d",
01046     CURRENT_TIME, ipaddr, 
01047     stats.new_in_adjacency,
01048     stats.new_neighbor      ,
01049     stats.delete_neighbor1      ,
01050     stats.delete_neighbor2,
01051     stats.delete_neighbor3);
01052 
01053   trace("IL %.9f _%d_ Created QRY: %d UPD: %d CLR: %d",CURRENT_TIME, ipaddr,
01054     stats.qry_objs_created      ,
01055     stats.upd_objs_created      ,
01056     stats.clr_objs_created);
01057 
01058   trace("IL %.9f _%d_ Received QRY: %d UPD: %d CLR: %d",CURRENT_TIME, ipaddr,
01059     stats.qry_objs_recvd      ,
01060     stats.upd_objs_recvd      ,
01061     stats.clr_objs_recvd);
01062 
01063   trace("IL %.9f _%d_ Total-Obj-Created: %d Obj-Pkt-Created: %d Obj-Pkt-Recvd: %d",
01064     CURRENT_TIME, ipaddr,
01065     stats.num_objects_created      ,
01066     stats.num_object_pkts_created      ,
01067     stats.num_object_pkts_recvd);
01068 
01069   trace("IL %.9f _%d_ Rexmit Pkts: %d Acked: %d Retired: %d Rexmits: %d",
01070     CURRENT_TIME, ipaddr,
01071     stats.num_rexmitable_pkts      ,
01072     stats.num_rexmitable_fully_acked      ,
01073     stats.num_rexmitable_retired      ,
01074     stats.num_rexmits);
01075 
01076 
01077   trace("IL %.9f _%d_ Sum-Response-List-Size Created: %d Retired: %d",
01078     CURRENT_TIME, ipaddr,
01079     stats.sum_response_list_sz      ,
01080     stats.sum_rexmitable_retired_response_sz);
01081 
01082   trace("IL %.9f _%d_ Holes Created: %d Retired: %d ReSeqQ-Drops: %d ReSeqQ-Recvd: %d",
01083     CURRENT_TIME, ipaddr,
01084     stats.num_holes_created      ,
01085     stats.num_holes_retired      ,
01086     stats.num_reseqq_drops,
01087     stats.num_recvd_from_queue);
01088 
01089   trace("IL %.9f _%d_ Unexpected-Acks: %d Out-Win-Obj: %d Out-Order-Obj: %d In-Order-Obj: %d", CURRENT_TIME, ipaddr,
01090     stats.num_unexpected_acks      ,
01091     stats.num_out_of_window_objs      ,
01092     stats.num_out_of_order_objs      ,
01093     stats.num_in_order_objs);
01094 }

Generated on Tue Mar 6 16:47:46 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6