1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
5.7 KiB

/*! \file arp.c \brief ARP Protocol Library. */
//*****************************************************************************
//
// File Name : 'arp.c'
// Title : ARP Protocol Library
// Author : Pascal Stang
// Created : 9/7/2004
// Revised : 7/3/2005
// Version : 0.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
//*****************************************************************************
#include "net.h"
#include "nic.h"
#include "arp.h"
#include "HardwareSerial.h"
#ifdef ARP_DEBUG_PRINT
#include "debug.h"
#include <avr/pgmspace.h>
#include "programStrings.h"
#include "HardwareSerial.h"
#endif
// global variables
/// Single ARP table entry/record
struct ArpEntry
{
uint32_t ipaddr; ///< remote-note IP address
struct netEthAddr ethaddr; ///< remote-node ethernet (hardware/mac) address
uint8_t time; ///< time to live (in ARP table); this is decremented by arpTimer()
};
struct ArpEntry ArpMyAddr; ///< my local interface information (IP and MAC address)
struct ArpEntry ArpTable[ARP_TABLE_SIZE]; ///< ARP table of matched IP<->MAC associations
void arpInit(void)
{
u08 i;
// initialize all ArpTable elements to unused
for(i=0; i<ARP_TABLE_SIZE; i++)
{
ArpTable[i].ipaddr = 0;
ArpTable[i].time = 0;
}
}
void arpSetAddress(struct netEthAddr* myeth, uint32_t myip)
{
// set local address record
ArpMyAddr.ethaddr = *myeth;
ArpMyAddr.ipaddr = myip;
}
void arpArpIn(unsigned int len, struct netEthArpHeader* packet)
{
#ifdef ARP_DEBUG
SPrint("Received ARP Request\r\n");
#if NET_DEBUG > 3
arpPrintHeader( &packet->arp );
#endif
#endif
// for now, we just reply to requests
// need to add ARP cache
if( (packet->arp.dipaddr == HTONL(ArpMyAddr.ipaddr)) &&
(packet->arp.opcode == htons(ARP_OPCODE_REQUEST)) )
{
// in ARP header
// copy sender's address info to dest. fields
packet->arp.dhwaddr = packet->arp.shwaddr;
packet->arp.dipaddr = packet->arp.sipaddr;
// fill in our information
packet->arp.shwaddr = ArpMyAddr.ethaddr;
packet->arp.sipaddr = HTONL(ArpMyAddr.ipaddr);
// change op to reply
packet->arp.opcode = htons(ARP_OPCODE_REPLY);
// in ethernet header
packet->eth.dest = packet->eth.src;
packet->eth.src = ArpMyAddr.ethaddr;
#ifdef ARP_DEBUG
SPrint("Sending ARP Reply\r\n");
#if NET_DEBUG > 3
arpPrintHeader( &packet->arp );
#endif
#endif
// send reply!
nicSend(len, (unsigned char*)packet);
}
}
void arpIpIn(struct netEthIpHeader* packet)
{
int8_t index;
// check if sender is already present in arp table
index = arpMatchIp(HTONL(packet->ip.srcipaddr));
if(index != -1)
{
// sender's IP address found, update ARP entry
ArpTable[index].ethaddr = packet->eth.src;
// and we're done
return;
}
// sender was not present in table,
// must add in empty/expired slot
for(index=0; index<ARP_TABLE_SIZE; index++)
{
if(!ArpTable[index].time)
{
// write entry
ArpTable[index].ethaddr = packet->eth.src;
ArpTable[index].ipaddr = HTONL(packet->ip.srcipaddr);
ArpTable[index].time = ARP_CACHE_TIME_TO_LIVE;
// and we're done
return;
}
}
// no space in table, we give up
}
void arpIpOut(struct netEthIpHeader* packet, uint32_t phyDstIp)
{
int index;
// check if destination is already present in arp table
// use the physical dstIp if it's provided, otherwise the dstIp in packet
if(phyDstIp)
index = arpMatchIp(phyDstIp);
else
index = arpMatchIp(HTONL(packet->ip.destipaddr));
// fill in ethernet info
if(index != -1)
{
// ARP entry present, fill eth address(es)
packet->eth.src = ArpMyAddr.ethaddr;
packet->eth.dest = ArpTable[index].ethaddr;
packet->eth.type = HTONS(ETHTYPE_IP);
}
else
{
// not in table, must send ARP request
packet->eth.src = ArpMyAddr.ethaddr;
// MUST CHANGE, but for now, send this one broadcast
packet->eth.dest.addr[0] = 0xFF;
packet->eth.dest.addr[1] = 0xFF;
packet->eth.dest.addr[2] = 0xFF;
packet->eth.dest.addr[3] = 0xFF;
packet->eth.dest.addr[4] = 0xFF;
packet->eth.dest.addr[5] = 0xFF;
packet->eth.type = HTONS(ETHTYPE_IP);
}
}
void arpTimer(void)
{
int index;
// this function meant to be called on a regular time interval
// decrement time-to-live for all entries
for(index=0; index<ARP_TABLE_SIZE; index++)
{
if(ArpTable[index].time)
ArpTable[index].time--;
}
}
int arpMatchIp(uint32_t ipaddr)
{
uint8_t i;
// check if IP address is present in arp table
for(i=0; i<ARP_TABLE_SIZE; i++)
{
if(ArpTable[i].ipaddr == ipaddr)
{
// IP address found
return i;
}
}
// no match
return -1;
}
#ifdef ARP_DEBUG_PRINT
void arpPrintHeader(struct netArpHeader* packet)
{
SPrint("ARP Packet:\r\n");
#if NET_DEBUG > 6
debugPrintHexTable(60, (unsigned char*)&packet);
#endif
// print operation type
SPrint("Operation : ");
if(packet->opcode == htons(ARP_OPCODE_REQUEST))
SPrint("REQUEST");
else if(packet->opcode == htons(ARP_OPCODE_REPLY))
SPrint("REPLY");
else
SPrint("UNKNOWN");
Serial.println();
// print source hardware address
SPrint("SrcHwAddr : "); netPrintEthAddr(&packet->shwaddr); Serial.println();
// print source protocol address
SPrint("SrcProtoAddr: "); netPrintIPAddr(HTONL(packet->sipaddr)); Serial.println();
// print target hardware address
SPrint("DstHwAddr : "); netPrintEthAddr(&packet->dhwaddr); Serial.println();
// print target protocol address
SPrint("DstProtoAddr: "); netPrintIPAddr(HTONL(packet->dipaddr)); Serial.println();
}
void arpPrintTable(void)
{
uint8_t i;
// print ARP table
SPrint("Time Eth Address IP Address\r\n");
SPrint("---------------------------------------\r\n");
for(i=0; i<ARP_TABLE_SIZE; i++)
{
Serial.print(ArpTable[i].time);
SPrint(" ");
netPrintEthAddr(&ArpTable[i].ethaddr);
SPrint(" ");
netPrintIPAddr(ArpTable[i].ipaddr);
Serial.println();
}
}
#endif