Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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 Apr 20 12:14:20 2004 for NS2.26SourcesOriginal by doxygen 1.3.3