big footnotes, too.
[unix-history] / usr / src / sys / kern / uipc_socket.c
CommitLineData
785e10b7 1/* uipc_socket.c 4.33 82/03/12 */
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"
ce9d8eb4 19
ce9d8eb4 20/*
cc15ab5d
BJ
21 * Socket support routines.
22 *
23 * DEAL WITH INTERRUPT NOTIFICATION.
ce9d8eb4 24 */
ce9d8eb4
BJ
25
26/*
27 * Create a socket.
28 */
2b4b57cd 29socreate(aso, type, asp, asa, options)
ce9d8eb4
BJ
30 struct socket **aso;
31 int type;
2b4b57cd
BJ
32 struct sockproto *asp;
33 struct sockaddr *asa;
92a533e6 34 int options;
ce9d8eb4
BJ
35{
36 register struct protosw *prp;
37 register struct socket *so;
38 struct mbuf *m;
cc15ab5d 39 int pf, proto, error;
2b4b57cd 40COUNT(SOCREATE);
ce9d8eb4
BJ
41
42 /*
cc15ab5d
BJ
43 * Use process standard protocol/protocol family if none
44 * specified by address argument.
ce9d8eb4 45 */
2b4b57cd 46 if (asp == 0) {
cc15ab5d 47 pf = PF_INET; /* should be u.u_protof */
ce9d8eb4
BJ
48 proto = 0;
49 } else {
2b4b57cd
BJ
50 pf = asp->sp_family;
51 proto = asp->sp_protocol;
ce9d8eb4 52 }
cc15ab5d
BJ
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);
ce9d8eb4
BJ
64
65 /*
66 * Get a socket structure.
67 */
cc15ab5d 68 m = m_getclr(M_WAIT);
ce9d8eb4
BJ
69 if (m == 0)
70 return (ENOBUFS);
ce9d8eb4 71 so = mtod(m, struct socket *);
92a533e6 72 so->so_options = options;
ce9d8eb4
BJ
73
74 /*
cc15ab5d
BJ
75 * Attach protocol to socket, initializing
76 * and reserving resources.
ce9d8eb4
BJ
77 */
78 so->so_proto = prp;
b91acce4
BJ
79 error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
80 if (error) {
2752c877 81 (void) m_free(dtom(so));
cc15ab5d 82 return (error);
ce9d8eb4
BJ
83 }
84 *aso = so;
85 return (0);
86}
87
ae921915
BJ
88sofree(so)
89 struct socket *so;
90{
91
2b4b57cd 92COUNT(SOFREE);
4ad99bae
BJ
93 if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
94 return;
95 sbrelease(&so->so_snd);
96 sbrelease(&so->so_rcv);
2752c877 97 (void) m_free(dtom(so));
ae921915
BJ
98}
99
92a533e6 100/*
cc15ab5d
BJ
101 * Close a socket on last file table reference removal.
102 * Initiate disconnect if connected.
103 * Free socket when disconnect complete.
89900a09
BJ
104 *
105 * THIS IS REALLY A UNIX INTERFACE ROUTINE
92a533e6 106 */
89900a09 107soclose(so, exiting)
92a533e6 108 register struct socket *so;
89900a09 109 int exiting;
92a533e6 110{
cc15ab5d
BJ
111 int s = splnet(); /* conservative */
112
2b4b57cd 113COUNT(SOCLOSE);
cc15ab5d
BJ
114 if (so->so_pcb == 0)
115 goto discard;
116 if (so->so_state & SS_ISCONNECTED) {
117 if ((so->so_state & SS_ISDISCONNECTING) == 0) {
2b4b57cd 118 u.u_error = sodisconnect(so, (struct sockaddr *)0);
cc15ab5d 119 if (u.u_error) {
89900a09
BJ
120 if (exiting)
121 goto drop;
cc15ab5d
BJ
122 splx(s);
123 return;
124 }
125 }
30b84e26 126 if ((so->so_options & SO_DONTLINGER) == 0) {
b8acc34d 127 if ((so->so_state & SS_ISDISCONNECTING) &&
89900a09
BJ
128 (so->so_options & SO_NONBLOCKING) &&
129 exiting == 0) {
b8acc34d
BJ
130 u.u_error = EINPROGRESS;
131 splx(s);
132 return;
133 }
89900a09 134 /* should use tsleep here, for at most linger */
b8acc34d
BJ
135 while (so->so_state & SS_ISCONNECTED)
136 sleep((caddr_t)&so->so_timeo, PZERO+1);
72857acf 137 }
cc15ab5d 138 }
89900a09 139drop:
cc15ab5d
BJ
140 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
141discard:
4ad99bae
BJ
142 so->so_state |= SS_USERGONE;
143 sofree(so);
cc15ab5d 144 splx(s);
92a533e6
BJ
145}
146
2b4b57cd
BJ
147sosplice(pso, so)
148 struct socket *pso, *so;
149{
150
151COUNT(SOSPLICE);
4c078bb2 152 if (pso->so_proto->pr_family != PF_UNIX) {
2b4b57cd
BJ
153 struct socket *tso;
154 tso = pso; pso = so; so = tso;
155 }
4c078bb2 156 if (pso->so_proto->pr_family != PF_UNIX)
2b4b57cd
BJ
157 return (EOPNOTSUPP);
158 /* check types and buffer space */
159 /* merge buffers */
160 return (0);
161}
162
ae921915 163/*ARGSUSED*/
cc15ab5d 164sostat(so, sb)
92a533e6 165 struct socket *so;
cc15ab5d 166 struct stat *sb;
92a533e6
BJ
167{
168
2b4b57cd 169COUNT(SOSTAT);
5e35cca3
BJ
170 bzero((caddr_t)sb, sizeof (*sb)); /* XXX */
171 return (0); /* XXX */
92a533e6
BJ
172}
173
2b4b57cd
BJ
174/*
175 * Accept connection on a socket.
176 */
177soaccept(so, asa)
178 struct socket *so;
179 struct sockaddr *asa;
180{
181 int s = splnet();
182 int error;
183
184COUNT(SOACCEPT);
2b4b57cd
BJ
185 if ((so->so_options & SO_ACCEPTCONN) == 0) {
186 error = EINVAL; /* XXX */
187 goto bad;
188 }
92d06f69
BJ
189 if ((so->so_state & SS_CONNAWAITING) == 0) {
190 error = ENOTCONN;
191 goto bad;
192 }
193 so->so_state &= ~SS_CONNAWAITING;
2b4b57cd
BJ
194 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
195bad:
196 splx(s);
197 return (error);
198}
199
ce9d8eb4 200/*
cc15ab5d
BJ
201 * Connect socket to a specified address.
202 * If already connected or connecting, then avoid
203 * the protocol entry, to keep its job simpler.
ce9d8eb4 204 */
2b4b57cd 205soconnect(so, asa)
ce9d8eb4 206 struct socket *so;
2b4b57cd 207 struct sockaddr *asa;
ce9d8eb4 208{
cc15ab5d
BJ
209 int s = splnet();
210 int error;
ce9d8eb4 211
2b4b57cd 212COUNT(SOCONNECT);
cc15ab5d
BJ
213 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
214 error = EISCONN;
215 goto bad;
216 }
2b4b57cd 217 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
cc15ab5d
BJ
218bad:
219 splx(s);
220 return (error);
ce9d8eb4
BJ
221}
222
223/*
cc15ab5d
BJ
224 * Disconnect from a socket.
225 * Address parameter is from system call for later multicast
226 * protocols. Check to make sure that connected and no disconnect
227 * in progress (for protocol's sake), and then invoke protocol.
ce9d8eb4 228 */
2b4b57cd 229sodisconnect(so, asa)
ce9d8eb4 230 struct socket *so;
2b4b57cd 231 struct sockaddr *asa;
ce9d8eb4 232{
cc15ab5d
BJ
233 int s = splnet();
234 int error;
ce9d8eb4 235
2b4b57cd 236COUNT(SODISCONNECT);
cc15ab5d
BJ
237 if ((so->so_state & SS_ISCONNECTED) == 0) {
238 error = ENOTCONN;
239 goto bad;
ce9d8eb4 240 }
cc15ab5d
BJ
241 if (so->so_state & SS_ISDISCONNECTING) {
242 error = EALREADY;
243 goto bad;
ce9d8eb4 244 }
2b4b57cd 245 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
cc15ab5d
BJ
246bad:
247 splx(s);
248 return (error);
ce9d8eb4
BJ
249}
250
cc15ab5d
BJ
251/*
252 * Send on a socket.
253 * If send must go all at once and message is larger than
254 * send buffering, then hard error.
255 * Lock against other senders.
256 * If must go all at once and not enough room now, then
257 * inform user that this would block and do nothing.
258 */
2b4b57cd 259sosend(so, asa)
ce9d8eb4 260 register struct socket *so;
2b4b57cd 261 struct sockaddr *asa;
ce9d8eb4 262{
cc15ab5d
BJ
263 struct mbuf *top = 0;
264 register struct mbuf *m, **mp = ⊤
ae921915
BJ
265 register u_int len;
266 int error = 0, space, s;
ce9d8eb4 267
2b4b57cd 268COUNT(SOSEND);
1bc8734a
BJ
269 if (so->so_state & SS_CANTSENDMORE) {
270 psignal(u.u_procp, SIGPIPE);
cc15ab5d 271 return (EPIPE);
1bc8734a 272 }
cc15ab5d
BJ
273 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
274 return (EMSGSIZE);
30b84e26 275 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NONBLOCKING))
cc15ab5d
BJ
276 return (EWOULDBLOCK);
277 sblock(&so->so_snd);
278#define snderr(errno) { error = errno; splx(s); goto release; }
279
280 s = splnet();
281again:
4c078bb2
BJ
282 if (so->so_error) {
283 error = so->so_error;
284 so->so_error = 0;
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);
cc15ab5d
BJ
296 if (error) {
297 splx(s);
ce9d8eb4
BJ
298 goto release;
299 }
cc15ab5d
BJ
300 top = 0;
301 mp = ⊤
ce9d8eb4 302 }
b91acce4
BJ
303 if (u.u_count == 0) {
304 splx(s);
305 goto release;
306 }
50fc8df6 307 space = sbspace(&so->so_snd);
6fa47729 308 if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
30b84e26 309 if (so->so_options & SO_NONBLOCKING)
cc15ab5d
BJ
310 snderr(EWOULDBLOCK);
311 sbunlock(&so->so_snd);
312 sbwait(&so->so_snd);
313 splx(s);
ce9d8eb4
BJ
314 goto again;
315 }
cc15ab5d 316 splx(s);
50fc8df6 317 while (u.u_count && space > 0) {
cc15ab5d
BJ
318 MGET(m, 1);
319 if (m == NULL) {
320 error = ENOBUFS;
321 m_freem(top);
322 goto release;
ce9d8eb4 323 }
c5ff2e32 324 if (u.u_count >= CLBYTES && space >= CLBYTES) {
cc15ab5d 325 register struct mbuf *p;
c5ff2e32 326 MCLGET(p, 1);
cc15ab5d
BJ
327 if (p == 0)
328 goto nopages;
329 m->m_off = (int)p - (int)m;
c5ff2e32 330 len = CLBYTES;
cc15ab5d 331 } else {
ce9d8eb4 332nopages:
cc15ab5d
BJ
333 m->m_off = MMINOFF;
334 len = MIN(MLEN, u.u_count);
ce9d8eb4 335 }
cc15ab5d
BJ
336 iomove(mtod(m, caddr_t), len, B_WRITE);
337 m->m_len = len;
338 *mp = m;
339 mp = &m->m_next;
50fc8df6 340 space = sbspace(&so->so_snd);
ce9d8eb4 341 }
cc15ab5d
BJ
342 s = splnet();
343 goto again;
344
ce9d8eb4 345release:
cc15ab5d 346 sbunlock(&so->so_snd);
ce9d8eb4
BJ
347 return (error);
348}
349
2b4b57cd 350soreceive(so, asa)
ce9d8eb4 351 register struct socket *so;
2b4b57cd 352 struct sockaddr *asa;
ce9d8eb4
BJ
353{
354 register struct mbuf *m, *n;
ae921915 355 u_int len;
edebca28
BJ
356 int eor, s, error = 0, cnt = u.u_count;
357 caddr_t base = u.u_base;
ce9d8eb4 358
2b4b57cd 359COUNT(SORECEIVE);
cc15ab5d
BJ
360restart:
361 sblock(&so->so_rcv);
362 s = splnet();
363
364#define rcverr(errno) { error = errno; splx(s); goto release; }
ce9d8eb4 365 if (so->so_rcv.sb_cc == 0) {
4c078bb2
BJ
366 if (so->so_error) {
367 error = so->so_error;
368 so->so_error = 0;
369 splx(s);
370 goto release;
371 }
cc15ab5d
BJ
372 if (so->so_state & SS_CANTRCVMORE) {
373 splx(s);
374 goto release;
375 }
196d84fd
BJ
376 if ((so->so_state & SS_ISCONNECTED) == 0 &&
377 (so->so_proto->pr_flags & PR_CONNREQUIRED))
378 rcverr(ENOTCONN);
30b84e26 379 if (so->so_options & SO_NONBLOCKING)
4c078bb2 380 rcverr(EWOULDBLOCK);
cc15ab5d 381 sbunlock(&so->so_rcv);
2752c877 382 sbwait(&so->so_rcv);
a4f6d93d 383 splx(s);
cc15ab5d 384 goto restart;
ce9d8eb4 385 }
92a533e6 386 m = so->so_rcv.sb_mb;
ce9d8eb4
BJ
387 if (m == 0)
388 panic("receive");
b031e888 389 if (so->so_proto->pr_flags & PR_ADDR) {
b031e888
BJ
390 if (m->m_len != sizeof (struct sockaddr))
391 panic("soreceive addr");
392 if (asa)
393 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
b031e888
BJ
394 so->so_rcv.sb_cc -= m->m_len;
395 so->so_rcv.sb_mbcnt -= MSIZE;
50fc8df6 396 m = m_free(m);
cc15ab5d
BJ
397 if (m == 0)
398 panic("receive 2");
50fc8df6 399 so->so_rcv.sb_mb = m;
cc15ab5d 400 }
edebca28
BJ
401 so->so_state &= ~SS_RCVATMARK;
402 if (so->so_oobmark && cnt > so->so_oobmark)
403 cnt = so->so_oobmark;
ce9d8eb4
BJ
404 eor = 0;
405 do {
edebca28 406 len = MIN(m->m_len, cnt);
ce9d8eb4
BJ
407 splx(s);
408 iomove(mtod(m, caddr_t), len, B_READ);
edebca28 409 cnt -= len;
ce9d8eb4
BJ
410 s = splnet();
411 if (len == m->m_len) {
e495e1cc
BJ
412 eor = (int)m->m_act;
413 sbfree(&so->so_rcv, m);
414 so->so_rcv.sb_mb = m->m_next;
ce9d8eb4
BJ
415 MFREE(m, n);
416 } else {
417 m->m_off += len;
418 m->m_len -= len;
92a533e6 419 so->so_rcv.sb_cc -= len;
ce9d8eb4 420 }
edebca28 421 } while ((m = so->so_rcv.sb_mb) && cnt && !eor);
ce9d8eb4
BJ
422 if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
423 do {
ce9d8eb4 424 if (m == 0)
cc15ab5d
BJ
425 panic("receive 3");
426 sbfree(&so->so_rcv, m);
ce9d8eb4
BJ
427 eor = (int)m->m_act;
428 so->so_rcv.sb_mb = m->m_next;
429 MFREE(m, n);
cc15ab5d 430 m = n;
ce9d8eb4 431 } while (eor == 0);
cc15ab5d
BJ
432 if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
433 (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
edebca28
BJ
434 if (so->so_oobmark) {
435 so->so_oobmark -= u.u_base - base;
436 if (so->so_oobmark == 0)
437 so->so_state |= SS_RCVATMARK;
438 }
cc15ab5d 439release:
ae921915 440 sbunlock(&so->so_rcv);
cc15ab5d 441 splx(s);
ae921915 442 return (error);
92a533e6
BJ
443}
444
edebca28
BJ
445sohasoutofband(so)
446 struct socket *so;
447{
448
449 if (so->so_pgrp == 0)
450 return;
451 if (so->so_pgrp > 0)
452 gsignal(so->so_pgrp, SIGURG);
0a0f7cbb
BJ
453 else {
454 struct proc *p = pfind(-so->so_pgrp);
455
456 if (p)
457 psignal(p, SIGURG);
458 }
edebca28
BJ
459}
460
ae921915
BJ
461/*ARGSUSED*/
462soioctl(so, cmd, cmdp)
92a533e6
BJ
463 register struct socket *so;
464 int cmd;
465 register caddr_t cmdp;
466{
467
2b4b57cd 468COUNT(SOIOCTL);
2156d53c 469 switch (cmd) {
92a533e6 470
30b84e26
BJ
471 case FIONBIO: {
472 int nbio;
473 if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
474 u.u_error = EFAULT;
475 return;
476 }
477 if (nbio)
478 so->so_options |= SO_NONBLOCKING;
479 else
480 so->so_options &= ~SO_NONBLOCKING;
481 return;
482 }
483
484 case FIOASYNC: {
485 int async;
486 if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
487 u.u_error = EFAULT;
488 return;
489 }
490 if (async)
491 ;
492 else
493 ;
494 return;
495 }
496
497 case SIOCSKEEP: {
498 int keep;
499 if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
500 u.u_error = EFAULT;
501 return;
502 }
503 if (keep)
504 so->so_options &= ~SO_NOKEEPALIVE;
505 else
506 so->so_options |= SO_NOKEEPALIVE;
507 return;
508 }
509
510 case SIOCGKEEP: {
511 int keep = (so->so_options & SO_NOKEEPALIVE) == 0;
512 if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
513 u.u_error = EFAULT;
514 return;
515 }
516
517 case SIOCSLINGER: {
518 int linger;
519 if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
520 u.u_error = EFAULT;
521 return;
522 }
523 so->so_linger = linger;
524 if (so->so_linger)
525 so->so_options &= ~SO_DONTLINGER;
526 else
527 so->so_options |= SO_DONTLINGER;
528 return;
529 }
530
531 case SIOCGLINGER: {
532 int linger = so->so_linger;
533 if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
534 u.u_error = EFAULT;
535 return;
536 }
537 }
edebca28
BJ
538 case SIOCSPGRP: {
539 int pgrp;
540 if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) {
541 u.u_error = EFAULT;
542 return;
543 }
544 so->so_pgrp = pgrp;
545 return;
546 }
547
548 case SIOCGPGRP: {
549 int pgrp = so->so_pgrp;
550 if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) {
551 u.u_error = EFAULT;
552 return;
553 }
554 }
30b84e26 555
b8acc34d
BJ
556 case SIOCDONE: {
557 int flags;
558 if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
559 u.u_error = EFAULT;
560 return;
561 }
30b84e26 562 flags++;
b8acc34d
BJ
563 if (flags & FREAD) {
564 int s = splimp();
565 socantrcvmore(so);
566 sbflush(&so->so_rcv);
785e10b7 567 splx(s);
b8acc34d
BJ
568 }
569 if (flags & FWRITE)
c30cd845 570 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
b8acc34d
BJ
571 return;
572 }
573
edebca28
BJ
574 case SIOCSENDOOB: {
575 char oob;
576 struct mbuf *m;
577 if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
578 u.u_error = EFAULT;
579 return;
580 }
581 m = m_get(M_DONTWAIT);
582 if (m == 0) {
583 u.u_error = ENOBUFS;
584 return;
585 }
586 m->m_off = MMINOFF;
587 m->m_len = 1;
588 *mtod(m, caddr_t) = oob;
589 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
590 return;
591 }
592
593 case SIOCRCVOOB: {
594 struct mbuf *m = m_get(M_DONTWAIT);
595 if (m == 0) {
596 u.u_error = ENOBUFS;
597 return;
598 }
599 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
600 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
601 if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
602 u.u_error = EFAULT;
603 return;
604 }
605 m_free(m);
606 return;
607 }
608
609 case SIOCATMARK: {
610 int atmark = (so->so_state&SS_RCVATMARK) != 0;
611 if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
612 u.u_error = EFAULT;
613 return;
614 }
615 return;
616 }
5e1eeba0 617 /* type/protocol specific ioctls */
92a533e6 618 }
5e1eeba0 619 u.u_error = EOPNOTSUPP;
ce9d8eb4 620}