modules/up/src/Core/network/Network.cc
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- netReadHandler
- Interface
- Interface
- Network
- Network
- dump
- receive
- cksum
//
// $Id: Network.cc,v 1.1.1.1 2000/03/10 16:32:19 engin Exp $
//
// Author(s): Ramesh Govindan
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cerrno>
extern "C" {
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
};
#include "util/Types.hh"
#include "util/Trail.hh"
#include "util/Handler.hh"
#include "util/Buffer.hh"
#include "sys/File.hh"
#include "sys/Pipe.hh"
#include "sched/Job.hh"
#include "sched/Dispatcher.hh"
#include "network/Ping.hh"
#include "network/Prefix.hh"
#include "network/Mtrace.hh"
#include "network/Network.hh"
#include "network/Headers.hh"
// Constants
static const int MaxBufferSize = 1024;
static const int MaxInterfaces = 32;
// File local
static TraceCode traceNetwork("network");
// Globals
Network* network = NULL;
static void
netReadHandler(void* ptr,
/* [<][>][^][v][top][bottom][index][help] */
void* arg)
{
((Network*) ptr)->receive((RawSocket*) arg);
}
Network::Interface::Interface(char* ifname,
/* [<][>][^][v][top][bottom][index][help] */
U32 ifaddr)
: ListNode()
{
name = strdup(ifname);
address.set(ifaddr);
TRACE(traceNetwork, "adding interface %s:%s\n", name, address.name());
}
Network::Interface::~Interface()
/* [<][>][^][v][top][bottom][index][help] */
{
TRACE(traceNetwork, "deleting interface %s:%s\n", name, address.name());
free(name);
}
Network::Network()
/* [<][>][^][v][top][bottom][index][help] */
{
Handler rh(netReadHandler, this);
Handler nh(NULL, NULL);
struct sockaddr_in sin;
int socklen = sizeof(sin);
int sock;
struct ifconf ifc;
struct ifreq ifrs[MaxInterfaces];
struct ifreq *ifr;
Network::Interface* interface;
U32 addr;
Address group;
icmpSocket = new RawSocket(rh, nh, RawSocketICMP);
igmpSocket = new RawSocket(rh, nh, RawSocketIGMP);
group.set(MtraceMulticast);
igmpSocket->join(group);
recvBuffer = new Buffer(MaxBufferSize);
// First find all interfaces
if ((sock = ::socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
FATAL("couldn't open socket for getting interfaces: %s\n",
strerror(errno));
// NotReached
}
ifc.ifc_len = sizeof(struct ifreq) * MaxInterfaces;
ifc.ifc_buf = (char*) &(ifrs[0]);
if (ioctl(sock, SIOCGIFCONF, (void*) &ifc) < 0) {
FATAL("failed ioctl for getting interface list: %s\n",
strerror(errno));
// NotReached
}
for (int i = 0; i < ifc.ifc_len; i++) {
ifr = &(ifrs[i]);
addr = ntohl(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr);
if (addr == 0) {
break;
}
if (addr != INADDR_LOOPBACK) {
interface = new Network::Interface(ifr->ifr_name, addr);
interfaces.append(interface);
}
}
close(sock);
if (interfaces.isEmpty()) {
FATAL("couldn't find any usable interfaces\n");
// NotReached
}
tprobesSent = 0;
tprobesTimedOut = 0;
icmprobesSent = 0;
icmprobesTimedOut = 0;
return;
}
Network::~Network()
/* [<][>][^][v][top][bottom][index][help] */
{
delete icmpSocket;
delete igmpSocket;
delete recvBuffer;
interfaces.clear();
pendingPings.clear();
pendingTProbes.clear();
pendingICMProbes.clear();
}
void
Network::dump(FILE* fp)
/* [<][>][^][v][top][bottom][index][help] */
{
fprintf(fp, "tprobes sent %Lu timed-out %Lu\n",
tprobesSent, tprobesTimedOut);
fprintf(fp, "icmprobes sent %Lu timed-out %Lu\n",
icmprobesSent, icmprobesTimedOut);
return;
}
void
Network::receive(RawSocket* socket)
/* [<][>][^][v][top][bottom][index][help] */
{
int length;
IP* ip;
ICMP* icmp;
IGMP* igmp;
U16 sum;
length = socket->read(recvBuffer->contents, recvBuffer->capacity);
if (length < 0) {
return;
}
ip = (IP*) recvBuffer->contents;
ip->ntoh();
if (ip->totalLength != length) {
return;
}
if (length < (ip->headerLength << 2)) {
return;
}
length -= ip->headerLength << 2;
switch (ip->protocol) {
case IPPROTO_ICMP:
{
// Sanity check ICMP packet
if (length < sizeof(ICMP)) {
return;
}
icmp = (ICMP*) ((char*) ip + (ip->headerLength << 2));
sum = icmp->checksum;
icmp->checksum = 0;
if (sum && (sum != network->cksum((U16*) icmp, length))) {
return;
}
icmp->ntoh();
// Farm out packet to whoever's waiting
for (Ping* ping = pendingPings.head(); ping != NULL;
ping = pendingPings.next(ping)) {
if (ping->receive(ip)) {
break;
}
}
for (TProbe* tp = pendingTProbes.head(); tp != NULL;
tp = pendingTProbes.next(tp)) {
if (tp->receive(ip)) {
break;
}
}
for (ICMProbe* tp = pendingICMProbes.head(); tp != NULL;
tp = pendingICMProbes.next(tp)) {
if (tp->receive(ip)) {
break;
}
}
break;
}
case IPPROTO_IGMP:
{
// Sanity check IGMP packet
if (length < sizeof(IGMP)) {
return;
}
igmp = (IGMP*) ((char*) ip + (ip->headerLength << 2));
sum = igmp->checksum;
igmp->checksum = 0;
if (sum && (sum != network->cksum((U16*) igmp, length))) {
return;
}
igmp->ntoh();
length-= sizeof(IGMP);
if (igmp->type != IGMPMtraceResp)
return;
if (length < sizeof(IGMPTrace)) {
TRACE(traceNetwork, "receive: IGMPMtraceResp from is too short\n");
return;
}
IGMPTrace *trace = (IGMPTrace*) (igmp + 1);
trace->ntoh();
length -= sizeof(IGMPTrace);
Mtrace* mt = pendingMtraces.head();
while (mt != NULL) {
Mtrace* nextMt = pendingMtraces.next(mt);
if (mt->accept_trace(trace))
mt->receive(trace, length);
mt = nextMt;
}
break;
}
default:
return;
}
return;
}
U16
Network::cksum(const U16* addr,
/* [<][>][^][v][top][bottom][index][help] */
int len)
{
int nleft = len;
const u_short *w = addr;
u_short answer;
u_short odd_byte = 0;
register int sum = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if( nleft == 1 ) {
*(u_char *)(&odd_byte) = *(u_char *)w;
sum += odd_byte;
}
/*
* add back carry outs from top 16 bits to low 16 bits
*/
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
// Copyright (c) 1994 by the University of Southern California.
// All rights reserved.
//
// Permission to use, copy, modify, and distribute this software and
// its documentation in source and binary forms for lawful
// non-commercial purposes and without fee is hereby granted, provided
// that the above copyright notice appear in all copies and that both
// the copyright notice and this permission notice appear in supporting
// documentation, and that any documentation, advertising materials,
// and other materials related to such distribution and use acknowledge
// that the software was developed by the University of Southern
// California and/or Information Sciences Institute.
// The name of the University of Southern California may not
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
// ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
// PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
// NON-INFRINGEMENT.
//
// IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
// TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
// THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Questions concerning this software should be directed to
// scan@isi.edu.
//