xref: /csrg-svn/sys/kern/uipc_socket.c (revision 5265)
1*5265Swnj /*	uipc_socket.c	4.19	81/12/19	*/
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"
165095Swnj #include "../net/in.h"
175095Swnj #include "../net/in_systm.h"
184786Swnj 
194786Swnj /*
204890Swnj  * Socket support routines.
214890Swnj  *
224890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
234786Swnj  */
244786Swnj 
254786Swnj /*
264786Swnj  * Create a socket.
274786Swnj  */
284927Swnj socreate(aso, type, asp, asa, options)
294786Swnj 	struct socket **aso;
304786Swnj 	int type;
314927Swnj 	struct sockproto *asp;
324927Swnj 	struct sockaddr *asa;
334829Swnj 	int options;
344786Swnj {
354786Swnj 	register struct protosw *prp;
364786Swnj 	register struct socket *so;
374786Swnj 	struct mbuf *m;
384890Swnj 	int pf, proto, error;
394927Swnj COUNT(SOCREATE);
404786Swnj 
414786Swnj 	/*
424890Swnj 	 * Use process standard protocol/protocol family if none
434890Swnj 	 * specified by address argument.
444786Swnj 	 */
454927Swnj 	if (asp == 0) {
464890Swnj 		pf = PF_INET;		/* should be u.u_protof */
474786Swnj 		proto = 0;
484786Swnj 	} else {
494927Swnj 		pf = asp->sp_family;
504927Swnj 		proto = asp->sp_protocol;
514786Swnj 	}
524786Swnj 
534786Swnj 	/*
544890Swnj 	 * If protocol specified, look for it, otherwise
554890Swnj 	 * for a protocol of the correct type in the right family.
564890Swnj 	 */
574890Swnj 	if (proto)
584890Swnj 		prp = pffindproto(pf, proto);
594890Swnj 	else
604890Swnj 		prp = pffindtype(pf, type);
614890Swnj 	if (prp == 0)
624890Swnj 		return (EPROTONOSUPPORT);
634890Swnj 
644890Swnj 	/*
654786Swnj 	 * Get a socket structure.
664786Swnj 	 */
674890Swnj 	m = m_getclr(M_WAIT);
684786Swnj 	if (m == 0)
694786Swnj 		return (ENOBUFS);
704786Swnj 	so = mtod(m, struct socket *);
714829Swnj 	so->so_options = options;
724786Swnj 
734786Swnj 	/*
744890Swnj 	 * Attach protocol to socket, initializing
754890Swnj 	 * and reserving resources.
764786Swnj 	 */
774786Swnj 	so->so_proto = prp;
784979Swnj 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
794979Swnj 	if (error) {
804971Swnj 		(void) m_free(dtom(so));
814890Swnj 		return (error);
824786Swnj 	}
834786Swnj 	*aso = so;
844786Swnj 	return (0);
854786Swnj }
864786Swnj 
874916Swnj sofree(so)
884916Swnj 	struct socket *so;
894916Swnj {
904916Swnj 
914927Swnj COUNT(SOFREE);
924950Swnj 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
934950Swnj 		return;
944950Swnj 	sbrelease(&so->so_snd);
954950Swnj 	sbrelease(&so->so_rcv);
964971Swnj 	(void) m_free(dtom(so));
974916Swnj }
984916Swnj 
994786Swnj /*
1004890Swnj  * Close a socket on last file table reference removal.
1014890Swnj  * Initiate disconnect if connected.
1024890Swnj  * Free socket when disconnect complete.
1034829Swnj  */
1044890Swnj soclose(so)
1054829Swnj 	register struct socket *so;
1064829Swnj {
1074890Swnj 	int s = splnet();		/* conservative */
1084829Swnj 
1094927Swnj COUNT(SOCLOSE);
1104890Swnj 	if (so->so_pcb == 0)
1114890Swnj 		goto discard;
1124890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1134890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1144927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1154890Swnj 			if (u.u_error) {
1164890Swnj 				splx(s);
1174890Swnj 				return;
1184890Swnj 			}
1194890Swnj 		}
1204890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) &&
1214890Swnj 		    (so->so_options & SO_NBIO)) {
1224890Swnj 			u.u_error = EINPROGRESS;
1234890Swnj 			splx(s);
1244890Swnj 			return;
1254890Swnj 		}
1265248Sroot 		while (so->so_state & SS_ISCONNECTED) {
1274890Swnj 			sleep((caddr_t)&so->so_timeo, PZERO+1);
1285248Sroot 		}
1294890Swnj 	}
1304890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1314890Swnj discard:
1324950Swnj 	so->so_state |= SS_USERGONE;
1334950Swnj 	sofree(so);
1344890Swnj 	splx(s);
1354829Swnj }
1364829Swnj 
1374927Swnj sosplice(pso, so)
1384927Swnj 	struct socket *pso, *so;
1394927Swnj {
1404927Swnj 
1414927Swnj COUNT(SOSPLICE);
1425168Swnj 	if (pso->so_proto->pr_family != PF_UNIX) {
1434927Swnj 		struct socket *tso;
1444927Swnj 		tso = pso; pso = so; so = tso;
1454927Swnj 	}
1465168Swnj 	if (pso->so_proto->pr_family != PF_UNIX)
1474927Swnj 		return (EOPNOTSUPP);
1484927Swnj 	/* check types and buffer space */
1494927Swnj 	/* merge buffers */
1504927Swnj 	return (0);
1514927Swnj }
1524927Swnj 
1534916Swnj /*ARGSUSED*/
1544890Swnj sostat(so, sb)
1554829Swnj 	struct socket *so;
1564890Swnj 	struct stat *sb;
1574829Swnj {
1584829Swnj 
1594927Swnj COUNT(SOSTAT);
1604890Swnj 	return (EOPNOTSUPP);
1614829Swnj }
1624829Swnj 
1634829Swnj /*
1644927Swnj  * Accept connection on a socket.
1654927Swnj  */
1664927Swnj soaccept(so, asa)
1674927Swnj 	struct socket *so;
1684927Swnj 	struct sockaddr *asa;
1694927Swnj {
1704927Swnj 	int s = splnet();
1714927Swnj 	int error;
1724927Swnj 
1734927Swnj COUNT(SOACCEPT);
1744927Swnj 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
1754927Swnj 		error = EINVAL;			/* XXX */
1764927Swnj 		goto bad;
1774927Swnj 	}
178*5265Swnj 	if ((so->so_state & SS_CONNAWAITING) == 0) {
179*5265Swnj 		error = ENOTCONN;
180*5265Swnj 		goto bad;
181*5265Swnj 	}
182*5265Swnj 	so->so_state &= ~SS_CONNAWAITING;
1834927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
1844927Swnj bad:
1854927Swnj 	splx(s);
1864927Swnj 	return (error);
1874927Swnj }
1884927Swnj 
1894927Swnj /*
1904890Swnj  * Connect socket to a specified address.
1914890Swnj  * If already connected or connecting, then avoid
1924890Swnj  * the protocol entry, to keep its job simpler.
1934786Swnj  */
1944927Swnj soconnect(so, asa)
1954786Swnj 	struct socket *so;
1964927Swnj 	struct sockaddr *asa;
1974786Swnj {
1984890Swnj 	int s = splnet();
1994890Swnj 	int error;
2004786Swnj 
2014927Swnj COUNT(SOCONNECT);
2024890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2034890Swnj 		error = EISCONN;
2044890Swnj 		goto bad;
2054890Swnj 	}
2064927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2074890Swnj bad:
2084890Swnj 	splx(s);
2094890Swnj 	return (error);
2104786Swnj }
2114786Swnj 
2124786Swnj /*
2134890Swnj  * Disconnect from a socket.
2144890Swnj  * Address parameter is from system call for later multicast
2154890Swnj  * protocols.  Check to make sure that connected and no disconnect
2164890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2174786Swnj  */
2184927Swnj sodisconnect(so, asa)
2194786Swnj 	struct socket *so;
2204927Swnj 	struct sockaddr *asa;
2214786Swnj {
2224890Swnj 	int s = splnet();
2234890Swnj 	int error;
2244786Swnj 
2254927Swnj COUNT(SODISCONNECT);
2264890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2274890Swnj 		error = ENOTCONN;
2284890Swnj 		goto bad;
2294890Swnj 	}
2304890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2314890Swnj 		error = EALREADY;
2324890Swnj 		goto bad;
2334890Swnj 	}
2344927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
2354890Swnj bad:
2364890Swnj 	splx(s);
2374890Swnj 	return (error);
2384786Swnj }
2394786Swnj 
2404786Swnj /*
2414890Swnj  * Send on a socket.
2424890Swnj  * If send must go all at once and message is larger than
2434890Swnj  * send buffering, then hard error.
2444890Swnj  * Lock against other senders.
2454890Swnj  * If must go all at once and not enough room now, then
2464890Swnj  * inform user that this would block and do nothing.
2474786Swnj  */
2484927Swnj sosend(so, asa)
2494786Swnj 	register struct socket *so;
2504927Swnj 	struct sockaddr *asa;
2514786Swnj {
2524890Swnj 	struct mbuf *top = 0;
2534890Swnj 	register struct mbuf *m, **mp = ⊤
2544916Swnj 	register u_int len;
2554916Swnj 	int error = 0, space, s;
2564786Swnj 
2574927Swnj COUNT(SOSEND);
2584890Swnj 	if (so->so_state & SS_CANTSENDMORE)
2594890Swnj 		return (EPIPE);
2604890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2614890Swnj 		return (EMSGSIZE);
2624890Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
2634890Swnj 		return (EWOULDBLOCK);
2644890Swnj 	sblock(&so->so_snd);
2654890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2664890Swnj 
2674890Swnj 	s = splnet();
2684890Swnj again:
2695168Swnj 	if (so->so_error) {
2705168Swnj 		error = so->so_error;
2715168Swnj 		so->so_error = 0;
2725168Swnj 		splx(s);
2735168Swnj 		goto release;
2745168Swnj 	}
2754890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2764890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2774890Swnj 			snderr(ENOTCONN);
2784927Swnj 		if (asa == 0)
2794890Swnj 			snderr(EDESTADDRREQ);
2804890Swnj 	}
2814890Swnj 	if (top) {
2824927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
2834890Swnj 		if (error) {
2844890Swnj 			splx(s);
2854786Swnj 			goto release;
2864786Swnj 		}
2874890Swnj 		top = 0;
2884890Swnj 		mp = ⊤
2894786Swnj 	}
2904979Swnj 	if (u.u_count == 0) {
2914979Swnj 		splx(s);
2924979Swnj 		goto release;
2934979Swnj 	}
2945018Swnj 	space = sbspace(&so->so_snd);
2955018Swnj 	if (space == 0 || sosendallatonce(so) && space < u.u_count) {
2964890Swnj 		if (so->so_options & SO_NBIO)
2974890Swnj 			snderr(EWOULDBLOCK);
2984890Swnj 		sbunlock(&so->so_snd);
2994890Swnj 		sbwait(&so->so_snd);
3004890Swnj 		splx(s);
3014786Swnj 		goto again;
3024786Swnj 	}
3034890Swnj 	splx(s);
3045018Swnj 	while (u.u_count && space > 0) {
3054890Swnj 		MGET(m, 1);
3064890Swnj 		if (m == NULL) {
3074890Swnj 			error = ENOBUFS;
3084890Swnj 			m_freem(top);
3094890Swnj 			goto release;
3104786Swnj 		}
3115095Swnj 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
3124890Swnj 			register struct mbuf *p;
3135095Swnj 			MCLGET(p, 1);
3144890Swnj 			if (p == 0)
3154890Swnj 				goto nopages;
3164890Swnj 			m->m_off = (int)p - (int)m;
3175095Swnj 			len = CLBYTES;
3184890Swnj 		} else {
3194786Swnj nopages:
3204890Swnj 			m->m_off = MMINOFF;
3214890Swnj 			len = MIN(MLEN, u.u_count);
3224786Swnj 		}
3234890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3244890Swnj 		m->m_len = len;
3254890Swnj 		*mp = m;
3264890Swnj 		mp = &m->m_next;
3275018Swnj 		space = sbspace(&so->so_snd);
3284786Swnj 	}
3294890Swnj 	s = splnet();
3304890Swnj 	goto again;
3314890Swnj 
3324786Swnj release:
3334890Swnj 	sbunlock(&so->so_snd);
3344786Swnj 	return (error);
3354786Swnj }
3364786Swnj 
3374927Swnj soreceive(so, asa)
3384786Swnj 	register struct socket *so;
3394927Swnj 	struct sockaddr *asa;
3404786Swnj {
3414786Swnj 	register struct mbuf *m, *n;
3424916Swnj 	u_int len;
3434890Swnj 	int eor, s, error = 0;
3444786Swnj 
3454927Swnj COUNT(SORECEIVE);
3464890Swnj restart:
3474890Swnj 	sblock(&so->so_rcv);
3484890Swnj 	s = splnet();
3494890Swnj 
3504890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3514786Swnj 	if (so->so_rcv.sb_cc == 0) {
3525168Swnj 		if (so->so_error) {
3535168Swnj 			error = so->so_error;
3545168Swnj 			so->so_error = 0;
3555168Swnj 			splx(s);
3565168Swnj 			goto release;
3575168Swnj 		}
3584890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3594890Swnj 			splx(s);
3604890Swnj 			goto release;
3614890Swnj 		}
3625015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3635015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3645015Sroot 			rcverr(ENOTCONN);
3654890Swnj 		if (so->so_options & SO_NBIO)
3665168Swnj 			rcverr(EWOULDBLOCK);
3674890Swnj 		sbunlock(&so->so_rcv);
3684971Swnj 		sbwait(&so->so_rcv);
3695012Swnj 		splx(s);
3704890Swnj 		goto restart;
3714786Swnj 	}
3724829Swnj 	m = so->so_rcv.sb_mb;
3734786Swnj 	if (m == 0)
3744786Swnj 		panic("receive");
3755039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
3765039Swnj 		if (m->m_len != sizeof (struct sockaddr))
3775039Swnj 			panic("soreceive addr");
3785039Swnj 		if (asa)
3795039Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
3805039Swnj 		so->so_rcv.sb_cc -= m->m_len;
3815039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
3825018Swnj 		m = m_free(m);
3834890Swnj 		if (m == 0)
3844890Swnj 			panic("receive 2");
3855018Swnj 		so->so_rcv.sb_mb = m;
3864890Swnj 	}
3874786Swnj 	eor = 0;
3884786Swnj 	do {
3894786Swnj 		len = MIN(m->m_len, u.u_count);
3904786Swnj 		if (len == m->m_len) {
3914786Swnj 			eor = (int)m->m_act;
3924890Swnj 			sbfree(&so->so_rcv, m);
3934786Swnj 		}
3944786Swnj 		splx(s);
3954786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
3964786Swnj 		s = splnet();
3974786Swnj 		if (len == m->m_len) {
3984786Swnj 			MFREE(m, n);
3995012Swnj 			so->so_rcv.sb_mb = n;
4004786Swnj 		} else {
4014786Swnj 			m->m_off += len;
4024786Swnj 			m->m_len -= len;
4034829Swnj 			so->so_rcv.sb_cc -= len;
4044786Swnj 		}
4054829Swnj 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
4064786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4074786Swnj 		do {
4084786Swnj 			if (m == 0)
4094890Swnj 				panic("receive 3");
4104890Swnj 			sbfree(&so->so_rcv, m);
4114786Swnj 			eor = (int)m->m_act;
4124786Swnj 			so->so_rcv.sb_mb = m->m_next;
4134786Swnj 			MFREE(m, n);
4144890Swnj 			m = n;
4154786Swnj 		} while (eor == 0);
4164890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
4174890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
4184890Swnj release:
4194916Swnj 	sbunlock(&so->so_rcv);
4204890Swnj 	splx(s);
4214916Swnj 	return (error);
4224786Swnj }
4234786Swnj 
4244916Swnj /*ARGSUSED*/
4254916Swnj soioctl(so, cmd, cmdp)
4264829Swnj 	register struct socket *so;
4274829Swnj 	int cmd;
4284829Swnj 	register caddr_t cmdp;
4294786Swnj {
4304786Swnj 
4314927Swnj COUNT(SOIOCTL);
4324829Swnj 	switch (cmdp) {
4334829Swnj 
4344829Swnj 	}
4354829Swnj 	switch (so->so_type) {
4364829Swnj 
4374829Swnj 	case SOCK_STREAM:
4384829Swnj 		break;
4394829Swnj 
4404829Swnj 	case SOCK_DGRAM:
4414829Swnj 		break;
4424829Swnj 
4434829Swnj 	case SOCK_RDM:
4444829Swnj 		break;
4454829Swnj 
4464829Swnj 	case SOCK_RAW:
4474829Swnj 		break;
4484829Swnj 
4494829Swnj 	}
4504786Swnj }
451