📄 arp.c
字号:
if (result != EINTR)
ip_warning((
"arp.c: read error on port %d: error %d\n",
fd, result ));
return NW_OK;
}
port->ap_flags &= ~APF_RARP_RD_IP;
if (port->ap_flags & APF_INADDR_SET)
ipaddr_set(port);
else if (port->ap_flags & APF_RARP_RD_SP)
rarp_read_setup(port);
return NW_OK;
}
assert (!offset);
/* Warning: the above assertion is illegal; puts and gets of
data can be brokenup in any piece the server likes. However
we assume that the server is eth.c and it transfers only
whole packets. */
data= bf_packIffLess(data, sizeof(rarp46_t));
rarp= (rarp46_t *)ptr2acc_data(data);
if ((data->acc_length >= sizeof(rarp46_t)) &&
(rarp->a46_hdr == htons(ARP_ETHERNET)) &&
(rarp->a46_pro == htons(ETH_IP_PROTO)) &&
(rarp->a46_hln == 6) &&
(rarp->a46_pln == 4) &&
(rarp->a46_op == htons(RARP_REPLY)) &&
(rarp->a46_tha.ea_addr[5] ==
port->ap_ethaddr.ea_addr[5]) &&
(rarp->a46_tha.ea_addr[4] ==
port->ap_ethaddr.ea_addr[4]) &&
(rarp->a46_tha.ea_addr[3] ==
port->ap_ethaddr.ea_addr[3]) &&
(rarp->a46_tha.ea_addr[2] ==
port->ap_ethaddr.ea_addr[2]) &&
(rarp->a46_tha.ea_addr[1] ==
port->ap_ethaddr.ea_addr[1]) &&
(rarp->a46_tha.ea_addr[0] ==
port->ap_ethaddr.ea_addr[0]) &&
!(port->ap_flags & APF_INADDR_SET))
{
memcpy (&port->ap_ipaddr, rarp->a46_tpa,
sizeof(ipaddr_t));
port->ap_flags |= APF_INADDR_SET;
#if DEBUG & 256
{ unsigned char *a; where(); a=(unsigned char *)&port->ap_ipaddr;
printf("arp.c: got ip address: %d.%d.%d.%d\n",
a[0], a[1], a[2], a[3]); }
#endif
}
bf_afree(data);
return NW_OK;
}
switch (port->ap_state & APS_STATMASK)
{
case APS_GETADDR:
if (!data)
{
result= (int)offset;
if (result<0)
{
port->ap_state= (port->ap_state &
~(APS_STATMASK|APS_SUSPEND))|
APS_ERROR;
break;
}
if (port->ap_state & APS_SUSPEND)
arp_main(port);
return NW_OK;
}
compare (bf_bufsize(data), ==, sizeof(*ethstat));
data= bf_packIffLess(data, sizeof(*ethstat));
compare (data->acc_length, ==, sizeof(*ethstat));
ethstat= (struct nwio_ethstat *)ptr2acc_data(data);
port->ap_ethaddr= ethstat->nwes_addr;
bf_afree(data);
return NW_OK;
default:
printf("arp_putdata(%d, 0x%d, 0x%lx) called but ap_state=0x%x\n",
fd, offset, (unsigned long)data, port->ap_state);
break;
}
return EGENERIC;
}
PRIVATE void rarp_timeout (fd, timer)
int fd;
timer_t *timer;
{
arp_port_t *port;
#if DEBUG & 256
{ where(); printf("in rarp_timeout()\n"); }
#endif
port= &arp_port_table[fd];
assert (timer == &port->ap_timer);
arp_main(port);
}
PRIVATE void ipaddr_set (port)
arp_port_t *port;
{
if (port->ap_flags & APF_RARPREQ)
{
port->ap_flags &= ~APF_RARPREQ;
(*port->ap_rarp_func)(port->ap_rarp_ref, port->ap_ipaddr);
}
if (port->ap_state & APS_RARPWAIT)
{
clck_untimer(&port->ap_timer);
port->ap_state= (port->ap_state &
~(APS_STATMASK|APS_SUSPEND)) | APS_ARPSTART;
arp_main(port);
}
}
PRIVATE void setup_read(port)
arp_port_t *port;
{
int result;
while (!(port->ap_flags & APF_ARP_RD_IP))
{
port->ap_flags |= APF_ARP_RD_IP;
result= eth_read (port->ap_eth_fd, ETH_MAX_PACK_SIZE);
if (result == NW_SUSPEND)
port->ap_flags |= APF_ARP_RD_SP;
if (result<0)
{
#if DEBUG
if (result != NW_SUSPEND)
{ where(); printf("arp.c: eth_read(..,%d)=%d\n", ETH_MAX_PACK_SIZE, result); }
#endif
return;
}
}
}
PRIVATE void setup_write(port)
arp_port_t *port;
{
int i, result;
while (port->ap_flags & APF_MORE2WRITE)
{
if (port->ap_flags & APF_CLIENTWRITE)
{
port->ap_flags &= ~APF_CLIENTWRITE;
port->ap_write_ipaddr= port->ap_req_ipaddr;
port->ap_write_code= ARP_REQUEST;
clck_timer(&port->ap_timer, get_time() + ARP_TIMEOUT,
arp_timeout, port-arp_port_table);
}
else
{
arp_cache_t *cache;
cache= arp_cache;
for (i=0; i<ARP_CACHE_NR; i++, cache++)
if ((cache->ac_flags & ACF_NETREQ) &&
cache->ac_eth_port ==
port->ap_eth_port)
{
cache->ac_flags &= ~ACF_NETREQ;
port->ap_write_ethaddr= cache->
ac_ethaddr;
port->ap_write_ipaddr= cache->
ac_ipaddr;
port->ap_write_code= ARP_REPLY;
break;
}
if (i>=ARP_CACHE_NR)
{
port->ap_flags &= ~APF_MORE2WRITE;
break;
}
}
port->ap_flags= (port->ap_flags & ~APF_ARP_WR_SP) |
APF_ARP_WR_IP;
#if DEBUG & 256
{ where(); printf("doing eth_write\n"); }
#endif
result= eth_write(port->ap_eth_fd, sizeof(arp46_t));
if (result == NW_SUSPEND)
port->ap_flags |= APF_ARP_WR_SP;
if (result<0)
{
#if DEBUG
if (result != NW_SUSPEND)
{ where(); printf("arp.c: eth_write(..,%d)=%d\n", sizeof(rarp46_t), result); }
#endif
return;
}
}
}
PRIVATE void process_arp_req (port, data)
arp_port_t *port;
acc_t *data;
{
arp46_t *arp;
arp_cache_t *prim, *sec;
int level;
time_t curr_tim;
ipaddr_t spa, tpa;
#if DEBUG & 256
{ where(); printf("process_arp_req(...)\n"); }
#endif
#if DEBUG & 256
{ where(); print_arp_cache(); }
#endif
arp= (arp46_t *)ptr2acc_data(data);
memcpy(&spa, arp->a46_spa, sizeof(ipaddr_t));
memcpy(&tpa, arp->a46_tpa, sizeof(ipaddr_t));
#if DEBUG & 256
{
if (arp->a46_hdr == htons(ARP_ETHERNET))
{ where(); printf("arp.c: a46_hdr OK\n"); }
if (arp->a46_hln == 6)
{ where(); printf("arp.c: a46_hln OK\n"); }
if (arp->a46_pro == htons(ETH_IP_PROTO))
{ where(); printf("arp.c: a46_pro OK\n"); }
if (arp->a46_pln == 4)
{ where(); printf("arp.c: a46_pln OK\n"); }
}
#endif
if (arp->a46_hdr != htons(ARP_ETHERNET) ||
arp->a46_hln != 6 ||
arp->a46_pro != htons(ETH_IP_PROTO) ||
arp->a46_pln != 4)
return;
#if DEBUG & 256
{ where(); printf("arp.c: a46_tpa= 0x%lx, ap_ipaddr= 0x%lx\n",
arp->a46_tpa, port->ap_ipaddr); }
#endif
if ((port->ap_flags & APF_CLIENTREQ) && (spa == port->ap_req_ipaddr))
level= ARP_TYPE3;
else if (arp->a46_op == htons(ARP_REQUEST) && (tpa ==
port->ap_ipaddr))
level= ARP_TYPE2;
else
level= ARP_TYPE1;
#if DEBUG & 256
{ where(); printf("arp.c: level= %d\n", level); }
#endif
prim= find_cache_ent(port->ap_eth_port, spa, level, &sec);
if (!prim)
{
prim= sec;
prim->ac_flags= ACF_EMPTY;
prim->ac_ipaddr= spa;
prim->ac_eth_port= port->ap_eth_port;
}
else if (prim->ac_type < level)
{
sec->ac_type= prim->ac_type;
prim->ac_type= level;
}
prim->ac_ethaddr= arp->a46_sha;
curr_tim= get_time();
prim->ac_expire= curr_tim+ ARP_EXP_TIME;
if (curr_tim > prim->ac_lastuse)
prim->ac_lastuse= curr_tim;
prim->ac_flags &= ~ACF_NOTRCH;
if (level== ARP_TYPE2)
{
prim->ac_flags |= ACF_NETREQ;
port->ap_flags |= APF_MORE2WRITE;
if (!(port->ap_flags & APF_ARP_WR_IP))
setup_write(port);
} else if (level== ARP_TYPE3)
{
prim->ac_lastuse= curr_tim + ARP_INUSE_OFFSET;
client_reply(port, &arp->a46_sha);
}
#if DEBUG & 256
{ where(); print_arp_cache(); }
#endif
}
PRIVATE void client_reply (port, ethaddr)
arp_port_t *port;
ether_addr_t *ethaddr;
{
port->ap_flags &= ~(APF_CLIENTREQ|APF_CLIENTWRITE);
clck_untimer(&port->ap_timer);
(*port->ap_req_func)(port->ap_req_ref, ethaddr);
}
PRIVATE arp_cache_t *find_cache_ent (eth_port, ipaddr, level, new_ent)
int eth_port;
ipaddr_t ipaddr;
int level;
arp_cache_t **new_ent;
{
arp_cache_t *cache, *prim, *sec;
int i;
cache= arp_cache;
prim= 0;
sec= 0;
for (i=0; i<ARP_CACHE_NR; i++, cache++)
{
if (cache->ac_eth_port == eth_port &&
cache->ac_ipaddr == ipaddr)
prim= cache;
if (cache->ac_type == level && (!sec || cache->ac_lastuse <
sec->ac_lastuse))
sec= cache;
}
assert(sec);
*new_ent= sec;
return prim;
}
PRIVATE void rarp_read_setup (port)
arp_port_t *port;
{
int result;
while (!(port->ap_flags & (APF_RARP_RD_IP|APF_INADDR_SET)))
{
port->ap_flags= (port->ap_flags & ~ APF_RARP_RD_SP) |
APF_RARP_RD_IP;
result= eth_read (port->ap_eth_fd, ETH_MAX_PACK_SIZE);
if (result == NW_SUSPEND)
port->ap_flags |= APF_RARP_RD_SP;
if (result<0)
{
#if DEBUG
if (result != NW_SUSPEND)
{ where(); printf("arp.c: eth_read(..,%d)=%d\n", ETH_MAX_PACK_SIZE, result); }
#endif
return;
}
if ((port->ap_state & APS_STATMASK) != APS_RARPPROTO)
return;
}
}
PUBLIC int rarp_req(eth_port, ref, func)
int eth_port;
int ref;
rarp_func_t func;
{
arp_port_t *port;
int i;
port= arp_port_table;
for (i=0; i<ARP_PORT_NR; i++, port++)
if (port->ap_eth_port == eth_port)
break;
if (i>=ARP_PORT_NR)
return EGENERIC;
if (port->ap_flags & APF_INADDR_SET)
{
(*func)(ref, port->ap_ipaddr);
return NW_OK;
}
port->ap_flags |= APF_RARPREQ;
port->ap_rarp_ref= ref;
port->ap_rarp_func= func;
return NW_SUSPEND;
}
PUBLIC void set_ipaddr (eth_port, ipaddr)
int eth_port;
ipaddr_t ipaddr;
{
arp_port_t *port;
int i;
port= arp_port_table;
for (i=0; i<ARP_PORT_NR; i++, port++)
if (port->ap_eth_port == eth_port)
break;
assert (i < ARP_PORT_NR);
port->ap_ipaddr= ipaddr;
port->ap_flags |= APF_INADDR_SET;
ipaddr_set(port);
}
PUBLIC int arp_ip_eth (eth_port, ref, ipaddr, func)
int eth_port;
int ref;
ipaddr_t ipaddr;
arp_req_func_t func;
{
arp_port_t *port;
int i;
arp_cache_t *prim, *sec;
#if DEBUG & 256
{ where(); printf("sending arp_req for: "); writeIpAddr(ipaddr);
printf("\n"); }
#endif
port= arp_port_table;
for (i=0; i<ARP_PORT_NR; i++, port++)
if (port->ap_eth_port == eth_port)
break;
if (i>=ARP_PORT_NR)
return EGENERIC;
if ((port->ap_state & APS_STATMASK) != APS_ARPMAIN)
{
port->ap_flags |= APF_CLIENTREQ|APF_MORE2WRITE |
APF_CLIENTWRITE;
port->ap_req_func= func;
port->ap_req_ref= ref;
port->ap_req_ipaddr= ipaddr;
port->ap_req_count= 0;
return NW_SUSPEND;
}
prim= find_cache_ent (eth_port, ipaddr, ARP_TYPE3, &sec);
if (prim)
{
if (prim->ac_type < ARP_TYPE3)
{
sec->ac_type= prim->ac_type;
prim->ac_type= ARP_TYPE3;
}
if (prim->ac_expire < get_time())
prim= 0;
}
if (!prim)
{
port->ap_flags |= APF_CLIENTREQ|APF_MORE2WRITE|APF_CLIENTWRITE;
port->ap_req_func= func;
port->ap_req_ref= ref;
port->ap_req_ipaddr= ipaddr;
port->ap_req_count= 0;
if (!(port->ap_flags & APF_ARP_WR_IP))
setup_write(port);
return NW_SUSPEND;
}
prim->ac_lastuse= get_time();
if (prim->ac_flags & ACF_NOTRCH)
return EDSTNOTRCH;
else
{
client_reply (port, &prim->ac_ethaddr);
return NW_OK;
}
}
PUBLIC int arp_ip_eth_nonbl (eth_port, ipaddr, ethaddr)
int eth_port;
ipaddr_t ipaddr;
ether_addr_t *ethaddr;
{
arp_port_t *port;
int i;
arp_cache_t *prim, *sec;
#if DEBUG & 256
{ where(); printf("got a arp_ip_eth_nonbl(%d, ", eth_port);
writeIpAddr(ipaddr); printf(", ...)\n"); }
#endif
port= arp_port_table;
for (i=0; i<ARP_PORT_NR; i++, port++)
if (port->ap_eth_port == eth_port)
break;
if (i>=ARP_PORT_NR)
return EGENERIC;
if ((port->ap_state & APS_STATMASK) != APS_ARPMAIN)
{
#if DEBUG
{ where(); printf("replying NW_SUSPEND\n"); }
#endif
return NW_SUSPEND;
}
prim= find_cache_ent (eth_port, ipaddr, ARP_TYPE3, &sec);
if (prim)
{
if (prim->ac_type < ARP_TYPE3)
{
sec->ac_type= prim->ac_type;
prim->ac_type= ARP_TYPE3;
}
if (prim->ac_expire < get_time())
prim= 0;
}
if (!prim)
{
#if DEBUG & 256
{ where(); printf("replying NW_SUSPEND\n"); }
#endif
return NW_SUSPEND;
}
if (prim->ac_flags & ACF_NOTRCH)
{
#if DEBUG
{ where(); printf("replying EDSTNOTRCH\n"); }
#endif
return EDSTNOTRCH;
}
else
{
prim->ac_lastuse= get_time();
if (ethaddr)
*ethaddr= prim->ac_ethaddr;
#if DEBUG & 256
{ where(); printf("replying NW_OK (\n"); writeEtherAddr(&prim->ac_ethaddr);
printf(")\n"); }
#endif
return NW_OK;
}
}
PRIVATE void arp_timeout (fd, timer)
int fd;
timer_t *timer;
{
arp_port_t *port;
arp_cache_t *prim, *sec;
int level;
time_t curr_tim;
port= &arp_port_table[fd];
assert (timer == &port->ap_timer);
if (++port->ap_req_count < MAX_ARP_RETRIES)
{
port->ap_flags |= APF_CLIENTWRITE|APF_MORE2WRITE;
if (!(port->ap_flags & APF_ARP_WR_IP))
setup_write(port);
}
else
{
level= ARP_TYPE3;
prim= find_cache_ent(port->ap_eth_port, port->ap_req_ipaddr,
level, &sec);
if (!prim)
{
prim= sec;
prim->ac_flags= ACF_EMPTY;
prim->ac_ipaddr= port->ap_req_ipaddr;
}
else if (prim->ac_type < level)
{
sec->ac_type= prim->ac_type;
prim->ac_type= level;
}
curr_tim= get_time();
prim->ac_expire= curr_tim+ ARP_NOTRCH_EXP_TIME;
prim->ac_lastuse= curr_tim + ARP_INUSE_OFFSET;
prim->ac_flags |= ACF_NOTRCH;
(*port->ap_req_func)(port->ap_req_ref,
(ether_addr_t *)0);
}
}
PRIVATE void print_arp_cache()
{
int i;
arp_cache_t *ci;
for (i=0, ci= arp_cache; i< ARP_CACHE_NR; i++, ci++)
{
if (!ci->ac_expire)
continue;
printf("%d %d ", ci->ac_flags, ci->ac_type);
writeEtherAddr(&ci->ac_ethaddr);
printf(" ");
writeIpAddr(ci->ac_ipaddr);
printf(" %d %ld %ld\n", ci->ac_eth_port, ci->ac_expire,
ci->ac_lastuse);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -