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