|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1998, 1999 Apple Computer, Inc. All Rights Reserved */ ! 23: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 24: /* ! 25: * Copyright (c) 1982, 1986, 1988, 1990, 1993 ! 26: * The Regents of the University of California. All rights reserved. ! 27: * ! 28: * Redistribution and use in source and binary forms, with or without ! 29: * modification, are permitted provided that the following conditions ! 30: * are met: ! 31: * 1. Redistributions of source code must retain the above copyright ! 32: * notice, this list of conditions and the following disclaimer. ! 33: * 2. Redistributions in binary form must reproduce the above copyright ! 34: * notice, this list of conditions and the following disclaimer in the ! 35: * documentation and/or other materials provided with the distribution. ! 36: * 3. All advertising materials mentioning features or use of this software ! 37: * must display the following acknowledgement: ! 38: * This product includes software developed by the University of ! 39: * California, Berkeley and its contributors. ! 40: * 4. Neither the name of the University nor the names of its contributors ! 41: * may be used to endorse or promote products derived from this software ! 42: * without specific prior written permission. ! 43: * ! 44: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 45: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 46: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 47: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 48: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 49: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 50: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 51: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 52: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 53: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 54: * SUCH DAMAGE. ! 55: * ! 56: * @(#)uipc_socket.c 8.6 (Berkeley) 5/2/95 ! 57: */ ! 58: ! 59: #include <sys/param.h> ! 60: #include <sys/systm.h> ! 61: #include <sys/proc.h> ! 62: #include <sys/fcntl.h> ! 63: #include <sys/malloc.h> ! 64: #include <sys/mbuf.h> ! 65: #include <sys/domain.h> ! 66: #include <sys/kernel.h> ! 67: #include <sys/poll.h> ! 68: #include <sys/protosw.h> ! 69: #include <sys/socket.h> ! 70: #include <sys/socketvar.h> ! 71: #include <sys/resourcevar.h> ! 72: #include <sys/signalvar.h> ! 73: #include <sys/sysctl.h> ! 74: #include <sys/uio.h> ! 75: #include <sys/ev.h> ! 76: #include <sys/kdebug.h> ! 77: ! 78: #if ISFB31 ! 79: #include <vm/vm_zone.h> ! 80: #else ! 81: #include <kern/zalloc.h> ! 82: #endif ! 83: ! 84: #include <machine/limits.h> ! 85: ! 86: int socket_debug = 0; ! 87: int socket_zone = M_SOCKET; ! 88: so_gen_t so_gencnt; /* generation count for sockets */ ! 89: ! 90: MALLOC_DEFINE(M_SONAME, "soname", "socket name"); ! 91: MALLOC_DEFINE(M_PCB, "pcb", "protocol control block"); ! 92: ! 93: #if KDEBUG ! 94: #define DBG_LAYER_IN_BEG NETDBG_CODE(DBG_NETSOCK, 0) ! 95: #define DBG_LAYER_IN_END NETDBG_CODE(DBG_NETSOCK, 2) ! 96: #define DBG_LAYER_OUT_BEG NETDBG_CODE(DBG_NETSOCK, 1) ! 97: #define DBG_LAYER_OUT_END NETDBG_CODE(DBG_NETSOCK, 3) ! 98: #define DBG_FNC_SOSEND NETDBG_CODE(DBG_NETSOCK, (4 << 8) | 1) ! 99: #define DBG_FNC_SORECEIVE NETDBG_CODE(DBG_NETSOCK, (8 << 8)) ! 100: #endif ! 101: ! 102: SYSCTL_DECL(_kern_ipc); ! 103: ! 104: static int somaxconn = SOMAXCONN; ! 105: SYSCTL_INT(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, ! 106: 0, ""); ! 107: ! 108: /* ! 109: * Socket operation routines. ! 110: * These routines are called by the routines in ! 111: * sys_socket.c or from a system process, and ! 112: * implement the semantics of socket operations by ! 113: * switching out to the protocol specific routines. ! 114: */ ! 115: ! 116: void socketinit() ! 117: { ! 118: } ! 119: ! 120: ! 121: /* ! 122: * Get a socket structure from our zone, and initialize it. ! 123: * We don't implement `waitok' yet (see comments in uipc_domain.c). ! 124: * Note that it would probably be better to allocate socket ! 125: * and PCB at the same time, but I'm not convinced that all ! 126: * the protocols can be easily modified to do this. ! 127: */ ! 128: struct socket * ! 129: soalloc(waitok) ! 130: int waitok; ! 131: { ! 132: struct socket *so; ! 133: ! 134: so = _MALLOC_ZONE(sizeof(*so), socket_zone, M_WAITOK); ! 135: if (so) { ! 136: /* XXX race condition for reentrant kernel */ ! 137: bzero(so, sizeof *so); ! 138: so->so_gencnt = ++so_gencnt; ! 139: so->so_zone = socket_zone; ! 140: } ! 141: return so; ! 142: } ! 143: ! 144: int ! 145: socreate(dom, aso, type, proto) ! 146: int dom; ! 147: struct socket **aso; ! 148: register int type; ! 149: int proto; ! 150: ! 151: { ! 152: struct proc *p = current_proc(); ! 153: register struct protosw *prp; ! 154: struct socket *so; ! 155: register int error = 0; ! 156: ! 157: if (proto) ! 158: prp = pffindproto(dom, proto, type); ! 159: else ! 160: prp = pffindtype(dom, type); ! 161: if (prp == 0 || prp->pr_usrreqs->pru_attach == 0) ! 162: return (EPROTONOSUPPORT); ! 163: if (prp->pr_type != type) ! 164: return (EPROTOTYPE); ! 165: so = soalloc(p != 0); ! 166: if (so == 0) ! 167: return (ENOBUFS); ! 168: ! 169: TAILQ_INIT(&so->so_incomp); ! 170: TAILQ_INIT(&so->so_comp); ! 171: so->so_type = type; ! 172: ! 173: if (p != 0) { ! 174: if (p->p_ucred->cr_uid == 0) ! 175: so->so_state = SS_PRIV; ! 176: ! 177: so->so_uid = p->p_ucred->cr_uid; ! 178: } ! 179: ! 180: so->so_proto = prp; ! 181: so->so_rcv.sb_flags |= SB_RECV; /* XXX */ ! 182: if (prp->pr_sfilter.tqh_first) ! 183: error = sfilter_init(so); ! 184: if (error == 0) ! 185: error = (*prp->pr_usrreqs->pru_attach)(so, proto, p); ! 186: ! 187: if (error) { ! 188: so->so_state |= SS_NOFDREF; ! 189: sofree(so); ! 190: return (error); ! 191: } ! 192: prp->pr_domain->dom_refs++; ! 193: so->so_rcv.sb_so = so->so_snd.sb_so = so; ! 194: TAILQ_INIT(&so->so_evlist); ! 195: *aso = so; ! 196: return (0); ! 197: } ! 198: ! 199: int ! 200: sobind(so, nam) ! 201: struct socket *so; ! 202: struct sockaddr *nam; ! 203: ! 204: { ! 205: struct proc *p = current_proc(); ! 206: int error; ! 207: struct kextcb *kp; ! 208: int s = splnet(); ! 209: ! 210: error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam, p); ! 211: if (error == 0) /* ??? */ ! 212: { kp = sotokextcb(so); ! 213: while (kp) ! 214: { if (kp->e_soif && kp->e_soif->sf_sobind) ! 215: { error = (*kp->e_soif->sf_sobind)(so, nam, kp); ! 216: if (error) ! 217: { if (error == EJUSTRETURN) ! 218: break; ! 219: splx(s); ! 220: return(error); ! 221: } ! 222: } ! 223: kp = kp->e_next; ! 224: } ! 225: } ! 226: splx(s); ! 227: return (error); ! 228: } ! 229: ! 230: void ! 231: sodealloc(so) ! 232: struct socket *so; ! 233: { ! 234: so->so_gencnt = ++so_gencnt; ! 235: _FREE_ZONE(so, sizeof(*so), so->so_zone); ! 236: } ! 237: ! 238: int ! 239: solisten(so, backlog) ! 240: register struct socket *so; ! 241: int backlog; ! 242: ! 243: { ! 244: struct kextcb *kp; ! 245: struct proc *p = current_proc(); ! 246: int s, error; ! 247: ! 248: s = splnet(); ! 249: error = (*so->so_proto->pr_usrreqs->pru_listen)(so, p); ! 250: if (error) { ! 251: splx(s); ! 252: return (error); ! 253: } ! 254: if (so->so_comp.tqh_first == NULL) ! 255: so->so_options |= SO_ACCEPTCONN; ! 256: if (backlog < 0 || backlog > somaxconn) ! 257: backlog = somaxconn; ! 258: so->so_qlimit = backlog; ! 259: kp = sotokextcb(so); ! 260: while (kp) ! 261: { ! 262: if (kp->e_soif && kp->e_soif->sf_solisten) ! 263: { error = (*kp->e_soif->sf_solisten)(so, kp); ! 264: if (error) ! 265: { if (error == EJUSTRETURN) ! 266: break; ! 267: splx(s); ! 268: return(error); ! 269: } ! 270: } ! 271: kp = kp->e_next; ! 272: } ! 273: ! 274: splx(s); ! 275: return (0); ! 276: } ! 277: ! 278: ! 279: void ! 280: sofree(so) ! 281: register struct socket *so; ! 282: { int error; ! 283: struct kextcb *kp; ! 284: struct socket *head = so->so_head; ! 285: ! 286: kp = sotokextcb(so); ! 287: while (kp) ! 288: { if (kp->e_soif && kp->e_soif->sf_sofree) ! 289: { error = (*kp->e_soif->sf_sofree)(so, kp); ! 290: if (error) ! 291: return; /* void fn */ ! 292: } ! 293: kp = kp->e_next; ! 294: } ! 295: ! 296: if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) ! 297: return; ! 298: if (head != NULL) { ! 299: if (so->so_state & SS_INCOMP) { ! 300: TAILQ_REMOVE(&head->so_incomp, so, so_list); ! 301: head->so_incqlen--; ! 302: } else if (so->so_state & SS_COMP) { ! 303: TAILQ_REMOVE(&head->so_comp, so, so_list); ! 304: } else { ! 305: panic("sofree: not queued"); ! 306: } ! 307: head->so_qlen--; ! 308: so->so_state &= ~(SS_INCOMP|SS_COMP); ! 309: so->so_head = NULL; ! 310: } ! 311: ! 312: sbrelease(&so->so_snd); ! 313: sorflush(so); ! 314: sfilter_term(so); ! 315: sodealloc(so); ! 316: } ! 317: ! 318: /* ! 319: * Close a socket on last file table reference removal. ! 320: * Initiate disconnect if connected. ! 321: * Free socket when disconnect complete. ! 322: */ ! 323: int ! 324: soclose(so) ! 325: register struct socket *so; ! 326: { ! 327: int s = splnet(); /* conservative */ ! 328: int error = 0; ! 329: struct kextcb *kp; ! 330: ! 331: #if FB31SIG ! 332: funsetown(so->so_pgid); ! 333: #endif ! 334: kp = sotokextcb(so); ! 335: while (kp) ! 336: { if (kp->e_soif && kp->e_soif->sf_soclose) ! 337: { error = (*kp->e_soif->sf_soclose)(so, kp); ! 338: if (error) ! 339: { splx(s); ! 340: return((error == EJUSTRETURN) ? 0 : error); ! 341: } ! 342: } ! 343: kp = kp->e_next; ! 344: } ! 345: ! 346: if (so->so_options & SO_ACCEPTCONN) { ! 347: struct socket *sp, *sonext; ! 348: ! 349: for (sp = so->so_incomp.tqh_first; sp != NULL; sp = sonext) { ! 350: sonext = sp->so_list.tqe_next; ! 351: (void) soabort(sp); ! 352: } ! 353: for (sp = so->so_comp.tqh_first; sp != NULL; sp = sonext) { ! 354: sonext = sp->so_list.tqe_next; ! 355: (void) soabort(sp); ! 356: } ! 357: } ! 358: if (so->so_pcb == 0) ! 359: goto discard; ! 360: if (so->so_state & SS_ISCONNECTED) { ! 361: if ((so->so_state & SS_ISDISCONNECTING) == 0) { ! 362: error = sodisconnect(so); ! 363: if (error) ! 364: goto drop; ! 365: } ! 366: if (so->so_options & SO_LINGER) { ! 367: if ((so->so_state & SS_ISDISCONNECTING) && ! 368: (so->so_state & SS_NBIO)) ! 369: goto drop; ! 370: while (so->so_state & SS_ISCONNECTED) { ! 371: error = tsleep((caddr_t)&so->so_timeo, ! 372: PSOCK | PCATCH, "soclos", so->so_linger); ! 373: if (error) ! 374: break; ! 375: } ! 376: } ! 377: } ! 378: drop: ! 379: if (so->so_pcb) { ! 380: int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so); ! 381: if (error == 0) ! 382: error = error2; ! 383: } ! 384: discard: ! 385: if (so->so_state & SS_NOFDREF) ! 386: panic("soclose: NOFDREF"); ! 387: so->so_state |= SS_NOFDREF; ! 388: so->so_proto->pr_domain->dom_refs--; ! 389: evsofree(so); ! 390: sofree(so); ! 391: splx(s); ! 392: return (error); ! 393: } ! 394: ! 395: /* ! 396: * Must be called at splnet... ! 397: */ ! 398: int ! 399: soabort(so) ! 400: struct socket *so; ! 401: { ! 402: ! 403: return (*so->so_proto->pr_usrreqs->pru_abort)(so); ! 404: } ! 405: ! 406: int ! 407: soaccept(so, nam) ! 408: register struct socket *so; ! 409: struct sockaddr **nam; ! 410: { int s = splnet(); ! 411: int error; ! 412: struct kextcb *kp; ! 413: ! 414: if ((so->so_state & SS_NOFDREF) == 0) ! 415: panic("soaccept: !NOFDREF"); ! 416: so->so_state &= ~SS_NOFDREF; ! 417: error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam); ! 418: if (error == 0) ! 419: { kp = sotokextcb(so); ! 420: while (kp) { ! 421: if (kp->e_soif && kp->e_soif->sf_soaccept) ! 422: { error = (*kp->e_soif->sf_soaccept)(so, nam, kp); ! 423: if (error) ! 424: { if (error == EJUSTRETURN) ! 425: break; ! 426: splx(s); ! 427: return(error); ! 428: } ! 429: } ! 430: kp = kp->e_next; ! 431: } ! 432: } ! 433: ! 434: ! 435: splx(s); ! 436: return (error); ! 437: } ! 438: ! 439: int ! 440: soconnect(so, nam) ! 441: register struct socket *so; ! 442: struct sockaddr *nam; ! 443: ! 444: { ! 445: int s; ! 446: int error; ! 447: struct proc *p = current_proc(); ! 448: struct kextcb *kp; ! 449: ! 450: if (so->so_options & SO_ACCEPTCONN) ! 451: return (EOPNOTSUPP); ! 452: s = splnet(); ! 453: /* ! 454: * If protocol is connection-based, can only connect once. ! 455: * Otherwise, if connected, try to disconnect first. ! 456: * This allows user to disconnect by connecting to, e.g., ! 457: * a null address. ! 458: */ ! 459: if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && ! 460: ((so->so_proto->pr_flags & PR_CONNREQUIRED) || ! 461: (error = sodisconnect(so)))) ! 462: error = EISCONN; ! 463: else { ! 464: error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, p); ! 465: if (error == 0) ! 466: { ! 467: kp = sotokextcb(so); ! 468: while (kp) ! 469: { ! 470: if (kp->e_soif && kp->e_soif->sf_soconnect) ! 471: { error = (*kp->e_soif->sf_soconnect)(so, nam, kp); ! 472: if (error) ! 473: { if (error == EJUSTRETURN) ! 474: break; ! 475: splx(s); ! 476: return(error); ! 477: } ! 478: } ! 479: kp = kp->e_next; ! 480: } ! 481: } ! 482: } ! 483: ! 484: splx(s); ! 485: return (error); ! 486: } ! 487: ! 488: int ! 489: soconnect2(so1, so2) ! 490: register struct socket *so1; ! 491: struct socket *so2; ! 492: { ! 493: int s = splnet(); ! 494: int error; ! 495: struct kextcb *kp; ! 496: ! 497: error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2); ! 498: if (error == 0) ! 499: { kp = sotokextcb(so1); ! 500: while (kp) ! 501: { if (kp->e_soif && kp->e_soif->sf_soconnect2) ! 502: { error = (*kp->e_soif->sf_soconnect2)(so1, so2, kp); ! 503: if (error) ! 504: { if (error == EJUSTRETURN) ! 505: break; ! 506: splx(s); ! 507: return(error); ! 508: } ! 509: } ! 510: kp = kp->e_next; ! 511: } ! 512: } ! 513: splx(s); ! 514: return (error); ! 515: } ! 516: ! 517: int ! 518: sodisconnect(so) ! 519: register struct socket *so; ! 520: { ! 521: int s = splnet(); ! 522: int error; ! 523: struct kextcb *kp; ! 524: ! 525: if ((so->so_state & SS_ISCONNECTED) == 0) { ! 526: error = ENOTCONN; ! 527: goto bad; ! 528: } ! 529: if (so->so_state & SS_ISDISCONNECTING) { ! 530: error = EALREADY; ! 531: goto bad; ! 532: } ! 533: error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so); ! 534: ! 535: if (error == 0) ! 536: { kp = sotokextcb(so); ! 537: while (kp) ! 538: { if (kp->e_soif && kp->e_soif->sf_sodisconnect) ! 539: { error = (*kp->e_soif->sf_sodisconnect)(so, kp); ! 540: if (error) ! 541: { if (error == EJUSTRETURN) ! 542: break; ! 543: splx(s); ! 544: return(error); ! 545: } ! 546: } ! 547: kp = kp->e_next; ! 548: } ! 549: } ! 550: ! 551: bad: ! 552: splx(s); ! 553: return (error); ! 554: } ! 555: ! 556: #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_DONTWAIT : M_WAIT) ! 557: /* ! 558: * Send on a socket. ! 559: * If send must go all at once and message is larger than ! 560: * send buffering, then hard error. ! 561: * Lock against other senders. ! 562: * If must go all at once and not enough room now, then ! 563: * inform user that this would block and do nothing. ! 564: * Otherwise, if nonblocking, send as much as possible. ! 565: * The data to be sent is described by "uio" if nonzero, ! 566: * otherwise by the mbuf chain "top" (which must be null ! 567: * if uio is not). Data provided in mbuf chain must be small ! 568: * enough to send all at once. ! 569: * ! 570: * Returns nonzero on error, timeout or signal; callers ! 571: * must check for short counts if EINTR/ERESTART are returned. ! 572: * Data and control buffers are freed on return. ! 573: * Experiment: ! 574: * MSG_HOLD: go thru most of sosend(), but just enqueue the mbuf ! 575: * MSG_SEND: go thru as for MSG_HOLD on current fragment, then ! 576: * point at the mbuf chain being constructed and go from there. ! 577: */ ! 578: int ! 579: sosend(so, addr, uio, top, control, flags) ! 580: register struct socket *so; ! 581: struct sockaddr *addr; ! 582: struct uio *uio; ! 583: struct mbuf *top; ! 584: struct mbuf *control; ! 585: int flags; ! 586: ! 587: { ! 588: struct mbuf **mp; ! 589: register struct mbuf *m; ! 590: register long space, len, resid; ! 591: int clen = 0, error, s, dontroute, mlen, sendflags; ! 592: int atomic = sosendallatonce(so) || top; ! 593: struct proc *p = current_proc(); ! 594: struct kextcb *kp; ! 595: ! 596: if (uio) ! 597: resid = uio->uio_resid; ! 598: else ! 599: resid = top->m_pkthdr.len; ! 600: ! 601: KERNEL_DEBUG((DBG_FNC_SOSEND | DBG_FUNC_START), ! 602: so, ! 603: resid, ! 604: so->so_snd.sb_cc, ! 605: so->so_snd.sb_lowat, ! 606: so->so_snd.sb_hiwat); ! 607: ! 608: /* ! 609: * In theory resid should be unsigned. ! 610: * However, space must be signed, as it might be less than 0 ! 611: * if we over-committed, and we must use a signed comparison ! 612: * of space and resid. On the other hand, a negative resid ! 613: * causes us to loop sending 0-length segments to the protocol. ! 614: * ! 615: * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM ! 616: * type sockets since that's an error. ! 617: */ ! 618: if (resid < 0 || so->so_type == SOCK_STREAM && (flags & MSG_EOR)) { ! 619: error = EINVAL; ! 620: goto out; ! 621: } ! 622: ! 623: dontroute = ! 624: (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && ! 625: (so->so_proto->pr_flags & PR_ATOMIC); ! 626: if (p) ! 627: p->p_stats->p_ru.ru_msgsnd++; ! 628: if (control) ! 629: clen = control->m_len; ! 630: #define snderr(errno) { error = errno; splx(s); goto release; } ! 631: ! 632: restart: ! 633: error = sblock(&so->so_snd, SBLOCKWAIT(flags)); ! 634: if (error) ! 635: goto out; ! 636: do { ! 637: s = splnet(); ! 638: if (so->so_state & SS_CANTSENDMORE) ! 639: snderr(EPIPE); ! 640: if (so->so_error) { ! 641: error = so->so_error; ! 642: so->so_error = 0; ! 643: splx(s); ! 644: goto release; ! 645: } ! 646: if ((so->so_state & SS_ISCONNECTED) == 0) { ! 647: /* ! 648: * `sendto' and `sendmsg' is allowed on a connection- ! 649: * based socket if it supports implied connect. ! 650: * Return ENOTCONN if not connected and no address is ! 651: * supplied. ! 652: */ ! 653: if ((so->so_proto->pr_flags & PR_CONNREQUIRED) && ! 654: (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) { ! 655: if ((so->so_state & SS_ISCONFIRMING) == 0 && ! 656: !(resid == 0 && clen != 0)) ! 657: snderr(ENOTCONN); ! 658: } else if (addr == 0 && !(flags&MSG_HOLD)) ! 659: snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? ! 660: ENOTCONN : EDESTADDRREQ); ! 661: } ! 662: space = sbspace(&so->so_snd); ! 663: if (flags & MSG_OOB) ! 664: space += 1024; ! 665: if ((atomic && resid > so->so_snd.sb_hiwat) || ! 666: clen > so->so_snd.sb_hiwat) ! 667: snderr(EMSGSIZE); ! 668: if (space < resid + clen && uio && ! 669: (atomic || space < so->so_snd.sb_lowat || space < clen)) { ! 670: if (so->so_state & SS_NBIO) ! 671: snderr(EWOULDBLOCK); ! 672: sbunlock(&so->so_snd); ! 673: error = sbwait(&so->so_snd); ! 674: splx(s); ! 675: if (error) ! 676: goto out; ! 677: goto restart; ! 678: } ! 679: splx(s); ! 680: mp = ⊤ ! 681: space -= clen; ! 682: do { ! 683: if (uio == NULL) { ! 684: /* ! 685: * Data is prepackaged in "top". ! 686: */ ! 687: resid = 0; ! 688: if (flags & MSG_EOR) ! 689: top->m_flags |= M_EOR; ! 690: } else do { ! 691: KERNEL_DEBUG(DBG_FNC_SOSEND | DBG_FUNC_NONE, -1, 0, 0, 0, 0); ! 692: if (top == 0) { ! 693: MGETHDR(m, M_WAIT, MT_DATA); ! 694: mlen = MHLEN; ! 695: m->m_pkthdr.len = 0; ! 696: m->m_pkthdr.rcvif = (struct ifnet *)0; ! 697: } else { ! 698: MGET(m, M_WAIT, MT_DATA); ! 699: mlen = MLEN; ! 700: } ! 701: if (resid >= MINCLSIZE) { ! 702: MCLGET(m, M_WAIT); ! 703: if ((m->m_flags & M_EXT) == 0) ! 704: goto nopages; ! 705: mlen = MCLBYTES; ! 706: len = min(min(mlen, resid), space); ! 707: } else { ! 708: nopages: ! 709: len = min(min(mlen, resid), space); ! 710: /* ! 711: * For datagram protocols, leave room ! 712: * for protocol headers in first mbuf. ! 713: */ ! 714: if (atomic && top == 0 && len < mlen) ! 715: MH_ALIGN(m, len); ! 716: } ! 717: KERNEL_DEBUG(DBG_FNC_SOSEND | DBG_FUNC_NONE, -1, 0, 0, 0, 0); ! 718: space -= len; ! 719: error = uiomove(mtod(m, caddr_t), (int)len, uio); ! 720: resid = uio->uio_resid; ! 721: ! 722: m->m_len = len; ! 723: *mp = m; ! 724: top->m_pkthdr.len += len; ! 725: if (error) ! 726: goto release; ! 727: mp = &m->m_next; ! 728: if (resid <= 0) { ! 729: if (flags & MSG_EOR) ! 730: top->m_flags |= M_EOR; ! 731: break; ! 732: } ! 733: } while (space > 0 && (atomic || resid < MINCLSIZE)); ! 734: ! 735: if (flags & (MSG_HOLD|MSG_SEND)) ! 736: { /* Enqueue for later, go away if HOLD */ ! 737: register struct mbuf *mb1; ! 738: if (so->so_temp && (flags & MSG_FLUSH)) ! 739: { m_freem(so->so_temp); ! 740: so->so_temp = NULL; ! 741: } ! 742: if (so->so_temp) ! 743: so->so_tail->m_next = top; ! 744: else ! 745: so->so_temp = top; ! 746: mb1 = top; ! 747: while (mb1->m_next) ! 748: mb1 = mb1->m_next; ! 749: so->so_tail = mb1; ! 750: if (flags&MSG_HOLD) ! 751: { top = NULL; ! 752: goto release; ! 753: } ! 754: top = so->so_temp; ! 755: } ! 756: if (dontroute) ! 757: so->so_options |= SO_DONTROUTE; ! 758: s = splnet(); /* XXX */ ! 759: kp = sotokextcb(so); ! 760: /* Compute flags here, for pru_send and NKEs */ ! 761: sendflags = (flags & MSG_OOB) ? PRUS_OOB : ! 762: /* ! 763: * If the user set MSG_EOF, the protocol ! 764: * understands this flag and nothing left to ! 765: * send then use PRU_SEND_EOF instead of PRU_SEND. ! 766: */ ! 767: ((flags & MSG_EOF) && ! 768: (so->so_proto->pr_flags & PR_IMPLOPCL) && ! 769: (resid <= 0)) ? ! 770: PRUS_EOF : ! 771: /* If there is more to send set PRUS_MORETOCOME */ ! 772: (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0; ! 773: while (kp) ! 774: { if (kp->e_soif && kp->e_soif->sf_sosend) ! 775: { error = (*kp->e_soif->sf_sosend)(so, &addr, ! 776: &uio, &top, ! 777: &control, ! 778: &sendflags, ! 779: kp); ! 780: if (error) ! 781: { if (error == EJUSTRETURN) ! 782: { sbunlock(&so->so_snd); ! 783: return(0); ! 784: } ! 785: goto release; ! 786: } ! 787: } ! 788: kp = kp->e_next; ! 789: } ! 790: ! 791: error = (*so->so_proto->pr_usrreqs->pru_send)(so, ! 792: sendflags, top, addr, control, p); ! 793: splx(s); ! 794: if (flags & MSG_SEND) ! 795: so->so_temp = NULL; ! 796: ! 797: if (dontroute) ! 798: so->so_options &= ~SO_DONTROUTE; ! 799: clen = 0; ! 800: control = 0; ! 801: top = 0; ! 802: mp = ⊤ ! 803: if (error) ! 804: goto release; ! 805: } while (resid && space > 0); ! 806: } while (resid); ! 807: ! 808: release: ! 809: sbunlock(&so->so_snd); ! 810: out: ! 811: if (top) ! 812: m_freem(top); ! 813: if (control) ! 814: m_freem(control); ! 815: ! 816: KERNEL_DEBUG(DBG_FNC_SOSEND | DBG_FUNC_END, ! 817: so, ! 818: resid, ! 819: so->so_snd.sb_cc, ! 820: space, ! 821: error); ! 822: ! 823: return (error); ! 824: } ! 825: ! 826: /* ! 827: * Implement receive operations on a socket. ! 828: * We depend on the way that records are added to the sockbuf ! 829: * by sbappend*. In particular, each record (mbufs linked through m_next) ! 830: * must begin with an address if the protocol so specifies, ! 831: * followed by an optional mbuf or mbufs containing ancillary data, ! 832: * and then zero or more mbufs of data. ! 833: * In order to avoid blocking network interrupts for the entire time here, ! 834: * we splx() while doing the actual copy to user space. ! 835: * Although the sockbuf is locked, new data may still be appended, ! 836: * and thus we must maintain consistency of the sockbuf during that time. ! 837: * ! 838: * The caller may receive the data as a single mbuf chain by supplying ! 839: * an mbuf **mp0 for use in returning the chain. The uio is then used ! 840: * only for the count in uio_resid. ! 841: */ ! 842: int ! 843: soreceive(so, psa, uio, mp0, controlp, flagsp) ! 844: register struct socket *so; ! 845: struct sockaddr **psa; ! 846: struct uio *uio; ! 847: struct mbuf **mp0; ! 848: struct mbuf **controlp; ! 849: int *flagsp; ! 850: { ! 851: register struct mbuf *m, **mp; ! 852: register int flags, len, error, s, offset; ! 853: struct protosw *pr = so->so_proto; ! 854: struct mbuf *nextrecord; ! 855: int moff, type = 0; ! 856: int orig_resid = uio->uio_resid; ! 857: struct kextcb *kp; ! 858: ! 859: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_START, ! 860: so, ! 861: uio->uio_resid, ! 862: so->so_rcv.sb_cc, ! 863: so->so_rcv.sb_lowat, ! 864: so->so_rcv.sb_hiwat); ! 865: ! 866: kp = sotokextcb(so); ! 867: while (kp) ! 868: { if (kp->e_soif && kp->e_soif->sf_soreceive) ! 869: { error = (*kp->e_soif->sf_soreceive)(so, psa, &uio, ! 870: mp0, controlp, ! 871: flagsp, kp); ! 872: if (error) ! 873: return((error == EJUSTRETURN) ? 0 : error); ! 874: } ! 875: kp = kp->e_next; ! 876: } ! 877: ! 878: mp = mp0; ! 879: if (psa) ! 880: *psa = 0; ! 881: if (controlp) ! 882: *controlp = 0; ! 883: if (flagsp) ! 884: flags = *flagsp &~ MSG_EOR; ! 885: else ! 886: flags = 0; ! 887: if (flags & MSG_OOB) { ! 888: m = m_get(M_WAIT, MT_DATA); ! 889: error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK); ! 890: if (error) ! 891: goto bad; ! 892: do { ! 893: error = uiomove(mtod(m, caddr_t), ! 894: (int) min(uio->uio_resid, m->m_len), uio); ! 895: m = m_free(m); ! 896: } while (uio->uio_resid && error == 0 && m); ! 897: bad: ! 898: if (m) ! 899: m_freem(m); ! 900: ! 901: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0); ! 902: return (error); ! 903: } ! 904: if (mp) ! 905: *mp = (struct mbuf *)0; ! 906: if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) ! 907: (*pr->pr_usrreqs->pru_rcvd)(so, 0); ! 908: ! 909: restart: ! 910: if (error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) ! 911: { ! 912: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0); ! 913: return (error); ! 914: } ! 915: s = splnet(); ! 916: ! 917: m = so->so_rcv.sb_mb; ! 918: /* ! 919: * If we have less data than requested, block awaiting more ! 920: * (subject to any timeout) if: ! 921: * 1. the current count is less than the low water mark, or ! 922: * 2. MSG_WAITALL is set, and it is possible to do the entire ! 923: * receive operation at once if we block (resid <= hiwat). ! 924: * 3. MSG_DONTWAIT is not set ! 925: * If MSG_WAITALL is set but resid is larger than the receive buffer, ! 926: * we have to do the receive in sections, and thus risk returning ! 927: * a short count if a timeout or signal occurs after we start. ! 928: */ ! 929: if (m == 0 || (((flags & MSG_DONTWAIT) == 0 && ! 930: so->so_rcv.sb_cc < uio->uio_resid) && ! 931: (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || ! 932: ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && ! 933: m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { ! 934: KASSERT(m != 0 || !so->so_rcv.sb_cc, ("receive 1")); ! 935: if (so->so_error) { ! 936: if (m) ! 937: goto dontblock; ! 938: error = so->so_error; ! 939: if ((flags & MSG_PEEK) == 0) ! 940: so->so_error = 0; ! 941: goto release; ! 942: } ! 943: if (so->so_state & SS_CANTRCVMORE) { ! 944: if (m) ! 945: goto dontblock; ! 946: else ! 947: goto release; ! 948: } ! 949: for (; m; m = m->m_next) ! 950: if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { ! 951: m = so->so_rcv.sb_mb; ! 952: goto dontblock; ! 953: } ! 954: if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && ! 955: (so->so_proto->pr_flags & PR_CONNREQUIRED)) { ! 956: error = ENOTCONN; ! 957: goto release; ! 958: } ! 959: if (uio->uio_resid == 0) ! 960: goto release; ! 961: if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { ! 962: error = EWOULDBLOCK; ! 963: goto release; ! 964: } ! 965: sbunlock(&so->so_rcv); ! 966: if (socket_debug) ! 967: printf("Waiting for socket data\n"); ! 968: error = sbwait(&so->so_rcv); ! 969: if (socket_debug) ! 970: printf("SORECEIVE - sbwait returned %d\n", error); ! 971: splx(s); ! 972: if (error) ! 973: { ! 974: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, error,0,0,0,0); ! 975: return (error); ! 976: } ! 977: goto restart; ! 978: } ! 979: dontblock: ! 980: #ifdef notyet /* XXXX */ ! 981: if (uio->uio_procp) ! 982: uio->uio_procp->p_stats->p_ru.ru_msgrcv++; ! 983: #endif ! 984: nextrecord = m->m_nextpkt; ! 985: if ((pr->pr_flags & PR_ADDR) && m->m_type == MT_SONAME) { ! 986: KASSERT(m->m_type == MT_SONAME, ("receive 1a")); ! 987: orig_resid = 0; ! 988: if (psa) ! 989: *psa = dup_sockaddr(mtod(m, struct sockaddr *), ! 990: mp0 == 0); ! 991: if (flags & MSG_PEEK) { ! 992: m = m->m_next; ! 993: } else { ! 994: sbfree(&so->so_rcv, m); ! 995: MFREE(m, so->so_rcv.sb_mb); ! 996: m = so->so_rcv.sb_mb; ! 997: } ! 998: } ! 999: while (m && m->m_type == MT_CONTROL && error == 0) { ! 1000: if (flags & MSG_PEEK) { ! 1001: if (controlp) ! 1002: *controlp = m_copy(m, 0, m->m_len); ! 1003: m = m->m_next; ! 1004: } else { ! 1005: sbfree(&so->so_rcv, m); ! 1006: if (controlp) { ! 1007: if (pr->pr_domain->dom_externalize && ! 1008: mtod(m, struct cmsghdr *)->cmsg_type == ! 1009: SCM_RIGHTS) ! 1010: error = (*pr->pr_domain->dom_externalize)(m); ! 1011: *controlp = m; ! 1012: so->so_rcv.sb_mb = m->m_next; ! 1013: m->m_next = 0; ! 1014: m = so->so_rcv.sb_mb; ! 1015: } else { ! 1016: MFREE(m, so->so_rcv.sb_mb); ! 1017: m = so->so_rcv.sb_mb; ! 1018: } ! 1019: } ! 1020: if (controlp) { ! 1021: orig_resid = 0; ! 1022: controlp = &(*controlp)->m_next; ! 1023: } ! 1024: } ! 1025: if (m) { ! 1026: if ((flags & MSG_PEEK) == 0) ! 1027: m->m_nextpkt = nextrecord; ! 1028: type = m->m_type; ! 1029: if (type == MT_OOBDATA) ! 1030: flags |= MSG_OOB; ! 1031: } ! 1032: moff = 0; ! 1033: offset = 0; ! 1034: while (m && uio->uio_resid > 0 && error == 0) { ! 1035: if (m->m_type == MT_OOBDATA) { ! 1036: if (type != MT_OOBDATA) ! 1037: break; ! 1038: } else if (type == MT_OOBDATA) ! 1039: break; ! 1040: #if 0 ! 1041: /* ! 1042: * This assertion needs rework. The trouble is Appletalk is uses many ! 1043: * mbuf types (NOT listed in mbuf.h!) which will trigger this panic. ! 1044: * For now just remove the assertion... CSM 9/98 ! 1045: */ ! 1046: else ! 1047: KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, ! 1048: ("receive 3")); ! 1049: #endif ! 1050: so->so_state &= ~SS_RCVATMARK; ! 1051: len = uio->uio_resid; ! 1052: if (so->so_oobmark && len > so->so_oobmark - offset) ! 1053: len = so->so_oobmark - offset; ! 1054: if (len > m->m_len - moff) ! 1055: len = m->m_len - moff; ! 1056: /* ! 1057: * If mp is set, just pass back the mbufs. ! 1058: * Otherwise copy them out via the uio, then free. ! 1059: * Sockbuf must be consistent here (points to current mbuf, ! 1060: * it points to next record) when we drop priority; ! 1061: * we must note any additions to the sockbuf when we ! 1062: * block interrupts again. ! 1063: */ ! 1064: if (mp == 0) { ! 1065: splx(s); ! 1066: error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); ! 1067: s = splnet(); ! 1068: if (error) ! 1069: goto release; ! 1070: } else ! 1071: uio->uio_resid -= len; ! 1072: if (len == m->m_len - moff) { ! 1073: if (m->m_flags & M_EOR) ! 1074: flags |= MSG_EOR; ! 1075: if (flags & MSG_PEEK) { ! 1076: m = m->m_next; ! 1077: moff = 0; ! 1078: } else { ! 1079: nextrecord = m->m_nextpkt; ! 1080: sbfree(&so->so_rcv, m); ! 1081: if (mp) { ! 1082: *mp = m; ! 1083: mp = &m->m_next; ! 1084: so->so_rcv.sb_mb = m = m->m_next; ! 1085: *mp = (struct mbuf *)0; ! 1086: } else { ! 1087: MFREE(m, so->so_rcv.sb_mb); ! 1088: m = so->so_rcv.sb_mb; ! 1089: } ! 1090: if (m) ! 1091: m->m_nextpkt = nextrecord; ! 1092: } ! 1093: } else { ! 1094: if (flags & MSG_PEEK) ! 1095: moff += len; ! 1096: else { ! 1097: if (mp) ! 1098: *mp = m_copym(m, 0, len, M_WAIT); ! 1099: m->m_data += len; ! 1100: m->m_len -= len; ! 1101: so->so_rcv.sb_cc -= len; ! 1102: } ! 1103: } ! 1104: if (so->so_oobmark) { ! 1105: if ((flags & MSG_PEEK) == 0) { ! 1106: so->so_oobmark -= len; ! 1107: if (so->so_oobmark == 0) { ! 1108: so->so_state |= SS_RCVATMARK; ! 1109: postevent(so, 0, EV_OOB); ! 1110: break; ! 1111: } ! 1112: } else { ! 1113: offset += len; ! 1114: if (offset == so->so_oobmark) ! 1115: break; ! 1116: } ! 1117: } ! 1118: if (flags & MSG_EOR) ! 1119: break; ! 1120: /* ! 1121: * If the MSG_WAITALL flag is set (for non-atomic socket), ! 1122: * we must not quit until "uio->uio_resid == 0" or an error ! 1123: * termination. If a signal/timeout occurs, return ! 1124: * with a short count but without error. ! 1125: * Keep sockbuf locked against other readers. ! 1126: */ ! 1127: while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && ! 1128: !sosendallatonce(so) && !nextrecord) { ! 1129: if (so->so_error || so->so_state & SS_CANTRCVMORE) ! 1130: break; ! 1131: error = sbwait(&so->so_rcv); ! 1132: if (error) { ! 1133: sbunlock(&so->so_rcv); ! 1134: splx(s); ! 1135: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, 0,0,0,0,0); ! 1136: return (0); ! 1137: } ! 1138: m = so->so_rcv.sb_mb; ! 1139: if (m) ! 1140: nextrecord = m->m_nextpkt; ! 1141: } ! 1142: } ! 1143: ! 1144: if (m && pr->pr_flags & PR_ATOMIC) { ! 1145: if (so->so_options & SO_DONTTRUNC) ! 1146: flags |= MSG_RCVMORE; ! 1147: else ! 1148: { flags |= MSG_TRUNC; ! 1149: if ((flags & MSG_PEEK) == 0) ! 1150: (void) sbdroprecord(&so->so_rcv); ! 1151: } ! 1152: } ! 1153: if ((flags & MSG_PEEK) == 0) { ! 1154: if (m == 0) ! 1155: so->so_rcv.sb_mb = nextrecord; ! 1156: if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) ! 1157: (*pr->pr_usrreqs->pru_rcvd)(so, flags); ! 1158: } ! 1159: if ((so->so_options & SO_WANTMORE) && so->so_rcv.sb_cc > 0) ! 1160: flags |= MSG_HAVEMORE; ! 1161: if (orig_resid == uio->uio_resid && orig_resid && ! 1162: (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { ! 1163: sbunlock(&so->so_rcv); ! 1164: splx(s); ! 1165: goto restart; ! 1166: } ! 1167: ! 1168: if (flagsp) ! 1169: *flagsp |= flags; ! 1170: release: ! 1171: sbunlock(&so->so_rcv); ! 1172: splx(s); ! 1173: ! 1174: KERNEL_DEBUG(DBG_FNC_SORECEIVE | DBG_FUNC_END, ! 1175: so, ! 1176: uio->uio_resid, ! 1177: so->so_rcv.sb_cc, ! 1178: 0, ! 1179: error); ! 1180: ! 1181: return (error); ! 1182: } ! 1183: ! 1184: int ! 1185: soshutdown(so, how) ! 1186: register struct socket *so; ! 1187: register int how; ! 1188: { ! 1189: register struct protosw *pr = so->so_proto; ! 1190: struct kextcb *kp; ! 1191: int ret; ! 1192: ! 1193: kp = sotokextcb(so); ! 1194: while (kp) ! 1195: { if (kp->e_soif && kp->e_soif->sf_soshutdown) ! 1196: { ret = (*kp->e_soif->sf_soshutdown)(so, how, kp); ! 1197: if (ret) ! 1198: return((ret == EJUSTRETURN) ? 0 : ret); ! 1199: } ! 1200: kp = kp->e_next; ! 1201: } ! 1202: ! 1203: how++; ! 1204: if (how & FREAD) { ! 1205: sorflush(so); ! 1206: postevent(so, 0, EV_RCLOSED); ! 1207: } ! 1208: if (how & FWRITE) { ! 1209: ret = ((*pr->pr_usrreqs->pru_shutdown)(so)); ! 1210: postevent(so, 0, EV_WCLOSED); ! 1211: return(ret); ! 1212: } ! 1213: return (0); ! 1214: } ! 1215: ! 1216: void ! 1217: sorflush(so) ! 1218: register struct socket *so; ! 1219: { ! 1220: register struct sockbuf *sb = &so->so_rcv; ! 1221: register struct protosw *pr = so->so_proto; ! 1222: register int s, error; ! 1223: struct sockbuf asb; ! 1224: struct kextcb *kp; ! 1225: ! 1226: kp = sotokextcb(so); ! 1227: while (kp) ! 1228: { if (kp->e_soif && kp->e_soif->sf_sorflush) ! 1229: { if ((*kp->e_soif->sf_sorflush)(so, kp)) ! 1230: return; ! 1231: } ! 1232: kp = kp->e_next; ! 1233: } ! 1234: ! 1235: sb->sb_flags |= SB_NOINTR; ! 1236: (void) sblock(sb, M_WAIT); ! 1237: s = splimp(); ! 1238: socantrcvmore(so); ! 1239: sbunlock(sb); ! 1240: asb = *sb; ! 1241: bzero((caddr_t)sb, sizeof (*sb)); ! 1242: splx(s); ! 1243: if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) ! 1244: (*pr->pr_domain->dom_dispose)(asb.sb_mb); ! 1245: sbrelease(&asb); ! 1246: } ! 1247: ! 1248: /* ! 1249: * Perhaps this routine, and sooptcopyout(), below, ought to come in ! 1250: * an additional variant to handle the case where the option value needs ! 1251: * to be some kind of integer, but not a specific size. ! 1252: * In addition to their use here, these functions are also called by the ! 1253: * protocol-level pr_ctloutput() routines. ! 1254: */ ! 1255: int ! 1256: sooptcopyin(sopt, buf, len, minlen) ! 1257: struct sockopt *sopt; ! 1258: void *buf; ! 1259: size_t len; ! 1260: size_t minlen; ! 1261: { ! 1262: size_t valsize; ! 1263: ! 1264: /* ! 1265: * If the user gives us more than we wanted, we ignore it, ! 1266: * but if we don't get the minimum length the caller ! 1267: * wants, we return EINVAL. On success, sopt->sopt_valsize ! 1268: * is set to however much we actually retrieved. ! 1269: */ ! 1270: if ((valsize = sopt->sopt_valsize) < minlen) ! 1271: return EINVAL; ! 1272: if (valsize > len) ! 1273: sopt->sopt_valsize = valsize = len; ! 1274: ! 1275: if (sopt->sopt_p != 0) ! 1276: return (copyin(sopt->sopt_val, buf, valsize)); ! 1277: ! 1278: bcopy(sopt->sopt_val, buf, valsize); ! 1279: return 0; ! 1280: } ! 1281: ! 1282: int ! 1283: sosetopt(so, sopt) ! 1284: struct socket *so; ! 1285: struct sockopt *sopt; ! 1286: { ! 1287: int error, optval; ! 1288: struct linger l; ! 1289: struct timeval tv; ! 1290: short val; ! 1291: struct kextcb *kp; ! 1292: ! 1293: kp = sotokextcb(so); ! 1294: while (kp) ! 1295: { if (kp->e_soif && kp->e_soif->sf_socontrol) ! 1296: { error = (*kp->e_soif->sf_socontrol)(so, sopt, kp); ! 1297: if (error) ! 1298: return((error == EJUSTRETURN) ? 0 : error); ! 1299: } ! 1300: kp = kp->e_next; ! 1301: } ! 1302: ! 1303: error = 0; ! 1304: if (sopt->sopt_level != SOL_SOCKET) { ! 1305: if (so->so_proto && so->so_proto->pr_ctloutput) ! 1306: return ((*so->so_proto->pr_ctloutput) ! 1307: (so, sopt)); ! 1308: error = ENOPROTOOPT; ! 1309: } else { ! 1310: switch (sopt->sopt_name) { ! 1311: case SO_LINGER: ! 1312: error = sooptcopyin(sopt, &l, sizeof l, sizeof l); ! 1313: if (error) ! 1314: goto bad; ! 1315: ! 1316: so->so_linger = l.l_linger; ! 1317: if (l.l_onoff) ! 1318: so->so_options |= SO_LINGER; ! 1319: else ! 1320: so->so_options &= ~SO_LINGER; ! 1321: break; ! 1322: ! 1323: case SO_DEBUG: ! 1324: case SO_KEEPALIVE: ! 1325: case SO_DONTROUTE: ! 1326: case SO_USELOOPBACK: ! 1327: case SO_BROADCAST: ! 1328: case SO_REUSEADDR: ! 1329: case SO_REUSEPORT: ! 1330: case SO_OOBINLINE: ! 1331: case SO_TIMESTAMP: ! 1332: case SO_DONTTRUNC: ! 1333: case SO_WANTMORE: ! 1334: error = sooptcopyin(sopt, &optval, sizeof optval, ! 1335: sizeof optval); ! 1336: if (error) ! 1337: goto bad; ! 1338: if (optval) ! 1339: so->so_options |= sopt->sopt_name; ! 1340: else ! 1341: so->so_options &= ~sopt->sopt_name; ! 1342: break; ! 1343: ! 1344: case SO_SNDBUF: ! 1345: case SO_RCVBUF: ! 1346: case SO_SNDLOWAT: ! 1347: case SO_RCVLOWAT: ! 1348: error = sooptcopyin(sopt, &optval, sizeof optval, ! 1349: sizeof optval); ! 1350: if (error) ! 1351: goto bad; ! 1352: ! 1353: /* ! 1354: * Values < 1 make no sense for any of these ! 1355: * options, so disallow them. ! 1356: */ ! 1357: if (optval < 1) { ! 1358: error = EINVAL; ! 1359: goto bad; ! 1360: } ! 1361: ! 1362: switch (sopt->sopt_name) { ! 1363: case SO_SNDBUF: ! 1364: case SO_RCVBUF: ! 1365: if (sbreserve(sopt->sopt_name == SO_SNDBUF ? ! 1366: &so->so_snd : &so->so_rcv, ! 1367: (u_long) optval) == 0) { ! 1368: error = ENOBUFS; ! 1369: goto bad; ! 1370: } ! 1371: break; ! 1372: ! 1373: /* ! 1374: * Make sure the low-water is never greater than ! 1375: * the high-water. ! 1376: */ ! 1377: case SO_SNDLOWAT: ! 1378: so->so_snd.sb_lowat = ! 1379: (optval > so->so_snd.sb_hiwat) ? ! 1380: so->so_snd.sb_hiwat : optval; ! 1381: break; ! 1382: case SO_RCVLOWAT: ! 1383: so->so_rcv.sb_lowat = ! 1384: (optval > so->so_rcv.sb_hiwat) ? ! 1385: so->so_rcv.sb_hiwat : optval; ! 1386: break; ! 1387: } ! 1388: break; ! 1389: ! 1390: case SO_SNDTIMEO: ! 1391: case SO_RCVTIMEO: ! 1392: error = sooptcopyin(sopt, &tv, sizeof tv, ! 1393: sizeof tv); ! 1394: if (error) ! 1395: goto bad; ! 1396: ! 1397: if (tv.tv_sec > SHRT_MAX / hz - hz) { ! 1398: error = EDOM; ! 1399: goto bad; ! 1400: } ! 1401: val = tv.tv_sec * hz + tv.tv_usec / tick; ! 1402: ! 1403: switch (sopt->sopt_name) { ! 1404: case SO_SNDTIMEO: ! 1405: so->so_snd.sb_timeo = val; ! 1406: break; ! 1407: case SO_RCVTIMEO: ! 1408: so->so_rcv.sb_timeo = val; ! 1409: break; ! 1410: } ! 1411: break; ! 1412: ! 1413: case SO_NKE: ! 1414: { struct so_nke nke; ! 1415: struct NFDescriptor *nf1, *nf2 = NULL; ! 1416: ! 1417: error = sooptcopyin(sopt, &nke, ! 1418: sizeof nke, sizeof nke); ! 1419: if (error) ! 1420: goto bad; ! 1421: ! 1422: error = nke_insert(so, &nke); ! 1423: break; ! 1424: } ! 1425: ! 1426: default: ! 1427: error = ENOPROTOOPT; ! 1428: break; ! 1429: } ! 1430: if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { ! 1431: (void) ((*so->so_proto->pr_ctloutput) ! 1432: (so, sopt)); ! 1433: } ! 1434: } ! 1435: bad: ! 1436: return (error); ! 1437: } ! 1438: ! 1439: /* Helper routine for getsockopt */ ! 1440: int ! 1441: sooptcopyout(sopt, buf, len) ! 1442: struct sockopt *sopt; ! 1443: void *buf; ! 1444: size_t len; ! 1445: { ! 1446: int error; ! 1447: size_t valsize; ! 1448: ! 1449: error = 0; ! 1450: ! 1451: /* ! 1452: * Documented get behavior is that we always return a value, ! 1453: * possibly truncated to fit in the user's buffer. ! 1454: * Traditional behavior is that we always tell the user ! 1455: * precisely how much we copied, rather than something useful ! 1456: * like the total amount we had available for her. ! 1457: * Note that this interface is not idempotent; the entire answer must ! 1458: * generated ahead of time. ! 1459: */ ! 1460: valsize = min(len, sopt->sopt_valsize); ! 1461: sopt->sopt_valsize = valsize; ! 1462: if (sopt->sopt_val != 0) { ! 1463: if (sopt->sopt_p != 0) ! 1464: error = copyout(buf, sopt->sopt_val, valsize); ! 1465: else ! 1466: bcopy(buf, sopt->sopt_val, valsize); ! 1467: } ! 1468: return error; ! 1469: } ! 1470: ! 1471: int ! 1472: sogetopt(so, sopt) ! 1473: struct socket *so; ! 1474: struct sockopt *sopt; ! 1475: { ! 1476: int error, optval; ! 1477: struct linger l; ! 1478: struct timeval tv; ! 1479: struct mbuf *m; ! 1480: struct kextcb *kp; ! 1481: ! 1482: kp = sotokextcb(so); ! 1483: while (kp) ! 1484: { if (kp->e_soif && kp->e_soif->sf_socontrol) ! 1485: { error = (*kp->e_soif->sf_socontrol)(so, sopt, kp); ! 1486: if (error) ! 1487: return((error == EJUSTRETURN) ? 0 : error); ! 1488: } ! 1489: kp = kp->e_next; ! 1490: } ! 1491: ! 1492: error = 0; ! 1493: if (sopt->sopt_level != SOL_SOCKET) { ! 1494: if (so->so_proto && so->so_proto->pr_ctloutput) { ! 1495: return ((*so->so_proto->pr_ctloutput) ! 1496: (so, sopt)); ! 1497: } else ! 1498: return (ENOPROTOOPT); ! 1499: } else { ! 1500: switch (sopt->sopt_name) { ! 1501: case SO_LINGER: ! 1502: l.l_onoff = so->so_options & SO_LINGER; ! 1503: l.l_linger = so->so_linger; ! 1504: error = sooptcopyout(sopt, &l, sizeof l); ! 1505: break; ! 1506: ! 1507: case SO_USELOOPBACK: ! 1508: case SO_DONTROUTE: ! 1509: case SO_DEBUG: ! 1510: case SO_KEEPALIVE: ! 1511: case SO_REUSEADDR: ! 1512: case SO_REUSEPORT: ! 1513: case SO_BROADCAST: ! 1514: case SO_OOBINLINE: ! 1515: case SO_TIMESTAMP: ! 1516: case SO_DONTTRUNC: ! 1517: case SO_WANTMORE: ! 1518: optval = so->so_options & sopt->sopt_name; ! 1519: integer: ! 1520: error = sooptcopyout(sopt, &optval, sizeof optval); ! 1521: break; ! 1522: ! 1523: case SO_TYPE: ! 1524: optval = so->so_type; ! 1525: goto integer; ! 1526: ! 1527: case SO_NREAD: ! 1528: { int pkt_total; ! 1529: struct mbuf *m1; ! 1530: ! 1531: pkt_total = 0; ! 1532: m1 = so->so_rcv.sb_mb; ! 1533: if (so->so_proto->pr_flags & PR_ATOMIC) ! 1534: { ! 1535: #if 0 ! 1536: kprintf("SKT CC: %d\n", so->so_rcv.sb_cc); ! 1537: #endif ! 1538: while (m1) ! 1539: { if (m1->m_type == MT_DATA) ! 1540: pkt_total += m1->m_len; ! 1541: #if 0 ! 1542: kprintf("CNT: %d/%d\n", m1->m_len, pkt_total); ! 1543: #endif ! 1544: m1 = m1->m_next; ! 1545: } ! 1546: optval = pkt_total; ! 1547: } else ! 1548: optval = so->so_rcv.sb_cc; ! 1549: #if 0 ! 1550: kprintf("RTN: %d\n", optval); ! 1551: #endif ! 1552: goto integer; ! 1553: } ! 1554: case SO_ERROR: ! 1555: optval = so->so_error; ! 1556: so->so_error = 0; ! 1557: goto integer; ! 1558: ! 1559: case SO_SNDBUF: ! 1560: optval = so->so_snd.sb_hiwat; ! 1561: goto integer; ! 1562: ! 1563: case SO_RCVBUF: ! 1564: optval = so->so_rcv.sb_hiwat; ! 1565: goto integer; ! 1566: ! 1567: case SO_SNDLOWAT: ! 1568: optval = so->so_snd.sb_lowat; ! 1569: goto integer; ! 1570: ! 1571: case SO_RCVLOWAT: ! 1572: optval = so->so_rcv.sb_lowat; ! 1573: goto integer; ! 1574: ! 1575: case SO_SNDTIMEO: ! 1576: case SO_RCVTIMEO: ! 1577: optval = (sopt->sopt_name == SO_SNDTIMEO ? ! 1578: so->so_snd.sb_timeo : so->so_rcv.sb_timeo); ! 1579: ! 1580: tv.tv_sec = optval / hz; ! 1581: tv.tv_usec = (optval % hz) * tick; ! 1582: error = sooptcopyout(sopt, &tv, sizeof tv); ! 1583: break; ! 1584: ! 1585: default: ! 1586: error = ENOPROTOOPT; ! 1587: break; ! 1588: } ! 1589: return (error); ! 1590: } ! 1591: } ! 1592: ! 1593: void ! 1594: sohasoutofband(so) ! 1595: register struct socket *so; ! 1596: { ! 1597: struct proc *p; ! 1598: ! 1599: struct kextcb *kp; ! 1600: ! 1601: kp = sotokextcb(so); ! 1602: while (kp) ! 1603: { if (kp->e_soif && kp->e_soif->sf_sohasoutofband) ! 1604: { if ((*kp->e_soif->sf_sohasoutofband)(so, kp)) ! 1605: return; ! 1606: } ! 1607: kp = kp->e_next; ! 1608: } ! 1609: if (so->so_pgid < 0) ! 1610: gsignal(-so->so_pgid, SIGURG); ! 1611: else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) ! 1612: psignal(p, SIGURG); ! 1613: selwakeup(&so->so_rcv.sb_sel); ! 1614: } ! 1615: ! 1616: /* ! 1617: * Network filter support ! 1618: */ ! 1619: /* Run the list of filters, creating extension control blocks */ ! 1620: sfilter_init(register struct socket *so) ! 1621: { struct kextcb *kp, **kpp; ! 1622: struct protosw *prp; ! 1623: struct NFDescriptor *nfp; ! 1624: ! 1625: prp = so->so_proto; ! 1626: nfp = prp->pr_sfilter.tqh_first; /* non-null */ ! 1627: kpp = &so->so_ext; ! 1628: kp = NULL; ! 1629: while (nfp) ! 1630: { MALLOC(kp, struct kextcb *, sizeof(*kp), ! 1631: M_TEMP, M_WAITOK); ! 1632: if (kp == NULL) ! 1633: return(ENOBUFS); /* so_free will clean up */ ! 1634: *kpp = kp; ! 1635: kpp = &kp->e_next; ! 1636: kp->e_next = NULL; ! 1637: kp->e_fcb = NULL; ! 1638: kp->e_nfd = nfp; ! 1639: kp->e_soif = nfp->nf_soif; ! 1640: kp->e_sout = nfp->nf_soutil; ! 1641: /* ! 1642: * Ignore return value for create ! 1643: * Everyone gets a chance at startup ! 1644: */ ! 1645: if (kp->e_soif && kp->e_soif->sf_socreate) ! 1646: (*kp->e_soif->sf_socreate)(so, prp, kp); ! 1647: nfp = nfp->nf_next.tqe_next; ! 1648: } ! 1649: return(0); ! 1650: } ! 1651: ! 1652: ! 1653: /* ! 1654: * Run the list of filters, freeing extension control blocks ! 1655: * Assumes the soif/soutil blocks have been handled. ! 1656: */ ! 1657: sfilter_term(struct socket *so) ! 1658: { struct kextcb *kp, *kp1; ! 1659: ! 1660: kp = so->so_ext; ! 1661: while (kp) ! 1662: { kp1 = kp->e_next; ! 1663: /* ! 1664: * Ignore return code on termination; everyone must ! 1665: * get terminated. ! 1666: */ ! 1667: if (kp->e_soif && kp->e_soif->sf_sofree) ! 1668: kp->e_soif->sf_sofree(so, kp); ! 1669: FREE(kp, M_TEMP); ! 1670: kp = kp1; ! 1671: } ! 1672: return(0); ! 1673: } ! 1674: ! 1675: ! 1676: int ! 1677: sopoll(struct socket *so, int events, struct ucred *cred) ! 1678: { ! 1679: struct proc *p = current_proc(); ! 1680: int revents = 0; ! 1681: int s = splnet(); ! 1682: ! 1683: if (events & (POLLIN | POLLRDNORM)) ! 1684: if (soreadable(so)) ! 1685: revents |= events & (POLLIN | POLLRDNORM); ! 1686: ! 1687: if (events & (POLLOUT | POLLWRNORM)) ! 1688: if (sowriteable(so)) ! 1689: revents |= events & (POLLOUT | POLLWRNORM); ! 1690: ! 1691: if (events & (POLLPRI | POLLRDBAND)) ! 1692: if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) ! 1693: revents |= events & (POLLPRI | POLLRDBAND); ! 1694: ! 1695: if (revents == 0) { ! 1696: if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { ! 1697: selrecord(p, &so->so_rcv.sb_sel); ! 1698: so->so_rcv.sb_flags |= SB_SEL; ! 1699: } ! 1700: ! 1701: if (events & (POLLOUT | POLLWRNORM)) { ! 1702: selrecord(p, &so->so_snd.sb_sel); ! 1703: so->so_snd.sb_flags |= SB_SEL; ! 1704: } ! 1705: } ! 1706: ! 1707: splx(s); ! 1708: return (revents); ! 1709: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.