ip_input.c

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

C
811
字号
#ifdef	DUMP_DEBUG1	dprint(dump_debug, 6, "ip_reass(1): q 0x%x m 0x%x t 0x%x\n", q, m, t);#endif	 /* DUMP_DEBUG */	m_cat(m, t);	q = q->ipf_next;	while (q != (struct ipasfrag *)fp) {		t = dtom(q);		q = q->ipf_next;#ifdef	DUMP_DEBUG1	dprint(dump_debug, 6, "ip_reass(2): q 0x%x m 0x%x t 0x%x\n", q, m, t);#endif	 /* DUMP_DEBUG */		m_cat(m, t);	}#ifdef  DUMP_DEBUG1	dprint(dump_debug, 6, "ip_reass: mcat OK\n");#endif   /* DUMP_DEBUG */	/*	 * Create header for new ip packet by	 * modifying header of first packet;	 * dequeue and discard fragment reassembly header.	 * Make header visible.	 */	ip = fp->ipq_next;	ip->ip_len = next;	((struct ip *)ip)->ip_src = fp->ipq_src;	((struct ip *)ip)->ip_dst = fp->ipq_dst;	remque(fp);	(void) m_free(dtom(fp));	m = dtom(ip);	m->m_len += sizeof (struct ipasfrag);	m->m_off -= sizeof (struct ipasfrag);	return ((struct ip *)ip);dropfrag:	m_freem(m);	return (0);}/* * Free a fragment reassembly header and all * associated datagrams. */ip_freef(fp)	struct ipq *fp;{	register struct ipasfrag *q, *p;	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {		p = q->ipf_next;		ip_deq(q);		m_freem(dtom(q));	}	remque(fp);	(void) m_free(dtom(fp));}/* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */ip_enq(p, prev)	register struct ipasfrag *p, *prev;{	p->ipf_prev = prev;	p->ipf_next = prev->ipf_next;	prev->ipf_next->ipf_prev = p;	prev->ipf_next = p;}/* * To ip_enq as remque is to insque. */ip_deq(p)	register struct ipasfrag *p;{	p->ipf_prev->ipf_next = p->ipf_next;	p->ipf_next->ipf_prev = p->ipf_prev;}/* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */ip_slowtimo(){	register struct ipq *fp;	int s = splnet();	ip_reasstot = 0;	fp = ipq.next;	if (fp == 0) {		(void) splx(s);		return;	}	while (fp != &ipq) {		ip_reasstot++;		--fp->ipq_ttl;		fp = fp->next;		if (fp->prev->ipq_ttl == 0)			ip_freef(fp->prev);	}	(void) splx(s);}/* * Drain off all datagram fragments. */ip_drain(){	while (ipq.next != &ipq)		ip_freef(ipq.next);}/* * Do option processing on a datagram, * possibly discarding it if bad options * are encountered. */ip_dooptions(ip)	struct ip *ip;{#ifdef NEVER	register u_char *cp;	int opt, optlen, cnt, code, type;	struct in_addr *sin;	register struct ip_timestamp *ipt;	register struct ifnet *ifp;	struct in_addr t;#endif NEVER#ifdef	DUMP_DEBUG1	dprint(dump_debug, 0,		"ip_dooptions(ip 0x%x)\n",		ip);#endif	/* DUMP_DEBUG */#ifdef	NEVER	cp = (u_char *)(ip + 1);	cnt = (ip->ip_hl << 2) - sizeof (struct ip);	for (; cnt > 0; cnt -= optlen, cp += optlen) {		opt = cp[0];		if (opt == IPOPT_EOL)			break;		if (opt == IPOPT_NOP)			optlen = 1;		else			optlen = cp[1];		switch (opt) {		default:			break;		/*		 * Source routing with record.		 * Find interface with current destination address.		 * If none on this machine then drop if strictly routed,		 * or do nothing if loosely routed.		 * Record interface address and bring up next address		 * component.  If strictly routed make sure next		 * address on directly accessible net.		 */		case IPOPT_LSRR:		case IPOPT_SSRR:			if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1))				break;			sin = (struct in_addr *)(cp + cp[2]);			ipaddr.sin_addr = *sin;			ifp = if_ifwithaddr((struct sockaddr *)&ipaddr);			type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL;			if (ifp == 0) {				if (opt == IPOPT_SSRR)					goto bad;				break;			}			t = ip->ip_dst; ip->ip_dst = *sin; *sin = t;			cp[2] += 4;			if (cp[2] > optlen - (sizeof (long) - 1))				break;			ip->ip_dst = sin[1];			if (opt == IPOPT_SSRR &&			    if_ifonnetof(in_netof(ip->ip_dst)) == 0)				goto bad;			break;		case IPOPT_TS:			code = cp - (u_char *)ip;			type = ICMP_PARAMPROB;			ipt = (struct ip_timestamp *)cp;			if (ipt->ipt_len < 5)				goto bad;			if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {				if (++ipt->ipt_oflw == 0)					goto bad;				break;			}			sin = (struct in_addr *)(cp+cp[2]);			switch (ipt->ipt_flg) {			case IPOPT_TS_TSONLY:				break;			case IPOPT_TS_TSANDADDR:			    if (ipt->ipt_ptr + 8 > ipt->ipt_len)				goto bad;			    if (ifinet == 0)				goto bad;	/* ??? */			    *sin++ = ((struct sockaddr_in *)				&ifinet->if_addr)->sin_addr;			    break;			case IPOPT_TS_PRESPEC:			    ipaddr.sin_addr = *sin;			    if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0)				continue;			    if (ipt->ipt_ptr + 8 > ipt->ipt_len)				goto bad;			    ipt->ipt_ptr += 4;			    break;			default:			    goto bad;			}			*(n_time *)sin = iptime();			ipt->ipt_ptr += 4;		}	}#endif	/* NEVER */	return (0);#ifdef NEVERbad:	icmp_error(ip, type, code);	return (1);#endif NEVER}#ifdef	NEVER/* * Strip out IP options, at higher * level protocol in the kernel. * Second argument is buffer to which options * will be moved, and return value is their length. */ip_stripoptions(ip, mopt)	struct ip *ip;	struct mbuf *mopt;{	register int i;	register struct mbuf *m;	int olen;	olen = (ip->ip_hl<<2) - sizeof (struct ip);	m = dtom(ip);	ip++;	if (mopt) {		mopt->m_len = olen;		mopt->m_off = MMINOFF;		bcopy((caddr_t)ip, mtod(m, caddr_t), (unsigned)olen);	}	i = m->m_len - (sizeof (struct ip) + olen);	bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i);	m->m_len -= olen;}u_char inetctlerrmap[PRC_NCMDS] = {	ECONNABORTED,	ECONNABORTED,	0,		0,	0,		0,		EHOSTDOWN,	EHOSTUNREACH,	ENETUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,	EMSGSIZE,	0,		0,		0,	0,		0,		0,		0};ip_ctlinput(cmd, arg)	int cmd;	caddr_t arg;{	struct in_addr *in;	int tcp_abort(), udp_abort();	extern struct inpcb tcb, udb;	if (cmd < 0 || cmd > PRC_NCMDS)		return;	if (inetctlerrmap[cmd] == 0)		return;		/* XXX */	if (cmd == PRC_IFDOWN)		in = &((struct sockaddr_in *)arg)->sin_addr;	else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH)		in = (struct in_addr *)arg;	else		in = &((struct icmp *)arg)->icmp_ip.ip_dst;/* THIS IS VERY QUESTIONABLE, SHOULD HIT ALL PROTOCOLS */	in_pcbnotify(&tcb, in, (int)inetctlerrmap[cmd], tcp_abort);	in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort);}#endif	/* NEVER */int	ipprintfs = 0;int	ipforwarding = 1;/* * Forward a packet.  If some error occurs return the sender * and icmp packet.  Note we can't always generate a meaningful * icmp message because icmp doesn't have a large enough repetoire * of codes and types. */ip_forward(ip)	register struct ip *ip;{#ifdef NEVER	register int error, type, code;	struct mbuf *mopt, *mcopy;#endif NEVER#ifdef	DUMP_DEBUG1	dprint(dump_debug, 0,		"ip_forward(ip 0x%x)\n",		ip);#endif	/* DUMP_DEBUG */#ifdef	NEVER	/*	 * don't forward broadcasts which escape from the net	 * for which they were destined  -- happens with multiple	 * IP nets on one Ethernet	 */	if (in_netof(ip->ip_dst) == INADDR_ANY ||	    (in_lnaof(ip->ip_dst) == INADDR_ANY &&	    in_netof(ip->ip_dst) == in_netof(ip->ip_src))) {		m_freem(dtom(ip));		return;	}	if (ipprintfs)		printf("forward: src %x dst %x ttl %x\n", ip->ip_src,			ip->ip_dst, ip->ip_ttl);	if (ipforwarding == 0) {		/* can't tell difference between net and host */		type = ICMP_UNREACH, code = ICMP_UNREACH_NET;		goto sendicmp;	}	if (ip->ip_ttl < IPTTLDEC) {		type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;		goto sendicmp;	}	ip->ip_ttl -= IPTTLDEC;	mopt = m_get(M_DONTWAIT, MT_DATA);	if (mopt == NULL) {		m_freem(dtom(ip));		return;	}	/*	 * Save at most 64 bytes of the packet in case	 * we need to generate an ICMP message to the src.	 */	mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64));	ip_stripoptions(ip, mopt);	error = ip_output(dtom(ip), mopt, (struct route *)0, IP_FORWARDING);	if (error == 0) {		if (mcopy)			m_freem(mcopy);		return;	}	if (mcopy == NULL)		return;	ip = mtod(mcopy, struct ip *);	type = ICMP_UNREACH, code = 0;		/* need ``undefined'' */	switch (error) {	case ENETUNREACH:	case ENETDOWN:		code = ICMP_UNREACH_NET;		break;	case EMSGSIZE:		code = ICMP_UNREACH_NEEDFRAG;		break;	case EPERM:		code = ICMP_UNREACH_PORT;		break;	case ENOBUFS:		type = ICMP_SOURCEQUENCH;		break;	case EHOSTDOWN:	case EHOSTUNREACH:		code = ICMP_UNREACH_HOST;		break;	}sendicmp:	/* don't give error replies to broadcasts */	if (in_lnaof(ip->ip_dst) == INADDR_ANY) {		m_freem(dtom(ip));		return;	}	icmp_error(ip, type, code);#endif	/* NEVER */}

⌨️ 快捷键说明

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