xref: /csrg-svn/sys/kern/uipc_socket.c (revision 7747)
1 /*	uipc_socket.c	4.47	82/08/14	*/
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 	register struct socket *so2;
125 
126 	if (so->so_options & SO_ACCEPTCONN) {
127 		while (so->so_q0 != so)
128 			soclose(so->so_q0, 1);
129 		while (so->so_q != so)
130 			soclose(so->so_q, 1);
131 	}
132 	if (so->so_pcb == 0)
133 		goto discard;
134 	if (exiting)
135 		so->so_options |= SO_KEEPALIVE;
136 	if (so->so_state & SS_ISCONNECTED) {
137 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
138 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
139 			if (u.u_error) {
140 				if (exiting)
141 					goto drop;
142 				splx(s);
143 				return;
144 			}
145 		}
146 		if ((so->so_options & SO_DONTLINGER) == 0) {
147 			if ((so->so_state & SS_ISDISCONNECTING) &&
148 			    (so->so_state & SS_NBIO) &&
149 			    exiting == 0) {
150 				u.u_error = EINPROGRESS;
151 				splx(s);
152 				return;
153 			}
154 			/* should use tsleep here, for at most linger */
155 			while (so->so_state & SS_ISCONNECTED)
156 				sleep((caddr_t)&so->so_timeo, PZERO+1);
157 		}
158 	}
159 drop:
160 	if (so->so_pcb) {
161 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
162 		if (exiting == 0 && u.u_error) {
163 			splx(s);
164 			return;
165 		}
166 	}
167 discard:
168 	so->so_state |= SS_NOFDREF;
169 	sofree(so);
170 	splx(s);
171 }
172 
173 /*ARGSUSED*/
174 sostat(so, sb)
175 	struct socket *so;
176 	struct stat *sb;
177 {
178 
179 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
180 	return (0);					/* XXX */
181 }
182 
183 /*
184  * Accept connection on a socket.
185  */
186 soaccept(so, asa)
187 	struct socket *so;
188 	struct sockaddr *asa;
189 {
190 	int s = splnet();
191 	int error;
192 
193 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
194 	splx(s);
195 	return (error);
196 }
197 
198 /*
199  * Connect socket to a specified address.
200  * If already connected or connecting, then avoid
201  * the protocol entry, to keep its job simpler.
202  */
203 soconnect(so, asa)
204 	struct socket *so;
205 	struct sockaddr *asa;
206 {
207 	int s = splnet();
208 	int error;
209 
210 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
211 		error = EISCONN;
212 		goto bad;
213 	}
214 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
215 bad:
216 	splx(s);
217 	return (error);
218 }
219 
220 /*
221  * Disconnect from a socket.
222  * Address parameter is from system call for later multicast
223  * protocols.  Check to make sure that connected and no disconnect
224  * in progress (for protocol's sake), and then invoke protocol.
225  */
226 sodisconnect(so, asa)
227 	struct socket *so;
228 	struct sockaddr *asa;
229 {
230 	int s = splnet();
231 	int error;
232 
233 	if ((so->so_state & SS_ISCONNECTED) == 0) {
234 		error = ENOTCONN;
235 		goto bad;
236 	}
237 	if (so->so_state & SS_ISDISCONNECTING) {
238 		error = EALREADY;
239 		goto bad;
240 	}
241 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
242 bad:
243 	splx(s);
244 	return (error);
245 }
246 
247 /*
248  * Send on a socket.
249  * If send must go all at once and message is larger than
250  * send buffering, then hard error.
251  * Lock against other senders.
252  * If must go all at once and not enough room now, then
253  * inform user that this would block and do nothing.
254  */
255 sosend(so, asa)
256 	register struct socket *so;
257 	struct sockaddr *asa;
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) && u.u_count > 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 (u.u_count == 0) {
303 		splx(s);
304 		goto release;
305 	}
306 	space = sbspace(&so->so_snd);
307 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
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 (u.u_count && space > 0) {
317 		MGET(m, 1);
318 		if (m == NULL) {
319 			error = ENOBUFS;			/* SIGPIPE? */
320 			goto release;
321 		}
322 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
323 			register struct mbuf *p;
324 			MCLGET(p, 1);
325 			if (p == 0)
326 				goto nopages;
327 			m->m_off = (int)p - (int)m;
328 			len = CLBYTES;
329 		} else {
330 nopages:
331 			m->m_off = MMINOFF;
332 			len = MIN(MLEN, u.u_count);
333 		}
334 		iomove(mtod(m, caddr_t), len, B_WRITE);
335 		m->m_len = len;
336 		*mp = m;
337 		mp = &m->m_next;
338 		space = sbspace(&so->so_snd);
339 	}
340 	goto again;
341 
342 release:
343 	sbunlock(&so->so_snd);
344 	if (top)
345 		m_freem(top);
346 	return (error);
347 }
348 
349 soreceive(so, asa, uio)
350 	register struct socket *so;
351 	struct sockaddr *asa;
352 	struct uio *uio;
353 {
354 	register struct iovec *iov;
355 	register struct mbuf *m, *n;
356 	u_int len;
357 	int eor, s, error = 0, resid = uio->uio_resid;
358 	int cnt;
359 
360 restart:
361 	sblock(&so->so_rcv);
362 	s = splnet();
363 
364 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
365 	if (so->so_rcv.sb_cc == 0) {
366 		if (so->so_error) {
367 			error = so->so_error;
368 			so->so_error = 0;
369 			splx(s);
370 			goto release;
371 		}
372 		if (so->so_state & SS_CANTRCVMORE) {
373 			splx(s);
374 			goto release;
375 		}
376 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
377 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
378 			rcverr(ENOTCONN);
379 		if (so->so_state & SS_NBIO)
380 			rcverr(EWOULDBLOCK);
381 		sbunlock(&so->so_rcv);
382 		sbwait(&so->so_rcv);
383 		splx(s);
384 		goto restart;
385 	}
386 	m = so->so_rcv.sb_mb;
387 	if (m == 0)
388 		panic("receive");
389 	if (so->so_proto->pr_flags & PR_ADDR) {
390 		if (m->m_len != sizeof (struct sockaddr))
391 			panic("soreceive addr");
392 		if (asa)
393 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
394 		so->so_rcv.sb_cc -= m->m_len;
395 		so->so_rcv.sb_mbcnt -= MSIZE;
396 		m = m_free(m);
397 		if (m == 0)
398 			panic("receive 2");
399 		so->so_rcv.sb_mb = m;
400 	}
401 	eor = 0;
402 	do {
403 		if (uio->uio_iovcnt == 0)
404 			break;
405 		iov = uio->uio_iov;
406 		len = iov->iov_len;
407 		so->so_state &= ~SS_RCVATMARK;
408 		if (so->so_oobmark && len > so->so_oobmark)
409 			len = so->so_oobmark;
410 		if (len > m->m_len)
411 			len = m->m_len;
412 		splx(s);
413 		uiomove(mtod(m, caddr_t), len, UIO_WRITETO, uio);
414 		s = splnet();
415 		if (len == m->m_len) {
416 			eor = (int)m->m_act;
417 			sbfree(&so->so_rcv, m);
418 			so->so_rcv.sb_mb = m->m_next;
419 			MFREE(m, n);
420 		} else {
421 			m->m_off += len;
422 			m->m_len -= len;
423 			so->so_rcv.sb_cc -= len;
424 		}
425 		if (so->so_oobmark) {
426 			so->so_oobmark -= len;
427 			if (so->so_oobmark == 0) {
428 				so->so_state |= SS_RCVATMARK;
429 				break;
430 			}
431 		}
432 	} while ((m = so->so_rcv.sb_mb) && !eor);
433 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
434 		do {
435 			if (m == 0)
436 				panic("receive 3");
437 			sbfree(&so->so_rcv, m);
438 			eor = (int)m->m_act;
439 			so->so_rcv.sb_mb = m->m_next;
440 			MFREE(m, n);
441 			m = n;
442 		} while (eor == 0);
443 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
444 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
445 release:
446 	sbunlock(&so->so_rcv);
447 	splx(s);
448 	return (error);
449 }
450 
451 sohasoutofband(so)
452 	struct socket *so;
453 {
454 
455 	if (so->so_pgrp == 0)
456 		return;
457 	if (so->so_pgrp > 0)
458 		gsignal(so->so_pgrp, SIGURG);
459 	else {
460 		struct proc *p = pfind(-so->so_pgrp);
461 
462 		if (p)
463 			psignal(p, SIGURG);
464 	}
465 }
466 
467 /*ARGSUSED*/
468 soioctl(so, cmd, data)
469 	register struct socket *so;
470 	int cmd;
471 	register char *data;
472 {
473 
474 	switch (cmd) {
475 
476 	case FIONBIO:
477 		if (*(int *)data)
478 			so->so_state |= SS_NBIO;
479 		else
480 			so->so_state &= ~SS_NBIO;
481 		return;
482 
483 	case FIOASYNC:
484 		if (*(int *)data)
485 			so->so_state |= SS_ASYNC;
486 		else
487 			so->so_state &= ~SS_ASYNC;
488 		return;
489 
490 	case SIOCSKEEP:
491 		if (*(int *)data)
492 			so->so_options &= ~SO_KEEPALIVE;
493 		else
494 			so->so_options |= SO_KEEPALIVE;
495 		return;
496 
497 	case SIOCGKEEP:
498 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
499 		return;
500 
501 	case SIOCSLINGER:
502 		so->so_linger = *(int *)data;
503 		if (so->so_linger)
504 			so->so_options &= ~SO_DONTLINGER;
505 		else
506 			so->so_options |= SO_DONTLINGER;
507 		return;
508 
509 	case SIOCGLINGER:
510 		*(int *)data = so->so_linger;
511 		return;
512 
513 	case SIOCSPGRP:
514 		so->so_pgrp = *(int *)data;
515 		return;
516 
517 	case SIOCGPGRP:
518 		*(int *)data = so->so_pgrp;
519 		return;
520 
521 	case SIOCDONE: {
522 		int flags = *(int *)data;
523 
524 		flags++;
525 		if (flags & FREAD) {
526 			int s = splimp();
527 			socantrcvmore(so);
528 			sbflush(&so->so_rcv);
529 			splx(s);
530 		}
531 		if (flags & FWRITE)
532 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
533 		return;
534 	}
535 
536 	case SIOCSENDOOB: {
537 		char oob = *(char *)data;
538 		struct mbuf *m;
539 
540 		m = m_get(M_DONTWAIT);
541 		if (m == 0) {
542 			u.u_error = ENOBUFS;
543 			return;
544 		}
545 		m->m_off = MMINOFF;
546 		m->m_len = sizeof (char);
547 		*mtod(m, char *) = oob;
548 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
549 		return;
550 	}
551 
552 	case SIOCRCVOOB: {
553 		struct mbuf *m = m_get(M_DONTWAIT);
554 
555 		if (m == 0) {
556 			u.u_error = ENOBUFS;
557 			return;
558 		}
559 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
560 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
561 		*(char *)data = *mtod(m, char *);
562 		(void) m_free(m);
563 		return;
564 	}
565 
566 	case SIOCATMARK:
567 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
568 		return;
569 
570 	/* routing table update calls */
571 	case SIOCADDRT:
572 	case SIOCDELRT:
573 		if (!suser())
574 			return;
575 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
576 		return;
577 
578 	/* type/protocol specific ioctls */
579 	}
580 	u.u_error = EOPNOTSUPP;
581 }
582