home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / MSDOS / WATTCP / WATTCP.ZIP / SRC / PCICMP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-13  |  6.9 KB  |  291 lines

  1. #include <copyright.h>
  2. #include <wattcp.h>
  3. #include <mem.h>
  4.  
  5. /*
  6.  * ICMP - RFC 792
  7.  */
  8.  
  9. static char *unreach[] = {
  10.     "Network Unreachable",
  11.     "Host Unreachable",
  12.     "Protocol Unreachable",
  13.     "Port Unreachable",
  14.     "Fragmentation needed and DF set",
  15.     "Source Route Failed" };
  16. static char *exceed[] = {
  17.     "TTL exceeded in transit",
  18.     "Frag ReAsm time exceeded" };
  19.  
  20. static char *redirect[] = {
  21.     "Redirect for Network",
  22.     "Redirect for Host",
  23.     "Redirect for TOS and Network",
  24.     "Redirect for TOS and Host" };
  25.  
  26. /* constants */
  27.  
  28.  
  29. typedef struct icmp_unused {
  30.     byte     type;
  31.     byte    code;
  32.     word    checksum;
  33.     longword    unused;
  34.     in_Header    ip;
  35.     byte    spares[ 8 ];
  36. };
  37.  
  38. typedef struct icmp_pointer {
  39.     byte    type;
  40.     byte    code;
  41.     word    checksum;
  42.     byte    pointer;
  43.     byte    unused[ 3 ];
  44.     in_Header    ip;
  45. };
  46. typedef struct icmp_ip {
  47.     byte    type;
  48.     byte    code;
  49.     word    checksum;
  50.     longword    ipaddr;
  51.     in_Header    ip;
  52. };
  53. typedef struct icmp_echo {
  54.     byte    type;
  55.     byte    code;
  56.     word    checksum;
  57.     word    identifier;
  58.     word    sequence;
  59. };
  60.  
  61. typedef struct icmp_timestamp {
  62.     byte    type;
  63.     byte    code;
  64.     word    checksum;
  65.     word    identifier;
  66.     word    sequence;
  67.     longword    original;    /* original timestamp */
  68.     longword    receive;    /* receive timestamp */
  69.     longword    transmit;    /* transmit timestamp */
  70. };
  71.  
  72. typedef struct icmp_info {
  73.     byte    type;
  74.     byte    code;
  75.     word    checksum;
  76.     word    identifier;
  77.     word    sequence;
  78. };
  79.  
  80. typedef union  {
  81.     struct icmp_unused    unused;
  82.     struct icmp_pointer    pointer;
  83.     struct icmp_ip        ip;
  84.     struct icmp_echo    echo;
  85.     struct icmp_timestamp    timestamp;
  86.     struct icmp_info    info;
  87. } icmp_pkt;
  88.  
  89. typedef struct _pkt {
  90.     in_Header     in;
  91.     icmp_pkt     icmp;
  92.     in_Header    data;
  93. };
  94.  
  95. static word icmp_id = 0;
  96.  
  97. static longword ping_hcache = 0;    /* host */
  98. static longword ping_tcache = 0;    /* time */
  99. static longword ping_number = 0;
  100. extern word multihomes;
  101.  
  102. longword _chk_ping( longword host, longword *ptr )
  103. {
  104.     if ( ping_hcache == host ) {
  105.     ping_hcache = 0xffffffffL;
  106.     *ptr = ping_number;
  107.     return( ping_tcache );
  108.     }
  109.     return( 0xffffffffL );
  110. }
  111.  
  112.  
  113. void icmp_print( icmp_pkt *icmp, char *msg)
  114. {
  115.     outs("\n\rICMP: ");
  116.     outs( msg );
  117.     outs("\n\r");
  118. }
  119.  
  120. /*
  121.  *
  122.  */
  123. struct _pkt *icmp_Format( longword destip )
  124. {
  125.     eth_address dest;
  126.     char *temp;
  127.  
  128.     /* we use arp rather than supplied hardware address */
  129.     /* after first ping this will still be in cache */
  130.  
  131.     if ( !_arp_resolve( destip , &dest, 0 ))
  132.     return( NULL );                /* unable to find address */
  133.     return( (struct _pkt*)_eth_formatpacket( &dest, 8 ));
  134. }
  135. /*
  136.  * icmp_Reply - format a reply packet
  137.  *            - note that src and dest are NETWORK order not host!!!!
  138.  */
  139. void *icmp_Reply( struct _pkt *p, longword src, longword dest, int icmp_length )
  140. {
  141.     in_Header *ip;
  142.     icmp_pkt *icmp;
  143.  
  144.     ip = &p->in;
  145.     memset( ip, 0, sizeof( in_Header ));
  146.     icmp = &p->icmp;
  147.  
  148.     /* finish the icmp checksum portion */
  149.     icmp->unused.checksum = 0;
  150.     icmp->unused.checksum = ~checksum( icmp, icmp_length );
  151.  
  152.     /* encapsulate into a nice ip packet */
  153.     ip->ver = 4;
  154.     ip->hdrlen = 5;
  155.     ip->length = intel16( sizeof( in_Header ) + icmp_length);
  156.     ip->tos = 0;
  157.     ip->identification = intel16( icmp_id ++);    /* not using ip id */
  158. //    ip->frag = 0;
  159.     ip->ttl = 250;
  160.     ip->proto = ICMP_PROTO;
  161.     ip->checksum = 0;
  162.     ip->source = src;
  163.     ip->destination = dest;
  164.     ip->checksum = ~ checksum( ip, sizeof( in_Header ));
  165.  
  166.     _eth_send( intel16( ip->length ));
  167.  
  168. }
  169.  
  170. icmp_handler( in_Header *ip )
  171. {
  172.     icmp_pkt *icmp, *newicmp;
  173.     struct _pkt *pkt;
  174.     int len, code;
  175.     in_Header *ret;
  176.  
  177.     len = in_GetHdrlenBytes( ip );
  178.     icmp = (icmp_pkt*)((byte *)ip + len);
  179.     len = intel16( ip->length ) - len;
  180.     if ( checksum( icmp, len ) != 0xffff ) {
  181.     outs("ICMP received with bad checksum\n\r");
  182.     return( 1 );
  183.     }
  184.  
  185.     code = icmp->unused.code;
  186.     ret = & (icmp->ip.ip);
  187.  
  188.     switch ( icmp->unused.type) {
  189.     case 0 : /* icmp echo reply received */
  190.         /* icmp_print( icmp, "received icmp echo receipt"); */
  191.  
  192.         /* check if we were waiting for it */
  193.         ping_hcache = intel( ip->source );
  194.         ping_tcache = set_timeout( 1 ) - *(longword *)(&icmp->echo.identifier );
  195.         if (ping_tcache > 0xffffffffL)
  196.             ping_tcache += 0x1800b0L;
  197.         ping_number = *(longword*)( ((byte*)(&icmp->echo.identifier)) + 4 );
  198.         /* do more */
  199.         break;
  200.  
  201.     case 3 : /* destination unreachable message */
  202.         if (code < 6) {
  203.             icmp_print( icmp, unreach[ code ]);
  204.  
  205.             /* handle udp or tcp socket */
  206.             if (ret->proto == TCP_PROTO)
  207.                         _tcp_cancel( ret, 1, unreach[ code ], 0 );
  208.             if (ret->proto == UDP_PROTO)
  209.             _udp_cancel( ret );
  210.         }
  211.         break;
  212.  
  213.     case 4  : /* source quench */
  214.                 if (debug_on > 0 ) icmp_print( icmp, "Source Quench");
  215.                 if (ret->proto == TCP_PROTO)
  216.                     _tcp_cancel( ret, 2, NULL, 0 );
  217.         break;
  218.  
  219.     case 5  : /* redirect */
  220.         if (code < 4) {
  221.                     if (ret->proto == TCP_PROTO)
  222.                         /* do it to some socket guy */
  223.                         _tcp_cancel( ret, 5, NULL, icmp->ip.ipaddr );
  224.  
  225.                     if (debug_on > 0 ) icmp_print( icmp, redirect[ code ]);
  226.         }
  227.         break;
  228.  
  229.     case 8  : /* icmp echo request */
  230.         /* icmp_print( icmp, "PING requested of us"); */
  231.  
  232.                 // don't reply if the request was made by ourselves
  233.                 // such as a problem with Etherslip pktdrvr
  234.                 if  ( (longword) (ip->destination - intel( my_ip_addr)) > multihomes )
  235.                     return( 1 );
  236.  
  237.                 // do arp and create packet
  238.                 /* format the packet with the request's hardware address */
  239.                 pkt = (struct _pkt*)(_eth_formatpacket( _eth_hardware(ip), 8));
  240.  
  241.         newicmp = &pkt->icmp;
  242.  
  243.         movmem( icmp, newicmp, len );
  244.         newicmp->echo.type = 0;
  245.         newicmp->echo.code = code;
  246.  
  247.         /* use supplied ip values in case we ever multi-home */
  248.         /* note that ip values are still in network order */
  249.         icmp_Reply( pkt,ip->destination, ip->source, len );
  250.  
  251.         /* icmp_print( newicmp, "PING reply sent"); */
  252.  
  253.         break;
  254.  
  255.     case 11 : /* time exceeded message */
  256.         if (code < 2 ) {
  257.             icmp_print( icmp, exceed[ code ]);
  258.                     if ((ret->proto == TCP_PROTO) && (code != 1))
  259.                         _tcp_cancel( ret, 1, NULL, 0 );
  260.                 }
  261.         break;
  262.  
  263.     case 12 : /* parameter problem message */
  264.         icmp_print( icmp, "IP Parameter problem");
  265.         break;
  266.  
  267.     case 13 : /* timestamp message */
  268.         icmp_print( icmp, "Timestamp message");
  269.         /* send reply */
  270.         break;
  271.  
  272.     case 14 : /* timestamp reply */
  273.         icmp_print( icmp, "Timestamp reply");
  274.         /* should store */
  275.         break;
  276.  
  277.     case 15 : /* info request */
  278.         icmp_print( icmp,"Info requested");
  279.         /* send reply */
  280.         break;
  281.  
  282.     case 16 : /* info reply */
  283.         icmp_print( icmp,"Info reply");
  284.         break;
  285.  
  286.     }
  287.     return( 1 );
  288. }
  289.  
  290.  
  291.