home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / PPPBCKP / SRC / SRC15B99.ZIP / WATTSRC.ZIP / PCICMP.C < prev    next >
Text File  |  1997-03-08  |  8KB  |  249 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 (ret->proto == TCP_PROTO)
  177.                     _tcp_cancel( ret, 2, NULL, 0 );
  178.                 break;
  179.  
  180.         case 5  : /* redirect */
  181.                 if (code < 4) {
  182.                     if (ret->proto == TCP_PROTO)
  183.                         /* do it to some socket guy */
  184.                         _tcp_cancel( ret, 5, NULL, icmp->ip.ipaddr );
  185.  
  186.                 }
  187.                 break;
  188.  
  189.         case 8  : /* icmp echo request */
  190.                 /* icmp_print( icmp, "PING requested of us"); */
  191.  
  192.                 // don't reply if the request was made by ourselves
  193.                 // such as a problem with Etherslip pktdrvr
  194.                 if  ( (longword) (ip->destination - intel( my_ip_addr)) > multihomes )
  195.                     return( 1 );
  196.  
  197.                 // do arp and create packet
  198.                 /* format the packet with the request's hardware address */
  199.                 pkt = (struct _pkt*)(_eth_formatpacket( _eth_hardware((byte*)ip), 8));
  200.  
  201.                 newicmp = &pkt->icmp;
  202.  
  203.                 movmem( icmp, newicmp, len );
  204.                 newicmp->echo.type = 0;
  205.                 newicmp->echo.code = code;
  206.  
  207.                 /* use supplied ip values in case we ever multi-home */
  208.                 /* note that ip values are still in network order */
  209.                 icmp_Reply( pkt,ip->destination, ip->source, len );
  210.  
  211.                 /* icmp_print( newicmp, "PING reply sent"); */
  212.  
  213.                 break;
  214.  
  215.         case 11 : /* time exceeded message */
  216.                 if (code < 2 ) {
  217.                     icmp_print( icmp, exceed[ code ]);
  218.                     if ((ret->proto == TCP_PROTO) && (code != 1))
  219.                         _tcp_cancel( ret, 1, NULL, 0 );
  220.                 }
  221.                 break;
  222.  
  223.         case 12 : /* parameter problem message */
  224.                 icmp_print( icmp, "IP Parameter problem");
  225.                 break;
  226.  
  227.         case 13 : /* timestamp message */
  228.                 icmp_print( icmp, "Timestamp message");
  229.                 /* send reply */
  230.                 break;
  231.  
  232.         case 14 : /* timestamp reply */
  233.                 icmp_print( icmp, "Timestamp reply");
  234.                 /* should store */
  235.                 break;
  236.  
  237.         case 15 : /* info request */
  238.                 icmp_print( icmp,"Info requested");
  239.                 /* send reply */
  240.                 break;
  241.  
  242.         case 16 : /* info reply */
  243.                 icmp_print( icmp,"Info reply");
  244.                 break;
  245.  
  246.     }
  247.     return( 1 );
  248. }
  249.