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