modules/up/src/Core/network/Network.cc

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

FUNCTIONS

This source file includes following functions.
  1. netReadHandler
  2. Interface
  3. Interface
  4. Network
  5. Network
  6. dump
  7. receive
  8. cksum

   1 //
   2 // $Id: Network.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 #include <cerrno>
  11 
  12 extern "C" {
  13 #include <sys/types.h>
  14 #include <sys/socket.h>
  15 #include <net/if.h>
  16 #include <netinet/in.h>
  17 #include <arpa/inet.h>
  18 #include <sys/ioctl.h>
  19 };
  20 
  21 #include "util/Types.hh"
  22 #include "util/Trail.hh"
  23 #include "util/Handler.hh"
  24 #include "util/Buffer.hh"
  25 #include "sys/File.hh"
  26 #include "sys/Pipe.hh"
  27 #include "sched/Job.hh"
  28 #include "sched/Dispatcher.hh"
  29 
  30 #include "network/Ping.hh"
  31 #include "network/Prefix.hh"
  32 #include "network/Mtrace.hh"
  33 #include "network/Network.hh"
  34 #include "network/Headers.hh"
  35 
  36 // Constants
  37 static const int        MaxBufferSize = 1024;
  38 static const int        MaxInterfaces = 32;
  39 
  40 // File local
  41 static TraceCode        traceNetwork("network");
  42 
  43 // Globals
  44 Network*        network = NULL;
  45 
  46 static void
  47 netReadHandler(void* ptr,
     /* [<][>][^][v][top][bottom][index][help] */
  48                 void* arg)
  49 {
  50     ((Network*) ptr)->receive((RawSocket*) arg);
  51 }
  52 
  53 Network::Interface::Interface(char* ifname,
     /* [<][>][^][v][top][bottom][index][help] */
  54                               U32 ifaddr)
  55         : ListNode()
  56 {
  57     name = strdup(ifname);
  58     address.set(ifaddr);
  59     TRACE(traceNetwork, "adding interface %s:%s\n", name, address.name());
  60 }
  61 
  62 Network::Interface::~Interface()
     /* [<][>][^][v][top][bottom][index][help] */
  63 {
  64     TRACE(traceNetwork, "deleting interface %s:%s\n", name, address.name());
  65     free(name);
  66 }
  67 
  68 Network::Network()
     /* [<][>][^][v][top][bottom][index][help] */
  69 {
  70     Handler             rh(netReadHandler, this);
  71     Handler             nh(NULL, NULL);
  72     struct sockaddr_in  sin;
  73     int                 socklen = sizeof(sin);
  74     int                 sock;
  75     struct ifconf       ifc;
  76     struct ifreq        ifrs[MaxInterfaces];
  77     struct ifreq        *ifr;
  78     Network::Interface* interface;
  79     U32                 addr;
  80     Address             group;
  81 
  82     icmpSocket = new RawSocket(rh, nh, RawSocketICMP);
  83     igmpSocket = new RawSocket(rh, nh, RawSocketIGMP);
  84 
  85     group.set(MtraceMulticast);
  86     igmpSocket->join(group);
  87     recvBuffer = new Buffer(MaxBufferSize);
  88 
  89     // First find all interfaces
  90     if ((sock = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  91         FATAL("couldn't open socket for getting interfaces: %s\n",
  92               strerror(errno));
  93         // NotReached
  94     }
  95 
  96     ifc.ifc_len = sizeof(struct ifreq) * MaxInterfaces;
  97     ifc.ifc_buf = (char*) &(ifrs[0]);
  98 
  99     if (ioctl(sock, SIOCGIFCONF, (void*) &ifc) < 0) {
 100         FATAL("failed ioctl for getting interface list: %s\n",
 101               strerror(errno));
 102         // NotReached
 103     }
 104 
 105     for (int i = 0; i < ifc.ifc_len; i++) {
 106         ifr = &(ifrs[i]);
 107         addr = ntohl(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr);
 108         if (addr == 0) {
 109             break;
 110         }
 111         if (addr != INADDR_LOOPBACK) {
 112             interface = new Network::Interface(ifr->ifr_name, addr);
 113             interfaces.append(interface);
 114         }
 115     }
 116     close(sock);
 117 
 118     if (interfaces.isEmpty()) {
 119         FATAL("couldn't find any usable interfaces\n");
 120         // NotReached
 121     }
 122 
 123     tprobesSent = 0;
 124     tprobesTimedOut = 0;
 125     icmprobesSent = 0;
 126     icmprobesTimedOut = 0;
 127     
 128     return;
 129 }
 130 
 131 Network::~Network()
     /* [<][>][^][v][top][bottom][index][help] */
 132 {
 133     delete icmpSocket;
 134     delete igmpSocket;
 135     delete recvBuffer;
 136     interfaces.clear();
 137     pendingPings.clear();
 138     pendingTProbes.clear();
 139     pendingICMProbes.clear();
 140 }
 141 
 142 void
 143 Network::dump(FILE* fp)
     /* [<][>][^][v][top][bottom][index][help] */
 144 {
 145     fprintf(fp, "tprobes sent %Lu timed-out %Lu\n", 
 146             tprobesSent, tprobesTimedOut);
 147     fprintf(fp, "icmprobes sent %Lu timed-out %Lu\n", 
 148             icmprobesSent, icmprobesTimedOut);
 149     return;
 150 }
 151 
 152 void
 153 Network::receive(RawSocket* socket)
     /* [<][>][^][v][top][bottom][index][help] */
 154 {
 155     int         length;
 156     IP*         ip;
 157     ICMP*       icmp;
 158     IGMP*       igmp;
 159     U16         sum;
 160 
 161     length = socket->read(recvBuffer->contents, recvBuffer->capacity);
 162     if (length < 0) {
 163         return;
 164     }
 165     ip = (IP*) recvBuffer->contents;
 166     ip->ntoh();
 167 
 168     if (ip->totalLength != length) {
 169         return;
 170     }
 171 
 172     if (length < (ip->headerLength << 2)) {
 173         return;
 174     }
 175     length -= ip->headerLength << 2;
 176 
 177     switch (ip->protocol) {
 178         case IPPROTO_ICMP: 
 179         {
 180             // Sanity check ICMP packet
 181             if (length < sizeof(ICMP)) {
 182                 return;
 183             }
 184     
 185             icmp = (ICMP*) ((char*) ip + (ip->headerLength << 2));
 186             sum = icmp->checksum;
 187             icmp->checksum = 0;
 188             if (sum && (sum != network->cksum((U16*) icmp, length))) {
 189                 return;
 190             }
 191             icmp->ntoh();
 192 
 193             // Farm out packet to whoever's waiting
 194             for (Ping* ping = pendingPings.head(); ping != NULL;
 195                  ping = pendingPings.next(ping)) {
 196                 if (ping->receive(ip)) {
 197                     break;
 198                 }
 199             }
 200             for (TProbe* tp = pendingTProbes.head(); tp != NULL;
 201                  tp = pendingTProbes.next(tp)) {
 202                 if (tp->receive(ip)) {
 203                     break;
 204                 }
 205             }
 206             for (ICMProbe* tp = pendingICMProbes.head(); tp != NULL;
 207                  tp = pendingICMProbes.next(tp)) {
 208                 if (tp->receive(ip)) {
 209                     break;
 210                 }
 211             }
 212             break;
 213         }
 214             
 215         case IPPROTO_IGMP:
 216         {
 217             // Sanity check IGMP packet
 218             if (length < sizeof(IGMP)) {
 219                 return;
 220             }
 221 
 222             igmp = (IGMP*) ((char*) ip + (ip->headerLength << 2));
 223             sum = igmp->checksum;
 224             igmp->checksum = 0;
 225             if (sum && (sum != network->cksum((U16*) igmp, length))) {
 226                 return;
 227             }
 228             igmp->ntoh();
 229             length-= sizeof(IGMP);
 230             if (igmp->type != IGMPMtraceResp)
 231                     return;
 232             if (length < sizeof(IGMPTrace)) {
 233                     TRACE(traceNetwork, "receive: IGMPMtraceResp from is too short\n");
 234                     return;
 235             }
 236             IGMPTrace *trace = (IGMPTrace*) (igmp + 1);
 237             trace->ntoh();
 238             length -= sizeof(IGMPTrace);
 239 
 240             Mtrace* mt = pendingMtraces.head();
 241             while (mt != NULL) {
 242                 Mtrace* nextMt = pendingMtraces.next(mt);
 243                 if (mt->accept_trace(trace))
 244                     mt->receive(trace, length);
 245                 mt = nextMt;
 246             }
 247             break;
 248         }
 249             
 250         default:
 251             return;
 252     }
 253     return;
 254 }
 255 
 256 U16
 257 Network::cksum(const U16* addr,
     /* [<][>][^][v][top][bottom][index][help] */
 258                int len)
 259 {
 260     int nleft = len;
 261     const u_short *w = addr;
 262     u_short answer;
 263     u_short odd_byte = 0;
 264     register int sum = 0;
 265 
 266     /*
 267      *  Our algorithm is simple, using a 32 bit accumulator (sum),
 268      *  we add sequential 16 bit words to it, and at the end, fold
 269      *  back all the carry bits from the top 16 bits into the lower
 270      *  16 bits.
 271      */
 272     while( nleft > 1 )  {
 273         sum += *w++;
 274         nleft -= 2;
 275     }
 276 
 277     /* mop up an odd byte, if necessary */
 278     if( nleft == 1 ) {
 279         *(u_char *)(&odd_byte) = *(u_char *)w;
 280         sum += odd_byte;
 281     }
 282 
 283     /*
 284      * add back carry outs from top 16 bits to low 16 bits
 285      */
 286     sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
 287     sum += (sum >> 16);                     /* add carry */
 288     answer = ~sum;                          /* truncate to 16 bits */
 289     return (answer);
 290 }
 291 
 292 
 293 //  Copyright (c) 1994 by the University of Southern California.
 294 //  All rights reserved.
 295 //
 296 //  Permission to use, copy, modify, and distribute this software and
 297 //  its documentation in source and binary forms for lawful
 298 //  non-commercial purposes and without fee is hereby granted, provided
 299 //  that the above copyright notice appear in all copies and that both
 300 //  the copyright notice and this permission notice appear in supporting
 301 //  documentation, and that any documentation, advertising materials,
 302 //  and other materials related to such distribution and use acknowledge
 303 //  that the software was developed by the University of Southern
 304 //  California and/or Information Sciences Institute.
 305 //  The name of the University of Southern California may not
 306 //  be used to endorse or promote products derived from this software
 307 //  without specific prior written permission.
 308 //
 309 //  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
 310 //  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
 311 //  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
 312 //  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 313 //  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
 314 //  NON-INFRINGEMENT.
 315 //
 316 //  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
 317 //  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
 318 //  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
 319 //  THE USE OR PERFORMANCE OF THIS SOFTWARE.
 320 //
 321 //  Questions concerning this software should be directed to 
 322 //  scan@isi.edu.
 323 //
 324 
 325 

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