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

ip.c

Go to the documentation of this file.
00001 /*!     \file network/ip.c
00002  *      \brief IP (Internet 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 <ctype.h>
00010 #include <errno.h>
00011 
00012 #include <arch/mem.h>
00013 
00014 #include <kernel/clock.h>
00015 #include <kernel/console.h>
00016 #include <kernel/kmalloc.h>
00017 
00018 #include <net/arp.h>
00019 #include <net/eth.h>
00020 #include <net/icmp.h>
00021 #include <net/network.h>
00022 #include <net/tcp.h>
00023 #include <net/udp.h>
00024 
00025 #include <net/ip.h>
00026 
00027 //! \brief Calculate the IP header checksum.
00028 //! \param buf The IP header content.
00029 //! \param hdr_len The IP header length.
00030 //! \return The result of the checksum.
00031 uint16_t ip_checksum(const void *buf, size_t hdr_len)
00032 {
00033         unsigned long sum = 0;
00034         const uint16_t *ip1;
00035 
00036         ip1 = buf;
00037         while (hdr_len > 1)
00038         {
00039                 sum += *ip1++;
00040                 if (sum & 0x80000000)
00041                         sum = (sum & 0xFFFF) + (sum >> 16);
00042                 hdr_len -= 2;
00043         }
00044 
00045         while (sum >> 16)
00046                 sum = (sum & 0xFFFF) + (sum >> 16);
00047 
00048         return(~sum);
00049 }
00050 
00051 //! \brief Dump an IP packet to the standard output.
00052 //! \param packet The IP packet.
00053 void dump_ip_packet(ip_t *packet)
00054 {
00055         int i;
00056         uint8_t *data = ((void *)packet + (packet->ip_hdr_len * sizeof(uint32_t)));
00057 
00058         // Dump the IP header                                           //
00059         kprintf(        "\n\r(ip header)"
00060                 "\n\rhdr_len:%u dwords, ip_version:%u, ToS:%#04X, tot_len:%u"
00061                 "\n\rid:%#010x, off:%#010x, TTL:%u, proto:%#04X, ip_chk:%#06X"
00062                 "\n\rip_src:%u.%u.%u.%u, ip_dst:%u.%u.%u.%u",
00063                 packet->ip_hdr_len, packet->ip_version, packet->ip_tos,
00064                 ntohs(packet->ip_len), ntohs(packet->ip_id), ntohs(packet->ip_off),
00065                 packet->ip_ttl, packet->ip_proto,
00066                 ntohs(packet->ip_chk),
00067 
00068                 IP_A(ntohl(packet->ip_src)), IP_B(ntohl(packet->ip_src)),
00069                 IP_C(ntohl(packet->ip_src)), IP_D(ntohl(packet->ip_src)),
00070 
00071                 IP_A(ntohl(packet->ip_dst)), IP_B(ntohl(packet->ip_dst)),
00072                 IP_C(ntohl(packet->ip_dst)), IP_D(ntohl(packet->ip_dst))
00073         );
00074         // Dump the IP data section                                     //
00075         kprintf("\n\r(ip data)\n\r");
00076         for (i=0; i<(ntohs(packet->ip_len) - packet->ip_hdr_len * sizeof(uint32_t)); i++)
00077                 if ( isprint(data[i]) )
00078                         kputchar(data[i]);
00079                 else
00080                         kputchar('.');
00081 }
00082 
00083 //! This is the IP address of this host (expressed in network format).
00084 static in_addr_t host_ip;
00085 //! This is the IP netmask of this host (expressed in network format).
00086 static in_addr_t host_netmask;
00087 
00088 //! \brief Set the IP and netmask for this host.
00089 //! \param ip The IP address in network format.
00090 //! \param netmask The netmask in network format.
00091 void set_host_ip_net(in_addr_t ip, in_addr_t netmask)
00092 {
00093         host_ip = ip;
00094         host_netmask = netmask;
00095 }
00096 
00097 //! \brief Get the IP address of this host.
00098 //! \return
00099 //!     The IP address expressed in network format.
00100 in_addr_t get_host_ip()
00101 {
00102         return( host_ip );
00103 }
00104 
00105 //! \brief Get the netmask of this host.
00106 //! \return
00107 //!     The netmask expressed in network format.
00108 in_addr_t get_host_netmask()
00109 {
00110         return( host_netmask );
00111 }
00112 
00113 //! \brief Get the broadcast address of the local network.
00114 //! \return
00115 //!     The broadcast address of this local network expressed
00116 //!     in network format.
00117 in_addr_t get_host_bcast()
00118 {
00119         return( (~host_netmask) | (host_ip & host_netmask) );
00120 }
00121 
00122 //! \brief
00123 //!     Converts an internet IP addres from number-and-dot string
00124 //!     notation into binary data network byte order.
00125 //! \param cp
00126 //!     The string of the number-and-dot notation IP address.
00127 //! \param inp
00128 //!     The destination where the binary network byte order address
00129 //!     will be put.
00130 //! \return Nonzero if the address is valid, zero if not.
00131 int inet_aton(const char *cp, in_addr_t *inp)
00132 {
00133         static const in_addr_t max[4] = { 0xFFFFFFFF, 0xFFFFFF, 0xFFFF, 0xFF };
00134         in_addr_t val;
00135         char c;
00136         union iaddr {
00137           uint8_t bytes[4];
00138           uint32_t word;
00139         } res;
00140         uint8_t *pp = res.bytes;
00141         int digit,base;
00142 
00143         res.word = 0;
00144 
00145         c = *cp;
00146         for (;;) {
00147                 // Collect number up to '.'                             //
00148                 // Values are specified as for C:                       //
00149                 // 0x=hex, 0=octal, isdigit=decimal.                    //
00150                 if (!isdigit(c)) goto ret_0;
00151                 val = 0; base = 10; digit = 0;
00152                 for (;;) {
00153                         if (isdigit(c)) {
00154                                 val = (val * base) + (c - '0');
00155                                 c = *++cp;
00156                                 digit = 1;
00157                         } else {
00158                                 break;
00159                         }
00160                 }
00161                 if (c == '.') {
00162                         // Internet format:                             //
00163                         //      a.b.c.d                                 //
00164                         //      a.b.c   (with c treated as 16 bits)     //
00165                         //      a.b     (with b treated as 24 bits)     //
00166                         if (pp > res.bytes + 2 || val > 0xff) {
00167                                 goto ret_0;
00168                         }
00169                         *pp++ = val;
00170                         c = *++cp;
00171                 } else
00172                         break;
00173         }
00174 
00175         // Check for trailing characters                                //
00176         if (c != '\0' && (!isascii(c) || !isspace(c))) {
00177                 goto ret_0;
00178         }
00179 
00180         // Did we get a valid digit?                                    //
00181         if (!digit) {
00182                 goto ret_0;
00183         }
00184 
00185         // Check whether the last part is in its limits depending on    //
00186         // the number of parts in total.                                //
00187         if (val > max[pp - res.bytes]) {
00188                 goto ret_0;
00189         }
00190 
00191         if (inp != NULL) {
00192                 *inp = res.word | htonl (val);
00193         }
00194 
00195         return (1);
00196 ret_0:
00197         return (0);
00198 }
00199 
00200 //! \brief Process an IP packet received from the ethernet layer.
00201 //! \param packet The IP packet.
00202 void to_ip_layer(ip_t *packet)
00203 {
00204         // Calculate the header checksum                                //
00205         if ( ip_checksum(packet, packet->ip_hdr_len * sizeof(dword)) )
00206         {
00207                 kprintf("\n\rip header checksum error!!!");
00208                 return;
00209         }
00210 
00211         //--------------------------------------------------------------//
00212         // Check if we can receive the packet or not                    //
00213         if (
00214                 (packet->ip_dst!=get_host_ip()) &&
00215                 (packet->ip_dst!=get_host_bcast()) &&
00216                 (packet->ip_dst!=INADDR_BROADCAST)
00217         )
00218                 return;
00219         //--------------------------------------------------------------//
00220 
00221         // Identify the right protocol                                  //
00222         switch( packet->ip_proto )
00223         {
00224                 case IPPROTO_ICMP:
00225                         // ICMP (Internet Control Message Protocol)     //
00226                         to_icmp_layer(packet);
00227                 break;
00228 
00229                 case IPPROTO_IGMP:
00230                         // Internet Group Message Protocol)             //
00231                         kprintf("\n\rIGMP protocol not yet implemented!");
00232                         dump_ip_packet(packet);
00233                 break;
00234 
00235                 case IPPROTO_TCP:
00236                         // TCP (Transmition Control Protocol)           //
00237                         to_tcp_layer(
00238                                 ((void *)packet + (packet->ip_hdr_len * sizeof(uint32_t))),
00239                                 (ntohs(packet->ip_len) - (packet->ip_hdr_len * sizeof(uint32_t))),
00240                                 packet->ip_src,
00241                                 packet->ip_dst
00242                         );
00243                         // dump_ip_packet(packet);
00244                 break;
00245 
00246                 case IPPROTO_UDP:
00247                         // UDP (User Datagram Protocol)                 //
00248                         to_udp_layer(
00249                                 ((void *)packet + (packet->ip_hdr_len * sizeof(uint32_t))),
00250                                 packet->ip_src,
00251                                 packet->ip_dst
00252                         );
00253                 break;
00254 
00255                 default:
00256                         kprintf("\n\rUnknown IP protocol!");
00257                         dump_ip_packet(packet);
00258                 break;
00259         }
00260 }
00261 
00262 //! \brief Send an IP packet to the ethernet layer.
00263 //! \param ip_to The IP destination address in network format.
00264 //! \param data The buffer of data to be sent.
00265 //! \param len The size of the buffer to be sent.
00266 //! \param ttl TTL (Time To Live).
00267 //! \param proto The upper-layer protocol type.
00268 //! \return
00269 //!     \li The number of bytes sent in case of success;
00270 //!     \li -#EMSGSIZE the packet is too big to be sent;
00271 //!     \li -#ENOMEM cannot allocate the packet structure;
00272 //!     \li -#ENETUNREACH destination address not found;
00273 int send_ip_packet(uint32_t ip_to, const void *data, size_t len, uint8_t ttl, uint8_t proto)
00274 {
00275         uint8_t eth_to[ETH_ADDR_LEN];
00276         size_t packet_len = len + sizeof(ip_t);
00277         ip_t *packet;
00278         int tot_len;
00279 
00280         if (packet_len > IP_FRAME_LEN)
00281                 return(-EMSGSIZE);
00282 
00283         packet = kmalloc(packet_len);
00284         if (packet == NULL)
00285                 return(-ENOMEM);
00286 
00287         // Create the IP header                                         //
00288         packet->ip_version = IP_V4;
00289         packet->ip_hdr_len = sizeof(ip_t) / sizeof(dword);
00290         packet->ip_tos = 0;
00291         packet->ip_len = htons(packet_len);
00292         packet->ip_id = htons(0xDEAD);  // :-) //
00293         packet->ip_off = htons(IP_FLAG_DF | 0);
00294         packet->ip_ttl = ttl;
00295         packet->ip_proto = proto;
00296         packet->ip_chk = 0;
00297         packet->ip_dst = ip_to;
00298         packet->ip_src = get_host_ip();
00299         packet->ip_chk = ip_checksum(packet, sizeof(ip_t));
00300 
00301         // Copy the data into the packet                                //
00302         memcpy(packet + 1, data, len);
00303 
00304         // Translate the IP address into ethernet address               //
00305         // using the ARP protocol.                                      //
00306         if ( !arp_ip_to_eth(eth_to, ip_to) )
00307         {
00308                 #ifdef DEBUG
00309                 kprintf("\n\rARP fails!");
00310                 #endif
00311                 // The ethernet address was not found!                  //
00312                 return(-ENETUNREACH);
00313         }
00314         #ifdef DEBUG
00315         kprintf("\n\rsending eth packet to %02x:%02x:%02x:%02x:%02x:%02x...",
00316                 eth_to[0], eth_to[1], eth_to[2], eth_to[3], eth_to[4], eth_to[5]
00317         );
00318         #endif
00319 
00320         // Go to the ethernet layer...                                  //
00321         tot_len = send_eth_packet(eth_to, packet, packet_len, htons(ETH_FRAME_IP));
00322 
00323         #ifdef DEBUG
00324         kprintf("\n\r%u bytes sent from ethernet layer", tot_len);
00325         #endif
00326 
00327         // Free the memory of the packet                                //
00328         kfree(packet);
00329 
00330         if ( tot_len < 0 )
00331                 // Something wrong from at the ethernet layer           //
00332                 return(tot_len);
00333 
00334         // Well done!                                                   //
00335         return(packet_len);
00336 }
00337 
00338 //! \brief Receive an IP packet.
00339 //! \param buf The buffer where the received packet will be copied.
00340 //! \param len The maximum size of the buffer.
00341 //! \return The size of the packet received in bytes.
00342 /**
00343  *      \todo
00344  *      Routine not implemented!
00345  *      For now return protocol not available error.
00346  */
00347 int recv_ip_packet(ip_t *buf, size_t len)
00348 {
00349         return( -ENOPROTOOPT );
00350 }

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