⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arp.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
				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 + -