1 /* 2 * Copyright (c) 1982, 1986 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.10 (Berkeley) 06/29/88 18 */ 19 20 #include "param.h" 21 #include "dir.h" 22 #include "user.h" 23 #include "proc.h" 24 #include "file.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 struct mbuf *m; 52 register int error; 53 54 if (proto) 55 prp = pffindproto(dom, proto, type); 56 else 57 prp = pffindtype(dom, type); 58 if (prp == 0) 59 return (EPROTONOSUPPORT); 60 if (prp->pr_type != type) 61 return (EPROTOTYPE); 62 m = m_getclr(M_WAIT, MT_SOCKET); 63 so = mtod(m, struct socket *); 64 so->so_options = 0; 65 so->so_state = 0; 66 so->so_type = type; 67 if (u.u_uid == 0) 68 so->so_state = SS_PRIV; 69 so->so_proto = prp; 70 error = 71 (*prp->pr_usrreq)(so, PRU_ATTACH, 72 (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 73 if (error) { 74 so->so_state |= SS_NOFDREF; 75 sofree(so); 76 return (error); 77 } 78 *aso = so; 79 return (0); 80 } 81 82 sobind(so, nam) 83 struct socket *so; 84 struct mbuf *nam; 85 { 86 int s = splnet(); 87 int error; 88 89 error = 90 (*so->so_proto->pr_usrreq)(so, PRU_BIND, 91 (struct mbuf *)0, nam, (struct mbuf *)0); 92 splx(s); 93 return (error); 94 } 95 96 solisten(so, backlog) 97 register struct socket *so; 98 int backlog; 99 { 100 int s = splnet(), error; 101 102 error = 103 (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 104 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 105 if (error) { 106 splx(s); 107 return (error); 108 } 109 if (so->so_q == 0) { 110 so->so_q = so; 111 so->so_q0 = so; 112 so->so_options |= SO_ACCEPTCONN; 113 } 114 if (backlog < 0) 115 backlog = 0; 116 so->so_qlimit = MIN(backlog, SOMAXCONN); 117 splx(s); 118 return (0); 119 } 120 121 sofree(so) 122 register struct socket *so; 123 { 124 125 if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 126 return; 127 if (so->so_head) { 128 if (!soqremque(so, 0) && !soqremque(so, 1)) 129 panic("sofree dq"); 130 so->so_head = 0; 131 } 132 sbrelease(&so->so_snd); 133 sorflush(so); 134 (void) m_free(dtom(so)); 135 } 136 137 /* 138 * Close a socket on last file table reference removal. 139 * Initiate disconnect if connected. 140 * Free socket when disconnect complete. 141 */ 142 soclose(so) 143 register struct socket *so; 144 { 145 int s = splnet(); /* conservative */ 146 int error = 0; 147 148 if (so->so_options & SO_ACCEPTCONN) { 149 while (so->so_q0 != so) 150 (void) soabort(so->so_q0); 151 while (so->so_q != so) 152 (void) soabort(so->so_q); 153 } 154 if (so->so_pcb == 0) 155 goto discard; 156 if (so->so_state & SS_ISCONNECTED) { 157 if ((so->so_state & SS_ISDISCONNECTING) == 0) { 158 error = sodisconnect(so); 159 if (error) 160 goto drop; 161 } 162 if (so->so_options & SO_LINGER) { 163 if ((so->so_state & SS_ISDISCONNECTING) && 164 (so->so_state & SS_NBIO)) 165 goto drop; 166 while (so->so_state & SS_ISCONNECTED) 167 sleep((caddr_t)&so->so_timeo, PZERO+1); 168 } 169 } 170 drop: 171 if (so->so_pcb) { 172 int error2 = 173 (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 174 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 175 if (error == 0) 176 error = error2; 177 } 178 discard: 179 if (so->so_state & SS_NOFDREF) 180 panic("soclose: NOFDREF"); 181 so->so_state |= SS_NOFDREF; 182 sofree(so); 183 splx(s); 184 return (error); 185 } 186 187 /* 188 * Must be called at splnet... 189 */ 190 soabort(so) 191 struct socket *so; 192 { 193 194 return ( 195 (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 196 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 197 } 198 199 soaccept(so, nam) 200 register struct socket *so; 201 struct mbuf *nam; 202 { 203 int s = splnet(); 204 int error; 205 206 if ((so->so_state & SS_NOFDREF) == 0) 207 panic("soaccept: !NOFDREF"); 208 so->so_state &= ~SS_NOFDREF; 209 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 210 (struct mbuf *)0, nam, (struct mbuf *)0); 211 splx(s); 212 return (error); 213 } 214 215 soconnect(so, nam) 216 register struct socket *so; 217 struct mbuf *nam; 218 { 219 int s; 220 int error; 221 222 if (so->so_options & SO_ACCEPTCONN) 223 return (EOPNOTSUPP); 224 s = splnet(); 225 /* 226 * If protocol is connection-based, can only connect once. 227 * Otherwise, if connected, try to disconnect first. 228 * This allows user to disconnect by connecting to, e.g., 229 * a null address. 230 */ 231 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 232 ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 233 (error = sodisconnect(so)))) 234 error = EISCONN; 235 else 236 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 237 (struct mbuf *)0, nam, (struct mbuf *)0); 238 splx(s); 239 return (error); 240 } 241 242 soconnect2(so1, so2) 243 register struct socket *so1; 244 struct socket *so2; 245 { 246 int s = splnet(); 247 int error; 248 249 error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 250 (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 251 splx(s); 252 return (error); 253 } 254 255 sodisconnect(so) 256 register struct socket *so; 257 { 258 int s = splnet(); 259 int error; 260 261 if ((so->so_state & SS_ISCONNECTED) == 0) { 262 error = ENOTCONN; 263 goto bad; 264 } 265 if (so->so_state & SS_ISDISCONNECTING) { 266 error = EALREADY; 267 goto bad; 268 } 269 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 270 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 271 bad: 272 splx(s); 273 return (error); 274 } 275 276 /* 277 * Send on a socket. 278 * If send must go all at once and message is larger than 279 * send buffering, then hard error. 280 * Lock against other senders. 281 * If must go all at once and not enough room now, then 282 * inform user that this would block and do nothing. 283 * Otherwise, if nonblocking, send as much as possible. 284 */ 285 sosend(so, nam, uio, flags, rights) 286 register struct socket *so; 287 struct mbuf *nam; 288 register struct uio *uio; 289 int flags; 290 struct mbuf *rights; 291 { 292 struct mbuf *top = 0; 293 register struct mbuf *m, **mp; 294 register int space; 295 int len, rlen = 0, error = 0, s, dontroute, first = 1; 296 297 if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 298 return (EMSGSIZE); 299 dontroute = 300 (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 301 (so->so_proto->pr_flags & PR_ATOMIC); 302 u.u_ru.ru_msgsnd++; 303 if (rights) 304 rlen = rights->m_len; 305 #define snderr(errno) { error = errno; splx(s); goto release; } 306 307 restart: 308 sblock(&so->so_snd); 309 do { 310 s = splnet(); 311 if (so->so_state & SS_CANTSENDMORE) 312 snderr(EPIPE); 313 if (so->so_error) { 314 error = so->so_error; 315 so->so_error = 0; /* ??? */ 316 splx(s); 317 goto release; 318 } 319 if ((so->so_state & SS_ISCONNECTED) == 0) { 320 if (so->so_proto->pr_flags & PR_CONNREQUIRED) 321 snderr(ENOTCONN); 322 if (nam == 0) 323 snderr(EDESTADDRREQ); 324 } 325 if (flags & MSG_OOB) 326 space = 1024; 327 else { 328 space = sbspace(&so->so_snd); 329 if (space <= rlen || 330 (sosendallatonce(so) && 331 space < uio->uio_resid + rlen) || 332 (uio->uio_resid >= CLBYTES && space < CLBYTES && 333 so->so_snd.sb_cc >= CLBYTES && 334 (so->so_state & SS_NBIO) == 0)) { 335 if (so->so_state & SS_NBIO) { 336 if (first) 337 error = EWOULDBLOCK; 338 splx(s); 339 goto release; 340 } 341 sbunlock(&so->so_snd); 342 sbwait(&so->so_snd); 343 splx(s); 344 goto restart; 345 } 346 } 347 splx(s); 348 mp = ⊤ 349 space -= rlen; 350 while (space > 0) { 351 MGET(m, M_WAIT, MT_DATA); 352 if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) { 353 MCLGET(m); 354 if (m->m_len != CLBYTES) 355 goto nopages; 356 len = MIN(CLBYTES, uio->uio_resid); 357 space -= CLBYTES; 358 } else { 359 nopages: 360 len = MIN(MIN(MLEN, uio->uio_resid), space); 361 space -= len; 362 } 363 error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 364 m->m_len = len; 365 *mp = m; 366 if (error) 367 goto release; 368 mp = &m->m_next; 369 if (uio->uio_resid <= 0) 370 break; 371 } 372 if (dontroute) 373 so->so_options |= SO_DONTROUTE; 374 s = splnet(); /* XXX */ 375 error = (*so->so_proto->pr_usrreq)(so, 376 (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 377 top, (caddr_t)nam, rights); 378 splx(s); 379 if (dontroute) 380 so->so_options &= ~SO_DONTROUTE; 381 rights = 0; 382 rlen = 0; 383 top = 0; 384 first = 0; 385 if (error) 386 break; 387 } while (uio->uio_resid); 388 389 release: 390 sbunlock(&so->so_snd); 391 if (top) 392 m_freem(top); 393 if (error == EPIPE) 394 psignal(u.u_procp, SIGPIPE); 395 return (error); 396 } 397 398 /* 399 * Implement receive operations on a socket. 400 * We depend on the way that records are added to the sockbuf 401 * by sbappend*. In particular, each record (mbufs linked through m_next) 402 * must begin with an address if the protocol so specifies, 403 * followed by an optional mbuf containing access rights if supported 404 * by the protocol, and then zero or more mbufs of data. 405 * In order to avoid blocking network interrupts for the entire time here, 406 * we splx() while doing the actual copy to user space. 407 * Although the sockbuf is locked, new data may still be appended, 408 * and thus we must maintain consistency of the sockbuf during that time. 409 */ 410 soreceive(so, aname, uio, flags, rightsp) 411 register struct socket *so; 412 struct mbuf **aname; 413 register struct uio *uio; 414 int flags; 415 struct mbuf **rightsp; 416 { 417 register struct mbuf *m; 418 register int len, error = 0, s, offset; 419 struct protosw *pr = so->so_proto; 420 struct mbuf *nextrecord; 421 int moff; 422 423 if (rightsp) 424 *rightsp = 0; 425 if (aname) 426 *aname = 0; 427 if (flags & MSG_OOB) { 428 m = m_get(M_WAIT, MT_DATA); 429 error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 430 m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 431 if (error) 432 goto bad; 433 do { 434 len = uio->uio_resid; 435 if (len > m->m_len) 436 len = m->m_len; 437 error = 438 uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 439 m = m_free(m); 440 } while (uio->uio_resid && error == 0 && m); 441 bad: 442 if (m) 443 m_freem(m); 444 return (error); 445 } 446 447 restart: 448 sblock(&so->so_rcv); 449 s = splnet(); 450 451 if (so->so_rcv.sb_cc == 0) { 452 if (so->so_error) { 453 error = so->so_error; 454 so->so_error = 0; 455 goto release; 456 } 457 if (so->so_state & SS_CANTRCVMORE) 458 goto release; 459 if ((so->so_state & SS_ISCONNECTED) == 0 && 460 (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 461 error = ENOTCONN; 462 goto release; 463 } 464 if (uio->uio_resid == 0) 465 goto release; 466 if (so->so_state & SS_NBIO) { 467 error = EWOULDBLOCK; 468 goto release; 469 } 470 sbunlock(&so->so_rcv); 471 sbwait(&so->so_rcv); 472 splx(s); 473 goto restart; 474 } 475 u.u_ru.ru_msgrcv++; 476 m = so->so_rcv.sb_mb; 477 if (m == 0) 478 panic("receive 1"); 479 nextrecord = m->m_act; 480 if (pr->pr_flags & PR_ADDR) { 481 if (m->m_type != MT_SONAME) 482 panic("receive 1a"); 483 if (flags & MSG_PEEK) { 484 if (aname) 485 *aname = m_copy(m, 0, m->m_len); 486 m = m->m_next; 487 } else { 488 sbfree(&so->so_rcv, m); 489 if (aname) { 490 *aname = m; 491 m = m->m_next; 492 (*aname)->m_next = 0; 493 so->so_rcv.sb_mb = m; 494 } else { 495 MFREE(m, so->so_rcv.sb_mb); 496 m = so->so_rcv.sb_mb; 497 } 498 if (m) 499 m->m_act = nextrecord; 500 } 501 } 502 if (m && m->m_type == MT_RIGHTS) { 503 if ((pr->pr_flags & PR_RIGHTS) == 0) 504 panic("receive 2"); 505 if (flags & MSG_PEEK) { 506 if (rightsp) 507 *rightsp = m_copy(m, 0, m->m_len); 508 m = m->m_next; 509 } else { 510 sbfree(&so->so_rcv, m); 511 if (rightsp) { 512 *rightsp = m; 513 so->so_rcv.sb_mb = m->m_next; 514 m->m_next = 0; 515 m = so->so_rcv.sb_mb; 516 } else { 517 MFREE(m, so->so_rcv.sb_mb); 518 m = so->so_rcv.sb_mb; 519 } 520 if (m) 521 m->m_act = nextrecord; 522 } 523 } 524 moff = 0; 525 offset = 0; 526 while (m && uio->uio_resid > 0 && error == 0) { 527 if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 528 panic("receive 3"); 529 len = uio->uio_resid; 530 so->so_state &= ~SS_RCVATMARK; 531 if (so->so_oobmark && len > so->so_oobmark - offset) 532 len = so->so_oobmark - offset; 533 if (len > m->m_len - moff) 534 len = m->m_len - moff; 535 splx(s); 536 error = 537 uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 538 s = splnet(); 539 if (len == m->m_len - moff) { 540 if (flags & MSG_PEEK) { 541 m = m->m_next; 542 moff = 0; 543 } else { 544 nextrecord = m->m_act; 545 sbfree(&so->so_rcv, m); 546 MFREE(m, so->so_rcv.sb_mb); 547 m = so->so_rcv.sb_mb; 548 if (m) 549 m->m_act = nextrecord; 550 } 551 } else { 552 if (flags & MSG_PEEK) 553 moff += len; 554 else { 555 m->m_off += len; 556 m->m_len -= len; 557 so->so_rcv.sb_cc -= len; 558 } 559 } 560 if (so->so_oobmark) { 561 if ((flags & MSG_PEEK) == 0) { 562 so->so_oobmark -= len; 563 if (so->so_oobmark == 0) { 564 so->so_state |= SS_RCVATMARK; 565 break; 566 } 567 } else 568 offset += len; 569 } 570 } 571 if ((flags & MSG_PEEK) == 0) { 572 if (m == 0) 573 so->so_rcv.sb_mb = nextrecord; 574 else if (pr->pr_flags & PR_ATOMIC) 575 (void) sbdroprecord(&so->so_rcv); 576 if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 577 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 578 (struct mbuf *)0, (struct mbuf *)0); 579 if (error == 0 && rightsp && *rightsp && 580 pr->pr_domain->dom_externalize) 581 error = (*pr->pr_domain->dom_externalize)(*rightsp); 582 } 583 release: 584 sbunlock(&so->so_rcv); 585 splx(s); 586 return (error); 587 } 588 589 soshutdown(so, how) 590 register struct socket *so; 591 register int how; 592 { 593 register struct protosw *pr = so->so_proto; 594 595 how++; 596 if (how & FREAD) 597 sorflush(so); 598 if (how & FWRITE) 599 return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 600 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 601 return (0); 602 } 603 604 sorflush(so) 605 register struct socket *so; 606 { 607 register struct sockbuf *sb = &so->so_rcv; 608 register struct protosw *pr = so->so_proto; 609 register int s; 610 struct sockbuf asb; 611 612 sblock(sb); 613 s = splimp(); 614 socantrcvmore(so); 615 sbunlock(sb); 616 asb = *sb; 617 bzero((caddr_t)sb, sizeof (*sb)); 618 splx(s); 619 if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 620 (*pr->pr_domain->dom_dispose)(asb.sb_mb); 621 sbrelease(&asb); 622 } 623 624 sosetopt(so, level, optname, m0) 625 register struct socket *so; 626 int level, optname; 627 struct mbuf *m0; 628 { 629 int error = 0; 630 register struct mbuf *m = m0; 631 632 if (level != SOL_SOCKET) { 633 if (so->so_proto && so->so_proto->pr_ctloutput) 634 return ((*so->so_proto->pr_ctloutput) 635 (PRCO_SETOPT, so, level, optname, &m0)); 636 error = ENOPROTOOPT; 637 } else { 638 switch (optname) { 639 640 case SO_LINGER: 641 if (m == NULL || m->m_len != sizeof (struct linger)) { 642 error = EINVAL; 643 goto bad; 644 } 645 so->so_linger = mtod(m, struct linger *)->l_linger; 646 /* fall thru... */ 647 648 case SO_DEBUG: 649 case SO_KEEPALIVE: 650 case SO_DONTROUTE: 651 case SO_USELOOPBACK: 652 case SO_BROADCAST: 653 case SO_REUSEADDR: 654 case SO_OOBINLINE: 655 if (m == NULL || m->m_len < sizeof (int)) { 656 error = EINVAL; 657 goto bad; 658 } 659 if (*mtod(m, int *)) 660 so->so_options |= optname; 661 else 662 so->so_options &= ~optname; 663 break; 664 665 case SO_SNDBUF: 666 case SO_RCVBUF: 667 case SO_SNDLOWAT: 668 case SO_RCVLOWAT: 669 case SO_SNDTIMEO: 670 case SO_RCVTIMEO: 671 if (m == NULL || m->m_len < sizeof (int)) { 672 error = EINVAL; 673 goto bad; 674 } 675 switch (optname) { 676 677 case SO_SNDBUF: 678 case SO_RCVBUF: 679 if (sbreserve(optname == SO_SNDBUF ? 680 &so->so_snd : &so->so_rcv, 681 (u_long) *mtod(m, int *)) == 0) { 682 error = ENOBUFS; 683 goto bad; 684 } 685 break; 686 687 case SO_SNDLOWAT: 688 so->so_snd.sb_lowat = *mtod(m, int *); 689 break; 690 case SO_RCVLOWAT: 691 so->so_rcv.sb_lowat = *mtod(m, int *); 692 break; 693 case SO_SNDTIMEO: 694 so->so_snd.sb_timeo = *mtod(m, int *); 695 break; 696 case SO_RCVTIMEO: 697 so->so_rcv.sb_timeo = *mtod(m, int *); 698 break; 699 } 700 break; 701 702 default: 703 error = ENOPROTOOPT; 704 break; 705 } 706 } 707 bad: 708 if (m) 709 (void) m_free(m); 710 return (error); 711 } 712 713 sogetopt(so, level, optname, mp) 714 register struct socket *so; 715 int level, optname; 716 struct mbuf **mp; 717 { 718 register struct mbuf *m; 719 720 if (level != SOL_SOCKET) { 721 if (so->so_proto && so->so_proto->pr_ctloutput) { 722 return ((*so->so_proto->pr_ctloutput) 723 (PRCO_GETOPT, so, level, optname, mp)); 724 } else 725 return (ENOPROTOOPT); 726 } else { 727 m = m_get(M_WAIT, MT_SOOPTS); 728 m->m_len = sizeof (int); 729 730 switch (optname) { 731 732 case SO_LINGER: 733 m->m_len = sizeof (struct linger); 734 mtod(m, struct linger *)->l_onoff = 735 so->so_options & SO_LINGER; 736 mtod(m, struct linger *)->l_linger = so->so_linger; 737 break; 738 739 case SO_USELOOPBACK: 740 case SO_DONTROUTE: 741 case SO_DEBUG: 742 case SO_KEEPALIVE: 743 case SO_REUSEADDR: 744 case SO_BROADCAST: 745 case SO_OOBINLINE: 746 *mtod(m, int *) = so->so_options & optname; 747 break; 748 749 case SO_TYPE: 750 *mtod(m, int *) = so->so_type; 751 break; 752 753 case SO_ERROR: 754 *mtod(m, int *) = so->so_error; 755 so->so_error = 0; 756 break; 757 758 case SO_SNDBUF: 759 *mtod(m, int *) = so->so_snd.sb_hiwat; 760 break; 761 762 case SO_RCVBUF: 763 *mtod(m, int *) = so->so_rcv.sb_hiwat; 764 break; 765 766 case SO_SNDLOWAT: 767 *mtod(m, int *) = so->so_snd.sb_lowat; 768 break; 769 770 case SO_RCVLOWAT: 771 *mtod(m, int *) = so->so_rcv.sb_lowat; 772 break; 773 774 case SO_SNDTIMEO: 775 *mtod(m, int *) = so->so_snd.sb_timeo; 776 break; 777 778 case SO_RCVTIMEO: 779 *mtod(m, int *) = so->so_rcv.sb_timeo; 780 break; 781 782 default: 783 (void)m_free(m); 784 return (ENOPROTOOPT); 785 } 786 *mp = m; 787 return (0); 788 } 789 } 790 791 sohasoutofband(so) 792 register struct socket *so; 793 { 794 struct proc *p; 795 796 if (so->so_pgrp < 0) 797 gsignal(-so->so_pgrp, SIGURG); 798 else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) 799 psignal(p, SIGURG); 800 if (so->so_rcv.sb_sel) { 801 selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 802 so->so_rcv.sb_sel = 0; 803 so->so_rcv.sb_flags &= ~SB_COLL; 804 } 805 } 806