V1.50 ((inet 4 of 4) updated IP/TCP and XNS sources for 4.3BSD)

Keith Bostic bostic at OKEEFFE.BERKELEY.EDU
Tue Apr 5 13:18:09 AEST 1988


Subject: (inet 4 of 4) updated IP/TCP and XNS sources for 4.3BSD
Index: sys 4.3BSD

Description:
	This is number 5 of 11 total articles posted to the newsgroup
	comp.bugs.4bsd.ucb-fixes.  This archive is number 4 of the 4
	articles that make up the inet posting.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	netinet
#	netinet/ip.h
#	netinet/ip_icmp.c
#	netinet/ip_icmp.h
#	netinet/ip_input.c
#	netinet/ip_output.c
#	netinet/ip_var.h
#	netinet/raw_ip.c
#	netinet/udp.h
#	netinet/udp_usrreq.c
#	netinet/udp_var.h
#
echo c - netinet
mkdir netinet > /dev/null 2>&1
echo x - netinet/ip.h
sed 's/^X//' >netinet/ip.h << 'END-of-netinet/ip.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)ip.h	7.6.1.1 (Berkeley) 3/15/88
X */
X#ifndef BYTE_ORDER
X/*
X * Definitions for byte order,
X * according to byte significance from low address to high.
X */
X#define	LITTLE_ENDIAN	1234	/* least-significant byte first (vax) */
X#define	BIG_ENDIAN	4321	/* most-significant byte first (IBM, net) */
X#define	PDP_ENDIAN	3412	/* LSB first in word, MSW first in long (pdp) */
X
X#ifdef vax
X#define	BYTE_ORDER	LITTLE_ENDIAN
X#else
X#define	BYTE_ORDER	BIG_ENDIAN	/* mc68000, tahoe, most others */
X#endif
X#endif BYTE_ORDER
X
X/*
X * Definitions for internet protocol version 4.
X * Per RFC 791, September 1981.
X */
X#define	IPVERSION	4
X
X/*
X * Structure of an internet header, naked of options.
X *
X * We declare ip_len and ip_off to be short, rather than u_short
X * pragmatically since otherwise unsigned comparisons can result
X * against negative integers quite easily, and fail in subtle ways.
X */
Xstruct ip {
X#if BYTE_ORDER == LITTLE_ENDIAN 
X	u_char	ip_hl:4,		/* header length */
X		ip_v:4;			/* version */
X#endif
X#if BYTE_ORDER == BIG_ENDIAN 
X	u_char	ip_v:4,			/* version */
X		ip_hl:4;		/* header length */
X#endif
X	u_char	ip_tos;			/* type of service */
X	short	ip_len;			/* total length */
X	u_short	ip_id;			/* identification */
X	short	ip_off;			/* fragment offset field */
X#define	IP_DF 0x4000			/* dont fragment flag */
X#define	IP_MF 0x2000			/* more fragments flag */
X	u_char	ip_ttl;			/* time to live */
X	u_char	ip_p;			/* protocol */
X	u_short	ip_sum;			/* checksum */
X	struct	in_addr ip_src,ip_dst;	/* source and dest address */
X};
X
X#define	IP_MAXPACKET	65535		/* maximum packet size */
X
X/*
X * Definitions for options.
X */
X#define	IPOPT_COPIED(o)		((o)&0x80)
X#define	IPOPT_CLASS(o)		((o)&0x60)
X#define	IPOPT_NUMBER(o)		((o)&0x1f)
X
X#define	IPOPT_CONTROL		0x00
X#define	IPOPT_RESERVED1		0x20
X#define	IPOPT_DEBMEAS		0x40
X#define	IPOPT_RESERVED2		0x60
X
X#define	IPOPT_EOL		0		/* end of option list */
X#define	IPOPT_NOP		1		/* no operation */
X
X#define	IPOPT_RR		7		/* record packet route */
X#define	IPOPT_TS		68		/* timestamp */
X#define	IPOPT_SECURITY		130		/* provide s,c,h,tcc */
X#define	IPOPT_LSRR		131		/* loose source route */
X#define	IPOPT_SATID		136		/* satnet id */
X#define	IPOPT_SSRR		137		/* strict source route */
X
X/*
X * Offsets to fields in options other than EOL and NOP.
X */
X#define	IPOPT_OPTVAL		0		/* option ID */
X#define	IPOPT_OLEN		1		/* option length */
X#define IPOPT_OFFSET		2		/* offset within option */
X#define	IPOPT_MINOFF		4		/* min value of above */
X
X/*
X * Time stamp option structure.
X */
Xstruct	ip_timestamp {
X	u_char	ipt_code;		/* IPOPT_TS */
X	u_char	ipt_len;		/* size of structure (variable) */
X	u_char	ipt_ptr;		/* index of current entry */
X#if BYTE_ORDER == LITTLE_ENDIAN 
X	u_char	ipt_flg:4,		/* flags, see below */
X		ipt_oflw:4;		/* overflow counter */
X#endif
X#if BYTE_ORDER == BIG_ENDIAN 
X	u_char	ipt_oflw:4,		/* overflow counter */
X		ipt_flg:4;		/* flags, see below */
X#endif
X	union ipt_timestamp {
X		n_long	ipt_time[1];
X		struct	ipt_ta {
X			struct in_addr ipt_addr;
X			n_long ipt_time;
X		} ipt_ta[1];
X	} ipt_timestamp;
X};
X
X/* flag bits for ipt_flg */
X#define	IPOPT_TS_TSONLY		0		/* timestamps only */
X#define	IPOPT_TS_TSANDADDR	1		/* timestamps and addresses */
X#define	IPOPT_TS_PRESPEC	2		/* specified modules only */
X
X/* bits for security (not byte swapped) */
X#define	IPOPT_SECUR_UNCLASS	0x0000
X#define	IPOPT_SECUR_CONFID	0xf135
X#define	IPOPT_SECUR_EFTO	0x789a
X#define	IPOPT_SECUR_MMMM	0xbc4d
X#define	IPOPT_SECUR_RESTR	0xaf13
X#define	IPOPT_SECUR_SECRET	0xd788
X#define	IPOPT_SECUR_TOPSECRET	0x6bc5
X
X/*
X * Internet implementation parameters.
X */
X#define	MAXTTL		255		/* maximum time to live (seconds) */
X#define	IPFRAGTTL	60		/* time to live for frags, slowhz */
X#define	IPTTLDEC	1		/* subtracted when forwarding */
X
X#define	IP_MSS		576		/* default maximum segment size */
END-of-netinet/ip.h
echo x - netinet/ip_icmp.c
sed 's/^X//' >netinet/ip_icmp.c << 'END-of-netinet/ip_icmp.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)ip_icmp.c	7.7 (Berkeley) 12/7/87
X */
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "protosw.h"
X#include "socket.h"
X#include "time.h"
X#include "kernel.h"
X
X#include "../net/route.h"
X#include "../net/if.h"
X
X#include "in.h"
X#include "in_systm.h"
X#include "in_var.h"
X#include "ip.h"
X#include "ip_icmp.h"
X#include "icmp_var.h"
X
X#ifdef ICMPPRINTFS
X/*
X * ICMP routines: error generation, receive packet processing, and
X * routines to turnaround packets back to the originator, and
X * host table maintenance routines.
X */
Xint	icmpprintfs = 0;
X#endif
X
X/*
X * Generate an error packet of type error
X * in response to bad packet ip.
X */
X/*VARARGS4*/
Xicmp_error(oip, type, code, ifp, dest)
X	struct ip *oip;
X	int type, code;
X	struct ifnet *ifp;
X	struct in_addr dest;
X{
X	register unsigned oiplen = oip->ip_hl << 2;
X	register struct icmp *icp;
X	struct mbuf *m;
X	struct ip *nip;
X	unsigned icmplen;
X
X#ifdef ICMPPRINTFS
X	if (icmpprintfs)
X		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
X#endif
X	if (type != ICMP_REDIRECT)
X		icmpstat.icps_error++;
X	/*
X	 * Don't send error if not the first fragment of message.
X	 * Don't error if the old packet protocol was ICMP
X	 * error message, only known informational types.
X	 */
X	if (oip->ip_off &~ (IP_MF|IP_DF))
X		goto free;
X	if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
X	  !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
X		icmpstat.icps_oldicmp++;
X		goto free;
X	}
X
X	/*
X	 * First, formulate icmp message
X	 */
X	m = m_get(M_DONTWAIT, MT_HEADER);
X	if (m == NULL)
X		goto free;
X	icmplen = oiplen + MIN(8, oip->ip_len);
X	m->m_len = icmplen + ICMP_MINLEN;
X	m->m_off = MMAXOFF - m->m_len;
X	icp = mtod(m, struct icmp *);
X	if ((u_int)type > ICMP_MAXTYPE)
X		panic("icmp_error");
X	icmpstat.icps_outhist[type]++;
X	icp->icmp_type = type;
X	if (type == ICMP_REDIRECT)
X		icp->icmp_gwaddr = dest;
X	else
X		icp->icmp_void = 0;
X	if (type == ICMP_PARAMPROB) {
X		icp->icmp_pptr = code;
X		code = 0;
X	}
X	icp->icmp_code = code;
X	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
X	nip = &icp->icmp_ip;
X	nip->ip_len += oiplen;
X	nip->ip_len = htons((u_short)nip->ip_len);
X
X	/*
X	 * Now, copy old ip header in front of icmp message.
X	 */
X	if (m->m_len + oiplen > MLEN)
X		oiplen = sizeof(struct ip);
X	if (m->m_len + oiplen > MLEN)
X		panic("icmp len");
X	m->m_off -= oiplen;
X	m->m_len += oiplen;
X	nip = mtod(m, struct ip *);
X	bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
X	nip->ip_len = m->m_len;
X	nip->ip_p = IPPROTO_ICMP;
X	icmp_reflect(nip, ifp);
X
Xfree:
X	m_freem(dtom(oip));
X}
X
Xstatic struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
Xstatic struct sockaddr_in icmpsrc = { AF_INET };
Xstatic struct sockaddr_in icmpdst = { AF_INET };
Xstatic struct sockaddr_in icmpgw = { AF_INET };
Xstruct in_ifaddr *ifptoia();
X
X/*
X * Process a received ICMP message.
X */
Xicmp_input(m, ifp)
X	register struct mbuf *m;
X	struct ifnet *ifp;
X{
X	register struct icmp *icp;
X	register struct ip *ip = mtod(m, struct ip *);
X	int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
X	register int i;
X	struct in_ifaddr *ia;
X	int (*ctlfunc)(), code;
X	extern u_char ip_protox[];
X	extern struct in_addr in_makeaddr();
X
X	/*
X	 * Locate icmp structure in mbuf, and check
X	 * that not corrupted and of at least minimum length.
X	 */
X#ifdef ICMPPRINTFS
X	if (icmpprintfs)
X		printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
X#endif
X	if (icmplen < ICMP_MINLEN) {
X		icmpstat.icps_tooshort++;
X		goto free;
X	}
X	i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
X 	if ((m->m_off > MMAXOFF || m->m_len < i) &&
X 		(m = m_pullup(m, i)) == 0)  {
X		icmpstat.icps_tooshort++;
X		return;
X	}
X 	ip = mtod(m, struct ip *);
X	m->m_len -= hlen;
X	m->m_off += hlen;
X	icp = mtod(m, struct icmp *);
X	if (in_cksum(m, icmplen)) {
X		icmpstat.icps_checksum++;
X		goto free;
X	}
X	m->m_len += hlen;
X	m->m_off -= hlen;
X
X#ifdef ICMPPRINTFS
X	/*
X	 * Message type specific processing.
X	 */
X	if (icmpprintfs)
X		printf("icmp_input, type %d code %d\n", icp->icmp_type,
X		    icp->icmp_code);
X#endif
X	if (icp->icmp_type > ICMP_MAXTYPE)
X		goto raw;
X	icmpstat.icps_inhist[icp->icmp_type]++;
X	code = icp->icmp_code;
X	switch (icp->icmp_type) {
X
X	case ICMP_UNREACH:
X		if (code > 5)
X			goto badcode;
X		code += PRC_UNREACH_NET;
X		goto deliver;
X
X	case ICMP_TIMXCEED:
X		if (code > 1)
X			goto badcode;
X		code += PRC_TIMXCEED_INTRANS;
X		goto deliver;
X
X	case ICMP_PARAMPROB:
X		if (code)
X			goto badcode;
X		code = PRC_PARAMPROB;
X		goto deliver;
X
X	case ICMP_SOURCEQUENCH:
X		if (code)
X			goto badcode;
X		code = PRC_QUENCH;
X	deliver:
X		/*
X		 * Problem with datagram; advise higher level routines.
X		 */
X		icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
X		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
X			icmpstat.icps_badlen++;
X			goto free;
X		}
X#ifdef ICMPPRINTFS
X		if (icmpprintfs)
X			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
X#endif
X		icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
X		if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
X			(*ctlfunc)(code, (struct sockaddr *)&icmpsrc);
X		break;
X
X	badcode:
X		icmpstat.icps_badcode++;
X		break;
X
X	case ICMP_ECHO:
X		icp->icmp_type = ICMP_ECHOREPLY;
X		goto reflect;
X
X	case ICMP_TSTAMP:
X		if (icmplen < ICMP_TSLEN) {
X			icmpstat.icps_badlen++;
X			break;
X		}
X		icp->icmp_type = ICMP_TSTAMPREPLY;
X		icp->icmp_rtime = iptime();
X		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
X		goto reflect;
X		
X	case ICMP_IREQ:
X#define	satosin(sa)	((struct sockaddr_in *)(sa))
X		if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp)))
X			ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
X			    in_lnaof(ip->ip_src));
X		icp->icmp_type = ICMP_IREQREPLY;
X		goto reflect;
X
X	case ICMP_MASKREQ:
X		if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0)
X			break;
X		icp->icmp_type = ICMP_MASKREPLY;
X		icp->icmp_mask = htonl(ia->ia_subnetmask);
X		if (ip->ip_src.s_addr == 0) {
X			if (ia->ia_ifp->if_flags & IFF_BROADCAST)
X			    ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
X			else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
X			    ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
X		}
Xreflect:
X		ip->ip_len += hlen;	/* since ip_input deducts this */
X		icmpstat.icps_reflect++;
X		icmpstat.icps_outhist[icp->icmp_type]++;
X		icmp_reflect(ip, ifp);
X		return;
X
X	case ICMP_REDIRECT:
X		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
X			icmpstat.icps_badlen++;
X			break;
X		}
X		/*
X		 * Short circuit routing redirects to force
X		 * immediate change in the kernel's routing
X		 * tables.  The message is also handed to anyone
X		 * listening on a raw socket (e.g. the routing
X		 * daemon for use in updating its tables).
X		 */
X		icmpgw.sin_addr = ip->ip_src;
X		icmpdst.sin_addr = icp->icmp_gwaddr;
X#ifdef	ICMPPRINTFS
X		if (icmpprintfs)
X			printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
X				icp->icmp_gwaddr);
X#endif
X		if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
X			icmpsrc.sin_addr =
X			 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
X			rtredirect((struct sockaddr *)&icmpsrc,
X			  (struct sockaddr *)&icmpdst, RTF_GATEWAY,
X			  (struct sockaddr *)&icmpgw);
X			icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
X			pfctlinput(PRC_REDIRECT_NET,
X			  (struct sockaddr *)&icmpsrc);
X		} else {
X			icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
X			rtredirect((struct sockaddr *)&icmpsrc,
X			  (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST,
X			  (struct sockaddr *)&icmpgw);
X			pfctlinput(PRC_REDIRECT_HOST,
X			  (struct sockaddr *)&icmpsrc);
X		}
X		break;
X
X	/*
X	 * No kernel processing for the following;
X	 * just fall through to send to raw listener.
X	 */
X	case ICMP_ECHOREPLY:
X	case ICMP_TSTAMPREPLY:
X	case ICMP_IREQREPLY:
X	case ICMP_MASKREPLY:
X	default:
X		break;
X	}
X
Xraw:
X	icmpsrc.sin_addr = ip->ip_src;
X	icmpdst.sin_addr = ip->ip_dst;
X	raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
X	    (struct sockaddr *)&icmpdst);
X	return;
X
Xfree:
X	m_freem(m);
X}
X
X/*
X * Reflect the ip packet back to the source
X */
Xicmp_reflect(ip, ifp)
X	register struct ip *ip;
X	struct ifnet *ifp;
X{
X	register struct in_ifaddr *ia;
X	struct in_addr t;
X	struct mbuf *opts = 0, *ip_srcroute();
X	int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
X
X	t = ip->ip_dst;
X	ip->ip_dst = ip->ip_src;
X	/*
X	 * If the incoming packet was addressed directly to us,
X	 * use dst as the src for the reply.  Otherwise (broadcast
X	 * or anonymous), use the address which corresponds
X	 * to the incoming interface.
X	 */
X	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
X		if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
X			break;
X		if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
X		    t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
X			break;
X	}
X	if (ia == (struct in_ifaddr *)0)
X		ia = ifptoia(ifp);
X	if (ia == (struct in_ifaddr *)0)
X		ia = in_ifaddr;
X	t = IA_SIN(ia)->sin_addr;
X	ip->ip_src = t;
X	ip->ip_ttl = MAXTTL;
X
X	if (optlen > 0) {
X		/*
X		 * Retrieve any source routing from the incoming packet
X		 * and strip out other options.  Adjust the IP length.
X		 */
X		opts = ip_srcroute();
X		ip->ip_len -= optlen;
X		ip_stripoptions(ip, (struct mbuf *)0);
X	}
X	icmp_send(ip, opts);
X	if (opts)
X		(void)m_free(opts);
X}
X
Xstruct in_ifaddr *
Xifptoia(ifp)
X	struct ifnet *ifp;
X{
X	register struct in_ifaddr *ia;
X
X	for (ia = in_ifaddr; ia; ia = ia->ia_next)
X		if (ia->ia_ifp == ifp)
X			return (ia);
X	return ((struct in_ifaddr *)0);
X}
X
X/*
X * Send an icmp packet back to the ip level,
X * after supplying a checksum.
X */
Xicmp_send(ip, opts)
X	register struct ip *ip;
X	struct mbuf *opts;
X{
X	register int hlen;
X	register struct icmp *icp;
X	register struct mbuf *m;
X
X	m = dtom(ip);
X	hlen = ip->ip_hl << 2;
X	m->m_off += hlen;
X	m->m_len -= hlen;
X	icp = mtod(m, struct icmp *);
X	icp->icmp_cksum = 0;
X	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
X	m->m_off -= hlen;
X	m->m_len += hlen;
X#ifdef ICMPPRINTFS
X	if (icmpprintfs)
X		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
X#endif
X	(void) ip_output(m, opts, (struct route *)0, 0);
X}
X
Xn_time
Xiptime()
X{
X	struct timeval atv;
X	u_long t;
X
X	microtime(&atv);
X	t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
X	return (htonl(t));
X}
END-of-netinet/ip_icmp.c
echo x - netinet/ip_icmp.h
sed 's/^X//' >netinet/ip_icmp.h << 'END-of-netinet/ip_icmp.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)ip_icmp.h	7.3 (Berkeley) 12/7/87
X */
X
X/*
X * Interface Control Message Protocol Definitions.
X * Per RFC 792, September 1981.
X */
X
X/*
X * Structure of an icmp header.
X */
Xstruct icmp {
X	u_char	icmp_type;		/* type of message, see below */
X	u_char	icmp_code;		/* type sub code */
X	u_short	icmp_cksum;		/* ones complement cksum of struct */
X	union {
X		u_char ih_pptr;			/* ICMP_PARAMPROB */
X		struct in_addr ih_gwaddr;	/* ICMP_REDIRECT */
X		struct ih_idseq {
X			n_short	icd_id;
X			n_short	icd_seq;
X		} ih_idseq;
X		int ih_void;
X	} icmp_hun;
X#define	icmp_pptr	icmp_hun.ih_pptr
X#define	icmp_gwaddr	icmp_hun.ih_gwaddr
X#define	icmp_id		icmp_hun.ih_idseq.icd_id
X#define	icmp_seq	icmp_hun.ih_idseq.icd_seq
X#define	icmp_void	icmp_hun.ih_void
X	union {
X		struct id_ts {
X			n_time its_otime;
X			n_time its_rtime;
X			n_time its_ttime;
X		} id_ts;
X		struct id_ip  {
X			struct ip idi_ip;
X			/* options and then 64 bits of data */
X		} id_ip;
X		u_long	id_mask;
X		char	id_data[1];
X	} icmp_dun;
X#define	icmp_otime	icmp_dun.id_ts.its_otime
X#define	icmp_rtime	icmp_dun.id_ts.its_rtime
X#define	icmp_ttime	icmp_dun.id_ts.its_ttime
X#define	icmp_ip		icmp_dun.id_ip.idi_ip
X#define	icmp_mask	icmp_dun.id_mask
X#define	icmp_data	icmp_dun.id_data
X};
X
X/*
X * Lower bounds on packet lengths for various types.
X * For the error advice packets must first insure that the
X * packet is large enought to contain the returned ip header.
X * Only then can we do the check to see if 64 bits of packet
X * data have been returned, since we need to check the returned
X * ip header length.
X */
X#define	ICMP_MINLEN	8				/* abs minimum */
X#define	ICMP_TSLEN	(8 + 3 * sizeof (n_time))	/* timestamp */
X#define	ICMP_MASKLEN	12				/* address mask */
X#define	ICMP_ADVLENMIN	(8 + sizeof (struct ip) + 8)	/* min */
X#define	ICMP_ADVLEN(p)	(8 + ((p)->icmp_ip.ip_hl << 2) + 8)
X	/* N.B.: must separately check that ip_hl >= 5 */
X
X/*
X * Definition of type and code field values.
X */
X#define	ICMP_ECHOREPLY		0		/* echo reply */
X#define	ICMP_UNREACH		3		/* dest unreachable, codes: */
X#define		ICMP_UNREACH_NET	0		/* bad net */
X#define		ICMP_UNREACH_HOST	1		/* bad host */
X#define		ICMP_UNREACH_PROTOCOL	2		/* bad protocol */
X#define		ICMP_UNREACH_PORT	3		/* bad port */
X#define		ICMP_UNREACH_NEEDFRAG	4		/* IP_DF caused drop */
X#define		ICMP_UNREACH_SRCFAIL	5		/* src route failed */
X#define	ICMP_SOURCEQUENCH	4		/* packet lost, slow down */
X#define	ICMP_REDIRECT		5		/* shorter route, codes: */
X#define		ICMP_REDIRECT_NET	0		/* for network */
X#define		ICMP_REDIRECT_HOST	1		/* for host */
X#define		ICMP_REDIRECT_TOSNET	2		/* for tos and net */
X#define		ICMP_REDIRECT_TOSHOST	3		/* for tos and host */
X#define	ICMP_ECHO		8		/* echo service */
X#define	ICMP_TIMXCEED		11		/* time exceeded, code: */
X#define		ICMP_TIMXCEED_INTRANS	0		/* ttl==0 in transit */
X#define		ICMP_TIMXCEED_REASS	1		/* ttl==0 in reass */
X#define	ICMP_PARAMPROB		12		/* ip header bad */
X#define	ICMP_TSTAMP		13		/* timestamp request */
X#define	ICMP_TSTAMPREPLY	14		/* timestamp reply */
X#define	ICMP_IREQ		15		/* information request */
X#define	ICMP_IREQREPLY		16		/* information reply */
X#define	ICMP_MASKREQ		17		/* address mask request */
X#define	ICMP_MASKREPLY		18		/* address mask reply */
X
X#define	ICMP_MAXTYPE		18
X
X#define	ICMP_INFOTYPE(type) \
X	((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
X	(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
X	(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
X	(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
END-of-netinet/ip_icmp.h
echo x - netinet/ip_input.c
sed 's/^X//' >netinet/ip_input.c << 'END-of-netinet/ip_input.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)ip_input.c	7.9 (Berkeley) 3/15/88
X */
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "domain.h"
X#include "protosw.h"
X#include "socket.h"
X#include "errno.h"
X#include "time.h"
X#include "kernel.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X
X#include "in.h"
X#include "in_pcb.h"
X#include "in_systm.h"
X#include "in_var.h"
X#include "ip.h"
X#include "ip_var.h"
X#include "ip_icmp.h"
X#include "tcp.h"
X
Xu_char	ip_protox[IPPROTO_MAX];
Xint	ipqmaxlen = IFQ_MAXLEN;
Xstruct	in_ifaddr *in_ifaddr;			/* first inet address */
X
X/*
X * We need to save the IP options in case a protocol wants to respond
X * to an incoming packet over the same route if the packet got here
X * using IP source routing.  This allows connection establishment and
X * maintenance when the remote end is on a network that is not known
X * to us.
X */
Xint	ip_nhops = 0;
Xstatic	struct ip_srcrt {
X	char	nop;				/* one NOP to align */
X	char	srcopt[IPOPT_OFFSET + 1];	/* OPTVAL, OLEN and OFFSET */
X	struct	in_addr route[MAX_IPOPTLEN];
X} ip_srcrt;
X
X/*
X * IP initialization: fill in IP protocol switch table.
X * All protocols not implemented in kernel go to raw IP protocol handler.
X */
Xip_init()
X{
X	register struct protosw *pr;
X	register int i;
X
X	pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW);
X	if (pr == 0)
X		panic("ip_init");
X	for (i = 0; i < IPPROTO_MAX; i++)
X		ip_protox[i] = pr - inetsw;
X	for (pr = inetdomain.dom_protosw;
X	    pr < inetdomain.dom_protoswNPROTOSW; pr++)
X		if (pr->pr_domain->dom_family == PF_INET &&
X		    pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
X			ip_protox[pr->pr_protocol] = pr - inetsw;
X	ipq.next = ipq.prev = &ipq;
X	ip_id = time.tv_sec & 0xffff;
X	ipintrq.ifq_maxlen = ipqmaxlen;
X}
X
Xu_char	ipcksum = 1;
Xstruct	ip *ip_reass();
Xstruct	sockaddr_in ipaddr = { AF_INET };
Xstruct	route ipforward_rt;
X
X/*
X * Ip input routine.  Checksum and byte swap header.  If fragmented
X * try to reassamble.  If complete and fragment queue exists, discard.
X * Process options.  Pass to next level.
X */
Xipintr()
X{
X	register struct ip *ip;
X	register struct mbuf *m;
X	struct mbuf *m0;
X	register int i;
X	register struct ipq *fp;
X	register struct in_ifaddr *ia;
X	struct ifnet *ifp;
X	int hlen, s;
X
Xnext:
X	/*
X	 * Get next datagram off input queue and get IP header
X	 * in first mbuf.
X	 */
X	s = splimp();
X	IF_DEQUEUEIF(&ipintrq, m, ifp);
X	splx(s);
X	if (m == 0)
X		return;
X	/*
X	 * If no IP addresses have been set yet but the interfaces
X	 * are receiving, can't do anything with incoming packets yet.
X	 */
X	if (in_ifaddr == NULL)
X		goto bad;
X	ipstat.ips_total++;
X	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
X	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
X		ipstat.ips_toosmall++;
X		goto next;
X	}
X	ip = mtod(m, struct ip *);
X	hlen = ip->ip_hl << 2;
X	if (hlen < sizeof(struct ip)) {	/* minimum header length */
X		ipstat.ips_badhlen++;
X		goto bad;
X	}
X	if (hlen > m->m_len) {
X		if ((m = m_pullup(m, hlen)) == 0) {
X			ipstat.ips_badhlen++;
X			goto next;
X		}
X		ip = mtod(m, struct ip *);
X	}
X	if (ipcksum)
X		if (ip->ip_sum = in_cksum(m, hlen)) {
X			ipstat.ips_badsum++;
X			goto bad;
X		}
X
X	/*
X	 * Convert fields to host representation.
X	 */
X	ip->ip_len = ntohs((u_short)ip->ip_len);
X	if (ip->ip_len < hlen) {
X		ipstat.ips_badlen++;
X		goto bad;
X	}
X	ip->ip_id = ntohs(ip->ip_id);
X	ip->ip_off = ntohs((u_short)ip->ip_off);
X
X	/*
X	 * Check that the amount of data in the buffers
X	 * is as at least much as the IP header would have us expect.
X	 * Trim mbufs if longer than we expect.
X	 * Drop packet if shorter than we expect.
X	 */
X	i = -(u_short)ip->ip_len;
X	m0 = m;
X	for (;;) {
X		i += m->m_len;
X		if (m->m_next == 0)
X			break;
X		m = m->m_next;
X	}
X	if (i != 0) {
X		if (i < 0) {
X			ipstat.ips_tooshort++;
X			m = m0;
X			goto bad;
X		}
X		if (i <= m->m_len)
X			m->m_len -= i;
X		else
X			m_adj(m0, -i);
X	}
X	m = m0;
X
X	/*
X	 * Process options and, if not destined for us,
X	 * ship it on.  ip_dooptions returns 1 when an
X	 * error was detected (causing an icmp message
X	 * to be sent and the original packet to be freed).
X	 */
X	ip_nhops = 0;		/* for source routed packets */
X	if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp))
X		goto next;
X
X	/*
X	 * Check our list of addresses, to see if the packet is for us.
X	 */
X	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
X#define	satosin(sa)	((struct sockaddr_in *)(sa))
X
X		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
X			goto ours;
X		if (
X#ifdef	DIRECTED_BROADCAST
X		    ia->ia_ifp == ifp &&
X#endif
X		    (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
X			u_long t;
X
X			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
X			    ip->ip_dst.s_addr)
X				goto ours;
X			if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
X				goto ours;
X			/*
X			 * Look for all-0's host part (old broadcast addr),
X			 * either for subnet or net.
X			 */
X			t = ntohl(ip->ip_dst.s_addr);
X			if (t == ia->ia_subnet)
X				goto ours;
X			if (t == ia->ia_net)
X				goto ours;
X		}
X	}
X	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
X		goto ours;
X	if (ip->ip_dst.s_addr == INADDR_ANY)
X		goto ours;
X
X	/*
X	 * Not for us; forward if possible and desirable.
X	 */
X	ip_forward(ip, ifp);
X	goto next;
X
Xours:
X	/*
X	 * If offset or IP_MF are set, must reassemble.
X	 * Otherwise, nothing need be done.
X	 * (We could look in the reassembly queue to see
X	 * if the packet was previously fragmented,
X	 * but it's not worth the time; just let them time out.)
X	 */
X	if (ip->ip_off &~ IP_DF) {
X		/*
X		 * Look for queue of fragments
X		 * of this datagram.
X		 */
X		for (fp = ipq.next; fp != &ipq; fp = fp->next)
X			if (ip->ip_id == fp->ipq_id &&
X			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
X			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
X			    ip->ip_p == fp->ipq_p)
X				goto found;
X		fp = 0;
Xfound:
X
X		/*
X		 * Adjust ip_len to not reflect header,
X		 * set ip_mff if more fragments are expected,
X		 * convert offset of this to bytes.
X		 */
X		ip->ip_len -= hlen;
X		((struct ipasfrag *)ip)->ipf_mff = 0;
X		if (ip->ip_off & IP_MF)
X			((struct ipasfrag *)ip)->ipf_mff = 1;
X		ip->ip_off <<= 3;
X
X		/*
X		 * If datagram marked as having more fragments
X		 * or if this is not the first fragment,
X		 * attempt reassembly; if it succeeds, proceed.
X		 */
X		if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) {
X			ipstat.ips_fragments++;
X			ip = ip_reass((struct ipasfrag *)ip, fp);
X			if (ip == 0)
X				goto next;
X			m = dtom(ip);
X		} else
X			if (fp)
X				ip_freef(fp);
X	} else
X		ip->ip_len -= hlen;
X
X	/*
X	 * Switch out to protocol's input routine.
X	 */
X	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp);
X	goto next;
Xbad:
X	m_freem(m);
X	goto next;
X}
X
X/*
X * Take incoming datagram fragment and try to
X * reassemble it into whole datagram.  If a chain for
X * reassembly of this datagram already exists, then it
X * is given as fp; otherwise have to make a chain.
X */
Xstruct ip *
Xip_reass(ip, fp)
X	register struct ipasfrag *ip;
X	register struct ipq *fp;
X{
X	register struct mbuf *m = dtom(ip);
X	register struct ipasfrag *q;
X	struct mbuf *t;
X	int hlen = ip->ip_hl << 2;
X	int i, next;
X
X	/*
X	 * Presence of header sizes in mbufs
X	 * would confuse code below.
X	 */
X	m->m_off += hlen;
X	m->m_len -= hlen;
X
X	/*
X	 * If first fragment to arrive, create a reassembly queue.
X	 */
X	if (fp == 0) {
X		if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL)
X			goto dropfrag;
X		fp = mtod(t, struct ipq *);
X		insque(fp, &ipq);
X		fp->ipq_ttl = IPFRAGTTL;
X		fp->ipq_p = ip->ip_p;
X		fp->ipq_id = ip->ip_id;
X		fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp;
X		fp->ipq_src = ((struct ip *)ip)->ip_src;
X		fp->ipq_dst = ((struct ip *)ip)->ip_dst;
X		q = (struct ipasfrag *)fp;
X		goto insert;
X	}
X
X	/*
X	 * Find a segment which begins after this one does.
X	 */
X	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next)
X		if (q->ip_off > ip->ip_off)
X			break;
X
X	/*
X	 * If there is a preceding segment, it may provide some of
X	 * our data already.  If so, drop the data from the incoming
X	 * segment.  If it provides all of our data, drop us.
X	 */
X	if (q->ipf_prev != (struct ipasfrag *)fp) {
X		i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off;
X		if (i > 0) {
X			if (i >= ip->ip_len)
X				goto dropfrag;
X			m_adj(dtom(ip), i);
X			ip->ip_off += i;
X			ip->ip_len -= i;
X		}
X	}
X
X	/*
X	 * While we overlap succeeding segments trim them or,
X	 * if they are completely covered, dequeue them.
X	 */
X	while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) {
X		i = (ip->ip_off + ip->ip_len) - q->ip_off;
X		if (i < q->ip_len) {
X			q->ip_len -= i;
X			q->ip_off += i;
X			m_adj(dtom(q), i);
X			break;
X		}
X		q = q->ipf_next;
X		m_freem(dtom(q->ipf_prev));
X		ip_deq(q->ipf_prev);
X	}
X
Xinsert:
X	/*
X	 * Stick new segment in its place;
X	 * check for complete reassembly.
X	 */
X	ip_enq(ip, q->ipf_prev);
X	next = 0;
X	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) {
X		if (q->ip_off != next)
X			return (0);
X		next += q->ip_len;
X	}
X	if (q->ipf_prev->ipf_mff)
X		return (0);
X
X	/*
X	 * Reassembly is complete; concatenate fragments.
X	 */
X	q = fp->ipq_next;
X	m = dtom(q);
X	t = m->m_next;
X	m->m_next = 0;
X	m_cat(m, t);
X	q = q->ipf_next;
X	while (q != (struct ipasfrag *)fp) {
X		t = dtom(q);
X		q = q->ipf_next;
X		m_cat(m, t);
X	}
X
X	/*
X	 * Create header for new ip packet by
X	 * modifying header of first packet;
X	 * dequeue and discard fragment reassembly header.
X	 * Make header visible.
X	 */
X	ip = fp->ipq_next;
X	ip->ip_len = next;
X	((struct ip *)ip)->ip_src = fp->ipq_src;
X	((struct ip *)ip)->ip_dst = fp->ipq_dst;
X	remque(fp);
X	(void) m_free(dtom(fp));
X	m = dtom(ip);
X	m->m_len += (ip->ip_hl << 2);
X	m->m_off -= (ip->ip_hl << 2);
X	return ((struct ip *)ip);
X
Xdropfrag:
X	ipstat.ips_fragdropped++;
X	m_freem(m);
X	return (0);
X}
X
X/*
X * Free a fragment reassembly header and all
X * associated datagrams.
X */
Xip_freef(fp)
X	struct ipq *fp;
X{
X	register struct ipasfrag *q, *p;
X
X	for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) {
X		p = q->ipf_next;
X		ip_deq(q);
X		m_freem(dtom(q));
X	}
X	remque(fp);
X	(void) m_free(dtom(fp));
X}
X
X/*
X * Put an ip fragment on a reassembly chain.
X * Like insque, but pointers in middle of structure.
X */
Xip_enq(p, prev)
X	register struct ipasfrag *p, *prev;
X{
X
X	p->ipf_prev = prev;
X	p->ipf_next = prev->ipf_next;
X	prev->ipf_next->ipf_prev = p;
X	prev->ipf_next = p;
X}
X
X/*
X * To ip_enq as remque is to insque.
X */
Xip_deq(p)
X	register struct ipasfrag *p;
X{
X
X	p->ipf_prev->ipf_next = p->ipf_next;
X	p->ipf_next->ipf_prev = p->ipf_prev;
X}
X
X/*
X * IP timer processing;
X * if a timer expires on a reassembly
X * queue, discard it.
X */
Xip_slowtimo()
X{
X	register struct ipq *fp;
X	int s = splnet();
X
X	fp = ipq.next;
X	if (fp == 0) {
X		splx(s);
X		return;
X	}
X	while (fp != &ipq) {
X		--fp->ipq_ttl;
X		fp = fp->next;
X		if (fp->prev->ipq_ttl == 0) {
X			ipstat.ips_fragtimeout++;
X			ip_freef(fp->prev);
X		}
X	}
X	splx(s);
X}
X
X/*
X * Drain off all datagram fragments.
X */
Xip_drain()
X{
X
X	while (ipq.next != &ipq) {
X		ipstat.ips_fragdropped++;
X		ip_freef(ipq.next);
X	}
X}
X
Xextern struct in_ifaddr *ifptoia();
Xstruct in_ifaddr *ip_rtaddr();
X
X/*
X * Do option processing on a datagram,
X * possibly discarding it if bad options
X * are encountered.
X */
Xip_dooptions(ip, ifp)
X	register struct ip *ip;
X	struct ifnet *ifp;
X{
X	register u_char *cp;
X	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB;
X	register struct ip_timestamp *ipt;
X	register struct in_ifaddr *ia;
X	struct in_addr *sin;
X	n_time ntime;
X
X	cp = (u_char *)(ip + 1);
X	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
X	for (; cnt > 0; cnt -= optlen, cp += optlen) {
X		opt = cp[IPOPT_OPTVAL];
X		if (opt == IPOPT_EOL)
X			break;
X		if (opt == IPOPT_NOP)
X			optlen = 1;
X		else {
X			optlen = cp[IPOPT_OLEN];
X			if (optlen <= 0 || optlen > cnt) {
X				code = &cp[IPOPT_OLEN] - (u_char *)ip;
X				goto bad;
X			}
X		}
X		switch (opt) {
X
X		default:
X			break;
X
X		/*
X		 * Source routing with record.
X		 * Find interface with current destination address.
X		 * If none on this machine then drop if strictly routed,
X		 * or do nothing if loosely routed.
X		 * Record interface address and bring up next address
X		 * component.  If strictly routed make sure next
X		 * address on directly accessible net.
X		 */
X		case IPOPT_LSRR:
X		case IPOPT_SSRR:
X			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
X				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
X				goto bad;
X			}
X			ipaddr.sin_addr = ip->ip_dst;
X			ia = (struct in_ifaddr *)
X				ifa_ifwithaddr((struct sockaddr *)&ipaddr);
X			if (ia == 0) {
X				if (opt == IPOPT_SSRR) {
X					type = ICMP_UNREACH;
X					code = ICMP_UNREACH_SRCFAIL;
X					goto bad;
X				}
X				/*
X				 * Loose routing, and not at next destination
X				 * yet; nothing to do except forward.
X				 */
X				break;
X			}
X			off--;			/* 0 origin */
X			if (off > optlen - sizeof(struct in_addr)) {
X				/*
X				 * End of source route.  Should be for us.
X				 */
X				save_rte(cp, ip->ip_src);
X				break;
X			}
X			/*
X			 * locate outgoing interface
X			 */
X			bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr,
X			    sizeof(ipaddr.sin_addr));
X			if ((opt == IPOPT_SSRR &&
X			    in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) ||
X			    (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
X				type = ICMP_UNREACH;
X				code = ICMP_UNREACH_SRCFAIL;
X				goto bad;
X			}
X			ip->ip_dst = ipaddr.sin_addr;
X			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
X			    (caddr_t)(cp + off), sizeof(struct in_addr));
X			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
X			break;
X
X		case IPOPT_RR:
X			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
X				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
X				goto bad;
X			}
X			/*
X			 * If no space remains, ignore.
X			 */
X			off--;			/* 0 origin */
X			if (off > optlen - sizeof(struct in_addr))
X				break;
X			bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr,
X			    sizeof(ipaddr.sin_addr));
X			/*
X			 * locate outgoing interface
X			 */
X			if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
X				type = ICMP_UNREACH;
X				code = ICMP_UNREACH_HOST;
X				goto bad;
X			}
X			bcopy((caddr_t)&(IA_SIN(ia)->sin_addr),
X			    (caddr_t)(cp + off), sizeof(struct in_addr));
X			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
X			break;
X
X		case IPOPT_TS:
X			code = cp - (u_char *)ip;
X			ipt = (struct ip_timestamp *)cp;
X			if (ipt->ipt_len < 5)
X				goto bad;
X			if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) {
X				if (++ipt->ipt_oflw == 0)
X					goto bad;
X				break;
X			}
X			sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1);
X			switch (ipt->ipt_flg) {
X
X			case IPOPT_TS_TSONLY:
X				break;
X
X			case IPOPT_TS_TSANDADDR:
X				if (ipt->ipt_ptr + sizeof(n_time) +
X				    sizeof(struct in_addr) > ipt->ipt_len)
X					goto bad;
X				ia = ifptoia(ifp);
X				bcopy((caddr_t)&IA_SIN(ia)->sin_addr,
X				    (caddr_t)sin, sizeof(struct in_addr));
X				ipt->ipt_ptr += sizeof(struct in_addr);
X				break;
X
X			case IPOPT_TS_PRESPEC:
X				if (ipt->ipt_ptr + sizeof(n_time) +
X				    sizeof(struct in_addr) > ipt->ipt_len)
X					goto bad;
X				bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr,
X				    sizeof(struct in_addr));
X				if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0)
X					continue;
X				ipt->ipt_ptr += sizeof(struct in_addr);
X				break;
X
X			default:
X				goto bad;
X			}
X			ntime = iptime();
X			bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1,
X			    sizeof(n_time));
X			ipt->ipt_ptr += sizeof(n_time);
X		}
X	}
X	return (0);
Xbad:
X	icmp_error(ip, type, code, ifp);
X	return (1);
X}
X
X/*
X * Given address of next destination (final or next hop),
X * return internet address info of interface to be used to get there.
X */
Xstruct in_ifaddr *
Xip_rtaddr(dst)
X	 struct in_addr dst;
X{
X	register struct sockaddr_in *sin;
X	register struct in_ifaddr *ia;
X
X	sin = (struct sockaddr_in *) &ipforward_rt.ro_dst;
X
X	if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) {
X		if (ipforward_rt.ro_rt) {
X			RTFREE(ipforward_rt.ro_rt);
X			ipforward_rt.ro_rt = 0;
X		}
X		sin->sin_family = AF_INET;
X		sin->sin_addr = dst;
X
X		rtalloc(&ipforward_rt);
X	}
X	if (ipforward_rt.ro_rt == 0)
X		return ((struct in_ifaddr *)0);
X	/*
X	 * Find address associated with outgoing interface.
X	 */
X	for (ia = in_ifaddr; ia; ia = ia->ia_next)
X		if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp)
X			break;
X	return (ia);
X}
X
X/*
X * Save incoming source route for use in replies,
X * to be picked up later by ip_srcroute if the receiver is interested.
X */
Xsave_rte(option, dst)
X	u_char *option;
X	struct in_addr dst;
X{
X	unsigned olen;
X	extern ipprintfs;
X
X	olen = option[IPOPT_OLEN];
X	if (olen > sizeof(ip_srcrt) - 1) {
X		if (ipprintfs)
X			printf("save_rte: olen %d\n", olen);
X		return;
X	}
X	bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen);
X	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);
X	ip_srcrt.route[ip_nhops++] = dst;
X}
X
X/*
X * Retrieve incoming source route for use in replies,
X * in the same form used by setsockopt.
X * The first hop is placed before the options, will be removed later.
X */
Xstruct mbuf *
Xip_srcroute()
X{
X	register struct in_addr *p, *q;
X	register struct mbuf *m;
X
X	if (ip_nhops == 0)
X		return ((struct mbuf *)0);
X	m = m_get(M_DONTWAIT, MT_SOOPTS);
X	if (m == 0)
X		return ((struct mbuf *)0);
X	m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1;
X
X	/*
X	 * First save first hop for return route
X	 */
X	p = &ip_srcrt.route[ip_nhops - 1];
X	*(mtod(m, struct in_addr *)) = *p--;
X
X	/*
X	 * Copy option fields and padding (nop) to mbuf.
X	 */
X	ip_srcrt.nop = IPOPT_NOP;
X	bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr),
X	    IPOPT_OFFSET + 1 + 1);
X	q = (struct in_addr *)(mtod(m, caddr_t) +
X	    sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1);
X	/*
X	 * Record return path as an IP source route,
X	 * reversing the path (pointers are now aligned).
X	 */
X	while (p >= ip_srcrt.route)
X		*q++ = *p--;
X	return (m);
X}
X
X/*
X * Strip out IP options, at higher
X * level protocol in the kernel.
X * Second argument is buffer to which options
X * will be moved, and return value is their length.
X */
Xip_stripoptions(ip, mopt)
X	struct ip *ip;
X	struct mbuf *mopt;
X{
X	register int i;
X	register struct mbuf *m;
X	register caddr_t opts;
X	int olen;
X
X	olen = (ip->ip_hl<<2) - sizeof (struct ip);
X	m = dtom(ip);
X	opts = (caddr_t)(ip + 1);
X	if (mopt) {
X		mopt->m_len = olen;
X		mopt->m_off = MMINOFF;
X		bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen);
X	}
X	i = m->m_len - (sizeof (struct ip) + olen);
X	bcopy(opts  + olen, opts, (unsigned)i);
X	m->m_len -= olen;
X	ip->ip_hl = sizeof(struct ip) >> 2;
X}
X
Xu_char inetctlerrmap[PRC_NCMDS] = {
X	0,		0,		0,		0,
X	0,		0,		EHOSTDOWN,	EHOSTUNREACH,
X	ENETUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,
X	EMSGSIZE,	EHOSTUNREACH,	0,		0,
X	0,		0,		0,		0,
X	ENOPROTOOPT
X};
X
X#ifndef	IPFORWARDING
X#define	IPFORWARDING	1
X#endif
X#ifndef	IPSENDREDIRECTS
X#define	IPSENDREDIRECTS	1
X#endif
Xint	ipprintfs = 0;
Xint	ipforwarding = IPFORWARDING;
Xextern	int in_interfaces;
Xint	ipsendredirects = IPSENDREDIRECTS;
X
X/*
X * Forward a packet.  If some error occurs return the sender
X * an icmp packet.  Note we can't always generate a meaningful
X * icmp message because icmp doesn't have a large enough repertoire
X * of codes and types.
X *
X * If not forwarding (possibly because we have only a single external
X * network), just drop the packet.  This could be confusing if ipforwarding
X * was zero but some routing protocol was advancing us as a gateway
X * to somewhere.  However, we must let the routing protocol deal with that.
X */
Xip_forward(ip, ifp)
X	register struct ip *ip;
X	struct ifnet *ifp;
X{
X	register int error, type = 0, code;
X	register struct sockaddr_in *sin;
X	struct mbuf *mcopy;
X	struct in_addr dest;
X
X	dest.s_addr = 0;
X	if (ipprintfs)
X		printf("forward: src %x dst %x ttl %x\n", ip->ip_src,
X			ip->ip_dst, ip->ip_ttl);
X	ip->ip_id = htons(ip->ip_id);
X	if (ipforwarding == 0 || in_interfaces <= 1) {
X		ipstat.ips_cantforward++;
X#ifdef GATEWAY
X		type = ICMP_UNREACH, code = ICMP_UNREACH_NET;
X		goto sendicmp;
X#else
X		m_freem(dtom(ip));
X		return;
X#endif
X	}
X	if (in_canforward(ip->ip_dst) == 0) {
X		m_freem(dtom(ip));
X		return;
X	}
X	if (ip->ip_ttl <= IPTTLDEC) {
X		type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS;
X		goto sendicmp;
X	}
X	ip->ip_ttl -= IPTTLDEC;
X
X	/*
X	 * Save at most 64 bytes of the packet in case
X	 * we need to generate an ICMP message to the src.
X	 */
X	mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
X
X	sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;
X	if (ipforward_rt.ro_rt == 0 ||
X	    ip->ip_dst.s_addr != sin->sin_addr.s_addr) {
X		if (ipforward_rt.ro_rt) {
X			RTFREE(ipforward_rt.ro_rt);
X			ipforward_rt.ro_rt = 0;
X		}
X		sin->sin_family = AF_INET;
X		sin->sin_addr = ip->ip_dst;
X
X		rtalloc(&ipforward_rt);
X	}
X	/*
X	 * If forwarding packet using same interface that it came in on,
X	 * perhaps should send a redirect to sender to shortcut a hop.
X	 * Only send redirect if source is sending directly to us,
X	 * and if packet was not source routed (or has any options).
X	 * Also, don't send redirect if forwarding using a default route
X	 * or a route modfied by a redirect.
X	 */
X#define	satosin(sa)	((struct sockaddr_in *)(sa))
X	if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp &&
X	    (ipforward_rt.ro_rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
X	    satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 &&
X	    ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) {
X		struct in_ifaddr *ia;
X		u_long src = ntohl(ip->ip_src.s_addr);
X		u_long dst = ntohl(ip->ip_dst.s_addr);
X
X		if ((ia = ifptoia(ifp)) &&
X		   (src & ia->ia_subnetmask) == ia->ia_subnet) {
X		    if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY)
X			dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr;
X		    else
X			dest = ip->ip_dst;
X		    /*
X		     * If the destination is reached by a route to host,
X		     * is on a subnet of a local net, or is directly
X		     * on the attached net (!), use host redirect.
X		     * (We may be the correct first hop for other subnets.)
X		     */
X		    type = ICMP_REDIRECT;
X		    code = ICMP_REDIRECT_NET;
X		    if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) ||
X		       (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0)
X			code = ICMP_REDIRECT_HOST;
X		    else for (ia = in_ifaddr; ia = ia->ia_next; )
X			if ((dst & ia->ia_netmask) == ia->ia_net) {
X			    if (ia->ia_subnetmask != ia->ia_netmask)
X				    code = ICMP_REDIRECT_HOST;
X			    break;
X			}
X		    if (ipprintfs)
X		        printf("redirect (%d) to %x\n", code, dest);
X		}
X	}
X
X	error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt,
X		IP_FORWARDING);
X	if (error)
X		ipstat.ips_cantforward++;
X	else if (type)
X		ipstat.ips_redirectsent++;
X	else {
X		if (mcopy)
X			m_freem(mcopy);
X		ipstat.ips_forward++;
X		return;
X	}
X	if (mcopy == NULL)
X		return;
X	ip = mtod(mcopy, struct ip *);
X	type = ICMP_UNREACH;
X	switch (error) {
X
X	case 0:				/* forwarded, but need redirect */
X		type = ICMP_REDIRECT;
X		/* code set above */
X		break;
X
X	case ENETUNREACH:
X	case ENETDOWN:
X		if (in_localaddr(ip->ip_dst))
X			code = ICMP_UNREACH_HOST;
X		else
X			code = ICMP_UNREACH_NET;
X		break;
X
X	case EMSGSIZE:
X		code = ICMP_UNREACH_NEEDFRAG;
X		break;
X
X	case EPERM:
X		code = ICMP_UNREACH_PORT;
X		break;
X
X	case ENOBUFS:
X		type = ICMP_SOURCEQUENCH;
X		break;
X
X	case EHOSTDOWN:
X	case EHOSTUNREACH:
X		code = ICMP_UNREACH_HOST;
X		break;
X	}
Xsendicmp:
X	icmp_error(ip, type, code, ifp, dest);
X}
END-of-netinet/ip_input.c
echo x - netinet/ip_output.c
sed 's/^X//' >netinet/ip_output.c << 'END-of-netinet/ip_output.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)ip_output.c	7.9 (Berkeley) 3/15/88
X */
X
X#include "param.h"
X#include "mbuf.h"
X#include "errno.h"
X#include "protosw.h"
X#include "socket.h"
X#include "socketvar.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X
X#include "in.h"
X#include "in_pcb.h"
X#include "in_systm.h"
X#include "in_var.h"
X#include "ip.h"
X#include "ip_var.h"
X
X#ifdef vax
X#include "../machine/mtpr.h"
X#endif
X
Xstruct mbuf *ip_insertoptions();
X
X/*
X * IP output.  The packet in mbuf chain m contains a skeletal IP
X * header (with len, off, ttl, proto, tos, src, dst).
X * The mbuf chain containing the packet will be freed.
X * The mbuf opt, if present, will not be freed.
X */
Xip_output(m0, opt, ro, flags)
X	struct mbuf *m0;
X	struct mbuf *opt;
X	struct route *ro;
X	int flags;
X{
X	register struct ip *ip, *mhip;
X	register struct ifnet *ifp;
X	register struct mbuf *m = m0;
X	register int hlen = sizeof (struct ip);
X	int len, off, error = 0;
X	struct route iproute;
X	struct sockaddr_in *dst;
X
X	if (opt) {
X		m = ip_insertoptions(m, opt, &len);
X		hlen = len;
X	}
X	ip = mtod(m, struct ip *);
X	/*
X	 * Fill in IP header.
X	 */
X	if ((flags & IP_FORWARDING) == 0) {
X		ip->ip_v = IPVERSION;
X		ip->ip_off &= IP_DF;
X		ip->ip_id = htons(ip_id++);
X		ip->ip_hl = hlen >> 2;
X	} else
X		hlen = ip->ip_hl << 2;
X
X	/*
X	 * Route packet.
X	 */
X	if (ro == 0) {
X		ro = &iproute;
X		bzero((caddr_t)ro, sizeof (*ro));
X	}
X	dst = (struct sockaddr_in *)&ro->ro_dst;
X	/*
X	 * If there is a cached route,
X	 * check that it is to the same destination
X	 * and is still up.  If not, free it and try again.
X	 */
X	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
X	   dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
X		RTFREE(ro->ro_rt);
X		ro->ro_rt = (struct rtentry *)0;
X	}
X	if (ro->ro_rt == 0) {
X		dst->sin_family = AF_INET;
X		dst->sin_addr = ip->ip_dst;
X	}
X	/*
X	 * If routing to interface only,
X	 * short circuit routing lookup.
X	 */
X	if (flags & IP_ROUTETOIF) {
X		struct in_ifaddr *ia;
X
X		ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst);
X		if (ia == 0)
X			ia = in_iaonnetof(in_netof(ip->ip_dst));
X		if (ia == 0) {
X			error = ENETUNREACH;
X			goto bad;
X		}
X		ifp = ia->ia_ifp;
X	} else {
X		if (ro->ro_rt == 0)
X			rtalloc(ro);
X		if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) {
X			if (in_localaddr(ip->ip_dst))
X				error = EHOSTUNREACH;
X			else
X				error = ENETUNREACH;
X			goto bad;
X		}
X		ro->ro_rt->rt_use++;
X		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
X			dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway;
X	}
X#ifndef notdef
X	/*
X	 * If source address not specified yet, use address
X	 * of outgoing interface.
X	 */
X	if (ip->ip_src.s_addr == INADDR_ANY) {
X		register struct in_ifaddr *ia;
X
X		for (ia = in_ifaddr; ia; ia = ia->ia_next)
X			if (ia->ia_ifp == ifp) {
X				ip->ip_src = IA_SIN(ia)->sin_addr;
X				break;
X			}
X	}
X#endif
X	/*
X	 * Look for broadcast address and
X	 * and verify user is allowed to send
X	 * such a packet.
X	 */
X	if (in_broadcast(dst->sin_addr)) {
X		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
X			error = EADDRNOTAVAIL;
X			goto bad;
X		}
X		if ((flags & IP_ALLOWBROADCAST) == 0) {
X			error = EACCES;
X			goto bad;
X		}
X		/* don't allow broadcast messages to be fragmented */
X		if (ip->ip_len > ifp->if_mtu) {
X			error = EMSGSIZE;
X			goto bad;
X		}
X	}
X
X	/*
X	 * If small enough for interface, can just send directly.
X	 */
X	if (ip->ip_len <= ifp->if_mtu) {
X		ip->ip_len = htons((u_short)ip->ip_len);
X		ip->ip_off = htons((u_short)ip->ip_off);
X		ip->ip_sum = 0;
X		ip->ip_sum = in_cksum(m, hlen);
X		error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst);
X		goto done;
X	}
X
X	/*
X	 * Too large for interface; fragment if possible.
X	 * Must be able to put at least 8 bytes per fragment.
X	 */
X	if (ip->ip_off & IP_DF) {
X		error = EMSGSIZE;
X		goto bad;
X	}
X	len = (ifp->if_mtu - hlen) &~ 7;
X	if (len < 8) {
X		error = EMSGSIZE;
X		goto bad;
X	}
X
X    {
X	int mhlen, firstlen = len;
X	struct mbuf **mnext = &m->m_act;
X
X	/*
X	 * Loop through length of segment after first fragment,
X	 * make new header and copy data of each part and link onto chain.
X	 */
X	m0 = m;
X	mhlen = sizeof (struct ip);
X	for (off = hlen + len; off < ip->ip_len; off += len) {
X		MGET(m, M_DONTWAIT, MT_HEADER);
X		if (m == 0) {
X			error = ENOBUFS;
X			goto bad;
X		}
X		m->m_off = MMAXOFF - hlen;
X		mhip = mtod(m, struct ip *);
X		*mhip = *ip;
X		if (hlen > sizeof (struct ip)) {
X			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
X			mhip->ip_hl = mhlen >> 2;
X		}
X		m->m_len = mhlen;
X		mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
X		if (ip->ip_off & IP_MF)
X			mhip->ip_off |= IP_MF;
X		if (off + len >= ip->ip_len)
X			len = ip->ip_len - off;
X		else
X			mhip->ip_off |= IP_MF;
X		mhip->ip_len = htons((u_short)(len + mhlen));
X		m->m_next = m_copy(m0, off, len);
X		if (m->m_next == 0) {
X			error = ENOBUFS;	/* ??? */
X			goto sendorfree;
X		}
X		mhip->ip_off = htons((u_short)mhip->ip_off);
X		mhip->ip_sum = 0;
X		mhip->ip_sum = in_cksum(m, mhlen);
X		*mnext = m;
X		mnext = &m->m_act;
X	}
X	/*
X	 * Update first fragment by trimming what's been copied out
X	 * and updating header, then send each fragment (in order).
X	 */
X	m_adj(m0, hlen + firstlen - ip->ip_len);
X	ip->ip_len = hlen + firstlen;
X	ip->ip_off |= IP_MF;
X	ip->ip_sum = 0;
X	ip->ip_sum = in_cksum(m0, hlen);
Xsendorfree:
X	for (m = m0; m; m = m0) {
X		m0 = m->m_act;
X		m->m_act = 0;
X		if (error == 0)
X			error = (*ifp->if_output)(ifp, m,
X			    (struct sockaddr *)dst);
X		else
X			m_freem(m);
X	}
X    }
Xdone:
X	if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)
X		RTFREE(ro->ro_rt);
X	return (error);
Xbad:
X	m_freem(m0);
X	goto done;
X}
X
X/*
X * Insert IP options into preformed packet.
X * Adjust IP destination as required for IP source routing,
X * as indicated by a non-zero in_addr at the start of the options.
X */
Xstruct mbuf *
Xip_insertoptions(m, opt, phlen)
X	register struct mbuf *m;
X	struct mbuf *opt;
X	int *phlen;
X{
X	register struct ipoption *p = mtod(opt, struct ipoption *);
X	struct mbuf *n;
X	register struct ip *ip = mtod(m, struct ip *);
X	unsigned optlen;
X
X	optlen = opt->m_len - sizeof(p->ipopt_dst);
X	if (p->ipopt_dst.s_addr)
X		ip->ip_dst = p->ipopt_dst;
X	if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) {
X		MGET(n, M_DONTWAIT, MT_HEADER);
X		if (n == 0)
X			return (m);
X		m->m_len -= sizeof(struct ip);
X		m->m_off += sizeof(struct ip);
X		n->m_next = m;
X		m = n;
X		m->m_off = MMAXOFF - sizeof(struct ip) - optlen;
X		m->m_len = optlen + sizeof(struct ip);
X		bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
X	} else {
X		m->m_off -= optlen;
X		m->m_len += optlen;
X		ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
X	}
X	ip = mtod(m, struct ip *);
X	bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);
X	*phlen = sizeof(struct ip) + optlen;
X	ip->ip_len += optlen;
X	return (m);
X}
X
X/*
X * Copy options from ip to jp,
X * omitting those not copied during fragmentation.
X */
Xip_optcopy(ip, jp)
X	struct ip *ip, *jp;
X{
X	register u_char *cp, *dp;
X	int opt, optlen, cnt;
X
X	cp = (u_char *)(ip + 1);
X	dp = (u_char *)(jp + 1);
X	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
X	for (; cnt > 0; cnt -= optlen, cp += optlen) {
X		opt = cp[0];
X		if (opt == IPOPT_EOL)
X			break;
X		if (opt == IPOPT_NOP)
X			optlen = 1;
X		else
X			optlen = cp[IPOPT_OLEN];
X		/* bogus lengths should have been caught by ip_dooptions */
X		if (optlen > cnt)
X			optlen = cnt;
X		if (IPOPT_COPIED(opt)) {
X			bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
X			dp += optlen;
X		}
X	}
X	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
X		*dp++ = IPOPT_EOL;
X	return (optlen);
X}
X
X/*
X * IP socket option processing.
X */
Xip_ctloutput(op, so, level, optname, m)
X	int op;
X	struct socket *so;
X	int level, optname;
X	struct mbuf **m;
X{
X	int error = 0;
X	struct inpcb *inp = sotoinpcb(so);
X
X	if (level != IPPROTO_IP)
X		error = EINVAL;
X	else switch (op) {
X
X	case PRCO_SETOPT:
X		switch (optname) {
X		case IP_OPTIONS:
X			return (ip_pcbopts(&inp->inp_options, *m));
X
X		default:
X			error = EINVAL;
X			break;
X		}
X		break;
X
X	case PRCO_GETOPT:
X		switch (optname) {
X		case IP_OPTIONS:
X			*m = m_get(M_WAIT, MT_SOOPTS);
X			if (inp->inp_options) {
X				(*m)->m_off = inp->inp_options->m_off;
X				(*m)->m_len = inp->inp_options->m_len;
X				bcopy(mtod(inp->inp_options, caddr_t),
X				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
X			} else
X				(*m)->m_len = 0;
X			break;
X		default:
X			error = EINVAL;
X			break;
X		}
X		break;
X	}
X	if (op == PRCO_SETOPT && *m)
X		(void)m_free(*m);
X	return (error);
X}
X
X/*
X * Set up IP options in pcb for insertion in output packets.
X * Store in mbuf with pointer in pcbopt, adding pseudo-option
X * with destination address if source routed.
X */
Xip_pcbopts(pcbopt, m)
X	struct mbuf **pcbopt;
X	register struct mbuf *m;
X{
X	register cnt, optlen;
X	register u_char *cp;
X	u_char opt;
X
X	/* turn off any old options */
X	if (*pcbopt)
X		(void)m_free(*pcbopt);
X	*pcbopt = 0;
X	if (m == (struct mbuf *)0 || m->m_len == 0) {
X		/*
X		 * Only turning off any previous options.
X		 */
X		if (m)
X			(void)m_free(m);
X		return (0);
X	}
X
X#ifndef	vax
X	if (m->m_len % sizeof(long))
X		goto bad;
X#endif
X	/*
X	 * IP first-hop destination address will be stored before
X	 * actual options; move other options back
X	 * and clear it when none present.
X	 */
X#if	MAX_IPOPTLEN >= MMAXOFF - MMINOFF
X	if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN)
X		goto bad;
X#else
X	if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF)
X		goto bad;
X#endif
X	cnt = m->m_len;
X	m->m_len += sizeof(struct in_addr);
X	cp = mtod(m, u_char *) + sizeof(struct in_addr);
X	ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
X	bzero(mtod(m, caddr_t), sizeof(struct in_addr));
X
X	for (; cnt > 0; cnt -= optlen, cp += optlen) {
X		opt = cp[IPOPT_OPTVAL];
X		if (opt == IPOPT_EOL)
X			break;
X		if (opt == IPOPT_NOP)
X			optlen = 1;
X		else {
X			optlen = cp[IPOPT_OLEN];
X			if (optlen <= IPOPT_OLEN || optlen > cnt)
X				goto bad;
X		}
X		switch (opt) {
X
X		default:
X			break;
X
X		case IPOPT_LSRR:
X		case IPOPT_SSRR:
X			/*
X			 * user process specifies route as:
X			 *	->A->B->C->D
X			 * D must be our final destination (but we can't
X			 * check that since we may not have connected yet).
X			 * A is first hop destination, which doesn't appear in
X			 * actual IP option, but is stored before the options.
X			 */
X			if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
X				goto bad;
X			m->m_len -= sizeof(struct in_addr);
X			cnt -= sizeof(struct in_addr);
X			optlen -= sizeof(struct in_addr);
X			cp[IPOPT_OLEN] = optlen;
X			/*
X			 * Move first hop before start of options.
X			 */
X			bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
X			    sizeof(struct in_addr));
X			/*
X			 * Then copy rest of options back
X			 * to close up the deleted entry.
X			 */
X			ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
X			    sizeof(struct in_addr)),
X			    (caddr_t)&cp[IPOPT_OFFSET+1],
X			    (unsigned)cnt + sizeof(struct in_addr));
X			break;
X		}
X	}
X	*pcbopt = m;
X	return (0);
X
Xbad:
X	(void)m_free(m);
X	return (EINVAL);
X}
END-of-netinet/ip_output.c
echo x - netinet/ip_var.h
sed 's/^X//' >netinet/ip_var.h << 'END-of-netinet/ip_var.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)ip_var.h	7.4 (Berkeley) 1/7/88
X */
X
X/*
X * Overlay for ip header used by other protocols (tcp, udp).
X */
Xstruct ipovly {
X	caddr_t	ih_next, ih_prev;	/* for protocol sequence q's */
X	u_char	ih_x1;			/* (unused) */
X	u_char	ih_pr;			/* protocol */
X	short	ih_len;			/* protocol length */
X	struct	in_addr ih_src;		/* source internet address */
X	struct	in_addr ih_dst;		/* destination internet address */
X};
X
X/*
X * Ip reassembly queue structure.  Each fragment
X * being reassembled is attached to one of these structures.
X * They are timed out after ipq_ttl drops to 0, and may also
X * be reclaimed if memory becomes tight.
X */
Xstruct ipq {
X	struct	ipq *next,*prev;	/* to other reass headers */
X	u_char	ipq_ttl;		/* time for reass q to live */
X	u_char	ipq_p;			/* protocol of this fragment */
X	u_short	ipq_id;			/* sequence id for reassembly */
X	struct	ipasfrag *ipq_next,*ipq_prev;
X					/* to ip headers of fragments */
X	struct	in_addr ipq_src,ipq_dst;
X};
X
X/*
X * Ip header, when holding a fragment.
X *
X * Note: ipf_next must be at same offset as ipq_next above
X */
Xstruct	ipasfrag {
X#if BYTE_ORDER == LITTLE_ENDIAN 
X	u_char	ip_hl:4,
X		ip_v:4;
X#endif
X#if BYTE_ORDER == BIG_ENDIAN 
X	u_char	ip_v:4,
X		ip_hl:4;
X#endif
X	u_char	ipf_mff;		/* copied from (ip_off&IP_MF) */
X	short	ip_len;
X	u_short	ip_id;
X	short	ip_off;
X	u_char	ip_ttl;
X	u_char	ip_p;
X	u_short	ip_sum;
X	struct	ipasfrag *ipf_next;	/* next fragment */
X	struct	ipasfrag *ipf_prev;	/* previous fragment */
X};
X
X/*
X * Structure stored in mbuf in inpcb.ip_options
X * and passed to ip_output when ip options are in use.
X * The actual length of the options (including ipopt_dst)
X * is in m_len.
X */
X#define MAX_IPOPTLEN	40
X
Xstruct ipoption {
X	struct	in_addr ipopt_dst;	/* first-hop dst if source routed */
X	char	ipopt_list[MAX_IPOPTLEN];	/* options proper */
X};
X
Xstruct	ipstat {
X	long	ips_total;		/* total packets received */
X	long	ips_badsum;		/* checksum bad */
X	long	ips_tooshort;		/* packet too short */
X	long	ips_toosmall;		/* not enough data */
X	long	ips_badhlen;		/* ip header length < data size */
X	long	ips_badlen;		/* ip length < ip header length */
X	long	ips_fragments;		/* fragments received */
X	long	ips_fragdropped;	/* frags dropped (dups, out of space) */
X	long	ips_fragtimeout;	/* fragments timed out */
X	long	ips_forward;		/* packets forwarded */
X	long	ips_cantforward;	/* packets rcvd for unreachable dest */
X	long	ips_redirectsent;	/* packets forwarded on same net */
X};
X
X#ifdef KERNEL
X/* flags passed to ip_output as last parameter */
X#define	IP_FORWARDING		0x1		/* most of ip header exists */
X#define	IP_ROUTETOIF		SO_DONTROUTE	/* bypass routing tables */
X#define	IP_ALLOWBROADCAST	SO_BROADCAST	/* can send broadcast packets */
X
Xstruct	ipstat	ipstat;
Xstruct	ipq	ipq;			/* ip reass. queue */
Xu_short	ip_id;				/* ip packet ctr, for ids */
X
Xstruct	mbuf *ip_srcroute();
X#endif
END-of-netinet/ip_var.h
echo x - netinet/raw_ip.c
sed 's/^X//' >netinet/raw_ip.c << 'END-of-netinet/raw_ip.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)raw_ip.c	7.3 (Berkeley) 12/7/87
X */
X
X#include "param.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "protosw.h"
X#include "socketvar.h"
X#include "errno.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X#include "../net/raw_cb.h"
X
X#include "in.h"
X#include "in_systm.h"
X#include "ip.h"
X#include "ip_var.h"
X
X/*
X * Raw interface to IP protocol.
X */
X
Xstruct	sockaddr_in ripdst = { AF_INET };
Xstruct	sockaddr_in ripsrc = { AF_INET };
Xstruct	sockproto ripproto = { PF_INET };
X/*
X * Setup generic address and protocol structures
X * for raw_input routine, then pass them along with
X * mbuf chain.
X */
Xrip_input(m)
X	struct mbuf *m;
X{
X	register struct ip *ip = mtod(m, struct ip *);
X
X	ripproto.sp_protocol = ip->ip_p;
X	ripdst.sin_addr = ip->ip_dst;
X	ripsrc.sin_addr = ip->ip_src;
X	raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
X	  (struct sockaddr *)&ripdst);
X}
X
X/*
X * Generate IP header and pass packet to ip_output.
X * Tack on options user may have setup with control call.
X */
Xrip_output(m0, so)
X	struct mbuf *m0;
X	struct socket *so;
X{
X	register struct mbuf *m;
X	register struct ip *ip;
X	int len = 0, error;
X	struct rawcb *rp = sotorawcb(so);
X	struct sockaddr_in *sin;
X
X	/*
X	 * Calculate data length and get an mbuf
X	 * for IP header.
X	 */
X	for (m = m0; m; m = m->m_next)
X		len += m->m_len;
X	m = m_get(M_DONTWAIT, MT_HEADER);
X	if (m == 0) {
X		error = ENOBUFS;
X		goto bad;
X	}
X	
X	/*
X	 * Fill in IP header as needed.
X	 */
X	m->m_off = MMAXOFF - sizeof(struct ip);
X	m->m_len = sizeof(struct ip);
X	m->m_next = m0;
X	ip = mtod(m, struct ip *);
X	ip->ip_tos = 0;
X	ip->ip_off = 0;
X	ip->ip_p = rp->rcb_proto.sp_protocol;
X	ip->ip_len = sizeof(struct ip) + len;
X	if (rp->rcb_flags & RAW_LADDR) {
X		sin = (struct sockaddr_in *)&rp->rcb_laddr;
X		if (sin->sin_family != AF_INET) {
X			error = EAFNOSUPPORT;
X			goto bad;
X		}
X		ip->ip_src.s_addr = sin->sin_addr.s_addr;
X	} else
X		ip->ip_src.s_addr = 0;
X	ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr;
X	ip->ip_ttl = MAXTTL;
X	return (ip_output(m, rp->rcb_options, &rp->rcb_route, 
X	   (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
Xbad:
X	m_freem(m);
X	return (error);
X}
X
X/*
X * Raw IP socket option processing.
X */
Xrip_ctloutput(op, so, level, optname, m)
X	int op;
X	struct socket *so;
X	int level, optname;
X	struct mbuf **m;
X{
X	int error = 0;
X	register struct rawcb *rp = sotorawcb(so);
X
X	if (level != IPPROTO_IP)
X		error = EINVAL;
X	else switch (op) {
X
X	case PRCO_SETOPT:
X		switch (optname) {
X		case IP_OPTIONS:
X			return (ip_pcbopts(&rp->rcb_options, *m));
X
X		default:
X			error = EINVAL;
X			break;
X		}
X		break;
X
X	case PRCO_GETOPT:
X		switch (optname) {
X		case IP_OPTIONS:
X			*m = m_get(M_WAIT, MT_SOOPTS);
X			if (rp->rcb_options) {
X				(*m)->m_off = rp->rcb_options->m_off;
X				(*m)->m_len = rp->rcb_options->m_len;
X				bcopy(mtod(rp->rcb_options, caddr_t),
X				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
X			} else
X				(*m)->m_len = 0;
X			break;
X		default:
X			error = EINVAL;
X			break;
X		}
X		break;
X	}
X	if (op == PRCO_SETOPT && *m)
X		(void)m_free(*m);
X	return (error);
X}
END-of-netinet/raw_ip.c
echo x - netinet/udp.h
sed 's/^X//' >netinet/udp.h << 'END-of-netinet/udp.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)udp.h	7.2 (Berkeley) 12/7/87
X */
X
X/*
X * Udp protocol header.
X * Per RFC 768, September, 1981.
X */
Xstruct udphdr {
X	u_short	uh_sport;		/* source port */
X	u_short	uh_dport;		/* destination port */
X	short	uh_ulen;		/* udp length */
X	u_short	uh_sum;			/* udp checksum */
X};
END-of-netinet/udp.h
echo x - netinet/udp_usrreq.c
sed 's/^X//' >netinet/udp_usrreq.c << 'END-of-netinet/udp_usrreq.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)udp_usrreq.c	7.5 (Berkeley) 3/11/88
X */
X
X#include "param.h"
X#include "dir.h"
X#include "user.h"
X#include "mbuf.h"
X#include "protosw.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "errno.h"
X#include "stat.h"
X
X#include "../net/if.h"
X#include "../net/route.h"
X
X#include "in.h"
X#include "in_pcb.h"
X#include "in_systm.h"
X#include "ip.h"
X#include "ip_var.h"
X#include "ip_icmp.h"
X#include "udp.h"
X#include "udp_var.h"
X
X/*
X * UDP protocol implementation.
X * Per RFC 768, August, 1980.
X */
Xudp_init()
X{
X
X	udb.inp_next = udb.inp_prev = &udb;
X}
X
X#ifndef	COMPAT_42
Xint	udpcksum = 1;
X#else
Xint	udpcksum = 0;		/* XXX */
X#endif
Xint	udp_ttl = UDP_TTL;
X
Xstruct	sockaddr_in udp_in = { AF_INET };
X
Xudp_input(m0, ifp)
X	struct mbuf *m0;
X	struct ifnet *ifp;
X{
X	register struct udpiphdr *ui;
X	register struct inpcb *inp;
X	register struct mbuf *m;
X	int len;
X	struct ip ip;
X
X	/*
X	 * Get IP and UDP header together in first mbuf.
X	 */
X	m = m0;
X	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) &&
X	    (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) {
X		udpstat.udps_hdrops++;
X		return;
X	}
X	ui = mtod(m, struct udpiphdr *);
X	if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2))
X		ip_stripoptions((struct ip *)ui, (struct mbuf *)0);
X
X	/*
X	 * Make mbuf data length reflect UDP length.
X	 * If not enough data to reflect UDP length, drop.
X	 */
X	len = ntohs((u_short)ui->ui_ulen);
X	if (((struct ip *)ui)->ip_len != len) {
X		if (len > ((struct ip *)ui)->ip_len) {
X			udpstat.udps_badlen++;
X			goto bad;
X		}
X		m_adj(m, len - ((struct ip *)ui)->ip_len);
X		/* ((struct ip *)ui)->ip_len = len; */
X	}
X	/*
X	 * Save a copy of the IP header in case we want restore it for ICMP.
X	 */
X	ip = *(struct ip*)ui;
X
X	/*
X	 * Checksum extended UDP header and data.
X	 */
X	if (udpcksum && ui->ui_sum) {
X		ui->ui_next = ui->ui_prev = 0;
X		ui->ui_x1 = 0;
X		ui->ui_len = ui->ui_ulen;
X		if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) {
X			udpstat.udps_badsum++;
X			m_freem(m);
X			return;
X		}
X	}
X
X	/*
X	 * Locate pcb for datagram.
X	 */
X	inp = in_pcblookup(&udb,
X	    ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport,
X		INPLOOKUP_WILDCARD);
X	if (inp == 0) {
X		/* don't send ICMP response for broadcast packet */
X		if (in_broadcast(ui->ui_dst))
X			goto bad;
X		*(struct ip *)ui = ip;
X		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,
X		    ifp);
X		return;
X	}
X
X	/*
X	 * Construct sockaddr format source address.
X	 * Stuff source address and datagram in user buffer.
X	 */
X	udp_in.sin_port = ui->ui_sport;
X	udp_in.sin_addr = ui->ui_src;
X	m->m_len -= sizeof (struct udpiphdr);
X	m->m_off += sizeof (struct udpiphdr);
X	if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
X	    m, (struct mbuf *)0) == 0)
X		goto bad;
X	sorwakeup(inp->inp_socket);
X	return;
Xbad:
X	m_freem(m);
X}
X
X/*
X * Notify a udp user of an asynchronous error;
X * just wake up so that he can collect error status.
X */
Xudp_notify(inp)
X	register struct inpcb *inp;
X{
X
X	sorwakeup(inp->inp_socket);
X	sowwakeup(inp->inp_socket);
X}
X
Xudp_ctlinput(cmd, sa)
X	int cmd;
X	struct sockaddr *sa;
X{
X	extern u_char inetctlerrmap[];
X	struct sockaddr_in *sin;
X	int in_rtchange();
X
X	if ((unsigned)cmd > PRC_NCMDS)
X		return;
X	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
X		return;
X	sin = (struct sockaddr_in *)sa;
X	if (sin->sin_addr.s_addr == INADDR_ANY)
X		return;
X
X	switch (cmd) {
X
X	case PRC_QUENCH:
X		break;
X
X	case PRC_ROUTEDEAD:
X	case PRC_REDIRECT_NET:
X	case PRC_REDIRECT_HOST:
X	case PRC_REDIRECT_TOSNET:
X	case PRC_REDIRECT_TOSHOST:
X		in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange);
X		break;
X
X	default:
X		if (inetctlerrmap[cmd] == 0)
X			return;		/* XXX */
X		in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd],
X			udp_notify);
X	}
X}
X
Xudp_output(inp, m0)
X	register struct inpcb *inp;
X	struct mbuf *m0;
X{
X	register struct mbuf *m;
X	register struct udpiphdr *ui;
X	register int len = 0;
X
X	/*
X	 * Calculate data length and get a mbuf
X	 * for UDP and IP headers.
X	 */
X	for (m = m0; m; m = m->m_next)
X		len += m->m_len;
X	MGET(m, M_DONTWAIT, MT_HEADER);
X	if (m == 0) {
X		m_freem(m0);
X		return (ENOBUFS);
X	}
X
X	/*
X	 * Fill in mbuf with extended UDP header
X	 * and addresses and length put into network format.
X	 */
X	m->m_off = MMAXOFF - sizeof (struct udpiphdr);
X	m->m_len = sizeof (struct udpiphdr);
X	m->m_next = m0;
X	ui = mtod(m, struct udpiphdr *);
X	ui->ui_next = ui->ui_prev = 0;
X	ui->ui_x1 = 0;
X	ui->ui_pr = IPPROTO_UDP;
X	ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
X	ui->ui_src = inp->inp_laddr;
X	ui->ui_dst = inp->inp_faddr;
X	ui->ui_sport = inp->inp_lport;
X	ui->ui_dport = inp->inp_fport;
X	ui->ui_ulen = ui->ui_len;
X
X	/*
X	 * Stuff checksum and output datagram.
X	 */
X	ui->ui_sum = 0;
X	if (udpcksum) {
X	    if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
X		ui->ui_sum = 0xffff;
X	}
X	((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
X	((struct ip *)ui)->ip_ttl = udp_ttl;
X	return (ip_output(m, inp->inp_options, &inp->inp_route,
X	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
X}
X
Xint	udp_sendspace = 2048;		/* really max datagram size */
Xint	udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */
X
X/*ARGSUSED*/
Xudp_usrreq(so, req, m, nam, rights)
X	struct socket *so;
X	int req;
X	struct mbuf *m, *nam, *rights;
X{
X	struct inpcb *inp = sotoinpcb(so);
X	int error = 0;
X
X	if (req == PRU_CONTROL)
X		return (in_control(so, (int)m, (caddr_t)nam,
X			(struct ifnet *)rights));
X	if (rights && rights->m_len) {
X		error = EINVAL;
X		goto release;
X	}
X	if (inp == NULL && req != PRU_ATTACH) {
X		error = EINVAL;
X		goto release;
X	}
X	switch (req) {
X
X	case PRU_ATTACH:
X		if (inp != NULL) {
X			error = EINVAL;
X			break;
X		}
X		error = in_pcballoc(so, &udb);
X		if (error)
X			break;
X		error = soreserve(so, udp_sendspace, udp_recvspace);
X		if (error)
X			break;
X		break;
X
X	case PRU_DETACH:
X		in_pcbdetach(inp);
X		break;
X
X	case PRU_BIND:
X		error = in_pcbbind(inp, nam);
X		break;
X
X	case PRU_LISTEN:
X		error = EOPNOTSUPP;
X		break;
X
X	case PRU_CONNECT:
X		if (inp->inp_faddr.s_addr != INADDR_ANY) {
X			error = EISCONN;
X			break;
X		}
X		error = in_pcbconnect(inp, nam);
X		if (error == 0)
X			soisconnected(so);
X		break;
X
X	case PRU_CONNECT2:
X		error = EOPNOTSUPP;
X		break;
X
X	case PRU_ACCEPT:
X		error = EOPNOTSUPP;
X		break;
X
X	case PRU_DISCONNECT:
X		if (inp->inp_faddr.s_addr == INADDR_ANY) {
X			error = ENOTCONN;
X			break;
X		}
X		in_pcbdisconnect(inp);
X		so->so_state &= ~SS_ISCONNECTED;		/* XXX */
X		break;
X
X	case PRU_SHUTDOWN:
X		socantsendmore(so);
X		break;
X
X	case PRU_SEND: {
X		struct in_addr laddr;
X		int s;
X
X		if (nam) {
X			laddr = inp->inp_laddr;
X			if (inp->inp_faddr.s_addr != INADDR_ANY) {
X				error = EISCONN;
X				break;
X			}
X			/*
X			 * Must block input while temporarily connected.
X			 */
X			s = splnet();
X			error = in_pcbconnect(inp, nam);
X			if (error) {
X				splx(s);
X				break;
X			}
X		} else {
X			if (inp->inp_faddr.s_addr == INADDR_ANY) {
X				error = ENOTCONN;
X				break;
X			}
X		}
X		error = udp_output(inp, m);
X		m = NULL;
X		if (nam) {
X			in_pcbdisconnect(inp);
X			inp->inp_laddr = laddr;
X			splx(s);
X		}
X		}
X		break;
X
X	case PRU_ABORT:
X		soisdisconnected(so);
X		in_pcbdetach(inp);
X		break;
X
X	case PRU_SOCKADDR:
X		in_setsockaddr(inp, nam);
X		break;
X
X	case PRU_PEERADDR:
X		in_setpeeraddr(inp, nam);
X		break;
X
X	case PRU_SENSE:
X		/*
X		 * stat: don't bother with a blocksize.
X		 */
X		return (0);
X
X	case PRU_SENDOOB:
X	case PRU_FASTTIMO:
X	case PRU_SLOWTIMO:
X	case PRU_PROTORCV:
X	case PRU_PROTOSEND:
X		error =  EOPNOTSUPP;
X		break;
X
X	case PRU_RCVD:
X	case PRU_RCVOOB:
X		return (EOPNOTSUPP);	/* do not free mbuf's */
X
X	default:
X		panic("udp_usrreq");
X	}
Xrelease:
X	if (m != NULL)
X		m_freem(m);
X	return (error);
X}
END-of-netinet/udp_usrreq.c
echo x - netinet/udp_var.h
sed 's/^X//' >netinet/udp_var.h << 'END-of-netinet/udp_var.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X *	@(#)udp_var.h	7.3 (Berkeley) 12/7/87
X */
X
X/*
X * UDP kernel structures and variables.
X */
Xstruct	udpiphdr {
X	struct 	ipovly ui_i;		/* overlaid ip structure */
X	struct	udphdr ui_u;		/* udp header */
X};
X#define	ui_next		ui_i.ih_next
X#define	ui_prev		ui_i.ih_prev
X#define	ui_x1		ui_i.ih_x1
X#define	ui_pr		ui_i.ih_pr
X#define	ui_len		ui_i.ih_len
X#define	ui_src		ui_i.ih_src
X#define	ui_dst		ui_i.ih_dst
X#define	ui_sport	ui_u.uh_sport
X#define	ui_dport	ui_u.uh_dport
X#define	ui_ulen		ui_u.uh_ulen
X#define	ui_sum		ui_u.uh_sum
X
Xstruct	udpstat {
X	int	udps_hdrops;
X	int	udps_badsum;
X	int	udps_badlen;
X};
X
X#define	UDP_TTL		30		/* deflt time to live for UDP packets */
X
X#ifdef KERNEL
Xstruct	inpcb udb;
Xstruct	udpstat udpstat;
X#endif
END-of-netinet/udp_var.h
exit



More information about the Comp.bugs.4bsd.ucb-fixes mailing list