xref: /csrg-svn/sys/kern/uipc_socket.c (revision 5404)
1*5404Swnj /*	uipc_socket.c	4.24	82/01/14	*/
24786Swnj 
34786Swnj #include "../h/param.h"
44829Swnj #include "../h/systm.h"
54786Swnj #include "../h/dir.h"
64786Swnj #include "../h/user.h"
74829Swnj #include "../h/proc.h"
84829Swnj #include "../h/file.h"
94786Swnj #include "../h/inode.h"
104829Swnj #include "../h/buf.h"
114786Swnj #include "../h/mbuf.h"
124829Swnj #include "../h/protosw.h"
134829Swnj #include "../h/socket.h"
144829Swnj #include "../h/socketvar.h"
154916Swnj #include "../h/stat.h"
165281Sroot #include "../h/ioctl.h"
175095Swnj #include "../net/in.h"
185095Swnj #include "../net/in_systm.h"
194786Swnj 
204786Swnj /*
214890Swnj  * Socket support routines.
224890Swnj  *
234890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
244786Swnj  */
254786Swnj 
264786Swnj /*
274786Swnj  * Create a socket.
284786Swnj  */
294927Swnj socreate(aso, type, asp, asa, options)
304786Swnj 	struct socket **aso;
314786Swnj 	int type;
324927Swnj 	struct sockproto *asp;
334927Swnj 	struct sockaddr *asa;
344829Swnj 	int options;
354786Swnj {
364786Swnj 	register struct protosw *prp;
374786Swnj 	register struct socket *so;
384786Swnj 	struct mbuf *m;
394890Swnj 	int pf, proto, error;
404927Swnj COUNT(SOCREATE);
414786Swnj 
424786Swnj 	/*
434890Swnj 	 * Use process standard protocol/protocol family if none
444890Swnj 	 * specified by address argument.
454786Swnj 	 */
464927Swnj 	if (asp == 0) {
474890Swnj 		pf = PF_INET;		/* should be u.u_protof */
484786Swnj 		proto = 0;
494786Swnj 	} else {
504927Swnj 		pf = asp->sp_family;
514927Swnj 		proto = asp->sp_protocol;
524786Swnj 	}
534786Swnj 
544786Swnj 	/*
554890Swnj 	 * If protocol specified, look for it, otherwise
564890Swnj 	 * for a protocol of the correct type in the right family.
574890Swnj 	 */
584890Swnj 	if (proto)
594890Swnj 		prp = pffindproto(pf, proto);
604890Swnj 	else
614890Swnj 		prp = pffindtype(pf, type);
624890Swnj 	if (prp == 0)
634890Swnj 		return (EPROTONOSUPPORT);
644890Swnj 
654890Swnj 	/*
664786Swnj 	 * Get a socket structure.
674786Swnj 	 */
684890Swnj 	m = m_getclr(M_WAIT);
694786Swnj 	if (m == 0)
704786Swnj 		return (ENOBUFS);
714786Swnj 	so = mtod(m, struct socket *);
724829Swnj 	so->so_options = options;
734786Swnj 
744786Swnj 	/*
754890Swnj 	 * Attach protocol to socket, initializing
764890Swnj 	 * and reserving resources.
774786Swnj 	 */
784786Swnj 	so->so_proto = prp;
794979Swnj 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
804979Swnj 	if (error) {
814971Swnj 		(void) m_free(dtom(so));
824890Swnj 		return (error);
834786Swnj 	}
844786Swnj 	*aso = so;
854786Swnj 	return (0);
864786Swnj }
874786Swnj 
884916Swnj sofree(so)
894916Swnj 	struct socket *so;
904916Swnj {
914916Swnj 
924927Swnj COUNT(SOFREE);
934950Swnj 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
944950Swnj 		return;
954950Swnj 	sbrelease(&so->so_snd);
964950Swnj 	sbrelease(&so->so_rcv);
974971Swnj 	(void) m_free(dtom(so));
984916Swnj }
994916Swnj 
1004786Swnj /*
1014890Swnj  * Close a socket on last file table reference removal.
1024890Swnj  * Initiate disconnect if connected.
1034890Swnj  * Free socket when disconnect complete.
1044829Swnj  */
1054890Swnj soclose(so)
1064829Swnj 	register struct socket *so;
1074829Swnj {
1084890Swnj 	int s = splnet();		/* conservative */
1094829Swnj 
1104927Swnj COUNT(SOCLOSE);
1114890Swnj 	if (so->so_pcb == 0)
1124890Swnj 		goto discard;
1134890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1144890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1154927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1164890Swnj 			if (u.u_error) {
1174890Swnj 				splx(s);
1184890Swnj 				return;
1194890Swnj 			}
1204890Swnj 		}
1215388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1225281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1235388Sroot 			    (so->so_options & SO_NONBLOCKING)) {
1245281Sroot 				u.u_error = EINPROGRESS;
1255281Sroot 				splx(s);
1265281Sroot 				return;
1275281Sroot 			}
1285388Sroot 			/* should use tsleep here */
1295281Sroot 			while (so->so_state & SS_ISCONNECTED)
1305281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1314890Swnj 		}
1324890Swnj 	}
1334890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1344890Swnj discard:
1354950Swnj 	so->so_state |= SS_USERGONE;
1364950Swnj 	sofree(so);
1374890Swnj 	splx(s);
1384829Swnj }
1394829Swnj 
1404927Swnj sosplice(pso, so)
1414927Swnj 	struct socket *pso, *so;
1424927Swnj {
1434927Swnj 
1444927Swnj COUNT(SOSPLICE);
1455168Swnj 	if (pso->so_proto->pr_family != PF_UNIX) {
1464927Swnj 		struct socket *tso;
1474927Swnj 		tso = pso; pso = so; so = tso;
1484927Swnj 	}
1495168Swnj 	if (pso->so_proto->pr_family != PF_UNIX)
1504927Swnj 		return (EOPNOTSUPP);
1514927Swnj 	/* check types and buffer space */
1524927Swnj 	/* merge buffers */
1534927Swnj 	return (0);
1544927Swnj }
1554927Swnj 
1564916Swnj /*ARGSUSED*/
1574890Swnj sostat(so, sb)
1584829Swnj 	struct socket *so;
1594890Swnj 	struct stat *sb;
1604829Swnj {
1614829Swnj 
1624927Swnj COUNT(SOSTAT);
1635303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1645303Sroot 	return (0);					/* XXX */
1654829Swnj }
1664829Swnj 
1674829Swnj /*
1684927Swnj  * Accept connection on a socket.
1694927Swnj  */
1704927Swnj soaccept(so, asa)
1714927Swnj 	struct socket *so;
1724927Swnj 	struct sockaddr *asa;
1734927Swnj {
1744927Swnj 	int s = splnet();
1754927Swnj 	int error;
1764927Swnj 
1774927Swnj COUNT(SOACCEPT);
1784927Swnj 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
1794927Swnj 		error = EINVAL;			/* XXX */
1804927Swnj 		goto bad;
1814927Swnj 	}
1825265Swnj 	if ((so->so_state & SS_CONNAWAITING) == 0) {
1835265Swnj 		error = ENOTCONN;
1845265Swnj 		goto bad;
1855265Swnj 	}
1865265Swnj 	so->so_state &= ~SS_CONNAWAITING;
1874927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
1884927Swnj bad:
1894927Swnj 	splx(s);
1904927Swnj 	return (error);
1914927Swnj }
1924927Swnj 
1934927Swnj /*
1944890Swnj  * Connect socket to a specified address.
1954890Swnj  * If already connected or connecting, then avoid
1964890Swnj  * the protocol entry, to keep its job simpler.
1974786Swnj  */
1984927Swnj soconnect(so, asa)
1994786Swnj 	struct socket *so;
2004927Swnj 	struct sockaddr *asa;
2014786Swnj {
2024890Swnj 	int s = splnet();
2034890Swnj 	int error;
2044786Swnj 
2054927Swnj COUNT(SOCONNECT);
2064890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2074890Swnj 		error = EISCONN;
2084890Swnj 		goto bad;
2094890Swnj 	}
2104927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2114890Swnj bad:
2124890Swnj 	splx(s);
2134890Swnj 	return (error);
2144786Swnj }
2154786Swnj 
2164786Swnj /*
2174890Swnj  * Disconnect from a socket.
2184890Swnj  * Address parameter is from system call for later multicast
2194890Swnj  * protocols.  Check to make sure that connected and no disconnect
2204890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2214786Swnj  */
2224927Swnj sodisconnect(so, asa)
2234786Swnj 	struct socket *so;
2244927Swnj 	struct sockaddr *asa;
2254786Swnj {
2264890Swnj 	int s = splnet();
2274890Swnj 	int error;
2284786Swnj 
2294927Swnj COUNT(SODISCONNECT);
2304890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2314890Swnj 		error = ENOTCONN;
2324890Swnj 		goto bad;
2334890Swnj 	}
2344890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2354890Swnj 		error = EALREADY;
2364890Swnj 		goto bad;
2374890Swnj 	}
2384927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
2394890Swnj bad:
2404890Swnj 	splx(s);
2414890Swnj 	return (error);
2424786Swnj }
2434786Swnj 
2444786Swnj /*
2454890Swnj  * Send on a socket.
2464890Swnj  * If send must go all at once and message is larger than
2474890Swnj  * send buffering, then hard error.
2484890Swnj  * Lock against other senders.
2494890Swnj  * If must go all at once and not enough room now, then
2504890Swnj  * inform user that this would block and do nothing.
2514786Swnj  */
2524927Swnj sosend(so, asa)
2534786Swnj 	register struct socket *so;
2544927Swnj 	struct sockaddr *asa;
2554786Swnj {
2564890Swnj 	struct mbuf *top = 0;
2574890Swnj 	register struct mbuf *m, **mp = ⊤
2584916Swnj 	register u_int len;
2594916Swnj 	int error = 0, space, s;
2604786Swnj 
2614927Swnj COUNT(SOSEND);
2624890Swnj 	if (so->so_state & SS_CANTSENDMORE)
2634890Swnj 		return (EPIPE);
2644890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2654890Swnj 		return (EMSGSIZE);
2665388Sroot 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NONBLOCKING))
2674890Swnj 		return (EWOULDBLOCK);
2684890Swnj 	sblock(&so->so_snd);
2694890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2704890Swnj 
2714890Swnj 	s = splnet();
2724890Swnj again:
2735168Swnj 	if (so->so_error) {
2745168Swnj 		error = so->so_error;
2755168Swnj 		so->so_error = 0;
2765168Swnj 		splx(s);
2775168Swnj 		goto release;
2785168Swnj 	}
2794890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2804890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2814890Swnj 			snderr(ENOTCONN);
2824927Swnj 		if (asa == 0)
2834890Swnj 			snderr(EDESTADDRREQ);
2844890Swnj 	}
2854890Swnj 	if (top) {
2864927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
2874890Swnj 		if (error) {
2884890Swnj 			splx(s);
2894786Swnj 			goto release;
2904786Swnj 		}
2914890Swnj 		top = 0;
2924890Swnj 		mp = ⊤
2934786Swnj 	}
2944979Swnj 	if (u.u_count == 0) {
2954979Swnj 		splx(s);
2964979Swnj 		goto release;
2974979Swnj 	}
2985018Swnj 	space = sbspace(&so->so_snd);
2995018Swnj 	if (space == 0 || sosendallatonce(so) && space < u.u_count) {
3005388Sroot 		if (so->so_options & SO_NONBLOCKING)
3014890Swnj 			snderr(EWOULDBLOCK);
3024890Swnj 		sbunlock(&so->so_snd);
3034890Swnj 		sbwait(&so->so_snd);
3044890Swnj 		splx(s);
3054786Swnj 		goto again;
3064786Swnj 	}
3074890Swnj 	splx(s);
3085018Swnj 	while (u.u_count && space > 0) {
3094890Swnj 		MGET(m, 1);
3104890Swnj 		if (m == NULL) {
3114890Swnj 			error = ENOBUFS;
3124890Swnj 			m_freem(top);
3134890Swnj 			goto release;
3144786Swnj 		}
3155095Swnj 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
3164890Swnj 			register struct mbuf *p;
3175095Swnj 			MCLGET(p, 1);
3184890Swnj 			if (p == 0)
3194890Swnj 				goto nopages;
3204890Swnj 			m->m_off = (int)p - (int)m;
3215095Swnj 			len = CLBYTES;
3224890Swnj 		} else {
3234786Swnj nopages:
3244890Swnj 			m->m_off = MMINOFF;
3254890Swnj 			len = MIN(MLEN, u.u_count);
3264786Swnj 		}
3274890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3284890Swnj 		m->m_len = len;
3294890Swnj 		*mp = m;
3304890Swnj 		mp = &m->m_next;
3315018Swnj 		space = sbspace(&so->so_snd);
3324786Swnj 	}
3334890Swnj 	s = splnet();
3344890Swnj 	goto again;
3354890Swnj 
3364786Swnj release:
3374890Swnj 	sbunlock(&so->so_snd);
3384786Swnj 	return (error);
3394786Swnj }
3404786Swnj 
3414927Swnj soreceive(so, asa)
3424786Swnj 	register struct socket *so;
3434927Swnj 	struct sockaddr *asa;
3444786Swnj {
3454786Swnj 	register struct mbuf *m, *n;
3464916Swnj 	u_int len;
3474890Swnj 	int eor, s, error = 0;
3484786Swnj 
3494927Swnj COUNT(SORECEIVE);
3504890Swnj restart:
3514890Swnj 	sblock(&so->so_rcv);
3524890Swnj 	s = splnet();
3534890Swnj 
3544890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3554786Swnj 	if (so->so_rcv.sb_cc == 0) {
3565168Swnj 		if (so->so_error) {
3575168Swnj 			error = so->so_error;
3585168Swnj 			so->so_error = 0;
3595168Swnj 			splx(s);
3605168Swnj 			goto release;
3615168Swnj 		}
3624890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3634890Swnj 			splx(s);
3644890Swnj 			goto release;
3654890Swnj 		}
3665015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3675015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3685015Sroot 			rcverr(ENOTCONN);
3695388Sroot 		if (so->so_options & SO_NONBLOCKING)
3705168Swnj 			rcverr(EWOULDBLOCK);
3714890Swnj 		sbunlock(&so->so_rcv);
3724971Swnj 		sbwait(&so->so_rcv);
3735012Swnj 		splx(s);
3744890Swnj 		goto restart;
3754786Swnj 	}
3764829Swnj 	m = so->so_rcv.sb_mb;
3774786Swnj 	if (m == 0)
3784786Swnj 		panic("receive");
3795039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
3805039Swnj 		if (m->m_len != sizeof (struct sockaddr))
3815039Swnj 			panic("soreceive addr");
3825039Swnj 		if (asa)
3835039Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
3845039Swnj 		so->so_rcv.sb_cc -= m->m_len;
3855039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
3865018Swnj 		m = m_free(m);
3874890Swnj 		if (m == 0)
3884890Swnj 			panic("receive 2");
3895018Swnj 		so->so_rcv.sb_mb = m;
3904890Swnj 	}
3914786Swnj 	eor = 0;
3924786Swnj 	do {
3934786Swnj 		len = MIN(m->m_len, u.u_count);
3944786Swnj 		if (len == m->m_len) {
3954786Swnj 			eor = (int)m->m_act;
3964890Swnj 			sbfree(&so->so_rcv, m);
3975358Sroot 			so->so_rcv.sb_mb = m->m_next;
3984786Swnj 		}
3994786Swnj 		splx(s);
4004786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
4014786Swnj 		s = splnet();
4024786Swnj 		if (len == m->m_len) {
4034786Swnj 			MFREE(m, n);
4044786Swnj 		} else {
4054786Swnj 			m->m_off += len;
4064786Swnj 			m->m_len -= len;
4074829Swnj 			so->so_rcv.sb_cc -= len;
4084786Swnj 		}
4094829Swnj 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
4104786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4114786Swnj 		do {
4124786Swnj 			if (m == 0)
4134890Swnj 				panic("receive 3");
4144890Swnj 			sbfree(&so->so_rcv, m);
4154786Swnj 			eor = (int)m->m_act;
4164786Swnj 			so->so_rcv.sb_mb = m->m_next;
4174786Swnj 			MFREE(m, n);
4184890Swnj 			m = n;
4194786Swnj 		} while (eor == 0);
4204890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
4214890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
4224890Swnj release:
4234916Swnj 	sbunlock(&so->so_rcv);
4244890Swnj 	splx(s);
4254916Swnj 	return (error);
4264786Swnj }
4274786Swnj 
4284916Swnj /*ARGSUSED*/
4294916Swnj soioctl(so, cmd, cmdp)
4304829Swnj 	register struct socket *so;
4314829Swnj 	int cmd;
4324829Swnj 	register caddr_t cmdp;
4334786Swnj {
4344786Swnj 
4354927Swnj COUNT(SOIOCTL);
4365358Sroot 	switch (cmd) {
4374829Swnj 
4385388Sroot 	case FIONBIO: {
4395388Sroot 		int nbio;
4405388Sroot 		if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
4415388Sroot 			u.u_error = EFAULT;
4425388Sroot 			return;
4435388Sroot 		}
4445388Sroot 		if (nbio)
4455388Sroot 			so->so_options |= SO_NONBLOCKING;
4465388Sroot 		else
4475388Sroot 			so->so_options &= ~SO_NONBLOCKING;
4485388Sroot 		return;
4495388Sroot 	}
4505388Sroot 
4515388Sroot 	case FIOASYNC: {
4525388Sroot 		int async;
4535388Sroot 		if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
4545388Sroot 			u.u_error = EFAULT;
4555388Sroot 			return;
4565388Sroot 		}
4575388Sroot 		if (async)
4585388Sroot 			;
4595388Sroot 		else
4605388Sroot 			;
4615388Sroot 		return;
4625388Sroot 	}
4635388Sroot 
4645388Sroot 	case SIOCSKEEP: {
4655388Sroot 		int keep;
4665388Sroot 		if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
4675388Sroot 			u.u_error = EFAULT;
4685388Sroot 			return;
4695388Sroot 		}
4705388Sroot 		if (keep)
4715388Sroot 			so->so_options &= ~SO_NOKEEPALIVE;
4725388Sroot 		else
4735388Sroot 			so->so_options |= SO_NOKEEPALIVE;
4745388Sroot 		return;
4755388Sroot 	}
4765388Sroot 
4775388Sroot 	case SIOCGKEEP: {
4785388Sroot 		int keep = (so->so_options & SO_NOKEEPALIVE) == 0;
4795388Sroot 		if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
4805388Sroot 			u.u_error = EFAULT;
4815388Sroot 		return;
4825388Sroot 	}
4835388Sroot 
4845388Sroot 	case SIOCSLINGER: {
4855388Sroot 		int linger;
4865388Sroot 		if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
4875388Sroot 			u.u_error = EFAULT;
4885388Sroot 			return;
4895388Sroot 		}
4905388Sroot 		so->so_linger = linger;
4915388Sroot 		if (so->so_linger)
4925388Sroot 			so->so_options &= ~SO_DONTLINGER;
4935388Sroot 		else
4945388Sroot 			so->so_options |= SO_DONTLINGER;
4955388Sroot 		return;
4965388Sroot 	}
4975388Sroot 
4985388Sroot 	case SIOCGLINGER: {
4995388Sroot 		int linger = so->so_linger;
5005388Sroot 		if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
5015388Sroot 			u.u_error = EFAULT;
5025388Sroot 			return;
5035388Sroot 		}
5045388Sroot 	}
5055388Sroot 
5065281Sroot 	case SIOCDONE: {
5075281Sroot 		int flags;
5085281Sroot 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
5095281Sroot 			u.u_error = EFAULT;
5105281Sroot 			return;
5115281Sroot 		}
5125388Sroot 		flags++;
5135281Sroot 		if (flags & FREAD) {
5145281Sroot 			int s = splimp();
5155281Sroot 			socantrcvmore(so);
5165281Sroot 			sbflush(&so->so_rcv);
5175281Sroot 		}
5185281Sroot 		if (flags & FWRITE)
519*5404Swnj 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
5205281Sroot 		return;
5214829Swnj 	}
5225281Sroot 
5235281Sroot 	}
5244829Swnj 	switch (so->so_type) {
5254829Swnj 
5264829Swnj 	case SOCK_STREAM:
5274829Swnj 		break;
5284829Swnj 
5294829Swnj 	case SOCK_DGRAM:
5304829Swnj 		break;
5314829Swnj 
5324829Swnj 	case SOCK_RDM:
5334829Swnj 		break;
5344829Swnj 
5354829Swnj 	case SOCK_RAW:
5364829Swnj 		break;
5374829Swnj 	}
5384786Swnj }
539