Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

arp.c

Go to the documentation of this file.
00001 /*! \file arp.c \brief ARP Protocol Library. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'arp.c'
00005 // Title        : ARP Protocol Library
00006 // Author       : Pascal Stang
00007 // Created      : 9/7/2004
00008 // Revised      : 7/3/2005
00009 // Version      : 0.1
00010 // Target MCU   : Atmel AVR series
00011 // Editor Tabs  : 4
00012 //
00013 //*****************************************************************************
00014 
00015 #include "global.h"
00016 #include "net.h"
00017 #include "nic.h"
00018 #include "arp.h"
00019 
00020 #include "rprintf.h"
00021 
00022 // global variables
00023 
00024 /// Single ARP table entry/record
00025 struct ArpEntry
00026 {
00027     uint32_t ipaddr;            ///< remote-note IP address
00028     struct netEthAddr ethaddr;  ///< remote-node ethernet (hardware/mac) address
00029     uint8_t time;               ///< time to live (in ARP table); this is decremented by arpTimer()
00030 };
00031 
00032 struct ArpEntry ArpMyAddr;      ///< my local interface information (IP and MAC address)
00033 struct ArpEntry ArpTable[ARP_TABLE_SIZE];   ///< ARP table of matched IP<->MAC associations
00034 
00035 
00036 void arpInit(void)
00037 {
00038     u08 i;
00039     // initialize all ArpTable elements to unused
00040     for(i=0; i<ARP_TABLE_SIZE; i++)
00041     {
00042         ArpTable[i].ipaddr = 0;
00043         ArpTable[i].time = 0;
00044     }
00045 }
00046 
00047 void arpSetAddress(struct netEthAddr* myeth, uint32_t myip)
00048 {
00049     // set local address record
00050     ArpMyAddr.ethaddr = *myeth;
00051     ArpMyAddr.ipaddr = myip;
00052 }
00053 
00054 void arpArpIn(unsigned int len, struct netEthArpHeader* packet)
00055 {
00056     #ifdef ARP_DEBUG
00057     rprintfProgStrM("Received ARP Request\r\n");
00058     arpPrintHeader( &packet->arp );
00059     #endif
00060 
00061     // for now, we just reply to requests
00062     // need to add ARP cache
00063     if( (packet->arp.dipaddr == HTONL(ArpMyAddr.ipaddr)) &&
00064         (packet->arp.opcode == htons(ARP_OPCODE_REQUEST)) )
00065     {
00066         // in ARP header
00067         // copy sender's address info to dest. fields
00068         packet->arp.dhwaddr = packet->arp.shwaddr;
00069         packet->arp.dipaddr = packet->arp.sipaddr;
00070         // fill in our information
00071         packet->arp.shwaddr = ArpMyAddr.ethaddr;
00072         packet->arp.sipaddr = HTONL(ArpMyAddr.ipaddr);
00073         // change op to reply
00074         packet->arp.opcode = htons(ARP_OPCODE_REPLY);
00075         
00076         // in ethernet header
00077         packet->eth.dest = packet->eth.src;
00078         packet->eth.src  = ArpMyAddr.ethaddr;
00079 
00080         #ifdef ARP_DEBUG
00081         rprintfProgStrM("Sending ARP Reply\r\n");
00082         arpPrintHeader( &packet->arp );
00083         //netPrintEthHeader((struct netEthHeader*)packet);
00084         //debugPrintHexTable(len, ((unsigned char*)packet));
00085         #endif
00086 
00087         // send reply!
00088         nicSend(len, (unsigned char*)packet);
00089     }
00090 }
00091 
00092 void arpIpIn(struct netEthIpHeader* packet)
00093 {
00094     int8_t index;
00095 
00096     // check if sender is already present in arp table
00097     index = arpMatchIp(HTONL(packet->ip.srcipaddr));
00098     if(index != -1)
00099     {
00100         // sender's IP address found, update ARP entry
00101         ArpTable[index].ethaddr = packet->eth.src;
00102         // and we're done
00103         return;
00104     }
00105 
00106     // sender was not present in table,
00107     // must add in empty/expired slot
00108     for(index=0; index<ARP_TABLE_SIZE; index++)
00109     {
00110         if(!ArpTable[index].time)
00111         {
00112             // write entry
00113             ArpTable[index].ethaddr = packet->eth.src;
00114             ArpTable[index].ipaddr = HTONL(packet->ip.srcipaddr);
00115             ArpTable[index].time = ARP_CACHE_TIME_TO_LIVE;
00116             // and we're done
00117             return;
00118         }
00119     }
00120 
00121     // no space in table, we give up
00122 }
00123 
00124 void arpIpOut(struct netEthIpHeader* packet, uint32_t phyDstIp)
00125 {
00126     int index;
00127     // check if destination is already present in arp table
00128     // use the physical dstIp if it's provided, otherwise the dstIp in packet
00129     if(phyDstIp)
00130         index = arpMatchIp(phyDstIp);
00131     else
00132         index = arpMatchIp(HTONL(packet->ip.destipaddr));
00133     // fill in ethernet info
00134     if(index != -1)
00135     {
00136         // ARP entry present, fill eth address(es)
00137         packet->eth.src  = ArpMyAddr.ethaddr;
00138         packet->eth.dest = ArpTable[index].ethaddr;
00139         packet->eth.type = HTONS(ETHTYPE_IP);
00140     }
00141     else
00142     {
00143         // not in table, must send ARP request
00144         packet->eth.src = ArpMyAddr.ethaddr;
00145         // MUST CHANGE, but for now, send this one broadcast
00146         packet->eth.dest.addr[0] = 0xFF;
00147         packet->eth.dest.addr[1] = 0xFF;
00148         packet->eth.dest.addr[2] = 0xFF;
00149         packet->eth.dest.addr[3] = 0xFF;
00150         packet->eth.dest.addr[4] = 0xFF;
00151         packet->eth.dest.addr[5] = 0xFF;
00152         packet->eth.type = HTONS(ETHTYPE_IP);
00153     }
00154 }
00155 
00156 void arpTimer(void)
00157 {
00158     int index;
00159     // this function meant to be called on a regular time interval
00160 
00161     // decrement time-to-live for all entries
00162     for(index=0; index<ARP_TABLE_SIZE; index++)
00163     {
00164         if(ArpTable[index].time)
00165             ArpTable[index].time--;
00166     }
00167 }
00168 
00169 int arpMatchIp(uint32_t ipaddr)
00170 {
00171     uint8_t i;
00172 
00173     // check if IP address is present in arp table
00174     for(i=0; i<ARP_TABLE_SIZE; i++)
00175     {
00176         if(ArpTable[i].ipaddr == ipaddr)
00177         {
00178             // IP address found
00179             return i;
00180         }
00181     }
00182 
00183     // no match
00184     return -1;
00185 }
00186 
00187 #ifdef ARP_DEBUG_PRINT
00188 void arpPrintHeader(struct netArpHeader* packet)
00189 {
00190     rprintfProgStrM("ARP Packet:\r\n");
00191     //debugPrintHexTable(60, ((unsigned char*)&packet)-14);
00192     // print operation type
00193     rprintfProgStrM("Operation   : ");
00194     if(packet->opcode == htons(ARP_OPCODE_REQUEST))
00195         rprintfProgStrM("REQUEST");
00196     else if(packet->opcode == htons(ARP_OPCODE_REPLY))
00197         rprintfProgStrM("REPLY");
00198     else
00199         rprintfProgStrM("UNKNOWN");
00200     rprintfCRLF();
00201     // print source hardware address
00202     rprintfProgStrM("SrcHwAddr   : ");  netPrintEthAddr(&packet->shwaddr);  rprintfCRLF();
00203     // print source protocol address
00204     rprintfProgStrM("SrcProtoAddr: ");  netPrintIPAddr(HTONL(packet->sipaddr)); rprintfCRLF();
00205     // print target hardware address
00206     rprintfProgStrM("DstHwAddr   : ");  netPrintEthAddr(&packet->dhwaddr);  rprintfCRLF();
00207     // print target protocol address
00208     rprintfProgStrM("DstProtoAddr: ");  netPrintIPAddr(HTONL(packet->dipaddr)); rprintfCRLF();
00209 }
00210 
00211 
00212 void arpPrintTable(void)
00213 {
00214     uint8_t i;
00215 
00216     // print ARP table
00217     rprintfProgStrM("Time    Eth Address    IP Address\r\n");
00218     rprintfProgStrM("---------------------------------------\r\n");
00219     for(i=0; i<ARP_TABLE_SIZE; i++)
00220     {
00221         rprintfu08(ArpTable[i].time);
00222         rprintfProgStrM("   ");
00223         netPrintEthAddr(&ArpTable[i].ethaddr);
00224         rprintfProgStrM("  ");
00225         netPrintIPAddr(ArpTable[i].ipaddr);
00226         rprintfCRLF();
00227     }
00228 }
00229 #endif

Generated on Mon Nov 6 23:36:59 2006 for Procyon ARMlib by  doxygen 1.4.2