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*52926Smckusick * @(#)uipc_socket.c 7.34 (Berkeley) 03/13/92 823421Smckusick */ 94786Swnj 1017102Sbloom #include "param.h" 1117102Sbloom #include "proc.h" 1217102Sbloom #include "file.h" 1335384Skarels #include "malloc.h" 1417102Sbloom #include "mbuf.h" 1517102Sbloom #include "domain.h" 1644721Skarels #include "kernel.h" 1717102Sbloom #include "protosw.h" 1817102Sbloom #include "socket.h" 1917102Sbloom #include "socketvar.h" 2050942Ssklower #include "resourcevar.h" 214786Swnj 224786Swnj /* 238300Sroot * Socket operation routines. 248300Sroot * These routines are called by the routines in 258300Sroot * sys_socket.c or from a system process, and 268300Sroot * implement the semantics of socket operations by 278300Sroot * switching out to the protocol specific routines. 284786Swnj */ 298594Sroot /*ARGSUSED*/ 3010267Ssam socreate(dom, aso, type, proto) 3152482Storek int dom; 324786Swnj struct socket **aso; 3312757Ssam register int type; 3412757Ssam int proto; 354786Swnj { 3650942Ssklower struct proc *p = curproc; /* XXX */ 374786Swnj register struct protosw *prp; 384786Swnj register struct socket *so; 3912757Ssam register int error; 404786Swnj 414890Swnj if (proto) 4221767Skarels prp = pffindproto(dom, proto, type); 434890Swnj else 449168Ssam prp = pffindtype(dom, type); 454890Swnj if (prp == 0) 464890Swnj return (EPROTONOSUPPORT); 478300Sroot if (prp->pr_type != type) 488300Sroot return (EPROTOTYPE); 4937478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 5037478Ssklower bzero((caddr_t)so, sizeof(*so)); 519168Ssam so->so_type = type; 5250942Ssklower if (p->p_ucred->cr_uid == 0) 536214Swnj so->so_state = SS_PRIV; 544786Swnj so->so_proto = prp; 5512757Ssam error = 5612757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 5721767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 584979Swnj if (error) { 597507Sroot so->so_state |= SS_NOFDREF; 607180Swnj sofree(so); 614890Swnj return (error); 624786Swnj } 634786Swnj *aso = so; 644786Swnj return (0); 654786Swnj } 664786Swnj 6710267Ssam sobind(so, nam) 688300Sroot struct socket *so; 698300Sroot struct mbuf *nam; 708300Sroot { 718300Sroot int s = splnet(); 728300Sroot int error; 738300Sroot 7441908Skarels error = 7541908Skarels (*so->so_proto->pr_usrreq)(so, PRU_BIND, 7612757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 778300Sroot splx(s); 788300Sroot return (error); 798300Sroot } 808300Sroot 818300Sroot solisten(so, backlog) 8212757Ssam register struct socket *so; 838300Sroot int backlog; 848300Sroot { 8512757Ssam int s = splnet(), error; 868300Sroot 8712757Ssam error = 8812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 8912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 908300Sroot if (error) { 918300Sroot splx(s); 928300Sroot return (error); 938300Sroot } 9438584Skarels if (so->so_q == 0) 958300Sroot so->so_options |= SO_ACCEPTCONN; 968300Sroot if (backlog < 0) 978300Sroot backlog = 0; 9835384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 9912493Ssam splx(s); 1008300Sroot return (0); 1018300Sroot } 1028300Sroot 1034916Swnj sofree(so) 10412757Ssam register struct socket *so; 1054916Swnj { 1064916Swnj 10731810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 10831810Skarels return; 1097507Sroot if (so->so_head) { 1107507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1117507Sroot panic("sofree dq"); 1127507Sroot so->so_head = 0; 1137507Sroot } 1144950Swnj sbrelease(&so->so_snd); 11512757Ssam sorflush(so); 11637478Ssklower FREE(so, M_SOCKET); 1174916Swnj } 1184916Swnj 1194786Swnj /* 1204890Swnj * Close a socket on last file table reference removal. 1214890Swnj * Initiate disconnect if connected. 1224890Swnj * Free socket when disconnect complete. 1234829Swnj */ 12412757Ssam soclose(so) 1254829Swnj register struct socket *so; 1264829Swnj { 1274890Swnj int s = splnet(); /* conservative */ 12833372Sbostic int error = 0; 1294829Swnj 1307507Sroot if (so->so_options & SO_ACCEPTCONN) { 13138584Skarels while (so->so_q0) 13210399Ssam (void) soabort(so->so_q0); 13338584Skarels while (so->so_q) 13410399Ssam (void) soabort(so->so_q); 1357507Sroot } 1364890Swnj if (so->so_pcb == 0) 1374890Swnj goto discard; 1384890Swnj if (so->so_state & SS_ISCONNECTED) { 1394890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 14026245Skarels error = sodisconnect(so); 14112757Ssam if (error) 14212757Ssam goto drop; 1434890Swnj } 14410267Ssam if (so->so_options & SO_LINGER) { 1455281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 14612757Ssam (so->so_state & SS_NBIO)) 14712757Ssam goto drop; 1485281Sroot while (so->so_state & SS_ISCONNECTED) 14940706Skarels if (error = tsleep((caddr_t)&so->so_timeo, 15040706Skarels PSOCK | PCATCH, netcls, so->so_linger)) 15140706Skarels break; 1524890Swnj } 1534890Swnj } 1545580Sroot drop: 1556880Ssam if (so->so_pcb) { 15612757Ssam int error2 = 15712757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 15812757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 15912757Ssam if (error == 0) 16012757Ssam error = error2; 1616880Ssam } 1624890Swnj discard: 16310399Ssam if (so->so_state & SS_NOFDREF) 16410399Ssam panic("soclose: NOFDREF"); 1657507Sroot so->so_state |= SS_NOFDREF; 1664950Swnj sofree(so); 1674890Swnj splx(s); 16812757Ssam return (error); 1694829Swnj } 1704829Swnj 17110399Ssam /* 17210399Ssam * Must be called at splnet... 17310399Ssam */ 17410399Ssam soabort(so) 17510399Ssam struct socket *so; 17610399Ssam { 17710399Ssam 17812757Ssam return ( 17912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 18012757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 18110399Ssam } 18210399Ssam 18310267Ssam soaccept(so, nam) 18412757Ssam register struct socket *so; 1858300Sroot struct mbuf *nam; 1864927Swnj { 1874927Swnj int s = splnet(); 1884927Swnj int error; 1894927Swnj 19010399Ssam if ((so->so_state & SS_NOFDREF) == 0) 19110399Ssam panic("soaccept: !NOFDREF"); 19210267Ssam so->so_state &= ~SS_NOFDREF; 1938300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 19412757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 1954927Swnj splx(s); 1964927Swnj return (error); 1974927Swnj } 1984927Swnj 19910267Ssam soconnect(so, nam) 20012757Ssam register struct socket *so; 2018300Sroot struct mbuf *nam; 2024786Swnj { 20330414Skarels int s; 2044890Swnj int error; 2054786Swnj 20630414Skarels if (so->so_options & SO_ACCEPTCONN) 20730414Skarels return (EOPNOTSUPP); 20830414Skarels s = splnet(); 20924768Skarels /* 21024768Skarels * If protocol is connection-based, can only connect once. 21124768Skarels * Otherwise, if connected, try to disconnect first. 21224768Skarels * This allows user to disconnect by connecting to, e.g., 21324768Skarels * a null address. 21424768Skarels */ 21524768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 21624768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 21724768Skarels (error = sodisconnect(so)))) 2184890Swnj error = EISCONN; 21924768Skarels else 22024768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22124768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2224890Swnj splx(s); 2234890Swnj return (error); 2244786Swnj } 2254786Swnj 22612757Ssam soconnect2(so1, so2) 22712757Ssam register struct socket *so1; 22812757Ssam struct socket *so2; 22912757Ssam { 23012757Ssam int s = splnet(); 23112757Ssam int error; 23212757Ssam 23313113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23413113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 23512757Ssam splx(s); 23612757Ssam return (error); 23712757Ssam } 23812757Ssam 23926245Skarels sodisconnect(so) 24012757Ssam register struct socket *so; 2414786Swnj { 2424890Swnj int s = splnet(); 2434890Swnj int error; 2444786Swnj 2454890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2464890Swnj error = ENOTCONN; 2474890Swnj goto bad; 2484890Swnj } 2494890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2504890Swnj error = EALREADY; 2514890Swnj goto bad; 2524890Swnj } 2538300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25426245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2554890Swnj bad: 2564890Swnj splx(s); 2574890Swnj return (error); 2584786Swnj } 2594786Swnj 26051755Smckusick #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) 2614786Swnj /* 2624890Swnj * Send on a socket. 2634890Swnj * If send must go all at once and message is larger than 2644890Swnj * send buffering, then hard error. 2654890Swnj * Lock against other senders. 2664890Swnj * If must go all at once and not enough room now, then 2674890Swnj * inform user that this would block and do nothing. 26816412Skarels * Otherwise, if nonblocking, send as much as possible. 26941908Skarels * The data to be sent is described by "uio" if nonzero, 27041908Skarels * otherwise by the mbuf chain "top" (which must be null 27141908Skarels * if uio is not). Data provided in mbuf chain must be small 27241908Skarels * enough to send all at once. 27341908Skarels * 27441908Skarels * Returns nonzero on error, timeout or signal; callers 27541908Skarels * must check for short counts if EINTR/ERESTART are returned. 27641908Skarels * Data and control buffers are freed on return. 2774786Swnj */ 27843417Skarels sosend(so, addr, uio, top, control, flags) 2794786Swnj register struct socket *so; 28041908Skarels struct mbuf *addr; 28141908Skarels struct uio *uio; 28241908Skarels struct mbuf *top; 28341908Skarels struct mbuf *control; 2848319Sroot int flags; 2854786Swnj { 28650942Ssklower struct proc *p = curproc; /* XXX */ 28741908Skarels struct mbuf **mp; 28835384Skarels register struct mbuf *m; 28941908Skarels register long space, len, resid; 29041908Skarels int clen = 0, error, s, dontroute, mlen; 29141908Skarels int atomic = sosendallatonce(so) || top; 2924786Swnj 29341908Skarels if (uio) 29441908Skarels resid = uio->uio_resid; 29541908Skarels else 29641908Skarels resid = top->m_pkthdr.len; 29712757Ssam dontroute = 29812757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29912757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30050942Ssklower p->p_stats->p_ru.ru_msgsnd++; 30140632Skarels if (control) 30241908Skarels clen = control->m_len; 30316412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30416412Skarels 3056419Sroot restart: 30651755Smckusick if (error = sblock(&so->so_snd, SBLOCKWAIT(flags))) 30741908Skarels goto out; 30816412Skarels do { 30916412Skarels s = splnet(); 31021108Skarels if (so->so_state & SS_CANTSENDMORE) 31116412Skarels snderr(EPIPE); 31237478Ssklower if (so->so_error) 31337478Ssklower snderr(so->so_error); 31416412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31537478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 31649059Ssklower if ((so->so_state & SS_ISCONFIRMING) == 0 && 31749059Ssklower !(resid == 0 && clen != 0)) 31837478Ssklower snderr(ENOTCONN); 31941908Skarels } else if (addr == 0) 32016412Skarels snderr(EDESTADDRREQ); 32116412Skarels } 32241908Skarels space = sbspace(&so->so_snd); 32316412Skarels if (flags & MSG_OOB) 32441908Skarels space += 1024; 32551755Smckusick if (atomic && resid > so->so_snd.sb_hiwat || 32651755Smckusick clen > so->so_snd.sb_hiwat) 32751755Smckusick snderr(EMSGSIZE); 32851755Smckusick if (space < resid + clen && uio && 32941908Skarels (atomic || space < so->so_snd.sb_lowat || space < clen)) { 33041908Skarels if (so->so_state & SS_NBIO) 33141908Skarels snderr(EWOULDBLOCK); 33241908Skarels sbunlock(&so->so_snd); 33343417Skarels error = sbwait(&so->so_snd); 33441908Skarels splx(s); 33541908Skarels if (error) 33641908Skarels goto out; 33741908Skarels goto restart; 33816412Skarels } 33916412Skarels splx(s); 34016412Skarels mp = ⊤ 34141908Skarels space -= clen; 34243417Skarels do { 34343417Skarels if (uio == NULL) { 34441908Skarels /* 34541908Skarels * Data is prepackaged in "top". 34641908Skarels */ 34741908Skarels resid = 0; 34841908Skarels if (flags & MSG_EOR) 34941908Skarels top->m_flags |= M_EOR; 35043417Skarels } else do { 35135384Skarels if (top == 0) { 35235384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35335384Skarels mlen = MHLEN; 35435384Skarels m->m_pkthdr.len = 0; 35535384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35635384Skarels } else { 35735384Skarels MGET(m, M_WAIT, MT_DATA); 35835384Skarels mlen = MLEN; 35935384Skarels } 36041908Skarels if (resid >= MINCLSIZE && space >= MCLBYTES) { 36135384Skarels MCLGET(m, M_WAIT); 36235384Skarels if ((m->m_flags & M_EXT) == 0) 36316412Skarels goto nopages; 36435384Skarels mlen = MCLBYTES; 36535384Skarels #ifdef MAPPED_MBUFS 36641908Skarels len = min(MCLBYTES, resid); 36741908Skarels #else 36841908Skarels if (top == 0) { 36941908Skarels len = min(MCLBYTES - max_hdr, resid); 37035384Skarels m->m_data += max_hdr; 37146452Ssklower } else 37246452Ssklower len = min(MCLBYTES, resid); 37335384Skarels #endif 37435384Skarels space -= MCLBYTES; 37516412Skarels } else { 37616412Skarels nopages: 37741908Skarels len = min(min(mlen, resid), space); 37821767Skarels space -= len; 37935384Skarels /* 38035384Skarels * For datagram protocols, leave room 38135384Skarels * for protocol headers in first mbuf. 38235384Skarels */ 38335391Skarels if (atomic && top == 0 && len < mlen) 38435384Skarels MH_ALIGN(m, len); 38516412Skarels } 38645515Skarels error = uiomove(mtod(m, caddr_t), (int)len, uio); 38741908Skarels resid = uio->uio_resid; 38816412Skarels m->m_len = len; 38916412Skarels *mp = m; 39035384Skarels top->m_pkthdr.len += len; 39116412Skarels if (error) 39216412Skarels goto release; 39316412Skarels mp = &m->m_next; 39441908Skarels if (resid <= 0) { 39541908Skarels if (flags & MSG_EOR) 39635384Skarels top->m_flags |= M_EOR; 39721108Skarels break; 39835384Skarels } 39935384Skarels } while (space > 0 && atomic); 40035384Skarels if (dontroute) 40135384Skarels so->so_options |= SO_DONTROUTE; 40235384Skarels s = splnet(); /* XXX */ 40335384Skarels error = (*so->so_proto->pr_usrreq)(so, 40435384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40541908Skarels top, addr, control); 40635384Skarels splx(s); 40735384Skarels if (dontroute) 40835384Skarels so->so_options &= ~SO_DONTROUTE; 40941908Skarels clen = 0; 41041908Skarels control = 0; 41135384Skarels top = 0; 41235384Skarels mp = ⊤ 41335384Skarels if (error) 41435384Skarels goto release; 41541908Skarels } while (resid && space > 0); 41641908Skarels } while (resid); 4174890Swnj 4184786Swnj release: 4194890Swnj sbunlock(&so->so_snd); 42041908Skarels out: 4216419Sroot if (top) 4226419Sroot m_freem(top); 42341908Skarels if (control) 42441908Skarels m_freem(control); 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, 43341908Skarels * followed by an optional mbuf or mbufs containing ancillary data, 43441908Skarels * 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. 43945515Skarels * 44041908Skarels * The caller may receive the data as a single mbuf chain by supplying 44143417Skarels * an mbuf **mp0 for use in returning the chain. The uio is then used 44241908Skarels * only for the count in uio_resid. 44325629Skarels */ 44443417Skarels soreceive(so, paddr, uio, mp0, controlp, flagsp) 4454786Swnj register struct socket *so; 44641908Skarels struct mbuf **paddr; 44741908Skarels struct uio *uio; 44843417Skarels struct mbuf **mp0; 44941908Skarels struct mbuf **controlp; 45035384Skarels int *flagsp; 4514786Swnj { 45243417Skarels register struct mbuf *m, **mp; 45343417Skarels register int flags, len, error, s, offset; 45412757Ssam struct protosw *pr = so->so_proto; 45541908Skarels struct mbuf *nextrecord; 45641908Skarels int moff, type; 4574786Swnj 45843417Skarels mp = mp0; 45941908Skarels if (paddr) 46041908Skarels *paddr = 0; 46135384Skarels if (controlp) 46235384Skarels *controlp = 0; 46335384Skarels if (flagsp) 46435384Skarels flags = *flagsp &~ MSG_EOR; 46545515Skarels else 46635384Skarels flags = 0; 46712757Ssam if (flags & MSG_OOB) { 4689635Ssam m = m_get(M_WAIT, MT_DATA); 46912757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 47024768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4718594Sroot if (error) 47210137Ssam goto bad; 4738319Sroot do { 47441908Skarels error = uiomove(mtod(m, caddr_t), 47541908Skarels (int) min(uio->uio_resid, m->m_len), uio); 4768319Sroot m = m_free(m); 4778594Sroot } while (uio->uio_resid && error == 0 && m); 47810137Ssam bad: 4798319Sroot if (m) 4808771Sroot m_freem(m); 4818594Sroot return (error); 4828319Sroot } 48341908Skarels if (mp) 48441908Skarels *mp = (struct mbuf *)0; 48543417Skarels if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 48635384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 48735384Skarels (struct mbuf *)0, (struct mbuf *)0); 4888319Sroot 4894890Swnj restart: 49051755Smckusick if (error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) 49140706Skarels return (error); 4928835Sroot s = splnet(); 4934890Swnj 49437478Ssklower m = so->so_rcv.sb_mb; 49544383Skarels /* 49644383Skarels * If we have less data than requested, block awaiting more 49744383Skarels * (subject to any timeout) if: 49844383Skarels * 1. the current count is less than the low water mark, or 49944383Skarels * 2. MSG_WAITALL is set, and it is possible to do the entire 50044383Skarels * receive operation at once if we block (resid <= hiwat). 50151755Smckusick * 3. MSG_DONTWAIT is not set 50244383Skarels * If MSG_WAITALL is set but resid is larger than the receive buffer, 50344383Skarels * we have to do the receive in sections, and thus risk returning 50444383Skarels * a short count if a timeout or signal occurs after we start. 50544383Skarels */ 50651755Smckusick if (m == 0 || ((flags & MSG_DONTWAIT) == 0 && 50751755Smckusick so->so_rcv.sb_cc < uio->uio_resid) && 50844383Skarels (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || 50950942Ssklower ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && 51050942Ssklower 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) 51751022Ssklower goto dontblock; 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) 52551022Ssklower goto dontblock; 52646479Skarels else 52746479Skarels goto release; 52846479Skarels } 52950942Ssklower for (; m; m = m->m_next) 53050942Ssklower if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { 53150942Ssklower m = so->so_rcv.sb_mb; 53250942Ssklower goto dontblock; 53350942Ssklower } 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; 54151755Smckusick if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { 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 } 55250942Ssklower dontblock: 553*52926Smckusick if (uio->uio_procp) 554*52926Smckusick uio->uio_procp->p_stats->p_ru.ru_msgrcv++; 55535384Skarels nextrecord = m->m_nextpkt; 55612757Ssam if (pr->pr_flags & PR_ADDR) { 55741908Skarels #ifdef DIAGNOSTIC 55825629Skarels if (m->m_type != MT_SONAME) 55916993Skarels panic("receive 1a"); 56041908Skarels #endif 56116993Skarels if (flags & MSG_PEEK) { 56241908Skarels if (paddr) 56341908Skarels *paddr = m_copy(m, 0, m->m_len); 56425629Skarels m = m->m_next; 56516993Skarels } else { 56625629Skarels sbfree(&so->so_rcv, m); 56741908Skarels if (paddr) { 56841908Skarels *paddr = m; 56935384Skarels so->so_rcv.sb_mb = m->m_next; 57035384Skarels m->m_next = 0; 57135384Skarels m = so->so_rcv.sb_mb; 57225629Skarels } else { 57326958Skarels MFREE(m, so->so_rcv.sb_mb); 57426958Skarels m = so->so_rcv.sb_mb; 57525629Skarels } 57616993Skarels } 57716993Skarels } 57841908Skarels while (m && m->m_type == MT_CONTROL && error == 0) { 57916993Skarels if (flags & MSG_PEEK) { 58035384Skarels if (controlp) 58135384Skarels *controlp = m_copy(m, 0, m->m_len); 58235384Skarels m = m->m_next; 58335384Skarels } else { 58435384Skarels sbfree(&so->so_rcv, m); 58535384Skarels if (controlp) { 58643097Ssklower if (pr->pr_domain->dom_externalize && 58743097Ssklower mtod(m, struct cmsghdr *)->cmsg_type == 58843097Ssklower SCM_RIGHTS) 58941908Skarels error = (*pr->pr_domain->dom_externalize)(m); 59035384Skarels *controlp = m; 59135384Skarels so->so_rcv.sb_mb = m->m_next; 59235384Skarels m->m_next = 0; 59335384Skarels m = so->so_rcv.sb_mb; 59435384Skarels } else { 59535384Skarels MFREE(m, so->so_rcv.sb_mb); 59635384Skarels m = so->so_rcv.sb_mb; 59735384Skarels } 59835384Skarels } 59941908Skarels if (controlp) 60041908Skarels controlp = &(*controlp)->m_next; 60135384Skarels } 60241908Skarels if (m) { 60344383Skarels if ((flags & MSG_PEEK) == 0) 60444383Skarels m->m_nextpkt = nextrecord; 60541908Skarels type = m->m_type; 60646452Ssklower if (type == MT_OOBDATA) 60746452Ssklower flags |= MSG_OOB; 60841908Skarels } 6098319Sroot moff = 0; 61032092Skarels offset = 0; 61146452Ssklower while (m && uio->uio_resid > 0 && error == 0) { 61246452Ssklower if (m->m_type == MT_OOBDATA) { 61346452Ssklower if (type != MT_OOBDATA) 61446452Ssklower break; 61546452Ssklower } else if (type == MT_OOBDATA) 61646452Ssklower break; 61741908Skarels #ifdef DIAGNOSTIC 61835384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 61925629Skarels panic("receive 3"); 62041908Skarels #endif 6217747Sroot so->so_state &= ~SS_RCVATMARK; 62243417Skarels len = uio->uio_resid; 62332092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 62432092Skarels len = so->so_oobmark - offset; 62521767Skarels if (len > m->m_len - moff) 6268319Sroot len = m->m_len - moff; 62741908Skarels /* 62841908Skarels * If mp is set, just pass back the mbufs. 62941908Skarels * Otherwise copy them out via the uio, then free. 63041908Skarels * Sockbuf must be consistent here (points to current mbuf, 63141908Skarels * it points to next record) when we drop priority; 63241908Skarels * we must note any additions to the sockbuf when we 63341908Skarels * block interrupts again. 63441908Skarels */ 63541908Skarels if (mp == 0) { 63641908Skarels splx(s); 63741908Skarels error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 63841908Skarels s = splnet(); 63943417Skarels } else 64043417Skarels uio->uio_resid -= len; 64121767Skarels if (len == m->m_len - moff) { 64250942Ssklower if (m->m_flags & M_EOR) 64350942Ssklower flags |= MSG_EOR; 64425629Skarels if (flags & MSG_PEEK) { 64525629Skarels m = m->m_next; 64625629Skarels moff = 0; 64725629Skarels } else { 64835384Skarels nextrecord = m->m_nextpkt; 64925629Skarels sbfree(&so->so_rcv, m); 65041908Skarels if (mp) { 65141908Skarels *mp = m; 65241908Skarels mp = &m->m_next; 65343417Skarels so->so_rcv.sb_mb = m = m->m_next; 65443417Skarels *mp = (struct mbuf *)0; 65541908Skarels } else { 65641908Skarels MFREE(m, so->so_rcv.sb_mb); 65741908Skarels m = so->so_rcv.sb_mb; 65841908Skarels } 65926958Skarels if (m) 66035384Skarels m->m_nextpkt = nextrecord; 66125629Skarels } 6624786Swnj } else { 66312757Ssam if (flags & MSG_PEEK) 6648319Sroot moff += len; 6658319Sroot else { 66643417Skarels if (mp) 66743417Skarels *mp = m_copym(m, 0, len, M_WAIT); 66835384Skarels m->m_data += len; 6698319Sroot m->m_len -= len; 6708319Sroot so->so_rcv.sb_cc -= len; 6718319Sroot } 6724786Swnj } 67332092Skarels if (so->so_oobmark) { 67432092Skarels if ((flags & MSG_PEEK) == 0) { 67532092Skarels so->so_oobmark -= len; 67632092Skarels if (so->so_oobmark == 0) { 67732092Skarels so->so_state |= SS_RCVATMARK; 67832092Skarels break; 67932092Skarels } 68032092Skarels } else 68132092Skarels offset += len; 6827747Sroot } 68350942Ssklower if (flags & MSG_EOR) 68440632Skarels break; 68541908Skarels /* 68641908Skarels * If the MSG_WAITALL flag is set (for non-atomic socket), 68743417Skarels * we must not quit until "uio->uio_resid == 0" or an error 68841908Skarels * termination. If a signal/timeout occurs, return 68943417Skarels * with a short count but without error. 69041908Skarels * Keep sockbuf locked against other readers. 69141908Skarels */ 69243417Skarels while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && 69350942Ssklower !sosendallatonce(so)) { 69446479Skarels if (so->so_error || so->so_state & SS_CANTRCVMORE) 69546479Skarels break; 69641908Skarels error = sbwait(&so->so_rcv); 69741908Skarels if (error) { 69841908Skarels sbunlock(&so->so_rcv); 69941908Skarels splx(s); 70041908Skarels return (0); 70141908Skarels } 70250942Ssklower if (m = so->so_rcv.sb_mb) 70341908Skarels nextrecord = m->m_nextpkt; 70441908Skarels } 70516993Skarels } 70616993Skarels if ((flags & MSG_PEEK) == 0) { 70726500Skarels if (m == 0) 70816993Skarels so->so_rcv.sb_mb = nextrecord; 70935384Skarels else if (pr->pr_flags & PR_ATOMIC) { 71035384Skarels flags |= MSG_TRUNC; 71126958Skarels (void) sbdroprecord(&so->so_rcv); 71235384Skarels } 71316993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 71416993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 71537478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 71637478Ssklower (struct mbuf *)0); 71716993Skarels } 71835384Skarels if (flagsp) 71935384Skarels *flagsp |= flags; 7204890Swnj release: 7214916Swnj sbunlock(&so->so_rcv); 7224890Swnj splx(s); 7234916Swnj return (error); 7244786Swnj } 7254786Swnj 72610267Ssam soshutdown(so, how) 72712757Ssam register struct socket *so; 72812757Ssam register int how; 72910267Ssam { 73012757Ssam register struct protosw *pr = so->so_proto; 73110267Ssam 73210267Ssam how++; 73312757Ssam if (how & FREAD) 73412757Ssam sorflush(so); 73510267Ssam if (how & FWRITE) 73612757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 73712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 73810267Ssam return (0); 73910267Ssam } 74010267Ssam 74112757Ssam sorflush(so) 74212757Ssam register struct socket *so; 74312757Ssam { 74412757Ssam register struct sockbuf *sb = &so->so_rcv; 74512757Ssam register struct protosw *pr = so->so_proto; 74612757Ssam register int s; 74712757Ssam struct sockbuf asb; 74812757Ssam 74940706Skarels sb->sb_flags |= SB_NOINTR; 75051755Smckusick (void) sblock(sb, M_WAITOK); 75112757Ssam s = splimp(); 75212757Ssam socantrcvmore(so); 75312757Ssam sbunlock(sb); 75412757Ssam asb = *sb; 75512757Ssam bzero((caddr_t)sb, sizeof (*sb)); 75612757Ssam splx(s); 75716993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 75816993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 75912757Ssam sbrelease(&asb); 76012757Ssam } 76112757Ssam 76218553Skarels sosetopt(so, level, optname, m0) 76312757Ssam register struct socket *so; 76410267Ssam int level, optname; 76518553Skarels struct mbuf *m0; 76610267Ssam { 76717158Ssam int error = 0; 76818553Skarels register struct mbuf *m = m0; 76910267Ssam 77017158Ssam if (level != SOL_SOCKET) { 77118369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 77218369Skarels return ((*so->so_proto->pr_ctloutput) 77318553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 77418369Skarels error = ENOPROTOOPT; 77518369Skarels } else { 77618369Skarels switch (optname) { 77710267Ssam 77818369Skarels case SO_LINGER: 77918369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 78018369Skarels error = EINVAL; 78118369Skarels goto bad; 78218369Skarels } 78318369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 78418369Skarels /* fall thru... */ 78517158Ssam 78618369Skarels case SO_DEBUG: 78718369Skarels case SO_KEEPALIVE: 78818369Skarels case SO_DONTROUTE: 78918369Skarels case SO_USELOOPBACK: 79018369Skarels case SO_BROADCAST: 79118369Skarels case SO_REUSEADDR: 79227191Skarels case SO_OOBINLINE: 79318369Skarels if (m == NULL || m->m_len < sizeof (int)) { 79418369Skarels error = EINVAL; 79518369Skarels goto bad; 79618369Skarels } 79718369Skarels if (*mtod(m, int *)) 79818369Skarels so->so_options |= optname; 79918369Skarels else 80018369Skarels so->so_options &= ~optname; 80118369Skarels break; 80218369Skarels 80318369Skarels case SO_SNDBUF: 80441908Skarels case SO_RCVBUF: 80540706Skarels case SO_SNDLOWAT: 80641908Skarels case SO_RCVLOWAT: 80718369Skarels if (m == NULL || m->m_len < sizeof (int)) { 80818369Skarels error = EINVAL; 80918369Skarels goto bad; 81018369Skarels } 81118369Skarels switch (optname) { 81218369Skarels 81318369Skarels case SO_SNDBUF: 81418369Skarels case SO_RCVBUF: 81541908Skarels if (sbreserve(optname == SO_SNDBUF ? 81641908Skarels &so->so_snd : &so->so_rcv, 81741908Skarels (u_long) *mtod(m, int *)) == 0) { 81818369Skarels error = ENOBUFS; 81918369Skarels goto bad; 82018369Skarels } 82118369Skarels break; 82218369Skarels 82318369Skarels case SO_SNDLOWAT: 82441908Skarels so->so_snd.sb_lowat = *mtod(m, int *); 82541908Skarels break; 82618369Skarels case SO_RCVLOWAT: 82741908Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 82818369Skarels break; 82944721Skarels } 83044721Skarels break; 83144721Skarels 83244721Skarels case SO_SNDTIMEO: 83344721Skarels case SO_RCVTIMEO: 83444721Skarels { 83544721Skarels struct timeval *tv; 83644721Skarels short val; 83744721Skarels 83844721Skarels if (m == NULL || m->m_len < sizeof (*tv)) { 83944721Skarels error = EINVAL; 84044721Skarels goto bad; 84144721Skarels } 84244721Skarels tv = mtod(m, struct timeval *); 84344721Skarels if (tv->tv_sec > SHRT_MAX / hz - hz) { 84444721Skarels error = EDOM; 84544721Skarels goto bad; 84644721Skarels } 84744721Skarels val = tv->tv_sec * hz + tv->tv_usec / tick; 84844721Skarels 84944721Skarels switch (optname) { 85044721Skarels 85118369Skarels case SO_SNDTIMEO: 85244721Skarels so->so_snd.sb_timeo = val; 85341908Skarels break; 85418369Skarels case SO_RCVTIMEO: 85544721Skarels so->so_rcv.sb_timeo = val; 85618369Skarels break; 85718369Skarels } 85818369Skarels break; 85944721Skarels } 86018369Skarels 86118369Skarels default: 86218369Skarels error = ENOPROTOOPT; 86318369Skarels break; 86417158Ssam } 86551022Ssklower m = 0; 86650942Ssklower if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) 86750942Ssklower (void) ((*so->so_proto->pr_ctloutput) 86850942Ssklower (PRCO_SETOPT, so, level, optname, &m0)); 86910267Ssam } 87017158Ssam bad: 87117158Ssam if (m) 87217158Ssam (void) m_free(m); 87317158Ssam return (error); 87410267Ssam } 87510267Ssam 87617158Ssam sogetopt(so, level, optname, mp) 87712757Ssam register struct socket *so; 87810267Ssam int level, optname; 87917158Ssam struct mbuf **mp; 88017158Ssam { 88112757Ssam register struct mbuf *m; 88210267Ssam 88318369Skarels if (level != SOL_SOCKET) { 88418369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 88518369Skarels return ((*so->so_proto->pr_ctloutput) 88618369Skarels (PRCO_GETOPT, so, level, optname, mp)); 88745515Skarels } else 88818369Skarels return (ENOPROTOOPT); 88918369Skarels } else { 89017158Ssam m = m_get(M_WAIT, MT_SOOPTS); 89125502Skarels m->m_len = sizeof (int); 89225502Skarels 89318369Skarels switch (optname) { 89417158Ssam 89518369Skarels case SO_LINGER: 89618369Skarels m->m_len = sizeof (struct linger); 89718369Skarels mtod(m, struct linger *)->l_onoff = 89818369Skarels so->so_options & SO_LINGER; 89918369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 90018369Skarels break; 90110267Ssam 90218369Skarels case SO_USELOOPBACK: 90318369Skarels case SO_DONTROUTE: 90418369Skarels case SO_DEBUG: 90518369Skarels case SO_KEEPALIVE: 90618369Skarels case SO_REUSEADDR: 90718369Skarels case SO_BROADCAST: 90827191Skarels case SO_OOBINLINE: 90918369Skarels *mtod(m, int *) = so->so_options & optname; 91018369Skarels break; 91118369Skarels 91225502Skarels case SO_TYPE: 91325502Skarels *mtod(m, int *) = so->so_type; 91425502Skarels break; 91525502Skarels 91624768Skarels case SO_ERROR: 91724768Skarels *mtod(m, int *) = so->so_error; 91824768Skarels so->so_error = 0; 91924768Skarels break; 92024768Skarels 92118369Skarels case SO_SNDBUF: 92218369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 92318369Skarels break; 92418369Skarels 92518369Skarels case SO_RCVBUF: 92618369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 92718369Skarels break; 92818369Skarels 92918369Skarels case SO_SNDLOWAT: 93018369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 93118369Skarels break; 93218369Skarels 93318369Skarels case SO_RCVLOWAT: 93418369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 93518369Skarels break; 93618369Skarels 93718369Skarels case SO_SNDTIMEO: 93844721Skarels case SO_RCVTIMEO: 93944721Skarels { 94044721Skarels int val = (optname == SO_SNDTIMEO ? 94144721Skarels so->so_snd.sb_timeo : so->so_rcv.sb_timeo); 94218369Skarels 94344721Skarels m->m_len = sizeof(struct timeval); 94444721Skarels mtod(m, struct timeval *)->tv_sec = val / hz; 94544721Skarels mtod(m, struct timeval *)->tv_usec = 94644721Skarels (val % hz) / tick; 94718369Skarels break; 94844721Skarels } 94918369Skarels 95018369Skarels default: 95126362Skarels (void)m_free(m); 95218369Skarels return (ENOPROTOOPT); 95318369Skarels } 95418369Skarels *mp = m; 95518369Skarels return (0); 95610267Ssam } 95710267Ssam } 95810267Ssam 9595423Swnj sohasoutofband(so) 96012757Ssam register struct socket *so; 9615423Swnj { 96223233Skarels struct proc *p; 9635423Swnj 96437478Ssklower if (so->so_pgid < 0) 96537478Ssklower gsignal(-so->so_pgid, SIGURG); 96637478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 96723233Skarels psignal(p, SIGURG); 96852526Smckusick selwakeup(&so->so_rcv.sb_sel); 9695423Swnj } 970