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