1 /* 2 * Copyright (c) 1982, 1986, 1988 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.15 (Berkeley) 08/11/89 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 sleep((caddr_t)&so->so_timeo, PZERO+1); 162 } 163 } 164 drop: 165 if (so->so_pcb) { 166 int error2 = 167 (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 168 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 169 if (error == 0) 170 error = error2; 171 } 172 discard: 173 if (so->so_state & SS_NOFDREF) 174 panic("soclose: NOFDREF"); 175 so->so_state |= SS_NOFDREF; 176 sofree(so); 177 splx(s); 178 return (error); 179 } 180 181 /* 182 * Must be called at splnet... 183 */ 184 soabort(so) 185 struct socket *so; 186 { 187 188 return ( 189 (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 190 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 191 } 192 193 soaccept(so, nam) 194 register struct socket *so; 195 struct mbuf *nam; 196 { 197 int s = splnet(); 198 int error; 199 200 if ((so->so_state & SS_NOFDREF) == 0) 201 panic("soaccept: !NOFDREF"); 202 so->so_state &= ~SS_NOFDREF; 203 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 204 (struct mbuf *)0, nam, (struct mbuf *)0); 205 splx(s); 206 return (error); 207 } 208 209 soconnect(so, nam) 210 register struct socket *so; 211 struct mbuf *nam; 212 { 213 int s; 214 int error; 215 216 if (so->so_options & SO_ACCEPTCONN) 217 return (EOPNOTSUPP); 218 s = splnet(); 219 /* 220 * If protocol is connection-based, can only connect once. 221 * Otherwise, if connected, try to disconnect first. 222 * This allows user to disconnect by connecting to, e.g., 223 * a null address. 224 */ 225 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 226 ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 227 (error = sodisconnect(so)))) 228 error = EISCONN; 229 else 230 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 231 (struct mbuf *)0, nam, (struct mbuf *)0); 232 splx(s); 233 return (error); 234 } 235 236 soconnect2(so1, so2) 237 register struct socket *so1; 238 struct socket *so2; 239 { 240 int s = splnet(); 241 int error; 242 243 error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 244 (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 245 splx(s); 246 return (error); 247 } 248 249 sodisconnect(so) 250 register struct socket *so; 251 { 252 int s = splnet(); 253 int error; 254 255 if ((so->so_state & SS_ISCONNECTED) == 0) { 256 error = ENOTCONN; 257 goto bad; 258 } 259 if (so->so_state & SS_ISDISCONNECTING) { 260 error = EALREADY; 261 goto bad; 262 } 263 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 264 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 265 bad: 266 splx(s); 267 return (error); 268 } 269 270 /* 271 * Send on a socket. 272 * If send must go all at once and message is larger than 273 * send buffering, then hard error. 274 * Lock against other senders. 275 * If must go all at once and not enough room now, then 276 * inform user that this would block and do nothing. 277 * Otherwise, if nonblocking, send as much as possible. 278 */ 279 sosend(so, nam, uio, flags, rights, control) 280 register struct socket *so; 281 struct mbuf *nam; 282 register struct uio *uio; 283 int flags; 284 struct mbuf *rights, *control; 285 { 286 struct mbuf *top = 0, **mp; 287 register struct mbuf *m; 288 register int space, len; 289 int rlen = 0, error = 0, s, dontroute, first = 1, mlen; 290 int atomic = sosendallatonce(so); 291 292 if (atomic && 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 snderr(so->so_error); 310 if ((so->so_state & SS_ISCONNECTED) == 0) { 311 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 312 if ((so->so_state & SS_ISCONFIRMING) == 0) 313 snderr(ENOTCONN); 314 } else if (nam == 0) 315 snderr(EDESTADDRREQ); 316 } 317 if (flags & MSG_OOB) 318 space = 1024; 319 else { 320 space = sbspace(&so->so_snd); 321 if (space <= rlen || 322 (atomic && space < uio->uio_resid + rlen) || 323 (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 324 so->so_snd.sb_cc >= MCLBYTES && 325 (so->so_state & SS_NBIO) == 0)) { 326 if (so->so_state & SS_NBIO) { 327 if (first) 328 error = EWOULDBLOCK; 329 splx(s); 330 goto release; 331 } 332 sbunlock(&so->so_snd); 333 sbwait(&so->so_snd); 334 splx(s); 335 goto restart; 336 } 337 } 338 splx(s); 339 mp = ⊤ 340 space -= rlen; 341 do { 342 do { 343 if (top == 0) { 344 MGETHDR(m, M_WAIT, MT_DATA); 345 mlen = MHLEN; 346 m->m_pkthdr.len = 0; 347 m->m_pkthdr.rcvif = (struct ifnet *)0; 348 } else { 349 MGET(m, M_WAIT, MT_DATA); 350 mlen = MLEN; 351 } 352 if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 353 MCLGET(m, M_WAIT); 354 if ((m->m_flags & M_EXT) == 0) 355 goto nopages; 356 mlen = MCLBYTES; 357 #ifdef MAPPED_MBUFS 358 len = min(MCLBYTES, uio->uio_resid); 359 if (len < mlen - max_hdr) 360 m->m_data += max_hdr; 361 #else 362 len = min(MCLBYTES - max_hdr, uio->uio_resid); 363 m->m_data += max_hdr; 364 #endif 365 space -= MCLBYTES; 366 } else { 367 nopages: 368 len = min(min(mlen, uio->uio_resid), space); 369 space -= len; 370 /* 371 * For datagram protocols, leave room 372 * for protocol headers in first mbuf. 373 */ 374 if (atomic && top == 0 && len < mlen) 375 MH_ALIGN(m, len); 376 } 377 error = uiomove(mtod(m, caddr_t), len, uio); 378 m->m_len = len; 379 *mp = m; 380 top->m_pkthdr.len += len; 381 if (error) 382 goto release; 383 mp = &m->m_next; 384 if (uio->uio_resid <= 0) { 385 if ((flags & MSG_EOR) && top) 386 top->m_flags |= M_EOR; 387 break; 388 } 389 } while (space > 0 && atomic); 390 if (dontroute) 391 so->so_options |= SO_DONTROUTE; 392 s = splnet(); /* XXX */ 393 error = (*so->so_proto->pr_usrreq)(so, 394 (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 395 top, (caddr_t)nam, rights, control); 396 splx(s); 397 if (dontroute) 398 so->so_options &= ~SO_DONTROUTE; 399 rights = 0; 400 rlen = 0; 401 top = 0; 402 mp = ⊤ 403 first = 0; 404 if (error) 405 goto release; 406 } while (uio->uio_resid && space > 0); 407 } while (uio->uio_resid); 408 409 release: 410 sbunlock(&so->so_snd); 411 if (top) 412 m_freem(top); 413 if (error == EPIPE) 414 psignal(u.u_procp, SIGPIPE); 415 return (error); 416 } 417 418 /* 419 * Implement receive operations on a socket. 420 * We depend on the way that records are added to the sockbuf 421 * by sbappend*. In particular, each record (mbufs linked through m_next) 422 * must begin with an address if the protocol so specifies, 423 * followed by an optional mbuf containing access rights if supported 424 * by the protocol, and then zero or more mbufs of data. 425 * In order to avoid blocking network interrupts for the entire time here, 426 * we splx() while doing the actual copy to user space. 427 * Although the sockbuf is locked, new data may still be appended, 428 * and thus we must maintain consistency of the sockbuf during that time. 429 */ 430 soreceive(so, aname, uio, flagsp, rightsp, controlp) 431 register struct socket *so; 432 struct mbuf **aname; 433 register struct uio *uio; 434 int *flagsp; 435 struct mbuf **rightsp, **controlp; 436 { 437 register struct mbuf *m; 438 register int flags, len, error = 0, s, offset; 439 struct protosw *pr = so->so_proto; 440 struct mbuf *nextrecord; 441 int moff; 442 443 if (rightsp) 444 *rightsp = 0; 445 if (aname) 446 *aname = 0; 447 if (controlp) 448 *controlp = 0; 449 if (flagsp) 450 flags = *flagsp &~ MSG_EOR; 451 else 452 flags = 0; 453 if (flags & MSG_OOB) { 454 m = m_get(M_WAIT, MT_DATA); 455 error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 456 m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 457 if (error) 458 goto bad; 459 do { 460 len = uio->uio_resid; 461 if (len > m->m_len) 462 len = m->m_len; 463 error = uiomove(mtod(m, caddr_t), (int)len, uio); 464 m = m_free(m); 465 } while (uio->uio_resid && error == 0 && m); 466 bad: 467 if (m) 468 m_freem(m); 469 return (error); 470 } 471 if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 472 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 473 (struct mbuf *)0, (struct mbuf *)0); 474 475 restart: 476 sblock(&so->so_rcv); 477 s = splnet(); 478 479 m = so->so_rcv.sb_mb; 480 if (m == 0) { 481 if (so->so_rcv.sb_cc) 482 panic("receive 1"); 483 if (so->so_error) { 484 error = so->so_error; 485 so->so_error = 0; 486 goto release; 487 } 488 if (so->so_state & SS_CANTRCVMORE) 489 goto release; 490 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 491 (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 492 error = ENOTCONN; 493 goto release; 494 } 495 if (uio->uio_resid == 0) 496 goto release; 497 if (so->so_state & SS_NBIO) { 498 error = EWOULDBLOCK; 499 goto release; 500 } 501 sbunlock(&so->so_rcv); 502 sbwait(&so->so_rcv); 503 splx(s); 504 goto restart; 505 } 506 u.u_ru.ru_msgrcv++; 507 if (m->m_type == 0) 508 panic("receive 3a"); 509 nextrecord = m->m_nextpkt; 510 if (pr->pr_flags & PR_ADDR) { 511 if (m->m_type != MT_SONAME) 512 panic("receive 1a"); 513 if (flags & MSG_PEEK) { 514 if (aname) 515 *aname = m_copy(m, 0, m->m_len); 516 m = m->m_next; 517 } else { 518 sbfree(&so->so_rcv, m); 519 if (aname) { 520 *aname = m; 521 so->so_rcv.sb_mb = m->m_next; 522 m->m_next = 0; 523 m = so->so_rcv.sb_mb; 524 } else { 525 MFREE(m, so->so_rcv.sb_mb); 526 m = so->so_rcv.sb_mb; 527 } 528 } 529 } 530 if (m && m->m_type == MT_RIGHTS) { 531 if ((pr->pr_flags & PR_RIGHTS) == 0) 532 panic("receive 2"); 533 if (flags & MSG_PEEK) { 534 if (rightsp) 535 *rightsp = m_copy(m, 0, m->m_len); 536 m = m->m_next; 537 } else { 538 sbfree(&so->so_rcv, m); 539 if (rightsp) { 540 *rightsp = m; 541 so->so_rcv.sb_mb = m->m_next; 542 m->m_next = 0; 543 m = so->so_rcv.sb_mb; 544 } else { 545 MFREE(m, so->so_rcv.sb_mb); 546 m = so->so_rcv.sb_mb; 547 } 548 } 549 } 550 if (m && m->m_type == MT_CONTROL) { 551 if (flags & MSG_PEEK) { 552 if (controlp) 553 *controlp = m_copy(m, 0, m->m_len); 554 m = m->m_next; 555 } else { 556 sbfree(&so->so_rcv, m); 557 if (controlp) { 558 *controlp = m; 559 so->so_rcv.sb_mb = m->m_next; 560 m->m_next = 0; 561 m = so->so_rcv.sb_mb; 562 } else { 563 MFREE(m, so->so_rcv.sb_mb); 564 m = so->so_rcv.sb_mb; 565 } 566 } 567 } 568 if (m) 569 m->m_nextpkt = nextrecord; 570 moff = 0; 571 offset = 0; 572 while (m && uio->uio_resid > 0 && error == 0) { 573 if (m->m_type == MT_OOBDATA) 574 flags |= MSG_OOB; 575 else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 576 panic("receive 3"); 577 if (m->m_flags & M_EOR) 578 flags |= MSG_EOR; 579 len = uio->uio_resid; 580 so->so_state &= ~SS_RCVATMARK; 581 if (so->so_oobmark && len > so->so_oobmark - offset) 582 len = so->so_oobmark - offset; 583 if (len > m->m_len - moff) 584 len = m->m_len - moff; 585 splx(s); 586 error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 587 s = splnet(); 588 if (len == m->m_len - moff) { 589 if (flags & MSG_PEEK) { 590 m = m->m_next; 591 moff = 0; 592 } else { 593 nextrecord = m->m_nextpkt; 594 sbfree(&so->so_rcv, m); 595 MFREE(m, so->so_rcv.sb_mb); 596 m = so->so_rcv.sb_mb; 597 if (m) 598 m->m_nextpkt = nextrecord; 599 } 600 } else { 601 if (flags & MSG_PEEK) 602 moff += len; 603 else { 604 m->m_data += len; 605 m->m_len -= len; 606 so->so_rcv.sb_cc -= len; 607 } 608 } 609 if (so->so_oobmark) { 610 if ((flags & MSG_PEEK) == 0) { 611 so->so_oobmark -= len; 612 if (so->so_oobmark == 0) { 613 so->so_state |= SS_RCVATMARK; 614 break; 615 } 616 } else 617 offset += len; 618 } 619 } 620 if (m && (flags & MSG_EOR)) { 621 flags &= ~MSG_EOR; 622 if ((flags & MSG_PEEK) == 0) 623 m->m_flags |= M_EOR; 624 } 625 if ((flags & MSG_PEEK) == 0) { 626 if (m == 0) 627 so->so_rcv.sb_mb = nextrecord; 628 else if (pr->pr_flags & PR_ATOMIC) { 629 flags |= MSG_TRUNC; 630 (void) sbdroprecord(&so->so_rcv); 631 } 632 if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 633 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 634 (struct mbuf *)flags, (struct mbuf *)0, 635 (struct mbuf *)0); 636 if (error == 0 && rightsp && *rightsp && 637 pr->pr_domain->dom_externalize) 638 error = (*pr->pr_domain->dom_externalize)(*rightsp); 639 } 640 if (flagsp) 641 *flagsp |= flags; 642 release: 643 sbunlock(&so->so_rcv); 644 splx(s); 645 return (error); 646 } 647 648 soshutdown(so, how) 649 register struct socket *so; 650 register int how; 651 { 652 register struct protosw *pr = so->so_proto; 653 654 how++; 655 if (how & FREAD) 656 sorflush(so); 657 if (how & FWRITE) 658 return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 659 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 660 return (0); 661 } 662 663 sorflush(so) 664 register struct socket *so; 665 { 666 register struct sockbuf *sb = &so->so_rcv; 667 register struct protosw *pr = so->so_proto; 668 register int s; 669 struct sockbuf asb; 670 671 sblock(sb); 672 s = splimp(); 673 socantrcvmore(so); 674 sbunlock(sb); 675 asb = *sb; 676 bzero((caddr_t)sb, sizeof (*sb)); 677 splx(s); 678 if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 679 (*pr->pr_domain->dom_dispose)(asb.sb_mb); 680 sbrelease(&asb); 681 } 682 683 sosetopt(so, level, optname, m0) 684 register struct socket *so; 685 int level, optname; 686 struct mbuf *m0; 687 { 688 int error = 0; 689 register struct mbuf *m = m0; 690 691 if (level != SOL_SOCKET) { 692 if (so->so_proto && so->so_proto->pr_ctloutput) 693 return ((*so->so_proto->pr_ctloutput) 694 (PRCO_SETOPT, so, level, optname, &m0)); 695 error = ENOPROTOOPT; 696 } else { 697 switch (optname) { 698 699 case SO_LINGER: 700 if (m == NULL || m->m_len != sizeof (struct linger)) { 701 error = EINVAL; 702 goto bad; 703 } 704 so->so_linger = mtod(m, struct linger *)->l_linger; 705 /* fall thru... */ 706 707 case SO_DEBUG: 708 case SO_KEEPALIVE: 709 case SO_DONTROUTE: 710 case SO_USELOOPBACK: 711 case SO_BROADCAST: 712 case SO_REUSEADDR: 713 case SO_OOBINLINE: 714 if (m == NULL || m->m_len < sizeof (int)) { 715 error = EINVAL; 716 goto bad; 717 } 718 if (*mtod(m, int *)) 719 so->so_options |= optname; 720 else 721 so->so_options &= ~optname; 722 break; 723 724 case SO_SNDBUF: 725 case SO_RCVBUF: 726 case SO_SNDLOWAT: 727 case SO_RCVLOWAT: 728 case SO_SNDTIMEO: 729 case SO_RCVTIMEO: 730 if (m == NULL || m->m_len < sizeof (int)) { 731 error = EINVAL; 732 goto bad; 733 } 734 switch (optname) { 735 736 case SO_SNDBUF: 737 case SO_RCVBUF: 738 if (sbreserve(optname == SO_SNDBUF ? 739 &so->so_snd : &so->so_rcv, 740 (u_long) *mtod(m, int *)) == 0) { 741 error = ENOBUFS; 742 goto bad; 743 } 744 break; 745 746 case SO_SNDLOWAT: 747 so->so_snd.sb_lowat = *mtod(m, int *); 748 break; 749 case SO_RCVLOWAT: 750 so->so_rcv.sb_lowat = *mtod(m, int *); 751 break; 752 case SO_SNDTIMEO: 753 so->so_snd.sb_timeo = *mtod(m, int *); 754 break; 755 case SO_RCVTIMEO: 756 so->so_rcv.sb_timeo = *mtod(m, int *); 757 break; 758 } 759 break; 760 761 default: 762 error = ENOPROTOOPT; 763 break; 764 } 765 } 766 bad: 767 if (m) 768 (void) m_free(m); 769 return (error); 770 } 771 772 sogetopt(so, level, optname, mp) 773 register struct socket *so; 774 int level, optname; 775 struct mbuf **mp; 776 { 777 register struct mbuf *m; 778 779 if (level != SOL_SOCKET) { 780 if (so->so_proto && so->so_proto->pr_ctloutput) { 781 return ((*so->so_proto->pr_ctloutput) 782 (PRCO_GETOPT, so, level, optname, mp)); 783 } else 784 return (ENOPROTOOPT); 785 } else { 786 m = m_get(M_WAIT, MT_SOOPTS); 787 m->m_len = sizeof (int); 788 789 switch (optname) { 790 791 case SO_LINGER: 792 m->m_len = sizeof (struct linger); 793 mtod(m, struct linger *)->l_onoff = 794 so->so_options & SO_LINGER; 795 mtod(m, struct linger *)->l_linger = so->so_linger; 796 break; 797 798 case SO_USELOOPBACK: 799 case SO_DONTROUTE: 800 case SO_DEBUG: 801 case SO_KEEPALIVE: 802 case SO_REUSEADDR: 803 case SO_BROADCAST: 804 case SO_OOBINLINE: 805 *mtod(m, int *) = so->so_options & optname; 806 break; 807 808 case SO_TYPE: 809 *mtod(m, int *) = so->so_type; 810 break; 811 812 case SO_ERROR: 813 *mtod(m, int *) = so->so_error; 814 so->so_error = 0; 815 break; 816 817 case SO_SNDBUF: 818 *mtod(m, int *) = so->so_snd.sb_hiwat; 819 break; 820 821 case SO_RCVBUF: 822 *mtod(m, int *) = so->so_rcv.sb_hiwat; 823 break; 824 825 case SO_SNDLOWAT: 826 *mtod(m, int *) = so->so_snd.sb_lowat; 827 break; 828 829 case SO_RCVLOWAT: 830 *mtod(m, int *) = so->so_rcv.sb_lowat; 831 break; 832 833 case SO_SNDTIMEO: 834 *mtod(m, int *) = so->so_snd.sb_timeo; 835 break; 836 837 case SO_RCVTIMEO: 838 *mtod(m, int *) = so->so_rcv.sb_timeo; 839 break; 840 841 default: 842 (void)m_free(m); 843 return (ENOPROTOOPT); 844 } 845 *mp = m; 846 return (0); 847 } 848 } 849 850 sohasoutofband(so) 851 register struct socket *so; 852 { 853 struct proc *p; 854 855 if (so->so_pgid < 0) 856 gsignal(-so->so_pgid, SIGURG); 857 else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 858 psignal(p, SIGURG); 859 if (so->so_rcv.sb_sel) { 860 selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 861 so->so_rcv.sb_sel = 0; 862 so->so_rcv.sb_flags &= ~SB_COLL; 863 } 864 } 865