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

arp.c File Reference

ARP (Address Resolution Protocol) layer. More...

#include <const.h>
#include <errno.h>
#include <arch/mem.h>
#include <kernel/clock.h>
#include <kernel/console.h>
#include <kernel/kmalloc.h>
#include <kernel/semaphore.h>
#include <kernel/task.h>
#include <net/eth.h>
#include <net/ip.h>
#include <net/network.h>
#include <net/rtl8139.h>
#include <net/arp.h>

Go to the source code of this file.

Defines

#define ARP_TABLE_DIM   10
 The ARP cache maximum entries.


Functions

bool mac_addr_cmp (uint8_t *m1, uint8_t *m2)
 Compare two ethernet addresses.
Parameters:
m1  A pointer to the first address to compare.
m2  A pointer to the second address to compare.
Returns:
TRUE if they match, otherwise return FALSE.


void arp_add_cache (in_addr_t ip, uint8_t *mac)
 Insert an address resolution into the ARP cache.
Parameters:
ip  The IP address (in network format).
mac  The ethernet address.


bool arp_remove_cache (in_addr_t ip)
 Remove an entry from the ARP cache.
Parameters:
ip  The IP address to remove (in network format).
Returns:
TRUE if the entry has been found, FALSE otherwise.


void arp_reset_cache ()
 Reset the ARP resolution cache.

bool arp_ip_to_eth (uint8_t *eth_addr, in_addr_t ip_addr)
 Translate from IP address to ethernet address.
Parameters:
eth_addr  A pointer to the ethernet address.
ip_addr  The IP address to translate (in network format).
Returns:
TRUE if the translation can be performed, FALSE otherwise.


void to_arp_layer (arp_t *packet)
 Get an ARP packet from the ethernet layer.
Parameters:
packet  The ARP packet.


int send_arp_packet (in_addr_t ip_to, const uint8_t *eth_to, uint16_t arp_op)
 Send an ARP packet to the ethernet layer.
Parameters:
ip_to  The wanted IP destination address in network format.
eth_to  The ethernet destination address.
arp_op  The ARP operation.
Returns:
  • The number of bytes sent in case of success;
  • a negative value if an error occurs.


int recv_arp_packet (arp_t *buf, size_t len)
 Receive an ARP packet.
Parameters:
buf  The buffer where the received packet will be copied.
len  The maximum size of the buffer.
Returns:
The size of the packet received in bytes.


void arp_request (char *ip_dot)
 Send an ARP request.
Parameters:
ip_dot  The wanted IP address in numbers-and-dot notation. If ip_dot is not a valid ip address print the arp table to stdout.



Variables

uint8_t eth_bcast [ETH_ADDR_LEN]
 Broadcast ethernet address.

struct {
   in_addr_t   ip
   uint8_t   mac [ETH_ADDR_LEN]
   uint32_t   tickstamp
arp_table [ARP_TABLE_DIM]
 ARP cache (here are stored all addresses resolutions IP<->MAC).

semaphore_t arp_mutex
 ARP cache mutex semaphore.


Detailed Description

ARP (Address Resolution Protocol) layer.

Author:
Andrea Righi <drizzt@inwind.it>
Date:
Last update: 2003-11-09
Note:
Copyright (©) 2003 Andrea Righi

Definition in file arp.c.


Define Documentation

#define ARP_TABLE_DIM   10
 

The ARP cache maximum entries.

Definition at line 33 of file arp.c.


Function Documentation

void arp_add_cache in_addr_t    ip,
uint8_t   mac
 

Insert an address resolution into the ARP cache.

Parameters:
ip  The IP address (in network format).
mac  The ethernet address.

Definition at line 64 of file arp.c.

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 }

bool arp_ip_to_eth uint8_t   eth_addr,
in_addr_t    ip_addr
 

Translate from IP address to ethernet address.

Parameters:
eth_addr  A pointer to the ethernet address.
ip_addr  The IP address to translate (in network format).
Returns:
TRUE if the translation can be performed, FALSE otherwise.

Definition at line 147 of file arp.c.

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 }

bool arp_remove_cache in_addr_t    ip
 

Remove an entry from the ARP cache.

Parameters:
ip  The IP address to remove (in network format).
Returns:
TRUE if the entry has been found, FALSE otherwise.

Definition at line 117 of file arp.c.

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 }

void arp_request char *    ip_dot
 

Send an ARP request.

Parameters:
ip_dot  The wanted IP address in numbers-and-dot notation. If ip_dot is not a valid ip address print the arp table to stdout.

Definition at line 409 of file arp.c.

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 }

void arp_reset_cache  
 

Reset the ARP resolution cache.

Definition at line 137 of file arp.c.

00138 {
00139         INIT_MUTEX(&arp_mutex);
00140         memset(arp_table, 0, sizeof(arp_table));
00141 }

bool mac_addr_cmp uint8_t   m1,
uint8_t   m2
 

Compare two ethernet addresses.

Parameters:
m1  A pointer to the first address to compare.
m2  A pointer to the second address to compare.
Returns:
TRUE if they match, otherwise return FALSE.

Definition at line 53 of file arp.c.

00054 {
00055         if ( memcmp(m1, m2, ETH_ADDR_LEN)==0 )
00056                 return(TRUE);
00057         else
00058                 return(FALSE);
00059 }

int recv_arp_packet arp_t   buf,
size_t    len
 

Receive an ARP packet.

Parameters:
buf  The buffer where the received packet will be copied.
len  The maximum size of the buffer.
Returns:
The size of the packet received in bytes.

Todo:
Routine not implemented! For now return protocol not available error.

Definition at line 399 of file arp.c.

00400 {
00401         return( -ENOPROTOOPT );
00402 }

int send_arp_packet in_addr_t    ip_to,
const uint8_t   eth_to,
uint16_t    arp_op
 

Send an ARP packet to the ethernet layer.

Parameters:
ip_to  The wanted IP destination address in network format.
eth_to  The ethernet destination address.
arp_op  The ARP operation.
Returns:
  • The number of bytes sent in case of success;
  • a negative value if an error occurs.

Definition at line 341 of file arp.c.

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 }

void to_arp_layer arp_t   packet
 

Get an ARP packet from the ethernet layer.

Parameters:
packet  The ARP packet.

Definition at line 249 of file arp.c.

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 }


Variable Documentation

semaphore_t arp_mutex
 

ARP cache mutex semaphore.

Definition at line 47 of file arp.c.

struct { ... } arp_table[ARP_TABLE_DIM] [static]
 

ARP cache (here are stored all addresses resolutions IP<->MAC).

uint8_t eth_bcast[ETH_ADDR_LEN] [static]
 

Initial value:

{
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
}
Broadcast ethernet address.

Definition at line 27 of file arp.c.

in_addr_t ip
 

IP address.

Definition at line 39 of file arp.c.

uint8_t mac[ETH_ADDR_LEN]
 

Ethernet address.

Definition at line 41 of file arp.c.

uint32_t tickstamp
 

Timestamp.

Definition at line 43 of file arp.c.


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