xref: /csrg-svn/sys/kern/uipc_socket.c (revision 4786)
1*4786Swnj /*	uipc_socket.c	4.1	81/11/07	*/
2*4786Swnj 
3*4786Swnj #include "../h/param.h"
4*4786Swnj #include "../h/dir.h"
5*4786Swnj #include "../h/user.h"
6*4786Swnj #include "file.h"
7*4786Swnj #include "../h/inode.h"
8*4786Swnj #include "../h/mbuf.h"
9*4786Swnj #include "protocol.h"
10*4786Swnj #include "protocolsw.h"
11*4786Swnj #include "socket.h"
12*4786Swnj #include "socketvar.h"
13*4786Swnj 
14*4786Swnj struct	socket zerosocket;
15*4786Swnj struct	in_addr zeroin_addr;
16*4786Swnj 
17*4786Swnj /*
18*4786Swnj  * Socket system call interface.  Copy in arguments
19*4786Swnj  * set up file descriptor and call internal socket
20*4786Swnj  * creation routine.
21*4786Swnj  */
22*4786Swnj ssocket()
23*4786Swnj {
24*4786Swnj 	register struct a {
25*4786Swnj 		int type;
26*4786Swnj 		in_addr *ain;
27*4786Swnj 		int flags;
28*4786Swnj 	} *uap = (struct a *)u.u_ap;
29*4786Swnj 	in_addr in;
30*4786Swnj 	struct socket *so0;
31*4786Swnj 	register struct socket *so;
32*4786Swnj 	register struct file *fp;
33*4786Swnj 
34*4786Swnj 	if ((fp = falloc()) == NULL)
35*4786Swnj 		return;
36*4786Swnj 	fp->f_flag = FSOCKET|FREAD|FWRITE;
37*4786Swnj 	if (copyin((caddr_t)uap->ain, &in, sizeof (in))) {
38*4786Swnj 		u.u_error = EFAULT;
39*4786Swnj 		return;
40*4786Swnj 	}
41*4786Swnj 	u.u_error = socket(&so0, a->type, &in, a->flags);
42*4786Swnj 	if (u.u_error)
43*4786Swnj 		goto bad;
44*4786Swnj 	fp->f_socket = so;
45*4786Swnj 	return;
46*4786Swnj bad:
47*4786Swnj 	u.u_ofile[u.u_r.r_val1] = 0;
48*4786Swnj 	fp->f_count = 0;
49*4786Swnj }
50*4786Swnj 
51*4786Swnj /*
52*4786Swnj  * Create a socket.
53*4786Swnj  */
54*4786Swnj socket(aso, type, iap, flags)
55*4786Swnj 	struct socket **aso;
56*4786Swnj 	int type;
57*4786Swnj 	register struct in_addr *iap;
58*4786Swnj 	int flags;
59*4786Swnj {
60*4786Swnj 	register struct protosw *prp;
61*4786Swnj 	register struct socket *so;
62*4786Swnj 	struct mbuf *m;
63*4786Swnj 	int pf, proto;
64*4786Swnj 
65*4786Swnj 	/*
66*4786Swnj 	 * Pin down protocol if possible.
67*4786Swnj 	 * If no address specified, use a generic protocol.
68*4786Swnj 	 */
69*4786Swnj 	if (iap == 0) {
70*4786Swnj 		pf = PF_GENERIC;
71*4786Swnj 		proto = 0;
72*4786Swnj 	} else {
73*4786Swnj 		pf = iap->ia_pf;
74*4786Swnj 		proto = iap->ia_proto;
75*4786Swnj 	}
76*4786Swnj 	if (proto) {
77*4786Swnj 		/*
78*4786Swnj 		 * A specific protocol was requested.  Look
79*4786Swnj 		 * for the protocol.  If not found, then we
80*4786Swnj 		 * don't support it.
81*4786Swnj 		 */
82*4786Swnj 		prp = pf_findproto(pf, proto);
83*4786Swnj 		if (prp == 0)
84*4786Swnj 			return (EPROTONOTSUPP);
85*4786Swnj 	} else {
86*4786Swnj 		/*
87*4786Swnj 		 * No specific protocol was requested.  Look
88*4786Swnj 		 * in the specified (or generic) protocol set
89*4786Swnj 		 * for a protocol of this type.
90*4786Swnj 		 */
91*4786Swnj 		prp = pf_findtype(pf, type);
92*4786Swnj 		if (prp == 0)
93*4786Swnj 			return (ESOCKTYPENOTSUPP);
94*4786Swnj 	}
95*4786Swnj 
96*4786Swnj 	/*
97*4786Swnj 	 * Get a socket structure.
98*4786Swnj 	 */
99*4786Swnj 	m = m_get(M_WAIT);
100*4786Swnj 	if (m == 0)
101*4786Swnj 		return (ENOBUFS);
102*4786Swnj 	m->m_off = MMINOFF;
103*4786Swnj 	so = mtod(m, struct socket *);
104*4786Swnj 	*so = zerosocket;
105*4786Swnj 	so->so_flags = flags;
106*4786Swnj 
107*4786Swnj 	/*
108*4786Swnj 	 * An early call to protocol initialization.  If protocol
109*4786Swnj 	 * actually hasn't been decided on yet (till we know
110*4786Swnj 	 * peer), then the generic protocol allocated so far can
111*4786Swnj 	 * just make sure a reasonable amount of resources will
112*4786Swnj 	 * be available to it (say by allocating liberally now
113*4786Swnj 	 * and returning some of the resources later).
114*4786Swnj 	 */
115*4786Swnj 	so->so_proto = prp;
116*4786Swnj 	(*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0);
117*4786Swnj 	if (so->so_error) {
118*4786Swnj 		m_free(dtom(so));
119*4786Swnj 		return (u.u_error);
120*4786Swnj 	}
121*4786Swnj 	*aso = so;
122*4786Swnj 	return (0);
123*4786Swnj }
124*4786Swnj 
125*4786Swnj /*
126*4786Swnj  * Connect socket to foreign peer; system call
127*4786Swnj  * interface.  Copy in arguments and call internal routine.
128*4786Swnj  */
129*4786Swnj sconnect()
130*4786Swnj {
131*4786Swnj 	register struct a {
132*4786Swnj 		int fdes;
133*4786Swnj 		in_addr *a;
134*4786Swnj 	} *uap = (struct a *)u.u_ap;
135*4786Swnj 	in_addr in;
136*4786Swnj 
137*4786Swnj 	if (copyin((caddr_t)uap->aaddr, &in, sizeof (in))) {
138*4786Swnj 		u.u_error = EFAULT;
139*4786Swnj 		return;
140*4786Swnj 	}
141*4786Swnj 	fp = getf(uap->fdes);
142*4786Swnj 	if (fp == 0)
143*4786Swnj 		return;
144*4786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
145*4786Swnj 		u.u_error = ENOTSOCK;
146*4786Swnj 		return;
147*4786Swnj 	}
148*4786Swnj 	u.u_error = connect(fp->f_socket, &in);
149*4786Swnj 	if (u.u_error)
150*4786Swnj 		return;
151*4786Swnj 	s = splnet();
152*4786Swnj 	for (;;) {
153*4786Swnj 		/* should use tsleep here */
154*4786Swnj 		if ((*so->so_proto->pr_usrreq)(so, PRU_ISCONN, 0, &in) == 0)
155*4786Swnj 			break;
156*4786Swnj 		sleep((caddr_t)&so->so_timeo, PZERO+1);
157*4786Swnj 	}
158*4786Swnj 	splx(s);
159*4786Swnj }
160*4786Swnj 
161*4786Swnj connect(so, iap)
162*4786Swnj 	struct socket *so;
163*4786Swnj 	struct in_addr *iap;
164*4786Swnj {
165*4786Swnj 
166*4786Swnj 	return ((*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, &in));
167*4786Swnj }
168*4786Swnj 
169*4786Swnj /*
170*4786Swnj  * Disconnect socket from foreign peer; system call
171*4786Swnj  * interface.  Copy in arguments and call internal routine.
172*4786Swnj  */
173*4786Swnj sdisconnect()
174*4786Swnj {
175*4786Swnj 	register struct a {
176*4786Swnj 		int fdes;
177*4786Swnj 		in_addr *a;
178*4786Swnj 	} *uap = (struct a *)u.u_ap;
179*4786Swnj 	in_addr in;
180*4786Swnj 
181*4786Swnj 	if (uap->a && copyin((caddr_t)uap->aaddr, &in, sizeof (in))) {
182*4786Swnj 		u.u_error = EFAULT;
183*4786Swnj 		return;
184*4786Swnj 	}
185*4786Swnj 	fp = getf(uap->fdes);
186*4786Swnj 	if (fp == 0)
187*4786Swnj 		return;
188*4786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
189*4786Swnj 		u.u_error = ENOTSOCK;
190*4786Swnj 		return;
191*4786Swnj 	}
192*4786Swnj 	disconnect(fp->f_socket, uap->a ? &in : 0);
193*4786Swnj }
194*4786Swnj 
195*4786Swnj disconnect(so, iap)
196*4786Swnj 	struct socket *so;
197*4786Swnj 	struct in_addr *iap;
198*4786Swnj {
199*4786Swnj 
200*4786Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, &in);
201*4786Swnj }
202*4786Swnj 
203*4786Swnj /*
204*4786Swnj  * Send data on socket.
205*4786Swnj  */
206*4786Swnj ssend()
207*4786Swnj {
208*4786Swnj 	register struct a {
209*4786Swnj 		int fdes;
210*4786Swnj 		in_addr *ain;
211*4786Swnj 		caddr_t cbuf;
212*4786Swnj 		int count;
213*4786Swnj 	} *uap = (struct a *)u.u_ap;
214*4786Swnj 
215*4786Swnj 	fp = getf(uap->fdes);
216*4786Swnj 	if (fp == 0)
217*4786Swnj 		return;
218*4786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
219*4786Swnj 		u.u_error = ENOTSOCK;
220*4786Swnj 		return;
221*4786Swnj 	}
222*4786Swnj 	if (uap->count < 0) {
223*4786Swnj 		u.u_error = EINVAL;
224*4786Swnj 		return;
225*4786Swnj 	}
226*4786Swnj 	u.u_base = uap->buf;
227*4786Swnj 	u.u_count = uap->len;
228*4786Swnj 	u.u_segflg = 0;
229*4786Swnj 	if (useracc(u.u_base, u.u_count, B_READ) == 0 ||
230*4786Swnj 	    uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) {
231*4786Swnj 		u.u_error = EFAULT;
232*4786Swnj 		return;
233*4786Swnj 	}
234*4786Swnj 	u.u_error = send(fp->f_socket, uap->ain ? &in : 0);
235*4786Swnj }
236*4786Swnj 
237*4786Swnj send(so, iap)
238*4786Swnj 	register struct socket *so;
239*4786Swnj 	struct in_addr *iap;
240*4786Swnj {
241*4786Swnj 	register struct mbuf *m, **mp;
242*4786Swnj 	struct mbuf *top;
243*4786Swnj 	int error = 0;
244*4786Swnj 
245*4786Swnj 	if (so->so_proto->pr_flags & PR_ATOMIC) {
246*4786Swnj 		if (u.u_count > so->so_snd.sb_hiwat) {
247*4786Swnj 			error = EMSGSIZE;
248*4786Swnj 			goto release;
249*4786Swnj 		}
250*4786Swnj 	}
251*4786Swnj again:
252*4786Swnj 	while (so->so_snd.sb_flags & SB_LOCK) {
253*4786Swnj 		so->so_snd.sb_flags |= SB_WANT;
254*4786Swnj 		sleep((caddr_t)&so->so_snd.sb_flags, PZERO+1);
255*4786Swnj 	}
256*4786Swnj 	if (so->so_snd.sb_hiwat - so->so_snd.sb_cc < u.u_count) {
257*4786Swnj 		so->so_snd.sb_flags |= SB_WAIT;
258*4786Swnj 		sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1);
259*4786Swnj 		goto again;
260*4786Swnj 	}
261*4786Swnj 	so->so_snd.sb_flags |= SB_LOCK;
262*4786Swnj 	while (u.u_count > 0) {
263*4786Swnj 		bufs = so->so_snd.sb_mbmax - so->so_snd.sb_mbcnt;
264*4786Swnj 		while (bufs == 0) {
265*4786Swnj 			so->so_snd.sb_flags |= SB_WAIT;
266*4786Swnj 			sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1);
267*4786Swnj 		}
268*4786Swnj 		mp = &top;
269*4786Swnj 		top = 0;
270*4786Swnj 		while (--bufs >= 0 && u.u_count > 0) {
271*4786Swnj 			MGET(m, 1);
272*4786Swnj 			if (m == NULL) {
273*4786Swnj 				error = ENOBUFS;
274*4786Swnj 				m_freem(top);
275*4786Swnj 				goto release;
276*4786Swnj 			}
277*4786Swnj 			if (u.u_count >= PGSIZE && bufs >= NMBPG) {
278*4786Swnj 				MPGET(p, 1);
279*4786Swnj 				if (p == 0)
280*4786Swnj 					goto nopage;
281*4786Swnj 				m->m_off = (int)p - (int)m;
282*4786Swnj 				len = PGSIZE;
283*4786Swnj 			} else {
284*4786Swnj nopages:
285*4786Swnj 				m->m_off = MMINOFF;
286*4786Swnj 				len = MIN(MLEN, u.u_count);
287*4786Swnj 			}
288*4786Swnj 			iomove(mtod(m, caddr_t), len, B_WRITE);
289*4786Swnj 			m->m_len = len;
290*4786Swnj 			*mp = m;
291*4786Swnj 			mp = &m->m_next;
292*4786Swnj 		}
293*4786Swnj 		s = splnet();
294*4786Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap);
295*4786Swnj 		splx(s);
296*4786Swnj 		if (error)
297*4786Swnj 			break;
298*4786Swnj 	}
299*4786Swnj release:
300*4786Swnj 	so->so_snd.sb_flags &= ~SB_LOCK;
301*4786Swnj 	if (so->so_snd.sb_flags & SB_WANT)
302*4786Swnj 		wakeup((caddr_t)&so->so_sb.sb_flags);
303*4786Swnj 	return (error);
304*4786Swnj }
305*4786Swnj 
306*4786Swnj /*
307*4786Swnj  * Receive data on socket.
308*4786Swnj  */
309*4786Swnj sreceive()
310*4786Swnj {
311*4786Swnj 	register struct a {
312*4786Swnj 		int fdes;
313*4786Swnj 		in_addr *ain;
314*4786Swnj 		caddr_t cbuf;
315*4786Swnj 		int count;
316*4786Swnj 	} *uap = (struct a *)u.u_ap;
317*4786Swnj 
318*4786Swnj 	fp = getf(uap->fdes);
319*4786Swnj 	if (fp == 0)
320*4786Swnj 		return;
321*4786Swnj 	if ((fp->f_flag & FSOCKET) == 0) {
322*4786Swnj 		u.u_error = ENOTSOCK;
323*4786Swnj 		return;
324*4786Swnj 	}
325*4786Swnj 	if (uap->count < 0) {
326*4786Swnj 		u.u_error = EINVAL;
327*4786Swnj 		return;
328*4786Swnj 	}
329*4786Swnj 	u.u_base = uap->buf;
330*4786Swnj 	u.u_count = uap->len;
331*4786Swnj 	u.u_segflg = 0;
332*4786Swnj 	if (useracc(u.u_base, u.u_count, B_WRITE) == 0 ||
333*4786Swnj 	    uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) {
334*4786Swnj 		u.u_error = EFAULT;
335*4786Swnj 		return;
336*4786Swnj 	}
337*4786Swnj 	receive(fp->f_socket, uap->ain ? &in : 0);
338*4786Swnj }
339*4786Swnj 
340*4786Swnj receive(so, iap)
341*4786Swnj 	register struct socket *so;
342*4786Swnj 	struct in_addr *iap;
343*4786Swnj {
344*4786Swnj 	register struct mbuf *m, *n;
345*4786Swnj 	register int eor, len, s;
346*4786Swnj 
347*4786Swnj again:
348*4786Swnj 	while (so->so_rcv.sb_flags & SB_LOCK) {
349*4786Swnj 		so->so_rcv.sb_flags |= SB_WANT;
350*4786Swnj 		sleep((caddr_t)&so->so_rcv.sb_flags, PZERO+1);
351*4786Swnj 	}
352*4786Swnj 	if (so->so_rcv.sb_cc == 0) {
353*4786Swnj 		if ((so->so_proto->pr_usrreq)(so, PR_ISDISCONN, 0, 0) == 0)
354*4786Swnj 			return;
355*4786Swnj 		so->so_rcv.sb_flags |= SB_WAIT;
356*4786Swnj 		sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1);
357*4786Swnj 		goto again;
358*4786Swnj 	}
359*4786Swnj 	so->so_rcv.sb_flags |= SB_LOCK;
360*4786Swnj 	m = up->uc_rcv.sb_mb;
361*4786Swnj 	if (m == 0)
362*4786Swnj 		panic("receive");
363*4786Swnj 	eor = 0;
364*4786Swnj 	do {
365*4786Swnj 		len = MIN(m->m_len, u.u_count);
366*4786Swnj 		if (len == m->m_len) {
367*4786Swnj 			eor = (int)m->m_act;
368*4786Swnj 			up->uc_rcv.sb_mb = m->m_next;
369*4786Swnj 			up->uc_rcv.sb_cc -= len;
370*4786Swnj 			if (up->uc_rcv.sb_cc < 0)
371*4786Swnj 				panic("receive 2");
372*4786Swnj 		}
373*4786Swnj 		splx(s);
374*4786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
375*4786Swnj 		s = splnet();
376*4786Swnj 		if (len == m->m_len) {
377*4786Swnj 			MFREE(m, n);
378*4786Swnj 		} else {
379*4786Swnj 			m->m_off += len;
380*4786Swnj 			m->m_len -= len;
381*4786Swnj 			up->uc_rcv.sb_cc -= len;
382*4786Swnj 			if (up->uc_rcv.sb_cc < 0)
383*4786Swnj 				panic("receive 3");
384*4786Swnj 		}
385*4786Swnj 	} while ((m = up->uc_rcv.sb_mb) && u.u_count && !eor);
386*4786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
387*4786Swnj 		do {
388*4786Swnj 			m = so->so_rcv.sb_mb;
389*4786Swnj 			if (m == 0)
390*4786Swnj 				panic("receive 4");
391*4786Swnj 			up->uc_rcv.sb_cc -= m->m_len;
392*4786Swnj 			if (up->uc_rcv.sb_cc < 0)
393*4786Swnj 				panic("receive 5");
394*4786Swnj 			eor = (int)m->m_act;
395*4786Swnj 			so->so_rcv.sb_mb = m->m_next;
396*4786Swnj 			MFREE(m, n);
397*4786Swnj 		} while (eor == 0);
398*4786Swnj 	if (iap)
399*4786Swnj 		if ((so->so_proto->pr_flags & PR_PROVIDEADDR)) {
400*4786Swnj 			m = up->uc_rcv.sb_mb;
401*4786Swnj 			if (m == 0)
402*4786Swnj 				panic("receive 6");
403*4786Swnj 			up->uc_rcv.sb_mb = m->m_next;
404*4786Swnj 			up->uc_rcv.sb_cc -= m->m_len;
405*4786Swnj 			len = MIN(m->m_len, sizeof (struct in_addr));
406*4786Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)iap, len);
407*4786Swnj 		} else
408*4786Swnj 			*iap = zeroin_addr;
409*4786Swnj 	(*so->so_proto->pr_usrreq)(up, PRU_RCVD, m, 0);
410*4786Swnj }
411*4786Swnj 
412*4786Swnj skioctl()
413*4786Swnj {
414*4786Swnj 
415*4786Swnj 	/* switch out based on socket type */
416*4786Swnj }
417