xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4916)
1*4916Swnj /*	uipc_socket.c	4.5	81/11/16	*/
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/protocol.h"
134829Swnj #include "../h/protosw.h"
144829Swnj #include "../h/socket.h"
154829Swnj #include "../h/socketvar.h"
164829Swnj #include "../h/inaddr.h"
17*4916Swnj #include "../h/stat.h"
184829Swnj #include "../net/inet.h"
194829Swnj #include "../net/inet_systm.h"
204786Swnj 
214786Swnj /*
224890Swnj  * Socket support routines.
234890Swnj  *
244890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
254890Swnj  * DO NEWFD STUFF
264786Swnj  */
274786Swnj 
284786Swnj /*
294786Swnj  * Create a socket.
304786Swnj  */
314829Swnj socket(aso, type, iap, options)
324786Swnj 	struct socket **aso;
334786Swnj 	int type;
344786Swnj 	register struct in_addr *iap;
354829Swnj 	int options;
364786Swnj {
374786Swnj 	register struct protosw *prp;
384786Swnj 	register struct socket *so;
394786Swnj 	struct mbuf *m;
404890Swnj 	int pf, proto, error;
414786Swnj 
424786Swnj 	/*
434890Swnj 	 * Use process standard protocol/protocol family if none
444890Swnj 	 * specified by address argument.
454786Swnj 	 */
464786Swnj 	if (iap == 0) {
474890Swnj 		pf = PF_INET;		/* should be u.u_protof */
484786Swnj 		proto = 0;
494786Swnj 	} else {
504786Swnj 		pf = iap->ia_pf;
514786Swnj 		proto = iap->ia_proto;
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;
794786Swnj 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
804786Swnj 	if (so->so_error) {
814890Swnj 		error = so->so_error;
824786Swnj 		m_free(dtom(so));
834890Swnj 		return (error);
844786Swnj 	}
854786Swnj 	*aso = so;
864786Swnj 	return (0);
874786Swnj }
884786Swnj 
89*4916Swnj sofree(so)
90*4916Swnj 	struct socket *so;
91*4916Swnj {
92*4916Swnj 
93*4916Swnj 	m_free(dtom(so));
94*4916Swnj }
95*4916Swnj 
964786Swnj /*
974890Swnj  * Close a socket on last file table reference removal.
984890Swnj  * Initiate disconnect if connected.
994890Swnj  * Free socket when disconnect complete.
1004829Swnj  */
1014890Swnj soclose(so)
1024829Swnj 	register struct socket *so;
1034829Swnj {
1044890Swnj 	int s = splnet();		/* conservative */
1054829Swnj 
1064890Swnj 	if (so->so_pcb == 0)
1074890Swnj 		goto discard;
1084890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1094890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
110*4916Swnj 			u.u_error = disconnect(so, (struct in_addr *)0);
1114890Swnj 			if (u.u_error) {
1124890Swnj 				splx(s);
1134890Swnj 				return;
1144890Swnj 			}
1154890Swnj 		}
1164890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) &&
1174890Swnj 		    (so->so_options & SO_NBIO)) {
1184890Swnj 			u.u_error = EINPROGRESS;
1194890Swnj 			splx(s);
1204890Swnj 			return;
1214890Swnj 		}
1224890Swnj 		while (so->so_state & SS_ISCONNECTED)
1234890Swnj 			sleep((caddr_t)&so->so_timeo, PZERO+1);
1244890Swnj 	}
1254890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1264890Swnj discard:
1274890Swnj 	if (so->so_pcb == 0)
1284890Swnj 		sofree(so);
1294890Swnj 	splx(s);
1304829Swnj }
1314829Swnj 
132*4916Swnj /*ARGSUSED*/
1334890Swnj sostat(so, sb)
1344829Swnj 	struct socket *so;
1354890Swnj 	struct stat *sb;
1364829Swnj {
1374829Swnj 
1384890Swnj 	return (EOPNOTSUPP);
1394829Swnj }
1404829Swnj 
1414829Swnj /*
1424890Swnj  * Connect socket to a specified address.
1434890Swnj  * If already connected or connecting, then avoid
1444890Swnj  * the protocol entry, to keep its job simpler.
1454786Swnj  */
1464786Swnj connect(so, iap)
1474786Swnj 	struct socket *so;
1484786Swnj 	struct in_addr *iap;
1494786Swnj {
1504890Swnj 	int s = splnet();
1514890Swnj 	int error;
1524786Swnj 
1534890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
1544890Swnj 		error = EISCONN;
1554890Swnj 		goto bad;
1564890Swnj 	}
1574890Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap);
1584890Swnj bad:
1594890Swnj 	splx(s);
1604890Swnj 	return (error);
1614786Swnj }
1624786Swnj 
1634786Swnj /*
1644890Swnj  * Disconnect from a socket.
1654890Swnj  * Address parameter is from system call for later multicast
1664890Swnj  * protocols.  Check to make sure that connected and no disconnect
1674890Swnj  * in progress (for protocol's sake), and then invoke protocol.
1684786Swnj  */
169*4916Swnj /*ARGSUSED*/
1704786Swnj disconnect(so, iap)
1714786Swnj 	struct socket *so;
1724786Swnj 	struct in_addr *iap;
1734786Swnj {
1744890Swnj 	int s = splnet();
1754890Swnj 	int error;
1764786Swnj 
1774890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
1784890Swnj 		error = ENOTCONN;
1794890Swnj 		goto bad;
1804890Swnj 	}
1814890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
1824890Swnj 		error = EALREADY;
1834890Swnj 		goto bad;
1844890Swnj 	}
1854890Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0);
1864890Swnj bad:
1874890Swnj 	splx(s);
1884890Swnj 	return (error);
1894786Swnj }
1904786Swnj 
1914786Swnj /*
1924890Swnj  * Send on a socket.
1934890Swnj  * If send must go all at once and message is larger than
1944890Swnj  * send buffering, then hard error.
1954890Swnj  * Lock against other senders.
1964890Swnj  * If must go all at once and not enough room now, then
1974890Swnj  * inform user that this would block and do nothing.
1984786Swnj  */
1994786Swnj send(so, iap)
2004786Swnj 	register struct socket *so;
201*4916Swnj 	struct inaddr *iap;
2024786Swnj {
2034890Swnj 	struct mbuf *top = 0;
2044890Swnj 	register struct mbuf *m, **mp = ⊤
205*4916Swnj 	register u_int len;
206*4916Swnj 	int error = 0, space, s;
2074786Swnj 
2084890Swnj 	if (so->so_state & SS_CANTSENDMORE)
2094890Swnj 		return (EPIPE);
2104890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2114890Swnj 		return (EMSGSIZE);
2124890Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
2134890Swnj 		return (EWOULDBLOCK);
2144890Swnj 	sblock(&so->so_snd);
2154890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2164890Swnj 
2174890Swnj 	s = splnet();
2184890Swnj again:
2194890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2204890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2214890Swnj 			snderr(ENOTCONN);
2224890Swnj 		if (iap == 0)
2234890Swnj 			snderr(EDESTADDRREQ);
2244890Swnj 	}
2254890Swnj 	if (so->so_error)
2264890Swnj 		snderr(so->so_error);
2274890Swnj 	if (top) {
2284890Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
2294890Swnj 		if (error) {
2304890Swnj 			splx(s);
2314786Swnj 			goto release;
2324786Swnj 		}
2334890Swnj 		top = 0;
2344890Swnj 		mp = ⊤
2354786Swnj 	}
2364890Swnj 	if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) {
2374890Swnj 		if (so->so_options & SO_NBIO)
2384890Swnj 			snderr(EWOULDBLOCK);
2394890Swnj 		sbunlock(&so->so_snd);
2404890Swnj 		sbwait(&so->so_snd);
2414890Swnj 		splx(s);
2424786Swnj 		goto again;
2434786Swnj 	}
2444890Swnj 	splx(s);
245*4916Swnj 	while (u.u_count && (space = sbspace(&so->so_snd)) > 0) {
2464890Swnj 		MGET(m, 1);
2474890Swnj 		if (m == NULL) {
2484890Swnj 			error = ENOBUFS;
2494890Swnj 			m_freem(top);
2504890Swnj 			goto release;
2514786Swnj 		}
252*4916Swnj 		if (u.u_count >= PGSIZE && space >= NMBPG) {
2534890Swnj 			register struct mbuf *p;
2544890Swnj 			MPGET(p, 1);
2554890Swnj 			if (p == 0)
2564890Swnj 				goto nopages;
2574890Swnj 			m->m_off = (int)p - (int)m;
2584890Swnj 			len = PGSIZE;
2594890Swnj 		} else {
2604786Swnj nopages:
2614890Swnj 			m->m_off = MMINOFF;
2624890Swnj 			len = MIN(MLEN, u.u_count);
2634786Swnj 		}
2644890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
2654890Swnj 		m->m_len = len;
2664890Swnj 		*mp = m;
2674890Swnj 		mp = &m->m_next;
2684786Swnj 	}
2694890Swnj 	s = splnet();
2704890Swnj 	goto again;
2714890Swnj 
2724786Swnj release:
2734890Swnj 	sbunlock(&so->so_snd);
2744786Swnj 	return (error);
2754786Swnj }
2764786Swnj 
2774786Swnj receive(so, iap)
2784786Swnj 	register struct socket *so;
279*4916Swnj 	struct inaddr *iap;
2804786Swnj {
2814786Swnj 	register struct mbuf *m, *n;
282*4916Swnj 	u_int len;
2834890Swnj 	int eor, s, error = 0;
2844786Swnj 
2854890Swnj restart:
2864890Swnj 	sblock(&so->so_rcv);
2874890Swnj 	s = splnet();
2884890Swnj 
2894890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
2904786Swnj 	if (so->so_rcv.sb_cc == 0) {
2914890Swnj 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
2924890Swnj 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
2934890Swnj 			rcverr(ENOTCONN);
2944890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
2954890Swnj 			splx(s);
2964890Swnj 			goto release;
2974890Swnj 		}
2984890Swnj 		if (so->so_options & SO_NBIO)
299*4916Swnj 			rcverr (EWOULDBLOCK);
3004890Swnj 		sbunlock(&so->so_rcv);
3014786Swnj 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
3024890Swnj 		goto restart;
3034786Swnj 	}
3044829Swnj 	m = so->so_rcv.sb_mb;
3054786Swnj 	if (m == 0)
3064786Swnj 		panic("receive");
3074890Swnj 	/*
3084890Swnj 	 * Pull address off receive chain, if protocol
3094890Swnj 	 * put one there.
3104890Swnj 	 */
3114890Swnj 	if ((so->so_proto->pr_flags & PR_ADDR)) {
3124890Swnj 		so->so_rcv.sb_mb = m->m_next;
3134890Swnj 		if (iap) {
3144890Swnj 			so->so_rcv.sb_cc -= m->m_len;
3154890Swnj 			len = MIN(m->m_len, sizeof (struct in_addr));
3164890Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
3174890Swnj 		} else
3184902Swnj 			bzero((caddr_t)iap, sizeof (*iap));
3194890Swnj 		m = so->so_rcv.sb_mb;
3204890Swnj 		if (m == 0)
3214890Swnj 			panic("receive 2");
3224890Swnj 	}
3234890Swnj 
3244890Swnj 	/*
3254890Swnj 	 * Next pull data off the chain.
3264890Swnj 	 * Stop at eor or when run out of space in user buffer.
3274890Swnj 	 */
3284786Swnj 	eor = 0;
3294786Swnj 	do {
3304786Swnj 		len = MIN(m->m_len, u.u_count);
3314786Swnj 		if (len == m->m_len) {
3324786Swnj 			eor = (int)m->m_act;
3334890Swnj 			sbfree(&so->so_rcv, m);
3344786Swnj 		}
3354786Swnj 		splx(s);
3364786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
3374786Swnj 		s = splnet();
3384786Swnj 		if (len == m->m_len) {
3394786Swnj 			MFREE(m, n);
3404786Swnj 		} else {
3414786Swnj 			m->m_off += len;
3424786Swnj 			m->m_len -= len;
3434829Swnj 			so->so_rcv.sb_cc -= len;
3444786Swnj 		}
3454829Swnj 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
3464890Swnj 
3474890Swnj 	/*
3484890Swnj 	 * If atomic protocol discard rest of record.
3494890Swnj 	 */
3504786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
3514786Swnj 		do {
3524786Swnj 			if (m == 0)
3534890Swnj 				panic("receive 3");
3544890Swnj 			sbfree(&so->so_rcv, m);
3554786Swnj 			eor = (int)m->m_act;
3564786Swnj 			so->so_rcv.sb_mb = m->m_next;
3574786Swnj 			MFREE(m, n);
3584890Swnj 			m = n;
3594786Swnj 		} while (eor == 0);
3604890Swnj 
3614890Swnj 	/*
3624890Swnj 	 * If protocol cares, inform it that
3634890Swnj 	 * there is more space in the receive buffer.
3644890Swnj 	 */
3654890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
3664890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
3674890Swnj 
3684890Swnj release:
369*4916Swnj 	sbunlock(&so->so_rcv);
3704890Swnj 	splx(s);
371*4916Swnj 	return (error);
3724786Swnj }
3734786Swnj 
374*4916Swnj /*ARGSUSED*/
375*4916Swnj soioctl(so, cmd, cmdp)
3764829Swnj 	register struct socket *so;
3774829Swnj 	int cmd;
3784829Swnj 	register caddr_t cmdp;
3794786Swnj {
3804786Swnj 
3814829Swnj 	switch (cmdp) {
3824829Swnj 
3834829Swnj 	}
3844829Swnj 	switch (so->so_type) {
3854829Swnj 
3864829Swnj 	case SOCK_STREAM:
3874829Swnj 		break;
3884829Swnj 
3894829Swnj 	case SOCK_DGRAM:
3904829Swnj 		break;
3914829Swnj 
3924829Swnj 	case SOCK_RDM:
3934829Swnj 		break;
3944829Swnj 
3954829Swnj 	case SOCK_RAW:
3964829Swnj 		break;
3974829Swnj 
3984829Swnj 	}
3994786Swnj }
400