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