## modules/up/src/Core/network/ICMProbe.cc

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. icmprobeTimerHandler
2. ICMProbe
3. ICMProbe
4. send
5. handleTimer
6. receive

       1 //
       2 // $Id: ICMProbe.cc,v 1.1.1.1 2000/03/10 16:32:19 engin Exp $
       3 //
       4 // Author(s): Ramesh Govindan
       5
       6 #ifdef HAVE_CONFIG_H
       7 #include <config.h>
       8 #endif
       9
      10 extern "C" {
      11 #include <sys/types.h>
      12 #include <netinet/in_systm.h>
      13 #include <netinet/in.h>
      14 #include <netinet/ip.h>
      15 }
      16
      17 #include "util/Types.hh"
      18 #include "util/Trail.hh"
      19 #include "util/Handler.hh"
      20 #include "util/Buffer.hh"
      21 #include "sys/File.hh"
      22 #include "sys/Pipe.hh"
      23 #include "sys/Time.hh"
      24 #include "sched/Timer.hh"
      25 #include "sched/Dispatcher.hh"
      26
      27 #include "network/ICMProbe.hh"
      28 #include "network/Headers.hh"
      29 #include "network/Network.hh"
      30
      31 // Constants
      32 static const unsigned char      UDPProtocol = 17;
      33
      34 // Locals
      35 static TraceCode        traceICMProbe("net");
      36 static TimeShort        maxWait(10, 0);
      37 static unsigned int     probeNumber = 0x80000000;
      38
      39 static void
      40 icmprobeTimerHandler(void* ptr,
         /* [<][>][^][v][top][bottom][index][help] */
      41                    void*)
      42 {
      43     ((ICMProbe*) ptr)->handleTimer();
      44 }
      45
      46 ICMProbe::ICMProbe(Address* a,
         /* [<][>][^][v][top][bottom][index][help] */
      47                    Handler& cb,
      48                    int hc,
      49                    Address* v)
      50    : ListNode()
      51 {
      52     done = cb;
      53     to = *a;
      54     hopcount = hc;
      55     if (v) {
      56         via = *v;
      57     }
      58     timer = NULL;
      59     result = ICMProbeResultNone;
      60     residualHops = 0;
      61     network->pendingICMProbes.append(this);
      62     probeId = 0;
      63     lastRtt = InfiniteInterval;
      64     sent = 0;
      65 }
      66
      67 ICMProbe::~ICMProbe()
         /* [<][>][^][v][top][bottom][index][help] */
      68 {
      69     network->pendingICMProbes.remove(this);
      70     if (timer) {
      71         delete timer;
      72     }
      73 }
      74
      75 void
      76 ICMProbe::send()
         /* [<][>][^][v][top][bottom][index][help] */
      77 {
      78     Handler     th(icmprobeTimerHandler, this);
      79     Handler     nh(NULL, NULL);
      80     Buffer*     buf;
      81     IP*         ip;
      82     IPOptLSRR*  ipopt;
      83     ICMP*       icmp;
      84     RawSocket*  raw;
      85     U32*        t;
      86     TimeLong    at;
      87     Address     srcaddr;
      88
      89     responder.set(0);
      90     result = ICMProbeResultNone;
      91     sent++;
      92     network->icmprobesSent++;
      93
      94     // Send packet
      95     raw = new RawSocket(nh, nh, RawSocketICMP);
      96     if (via.get()) {
      97         buf = new Buffer(sizeof(IP) + sizeof(IPOptLSRR) + sizeof(ICMP) + 8);
      98     } else {
      99         buf = new Buffer(sizeof(IP) + sizeof(ICMP) + 8);
     100     }
     101     buf->zeroFill();
     102
     103     ip = (IP*) buf->contents;
     104     ip->headerLength = via.get() ?
     105         (sizeof(IP) + sizeof(IPOptLSRR)) >> 2 :
     106          sizeof(IP) >> 2;
     107     ip->version = 4;
     108     ip->typeOfService = 0;
     109     ip->totalLength = (ip->headerLength << 2) + sizeof(ICMP);
     110     ip->identifier = 0;
     111     ip->fragmentOffset = 0;
     112     ip->timeToLive = hopcount;
     113     ip->protocol = IPPROTO_ICMP;
     114     ip->source = (network->interfaces.head())->address.get();
     115     ip->destination = (via.get()) ? via.get() : to.get();
     116     ip->hton();
     117     ip->checksum = 0;
     118     ip->checksum = network->cksum((U16*) ip, ip->headerLength << 2);
     119
     120     if (via.get()) {
     121         IPOptLSRR*      lsrr;
     122
     123         lsrr = (IPOptLSRR*) (ip + 1);
     124         lsrr->nullopt = IPOPT_NOP;
     125         lsrr->lsrropt = IPOPT_LSRR;
     126         lsrr->length = sizeof(U32) + 3;
     127         lsrr->pointer = IPOPT_MINOFF;
     128         lsrr->gateway = to.get();
     129         lsrr->hton();
     130         icmp = (ICMP*) (lsrr + 1);
     131     } else {
     132         icmp = (ICMP*) (ip + 1);
     133     }
     134
     135     ASSERT(probeNumber != 0xffffffff);  // Wrap around
     136     probeNumber++;
     137     probeId = probeNumber;
     138
     139     icmp->type = ICMPTypeEcho;
     140     icmp->code = 0;
     141     icmp->gateway = probeNumber;
     142     icmp->hton();
     143     icmp->checksum = 0;
     144     icmp->checksum = network->cksum((U16*) icmp, sizeof(ICMP) + 8);
     145
     146     dispatcher.systemClock.sync();
     147     sentAt = dispatcher.systemClock;
     148
     149     raw->sendTo(buf->contents, buf->size, to, 0);
     150
     151     TRACE(traceICMProbe, "icmprobe to %s:%d\n", to.name(), hopcount);
     152
     153     delete raw;
     154     delete buf;
     155
     156     if (timer) {
     157         delete timer;
     158     }
     159     at = dispatcher.systemClock;
     160     at = at + maxWait;
     161     timer = new Timer(th, at);
     162
     163     return;
     164 }
     165
     166 void
     167 ICMProbe::handleTimer()
         /* [<][>][^][v][top][bottom][index][help] */
     168 {
     169     TRACE(traceICMProbe, "icmprobe failed to %s\n", to.name());
     170
     171     timer = NULL;
     172     network->icmprobesTimedOut++;
     173     done.callBack((void*) this);
     174     lastRtt = InfiniteInterval;
     175     return;
     176 }
     177
     178 Boolean
     179 ICMProbe::receive(IP* ip)
         /* [<][>][^][v][top][bottom][index][help] */
     180 {
     181     ICMP*               icmp;
     182     unsigned short      sum;
     183     IP*                 iip;
     184     int                 datalen;
     185
     186     // Verify signature to see if it is for us
     187     icmp = (struct ICMP*) ((char*) ip + (ip->headerLength << 2));
     188     if (icmp->type != ICMPTypeTimeExceeded &&
     189         icmp->type != ICMPTypeDestinationUnreachable &&
     190         icmp->type != ICMPTypeEchoReply)
     191         return false;
     192
     193     if (icmp->type == ICMPTypeTimeExceeded ||
     194         icmp->type == ICMPTypeDestinationUnreachable) {
     195
     196        datalen = ip->totalLength - (ip->headerLength << 2) - sizeof(ICMP);
     197        if (datalen < sizeof(IP))
     198           return false;         // Malformed response, discard
     199
     200        iip = (struct IP*) (icmp + 1);
     201        iip->ntoh();
     202
     203        if (datalen < ((iip->headerLength << 2) + 2 * sizeof(unsigned long)))
     204           return false;         // Timestamp not there, discard
     205
     206        if (iip->destination != to.get())
     207           return false;
     208
     209        ICMP* icmpi = (ICMP*) (((char*) iip) + (iip->headerLength<<2));
     210        icmpi->ntoh();
     211
     212        if (icmpi->gateway != probeNumber) // it is not the pkt we sent
     213           return false;
     214     }
     215
     216     dispatcher.systemClock.sync();
     217     lastRtt = dispatcher.systemClock - sentAt;
     218
     219     switch (icmp->type) {
     220     case ICMPTypeEchoReply:
     221        if (ip->source != to.get()) {
     222           return false;
     223        }
     224        if (icmp->gateway != probeNumber) {
     225           return false;
     226        }
     227
     228        responder.set(ip->source);
     229        residualHops = 0;
     230        result = ICMProbeResultReachedNode;
     231
     232        TRACE(traceICMProbe, "received icmprobe for %s:%d from %s\n",
     233              to.name(), hopcount, responder.name());
     234        done.callBack((void*) this);
     235        break;
     236
     237     case ICMPTypeTimeExceeded:
     238        if (iip->timeToLive <= 1) {
     239           responder.set(ip->source);
     240           result = ICMProbeResultTimeExpired;
     241           TRACE(traceICMProbe, "received icmprobe for %s:%d from %s\n",
     242                 to.name(), hopcount, responder.name());
     243        } else {
     244           responder.set(ip->source);
     245           ERROR("unexpected ttl %d in ICMP TimeExceeded from %s\n",
     246                 iip->timeToLive, responder.name());
     247           result = ICMProbeResultDontCare;
     248        }
     249        done.callBack((void*) this);
     250        break;
     251
     252     case ICMPTypeDestinationUnreachable:
     253        residualHops = iip->timeToLive;
     254        responder.set(ip->source);
     255        switch (icmp->code) {
     256        case ICMPUnreachNet:
     257        case ICMPUnreachHost:
     258           result = ICMProbeResultUnreachable;
     259           break;
     260
     261        case ICMPUnreachProto:
     262        case ICMPUnreachPort:
     263           result = ICMProbeResultReachedNode;
     264           break;
     265
     266        case ICMPUnreachSrtFail:
     267           result = ICMProbeResultSourceRouteFailed;
     268           break;
     269
     270        case ICMPUnreachNeedFrag:
     271        default:
     272           result = ICMProbeResultDontCare;
     273           break;
     274        }
     275        TRACE(traceICMProbe, "received icmprobe for %s:%d from %s\n",
     276              to.name(), hopcount, responder.name());
     277        done.callBack((void*) this);
     278        // FallThrough
     279
     280     default:
     281        break;
     282     }
     283     return true;
     284 }
     285
     286 //  Copyright (c) 1994 by the University of Southern California.
     287 //  All rights reserved.
     288 //
     289 //  Permission to use, copy, modify, and distribute this software and
     290 //  its documentation in source and binary forms for lawful
     291 //  non-commercial purposes and without fee is hereby granted, provided
     292 //  that the above copyright notice appear in all copies and that both
     293 //  the copyright notice and this permission notice appear in supporting
     294 //  documentation, and that any documentation, advertising materials,
     295 //  and other materials related to such distribution and use acknowledge
     296 //  that the software was developed by the University of Southern
     297 //  California and/or Information Sciences Institute.
     298 //  The name of the University of Southern California may not
     299 //  be used to endorse or promote products derived from this software
     300 //  without specific prior written permission.
     301 //
     302 //  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
     303 //  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
     304 //  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
     305 //  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     306 //  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
     307 //  NON-INFRINGEMENT.
     308 //
     309 //  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
     310 //  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
     311 //  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
     312 //  THE USE OR PERFORMANCE OF THIS SOFTWARE.
     313 //
     314 //  Questions concerning this software should be directed to
     315 //  scan@isi.edu.
     316 //
     317
     318

/* [<][>][^][v][top][bottom][index][help] */