kernel.h include for lbolt
[unix-history] / usr / src / sys / kern / uipc_socket.c
CommitLineData
c7256358 1/* uipc_socket.c 4.49 82/09/04 */
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
c7256358 275 u.u_ru.ru_msgsnd++;
cc15ab5d 276again:
0f90f987
BJ
277 s = splnet();
278 if (so->so_state & SS_CANTSENDMORE) {
279 psignal(u.u_procp, SIGPIPE);
280 snderr(EPIPE);
281 }
4c078bb2
BJ
282 if (so->so_error) {
283 error = so->so_error;
0f90f987 284 so->so_error = 0; /* ??? */
4c078bb2
BJ
285 splx(s);
286 goto release;
287 }
cc15ab5d
BJ
288 if ((so->so_state & SS_ISCONNECTED) == 0) {
289 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
290 snderr(ENOTCONN);
2b4b57cd 291 if (asa == 0)
cc15ab5d
BJ
292 snderr(EDESTADDRREQ);
293 }
cc15ab5d 294 if (top) {
2b4b57cd 295 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
0f90f987 296 top = 0;
cc15ab5d
BJ
297 if (error) {
298 splx(s);
ce9d8eb4
BJ
299 goto release;
300 }
cc15ab5d 301 mp = ⊤
ce9d8eb4 302 }
5699bf69 303 if (uio->uio_resid == 0) {
b91acce4
BJ
304 splx(s);
305 goto release;
306 }
50fc8df6 307 space = sbspace(&so->so_snd);
5699bf69 308 if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) {
62364f0e 309 if (so->so_state & SS_NBIO)
cc15ab5d
BJ
310 snderr(EWOULDBLOCK);
311 sbunlock(&so->so_snd);
312 sbwait(&so->so_snd);
313 splx(s);
0f90f987 314 goto restart;
ce9d8eb4 315 }
cc15ab5d 316 splx(s);
5699bf69
BJ
317 while (uio->uio_resid > 0 && space > 0) {
318 register struct iovec *iov = uio->uio_iov;
319
320 if (iov->iov_len == 0) {
321 uio->uio_iov++;
322 uio->uio_iovcnt--;
323 if (uio->uio_iovcnt < 0)
324 panic("sosend");
325 continue;
326 }
cc15ab5d
BJ
327 MGET(m, 1);
328 if (m == NULL) {
0f90f987 329 error = ENOBUFS; /* SIGPIPE? */
cc15ab5d 330 goto release;
ce9d8eb4 331 }
5699bf69 332 if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
cc15ab5d 333 register struct mbuf *p;
c5ff2e32 334 MCLGET(p, 1);
cc15ab5d
BJ
335 if (p == 0)
336 goto nopages;
337 m->m_off = (int)p - (int)m;
c5ff2e32 338 len = CLBYTES;
cc15ab5d 339 } else {
ce9d8eb4 340nopages:
cc15ab5d 341 m->m_off = MMINOFF;
5699bf69 342 len = MIN(MLEN, iov->iov_len);
ce9d8eb4 343 }
5699bf69 344 uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
cc15ab5d
BJ
345 m->m_len = len;
346 *mp = m;
347 mp = &m->m_next;
50fc8df6 348 space = sbspace(&so->so_snd);
ce9d8eb4 349 }
cc15ab5d
BJ
350 goto again;
351
ce9d8eb4 352release:
cc15ab5d 353 sbunlock(&so->so_snd);
0f90f987
BJ
354 if (top)
355 m_freem(top);
ce9d8eb4
BJ
356 return (error);
357}
358
32a43ee2 359soreceive(so, asa, uio)
ce9d8eb4 360 register struct socket *so;
2b4b57cd 361 struct sockaddr *asa;
32a43ee2 362 struct uio *uio;
ce9d8eb4 363{
32a43ee2 364 register struct iovec *iov;
ce9d8eb4 365 register struct mbuf *m, *n;
ae921915 366 u_int len;
5699bf69 367 int eor, s, error = 0;
ce9d8eb4 368
cc15ab5d
BJ
369restart:
370 sblock(&so->so_rcv);
371 s = splnet();
372
373#define rcverr(errno) { error = errno; splx(s); goto release; }
ce9d8eb4 374 if (so->so_rcv.sb_cc == 0) {
4c078bb2
BJ
375 if (so->so_error) {
376 error = so->so_error;
377 so->so_error = 0;
378 splx(s);
379 goto release;
380 }
cc15ab5d
BJ
381 if (so->so_state & SS_CANTRCVMORE) {
382 splx(s);
383 goto release;
384 }
196d84fd
BJ
385 if ((so->so_state & SS_ISCONNECTED) == 0 &&
386 (so->so_proto->pr_flags & PR_CONNREQUIRED))
387 rcverr(ENOTCONN);
62364f0e 388 if (so->so_state & SS_NBIO)
4c078bb2 389 rcverr(EWOULDBLOCK);
cc15ab5d 390 sbunlock(&so->so_rcv);
2752c877 391 sbwait(&so->so_rcv);
a4f6d93d 392 splx(s);
cc15ab5d 393 goto restart;
ce9d8eb4 394 }
c7256358 395 u.u_ru.ru_msgrcv++;
92a533e6 396 m = so->so_rcv.sb_mb;
ce9d8eb4
BJ
397 if (m == 0)
398 panic("receive");
b031e888 399 if (so->so_proto->pr_flags & PR_ADDR) {
b031e888
BJ
400 if (m->m_len != sizeof (struct sockaddr))
401 panic("soreceive addr");
402 if (asa)
403 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
b031e888
BJ
404 so->so_rcv.sb_cc -= m->m_len;
405 so->so_rcv.sb_mbcnt -= MSIZE;
50fc8df6 406 m = m_free(m);
cc15ab5d
BJ
407 if (m == 0)
408 panic("receive 2");
50fc8df6 409 so->so_rcv.sb_mb = m;
cc15ab5d 410 }
ce9d8eb4
BJ
411 eor = 0;
412 do {
5699bf69 413 if (uio->uio_resid <= 0)
32a43ee2 414 break;
5699bf69 415 len = uio->uio_resid;
32a43ee2
BJ
416 so->so_state &= ~SS_RCVATMARK;
417 if (so->so_oobmark && len > so->so_oobmark)
418 len = so->so_oobmark;
419 if (len > m->m_len)
420 len = m->m_len;
ce9d8eb4 421 splx(s);
5699bf69 422 uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
ce9d8eb4
BJ
423 s = splnet();
424 if (len == m->m_len) {
e495e1cc
BJ
425 eor = (int)m->m_act;
426 sbfree(&so->so_rcv, m);
427 so->so_rcv.sb_mb = m->m_next;
ce9d8eb4
BJ
428 MFREE(m, n);
429 } else {
430 m->m_off += len;
431 m->m_len -= len;
92a533e6 432 so->so_rcv.sb_cc -= len;
ce9d8eb4 433 }
32a43ee2
BJ
434 if (so->so_oobmark) {
435 so->so_oobmark -= len;
436 if (so->so_oobmark == 0) {
437 so->so_state |= SS_RCVATMARK;
438 break;
439 }
440 }
441 } while ((m = so->so_rcv.sb_mb) && !eor);
ce9d8eb4
BJ
442 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
443 do {
ce9d8eb4 444 if (m == 0)
cc15ab5d
BJ
445 panic("receive 3");
446 sbfree(&so->so_rcv, m);
ce9d8eb4
BJ
447 eor = (int)m->m_act;
448 so->so_rcv.sb_mb = m->m_next;
449 MFREE(m, n);
cc15ab5d 450 m = n;
ce9d8eb4 451 } while (eor == 0);
cc15ab5d
BJ
452 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
453 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
cc15ab5d 454release:
ae921915 455 sbunlock(&so->so_rcv);
cc15ab5d 456 splx(s);
ae921915 457 return (error);
92a533e6
BJ
458}
459
edebca28
BJ
460sohasoutofband(so)
461 struct socket *so;
462{
463
464 if (so->so_pgrp == 0)
465 return;
466 if (so->so_pgrp > 0)
467 gsignal(so->so_pgrp, SIGURG);
0a0f7cbb
BJ
468 else {
469 struct proc *p = pfind(-so->so_pgrp);
470
471 if (p)
472 psignal(p, SIGURG);
473 }
edebca28
BJ
474}
475
ae921915 476/*ARGSUSED*/
4b72e2f9 477soioctl(so, cmd, data)
92a533e6
BJ
478 register struct socket *so;
479 int cmd;
4b72e2f9 480 register char *data;
92a533e6
BJ
481{
482
2156d53c 483 switch (cmd) {
92a533e6 484
4b72e2f9
SL
485 case FIONBIO:
486 if (*(int *)data)
62364f0e 487 so->so_state |= SS_NBIO;
30b84e26 488 else
62364f0e 489 so->so_state &= ~SS_NBIO;
30b84e26 490 return;
30b84e26 491
4b72e2f9
SL
492 case FIOASYNC:
493 if (*(int *)data)
62364f0e 494 so->so_state |= SS_ASYNC;
30b84e26 495 else
62364f0e 496 so->so_state &= ~SS_ASYNC;
30b84e26 497 return;
30b84e26 498
4b72e2f9
SL
499 case SIOCSKEEP:
500 if (*(int *)data)
9d2f171f 501 so->so_options &= ~SO_KEEPALIVE;
90aaea96
BJ
502 else
503 so->so_options |= SO_KEEPALIVE;
30b84e26 504 return;
30b84e26 505
4b72e2f9
SL
506 case SIOCGKEEP:
507 *(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
30b84e26 508 return;
30b84e26 509
4b72e2f9
SL
510 case SIOCSLINGER:
511 so->so_linger = *(int *)data;
30b84e26
BJ
512 if (so->so_linger)
513 so->so_options &= ~SO_DONTLINGER;
514 else
515 so->so_options |= SO_DONTLINGER;
516 return;
30b84e26 517
4b72e2f9
SL
518 case SIOCGLINGER:
519 *(int *)data = so->so_linger;
edebca28 520 return;
edebca28 521
4b72e2f9
SL
522 case SIOCSPGRP:
523 so->so_pgrp = *(int *)data;
524 return;
525
526 case SIOCGPGRP:
527 *(int *)data = so->so_pgrp;
528 return;
30b84e26 529
b8acc34d 530 case SIOCDONE: {
4b72e2f9
SL
531 int flags = *(int *)data;
532
30b84e26 533 flags++;
b8acc34d
BJ
534 if (flags & FREAD) {
535 int s = splimp();
536 socantrcvmore(so);
537 sbflush(&so->so_rcv);
785e10b7 538 splx(s);
b8acc34d
BJ
539 }
540 if (flags & FWRITE)
c30cd845 541 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
b8acc34d
BJ
542 return;
543 }
544
edebca28 545 case SIOCSENDOOB: {
4b72e2f9 546 char oob = *(char *)data;
edebca28 547 struct mbuf *m;
4b72e2f9 548
edebca28
BJ
549 m = m_get(M_DONTWAIT);
550 if (m == 0) {
551 u.u_error = ENOBUFS;
552 return;
553 }
554 m->m_off = MMINOFF;
4b72e2f9
SL
555 m->m_len = sizeof (char);
556 *mtod(m, char *) = oob;
edebca28
BJ
557 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
558 return;
559 }
560
561 case SIOCRCVOOB: {
562 struct mbuf *m = m_get(M_DONTWAIT);
4b72e2f9 563
edebca28
BJ
564 if (m == 0) {
565 u.u_error = ENOBUFS;
566 return;
567 }
568 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
569 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
4b72e2f9
SL
570 *(char *)data = *mtod(m, char *);
571 (void) m_free(m);
edebca28
BJ
572 return;
573 }
574
4b72e2f9
SL
575 case SIOCATMARK:
576 *(int *)data = (so->so_state&SS_RCVATMARK) != 0;
edebca28 577 return;
2a4251c4
SL
578
579 /* routing table update calls */
580 case SIOCADDRT:
581 case SIOCDELRT:
2a4251c4
SL
582 if (!suser())
583 return;
4b72e2f9 584 u.u_error = rtrequest(cmd, (struct rtentry *)data);
2a4251c4 585 return;
2a4251c4 586
5e1eeba0 587 /* type/protocol specific ioctls */
92a533e6 588 }
5e1eeba0 589 u.u_error = EOPNOTSUPP;
ce9d8eb4 590}