ip_input.c

来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 811 行 · 第 1/2 页

C
811
字号
#ifndef lintstatic char sccsid[] = "@(#)ip_input.c 1.1 92/07/30 Copyr 1986 Sun Micro";#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. */#include <sys/param.h>#include "boot/systm.h"#include <sys/mbuf.h>#include "boot/domain.h"#include "boot/protosw.h"#include <sys/socket.h>#include <sys/errno.h>#include <sys/time.h>#include <sys/kernel.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_pcb.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_var.h>#include <netinet/ip_icmp.h>#include <netinet/tcp.h>#include <mon/sunromvec.h>u_char	ip_protox[IPPROTO_MAX];int	ipqmaxlen = IFQ_MAXLEN;struct	ifnet *ifinet;			/* first inet interface */int	ip_gotit = 0;int	ip_reasstot = 0;static int dump_debug = 30;#undef	IPFRAGTTL#define	IPFRAGTTL	8#define	MAXTRACE	128struct	{	int	ip_ident;	int	ip_time;	int	ip_diff;	int	ip_offset;} ip_trace[MAXTRACE];int	ip_trace_index = MAXTRACE-1;#define	NEXT_TRACE(i)	(i=((i)==(MAXTRACE-1)?0:i+1))#ifdef OPENPROMS#define	millitime()	prom_gettime()#else#define	millitime()	(*romp->v_nmiclock)#endif !OPENPROMS/* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ip_init(){	register struct protosw *pr;	register int i;	struct ifnet *if_ifwithaf();	pr = pffindproto(PF_INET, IPPROTO_RAW);	if (pr == 0)		panic("ip_init");	for (i = 0; i < IPPROTO_MAX; i++)		ip_protox[i] = pr - inetsw;	for (pr = inetdomain.dom_protosw;	    pr < inetdomain.dom_protoswNPROTOSW; pr++) {		if (pr->pr_family == PF_INET &&		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) {			ip_protox[pr->pr_protocol] = pr - inetsw;		}	}	ipq.next = ipq.prev = &ipq;	ip_id = time.tv_sec & 0xffff;	ifinet = if_ifwithaf(AF_INET);}u_char	i_ipcksum = 1;struct	ip *ip_reass();struct	sockaddr_in ipaddr = { AF_INET };/* * Ip input routine.  Checksum and byte swap header.  If fragmented * try to reassamble.  If complete and fragment queue exists, discard. * Process options.  Pass to next level. */ipintr(m)	struct mbuf *m;{	register struct ip *ip;	struct mbuf *m0;	register int i;	register struct ipq *fp;	int hlen;	register struct ifaddr *ifa;#ifdef	DUMP_DEBUG1	dprint(dump_debug, 6,		"ipintr(m 0x%x) type 0x%x\n", m, m->m_type);#endif	/* DUMP_DEBUG */	ip_gotit = 0;	/*	 * Get next datagram off input queue and get IP header	 * in first mbuf.	 */	if (m == 0)	{		dprint(dump_debug, 0,			"ipintr: NULL mbuf\n");		return;	}	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&	    (m = m_pullup(m, sizeof (struct ip))) == 0) {		dprint(dump_debug, 0,			"ipintr: mbuff too small\n");		ipstat.ips_toosmall++;		return;	}	ip = mtod(m, struct ip *);	hlen = ip->ip_hl << 2;	if (hlen < 10) {	/* minimum header length */		dprint(dump_debug, 0,			"ipintr: bad hl 0x%x\n", hlen);		ipstat.ips_badhlen++;		m_freem(m);		return;	}	if (hlen > m->m_len) {		if ((m = m_pullup(m, hlen)) == 0) {			dprint(dump_debug, 0,				"ipintr: bad pullup\n");			ipstat.ips_badhlen++;			return;		}		ip = mtod(m, struct ip *);	}	if (i_ipcksum)		if (ip->ip_sum = ipcksum((caddr_t)ip, (unsigned short)hlen)) {			dprint(dump_debug, 0,				"ipintr: ip_sum 0x%x\n",				ip->ip_sum);			ipstat.ips_badsum++;			goto bad;		}	/*	 * Convert fields to host representation.	 */	ip->ip_len = ntohs((u_short)ip->ip_len);#ifdef  DUMP_DEBUG1	dprint(dump_debug, 6, "ipintr: ip_len 0x%x\n", ip->ip_len);#endif	if (ip->ip_len < hlen) {		ipstat.ips_badlen++;		goto bad;	}	ip->ip_id = ntohs(ip->ip_id);	ip->ip_off = ntohs((u_short)ip->ip_off);	/*	 * Check that the amount of data in the buffers	 * is as at least much as the IP header would have us expect.	 * Trim mbufs if longer than we expect.	 * Drop packet if shorter than we expect.	 */	i = -ip->ip_len;	m0 = m;	for (;;) {		i += m->m_len;		if (m->m_next == 0)			break;		m = m->m_next;	}	if (i != 0) {		if (i < 0) {			ipstat.ips_tooshort++;			m = m0;			goto bad;		}		if (i <= m->m_len)			m->m_len -= i;		else			m_adj(m0, -i);	}	m = m0;	/*	 * Process options and, if not destined for us,	 * ship it on.  ip_dooptions returns 1 when an	 * error was detected (causing an icmp message	 * to be sent).	 */	if (hlen > sizeof (struct ip) && ip_dooptions(ip))		return;	/*	 * Fast check on the first internet	 * interface in the list.	 */	if (ifinet) {		struct sockaddr_in *sin;		ifa = ifinet->if_addrlist;		sin = (struct sockaddr_in *)&ifa->ifa_addr;		if (sin->sin_addr.s_addr == ip->ip_dst.s_addr)			goto ours;		if ((ifinet->if_flags & IFF_BROADCAST) &&		    ip->ip_dst.s_addr == INADDR_ANY)			goto ours;	}	ipaddr.sin_addr = ip->ip_dst;	if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0 &&	    (*(int *)&ip->ip_dst) != -1) {		ip_forward(ip);		return;	}ours:	/*	 * Look for queue of fragments	 * of this datagram.	 */	for (fp = ipq.next; fp != &ipq; fp = fp->next)		if (ip->ip_id == fp->ipq_id &&		    ip->ip_src.s_addr == fp->ipq_src.s_addr &&		    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&		    ip->ip_p == fp->ipq_p)  {			goto found;		    }	fp = 0;found:	ip_trace[NEXT_TRACE(ip_trace_index)].ip_ident = ip->ip_id;	ip_trace[ip_trace_index].ip_time = millitime();	ip_trace[ip_trace_index].ip_diff = ip_trace[ip_trace_index].ip_time -		ip_trace[ip_trace_index-1].ip_time;	ip_trace[ip_trace_index].ip_offset = ip->ip_off;	/*	 * Adjust ip_len to not reflect header,	 * set ip_mff if more fragments are expected,	 * convert offset of this to bytes.	 */	ip->ip_len -= hlen;	((struct ipasfrag *)ip)->ipf_mff = 0;	if (ip->ip_off & IP_MF)		((struct ipasfrag *)ip)->ipf_mff = 1;	ip->ip_off <<= 3;	/*	 * If datagram marked as having more fragments	 * or if this is not the first fragment,	 * attempt reassembly; if it succeeds, proceed.	 */	if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {		ip = ip_reass((struct ipasfrag *)ip, fp);		if (ip == 0)	{			return;		}		hlen = ip->ip_hl << 2;		m = dtom(ip);	} else		if (fp)			ip_freef(fp);	ip_gotit = 1;	/*	 * Switch out to protocol's input routine.	 */	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m);	return;bad:	dprint(dump_debug, 0,		"ipintr: bad\n");	m_freem(m);	return;}/* * Take incoming datagram fragment and try to * reassemble it into whole datagram.  If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */struct ip *ip_reass(ip, fp)	register struct ipasfrag *ip;	register struct ipq *fp;{	register struct mbuf *m = dtom(ip);	register struct ipasfrag *q;	struct mbuf *t;	int hlen = ip->ip_hl << 2;	int i, next;#ifdef	 DUMP_DEBUG1	dprint(dump_debug, 6, "ip_reass(ip 0x%x fp 0x%x)\n", ip, fp);#endif	 /* DUMP_DEBUG */	/*	 * Presence of header sizes in mbufs	 * would confuse code below.	 */	m->m_off += hlen;	m->m_len -= hlen;	/*	 * If first fragment to arrive, create a reassembly queue.	 */	if (fp == 0) {		if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL)			goto dropfrag;		fp = mtod(t, struct ipq *);#ifdef   DUMP_DEBUG1	dprint(dump_debug, 6, "ip_reass: t 0x%x fp 0x%x type 0x%x\n",		t, fp, t->m_type);#endif   /* DUMP_DEBUG */		insque(fp, &ipq);		fp->ipq_ttl = IPFRAGTTL;		fp->ipq_p = ip->ip_p;		fp->ipq_id = ip->ip_id;		fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;		fp->ipq_src = ((struct ip *)ip)->ip_src;		fp->ipq_dst = ((struct ip *)ip)->ip_dst;		q = (struct ipasfrag *)fp;		goto insert;	}	/*	 * Find a segment which begins after this one does.	 */	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)		if (q->ip_off > ip->ip_off)			break;	/*	 * If there is a preceding segment, it may provide some of	 * our data already.  If so, drop the data from the incoming	 * segment.  If it provides all of our data, drop us.	 */	if (q->ipf_prev != (struct ipasfrag *)fp) {		i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;		if (i > 0) {			if (i >= ip->ip_len)				goto dropfrag;			m_adj(dtom(ip), i);			ip->ip_off += i;			ip->ip_len -= i;		}	}	/*	 * While we overlap succeeding segments trim them or,	 * if they are completely covered, dequeue them.	 */	while (q != (struct ipasfrag *)fp &&	    ip->ip_off + ip->ip_len > q->ip_off) {		i = (ip->ip_off + ip->ip_len) - q->ip_off;		if (i < q->ip_len) {			q->ip_len -= i;			q->ip_off += i;			m_adj(dtom(q), i);			break;		}		q = q->ipf_next;		m_freem(dtom(q->ipf_prev));		ip_deq(q->ipf_prev);	}insert:	/*	 * Stick new segment in its place;	 * check for complete reassembly.	 */	ip_enq(ip, q->ipf_prev);	next = 0;	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {		if (q->ip_off != next)			return (0);		next += q->ip_len;	}	if (q->ipf_prev->ipf_mff)		return (0);	/*	 * Reassembly is complete; concatenate fragments.	 */	q = fp->ipq_next;	m = dtom(q);	t = m->m_next;	m->m_next = 0;

⌨️ 快捷键说明

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