xref: /csrg-svn/sys/kern/uipc_socket.c (revision 7180)
1 /*	uipc_socket.c	4.41	82/06/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 
21 /*
22  * Socket support routines.
23  *
24  * DEAL WITH INTERRUPT NOTIFICATION.
25  */
26 
27 /*
28  * Create a socket.
29  */
30 socreate(aso, type, asp, asa, options)
31 	struct socket **aso;
32 	int type;
33 	struct sockproto *asp;
34 	struct sockaddr *asa;
35 	int options;
36 {
37 	register struct protosw *prp;
38 	register struct socket *so;
39 	struct mbuf *m;
40 	int pf, proto, error;
41 COUNT(SOCREATE);
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 	so->so_state = 0;
75 	if (u.u_uid == 0)
76 		so->so_state = SS_PRIV;
77 
78 	/*
79 	 * Attach protocol to socket, initializing
80 	 * and reserving resources.
81 	 */
82 	so->so_proto = prp;
83 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
84 	if (error) {
85 		if (so->so_snd.sb_mbmax || so->so_rcv.sb_mbmax)
86 			panic("socreate");
87 		so->so_state |= SS_USERGONE;
88 		sofree(so);
89 		return (error);
90 	}
91 	*aso = so;
92 	return (0);
93 }
94 
95 sofree(so)
96 	struct socket *so;
97 {
98 
99 COUNT(SOFREE);
100 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
101 		return;
102 	sbrelease(&so->so_snd);
103 	sbrelease(&so->so_rcv);
104 	(void) m_free(dtom(so));
105 }
106 
107 /*
108  * Close a socket on last file table reference removal.
109  * Initiate disconnect if connected.
110  * Free socket when disconnect complete.
111  *
112  * THIS IS REALLY A UNIX INTERFACE ROUTINE
113  */
114 soclose(so, exiting)
115 	register struct socket *so;
116 	int exiting;
117 {
118 	int s = splnet();		/* conservative */
119 
120 COUNT(SOCLOSE);
121 	if (so->so_pcb == 0)
122 		goto discard;
123 	if (exiting)
124 		so->so_options |= SO_KEEPALIVE;
125 	if (so->so_state & SS_ISCONNECTED) {
126 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
127 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
128 			if (u.u_error) {
129 				if (exiting)
130 					goto drop;
131 				splx(s);
132 				return;
133 			}
134 		}
135 		if ((so->so_options & SO_DONTLINGER) == 0) {
136 			if ((so->so_state & SS_ISDISCONNECTING) &&
137 			    (so->so_state & SS_NBIO) &&
138 			    exiting == 0) {
139 				u.u_error = EINPROGRESS;
140 				splx(s);
141 				return;
142 			}
143 			/* should use tsleep here, for at most linger */
144 			while (so->so_state & SS_ISCONNECTED)
145 				sleep((caddr_t)&so->so_timeo, PZERO+1);
146 		}
147 	}
148 drop:
149 	if (so->so_pcb) {
150 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
151 		if (exiting == 0 && u.u_error) {
152 			splx(s);
153 			return;
154 		}
155 	}
156 discard:
157 	so->so_state |= SS_USERGONE;
158 	sofree(so);
159 	splx(s);
160 }
161 
162 /*ARGSUSED*/
163 sostat(so, sb)
164 	struct socket *so;
165 	struct stat *sb;
166 {
167 
168 COUNT(SOSTAT);
169 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
170 	return (0);					/* XXX */
171 }
172 
173 /*
174  * Accept connection on a socket.
175  */
176 soaccept(so, asa)
177 	struct socket *so;
178 	struct sockaddr *asa;
179 {
180 	int s = splnet();
181 	int error;
182 
183 COUNT(SOACCEPT);
184 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
185 		error = EINVAL;			/* XXX */
186 		goto bad;
187 	}
188 	if ((so->so_state & SS_CONNAWAITING) == 0) {
189 		error = ENOTCONN;
190 		goto bad;
191 	}
192 	so->so_state &= ~SS_CONNAWAITING;
193 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
194 bad:
195 	splx(s);
196 	return (error);
197 }
198 
199 /*
200  * Connect socket to a specified address.
201  * If already connected or connecting, then avoid
202  * the protocol entry, to keep its job simpler.
203  */
204 soconnect(so, asa)
205 	struct socket *so;
206 	struct sockaddr *asa;
207 {
208 	int s = splnet();
209 	int error;
210 
211 COUNT(SOCONNECT);
212 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
213 		error = EISCONN;
214 		goto bad;
215 	}
216 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
217 bad:
218 	splx(s);
219 	return (error);
220 }
221 
222 /*
223  * Disconnect from a socket.
224  * Address parameter is from system call for later multicast
225  * protocols.  Check to make sure that connected and no disconnect
226  * in progress (for protocol's sake), and then invoke protocol.
227  */
228 sodisconnect(so, asa)
229 	struct socket *so;
230 	struct sockaddr *asa;
231 {
232 	int s = splnet();
233 	int error;
234 
235 COUNT(SODISCONNECT);
236 	if ((so->so_state & SS_ISCONNECTED) == 0) {
237 		error = ENOTCONN;
238 		goto bad;
239 	}
240 	if (so->so_state & SS_ISDISCONNECTING) {
241 		error = EALREADY;
242 		goto bad;
243 	}
244 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
245 bad:
246 	splx(s);
247 	return (error);
248 }
249 
250 /*
251  * Send on a socket.
252  * If send must go all at once and message is larger than
253  * send buffering, then hard error.
254  * Lock against other senders.
255  * If must go all at once and not enough room now, then
256  * inform user that this would block and do nothing.
257  */
258 sosend(so, asa)
259 	register struct socket *so;
260 	struct sockaddr *asa;
261 {
262 	struct mbuf *top = 0;
263 	register struct mbuf *m, **mp = ⊤
264 	register u_int len;
265 	int error = 0, space, s;
266 
267 COUNT(SOSEND);
268 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
269 		return (EMSGSIZE);
270 #ifdef notdef
271 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
272 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
273 		return (EWOULDBLOCK);
274 #endif
275 restart:
276 	sblock(&so->so_snd);
277 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
278 
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 (asa == 0)
295 			snderr(EDESTADDRREQ);
296 	}
297 	if (top) {
298 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
299 		top = 0;
300 		if (error) {
301 			splx(s);
302 			goto release;
303 		}
304 		mp = ⊤
305 	}
306 	if (u.u_count == 0) {
307 		splx(s);
308 		goto release;
309 	}
310 	space = sbspace(&so->so_snd);
311 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
312 		if (so->so_state & SS_NBIO)
313 			snderr(EWOULDBLOCK);
314 		sbunlock(&so->so_snd);
315 		sbwait(&so->so_snd);
316 		splx(s);
317 		goto restart;
318 	}
319 	splx(s);
320 	while (u.u_count && space > 0) {
321 		MGET(m, 1);
322 		if (m == NULL) {
323 			error = ENOBUFS;			/* SIGPIPE? */
324 			goto release;
325 		}
326 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
327 			register struct mbuf *p;
328 			MCLGET(p, 1);
329 			if (p == 0)
330 				goto nopages;
331 			m->m_off = (int)p - (int)m;
332 			len = CLBYTES;
333 		} else {
334 nopages:
335 			m->m_off = MMINOFF;
336 			len = MIN(MLEN, u.u_count);
337 		}
338 		iomove(mtod(m, caddr_t), len, B_WRITE);
339 		m->m_len = len;
340 		*mp = m;
341 		mp = &m->m_next;
342 		space = sbspace(&so->so_snd);
343 	}
344 	goto again;
345 
346 release:
347 	sbunlock(&so->so_snd);
348 	if (top)
349 		m_freem(top);
350 	return (error);
351 }
352 
353 soreceive(so, asa)
354 	register struct socket *so;
355 	struct sockaddr *asa;
356 {
357 	register struct mbuf *m, *n;
358 	u_int len;
359 	int eor, s, error = 0, cnt = u.u_count;
360 	caddr_t base = u.u_base;
361 
362 COUNT(SORECEIVE);
363 restart:
364 	sblock(&so->so_rcv);
365 	s = splnet();
366 
367 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
368 	if (so->so_rcv.sb_cc == 0) {
369 		if (so->so_error) {
370 			error = so->so_error;
371 			so->so_error = 0;
372 			splx(s);
373 			goto release;
374 		}
375 		if (so->so_state & SS_CANTRCVMORE) {
376 			splx(s);
377 			goto release;
378 		}
379 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
380 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
381 			rcverr(ENOTCONN);
382 		if (so->so_state & SS_NBIO)
383 			rcverr(EWOULDBLOCK);
384 		sbunlock(&so->so_rcv);
385 		sbwait(&so->so_rcv);
386 		splx(s);
387 		goto restart;
388 	}
389 	m = so->so_rcv.sb_mb;
390 	if (m == 0)
391 		panic("receive");
392 	if (so->so_proto->pr_flags & PR_ADDR) {
393 		if (m->m_len != sizeof (struct sockaddr))
394 			panic("soreceive addr");
395 		if (asa)
396 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
397 		so->so_rcv.sb_cc -= m->m_len;
398 		so->so_rcv.sb_mbcnt -= MSIZE;
399 		m = m_free(m);
400 		if (m == 0)
401 			panic("receive 2");
402 		so->so_rcv.sb_mb = m;
403 	}
404 	so->so_state &= ~SS_RCVATMARK;
405 	if (so->so_oobmark && cnt > so->so_oobmark)
406 		cnt = so->so_oobmark;
407 	eor = 0;
408 	do {
409 		len = MIN(m->m_len, cnt);
410 		splx(s);
411 		iomove(mtod(m, caddr_t), len, B_READ);
412 		cnt -= len;
413 		s = splnet();
414 		if (len == m->m_len) {
415 			eor = (int)m->m_act;
416 			sbfree(&so->so_rcv, m);
417 			so->so_rcv.sb_mb = m->m_next;
418 			MFREE(m, n);
419 		} else {
420 			m->m_off += len;
421 			m->m_len -= len;
422 			so->so_rcv.sb_cc -= len;
423 		}
424 	} while ((m = so->so_rcv.sb_mb) && cnt && !eor);
425 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
426 		do {
427 			if (m == 0)
428 				panic("receive 3");
429 			sbfree(&so->so_rcv, m);
430 			eor = (int)m->m_act;
431 			so->so_rcv.sb_mb = m->m_next;
432 			MFREE(m, n);
433 			m = n;
434 		} while (eor == 0);
435 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
436 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
437 	if (so->so_oobmark) {
438 		so->so_oobmark -= u.u_base - base;
439 		if (so->so_oobmark == 0)
440 			so->so_state |= SS_RCVATMARK;
441 	}
442 release:
443 	sbunlock(&so->so_rcv);
444 	splx(s);
445 	return (error);
446 }
447 
448 sohasoutofband(so)
449 	struct socket *so;
450 {
451 
452 	if (so->so_pgrp == 0)
453 		return;
454 	if (so->so_pgrp > 0)
455 		gsignal(so->so_pgrp, SIGURG);
456 	else {
457 		struct proc *p = pfind(-so->so_pgrp);
458 
459 		if (p)
460 			psignal(p, SIGURG);
461 	}
462 }
463 
464 /*ARGSUSED*/
465 soioctl(so, cmd, cmdp)
466 	register struct socket *so;
467 	int cmd;
468 	register caddr_t cmdp;
469 {
470 
471 COUNT(SOIOCTL);
472 	switch (cmd) {
473 
474 	case FIONBIO: {
475 		int nbio;
476 		if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
477 			u.u_error = EFAULT;
478 			return;
479 		}
480 		if (nbio)
481 			so->so_state |= SS_NBIO;
482 		else
483 			so->so_state &= ~SS_NBIO;
484 		return;
485 	}
486 
487 	case FIOASYNC: {
488 		int async;
489 		if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
490 			u.u_error = EFAULT;
491 			return;
492 		}
493 		if (async)
494 			so->so_state |= SS_ASYNC;
495 		else
496 			so->so_state &= ~SS_ASYNC;
497 		return;
498 	}
499 
500 	case SIOCSKEEP: {
501 		int keep;
502 		if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
503 			u.u_error = EFAULT;
504 			return;
505 		}
506 		if (keep)
507 			so->so_options &= ~SO_KEEPALIVE;
508 		else
509 			so->so_options |= SO_KEEPALIVE;
510 		return;
511 	}
512 
513 	case SIOCGKEEP: {
514 		int keep = (so->so_options & SO_KEEPALIVE) != 0;
515 		if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
516 			u.u_error = EFAULT;
517 		return;
518 	}
519 
520 	case SIOCSLINGER: {
521 		int linger;
522 		if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
523 			u.u_error = EFAULT;
524 			return;
525 		}
526 		so->so_linger = linger;
527 		if (so->so_linger)
528 			so->so_options &= ~SO_DONTLINGER;
529 		else
530 			so->so_options |= SO_DONTLINGER;
531 		return;
532 	}
533 
534 	case SIOCGLINGER: {
535 		int linger = so->so_linger;
536 		if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
537 			u.u_error = EFAULT;
538 			return;
539 		}
540 	}
541 	case SIOCSPGRP: {
542 		int pgrp;
543 		if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) {
544 			u.u_error = EFAULT;
545 			return;
546 		}
547 		so->so_pgrp = pgrp;
548 		return;
549 	}
550 
551 	case SIOCGPGRP: {
552 		int pgrp = so->so_pgrp;
553 		if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) {
554 			u.u_error = EFAULT;
555 			return;
556 		}
557 	}
558 
559 	case SIOCDONE: {
560 		int flags;
561 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
562 			u.u_error = EFAULT;
563 			return;
564 		}
565 		flags++;
566 		if (flags & FREAD) {
567 			int s = splimp();
568 			socantrcvmore(so);
569 			sbflush(&so->so_rcv);
570 			splx(s);
571 		}
572 		if (flags & FWRITE)
573 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
574 		return;
575 	}
576 
577 	case SIOCSENDOOB: {
578 		char oob;
579 		struct mbuf *m;
580 		if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
581 			u.u_error = EFAULT;
582 			return;
583 		}
584 		m = m_get(M_DONTWAIT);
585 		if (m == 0) {
586 			u.u_error = ENOBUFS;
587 			return;
588 		}
589 		m->m_off = MMINOFF;
590 		m->m_len = 1;
591 		*mtod(m, caddr_t) = oob;
592 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
593 		return;
594 	}
595 
596 	case SIOCRCVOOB: {
597 		struct mbuf *m = m_get(M_DONTWAIT);
598 		if (m == 0) {
599 			u.u_error = ENOBUFS;
600 			return;
601 		}
602 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
603 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
604 		if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
605 			u.u_error = EFAULT;
606 			return;
607 		}
608 		m_free(m);
609 		return;
610 	}
611 
612 	case SIOCATMARK: {
613 		int atmark = (so->so_state&SS_RCVATMARK) != 0;
614 		if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
615 			u.u_error = EFAULT;
616 			return;
617 		}
618 		return;
619 	}
620 
621 	/* routing table update calls */
622 	case SIOCADDRT:
623 	case SIOCDELRT:
624 	case SIOCCHGRT: {
625 		struct rtentry route;
626 		if (!suser())
627 			return;
628 		if (copyin(cmdp, (caddr_t)&route, sizeof (route))) {
629 			u.u_error = EFAULT;
630 			return;
631 		}
632 		u.u_error = rtrequest(cmd, &route);
633 		return;
634 	}
635 
636 	/* type/protocol specific ioctls */
637 	}
638 	u.u_error = EOPNOTSUPP;
639 }
640