xref: /csrg-svn/sys/kern/uipc_socket.c (revision 5429)
1 /*	uipc_socket.c	4.26	82/01/17	*/
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 soclose(so)
106 	register struct socket *so;
107 {
108 	int s = splnet();		/* conservative */
109 
110 COUNT(SOCLOSE);
111 	if (so->so_pcb == 0)
112 		goto discard;
113 	if (so->so_state & SS_ISCONNECTED) {
114 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
115 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
116 			if (u.u_error) {
117 				splx(s);
118 				return;
119 			}
120 		}
121 		if ((so->so_options & SO_DONTLINGER) == 0) {
122 			if ((so->so_state & SS_ISDISCONNECTING) &&
123 			    (so->so_options & SO_NONBLOCKING)) {
124 				u.u_error = EINPROGRESS;
125 				splx(s);
126 				return;
127 			}
128 			/* should use tsleep here */
129 			while (so->so_state & SS_ISCONNECTED)
130 				sleep((caddr_t)&so->so_timeo, PZERO+1);
131 		}
132 	}
133 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
134 discard:
135 	so->so_state |= SS_USERGONE;
136 	sofree(so);
137 	splx(s);
138 }
139 
140 sosplice(pso, so)
141 	struct socket *pso, *so;
142 {
143 
144 COUNT(SOSPLICE);
145 	if (pso->so_proto->pr_family != PF_UNIX) {
146 		struct socket *tso;
147 		tso = pso; pso = so; so = tso;
148 	}
149 	if (pso->so_proto->pr_family != PF_UNIX)
150 		return (EOPNOTSUPP);
151 	/* check types and buffer space */
152 	/* merge buffers */
153 	return (0);
154 }
155 
156 /*ARGSUSED*/
157 sostat(so, sb)
158 	struct socket *so;
159 	struct stat *sb;
160 {
161 
162 COUNT(SOSTAT);
163 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
164 	return (0);					/* XXX */
165 }
166 
167 /*
168  * Accept connection on a socket.
169  */
170 soaccept(so, asa)
171 	struct socket *so;
172 	struct sockaddr *asa;
173 {
174 	int s = splnet();
175 	int error;
176 
177 COUNT(SOACCEPT);
178 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
179 		error = EINVAL;			/* XXX */
180 		goto bad;
181 	}
182 	if ((so->so_state & SS_CONNAWAITING) == 0) {
183 		error = ENOTCONN;
184 		goto bad;
185 	}
186 	so->so_state &= ~SS_CONNAWAITING;
187 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
188 bad:
189 	splx(s);
190 	return (error);
191 }
192 
193 /*
194  * Connect socket to a specified address.
195  * If already connected or connecting, then avoid
196  * the protocol entry, to keep its job simpler.
197  */
198 soconnect(so, asa)
199 	struct socket *so;
200 	struct sockaddr *asa;
201 {
202 	int s = splnet();
203 	int error;
204 
205 COUNT(SOCONNECT);
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 COUNT(SODISCONNECT);
230 	if ((so->so_state & SS_ISCONNECTED) == 0) {
231 		error = ENOTCONN;
232 		goto bad;
233 	}
234 	if (so->so_state & SS_ISDISCONNECTING) {
235 		error = EALREADY;
236 		goto bad;
237 	}
238 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
239 bad:
240 	splx(s);
241 	return (error);
242 }
243 
244 /*
245  * Send on a socket.
246  * If send must go all at once and message is larger than
247  * send buffering, then hard error.
248  * Lock against other senders.
249  * If must go all at once and not enough room now, then
250  * inform user that this would block and do nothing.
251  */
252 sosend(so, asa)
253 	register struct socket *so;
254 	struct sockaddr *asa;
255 {
256 	struct mbuf *top = 0;
257 	register struct mbuf *m, **mp = ⊤
258 	register u_int len;
259 	int error = 0, space, s;
260 
261 COUNT(SOSEND);
262 	if (so->so_state & SS_CANTSENDMORE)
263 		return (EPIPE);
264 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
265 		return (EMSGSIZE);
266 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NONBLOCKING))
267 		return (EWOULDBLOCK);
268 	sblock(&so->so_snd);
269 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
270 
271 	s = splnet();
272 again:
273 	if (so->so_error) {
274 		error = so->so_error;
275 		so->so_error = 0;
276 		splx(s);
277 		goto release;
278 	}
279 	if ((so->so_state & SS_ISCONNECTED) == 0) {
280 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
281 			snderr(ENOTCONN);
282 		if (asa == 0)
283 			snderr(EDESTADDRREQ);
284 	}
285 	if (top) {
286 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
287 		if (error) {
288 			splx(s);
289 			goto release;
290 		}
291 		top = 0;
292 		mp = ⊤
293 	}
294 	if (u.u_count == 0) {
295 		splx(s);
296 		goto release;
297 	}
298 	space = sbspace(&so->so_snd);
299 	if (space == 0 || sosendallatonce(so) && space < u.u_count) {
300 		if (so->so_options & SO_NONBLOCKING)
301 			snderr(EWOULDBLOCK);
302 		sbunlock(&so->so_snd);
303 		sbwait(&so->so_snd);
304 		splx(s);
305 		goto again;
306 	}
307 	splx(s);
308 	while (u.u_count && space > 0) {
309 		MGET(m, 1);
310 		if (m == NULL) {
311 			error = ENOBUFS;
312 			m_freem(top);
313 			goto release;
314 		}
315 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
316 			register struct mbuf *p;
317 			MCLGET(p, 1);
318 			if (p == 0)
319 				goto nopages;
320 			m->m_off = (int)p - (int)m;
321 			len = CLBYTES;
322 		} else {
323 nopages:
324 			m->m_off = MMINOFF;
325 			len = MIN(MLEN, u.u_count);
326 		}
327 		iomove(mtod(m, caddr_t), len, B_WRITE);
328 		m->m_len = len;
329 		*mp = m;
330 		mp = &m->m_next;
331 		space = sbspace(&so->so_snd);
332 	}
333 	s = splnet();
334 	goto again;
335 
336 release:
337 	sbunlock(&so->so_snd);
338 	return (error);
339 }
340 
341 soreceive(so, asa)
342 	register struct socket *so;
343 	struct sockaddr *asa;
344 {
345 	register struct mbuf *m, *n;
346 	u_int len;
347 	int eor, s, error = 0, cnt = u.u_count;
348 	caddr_t base = u.u_base;
349 
350 COUNT(SORECEIVE);
351 restart:
352 	sblock(&so->so_rcv);
353 	s = splnet();
354 
355 #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
356 	if (so->so_rcv.sb_cc == 0) {
357 		if (so->so_error) {
358 			error = so->so_error;
359 			so->so_error = 0;
360 			splx(s);
361 			goto release;
362 		}
363 		if (so->so_state & SS_CANTRCVMORE) {
364 			splx(s);
365 			goto release;
366 		}
367 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
368 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
369 			rcverr(ENOTCONN);
370 		if (so->so_options & SO_NONBLOCKING)
371 			rcverr(EWOULDBLOCK);
372 		sbunlock(&so->so_rcv);
373 		sbwait(&so->so_rcv);
374 		splx(s);
375 		goto restart;
376 	}
377 	m = so->so_rcv.sb_mb;
378 	if (m == 0)
379 		panic("receive");
380 	if (so->so_proto->pr_flags & PR_ADDR) {
381 		if (m->m_len != sizeof (struct sockaddr))
382 			panic("soreceive addr");
383 		if (asa)
384 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
385 		so->so_rcv.sb_cc -= m->m_len;
386 		so->so_rcv.sb_mbcnt -= MSIZE;
387 		m = m_free(m);
388 		if (m == 0)
389 			panic("receive 2");
390 		so->so_rcv.sb_mb = m;
391 	}
392 	so->so_state &= ~SS_RCVATMARK;
393 	if (so->so_oobmark && cnt > so->so_oobmark)
394 		cnt = so->so_oobmark;
395 	eor = 0;
396 	do {
397 		len = MIN(m->m_len, cnt);
398 		if (len == m->m_len) {
399 			eor = (int)m->m_act;
400 			sbfree(&so->so_rcv, m);
401 			so->so_rcv.sb_mb = m->m_next;
402 		}
403 		splx(s);
404 		iomove(mtod(m, caddr_t), len, B_READ);
405 		cnt -= len;
406 		s = splnet();
407 		if (len == m->m_len) {
408 			MFREE(m, n);
409 		} else {
410 			m->m_off += len;
411 			m->m_len -= len;
412 			so->so_rcv.sb_cc -= len;
413 		}
414 	} while ((m = so->so_rcv.sb_mb) && cnt && !eor);
415 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
416 		do {
417 			if (m == 0)
418 				panic("receive 3");
419 			sbfree(&so->so_rcv, m);
420 			eor = (int)m->m_act;
421 			so->so_rcv.sb_mb = m->m_next;
422 			MFREE(m, n);
423 			m = n;
424 		} while (eor == 0);
425 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
426 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
427 	if (so->so_oobmark) {
428 		so->so_oobmark -= u.u_base - base;
429 		if (so->so_oobmark == 0)
430 			so->so_state |= SS_RCVATMARK;
431 	}
432 release:
433 	sbunlock(&so->so_rcv);
434 	splx(s);
435 	return (error);
436 }
437 
438 sohasoutofband(so)
439 	struct socket *so;
440 {
441 
442 	if (so->so_pgrp == 0)
443 		return;
444 	if (so->so_pgrp > 0)
445 		gsignal(so->so_pgrp, SIGURG);
446 	else {
447 		struct proc *p = pfind(-so->so_pgrp);
448 
449 		if (p)
450 			psignal(p, SIGURG);
451 	}
452 }
453 
454 /*ARGSUSED*/
455 soioctl(so, cmd, cmdp)
456 	register struct socket *so;
457 	int cmd;
458 	register caddr_t cmdp;
459 {
460 
461 COUNT(SOIOCTL);
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_options |= SO_NONBLOCKING;
472 		else
473 			so->so_options &= ~SO_NONBLOCKING;
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 			;
485 		else
486 			;
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_NOKEEPALIVE;
498 		else
499 			so->so_options |= SO_NOKEEPALIVE;
500 		return;
501 	}
502 
503 	case SIOCGKEEP: {
504 		int keep = (so->so_options & SO_NOKEEPALIVE) == 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 		}
561 		if (flags & FWRITE)
562 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
563 		return;
564 	}
565 
566 	case SIOCSENDOOB: {
567 		char oob;
568 		struct mbuf *m;
569 		if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
570 			u.u_error = EFAULT;
571 			return;
572 		}
573 		m = m_get(M_DONTWAIT);
574 		if (m == 0) {
575 			u.u_error = ENOBUFS;
576 			return;
577 		}
578 		m->m_off = MMINOFF;
579 		m->m_len = 1;
580 		*mtod(m, caddr_t) = oob;
581 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
582 		return;
583 	}
584 
585 	case SIOCRCVOOB: {
586 		struct mbuf *m = m_get(M_DONTWAIT);
587 		if (m == 0) {
588 			u.u_error = ENOBUFS;
589 			return;
590 		}
591 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
592 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
593 		if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
594 			u.u_error = EFAULT;
595 			return;
596 		}
597 		m_free(m);
598 		return;
599 	}
600 
601 	case SIOCATMARK: {
602 		int atmark = (so->so_state&SS_RCVATMARK) != 0;
603 		if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
604 			u.u_error = EFAULT;
605 			return;
606 		}
607 		return;
608 	}
609 	}
610 	switch (so->so_type) {
611 
612 	case SOCK_STREAM:
613 		break;
614 
615 	case SOCK_DGRAM:
616 		break;
617 
618 	case SOCK_RDM:
619 		break;
620 
621 	case SOCK_RAW:
622 		break;
623 	}
624 }
625