123421Smckusick /* 241908Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 333185Sbostic * All rights reserved. 423421Smckusick * 544450Sbostic * %sccs.include.redist.c% 633185Sbostic * 7*49059Ssklower * @(#)uipc_socket.c 7.27 (Berkeley) 05/03/91 823421Smckusick */ 94786Swnj 1017102Sbloom #include "param.h" 1117102Sbloom #include "user.h" 1217102Sbloom #include "proc.h" 1317102Sbloom #include "file.h" 1435384Skarels #include "malloc.h" 1517102Sbloom #include "mbuf.h" 1617102Sbloom #include "domain.h" 1744721Skarels #include "kernel.h" 1817102Sbloom #include "protosw.h" 1917102Sbloom #include "socket.h" 2017102Sbloom #include "socketvar.h" 2144721Skarels #include "time.h" 224786Swnj 234786Swnj /* 248300Sroot * Socket operation routines. 258300Sroot * These routines are called by the routines in 268300Sroot * sys_socket.c or from a system process, and 278300Sroot * implement the semantics of socket operations by 288300Sroot * switching out to the protocol specific routines. 2912757Ssam * 3012757Ssam * TODO: 3112757Ssam * test socketpair 3221767Skarels * clean up async 3312757Ssam * out-of-band is a kludge 344786Swnj */ 358594Sroot /*ARGSUSED*/ 3610267Ssam socreate(dom, aso, type, proto) 374786Swnj struct socket **aso; 3812757Ssam register int type; 3912757Ssam int proto; 404786Swnj { 414786Swnj register struct protosw *prp; 424786Swnj register struct socket *so; 4312757Ssam register int error; 444786Swnj 454890Swnj if (proto) 4621767Skarels prp = pffindproto(dom, proto, type); 474890Swnj else 489168Ssam prp = pffindtype(dom, type); 494890Swnj if (prp == 0) 504890Swnj return (EPROTONOSUPPORT); 518300Sroot if (prp->pr_type != type) 528300Sroot return (EPROTOTYPE); 5337478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 5437478Ssklower bzero((caddr_t)so, sizeof(*so)); 559168Ssam so->so_type = type; 566214Swnj if (u.u_uid == 0) 576214Swnj so->so_state = SS_PRIV; 584786Swnj so->so_proto = prp; 5912757Ssam error = 6012757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 6121767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 624979Swnj if (error) { 637507Sroot so->so_state |= SS_NOFDREF; 647180Swnj sofree(so); 654890Swnj return (error); 664786Swnj } 674786Swnj *aso = so; 684786Swnj return (0); 694786Swnj } 704786Swnj 7110267Ssam sobind(so, nam) 728300Sroot struct socket *so; 738300Sroot struct mbuf *nam; 748300Sroot { 758300Sroot int s = splnet(); 768300Sroot int error; 778300Sroot 7841908Skarels error = 7941908Skarels (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8012757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 818300Sroot splx(s); 828300Sroot return (error); 838300Sroot } 848300Sroot 858300Sroot solisten(so, backlog) 8612757Ssam register struct socket *so; 878300Sroot int backlog; 888300Sroot { 8912757Ssam int s = splnet(), error; 908300Sroot 9112757Ssam error = 9212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 9312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 948300Sroot if (error) { 958300Sroot splx(s); 968300Sroot return (error); 978300Sroot } 9838584Skarels if (so->so_q == 0) 998300Sroot so->so_options |= SO_ACCEPTCONN; 1008300Sroot if (backlog < 0) 1018300Sroot backlog = 0; 10235384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 10312493Ssam splx(s); 1048300Sroot return (0); 1058300Sroot } 1068300Sroot 1074916Swnj sofree(so) 10812757Ssam register struct socket *so; 1094916Swnj { 1104916Swnj 11131810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 11231810Skarels return; 1137507Sroot if (so->so_head) { 1147507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1157507Sroot panic("sofree dq"); 1167507Sroot so->so_head = 0; 1177507Sroot } 1184950Swnj sbrelease(&so->so_snd); 11912757Ssam sorflush(so); 12037478Ssklower FREE(so, M_SOCKET); 1214916Swnj } 1224916Swnj 1234786Swnj /* 1244890Swnj * Close a socket on last file table reference removal. 1254890Swnj * Initiate disconnect if connected. 1264890Swnj * Free socket when disconnect complete. 1274829Swnj */ 12812757Ssam soclose(so) 1294829Swnj register struct socket *so; 1304829Swnj { 1314890Swnj int s = splnet(); /* conservative */ 13233372Sbostic int error = 0; 1334829Swnj 1347507Sroot if (so->so_options & SO_ACCEPTCONN) { 13538584Skarels while (so->so_q0) 13610399Ssam (void) soabort(so->so_q0); 13738584Skarels while (so->so_q) 13810399Ssam (void) soabort(so->so_q); 1397507Sroot } 1404890Swnj if (so->so_pcb == 0) 1414890Swnj goto discard; 1424890Swnj if (so->so_state & SS_ISCONNECTED) { 1434890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 14426245Skarels error = sodisconnect(so); 14512757Ssam if (error) 14612757Ssam goto drop; 1474890Swnj } 14810267Ssam if (so->so_options & SO_LINGER) { 1495281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15012757Ssam (so->so_state & SS_NBIO)) 15112757Ssam goto drop; 1525281Sroot while (so->so_state & SS_ISCONNECTED) 15340706Skarels if (error = tsleep((caddr_t)&so->so_timeo, 15440706Skarels PSOCK | PCATCH, netcls, so->so_linger)) 15540706Skarels break; 1564890Swnj } 1574890Swnj } 1585580Sroot drop: 1596880Ssam if (so->so_pcb) { 16012757Ssam int error2 = 16112757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16212757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 16312757Ssam if (error == 0) 16412757Ssam error = error2; 1656880Ssam } 1664890Swnj discard: 16710399Ssam if (so->so_state & SS_NOFDREF) 16810399Ssam panic("soclose: NOFDREF"); 1697507Sroot so->so_state |= SS_NOFDREF; 1704950Swnj sofree(so); 1714890Swnj splx(s); 17212757Ssam return (error); 1734829Swnj } 1744829Swnj 17510399Ssam /* 17610399Ssam * Must be called at splnet... 17710399Ssam */ 17810399Ssam soabort(so) 17910399Ssam struct socket *so; 18010399Ssam { 18110399Ssam 18212757Ssam return ( 18312757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 18412757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 18510399Ssam } 18610399Ssam 18710267Ssam soaccept(so, nam) 18812757Ssam register struct socket *so; 1898300Sroot struct mbuf *nam; 1904927Swnj { 1914927Swnj int s = splnet(); 1924927Swnj int error; 1934927Swnj 19410399Ssam if ((so->so_state & SS_NOFDREF) == 0) 19510399Ssam panic("soaccept: !NOFDREF"); 19610267Ssam so->so_state &= ~SS_NOFDREF; 1978300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 19812757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 1994927Swnj splx(s); 2004927Swnj return (error); 2014927Swnj } 2024927Swnj 20310267Ssam soconnect(so, nam) 20412757Ssam register struct socket *so; 2058300Sroot struct mbuf *nam; 2064786Swnj { 20730414Skarels int s; 2084890Swnj int error; 2094786Swnj 21030414Skarels if (so->so_options & SO_ACCEPTCONN) 21130414Skarels return (EOPNOTSUPP); 21230414Skarels s = splnet(); 21324768Skarels /* 21424768Skarels * If protocol is connection-based, can only connect once. 21524768Skarels * Otherwise, if connected, try to disconnect first. 21624768Skarels * This allows user to disconnect by connecting to, e.g., 21724768Skarels * a null address. 21824768Skarels */ 21924768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 22024768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 22124768Skarels (error = sodisconnect(so)))) 2224890Swnj error = EISCONN; 22324768Skarels else 22424768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22524768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2264890Swnj splx(s); 2274890Swnj return (error); 2284786Swnj } 2294786Swnj 23012757Ssam soconnect2(so1, so2) 23112757Ssam register struct socket *so1; 23212757Ssam struct socket *so2; 23312757Ssam { 23412757Ssam int s = splnet(); 23512757Ssam int error; 23612757Ssam 23713113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23813113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 23912757Ssam splx(s); 24012757Ssam return (error); 24112757Ssam } 24212757Ssam 24326245Skarels sodisconnect(so) 24412757Ssam register struct socket *so; 2454786Swnj { 2464890Swnj int s = splnet(); 2474890Swnj int error; 2484786Swnj 2494890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2504890Swnj error = ENOTCONN; 2514890Swnj goto bad; 2524890Swnj } 2534890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2544890Swnj error = EALREADY; 2554890Swnj goto bad; 2564890Swnj } 2578300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25826245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2594890Swnj bad: 2604890Swnj splx(s); 2614890Swnj return (error); 2624786Swnj } 2634786Swnj 2644786Swnj /* 2654890Swnj * Send on a socket. 2664890Swnj * If send must go all at once and message is larger than 2674890Swnj * send buffering, then hard error. 2684890Swnj * Lock against other senders. 2694890Swnj * If must go all at once and not enough room now, then 2704890Swnj * inform user that this would block and do nothing. 27116412Skarels * Otherwise, if nonblocking, send as much as possible. 27241908Skarels * The data to be sent is described by "uio" if nonzero, 27341908Skarels * otherwise by the mbuf chain "top" (which must be null 27441908Skarels * if uio is not). Data provided in mbuf chain must be small 27541908Skarels * enough to send all at once. 27641908Skarels * 27741908Skarels * Returns nonzero on error, timeout or signal; callers 27841908Skarels * must check for short counts if EINTR/ERESTART are returned. 27941908Skarels * Data and control buffers are freed on return. 2804786Swnj */ 28143417Skarels sosend(so, addr, uio, top, control, flags) 2824786Swnj register struct socket *so; 28341908Skarels struct mbuf *addr; 28441908Skarels struct uio *uio; 28541908Skarels struct mbuf *top; 28641908Skarels struct mbuf *control; 2878319Sroot int flags; 2884786Swnj { 28941908Skarels struct mbuf **mp; 29035384Skarels register struct mbuf *m; 29141908Skarels register long space, len, resid; 29241908Skarels int clen = 0, error, s, dontroute, mlen; 29341908Skarels int atomic = sosendallatonce(so) || top; 2944786Swnj 29541908Skarels if (uio) 29641908Skarels resid = uio->uio_resid; 29741908Skarels else 29841908Skarels resid = top->m_pkthdr.len; 29912757Ssam dontroute = 30012757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 30112757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30216412Skarels u.u_ru.ru_msgsnd++; 30340632Skarels if (control) 30441908Skarels clen = control->m_len; 30516412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30616412Skarels 3076419Sroot restart: 30840706Skarels if (error = sblock(&so->so_snd)) 30941908Skarels goto out; 31016412Skarels do { 31116412Skarels s = splnet(); 31221108Skarels if (so->so_state & SS_CANTSENDMORE) 31316412Skarels snderr(EPIPE); 31437478Ssklower if (so->so_error) 31537478Ssklower snderr(so->so_error); 31616412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31737478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 318*49059Ssklower if ((so->so_state & SS_ISCONFIRMING) == 0 && 319*49059Ssklower !(resid == 0 && clen != 0)) 32037478Ssklower snderr(ENOTCONN); 32141908Skarels } else if (addr == 0) 32216412Skarels snderr(EDESTADDRREQ); 32316412Skarels } 32441908Skarels space = sbspace(&so->so_snd); 32516412Skarels if (flags & MSG_OOB) 32641908Skarels space += 1024; 32741908Skarels if (space < resid + clen && 32841908Skarels (atomic || space < so->so_snd.sb_lowat || space < clen)) { 32941908Skarels if (atomic && resid > so->so_snd.sb_hiwat || 33041908Skarels clen > so->so_snd.sb_hiwat) 33141908Skarels snderr(EMSGSIZE); 33241908Skarels if (so->so_state & SS_NBIO) 33341908Skarels snderr(EWOULDBLOCK); 33441908Skarels sbunlock(&so->so_snd); 33543417Skarels error = sbwait(&so->so_snd); 33641908Skarels splx(s); 33741908Skarels if (error) 33841908Skarels goto out; 33941908Skarels goto restart; 34016412Skarels } 34116412Skarels splx(s); 34216412Skarels mp = ⊤ 34341908Skarels space -= clen; 34443417Skarels do { 34543417Skarels if (uio == NULL) { 34641908Skarels /* 34741908Skarels * Data is prepackaged in "top". 34841908Skarels */ 34941908Skarels resid = 0; 35041908Skarels if (flags & MSG_EOR) 35141908Skarels top->m_flags |= M_EOR; 35243417Skarels } else do { 35335384Skarels if (top == 0) { 35435384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35535384Skarels mlen = MHLEN; 35635384Skarels m->m_pkthdr.len = 0; 35735384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35835384Skarels } else { 35935384Skarels MGET(m, M_WAIT, MT_DATA); 36035384Skarels mlen = MLEN; 36135384Skarels } 36241908Skarels if (resid >= MINCLSIZE && space >= MCLBYTES) { 36335384Skarels MCLGET(m, M_WAIT); 36435384Skarels if ((m->m_flags & M_EXT) == 0) 36516412Skarels goto nopages; 36635384Skarels mlen = MCLBYTES; 36735384Skarels #ifdef MAPPED_MBUFS 36841908Skarels len = min(MCLBYTES, resid); 36941908Skarels #else 37041908Skarels if (top == 0) { 37141908Skarels len = min(MCLBYTES - max_hdr, resid); 37235384Skarels m->m_data += max_hdr; 37346452Ssklower } else 37446452Ssklower len = min(MCLBYTES, resid); 37535384Skarels #endif 37635384Skarels space -= MCLBYTES; 37716412Skarels } else { 37816412Skarels nopages: 37941908Skarels len = min(min(mlen, resid), space); 38021767Skarels space -= len; 38135384Skarels /* 38235384Skarels * For datagram protocols, leave room 38335384Skarels * for protocol headers in first mbuf. 38435384Skarels */ 38535391Skarels if (atomic && top == 0 && len < mlen) 38635384Skarels MH_ALIGN(m, len); 38716412Skarels } 38845515Skarels error = uiomove(mtod(m, caddr_t), (int)len, uio); 38941908Skarels resid = uio->uio_resid; 39016412Skarels m->m_len = len; 39116412Skarels *mp = m; 39235384Skarels top->m_pkthdr.len += len; 39316412Skarels if (error) 39416412Skarels goto release; 39516412Skarels mp = &m->m_next; 39641908Skarels if (resid <= 0) { 39741908Skarels if (flags & MSG_EOR) 39835384Skarels top->m_flags |= M_EOR; 39921108Skarels break; 40035384Skarels } 40135384Skarels } while (space > 0 && atomic); 40235384Skarels if (dontroute) 40335384Skarels so->so_options |= SO_DONTROUTE; 40435384Skarels s = splnet(); /* XXX */ 40535384Skarels error = (*so->so_proto->pr_usrreq)(so, 40635384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40741908Skarels top, addr, control); 40835384Skarels splx(s); 40935384Skarels if (dontroute) 41035384Skarels so->so_options &= ~SO_DONTROUTE; 41141908Skarels clen = 0; 41241908Skarels control = 0; 41335384Skarels top = 0; 41435384Skarels mp = ⊤ 41535384Skarels if (error) 41635384Skarels goto release; 41741908Skarels } while (resid && space > 0); 41841908Skarels } while (resid); 4194890Swnj 4204786Swnj release: 4214890Swnj sbunlock(&so->so_snd); 42241908Skarels out: 4236419Sroot if (top) 4246419Sroot m_freem(top); 42541908Skarels if (control) 42641908Skarels m_freem(control); 4274786Swnj return (error); 4284786Swnj } 4294786Swnj 43025629Skarels /* 43125629Skarels * Implement receive operations on a socket. 43225629Skarels * We depend on the way that records are added to the sockbuf 43325629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 43425629Skarels * must begin with an address if the protocol so specifies, 43541908Skarels * followed by an optional mbuf or mbufs containing ancillary data, 43641908Skarels * and then zero or more mbufs of data. 43725629Skarels * In order to avoid blocking network interrupts for the entire time here, 43825629Skarels * we splx() while doing the actual copy to user space. 43925629Skarels * Although the sockbuf is locked, new data may still be appended, 44025629Skarels * and thus we must maintain consistency of the sockbuf during that time. 44145515Skarels * 44241908Skarels * The caller may receive the data as a single mbuf chain by supplying 44343417Skarels * an mbuf **mp0 for use in returning the chain. The uio is then used 44441908Skarels * only for the count in uio_resid. 44525629Skarels */ 44643417Skarels soreceive(so, paddr, uio, mp0, controlp, flagsp) 4474786Swnj register struct socket *so; 44841908Skarels struct mbuf **paddr; 44941908Skarels struct uio *uio; 45043417Skarels struct mbuf **mp0; 45141908Skarels struct mbuf **controlp; 45235384Skarels int *flagsp; 4534786Swnj { 45443417Skarels register struct mbuf *m, **mp; 45543417Skarels register int flags, len, error, s, offset; 45612757Ssam struct protosw *pr = so->so_proto; 45741908Skarels struct mbuf *nextrecord; 45841908Skarels int moff, type; 4594786Swnj 46043417Skarels mp = mp0; 46141908Skarels if (paddr) 46241908Skarels *paddr = 0; 46335384Skarels if (controlp) 46435384Skarels *controlp = 0; 46535384Skarels if (flagsp) 46635384Skarels flags = *flagsp &~ MSG_EOR; 46745515Skarels else 46835384Skarels flags = 0; 46912757Ssam if (flags & MSG_OOB) { 4709635Ssam m = m_get(M_WAIT, MT_DATA); 47112757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 47224768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4738594Sroot if (error) 47410137Ssam goto bad; 4758319Sroot do { 47641908Skarels error = uiomove(mtod(m, caddr_t), 47741908Skarels (int) min(uio->uio_resid, m->m_len), uio); 4788319Sroot m = m_free(m); 4798594Sroot } while (uio->uio_resid && error == 0 && m); 48010137Ssam bad: 4818319Sroot if (m) 4828771Sroot m_freem(m); 4838594Sroot return (error); 4848319Sroot } 48541908Skarels if (mp) 48641908Skarels *mp = (struct mbuf *)0; 48743417Skarels if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 48835384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 48935384Skarels (struct mbuf *)0, (struct mbuf *)0); 4908319Sroot 4914890Swnj restart: 49240706Skarels if (error = sblock(&so->so_rcv)) 49340706Skarels return (error); 4948835Sroot s = splnet(); 4954890Swnj 49637478Ssklower m = so->so_rcv.sb_mb; 49744383Skarels /* 49844383Skarels * If we have less data than requested, block awaiting more 49944383Skarels * (subject to any timeout) if: 50044383Skarels * 1. the current count is less than the low water mark, or 50144383Skarels * 2. MSG_WAITALL is set, and it is possible to do the entire 50244383Skarels * receive operation at once if we block (resid <= hiwat). 50344383Skarels * If MSG_WAITALL is set but resid is larger than the receive buffer, 50444383Skarels * we have to do the receive in sections, and thus risk returning 50544383Skarels * a short count if a timeout or signal occurs after we start. 50644383Skarels */ 50746479Skarels while (m == 0 || so->so_rcv.sb_cc < uio->uio_resid && 50844383Skarels (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || 50946479Skarels ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && 51046479Skarels m->m_nextpkt == 0) { 51141908Skarels #ifdef DIAGNOSTIC 51241908Skarels if (m == 0 && so->so_rcv.sb_cc) 51337478Ssklower panic("receive 1"); 51441908Skarels #endif 5155168Swnj if (so->so_error) { 51646479Skarels if (m) 51746479Skarels break; 5185168Swnj error = so->so_error; 51946479Skarels if ((flags & MSG_PEEK) == 0) 52046479Skarels so->so_error = 0; 5215168Swnj goto release; 5225168Swnj } 52346479Skarels if (so->so_state & SS_CANTRCVMORE) { 52446479Skarels if (m) 52546479Skarels break; 52646479Skarels else 52746479Skarels goto release; 52846479Skarels } 52946479Skarels for (; m; m = m->m_next) 53046479Skarels if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { 53146479Skarels m = so->so_rcv.sb_mb; 53246479Skarels goto dontblock; 53346479Skarels } 53438584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 53532567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 53632567Sbostic error = ENOTCONN; 53732567Sbostic goto release; 5384890Swnj } 53943417Skarels if (uio->uio_resid == 0) 54025629Skarels goto release; 54132567Sbostic if (so->so_state & SS_NBIO) { 54232567Sbostic error = EWOULDBLOCK; 54332567Sbostic goto release; 54432567Sbostic } 5454890Swnj sbunlock(&so->so_rcv); 54643417Skarels error = sbwait(&so->so_rcv); 5475012Swnj splx(s); 54841908Skarels if (error) 54941908Skarels return (error); 5504890Swnj goto restart; 5514786Swnj } 55246479Skarels dontblock: 5538041Sroot u.u_ru.ru_msgrcv++; 55435384Skarels nextrecord = m->m_nextpkt; 55512757Ssam if (pr->pr_flags & PR_ADDR) { 55641908Skarels #ifdef DIAGNOSTIC 55725629Skarels if (m->m_type != MT_SONAME) 55816993Skarels panic("receive 1a"); 55941908Skarels #endif 56016993Skarels if (flags & MSG_PEEK) { 56141908Skarels if (paddr) 56241908Skarels *paddr = m_copy(m, 0, m->m_len); 56325629Skarels m = m->m_next; 56416993Skarels } else { 56525629Skarels sbfree(&so->so_rcv, m); 56641908Skarels if (paddr) { 56741908Skarels *paddr = m; 56835384Skarels so->so_rcv.sb_mb = m->m_next; 56935384Skarels m->m_next = 0; 57035384Skarels m = so->so_rcv.sb_mb; 57125629Skarels } else { 57226958Skarels MFREE(m, so->so_rcv.sb_mb); 57326958Skarels m = so->so_rcv.sb_mb; 57425629Skarels } 57516993Skarels } 57616993Skarels } 57741908Skarels while (m && m->m_type == MT_CONTROL && error == 0) { 57816993Skarels if (flags & MSG_PEEK) { 57935384Skarels if (controlp) 58035384Skarels *controlp = m_copy(m, 0, m->m_len); 58135384Skarels m = m->m_next; 58235384Skarels } else { 58335384Skarels sbfree(&so->so_rcv, m); 58435384Skarels if (controlp) { 58543097Ssklower if (pr->pr_domain->dom_externalize && 58643097Ssklower mtod(m, struct cmsghdr *)->cmsg_type == 58743097Ssklower SCM_RIGHTS) 58841908Skarels error = (*pr->pr_domain->dom_externalize)(m); 58935384Skarels *controlp = m; 59035384Skarels so->so_rcv.sb_mb = m->m_next; 59135384Skarels m->m_next = 0; 59235384Skarels m = so->so_rcv.sb_mb; 59335384Skarels } else { 59435384Skarels MFREE(m, so->so_rcv.sb_mb); 59535384Skarels m = so->so_rcv.sb_mb; 59635384Skarels } 59735384Skarels } 59841908Skarels if (controlp) 59941908Skarels controlp = &(*controlp)->m_next; 60035384Skarels } 60141908Skarels if (m) { 60244383Skarels if ((flags & MSG_PEEK) == 0) 60344383Skarels m->m_nextpkt = nextrecord; 60441908Skarels type = m->m_type; 60546452Ssklower if (type == MT_OOBDATA) 60646452Ssklower flags |= MSG_OOB; 60741908Skarels } 6088319Sroot moff = 0; 60932092Skarels offset = 0; 61046452Ssklower while (m && uio->uio_resid > 0 && error == 0) { 61146452Ssklower if (m->m_type == MT_OOBDATA) { 61246452Ssklower if (type != MT_OOBDATA) 61346452Ssklower break; 61446452Ssklower } else if (type == MT_OOBDATA) 61546452Ssklower break; 61641908Skarels #ifdef DIAGNOSTIC 61735384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 61825629Skarels panic("receive 3"); 61941908Skarels #endif 6207747Sroot so->so_state &= ~SS_RCVATMARK; 62143417Skarels len = uio->uio_resid; 62232092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 62332092Skarels len = so->so_oobmark - offset; 62421767Skarels if (len > m->m_len - moff) 6258319Sroot len = m->m_len - moff; 62641908Skarels /* 62741908Skarels * If mp is set, just pass back the mbufs. 62841908Skarels * Otherwise copy them out via the uio, then free. 62941908Skarels * Sockbuf must be consistent here (points to current mbuf, 63041908Skarels * it points to next record) when we drop priority; 63141908Skarels * we must note any additions to the sockbuf when we 63241908Skarels * block interrupts again. 63341908Skarels */ 63441908Skarels if (mp == 0) { 63541908Skarels splx(s); 63641908Skarels error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 63741908Skarels s = splnet(); 63843417Skarels } else 63943417Skarels uio->uio_resid -= len; 64021767Skarels if (len == m->m_len - moff) { 64141908Skarels if (m->m_flags & M_EOR) 64241908Skarels flags |= MSG_EOR; 64325629Skarels if (flags & MSG_PEEK) { 64425629Skarels m = m->m_next; 64525629Skarels moff = 0; 64625629Skarels } else { 64735384Skarels nextrecord = m->m_nextpkt; 64825629Skarels sbfree(&so->so_rcv, m); 64941908Skarels if (mp) { 65041908Skarels *mp = m; 65141908Skarels mp = &m->m_next; 65243417Skarels so->so_rcv.sb_mb = m = m->m_next; 65343417Skarels *mp = (struct mbuf *)0; 65441908Skarels } else { 65541908Skarels MFREE(m, so->so_rcv.sb_mb); 65641908Skarels m = so->so_rcv.sb_mb; 65741908Skarels } 65826958Skarels if (m) 65935384Skarels m->m_nextpkt = nextrecord; 66025629Skarels } 6614786Swnj } else { 66212757Ssam if (flags & MSG_PEEK) 6638319Sroot moff += len; 6648319Sroot else { 66543417Skarels if (mp) 66643417Skarels *mp = m_copym(m, 0, len, M_WAIT); 66735384Skarels m->m_data += len; 6688319Sroot m->m_len -= len; 6698319Sroot so->so_rcv.sb_cc -= len; 6708319Sroot } 6714786Swnj } 67232092Skarels if (so->so_oobmark) { 67332092Skarels if ((flags & MSG_PEEK) == 0) { 67432092Skarels so->so_oobmark -= len; 67532092Skarels if (so->so_oobmark == 0) { 67632092Skarels so->so_state |= SS_RCVATMARK; 67732092Skarels break; 67832092Skarels } 67932092Skarels } else 68032092Skarels offset += len; 6817747Sroot } 68241908Skarels if (flags & MSG_EOR) 68340632Skarels break; 68441908Skarels /* 68541908Skarels * If the MSG_WAITALL flag is set (for non-atomic socket), 68643417Skarels * we must not quit until "uio->uio_resid == 0" or an error 68741908Skarels * termination. If a signal/timeout occurs, return 68843417Skarels * with a short count but without error. 68941908Skarels * Keep sockbuf locked against other readers. 69041908Skarels */ 69143417Skarels while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && 69241908Skarels !sosendallatonce(so)) { 69346479Skarels if (so->so_error || so->so_state & SS_CANTRCVMORE) 69446479Skarels break; 69541908Skarels error = sbwait(&so->so_rcv); 69641908Skarels if (error) { 69741908Skarels sbunlock(&so->so_rcv); 69841908Skarels splx(s); 69941908Skarels return (0); 70041908Skarels } 70141908Skarels if (m = so->so_rcv.sb_mb) 70241908Skarels nextrecord = m->m_nextpkt; 70341908Skarels } 70416993Skarels } 70516993Skarels if ((flags & MSG_PEEK) == 0) { 70626500Skarels if (m == 0) 70716993Skarels so->so_rcv.sb_mb = nextrecord; 70835384Skarels else if (pr->pr_flags & PR_ATOMIC) { 70935384Skarels flags |= MSG_TRUNC; 71026958Skarels (void) sbdroprecord(&so->so_rcv); 71135384Skarels } 71216993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 71316993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 71437478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 71537478Ssklower (struct mbuf *)0); 71616993Skarels } 71735384Skarels if (flagsp) 71835384Skarels *flagsp |= flags; 7194890Swnj release: 7204916Swnj sbunlock(&so->so_rcv); 7214890Swnj splx(s); 7224916Swnj return (error); 7234786Swnj } 7244786Swnj 72510267Ssam soshutdown(so, how) 72612757Ssam register struct socket *so; 72712757Ssam register int how; 72810267Ssam { 72912757Ssam register struct protosw *pr = so->so_proto; 73010267Ssam 73110267Ssam how++; 73212757Ssam if (how & FREAD) 73312757Ssam sorflush(so); 73410267Ssam if (how & FWRITE) 73512757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 73612757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 73710267Ssam return (0); 73810267Ssam } 73910267Ssam 74012757Ssam sorflush(so) 74112757Ssam register struct socket *so; 74212757Ssam { 74312757Ssam register struct sockbuf *sb = &so->so_rcv; 74412757Ssam register struct protosw *pr = so->so_proto; 74512757Ssam register int s; 74612757Ssam struct sockbuf asb; 74712757Ssam 74840706Skarels sb->sb_flags |= SB_NOINTR; 74940706Skarels (void) sblock(sb); 75012757Ssam s = splimp(); 75112757Ssam socantrcvmore(so); 75212757Ssam sbunlock(sb); 75312757Ssam asb = *sb; 75412757Ssam bzero((caddr_t)sb, sizeof (*sb)); 75512757Ssam splx(s); 75616993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 75716993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 75812757Ssam sbrelease(&asb); 75912757Ssam } 76012757Ssam 76118553Skarels sosetopt(so, level, optname, m0) 76212757Ssam register struct socket *so; 76310267Ssam int level, optname; 76418553Skarels struct mbuf *m0; 76510267Ssam { 76617158Ssam int error = 0; 76718553Skarels register struct mbuf *m = m0; 76810267Ssam 76917158Ssam if (level != SOL_SOCKET) { 77018369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 77118369Skarels return ((*so->so_proto->pr_ctloutput) 77218553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 77318369Skarels error = ENOPROTOOPT; 77418369Skarels } else { 77518369Skarels switch (optname) { 77610267Ssam 77718369Skarels case SO_LINGER: 77818369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 77918369Skarels error = EINVAL; 78018369Skarels goto bad; 78118369Skarels } 78218369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 78318369Skarels /* fall thru... */ 78417158Ssam 78518369Skarels case SO_DEBUG: 78618369Skarels case SO_KEEPALIVE: 78718369Skarels case SO_DONTROUTE: 78818369Skarels case SO_USELOOPBACK: 78918369Skarels case SO_BROADCAST: 79018369Skarels case SO_REUSEADDR: 79127191Skarels case SO_OOBINLINE: 79218369Skarels if (m == NULL || m->m_len < sizeof (int)) { 79318369Skarels error = EINVAL; 79418369Skarels goto bad; 79518369Skarels } 79618369Skarels if (*mtod(m, int *)) 79718369Skarels so->so_options |= optname; 79818369Skarels else 79918369Skarels so->so_options &= ~optname; 80018369Skarels break; 80118369Skarels 80218369Skarels case SO_SNDBUF: 80341908Skarels case SO_RCVBUF: 80440706Skarels case SO_SNDLOWAT: 80541908Skarels case SO_RCVLOWAT: 80618369Skarels if (m == NULL || m->m_len < sizeof (int)) { 80718369Skarels error = EINVAL; 80818369Skarels goto bad; 80918369Skarels } 81018369Skarels switch (optname) { 81118369Skarels 81218369Skarels case SO_SNDBUF: 81318369Skarels case SO_RCVBUF: 81441908Skarels if (sbreserve(optname == SO_SNDBUF ? 81541908Skarels &so->so_snd : &so->so_rcv, 81641908Skarels (u_long) *mtod(m, int *)) == 0) { 81718369Skarels error = ENOBUFS; 81818369Skarels goto bad; 81918369Skarels } 82018369Skarels break; 82118369Skarels 82218369Skarels case SO_SNDLOWAT: 82341908Skarels so->so_snd.sb_lowat = *mtod(m, int *); 82441908Skarels break; 82518369Skarels case SO_RCVLOWAT: 82641908Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 82718369Skarels break; 82844721Skarels } 82944721Skarels break; 83044721Skarels 83144721Skarels case SO_SNDTIMEO: 83244721Skarels case SO_RCVTIMEO: 83344721Skarels { 83444721Skarels struct timeval *tv; 83544721Skarels short val; 83644721Skarels 83744721Skarels if (m == NULL || m->m_len < sizeof (*tv)) { 83844721Skarels error = EINVAL; 83944721Skarels goto bad; 84044721Skarels } 84144721Skarels tv = mtod(m, struct timeval *); 84244721Skarels if (tv->tv_sec > SHRT_MAX / hz - hz) { 84344721Skarels error = EDOM; 84444721Skarels goto bad; 84544721Skarels } 84644721Skarels val = tv->tv_sec * hz + tv->tv_usec / tick; 84744721Skarels 84844721Skarels switch (optname) { 84944721Skarels 85018369Skarels case SO_SNDTIMEO: 85144721Skarels so->so_snd.sb_timeo = val; 85241908Skarels break; 85318369Skarels case SO_RCVTIMEO: 85444721Skarels so->so_rcv.sb_timeo = val; 85518369Skarels break; 85618369Skarels } 85718369Skarels break; 85844721Skarels } 85918369Skarels 86018369Skarels default: 86118369Skarels error = ENOPROTOOPT; 86218369Skarels break; 86317158Ssam } 86410267Ssam } 86517158Ssam bad: 86617158Ssam if (m) 86717158Ssam (void) m_free(m); 86817158Ssam return (error); 86910267Ssam } 87010267Ssam 87117158Ssam sogetopt(so, level, optname, mp) 87212757Ssam register struct socket *so; 87310267Ssam int level, optname; 87417158Ssam struct mbuf **mp; 87517158Ssam { 87612757Ssam register struct mbuf *m; 87710267Ssam 87818369Skarels if (level != SOL_SOCKET) { 87918369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 88018369Skarels return ((*so->so_proto->pr_ctloutput) 88118369Skarels (PRCO_GETOPT, so, level, optname, mp)); 88245515Skarels } else 88318369Skarels return (ENOPROTOOPT); 88418369Skarels } else { 88517158Ssam m = m_get(M_WAIT, MT_SOOPTS); 88625502Skarels m->m_len = sizeof (int); 88725502Skarels 88818369Skarels switch (optname) { 88917158Ssam 89018369Skarels case SO_LINGER: 89118369Skarels m->m_len = sizeof (struct linger); 89218369Skarels mtod(m, struct linger *)->l_onoff = 89318369Skarels so->so_options & SO_LINGER; 89418369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 89518369Skarels break; 89610267Ssam 89718369Skarels case SO_USELOOPBACK: 89818369Skarels case SO_DONTROUTE: 89918369Skarels case SO_DEBUG: 90018369Skarels case SO_KEEPALIVE: 90118369Skarels case SO_REUSEADDR: 90218369Skarels case SO_BROADCAST: 90327191Skarels case SO_OOBINLINE: 90418369Skarels *mtod(m, int *) = so->so_options & optname; 90518369Skarels break; 90618369Skarels 90725502Skarels case SO_TYPE: 90825502Skarels *mtod(m, int *) = so->so_type; 90925502Skarels break; 91025502Skarels 91124768Skarels case SO_ERROR: 91224768Skarels *mtod(m, int *) = so->so_error; 91324768Skarels so->so_error = 0; 91424768Skarels break; 91524768Skarels 91618369Skarels case SO_SNDBUF: 91718369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 91818369Skarels break; 91918369Skarels 92018369Skarels case SO_RCVBUF: 92118369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 92218369Skarels break; 92318369Skarels 92418369Skarels case SO_SNDLOWAT: 92518369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 92618369Skarels break; 92718369Skarels 92818369Skarels case SO_RCVLOWAT: 92918369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 93018369Skarels break; 93118369Skarels 93218369Skarels case SO_SNDTIMEO: 93344721Skarels case SO_RCVTIMEO: 93444721Skarels { 93544721Skarels int val = (optname == SO_SNDTIMEO ? 93644721Skarels so->so_snd.sb_timeo : so->so_rcv.sb_timeo); 93718369Skarels 93844721Skarels m->m_len = sizeof(struct timeval); 93944721Skarels mtod(m, struct timeval *)->tv_sec = val / hz; 94044721Skarels mtod(m, struct timeval *)->tv_usec = 94144721Skarels (val % hz) / tick; 94218369Skarels break; 94344721Skarels } 94418369Skarels 94518369Skarels default: 94626362Skarels (void)m_free(m); 94718369Skarels return (ENOPROTOOPT); 94818369Skarels } 94918369Skarels *mp = m; 95018369Skarels return (0); 95110267Ssam } 95210267Ssam } 95310267Ssam 9545423Swnj sohasoutofband(so) 95512757Ssam register struct socket *so; 9565423Swnj { 95723233Skarels struct proc *p; 9585423Swnj 95937478Ssklower if (so->so_pgid < 0) 96037478Ssklower gsignal(-so->so_pgid, SIGURG); 96137478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 96223233Skarels psignal(p, SIGURG); 96324768Skarels if (so->so_rcv.sb_sel) { 96424768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 96524768Skarels so->so_rcv.sb_sel = 0; 96624768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 96724768Skarels } 9685423Swnj } 969