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