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

Keith Bostic bostic at OKEEFFE.BERKELEY.EDU
Tue Apr 5 13:17:57 AEST 1988


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

Description:
	This is number 2 of 11 total articles posted to the newsgroup
	comp.bugs.4bsd.ucb-fixes.  This archive is number 1 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:
#
#	README
#	h
#	h/mbuf.h
#	h/socketvar.h
#	net
#	net/route.c
#	net/route.h
#	net/if_sl.c
#	sys
#	sys/uipc_mbuf.c
#	sys/uipc_socket.c
#	sys/uipc_usrreq.c
#
echo x - README
sed 's/^X//' >README << 'END-of-README'
XThis is the description of a release of updated networking software
Xfor the 4.3BSD distribution from the University of California, Berkeley.
XThese changes are part of the current Berkeley operating system and
Xwill be included in future tape releases.  This release is being
Xmade available by anonymous FTP from the ARPANET and on the Usenet
Xnewsgroup comp.bugs.4bsd.ucb-fixes.
X
XThe major changes in this release are in the TCP send policy.
XBecause the improvements in the send policy could significantly
Xreduce congestion on the ARPANET and the NSFNET, all sites with
Xdirect or indirect connections to long-haul nets are urged to upgrade
Xas quickly as possible.  Vendors supplying TCP products based on 4.2BSD
Xor 4.3BSD are strongly urged to update as quickly as possible.  Vendors
Xusing other TCP implementations should consider the use of the new algorithms
Xas well, and may find the current Berkeley source code useful as a guide
Xto their implementation.
X
XThe FTP release consists of five files: tcp.tar, inet.tar, netns.tar,
Xsocket.tar and imp.tar.  They are all present on host ucbarpa.Berkeley.EDU
Xin the directory pub/4.3.  (Each is also available in compressed form,
Xindicated by a trailing ".Z".)  Each archive file includes a copy of this
Xfile (called README).
X
XThe first file, tcp.tar, contains sources for the current version of TCP,
Xincluding the slow start algorithm and other work by Van Jacobson of LBL
Xand a retransmission timer algorithm suggested by Phil Karn.  It is designed
Xto replace the 4.3BSD TCP, although it also has #ifdef's for installation
Xin a 4.2-based system (including SunOS versions up to 3.6).  The changes made
Xsince the release of 4.3 dramatically improve performance over slow and/or
Xlossy networks such as the ARPANET/Milnet and Satnet, and also reduce the
Xnumber of unnecessary retransmissions nearly to zero.  Performance on
Xfast, local-area networks is also somewhat improved, especially on faster
Xprocessors when larger buffers are used.  Several new bug fixes have
Xalso been made.  The file TCP_INSTALL contains some hints on configuring
XTCP for systems other than standard 4.3BSD and 4.2BSD.
X
XThe second file, inet.tar, contains sources for IP, ICMP, UDP and common
Xinternet code (all of the netinet directory except the TCP sources).
XIt also includes a few files from the sys and h directories that have
Xbeen changed since the 4.3BSD release.  There are changes in the processing
Xof IP record-route and timestamp options and in handling of certain broadcast
XUDP requests.  The mbuf allocation routines include a fix for a race and
Xchanges to call the protocol drain routines when appropriate, and will
Xno longer panic when new allocation requests discover that the mbuf map
Xhas been exhausted.  A recent problem in the code for fragmenting IP packets
Xwith options is fixed.  The complete source for the netstat program is also
Xincluded in inet.tar.  It will be usable only on 4.3BSD systems without
Xmodification.  (Note: there are two versions of main.c and host.c in
Xthe netstat directory.  Unless you are installing the new imp code,
Xyou must use main.c.oldimp and host.c.oldimp.)
X
XThe combination of tcp.tar and inet.tar is sufficient to upgrade a 4.3BSD
Xsystem to the current level of IP/TCP.  It is strongly recommended that
X4.3BSD sites that are connected to the Internet, directly or indirectly,
Xas well as 4.3BSD gateway sites, should upgrade as quickly as possible.
X
XThe third file, netns.tar, contains the current version of the Xerox NS
Xprotocols from the netns source directory.  The Sequenced Packet Protocol
Xhas modifications similar to those in TCP, as well as several bug fixes.
XSites that use XNS must upgrade it at the same time as TCP, as the old
XXNS code used the old tcp_timer.h.
X
XThe fourth file, socket.tar, includes the remainder of the socket and generic
Xnetwork source files.  These files are identical to those in the 4.3BSD
Xrelease.  They are provided for completeness for those who do not have access
Xto the original 4.3BSD sources.  They are not required for installation
Xof the TCP and other internet fixes in a 4.3BSD system, nor for installation
Xof the new internet code into most 4.2BSD-derived systems.  They may
Xbe useful for upgrading the socket or network code in a 4.2BSD-derived
Xsystem.  We cannot provide any assistance in such upgrades, but we
Xare interested in hearing about any successful upgrades.
X
XThe fifth file, imp.tar, includes recent modifications to the code for
Xhandling an ARPANET/Milnet IMP using an AHIP (1822) interface.  It was not
Xquite ready for distribution when the rest of the update was finished, and
Xmay not be present in the anonymous FTP area immediately.  If you want
Xit, check back later or watch for an announcement on the tcp-ip mailing
Xlist.
X
XNote that the Berkeley network source code is *not* public-domain.
XHowever, as it contains no code licensed by AT&T or others, it is owned
Xby the Regents of the University of California, Berkeley.  It is provided
Xas-is, without any warranty, for any purpose.  It may be used, modified or
Xredistributed in source or binary forms, as long as due credit is given
Xto the University and the University copyright notices are retained.
X
XThese sources may be updated from time to time as improvements or additions
Xare made.  The next update will include support for IP multicast done
Xby Steve Deering at Stanford.  Updates will be announced on the tcp-ip
Xmailing list, which is redistributed on Usenet.
X
X	Mike Karels	karels at Berkeley.EDU
X	Van Jacobson	van at lbl-csam.arpa
END-of-README
echo c - h
mkdir h
echo x - h/mbuf.h
sed 's/^X//' >h/mbuf.h << 'END-of-h/mbuf.h'
X/*
X * Copyright (c) 1982, 1986, 1988 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 *	@(#)mbuf.h	7.8.1.2 (Berkeley) 2/8/88
X */
X
X/*
X * Constants related to memory allocator.
X */
X#define	MSIZE		128			/* size of an mbuf */
X
X#if CLBYTES > 1024
X#define	MCLBYTES	1024
X#define	MCLSHIFT	10
X#define	MCLOFSET	(MCLBYTES - 1)
X#else
X#define	MCLBYTES	CLBYTES
X#define	MCLSHIFT	CLSHIFT
X#define	MCLOFSET	CLOFSET
X#endif
X
X#define	MMINOFF		12			/* mbuf header length */
X#define	MTAIL		4
X#define	MMAXOFF		(MSIZE-MTAIL)		/* offset where data ends */
X#define	MLEN		(MSIZE-MMINOFF-MTAIL)	/* mbuf data length */
X#ifdef GATEWAY
X#define	NMBCLUSTERS	512
X#else
X#define	NMBCLUSTERS	256
X#endif
X#define	NMBPCL		(CLBYTES/MSIZE)		/* # mbufs per cluster */
X
X/*
X * Macros for type conversion
X */
X
X/* network cluster number to virtual address, and back */
X#define	cltom(x) ((struct mbuf *)((int)mbutl + ((x) << MCLSHIFT)))
X#define	mtocl(x) (((int)x - (int)mbutl) >> MCLSHIFT)
X
X/* address in mbuf to mbuf head */
X#define	dtom(x)		((struct mbuf *)((int)x & ~(MSIZE-1)))
X
X/* mbuf head, to typed data */
X#define	mtod(x,t)	((t)((int)(x) + (x)->m_off))
X
Xstruct mbuf {
X	struct	mbuf *m_next;		/* next buffer in chain */
X	u_long	m_off;			/* offset of data */
X	short	m_len;			/* amount of data in this mbuf */
X	short	m_type;			/* mbuf type (0 == free) */
X	u_char	m_dat[MLEN];		/* data storage */
X	struct	mbuf *m_act;		/* link in higher-level mbuf list */
X};
X
X/* mbuf types */
X#define	MT_FREE		0	/* should be on free list */
X#define	MT_DATA		1	/* dynamic (data) allocation */
X#define	MT_HEADER	2	/* packet header */
X#define	MT_SOCKET	3	/* socket structure */
X#define	MT_PCB		4	/* protocol control block */
X#define	MT_RTABLE	5	/* routing tables */
X#define	MT_HTABLE	6	/* IMP host tables */
X#define	MT_ATABLE	7	/* address resolution tables */
X#define	MT_SONAME	8	/* socket name */
X#define	MT_ZOMBIE	9	/* zombie proc status */
X#define	MT_SOOPTS	10	/* socket options */
X#define	MT_FTABLE	11	/* fragment reassembly header */
X#define	MT_RIGHTS	12	/* access rights */
X#define	MT_IFADDR	13	/* interface address */
X
X/* flags to m_get */
X#define	M_DONTWAIT	0
X#define	M_WAIT		1
X
X/* flags to m_pgalloc */
X#define	MPG_MBUFS	0		/* put new mbufs on free list */
X#define	MPG_CLUSTERS	1		/* put new clusters on free list */
X#define	MPG_SPACE	2		/* don't free; caller wants space */
X
X/* length to m_copy to copy all */
X#define	M_COPYALL	1000000000
X
X/*
X * m_pullup will pull up additional length if convenient;
X * should be enough to hold headers of second-level and higher protocols. 
X */
X#define	MPULL_EXTRA	32
X
X#define	MGET(m, i, t) \
X	{ int ms = splimp(); \
X	  if ((m)=mfree) \
X		{ if ((m)->m_type != MT_FREE) panic("mget"); (m)->m_type = t; \
X		  mbstat.m_mtypes[MT_FREE]--; mbstat.m_mtypes[t]++; \
X		  mfree = (m)->m_next; (m)->m_next = 0; \
X		  (m)->m_off = MMINOFF; } \
X	  else \
X		(m) = m_more(i, t); \
X	  splx(ms); }
X/*
X * Mbuf page cluster macros.
X * MCLALLOC allocates mbuf page clusters.
X * Note that it works only with a count of 1 at the moment.
X * MCLGET adds such clusters to a normal mbuf.
X * m->m_len is set to MCLBYTES upon success, and to MLEN on failure.
X * MCLFREE frees clusters allocated by MCLALLOC.
X */
X#define	MCLALLOC(m, i) \
X	{ int ms = splimp(); \
X	  if (mclfree == 0) \
X		(void)m_clalloc((i), MPG_CLUSTERS, M_DONTWAIT); \
X	  if ((m)=mclfree) \
X	     {++mclrefcnt[mtocl(m)];mbstat.m_clfree--;mclfree = (m)->m_next;} \
X	  splx(ms); }
X#define	M_HASCL(m)	((m)->m_off >= MSIZE)
X#define	MTOCL(m)	((struct mbuf *)(mtod((m), int) &~ MCLOFSET))
X
X#define	MCLGET(m) \
X	{ struct mbuf *p; \
X	  MCLALLOC(p, 1); \
X	  if (p) { \
X		(m)->m_off = (int)p - (int)(m); \
X		(m)->m_len = MCLBYTES; \
X	  } else \
X		(m)->m_len = MLEN; \
X	}
X#define	MCLFREE(m) { \
X	if (--mclrefcnt[mtocl(m)] == 0) \
X	    { (m)->m_next = mclfree;mclfree = (m);mbstat.m_clfree++;} \
X	}
X#define	MFREE(m, n) \
X	{ int ms = splimp(); \
X	  if ((m)->m_type == MT_FREE) panic("mfree"); \
X	  mbstat.m_mtypes[(m)->m_type]--; mbstat.m_mtypes[MT_FREE]++; \
X	  (m)->m_type = MT_FREE; \
X	  if (M_HASCL(m)) { \
X		(n) = MTOCL(m); \
X		MCLFREE(n); \
X	  } \
X	  (n) = (m)->m_next; (m)->m_next = mfree; \
X	  (m)->m_off = 0; (m)->m_act = 0; mfree = (m); \
X	  splx(ms); \
X	  if (m_want) { \
X		  m_want = 0; \
X		  wakeup((caddr_t)&mfree); \
X	  } \
X	}
X
X/*
X * Mbuf statistics.
X */
Xstruct mbstat {
X	u_long	m_mbufs;	/* mbufs obtained from page pool */
X	u_long	m_clusters;	/* clusters obtained from page pool */
X	u_long	m_space;	/* interface pages obtained from page pool */
X	u_long	m_clfree;	/* free clusters */
X	u_long	m_drops;	/* times failed to find space */
X	u_long	m_wait;		/* times waited for space */
X	u_long	m_drain;	/* times drained protocols for space */
X	u_short	m_mtypes[256];	/* type specific mbuf allocations */
X};
X
X#ifdef	KERNEL
Xextern	struct mbuf mbutl[];		/* virtual address of net free mem */
Xextern	struct pte Mbmap[];		/* page tables to map Netutl */
Xstruct	mbstat mbstat;
Xint	nmbclusters;
Xstruct	mbuf *mfree, *mclfree;
Xchar	mclrefcnt[NMBCLUSTERS + 1];
Xint	m_want;
Xstruct	mbuf *m_get(),*m_getclr(),*m_free(),*m_more(),*m_copy(),*m_pullup();
Xcaddr_t	m_clalloc();
X#endif
END-of-h/mbuf.h
echo x - h/socketvar.h
sed 's/^X//' >h/socketvar.h << 'END-of-h/socketvar.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 *	@(#)socketvar.h	7.3 (Berkeley) 12/30/87
X */
X
X/*
X * Kernel structure per socket.
X * Contains send and receive buffer queues,
X * handle on protocol and pointer to protocol
X * private data and error information.
X */
Xstruct socket {
X	short	so_type;		/* generic type, see socket.h */
X	short	so_options;		/* from socket call, see socket.h */
X	short	so_linger;		/* time to linger while closing */
X	short	so_state;		/* internal state flags SS_*, below */
X	caddr_t	so_pcb;			/* protocol control block */
X	struct	protosw *so_proto;	/* protocol handle */
X/*
X * Variables for connection queueing.
X * Socket where accepts occur is so_head in all subsidiary sockets.
X * If so_head is 0, socket is not related to an accept.
X * For head socket so_q0 queues partially completed connections,
X * while so_q is a queue of connections ready to be accepted.
X * If a connection is aborted and it has so_head set, then
X * it has to be pulled out of either so_q0 or so_q.
X * We allow connections to queue up based on current queue lengths
X * and limit on number of queued connections for this socket.
X */
X	struct	socket *so_head;	/* back pointer to accept socket */
X	struct	socket *so_q0;		/* queue of partial connections */
X	struct	socket *so_q;		/* queue of incoming connections */
X	short	so_q0len;		/* partials on so_q0 */
X	short	so_qlen;		/* number of connections on so_q */
X	short	so_qlimit;		/* max number queued connections */
X	short	so_timeo;		/* connection timeout */
X	u_short	so_error;		/* error affecting connection */
X	short	so_pgrp;		/* pgrp for signals */
X	u_long	so_oobmark;		/* chars to oob mark */
X/*
X * Variables for socket buffering.
X */
X	struct	sockbuf {
X		u_long	sb_cc;		/* actual chars in buffer */
X		u_long	sb_hiwat;	/* max actual char count */
X		u_long	sb_mbcnt;	/* chars of mbufs used */
X		u_long	sb_mbmax;	/* max chars of mbufs to use */
X		u_long	sb_lowat;	/* low water mark (not used yet) */
X		struct	mbuf *sb_mb;	/* the mbuf chain */
X		struct	proc *sb_sel;	/* process selecting read/write */
X		short	sb_timeo;	/* timeout (not used yet) */
X		short	sb_flags;	/* flags, see below */
X	} so_rcv, so_snd;
X#define	SB_MAX		(64*1024)	/* max chars in sockbuf */
X#define	SB_LOCK		0x01		/* lock on data queue (so_rcv only) */
X#define	SB_WANT		0x02		/* someone is waiting to lock */
X#define	SB_WAIT		0x04		/* someone is waiting for data/space */
X#define	SB_SEL		0x08		/* buffer is selected */
X#define	SB_COLL		0x10		/* collision selecting */
X};
X
X/*
X * Socket state bits.
X */
X#define	SS_NOFDREF		0x001	/* no file table ref any more */
X#define	SS_ISCONNECTED		0x002	/* socket connected to a peer */
X#define	SS_ISCONNECTING		0x004	/* in process of connecting to peer */
X#define	SS_ISDISCONNECTING	0x008	/* in process of disconnecting */
X#define	SS_CANTSENDMORE		0x010	/* can't send more data to peer */
X#define	SS_CANTRCVMORE		0x020	/* can't receive more data from peer */
X#define	SS_RCVATMARK		0x040	/* at mark on input */
X
X#define	SS_PRIV			0x080	/* privileged for broadcast, raw... */
X#define	SS_NBIO			0x100	/* non-blocking ops */
X#define	SS_ASYNC		0x200	/* async i/o notify */
X
X
X/*
X * Macros for sockets and socket buffering.
X */
X
X/* how much space is there in a socket buffer (so->so_snd or so->so_rcv) */
X#define	sbspace(sb) \
X    (MIN((long)((sb)->sb_hiwat - (sb)->sb_cc),\
X	 (long)((sb)->sb_mbmax - (sb)->sb_mbcnt)))
X
X/* do we have to send all at once on a socket? */
X#define	sosendallatonce(so) \
X    ((so)->so_proto->pr_flags & PR_ATOMIC)
X
X/* can we read something from so? */
X#define	soreadable(so) \
X    ((so)->so_rcv.sb_cc || ((so)->so_state & SS_CANTRCVMORE) || \
X	(so)->so_qlen || (so)->so_error)
X
X/* can we write something to so? */
X#define	sowriteable(so) \
X    (sbspace(&(so)->so_snd) > 0 && \
X	(((so)->so_state&SS_ISCONNECTED) || \
X	  ((so)->so_proto->pr_flags&PR_CONNREQUIRED)==0) || \
X     ((so)->so_state & SS_CANTSENDMORE) || \
X     (so)->so_error)
X
X/* adjust counters in sb reflecting allocation of m */
X#define	sballoc(sb, m) { \
X	(sb)->sb_cc += (m)->m_len; \
X	(sb)->sb_mbcnt += MSIZE; \
X	if ((m)->m_off > MMAXOFF) \
X		(sb)->sb_mbcnt += CLBYTES; \
X}
X
X/* adjust counters in sb reflecting freeing of m */
X#define	sbfree(sb, m) { \
X	(sb)->sb_cc -= (m)->m_len; \
X	(sb)->sb_mbcnt -= MSIZE; \
X	if ((m)->m_off > MMAXOFF) \
X		(sb)->sb_mbcnt -= CLBYTES; \
X}
X
X/* set lock on sockbuf sb */
X#define sblock(sb) { \
X	while ((sb)->sb_flags & SB_LOCK) { \
X		(sb)->sb_flags |= SB_WANT; \
X		sleep((caddr_t)&(sb)->sb_flags, PZERO+1); \
X	} \
X	(sb)->sb_flags |= SB_LOCK; \
X}
X
X/* release lock on sockbuf sb */
X#define	sbunlock(sb) { \
X	(sb)->sb_flags &= ~SB_LOCK; \
X	if ((sb)->sb_flags & SB_WANT) { \
X		(sb)->sb_flags &= ~SB_WANT; \
X		wakeup((caddr_t)&(sb)->sb_flags); \
X	} \
X}
X
X#define	sorwakeup(so)	sowakeup((so), &(so)->so_rcv)
X#define	sowwakeup(so)	sowakeup((so), &(so)->so_snd)
X
X#ifdef KERNEL
Xstruct	socket *sonewconn();
X#endif
END-of-h/socketvar.h
echo c - net
mkdir net
echo x - net/route.c
sed 's/^X//' >net/route.c << 'END-of-net/route.c'
X/*
X * Copyright (c) 1980, 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 *	@(#)route.c	7.3 (Berkeley) 12/30/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 "dir.h"
X#include "user.h"
X#include "ioctl.h"
X#include "errno.h"
X
X#include "if.h"
X#include "af.h"
X#include "route.h"
X
Xint	rttrash;		/* routes not in table but not freed */
Xstruct	sockaddr wildcard;	/* zero valued cookie for wildcard searches */
Xint	rthashsize = RTHASHSIZ;	/* for netstat, etc. */
X
X/*
X * Packet routing routines.
X */
Xrtalloc(ro)
X	register struct route *ro;
X{
X	register struct rtentry *rt;
X	register struct mbuf *m;
X	register u_long hash;
X	struct sockaddr *dst = &ro->ro_dst;
X	int (*match)(), doinghost, s;
X	struct afhash h;
X	u_int af = dst->sa_family;
X	struct mbuf **table;
X
X	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
X		return;				 /* XXX */
X	if (af >= AF_MAX)
X		return;
X	(*afswitch[af].af_hash)(dst, &h);
X	match = afswitch[af].af_netmatch;
X	hash = h.afh_hosthash, table = rthost, doinghost = 1;
X	s = splnet();
Xagain:
X	for (m = table[RTHASHMOD(hash)]; m; m = m->m_next) {
X		rt = mtod(m, struct rtentry *);
X		if (rt->rt_hash != hash)
X			continue;
X		if ((rt->rt_flags & RTF_UP) == 0 ||
X		    (rt->rt_ifp->if_flags & IFF_UP) == 0)
X			continue;
X		if (doinghost) {
X			if (bcmp((caddr_t)&rt->rt_dst, (caddr_t)dst,
X			    sizeof (*dst)))
X				continue;
X		} else {
X			if (rt->rt_dst.sa_family != af ||
X			    !(*match)(&rt->rt_dst, dst))
X				continue;
X		}
X		rt->rt_refcnt++;
X		splx(s);
X		if (dst == &wildcard)
X			rtstat.rts_wildcard++;
X		ro->ro_rt = rt;
X		return;
X	}
X	if (doinghost) {
X		doinghost = 0;
X		hash = h.afh_nethash, table = rtnet;
X		goto again;
X	}
X	/*
X	 * Check for wildcard gateway, by convention network 0.
X	 */
X	if (dst != &wildcard) {
X		dst = &wildcard, hash = 0;
X		goto again;
X	}
X	splx(s);
X	rtstat.rts_unreach++;
X}
X
Xrtfree(rt)
X	register struct rtentry *rt;
X{
X
X	if (rt == 0)
X		panic("rtfree");
X	rt->rt_refcnt--;
X	if (rt->rt_refcnt == 0 && (rt->rt_flags&RTF_UP) == 0) {
X		rttrash--;
X		(void) m_free(dtom(rt));
X	}
X}
X
X/*
X * Force a routing table entry to the specified
X * destination to go through the given gateway.
X * Normally called as a result of a routing redirect
X * message from the network layer.
X *
X * N.B.: must be called at splnet or higher
X *
X */
Xrtredirect(dst, gateway, flags, src)
X	struct sockaddr *dst, *gateway, *src;
X	int flags;
X{
X	struct route ro;
X	register struct rtentry *rt;
X
X	/* verify the gateway is directly reachable */
X	if (ifa_ifwithnet(gateway) == 0) {
X		rtstat.rts_badredirect++;
X		return;
X	}
X	ro.ro_dst = *dst;
X	ro.ro_rt = 0;
X	rtalloc(&ro);
X	rt = ro.ro_rt;
X#define	equal(a1, a2) \
X	(bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0)
X	/*
X	 * If the redirect isn't from our current router for this dst,
X	 * it's either old or wrong.  If it redirects us to ourselves,
X	 * we have a routing loop, perhaps as a result of an interface
X	 * going down recently.
X	 */
X	if ((rt && !equal(src, &rt->rt_gateway)) || ifa_ifwithaddr(gateway)) {
X		rtstat.rts_badredirect++;
X		if (rt)
X			rtfree(rt);
X		return;
X	}
X	/*
X	 * Create a new entry if we just got back a wildcard entry
X	 * or the the lookup failed.  This is necessary for hosts
X	 * which use routing redirects generated by smart gateways
X	 * to dynamically build the routing tables.
X	 */
X	if (rt &&
X	    (*afswitch[dst->sa_family].af_netmatch)(&wildcard, &rt->rt_dst)) {
X		rtfree(rt);
X		rt = 0;
X	}
X	if (rt == 0) {
X		rtinit(dst, gateway, (int)SIOCADDRT,
X		    (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
X		rtstat.rts_dynamic++;
X		return;
X	}
X	/*
X	 * Don't listen to the redirect if it's
X	 * for a route to an interface. 
X	 */
X	if (rt->rt_flags & RTF_GATEWAY) {
X		if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
X			/*
X			 * Changing from route to net => route to host.
X			 * Create new route, rather than smashing route to net.
X			 */
X			rtinit(dst, gateway, (int)SIOCADDRT,
X			    flags | RTF_DYNAMIC);
X			rtstat.rts_dynamic++;
X		} else {
X			/*
X			 * Smash the current notion of the gateway to
X			 * this destination.
X			 */
X			rt->rt_gateway = *gateway;
X			rt->rt_flags |= RTF_MODIFIED;
X			rtstat.rts_newgateway++;
X		}
X	} else
X		rtstat.rts_badredirect++;
X	rtfree(rt);
X}
X
X/*
X * Routing table ioctl interface.
X */
Xrtioctl(cmd, data)
X	int cmd;
X	caddr_t data;
X{
X
X	if (cmd != SIOCADDRT && cmd != SIOCDELRT)
X		return (EINVAL);
X	if (!suser())
X		return (u.u_error);
X	return (rtrequest(cmd, (struct rtentry *)data));
X}
X
X/*
X * Carry out a request to change the routing table.  Called by
X * interfaces at boot time to make their ``local routes'' known,
X * for ioctl's, and as the result of routing redirects.
X */
Xrtrequest(req, entry)
X	int req;
X	register struct rtentry *entry;
X{
X	register struct mbuf *m, **mprev;
X	struct mbuf **mfirst;
X	register struct rtentry *rt;
X	struct afhash h;
X	int s, error = 0, (*match)();
X	u_int af;
X	u_long hash;
X	struct ifaddr *ifa;
X	struct ifaddr *ifa_ifwithdstaddr();
X
X	af = entry->rt_dst.sa_family;
X	if (af >= AF_MAX)
X		return (EAFNOSUPPORT);
X	(*afswitch[af].af_hash)(&entry->rt_dst, &h);
X	if (entry->rt_flags & RTF_HOST) {
X		hash = h.afh_hosthash;
X		mprev = &rthost[RTHASHMOD(hash)];
X	} else {
X		hash = h.afh_nethash;
X		mprev = &rtnet[RTHASHMOD(hash)];
X	}
X	match = afswitch[af].af_netmatch;
X	s = splimp();
X	for (mfirst = mprev; m = *mprev; mprev = &m->m_next) {
X		rt = mtod(m, struct rtentry *);
X		if (rt->rt_hash != hash)
X			continue;
X		if (entry->rt_flags & RTF_HOST) {
X			if (!equal(&rt->rt_dst, &entry->rt_dst))
X				continue;
X		} else {
X			if (rt->rt_dst.sa_family != entry->rt_dst.sa_family ||
X			    (*match)(&rt->rt_dst, &entry->rt_dst) == 0)
X				continue;
X		}
X		if (equal(&rt->rt_gateway, &entry->rt_gateway))
X			break;
X	}
X	switch (req) {
X
X	case SIOCDELRT:
X		if (m == 0) {
X			error = ESRCH;
X			goto bad;
X		}
X		*mprev = m->m_next;
X		if (rt->rt_refcnt > 0) {
X			rt->rt_flags &= ~RTF_UP;
X			rttrash++;
X			m->m_next = 0;
X		} else
X			(void) m_free(m);
X		break;
X
X	case SIOCADDRT:
X		if (m) {
X			error = EEXIST;
X			goto bad;
X		}
X		if ((entry->rt_flags & RTF_GATEWAY) == 0) {
X			/*
X			 * If we are adding a route to an interface,
X			 * and the interface is a pt to pt link
X			 * we should search for the destination
X			 * as our clue to the interface.  Otherwise
X			 * we can use the local address.
X			 */
X			ifa = 0;
X			if (entry->rt_flags & RTF_HOST) 
X				ifa = ifa_ifwithdstaddr(&entry->rt_dst);
X			if (ifa == 0)
X				ifa = ifa_ifwithaddr(&entry->rt_gateway);
X		} else {
X			/*
X			 * If we are adding a route to a remote net
X			 * or host, the gateway may still be on the
X			 * other end of a pt to pt link.
X			 */
X			ifa = ifa_ifwithdstaddr(&entry->rt_gateway);
X		}
X		if (ifa == 0) {
X			ifa = ifa_ifwithnet(&entry->rt_gateway);
X			if (ifa == 0) {
X				error = ENETUNREACH;
X				goto bad;
X			}
X		}
X		m = m_get(M_DONTWAIT, MT_RTABLE);
X		if (m == 0) {
X			error = ENOBUFS;
X			goto bad;
X		}
X		m->m_next = *mfirst;
X		*mfirst = m;
X		m->m_off = MMINOFF;
X		m->m_len = sizeof (struct rtentry);
X		rt = mtod(m, struct rtentry *);
X		rt->rt_hash = hash;
X		rt->rt_dst = entry->rt_dst;
X		rt->rt_gateway = entry->rt_gateway;
X		rt->rt_flags = RTF_UP |
X		    (entry->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC));
X		rt->rt_refcnt = 0;
X		rt->rt_use = 0;
X		rt->rt_ifp = ifa->ifa_ifp;
X		break;
X	}
Xbad:
X	splx(s);
X	return (error);
X}
X
X/*
X * Set up a routing table entry, normally
X * for an interface.
X */
Xrtinit(dst, gateway, cmd, flags)
X	struct sockaddr *dst, *gateway;
X	int cmd, flags;
X{
X	struct rtentry route;
X
X	bzero((caddr_t)&route, sizeof (route));
X	route.rt_dst = *dst;
X	route.rt_gateway = *gateway;
X	route.rt_flags = flags;
X	(void) rtrequest(cmd, &route);
X}
END-of-net/route.c
echo x - net/route.h
sed 's/^X//' >net/route.h << 'END-of-net/route.h'
X/*
X * Copyright (c) 1980, 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 *	@(#)route.h	7.3 (Berkeley) 12/30/87
X */
X
X/*
X * Kernel resident routing tables.
X * 
X * The routing tables are initialized when interface addresses
X * are set by making entries for all directly connected interfaces.
X */
X
X/*
X * A route consists of a destination address and a reference
X * to a routing entry.  These are often held by protocols
X * in their control blocks, e.g. inpcb.
X */
Xstruct route {
X	struct	rtentry *ro_rt;
X	struct	sockaddr ro_dst;
X};
X
X/*
X * We distinguish between routes to hosts and routes to networks,
X * preferring the former if available.  For each route we infer
X * the interface to use from the gateway address supplied when
X * the route was entered.  Routes that forward packets through
X * gateways are marked so that the output routines know to address the
X * gateway rather than the ultimate destination.
X */
Xstruct rtentry {
X	u_long	rt_hash;		/* to speed lookups */
X	struct	sockaddr rt_dst;	/* key */
X	struct	sockaddr rt_gateway;	/* value */
X	short	rt_flags;		/* up/down?, host/net */
X	short	rt_refcnt;		/* # held references */
X	u_long	rt_use;			/* raw # packets forwarded */
X	struct	ifnet *rt_ifp;		/* the answer: interface to use */
X};
X
X#define	RTF_UP		0x1		/* route useable */
X#define	RTF_GATEWAY	0x2		/* destination is a gateway */
X#define	RTF_HOST	0x4		/* host entry (net otherwise) */
X#define	RTF_DYNAMIC	0x10		/* created dynamically (by redirect) */
X#define	RTF_MODIFIED	0x20		/* modified dynamically (by redirect) */
X
X/*
X * Routing statistics.
X */
Xstruct	rtstat {
X	short	rts_badredirect;	/* bogus redirect calls */
X	short	rts_dynamic;		/* routes created by redirects */
X	short	rts_newgateway;		/* routes modified by redirects */
X	short	rts_unreach;		/* lookups which failed */
X	short	rts_wildcard;		/* lookups satisfied by a wildcard */
X};
X
X#ifdef KERNEL
X#define	RTFREE(rt) \
X	if ((rt)->rt_refcnt == 1) \
X		rtfree(rt); \
X	else \
X		(rt)->rt_refcnt--;
X
X#ifdef	GATEWAY
X#define	RTHASHSIZ	64
X#else
X#define	RTHASHSIZ	8
X#endif
X#if	(RTHASHSIZ & (RTHASHSIZ - 1)) == 0
X#define RTHASHMOD(h)	((h) & (RTHASHSIZ - 1))
X#else
X#define RTHASHMOD(h)	((h) % RTHASHSIZ)
X#endif
Xstruct	mbuf *rthost[RTHASHSIZ];
Xstruct	mbuf *rtnet[RTHASHSIZ];
Xstruct	rtstat	rtstat;
X#endif
END-of-net/route.h
echo x - net/if_sl.c
sed 's/^X//' >net/if_sl.c << 'END-of-net/if_sl.c'
X/*
X * Copyright (c) 1987 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 *	@(#)if_sl.c	7.6.1.1 (Berkeley) 3/15/88
X */
X
X/*
X * Serial Line interface
X *
X * Rick Adams
X * Center for Seismic Studies
X * 1300 N 17th Street, Suite 1450
X * Arlington, Virginia 22209
X * (703)276-7900
X * rick at seismo.ARPA
X * seismo!rick
X *
X * Pounded on heavily by Chris Torek (chris at mimsy.umd.edu, umcp-cs!chris).
X * N.B.: this belongs in netinet, not net, the way it stands now.
X * Should have a link-layer type designation, but wouldn't be
X * backwards-compatible.
X *
X * Converted to 4.3BSD Beta by Chris Torek.
X * Other changes made at Berkeley, based in part on code by Kirk Smith.
X */
X
X/* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
X/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
X
X#include "sl.h"
X#if NSL > 0
X
X#include "param.h"
X#include "mbuf.h"
X#include "buf.h"
X#include "dk.h"
X#include "socket.h"
X#include "ioctl.h"
X#include "file.h"
X#include "tty.h"
X#include "errno.h"
X
X#include "if.h"
X#include "netisr.h"
X#include "route.h"
X#if INET
X#include "../netinet/in.h"
X#include "../netinet/in_systm.h"
X#include "../netinet/in_var.h"
X#include "../netinet/ip.h"
X#endif
X
X#include "../machine/mtpr.h"
X
X/*
X * N.B.: SLMTU is now a hard limit on input packet size.
X * SLMTU must be <= CLBYTES - sizeof(struct ifnet *).
X */
X#define	SLMTU	1006
X#define	SLIP_HIWAT	1000	/* don't start a new packet if HIWAT on queue */
X#define	CLISTRESERVE	1000	/* Can't let clists get too low */
X
Xstruct sl_softc {
X	struct	ifnet sc_if;	/* network-visible interface */
X	short	sc_flags;	/* see below */
X	short	sc_ilen;	/* length of input-packet-so-far */
X	struct	tty *sc_ttyp;	/* pointer to tty structure */
X	char	*sc_mp;		/* pointer to next available buf char */
X	char	*sc_buf;	/* input buffer */
X} sl_softc[NSL];
X
X/* flags */
X#define	SC_ESCAPED	0x0001	/* saw a FRAME_ESCAPE */
X
X#define FRAME_END	 	0300		/* Frame End */
X#define FRAME_ESCAPE		0333		/* Frame Esc */
X#define TRANS_FRAME_END	 	0334		/* transposed frame end */
X#define TRANS_FRAME_ESCAPE 	0335		/* transposed frame esc */
X
X#define t_sc T_LINEP
X
Xint sloutput(), slioctl(), ttrstrt();
X
X/*
X * Called from boot code to establish sl interfaces.
X */
Xslattach()
X{
X	register struct sl_softc *sc;
X	register int i = 0;
X
X	for (sc = sl_softc; i < NSL; sc++) {
X		sc->sc_if.if_name = "sl";
X		sc->sc_if.if_unit = i++;
X		sc->sc_if.if_mtu = SLMTU;
X		sc->sc_if.if_flags = IFF_POINTOPOINT;
X		sc->sc_if.if_ioctl = slioctl;
X		sc->sc_if.if_output = sloutput;
X		sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
X		if_attach(&sc->sc_if);
X	}
X}
X
X/*
X * Line specific open routine.
X * Attach the given tty to the first available sl unit.
X */
X/* ARGSUSED */
Xslopen(dev, tp)
X	dev_t dev;
X	register struct tty *tp;
X{
X	register struct sl_softc *sc;
X	register int nsl;
X
X	if (!suser())
X		return (EPERM);
X	if (tp->t_line == SLIPDISC)
X		return (EBUSY);
X
X	for (nsl = 0, sc = sl_softc; nsl < NSL; nsl++, sc++)
X		if (sc->sc_ttyp == NULL) {
X			sc->sc_flags = 0;
X			sc->sc_ilen = 0;
X			if (slinit(sc) == 0)
X				return (ENOBUFS);
X			tp->t_sc = (caddr_t)sc;
X			sc->sc_ttyp = tp;
X			ttyflush(tp, FREAD | FWRITE);
X			return (0);
X		}
X
X	return (ENXIO);
X}
X
X/*
X * Line specific close routine.
X * Detach the tty from the sl unit.
X * Mimics part of ttyclose().
X */
Xslclose(tp)
X	struct tty *tp;
X{
X	register struct sl_softc *sc;
X	int s;
X
X	ttywflush(tp);
X	tp->t_line = 0;
X	s = splimp();		/* paranoid; splnet probably ok */
X	sc = (struct sl_softc *)tp->t_sc;
X	if (sc != NULL) {
X		if_down(&sc->sc_if);
X		sc->sc_ttyp = NULL;
X		tp->t_sc = NULL;
X		MCLFREE((struct mbuf *)sc->sc_buf);
X		sc->sc_buf = 0;
X	}
X	splx(s);
X}
X
X/*
X * Line specific (tty) ioctl routine.
X * Provide a way to get the sl unit number.
X */
X/* ARGSUSED */
Xsltioctl(tp, cmd, data, flag)
X	struct tty *tp;
X	caddr_t data;
X{
X
X	if (cmd == TIOCGETD) {
X		*(int *)data = ((struct sl_softc *)tp->t_sc)->sc_if.if_unit;
X		return (0);
X	}
X	return (-1);
X}
X
X/*
X * Queue a packet.  Start transmission if not active.
X */
Xsloutput(ifp, m, dst)
X	register struct ifnet *ifp;
X	register struct mbuf *m;
X	struct sockaddr *dst;
X{
X	register struct sl_softc *sc;
X	int s;
X
X	/*
X	 * `Cannot happen' (see slioctl).  Someday we will extend
X	 * the line protocol to support other address families.
X	 */
X	if (dst->sa_family != AF_INET) {
X		printf("sl%d: af%d not supported\n", ifp->if_unit,
X			dst->sa_family);
X		m_freem(m);
X		return (EAFNOSUPPORT);
X	}
X
X	sc = &sl_softc[ifp->if_unit];
X	if (sc->sc_ttyp == NULL) {
X		m_freem(m);
X		return (ENETDOWN);	/* sort of */
X	}
X	if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
X		m_freem(m);
X		return (EHOSTUNREACH);
X	}
X	s = splimp();
X	if (IF_QFULL(&ifp->if_snd)) {
X		IF_DROP(&ifp->if_snd);
X		splx(s);
X		m_freem(m);
X		sc->sc_if.if_oerrors++;
X		return (ENOBUFS);
X	}
X	IF_ENQUEUE(&ifp->if_snd, m);
X	if (sc->sc_ttyp->t_outq.c_cc == 0) {
X		splx(s);
X		slstart(sc->sc_ttyp);
X	} else
X		splx(s);
X	return (0);
X}
X
X/*
X * Start output on interface.  Get another datagram
X * to send from the interface queue and map it to
X * the interface before starting output.
X */
Xslstart(tp)
X	register struct tty *tp;
X{
X	register struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
X	register struct mbuf *m;
X	register int len;
X	register u_char *cp;
X	int nd, np, n, s;
X	struct mbuf *m2;
X	extern int cfreecount;
X
X	for (;;) {
X		/*
X		 * If there is more in the output queue, just send it now.
X		 * We are being called in lieu of ttstart and must do what
X		 * it would.
X		 */
X		if (tp->t_outq.c_cc > 0)
X			ttstart(tp);
X		if (tp->t_outq.c_cc > SLIP_HIWAT)
X			return;
X
X		/*
X		 * This happens briefly when the line shuts down.
X		 */
X		if (sc == NULL)
X			return;
X
X		/*
X		 * If system is getting low on clists
X		 * and we have something running already, stop here.
X		 */
X		if (cfreecount < CLISTRESERVE + SLMTU && tp->t_outq.c_cc == 0)
X			return;
X
X		/*
X		 * Get a packet and send it to the interface.
X		 */
X		s = splimp();
X		IF_DEQUEUE(&sc->sc_if.if_snd, m);
X		splx(s);
X		if (m == NULL)
X			return;
X
X		/*
X		 * The extra FRAME_END will start up a new packet, and thus
X		 * will flush any accumulated garbage.  We do this whenever
X		 * the line may have been idle for some time.
X		 */
X		if (tp->t_outq.c_cc == 0)
X			(void) putc(FRAME_END, &tp->t_outq);
X
X		while (m) {
X			cp = mtod(m, u_char *);
X			len = m->m_len;
X			while (len > 0) {
X				/*
X				 * Find out how many bytes in the string we can
X				 * handle without doing something special.
X				 */
X				nd = locc(FRAME_ESCAPE, len, cp);
X				np = locc(FRAME_END, len, cp);
X				n = len - MAX(nd, np);
X				if (n) {
X					/*
X					 * Put n characters at once
X					 * into the tty output queue.
X					 */
X					if (b_to_q((char *)cp, n, &tp->t_outq))
X						break;
X					len -= n;
X					cp += n;
X				}
X				/*
X				 * If there are characters left in the mbuf,
X				 * the first one must be special..
X				 * Put it out in a different form.
X				 */
X				if (len) {
X					if (putc(FRAME_ESCAPE, &tp->t_outq))
X						break;
X					if (putc(*cp == FRAME_ESCAPE ?
X					   TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
X					   &tp->t_outq)) {
X						(void) unputc(&tp->t_outq);
X						break;
X					}
X					cp++;
X					len--;
X				}
X			}
X			MFREE(m, m2);
X			m = m2;
X		}
X
X		if (putc(FRAME_END, &tp->t_outq)) {
X			/*
X			 * Not enough room.  Remove a char to make room
X			 * and end the packet normally.
X			 * If you get many collisions (more than one or two
X			 * a day) you probably do not have enough clists
X			 * and you should increase "nclist" in param.c.
X			 */
X			(void) unputc(&tp->t_outq);
X			(void) putc(FRAME_END, &tp->t_outq);
X			sc->sc_if.if_collisions++;
X		} else
X			sc->sc_if.if_opackets++;
X	}
X}
X
Xslinit(sc)
X	register struct sl_softc *sc;
X{
X	struct mbuf *p;
X
X	if (sc->sc_buf == (char *) 0) {
X		MCLALLOC(p, 1);
X		if (p) {
X			sc->sc_buf = (char *)p;
X			sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
X		} else {
X			printf("sl%d: can't allocate buffer\n", sc - sl_softc);
X			sc->sc_if.if_flags &= ~IFF_UP;
X			return (0);
X		}
X	}
X	return (1);
X}
X
X/*
X * Copy data buffer to mbuf chain; add ifnet pointer ifp.
X */
Xstruct mbuf *
Xsl_btom(sc, len, ifp)
X	struct sl_softc *sc;
X	register int len;
X	struct ifnet *ifp;
X{
X	register caddr_t cp;
X	register struct mbuf *m, **mp;
X	register unsigned count;
X	struct mbuf *top = NULL;
X
X	cp = sc->sc_buf + sizeof(struct ifnet *);
X	mp = ⊤
X	while (len > 0) {
X		MGET(m, M_DONTWAIT, MT_DATA);
X		if ((*mp = m) == NULL) {
X			m_freem(top);
X			return (NULL);
X		}
X		if (ifp)
X			m->m_off += sizeof(ifp);
X		/*
X		 * If we have at least NBPG bytes,
X		 * allocate a new page.  Swap the current buffer page
X		 * with the new one.  We depend on having a space
X		 * left at the beginning of the buffer
X		 * for the interface pointer.
X		 */
X		if (len >= NBPG) {
X			MCLGET(m);
X			if (m->m_len == CLBYTES) {
X				cp = mtod(m, char *);
X				m->m_off = (int)sc->sc_buf - (int)m;
X				sc->sc_buf = cp;
X				if (ifp) {
X					m->m_off += sizeof(ifp);
X					count = MIN(len,
X					    CLBYTES - sizeof(struct ifnet *));
X				} else
X					count = MIN(len, CLBYTES);
X				goto nocopy;
X			}
X		}
X		if (ifp)
X			count = MIN(len, MLEN - sizeof(ifp));
X		else
X			count = MIN(len, MLEN);
X		bcopy(cp, mtod(m, caddr_t), count);
Xnocopy:
X		m->m_len = count;
X		if (ifp) {
X			m->m_off -= sizeof(ifp);
X			m->m_len += sizeof(ifp);
X			*mtod(m, struct ifnet **) = ifp;
X			ifp = NULL;
X		}
X		cp += count;
X		len -= count;
X		mp = &m->m_next;
X	}
X	return (top);
X}
X
X/*
X * tty interface receiver interrupt.
X */
Xslinput(c, tp)
X	register int c;
X	register struct tty *tp;
X{
X	register struct sl_softc *sc;
X	register struct mbuf *m;
X	int s;
X
X	tk_nin++;
X	sc = (struct sl_softc *)tp->t_sc;
X	if (sc == NULL)
X		return;
X
X	c &= 0xff;
X	if (sc->sc_flags & SC_ESCAPED) {
X		sc->sc_flags &= ~SC_ESCAPED;
X		switch (c) {
X
X		case TRANS_FRAME_ESCAPE:
X			c = FRAME_ESCAPE;
X			break;
X
X		case TRANS_FRAME_END:
X			c = FRAME_END;
X			break;
X
X		default:
X			sc->sc_if.if_ierrors++;
X			sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
X			sc->sc_ilen = 0;
X			return;
X		}
X	} else {
X		switch (c) {
X
X		case FRAME_END:
X			if (sc->sc_ilen == 0)	/* ignore */
X				return;
X			m = sl_btom(sc, sc->sc_ilen, &sc->sc_if);
X			if (m == NULL) {
X				sc->sc_if.if_ierrors++;
X				return;
X			}
X			sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
X			sc->sc_ilen = 0;
X			sc->sc_if.if_ipackets++;
X			s = splimp();
X			if (IF_QFULL(&ipintrq)) {
X				IF_DROP(&ipintrq);
X				sc->sc_if.if_ierrors++;
X				m_freem(m);
X			} else {
X				IF_ENQUEUE(&ipintrq, m);
X				schednetisr(NETISR_IP);
X			}
X			splx(s);
X			return;
X
X		case FRAME_ESCAPE:
X			sc->sc_flags |= SC_ESCAPED;
X			return;
X		}
X	}
X	if (++sc->sc_ilen > SLMTU) {
X		sc->sc_if.if_ierrors++;
X		sc->sc_mp = sc->sc_buf + sizeof(struct ifnet *);
X		sc->sc_ilen = 0;
X		return;
X	}
X	*sc->sc_mp++ = c;
X}
X
X/*
X * Process an ioctl request.
X */
Xslioctl(ifp, cmd, data)
X	register struct ifnet *ifp;
X	int cmd;
X	caddr_t data;
X{
X	register struct ifaddr *ifa = (struct ifaddr *)data;
X	int s = splimp(), error = 0;
X
X	switch (cmd) {
X
X	case SIOCSIFADDR:
X		if (ifa->ifa_addr.sa_family == AF_INET)
X			ifp->if_flags |= IFF_UP;
X		else
X			error = EAFNOSUPPORT;
X		break;
X
X	case SIOCSIFDSTADDR:
X		if (ifa->ifa_addr.sa_family != AF_INET)
X			error = EAFNOSUPPORT;
X		break;
X
X	default:
X		error = EINVAL;
X	}
X	splx(s);
X	return (error);
X}
X#endif
END-of-net/if_sl.c
echo c - sys
mkdir sys
echo x - sys/uipc_mbuf.c
sed 's/^X//' >sys/uipc_mbuf.c << 'END-of-sys/uipc_mbuf.c'
X/*
X * Copyright (c) 1982, 1986, 1988 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 *	@(#)uipc_mbuf.c	7.4.1.2 (Berkeley) 2/8/88
X */
X
X#include "../machine/pte.h"
X
X#include "param.h"
X#include "dir.h"
X#include "user.h"
X#include "proc.h"
X#include "cmap.h"
X#include "map.h"
X#include "mbuf.h"
X#include "vm.h"
X#include "kernel.h"
X#include "syslog.h"
X#include "domain.h"
X#include "protosw.h"
X
Xmbinit()
X{
X	int s;
X
X#if CLBYTES < 4096
X#define NCL_INIT	(4096/CLBYTES)
X#else
X#define NCL_INIT	1
X#endif
X	s = splimp();
X	if (m_clalloc(NCL_INIT, MPG_MBUFS, M_DONTWAIT) == 0)
X		goto bad;
X	if (m_clalloc(NCL_INIT, MPG_CLUSTERS, M_DONTWAIT) == 0)
X		goto bad;
X	splx(s);
X	return;
Xbad:
X	panic("mbinit");
X}
X
X/*
X * Must be called at splimp.
X */
X/* ARGSUSED */
Xcaddr_t
Xm_clalloc(ncl, how, canwait)
X	register int ncl;
X	int how;
X{
X	int npg, mbx;
X	register struct mbuf *m;
X	register int i;
X	static int logged;
X
X	npg = ncl * CLSIZE;
X	mbx = rmalloc(mbmap, (long)npg);
X	if (mbx == 0) {
X		if (logged == 0) {
X			logged++;
X			log(LOG_ERR, "mbuf map full\n");
X		}
X		return (0);
X	}
X	m = cltom(mbx * NBPG / MCLBYTES);
X	if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
X		rmfree(mbmap, (long)npg, (long)mbx);
X		return (0);
X	}
X	vmaccess(&Mbmap[mbx], (caddr_t)m, npg);
X	switch (how) {
X
X	case MPG_CLUSTERS:
X		ncl = ncl * CLBYTES / MCLBYTES;
X		for (i = 0; i < ncl; i++) {
X			m->m_off = 0;
X			m->m_next = mclfree;
X			mclfree = m;
X			m += MCLBYTES / sizeof (*m);
X			mbstat.m_clfree++;
X		}
X		mbstat.m_clusters += ncl;
X		break;
X
X	case MPG_MBUFS:
X		for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) {
X			m->m_off = 0;
X			m->m_type = MT_DATA;
X			mbstat.m_mtypes[MT_DATA]++;
X			mbstat.m_mbufs++;
X			(void) m_free(m);
X			m++;
X		}
X		break;
X
X	case MPG_SPACE:
X		mbstat.m_space++;
X		break;
X	}
X	return ((caddr_t)m);
X}
X
Xm_pgfree(addr, n)
X	caddr_t addr;
X	int n;
X{
X
X#ifdef lint
X	addr = addr; n = n;
X#endif
X}
X
X/*
X * Must be called at splimp.
X */
Xm_expand(canwait)
X	int canwait;
X{
X	register struct domain *dp;
X	register struct protosw *pr;
X	int tries;
X
X	for (tries = 0;; ) {
X		if (m_clalloc(1, MPG_MBUFS, canwait))
X			return (1);
X		if (canwait == 0 || tries++)
X			return (0);
X
X		/* ask protocols to free space */
X		for (dp = domains; dp; dp = dp->dom_next)
X			for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW;
X			    pr++)
X				if (pr->pr_drain)
X					(*pr->pr_drain)();
X		mbstat.m_drain++;
X	}
X}
X
X/* NEED SOME WAY TO RELEASE SPACE */
X
X/*
X * Space allocation routines.
X * These are also available as macros
X * for critical paths.
X */
Xstruct mbuf *
Xm_get(canwait, type)
X	int canwait, type;
X{
X	register struct mbuf *m;
X
X	MGET(m, canwait, type);
X	return (m);
X}
X
Xstruct mbuf *
Xm_getclr(canwait, type)
X	int canwait, type;
X{
X	register struct mbuf *m;
X
X	MGET(m, canwait, type);
X	if (m == 0)
X		return (0);
X	bzero(mtod(m, caddr_t), MLEN);
X	return (m);
X}
X
Xstruct mbuf *
Xm_free(m)
X	struct mbuf *m;
X{
X	register struct mbuf *n;
X
X	MFREE(m, n);
X	return (n);
X}
X
X/*
X * Get more mbufs; called from MGET macro if mfree list is empty.
X * Must be called at splimp.
X */
X/*ARGSUSED*/
Xstruct mbuf *
Xm_more(canwait, type)
X	int canwait, type;
X{
X	register struct mbuf *m;
X
X	while (m_expand(canwait) == 0) {
X		if (canwait == M_WAIT) {
X			mbstat.m_wait++;
X			m_want++;
X			sleep((caddr_t)&mfree, PZERO - 1);
X		} else {
X			mbstat.m_drops++;
X			return (NULL);
X		}
X	}
X#define m_more(x,y) (panic("m_more"), (struct mbuf *)0)
X	MGET(m, canwait, type);
X#undef m_more
X	return (m);
X}
X
Xm_freem(m)
X	register struct mbuf *m;
X{
X	register struct mbuf *n;
X	register int s;
X
X	if (m == NULL)
X		return;
X	s = splimp();
X	do {
X		MFREE(m, n);
X	} while (m = n);
X	splx(s);
X}
X
X/*
X * Mbuffer utility routines.
X */
X
X/*
X * Make a copy of an mbuf chain starting "off" bytes from the beginning,
X * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
X * Should get M_WAIT/M_DONTWAIT from caller.
X */
Xstruct mbuf *
Xm_copy(m, off, len)
X	register struct mbuf *m;
X	int off;
X	register int len;
X{
X	register struct mbuf *n, **np;
X	struct mbuf *top, *p;
X
X	if (len == 0)
X		return (0);
X	if (off < 0 || len < 0)
X		panic("m_copy");
X	while (off > 0) {
X		if (m == 0)
X			panic("m_copy");
X		if (off < m->m_len)
X			break;
X		off -= m->m_len;
X		m = m->m_next;
X	}
X	np = ⊤
X	top = 0;
X	while (len > 0) {
X		if (m == 0) {
X			if (len != M_COPYALL)
X				panic("m_copy");
X			break;
X		}
X		MGET(n, M_DONTWAIT, m->m_type);
X		*np = n;
X		if (n == 0)
X			goto nospace;
X		n->m_len = MIN(len, m->m_len - off);
X		if (m->m_off > MMAXOFF) {
X			p = mtod(m, struct mbuf *);
X			n->m_off = ((int)p - (int)n) + off;
X			mclrefcnt[mtocl(p)]++;
X		} else
X			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
X			    (unsigned)n->m_len);
X		if (len != M_COPYALL)
X			len -= n->m_len;
X		off = 0;
X		m = m->m_next;
X		np = &n->m_next;
X	}
X	return (top);
Xnospace:
X	m_freem(top);
X	return (0);
X}
X
Xm_cat(m, n)
X	register struct mbuf *m, *n;
X{
X	while (m->m_next)
X		m = m->m_next;
X	while (n) {
X		if (m->m_off >= MMAXOFF ||
X		    m->m_off + m->m_len + n->m_len > MMAXOFF) {
X			/* just join the two chains */
X			m->m_next = n;
X			return;
X		}
X		/* splat the data from one into the other */
X		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
X		    (u_int)n->m_len);
X		m->m_len += n->m_len;
X		n = m_free(n);
X	}
X}
X
Xm_adj(mp, len)
X	struct mbuf *mp;
X	register int len;
X{
X	register struct mbuf *m;
X	register count;
X
X	if ((m = mp) == NULL)
X		return;
X	if (len >= 0) {
X		while (m != NULL && len > 0) {
X			if (m->m_len <= len) {
X				len -= m->m_len;
X				m->m_len = 0;
X				m = m->m_next;
X			} else {
X				m->m_len -= len;
X				m->m_off += len;
X				break;
X			}
X		}
X	} else {
X		/*
X		 * Trim from tail.  Scan the mbuf chain,
X		 * calculating its length and finding the last mbuf.
X		 * If the adjustment only affects this mbuf, then just
X		 * adjust and return.  Otherwise, rescan and truncate
X		 * after the remaining size.
X		 */
X		len = -len;
X		count = 0;
X		for (;;) {
X			count += m->m_len;
X			if (m->m_next == (struct mbuf *)0)
X				break;
X			m = m->m_next;
X		}
X		if (m->m_len >= len) {
X			m->m_len -= len;
X			return;
X		}
X		count -= len;
X		/*
X		 * Correct length for chain is "count".
X		 * Find the mbuf with last data, adjust its length,
X		 * and toss data from remaining mbufs on chain.
X		 */
X		for (m = mp; m; m = m->m_next) {
X			if (m->m_len >= count) {
X				m->m_len = count;
X				break;
X			}
X			count -= m->m_len;
X		}
X		while (m = m->m_next)
X			m->m_len = 0;
X	}
X}
X
X/*
X * Rearange an mbuf chain so that len bytes are contiguous
X * and in the data area of an mbuf (so that mtod and dtom
X * will work for a structure of size len).  Returns the resulting
X * mbuf chain on success, frees it and returns null on failure.
X * If there is room, it will add up to MPULL_EXTRA bytes to the
X * contiguous region in an attempt to avoid being called next time.
X */
Xstruct mbuf *
Xm_pullup(n, len)
X	register struct mbuf *n;
X	int len;
X{
X	register struct mbuf *m;
X	register int count;
X	int space;
X
X	if (n->m_off + len <= MMAXOFF && n->m_next) {
X		m = n;
X		n = n->m_next;
X		len -= m->m_len;
X	} else {
X		if (len > MLEN)
X			goto bad;
X		MGET(m, M_DONTWAIT, n->m_type);
X		if (m == 0)
X			goto bad;
X		m->m_len = 0;
X	}
X	space = MMAXOFF - m->m_off;
X	do {
X		count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len);
X		bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len,
X		  (unsigned)count);
X		len -= count;
X		m->m_len += count;
X		n->m_len -= count;
X		if (n->m_len)
X			n->m_off += count;
X		else
X			n = m_free(n);
X	} while (len > 0 && n);
X	if (len > 0) {
X		(void) m_free(m);
X		goto bad;
X	}
X	m->m_next = n;
X	return (m);
Xbad:
X	m_freem(n);
X	return (0);
X}
END-of-sys/uipc_mbuf.c
echo x - sys/uipc_socket.c
sed 's/^X//' >sys/uipc_socket.c << 'END-of-sys/uipc_socket.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 *	@(#)uipc_socket.c	7.8 (Berkeley) 1/20/88
X */
X
X#include "param.h"
X#include "dir.h"
X#include "user.h"
X#include "proc.h"
X#include "file.h"
X#include "mbuf.h"
X#include "domain.h"
X#include "protosw.h"
X#include "socket.h"
X#include "socketvar.h"
X
X/*
X * Socket operation routines.
X * These routines are called by the routines in
X * sys_socket.c or from a system process, and
X * implement the semantics of socket operations by
X * switching out to the protocol specific routines.
X *
X * TODO:
X *	test socketpair
X *	clean up async
X *	out-of-band is a kludge
X */
X/*ARGSUSED*/
Xsocreate(dom, aso, type, proto)
X	struct socket **aso;
X	register int type;
X	int proto;
X{
X	register struct protosw *prp;
X	register struct socket *so;
X	register struct mbuf *m;
X	register int error;
X
X	if (proto)
X		prp = pffindproto(dom, proto, type);
X	else
X		prp = pffindtype(dom, type);
X	if (prp == 0)
X		return (EPROTONOSUPPORT);
X	if (prp->pr_type != type)
X		return (EPROTOTYPE);
X	m = m_getclr(M_WAIT, MT_SOCKET);
X	so = mtod(m, struct socket *);
X	so->so_options = 0;
X	so->so_state = 0;
X	so->so_type = type;
X	if (u.u_uid == 0)
X		so->so_state = SS_PRIV;
X	so->so_proto = prp;
X	error =
X	    (*prp->pr_usrreq)(so, PRU_ATTACH,
X		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
X	if (error) {
X		so->so_state |= SS_NOFDREF;
X		sofree(so);
X		return (error);
X	}
X	*aso = so;
X	return (0);
X}
X
Xsobind(so, nam)
X	struct socket *so;
X	struct mbuf *nam;
X{
X	int s = splnet();
X	int error;
X
X	error =
X	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
X		(struct mbuf *)0, nam, (struct mbuf *)0);
X	splx(s);
X	return (error);
X}
X
Xsolisten(so, backlog)
X	register struct socket *so;
X	int backlog;
X{
X	int s = splnet(), error;
X
X	error =
X	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
X		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
X	if (error) {
X		splx(s);
X		return (error);
X	}
X	if (so->so_q == 0) {
X		so->so_q = so;
X		so->so_q0 = so;
X		so->so_options |= SO_ACCEPTCONN;
X	}
X	if (backlog < 0)
X		backlog = 0;
X	so->so_qlimit = MIN(backlog, SOMAXCONN);
X	splx(s);
X	return (0);
X}
X
Xsofree(so)
X	register struct socket *so;
X{
X
X	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
X		return;
X	if (so->so_head) {
X		if (!soqremque(so, 0) && !soqremque(so, 1))
X			panic("sofree dq");
X		so->so_head = 0;
X	}
X	sbrelease(&so->so_snd);
X	sorflush(so);
X	(void) m_free(dtom(so));
X}
X
X/*
X * Close a socket on last file table reference removal.
X * Initiate disconnect if connected.
X * Free socket when disconnect complete.
X */
Xsoclose(so)
X	register struct socket *so;
X{
X	int s = splnet();		/* conservative */
X	int error = 0;
X
X	if (so->so_options & SO_ACCEPTCONN) {
X		while (so->so_q0 != so)
X			(void) soabort(so->so_q0);
X		while (so->so_q != so)
X			(void) soabort(so->so_q);
X	}
X	if (so->so_pcb == 0)
X		goto discard;
X	if (so->so_state & SS_ISCONNECTED) {
X		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
X			error = sodisconnect(so);
X			if (error)
X				goto drop;
X		}
X		if (so->so_options & SO_LINGER) {
X			if ((so->so_state & SS_ISDISCONNECTING) &&
X			    (so->so_state & SS_NBIO))
X				goto drop;
X			while (so->so_state & SS_ISCONNECTED)
X				sleep((caddr_t)&so->so_timeo, PZERO+1);
X		}
X	}
Xdrop:
X	if (so->so_pcb) {
X		int error2 =
X		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
X			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
X		if (error == 0)
X			error = error2;
X	}
Xdiscard:
X	if (so->so_state & SS_NOFDREF)
X		panic("soclose: NOFDREF");
X	so->so_state |= SS_NOFDREF;
X	sofree(so);
X	splx(s);
X	return (error);
X}
X
X/*
X * Must be called at splnet...
X */
Xsoabort(so)
X	struct socket *so;
X{
X
X	return (
X	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
X		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
X}
X
Xsoaccept(so, nam)
X	register struct socket *so;
X	struct mbuf *nam;
X{
X	int s = splnet();
X	int error;
X
X	if ((so->so_state & SS_NOFDREF) == 0)
X		panic("soaccept: !NOFDREF");
X	so->so_state &= ~SS_NOFDREF;
X	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
X	    (struct mbuf *)0, nam, (struct mbuf *)0);
X	splx(s);
X	return (error);
X}
X
Xsoconnect(so, nam)
X	register struct socket *so;
X	struct mbuf *nam;
X{
X	int s;
X	int error;
X
X	if (so->so_options & SO_ACCEPTCONN)
X		return (EOPNOTSUPP);
X	s = splnet();
X	/*
X	 * If protocol is connection-based, can only connect once.
X	 * Otherwise, if connected, try to disconnect first.
X	 * This allows user to disconnect by connecting to, e.g.,
X	 * a null address.
X	 */
X	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
X	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
X	    (error = sodisconnect(so))))
X		error = EISCONN;
X	else
X		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
X		    (struct mbuf *)0, nam, (struct mbuf *)0);
X	splx(s);
X	return (error);
X}
X
Xsoconnect2(so1, so2)
X	register struct socket *so1;
X	struct socket *so2;
X{
X	int s = splnet();
X	int error;
X
X	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
X	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
X	splx(s);
X	return (error);
X}
X
Xsodisconnect(so)
X	register struct socket *so;
X{
X	int s = splnet();
X	int error;
X
X	if ((so->so_state & SS_ISCONNECTED) == 0) {
X		error = ENOTCONN;
X		goto bad;
X	}
X	if (so->so_state & SS_ISDISCONNECTING) {
X		error = EALREADY;
X		goto bad;
X	}
X	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
X	    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
Xbad:
X	splx(s);
X	return (error);
X}
X
X/*
X * Send on a socket.
X * If send must go all at once and message is larger than
X * send buffering, then hard error.
X * Lock against other senders.
X * If must go all at once and not enough room now, then
X * inform user that this would block and do nothing.
X * Otherwise, if nonblocking, send as much as possible.
X */
Xsosend(so, nam, uio, flags, rights)
X	register struct socket *so;
X	struct mbuf *nam;
X	register struct uio *uio;
X	int flags;
X	struct mbuf *rights;
X{
X	struct mbuf *top = 0;
X	register struct mbuf *m, **mp;
X	register int space;
X	int len, rlen = 0, error = 0, s, dontroute, first = 1;
X
X	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
X		return (EMSGSIZE);
X	dontroute =
X	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
X	    (so->so_proto->pr_flags & PR_ATOMIC);
X	u.u_ru.ru_msgsnd++;
X	if (rights)
X		rlen = rights->m_len;
X#define	snderr(errno)	{ error = errno; splx(s); goto release; }
X
Xrestart:
X	sblock(&so->so_snd);
X	do {
X		s = splnet();
X		if (so->so_state & SS_CANTSENDMORE)
X			snderr(EPIPE);
X		if (so->so_error) {
X			error = so->so_error;
X			so->so_error = 0;			/* ??? */
X			splx(s);
X			goto release;
X		}
X		if ((so->so_state & SS_ISCONNECTED) == 0) {
X			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
X				snderr(ENOTCONN);
X			if (nam == 0)
X				snderr(EDESTADDRREQ);
X		}
X		if (flags & MSG_OOB)
X			space = 1024;
X		else {
X			space = sbspace(&so->so_snd);
X			if (space <= rlen ||
X			   (sosendallatonce(so) &&
X				space < uio->uio_resid + rlen) ||
X			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
X			   so->so_snd.sb_cc >= CLBYTES &&
X			   (so->so_state & SS_NBIO) == 0)) {
X				if (so->so_state & SS_NBIO) {
X					if (first)
X						error = EWOULDBLOCK;
X					splx(s);
X					goto release;
X				}
X				sbunlock(&so->so_snd);
X				sbwait(&so->so_snd);
X				splx(s);
X				goto restart;
X			}
X		}
X		splx(s);
X		mp = ⊤
X		space -= rlen;
X		while (space > 0) {
X			MGET(m, M_WAIT, MT_DATA);
X			if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) {
X				MCLGET(m);
X				if (m->m_len != CLBYTES)
X					goto nopages;
X				len = MIN(CLBYTES, uio->uio_resid);
X				space -= CLBYTES;
X			} else {
Xnopages:
X				len = MIN(MIN(MLEN, uio->uio_resid), space);
X				space -= len;
X			}
X			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
X			m->m_len = len;
X			*mp = m;
X			if (error)
X				goto release;
X			mp = &m->m_next;
X			if (uio->uio_resid <= 0)
X				break;
X		}
X		if (dontroute)
X			so->so_options |= SO_DONTROUTE;
X		s = splnet();					/* XXX */
X		error = (*so->so_proto->pr_usrreq)(so,
X		    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
X		    top, (caddr_t)nam, rights);
X		splx(s);
X		if (dontroute)
X			so->so_options &= ~SO_DONTROUTE;
X		rights = 0;
X		rlen = 0;
X		top = 0;
X		first = 0;
X		if (error)
X			break;
X	} while (uio->uio_resid);
X
Xrelease:
X	sbunlock(&so->so_snd);
X	if (top)
X		m_freem(top);
X	if (error == EPIPE)
X		psignal(u.u_procp, SIGPIPE);
X	return (error);
X}
X
X/*
X * Implement receive operations on a socket.
X * We depend on the way that records are added to the sockbuf
X * by sbappend*.  In particular, each record (mbufs linked through m_next)
X * must begin with an address if the protocol so specifies,
X * followed by an optional mbuf containing access rights if supported
X * by the protocol, and then zero or more mbufs of data.
X * In order to avoid blocking network interrupts for the entire time here,
X * we splx() while doing the actual copy to user space.
X * Although the sockbuf is locked, new data may still be appended,
X * and thus we must maintain consistency of the sockbuf during that time.
X */
Xsoreceive(so, aname, uio, flags, rightsp)
X	register struct socket *so;
X	struct mbuf **aname;
X	register struct uio *uio;
X	int flags;
X	struct mbuf **rightsp;
X{
X	register struct mbuf *m;
X	register int len, error = 0, s, offset;
X	struct protosw *pr = so->so_proto;
X	struct mbuf *nextrecord;
X	int moff;
X
X	if (rightsp)
X		*rightsp = 0;
X	if (aname)
X		*aname = 0;
X	if (flags & MSG_OOB) {
X		m = m_get(M_WAIT, MT_DATA);
X		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
X		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
X		if (error)
X			goto bad;
X		do {
X			len = uio->uio_resid;
X			if (len > m->m_len)
X				len = m->m_len;
X			error =
X			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
X			m = m_free(m);
X		} while (uio->uio_resid && error == 0 && m);
Xbad:
X		if (m)
X			m_freem(m);
X		return (error);
X	}
X
Xrestart:
X	sblock(&so->so_rcv);
X	s = splnet();
X
X	if (so->so_rcv.sb_cc == 0) {
X		if (so->so_error) {
X			error = so->so_error;
X			so->so_error = 0;
X			goto release;
X		}
X		if (so->so_state & SS_CANTRCVMORE)
X			goto release;
X		if ((so->so_state & SS_ISCONNECTED) == 0 &&
X		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
X			error = ENOTCONN;
X			goto release;
X		}
X		if (uio->uio_resid == 0)
X			goto release;
X		if (so->so_state & SS_NBIO) {
X			error = EWOULDBLOCK;
X			goto release;
X		}
X		sbunlock(&so->so_rcv);
X		sbwait(&so->so_rcv);
X		splx(s);
X		goto restart;
X	}
X	u.u_ru.ru_msgrcv++;
X	m = so->so_rcv.sb_mb;
X	if (m == 0)
X		panic("receive 1");
X	nextrecord = m->m_act;
X	if (pr->pr_flags & PR_ADDR) {
X		if (m->m_type != MT_SONAME)
X			panic("receive 1a");
X		if (flags & MSG_PEEK) {
X			if (aname)
X				*aname = m_copy(m, 0, m->m_len);
X			m = m->m_next;
X		} else {
X			sbfree(&so->so_rcv, m);
X			if (aname) {
X				*aname = m;
X				m = m->m_next;
X				(*aname)->m_next = 0;
X				so->so_rcv.sb_mb = m;
X			} else {
X				MFREE(m, so->so_rcv.sb_mb);
X				m = so->so_rcv.sb_mb;
X			}
X			if (m)
X				m->m_act = nextrecord;
X		}
X	}
X	if (m && m->m_type == MT_RIGHTS) {
X		if ((pr->pr_flags & PR_RIGHTS) == 0)
X			panic("receive 2");
X		if (flags & MSG_PEEK) {
X			if (rightsp)
X				*rightsp = m_copy(m, 0, m->m_len);
X			m = m->m_next;
X		} else {
X			sbfree(&so->so_rcv, m);
X			if (rightsp) {
X				*rightsp = m;
X				so->so_rcv.sb_mb = m->m_next;
X				m->m_next = 0;
X				m = so->so_rcv.sb_mb;
X			} else {
X				MFREE(m, so->so_rcv.sb_mb);
X				m = so->so_rcv.sb_mb;
X			}
X			if (m)
X				m->m_act = nextrecord;
X		}
X	}
X	moff = 0;
X	offset = 0;
X	while (m && uio->uio_resid > 0 && error == 0) {
X		if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
X			panic("receive 3");
X		len = uio->uio_resid;
X		so->so_state &= ~SS_RCVATMARK;
X		if (so->so_oobmark && len > so->so_oobmark - offset)
X			len = so->so_oobmark - offset;
X		if (len > m->m_len - moff)
X			len = m->m_len - moff;
X		splx(s);
X		error =
X		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
X		s = splnet();
X		if (len == m->m_len - moff) {
X			if (flags & MSG_PEEK) {
X				m = m->m_next;
X				moff = 0;
X			} else {
X				nextrecord = m->m_act;
X				sbfree(&so->so_rcv, m);
X				MFREE(m, so->so_rcv.sb_mb);
X				m = so->so_rcv.sb_mb;
X				if (m)
X					m->m_act = nextrecord;
X			}
X		} else {
X			if (flags & MSG_PEEK)
X				moff += len;
X			else {
X				m->m_off += len;
X				m->m_len -= len;
X				so->so_rcv.sb_cc -= len;
X			}
X		}
X		if (so->so_oobmark) {
X			if ((flags & MSG_PEEK) == 0) {
X				so->so_oobmark -= len;
X				if (so->so_oobmark == 0) {
X					so->so_state |= SS_RCVATMARK;
X					break;
X				}
X			} else
X				offset += len;
X		}
X	}
X	if ((flags & MSG_PEEK) == 0) {
X		if (m == 0)
X			so->so_rcv.sb_mb = nextrecord;
X		else if (pr->pr_flags & PR_ATOMIC)
X			(void) sbdroprecord(&so->so_rcv);
X		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
X			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
X			    (struct mbuf *)0, (struct mbuf *)0);
X		if (error == 0 && rightsp && *rightsp &&
X		    pr->pr_domain->dom_externalize)
X			error = (*pr->pr_domain->dom_externalize)(*rightsp);
X	}
Xrelease:
X	sbunlock(&so->so_rcv);
X	splx(s);
X	return (error);
X}
X
Xsoshutdown(so, how)
X	register struct socket *so;
X	register int how;
X{
X	register struct protosw *pr = so->so_proto;
X
X	how++;
X	if (how & FREAD)
X		sorflush(so);
X	if (how & FWRITE)
X		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
X		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
X	return (0);
X}
X
Xsorflush(so)
X	register struct socket *so;
X{
X	register struct sockbuf *sb = &so->so_rcv;
X	register struct protosw *pr = so->so_proto;
X	register int s;
X	struct sockbuf asb;
X
X	sblock(sb);
X	s = splimp();
X	socantrcvmore(so);
X	sbunlock(sb);
X	asb = *sb;
X	bzero((caddr_t)sb, sizeof (*sb));
X	splx(s);
X	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
X		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
X	sbrelease(&asb);
X}
X
Xsosetopt(so, level, optname, m0)
X	register struct socket *so;
X	int level, optname;
X	struct mbuf *m0;
X{
X	int error = 0;
X	register struct mbuf *m = m0;
X
X	if (level != SOL_SOCKET) {
X		if (so->so_proto && so->so_proto->pr_ctloutput)
X			return ((*so->so_proto->pr_ctloutput)
X				  (PRCO_SETOPT, so, level, optname, &m0));
X		error = ENOPROTOOPT;
X	} else {
X		switch (optname) {
X
X		case SO_LINGER:
X			if (m == NULL || m->m_len != sizeof (struct linger)) {
X				error = EINVAL;
X				goto bad;
X			}
X			so->so_linger = mtod(m, struct linger *)->l_linger;
X			/* fall thru... */
X
X		case SO_DEBUG:
X		case SO_KEEPALIVE:
X		case SO_DONTROUTE:
X		case SO_USELOOPBACK:
X		case SO_BROADCAST:
X		case SO_REUSEADDR:
X		case SO_OOBINLINE:
X			if (m == NULL || m->m_len < sizeof (int)) {
X				error = EINVAL;
X				goto bad;
X			}
X			if (*mtod(m, int *))
X				so->so_options |= optname;
X			else
X				so->so_options &= ~optname;
X			break;
X
X		case SO_SNDBUF:
X		case SO_RCVBUF:
X		case SO_SNDLOWAT:
X		case SO_RCVLOWAT:
X		case SO_SNDTIMEO:
X		case SO_RCVTIMEO:
X			if (m == NULL || m->m_len < sizeof (int)) {
X				error = EINVAL;
X				goto bad;
X			}
X			switch (optname) {
X
X			case SO_SNDBUF:
X			case SO_RCVBUF:
X				if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
X				    &so->so_rcv, *mtod(m, int *)) == 0) {
X					error = ENOBUFS;
X					goto bad;
X				}
X				break;
X
X			case SO_SNDLOWAT:
X				so->so_snd.sb_lowat = *mtod(m, int *);
X				break;
X			case SO_RCVLOWAT:
X				so->so_rcv.sb_lowat = *mtod(m, int *);
X				break;
X			case SO_SNDTIMEO:
X				so->so_snd.sb_timeo = *mtod(m, int *);
X				break;
X			case SO_RCVTIMEO:
X				so->so_rcv.sb_timeo = *mtod(m, int *);
X				break;
X			}
X			break;
X
X		default:
X			error = ENOPROTOOPT;
X			break;
X		}
X	}
Xbad:
X	if (m)
X		(void) m_free(m);
X	return (error);
X}
X
Xsogetopt(so, level, optname, mp)
X	register struct socket *so;
X	int level, optname;
X	struct mbuf **mp;
X{
X	register struct mbuf *m;
X
X	if (level != SOL_SOCKET) {
X		if (so->so_proto && so->so_proto->pr_ctloutput) {
X			return ((*so->so_proto->pr_ctloutput)
X				  (PRCO_GETOPT, so, level, optname, mp));
X		} else 
X			return (ENOPROTOOPT);
X	} else {
X		m = m_get(M_WAIT, MT_SOOPTS);
X		m->m_len = sizeof (int);
X
X		switch (optname) {
X
X		case SO_LINGER:
X			m->m_len = sizeof (struct linger);
X			mtod(m, struct linger *)->l_onoff =
X				so->so_options & SO_LINGER;
X			mtod(m, struct linger *)->l_linger = so->so_linger;
X			break;
X
X		case SO_USELOOPBACK:
X		case SO_DONTROUTE:
X		case SO_DEBUG:
X		case SO_KEEPALIVE:
X		case SO_REUSEADDR:
X		case SO_BROADCAST:
X		case SO_OOBINLINE:
X			*mtod(m, int *) = so->so_options & optname;
X			break;
X
X		case SO_TYPE:
X			*mtod(m, int *) = so->so_type;
X			break;
X
X		case SO_ERROR:
X			*mtod(m, int *) = so->so_error;
X			so->so_error = 0;
X			break;
X
X		case SO_SNDBUF:
X			*mtod(m, int *) = so->so_snd.sb_hiwat;
X			break;
X
X		case SO_RCVBUF:
X			*mtod(m, int *) = so->so_rcv.sb_hiwat;
X			break;
X
X		case SO_SNDLOWAT:
X			*mtod(m, int *) = so->so_snd.sb_lowat;
X			break;
X
X		case SO_RCVLOWAT:
X			*mtod(m, int *) = so->so_rcv.sb_lowat;
X			break;
X
X		case SO_SNDTIMEO:
X			*mtod(m, int *) = so->so_snd.sb_timeo;
X			break;
X
X		case SO_RCVTIMEO:
X			*mtod(m, int *) = so->so_rcv.sb_timeo;
X			break;
X
X		default:
X			(void)m_free(m);
X			return (ENOPROTOOPT);
X		}
X		*mp = m;
X		return (0);
X	}
X}
X
Xsohasoutofband(so)
X	register struct socket *so;
X{
X	struct proc *p;
X
X	if (so->so_pgrp < 0)
X		gsignal(-so->so_pgrp, SIGURG);
X	else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
X		psignal(p, SIGURG);
X	if (so->so_rcv.sb_sel) {
X		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
X		so->so_rcv.sb_sel = 0;
X		so->so_rcv.sb_flags &= ~SB_COLL;
X	}
X}
END-of-sys/uipc_socket.c
echo x - sys/uipc_usrreq.c
sed 's/^X//' >sys/uipc_usrreq.c << 'END-of-sys/uipc_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 *	@(#)uipc_usrreq.c	7.4 (Berkeley) 2/8/88
X */
X
X#include "param.h"
X#include "dir.h"
X#include "user.h"
X#include "mbuf.h"
X#include "domain.h"
X#include "protosw.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "unpcb.h"
X#include "un.h"
X#include "inode.h"
X#include "file.h"
X#include "stat.h"
X
X/*
X * Unix communications domain.
X *
X * TODO:
X *	SEQPACKET, RDM
X *	rethink name space problems
X *	need a proper out-of-band
X */
Xstruct	sockaddr sun_noname = { AF_UNIX };
Xino_t	unp_ino;			/* prototype for fake inode numbers */
X
X/*ARGSUSED*/
Xuipc_usrreq(so, req, m, nam, rights)
X	struct socket *so;
X	int req;
X	struct mbuf *m, *nam, *rights;
X{
X	struct unpcb *unp = sotounpcb(so);
X	register struct socket *so2;
X	int error = 0;
X
X	if (req == PRU_CONTROL)
X		return (EOPNOTSUPP);
X	if (req != PRU_SEND && rights && rights->m_len) {
X		error = EOPNOTSUPP;
X		goto release;
X	}
X	if (unp == 0 && req != PRU_ATTACH) {
X		error = EINVAL;
X		goto release;
X	}
X	switch (req) {
X
X	case PRU_ATTACH:
X		if (unp) {
X			error = EISCONN;
X			break;
X		}
X		error = unp_attach(so);
X		break;
X
X	case PRU_DETACH:
X		unp_detach(unp);
X		break;
X
X	case PRU_BIND:
X		error = unp_bind(unp, nam);
X		break;
X
X	case PRU_LISTEN:
X		if (unp->unp_inode == 0)
X			error = EINVAL;
X		break;
X
X	case PRU_CONNECT:
X		error = unp_connect(so, nam);
X		break;
X
X	case PRU_CONNECT2:
X		error = unp_connect2(so, (struct socket *)nam);
X		break;
X
X	case PRU_DISCONNECT:
X		unp_disconnect(unp);
X		break;
X
X	case PRU_ACCEPT:
X		/*
X		 * Pass back name of connected socket,
X		 * if it was bound and we are still connected
X		 * (our peer may have closed already!).
X		 */
X		if (unp->unp_conn && unp->unp_conn->unp_addr) {
X			nam->m_len = unp->unp_conn->unp_addr->m_len;
X			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
X			    mtod(nam, caddr_t), (unsigned)nam->m_len);
X		} else {
X			nam->m_len = sizeof(sun_noname);
X			*(mtod(nam, struct sockaddr *)) = sun_noname;
X		}
X		break;
X
X	case PRU_SHUTDOWN:
X		socantsendmore(so);
X		unp_usrclosed(unp);
X		break;
X
X	case PRU_RCVD:
X		switch (so->so_type) {
X
X		case SOCK_DGRAM:
X			panic("uipc 1");
X			/*NOTREACHED*/
X
X		case SOCK_STREAM:
X#define	rcv (&so->so_rcv)
X#define snd (&so2->so_snd)
X			if (unp->unp_conn == 0)
X				break;
X			so2 = unp->unp_conn->unp_socket;
X			/*
X			 * Adjust backpressure on sender
X			 * and wakeup any waiting to write.
X			 */
X			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
X			unp->unp_mbcnt = rcv->sb_mbcnt;
X			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
X			unp->unp_cc = rcv->sb_cc;
X			sowwakeup(so2);
X#undef snd
X#undef rcv
X			break;
X
X		default:
X			panic("uipc 2");
X		}
X		break;
X
X	case PRU_SEND:
X		if (rights) {
X			error = unp_internalize(rights);
X			if (error)
X				break;
X		}
X		switch (so->so_type) {
X
X		case SOCK_DGRAM: {
X			struct sockaddr *from;
X
X			if (nam) {
X				if (unp->unp_conn) {
X					error = EISCONN;
X					break;
X				}
X				error = unp_connect(so, nam);
X				if (error)
X					break;
X			} else {
X				if (unp->unp_conn == 0) {
X					error = ENOTCONN;
X					break;
X				}
X			}
X			so2 = unp->unp_conn->unp_socket;
X			if (unp->unp_addr)
X				from = mtod(unp->unp_addr, struct sockaddr *);
X			else
X				from = &sun_noname;
X			if (sbspace(&so2->so_rcv) > 0 &&
X			    sbappendaddr(&so2->so_rcv, from, m, rights)) {
X				sorwakeup(so2);
X				m = 0;
X			} else
X				error = ENOBUFS;
X			if (nam)
X				unp_disconnect(unp);
X			break;
X		}
X
X		case SOCK_STREAM:
X#define	rcv (&so2->so_rcv)
X#define	snd (&so->so_snd)
X			if (so->so_state & SS_CANTSENDMORE) {
X				error = EPIPE;
X				break;
X			}
X			if (unp->unp_conn == 0)
X				panic("uipc 3");
X			so2 = unp->unp_conn->unp_socket;
X			/*
X			 * Send to paired receive port, and then reduce
X			 * send buffer hiwater marks to maintain backpressure.
X			 * Wake up readers.
X			 */
X			if (rights)
X				(void)sbappendrights(rcv, m, rights);
X			else
X				sbappend(rcv, m);
X			snd->sb_mbmax -=
X			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
X			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
X			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
X			unp->unp_conn->unp_cc = rcv->sb_cc;
X			sorwakeup(so2);
X			m = 0;
X#undef snd
X#undef rcv
X			break;
X
X		default:
X			panic("uipc 4");
X		}
X		break;
X
X	case PRU_ABORT:
X		unp_drop(unp, ECONNABORTED);
X		break;
X
X	case PRU_SENSE:
X		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
X		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
X			so2 = unp->unp_conn->unp_socket;
X			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
X		}
X		((struct stat *) m)->st_dev = NODEV;
X		if (unp->unp_ino == 0)
X			unp->unp_ino = unp_ino++;
X		((struct stat *) m)->st_ino = unp->unp_ino;
X		return (0);
X
X	case PRU_RCVOOB:
X		return (EOPNOTSUPP);
X
X	case PRU_SENDOOB:
X		error = EOPNOTSUPP;
X		break;
X
X	case PRU_SOCKADDR:
X		break;
X
X	case PRU_PEERADDR:
X		if (unp->unp_conn && unp->unp_conn->unp_addr) {
X			nam->m_len = unp->unp_conn->unp_addr->m_len;
X			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
X			    mtod(nam, caddr_t), (unsigned)nam->m_len);
X		}
X		break;
X
X	case PRU_SLOWTIMO:
X		break;
X
X	default:
X		panic("piusrreq");
X	}
Xrelease:
X	if (m)
X		m_freem(m);
X	return (error);
X}
X
X/*
X * Both send and receive buffers are allocated PIPSIZ bytes of buffering
X * for stream sockets, although the total for sender and receiver is
X * actually only PIPSIZ.
X * Datagram sockets really use the sendspace as the maximum datagram size,
X * and don't really want to reserve the sendspace.  Their recvspace should
X * be large enough for at least one max-size datagram plus address.
X */
X#define	PIPSIZ	4096
Xint	unpst_sendspace = PIPSIZ;
Xint	unpst_recvspace = PIPSIZ;
Xint	unpdg_sendspace = 2*1024;	/* really max datagram size */
Xint	unpdg_recvspace = 4*1024;
X
Xint	unp_rights;			/* file descriptors in flight */
X
Xunp_attach(so)
X	struct socket *so;
X{
X	register struct mbuf *m;
X	register struct unpcb *unp;
X	int error;
X	
X	switch (so->so_type) {
X
X	case SOCK_STREAM:
X		error = soreserve(so, unpst_sendspace, unpst_recvspace);
X		break;
X
X	case SOCK_DGRAM:
X		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
X		break;
X	}
X	if (error)
X		return (error);
X	m = m_getclr(M_DONTWAIT, MT_PCB);
X	if (m == NULL)
X		return (ENOBUFS);
X	unp = mtod(m, struct unpcb *);
X	so->so_pcb = (caddr_t)unp;
X	unp->unp_socket = so;
X	return (0);
X}
X
Xunp_detach(unp)
X	register struct unpcb *unp;
X{
X	
X	if (unp->unp_inode) {
X		unp->unp_inode->i_socket = 0;
X		irele(unp->unp_inode);
X		unp->unp_inode = 0;
X	}
X	if (unp->unp_conn)
X		unp_disconnect(unp);
X	while (unp->unp_refs)
X		unp_drop(unp->unp_refs, ECONNRESET);
X	soisdisconnected(unp->unp_socket);
X	unp->unp_socket->so_pcb = 0;
X	m_freem(unp->unp_addr);
X	(void) m_free(dtom(unp));
X	if (unp_rights)
X		unp_gc();
X}
X
Xunp_bind(unp, nam)
X	struct unpcb *unp;
X	struct mbuf *nam;
X{
X	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
X	register struct inode *ip;
X	register struct nameidata *ndp = &u.u_nd;
X	int error;
X
X	ndp->ni_dirp = soun->sun_path;
X	if (unp->unp_inode != NULL || nam->m_len == MLEN)
X		return (EINVAL);
X	*(mtod(nam, caddr_t) + nam->m_len) = 0;
X/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
X	ndp->ni_nameiop = CREATE | FOLLOW;
X	ndp->ni_segflg = UIO_SYSSPACE;
X	ip = namei(ndp);
X	if (ip) {
X		iput(ip);
X		return (EADDRINUSE);
X	}
X	if (error = u.u_error) {
X		u.u_error = 0;			/* XXX */
X		return (error);
X	}
X	ip = maknode(IFSOCK | 0777, ndp);
X	if (ip == NULL) {
X		error = u.u_error;		/* XXX */
X		u.u_error = 0;			/* XXX */
X		return (error);
X	}
X	ip->i_socket = unp->unp_socket;
X	unp->unp_inode = ip;
X	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
X	iunlock(ip);			/* but keep reference */
X	return (0);
X}
X
Xunp_connect(so, nam)
X	struct socket *so;
X	struct mbuf *nam;
X{
X	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
X	register struct inode *ip;
X	int error;
X	register struct socket *so2;
X	register struct nameidata *ndp = &u.u_nd;
X
X	ndp->ni_dirp = soun->sun_path;
X	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
X		return (EMSGSIZE);
X	*(mtod(nam, caddr_t) + nam->m_len) = 0;
X	ndp->ni_nameiop = LOOKUP | FOLLOW;
X	ndp->ni_segflg = UIO_SYSSPACE;
X	ip = namei(ndp);
X	if (ip == 0) {
X		error = u.u_error;
X		u.u_error = 0;
X		return (error);		/* XXX */
X	}
X	if (access(ip, IWRITE)) {
X		error = u.u_error;
X		u.u_error = 0; 		/* XXX */
X		goto bad;
X	}
X	if ((ip->i_mode&IFMT) != IFSOCK) {
X		error = ENOTSOCK;
X		goto bad;
X	}
X	so2 = ip->i_socket;
X	if (so2 == 0) {
X		error = ECONNREFUSED;
X		goto bad;
X	}
X	if (so->so_type != so2->so_type) {
X		error = EPROTOTYPE;
X		goto bad;
X	}
X	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
X	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
X	     (so2 = sonewconn(so2)) == 0)) {
X		error = ECONNREFUSED;
X		goto bad;
X	}
X	error = unp_connect2(so, so2);
Xbad:
X	iput(ip);
X	return (error);
X}
X
Xunp_connect2(so, so2)
X	register struct socket *so;
X	register struct socket *so2;
X{
X	register struct unpcb *unp = sotounpcb(so);
X	register struct unpcb *unp2;
X
X	if (so2->so_type != so->so_type)
X		return (EPROTOTYPE);
X	unp2 = sotounpcb(so2);
X	unp->unp_conn = unp2;
X	switch (so->so_type) {
X
X	case SOCK_DGRAM:
X		unp->unp_nextref = unp2->unp_refs;
X		unp2->unp_refs = unp;
X		soisconnected(so);
X		break;
X
X	case SOCK_STREAM:
X		unp2->unp_conn = unp;
X		soisconnected(so2);
X		soisconnected(so);
X		break;
X
X	default:
X		panic("unp_connect2");
X	}
X	return (0);
X}
X
Xunp_disconnect(unp)
X	struct unpcb *unp;
X{
X	register struct unpcb *unp2 = unp->unp_conn;
X
X	if (unp2 == 0)
X		return;
X	unp->unp_conn = 0;
X	switch (unp->unp_socket->so_type) {
X
X	case SOCK_DGRAM:
X		if (unp2->unp_refs == unp)
X			unp2->unp_refs = unp->unp_nextref;
X		else {
X			unp2 = unp2->unp_refs;
X			for (;;) {
X				if (unp2 == 0)
X					panic("unp_disconnect");
X				if (unp2->unp_nextref == unp)
X					break;
X				unp2 = unp2->unp_nextref;
X			}
X			unp2->unp_nextref = unp->unp_nextref;
X		}
X		unp->unp_nextref = 0;
X		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
X		break;
X
X	case SOCK_STREAM:
X		soisdisconnected(unp->unp_socket);
X		unp2->unp_conn = 0;
X		soisdisconnected(unp2->unp_socket);
X		break;
X	}
X}
X
X#ifdef notdef
Xunp_abort(unp)
X	struct unpcb *unp;
X{
X
X	unp_detach(unp);
X}
X#endif
X
X/*ARGSUSED*/
Xunp_usrclosed(unp)
X	struct unpcb *unp;
X{
X
X}
X
Xunp_drop(unp, errno)
X	struct unpcb *unp;
X	int errno;
X{
X	struct socket *so = unp->unp_socket;
X
X	so->so_error = errno;
X	unp_disconnect(unp);
X	if (so->so_head) {
X		so->so_pcb = (caddr_t) 0;
X		m_freem(unp->unp_addr);
X		(void) m_free(dtom(unp));
X		sofree(so);
X	}
X}
X
X#ifdef notdef
Xunp_drain()
X{
X
X}
X#endif
X
Xunp_externalize(rights)
X	struct mbuf *rights;
X{
X	int newfds = rights->m_len / sizeof (int);
X	register int i;
X	register struct file **rp = mtod(rights, struct file **);
X	register struct file *fp;
X	int f;
X
X	if (newfds > ufavail()) {
X		for (i = 0; i < newfds; i++) {
X			fp = *rp;
X			unp_discard(fp);
X			*rp++ = 0;
X		}
X		return (EMSGSIZE);
X	}
X	for (i = 0; i < newfds; i++) {
X		f = ufalloc(0);
X		if (f < 0)
X			panic("unp_externalize");
X		fp = *rp;
X		u.u_ofile[f] = fp;
X		fp->f_msgcount--;
X		unp_rights--;
X		*(int *)rp++ = f;
X	}
X	return (0);
X}
X
Xunp_internalize(rights)
X	struct mbuf *rights;
X{
X	register struct file **rp;
X	int oldfds = rights->m_len / sizeof (int);
X	register int i;
X	register struct file *fp;
X
X	rp = mtod(rights, struct file **);
X	for (i = 0; i < oldfds; i++)
X		if (getf(*(int *)rp++) == 0)
X			return (EBADF);
X	rp = mtod(rights, struct file **);
X	for (i = 0; i < oldfds; i++) {
X		fp = getf(*(int *)rp);
X		*rp++ = fp;
X		fp->f_count++;
X		fp->f_msgcount++;
X		unp_rights++;
X	}
X	return (0);
X}
X
Xint	unp_defer, unp_gcing;
Xint	unp_mark();
Xextern	struct domain unixdomain;
X
Xunp_gc()
X{
X	register struct file *fp;
X	register struct socket *so;
X
X	if (unp_gcing)
X		return;
X	unp_gcing = 1;
Xrestart:
X	unp_defer = 0;
X	for (fp = file; fp < fileNFILE; fp++)
X		fp->f_flag &= ~(FMARK|FDEFER);
X	do {
X		for (fp = file; fp < fileNFILE; fp++) {
X			if (fp->f_count == 0)
X				continue;
X			if (fp->f_flag & FDEFER) {
X				fp->f_flag &= ~FDEFER;
X				unp_defer--;
X			} else {
X				if (fp->f_flag & FMARK)
X					continue;
X				if (fp->f_count == fp->f_msgcount)
X					continue;
X				fp->f_flag |= FMARK;
X			}
X			if (fp->f_type != DTYPE_SOCKET ||
X			    (so = (struct socket *)fp->f_data) == 0)
X				continue;
X			if (so->so_proto->pr_domain != &unixdomain ||
X			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
X				continue;
X			if (so->so_rcv.sb_flags & SB_LOCK) {
X				sbwait(&so->so_rcv);
X				goto restart;
X			}
X			unp_scan(so->so_rcv.sb_mb, unp_mark);
X		}
X	} while (unp_defer);
X	for (fp = file; fp < fileNFILE; fp++) {
X		if (fp->f_count == 0)
X			continue;
X		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
X			while (fp->f_msgcount)
X				unp_discard(fp);
X	}
X	unp_gcing = 0;
X}
X
Xunp_dispose(m)
X	struct mbuf *m;
X{
X	int unp_discard();
X
X	if (m)
X		unp_scan(m, unp_discard);
X}
X
Xunp_scan(m0, op)
X	register struct mbuf *m0;
X	int (*op)();
X{
X	register struct mbuf *m;
X	register struct file **rp;
X	register int i;
X	int qfds;
X
X	while (m0) {
X		for (m = m0; m; m = m->m_next)
X			if (m->m_type == MT_RIGHTS && m->m_len) {
X				qfds = m->m_len / sizeof (struct file *);
X				rp = mtod(m, struct file **);
X				for (i = 0; i < qfds; i++)
X					(*op)(*rp++);
X				break;		/* XXX, but saves time */
X			}
X		m0 = m0->m_act;
X	}
X}
X
Xunp_mark(fp)
X	struct file *fp;
X{
X
X	if (fp->f_flag & FMARK)
X		return;
X	unp_defer++;
X	fp->f_flag |= (FMARK|FDEFER);
X}
X
Xunp_discard(fp)
X	struct file *fp;
X{
X
X	fp->f_msgcount--;
X	unp_rights--;
X	closef(fp);
X}
END-of-sys/uipc_usrreq.c
exit



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