new timeofday and interval timer stuff; itimers need testing
[unix-history] / usr / src / sys / kern / uipc_socket.c
CommitLineData
5699bf69 1/* uipc_socket.c 4.48 82/08/22 */
ce9d8eb4
BJ
2
3#include "../h/param.h"
92a533e6 4#include "../h/systm.h"
ce9d8eb4
BJ
5#include "../h/dir.h"
6#include "../h/user.h"
92a533e6
BJ
7#include "../h/proc.h"
8#include "../h/file.h"
ce9d8eb4 9#include "../h/inode.h"
92a533e6 10#include "../h/buf.h"
ce9d8eb4 11#include "../h/mbuf.h"
92a533e6
BJ
12#include "../h/protosw.h"
13#include "../h/socket.h"
14#include "../h/socketvar.h"
ae921915 15#include "../h/stat.h"
b8acc34d 16#include "../h/ioctl.h"
c5ff2e32
BJ
17#include "../net/in.h"
18#include "../net/in_systm.h"
2a4251c4 19#include "../net/route.h"
32a43ee2 20#include "../h/uio.h"
ce9d8eb4 21
ce9d8eb4 22/*
cc15ab5d
BJ
23 * Socket support routines.
24 *
25 * DEAL WITH INTERRUPT NOTIFICATION.
ce9d8eb4 26 */
ce9d8eb4
BJ
27
28/*
29 * Create a socket.
30 */
2b4b57cd 31socreate(aso, type, asp, asa, options)
ce9d8eb4
BJ
32 struct socket **aso;
33 int type;
2b4b57cd
BJ
34 struct sockproto *asp;
35 struct sockaddr *asa;
92a533e6 36 int options;
ce9d8eb4
BJ
37{
38 register struct protosw *prp;
39 register struct socket *so;
40 struct mbuf *m;
cc15ab5d 41 int pf, proto, error;
ce9d8eb4
BJ
42
43 /*
cc15ab5d
BJ
44 * Use process standard protocol/protocol family if none
45 * specified by address argument.
ce9d8eb4 46 */
2b4b57cd 47 if (asp == 0) {
cc15ab5d 48 pf = PF_INET; /* should be u.u_protof */
ce9d8eb4
BJ
49 proto = 0;
50 } else {
2b4b57cd
BJ
51 pf = asp->sp_family;
52 proto = asp->sp_protocol;
ce9d8eb4 53 }
cc15ab5d
BJ
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);
ce9d8eb4
BJ
65
66 /*
67 * Get a socket structure.
68 */
cc15ab5d 69 m = m_getclr(M_WAIT);
ce9d8eb4
BJ
70 if (m == 0)
71 return (ENOBUFS);
ce9d8eb4 72 so = mtod(m, struct socket *);
92a533e6 73 so->so_options = options;
90aaea96
BJ
74 if (options & SO_ACCEPTCONN) {
75 so->so_q = so;
76 so->so_q0 = so;
77 so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1;
78 }
62364f0e
BJ
79 so->so_state = 0;
80 if (u.u_uid == 0)
81 so->so_state = SS_PRIV;
ce9d8eb4
BJ
82
83 /*
cc15ab5d
BJ
84 * Attach protocol to socket, initializing
85 * and reserving resources.
ce9d8eb4
BJ
86 */
87 so->so_proto = prp;
b91acce4
BJ
88 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
89 if (error) {
90aaea96 90 so->so_state |= SS_NOFDREF;
de48daf3 91 sofree(so);
cc15ab5d 92 return (error);
ce9d8eb4
BJ
93 }
94 *aso = so;
95 return (0);
96}
97
ae921915
BJ
98sofree(so)
99 struct socket *so;
100{
101
90aaea96
BJ
102 if (so->so_head) {
103 if (!soqremque(so, 0) && !soqremque(so, 1))
104 panic("sofree dq");
105 so->so_head = 0;
106 }
107 if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
4ad99bae
BJ
108 return;
109 sbrelease(&so->so_snd);
110 sbrelease(&so->so_rcv);
2752c877 111 (void) m_free(dtom(so));
ae921915
BJ
112}
113
92a533e6 114/*
cc15ab5d
BJ
115 * Close a socket on last file table reference removal.
116 * Initiate disconnect if connected.
117 * Free socket when disconnect complete.
92a533e6 118 */
89900a09 119soclose(so, exiting)
92a533e6 120 register struct socket *so;
89900a09 121 int exiting;
92a533e6 122{
cc15ab5d
BJ
123 int s = splnet(); /* conservative */
124
90aaea96
BJ
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 }
cc15ab5d
BJ
131 if (so->so_pcb == 0)
132 goto discard;
1ee9e088
BJ
133 if (exiting)
134 so->so_options |= SO_KEEPALIVE;
cc15ab5d
BJ
135 if (so->so_state & SS_ISCONNECTED) {
136 if ((so->so_state & SS_ISDISCONNECTING) == 0) {
2b4b57cd 137 u.u_error = sodisconnect(so, (struct sockaddr *)0);
cc15ab5d 138 if (u.u_error) {
89900a09
BJ
139 if (exiting)
140 goto drop;
cc15ab5d
BJ
141 splx(s);
142 return;
143 }
144 }
30b84e26 145 if ((so->so_options & SO_DONTLINGER) == 0) {
b8acc34d 146 if ((so->so_state & SS_ISDISCONNECTING) &&
62364f0e 147 (so->so_state & SS_NBIO) &&
89900a09 148 exiting == 0) {
b8acc34d
BJ
149 u.u_error = EINPROGRESS;
150 splx(s);
151 return;
152 }
89900a09 153 /* should use tsleep here, for at most linger */
b8acc34d
BJ
154 while (so->so_state & SS_ISCONNECTED)
155 sleep((caddr_t)&so->so_timeo, PZERO+1);
72857acf 156 }
cc15ab5d 157 }
89900a09 158drop:
37c0974a
SL
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 }
cc15ab5d 166discard:
90aaea96 167 so->so_state |= SS_NOFDREF;
4ad99bae 168 sofree(so);
cc15ab5d 169 splx(s);
92a533e6
BJ
170}
171
ae921915 172/*ARGSUSED*/
cc15ab5d 173sostat(so, sb)
92a533e6 174 struct socket *so;
cc15ab5d 175 struct stat *sb;
92a533e6
BJ
176{
177
5e35cca3
BJ
178 bzero((caddr_t)sb, sizeof (*sb)); /* XXX */
179 return (0); /* XXX */
92a533e6
BJ
180}
181
2b4b57cd
BJ
182/*
183 * Accept connection on a socket.
184 */
185soaccept(so, asa)
186 struct socket *so;
187 struct sockaddr *asa;
188{
189 int s = splnet();
190 int error;
191
2b4b57cd 192 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
2b4b57cd
BJ
193 splx(s);
194 return (error);
195}
196
ce9d8eb4 197/*
cc15ab5d
BJ
198 * Connect socket to a specified address.
199 * If already connected or connecting, then avoid
200 * the protocol entry, to keep its job simpler.
ce9d8eb4 201 */
2b4b57cd 202soconnect(so, asa)
ce9d8eb4 203 struct socket *so;
2b4b57cd 204 struct sockaddr *asa;
ce9d8eb4 205{
cc15ab5d
BJ
206 int s = splnet();
207 int error;
ce9d8eb4 208
cc15ab5d
BJ
209 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
210 error = EISCONN;
211 goto bad;
212 }
2b4b57cd 213 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
cc15ab5d
BJ
214bad:
215 splx(s);
216 return (error);
ce9d8eb4
BJ
217}
218
219/*
cc15ab5d
BJ
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.
ce9d8eb4 224 */
2b4b57cd 225sodisconnect(so, asa)
ce9d8eb4 226 struct socket *so;
2b4b57cd 227 struct sockaddr *asa;
ce9d8eb4 228{
cc15ab5d
BJ
229 int s = splnet();
230 int error;
ce9d8eb4 231
cc15ab5d
BJ
232 if ((so->so_state & SS_ISCONNECTED) == 0) {
233 error = ENOTCONN;
234 goto bad;
ce9d8eb4 235 }
cc15ab5d
BJ
236 if (so->so_state & SS_ISDISCONNECTING) {
237 error = EALREADY;
238 goto bad;
ce9d8eb4 239 }
2b4b57cd 240 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
cc15ab5d
BJ
241bad:
242 splx(s);
243 return (error);
ce9d8eb4
BJ
244}
245
cc15ab5d
BJ
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 */
5699bf69 254sosend(so, asa, uio)
ce9d8eb4 255 register struct socket *so;
2b4b57cd 256 struct sockaddr *asa;
5699bf69 257 struct uio *uio;
ce9d8eb4 258{
cc15ab5d
BJ
259 struct mbuf *top = 0;
260 register struct mbuf *m, **mp = ⊤
ae921915
BJ
261 register u_int len;
262 int error = 0, space, s;
ce9d8eb4 263
5699bf69 264 if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
cc15ab5d 265 return (EMSGSIZE);
0f90f987
BJ
266#ifdef notdef
267 /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
62364f0e 268 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
cc15ab5d 269 return (EWOULDBLOCK);
0f90f987
BJ
270#endif
271restart:
cc15ab5d
BJ
272 sblock(&so->so_snd);
273#define snderr(errno) { error = errno; splx(s); goto release; }
274
cc15ab5d 275again:
0f90f987
BJ
276 s = splnet();
277 if (so->so_state & SS_CANTSENDMORE) {
278 psignal(u.u_procp, SIGPIPE);
279 snderr(EPIPE);
280 }
4c078bb2
BJ
281 if (so->so_error) {
282 error = so->so_error;
0f90f987 283 so->so_error = 0; /* ??? */
4c078bb2
BJ
284 splx(s);
285 goto release;
286 }
cc15ab5d
BJ
287 if ((so->so_state & SS_ISCONNECTED) == 0) {
288 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
289 snderr(ENOTCONN);
2b4b57cd 290 if (asa == 0)
cc15ab5d
BJ
291 snderr(EDESTADDRREQ);
292 }
cc15ab5d 293 if (top) {
2b4b57cd 294 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
0f90f987 295 top = 0;
cc15ab5d
BJ
296 if (error) {
297 splx(s);
ce9d8eb4
BJ
298 goto release;
299 }
cc15ab5d 300 mp = ⊤
ce9d8eb4 301 }
5699bf69 302 if (uio->uio_resid == 0) {
b91acce4
BJ
303 splx(s);
304 goto release;
305 }
50fc8df6 306 space = sbspace(&so->so_snd);
5699bf69 307 if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) {
62364f0e 308 if (so->so_state & SS_NBIO)
cc15ab5d
BJ
309 snderr(EWOULDBLOCK);
310 sbunlock(&so->so_snd);
311 sbwait(&so->so_snd);
312 splx(s);
0f90f987 313 goto restart;
ce9d8eb4 314 }
cc15ab5d 315 splx(s);
5699bf69
BJ
316 while (uio->uio_resid > 0 && space > 0) {
317 register struct iovec *iov = uio->uio_iov;
318
319 if (iov->iov_len == 0) {
320 uio->uio_iov++;
321 uio->uio_iovcnt--;
322 if (uio->uio_iovcnt < 0)
323 panic("sosend");
324 continue;
325 }
cc15ab5d
BJ
326 MGET(m, 1);
327 if (m == NULL) {
0f90f987 328 error = ENOBUFS; /* SIGPIPE? */
cc15ab5d 329 goto release;
ce9d8eb4 330 }
5699bf69 331 if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
cc15ab5d 332 register struct mbuf *p;
c5ff2e32 333 MCLGET(p, 1);
cc15ab5d
BJ
334 if (p == 0)
335 goto nopages;
336 m->m_off = (int)p - (int)m;
c5ff2e32 337 len = CLBYTES;
cc15ab5d 338 } else {
ce9d8eb4 339nopages:
cc15ab5d 340 m->m_off = MMINOFF;
5699bf69 341 len = MIN(MLEN, iov->iov_len);
ce9d8eb4 342 }
5699bf69 343 uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
cc15ab5d
BJ
344 m->m_len = len;
345 *mp = m;
346 mp = &m->m_next;
50fc8df6 347 space = sbspace(&so->so_snd);
ce9d8eb4 348 }
cc15ab5d
BJ
349 goto again;
350
ce9d8eb4 351release:
cc15ab5d 352 sbunlock(&so->so_snd);
0f90f987
BJ
353 if (top)
354 m_freem(top);
ce9d8eb4
BJ
355 return (error);
356}
357
32a43ee2 358soreceive(so, asa, uio)
ce9d8eb4 359 register struct socket *so;
2b4b57cd 360 struct sockaddr *asa;
32a43ee2 361 struct uio *uio;
ce9d8eb4 362{
32a43ee2 363 register struct iovec *iov;
ce9d8eb4 364 register struct mbuf *m, *n;
ae921915 365 u_int len;
5699bf69 366 int eor, s, error = 0;
ce9d8eb4 367
cc15ab5d
BJ
368restart:
369 sblock(&so->so_rcv);
370 s = splnet();
371
372#define rcverr(errno) { error = errno; splx(s); goto release; }
ce9d8eb4 373 if (so->so_rcv.sb_cc == 0) {
4c078bb2
BJ
374 if (so->so_error) {
375 error = so->so_error;
376 so->so_error = 0;
377 splx(s);
378 goto release;
379 }
cc15ab5d
BJ
380 if (so->so_state & SS_CANTRCVMORE) {
381 splx(s);
382 goto release;
383 }
196d84fd
BJ
384 if ((so->so_state & SS_ISCONNECTED) == 0 &&
385 (so->so_proto->pr_flags & PR_CONNREQUIRED))
386 rcverr(ENOTCONN);
62364f0e 387 if (so->so_state & SS_NBIO)
4c078bb2 388 rcverr(EWOULDBLOCK);
cc15ab5d 389 sbunlock(&so->so_rcv);
2752c877 390 sbwait(&so->so_rcv);
a4f6d93d 391 splx(s);
cc15ab5d 392 goto restart;
ce9d8eb4 393 }
92a533e6 394 m = so->so_rcv.sb_mb;
ce9d8eb4
BJ
395 if (m == 0)
396 panic("receive");
b031e888 397 if (so->so_proto->pr_flags & PR_ADDR) {
b031e888
BJ
398 if (m->m_len != sizeof (struct sockaddr))
399 panic("soreceive addr");
400 if (asa)
401 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
b031e888
BJ
402 so->so_rcv.sb_cc -= m->m_len;
403 so->so_rcv.sb_mbcnt -= MSIZE;
50fc8df6 404 m = m_free(m);
cc15ab5d
BJ
405 if (m == 0)
406 panic("receive 2");
50fc8df6 407 so->so_rcv.sb_mb = m;
cc15ab5d 408 }
ce9d8eb4
BJ
409 eor = 0;
410 do {
5699bf69 411 if (uio->uio_resid <= 0)
32a43ee2 412 break;
5699bf69 413 len = uio->uio_resid;
32a43ee2
BJ
414 so->so_state &= ~SS_RCVATMARK;
415 if (so->so_oobmark && len > so->so_oobmark)
416 len = so->so_oobmark;
417 if (len > m->m_len)
418 len = m->m_len;
ce9d8eb4 419 splx(s);
5699bf69 420 uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
ce9d8eb4
BJ
421 s = splnet();
422 if (len == m->m_len) {
e495e1cc
BJ
423 eor = (int)m->m_act;
424 sbfree(&so->so_rcv, m);
425 so->so_rcv.sb_mb = m->m_next;
ce9d8eb4
BJ
426 MFREE(m, n);
427 } else {
428 m->m_off += len;
429 m->m_len -= len;
92a533e6 430 so->so_rcv.sb_cc -= len;
ce9d8eb4 431 }
32a43ee2
BJ
432 if (so->so_oobmark) {
433 so->so_oobmark -= len;
434 if (so->so_oobmark == 0) {
435 so->so_state |= SS_RCVATMARK;
436 break;
437 }
438 }
439 } while ((m = so->so_rcv.sb_mb) && !eor);
ce9d8eb4
BJ
440 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
441 do {
ce9d8eb4 442 if (m == 0)
cc15ab5d
BJ
443 panic("receive 3");
444 sbfree(&so->so_rcv, m);
ce9d8eb4
BJ
445 eor = (int)m->m_act;
446 so->so_rcv.sb_mb = m->m_next;
447 MFREE(m, n);
cc15ab5d 448 m = n;
ce9d8eb4 449 } while (eor == 0);
cc15ab5d
BJ
450 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
451 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
cc15ab5d 452release:
ae921915 453 sbunlock(&so->so_rcv);
cc15ab5d 454 splx(s);
ae921915 455 return (error);
92a533e6
BJ
456}
457
edebca28
BJ
458sohasoutofband(so)
459 struct socket *so;
460{
461
462 if (so->so_pgrp == 0)
463 return;
464 if (so->so_pgrp > 0)
465 gsignal(so->so_pgrp, SIGURG);
0a0f7cbb
BJ
466 else {
467 struct proc *p = pfind(-so->so_pgrp);
468
469 if (p)
470 psignal(p, SIGURG);
471 }
edebca28
BJ
472}
473
ae921915 474/*ARGSUSED*/
4b72e2f9 475soioctl(so, cmd, data)
92a533e6
BJ
476 register struct socket *so;
477 int cmd;
4b72e2f9 478 register char *data;
92a533e6
BJ
479{
480
2156d53c 481 switch (cmd) {
92a533e6 482
4b72e2f9
SL
483 case FIONBIO:
484 if (*(int *)data)
62364f0e 485 so->so_state |= SS_NBIO;
30b84e26 486 else
62364f0e 487 so->so_state &= ~SS_NBIO;
30b84e26 488 return;
30b84e26 489
4b72e2f9
SL
490 case FIOASYNC:
491 if (*(int *)data)
62364f0e 492 so->so_state |= SS_ASYNC;
30b84e26 493 else
62364f0e 494 so->so_state &= ~SS_ASYNC;
30b84e26 495 return;
30b84e26 496
4b72e2f9
SL
497 case SIOCSKEEP:
498 if (*(int *)data)
9d2f171f 499 so->so_options &= ~SO_KEEPALIVE;
90aaea96
BJ
500 else
501 so->so_options |= SO_KEEPALIVE;
30b84e26 502 return;
30b84e26 503
4b72e2f9
SL
504 case SIOCGKEEP:
505 *(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
30b84e26 506 return;
30b84e26 507
4b72e2f9
SL
508 case SIOCSLINGER:
509 so->so_linger = *(int *)data;
30b84e26
BJ
510 if (so->so_linger)
511 so->so_options &= ~SO_DONTLINGER;
512 else
513 so->so_options |= SO_DONTLINGER;
514 return;
30b84e26 515
4b72e2f9
SL
516 case SIOCGLINGER:
517 *(int *)data = so->so_linger;
edebca28 518 return;
edebca28 519
4b72e2f9
SL
520 case SIOCSPGRP:
521 so->so_pgrp = *(int *)data;
522 return;
523
524 case SIOCGPGRP:
525 *(int *)data = so->so_pgrp;
526 return;
30b84e26 527
b8acc34d 528 case SIOCDONE: {
4b72e2f9
SL
529 int flags = *(int *)data;
530
30b84e26 531 flags++;
b8acc34d
BJ
532 if (flags & FREAD) {
533 int s = splimp();
534 socantrcvmore(so);
535 sbflush(&so->so_rcv);
785e10b7 536 splx(s);
b8acc34d
BJ
537 }
538 if (flags & FWRITE)
c30cd845 539 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
b8acc34d
BJ
540 return;
541 }
542
edebca28 543 case SIOCSENDOOB: {
4b72e2f9 544 char oob = *(char *)data;
edebca28 545 struct mbuf *m;
4b72e2f9 546
edebca28
BJ
547 m = m_get(M_DONTWAIT);
548 if (m == 0) {
549 u.u_error = ENOBUFS;
550 return;
551 }
552 m->m_off = MMINOFF;
4b72e2f9
SL
553 m->m_len = sizeof (char);
554 *mtod(m, char *) = oob;
edebca28
BJ
555 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
556 return;
557 }
558
559 case SIOCRCVOOB: {
560 struct mbuf *m = m_get(M_DONTWAIT);
4b72e2f9 561
edebca28
BJ
562 if (m == 0) {
563 u.u_error = ENOBUFS;
564 return;
565 }
566 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
567 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
4b72e2f9
SL
568 *(char *)data = *mtod(m, char *);
569 (void) m_free(m);
edebca28
BJ
570 return;
571 }
572
4b72e2f9
SL
573 case SIOCATMARK:
574 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
edebca28 575 return;
2a4251c4
SL
576
577 /* routing table update calls */
578 case SIOCADDRT:
579 case SIOCDELRT:
2a4251c4
SL
580 if (!suser())
581 return;
4b72e2f9 582 u.u_error = rtrequest(cmd, (struct rtentry *)data);
2a4251c4 583 return;
2a4251c4 584
5e1eeba0 585 /* type/protocol specific ioctls */
92a533e6 586 }
5e1eeba0 587 u.u_error = EOPNOTSUPP;
ce9d8eb4 588}