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

📄 icmp.c

📁 minux的源代码,一个非常小的操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
icmp.c
*/

#include "inet.h"
#include "buf.h"
#include "type.h"

#include "assert.h"
#include "clock.h"
#include "icmp.h"
#include "icmp_lib.h"
#include "io.h"
#include "ip.h"
#include "ip_int.h"
#include "ipr.h"

INIT_PANIC();

typedef struct icmp_port
{
	int icp_flags;
	int icp_state;
	int icp_ipport;
	int icp_ipfd;
	acc_t *icp_head_queue;
	acc_t *icp_tail_queue;
	acc_t *icp_write_pack;
} icmp_port_t;

#define ICPF_EMPTY	0x0
#define ICPF_SUSPEND	0x1
#define ICPF_READ_IP	0x2
#define ICPF_READ_SP	0x4
#define ICPF_WRITE_IP	0x8
#define ICPF_WRITE_SP	0x10

#define ICPS_BEGIN	0
#define ICPS_IPOPT	1
#define ICPS_MAIN	2
#define ICPS_ERROR	3

#define ICMP_PORT_NR	IP_PORT_NR

PRIVATE  icmp_port_t icmp_port_table[ICMP_PORT_NR];

FORWARD void icmp_main ARGS(( icmp_port_t *icmp_port ));
FORWARD acc_t *icmp_getdata ARGS(( int port, size_t offset,
	size_t count, int for_ioctl ));
FORWARD int icmp_putdata ARGS(( int port, size_t offset,
	acc_t *data, int for_ioctl ));
FORWARD void icmp_read ARGS(( icmp_port_t *icmp_port ));
FORWARD void process_data ARGS(( icmp_port_t *icmp_port,
	acc_t *data ));
FORWARD u16_t icmp_pack_oneCsum ARGS(( acc_t *ip_pack ));
FORWARD void icmp_echo_request ARGS(( icmp_port_t *icmp_port,
	acc_t *ip_pack, int ip_hdr_len, ip_hdr_t *ip_hdr,
	acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));
FORWARD void icmp_dst_unreach ARGS(( icmp_port_t *icmp_port,
	acc_t *ip_pack, int ip_hdr_len, ip_hdr_t *ip_hdr,
	acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));
FORWARD void icmp_time_exceeded ARGS(( icmp_port_t *icmp_port,
	acc_t *ip_pack, int ip_hdr_len, ip_hdr_t *ip_hdr,
	acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));
FORWARD void icmp_router_advertisement ARGS(( icmp_port_t *icmp_port,
	acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));
FORWARD void icmp_redirect ARGS(( icmp_port_t *icmp_port,
	ip_hdr_t *ip_hdr, acc_t *icmp_pack, int icmp_len,
	icmp_hdr_t *icmp_hdr ));
FORWARD acc_t *make_repl_ip ARGS(( ip_hdr_t *ip_hdr,
	int ip_len ));
FORWARD void enqueue_pack ARGS(( icmp_port_t *icmp_port,
	acc_t *reply_ip_hdr ));
FORWARD void icmp_write ARGS(( icmp_port_t *icmp_port ));
FORWARD void icmp_buffree ARGS(( int priority, size_t reqsize ));

PUBLIC void icmp_init()
{
	int i;
	icmp_port_t *icmp_port;

	assert (BUF_S >= sizeof (nwio_ipopt_t));

	for (i= 0, icmp_port= icmp_port_table; i<ICMP_PORT_NR; i++,
		icmp_port++)
	{
		icmp_port->icp_flags= ICPF_EMPTY;
		icmp_port->icp_state= ICPS_BEGIN;
		icmp_port->icp_ipport= i;
	}

	bf_logon(icmp_buffree);

	for (i= 0, icmp_port= icmp_port_table; i<ICMP_PORT_NR; i++,
		icmp_port++)
	{
		icmp_main (icmp_port);
	}
}

PRIVATE void icmp_main(icmp_port)
icmp_port_t *icmp_port;
{
	int result;
	switch (icmp_port->icp_state)
	{
	case ICPS_BEGIN:
		icmp_port->icp_head_queue= 0;
		icmp_port->icp_ipfd= ip_open (icmp_port->icp_ipport,
			icmp_port-icmp_port_table, icmp_getdata,
			icmp_putdata);
		if (icmp_port->icp_ipfd<0)
		{
			where();
			printf("unable to open ip_port %d\n",
				icmp_port->icp_ipport);
			break;
		}
		icmp_port->icp_state= ICPS_IPOPT;
		icmp_port->icp_flags &= ~ICPF_SUSPEND;
		result= ip_ioctl (icmp_port->icp_ipfd, NWIOSIPOPT);
		if (result == NW_SUSPEND)
		{
			icmp_port->icp_flags |= ICPF_SUSPEND;
			break;
		}
		else if (result<0)
		{
			where();
			printf("ip_ioctl (.., NWIOSIPOPT)= %d\n",
				result);
			break;
		}
		/* falls through */
	case ICPS_IPOPT:
		icmp_port->icp_state= ICPS_MAIN;
		icmp_port->icp_flags &= ~ICPF_SUSPEND;
		icmp_read(icmp_port);
		break;
	default:
		where();
		printf("unknown state %d\n", icmp_port->icp_state);
		break;
	}
}

PRIVATE acc_t *icmp_getdata(port, offset, count, for_ioctl)
int port;
size_t offset, count;
int for_ioctl;
{
	icmp_port_t *icmp_port;
	nwio_ipopt_t *ipopt;
	acc_t *data;
	int result;

	icmp_port= &icmp_port_table[port];

	if (icmp_port->icp_flags & ICPF_WRITE_IP)
	{
		if (!count)
		{
			bf_afree(icmp_port->icp_write_pack);
			icmp_port->icp_write_pack= 0;

			result= (int)offset;
			if (result<0)
			{
				where();
				printf("got write error %d\n", result);
			}
#if DEBUG & 256
 { where(); printf("ip_write completed\n"); }
#endif
			if (icmp_port->icp_flags & ICPF_WRITE_SP)
			{
				icmp_port->icp_flags &=
					~(ICPF_WRITE_IP|ICPF_WRITE_SP);
				icmp_write (icmp_port);
			}
			return NW_OK;
		}
		return bf_cut(icmp_port->icp_write_pack, offset, count);
	}
	switch (icmp_port->icp_state)
	{
	case ICPS_IPOPT:
		if (!count)
		{
			result= (int)offset;
			if (result < 0)
			{
				icmp_port->icp_state= ICPS_ERROR;
				break;
			}
			if (icmp_port->icp_flags & ICPF_SUSPEND)
				icmp_main(icmp_port);
			return NW_OK;
		}

assert (count == sizeof (*ipopt));
		data= bf_memreq (sizeof (*ipopt));
assert (data->acc_length == sizeof(*ipopt));
		ipopt= (nwio_ipopt_t *)ptr2acc_data(data);
		ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC |
			NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC |
			NWIO_HDR_O_ANY | NWIO_RWDATALL;
		ipopt->nwio_proto= IPPROTO_ICMP;
		return data;
	default:
		where();
		printf("unknown state %d\n", icmp_port->icp_state);
		return 0;
	}
}

PRIVATE int icmp_putdata(port, offset, data, for_ioctl)
int port;
size_t offset;
acc_t *data;
int for_ioctl;
{
	icmp_port_t *icmp_port;
	int result;

	icmp_port= &icmp_port_table[port];

	if (icmp_port->icp_flags & ICPF_READ_IP)
	{
assert (!for_ioctl);
		if (!data)
		{
			result= (int)offset;
			if (result<0)
			{
				where();
				printf("got read error %d\n", result);
			}
			if (icmp_port->icp_flags & ICPF_READ_SP)
			{
				icmp_port->icp_flags &=
					~(ICPF_READ_IP|ICPF_READ_SP);
				icmp_read (icmp_port);
			}
			return NW_OK;
		}
		process_data(icmp_port, data);
		return NW_OK;
	}
	switch (icmp_port->icp_state)
	{
	default:
		where();
		printf("unknown state %d\n", icmp_port->icp_state);
		return 0;
	}
}

PRIVATE void icmp_read(icmp_port)
icmp_port_t *icmp_port;
{
	int result;

assert (!(icmp_port->icp_flags & (ICPF_READ_IP|ICPF_READ_SP) || 
	(icmp_port->icp_flags & (ICPF_READ_IP|ICPF_READ_SP)) ==
	(ICPF_READ_IP|ICPF_READ_SP)));

	for (;;)
	{
		icmp_port->icp_flags |= ICPF_READ_IP;
		icmp_port->icp_flags &= ~ICPF_READ_SP;

		result= ip_read(icmp_port->icp_ipfd, ICMP_MAX_DATAGRAM);
		if (result == NW_SUSPEND)
		{
			icmp_port->icp_flags |= ICPF_READ_SP;
			return;
		}
	}
}

PUBLIC void icmp_frag_ass_tim(pack)
acc_t *pack;
{
	ip_warning(( "icmp_frag_ass() called" ));
	bf_afree(pack);
}

PUBLIC void icmp_getnetmask(ip_port)
int ip_port;
{
	ip_port_t *port;

#if DEBUG & 256
 { where(); printf("icmp.c: icmp_getnetmask(ip_port= %d)\n", ip_port); }
#endif
	port= &ip_port_table[ip_port];
#if DEBUG & 2
 { where(); printf ("icmp_getnetmask() NOT implemented\n"); }
#endif

	port->ip_netmask= HTONL(0xffffff00L);
	port->ip_flags |= IPF_NETMASKSET;
#if DEBUG & 256
 { where(); printf("icmp.c: setting netmask to "); 
   writeIpAddr(port->ip_netmask); printf("\n"); }
#endif
}

PUBLIC void icmp_dont_frag(pack)
acc_t *pack;
{
printf ("icmp_dont_frag() called\n");
	bf_afree(pack);
}

PUBLIC void icmp_ttl_exceded(pack)
acc_t *pack;
{
printf ("icmp_ttl_execeded() called\n");
	bf_afree(pack);
}

PRIVATE void process_data(icmp_port, data)
icmp_port_t *icmp_port;
acc_t *data;
{
	ip_hdr_t *ip_hdr;
	icmp_hdr_t *icmp_hdr;
	acc_t *icmp_data;
	int ip_hdr_len;
	size_t pack_len;

#if DEBUG & 256
 { where(); printf("got an icmp packet\n"); }
#endif
	data= bf_packIffLess(data, IP_MIN_HDR_SIZE);
	ip_hdr= (ip_hdr_t *)ptr2acc_data(data);
	ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;

	if (ip_hdr_len>IP_MIN_HDR_SIZE)
	{
		data= bf_packIffLess(data, ip_hdr_len);
		ip_hdr= (ip_hdr_t *)ptr2acc_data(data);
	}

	pack_len= bf_bufsize(data);
	pack_len -= ip_hdr_len;
	if (pack_len < ICMP_MIN_HDR_LEN)
	{
#if DEBUG
 { where(); printf("got an incomplete icmp packet\n"); }
#endif
		bf_afree(data);
		return;
	}

	icmp_data= bf_cut(data, ip_hdr_len, pack_len);

	icmp_data= bf_packIffLess (icmp_data, ICMP_MIN_HDR_LEN);
	icmp_hdr= (icmp_hdr_t *)ptr2acc_data(icmp_data);


	if ((u16_t)~icmp_pack_oneCsum(icmp_data))
	{
#if DEBUG
 { where(); printf("got packet with bad checksum (= 0x%x)\n",
	(u16_t)~icmp_pack_oneCsum(icmp_data)); }
#endif
		bf_afree(data);
		bf_afree(icmp_data);
		return;
	}
	switch (icmp_hdr->ih_type)
	{
	case ICMP_TYPE_ECHO_REPL:
#if DEBUG
 { where(); printf("got an icmp echo reply\n"); }
#endif
		break;
	case ICMP_TYPE_DST_UNRCH:
		icmp_dst_unreach (icmp_port, data, ip_hdr_len, ip_hdr,
			icmp_data, pack_len, icmp_hdr);
		break;
	case ICMP_TYPE_REDIRECT:
		icmp_redirect (icmp_port, ip_hdr, icmp_data, pack_len,
			icmp_hdr);
		break;
	case ICMP_TYPE_ECHO_REQ:
		icmp_echo_request(icmp_port, data, ip_hdr_len, ip_hdr,
			icmp_data, pack_len, icmp_hdr);
		return;
	case ICMP_TYPE_ROUTER_ADVER:
		icmp_router_advertisement(icmp_port, icmp_data, pack_len, 
			icmp_hdr);
		break;
	case ICMP_TYPE_TIME_EXCEEDED:
		icmp_time_exceeded (icmp_port, data, ip_hdr_len, ip_hdr,
			icmp_data, pack_len, icmp_hdr);
		break;
	default:
#if DEBUG
 { where(); printf("got an unknown icmp (%d) from ", icmp_hdr->ih_type); 
	writeIpAddr(ip_hdr->ih_src); printf("\n"); }
#endif
		break;
	}
	bf_afree(data);
	bf_afree(icmp_data);
}

PRIVATE void icmp_echo_request(icmp_port, ip_data, ip_len, ip_hdr,
	icmp_data, icmp_len, icmp_hdr)
icmp_port_t *icmp_port;
acc_t *ip_data, *icmp_data;
int ip_len, icmp_len;
ip_hdr_t *ip_hdr;
icmp_hdr_t *icmp_hdr;
{
	acc_t *repl_ip_hdr, *repl_icmp;
	icmp_hdr_t *repl_icmp_hdr;
	u32_t tmp_chksum;
	u16_t u16;

	if (icmp_hdr->ih_code != 0)
	{
#if DEBUG
 { where(); printf("got an icmp echo request with unknown code (%d)\n",
		icmp_hdr->ih_code); }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -