📄 arp.c
字号:
//-----------------------------------------------------------------------------
// Copyright (c) 2002 Jim Brady
// Do not use commercially without author's permission
// Last revised August 2002
// Net ARP.C
//
// This module handles ARP messages and ARP resolution and manages
// the ARP cache. Refer to RFC 826 and RFC 1122
//-----------------------------------------------------------------------------
//#include "stdio.h"
#include "stdlib.h"
#include "net.h"
#include "eth.h"
#include "serial.h"
#include "ip.h"
#include "arp.h"
#include "utils.h"
extern WAIT wait;
extern UCHAR my_hwaddr[];
extern UCHAR broadcast_hwaddr[];
extern ulong my_ipaddr;
extern ulong my_subnet;
extern ulong gateway_ipaddr;
extern UCHAR debug;
ARP_CACHE arp_cache[CACHESIZE];
UCHAR waiting_for_arp;
void init_arp(void)
{
memset(arp_cache, 0, sizeof(arp_cache));
memset(&wait, 0, sizeof(wait));
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
//------------------------------------------------------------------------
//每隔60 s刷新一次ARP表. 超过60s未用的记录删掉.
void age_arp_cache(void)
{
UCHAR i;
for (i=0; i < CACHESIZE; i++)
{ //如果ARP cahce表的某一记录的ipaddr和timer不为0,此记录的timer减一.如果减一等于0, 此记录丢弃.
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) serial_send("ARP: Aged out a cache entry\r");
}
}
}
}
//------------------------------------------------------------------------
// 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
//------------------------------------------------------------------------
//arp_send(arp->source_hwaddr, arp->source_ipaddr, ARP_RESPONSE);
// UCHAR * hwaddr, 本端硬件地址;
// ulong ipaddr, 对端IP地址;
// UCHAR msg_type, 本端ARP类型为: ARP请求还是ARP应答
void arp_send(UCHAR * hwaddr, ulong ipaddr, UCHAR msg_type)
{
UCHAR * outbuf;
ARP_HEADER * arp;
// Allocate memory for entire outgoing message including
// eth header. Always 42 bytes
// outbuf = (UCHAR *)malloc(42);
outbuf = TX_BUFF;
if (outbuf == NULL)
{
// if (debug) serial_send("ARP: Oops, out of memory\r");
return;
}
// Allow 14 bytes for the ethernet header
arp = (ARP_HEADER *)(outbuf + 14); //定位ARP头
arp->hardware_type = DIX_ETHERNET; //硬件地址类型: DIX_DIX_ETHERNET
arp->protocol_type = IP_PACKET; //上层协议类型: IP_PACKET
arp->hwaddr_len = 6; //硬件地址长度: 6
arp->ipaddr_len = 4; //上层协议长度: 6
arp->message_type = (uint)msg_type; //ARP类型: 请求还是应答
// My hardware address and IP addresses
memcpy((char *)arp->source_hwaddr, my_hwaddr, 6);
arp->source_ipaddr = my_ipaddr;
// Destination hwaddr and dest IP addr
if (msg_type == ARP_REQUEST) //如果是ARP请求,向所有主机(EtherADDR = 0)查询指定IP地址的对应硬件地址(取0);
memset((char *)arp->dest_hwaddr, 0, 6);
else
memcpy((char *)arp->dest_hwaddr, hwaddr, 6);
arp->dest_ipaddr = ipaddr;
#ifdef __LITTLEENDIAN__
arp->hardware_type = ntohs(arp->hardware_type);
arp->protocol_type = ntohs(arp->protocol_type);
arp->message_type = ntohs(arp->message_type);
arp->source_ipaddr = ntohl(arp->source_ipaddr);
arp->dest_ipaddr = ntohl(arp->dest_ipaddr);
#endif
// 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) //如果是ARP请求,向所有主机(EtherADDR = 0)查询指定IP地址的对应硬件地址(取0)
eth_send(outbuf, broadcast_hwaddr, ARP_PACKET, 28);
else
eth_send(outbuf, hwaddr, ARP_PACKET, 28);
#ifdef __LITTLEENDIAN__
free(outbuf);
#endif
}
//------------------------------------------------------------------------
// 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()
{
static UCHAR retries = 0;
if ((waiting_for_arp) && (wait.timer))
{
wait.timer--;
if (wait.timer == 0)
{
retries++;
if (retries <= 2)
{
// //if (debug) serial_send("ARP: Re-sending ARP broadcast\r");
arp_send(NULL, wait.ipaddr, ARP_REQUEST);
wait.timer = ARP_TIMEOUT;
}
else
{
// //if (debug) serial_send("ARP: Gave up waiting for response\r");
wait.timer = 0;
waiting_for_arp = 0;
free(wait.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(ulong dest_ipaddr)
{
UCHAR i;
// If destination IP is not on my subnet then we really want eth addr
// of gateway, not destination IP如果目的ip地址跟本机ip地址不是一个子网,就用网关地址
if ((dest_ipaddr ^ my_ipaddr) & my_subnet)
{
if (gateway_ipaddr == 0)
{
// //if (debug) serial_send("ARP: Error, gateway addr not set\r");
return (NULL);
}
else dest_ipaddr = 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) //在cache里找到与dest_ipaddr一致的选项,取选项中对应的硬件地址返回;
return (&arp_cache[i].hwaddr[0]);
}
//if (debug) serial_send("ARP: IP addr not found in cache\r");
//if (debug) serial_send("ARP: Sending an ARP broadcast\r");
// 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(UCHAR * inbuf)
{
UCHAR i, cached, oldest;
uint minimum;
ARP_HEADER * arp;
arp = (ARP_HEADER *)(inbuf + 14);
cached = FALSE;
#ifdef __LITTLEENDIAN__
arp->message_type = ntohs(arp->message_type);
arp->hardware_type = ntohs(arp->hardware_type);
arp->protocol_type = ntohs(arp->protocol_type);
arp->source_ipaddr = ntohl(arp->source_ipaddr);
arp->dest_ipaddr = ntohl(arp->dest_ipaddr);
#endif
// Print message
if (debug)
{
// if (arp->message_type == ARP_REQUEST)
// serial_send("ARP: Request rcvd\n");
// else serial_send("ARP: Response rcvd\n");
}
// Validate incoming frame
//非法ARP帧丢弃
if ((arp->hardware_type != DIX_ETHERNET) ||
(arp->protocol_type != IP_PACKET))
return;
// Search ARP cache for senders IP address
// If found, update entry and restart timer
//如果收到ARP报文的源协议IP地址在ARP CACHE表中,根据此报文的源硬件地址刷新cache表相同IP地址选项的硬件地址
for (i=0; i < CACHESIZE; i++)
{
if (arp_cache[i].ipaddr == arp->source_ipaddr)
{
memcpy((char*)&arp_cache[i].hwaddr[0], (char*)&arp->source_hwaddr[0], 6);
arp_cache[i].timer = CACHETIME;
cached = TRUE;
// if (debug) serial_send("ARP: Cache entry updated\r\n");
break;
}
}
// printf("%02x-%02x-%02x-%02x-%02x-%02x==souceip=%x---destip=%X\n", arp->source_hwaddr[0], arp->source_hwaddr[1], arp->source_hwaddr[2], arp->source_hwaddr[3], arp->source_hwaddr[4], arp->source_hwaddr[5], arp->source_ipaddr, arp->dest_ipaddr);
//如果ARP包不是送往本机(目的地址非本机),丢弃
if (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
//如果cache表没有收到ARP报文的选项
if (cached == FALSE)
{
// Find first blank space and add entry
// Blank entries are indicated by ip addr = 0
for (i=0; i < CACHESIZE; i++)
{
//找到cache表第一个空选项, 把收到ARP报文相应源协议IP地址和硬件地址插入;
if (arp_cache[i].ipaddr == 0)
{
arp_cache[i].ipaddr = arp->source_ipaddr;
memcpy((char*)&arp_cache[i].hwaddr[0], (char*)&arp->source_hwaddr[0], 6);
arp_cache[i].timer = CACHETIME;
//if (debug) serial_send("ARP: New cache entry added\r");
break;
}
}
// If no blank entries in arp cache then sort cache
// to find oldest entry and replace it
//如果cache表没有多余选项,拿最老的选项替换
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 = arp->source_ipaddr;
memcpy((char*)&arp_cache[oldest].hwaddr[0], (char*)&arp->source_hwaddr[0], 6);
arp_cache[oldest].timer = CACHETIME;
// if (debug) serial_send("ARP: Cache full, so replaced oldest\r\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
if (arp->message_type == ARP_RESPONSE)
{
if ((waiting_for_arp) && (wait.ipaddr == arp->source_ipaddr))
{
waiting_for_arp = FALSE;
//收到的ARP应答包含协议地址与等待中的IP地址一致,向此等待地址和等待端口发送以前的消息;
ip_send(wait.buf, wait.ipaddr, wait.proto_id, wait.len);
}
}
else if (arp->message_type == ARP_REQUEST) //对于ARP请求
{
// Send ARP response
//if (debug) serial_send("ARP: Sending response\r");
//返回包括本端协议(IP)地址和硬件(MAC)地址的应答
arp_send((UCHAR *)arp->source_hwaddr, arp->source_ipaddr, ARP_RESPONSE);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -