1 /* 2 * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)uipc_socket.c 7.19 (Berkeley) 06/14/90 18 */ 19 20 #include "param.h" 21 #include "user.h" 22 #include "proc.h" 23 #include "file.h" 24 #include "malloc.h" 25 #include "mbuf.h" 26 #include "domain.h" 27 #include "protosw.h" 28 #include "socket.h" 29 #include "socketvar.h" 30 31 /* 32 * Socket operation routines. 33 * These routines are called by the routines in 34 * sys_socket.c or from a system process, and 35 * implement the semantics of socket operations by 36 * switching out to the protocol specific routines. 37 * 38 * TODO: 39 * test socketpair 40 * clean up async 41 * out-of-band is a kludge 42 */ 43 /*ARGSUSED*/ 44 socreate(dom, aso, type, proto) 45 struct socket **aso; 46 register int type; 47 int proto; 48 { 49 register struct protosw *prp; 50 register struct socket *so; 51 register int error; 52 53 if (proto) 54 prp = pffindproto(dom, proto, type); 55 else 56 prp = pffindtype(dom, type); 57 if (prp == 0) 58 return (EPROTONOSUPPORT); 59 if (prp->pr_type != type) 60 return (EPROTOTYPE); 61 MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 62 bzero((caddr_t)so, sizeof(*so)); 63 so->so_type = type; 64 if (u.u_uid == 0) 65 so->so_state = SS_PRIV; 66 so->so_proto = prp; 67 error = 68 (*prp->pr_usrreq)(so, PRU_ATTACH, 69 (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 70 if (error) { 71 so->so_state |= SS_NOFDREF; 72 sofree(so); 73 return (error); 74 } 75 *aso = so; 76 return (0); 77 } 78 79 sobind(so, nam) 80 struct socket *so; 81 struct mbuf *nam; 82 { 83 int s = splnet(); 84 int error; 85 86 error = 87 (*so->so_proto->pr_usrreq)(so, PRU_BIND, 88 (struct mbuf *)0, nam, (struct mbuf *)0); 89 splx(s); 90 return (error); 91 } 92 93 solisten(so, backlog) 94 register struct socket *so; 95 int backlog; 96 { 97 int s = splnet(), error; 98 99 error = 100 (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 101 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 102 if (error) { 103 splx(s); 104 return (error); 105 } 106 if (so->so_q == 0) 107 so->so_options |= SO_ACCEPTCONN; 108 if (backlog < 0) 109 backlog = 0; 110 so->so_qlimit = min(backlog, SOMAXCONN); 111 splx(s); 112 return (0); 113 } 114 115 sofree(so) 116 register struct socket *so; 117 { 118 119 if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 120 return; 121 if (so->so_head) { 122 if (!soqremque(so, 0) && !soqremque(so, 1)) 123 panic("sofree dq"); 124 so->so_head = 0; 125 } 126 sbrelease(&so->so_snd); 127 sorflush(so); 128 FREE(so, M_SOCKET); 129 } 130 131 /* 132 * Close a socket on last file table reference removal. 133 * Initiate disconnect if connected. 134 * Free socket when disconnect complete. 135 */ 136 soclose(so) 137 register struct socket *so; 138 { 139 int s = splnet(); /* conservative */ 140 int error = 0; 141 142 if (so->so_options & SO_ACCEPTCONN) { 143 while (so->so_q0) 144 (void) soabort(so->so_q0); 145 while (so->so_q) 146 (void) soabort(so->so_q); 147 } 148 if (so->so_pcb == 0) 149 goto discard; 150 if (so->so_state & SS_ISCONNECTED) { 151 if ((so->so_state & SS_ISDISCONNECTING) == 0) { 152 error = sodisconnect(so); 153 if (error) 154 goto drop; 155 } 156 if (so->so_options & SO_LINGER) { 157 if ((so->so_state & SS_ISDISCONNECTING) && 158 (so->so_state & SS_NBIO)) 159 goto drop; 160 while (so->so_state & SS_ISCONNECTED) 161 if (error = tsleep((caddr_t)&so->so_timeo, 162 PSOCK | PCATCH, netcls, so->so_linger)) 163 break; 164 } 165 } 166 drop: 167 if (so->so_pcb) { 168 int error2 = 169 (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 170 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 171 if (error == 0) 172 error = error2; 173 } 174 discard: 175 if (so->so_state & SS_NOFDREF) 176 panic("soclose: NOFDREF"); 177 so->so_state |= SS_NOFDREF; 178 sofree(so); 179 splx(s); 180 return (error); 181 } 182 183 /* 184 * Must be called at splnet... 185 */ 186 soabort(so) 187 struct socket *so; 188 { 189 190 return ( 191 (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 192 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 193 } 194 195 soaccept(so, nam) 196 register struct socket *so; 197 struct mbuf *nam; 198 { 199 int s = splnet(); 200 int error; 201 202 if ((so->so_state & SS_NOFDREF) == 0) 203 panic("soaccept: !NOFDREF"); 204 so->so_state &= ~SS_NOFDREF; 205 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 206 (struct mbuf *)0, nam, (struct mbuf *)0); 207 splx(s); 208 return (error); 209 } 210 211 soconnect(so, nam) 212 register struct socket *so; 213 struct mbuf *nam; 214 { 215 int s; 216 int error; 217 218 if (so->so_options & SO_ACCEPTCONN) 219 return (EOPNOTSUPP); 220 s = splnet(); 221 /* 222 * If protocol is connection-based, can only connect once. 223 * Otherwise, if connected, try to disconnect first. 224 * This allows user to disconnect by connecting to, e.g., 225 * a null address. 226 */ 227 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 228 ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 229 (error = sodisconnect(so)))) 230 error = EISCONN; 231 else 232 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 233 (struct mbuf *)0, nam, (struct mbuf *)0); 234 splx(s); 235 return (error); 236 } 237 238 soconnect2(so1, so2) 239 register struct socket *so1; 240 struct socket *so2; 241 { 242 int s = splnet(); 243 int error; 244 245 error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 246 (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 247 splx(s); 248 return (error); 249 } 250 251 sodisconnect(so) 252 register struct socket *so; 253 { 254 int s = splnet(); 255 int error; 256 257 if ((so->so_state & SS_ISCONNECTED) == 0) { 258 error = ENOTCONN; 259 goto bad; 260 } 261 if (so->so_state & SS_ISDISCONNECTING) { 262 error = EALREADY; 263 goto bad; 264 } 265 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 266 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 267 bad: 268 splx(s); 269 return (error); 270 } 271 272 /* 273 * Send on a socket. 274 * If send must go all at once and message is larger than 275 * send buffering, then hard error. 276 * Lock against other senders. 277 * If must go all at once and not enough room now, then 278 * inform user that this would block and do nothing. 279 * Otherwise, if nonblocking, send as much as possible. 280 * The data to be sent is described by "uio" if nonzero, 281 * otherwise by the mbuf chain "top" (which must be null 282 * if uio is not). Data provided in mbuf chain must be small 283 * enough to send all at once. 284 * 285 * Returns nonzero on error, timeout or signal; callers 286 * must check for short counts if EINTR/ERESTART are returned. 287 * Data and control buffers are freed on return. 288 */ 289 sosend(so, addr, uio, top, control, flags/*, sbwait_func, sbwait_arg*/) 290 register struct socket *so; 291 struct mbuf *addr; 292 struct uio *uio; 293 struct mbuf *top; 294 struct mbuf *control; 295 int flags; 296 /* 297 int (*sbwait_func)(); 298 caddr_t sbwait_arg; 299 */ 300 { 301 struct mbuf **mp; 302 register struct mbuf *m; 303 register long space, len, resid; 304 int clen = 0, error, s, dontroute, mlen; 305 int atomic = sosendallatonce(so) || top; 306 307 if (uio) 308 resid = uio->uio_resid; 309 else 310 resid = top->m_pkthdr.len; 311 dontroute = 312 (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 313 (so->so_proto->pr_flags & PR_ATOMIC); 314 u.u_ru.ru_msgsnd++; 315 if (control) 316 clen = control->m_len; 317 #define snderr(errno) { error = errno; splx(s); goto release; } 318 319 restart: 320 if (error = sblock(&so->so_snd)) 321 goto out; 322 do { 323 s = splnet(); 324 if (so->so_state & SS_CANTSENDMORE) 325 snderr(EPIPE); 326 if (so->so_error) 327 snderr(so->so_error); 328 if ((so->so_state & SS_ISCONNECTED) == 0) { 329 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 330 if ((so->so_state & SS_ISCONFIRMING) == 0) 331 snderr(ENOTCONN); 332 } else if (addr == 0) 333 snderr(EDESTADDRREQ); 334 } 335 space = sbspace(&so->so_snd); 336 if (flags & MSG_OOB) 337 space += 1024; 338 if (space < resid + clen && 339 (atomic || space < so->so_snd.sb_lowat || space < clen)) { 340 if (atomic && resid > so->so_snd.sb_hiwat || 341 clen > so->so_snd.sb_hiwat) 342 snderr(EMSGSIZE); 343 if (so->so_state & SS_NBIO) 344 snderr(EWOULDBLOCK); 345 sbunlock(&so->so_snd); 346 /* 347 if (sbwait_func) 348 error = (*sbwait_func)(&so->so_snd, sbwait_arg); 349 else 350 */ 351 error = sbwait(&so->so_snd); 352 splx(s); 353 if (error) 354 goto out; 355 goto restart; 356 } 357 splx(s); 358 mp = ⊤ 359 space -= clen; 360 if (uio == NULL) { 361 /* 362 * Data is prepackaged in "top". 363 */ 364 resid = 0; 365 if (flags & MSG_EOR) 366 top->m_flags |= M_EOR; 367 } else do { 368 do { 369 if (top == 0) { 370 MGETHDR(m, M_WAIT, MT_DATA); 371 mlen = MHLEN; 372 m->m_pkthdr.len = 0; 373 m->m_pkthdr.rcvif = (struct ifnet *)0; 374 } else { 375 MGET(m, M_WAIT, MT_DATA); 376 mlen = MLEN; 377 } 378 if (resid >= MINCLSIZE && space >= MCLBYTES) { 379 MCLGET(m, M_WAIT); 380 if ((m->m_flags & M_EXT) == 0) 381 goto nopages; 382 mlen = MCLBYTES; 383 #ifdef MAPPED_MBUFS 384 len = min(MCLBYTES, resid); 385 #else 386 if (top == 0) { 387 len = min(MCLBYTES - max_hdr, resid); 388 m->m_data += max_hdr; 389 } 390 #endif 391 space -= MCLBYTES; 392 } else { 393 nopages: 394 len = min(min(mlen, resid), space); 395 space -= len; 396 /* 397 * For datagram protocols, leave room 398 * for protocol headers in first mbuf. 399 */ 400 if (atomic && top == 0 && len < mlen) 401 MH_ALIGN(m, len); 402 } 403 error = uiomove(mtod(m, caddr_t), len, uio); 404 resid = uio->uio_resid; 405 m->m_len = len; 406 *mp = m; 407 top->m_pkthdr.len += len; 408 if (error) 409 goto release; 410 mp = &m->m_next; 411 if (resid <= 0) { 412 if (flags & MSG_EOR) 413 top->m_flags |= M_EOR; 414 break; 415 } 416 } while (space > 0 && atomic); 417 if (dontroute) 418 so->so_options |= SO_DONTROUTE; 419 s = splnet(); /* XXX */ 420 error = (*so->so_proto->pr_usrreq)(so, 421 (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 422 top, addr, control); 423 splx(s); 424 if (dontroute) 425 so->so_options &= ~SO_DONTROUTE; 426 clen = 0; 427 control = 0; 428 top = 0; 429 mp = ⊤ 430 if (error) 431 goto release; 432 } while (resid && space > 0); 433 } while (resid); 434 435 release: 436 sbunlock(&so->so_snd); 437 out: 438 if (top) 439 m_freem(top); 440 if (control) 441 m_freem(control); 442 return (error); 443 } 444 445 /* 446 * Implement receive operations on a socket. 447 * We depend on the way that records are added to the sockbuf 448 * by sbappend*. In particular, each record (mbufs linked through m_next) 449 * must begin with an address if the protocol so specifies, 450 * followed by an optional mbuf or mbufs containing ancillary data, 451 * and then zero or more mbufs of data. 452 * In order to avoid blocking network interrupts for the entire time here, 453 * we splx() while doing the actual copy to user space. 454 * Although the sockbuf is locked, new data may still be appended, 455 * and thus we must maintain consistency of the sockbuf during that time. 456 * 457 * The caller may receive the data as a single mbuf chain by supplying 458 * an mbuf **mp for use in returning the chain. The uio is then used 459 * only for the count in uio_resid. 460 */ 461 soreceive(so, paddr, uio, mp, controlp, flagsp/*, sbwait_func, sbwait_arg*/) 462 register struct socket *so; 463 struct mbuf **paddr; 464 struct uio *uio; 465 struct mbuf **mp; 466 struct mbuf **controlp; 467 int *flagsp; 468 /* 469 int (*sbwait_func)(); 470 caddr_t sbwait_arg; 471 */ 472 { 473 register struct mbuf *m; 474 register int resid, flags, len, error, s, offset; 475 struct protosw *pr = so->so_proto; 476 struct mbuf *nextrecord; 477 int moff, type; 478 479 if (paddr) 480 *paddr = 0; 481 if (controlp) 482 *controlp = 0; 483 if (flagsp) 484 flags = *flagsp &~ MSG_EOR; 485 else 486 flags = 0; 487 if (flags & MSG_OOB) { 488 m = m_get(M_WAIT, MT_DATA); 489 error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 490 m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 491 if (error) 492 goto bad; 493 do { 494 error = uiomove(mtod(m, caddr_t), 495 (int) min(uio->uio_resid, m->m_len), uio); 496 m = m_free(m); 497 } while (uio->uio_resid && error == 0 && m); 498 bad: 499 if (m) 500 m_freem(m); 501 return (error); 502 } 503 if (mp) 504 *mp = (struct mbuf *)0; 505 resid = uio->uio_resid; 506 if (so->so_state & SS_ISCONFIRMING && resid) 507 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 508 (struct mbuf *)0, (struct mbuf *)0); 509 510 restart: 511 if (error = sblock(&so->so_rcv)) 512 return (error); 513 s = splnet(); 514 515 m = so->so_rcv.sb_mb; 516 if (m == 0 || (so->so_rcv.sb_cc < resid && 517 so->so_rcv.sb_cc < so->so_rcv.sb_lowat)) { 518 #ifdef DIAGNOSTIC 519 if (m == 0 && so->so_rcv.sb_cc) 520 panic("receive 1"); 521 #endif 522 if (so->so_error) { 523 error = so->so_error; 524 so->so_error = 0; 525 goto release; 526 } 527 if (so->so_state & SS_CANTRCVMORE) 528 goto release; 529 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 530 (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 531 error = ENOTCONN; 532 goto release; 533 } 534 if (resid == 0) 535 goto release; 536 if (so->so_state & SS_NBIO) { 537 error = EWOULDBLOCK; 538 goto release; 539 } 540 sbunlock(&so->so_rcv); 541 /* 542 if (sbwait_func) 543 error = (*sbwait_func)(&so->so_rcv, sbwait_arg); 544 else 545 */ 546 error = sbwait(&so->so_rcv); 547 splx(s); 548 if (error) 549 return (error); 550 goto restart; 551 } 552 u.u_ru.ru_msgrcv++; 553 #ifdef DIAGNOSTIC 554 if (m->m_type == 0) 555 panic("receive 3a"); 556 #endif 557 nextrecord = m->m_nextpkt; 558 if (pr->pr_flags & PR_ADDR) { 559 #ifdef DIAGNOSTIC 560 if (m->m_type != MT_SONAME) 561 panic("receive 1a"); 562 #endif 563 if (flags & MSG_PEEK) { 564 if (paddr) 565 *paddr = m_copy(m, 0, m->m_len); 566 m = m->m_next; 567 } else { 568 sbfree(&so->so_rcv, m); 569 if (paddr) { 570 *paddr = m; 571 so->so_rcv.sb_mb = m->m_next; 572 m->m_next = 0; 573 m = so->so_rcv.sb_mb; 574 } else { 575 MFREE(m, so->so_rcv.sb_mb); 576 m = so->so_rcv.sb_mb; 577 } 578 } 579 } 580 while (m && m->m_type == MT_CONTROL && error == 0) { 581 if (flags & MSG_PEEK) { 582 if (controlp) 583 *controlp = m_copy(m, 0, m->m_len); 584 m = m->m_next; 585 } else { 586 sbfree(&so->so_rcv, m); 587 if (controlp) { 588 if (pr->pr_domain->dom_externalize && 589 mtod(m, struct cmsghdr *)->cmsg_type == 590 SCM_RIGHTS) 591 error = (*pr->pr_domain->dom_externalize)(m); 592 *controlp = m; 593 so->so_rcv.sb_mb = m->m_next; 594 m->m_next = 0; 595 m = so->so_rcv.sb_mb; 596 } else { 597 MFREE(m, so->so_rcv.sb_mb); 598 m = so->so_rcv.sb_mb; 599 } 600 } 601 if (controlp) 602 controlp = &(*controlp)->m_next; 603 } 604 if (m) { 605 m->m_nextpkt = nextrecord; 606 type = m->m_type; 607 } 608 moff = 0; 609 offset = 0; 610 while (m && m->m_type == type && resid > 0 && error == 0) { 611 if (m->m_type == MT_OOBDATA) 612 flags |= MSG_OOB; 613 #ifdef DIAGNOSTIC 614 else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 615 panic("receive 3"); 616 #endif 617 type = m->m_type; 618 so->so_state &= ~SS_RCVATMARK; 619 len = resid; 620 if (so->so_oobmark && len > so->so_oobmark - offset) 621 len = so->so_oobmark - offset; 622 if (len > m->m_len - moff) 623 len = m->m_len - moff; 624 /* 625 * If mp is set, just pass back the mbufs. 626 * Otherwise copy them out via the uio, then free. 627 * Sockbuf must be consistent here (points to current mbuf, 628 * it points to next record) when we drop priority; 629 * we must note any additions to the sockbuf when we 630 * block interrupts again. 631 */ 632 if (mp == 0) { 633 splx(s); 634 error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 635 resid = uio->uio_resid; 636 s = splnet(); 637 } 638 if (len == m->m_len - moff) { 639 if (m->m_flags & M_EOR) 640 flags |= MSG_EOR; 641 if (flags & MSG_PEEK) { 642 m = m->m_next; 643 moff = 0; 644 } else { 645 nextrecord = m->m_nextpkt; 646 sbfree(&so->so_rcv, m); 647 if (mp) { 648 *mp = m; 649 mp = &m->m_next; 650 m = m->m_next; 651 } else { 652 MFREE(m, so->so_rcv.sb_mb); 653 m = so->so_rcv.sb_mb; 654 } 655 if (m) 656 m->m_nextpkt = nextrecord; 657 } 658 } else { 659 if (flags & MSG_PEEK) 660 moff += len; 661 else { 662 m->m_data += len; 663 m->m_len -= len; 664 so->so_rcv.sb_cc -= len; 665 } 666 } 667 if (so->so_oobmark) { 668 if ((flags & MSG_PEEK) == 0) { 669 so->so_oobmark -= len; 670 if (so->so_oobmark == 0) { 671 so->so_state |= SS_RCVATMARK; 672 break; 673 } 674 } else 675 offset += len; 676 } 677 if (flags & MSG_EOR) 678 break; 679 /* 680 * If the MSG_WAITALL flag is set (for non-atomic socket), 681 * we must not quit until "resid == 0" or an error 682 * termination. If a signal/timeout occurs, return 683 * prematurely but without error. 684 * Keep sockbuf locked against other readers. 685 */ 686 while (flags & MSG_WAITALL && m == 0 && resid > 0 && 687 !sosendallatonce(so)) { 688 error = sbwait(&so->so_rcv); 689 if (error) { 690 sbunlock(&so->so_rcv); 691 splx(s); 692 if (mp) 693 *mp = (struct mbuf *)0; 694 return (0); 695 } 696 if (m = so->so_rcv.sb_mb) 697 nextrecord = m->m_nextpkt; 698 if (so->so_error || so->so_state & SS_CANTRCVMORE) 699 break; 700 continue; 701 } 702 } 703 if (mp) 704 *mp = (struct mbuf *)0; 705 if ((flags & MSG_PEEK) == 0) { 706 if (m == 0) 707 so->so_rcv.sb_mb = nextrecord; 708 else if (pr->pr_flags & PR_ATOMIC) { 709 flags |= MSG_TRUNC; 710 (void) sbdroprecord(&so->so_rcv); 711 } 712 if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 713 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 714 (struct mbuf *)flags, (struct mbuf *)0, 715 (struct mbuf *)0); 716 } 717 if (flagsp) 718 *flagsp |= flags; 719 release: 720 sbunlock(&so->so_rcv); 721 splx(s); 722 return (error); 723 } 724 725 soshutdown(so, how) 726 register struct socket *so; 727 register int how; 728 { 729 register struct protosw *pr = so->so_proto; 730 731 how++; 732 if (how & FREAD) 733 sorflush(so); 734 if (how & FWRITE) 735 return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 736 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 737 return (0); 738 } 739 740 sorflush(so) 741 register struct socket *so; 742 { 743 register struct sockbuf *sb = &so->so_rcv; 744 register struct protosw *pr = so->so_proto; 745 register int s; 746 struct sockbuf asb; 747 748 sb->sb_flags |= SB_NOINTR; 749 (void) sblock(sb); 750 s = splimp(); 751 socantrcvmore(so); 752 sbunlock(sb); 753 asb = *sb; 754 bzero((caddr_t)sb, sizeof (*sb)); 755 splx(s); 756 if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 757 (*pr->pr_domain->dom_dispose)(asb.sb_mb); 758 sbrelease(&asb); 759 } 760 761 sosetopt(so, level, optname, m0) 762 register struct socket *so; 763 int level, optname; 764 struct mbuf *m0; 765 { 766 int error = 0; 767 register struct mbuf *m = m0; 768 769 if (level != SOL_SOCKET) { 770 if (so->so_proto && so->so_proto->pr_ctloutput) 771 return ((*so->so_proto->pr_ctloutput) 772 (PRCO_SETOPT, so, level, optname, &m0)); 773 error = ENOPROTOOPT; 774 } else { 775 switch (optname) { 776 777 case SO_LINGER: 778 if (m == NULL || m->m_len != sizeof (struct linger)) { 779 error = EINVAL; 780 goto bad; 781 } 782 so->so_linger = mtod(m, struct linger *)->l_linger; 783 /* fall thru... */ 784 785 case SO_DEBUG: 786 case SO_KEEPALIVE: 787 case SO_DONTROUTE: 788 case SO_USELOOPBACK: 789 case SO_BROADCAST: 790 case SO_REUSEADDR: 791 case SO_OOBINLINE: 792 if (m == NULL || m->m_len < sizeof (int)) { 793 error = EINVAL; 794 goto bad; 795 } 796 if (*mtod(m, int *)) 797 so->so_options |= optname; 798 else 799 so->so_options &= ~optname; 800 break; 801 802 case SO_SNDBUF: 803 case SO_RCVBUF: 804 case SO_SNDLOWAT: 805 case SO_RCVLOWAT: 806 case SO_SNDTIMEO: 807 case SO_RCVTIMEO: 808 if (m == NULL || m->m_len < sizeof (int)) { 809 error = EINVAL; 810 goto bad; 811 } 812 switch (optname) { 813 814 case SO_SNDBUF: 815 case SO_RCVBUF: 816 if (sbreserve(optname == SO_SNDBUF ? 817 &so->so_snd : &so->so_rcv, 818 (u_long) *mtod(m, int *)) == 0) { 819 error = ENOBUFS; 820 goto bad; 821 } 822 break; 823 824 case SO_SNDLOWAT: 825 so->so_snd.sb_lowat = *mtod(m, int *); 826 break; 827 case SO_RCVLOWAT: 828 so->so_rcv.sb_lowat = *mtod(m, int *); 829 break; 830 case SO_SNDTIMEO: 831 so->so_snd.sb_timeo = *mtod(m, int *); 832 break; 833 case SO_RCVTIMEO: 834 so->so_rcv.sb_timeo = *mtod(m, int *); 835 break; 836 } 837 break; 838 839 default: 840 error = ENOPROTOOPT; 841 break; 842 } 843 } 844 bad: 845 if (m) 846 (void) m_free(m); 847 return (error); 848 } 849 850 sogetopt(so, level, optname, mp) 851 register struct socket *so; 852 int level, optname; 853 struct mbuf **mp; 854 { 855 register struct mbuf *m; 856 857 if (level != SOL_SOCKET) { 858 if (so->so_proto && so->so_proto->pr_ctloutput) { 859 return ((*so->so_proto->pr_ctloutput) 860 (PRCO_GETOPT, so, level, optname, mp)); 861 } else 862 return (ENOPROTOOPT); 863 } else { 864 m = m_get(M_WAIT, MT_SOOPTS); 865 m->m_len = sizeof (int); 866 867 switch (optname) { 868 869 case SO_LINGER: 870 m->m_len = sizeof (struct linger); 871 mtod(m, struct linger *)->l_onoff = 872 so->so_options & SO_LINGER; 873 mtod(m, struct linger *)->l_linger = so->so_linger; 874 break; 875 876 case SO_USELOOPBACK: 877 case SO_DONTROUTE: 878 case SO_DEBUG: 879 case SO_KEEPALIVE: 880 case SO_REUSEADDR: 881 case SO_BROADCAST: 882 case SO_OOBINLINE: 883 *mtod(m, int *) = so->so_options & optname; 884 break; 885 886 case SO_TYPE: 887 *mtod(m, int *) = so->so_type; 888 break; 889 890 case SO_ERROR: 891 *mtod(m, int *) = so->so_error; 892 so->so_error = 0; 893 break; 894 895 case SO_SNDBUF: 896 *mtod(m, int *) = so->so_snd.sb_hiwat; 897 break; 898 899 case SO_RCVBUF: 900 *mtod(m, int *) = so->so_rcv.sb_hiwat; 901 break; 902 903 case SO_SNDLOWAT: 904 *mtod(m, int *) = so->so_snd.sb_lowat; 905 break; 906 907 case SO_RCVLOWAT: 908 *mtod(m, int *) = so->so_rcv.sb_lowat; 909 break; 910 911 case SO_SNDTIMEO: 912 *mtod(m, int *) = so->so_snd.sb_timeo; 913 break; 914 915 case SO_RCVTIMEO: 916 *mtod(m, int *) = so->so_rcv.sb_timeo; 917 break; 918 919 default: 920 (void)m_free(m); 921 return (ENOPROTOOPT); 922 } 923 *mp = m; 924 return (0); 925 } 926 } 927 928 sohasoutofband(so) 929 register struct socket *so; 930 { 931 struct proc *p; 932 933 if (so->so_pgid < 0) 934 gsignal(-so->so_pgid, SIGURG); 935 else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 936 psignal(p, SIGURG); 937 if (so->so_rcv.sb_sel) { 938 selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 939 so->so_rcv.sb_sel = 0; 940 so->so_rcv.sb_flags &= ~SB_COLL; 941 } 942 } 943