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