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

📄 neticmp.c

📁 ucos操作系统下TCPIP实现代码
💻 C
字号:
/*****************************************************************************
* neticmp.c - Network Internet Control Message Protocol program file.
*
* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice and the following disclaimer are included verbatim in any 
* distributions. No written agreement, license, or royalty fee is required
* for any of the authorized uses.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
* REVISION HISTORY
*
* 98-01-22 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
*	Extracted from BSD's ip_icmp.c and icmp_var.h.
*****************************************************************************/
/*
 * Copyright (c) 1982, 1986, 1988, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
 *
 *	@(#)icmp_var.h	8.1 (Berkeley) 6/10/93
 */
/*
 * ICMP routines: error generation, receive packet processing, and
 * routines to turnaround packets back to the originator, and
 * host table maintenance routines.
 */



#include "typedefs.h"
#include "avconfig.h"
#include <string.h>
#include "stdio.h"				// Required for debug.h
#include "time.h"
#include "avos.h"

#include "netbuf.h"
#include "net.h"
#include "netip.h"
#include "netiphdr.h"
#include "neticmp.h"

#include "debug.h"


/*************************/
/*** LOCAL DEFINITIONS ***/
/*************************/
/*
 * Names for ICMP sysctl objects
 */
#define	ICMPCTL_MASKREPL	1	/* allow replies to netmask requests */
#define ICMPCTL_MAXID		2

#define ICMPCTL_NAMES { \
	{ 0, 0 }, \
	{ "maskrepl", CTLTYPE_INT }, \
}

                                                                    
/************************/
/*** LOCAL DATA TYPES ***/
/************************/


/***********************************/
/*** LOCAL FUNCTION DECLARATIONS ***/
/***********************************/
static void icmpReflect(NBuf *nb);
static void icmpSend(
	register NBuf *nb,
	NBuf *opts
);
static u_long iptime(void);


/******************************/
/*** PUBLIC DATA STRUCTURES ***/
/******************************/
IcmpStats icmpStats;


/***********************************/
/*** PUBLIC FUNCTION DEFINITIONS ***/
/***********************************/
void icmpInit(void)
{
	memset(&icmpStats, 0, sizeof(icmpStats));
}


/*
 * Generate an error packet of type error
 * in response to bad packet ip.
 */
void icmp_error(
	NBuf *nb,
	int type, 
	int code,
	n_long dest
)
{
	register IPHdr *oip = nBUFTOPTR(nb, IPHdr *), *nip;
	register unsigned oiplen = oip->ip_hl << 2;
	register IcmpHdr *icp;
	register NBuf *n0;
	unsigned icmplen;

	ICMPDEBUG((LOG_INFO, "icmp_error(%x, %d, %d)\n", oip, type, code));
	
	if (type != ICMP_REDIRECT)
		icmpStats.icps_error++;
	/*
	 * Don't send error if not the first fragment of message.
	 * Don't error if the old packet protocol was ICMP
	 * error message, only known informational types.
	 */
	if (oip->ip_off &~ (IP_MF|IP_DF))
		goto freeit;
	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
			nb->len >= oiplen + ICMP_MINLEN &&
			!ICMP_INFOTYPE(((IcmpHdr *)((caddr_t)oip + oiplen))->icmp_type)) {
		icmpStats.icps_oldicmp++;
		goto freeit;
	}
	/* Don't send error in response to a multicast or broadcast packet */
	/* XXX */
	/*
	 * First, formulate icmp message
	 */
	nGET(n0);
	if (n0 == NULL)
		goto freeit;
	icmplen = oiplen + min(8, oip->ip_len);
	n0->len = n0->chainLen = icmplen + ICMP_MINLEN;
	nALIGN(n0, n0->len);
	icp = nBUFTOPTR(n0, IcmpHdr *);
	if ((u_int)type > ICMP_MAXTYPE)
		panic("icmp_error");
	icmpStats.icps_outhist[type]++;
	icp->icmp_type = type;
	if (type == ICMP_REDIRECT)
		icp->icmp_gwaddr.s_addr = dest;
	else {
		icp->icmp_void = 0;
		/* 
		 * The following assignments assume an overlay with the
		 * zeroed icmp_void field.
		 */
		if (type == ICMP_PARAMPROB) {
			icp->icmp_pptr = code;
			code = 0;
		} 
	}

	icp->icmp_code = code;
	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
	nip = &icp->icmp_ip;
	nip->ip_len = htons((u_short)(nip->ip_len + oiplen));

	/*
	 * Now, copy old ip header (without options)
	 * in front of icmp message.
	 */
	nPREPEND(n0, oip, sizeof(IPHdr));
	nip = nBUFTOPTR(n0, IPHdr *);
	nip->ip_len = n0->len;
	nip->ip_hl = sizeof(IPHdr) >> 2;
	nip->ip_p = IPPROTO_ICMP;
	nip->ip_tos = 0;
	icmpReflect(n0);

freeit:
	nFreeChain(nb);
}

static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
struct sockaddr_in icmpmask = { 8, 0 };

/*
 * Process a received ICMP message.
 */
void icmpInput(NBuf *inBuf, int ipHdrLen)
{
	register IcmpHdr *icp;
	register IPHdr *ip = nBUFTOPTR(inBuf, IPHdr *);
	int icmplen = ip->ip_len - ipHdrLen;
	register int i;
	int code;
	extern u_char ip_protox[];

	ICMPDEBUG((LOG_INFO, "icmp_input from %s to %s, len %d\n",
			ip_ntoa(ip->ip_src.s_addr), 
			ip_ntoa2(ip->ip_dst.s_addr),
			icmplen));
			
	/*
	 * Locate icmp structure in nBuf, and check
	 * that not corrupted and of at least minimum length.
	 */
	if (icmplen < ICMP_MINLEN) {
		icmpStats.icps_tooshort++;
		goto freeit;
	}
	i = ipHdrLen + min(icmplen, ICMP_ADVLENMIN);
	if (inBuf->len < i && (inBuf = nPullup(inBuf, i)) == NULL)  {
		icmpStats.icps_tooshort++;
		return;
	}
	ip = nBUFTOPTR(inBuf, IPHdr *);
	icp = (IcmpHdr *)(nBUFTOPTR(inBuf, char *) + ipHdrLen);
	if (inChkSum(inBuf, icmplen, ipHdrLen)) {
		icmpStats.icps_checksum++;
		goto freeit;
	}

	/*
	 * Message type specific processing.
	 */
	ICMPDEBUG((LOG_INFO, "icmp_input, type %d code %d\n", icp->icmp_type,
		    icp->icmp_code));
	if (icp->icmp_type > ICMP_MAXTYPE)
		goto raw;
	icmpStats.icps_inhist[icp->icmp_type]++;
	code = icp->icmp_code;
	switch (icp->icmp_type) {

	case ICMP_UNREACH:
		switch (code) {
			case ICMP_UNREACH_NET:
			case ICMP_UNREACH_HOST:
			case ICMP_UNREACH_PROTOCOL:
			case ICMP_UNREACH_PORT:
			case ICMP_UNREACH_SRCFAIL:
				code += PRC_UNREACH_NET;
				break;

			case ICMP_UNREACH_NEEDFRAG:
				code = PRC_MSGSIZE;
				break;
				
			case ICMP_UNREACH_NET_UNKNOWN:
			case ICMP_UNREACH_NET_PROHIB:
			case ICMP_UNREACH_TOSNET:
				code = PRC_UNREACH_NET;
				break;

			case ICMP_UNREACH_HOST_UNKNOWN:
			case ICMP_UNREACH_ISOLATED:
			case ICMP_UNREACH_HOST_PROHIB:
			case ICMP_UNREACH_TOSHOST:
				code = PRC_UNREACH_HOST;
				break;

			default:
				goto badcode;
		}
		goto deliver;

	case ICMP_TIMXCEED:
		if (code > 1)
			goto badcode;
		code += PRC_TIMXCEED_INTRANS;
		goto deliver;

	case ICMP_PARAMPROB:
		if (code > 1)
			goto badcode;
		code = PRC_PARAMPROB;
		goto deliver;

	case ICMP_SOURCEQUENCH:
		if (code)
			goto badcode;
		code = PRC_QUENCH;
	deliver:
		/*
		 * Problem with datagram; advise higher level routines.
		 */
		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
				icp->icmp_ip.ip_hl < (sizeof(IPHdr) >> 2)) {
			icmpStats.icps_badlen++;
			goto freeit;
		}
		NTOHS(icp->icmp_ip.ip_len);
		ICMPDEBUG((LOG_INFO, "icmp_input: deliver to protocol %d\n", icp->icmp_ip.ip_p));
		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
#ifdef XXX  /* We need a method here of selecting input handlers... */
		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
			    &icp->icmp_ip);
#endif
		
		break;

	badcode:
		icmpStats.icps_badcode++;
		break;

	case ICMP_ECHO:
		icp->icmp_type = ICMP_ECHOREPLY;
		goto reflect;

	case ICMP_TSTAMP:
		if (icmplen < ICMP_TSLEN) {
			icmpStats.icps_badlen++;
			break;
		}
		icp->icmp_type = ICMP_TSTAMPREPLY;
		icp->icmp_rtime = iptime();
		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
		goto reflect;
		
	case ICMP_MASKREQ:
#ifdef XXX /* Not currently supported... */
#define	satosin(sa)	((struct sockaddr_in *)(sa))
		if (icmpmaskrepl == 0)
			break;
		/*
		 * We are not able to respond with all ones broadcast
		 * unless we receive it over a point-to-point interface.
		 */
		if (icmplen < ICMP_MASKLEN)
			break;
		switch (ip->ip_dst.s_addr) {

		case INADDR_BROADCAST:
		case INADDR_ANY:
			icmpdst.sin_addr = ip->ip_src;
			break;

		default:
			icmpdst.sin_addr = ip->ip_dst;
		}
		ia = (struct in_ifaddr *)ifaof_ifpforaddr(
			    (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
		if (ia == 0)
			break;
		icp->icmp_type = ICMP_MASKREPLY;
		icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
		if (ip->ip_src.s_addr == 0) {
			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
		}
#else
		break;
#endif
reflect:
#ifdef XXX
	/* XXX No longer! */
		ip->ip_len += ipHdrLen;	/* since ip_input deducts this */
#endif
		icmpStats.icps_reflect++;
		icmpStats.icps_outhist[icp->icmp_type]++;
		icmpReflect(inBuf);
		return;

	case ICMP_REDIRECT:
#ifdef XXX /* Not currently supported... */
		if (code > 3)
			goto badcode;
		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
		    icp->icmp_ip.ip_hl < (sizeof(IPHdr) >> 2)) {
			icmpStats.icps_badlen++;
			break;
		}
		/*
		 * Short circuit routing redirects to force
		 * immediate change in the kernel's routing
		 * tables.  The message is also handed to anyone
		 * listening on a raw socket (e.g. the routing
		 * daemon for use in updating its tables).
		 */
		icmpgw.sin_addr = ip->ip_src;
		icmpdst.sin_addr = icp->icmp_gwaddr;
#ifdef	ICMPPRINTFS
		if (icmpprintfs)
			printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
				icp->icmp_gwaddr);
#endif
		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
		rtredirect((struct sockaddr *)&icmpsrc,
		  (struct sockaddr *)&icmpdst,
		  (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
		  (struct sockaddr *)&icmpgw, (struct rtentry **)0);
		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
#endif
		break;

	/*
	 * No kernel processing for the following;
	 * just fall through to send to raw listener.
	 */
	case ICMP_ECHOREPLY:
	case ICMP_ROUTERADVERT:
	case ICMP_ROUTERSOLICIT:
	case ICMP_TSTAMPREPLY:
	case ICMP_IREQREPLY:
	case ICMP_MASKREPLY:
	default:
		break;
	}

raw:
	ripInput(inBuf);
	return;

freeit:
	nFreeChain(inBuf);
}


/**********************************/
/*** LOCAL FUNCTION DEFINITIONS ***/
/**********************************/
/*
 * Reflect the ip packet back to the source
 */
static void icmpReflect(NBuf *nb)
{
	register IPHdr *ip = nBUFTOPTR(nb, IPHdr *);

	/* Send back to source, use our address as new source. */
	ip->ip_dst = ip->ip_src;
	ip->ip_src.s_addr = htonl(localHost);
	
	ip->ip_ttl = MAXTTL;

	icmpSend(nb, NULL);
}

/*
 * Send an icmp packet back to the ip level,
 * after supplying a checksum.
 */
#pragma argsused
static void icmpSend(
	register NBuf *nb,
	NBuf *opts
)
{
	register IPHdr *ip = nBUFTOPTR(nb, IPHdr *);
	register int ipHdrLen;
	register IcmpHdr *icp;

	/* Compute the ICMP checksum on the datagram body only. */
	ipHdrLen = ip->ip_hl << 2;
	icp = (IcmpHdr *)(nBUFTOPTR(nb, char *) + ipHdrLen);
	icp->icmp_cksum = 0;
	icp->icmp_cksum = inChkSum(nb, ip->ip_len - ipHdrLen, ipHdrLen);
	ICMPDEBUG((LOG_INFO, "icmp_send %d p%d t%d c%d from %s to %s chk=%X\n", 
				nb->len, ip->ip_p,
				icp->icmp_type, icp->icmp_code,
				ip_ntoa(ip->ip_src.s_addr), 
				ip_ntoa2(ip->ip_dst.s_addr),
				icp->icmp_cksum));
	
	ipRawOut(nb);
}

static u_long iptime(void)
{
	struct time ctime;
	u_long t;

	if (clk_stat()) {
		gettime(&ctime);
		t = ((((u_long)ctime.hour * 24
				+ (u_long)ctime.min) * 60
					+ (u_long)ctime.sec) * 60
						+ (u_long)ctime.hund) * 10;
	}
	else
		t = 0;
	return (htonl(t));
}

⌨️ 快捷键说明

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