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