123421Smckusick /* 2*35384Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 333185Sbostic * All rights reserved. 423421Smckusick * 533185Sbostic * Redistribution and use in source and binary forms are permitted 634861Sbostic * provided that the above copyright notice and this paragraph are 734861Sbostic * duplicated in all such forms and that any documentation, 834861Sbostic * advertising materials, and other materials related to such 934861Sbostic * distribution and use acknowledge that the software was developed 1034861Sbostic * by the University of California, Berkeley. The name of the 1134861Sbostic * University may not be used to endorse or promote products derived 1234861Sbostic * from this software without specific prior written permission. 1334861Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434861Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534861Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633185Sbostic * 17*35384Skarels * @(#)uipc_socket.c 7.11 (Berkeley) 08/21/88 1823421Smckusick */ 194786Swnj 2017102Sbloom #include "param.h" 2117102Sbloom #include "dir.h" 2217102Sbloom #include "user.h" 2317102Sbloom #include "proc.h" 2417102Sbloom #include "file.h" 25*35384Skarels #include "malloc.h" 2617102Sbloom #include "mbuf.h" 2717102Sbloom #include "domain.h" 2817102Sbloom #include "protosw.h" 2917102Sbloom #include "socket.h" 3017102Sbloom #include "socketvar.h" 314786Swnj 324786Swnj /* 338300Sroot * Socket operation routines. 348300Sroot * These routines are called by the routines in 358300Sroot * sys_socket.c or from a system process, and 368300Sroot * implement the semantics of socket operations by 378300Sroot * switching out to the protocol specific routines. 3812757Ssam * 3912757Ssam * TODO: 4012757Ssam * test socketpair 4121767Skarels * clean up async 4212757Ssam * out-of-band is a kludge 434786Swnj */ 448594Sroot /*ARGSUSED*/ 4510267Ssam socreate(dom, aso, type, proto) 464786Swnj struct socket **aso; 4712757Ssam register int type; 4812757Ssam int proto; 494786Swnj { 504786Swnj register struct protosw *prp; 514786Swnj register struct socket *so; 5212757Ssam register struct mbuf *m; 5312757Ssam register int error; 544786Swnj 554890Swnj if (proto) 5621767Skarels prp = pffindproto(dom, proto, type); 574890Swnj else 589168Ssam prp = pffindtype(dom, type); 594890Swnj if (prp == 0) 604890Swnj return (EPROTONOSUPPORT); 618300Sroot if (prp->pr_type != type) 628300Sroot return (EPROTOTYPE); 639635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 644786Swnj so = mtod(m, struct socket *); 6512757Ssam so->so_options = 0; 666214Swnj so->so_state = 0; 679168Ssam so->so_type = type; 686214Swnj if (u.u_uid == 0) 696214Swnj so->so_state = SS_PRIV; 704786Swnj so->so_proto = prp; 7112757Ssam error = 7212757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 7321767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 744979Swnj if (error) { 757507Sroot so->so_state |= SS_NOFDREF; 767180Swnj sofree(so); 774890Swnj return (error); 784786Swnj } 794786Swnj *aso = so; 804786Swnj return (0); 814786Swnj } 824786Swnj 8310267Ssam sobind(so, nam) 848300Sroot struct socket *so; 858300Sroot struct mbuf *nam; 868300Sroot { 878300Sroot int s = splnet(); 888300Sroot int error; 898300Sroot 908300Sroot error = 9112757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 9212757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 938300Sroot splx(s); 948300Sroot return (error); 958300Sroot } 968300Sroot 978300Sroot solisten(so, backlog) 9812757Ssam register struct socket *so; 998300Sroot int backlog; 1008300Sroot { 10112757Ssam int s = splnet(), error; 1028300Sroot 10312757Ssam error = 10412757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 10512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1068300Sroot if (error) { 1078300Sroot splx(s); 1088300Sroot return (error); 1098300Sroot } 1108300Sroot if (so->so_q == 0) { 1118300Sroot so->so_q = so; 1128300Sroot so->so_q0 = so; 1138300Sroot so->so_options |= SO_ACCEPTCONN; 1148300Sroot } 1158300Sroot if (backlog < 0) 1168300Sroot backlog = 0; 117*35384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 11812493Ssam splx(s); 1198300Sroot return (0); 1208300Sroot } 1218300Sroot 1224916Swnj sofree(so) 12312757Ssam register struct socket *so; 1244916Swnj { 1254916Swnj 12631810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 12731810Skarels return; 1287507Sroot if (so->so_head) { 1297507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1307507Sroot panic("sofree dq"); 1317507Sroot so->so_head = 0; 1327507Sroot } 1334950Swnj sbrelease(&so->so_snd); 13412757Ssam sorflush(so); 1354971Swnj (void) m_free(dtom(so)); 1364916Swnj } 1374916Swnj 1384786Swnj /* 1394890Swnj * Close a socket on last file table reference removal. 1404890Swnj * Initiate disconnect if connected. 1414890Swnj * Free socket when disconnect complete. 1424829Swnj */ 14312757Ssam soclose(so) 1444829Swnj register struct socket *so; 1454829Swnj { 1464890Swnj int s = splnet(); /* conservative */ 14733372Sbostic int error = 0; 1484829Swnj 1497507Sroot if (so->so_options & SO_ACCEPTCONN) { 1507507Sroot while (so->so_q0 != so) 15110399Ssam (void) soabort(so->so_q0); 1527507Sroot while (so->so_q != so) 15310399Ssam (void) soabort(so->so_q); 1547507Sroot } 1554890Swnj if (so->so_pcb == 0) 1564890Swnj goto discard; 1574890Swnj if (so->so_state & SS_ISCONNECTED) { 1584890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 15926245Skarels error = sodisconnect(so); 16012757Ssam if (error) 16112757Ssam goto drop; 1624890Swnj } 16310267Ssam if (so->so_options & SO_LINGER) { 1645281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 16512757Ssam (so->so_state & SS_NBIO)) 16612757Ssam goto drop; 1675281Sroot while (so->so_state & SS_ISCONNECTED) 1685281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1694890Swnj } 1704890Swnj } 1715580Sroot drop: 1726880Ssam if (so->so_pcb) { 17312757Ssam int error2 = 17412757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17612757Ssam if (error == 0) 17712757Ssam error = error2; 1786880Ssam } 1794890Swnj discard: 18010399Ssam if (so->so_state & SS_NOFDREF) 18110399Ssam panic("soclose: NOFDREF"); 1827507Sroot so->so_state |= SS_NOFDREF; 1834950Swnj sofree(so); 1844890Swnj splx(s); 18512757Ssam return (error); 1864829Swnj } 1874829Swnj 18810399Ssam /* 18910399Ssam * Must be called at splnet... 19010399Ssam */ 19110399Ssam soabort(so) 19210399Ssam struct socket *so; 19310399Ssam { 19410399Ssam 19512757Ssam return ( 19612757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19810399Ssam } 19910399Ssam 20010267Ssam soaccept(so, nam) 20112757Ssam register struct socket *so; 2028300Sroot struct mbuf *nam; 2034927Swnj { 2044927Swnj int s = splnet(); 2054927Swnj int error; 2064927Swnj 20710399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20810399Ssam panic("soaccept: !NOFDREF"); 20910267Ssam so->so_state &= ~SS_NOFDREF; 2108300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 21112757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2124927Swnj splx(s); 2134927Swnj return (error); 2144927Swnj } 2154927Swnj 21610267Ssam soconnect(so, nam) 21712757Ssam register struct socket *so; 2188300Sroot struct mbuf *nam; 2194786Swnj { 22030414Skarels int s; 2214890Swnj int error; 2224786Swnj 22330414Skarels if (so->so_options & SO_ACCEPTCONN) 22430414Skarels return (EOPNOTSUPP); 22530414Skarels s = splnet(); 22624768Skarels /* 22724768Skarels * If protocol is connection-based, can only connect once. 22824768Skarels * Otherwise, if connected, try to disconnect first. 22924768Skarels * This allows user to disconnect by connecting to, e.g., 23024768Skarels * a null address. 23124768Skarels */ 23224768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 23324768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 23424768Skarels (error = sodisconnect(so)))) 2354890Swnj error = EISCONN; 23624768Skarels else 23724768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23824768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2394890Swnj splx(s); 2404890Swnj return (error); 2414786Swnj } 2424786Swnj 24312757Ssam soconnect2(so1, so2) 24412757Ssam register struct socket *so1; 24512757Ssam struct socket *so2; 24612757Ssam { 24712757Ssam int s = splnet(); 24812757Ssam int error; 24912757Ssam 25013113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 25113113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 25212757Ssam splx(s); 25312757Ssam return (error); 25412757Ssam } 25512757Ssam 25626245Skarels sodisconnect(so) 25712757Ssam register struct socket *so; 2584786Swnj { 2594890Swnj int s = splnet(); 2604890Swnj int error; 2614786Swnj 2624890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2634890Swnj error = ENOTCONN; 2644890Swnj goto bad; 2654890Swnj } 2664890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2674890Swnj error = EALREADY; 2684890Swnj goto bad; 2694890Swnj } 2708300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 27126245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2724890Swnj bad: 2734890Swnj splx(s); 2744890Swnj return (error); 2754786Swnj } 2764786Swnj 2774786Swnj /* 2784890Swnj * Send on a socket. 2794890Swnj * If send must go all at once and message is larger than 2804890Swnj * send buffering, then hard error. 2814890Swnj * Lock against other senders. 2824890Swnj * If must go all at once and not enough room now, then 2834890Swnj * inform user that this would block and do nothing. 28416412Skarels * Otherwise, if nonblocking, send as much as possible. 2854786Swnj */ 286*35384Skarels sosend(so, nam, uio, flags, rights, control) 2874786Swnj register struct socket *so; 2888300Sroot struct mbuf *nam; 28912757Ssam register struct uio *uio; 2908319Sroot int flags; 291*35384Skarels struct mbuf *rights, *control; 2924786Swnj { 293*35384Skarels struct mbuf *top = 0, **mp; 294*35384Skarels register struct mbuf *m; 295*35384Skarels register int space, len; 296*35384Skarels int rlen = 0, error = 0, s, dontroute, first = 1, mlen; 297*35384Skarels int atomic = sosendallatonce(so); 2984786Swnj 299*35384Skarels if (atomic && uio->uio_resid > so->so_snd.sb_hiwat) 3004890Swnj return (EMSGSIZE); 30112757Ssam dontroute = 30212757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 30312757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30416412Skarels u.u_ru.ru_msgsnd++; 30525629Skarels if (rights) 30625629Skarels rlen = rights->m_len; 30716412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30816412Skarels 3096419Sroot restart: 3104890Swnj sblock(&so->so_snd); 31116412Skarels do { 31216412Skarels s = splnet(); 31321108Skarels if (so->so_state & SS_CANTSENDMORE) 31416412Skarels snderr(EPIPE); 31516412Skarels if (so->so_error) { 31616412Skarels error = so->so_error; 31716412Skarels so->so_error = 0; /* ??? */ 31816412Skarels splx(s); 31916412Skarels goto release; 32016412Skarels } 32116412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 32216412Skarels if (so->so_proto->pr_flags & PR_CONNREQUIRED) 32316412Skarels snderr(ENOTCONN); 32416412Skarels if (nam == 0) 32516412Skarels snderr(EDESTADDRREQ); 32616412Skarels } 32716412Skarels if (flags & MSG_OOB) 32816412Skarels space = 1024; 32916412Skarels else { 33016412Skarels space = sbspace(&so->so_snd); 33125629Skarels if (space <= rlen || 332*35384Skarels (atomic && space < uio->uio_resid + rlen) || 333*35384Skarels (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 334*35384Skarels so->so_snd.sb_cc >= MCLBYTES && 33516992Skarels (so->so_state & SS_NBIO) == 0)) { 33616412Skarels if (so->so_state & SS_NBIO) { 33716412Skarels if (first) 33816412Skarels error = EWOULDBLOCK; 33916412Skarels splx(s); 34016412Skarels goto release; 34116412Skarels } 34216412Skarels sbunlock(&so->so_snd); 34316412Skarels sbwait(&so->so_snd); 34416412Skarels splx(s); 34516412Skarels goto restart; 34616412Skarels } 34716412Skarels } 34816412Skarels splx(s); 34916412Skarels mp = ⊤ 35025629Skarels space -= rlen; 351*35384Skarels do { 352*35384Skarels do { 353*35384Skarels if (top == 0) { 354*35384Skarels MGETHDR(m, M_WAIT, MT_DATA); 355*35384Skarels mlen = MHLEN; 356*35384Skarels m->m_pkthdr.len = 0; 357*35384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 358*35384Skarels } else { 359*35384Skarels MGET(m, M_WAIT, MT_DATA); 360*35384Skarels mlen = MLEN; 361*35384Skarels } 362*35384Skarels if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 363*35384Skarels MCLGET(m, M_WAIT); 364*35384Skarels if ((m->m_flags & M_EXT) == 0) 36516412Skarels goto nopages; 366*35384Skarels mlen = MCLBYTES; 367*35384Skarels #ifdef MAPPED_MBUFS 368*35384Skarels len = min(MCLBYTES, uio->uio_resid); 369*35384Skarels if (len < mlen - max_hdr) 370*35384Skarels m->m_data += max_hdr; 371*35384Skarels #else 372*35384Skarels len = min(MCLBYTES - max_hdr, uio->uio_resid); 373*35384Skarels m->m_data += max_hdr; 374*35384Skarels #endif 375*35384Skarels space -= MCLBYTES; 37616412Skarels } else { 37716412Skarels nopages: 378*35384Skarels len = min(min(mlen, uio->uio_resid), space); 37921767Skarels space -= len; 380*35384Skarels /* 381*35384Skarels * For datagram protocols, leave room 382*35384Skarels * for protocol headers in first mbuf. 383*35384Skarels */ 384*35384Skarels if (atomic && len < mlen) 385*35384Skarels MH_ALIGN(m, len); 38616412Skarels } 38716412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 38816412Skarels m->m_len = len; 38916412Skarels *mp = m; 390*35384Skarels top->m_pkthdr.len += len; 39116412Skarels if (error) 39216412Skarels goto release; 39316412Skarels mp = &m->m_next; 394*35384Skarels if (uio->uio_resid <= 0) { 395*35384Skarels if ((flags & MSG_EOR) && top) 396*35384Skarels top->m_flags |= M_EOR; 39721108Skarels break; 398*35384Skarels } 399*35384Skarels } while (space > 0 && atomic); 400*35384Skarels if (dontroute) 401*35384Skarels so->so_options |= SO_DONTROUTE; 402*35384Skarels s = splnet(); /* XXX */ 403*35384Skarels error = (*so->so_proto->pr_usrreq)(so, 404*35384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 405*35384Skarels top, (caddr_t)nam, rights, control); 406*35384Skarels splx(s); 407*35384Skarels if (dontroute) 408*35384Skarels so->so_options &= ~SO_DONTROUTE; 409*35384Skarels rights = 0; 410*35384Skarels rlen = 0; 411*35384Skarels top = 0; 412*35384Skarels mp = ⊤ 413*35384Skarels first = 0; 414*35384Skarels if (error) 415*35384Skarels goto release; 416*35384Skarels } while (uio->uio_resid && space > 0); 41716412Skarels } while (uio->uio_resid); 4184890Swnj 4194786Swnj release: 4204890Swnj sbunlock(&so->so_snd); 4216419Sroot if (top) 4226419Sroot m_freem(top); 42321108Skarels if (error == EPIPE) 42421108Skarels psignal(u.u_procp, SIGPIPE); 4254786Swnj return (error); 4264786Swnj } 4274786Swnj 42825629Skarels /* 42925629Skarels * Implement receive operations on a socket. 43025629Skarels * We depend on the way that records are added to the sockbuf 43125629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 43225629Skarels * must begin with an address if the protocol so specifies, 43325629Skarels * followed by an optional mbuf containing access rights if supported 43425629Skarels * by the protocol, and then zero or more mbufs of data. 43525629Skarels * In order to avoid blocking network interrupts for the entire time here, 43625629Skarels * we splx() while doing the actual copy to user space. 43725629Skarels * Although the sockbuf is locked, new data may still be appended, 43825629Skarels * and thus we must maintain consistency of the sockbuf during that time. 43925629Skarels */ 440*35384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp) 4414786Swnj register struct socket *so; 4428300Sroot struct mbuf **aname; 44312757Ssam register struct uio *uio; 444*35384Skarels int *flagsp; 445*35384Skarels struct mbuf **rightsp, **controlp; 4464786Swnj { 44726958Skarels register struct mbuf *m; 448*35384Skarels register int flags, len, error = 0, s, offset; 44912757Ssam struct protosw *pr = so->so_proto; 45016993Skarels struct mbuf *nextrecord; 45112757Ssam int moff; 4524786Swnj 45312757Ssam if (rightsp) 45412757Ssam *rightsp = 0; 45512757Ssam if (aname) 45612757Ssam *aname = 0; 457*35384Skarels if (controlp) 458*35384Skarels *controlp = 0; 459*35384Skarels if (flagsp) 460*35384Skarels flags = *flagsp &~ MSG_EOR; 461*35384Skarels else 462*35384Skarels flags = 0; 46312757Ssam if (flags & MSG_OOB) { 4649635Ssam m = m_get(M_WAIT, MT_DATA); 46512757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 46624768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4678594Sroot if (error) 46810137Ssam goto bad; 4698319Sroot do { 47010137Ssam len = uio->uio_resid; 4718319Sroot if (len > m->m_len) 4728319Sroot len = m->m_len; 4738594Sroot error = 4748793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4758319Sroot m = m_free(m); 4768594Sroot } while (uio->uio_resid && error == 0 && m); 47710137Ssam bad: 4788319Sroot if (m) 4798771Sroot m_freem(m); 4808594Sroot return (error); 4818319Sroot } 482*35384Skarels if (so->so_state & SS_ISCONFIRMING) 483*35384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 484*35384Skarels (struct mbuf *)0, (struct mbuf *)0); 4858319Sroot 4864890Swnj restart: 4874890Swnj sblock(&so->so_rcv); 4888835Sroot s = splnet(); 4894890Swnj 4904786Swnj if (so->so_rcv.sb_cc == 0) { 4915168Swnj if (so->so_error) { 4925168Swnj error = so->so_error; 4935168Swnj so->so_error = 0; 4945168Swnj goto release; 4955168Swnj } 49632567Sbostic if (so->so_state & SS_CANTRCVMORE) 4974890Swnj goto release; 49832567Sbostic if ((so->so_state & SS_ISCONNECTED) == 0 && 49932567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 50032567Sbostic error = ENOTCONN; 50132567Sbostic goto release; 5024890Swnj } 50325629Skarels if (uio->uio_resid == 0) 50425629Skarels goto release; 50532567Sbostic if (so->so_state & SS_NBIO) { 50632567Sbostic error = EWOULDBLOCK; 50732567Sbostic goto release; 50832567Sbostic } 5094890Swnj sbunlock(&so->so_rcv); 5104971Swnj sbwait(&so->so_rcv); 5115012Swnj splx(s); 5124890Swnj goto restart; 5134786Swnj } 5148041Sroot u.u_ru.ru_msgrcv++; 5154829Swnj m = so->so_rcv.sb_mb; 51625629Skarels if (m == 0) 51725629Skarels panic("receive 1"); 518*35384Skarels if (m->m_type == 0) 519*35384Skarels panic("receive 3a"); 520*35384Skarels nextrecord = m->m_nextpkt; 52112757Ssam if (pr->pr_flags & PR_ADDR) { 52225629Skarels if (m->m_type != MT_SONAME) 52316993Skarels panic("receive 1a"); 52416993Skarels if (flags & MSG_PEEK) { 52516993Skarels if (aname) 5268319Sroot *aname = m_copy(m, 0, m->m_len); 52725629Skarels m = m->m_next; 52816993Skarels } else { 52925629Skarels sbfree(&so->so_rcv, m); 53016993Skarels if (aname) { 53116993Skarels *aname = m; 532*35384Skarels so->so_rcv.sb_mb = m->m_next; 533*35384Skarels m->m_next = 0; 534*35384Skarels m = so->so_rcv.sb_mb; 53525629Skarels } else { 53626958Skarels MFREE(m, so->so_rcv.sb_mb); 53726958Skarels m = so->so_rcv.sb_mb; 53825629Skarels } 53916993Skarels } 54016993Skarels } 54116993Skarels if (m && m->m_type == MT_RIGHTS) { 54216993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 54326958Skarels panic("receive 2"); 54416993Skarels if (flags & MSG_PEEK) { 54516993Skarels if (rightsp) 54612757Ssam *rightsp = m_copy(m, 0, m->m_len); 54725629Skarels m = m->m_next; 54816993Skarels } else { 54925629Skarels sbfree(&so->so_rcv, m); 55016993Skarels if (rightsp) { 55116993Skarels *rightsp = m; 55226958Skarels so->so_rcv.sb_mb = m->m_next; 55325629Skarels m->m_next = 0; 55426958Skarels m = so->so_rcv.sb_mb; 55525629Skarels } else { 55626958Skarels MFREE(m, so->so_rcv.sb_mb); 55726958Skarels m = so->so_rcv.sb_mb; 55825629Skarels } 55912757Ssam } 5604890Swnj } 561*35384Skarels if (m && m->m_type == MT_CONTROL) { 562*35384Skarels if (flags & MSG_PEEK) { 563*35384Skarels if (controlp) 564*35384Skarels *controlp = m_copy(m, 0, m->m_len); 565*35384Skarels m = m->m_next; 566*35384Skarels } else { 567*35384Skarels sbfree(&so->so_rcv, m); 568*35384Skarels if (controlp) { 569*35384Skarels *controlp = m; 570*35384Skarels so->so_rcv.sb_mb = m->m_next; 571*35384Skarels m->m_next = 0; 572*35384Skarels m = so->so_rcv.sb_mb; 573*35384Skarels } else { 574*35384Skarels MFREE(m, so->so_rcv.sb_mb); 575*35384Skarels m = so->so_rcv.sb_mb; 576*35384Skarels } 577*35384Skarels } 578*35384Skarels } 579*35384Skarels if (m) 580*35384Skarels m->m_nextpkt = nextrecord; 5818319Sroot moff = 0; 58232092Skarels offset = 0; 58316993Skarels while (m && uio->uio_resid > 0 && error == 0) { 584*35384Skarels if (m->m_type == MT_OOBDATA) 585*35384Skarels flags |= MSG_OOB; 586*35384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 58725629Skarels panic("receive 3"); 588*35384Skarels if (m->m_flags & M_EOR) 589*35384Skarels flags |= MSG_EOR; 5907827Sroot len = uio->uio_resid; 5917747Sroot so->so_state &= ~SS_RCVATMARK; 59232092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 59332092Skarels len = so->so_oobmark - offset; 59421767Skarels if (len > m->m_len - moff) 5958319Sroot len = m->m_len - moff; 5964786Swnj splx(s); 5978594Sroot error = 5988793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5994786Swnj s = splnet(); 60021767Skarels if (len == m->m_len - moff) { 60125629Skarels if (flags & MSG_PEEK) { 60225629Skarels m = m->m_next; 60325629Skarels moff = 0; 60425629Skarels } else { 605*35384Skarels nextrecord = m->m_nextpkt; 60625629Skarels sbfree(&so->so_rcv, m); 60726958Skarels MFREE(m, so->so_rcv.sb_mb); 60826958Skarels m = so->so_rcv.sb_mb; 60926958Skarels if (m) 610*35384Skarels m->m_nextpkt = nextrecord; 61125629Skarels } 6124786Swnj } else { 61312757Ssam if (flags & MSG_PEEK) 6148319Sroot moff += len; 6158319Sroot else { 616*35384Skarels m->m_data += len; 6178319Sroot m->m_len -= len; 6188319Sroot so->so_rcv.sb_cc -= len; 6198319Sroot } 6204786Swnj } 62132092Skarels if (so->so_oobmark) { 62232092Skarels if ((flags & MSG_PEEK) == 0) { 62332092Skarels so->so_oobmark -= len; 62432092Skarels if (so->so_oobmark == 0) { 62532092Skarels so->so_state |= SS_RCVATMARK; 62632092Skarels break; 62732092Skarels } 62832092Skarels } else 62932092Skarels offset += len; 6307747Sroot } 63116993Skarels } 632*35384Skarels if (m && (flags & MSG_EOR)) { 633*35384Skarels flags &= ~MSG_EOR; 634*35384Skarels if ((flags & MSG_PEEK) == 0) 635*35384Skarels m->m_flags |= M_EOR; 636*35384Skarels } 63716993Skarels if ((flags & MSG_PEEK) == 0) { 63826500Skarels if (m == 0) 63916993Skarels so->so_rcv.sb_mb = nextrecord; 640*35384Skarels else if (pr->pr_flags & PR_ATOMIC) { 641*35384Skarels flags |= MSG_TRUNC; 64226958Skarels (void) sbdroprecord(&so->so_rcv); 643*35384Skarels } 64416993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 64516993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 64616993Skarels (struct mbuf *)0, (struct mbuf *)0); 64725629Skarels if (error == 0 && rightsp && *rightsp && 64825629Skarels pr->pr_domain->dom_externalize) 64925629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 65016993Skarels } 651*35384Skarels if (flagsp) 652*35384Skarels *flagsp |= flags; 6534890Swnj release: 6544916Swnj sbunlock(&so->so_rcv); 6554890Swnj splx(s); 6564916Swnj return (error); 6574786Swnj } 6584786Swnj 65910267Ssam soshutdown(so, how) 66012757Ssam register struct socket *so; 66112757Ssam register int how; 66210267Ssam { 66312757Ssam register struct protosw *pr = so->so_proto; 66410267Ssam 66510267Ssam how++; 66612757Ssam if (how & FREAD) 66712757Ssam sorflush(so); 66810267Ssam if (how & FWRITE) 66912757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 67012757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 67110267Ssam return (0); 67210267Ssam } 67310267Ssam 67412757Ssam sorflush(so) 67512757Ssam register struct socket *so; 67612757Ssam { 67712757Ssam register struct sockbuf *sb = &so->so_rcv; 67812757Ssam register struct protosw *pr = so->so_proto; 67912757Ssam register int s; 68012757Ssam struct sockbuf asb; 68112757Ssam 68212757Ssam sblock(sb); 68312757Ssam s = splimp(); 68412757Ssam socantrcvmore(so); 68512757Ssam sbunlock(sb); 68612757Ssam asb = *sb; 68712757Ssam bzero((caddr_t)sb, sizeof (*sb)); 68812757Ssam splx(s); 68916993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 69016993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 69112757Ssam sbrelease(&asb); 69212757Ssam } 69312757Ssam 69418553Skarels sosetopt(so, level, optname, m0) 69512757Ssam register struct socket *so; 69610267Ssam int level, optname; 69718553Skarels struct mbuf *m0; 69810267Ssam { 69917158Ssam int error = 0; 70018553Skarels register struct mbuf *m = m0; 70110267Ssam 70217158Ssam if (level != SOL_SOCKET) { 70318369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 70418369Skarels return ((*so->so_proto->pr_ctloutput) 70518553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 70618369Skarels error = ENOPROTOOPT; 70718369Skarels } else { 70818369Skarels switch (optname) { 70910267Ssam 71018369Skarels case SO_LINGER: 71118369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 71218369Skarels error = EINVAL; 71318369Skarels goto bad; 71418369Skarels } 71518369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 71618369Skarels /* fall thru... */ 71717158Ssam 71818369Skarels case SO_DEBUG: 71918369Skarels case SO_KEEPALIVE: 72018369Skarels case SO_DONTROUTE: 72118369Skarels case SO_USELOOPBACK: 72218369Skarels case SO_BROADCAST: 72318369Skarels case SO_REUSEADDR: 72427191Skarels case SO_OOBINLINE: 72518369Skarels if (m == NULL || m->m_len < sizeof (int)) { 72618369Skarels error = EINVAL; 72718369Skarels goto bad; 72818369Skarels } 72918369Skarels if (*mtod(m, int *)) 73018369Skarels so->so_options |= optname; 73118369Skarels else 73218369Skarels so->so_options &= ~optname; 73318369Skarels break; 73418369Skarels 73518369Skarels case SO_SNDBUF: 73618369Skarels case SO_RCVBUF: 73718369Skarels case SO_SNDLOWAT: 73818369Skarels case SO_RCVLOWAT: 73918369Skarels case SO_SNDTIMEO: 74018369Skarels case SO_RCVTIMEO: 74118369Skarels if (m == NULL || m->m_len < sizeof (int)) { 74218369Skarels error = EINVAL; 74318369Skarels goto bad; 74418369Skarels } 74518369Skarels switch (optname) { 74618369Skarels 74718369Skarels case SO_SNDBUF: 74818369Skarels case SO_RCVBUF: 74934492Skarels if (sbreserve(optname == SO_SNDBUF ? 75034492Skarels &so->so_snd : &so->so_rcv, 75134492Skarels (u_long) *mtod(m, int *)) == 0) { 75218369Skarels error = ENOBUFS; 75318369Skarels goto bad; 75418369Skarels } 75518369Skarels break; 75618369Skarels 75718369Skarels case SO_SNDLOWAT: 75818369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 75918369Skarels break; 76018369Skarels case SO_RCVLOWAT: 76118369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 76218369Skarels break; 76318369Skarels case SO_SNDTIMEO: 76418369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 76518369Skarels break; 76618369Skarels case SO_RCVTIMEO: 76718369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 76818369Skarels break; 76918369Skarels } 77018369Skarels break; 77118369Skarels 77218369Skarels default: 77318369Skarels error = ENOPROTOOPT; 77418369Skarels break; 77517158Ssam } 77610267Ssam } 77717158Ssam bad: 77817158Ssam if (m) 77917158Ssam (void) m_free(m); 78017158Ssam return (error); 78110267Ssam } 78210267Ssam 78317158Ssam sogetopt(so, level, optname, mp) 78412757Ssam register struct socket *so; 78510267Ssam int level, optname; 78617158Ssam struct mbuf **mp; 78717158Ssam { 78812757Ssam register struct mbuf *m; 78910267Ssam 79018369Skarels if (level != SOL_SOCKET) { 79118369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 79218369Skarels return ((*so->so_proto->pr_ctloutput) 79318369Skarels (PRCO_GETOPT, so, level, optname, mp)); 79418369Skarels } else 79518369Skarels return (ENOPROTOOPT); 79618369Skarels } else { 79717158Ssam m = m_get(M_WAIT, MT_SOOPTS); 79825502Skarels m->m_len = sizeof (int); 79925502Skarels 80018369Skarels switch (optname) { 80117158Ssam 80218369Skarels case SO_LINGER: 80318369Skarels m->m_len = sizeof (struct linger); 80418369Skarels mtod(m, struct linger *)->l_onoff = 80518369Skarels so->so_options & SO_LINGER; 80618369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 80718369Skarels break; 80810267Ssam 80918369Skarels case SO_USELOOPBACK: 81018369Skarels case SO_DONTROUTE: 81118369Skarels case SO_DEBUG: 81218369Skarels case SO_KEEPALIVE: 81318369Skarels case SO_REUSEADDR: 81418369Skarels case SO_BROADCAST: 81527191Skarels case SO_OOBINLINE: 81618369Skarels *mtod(m, int *) = so->so_options & optname; 81718369Skarels break; 81818369Skarels 81925502Skarels case SO_TYPE: 82025502Skarels *mtod(m, int *) = so->so_type; 82125502Skarels break; 82225502Skarels 82324768Skarels case SO_ERROR: 82424768Skarels *mtod(m, int *) = so->so_error; 82524768Skarels so->so_error = 0; 82624768Skarels break; 82724768Skarels 82818369Skarels case SO_SNDBUF: 82918369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 83018369Skarels break; 83118369Skarels 83218369Skarels case SO_RCVBUF: 83318369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 83418369Skarels break; 83518369Skarels 83618369Skarels case SO_SNDLOWAT: 83718369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 83818369Skarels break; 83918369Skarels 84018369Skarels case SO_RCVLOWAT: 84118369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 84218369Skarels break; 84318369Skarels 84418369Skarels case SO_SNDTIMEO: 84518369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 84618369Skarels break; 84718369Skarels 84818369Skarels case SO_RCVTIMEO: 84918369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 85018369Skarels break; 85118369Skarels 85218369Skarels default: 85326362Skarels (void)m_free(m); 85418369Skarels return (ENOPROTOOPT); 85518369Skarels } 85618369Skarels *mp = m; 85718369Skarels return (0); 85810267Ssam } 85910267Ssam } 86010267Ssam 8615423Swnj sohasoutofband(so) 86212757Ssam register struct socket *so; 8635423Swnj { 86423233Skarels struct proc *p; 8655423Swnj 86623233Skarels if (so->so_pgrp < 0) 86723233Skarels gsignal(-so->so_pgrp, SIGURG); 86823233Skarels else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) 86923233Skarels psignal(p, SIGURG); 87024768Skarels if (so->so_rcv.sb_sel) { 87124768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 87224768Skarels so->so_rcv.sb_sel = 0; 87324768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 87424768Skarels } 8755423Swnj } 876