📄 arp.c
字号:
//-----------------------------------------------------------------------------
// Net ARP.C
//
// This module handles ARP messages and ARP resolution and manages
// the ARP cache. Refer to RFC 826 and RFC 1122
//-----------------------------------------------------------------------------
#include "44b.h"
#include "44blib.h"
#include "def.h"
#include "option.h"
#include "ethernet.h"
#include "arp.h"
#include "string.h"
//#include "stdlib.h"
#include "stdio.h"
#include "lib.h"
extern struct WAIT waitq;
extern unsigned char my_hwaddr[];
extern unsigned char broadcast_hwaddr[];
extern unsigned long my_ipaddr;
extern unsigned long my_subnet;
extern unsigned long gateway_ipaddr;
extern unsigned char debug;
struct ARP_CACHE arp_cache[CACHESIZE];
unsigned char waiting_for_arp;
unsigned long arptemp1,arptemp2,arptemp3;
void init_arp(void)
{
memset(arp_cache, 0, sizeof(arp_cache));
memset(&waitq, 0, sizeof(waitq));
waiting_for_arp = FALSE;
}
//------------------------------------------------------------------------
// This is called every 60 seconds to age the ARP cache
// If an entry times out then it is deleted from the cache
// See "TCP/IP Illustrated, Volume 1" Sect 4.3
//------------------------------------------------------------------------
void age_arp_cache(void)
{
unsigned char i;
for (i=0; i < CACHESIZE; i++)
{
if ((arp_cache[i].ipaddr != 0) && (arp_cache[i].timer))
{
arp_cache[i].timer--;
if (arp_cache[i].timer == 0)
{
// Timed out so clear out cache entry
// Do not need to zero hwaddr
arp_cache[i].ipaddr = 0;
// if (debug) printf("ARP: Aged out a cache entry\n");
}
}
}
}
//------------------------------------------------------------------------
// This allocates memory for the entire outgoing message,
// including eth and ip headers, then builds an outgoing
// ARP response message
// See "TCP/IP Illustrated, Volume 1" Sect 4.4
//------------------------------------------------------------------------
void arp_send(unsigned char * hwaddr, unsigned long ipaddr, unsigned short msg_type)
{
unsigned char * outbuf;
struct ARP_HEADER *arp;
// Allocate memory for entire outgoing message including
// eth header. Always 42 bytes
outbuf = (unsigned char *)malloc(42);
if (outbuf == NULL)
{
// if (debug) printf("ARP: Oops, out of memory\r");
return;
}
// Allow 14 bytes for the ethernet header
arp = (struct ARP_HEADER *)(outbuf + 14);
arp->hardware_type = ntohs(DIX_ETHERNET);
arp->protocol_type = ntohs(IP_PACKET);
arp->hwaddr_len = 6;
arp->ipaddr_len = 4;
arp->message_type = ntohs(msg_type);
// My hardware address and IP addresses
memcpy(arp->source_hwaddr, my_hwaddr, 6);
arp->source_ipaddr = ntohl(my_ipaddr);
// Destination hwaddr and dest IP addr
if (msg_type == ARP_REQUEST) memset(arp->dest_hwaddr, 0, 6);
else memcpy(arp->dest_hwaddr, hwaddr, 6);
arp->dest_ipaddr = ntohl(ipaddr);
// If request then the message is a brodcast, if a response then
// send to specified hwaddr
// ARP payload size is always 28 bytes
if (msg_type == ARP_REQUEST) eth_send(outbuf, broadcast_hwaddr, ARP_PACKET, 28);
else eth_send(outbuf, hwaddr, ARP_PACKET, 28);
}
//------------------------------------------------------------------------
// This re-sends an ARP request if there was no response to
// the first one. It is called every 0.5 seconds. If there
// is no response after 2 re-tries, the datagram that IP was
// trying to send is deleted
//-----------------------------------------------------------------------
void arp_retransmit(void)
{
static unsigned char retries = 0;
if ((waiting_for_arp) && (waitq.timer))
{
waitq.timer--;
if (waitq.timer == 0)
{
retries++;
if (retries <= 2)
{
// if (debug) printf("ARP: Re-sending ARP broadcast\n");
arp_send(NULL, waitq.ipaddr, ARP_REQUEST);
waitq.timer = ARP_TIMEOUT;
}
else
{
// if (debug) printf("ARP: Gave up waiting for response\n");
waitq.timer = 0;
waiting_for_arp = 0;
free(waitq.buf);
}
}
}
}
//------------------------------------------------------------------------
// Find the ethernet hardware address for the given ip address
// If destination IP is on my subnet then we want the eth
// address of destination, otherwise we want eth addr of gateway.
// Look in ARP cache first. If not found there, send ARP request.
// Return pointer to the hardware address or NULL if not found
// See "TCP/IP Illustrated, Volume 1" Sect 4.5
//------------------------------------------------------------------------
unsigned char * arp_resolve(unsigned long dest_ipaddr)
{
unsigned char i;
// If destination IP is not on my subnet then we really want eth addr
// of gateway, not destination IP
if ((dest_ipaddr ^ my_ipaddr) & my_subnet)
{
if (gateway_ipaddr == 0)
{
// if (debug) printf("ARP: Error, gateway addr not set\n");
// Uart_Printf("ARP: Error, gateway addr not set\n");
return (NULL);
}
else dest_ipaddr = gateway_ipaddr;
Uart_Printf("ARP: the gateway addr= %x\n",gateway_ipaddr);
}
// See if IP addr of interest is in ARP cache
for (i=0; i < CACHESIZE; i++)
{
if (arp_cache[i].ipaddr == dest_ipaddr)
return (&arp_cache[i].hwaddr[0]);
}
// if (debug) printf("ARP: IP addr not found in cache\n");
// if (debug) printf("ARP: Sending an ARP broadcast\n");
// Not in cache so broadcast ARP request
arp_send(NULL, dest_ipaddr, ARP_REQUEST);
// Set a flag to indicate that an IP datagram is waiting
// to be sent
waiting_for_arp = TRUE;
// Null means that we have sent an ARP request
return (NULL);
}
//------------------------------------------------------------------------
// This handles incoming ARP messages
// See "TCP/IP Illustrated, Volume 1" Sect 4.4
// Todo: Resolve problem of trying to add to a full cache
//------------------------------------------------------------------------
void arp_rcve(unsigned char * inbuf)
{
unsigned char i, cached, oldest;
unsigned short minimum;
struct ARP_HEADER * arp;
arp = (struct ARP_HEADER *)(inbuf+14);
cached = FALSE;
// Print message
//arptemp=arp->hardware_type;
// Validate incoming frame
if ((ntohs(arp->hardware_type) != DIX_ETHERNET) ||
(ntohs(arp->protocol_type) != IP_PACKET)) return;
//Uart_Printf("\nARP: is on verirr\n");
// Search ARP cache for senders IP address
// If found, update entry and restart timer
for (i=0; i < CACHESIZE; i++)
{
if (arp_cache[i].ipaddr == ntohl(arp->source_ipaddr))
{
memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6);
arp_cache[i].timer = CACHETIME;
cached = TRUE;
// Uart_Printf("ARP: Cache entry updated\n");
break;
}
}
if (ntohl(arp->dest_ipaddr) != my_ipaddr) return;
// At this point we know the the frame is addressed to me
// If not already in cache then add entry and start timer
if (cached == FALSE)
{
// Find first blank space and add entry
// Blank entries are indicated by ip addr = 0
for (i=0; i < CACHESIZE; i++)
{
if (arp_cache[i].ipaddr == 0)
{
// arptemp1=arp->source_ipaddr;
arp_cache[i].ipaddr = ntohl(arp->source_ipaddr);
arptemp2=arp_cache[i].ipaddr;
memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6);
arp_cache[i].timer = CACHETIME;
// Uart_Printf("ARP: New cache entry added\n");
break;
}
}
// If no blank entries in arp cache then sort cache
// to find oldest entry and replace it
if (i == CACHESIZE)
{
// Oldest entry is the one with lowest timer value
minimum = 0xFFFF;
for (i=0; i < CACHESIZE; i++)
{
if (arp_cache[i].timer < minimum)
{
minimum = arp_cache[i].timer;
oldest = i;
}
}
// "oldest" is now index of oldest entry, so replace it
arp_cache[oldest].ipaddr = ntohl(arp->source_ipaddr);
memcpy(&arp_cache[oldest].hwaddr[0], &arp->source_hwaddr[0], 6);
arp_cache[oldest].timer = CACHETIME;
// if (debug) printf("ARP: Cache full, so replaced oldest\n");
}
}
// If we are waiting for an arp response and the arp response
// that just came in is addressed to me and is from the host
// we are waiting for, then send the message-in-waiting
// Uart_Printf("arp->message_type= %x\n",arp->message_type);
if (ntohs(arp->message_type) == ARP_RESPONSE)
{
// Uart_Printf("arp->message_type= %x\n",ntohs(arp->message_type));
if ((waiting_for_arp) && (waitq.ipaddr == ntohl(arp->source_ipaddr)))
{
waiting_for_arp = FALSE;
ip_send(waitq.buf, waitq.ipaddr, waitq.proto_id, waitq.len);
}
}
else if (ntohs(arp->message_type) == ARP_REQUEST)
{
// Send ARP response
// Uart_Printf("ARP: Sending response\n");
arp_send(arp->source_hwaddr, ntohl(arp->source_ipaddr), ARP_RESPONSE);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -