home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
msvp98b1.lzh
/
MSNICM.C
< prev
next >
Wrap
Text File
|
1993-05-14
|
9KB
|
363 lines
/* File MSNICM.C
* ICMP packet processor
*
* Copyright (C) 1991, University of Waterloo.
* Copyright (C) 1985, 1992, Trustees of Columbia University in the
* City of New York. Permission is granted to any individual or institution
* to use this software as long as it is not sold for profit. This copyright
* notice must be retained. This software may not be included in commercial
* products without written permission of Columbia University.
*
* Original version created by Erick Engelke of the University of
* Waterloo, Waterloo, Ontario, Canada.
* Adapted and modified for MS-DOS Kermit by Joe R. Doupnik,
* Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
*
* Last edit
* 1 Feb 1992
*/
#include "msntcp.h"
#include "msnlib.h"
/*
* ICMP - RFC 792
*/
static byte *unreach[] = {
"Network Unreachable",
"Host Unreachable",
"Protocol Unreachable",
"Port Unreachable",
"Fragmentation needed and DF set",
"Source Route Failed" };
static byte *exceed[] = {
"TTL exceeded in transit",
"Frag ReAsm time exceeded" };
static byte *redirect[] = {
"Redirect for Network",
"Redirect for Host",
"Redirect for TOS and Network",
"Redirect for TOS and Host" };
/* constants */
typedef struct icmp_unused {
byte type;
byte code;
word checksum;
longword unused;
in_Header ip;
byte spares[ 8 ];
};
typedef struct icmp_pointer {
byte type;
byte code;
word checksum;
byte pointer;
byte unused[ 3 ];
in_Header ip;
};
typedef struct icmp_ip {
byte type;
byte code;
word checksum;
longword ipaddr;
in_Header ip;
};
typedef struct icmp_echo {
byte type;
byte code;
word checksum;
word identifier;
word sequence;
};
typedef struct icmp_timestamp {
byte type;
byte code;
word checksum;
word identifier;
word sequence;
longword original; /* original timestamp */
longword receive; /* receive timestamp */
longword transmit; /* transmit timestamp */
};
typedef struct icmp_info {
byte type;
byte code;
word checksum;
word identifier;
word sequence;
};
typedef union {
struct icmp_unused unused;
struct icmp_pointer pointer;
struct icmp_ip ip;
struct icmp_echo echo;
struct icmp_timestamp timestamp;
struct icmp_info info;
} icmp_pkt;
typedef struct pkt {
in_Header in;
icmp_pkt icmp;
in_Header data;
};
static word icmp_id = 0;
static longword ping_hcache = 0L; /* host */
static longword ping_tcache = 0L; /* time */
static longword ping_number = 0L;
extern word debug_on;
extern word sourcequench; /* non-zero if rcv'd ICMP S. Q. */
int icmp_unreach = 0; /* tell world about unreachables */
int icmp_redirect = 0;
void
icmp_init() /* reinit all local statics */
{
ping_hcache = ping_tcache = ping_number = 0L;
icmp_id = 0;
return;
}
#ifndef KERMIT
longword
chk_ping(longword host, longword *ptr)
{
if ((ping_hcache == host) && (ptr != NULL))
{
ping_hcache = 0xffffffffL;
*ptr = ping_number;
return (ping_tcache);
}
return (0xffffffffL);
}
#endif /* KERMIT */
void
icmp_print(byte *msg)
{
if (msg == NULL) return;
outs("\n\r ICMP: ");
outs(msg);
}
struct pkt *
icmp_Format(longword destip)
{
eth_address dest;
/* we use arp rather than supplied hardware address */
/* after first ping this will still be in cache */
if (arp_resolve(destip, dest) == 0)
return (NULL); /* unable to find address */
return ((struct pkt*)eth_formatpacket(dest, 0x0008));
}
/*
* icmp_Reply - format a reply packet
* - note that src and dest are NETWORK order not host!!!!
*/
int
icmp_Reply(struct pkt *p, longword src, longword dest, int icmp_length)
{
if (p == NULL) return (0); /* failure */
/* finish the icmp checksum portion */
p->icmp.unused.checksum = 0;
p->icmp.unused.checksum = ~checksum(&p->icmp, icmp_length);
/* encapsulate into a nice IP packet */
p->in.hdrlen_ver = 0x45;
p->in.length = htons(sizeof(in_Header) + icmp_length);
p->in.tos = 0;
p->in.identification = htons(icmp_id++); /* not using IP id */
p->in.frag = 0;
p->in.ttl = 250;
p->in.proto = ICMP_PROTO;
p->in.checksum = 0;
p->in.source = src;
p->in.destination = dest;
p->in.checksum = ~checksum(&p->in, sizeof(in_Header));
return (eth_send(htons(p->in.length))); /* send the reply */
}
do_ping(byte * hostid, longword hostip)
{
struct pkt *pkt;
byte mybuf[17];
if (hostip == 0L) /* if no host IP number yet */
if ((hostip = resolve(hostid)) == 0L)
return (-1); /* failed to resolve host */
pkt = icmp_Format(hostip);
pkt->icmp.echo.type = 8; /* Echo Request */
pkt->icmp.echo.code = 0;
pkt->icmp.echo.identifier = htonl(my_ip_addr) & 0xffff;
pkt->icmp.echo.sequence = ping_number++;
pkt->icmp.timestamp.original = htonl(0x12345678);
icmp_Reply(pkt, htonl(my_ip_addr), htonl(hostip),
4 + sizeof(struct icmp_echo));
outs("\r\n Sending Ping to ");
ntoa(mybuf, hostip); outs(mybuf);
return (0);
}
int
icmp_handler(in_Header *ip)
{
register icmp_pkt *icmp, *newicmp;
struct pkt *pkt;
int len, code;
in_Header *ret;
byte nametemp[17];
extern void do_redirect(long, void *);
len = in_GetHdrlenBytes(ip);
icmp = (icmp_pkt *)((byte *)ip + len);
len = ntohs(ip->length) - len;
if (checksum(icmp, len) != 0xffff)
return (0); /* 0 = failure */
code = icmp->unused.code;
switch (icmp->unused.type)
{
case 0: /* icmp echo reply received */
/* icmp_print("received icmp echo receipt"); */
/* check if we were waiting for it */
if (icmp->echo.identifier == (ntohl(my_ip_addr) & 0xffff))
{ /* answer to our request */
outs("\r\n host is alive\r\n");
break;
}
#ifndef KERMIT
ping_hcache = ntohl(ip->source);
ping_tcache = set_timeout(1) -
*(longword *)(&icmp->echo.identifier);
if (ping_tcache > 0xffffffffL)
ping_tcache += 0x1800b0L;
ping_number =
*(longword*)(((byte*)(&icmp->echo.identifier)) + 4);
/* do more */
#endif /* Kermit */
break;
case 3 : /* destination or port unreachable message */
if (code < 6)
{
icmp_print(unreach[code]); /* display msg */
icmp_unreach = 1 + code; /* say unreachable condx */
/* handle udp or tcp socket */
ret = (in_Header *)(icmp) + sizeof(icmp_pkt);
if (ret->proto == TCP_PROTO)
tcp_cancel(ret);
if (ret->proto == UDP_PROTO)
udp_cancel(ret);
}
break;
case 4: /* source quench */
/* icmp_print("Source Quench"); */
sourcequench = 1; /* set flag, used in TCP code */
break;
case 5: /* redirect */
if (code < 4)
{ /* new gateway IP address to use */
arp_register(ntohl(icmp->ip.ipaddr),
ntohl(icmp->ip.ip.destination));
/* for this host IP address */
/* and add to list of gateways */
ntoa(nametemp, ntohl(icmp->ip.ipaddr));
icmp_print(redirect[code]);
outs(" to gateway "); outs(nametemp);
do_redirect(ntohl(icmp->ip.ipaddr), &icmp->ip.ip);
/* new gateway returned IP header */
}
break;
case 8: /* icmp echo request */
/* icmp_print("PING requested of us"); */
/* format the packet with the request's hardware address */
pkt = (struct pkt*)(eth_formatpacket(
(eth_address *)eth_hardware(ip), 8));
newicmp = &pkt->icmp;
bcopy(icmp, newicmp, len);
newicmp->echo.type = 0;
newicmp->echo.code = code;
/* use supplied ip values in case we ever multi-home */
/* note that ip values are still in network order */
icmp_Reply(pkt, ip->destination, ip->source, len);
/* icmp_print("PING reply sent"); */
break;
case 11: /* time exceeded message */
if (code < 2)
icmp_print(exceed[code]);
break;
case 12: /* parameter problem message */
icmp_print("IP Parameter problem");
break;
case 13: /* timestamp message */
/* icmp_print("Timestamp message"); */
/* send reply */
break;
case 14: /* timestamp reply */
/* icmp_print("Timestamp reply"); */
/* should store */
break;
case 15: /* info request */
/* icmp_print("Info requested"); */
/* send reply */
break;
case 16: /* info reply */
/* icmp_print("Info reply"); */
break;
} /* end of switch */
return (1); /* status of success */
}
/* Return ICMP Destination and Port Unreachable message */
void
icmp_noport(in_Header *ip)
{
register icmp_pkt *icmp, *newicmp;
struct pkt *pkt;
int len;
len = in_GetHdrlenBytes(ip);
icmp = (icmp_pkt *)((byte *)ip + len);
pkt = (struct pkt*)(eth_formatpacket(
(eth_address *)eth_hardware(ip), 0x0008));
newicmp = &pkt->icmp;
newicmp->unused.type = 3; /* destination unreachable */
newicmp->unused.code = 3; /* port unreachable */
newicmp->unused.unused = 0L; /* must be zero for unreachables */
/* send back Internet header + first 64 bits of datagram */
bcopy(ip, &newicmp->unused.ip, 8 + sizeof(in_Header));
icmp_Reply(pkt, ip->destination, ip->source,
sizeof(struct icmp_unused)); /* compose and send reply */
}