spl5 not splimp
[unix-history] / usr / src / sys / kern / uipc_socket.c
CommitLineData
6fa47729 1/* uipc_socket.c 4.30 82/01/24 */
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);
cc15ab5d
BJ
269 if (so->so_state & SS_CANTSENDMORE)
270 return (EPIPE);
271 if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
272 return (EMSGSIZE);
30b84e26 273 if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NONBLOCKING))
cc15ab5d
BJ
274 return (EWOULDBLOCK);
275 sblock(&so->so_snd);
276#define snderr(errno) { error = errno; splx(s); goto release; }
277
278 s = splnet();
279again:
4c078bb2
BJ
280 if (so->so_error) {
281 error = so->so_error;
282 so->so_error = 0;
283 splx(s);
284 goto release;
285 }
cc15ab5d
BJ
286 if ((so->so_state & SS_ISCONNECTED) == 0) {
287 if (so->so_proto->pr_flags & PR_CONNREQUIRED)
288 snderr(ENOTCONN);
2b4b57cd 289 if (asa == 0)
cc15ab5d
BJ
290 snderr(EDESTADDRREQ);
291 }
cc15ab5d 292 if (top) {
2b4b57cd 293 error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
cc15ab5d
BJ
294 if (error) {
295 splx(s);
ce9d8eb4
BJ
296 goto release;
297 }
cc15ab5d
BJ
298 top = 0;
299 mp = ⊤
ce9d8eb4 300 }
b91acce4
BJ
301 if (u.u_count == 0) {
302 splx(s);
303 goto release;
304 }
50fc8df6 305 space = sbspace(&so->so_snd);
6fa47729 306 if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
30b84e26 307 if (so->so_options & SO_NONBLOCKING)
cc15ab5d
BJ
308 snderr(EWOULDBLOCK);
309 sbunlock(&so->so_snd);
310 sbwait(&so->so_snd);
311 splx(s);
ce9d8eb4
BJ
312 goto again;
313 }
cc15ab5d 314 splx(s);
50fc8df6 315 while (u.u_count && space > 0) {
cc15ab5d
BJ
316 MGET(m, 1);
317 if (m == NULL) {
318 error = ENOBUFS;
319 m_freem(top);
320 goto release;
ce9d8eb4 321 }
c5ff2e32 322 if (u.u_count >= CLBYTES && space >= CLBYTES) {
cc15ab5d 323 register struct mbuf *p;
c5ff2e32 324 MCLGET(p, 1);
cc15ab5d
BJ
325 if (p == 0)
326 goto nopages;
327 m->m_off = (int)p - (int)m;
c5ff2e32 328 len = CLBYTES;
cc15ab5d 329 } else {
ce9d8eb4 330nopages:
cc15ab5d
BJ
331 m->m_off = MMINOFF;
332 len = MIN(MLEN, u.u_count);
ce9d8eb4 333 }
cc15ab5d
BJ
334 iomove(mtod(m, caddr_t), len, B_WRITE);
335 m->m_len = len;
336 *mp = m;
337 mp = &m->m_next;
50fc8df6 338 space = sbspace(&so->so_snd);
ce9d8eb4 339 }
cc15ab5d
BJ
340 s = splnet();
341 goto again;
342
ce9d8eb4 343release:
cc15ab5d 344 sbunlock(&so->so_snd);
ce9d8eb4
BJ
345 return (error);
346}
347
2b4b57cd 348soreceive(so, asa)
ce9d8eb4 349 register struct socket *so;
2b4b57cd 350 struct sockaddr *asa;
ce9d8eb4
BJ
351{
352 register struct mbuf *m, *n;
ae921915 353 u_int len;
edebca28
BJ
354 int eor, s, error = 0, cnt = u.u_count;
355 caddr_t base = u.u_base;
ce9d8eb4 356
2b4b57cd 357COUNT(SORECEIVE);
cc15ab5d
BJ
358restart:
359 sblock(&so->so_rcv);
360 s = splnet();
361
362#define rcverr(errno) { error = errno; splx(s); goto release; }
ce9d8eb4 363 if (so->so_rcv.sb_cc == 0) {
4c078bb2
BJ
364 if (so->so_error) {
365 error = so->so_error;
366 so->so_error = 0;
367 splx(s);
368 goto release;
369 }
cc15ab5d
BJ
370 if (so->so_state & SS_CANTRCVMORE) {
371 splx(s);
372 goto release;
373 }
196d84fd
BJ
374 if ((so->so_state & SS_ISCONNECTED) == 0 &&
375 (so->so_proto->pr_flags & PR_CONNREQUIRED))
376 rcverr(ENOTCONN);
30b84e26 377 if (so->so_options & SO_NONBLOCKING)
4c078bb2 378 rcverr(EWOULDBLOCK);
cc15ab5d 379 sbunlock(&so->so_rcv);
2752c877 380 sbwait(&so->so_rcv);
a4f6d93d 381 splx(s);
cc15ab5d 382 goto restart;
ce9d8eb4 383 }
92a533e6 384 m = so->so_rcv.sb_mb;
ce9d8eb4
BJ
385 if (m == 0)
386 panic("receive");
b031e888 387 if (so->so_proto->pr_flags & PR_ADDR) {
b031e888
BJ
388 if (m->m_len != sizeof (struct sockaddr))
389 panic("soreceive addr");
390 if (asa)
391 bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
b031e888
BJ
392 so->so_rcv.sb_cc -= m->m_len;
393 so->so_rcv.sb_mbcnt -= MSIZE;
50fc8df6 394 m = m_free(m);
cc15ab5d
BJ
395 if (m == 0)
396 panic("receive 2");
50fc8df6 397 so->so_rcv.sb_mb = m;
cc15ab5d 398 }
edebca28
BJ
399 so->so_state &= ~SS_RCVATMARK;
400 if (so->so_oobmark && cnt > so->so_oobmark)
401 cnt = so->so_oobmark;
ce9d8eb4
BJ
402 eor = 0;
403 do {
edebca28 404 len = MIN(m->m_len, cnt);
ce9d8eb4
BJ
405 if (len == m->m_len) {
406 eor = (int)m->m_act;
cc15ab5d 407 sbfree(&so->so_rcv, m);
2156d53c 408 so->so_rcv.sb_mb = m->m_next;
ce9d8eb4
BJ
409 }
410 splx(s);
411 iomove(mtod(m, caddr_t), len, B_READ);
edebca28 412 cnt -= len;
ce9d8eb4
BJ
413 s = splnet();
414 if (len == m->m_len) {
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);
567 }
568 if (flags & FWRITE)
c30cd845 569 u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
b8acc34d
BJ
570 return;
571 }
572
edebca28
BJ
573 case SIOCSENDOOB: {
574 char oob;
575 struct mbuf *m;
576 if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
577 u.u_error = EFAULT;
578 return;
579 }
580 m = m_get(M_DONTWAIT);
581 if (m == 0) {
582 u.u_error = ENOBUFS;
583 return;
584 }
585 m->m_off = MMINOFF;
586 m->m_len = 1;
587 *mtod(m, caddr_t) = oob;
588 (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
589 return;
590 }
591
592 case SIOCRCVOOB: {
593 struct mbuf *m = m_get(M_DONTWAIT);
594 if (m == 0) {
595 u.u_error = ENOBUFS;
596 return;
597 }
598 m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
599 (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
600 if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
601 u.u_error = EFAULT;
602 return;
603 }
604 m_free(m);
605 return;
606 }
607
608 case SIOCATMARK: {
609 int atmark = (so->so_state&SS_RCVATMARK) != 0;
610 if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
611 u.u_error = EFAULT;
612 return;
613 }
614 return;
615 }
5e1eeba0 616 /* type/protocol specific ioctls */
92a533e6 617 }
5e1eeba0 618 u.u_error = EOPNOTSUPP;
ce9d8eb4 619}