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

arp.c

Go to the documentation of this file.
00001 /*!     \file network/arp.c
00002  *      \brief ARP (Address Resolution 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 
00011 #include <arch/mem.h>
00012 
00013 #include <kernel/clock.h>
00014 #include <kernel/console.h>
00015 #include <kernel/kmalloc.h>
00016 #include <kernel/semaphore.h>
00017 #include <kernel/task.h>
00018 
00019 #include <net/eth.h>
00020 #include <net/ip.h>
00021 #include <net/network.h>
00022 #include <net/rtl8139.h>
00023 
00024 #include <net/arp.h>
00025 
00026 //! Broadcast ethernet address.
00027 static uint8_t eth_bcast[ETH_ADDR_LEN] =
00028 {
00029         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
00030 };
00031 
00032 //! The ARP cache maximum entries.
00033 #define ARP_TABLE_DIM   10
00034 
00035 //! ARP cache (here are stored all addresses resolutions IP<->MAC).
00036 static struct
00037 {
00038         //! IP address.
00039         in_addr_t ip;
00040         //! Ethernet address.
00041         uint8_t mac[ETH_ADDR_LEN];
00042         //! Timestamp.
00043         uint32_t tickstamp;
00044 } arp_table[ARP_TABLE_DIM];
00045 
00046 //! ARP cache mutex semaphore.
00047 semaphore_t arp_mutex;
00048 
00049 //! \brief Compare two ethernet addresses.
00050 //! \param m1 A pointer to the first address to compare.
00051 //! \param m2 A pointer to the second address to compare.
00052 //! \return #TRUE if they match, otherwise return #FALSE.
00053 bool mac_addr_cmp(uint8_t *m1, uint8_t *m2)
00054 {
00055         if ( memcmp(m1, m2, ETH_ADDR_LEN)==0 )
00056                 return(TRUE);
00057         else
00058                 return(FALSE);
00059 }
00060 
00061 //! \brief Insert an address resolution into the ARP cache.
00062 //! \param ip The IP address (in network format).
00063 //! \param mac The ethernet address.
00064 void arp_add_cache(in_addr_t ip, uint8_t *mac)
00065 {
00066         uint32_t age_max=0, pos_max=0, age, ticks;
00067         int i;
00068 
00069         DOWN(&arp_mutex);
00070 
00071         // Check if the address is already present                      //
00072         for(i=0; i<ARP_TABLE_DIM; i++)
00073         {
00074                 if ( arp_table[i].ip == ip )
00075                 {
00076                         // Address already present => refresh cache     //
00077                         memcpy(arp_table[i].mac, mac, ETH_ADDR_LEN);
00078                         arp_table[i].tickstamp = sys_get_ticks();
00079 
00080                         UP(&arp_mutex);
00081                         return;
00082                 }
00083         }
00084         // Find an empty entry in the table                             //
00085         for(i=0; i<ARP_TABLE_DIM; i++)
00086         {
00087                 if ( arp_table[i].ip == 0 )
00088                 {
00089                         // Store the address into the ARP table         //
00090                         arp_table[i].ip = ip;
00091                         memcpy(arp_table[i].mac, mac, ETH_ADDR_LEN);
00092                         arp_table[i].tickstamp = sys_get_ticks();
00093 
00094                         UP(&arp_mutex);
00095                         return;
00096                 }
00097                 // Calculate the age of this entry                      //
00098                 ticks = sys_get_ticks();
00099                 age = ticks - arp_table[i].tickstamp;
00100                 if ( age >= age_max )
00101                 {
00102                         age_max = age;
00103                         pos_max = i;
00104                 }
00105         }
00106         // The ARP table is full => overwrite the oldest entry          //
00107         arp_table[pos_max].ip = ip;
00108         memcpy(arp_table[pos_max].mac, mac, ETH_ADDR_LEN);
00109         arp_table[pos_max].tickstamp = sys_get_ticks();
00110 
00111         UP(&arp_mutex);
00112 }
00113 
00114 //! \brief Remove an entry from the ARP cache.
00115 //! \param ip The IP address to remove (in network format).
00116 //! \return #TRUE if the entry has been found, #FALSE otherwise.
00117 bool arp_remove_cache(in_addr_t ip)
00118 {
00119         int i;
00120 
00121         DOWN(&arp_mutex);
00122 
00123         for(i=0; i<ARP_TABLE_DIM; i++)
00124                 if ( arp_table[i].ip == ip )
00125                 {
00126                         arp_table[i].ip = 0;
00127                         UP(&arp_mutex);
00128                         return(TRUE);
00129                 }
00130 
00131         // The entry has not been found                                 //
00132         UP(&arp_mutex);
00133         return(FALSE);
00134 }
00135 
00136 //! \brief Reset the ARP resolution cache.
00137 void arp_reset_cache()
00138 {
00139         INIT_MUTEX(&arp_mutex);
00140         memset(arp_table, 0, sizeof(arp_table));
00141 }
00142 
00143 //! \brief Translate from IP address to ethernet address.
00144 //! \param eth_addr A pointer to the ethernet address.
00145 //! \param ip_addr The IP address to translate (in network format).
00146 //! \return #TRUE if the translation can be performed, #FALSE otherwise.
00147 bool arp_ip_to_eth(uint8_t *eth_addr, in_addr_t ip_addr)
00148 {
00149         int i;
00150         timeout_t time1, time2;
00151 
00152         if ( get_eth_mac_addr()==NULL )
00153                 // Ethernet device is down!                             //
00154                 return(FALSE);
00155 
00156         // --- Special addresses ---                                    //
00157         if ( (ip_addr==INADDR_ANY) || (ip_addr==get_host_ip()) )
00158         {
00159                 // Maybe we're asking our MAC address (???)             //
00160                 memcpy(eth_addr, get_eth_mac_addr(), ETH_ADDR_LEN);
00161                 return(TRUE);
00162         }
00163 
00164         // Check for a broadcast request                                //
00165         if ( (ip_addr==get_host_bcast()) || (ip_addr==INADDR_BROADCAST) )
00166         {
00167                 // Broadcast in the current LAN                         //
00168                 memcpy(eth_addr, eth_bcast, ETH_ADDR_LEN);
00169                 return(TRUE);
00170         }
00171         // --- End of special addresses ---                             //
00172 
00173         // Search the address into the ARP cache                //
00174         DOWN(&arp_mutex);
00175         for(i=0; i<ARP_TABLE_DIM; i++)
00176         {
00177                 if ( arp_table[i].ip == ip_addr)
00178                 {
00179                         // Resolution is found in the cache     //
00180                         memcpy(eth_addr, arp_table[i].mac, ETH_ADDR_LEN);
00181 
00182                         UP(&arp_mutex);
00183                         return(TRUE);
00184                 }
00185         }
00186         UP(&arp_mutex);
00187 
00188         // Initialize a timeout to ask who has the ip address           //
00189         set_timeout(&time1, 4000);
00190         set_timeout(&time2, 0);
00191 
00192         while(TRUE)
00193         {
00194                 // Search the address into the ARP cache                //
00195                 DOWN(&arp_mutex);
00196                 for(i=0; i<ARP_TABLE_DIM; i++)
00197                 {
00198                         if ( arp_table[i].ip == ip_addr)
00199                         {
00200                                 // Resolution is found in the cache     //
00201                                 memcpy(eth_addr, arp_table[i].mac, ETH_ADDR_LEN);
00202 
00203                                 UP(&arp_mutex);
00204                                 return(TRUE);
00205                         }
00206                 }
00207                 UP(&arp_mutex);
00208 
00209                 // Resolution not found into the cache                  //
00210                 if ( is_timeout(&time1) )
00211                 {
00212                         // In this LAN none has this IP                 //
00213                         return(FALSE);
00214                 }
00215 
00216                 if ( is_timeout(&time2) )
00217                 {
00218                         kprintf(        "\n\rarp who-has %u.%u.%u.%u tell %u.%u.%u.%u"
00219                                 " (%02x:%02x:%02x:%02x:%02x:%02x)",
00220 
00221                                 IP_A(ntohl(ip_addr)),
00222                                 IP_B(ntohl(ip_addr)),
00223                                 IP_C(ntohl(ip_addr)),
00224                                 IP_D(ntohl(ip_addr)),
00225 
00226                                 IP_A(ntohl(get_host_ip())),
00227                                 IP_B(ntohl(get_host_ip())),
00228                                 IP_C(ntohl(get_host_ip())),
00229                                 IP_D(ntohl(get_host_ip())),
00230 
00231                                 get_eth_mac_addr()[0],
00232                                 get_eth_mac_addr()[1],
00233                                 get_eth_mac_addr()[2],
00234                                 get_eth_mac_addr()[3],
00235                                 get_eth_mac_addr()[4],
00236                                 get_eth_mac_addr()[5]
00237                         );
00238                         // Ask in broadcast who has the ip              //
00239                         send_arp_packet(ip_addr, eth_bcast, ARP_OP_REQUEST);
00240                         // Wait 1sec before re-sending the request              //
00241                         set_timeout(&time2, 1000);
00242                 }
00243                 idle();
00244         }
00245 }
00246 
00247 //! \brief Get an ARP packet from the ethernet layer.
00248 //! \param packet The ARP packet.
00249 void to_arp_layer(arp_t *packet)
00250 {
00251         #ifdef DEBUG
00252         // Dump the packet contents                                     //
00253         kprintf(
00254                 "\n\rhard_type:%04X proto_type:%04X hard_size:%u"
00255                 "\n\rproto_size:%u op:%04X"
00256                 "\n\rsource=%02x:%02x:%02x:%02x:%02x:%02x (%u.%u.%u.%u)"
00257                 "\n\rdest  =%02x:%02x:%02x:%02x:%02x:%02x (%u.%u.%u.%u)",
00258 
00259                 ntohs(packet->arp_hard_type), ntohs(packet->arp_proto_type), packet->arp_hard_size,
00260                 packet->arp_proto_size, ntohs(packet->arp_op),
00261 
00262                 packet->arp_eth_source[0], packet->arp_eth_source[1], packet->arp_eth_source[2],
00263                 packet->arp_eth_source[3], packet->arp_eth_source[4], packet->arp_eth_source[5],
00264 
00265                 IP_A(ntohl(packet->arp_ip_source)), IP_B(ntohl(packet->arp_ip_source)),
00266                 IP_C(ntohl(packet->arp_ip_source)), IP_D(ntohl(packet->arp_ip_source)),
00267 
00268                 packet->arp_eth_dest[0], packet->arp_eth_dest[1], packet->arp_eth_dest[2],
00269                 packet->arp_eth_dest[3], packet->arp_eth_dest[4], packet->arp_eth_dest[5],
00270 
00271                 IP_A(ntohl(packet->arp_ip_dest)), IP_B(ntohl(packet->arp_ip_dest)),
00272                 IP_C(ntohl(packet->arp_ip_dest)), IP_D(ntohl(packet->arp_ip_dest))
00273         );
00274 
00275         kprintf("\n\radding into ARP cache %u.%u.%u.%u",
00276                 IP_A(ntohl(packet->arp_ip_source)),
00277                 IP_B(ntohl(packet->arp_ip_source)),
00278                 IP_C(ntohl(packet->arp_ip_source)),
00279                 IP_D(ntohl(packet->arp_ip_source))
00280         );
00281         #endif
00282         // Add the address into the ARP cache                           //
00283         arp_add_cache(packet->arp_ip_source, packet->arp_eth_source);
00284 
00285         // Identify the ARP operation                                   //
00286         switch( ntohs(packet->arp_op) )
00287         {
00288                 case ARP_OP_REQUEST:
00289                 #ifdef ARP_DEBUG
00290                 kprintf("\n\rarp who-has %u.%u.%u.%u tell %u.%u.%u.%u (%02x:%02x:%02x:%02x:%02x:%02x)",
00291 
00292                         IP_A(ntohl(packet->arp_ip_dest)), IP_B(ntohl(packet->arp_ip_dest)),
00293                         IP_C(ntohl(packet->arp_ip_dest)), IP_D(ntohl(packet->arp_ip_dest)),
00294 
00295                         IP_A(ntohl(packet->arp_ip_source)), IP_B(ntohl(packet->arp_ip_source)),
00296                         IP_C(ntohl(packet->arp_ip_source)), IP_D(ntohl(packet->arp_ip_source)),
00297 
00298                         packet->arp_eth_source[0], packet->arp_eth_source[1], packet->arp_eth_source[2],
00299                         packet->arp_eth_source[3], packet->arp_eth_source[4], packet->arp_eth_source[5]
00300                 );
00301                 #endif
00302                 // Check if we must reply our address to the sender     //
00303                 if (packet->arp_ip_dest == get_host_ip())
00304                 {
00305                         // Send our address resolution                  //
00306                         send_arp_packet(
00307                                 packet->arp_ip_source,
00308                                 packet->arp_eth_source,
00309                                 ARP_OP_REPLY
00310                         );
00311                 }
00312                 break;
00313 
00314                 case ARP_OP_REPLY:
00315                 #ifdef ARP_DEBUG
00316                 // Echo reply received                                  //
00317                 kprintf("\n\rarp reply %u.%u.%u.%u is-at %02x:%02x:%02x:%02x:%02x:%02x",
00318 
00319                         IP_A(ntohl(packet->arp_ip_source)), IP_B(ntohl(packet->arp_ip_source)),
00320                         IP_C(ntohl(packet->arp_ip_source)), IP_D(ntohl(packet->arp_ip_source)),
00321 
00322                         packet->arp_eth_source[0], packet->arp_eth_source[1], packet->arp_eth_source[2],
00323                         packet->arp_eth_source[3], packet->arp_eth_source[4], packet->arp_eth_source[5]
00324                 );
00325                 #endif
00326                 break;
00327 
00328                 default:
00329                 kprintf("\n\rarp: message unknown!");
00330                 break;
00331         }
00332 }
00333 
00334 //! \brief Send an ARP packet to the ethernet layer.
00335 //! \param ip_to The wanted IP destination address in network format.
00336 //! \param eth_to The ethernet destination address.
00337 //! \param arp_op The ARP operation.
00338 //! \return
00339 //!     \li The number of bytes sent in case of success;
00340 //!     \li a negative value if an error occurs.
00341 int send_arp_packet(in_addr_t ip_to, const uint8_t *eth_to, uint16_t arp_op)
00342 {
00343         arp_t *packet;
00344         int tot_len;
00345         uint8_t *mac_addr;
00346 
00347         packet = kmalloc(sizeof(arp_t));
00348         if (packet==NULL)
00349                 return(-ENOMEM);
00350 
00351         // Create the ARP header                                        //
00352         packet->arp_hard_type = htons(ARPHRD_ETHER);
00353         packet->arp_proto_type = htons(ETH_FRAME_IP);
00354         packet->arp_hard_size = ETH_ADDR_LEN;
00355         packet->arp_proto_size = sizeof(in_addr_t);
00356         packet->arp_op = htons(arp_op);
00357 
00358         // Copy the MAC address of this host                            //
00359         if ( (mac_addr = get_eth_mac_addr()) == NULL )
00360                 // No such device or address!                           //
00361                 return(-ENXIO);
00362 
00363         memcpy(packet->arp_eth_source, mac_addr, ETH_ADDR_LEN);
00364         // Copy the IP address of this host                             //
00365         packet->arp_ip_source = get_host_ip();
00366 
00367         // Set the destination MAC address                              //
00368         memcpy(packet->arp_eth_dest, eth_to, ETH_ADDR_LEN);
00369         // Set the destination IP                                       //
00370         packet->arp_ip_dest = ip_to;
00371 
00372         // Go to the ethernet layer...                                  //
00373         tot_len = send_eth_packet(eth_to, packet, sizeof(arp_t), htons(ETH_FRAME_ARP));
00374 
00375         #ifdef DEBUG
00376         kprintf("\n\r%u bytes sent from ethernet layer", tot_len);
00377         #endif
00378 
00379         // Free the memory of the packet                                //
00380         kfree(packet);
00381 
00382         if ( tot_len < 0 )
00383                 // Something wrong from at the ethernet layer           //
00384                 return(tot_len);
00385 
00386         // Well done!                                                   //
00387         return(0);
00388 }
00389 
00390 //! \brief Receive an ARP packet.
00391 //! \param buf The buffer where the received packet will be copied.
00392 //! \param len The maximum size of the buffer.
00393 //! \return The size of the packet received in bytes.
00394 /**
00395  *      \todo
00396  *      Routine not implemented!
00397  *      For now return protocol not available error.
00398  */
00399 int recv_arp_packet(arp_t *buf, size_t len)
00400 {
00401         return( -ENOPROTOOPT );
00402 }
00403 
00404 //! \brief Send an ARP request.
00405 //! \param ip_dot
00406 //!     The wanted IP address in numbers-and-dot notation.
00407 //!     If \p ip_dot is not a valid ip address print the arp table
00408 //!     to stdout.
00409 void arp_request(char *ip_dot)
00410 {
00411         uint8_t eth[ETH_ADDR_LEN];
00412         in_addr_t ip;
00413         int i;
00414 
00415         // Translate the IP address from numbers-and-dot notation into  //
00416         // binary network order byte number.                            //
00417         if ( !inet_aton(ip_dot, &ip) )
00418         {
00419                 // Not a valid address => dump the ARP cache to stdout  //
00420                 // TODO: return if the ethernet card is not initialized //
00421                 kprintf("\n\rIP address      MAC address");
00422                 for(i=0; i<ARP_TABLE_DIM; i++)
00423                 {
00424                         if ( arp_table[i].ip != 0 )
00425                         {
00426                                 kprintf("\n\r%u.%u.%u.%u",
00427                                         IP_A(ntohl(arp_table[i].ip)),
00428                                         IP_B(ntohl(arp_table[i].ip)),
00429                                         IP_C(ntohl(arp_table[i].ip)),
00430                                         IP_D(ntohl(arp_table[i].ip))
00431                                 );
00432                                 gotoxy(16, -1);
00433                                 kprintf("%02x:%02x:%02x:%02x:%02x:%02x",
00434                                         arp_table[i].mac[0],
00435                                         arp_table[i].mac[1],
00436                                         arp_table[i].mac[2],
00437                                         arp_table[i].mac[3],
00438                                         arp_table[i].mac[4],
00439                                         arp_table[i].mac[5]
00440                                 );
00441                         }
00442                 }
00443                 kprintf("\n\r");
00444                 return;
00445         }
00446 
00447         // If a valid address is passed perform the address resolution  //
00448         if ( arp_ip_to_eth(eth, ip) )
00449                 kprintf("\n\rarp reply %u.%u.%u.%u is-at %02x:%02x:%02x:%02x:%02x:%02x\n\r",
00450 
00451                         IP_A(ntohl(ip)), IP_B(ntohl(ip)),
00452                         IP_C(ntohl(ip)), IP_D(ntohl(ip)),
00453 
00454                         eth[0], eth[1], eth[2],
00455                         eth[3], eth[4], eth[5]
00456                 );
00457         else
00458                 kprintf("\n\rhost unreachable!\n\r");
00459 }

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