home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / CEREBRUM / WAT9609.ZIP / SRC / PCICMP.C < prev    next >
Text File  |  1994-11-28  |  7KB  |  251 lines

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