📄 arp.c
字号:
#include <datatypes.h>
#include <debug.h>
#include <ethernet.h>
#include <arp.h>
#include <timers.h>
#include <system.h>
#include <globalvariables.h>
/** \brief ARP cache table holding ARP_TSIZE cache values
*
* ARP cache table is an array of arp_entry structures holding
* all of the necessary information about the state, timeouts and
* hardware/IP addresses of individual entries. By modifying the
* #ARP_TSIZE, cache size can be changed and thus RAM memory occupied
* by the ARP cache significantly reduced or increased. See arp_entry
* definition for more information about struct fields.
*/
struct arp_entry arp_table[ARP_TSIZE];
/** \brief ARP timer handle used for measuring timeouts, doing retransmissions,..
*
* ARP module uses this timer handle to detect that a certain period of
* time has expired (defined by the value of #ARP_MANG_TOUT) and that
* cache entries should be examined to see what to do with them.
*/
UINT8 arp_timer;
/** \brief Process and analyze the received ARP packet
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
*
* \date 10.07.2002
* \param frame Pointer to ethernet_frame structure containing information
* about the received frame
* \return Return #TRUE if Ethernet frame processed held ARP packet,
* otherwise #FALSE.
*
* Invoke process_arp function whenever ARP packet is received
* (see main_demo.c for an example loop). This function will process the
* received packet, analyze it'c content briefly and perform on of the
* two possible actions:
* \li If the received packet is ARP request it will invoke
* arp_send_reply in order to send ARP reply back
* \li If the received packet is ARP response it will iterate through
* the cache table and try to find ARP entry that is beeing resolved
* or refreshed
*/
UINT8 process_arp (struct ethernet_frame* frame)
{
UINT8 temp;
/* Check if ARP packet*/
if( frame->protocol == ARP_ETHCODE )
{
/* Yep, ARP */
NETWORK_RECEIVE_INITIALIZE(frame->buf_index);
/* Is it long enough? */
if( frame->frame_size < (2*MAXHWALEN + 2*MAXPRALEN + 2 + 6) )
{
/* Somehow corrupted ARP packet */
ARP_DEBUGOUT("Corrupted ARP packet\n\r");
return(TRUE);
}
/* Ignore next 6 bytes: <HW type>, <Protocol type> */
/* <HW address len> and <Protocol address len> */
for(temp=0; temp<6; temp++)
RECEIVE_NETWORK_B();
ARP_DEBUGOUT("Incoming ARP..\n\r");
/* Check if request or response */
if( RECEIVE_NETWORK_B() == 0x00)
{
temp = RECEIVE_NETWORK_B(); /* get opcode */
if( temp == ARP_REQUEST ) {
ARP_DEBUGOUT(" ARP REQUEST Received..\n\r");
arp_send_response();
} else if( temp == ARP_REPLY ) {
ARP_DEBUGOUT("ARP Response Received..\n\r");
arp_get_response();
}
/* Wasn't request or response or all done, dump it */
}
/*NETWORK_RECEIVE_END();*/
return(TRUE);
}
/* Wasn't ARP, don't touch the packet */
return(FALSE);
}
/** \brief Send response to an ARP request
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 10.07.2002
* \warning
* \li This function starts reading data from Ethernet controller
* without initializing it for reading it first, so NIC must already
* be initialized for reading from correct address (it expects ar$sha
* field from ARP packet immediately)
*
* This function is invoked from process_arp() function in order to send
* a reply to an ARP request. First, incoming packet is checked to see
* if it is intended for us or not. If not, function does not do anything.
* Otherwise, ARP reply packet is formed and sent.
*/
void arp_send_response(void)
{
struct arp_entry *qstruct;
UINT8 rem_hwadr[MAXHWALEN];
UINT32 rem_ip;
UINT32 ltemp;
INT8 i;
BYTE j;
/* Record Sender's HW address */
for( i=0; i<MAXHWALEN; i++)
rem_hwadr[i] = RECEIVE_NETWORK_B();
/* Read Sender's IP Address */
for( i=0; i<MAXPRALEN; i++) {
rem_ip <<= 8;
rem_ip |= RECEIVE_NETWORK_B();
}
/* Skip Target HW address */
RECEIVE_NETWORK_B();
RECEIVE_NETWORK_B();
RECEIVE_NETWORK_B();
RECEIVE_NETWORK_B();
RECEIVE_NETWORK_B();
RECEIVE_NETWORK_B();
/* Is The Packet For Us? */
for( i=0; i<MAXPRALEN; i++) {
ltemp <<= 8;
ltemp |= RECEIVE_NETWORK_B();
}
if( ltemp != localmachine.localip )
return; /* No */
ARP_DEBUGOUT("Preparing for ARP Reply\n\r");
/* OK. Now send reply */
NETWORK_SEND_INITIALIZE(ARP_BUFFER);
/* Add datalink (Ethernet addresses) information */
for( i=0; i<MAXHWALEN; i++) {
send_frame.destination[i] = rem_hwadr[i];
send_frame.source[i] = localmachine.localHW[i];
}
send_frame.protocol = PROTOCOL_ARP;
NETWORK_ADD_DATALINK(&send_frame);
/* PUT ARP Data */
SEND_NETWORK_B( (BYTE)(AR_HARDWARE>>8) ); /* Hardware Type */
SEND_NETWORK_B( (BYTE)AR_HARDWARE );
SEND_NETWORK_B(0x08); /* Protocol Type */
SEND_NETWORK_B(0x00);
SEND_NETWORK_B(MAXHWALEN); /* HW Adr Len */
SEND_NETWORK_B(MAXPRALEN); /* Protocol Adr. Len*/
SEND_NETWORK_B( 0x00 ); /* ARP Opcode */
SEND_NETWORK_B( 0x02 );
SEND_NETWORK_B((UINT8)(localmachine.localHW[0])); /* Address fields */
SEND_NETWORK_B((UINT8)(localmachine.localHW[1]));
SEND_NETWORK_B((UINT8)(localmachine.localHW[2]));
SEND_NETWORK_B((UINT8)(localmachine.localHW[3]));
SEND_NETWORK_B((UINT8)(localmachine.localHW[4]));
SEND_NETWORK_B((UINT8)(localmachine.localHW[5]));
SEND_NETWORK_B((UINT8)(localmachine.localip>>24));
SEND_NETWORK_B((UINT8)(localmachine.localip>>16));
SEND_NETWORK_B((UINT8)(localmachine.localip>>8));
SEND_NETWORK_B((UINT8)(localmachine.localip));
SEND_NETWORK_B((UINT8)rem_hwadr[0]);
SEND_NETWORK_B((UINT8)rem_hwadr[1]);
SEND_NETWORK_B((UINT8)rem_hwadr[2]);
SEND_NETWORK_B((UINT8)rem_hwadr[3]);
SEND_NETWORK_B((UINT8)rem_hwadr[4]);
SEND_NETWORK_B((UINT8)rem_hwadr[5]);
SEND_NETWORK_B((UINT8)(rem_ip>>24));
SEND_NETWORK_B((UINT8)(rem_ip>>16));
SEND_NETWORK_B((UINT8)(rem_ip>>8));
SEND_NETWORK_B((UINT8)rem_ip);
NETWORK_COMPLETE_SEND(0x0040); /* Send the packet */
ARP_DEBUGOUT("ARP Reply Sent..\n\r");
/* Add the Sender's info to cache because we can */
arp_add(rem_ip, &send_frame.destination[0], ARP_TEMP_IP);
return;
}
/** \brief Extract data from the received ARP packet
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 10.07.2002
* \warning
* \li This function starts reading data from Ethernet controller
* without initializing it for reading it first, so NIC must already
* be initialized for reading from correct address (it expects ar$sha
* field from ARP packet immediately)
*
* This function is invoked from process_arp() function when ARP reply
* packet is detected. Basic checking is performed to see if the packet
* is intended for us, and if it is, ARP cache table is checked and
* corresponding entry is refreshed (resolved).
*
*/
void arp_get_response(void)
{
struct arp_entry *qstruct;
UINT8 rem_hwadr[MAXHWALEN];
UINT32 rem_ip = 0;
UINT32 ltemp = 0;
INT8 i;
UINT8 j;
/* Read Sender's HW address */
for( i=0; i<MAXHWALEN; i++)
rem_hwadr[i] = RECEIVE_NETWORK_B();
/* Read Sender's IP Address */
for( i=0; i<MAXPRALEN; i++)
{
rem_ip <<= 8;
rem_ip |= RECEIVE_NETWORK_B();
}
/* Skip our HW Address */
for(i=0; i<MAXHWALEN; i++)
RECEIVE_NETWORK_B();
/* Is The Packet For Us? */
for( i=0; i<MAXPRALEN; i++)
{
ltemp <<= 8;
ltemp |= RECEIVE_NETWORK_B();
}
if( ltemp != localmachine.localip )
return; /* No */
ARP_DEBUGOUT("Now entering to process ARP Reply..\n\r");
/* Are we waiting for that reply? */
for( i=1; i<ARP_TSIZE; i++ )
{
qstruct = &arp_table[i];
if( qstruct->state == ARP_FREE )
continue;
if( qstruct->state == ARP_RESERVED )
continue;
if( rem_ip == qstruct->pradr )
{
/* We are caching that IP, refresh it */
ARP_DEBUGOUT("Refreshing ARP cache from Reply..\n\r");
for( j=0; j<MAXHWALEN; j++ )
qstruct->hwadr[j] = rem_hwadr[j];
qstruct->ttl = ARP_TIMEOUT;
qstruct->retries = ARP_MAXRETRY; /* No need for Retry */
qstruct->state = ARP_RESOLVED;
/* Done */
break;
}
}
}
/** \brief Send ARP request based on information in an ARP cache table
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 1.11.2001
* \param entry Index of ARP cache entry that is beeing resolved
*
* Invoked from arp_find() and arp_manage() functions, arp_send_request
* creates ARP request packet based on data stored in the ARP cache entry
* who's index is given as a parameter.
*/
void arp_send_req (UINT8 entry)
{
struct arp_entry *qstruct;
UINT8 i;
qstruct = &arp_table[entry];
NETWORK_SEND_INITIALIZE(ARP_BUFFER);
/* Add datalink (Ethernet addresses) information */
for( i=0; i<MAXHWALEN; i++) {
send_frame.destination[i] = 0xFF;
send_frame.source[i] = localmachine.localHW[i];
}
send_frame.protocol = PROTOCOL_ARP;
NETWORK_ADD_DATALINK(&send_frame);
/* PUT ARP Data */
SEND_NETWORK_B( (BYTE) (AR_HARDWARE>>8) ); /* Hardware Type */
SEND_NETWORK_B( (BYTE) AR_HARDWARE );
SEND_NETWORK_B(0x08); /* Protocol Type */
SEND_NETWORK_B(0x00);
SEND_NETWORK_B(MAXHWALEN); /* HW Adr Len */
SEND_NETWORK_B(MAXPRALEN); /* Protocol Adr. Len*/
SEND_NETWORK_B( (BYTE)(ARP_REQUEST>>8)); /* ARP Opcode */
SEND_NETWORK_B( (BYTE) ARP_REQUEST );
SEND_NETWORK_B((UINT8)localmachine.localHW[0]);
SEND_NETWORK_B((UINT8)localmachine.localHW[1]);
SEND_NETWORK_B((UINT8)localmachine.localHW[2]);
SEND_NETWORK_B((UINT8)localmachine.localHW[3]);
SEND_NETWORK_B((UINT8)localmachine.localHW[4]);
SEND_NETWORK_B((UINT8)localmachine.localHW[5]);
SEND_NETWORK_B((UINT8)(localmachine.localip>>24));
SEND_NETWORK_B((UINT8)(localmachine.localip>>16));
SEND_NETWORK_B((UINT8)(localmachine.localip>>8));
SEND_NETWORK_B((UINT8)localmachine.localip);
SEND_NETWORK_B((UINT8)0xFF);
SEND_NETWORK_B((UINT8)0xFF);
SEND_NETWORK_B((UINT8)0xFF);
SEND_NETWORK_B((UINT8)0xFF);
SEND_NETWORK_B((UINT8)0xFF);
SEND_NETWORK_B((UINT8)0xFF);
SEND_NETWORK_B((UINT8)(qstruct->pradr>>24));
SEND_NETWORK_B((UINT8)(qstruct->pradr>>16));
SEND_NETWORK_B((UINT8)(qstruct->pradr>>8));
SEND_NETWORK_B((UINT8)qstruct->pradr);
/* Packet assembled now, just send it ... */
NETWORK_COMPLETE_SEND(0x0040); /* Min packet size */
ARP_DEBUGOUT("ARP Request Sent\n\r");
}
/** \brief Allocate ARP entry in ARP cache table
* \author
* \li Jari Lahti (jari.lahti@violasystems.com)
* \date 1.11.2001
* \param type Type of ARP cache entry beeing allocated. Can be one of the
* following:
* \li #ARP_FIXED_IP
* \li #ARP_TEMP_IP
* \return >=0 - pointer to allocated ARP entry (actaully index in the
* ARP cache table)
*
* Allocate arp entry for given type. Chooses the unused entry if
* one exists. Otherwice deletes entries in round-robin fashion.
*/
INT8 arp_alloc (UINT8 type)
{
struct arp_entry *qstruct;
INT8 i;
static BYTE aenext = 1; /* Cache Manager */
INT16 found;
/* try to find free entry */
found=-1;
for( i=0; i<ARP_TSIZE; i++ ) {
if( arp_table[i].state == ARP_FREE ) {
found=i;
break;
}
}
if(found != (-1) ) {
qstruct = &arp_table[found];
qstruct->state = ARP_RESERVED;
qstruct->type = type;
return( (UINT8)found );
}
/* if no success, try ro find first temporary entry */
/* on round-robin fashion */
for( i=0; i<ARP_TSIZE; i++ ) {
if( arp_table[aenext].type == ARP_TEMP_IP) {
found = aenext;
break;
}
/* Move to next entry */
aenext = (aenext + 1);
if( aenext >= ARP_TSIZE )
aenext = 1;
}
/* Was there free or temporary entries? */
if( found == (-1) )
return(-1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -