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