xref: /csrg-svn/sys/kern/uipc_socket.c (revision 6880)
1 /*	uipc_socket.c	4.40	82/05/20	*/
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 		(void) m_free(dtom(so));
86 		return (error);
87 	}
88 	*aso = so;
89 	return (0);
90 }
91 
92 sofree(so)
93 	struct socket *so;
94 {
95 
96 COUNT(SOFREE);
97 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
98 		return;
99 	sbrelease(&so->so_snd);
100 	sbrelease(&so->so_rcv);
101 	(void) m_free(dtom(so));
102 }
103 
104 /*
105  * Close a socket on last file table reference removal.
106  * Initiate disconnect if connected.
107  * Free socket when disconnect complete.
108  *
109  * THIS IS REALLY A UNIX INTERFACE ROUTINE
110  */
111 soclose(so, exiting)
112 	register struct socket *so;
113 	int exiting;
114 {
115 	int s = splnet();		/* conservative */
116 
117 COUNT(SOCLOSE);
118 	if (so->so_pcb == 0)
119 		goto discard;
120 	if (exiting)
121 		so->so_options |= SO_KEEPALIVE;
122 	if (so->so_state & SS_ISCONNECTED) {
123 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
124 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
125 			if (u.u_error) {
126 				if (exiting)
127 					goto drop;
128 				splx(s);
129 				return;
130 			}
131 		}
132 		if ((so->so_options & SO_DONTLINGER) == 0) {
133 			if ((so->so_state & SS_ISDISCONNECTING) &&
134 			    (so->so_state & SS_NBIO) &&
135 			    exiting == 0) {
136 				u.u_error = EINPROGRESS;
137 				splx(s);
138 				return;
139 			}
140 			/* should use tsleep here, for at most linger */
141 			while (so->so_state & SS_ISCONNECTED)
142 				sleep((caddr_t)&so->so_timeo, PZERO+1);
143 		}
144 	}
145 drop:
146 	if (so->so_pcb) {
147 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
148 		if (exiting == 0 && u.u_error) {
149 			splx(s);
150 			return;
151 		}
152 	}
153 discard:
154 	so->so_state |= SS_USERGONE;
155 	sofree(so);
156 	splx(s);
157 }
158 
159 /*ARGSUSED*/
160 sostat(so, sb)
161 	struct socket *so;
162 	struct stat *sb;
163 {
164 
165 COUNT(SOSTAT);
166 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
167 	return (0);					/* XXX */
168 }
169 
170 /*
171  * Accept connection on a socket.
172  */
173 soaccept(so, asa)
174 	struct socket *so;
175 	struct sockaddr *asa;
176 {
177 	int s = splnet();
178 	int error;
179 
180 COUNT(SOACCEPT);
181 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
182 		error = EINVAL;			/* XXX */
183 		goto bad;
184 	}
185 	if ((so->so_state & SS_CONNAWAITING) == 0) {
186 		error = ENOTCONN;
187 		goto bad;
188 	}
189 	so->so_state &= ~SS_CONNAWAITING;
190 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
191 bad:
192 	splx(s);
193 	return (error);
194 }
195 
196 /*
197  * Connect socket to a specified address.
198  * If already connected or connecting, then avoid
199  * the protocol entry, to keep its job simpler.
200  */
201 soconnect(so, asa)
202 	struct socket *so;
203 	struct sockaddr *asa;
204 {
205 	int s = splnet();
206 	int error;
207 
208 COUNT(SOCONNECT);
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 COUNT(SODISCONNECT);
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 COUNT(SOSEND);
265 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
266 		return (EMSGSIZE);
267 #ifdef notdef
268 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
269 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
270 		return (EWOULDBLOCK);
271 #endif
272 restart:
273 	sblock(&so->so_snd);
274 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
275 
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 (u.u_count == 0) {
304 		splx(s);
305 		goto release;
306 	}
307 	space = sbspace(&so->so_snd);
308 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
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 (u.u_count && space > 0) {
318 		MGET(m, 1);
319 		if (m == NULL) {
320 			error = ENOBUFS;			/* SIGPIPE? */
321 			goto release;
322 		}
323 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
324 			register struct mbuf *p;
325 			MCLGET(p, 1);
326 			if (p == 0)
327 				goto nopages;
328 			m->m_off = (int)p - (int)m;
329 			len = CLBYTES;
330 		} else {
331 nopages:
332 			m->m_off = MMINOFF;
333 			len = MIN(MLEN, u.u_count);
334 		}
335 		iomove(mtod(m, caddr_t), len, B_WRITE);
336 		m->m_len = len;
337 		*mp = m;
338 		mp = &m->m_next;
339 		space = sbspace(&so->so_snd);
340 	}
341 	goto again;
342 
343 release:
344 	sbunlock(&so->so_snd);
345 	if (top)
346 		m_freem(top);
347 	return (error);
348 }
349 
350 soreceive(so, asa)
351 	register struct socket *so;
352 	struct sockaddr *asa;
353 {
354 	register struct mbuf *m, *n;
355 	u_int len;
356 	int eor, s, error = 0, cnt = u.u_count;
357 	caddr_t base = u.u_base;
358 
359 COUNT(SORECEIVE);
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 	so->so_state &= ~SS_RCVATMARK;
402 	if (so->so_oobmark && cnt > so->so_oobmark)
403 		cnt = so->so_oobmark;
404 	eor = 0;
405 	do {
406 		len = MIN(m->m_len, cnt);
407 		splx(s);
408 		iomove(mtod(m, caddr_t), len, B_READ);
409 		cnt -= len;
410 		s = splnet();
411 		if (len == m->m_len) {
412 			eor = (int)m->m_act;
413 			sbfree(&so->so_rcv, m);
414 			so->so_rcv.sb_mb = m->m_next;
415 			MFREE(m, n);
416 		} else {
417 			m->m_off += len;
418 			m->m_len -= len;
419 			so->so_rcv.sb_cc -= len;
420 		}
421 	} while ((m = so->so_rcv.sb_mb) && cnt && !eor);
422 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
423 		do {
424 			if (m == 0)
425 				panic("receive 3");
426 			sbfree(&so->so_rcv, m);
427 			eor = (int)m->m_act;
428 			so->so_rcv.sb_mb = m->m_next;
429 			MFREE(m, n);
430 			m = n;
431 		} while (eor == 0);
432 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
433 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
434 	if (so->so_oobmark) {
435 		so->so_oobmark -= u.u_base - base;
436 		if (so->so_oobmark == 0)
437 			so->so_state |= SS_RCVATMARK;
438 	}
439 release:
440 	sbunlock(&so->so_rcv);
441 	splx(s);
442 	return (error);
443 }
444 
445 sohasoutofband(so)
446 	struct socket *so;
447 {
448 
449 	if (so->so_pgrp == 0)
450 		return;
451 	if (so->so_pgrp > 0)
452 		gsignal(so->so_pgrp, SIGURG);
453 	else {
454 		struct proc *p = pfind(-so->so_pgrp);
455 
456 		if (p)
457 			psignal(p, SIGURG);
458 	}
459 }
460 
461 /*ARGSUSED*/
462 soioctl(so, cmd, cmdp)
463 	register struct socket *so;
464 	int cmd;
465 	register caddr_t cmdp;
466 {
467 
468 COUNT(SOIOCTL);
469 	switch (cmd) {
470 
471 	case FIONBIO: {
472 		int nbio;
473 		if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
474 			u.u_error = EFAULT;
475 			return;
476 		}
477 		if (nbio)
478 			so->so_state |= SS_NBIO;
479 		else
480 			so->so_state &= ~SS_NBIO;
481 		return;
482 	}
483 
484 	case FIOASYNC: {
485 		int async;
486 		if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
487 			u.u_error = EFAULT;
488 			return;
489 		}
490 		if (async)
491 			so->so_state |= SS_ASYNC;
492 		else
493 			so->so_state &= ~SS_ASYNC;
494 		return;
495 	}
496 
497 	case SIOCSKEEP: {
498 		int keep;
499 		if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
500 			u.u_error = EFAULT;
501 			return;
502 		}
503 		if (keep)
504 			so->so_options &= ~SO_KEEPALIVE;
505 		else
506 			so->so_options |= SO_KEEPALIVE;
507 		return;
508 	}
509 
510 	case SIOCGKEEP: {
511 		int keep = (so->so_options & SO_KEEPALIVE) != 0;
512 		if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
513 			u.u_error = EFAULT;
514 		return;
515 	}
516 
517 	case SIOCSLINGER: {
518 		int linger;
519 		if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
520 			u.u_error = EFAULT;
521 			return;
522 		}
523 		so->so_linger = linger;
524 		if (so->so_linger)
525 			so->so_options &= ~SO_DONTLINGER;
526 		else
527 			so->so_options |= SO_DONTLINGER;
528 		return;
529 	}
530 
531 	case SIOCGLINGER: {
532 		int linger = so->so_linger;
533 		if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
534 			u.u_error = EFAULT;
535 			return;
536 		}
537 	}
538 	case SIOCSPGRP: {
539 		int pgrp;
540 		if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) {
541 			u.u_error = EFAULT;
542 			return;
543 		}
544 		so->so_pgrp = pgrp;
545 		return;
546 	}
547 
548 	case SIOCGPGRP: {
549 		int pgrp = so->so_pgrp;
550 		if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) {
551 			u.u_error = EFAULT;
552 			return;
553 		}
554 	}
555 
556 	case SIOCDONE: {
557 		int flags;
558 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
559 			u.u_error = EFAULT;
560 			return;
561 		}
562 		flags++;
563 		if (flags & FREAD) {
564 			int s = splimp();
565 			socantrcvmore(so);
566 			sbflush(&so->so_rcv);
567 			splx(s);
568 		}
569 		if (flags & FWRITE)
570 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
571 		return;
572 	}
573 
574 	case SIOCSENDOOB: {
575 		char oob;
576 		struct mbuf *m;
577 		if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
578 			u.u_error = EFAULT;
579 			return;
580 		}
581 		m = m_get(M_DONTWAIT);
582 		if (m == 0) {
583 			u.u_error = ENOBUFS;
584 			return;
585 		}
586 		m->m_off = MMINOFF;
587 		m->m_len = 1;
588 		*mtod(m, caddr_t) = oob;
589 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
590 		return;
591 	}
592 
593 	case SIOCRCVOOB: {
594 		struct mbuf *m = m_get(M_DONTWAIT);
595 		if (m == 0) {
596 			u.u_error = ENOBUFS;
597 			return;
598 		}
599 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
600 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
601 		if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
602 			u.u_error = EFAULT;
603 			return;
604 		}
605 		m_free(m);
606 		return;
607 	}
608 
609 	case SIOCATMARK: {
610 		int atmark = (so->so_state&SS_RCVATMARK) != 0;
611 		if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
612 			u.u_error = EFAULT;
613 			return;
614 		}
615 		return;
616 	}
617 
618 	/* routing table update calls */
619 	case SIOCADDRT:
620 	case SIOCDELRT:
621 	case SIOCCHGRT: {
622 		struct rtentry route;
623 		if (!suser())
624 			return;
625 		if (copyin(cmdp, (caddr_t)&route, sizeof (route))) {
626 			u.u_error = EFAULT;
627 			return;
628 		}
629 		u.u_error = rtrequest(cmd, &route);
630 		return;
631 	}
632 
633 	/* type/protocol specific ioctls */
634 	}
635 	u.u_error = EOPNOTSUPP;
636 }
637