xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4890)
1*4890Swnj /*	uipc_socket.c	4.3	81/11/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/protocol.h"
134829Swnj #include "../h/protosw.h"
144829Swnj #include "../h/socket.h"
154829Swnj #include "../h/socketvar.h"
164829Swnj #include "../h/inaddr.h"
174829Swnj #include "../net/inet.h"
184829Swnj #include "../net/inet_systm.h"
194786Swnj 
204786Swnj /*
21*4890Swnj  * Socket support routines.
22*4890Swnj  *
23*4890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
24*4890Swnj  * DO NEWFD STUFF
254786Swnj  */
264786Swnj 
274786Swnj /*
284786Swnj  * Create a socket.
294786Swnj  */
304829Swnj socket(aso, type, iap, options)
314786Swnj 	struct socket **aso;
324786Swnj 	int type;
334786Swnj 	register struct in_addr *iap;
344829Swnj 	int options;
354786Swnj {
364786Swnj 	register struct protosw *prp;
374786Swnj 	register struct socket *so;
384786Swnj 	struct mbuf *m;
39*4890Swnj 	int pf, proto, error;
404786Swnj 
414786Swnj 	/*
42*4890Swnj 	 * Use process standard protocol/protocol family if none
43*4890Swnj 	 * specified by address argument.
444786Swnj 	 */
454786Swnj 	if (iap == 0) {
46*4890Swnj 		pf = PF_INET;		/* should be u.u_protof */
474786Swnj 		proto = 0;
484786Swnj 	} else {
494786Swnj 		pf = iap->ia_pf;
504786Swnj 		proto = iap->ia_proto;
514786Swnj 	}
524786Swnj 
534786Swnj 	/*
54*4890Swnj 	 * If protocol specified, look for it, otherwise
55*4890Swnj 	 * for a protocol of the correct type in the right family.
56*4890Swnj 	 */
57*4890Swnj 	if (proto)
58*4890Swnj 		prp = pffindproto(pf, proto);
59*4890Swnj 	else
60*4890Swnj 		prp = pffindtype(pf, type);
61*4890Swnj 	if (prp == 0)
62*4890Swnj 		return (EPROTONOSUPPORT);
63*4890Swnj 
64*4890Swnj 	/*
654786Swnj 	 * Get a socket structure.
664786Swnj 	 */
67*4890Swnj 	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 	/*
74*4890Swnj 	 * Attach protocol to socket, initializing
75*4890Swnj 	 * and reserving resources.
764786Swnj 	 */
774786Swnj 	so->so_proto = prp;
784786Swnj 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
794786Swnj 	if (so->so_error) {
80*4890Swnj /*###80 [cc] operands of = have incompatible types %%%*/
81*4890Swnj /*###80 [cc] zerosocket undefined %%%*/
82*4890Swnj 		error = so->so_error;
834786Swnj 		m_free(dtom(so));
84*4890Swnj 		return (error);
854786Swnj 	}
864786Swnj 	*aso = so;
874786Swnj 	return (0);
884786Swnj }
894786Swnj 
904786Swnj /*
91*4890Swnj  * Close a socket on last file table reference removal.
92*4890Swnj  * Initiate disconnect if connected.
93*4890Swnj  * Free socket when disconnect complete.
944829Swnj  */
95*4890Swnj soclose(so)
964829Swnj 	register struct socket *so;
974829Swnj {
98*4890Swnj 	int s = splnet();		/* conservative */
994829Swnj 
100*4890Swnj 	if (so->so_pcb == 0)
101*4890Swnj 		goto discard;
102*4890Swnj 	if (so->so_state & SS_ISCONNECTED) {
103*4890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
104*4890Swnj 			u.u_error = disconnect(so, 0);
105*4890Swnj 			if (u.u_error) {
106*4890Swnj 				splx(s);
107*4890Swnj 				return;
108*4890Swnj 			}
109*4890Swnj 		}
110*4890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) &&
111*4890Swnj 		    (so->so_options & SO_NBIO)) {
112*4890Swnj 			u.u_error = EINPROGRESS;
113*4890Swnj 			splx(s);
114*4890Swnj 			return;
115*4890Swnj 		}
116*4890Swnj 		while (so->so_state & SS_ISCONNECTED)
117*4890Swnj 			sleep((caddr_t)&so->so_timeo, PZERO+1);
118*4890Swnj 	}
119*4890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
120*4890Swnj discard:
121*4890Swnj 	if (so->so_pcb == 0)
122*4890Swnj 		sofree(so);
123*4890Swnj 	splx(s);
1244829Swnj }
1254829Swnj 
126*4890Swnj sostat(so, sb)
1274829Swnj 	struct socket *so;
128*4890Swnj 	struct stat *sb;
1294829Swnj {
1304829Swnj 
131*4890Swnj 	return (EOPNOTSUPP);
1324829Swnj }
1334829Swnj 
1344829Swnj /*
135*4890Swnj  * Connect socket to a specified address.
136*4890Swnj  * If already connected or connecting, then avoid
137*4890Swnj  * the protocol entry, to keep its job simpler.
1384786Swnj  */
1394786Swnj connect(so, iap)
1404786Swnj 	struct socket *so;
1414786Swnj 	struct in_addr *iap;
1424786Swnj {
143*4890Swnj 	int s = splnet();
144*4890Swnj 	int error;
1454786Swnj 
146*4890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
147*4890Swnj 		error = EISCONN;
148*4890Swnj 		goto bad;
149*4890Swnj 	}
150*4890Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap);
151*4890Swnj bad:
152*4890Swnj 	splx(s);
153*4890Swnj 	return (error);
1544786Swnj }
1554786Swnj 
1564786Swnj /*
157*4890Swnj  * Disconnect from a socket.
158*4890Swnj  * Address parameter is from system call for later multicast
159*4890Swnj  * protocols.  Check to make sure that connected and no disconnect
160*4890Swnj  * in progress (for protocol's sake), and then invoke protocol.
1614786Swnj  */
1624786Swnj disconnect(so, iap)
1634786Swnj 	struct socket *so;
1644786Swnj 	struct in_addr *iap;
1654786Swnj {
166*4890Swnj 	int s = splnet();
167*4890Swnj 	int error;
1684786Swnj 
169*4890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
170*4890Swnj 		error = ENOTCONN;
171*4890Swnj 		goto bad;
172*4890Swnj 	}
173*4890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
174*4890Swnj 		error = EALREADY;
175*4890Swnj 		goto bad;
176*4890Swnj 	}
177*4890Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0);
178*4890Swnj bad:
179*4890Swnj 	splx(s);
180*4890Swnj 	return (error);
1814786Swnj }
1824786Swnj 
1834786Swnj /*
184*4890Swnj  * Send on a socket.
185*4890Swnj  * If send must go all at once and message is larger than
186*4890Swnj  * send buffering, then hard error.
187*4890Swnj  * Lock against other senders.
188*4890Swnj  * If must go all at once and not enough room now, then
189*4890Swnj  * inform user that this would block and do nothing.
1904786Swnj  */
1914786Swnj send(so, iap)
1924786Swnj 	register struct socket *so;
1934786Swnj 	struct in_addr *iap;
1944786Swnj {
195*4890Swnj 	struct mbuf *top = 0;
196*4890Swnj 	register struct mbuf *m, **mp = ⊤
197*4890Swnj 	register int bufs;
198*4890Swnj 	register int len;
1994786Swnj 	int error = 0;
200*4890Swnj 	int s;
2014786Swnj 
202*4890Swnj 	if (so->so_state & SS_CANTSENDMORE)
203*4890Swnj 		return (EPIPE);
204*4890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
205*4890Swnj 		return (EMSGSIZE);
206*4890Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO))
207*4890Swnj 		return (EWOULDBLOCK);
208*4890Swnj 	sblock(&so->so_snd);
209*4890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
210*4890Swnj 
211*4890Swnj 	s = splnet();
212*4890Swnj again:
213*4890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
214*4890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
215*4890Swnj 			snderr(ENOTCONN);
216*4890Swnj 		if (iap == 0)
217*4890Swnj 			snderr(EDESTADDRREQ);
218*4890Swnj 	}
219*4890Swnj 	if (so->so_error)
220*4890Swnj 		snderr(so->so_error);
221*4890Swnj 	if (top) {
222*4890Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
223*4890Swnj 		if (error) {
224*4890Swnj 			splx(s);
2254786Swnj 			goto release;
2264786Swnj 		}
227*4890Swnj 		top = 0;
228*4890Swnj 		mp = ⊤
2294786Swnj 	}
230*4890Swnj 	if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) {
231*4890Swnj 		if (so->so_options & SO_NBIO)
232*4890Swnj 			snderr(EWOULDBLOCK);
233*4890Swnj 		sbunlock(&so->so_snd);
234*4890Swnj 		sbwait(&so->so_snd);
235*4890Swnj 		splx(s);
2364786Swnj 		goto again;
2374786Swnj 	}
238*4890Swnj 	splx(s);
239*4890Swnj 	while (u.u_count > 0 && sbspace(&so->so_snd) > 0) {
240*4890Swnj 		MGET(m, 1);
241*4890Swnj 		if (m == NULL) {
242*4890Swnj 			error = ENOBUFS;
243*4890Swnj 			m_freem(top);
244*4890Swnj 			goto release;
2454786Swnj 		}
246*4890Swnj 		if (u.u_count >= PGSIZE && bufs >= NMBPG) {
247*4890Swnj 			register struct mbuf *p;
248*4890Swnj 			MPGET(p, 1);
249*4890Swnj 			if (p == 0)
250*4890Swnj 				goto nopages;
251*4890Swnj 			m->m_off = (int)p - (int)m;
252*4890Swnj 			len = PGSIZE;
253*4890Swnj 		} else {
2544786Swnj nopages:
255*4890Swnj 			m->m_off = MMINOFF;
256*4890Swnj 			len = MIN(MLEN, u.u_count);
2574786Swnj 		}
258*4890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
259*4890Swnj 		m->m_len = len;
260*4890Swnj 		*mp = m;
261*4890Swnj 		mp = &m->m_next;
2624786Swnj 	}
263*4890Swnj 	s = splnet();
264*4890Swnj 	goto again;
265*4890Swnj 
2664786Swnj release:
267*4890Swnj 	sbunlock(&so->so_snd);
2684786Swnj 	return (error);
2694786Swnj }
2704786Swnj 
2714786Swnj receive(so, iap)
2724786Swnj 	register struct socket *so;
2734786Swnj 	struct in_addr *iap;
2744786Swnj {
2754786Swnj 	register struct mbuf *m, *n;
276*4890Swnj 	register int len;
277*4890Swnj 	int eor, s, error = 0;
2784786Swnj 
279*4890Swnj restart:
280*4890Swnj 	sblock(&so->so_rcv);
281*4890Swnj 	s = splnet();
282*4890Swnj 
283*4890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
2844786Swnj 	if (so->so_rcv.sb_cc == 0) {
285*4890Swnj 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
286*4890Swnj 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
287*4890Swnj 			rcverr(ENOTCONN);
288*4890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
289*4890Swnj 			splx(s);
290*4890Swnj 			goto release;
291*4890Swnj 		}
292*4890Swnj 		if (so->so_options & SO_NBIO)
293*4890Swnj 			rcverr(EWOULDBLOCK);
294*4890Swnj 		sbunlock(&so->so_rcv);
2954786Swnj 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
296*4890Swnj 		goto restart;
2974786Swnj 	}
2984829Swnj 	m = so->so_rcv.sb_mb;
2994786Swnj 	if (m == 0)
3004786Swnj 		panic("receive");
301*4890Swnj 
302*4890Swnj 	/*
303*4890Swnj 	 * Pull address off receive chain, if protocol
304*4890Swnj 	 * put one there.
305*4890Swnj 	 */
306*4890Swnj 	if ((so->so_proto->pr_flags & PR_ADDR)) {
307*4890Swnj 		so->so_rcv.sb_mb = m->m_next;
308*4890Swnj 		if (iap) {
309*4890Swnj 			so->so_rcv.sb_cc -= m->m_len;
310*4890Swnj 			len = MIN(m->m_len, sizeof (struct in_addr));
311*4890Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
312*4890Swnj 		} else
313*4890Swnj 			*iap = zeroin_addr;
314*4890Swnj 		m = so->so_rcv.sb_mb;
315*4890Swnj 		if (m == 0)
316*4890Swnj 			panic("receive 2");
317*4890Swnj 	}
318*4890Swnj 
319*4890Swnj 	/*
320*4890Swnj 	 * Next pull data off the chain.
321*4890Swnj 	 * Stop at eor or when run out of space in user buffer.
322*4890Swnj 	 */
3234786Swnj 	eor = 0;
3244786Swnj 	do {
3254786Swnj 		len = MIN(m->m_len, u.u_count);
3264786Swnj 		if (len == m->m_len) {
3274786Swnj 			eor = (int)m->m_act;
328*4890Swnj 			sbfree(&so->so_rcv, m);
3294786Swnj 		}
3304786Swnj 		splx(s);
3314786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
3324786Swnj 		s = splnet();
3334786Swnj 		if (len == m->m_len) {
3344786Swnj 			MFREE(m, n);
3354786Swnj 		} else {
3364786Swnj 			m->m_off += len;
3374786Swnj 			m->m_len -= len;
3384829Swnj 			so->so_rcv.sb_cc -= len;
3394786Swnj 		}
3404829Swnj 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
341*4890Swnj 
342*4890Swnj 	/*
343*4890Swnj 	 * If atomic protocol discard rest of record.
344*4890Swnj 	 */
3454786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
3464786Swnj 		do {
3474786Swnj 			if (m == 0)
348*4890Swnj 				panic("receive 3");
349*4890Swnj 			sbfree(&so->so_rcv, m);
3504786Swnj 			eor = (int)m->m_act;
3514786Swnj 			so->so_rcv.sb_mb = m->m_next;
3524786Swnj 			MFREE(m, n);
353*4890Swnj 			m = n;
3544786Swnj 		} while (eor == 0);
355*4890Swnj 
356*4890Swnj 	/*
357*4890Swnj 	 * If protocol cares, inform it that
358*4890Swnj 	 * there is more space in the receive buffer.
359*4890Swnj 	 */
360*4890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
361*4890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
362*4890Swnj 
363*4890Swnj release:
364*4890Swnj 	sounlock(&so->so_rcv);
365*4890Swnj 	splx(s);
3664786Swnj }
3674786Swnj 
3684829Swnj skioctl(so, cmd, cmdp)
3694829Swnj 	register struct socket *so;
3704829Swnj 	int cmd;
3714829Swnj 	register caddr_t cmdp;
3724786Swnj {
3734786Swnj 
3744829Swnj 	switch (cmdp) {
3754829Swnj 
3764829Swnj 	}
3774829Swnj 	switch (so->so_type) {
3784829Swnj 
3794829Swnj 	case SOCK_STREAM:
3804829Swnj 		break;
3814829Swnj 
3824829Swnj 	case SOCK_DGRAM:
3834829Swnj 		break;
3844829Swnj 
3854829Swnj 	case SOCK_RDM:
3864829Swnj 		break;
3874829Swnj 
3884829Swnj 	case SOCK_RAW:
3894829Swnj 		break;
3904829Swnj 
3914829Swnj 	}
3924786Swnj }
393*4890Swnj /*###417 [cc] operands of = have incompatible types %%%*/
394*4890Swnj /*###417 [cc] zeroin_addr undefined %%%*/
395