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