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