Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

icmp.c

Go to the documentation of this file.
00001 /*!     \file network/icmp.c
00002  *      \brief ICMP (Internet Control Message Protocol) layer.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2003-11-09
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  */
00007 
00008 #include <const.h>
00009 #include <errno.h>
00010 #include <stdlib.h>
00011 
00012 #include <arch/i386.h>
00013 #include <arch/mem.h>
00014 
00015 #include <kernel/clock.h>
00016 #include <kernel/console.h>
00017 #include <kernel/kmalloc.h>
00018 
00019 #include <net/ip.h>
00020 #include <net/network.h>
00021 
00022 #include <net/icmp.h>
00023 
00024 //! \brief Process an ICMP packet received from the IP layer.
00025 //! \param packet The ICMP packet received.
00026 void to_icmp_layer(ip_t *packet)
00027 {
00028         int size = ntohs(packet->ip_len) - (packet->ip_hdr_len)*sizeof(uint32_t);
00029         icmp_t *icmp_packet = (icmp_t *)((void *)packet + (packet->ip_hdr_len)*sizeof(uint32_t));
00030 #if 0
00031         kprintf(        "\n\ricmp_type:%02X, icmp_code:%02X, icmp_chk:%04X"
00032                 "\n\rping_id:%04X, ping_seq:%u"
00033                 "\n\rping %u bytes",
00034                 icmp_packet->icmp_type,
00035                 icmp_packet->icmp_code,
00036                 icmp_packet->icmp_chk,
00037                 ((icmp_ping_t *)icmp_packet)->ping_id,
00038                 ((icmp_ping_t *)icmp_packet)->ping_seq,
00039                 size-sizeof(icmp_ping_t)
00040         );
00041         kprintf( "\n\rlocal checksum = %04X", ip_checksum(icmp_packet, size) );
00042 #endif
00043         // Calculate the header checksum                                //
00044         if ( ip_checksum(icmp_packet, size) )
00045         {
00046                 kprintf("\n\ricmp: header checksum error!!!");
00047                 return;
00048         }
00049         // Identify the message type                                    //
00050         switch( icmp_packet->icmp_type )
00051         {
00052                 case ICMP_ECHO:
00053                         // Print the echo request to stdout             //
00054                         #ifdef ICMP_DEBUG
00055                         kprintf(        "\n\recho request %u(%u) bytes "
00056                                 "%u.%u.%u.%u > %u.%u.%u.%u id=%u seq=%u ttl=%u",
00057                                 size,
00058                                 size - sizeof(icmp_ping_t),
00059 
00060                                 IP_A(ntohl(packet->ip_src)), IP_B(ntohl(packet->ip_src)),
00061                                 IP_C(ntohl(packet->ip_src)), IP_D(ntohl(packet->ip_src)),
00062 
00063                                 IP_A(ntohl(packet->ip_dst)), IP_B(ntohl(packet->ip_dst)),
00064                                 IP_C(ntohl(packet->ip_dst)), IP_D(ntohl(packet->ip_dst)),
00065 
00066                                 ((icmp_ping_t *)icmp_packet)->ping_id,
00067                                 ((icmp_ping_t *)icmp_packet)->ping_seq,
00068                                 packet->ip_ttl
00069                         );
00070                         #endif
00071                         // Check if we must send the echo reply message //
00072                         if (
00073                                 (packet->ip_dst==get_host_ip()) ||
00074                                 (packet->ip_dst==get_host_bcast()) ||
00075                                 (packet->ip_dst==INADDR_BROADCAST)
00076                         )
00077                         {
00078                                 #ifdef ICMP_DEBUG
00079                                 // Notify that we're sending the reply  //
00080                                 kprintf(        "\n\recho reply %u(%u) bytes "
00081                                         "%u.%u.%u.%u > %u.%u.%u.%u id=%u seq=%u ttl=%u",
00082                                         size,
00083                                         size - sizeof(icmp_ping_t),
00084 
00085                                         IP_A(ntohl(get_host_ip())), IP_B(ntohl(get_host_ip())),
00086                                         IP_C(ntohl(get_host_ip())), IP_D(ntohl(get_host_ip())),
00087 
00088                                         IP_A(ntohl(packet->ip_src)), IP_B(ntohl(packet->ip_src)),
00089                                         IP_C(ntohl(packet->ip_src)), IP_D(ntohl(packet->ip_src)),
00090 
00091                                         ((icmp_ping_t *)icmp_packet)->ping_id,
00092                                         ((icmp_ping_t *)icmp_packet)->ping_seq,
00093                                         IP_DEFAULT_TTL
00094                                 );
00095                                 #endif
00096                                 // Send the echo reply                  //
00097                                 send_icmp_packet(
00098                                         packet->ip_src,
00099                                         ICMP_ECHOREPLY,
00100                                         (void *)icmp_packet + sizeof(icmp_t),
00101                                         size-sizeof(icmp_t)
00102                                 );
00103                         }
00104                 break;
00105 
00106                 case ICMP_ECHOREPLY:
00107                         // Show the echo reply message                  //
00108                         kprintf("\n\recho reply %u.%u.%u.%u > %u.%u.%u.%u id=%u seq=%u ttl=%u",
00109 
00110                                 IP_A(ntohl(packet->ip_src)), IP_B(ntohl(packet->ip_src)),
00111                                 IP_C(ntohl(packet->ip_src)), IP_D(ntohl(packet->ip_src)),
00112 
00113                                 IP_A(ntohl(packet->ip_dst)), IP_B(ntohl(packet->ip_dst)),
00114                                 IP_C(ntohl(packet->ip_dst)), IP_D(ntohl(packet->ip_dst)),
00115 
00116                                 ((icmp_ping_t *)icmp_packet)->ping_id,
00117                                 ((icmp_ping_t *)icmp_packet)->ping_seq,
00118                                 packet->ip_ttl
00119                         );
00120                         // TODO:                                        //
00121                         // Insert the message into the icmp recv buffer //
00122                 break;
00123 
00124                 default:
00125                         kprintf("\n\ricmp: ??? %u.%u.%u.%u > %u.%u.%u.%u id=%u seq=%u ttl=%u",
00126 
00127                                 IP_A(ntohl(packet->ip_src)), IP_B(ntohl(packet->ip_src)),
00128                                 IP_C(ntohl(packet->ip_src)), IP_D(ntohl(packet->ip_src)),
00129 
00130                                 IP_A(ntohl(packet->ip_dst)), IP_B(ntohl(packet->ip_dst)),
00131                                 IP_C(ntohl(packet->ip_dst)), IP_D(ntohl(packet->ip_dst)),
00132 
00133                                 ((icmp_ping_t *)icmp_packet)->ping_id,
00134                                 ((icmp_ping_t *)icmp_packet)->ping_seq,
00135                                 packet->ip_ttl
00136                         );
00137                 break;
00138         }
00139 }
00140 
00141 //! \brief Send an ICMP packet.
00142 //! \param ip_to The IP destination address (in network format).
00143 //! \param message The ICMP message to send.
00144 //! \param data The data buffer to send into the ICMP packet.
00145 //! \param len The size of the data buffer.
00146 //! \return
00147 //!     \li The number of bytes sent in case of success;
00148 //!     \li a negative value if an error occurs.
00149 int send_icmp_packet(in_addr_t ip_to, uint8_t message, uint8_t *data, size_t len)
00150 {
00151         icmp_t *packet;
00152         int tot_len;
00153 
00154         packet = kmalloc(len + sizeof(icmp_t));
00155         if (packet == NULL)
00156                 // Out of memory!                                       //
00157                 return(-ENOMEM);
00158 
00159         // Create the ICMP header                                       //
00160         packet->icmp_type = message;
00161         packet->icmp_code = 0;
00162         packet->icmp_chk = 0;
00163 
00164         // Copy the data into the packet                                //
00165         memcpy(packet + 1, data, len);
00166         len += sizeof(icmp_t);
00167 
00168         // Calculate the checksum of the ICMP message                   //
00169         packet->icmp_chk = ip_checksum(packet, len);
00170 
00171         // Send the IP packet                                           //
00172         tot_len = send_ip_packet(ip_to, packet, len, IP_DEFAULT_TTL, IPPROTO_ICMP);
00173 
00174         #ifdef DEBUG
00175         kprintf("\n\r%u bytes sent from ip layer", tot_len);
00176         #endif
00177 
00178         // Free the memory of the packet                                //
00179         kfree(packet);
00180 
00181         if ( tot_len < 0 )
00182                 // Something wrong from at the IP layer                 //
00183                 return(tot_len);
00184 
00185         return(len);
00186 }
00187 
00188 //! \brief Receive an ICMP packet.
00189 //! \param buf The buffer where the received packet will be copied.
00190 //! \param len The maximum size of the buffer.
00191 //! \return The size of the packet received in bytes.
00192 /**
00193  *      \todo
00194  *      Routine not implemented!
00195  *      For now return protocol not available error.
00196  */
00197 int recv_icmp_packet(icmp_t *buf, size_t len)
00198 {
00199         return( -ENOPROTOOPT );
00200 }
00201 
00202 //! \brief Send a ping to a destination host
00203 //! \param ip_dot
00204 //!     The host IP destination expressed in numbers-and-dot notation.
00205 void ping(char *ip_dot)
00206 {
00207         struct
00208         {
00209                 uint16_t ping_id;
00210                 uint16_t ping_seq;
00211                 uint8_t data[128 - sizeof(ip_t) + sizeof(icmp_ping_t)];
00212         } packet;
00213         int tot_sent, i;
00214         in_addr_t ip, host_ip = ntohl( get_host_ip() );
00215 
00216         // Translate the IP address from numbers-and-dot notation into  //
00217         // binary network order byte number.                            //
00218         if ( !inet_aton(ip_dot, &ip) )
00219         {
00220                 kprintf("\n\rUsage: ping <IP address>\n\r");
00221                 return;
00222         }
00223 
00224         // Fill the packet                                              //
00225         for (i = 0; i < _countof(packet.data); i++)
00226                 packet.data[i] = 'a' + i % 26;
00227 
00228         // Fill the header of the ping                                  //
00229         packet.ping_id = 3636;
00230         packet.ping_seq = 0;
00231 
00232         kprintf("\n\rPING: %u(%u) bytes %u.%u.%u.%u from %u.%u.%u.%u",
00233 
00234                 sizeof(packet)-sizeof(icmp_ping_t),
00235                 sizeof(packet),
00236 
00237                 IP_A(ntohl(ip)), IP_B(ntohl(ip)), IP_C(ntohl(ip)), IP_D(ntohl(ip)),
00238                 IP_A(host_ip), IP_B(host_ip), IP_C(host_ip), IP_D(host_ip)
00239         );
00240 
00241         tot_sent = send_icmp_packet(
00242                         ip,
00243                         ICMP_ECHO,
00244                         (uint8_t *)&packet,
00245                         sizeof(packet)
00246         );
00247         if ( tot_sent < 0 )
00248         {
00249                 switch( tot_sent )
00250                 {
00251                         case (-ENETUNREACH):
00252                                 kprintf("\n\rHost unreachable!");
00253                         break;
00254 
00255                         kprintf("\n\rCannot send data to ip layer!");
00256                         break;
00257                 }
00258                 kprintf("\n\r");
00259                 return;
00260         }
00261         // Wait 500ms for the answer                                    //
00262         delay(500);
00263         // Well done!                                                   //
00264         kprintf("\n\r");
00265 }

Generated on Fri Feb 20 15:32:15 2004 for Minirighi by doxygen1.2.18