xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4829)
1*4829Swnj /*	uipc_socket.c	4.2	81/11/08	*/
24786Swnj 
34786Swnj #include "../h/param.h"
4*4829Swnj #include "../h/systm.h"
54786Swnj #include "../h/dir.h"
64786Swnj #include "../h/user.h"
7*4829Swnj #include "../h/proc.h"
8*4829Swnj #include "../h/file.h"
94786Swnj #include "../h/inode.h"
10*4829Swnj #include "../h/buf.h"
114786Swnj #include "../h/mbuf.h"
12*4829Swnj #include "../h/protocol.h"
13*4829Swnj #include "../h/protosw.h"
14*4829Swnj #include "../h/socket.h"
15*4829Swnj #include "../h/socketvar.h"
16*4829Swnj #include "../h/inaddr.h"
17*4829Swnj #include "../net/inet.h"
18*4829Swnj #include "../net/inet_systm.h"
194786Swnj 
204786Swnj struct	socket zerosocket;
214786Swnj struct	in_addr zeroin_addr;
224786Swnj 
234786Swnj /*
244786Swnj  * Socket system call interface.  Copy in arguments
254786Swnj  * set up file descriptor and call internal socket
264786Swnj  * creation routine.
274786Swnj  */
284786Swnj ssocket()
294786Swnj {
304786Swnj 	register struct a {
31*4829Swnj 		int	type;
32*4829Swnj 		struct	in_addr *ain;
33*4829Swnj 		int	options;
344786Swnj 	} *uap = (struct a *)u.u_ap;
35*4829Swnj 	struct in_addr in;
364786Swnj 	struct socket *so0;
374786Swnj 	register struct socket *so;
384786Swnj 	register struct file *fp;
394786Swnj 
404786Swnj 	if ((fp = falloc()) == NULL)
414786Swnj 		return;
424786Swnj 	fp->f_flag = FSOCKET|FREAD|FWRITE;
434786Swnj 	if (copyin((caddr_t)uap->ain, &in, sizeof (in))) {
444786Swnj 		u.u_error = EFAULT;
454786Swnj 		return;
464786Swnj 	}
47*4829Swnj 	u.u_error = socket(&so0, uap->type, &in, uap->options);
484786Swnj 	if (u.u_error)
494786Swnj 		goto bad;
504786Swnj 	fp->f_socket = so;
514786Swnj 	return;
524786Swnj bad:
534786Swnj 	u.u_ofile[u.u_r.r_val1] = 0;
544786Swnj 	fp->f_count = 0;
554786Swnj }
564786Swnj 
574786Swnj /*
584786Swnj  * Create a socket.
594786Swnj  */
60*4829Swnj socket(aso, type, iap, options)
614786Swnj 	struct socket **aso;
624786Swnj 	int type;
634786Swnj 	register struct in_addr *iap;
64*4829Swnj 	int options;
654786Swnj {
664786Swnj 	register struct protosw *prp;
674786Swnj 	register struct socket *so;
684786Swnj 	struct mbuf *m;
694786Swnj 	int pf, proto;
704786Swnj 
714786Swnj 	/*
724786Swnj 	 * Pin down protocol if possible.
734786Swnj 	 * If no address specified, use a generic protocol.
744786Swnj 	 */
754786Swnj 	if (iap == 0) {
764786Swnj 		pf = PF_GENERIC;
774786Swnj 		proto = 0;
784786Swnj 	} else {
794786Swnj 		pf = iap->ia_pf;
804786Swnj 		proto = iap->ia_proto;
814786Swnj 	}
824786Swnj 	if (proto) {
834786Swnj 		/*
844786Swnj 		 * A specific protocol was requested.  Look
854786Swnj 		 * for the protocol.  If not found, then we
864786Swnj 		 * don't support it.
874786Swnj 		 */
884786Swnj 		prp = pf_findproto(pf, proto);
894786Swnj 		if (prp == 0)
90*4829Swnj 			return (EPROTONOSUPPORT);
914786Swnj 	} else {
924786Swnj 		/*
934786Swnj 		 * No specific protocol was requested.  Look
944786Swnj 		 * in the specified (or generic) protocol set
954786Swnj 		 * for a protocol of this type.
964786Swnj 		 */
974786Swnj 		prp = pf_findtype(pf, type);
984786Swnj 		if (prp == 0)
99*4829Swnj 			return (pf == PF_GENERIC ?
100*4829Swnj 			    ESOCKTNOSUPPORT : EPROTONOSUPPORT);
1014786Swnj 	}
1024786Swnj 
1034786Swnj 	/*
1044786Swnj 	 * Get a socket structure.
1054786Swnj 	 */
1064786Swnj 	m = m_get(M_WAIT);
1074786Swnj 	if (m == 0)
1084786Swnj 		return (ENOBUFS);
1094786Swnj 	m->m_off = MMINOFF;
1104786Swnj 	so = mtod(m, struct socket *);
1114786Swnj 	*so = zerosocket;
112*4829Swnj 	so->so_options = options;
1134786Swnj 
1144786Swnj 	/*
1154786Swnj 	 * An early call to protocol initialization.  If protocol
1164786Swnj 	 * actually hasn't been decided on yet (till we know
1174786Swnj 	 * peer), then the generic protocol allocated so far can
1184786Swnj 	 * just make sure a reasonable amount of resources will
1194786Swnj 	 * be available to it (say by allocating liberally now
1204786Swnj 	 * and returning some of the resources later).
1214786Swnj 	 */
1224786Swnj 	so->so_proto = prp;
1234786Swnj 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
1244786Swnj 	if (so->so_error) {
1254786Swnj 		m_free(dtom(so));
1264786Swnj 		return (u.u_error);
1274786Swnj 	}
1284786Swnj 	*aso = so;
1294786Swnj 	return (0);
1304786Swnj }
1314786Swnj 
132*4829Swnj spipe()
133*4829Swnj {
134*4829Swnj 
135*4829Swnj }
136*4829Swnj 
137*4829Swnj skclose(so)
138*4829Swnj 	register struct socket *so;
139*4829Swnj {
140*4829Swnj 
141*4829Swnj 	if (so->so_pcb)
142*4829Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
143*4829Swnj }
144*4829Swnj 
1454786Swnj /*
146*4829Swnj  * Select a socket.
147*4829Swnj  */
148*4829Swnj soselect(so, flag)
149*4829Swnj 	register struct socket *so;
150*4829Swnj 	int flag;
151*4829Swnj {
152*4829Swnj 	register struct proc *p;
153*4829Swnj 
154*4829Swnj 	if (so->so_rcv.sb_cc)
155*4829Swnj 		return (1);
156*4829Swnj 	if ((p = so->so_rcv.sb_sel) && p->p_wchan == (caddr_t)select)
157*4829Swnj 		so->so_rcv.sb_flags |= SB_COLL;
158*4829Swnj 	else
159*4829Swnj 		so->so_rcv.sb_sel = u.u_procp;
160*4829Swnj 	return (0);
161*4829Swnj }
162*4829Swnj 
163*4829Swnj /*
164*4829Swnj  * Wakeup read sleep/select'ers.
165*4829Swnj  */
166*4829Swnj sowakeup(so)
167*4829Swnj 	struct socket *so;
168*4829Swnj {
169*4829Swnj 
170*4829Swnj 	if (so->so_rcv.sb_cc && so->so_rcv.sb_sel) {
171*4829Swnj 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
172*4829Swnj 		so->so_rcv.sb_sel = 0;
173*4829Swnj 		so->so_rcv.sb_flags &= ~SB_COLL;
174*4829Swnj 	}
175*4829Swnj 	if (so->so_rcv.sb_flags & SB_WAIT) {
176*4829Swnj 		so->so_rcv.sb_flags &= ~SB_WAIT;
177*4829Swnj 		wakeup((caddr_t)&so->so_rcv.sb_cc);
178*4829Swnj 	}
179*4829Swnj }
180*4829Swnj 
181*4829Swnj /*
1824786Swnj  * Connect socket to foreign peer; system call
1834786Swnj  * interface.  Copy in arguments and call internal routine.
1844786Swnj  */
1854786Swnj sconnect()
1864786Swnj {
1874786Swnj 	register struct a {
1884786Swnj 		int fdes;
189*4829Swnj 		struct in_addr *a;
1904786Swnj 	} *uap = (struct a *)u.u_ap;
1914786Swnj 	in_addr in;
192*4829Swnj 	register struct file *fp;
193*4829Swnj 	register struct socket *so;
194*4829Swnj 	int s;
1954786Swnj 
196*4829Swnj 	if (copyin((caddr_t)uap->a, &in, sizeof (in))) {
1974786Swnj 		u.u_error = EFAULT;
1984786Swnj 		return;
1994786Swnj 	}
2004786Swnj 	fp = getf(uap->fdes);
2014786Swnj 	if (fp == 0)
2024786Swnj 		return;
2034786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
2044786Swnj 		u.u_error = ENOTSOCK;
2054786Swnj 		return;
2064786Swnj 	}
207*4829Swnj 	so = fp->f_socket;
208*4829Swnj 	u.u_error = connect(so, &in);
2094786Swnj 	if (u.u_error)
2104786Swnj 		return;
2114786Swnj 	s = splnet();
2124786Swnj 	for (;;) {
2134786Swnj 		/* should use tsleep here */
2144786Swnj 		if ((*so->so_proto->pr_usrreq)(so, PRU_ISCONN, 0, &in) == 0)
2154786Swnj 			break;
2164786Swnj 		sleep((caddr_t)&so->so_timeo, PZERO+1);
2174786Swnj 	}
2184786Swnj 	splx(s);
2194786Swnj }
2204786Swnj 
2214786Swnj connect(so, iap)
2224786Swnj 	struct socket *so;
2234786Swnj 	struct in_addr *iap;
2244786Swnj {
2254786Swnj 
226*4829Swnj 	return ((*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, iap));
2274786Swnj }
2284786Swnj 
2294786Swnj /*
2304786Swnj  * Disconnect socket from foreign peer; system call
2314786Swnj  * interface.  Copy in arguments and call internal routine.
2324786Swnj  */
2334786Swnj sdisconnect()
2344786Swnj {
2354786Swnj 	register struct a {
236*4829Swnj 		int	fdes;
237*4829Swnj 		in_addr	 *addr;
2384786Swnj 	} *uap = (struct a *)u.u_ap;
2394786Swnj 	in_addr in;
240*4829Swnj 	register struct file *fp;
2414786Swnj 
242*4829Swnj 	if (uap->addr &&
243*4829Swnj 	    copyin((caddr_t)uap->addr, (caddr_t)&in, sizeof (in))) {
2444786Swnj 		u.u_error = EFAULT;
2454786Swnj 		return;
2464786Swnj 	}
2474786Swnj 	fp = getf(uap->fdes);
2484786Swnj 	if (fp == 0)
2494786Swnj 		return;
2504786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
2514786Swnj 		u.u_error = ENOTSOCK;
2524786Swnj 		return;
2534786Swnj 	}
254*4829Swnj 	disconnect(fp->f_socket, uap->addr ? &in : 0);
2554786Swnj }
2564786Swnj 
2574786Swnj disconnect(so, iap)
2584786Swnj 	struct socket *so;
2594786Swnj 	struct in_addr *iap;
2604786Swnj {
2614786Swnj 
262*4829Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, iap);
2634786Swnj }
2644786Swnj 
2654786Swnj /*
2664786Swnj  * Send data on socket.
2674786Swnj  */
2684786Swnj ssend()
2694786Swnj {
2704786Swnj 	register struct a {
271*4829Swnj 		int	fdes;
272*4829Swnj 		in_addr	*ain;
273*4829Swnj 		caddr_t	cbuf;
274*4829Swnj 		int	count;
2754786Swnj 	} *uap = (struct a *)u.u_ap;
276*4829Swnj 	register struct file *fp;
277*4829Swnj 	struct in_addr in;
2784786Swnj 
2794786Swnj 	fp = getf(uap->fdes);
2804786Swnj 	if (fp == 0)
2814786Swnj 		return;
2824786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
2834786Swnj 		u.u_error = ENOTSOCK;
2844786Swnj 		return;
2854786Swnj 	}
2864786Swnj 	if (uap->count < 0) {
2874786Swnj 		u.u_error = EINVAL;
2884786Swnj 		return;
2894786Swnj 	}
290*4829Swnj 	u.u_base = uap->cbuf;
291*4829Swnj 	u.u_count = uap->count;
2924786Swnj 	u.u_segflg = 0;
2934786Swnj 	if (useracc(u.u_base, u.u_count, B_READ) == 0 ||
2944786Swnj 	    uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) {
2954786Swnj 		u.u_error = EFAULT;
2964786Swnj 		return;
2974786Swnj 	}
2984786Swnj 	u.u_error = send(fp->f_socket, uap->ain ? &in : 0);
2994786Swnj }
3004786Swnj 
3014786Swnj send(so, iap)
3024786Swnj 	register struct socket *so;
3034786Swnj 	struct in_addr *iap;
3044786Swnj {
3054786Swnj 	register struct mbuf *m, **mp;
3064786Swnj 	struct mbuf *top;
3074786Swnj 	int error = 0;
3084786Swnj 
3094786Swnj 	if (so->so_proto->pr_flags & PR_ATOMIC) {
3104786Swnj 		if (u.u_count > so->so_snd.sb_hiwat) {
3114786Swnj 			error = EMSGSIZE;
3124786Swnj 			goto release;
3134786Swnj 		}
3144786Swnj 	}
3154786Swnj again:
3164786Swnj 	while (so->so_snd.sb_flags & SB_LOCK) {
3174786Swnj 		so->so_snd.sb_flags |= SB_WANT;
3184786Swnj 		sleep((caddr_t)&so->so_snd.sb_flags, PZERO+1);
3194786Swnj 	}
3204786Swnj 	if (so->so_snd.sb_hiwat - so->so_snd.sb_cc < u.u_count) {
3214786Swnj 		so->so_snd.sb_flags |= SB_WAIT;
3224786Swnj 		sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1);
3234786Swnj 		goto again;
3244786Swnj 	}
3254786Swnj 	so->so_snd.sb_flags |= SB_LOCK;
3264786Swnj 	while (u.u_count > 0) {
327*4829Swnj 		register int bufs = so->so_snd.sb_mbmax - so->so_snd.sb_mbcnt;
3284786Swnj 		while (bufs == 0) {
3294786Swnj 			so->so_snd.sb_flags |= SB_WAIT;
3304786Swnj 			sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1);
3314786Swnj 		}
3324786Swnj 		mp = &top;
3334786Swnj 		top = 0;
3344786Swnj 		while (--bufs >= 0 && u.u_count > 0) {
335*4829Swnj 			register int len;
3364786Swnj 			MGET(m, 1);
3374786Swnj 			if (m == NULL) {
3384786Swnj 				error = ENOBUFS;
3394786Swnj 				m_freem(top);
3404786Swnj 				goto release;
3414786Swnj 			}
3424786Swnj 			if (u.u_count >= PGSIZE && bufs >= NMBPG) {
343*4829Swnj 				register struct mbuf *p;
3444786Swnj 				MPGET(p, 1);
3454786Swnj 				if (p == 0)
346*4829Swnj 					goto nopages;
3474786Swnj 				m->m_off = (int)p - (int)m;
3484786Swnj 				len = PGSIZE;
3494786Swnj 			} else {
3504786Swnj nopages:
3514786Swnj 				m->m_off = MMINOFF;
3524786Swnj 				len = MIN(MLEN, u.u_count);
3534786Swnj 			}
3544786Swnj 			iomove(mtod(m, caddr_t), len, B_WRITE);
3554786Swnj 			m->m_len = len;
3564786Swnj 			*mp = m;
3574786Swnj 			mp = &m->m_next;
3584786Swnj 		}
359*4829Swnj 		{ register int s = splnet();
360*4829Swnj 		  error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
361*4829Swnj 		  splx(s); }
3624786Swnj 		if (error)
3634786Swnj 			break;
3644786Swnj 	}
3654786Swnj release:
3664786Swnj 	so->so_snd.sb_flags &= ~SB_LOCK;
3674786Swnj 	if (so->so_snd.sb_flags & SB_WANT)
368*4829Swnj 		wakeup((caddr_t)&so->so_snd.sb_flags);
3694786Swnj 	return (error);
3704786Swnj }
3714786Swnj 
3724786Swnj /*
3734786Swnj  * Receive data on socket.
3744786Swnj  */
3754786Swnj sreceive()
3764786Swnj {
3774786Swnj 	register struct a {
378*4829Swnj 		int	fdes;
379*4829Swnj 		in_addr	*ain;
380*4829Swnj 		caddr_t	cbuf;
381*4829Swnj 		int	count;
3824786Swnj 	} *uap = (struct a *)u.u_ap;
383*4829Swnj 	register struct file *fp;
384*4829Swnj 	struct in_addr *in;
3854786Swnj 
3864786Swnj 	fp = getf(uap->fdes);
3874786Swnj 	if (fp == 0)
3884786Swnj 		return;
3894786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
3904786Swnj 		u.u_error = ENOTSOCK;
3914786Swnj 		return;
3924786Swnj 	}
3934786Swnj 	if (uap->count < 0) {
3944786Swnj 		u.u_error = EINVAL;
3954786Swnj 		return;
3964786Swnj 	}
397*4829Swnj 	u.u_base = uap->cbuf;
398*4829Swnj 	u.u_count = uap->count;
3994786Swnj 	u.u_segflg = 0;
4004786Swnj 	if (useracc(u.u_base, u.u_count, B_WRITE) == 0 ||
4014786Swnj 	    uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) {
4024786Swnj 		u.u_error = EFAULT;
4034786Swnj 		return;
4044786Swnj 	}
4054786Swnj 	receive(fp->f_socket, uap->ain ? &in : 0);
4064786Swnj }
4074786Swnj 
4084786Swnj receive(so, iap)
4094786Swnj 	register struct socket *so;
4104786Swnj 	struct in_addr *iap;
4114786Swnj {
4124786Swnj 	register struct mbuf *m, *n;
4134786Swnj 	register int eor, len, s;
4144786Swnj 
4154786Swnj again:
4164786Swnj 	while (so->so_rcv.sb_flags & SB_LOCK) {
4174786Swnj 		so->so_rcv.sb_flags |= SB_WANT;
4184786Swnj 		sleep((caddr_t)&so->so_rcv.sb_flags, PZERO+1);
4194786Swnj 	}
4204786Swnj 	if (so->so_rcv.sb_cc == 0) {
421*4829Swnj 		if ((so->so_proto->pr_usrreq)(so, PRU_ISDISCONN, 0, 0) == 0)
4224786Swnj 			return;
4234786Swnj 		so->so_rcv.sb_flags |= SB_WAIT;
4244786Swnj 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
4254786Swnj 		goto again;
4264786Swnj 	}
4274786Swnj 	so->so_rcv.sb_flags |= SB_LOCK;
428*4829Swnj 	m = so->so_rcv.sb_mb;
4294786Swnj 	if (m == 0)
4304786Swnj 		panic("receive");
4314786Swnj 	eor = 0;
4324786Swnj 	do {
4334786Swnj 		len = MIN(m->m_len, u.u_count);
4344786Swnj 		if (len == m->m_len) {
4354786Swnj 			eor = (int)m->m_act;
436*4829Swnj 			so->so_rcv.sb_mb = m->m_next;
437*4829Swnj 			so->so_rcv.sb_cc -= len;
438*4829Swnj 			if (so->so_rcv.sb_cc < 0)
4394786Swnj 				panic("receive 2");
4404786Swnj 		}
4414786Swnj 		splx(s);
4424786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
4434786Swnj 		s = splnet();
4444786Swnj 		if (len == m->m_len) {
4454786Swnj 			MFREE(m, n);
4464786Swnj 		} else {
4474786Swnj 			m->m_off += len;
4484786Swnj 			m->m_len -= len;
449*4829Swnj 			so->so_rcv.sb_cc -= len;
450*4829Swnj 			if (so->so_rcv.sb_cc < 0)
4514786Swnj 				panic("receive 3");
4524786Swnj 		}
453*4829Swnj 	} while ((m = so->so_rcv.sb_mb) && u.u_count && !eor);
4544786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4554786Swnj 		do {
4564786Swnj 			m = so->so_rcv.sb_mb;
4574786Swnj 			if (m == 0)
4584786Swnj 				panic("receive 4");
459*4829Swnj 			so->so_rcv.sb_cc -= m->m_len;
460*4829Swnj 			if (so->so_rcv.sb_cc < 0)
4614786Swnj 				panic("receive 5");
4624786Swnj 			eor = (int)m->m_act;
4634786Swnj 			so->so_rcv.sb_mb = m->m_next;
4644786Swnj 			MFREE(m, n);
4654786Swnj 		} while (eor == 0);
4664786Swnj 	if (iap)
467*4829Swnj 		if ((so->so_proto->pr_flags & PR_ADDR)) {
468*4829Swnj 			m = so->so_rcv.sb_mb;
4694786Swnj 			if (m == 0)
4704786Swnj 				panic("receive 6");
471*4829Swnj 			so->so_rcv.sb_mb = m->m_next;
472*4829Swnj 			so->so_rcv.sb_cc -= m->m_len;
4734786Swnj 			len = MIN(m->m_len, sizeof (struct in_addr));
4744786Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
4754786Swnj 		} else
4764786Swnj 			*iap = zeroin_addr;
477*4829Swnj 	(*so->so_proto->pr_usrreq)(so, PRU_RCVD, m, 0);
4784786Swnj }
4794786Swnj 
480*4829Swnj skioctl(so, cmd, cmdp)
481*4829Swnj 	register struct socket *so;
482*4829Swnj 	int cmd;
483*4829Swnj 	register caddr_t cmdp;
4844786Swnj {
4854786Swnj 
486*4829Swnj 	switch (cmdp) {
487*4829Swnj 
488*4829Swnj 	}
489*4829Swnj 	switch (so->so_type) {
490*4829Swnj 
491*4829Swnj 	case SOCK_STREAM:
492*4829Swnj 		break;
493*4829Swnj 
494*4829Swnj 	case SOCK_DGRAM:
495*4829Swnj 		break;
496*4829Swnj 
497*4829Swnj 	case SOCK_RDM:
498*4829Swnj 		break;
499*4829Swnj 
500*4829Swnj 	case SOCK_RAW:
501*4829Swnj 		break;
502*4829Swnj 
503*4829Swnj 	}
5044786Swnj }
505*4829Swnj 
506*4829Swnj sostat(so)
507*4829Swnj 	struct socket *so;
508*4829Swnj {
509*4829Swnj 
510*4829Swnj }
511*4829Swnj 
512*4829Swnj /*
513*4829Swnj  * Generic protocol handler.
514*4829Swnj  */
515*4829Swnj gen_usrreq()
516*4829Swnj {
517*4829Swnj 
518*4829Swnj }
519