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