xref: /original-bsd/sys/kern/uipc_socket.c (revision 9a96b58b)
1 /*	uipc_socket.c	4.39	82/04/10	*/
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 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
147 discard:
148 	so->so_state |= SS_USERGONE;
149 	sofree(so);
150 	splx(s);
151 }
152 
153 /*ARGSUSED*/
154 sostat(so, sb)
155 	struct socket *so;
156 	struct stat *sb;
157 {
158 
159 COUNT(SOSTAT);
160 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
161 	return (0);					/* XXX */
162 }
163 
164 /*
165  * Accept connection on a socket.
166  */
167 soaccept(so, asa)
168 	struct socket *so;
169 	struct sockaddr *asa;
170 {
171 	int s = splnet();
172 	int error;
173 
174 COUNT(SOACCEPT);
175 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
176 		error = EINVAL;			/* XXX */
177 		goto bad;
178 	}
179 	if ((so->so_state & SS_CONNAWAITING) == 0) {
180 		error = ENOTCONN;
181 		goto bad;
182 	}
183 	so->so_state &= ~SS_CONNAWAITING;
184 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
185 bad:
186 	splx(s);
187 	return (error);
188 }
189 
190 /*
191  * Connect socket to a specified address.
192  * If already connected or connecting, then avoid
193  * the protocol entry, to keep its job simpler.
194  */
195 soconnect(so, asa)
196 	struct socket *so;
197 	struct sockaddr *asa;
198 {
199 	int s = splnet();
200 	int error;
201 
202 COUNT(SOCONNECT);
203 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
204 		error = EISCONN;
205 		goto bad;
206 	}
207 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
208 bad:
209 	splx(s);
210 	return (error);
211 }
212 
213 /*
214  * Disconnect from a socket.
215  * Address parameter is from system call for later multicast
216  * protocols.  Check to make sure that connected and no disconnect
217  * in progress (for protocol's sake), and then invoke protocol.
218  */
219 sodisconnect(so, asa)
220 	struct socket *so;
221 	struct sockaddr *asa;
222 {
223 	int s = splnet();
224 	int error;
225 
226 COUNT(SODISCONNECT);
227 	if ((so->so_state & SS_ISCONNECTED) == 0) {
228 		error = ENOTCONN;
229 		goto bad;
230 	}
231 	if (so->so_state & SS_ISDISCONNECTING) {
232 		error = EALREADY;
233 		goto bad;
234 	}
235 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
236 bad:
237 	splx(s);
238 	return (error);
239 }
240 
241 /*
242  * Send on a socket.
243  * If send must go all at once and message is larger than
244  * send buffering, then hard error.
245  * Lock against other senders.
246  * If must go all at once and not enough room now, then
247  * inform user that this would block and do nothing.
248  */
249 sosend(so, asa)
250 	register struct socket *so;
251 	struct sockaddr *asa;
252 {
253 	struct mbuf *top = 0;
254 	register struct mbuf *m, **mp = ⊤
255 	register u_int len;
256 	int error = 0, space, s;
257 
258 COUNT(SOSEND);
259 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
260 		return (EMSGSIZE);
261 #ifdef notdef
262 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
263 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
264 		return (EWOULDBLOCK);
265 #endif
266 restart:
267 	sblock(&so->so_snd);
268 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
269 
270 again:
271 	s = splnet();
272 	if (so->so_state & SS_CANTSENDMORE) {
273 		psignal(u.u_procp, SIGPIPE);
274 		snderr(EPIPE);
275 	}
276 	if (so->so_error) {
277 		error = so->so_error;
278 		so->so_error = 0;				/* ??? */
279 		splx(s);
280 		goto release;
281 	}
282 	if ((so->so_state & SS_ISCONNECTED) == 0) {
283 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
284 			snderr(ENOTCONN);
285 		if (asa == 0)
286 			snderr(EDESTADDRREQ);
287 	}
288 	if (top) {
289 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
290 		top = 0;
291 		if (error) {
292 			splx(s);
293 			goto release;
294 		}
295 		mp = ⊤
296 	}
297 	if (u.u_count == 0) {
298 		splx(s);
299 		goto release;
300 	}
301 	space = sbspace(&so->so_snd);
302 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
303 		if (so->so_state & SS_NBIO)
304 			snderr(EWOULDBLOCK);
305 		sbunlock(&so->so_snd);
306 		sbwait(&so->so_snd);
307 		splx(s);
308 		goto restart;
309 	}
310 	splx(s);
311 	while (u.u_count && space > 0) {
312 		MGET(m, 1);
313 		if (m == NULL) {
314 			error = ENOBUFS;			/* SIGPIPE? */
315 			goto release;
316 		}
317 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
318 			register struct mbuf *p;
319 			MCLGET(p, 1);
320 			if (p == 0)
321 				goto nopages;
322 			m->m_off = (int)p - (int)m;
323 			len = CLBYTES;
324 		} else {
325 nopages:
326 			m->m_off = MMINOFF;
327 			len = MIN(MLEN, u.u_count);
328 		}
329 		iomove(mtod(m, caddr_t), len, B_WRITE);
330 		m->m_len = len;
331 		*mp = m;
332 		mp = &m->m_next;
333 		space = sbspace(&so->so_snd);
334 	}
335 	goto again;
336 
337 release:
338 	sbunlock(&so->so_snd);
339 	if (top)
340 		m_freem(top);
341 	return (error);
342 }
343 
344 soreceive(so, asa)
345 	register struct socket *so;
346 	struct sockaddr *asa;
347 {
348 	register struct mbuf *m, *n;
349 	u_int len;
350 	int eor, s, error = 0, cnt = u.u_count;
351 	caddr_t base = u.u_base;
352 
353 COUNT(SORECEIVE);
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 COUNT(SOIOCTL);
463 	switch (cmd) {
464 
465 	case FIONBIO: {
466 		int nbio;
467 		if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
468 			u.u_error = EFAULT;
469 			return;
470 		}
471 		if (nbio)
472 			so->so_state |= SS_NBIO;
473 		else
474 			so->so_state &= ~SS_NBIO;
475 		return;
476 	}
477 
478 	case FIOASYNC: {
479 		int async;
480 		if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
481 			u.u_error = EFAULT;
482 			return;
483 		}
484 		if (async)
485 			so->so_state |= SS_ASYNC;
486 		else
487 			so->so_state &= ~SS_ASYNC;
488 		return;
489 	}
490 
491 	case SIOCSKEEP: {
492 		int keep;
493 		if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
494 			u.u_error = EFAULT;
495 			return;
496 		}
497 		if (keep)
498 			so->so_options &= ~SO_KEEPALIVE;
499 		else
500 			so->so_options |= SO_KEEPALIVE;
501 		return;
502 	}
503 
504 	case SIOCGKEEP: {
505 		int keep = (so->so_options & SO_KEEPALIVE) != 0;
506 		if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
507 			u.u_error = EFAULT;
508 		return;
509 	}
510 
511 	case SIOCSLINGER: {
512 		int linger;
513 		if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
514 			u.u_error = EFAULT;
515 			return;
516 		}
517 		so->so_linger = linger;
518 		if (so->so_linger)
519 			so->so_options &= ~SO_DONTLINGER;
520 		else
521 			so->so_options |= SO_DONTLINGER;
522 		return;
523 	}
524 
525 	case SIOCGLINGER: {
526 		int linger = so->so_linger;
527 		if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
528 			u.u_error = EFAULT;
529 			return;
530 		}
531 	}
532 	case SIOCSPGRP: {
533 		int pgrp;
534 		if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) {
535 			u.u_error = EFAULT;
536 			return;
537 		}
538 		so->so_pgrp = pgrp;
539 		return;
540 	}
541 
542 	case SIOCGPGRP: {
543 		int pgrp = so->so_pgrp;
544 		if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) {
545 			u.u_error = EFAULT;
546 			return;
547 		}
548 	}
549 
550 	case SIOCDONE: {
551 		int flags;
552 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
553 			u.u_error = EFAULT;
554 			return;
555 		}
556 		flags++;
557 		if (flags & FREAD) {
558 			int s = splimp();
559 			socantrcvmore(so);
560 			sbflush(&so->so_rcv);
561 			splx(s);
562 		}
563 		if (flags & FWRITE)
564 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
565 		return;
566 	}
567 
568 	case SIOCSENDOOB: {
569 		char oob;
570 		struct mbuf *m;
571 		if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
572 			u.u_error = EFAULT;
573 			return;
574 		}
575 		m = m_get(M_DONTWAIT);
576 		if (m == 0) {
577 			u.u_error = ENOBUFS;
578 			return;
579 		}
580 		m->m_off = MMINOFF;
581 		m->m_len = 1;
582 		*mtod(m, caddr_t) = oob;
583 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
584 		return;
585 	}
586 
587 	case SIOCRCVOOB: {
588 		struct mbuf *m = m_get(M_DONTWAIT);
589 		if (m == 0) {
590 			u.u_error = ENOBUFS;
591 			return;
592 		}
593 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
594 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
595 		if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
596 			u.u_error = EFAULT;
597 			return;
598 		}
599 		m_free(m);
600 		return;
601 	}
602 
603 	case SIOCATMARK: {
604 		int atmark = (so->so_state&SS_RCVATMARK) != 0;
605 		if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
606 			u.u_error = EFAULT;
607 			return;
608 		}
609 		return;
610 	}
611 
612 	/* routing table update calls */
613 	case SIOCADDRT:
614 	case SIOCDELRT:
615 	case SIOCCHGRT: {
616 		struct rtentry route;
617 		if (!suser())
618 			return;
619 		if (copyin(cmdp, (caddr_t)&route, sizeof (route))) {
620 			u.u_error = EFAULT;
621 			return;
622 		}
623 		u.u_error = rtrequest(cmd, &route);
624 		return;
625 	}
626 
627 	/* type/protocol specific ioctls */
628 	}
629 	u.u_error = EOPNOTSUPP;
630 }
631