xref: /csrg-svn/sys/kern/uipc_socket.c (revision 7827)
1 /*	uipc_socket.c	4.48	82/08/22	*/
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 support routines.
24  *
25  * DEAL WITH INTERRUPT NOTIFICATION.
26  */
27 
28 /*
29  * Create a socket.
30  */
31 socreate(aso, type, asp, asa, options)
32 	struct socket **aso;
33 	int type;
34 	struct sockproto *asp;
35 	struct sockaddr *asa;
36 	int options;
37 {
38 	register struct protosw *prp;
39 	register struct socket *so;
40 	struct mbuf *m;
41 	int pf, proto, error;
42 
43 	/*
44 	 * Use process standard protocol/protocol family if none
45 	 * specified by address argument.
46 	 */
47 	if (asp == 0) {
48 		pf = PF_INET;		/* should be u.u_protof */
49 		proto = 0;
50 	} else {
51 		pf = asp->sp_family;
52 		proto = asp->sp_protocol;
53 	}
54 
55 	/*
56 	 * If protocol specified, look for it, otherwise
57 	 * for a protocol of the correct type in the right family.
58 	 */
59 	if (proto)
60 		prp = pffindproto(pf, proto);
61 	else
62 		prp = pffindtype(pf, type);
63 	if (prp == 0)
64 		return (EPROTONOSUPPORT);
65 
66 	/*
67 	 * Get a socket structure.
68 	 */
69 	m = m_getclr(M_WAIT);
70 	if (m == 0)
71 		return (ENOBUFS);
72 	so = mtod(m, struct socket *);
73 	so->so_options = options;
74 	if (options & SO_ACCEPTCONN) {
75 		so->so_q = so;
76 		so->so_q0 = so;
77 		so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1;
78 	}
79 	so->so_state = 0;
80 	if (u.u_uid == 0)
81 		so->so_state = SS_PRIV;
82 
83 	/*
84 	 * Attach protocol to socket, initializing
85 	 * and reserving resources.
86 	 */
87 	so->so_proto = prp;
88 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
89 	if (error) {
90 		so->so_state |= SS_NOFDREF;
91 		sofree(so);
92 		return (error);
93 	}
94 	*aso = so;
95 	return (0);
96 }
97 
98 sofree(so)
99 	struct socket *so;
100 {
101 
102 	if (so->so_head) {
103 		if (!soqremque(so, 0) && !soqremque(so, 1))
104 			panic("sofree dq");
105 		so->so_head = 0;
106 	}
107 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
108 		return;
109 	sbrelease(&so->so_snd);
110 	sbrelease(&so->so_rcv);
111 	(void) m_free(dtom(so));
112 }
113 
114 /*
115  * Close a socket on last file table reference removal.
116  * Initiate disconnect if connected.
117  * Free socket when disconnect complete.
118  */
119 soclose(so, exiting)
120 	register struct socket *so;
121 	int exiting;
122 {
123 	int s = splnet();		/* conservative */
124 
125 	if (so->so_options & SO_ACCEPTCONN) {
126 		while (so->so_q0 != so)
127 			soclose(so->so_q0, 1);
128 		while (so->so_q != so)
129 			soclose(so->so_q, 1);
130 	}
131 	if (so->so_pcb == 0)
132 		goto discard;
133 	if (exiting)
134 		so->so_options |= SO_KEEPALIVE;
135 	if (so->so_state & SS_ISCONNECTED) {
136 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
137 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
138 			if (u.u_error) {
139 				if (exiting)
140 					goto drop;
141 				splx(s);
142 				return;
143 			}
144 		}
145 		if ((so->so_options & SO_DONTLINGER) == 0) {
146 			if ((so->so_state & SS_ISDISCONNECTING) &&
147 			    (so->so_state & SS_NBIO) &&
148 			    exiting == 0) {
149 				u.u_error = EINPROGRESS;
150 				splx(s);
151 				return;
152 			}
153 			/* should use tsleep here, for at most linger */
154 			while (so->so_state & SS_ISCONNECTED)
155 				sleep((caddr_t)&so->so_timeo, PZERO+1);
156 		}
157 	}
158 drop:
159 	if (so->so_pcb) {
160 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
161 		if (exiting == 0 && u.u_error) {
162 			splx(s);
163 			return;
164 		}
165 	}
166 discard:
167 	so->so_state |= SS_NOFDREF;
168 	sofree(so);
169 	splx(s);
170 }
171 
172 /*ARGSUSED*/
173 sostat(so, sb)
174 	struct socket *so;
175 	struct stat *sb;
176 {
177 
178 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
179 	return (0);					/* XXX */
180 }
181 
182 /*
183  * Accept connection on a socket.
184  */
185 soaccept(so, asa)
186 	struct socket *so;
187 	struct sockaddr *asa;
188 {
189 	int s = splnet();
190 	int error;
191 
192 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
193 	splx(s);
194 	return (error);
195 }
196 
197 /*
198  * Connect socket to a specified address.
199  * If already connected or connecting, then avoid
200  * the protocol entry, to keep its job simpler.
201  */
202 soconnect(so, asa)
203 	struct socket *so;
204 	struct sockaddr *asa;
205 {
206 	int s = splnet();
207 	int error;
208 
209 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
210 		error = EISCONN;
211 		goto bad;
212 	}
213 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
214 bad:
215 	splx(s);
216 	return (error);
217 }
218 
219 /*
220  * Disconnect from a socket.
221  * Address parameter is from system call for later multicast
222  * protocols.  Check to make sure that connected and no disconnect
223  * in progress (for protocol's sake), and then invoke protocol.
224  */
225 sodisconnect(so, asa)
226 	struct socket *so;
227 	struct sockaddr *asa;
228 {
229 	int s = splnet();
230 	int error;
231 
232 	if ((so->so_state & SS_ISCONNECTED) == 0) {
233 		error = ENOTCONN;
234 		goto bad;
235 	}
236 	if (so->so_state & SS_ISDISCONNECTING) {
237 		error = EALREADY;
238 		goto bad;
239 	}
240 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
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, asa, uio)
255 	register struct socket *so;
256 	struct sockaddr *asa;
257 	struct uio *uio;
258 {
259 	struct mbuf *top = 0;
260 	register struct mbuf *m, **mp = ⊤
261 	register u_int len;
262 	int error = 0, space, s;
263 
264 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
265 		return (EMSGSIZE);
266 #ifdef notdef
267 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
268 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
269 		return (EWOULDBLOCK);
270 #endif
271 restart:
272 	sblock(&so->so_snd);
273 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
274 
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 (asa == 0)
291 			snderr(EDESTADDRREQ);
292 	}
293 	if (top) {
294 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
295 		top = 0;
296 		if (error) {
297 			splx(s);
298 			goto release;
299 		}
300 		mp = ⊤
301 	}
302 	if (uio->uio_resid == 0) {
303 		splx(s);
304 		goto release;
305 	}
306 	space = sbspace(&so->so_snd);
307 	if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) {
308 		if (so->so_state & SS_NBIO)
309 			snderr(EWOULDBLOCK);
310 		sbunlock(&so->so_snd);
311 		sbwait(&so->so_snd);
312 		splx(s);
313 		goto restart;
314 	}
315 	splx(s);
316 	while (uio->uio_resid > 0 && space > 0) {
317 		register struct iovec *iov = uio->uio_iov;
318 
319 		if (iov->iov_len == 0) {
320 			uio->uio_iov++;
321 			uio->uio_iovcnt--;
322 			if (uio->uio_iovcnt < 0)
323 				panic("sosend");
324 			continue;
325 		}
326 		MGET(m, 1);
327 		if (m == NULL) {
328 			error = ENOBUFS;			/* SIGPIPE? */
329 			goto release;
330 		}
331 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
332 			register struct mbuf *p;
333 			MCLGET(p, 1);
334 			if (p == 0)
335 				goto nopages;
336 			m->m_off = (int)p - (int)m;
337 			len = CLBYTES;
338 		} else {
339 nopages:
340 			m->m_off = MMINOFF;
341 			len = MIN(MLEN, iov->iov_len);
342 		}
343 		uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
344 		m->m_len = len;
345 		*mp = m;
346 		mp = &m->m_next;
347 		space = sbspace(&so->so_snd);
348 	}
349 	goto again;
350 
351 release:
352 	sbunlock(&so->so_snd);
353 	if (top)
354 		m_freem(top);
355 	return (error);
356 }
357 
358 soreceive(so, asa, uio)
359 	register struct socket *so;
360 	struct sockaddr *asa;
361 	struct uio *uio;
362 {
363 	register struct iovec *iov;
364 	register struct mbuf *m, *n;
365 	u_int len;
366 	int eor, s, error = 0;
367 
368 restart:
369 	sblock(&so->so_rcv);
370 	s = splnet();
371 
372 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
373 	if (so->so_rcv.sb_cc == 0) {
374 		if (so->so_error) {
375 			error = so->so_error;
376 			so->so_error = 0;
377 			splx(s);
378 			goto release;
379 		}
380 		if (so->so_state & SS_CANTRCVMORE) {
381 			splx(s);
382 			goto release;
383 		}
384 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
385 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
386 			rcverr(ENOTCONN);
387 		if (so->so_state & SS_NBIO)
388 			rcverr(EWOULDBLOCK);
389 		sbunlock(&so->so_rcv);
390 		sbwait(&so->so_rcv);
391 		splx(s);
392 		goto restart;
393 	}
394 	m = so->so_rcv.sb_mb;
395 	if (m == 0)
396 		panic("receive");
397 	if (so->so_proto->pr_flags & PR_ADDR) {
398 		if (m->m_len != sizeof (struct sockaddr))
399 			panic("soreceive addr");
400 		if (asa)
401 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
402 		so->so_rcv.sb_cc -= m->m_len;
403 		so->so_rcv.sb_mbcnt -= MSIZE;
404 		m = m_free(m);
405 		if (m == 0)
406 			panic("receive 2");
407 		so->so_rcv.sb_mb = m;
408 	}
409 	eor = 0;
410 	do {
411 		if (uio->uio_resid <= 0)
412 			break;
413 		len = uio->uio_resid;
414 		so->so_state &= ~SS_RCVATMARK;
415 		if (so->so_oobmark && len > so->so_oobmark)
416 			len = so->so_oobmark;
417 		if (len > m->m_len)
418 			len = m->m_len;
419 		splx(s);
420 		uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
421 		s = splnet();
422 		if (len == m->m_len) {
423 			eor = (int)m->m_act;
424 			sbfree(&so->so_rcv, m);
425 			so->so_rcv.sb_mb = m->m_next;
426 			MFREE(m, n);
427 		} else {
428 			m->m_off += len;
429 			m->m_len -= len;
430 			so->so_rcv.sb_cc -= len;
431 		}
432 		if (so->so_oobmark) {
433 			so->so_oobmark -= len;
434 			if (so->so_oobmark == 0) {
435 				so->so_state |= SS_RCVATMARK;
436 				break;
437 			}
438 		}
439 	} while ((m = so->so_rcv.sb_mb) && !eor);
440 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
441 		do {
442 			if (m == 0)
443 				panic("receive 3");
444 			sbfree(&so->so_rcv, m);
445 			eor = (int)m->m_act;
446 			so->so_rcv.sb_mb = m->m_next;
447 			MFREE(m, n);
448 			m = n;
449 		} while (eor == 0);
450 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
451 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
452 release:
453 	sbunlock(&so->so_rcv);
454 	splx(s);
455 	return (error);
456 }
457 
458 sohasoutofband(so)
459 	struct socket *so;
460 {
461 
462 	if (so->so_pgrp == 0)
463 		return;
464 	if (so->so_pgrp > 0)
465 		gsignal(so->so_pgrp, SIGURG);
466 	else {
467 		struct proc *p = pfind(-so->so_pgrp);
468 
469 		if (p)
470 			psignal(p, SIGURG);
471 	}
472 }
473 
474 /*ARGSUSED*/
475 soioctl(so, cmd, data)
476 	register struct socket *so;
477 	int cmd;
478 	register char *data;
479 {
480 
481 	switch (cmd) {
482 
483 	case FIONBIO:
484 		if (*(int *)data)
485 			so->so_state |= SS_NBIO;
486 		else
487 			so->so_state &= ~SS_NBIO;
488 		return;
489 
490 	case FIOASYNC:
491 		if (*(int *)data)
492 			so->so_state |= SS_ASYNC;
493 		else
494 			so->so_state &= ~SS_ASYNC;
495 		return;
496 
497 	case SIOCSKEEP:
498 		if (*(int *)data)
499 			so->so_options &= ~SO_KEEPALIVE;
500 		else
501 			so->so_options |= SO_KEEPALIVE;
502 		return;
503 
504 	case SIOCGKEEP:
505 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
506 		return;
507 
508 	case SIOCSLINGER:
509 		so->so_linger = *(int *)data;
510 		if (so->so_linger)
511 			so->so_options &= ~SO_DONTLINGER;
512 		else
513 			so->so_options |= SO_DONTLINGER;
514 		return;
515 
516 	case SIOCGLINGER:
517 		*(int *)data = so->so_linger;
518 		return;
519 
520 	case SIOCSPGRP:
521 		so->so_pgrp = *(int *)data;
522 		return;
523 
524 	case SIOCGPGRP:
525 		*(int *)data = so->so_pgrp;
526 		return;
527 
528 	case SIOCDONE: {
529 		int flags = *(int *)data;
530 
531 		flags++;
532 		if (flags & FREAD) {
533 			int s = splimp();
534 			socantrcvmore(so);
535 			sbflush(&so->so_rcv);
536 			splx(s);
537 		}
538 		if (flags & FWRITE)
539 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
540 		return;
541 	}
542 
543 	case SIOCSENDOOB: {
544 		char oob = *(char *)data;
545 		struct mbuf *m;
546 
547 		m = m_get(M_DONTWAIT);
548 		if (m == 0) {
549 			u.u_error = ENOBUFS;
550 			return;
551 		}
552 		m->m_off = MMINOFF;
553 		m->m_len = sizeof (char);
554 		*mtod(m, char *) = oob;
555 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
556 		return;
557 	}
558 
559 	case SIOCRCVOOB: {
560 		struct mbuf *m = m_get(M_DONTWAIT);
561 
562 		if (m == 0) {
563 			u.u_error = ENOBUFS;
564 			return;
565 		}
566 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
567 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
568 		*(char *)data = *mtod(m, char *);
569 		(void) m_free(m);
570 		return;
571 	}
572 
573 	case SIOCATMARK:
574 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
575 		return;
576 
577 	/* routing table update calls */
578 	case SIOCADDRT:
579 	case SIOCDELRT:
580 		if (!suser())
581 			return;
582 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
583 		return;
584 
585 	/* type/protocol specific ioctls */
586 	}
587 	u.u_error = EOPNOTSUPP;
588 }
589