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