xref: /csrg-svn/sys/kern/uipc_socket.c (revision 8319)
1 /*	uipc_socket.c	4.51	82/10/05	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/proc.h"
8 #include "../h/file.h"
9 #include "../h/inode.h"
10 #include "../h/buf.h"
11 #include "../h/mbuf.h"
12 #include "../h/protosw.h"
13 #include "../h/socket.h"
14 #include "../h/socketvar.h"
15 #include "../h/stat.h"
16 #include "../h/ioctl.h"
17 #include "../net/in.h"
18 #include "../net/in_systm.h"
19 #include "../net/route.h"
20 #include "../h/uio.h"
21 
22 /*
23  * Socket operation routines.
24  * These routines are called by the routines in
25  * sys_socket.c or from a system process, and
26  * implement the semantics of socket operations by
27  * switching out to the protocol specific routines.
28  */
29 
30 socreate(dom, aso, type, proto, opt)
31 	struct socket **aso;
32 	int type, proto;
33 	struct socketopt *opt;
34 {
35 	register struct protosw *prp;
36 	register struct socket *so;
37 	struct mbuf *m;
38 	int pf, error;
39 
40 	pf = dom ? PF_UNIX : PF_INET;		/* should be u.u_protof */
41 	if (proto)
42 		prp = pffindproto(pf, proto);
43 	else
44 		prp = pffindtype(pf, type);
45 	if (prp == 0)
46 		return (EPROTONOSUPPORT);
47 	if (prp->pr_type != type)
48 		return (EPROTOTYPE);
49 	m = m_getclr(M_WAIT);
50 	if (m == 0)
51 		return (ENOBUFS);
52 	so = mtod(m, struct socket *);
53 	so->so_options = 0;
54 	so->so_state = 0;
55 	if (u.u_uid == 0)
56 		so->so_state = SS_PRIV;
57 	so->so_proto = prp;
58 	error = (*prp->pr_usrreq)(so, PRU_ATTACH,
59 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
60 	if (error) {
61 		so->so_state |= SS_NOFDREF;
62 		sofree(so);
63 		return (error);
64 	}
65 	*aso = so;
66 	return (0);
67 }
68 
69 sobind(so, nam, opt)
70 	struct socket *so;
71 	struct mbuf *nam;
72 	struct socketopt *opt;
73 {
74 	int s = splnet();
75 	int error;
76 
77 	error =
78 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
79 		(struct mbuf *)0, nam, opt);
80 	splx(s);
81 	return (error);
82 }
83 
84 solisten(so, backlog)
85 	struct socket *so;
86 	int backlog;
87 {
88 	int s = splnet();
89 	int error;
90 
91 	error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
92 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
93 	if (error) {
94 		splx(s);
95 		return (error);
96 	}
97 	if (so->so_q == 0) {
98 		so->so_q = so;
99 		so->so_q0 = so;
100 		so->so_options |= SO_ACCEPTCONN;
101 	}
102 	if (backlog < 0)
103 		backlog = 0;
104 	so->so_qlimit = backlog < 5 ? backlog : 5;
105 	so->so_options |= SO_NEWFDONCONN;
106 	return (0);
107 }
108 
109 sofree(so)
110 	struct socket *so;
111 {
112 
113 	if (so->so_head) {
114 		if (!soqremque(so, 0) && !soqremque(so, 1))
115 			panic("sofree dq");
116 		so->so_head = 0;
117 	}
118 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
119 		return;
120 	sbrelease(&so->so_snd);
121 	sbrelease(&so->so_rcv);
122 	(void) m_free(dtom(so));
123 }
124 
125 /*
126  * Close a socket on last file table reference removal.
127  * Initiate disconnect if connected.
128  * Free socket when disconnect complete.
129  */
130 soclose(so, exiting)
131 	register struct socket *so;
132 	int exiting;
133 {
134 	int s = splnet();		/* conservative */
135 
136 	if (so->so_options & SO_ACCEPTCONN) {
137 		while (so->so_q0 != so)
138 			soclose(so->so_q0, 1);
139 		while (so->so_q != so)
140 			soclose(so->so_q, 1);
141 	}
142 	if (so->so_pcb == 0)
143 		goto discard;
144 	if (exiting)
145 		so->so_options |= SO_KEEPALIVE;
146 	if (so->so_state & SS_ISCONNECTED) {
147 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
148 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
149 			if (u.u_error) {
150 				if (exiting)
151 					goto drop;
152 				splx(s);
153 				return;
154 			}
155 		}
156 		if ((so->so_options & SO_DONTLINGER) == 0) {
157 			if ((so->so_state & SS_ISDISCONNECTING) &&
158 			    (so->so_state & SS_NBIO) &&
159 			    exiting == 0) {
160 				u.u_error = EINPROGRESS;
161 				splx(s);
162 				return;
163 			}
164 			/* should use tsleep here, for at most linger */
165 			while (so->so_state & SS_ISCONNECTED)
166 				sleep((caddr_t)&so->so_timeo, PZERO+1);
167 		}
168 	}
169 drop:
170 	if (so->so_pcb) {
171 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
172 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
173 		if (exiting == 0 && u.u_error) {
174 			splx(s);
175 			return;
176 		}
177 	}
178 discard:
179 	so->so_state |= SS_NOFDREF;
180 	sofree(so);
181 	splx(s);
182 }
183 
184 /*ARGSUSED*/
185 sostat(so, sb)
186 	struct socket *so;
187 	struct stat *sb;
188 {
189 
190 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
191 	return (0);					/* XXX */
192 }
193 
194 soaccept(so, nam, opt)
195 	struct socket *so;
196 	struct mbuf *nam;
197 	struct socketopt *opt;
198 {
199 	int s = splnet();
200 	int error;
201 
202 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
203 	    (struct mbuf *)0, nam, opt);
204 	splx(s);
205 	return (error);
206 }
207 
208 soconnect(so, nam, opt)
209 	struct socket *so;
210 	struct mbuf *nam;
211 	struct socketopt *opt;
212 {
213 	int s = splnet();
214 	int error;
215 
216 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
217 		error = EISCONN;
218 		goto bad;
219 	}
220 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
221 	    (struct mbuf *)0, nam, opt);
222 bad:
223 	splx(s);
224 	return (error);
225 }
226 
227 sodisconnect(so, nam)
228 	struct socket *so;
229 	struct mbuf *nam;
230 {
231 	int s = splnet();
232 	int error;
233 
234 	if ((so->so_state & SS_ISCONNECTED) == 0) {
235 		error = ENOTCONN;
236 		goto bad;
237 	}
238 	if (so->so_state & SS_ISDISCONNECTING) {
239 		error = EALREADY;
240 		goto bad;
241 	}
242 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
243 	    (struct mbuf *)0, nam, (struct socketopt *)0);
244 bad:
245 	splx(s);
246 	return (error);
247 }
248 
249 /*
250  * Send on a socket.
251  * If send must go all at once and message is larger than
252  * send buffering, then hard error.
253  * Lock against other senders.
254  * If must go all at once and not enough room now, then
255  * inform user that this would block and do nothing.
256  */
257 sosend(so, nam, uio, flags)
258 	register struct socket *so;
259 	struct mbuf *nam;
260 	struct uio *uio;
261 	int flags;
262 {
263 	struct mbuf *top = 0;
264 	register struct mbuf *m, **mp = &top;
265 	register u_int len;
266 	int error = 0, space, s;
267 
268 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
269 		return (EMSGSIZE);
270 restart:
271 	sblock(&so->so_snd);
272 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
273 
274 	u.u_ru.ru_msgsnd++;
275 again:
276 	s = splnet();
277 	if (so->so_state & SS_CANTSENDMORE) {
278 		psignal(u.u_procp, SIGPIPE);
279 		snderr(EPIPE);
280 	}
281 	if (so->so_error) {
282 		error = so->so_error;
283 		so->so_error = 0;				/* ??? */
284 		splx(s);
285 		goto release;
286 	}
287 	if ((so->so_state & SS_ISCONNECTED) == 0) {
288 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
289 			snderr(ENOTCONN);
290 		if (nam == 0)
291 			snderr(EDESTADDRREQ);
292 	}
293 	if (top) {
294 		error = (*so->so_proto->pr_usrreq)(so,
295 		    (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
296 		    top, (caddr_t)nam, (struct socketopt *)0);
297 		top = 0;
298 		if (error) {
299 			splx(s);
300 			goto release;
301 		}
302 		mp = &top;
303 	}
304 	if (uio->uio_resid == 0) {
305 		splx(s);
306 		goto release;
307 	}
308 	if (flags & SOF_OOB)
309 		space = 1024;
310 	else {
311 		space = sbspace(&so->so_snd);
312 		if (space <= 0 ||
313 		    sosendallatonce(so) && space < uio->uio_resid) {
314 			if (so->so_state & SS_NBIO)
315 				snderr(EWOULDBLOCK);
316 			sbunlock(&so->so_snd);
317 			sbwait(&so->so_snd);
318 			splx(s);
319 			goto restart;
320 		}
321 	}
322 	splx(s);
323 	while (uio->uio_resid > 0 && space > 0) {
324 		register struct iovec *iov = uio->uio_iov;
325 
326 		if (iov->iov_len == 0) {
327 			uio->uio_iov++;
328 			uio->uio_iovcnt--;
329 			if (uio->uio_iovcnt < 0)
330 				panic("sosend");
331 			continue;
332 		}
333 		MGET(m, 1);
334 		if (m == NULL) {
335 			error = ENOBUFS;			/* SIGPIPE? */
336 			goto release;
337 		}
338 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
339 			register struct mbuf *p;
340 			MCLGET(p, 1);
341 			if (p == 0)
342 				goto nopages;
343 			m->m_off = (int)p - (int)m;
344 			len = CLBYTES;
345 		} else {
346 nopages:
347 			len = MIN(MLEN, iov->iov_len);
348 		}
349 		uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
350 		m->m_len = len;
351 		*mp = m;
352 		mp = &m->m_next;
353 		if (flags & SOF_OOB)
354 			space -= len;
355 		else
356 			space = sbspace(&so->so_snd);
357 	}
358 	goto again;
359 
360 release:
361 	sbunlock(&so->so_snd);
362 	if (top)
363 		m_freem(top);
364 	return (error);
365 }
366 
367 soreceive(so, aname, uio, flags)
368 	register struct socket *so;
369 	struct mbuf **aname;
370 	struct uio *uio;
371 	int flags;
372 {
373 	register struct iovec *iov;
374 	register struct mbuf *m, *n;
375 	u_int len;
376 	int eor, s, error = 0, moff, tomark;
377 
378 	if (flags & SOF_OOB) {
379 		struct mbuf *m = m_get(M_WAIT);
380 
381 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
382 		    m, (struct mbuf *)0, (struct socketopt *)0);
383 		len = uio->uio_resid;
384 		do {
385 			if (len > m->m_len)
386 				len = m->m_len;
387 			uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
388 			m = m_free(m);
389 		} while (uio->uio_resid && u.u_error == 0 && m);
390 		if (m)
391 			(void) m_freem(m);
392 		return;
393 	}
394 
395 restart:
396 	sblock(&so->so_rcv);
397 	s = splnet();
398 
399 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
400 	if (so->so_rcv.sb_cc == 0) {
401 		if (so->so_error) {
402 			error = so->so_error;
403 			so->so_error = 0;
404 			splx(s);
405 			goto release;
406 		}
407 		if (so->so_state & SS_CANTRCVMORE) {
408 			splx(s);
409 			goto release;
410 		}
411 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
412 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
413 			rcverr(ENOTCONN);
414 		if (so->so_state & SS_NBIO)
415 			rcverr(EWOULDBLOCK);
416 		sbunlock(&so->so_rcv);
417 		sbwait(&so->so_rcv);
418 		splx(s);
419 		goto restart;
420 	}
421 	u.u_ru.ru_msgrcv++;
422 	m = so->so_rcv.sb_mb;
423 	if (m == 0)
424 		panic("receive");
425 	if (so->so_proto->pr_flags & PR_ADDR) {
426 		if ((flags & SOF_PREVIEW) == 0) {
427 			so->so_rcv.sb_cc -= m->m_len;
428 			so->so_rcv.sb_mbcnt -= MSIZE;
429 		}
430 		if (aname) {
431 			if (flags & SOF_PREVIEW)
432 				*aname = m_copy(m, 0, m->m_len);
433 			else
434 				*aname = m;
435 			m = m->m_next;
436 			(*aname)->m_next = 0;
437 		} else
438 			if (flags & SOF_PREVIEW)
439 				m = m->m_next;
440 			else
441 				m = m_free(m);
442 		if (m == 0)
443 			panic("receive 2");
444 	}
445 	eor = 0;
446 	moff = 0;
447 	tomark = so->so_oobmark;
448 	do {
449 		if (uio->uio_resid <= 0)
450 			break;
451 		len = uio->uio_resid;
452 		so->so_state &= ~SS_RCVATMARK;
453 		if (tomark && len > tomark)
454 			len = tomark;
455 		if (len > m->m_len - moff)
456 			len = m->m_len - moff;
457 		splx(s);
458 		uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
459 		s = splnet();
460 		if (len == m->m_len) {
461 			eor = (int)m->m_act;
462 			if (flags & SOF_PREVIEW)
463 				m = m->m_next;
464 			else {
465 				sbfree(&so->so_rcv, m);
466 				MFREE(m, n);
467 				m = n;
468 			}
469 			moff = 0;
470 		} else {
471 			if (flags & SOF_PREVIEW)
472 				moff += len;
473 			else {
474 				m->m_off += len;
475 				m->m_len -= len;
476 				so->so_rcv.sb_cc -= len;
477 			}
478 		}
479 		if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
480 			so->so_oobmark -= len;
481 			if (so->so_oobmark == 0) {
482 				so->so_state |= SS_RCVATMARK;
483 				break;
484 			}
485 		}
486 		if (tomark) {
487 			tomark -= len;
488 			if (tomark == 0)
489 				break;
490 		}
491 	} while (m && !eor);
492 	if (flags & SOF_PREVIEW)
493 		goto release;
494 	so->so_rcv.sb_mb = m;
495 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
496 		do {
497 			if (m == 0)
498 				panic("receive 3");
499 			sbfree(&so->so_rcv, m);
500 			eor = (int)m->m_act;
501 			so->so_rcv.sb_mb = m->m_next;
502 			MFREE(m, n);
503 			m = n;
504 		} while (eor == 0);
505 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
506 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
507 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
508 release:
509 	sbunlock(&so->so_rcv);
510 	splx(s);
511 	return (error);
512 }
513 
514 sohasoutofband(so)
515 	struct socket *so;
516 {
517 
518 	if (so->so_pgrp == 0)
519 		return;
520 	if (so->so_pgrp > 0)
521 		gsignal(so->so_pgrp, SIGURG);
522 	else {
523 		struct proc *p = pfind(-so->so_pgrp);
524 
525 		if (p)
526 			psignal(p, SIGURG);
527 	}
528 }
529 
530 /*ARGSUSED*/
531 soioctl(so, cmd, data)
532 	register struct socket *so;
533 	int cmd;
534 	register char *data;
535 {
536 
537 	switch (cmd) {
538 
539 	case FIONBIO:
540 		if (*(int *)data)
541 			so->so_state |= SS_NBIO;
542 		else
543 			so->so_state &= ~SS_NBIO;
544 		return;
545 
546 	case FIOASYNC:
547 		if (*(int *)data)
548 			so->so_state |= SS_ASYNC;
549 		else
550 			so->so_state &= ~SS_ASYNC;
551 		return;
552 
553 	case SIOCSKEEP:
554 		if (*(int *)data)
555 			so->so_options &= ~SO_KEEPALIVE;
556 		else
557 			so->so_options |= SO_KEEPALIVE;
558 		return;
559 
560 	case SIOCGKEEP:
561 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
562 		return;
563 
564 	case SIOCSLINGER:
565 		so->so_linger = *(int *)data;
566 		if (so->so_linger)
567 			so->so_options &= ~SO_DONTLINGER;
568 		else
569 			so->so_options |= SO_DONTLINGER;
570 		return;
571 
572 	case SIOCGLINGER:
573 		*(int *)data = so->so_linger;
574 		return;
575 
576 	case SIOCSPGRP:
577 		so->so_pgrp = *(int *)data;
578 		return;
579 
580 	case SIOCGPGRP:
581 		*(int *)data = so->so_pgrp;
582 		return;
583 
584 	case SIOCDONE: {
585 		int flags = *(int *)data;
586 
587 		flags++;
588 		if (flags & FREAD) {
589 			int s = splimp();
590 			socantrcvmore(so);
591 			sbflush(&so->so_rcv);
592 			splx(s);
593 		}
594 		if (flags & FWRITE)
595 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
596 			    (struct mbuf *)0, (struct mbuf *)0,
597 			    (struct socketopt *)0);
598 		return;
599 	}
600 
601 	case SIOCSENDOOB: {
602 		char oob = *(char *)data;
603 		struct mbuf *m = m_get(M_DONTWAIT);
604 
605 		if (m == 0) {
606 			u.u_error = ENOBUFS;
607 			return;
608 		}
609 		m->m_len = 1;
610 		*mtod(m, char *) = oob;
611 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB,
612 		    m, (struct mbuf *)0, (struct socketopt *)0);
613 		return;
614 	}
615 
616 	case SIOCRCVOOB: {
617 		struct mbuf *m = m_get(M_WAIT);
618 
619 		if (m == 0) {
620 			u.u_error = ENOBUFS;
621 			return;
622 		}
623 		*mtod(m, caddr_t) = 0;
624 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
625 		    m, (struct mbuf *)0, (struct socketopt *)0);
626 		*(char *)data = *mtod(m, char *);
627 		(void) m_free(m);
628 		return;
629 	}
630 
631 	case SIOCATMARK:
632 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
633 		return;
634 
635 	/* routing table update calls */
636 	case SIOCADDRT:
637 	case SIOCDELRT:
638 		if (!suser())
639 			return;
640 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
641 		return;
642 
643 	/* type/protocol specific ioctls */
644 	}
645 	u.u_error = EOPNOTSUPP;
646 }
647