📄 m_arp.c
字号:
/*
* FILENAME: et_arp.c
*
* Copyright 2000 By InterNiche Technologies Inc. All rights reserved
*
* Ethernet (and similar media) arp code.
*
* MODULE: INET
*
* ROUTINES: et_send(), send_arp(),
* ROUTINES: find_oldest_arp(), make_arp_entry(), arpReply(), arprcv(),
* ROUTINES: send_via_arp(), arp_stats(),
*
* PORTABLE: yes
*/
#include "ipport.h"
#include "q.h"
#include "netbuf.h"
#include "net.h"
#include "ether.h"
#include "arp.h"
#include "ip.h"
#include "minip.h" /* (yaxon add) */
struct arptabent * arpcache; /* last ARP entry used */
static u_long cachetime; /* time we created arpcache entry */
int arp_ageout = 600; /* APR table refresh age, in seconds */
/* arp stats - In addition to MIB-2 */
unsigned arpReqsIn = 0; /* requests received */
unsigned arpReqsOut = 0; /* requests sent */
unsigned arpRepsIn = 0; /* replys received */
unsigned arpRepsOut = 0; /* replys sent */
struct arptabent arp_table[MAXARPS]; /* the actual table */
/* FUNCTION: et_send()
*
* et_send() - fill in outgoing ethernet-bound packet's ethernet
* header and send it. Header info is in arp entry passed and MIB
* info.
*
* PARAM1: PACKET pkt
* PARAM2: struct arptabent * tp
*
* RETURNS: Returns 0 if OK, or the usual ENP_ errors
*/
int
et_send(PACKET pkt, struct arptabent * tp)
{
struct ethhdr * ethhdr;
IFMIB etif = m_netp->n_mib; /* mib info for this ethernet interface */
tp->lasttime = cticks;
pkt->nb_prot -= ETHHDR_SIZE; /* prepare for prepending ethernet header */
pkt->nb_plen += ETHHDR_SIZE;
ethhdr = (struct ethhdr*)(pkt->nb_prot + ETHHDR_BIAS); /* prepare to prepend ethernet header */
if ((char*)ethhdr < pkt->nb_buff) /* sanity check pointer */
panic("et_send: prepend");
MEMCPY(ethhdr->e_dst, tp->t_phy_addr, 6); /* copy dest MAC address into packet */
MEMCPY(ethhdr->e_src, etif->ifPhysAddress, 6); /* MAC src */
ethhdr->e_type = ARPIP; /* MAC prototcol type, 0800 (IP) in net-endian */
#ifdef NP_DEBUG
if(m_netp->pkt_send == NULL)
{
panic("et_send")
}
#endif
return(m_netp->pkt_send(pkt)); /* send packet to media */
}
#define arpsize (ETHHDR_SIZE + sizeof(struct arp_hdr))
/* FUNCTION: send_arp()
*
* send_arp() - send an arp for outgoing ethernet packet pkt, which
* has no current arp table entry. This means making a partial entry
* and queuing the packet at the entry. Packet will be send when
* target IP host reply to the ARP we send herein. If no reply,
* timeout will eventually free packet.
*
*
* PARAM1: PACKET pkt
* PARAM2: ip_addr dest_ip
*
* RETURNS: Returns 0 if OK, or the usual ENP_ errors
*/
int
send_arp(PACKET pkt, ip_addr dest_ip)
{
struct arptabent * oldest;
struct ethhdr * ethhdr;
struct arp_hdr * arphdr;
IFMIB etif = m_netp->n_mib; /* mib info for this ethernet interface */
PACKET arppkt;
if(dest_ip == 0xFFFFFFFF) /* broadcast? */
{
/* get unused or oldest entry in table */
oldest = make_arp_entry(dest_ip, m_netp);
/* set MAC destination to ethernet broadcast (all FFs) */
MEMSET(oldest->t_phy_addr, 0xFF, 6);
return(et_send(pkt, oldest));
}
/* not broadcasting, so get a packet for an ARP request */
LOCK_NET_RESOURCE(FREEQ_RESID);
arppkt = pk_alloc(arpsize);
if (!arppkt)
{
pk_free(pkt);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
return ENP_RESOURCE;
}
UNLOCK_NET_RESOURCE(FREEQ_RESID);
arppkt->nb_prot = arppkt->nb_buff;
arppkt->nb_plen = arpsize;
arppkt->net = m_netp;
/* get unused or oldest entry in table */
oldest = make_arp_entry(dest_ip, m_netp);
oldest->pending = pkt; /* packet is "pended", not pk_free()d */
/* build arp request packet */
ethhdr = (struct ethhdr *)(arppkt->nb_buff + ETHHDR_BIAS); /* ethernet header at start of buffer */
arphdr = (struct arp_hdr *)(arppkt->nb_buff + ETHHDR_SIZE); /* arp header follows */
arphdr->ar_hd = ARPHW; /* net endian arp hardware type (ethernet) */
arphdr->ar_pro = ARPIP;
arphdr->ar_hln = 6;
arphdr->ar_pln = 4;
arphdr->ar_op = ARREQ;
arphdr->ar_tpa = dest_ip; /* target's IP address */
arphdr->ar_spa = m_netp->n_ipaddr; /* my IP address */
MEMCPY(arphdr->ar_sha, etif->ifPhysAddress, 6);
MEMSET(&(ethhdr->e_dst[0]), 0xFF, 6); /* destination to broadcast (all FFs) */
MEMCPY(ethhdr->e_src, etif->ifPhysAddress, 6);
ethhdr->e_type = ET_ARP; /* 0x0806 - ARP type on ethernet */
#ifdef NO_CC_PACKING /* move ARP fields to proper network boundaries */
{
struct arp_wire * arwp = (struct arp_wire *)arphdr;
MEMMOVE(&arwp->data[AR_SHA], arphdr->ar_sha, 6);
MEMMOVE(&arwp->data[AR_SPA], &arphdr->ar_spa, 4);
MEMMOVE(&arwp->data[AR_THA], arphdr->ar_tha, 6);
MEMMOVE(&arwp->data[AR_TPA], &arphdr->ar_tpa, 4);
}
#endif /* NO_CC_PACKING */
#ifdef NP_DEBUG
if(m_netp->pkt_send == NULL)
{
panic("send_arp")
}
#endif
/* send arp request */
m_netp->pkt_send(arppkt); /* driver should free arppkt later */
arpReqsOut++;
return ENP_SEND_PENDING;
}
/* FUNCTION: find_oldest_arp()
*
* Return LRU or first free entry in arp table - preperatory to
* making a new arp entry out of it. IP address passed is that of new
* entry so we can recycle previous entry for that IP if it exists.
*
* PARAM1: ip_addr dest_ip
*
* RETURNS: LRU or first free entry in arp table
*/
struct arptabent *
find_oldest_arp(ip_addr dest_ip)
{
struct arptabent * tp;
struct arptabent * oldest;
/* find lru (or free) entry, */
oldest = arp_table;
for (tp = arp_table; tp <= &arp_table[MAXARPS-1]; tp++)
{
if (tp->t_pro_addr == dest_ip) /* ip addr already has entry */
{
tp->lasttime = cticks;
return(tp);
}
if (!tp->t_pro_addr) /* entry is unused */
{
oldest = tp; /* use free entry as "oldest" */
/* need to keep scanning in case dest_ip already has an entry */
}
else if(oldest->lasttime > tp->lasttime)
{
oldest = tp; /* found an older (LRU) entry */
}
}
return oldest;
}
/* FUNCTION: make_arp_entry()
*
* make_arp_entry(ip_addr, NET) - find the first unused (or the
* oldest) arp table entry, and make a new entry for to prepare it
* for an arp reply. If the IP address already has an entry, the
* entry is returned with only the timestap modified.
*
* PARAM1: ip_addr dest_ip
* PARAM2: NET net
*
* RETURNS: Returns pointer to arp table entry selected.
*/
struct arptabent *
make_arp_entry(ip_addr dest_ip, NET net)
{
struct arptabent * oldest;
/* find usable (or existing) ARP table entry */
oldest = find_oldest_arp(dest_ip);
/* partially fill in arp entry */
oldest->createtime = cticks;
/* If recycling entry, don't leak packets which may be stuck here */
if ((oldest->pending) &&
(oldest->t_pro_addr != dest_ip)) /* don't clear pending if recycling */
{
LOCK_NET_RESOURCE(FREEQ_RESID);
pk_free(oldest->pending);
UNLOCK_NET_RESOURCE(FREEQ_RESID);
oldest->pending = NULL;
}
oldest->t_pro_addr = dest_ip;
oldest->net = net;
MEMSET(oldest->t_phy_addr, '\0', 6); /* clear mac address */
return oldest;
}
/* FUNCTION: arpReply()
*
* arpReply() - do arp reply to the passed arp request packet. packet
* must be freed (or reused) herein.
*
*
* PARAM1: PACKET pkt
*
* RETURNS: void
*/
void
arpReply(PACKET pkt)
{
PACKET outpkt;
struct arp_hdr * in;
struct arp_hdr * out;
struct ethhdr * ethout, * ethin;
LOCK_NET_RESOURCE(FREEQ_RESID);
outpkt = pk_alloc(sizeof(struct arp_hdr));
UNLOCK_NET_RESOURCE(FREEQ_RESID);
if (!outpkt)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -