xref: /csrg-svn/sys/kern/uipc_socket.c (revision 8300)
1 /*	uipc_socket.c	4.50	82/10/03	*/
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)
258 	register struct socket *so;
259 	struct mbuf *nam;
260 	struct uio *uio;
261 {
262 	struct mbuf *top = 0;
263 	register struct mbuf *m, **mp = &top;
264 	register u_int len;
265 	int error = 0, space, s;
266 
267 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
268 		return (EMSGSIZE);
269 #ifdef notdef
270 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
271 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
272 		return (EWOULDBLOCK);
273 #endif
274 restart:
275 	sblock(&so->so_snd);
276 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
277 
278 	u.u_ru.ru_msgsnd++;
279 again:
280 	s = splnet();
281 	if (so->so_state & SS_CANTSENDMORE) {
282 		psignal(u.u_procp, SIGPIPE);
283 		snderr(EPIPE);
284 	}
285 	if (so->so_error) {
286 		error = so->so_error;
287 		so->so_error = 0;				/* ??? */
288 		splx(s);
289 		goto release;
290 	}
291 	if ((so->so_state & SS_ISCONNECTED) == 0) {
292 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
293 			snderr(ENOTCONN);
294 		if (nam == 0)
295 			snderr(EDESTADDRREQ);
296 	}
297 	if (top) {
298 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND,
299 		    top, (caddr_t)nam, (struct socketopt *)0);
300 		top = 0;
301 		if (error) {
302 			splx(s);
303 			goto release;
304 		}
305 		mp = &top;
306 	}
307 	if (uio->uio_resid == 0) {
308 		splx(s);
309 		goto release;
310 	}
311 	space = sbspace(&so->so_snd);
312 	if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) {
313 		if (so->so_state & SS_NBIO)
314 			snderr(EWOULDBLOCK);
315 		sbunlock(&so->so_snd);
316 		sbwait(&so->so_snd);
317 		splx(s);
318 		goto restart;
319 	}
320 	splx(s);
321 	while (uio->uio_resid > 0 && space > 0) {
322 		register struct iovec *iov = uio->uio_iov;
323 
324 		if (iov->iov_len == 0) {
325 			uio->uio_iov++;
326 			uio->uio_iovcnt--;
327 			if (uio->uio_iovcnt < 0)
328 				panic("sosend");
329 			continue;
330 		}
331 		MGET(m, 1);
332 		if (m == NULL) {
333 			error = ENOBUFS;			/* SIGPIPE? */
334 			goto release;
335 		}
336 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
337 			register struct mbuf *p;
338 			MCLGET(p, 1);
339 			if (p == 0)
340 				goto nopages;
341 			m->m_off = (int)p - (int)m;
342 			len = CLBYTES;
343 		} else {
344 nopages:
345 			m->m_off = MMINOFF;
346 			len = MIN(MLEN, iov->iov_len);
347 		}
348 		uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
349 		m->m_len = len;
350 		*mp = m;
351 		mp = &m->m_next;
352 		space = sbspace(&so->so_snd);
353 	}
354 	goto again;
355 
356 release:
357 	sbunlock(&so->so_snd);
358 	if (top)
359 		m_freem(top);
360 	return (error);
361 }
362 
363 soreceive(so, aname, uio)
364 	register struct socket *so;
365 	struct mbuf **aname;
366 	struct uio *uio;
367 {
368 	register struct iovec *iov;
369 	register struct mbuf *m, *n;
370 	u_int len;
371 	int eor, s, error = 0;
372 
373 restart:
374 	sblock(&so->so_rcv);
375 	s = splnet();
376 
377 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
378 	if (so->so_rcv.sb_cc == 0) {
379 		if (so->so_error) {
380 			error = so->so_error;
381 			so->so_error = 0;
382 			splx(s);
383 			goto release;
384 		}
385 		if (so->so_state & SS_CANTRCVMORE) {
386 			splx(s);
387 			goto release;
388 		}
389 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
390 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
391 			rcverr(ENOTCONN);
392 		if (so->so_state & SS_NBIO)
393 			rcverr(EWOULDBLOCK);
394 		sbunlock(&so->so_rcv);
395 		sbwait(&so->so_rcv);
396 		splx(s);
397 		goto restart;
398 	}
399 	u.u_ru.ru_msgrcv++;
400 	m = so->so_rcv.sb_mb;
401 	if (m == 0)
402 		panic("receive");
403 	if (so->so_proto->pr_flags & PR_ADDR) {
404 		so->so_rcv.sb_cc -= m->m_len;
405 		so->so_rcv.sb_mbcnt -= MSIZE;
406 		if (aname) {
407 			*aname = m;
408 			m = m->m_next;
409 			(*aname)->m_next = 0;
410 		} else
411 			m = m_free(m);
412 		if (m == 0)
413 			panic("receive 2");
414 		so->so_rcv.sb_mb = m;
415 	}
416 	eor = 0;
417 	do {
418 		if (uio->uio_resid <= 0)
419 			break;
420 		len = uio->uio_resid;
421 		so->so_state &= ~SS_RCVATMARK;
422 		if (so->so_oobmark && len > so->so_oobmark)
423 			len = so->so_oobmark;
424 		if (len > m->m_len)
425 			len = m->m_len;
426 		splx(s);
427 		uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
428 		s = splnet();
429 		if (len == m->m_len) {
430 			eor = (int)m->m_act;
431 			sbfree(&so->so_rcv, m);
432 			so->so_rcv.sb_mb = m->m_next;
433 			MFREE(m, n);
434 		} else {
435 			m->m_off += len;
436 			m->m_len -= len;
437 			so->so_rcv.sb_cc -= len;
438 		}
439 		if (so->so_oobmark) {
440 			so->so_oobmark -= len;
441 			if (so->so_oobmark == 0) {
442 				so->so_state |= SS_RCVATMARK;
443 				break;
444 			}
445 		}
446 	} while ((m = so->so_rcv.sb_mb) && !eor);
447 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
448 		do {
449 			if (m == 0)
450 				panic("receive 3");
451 			sbfree(&so->so_rcv, m);
452 			eor = (int)m->m_act;
453 			so->so_rcv.sb_mb = m->m_next;
454 			MFREE(m, n);
455 			m = n;
456 		} while (eor == 0);
457 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
458 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
459 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
460 release:
461 	sbunlock(&so->so_rcv);
462 	splx(s);
463 	return (error);
464 }
465 
466 sohasoutofband(so)
467 	struct socket *so;
468 {
469 
470 	if (so->so_pgrp == 0)
471 		return;
472 	if (so->so_pgrp > 0)
473 		gsignal(so->so_pgrp, SIGURG);
474 	else {
475 		struct proc *p = pfind(-so->so_pgrp);
476 
477 		if (p)
478 			psignal(p, SIGURG);
479 	}
480 }
481 
482 /*ARGSUSED*/
483 soioctl(so, cmd, data)
484 	register struct socket *so;
485 	int cmd;
486 	register char *data;
487 {
488 
489 	switch (cmd) {
490 
491 	case FIONBIO:
492 		if (*(int *)data)
493 			so->so_state |= SS_NBIO;
494 		else
495 			so->so_state &= ~SS_NBIO;
496 		return;
497 
498 	case FIOASYNC:
499 		if (*(int *)data)
500 			so->so_state |= SS_ASYNC;
501 		else
502 			so->so_state &= ~SS_ASYNC;
503 		return;
504 
505 	case SIOCSKEEP:
506 		if (*(int *)data)
507 			so->so_options &= ~SO_KEEPALIVE;
508 		else
509 			so->so_options |= SO_KEEPALIVE;
510 		return;
511 
512 	case SIOCGKEEP:
513 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
514 		return;
515 
516 	case SIOCSLINGER:
517 		so->so_linger = *(int *)data;
518 		if (so->so_linger)
519 			so->so_options &= ~SO_DONTLINGER;
520 		else
521 			so->so_options |= SO_DONTLINGER;
522 		return;
523 
524 	case SIOCGLINGER:
525 		*(int *)data = so->so_linger;
526 		return;
527 
528 	case SIOCSPGRP:
529 		so->so_pgrp = *(int *)data;
530 		return;
531 
532 	case SIOCGPGRP:
533 		*(int *)data = so->so_pgrp;
534 		return;
535 
536 	case SIOCDONE: {
537 		int flags = *(int *)data;
538 
539 		flags++;
540 		if (flags & FREAD) {
541 			int s = splimp();
542 			socantrcvmore(so);
543 			sbflush(&so->so_rcv);
544 			splx(s);
545 		}
546 		if (flags & FWRITE)
547 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
548 			    (struct mbuf *)0, (struct mbuf *)0,
549 			    (struct socketopt *)0);
550 		return;
551 	}
552 
553 	case SIOCSENDOOB: {
554 		char oob = *(char *)data;
555 		struct mbuf *m;
556 
557 		m = m_get(M_DONTWAIT);
558 		if (m == 0) {
559 			u.u_error = ENOBUFS;
560 			return;
561 		}
562 		m->m_off = MMINOFF;
563 		m->m_len = sizeof (char);
564 		*mtod(m, char *) = oob;
565 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB,
566 		    m, (struct mbuf *)0, (struct socketopt *)0);
567 		return;
568 	}
569 
570 	case SIOCRCVOOB: {
571 		struct mbuf *m = m_get(M_DONTWAIT);
572 
573 		if (m == 0) {
574 			u.u_error = ENOBUFS;
575 			return;
576 		}
577 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
578 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
579 		    m, (struct mbuf *)0, (struct socketopt *)0);
580 		*(char *)data = *mtod(m, char *);
581 		(void) m_free(m);
582 		return;
583 	}
584 
585 	case SIOCATMARK:
586 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
587 		return;
588 
589 	/* routing table update calls */
590 	case SIOCADDRT:
591 	case SIOCDELRT:
592 		if (!suser())
593 			return;
594 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
595 		return;
596 
597 	/* type/protocol specific ioctls */
598 	}
599 	u.u_error = EOPNOTSUPP;
600 }
601