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