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