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