📄 arp.c
字号:
/*
* File: arp.c
* Purpose: Address Resolution Protocol routines.
*
* Notes:
*
* Modifications:
*/
#include "src/init/m5282evb.h"
#include "src/ethernet/nif.h"
#include "src/ethernet/tftp/arp.h"
#include "src/ethernet/tftp/ip.h"
#include "src/ethernet/tftp/timer.h"
/********************************************************************/
static uint8 *
arp_find_pair (ARP_INFO *arptab, uint16 protocol, uint8 *hwa, uint8 *pa)
{
/*
* This function searches through the ARP table for the
* specified <protocol,hwa> or <protocol,pa> address pair.
* If it is found, then a a pointer to the non-specified
* address is returned. Otherwise NULL is returned.
* If you pass in <protocol,pa> then you get <hwa> out.
* If you pass in <protocol,hwa> then you get <pa> out.
*/
int slot, i, match = FALSE;
uint8 *rvalue, old_ipl;
if (((hwa == 0) && (pa == 0)) || (arptab == 0))
return NULL;
/* Disable interrupts for now */
old_ipl = (uint8)asm_set_ipl(6);
rvalue = NULL;
/* check each protocol address for a match */
for (slot = 0; slot < arptab->tab_size; slot++)
{
if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) &&
(arptab->table[slot].protocol == protocol))
{
match = TRUE;
if (hwa != 0)
{
/* Check the Hardware Address field */
rvalue = &arptab->table[slot].pa[0];
for (i = 0; i < arptab->table[slot].hwa_size; i++)
{
if (arptab->table[slot].hwa[i] != hwa[i])
{
match = FALSE;
break;
}
}
}
else
{
/* Check the Protocol Address field */
rvalue = &arptab->table[slot].hwa[0];
for (i = 0; i < arptab->table[slot].pa_size; i++)
{
if (arptab->table[slot].pa[i] != pa[i])
{
match = FALSE;
break;
}
}
}
if (match)
{
break;
}
}
}
/* Allow interrupts again */
asm_set_ipl(old_ipl);
if (match)
return rvalue;
else
return NULL;
}
/********************************************************************/
void
arp_merge ( ARP_INFO *arptab,
uint16 protocol,
int hwa_size, uint8 *hwa,
int pa_size, uint8 *pa,
int longevity)
{
/*
* This function merges an entry into the ARP table. If
* either piece is NULL, the function exits, otherwise
* the entry is merged or added, provided there is space.
*/
int i, slot;
uint8 *ta;
if ((hwa == NULL) || (pa == NULL) || (arptab == NULL) ||
((longevity != ARP_ENTRY_TEMP) &&
(longevity != ARP_ENTRY_PERM)))
{
return;
}
/* First search ARP table for existing entry */
if ((ta = arp_find_pair(arptab,protocol,NULL,pa)) != 0)
{
/* Update hardware address */
for (i = 0; i < hwa_size; i++)
ta[i] = hwa[i];
return;
}
/* Next try to find an empty slot */
slot = -1;
for (i = 0; i < MAX_ARP_ENTRY; i++)
{
if (arptab->table[i].longevity == ARP_ENTRY_EMPTY)
{
slot = i;
break;
}
}
/* if no empty slot was found, pick a temp slot */
if (slot == -1)
{
for (i = 0; i < MAX_ARP_ENTRY; i++)
{
if (arptab->table[i].longevity == ARP_ENTRY_TEMP)
{
slot = i;
break;
}
}
}
/* if after all this, still no slot found, add in last slot */
if (slot == -1)
slot = (MAX_ARP_ENTRY -1);
/* add the entry into the slot */
arptab->table[slot].protocol = protocol;
arptab->table[slot].hwa_size = (uint8) hwa_size;
for (i = 0; i < hwa_size; i++)
arptab->table[slot].hwa[i] = hwa[i];
arptab->table[slot].pa_size = (uint8) pa_size;
for (i = 0; i < pa_size; i++)
arptab->table[slot].pa[i] = pa[i];
arptab->table[slot].longevity = longevity;
}
/********************************************************************/
void
arp_remove (ARP_INFO *arptab, uint16 protocol, uint8 *hwa, uint8 *pa)
{
/*
* This function removes an entry from the ARP table. The
* ARP table is searched according to the non-NULL address
* that is provided.
*/
int slot, i, match;
if (((hwa == 0) && (pa == 0)) || (arptab == 0))
return;
/* check each hardware adress for a match */
for (slot = 0; slot < arptab->tab_size; slot++)
{
if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) &&
(arptab->table[slot].protocol == protocol))
{
match = TRUE;
if (hwa != 0)
{
/* Check Hardware Address field */
for (i = 0; i < arptab->table[slot].hwa_size; i++)
{
if (arptab->table[slot].hwa[i] != hwa[i])
{
match = FALSE;
break;
}
}
}
else
{
/* Check Protocol Address field */
for (i = 0; i < arptab->table[slot].pa_size; i++)
{
if (arptab->table[slot].pa[i] != pa[i])
{
match = FALSE;
break;
}
}
}
if (match)
{
for (i = 0; i < arptab->table[slot].hwa_size; i++)
arptab->table[slot].hwa[i] = 0;
for (i = 0; i < arptab->table[slot].pa_size; i++)
arptab->table[slot].pa[i] = 0;
arptab->table[slot].longevity = ARP_ENTRY_EMPTY;
break;
}
}
}
}
/********************************************************************/
void
arp_request (NIF *nif, uint8 *pa, NBUF **ppNbuf)
{
/*
* This function broadcasts an ARP request for the
* protocol address pa. Written only for Ethernet.
*
* This routine accesses shared data!
* Interrupts should be disabled by calling funtion
*/
uint8 *addr;
NBUF *pNbuf;
arp_frame_hdr *arpframe;
int i;
pNbuf = nif->tx_alloc();
/* Make sure I grabbed a valid Tx buffer */
if (pNbuf == NULL)
{
#if defined(DEBUG_PRINT)
printf("ARP: arp_request couldn't allocate Tx buffer\n");
#endif
return;
}
arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET];
/* Build the ARP request packet */
arpframe->ar_hrd = ETHERNET;
arpframe->ar_pro = FRAME_IP;
arpframe->ar_hln = 6;
arpframe->ar_pln = 4;
arpframe->opcode = ARP_REQUEST;
addr = &nif->hwa[0];
for (i = 0; i < 6; i++)
arpframe->ar_sha[i] = addr[i];
addr = ip_get_myip(nif_get_protocol_info(nif,FRAME_IP));
for (i = 0; i < 4; i++)
arpframe->ar_spa[i] = addr[i];
for (i = 0; i < 6; i++)
arpframe->ar_tha[i] = 0x00;
for (i = 0; i < 4; i++)
arpframe->ar_tpa[i] = pa[i];
/* Save the length of my packet in the buffer structure */
pNbuf->length = 28;
/* Swap my buffer descriptor with the one IP is trying to send
* so I come first in the buffer ring */
nbuf_tx_swap(&pNbuf, ppNbuf);
nif->send( nif,
nif->broadcast,
nif->hwa,
FRAME_ARP,
pNbuf);
}
/********************************************************************/
static int
arp_resolve_pa (NIF *nif, uint16 protocol, uint8 *pa, uint8 **ha)
{
/*
* This function accepts a pointer to a protocol address and
* searches the ARP table for a hardware address match. If no
* no match found, FALSE is returned.
*/
ARP_INFO *arptab;
if ((pa == NULL) || (nif == NULL) || (protocol == 0))
return 0;
arptab = nif_get_protocol_info (nif,FRAME_ARP);
*ha = arp_find_pair(arptab,protocol,0,pa);
if (*ha == NULL)
{
/* do ARP request, still not guaranteed to find it! */
return 0;
}
/* else */
return 1;
}
/********************************************************************/
uint8 *
arp_resolve (NIF *nif, uint16 protocol, uint8 *pa, NBUF **ppNbuf)
{
int i;
uint8 *hwa;
/* First see if it is in table already */
if (arp_resolve_pa (nif, protocol, pa, &hwa))
return hwa;
/* Not in table, try to obtain it */
for (i = 0; i < 3; i++)
{
arp_request (nif, pa, ppNbuf);
/* Enable interrupts so we can get a packet */
asm_set_ipl(0);
timer_set_secs(TIMER_NETWORK, ARP_TIMEOUT);
while (timer_get_reference(TIMER_NETWORK))
{
if (arp_resolve_pa (nif, protocol, pa, &hwa))
{
/* Disable interrupts */
asm_set_ipl(6);
return hwa;
}
}
/* Disable interrupts */
asm_set_ipl(6);
}
return NULL;
}
/********************************************************************/
void
arp_init (ARP_INFO *arptab)
{
int slot, i;
arptab->tab_size = MAX_ARP_ENTRY;
for (slot = 0; slot < arptab->tab_size; slot++)
{
for (i = 0; i < MAX_HWA_SIZE; i++)
arptab->table[slot].hwa[i] = 0;
for (i = 0; i < MAX_PA_SIZE; i++)
arptab->table[slot].pa[i] = 0;
arptab->table[slot].longevity = ARP_ENTRY_EMPTY;
arptab->table[slot].hwa_size = 0;
arptab->table[slot].pa_size = 0;
}
}
/********************************************************************/
void
arp_handler (NIF *nif, NBUF *pRx_nbuf)
{
/* ARP protocol handler */
uint8 *addr;
ARP_INFO *arptab;
NBUF *pTx_nbuf;
int longevity;
arp_frame_hdr *rx_arpframe, *tx_arpframe;
arptab = nif_get_protocol_info (nif, FRAME_ARP);
rx_arpframe = (arp_frame_hdr *)&pRx_nbuf->data[ARP_HDR_OFFSET];
/* Check for appropriate ARP packet */
if ( (pRx_nbuf->length < 28)
|| (rx_arpframe->ar_hrd != ETHERNET)
|| (rx_arpframe->ar_hln != 6)
|| (rx_arpframe->ar_pro != FRAME_IP)
|| (rx_arpframe->ar_pln != 4))
return;
/* Check to see if addressed to me */
addr = ip_get_myip(nif_get_protocol_info(nif,FRAME_IP));
if ((rx_arpframe->ar_tpa[0] == addr[0]) &&
(rx_arpframe->ar_tpa[1] == addr[1]) &&
(rx_arpframe->ar_tpa[2] == addr[2]) &&
(rx_arpframe->ar_tpa[3] == addr[3]) )
{
longevity = ARP_ENTRY_PERM;
}
else
longevity = ARP_ENTRY_TEMP;
/* Add ARP info into table. */
arp_merge ( arptab,
rx_arpframe->ar_pro,
rx_arpframe->ar_hln,
&rx_arpframe->ar_sha[0],
rx_arpframe->ar_pln,
&rx_arpframe->ar_spa[0],
longevity);
switch (rx_arpframe->opcode)
{
case ARP_REQUEST:
/* Check to see if request is of me! */
if ((rx_arpframe->ar_tpa[0] == addr[0]) &&
(rx_arpframe->ar_tpa[1] == addr[1]) &&
(rx_arpframe->ar_tpa[2] == addr[2]) &&
(rx_arpframe->ar_tpa[3] == addr[3]) )
{
/* Allocate new TX buffer */
pTx_nbuf = nif->tx_alloc();
if (pTx_nbuf == NULL)
{
#if defined(DEBUG_PRINT)
printf("ARP: arp_handler couldn't allocate Tx buffer\n");
#endif
/* Re-enable interrupts */
asm_set_ipl(0);
return;
}
tx_arpframe = (arp_frame_hdr *)&pTx_nbuf->data[ARP_HDR_OFFSET];
/* Build new ARP frame from old one */
tx_arpframe->ar_hrd = ETHERNET;
tx_arpframe->ar_pro = FRAME_IP;
tx_arpframe->ar_hln = 6;
tx_arpframe->ar_pln = 4;
tx_arpframe->opcode = ARP_REPLY;
tx_arpframe->ar_tha[0] = rx_arpframe->ar_sha[0];
tx_arpframe->ar_tha[1] = rx_arpframe->ar_sha[1];
tx_arpframe->ar_tha[2] = rx_arpframe->ar_sha[2];
tx_arpframe->ar_tha[3] = rx_arpframe->ar_sha[3];
tx_arpframe->ar_tha[4] = rx_arpframe->ar_sha[4];
tx_arpframe->ar_tha[5] = rx_arpframe->ar_sha[5];
tx_arpframe->ar_tpa[0] = rx_arpframe->ar_spa[0];
tx_arpframe->ar_tpa[1] = rx_arpframe->ar_spa[1];
tx_arpframe->ar_tpa[2] = rx_arpframe->ar_spa[2];
tx_arpframe->ar_tpa[3] = rx_arpframe->ar_spa[3];
/* now copy in the new information */
addr = &nif->hwa[0];
tx_arpframe->ar_sha[0] = addr[0];
tx_arpframe->ar_sha[1] = addr[1];
tx_arpframe->ar_sha[2] = addr[2];
tx_arpframe->ar_sha[3] = addr[3];
tx_arpframe->ar_sha[4] = addr[4];
tx_arpframe->ar_sha[5] = addr[5];
addr = ip_get_myip(nif_get_protocol_info(nif,FRAME_IP));
tx_arpframe->ar_spa[0] = addr[0];
tx_arpframe->ar_spa[1] = addr[1];
tx_arpframe->ar_spa[2] = addr[2];
tx_arpframe->ar_spa[3] = addr[3];
/* Save the length of my packet in the buffer structure */
pTx_nbuf->length = 28;
nif->send( nif,
&tx_arpframe->ar_tha[0],
&tx_arpframe->ar_sha[0],
FRAME_ARP,
pTx_nbuf);
}
break;
case ARP_REPLY:
default:
break;
}
return;
}
/********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -