home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / wattcp.zip / PCICMP.C < prev    next >
C/C++ Source or Header  |  1992-04-13  |  7KB  |  286 lines

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