123421Smckusick /* 241908Skarels * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California. 333185Sbostic * All rights reserved. 423421Smckusick * 5*44450Sbostic * %sccs.include.redist.c% 633185Sbostic * 7*44450Sbostic * @(#)uipc_socket.c 7.22 (Berkeley) 06/28/90 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" 1717102Sbloom #include "protosw.h" 1817102Sbloom #include "socket.h" 1917102Sbloom #include "socketvar.h" 204786Swnj 214786Swnj /* 228300Sroot * Socket operation routines. 238300Sroot * These routines are called by the routines in 248300Sroot * sys_socket.c or from a system process, and 258300Sroot * implement the semantics of socket operations by 268300Sroot * switching out to the protocol specific routines. 2712757Ssam * 2812757Ssam * TODO: 2912757Ssam * test socketpair 3021767Skarels * clean up async 3112757Ssam * out-of-band is a kludge 324786Swnj */ 338594Sroot /*ARGSUSED*/ 3410267Ssam socreate(dom, aso, type, proto) 354786Swnj struct socket **aso; 3612757Ssam register int type; 3712757Ssam int proto; 384786Swnj { 394786Swnj register struct protosw *prp; 404786Swnj register struct socket *so; 4112757Ssam register int error; 424786Swnj 434890Swnj if (proto) 4421767Skarels prp = pffindproto(dom, proto, type); 454890Swnj else 469168Ssam prp = pffindtype(dom, type); 474890Swnj if (prp == 0) 484890Swnj return (EPROTONOSUPPORT); 498300Sroot if (prp->pr_type != type) 508300Sroot return (EPROTOTYPE); 5137478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 5237478Ssklower bzero((caddr_t)so, sizeof(*so)); 539168Ssam so->so_type = type; 546214Swnj if (u.u_uid == 0) 556214Swnj so->so_state = SS_PRIV; 564786Swnj so->so_proto = prp; 5712757Ssam error = 5812757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 5921767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 604979Swnj if (error) { 617507Sroot so->so_state |= SS_NOFDREF; 627180Swnj sofree(so); 634890Swnj return (error); 644786Swnj } 654786Swnj *aso = so; 664786Swnj return (0); 674786Swnj } 684786Swnj 6910267Ssam sobind(so, nam) 708300Sroot struct socket *so; 718300Sroot struct mbuf *nam; 728300Sroot { 738300Sroot int s = splnet(); 748300Sroot int error; 758300Sroot 7641908Skarels error = 7741908Skarels (*so->so_proto->pr_usrreq)(so, PRU_BIND, 7812757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 798300Sroot splx(s); 808300Sroot return (error); 818300Sroot } 828300Sroot 838300Sroot solisten(so, backlog) 8412757Ssam register struct socket *so; 858300Sroot int backlog; 868300Sroot { 8712757Ssam int s = splnet(), error; 888300Sroot 8912757Ssam error = 9012757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 9112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 928300Sroot if (error) { 938300Sroot splx(s); 948300Sroot return (error); 958300Sroot } 9638584Skarels if (so->so_q == 0) 978300Sroot so->so_options |= SO_ACCEPTCONN; 988300Sroot if (backlog < 0) 998300Sroot backlog = 0; 10035384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 10112493Ssam splx(s); 1028300Sroot return (0); 1038300Sroot } 1048300Sroot 1054916Swnj sofree(so) 10612757Ssam register struct socket *so; 1074916Swnj { 1084916Swnj 10931810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 11031810Skarels return; 1117507Sroot if (so->so_head) { 1127507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1137507Sroot panic("sofree dq"); 1147507Sroot so->so_head = 0; 1157507Sroot } 1164950Swnj sbrelease(&so->so_snd); 11712757Ssam sorflush(so); 11837478Ssklower FREE(so, M_SOCKET); 1194916Swnj } 1204916Swnj 1214786Swnj /* 1224890Swnj * Close a socket on last file table reference removal. 1234890Swnj * Initiate disconnect if connected. 1244890Swnj * Free socket when disconnect complete. 1254829Swnj */ 12612757Ssam soclose(so) 1274829Swnj register struct socket *so; 1284829Swnj { 1294890Swnj int s = splnet(); /* conservative */ 13033372Sbostic int error = 0; 1314829Swnj 1327507Sroot if (so->so_options & SO_ACCEPTCONN) { 13338584Skarels while (so->so_q0) 13410399Ssam (void) soabort(so->so_q0); 13538584Skarels while (so->so_q) 13610399Ssam (void) soabort(so->so_q); 1377507Sroot } 1384890Swnj if (so->so_pcb == 0) 1394890Swnj goto discard; 1404890Swnj if (so->so_state & SS_ISCONNECTED) { 1414890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 14226245Skarels error = sodisconnect(so); 14312757Ssam if (error) 14412757Ssam goto drop; 1454890Swnj } 14610267Ssam if (so->so_options & SO_LINGER) { 1475281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 14812757Ssam (so->so_state & SS_NBIO)) 14912757Ssam goto drop; 1505281Sroot while (so->so_state & SS_ISCONNECTED) 15140706Skarels if (error = tsleep((caddr_t)&so->so_timeo, 15240706Skarels PSOCK | PCATCH, netcls, so->so_linger)) 15340706Skarels break; 1544890Swnj } 1554890Swnj } 1565580Sroot drop: 1576880Ssam if (so->so_pcb) { 15812757Ssam int error2 = 15912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16012757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 16112757Ssam if (error == 0) 16212757Ssam error = error2; 1636880Ssam } 1644890Swnj discard: 16510399Ssam if (so->so_state & SS_NOFDREF) 16610399Ssam panic("soclose: NOFDREF"); 1677507Sroot so->so_state |= SS_NOFDREF; 1684950Swnj sofree(so); 1694890Swnj splx(s); 17012757Ssam return (error); 1714829Swnj } 1724829Swnj 17310399Ssam /* 17410399Ssam * Must be called at splnet... 17510399Ssam */ 17610399Ssam soabort(so) 17710399Ssam struct socket *so; 17810399Ssam { 17910399Ssam 18012757Ssam return ( 18112757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 18212757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 18310399Ssam } 18410399Ssam 18510267Ssam soaccept(so, nam) 18612757Ssam register struct socket *so; 1878300Sroot struct mbuf *nam; 1884927Swnj { 1894927Swnj int s = splnet(); 1904927Swnj int error; 1914927Swnj 19210399Ssam if ((so->so_state & SS_NOFDREF) == 0) 19310399Ssam panic("soaccept: !NOFDREF"); 19410267Ssam so->so_state &= ~SS_NOFDREF; 1958300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 19612757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 1974927Swnj splx(s); 1984927Swnj return (error); 1994927Swnj } 2004927Swnj 20110267Ssam soconnect(so, nam) 20212757Ssam register struct socket *so; 2038300Sroot struct mbuf *nam; 2044786Swnj { 20530414Skarels int s; 2064890Swnj int error; 2074786Swnj 20830414Skarels if (so->so_options & SO_ACCEPTCONN) 20930414Skarels return (EOPNOTSUPP); 21030414Skarels s = splnet(); 21124768Skarels /* 21224768Skarels * If protocol is connection-based, can only connect once. 21324768Skarels * Otherwise, if connected, try to disconnect first. 21424768Skarels * This allows user to disconnect by connecting to, e.g., 21524768Skarels * a null address. 21624768Skarels */ 21724768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 21824768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 21924768Skarels (error = sodisconnect(so)))) 2204890Swnj error = EISCONN; 22124768Skarels else 22224768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22324768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2244890Swnj splx(s); 2254890Swnj return (error); 2264786Swnj } 2274786Swnj 22812757Ssam soconnect2(so1, so2) 22912757Ssam register struct socket *so1; 23012757Ssam struct socket *so2; 23112757Ssam { 23212757Ssam int s = splnet(); 23312757Ssam int error; 23412757Ssam 23513113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23613113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 23712757Ssam splx(s); 23812757Ssam return (error); 23912757Ssam } 24012757Ssam 24126245Skarels sodisconnect(so) 24212757Ssam register struct socket *so; 2434786Swnj { 2444890Swnj int s = splnet(); 2454890Swnj int error; 2464786Swnj 2474890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2484890Swnj error = ENOTCONN; 2494890Swnj goto bad; 2504890Swnj } 2514890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2524890Swnj error = EALREADY; 2534890Swnj goto bad; 2544890Swnj } 2558300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25626245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2574890Swnj bad: 2584890Swnj splx(s); 2594890Swnj return (error); 2604786Swnj } 2614786Swnj 2624786Swnj /* 2634890Swnj * Send on a socket. 2644890Swnj * If send must go all at once and message is larger than 2654890Swnj * send buffering, then hard error. 2664890Swnj * Lock against other senders. 2674890Swnj * If must go all at once and not enough room now, then 2684890Swnj * inform user that this would block and do nothing. 26916412Skarels * Otherwise, if nonblocking, send as much as possible. 27041908Skarels * The data to be sent is described by "uio" if nonzero, 27141908Skarels * otherwise by the mbuf chain "top" (which must be null 27241908Skarels * if uio is not). Data provided in mbuf chain must be small 27341908Skarels * enough to send all at once. 27441908Skarels * 27541908Skarels * Returns nonzero on error, timeout or signal; callers 27641908Skarels * must check for short counts if EINTR/ERESTART are returned. 27741908Skarels * Data and control buffers are freed on return. 2784786Swnj */ 27943417Skarels sosend(so, addr, uio, top, control, flags) 2804786Swnj register struct socket *so; 28141908Skarels struct mbuf *addr; 28241908Skarels struct uio *uio; 28341908Skarels struct mbuf *top; 28441908Skarels struct mbuf *control; 2858319Sroot int flags; 2864786Swnj { 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); 30016412Skarels u.u_ru.ru_msgsnd++; 30140632Skarels if (control) 30241908Skarels clen = control->m_len; 30316412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30416412Skarels 3056419Sroot restart: 30640706Skarels if (error = sblock(&so->so_snd)) 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) { 31638584Skarels if ((so->so_state & SS_ISCONFIRMING) == 0) 31737478Ssklower snderr(ENOTCONN); 31841908Skarels } else if (addr == 0) 31916412Skarels snderr(EDESTADDRREQ); 32016412Skarels } 32141908Skarels space = sbspace(&so->so_snd); 32216412Skarels if (flags & MSG_OOB) 32341908Skarels space += 1024; 32441908Skarels if (space < resid + clen && 32541908Skarels (atomic || space < so->so_snd.sb_lowat || space < clen)) { 32641908Skarels if (atomic && resid > so->so_snd.sb_hiwat || 32741908Skarels clen > so->so_snd.sb_hiwat) 32841908Skarels snderr(EMSGSIZE); 32941908Skarels if (so->so_state & SS_NBIO) 33041908Skarels snderr(EWOULDBLOCK); 33141908Skarels sbunlock(&so->so_snd); 33243417Skarels error = sbwait(&so->so_snd); 33341908Skarels splx(s); 33441908Skarels if (error) 33541908Skarels goto out; 33641908Skarels goto restart; 33716412Skarels } 33816412Skarels splx(s); 33916412Skarels mp = ⊤ 34041908Skarels space -= clen; 34143417Skarels do { 34243417Skarels if (uio == NULL) { 34341908Skarels /* 34441908Skarels * Data is prepackaged in "top". 34541908Skarels */ 34641908Skarels resid = 0; 34741908Skarels if (flags & MSG_EOR) 34841908Skarels top->m_flags |= M_EOR; 34943417Skarels } else do { 35035384Skarels if (top == 0) { 35135384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35235384Skarels mlen = MHLEN; 35335384Skarels m->m_pkthdr.len = 0; 35435384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35535384Skarels } else { 35635384Skarels MGET(m, M_WAIT, MT_DATA); 35735384Skarels mlen = MLEN; 35835384Skarels } 35941908Skarels if (resid >= MINCLSIZE && space >= MCLBYTES) { 36035384Skarels MCLGET(m, M_WAIT); 36135384Skarels if ((m->m_flags & M_EXT) == 0) 36216412Skarels goto nopages; 36335384Skarels mlen = MCLBYTES; 36435384Skarels #ifdef MAPPED_MBUFS 36541908Skarels len = min(MCLBYTES, resid); 36641908Skarels #else 36741908Skarels if (top == 0) { 36841908Skarels len = min(MCLBYTES - max_hdr, resid); 36935384Skarels m->m_data += max_hdr; 37041908Skarels } 37135384Skarels #endif 37235384Skarels space -= MCLBYTES; 37316412Skarels } else { 37416412Skarels nopages: 37541908Skarels len = min(min(mlen, resid), space); 37621767Skarels space -= len; 37735384Skarels /* 37835384Skarels * For datagram protocols, leave room 37935384Skarels * for protocol headers in first mbuf. 38035384Skarels */ 38135391Skarels if (atomic && top == 0 && len < mlen) 38235384Skarels MH_ALIGN(m, len); 38316412Skarels } 38437728Smckusick error = uiomove(mtod(m, caddr_t), len, uio); 38541908Skarels resid = uio->uio_resid; 38616412Skarels m->m_len = len; 38716412Skarels *mp = m; 38835384Skarels top->m_pkthdr.len += len; 38916412Skarels if (error) 39016412Skarels goto release; 39116412Skarels mp = &m->m_next; 39241908Skarels if (resid <= 0) { 39341908Skarels if (flags & MSG_EOR) 39435384Skarels top->m_flags |= M_EOR; 39521108Skarels break; 39635384Skarels } 39735384Skarels } while (space > 0 && atomic); 39835384Skarels if (dontroute) 39935384Skarels so->so_options |= SO_DONTROUTE; 40035384Skarels s = splnet(); /* XXX */ 40135384Skarels error = (*so->so_proto->pr_usrreq)(so, 40235384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40341908Skarels top, addr, control); 40435384Skarels splx(s); 40535384Skarels if (dontroute) 40635384Skarels so->so_options &= ~SO_DONTROUTE; 40741908Skarels clen = 0; 40841908Skarels control = 0; 40935384Skarels top = 0; 41035384Skarels mp = ⊤ 41135384Skarels if (error) 41235384Skarels goto release; 41341908Skarels } while (resid && space > 0); 41441908Skarels } while (resid); 4154890Swnj 4164786Swnj release: 4174890Swnj sbunlock(&so->so_snd); 41841908Skarels out: 4196419Sroot if (top) 4206419Sroot m_freem(top); 42141908Skarels if (control) 42241908Skarels m_freem(control); 4234786Swnj return (error); 4244786Swnj } 4254786Swnj 42625629Skarels /* 42725629Skarels * Implement receive operations on a socket. 42825629Skarels * We depend on the way that records are added to the sockbuf 42925629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 43025629Skarels * must begin with an address if the protocol so specifies, 43141908Skarels * followed by an optional mbuf or mbufs containing ancillary data, 43241908Skarels * and then zero or more mbufs of data. 43325629Skarels * In order to avoid blocking network interrupts for the entire time here, 43425629Skarels * we splx() while doing the actual copy to user space. 43525629Skarels * Although the sockbuf is locked, new data may still be appended, 43625629Skarels * and thus we must maintain consistency of the sockbuf during that time. 43741908Skarels * 43841908Skarels * The caller may receive the data as a single mbuf chain by supplying 43943417Skarels * an mbuf **mp0 for use in returning the chain. The uio is then used 44041908Skarels * only for the count in uio_resid. 44125629Skarels */ 44243417Skarels soreceive(so, paddr, uio, mp0, controlp, flagsp) 4434786Swnj register struct socket *so; 44441908Skarels struct mbuf **paddr; 44541908Skarels struct uio *uio; 44643417Skarels struct mbuf **mp0; 44741908Skarels struct mbuf **controlp; 44835384Skarels int *flagsp; 4494786Swnj { 45043417Skarels register struct mbuf *m, **mp; 45143417Skarels register int flags, len, error, s, offset; 45212757Ssam struct protosw *pr = so->so_proto; 45341908Skarels struct mbuf *nextrecord; 45441908Skarels int moff, type; 4554786Swnj 45643417Skarels mp = mp0; 45741908Skarels if (paddr) 45841908Skarels *paddr = 0; 45935384Skarels if (controlp) 46035384Skarels *controlp = 0; 46135384Skarels if (flagsp) 46235384Skarels flags = *flagsp &~ MSG_EOR; 46335384Skarels else 46435384Skarels flags = 0; 46512757Ssam if (flags & MSG_OOB) { 4669635Ssam m = m_get(M_WAIT, MT_DATA); 46712757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 46824768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4698594Sroot if (error) 47010137Ssam goto bad; 4718319Sroot do { 47241908Skarels error = uiomove(mtod(m, caddr_t), 47341908Skarels (int) min(uio->uio_resid, m->m_len), uio); 4748319Sroot m = m_free(m); 4758594Sroot } while (uio->uio_resid && error == 0 && m); 47610137Ssam bad: 4778319Sroot if (m) 4788771Sroot m_freem(m); 4798594Sroot return (error); 4808319Sroot } 48141908Skarels if (mp) 48241908Skarels *mp = (struct mbuf *)0; 48343417Skarels if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 48435384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 48535384Skarels (struct mbuf *)0, (struct mbuf *)0); 4868319Sroot 4874890Swnj restart: 48840706Skarels if (error = sblock(&so->so_rcv)) 48940706Skarels return (error); 4908835Sroot s = splnet(); 4914890Swnj 49237478Ssklower m = so->so_rcv.sb_mb; 49344383Skarels /* 49444383Skarels * If we have less data than requested, block awaiting more 49544383Skarels * (subject to any timeout) if: 49644383Skarels * 1. the current count is less than the low water mark, or 49744383Skarels * 2. MSG_WAITALL is set, and it is possible to do the entire 49844383Skarels * receive operation at once if we block (resid <= hiwat). 49944383Skarels * If MSG_WAITALL is set but resid is larger than the receive buffer, 50044383Skarels * we have to do the receive in sections, and thus risk returning 50144383Skarels * a short count if a timeout or signal occurs after we start. 50244383Skarels */ 50344383Skarels if (m == 0 || so->so_rcv.sb_cc < uio->uio_resid && 50444383Skarels (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || 50544383Skarels ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat))) { 50641908Skarels #ifdef DIAGNOSTIC 50741908Skarels if (m == 0 && so->so_rcv.sb_cc) 50837478Ssklower panic("receive 1"); 50941908Skarels #endif 5105168Swnj if (so->so_error) { 5115168Swnj error = so->so_error; 5125168Swnj so->so_error = 0; 5135168Swnj goto release; 5145168Swnj } 51532567Sbostic if (so->so_state & SS_CANTRCVMORE) 5164890Swnj goto release; 51738584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 51832567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 51932567Sbostic error = ENOTCONN; 52032567Sbostic goto release; 5214890Swnj } 52243417Skarels if (uio->uio_resid == 0) 52325629Skarels goto release; 52432567Sbostic if (so->so_state & SS_NBIO) { 52532567Sbostic error = EWOULDBLOCK; 52632567Sbostic goto release; 52732567Sbostic } 5284890Swnj sbunlock(&so->so_rcv); 52943417Skarels error = sbwait(&so->so_rcv); 5305012Swnj splx(s); 53141908Skarels if (error) 53241908Skarels return (error); 5334890Swnj goto restart; 5344786Swnj } 5358041Sroot u.u_ru.ru_msgrcv++; 53635384Skarels nextrecord = m->m_nextpkt; 53712757Ssam if (pr->pr_flags & PR_ADDR) { 53841908Skarels #ifdef DIAGNOSTIC 53925629Skarels if (m->m_type != MT_SONAME) 54016993Skarels panic("receive 1a"); 54141908Skarels #endif 54216993Skarels if (flags & MSG_PEEK) { 54341908Skarels if (paddr) 54441908Skarels *paddr = m_copy(m, 0, m->m_len); 54525629Skarels m = m->m_next; 54616993Skarels } else { 54725629Skarels sbfree(&so->so_rcv, m); 54841908Skarels if (paddr) { 54941908Skarels *paddr = m; 55035384Skarels so->so_rcv.sb_mb = m->m_next; 55135384Skarels m->m_next = 0; 55235384Skarels m = so->so_rcv.sb_mb; 55325629Skarels } else { 55426958Skarels MFREE(m, so->so_rcv.sb_mb); 55526958Skarels m = so->so_rcv.sb_mb; 55625629Skarels } 55716993Skarels } 55816993Skarels } 55941908Skarels while (m && m->m_type == MT_CONTROL && error == 0) { 56016993Skarels if (flags & MSG_PEEK) { 56135384Skarels if (controlp) 56235384Skarels *controlp = m_copy(m, 0, m->m_len); 56335384Skarels m = m->m_next; 56435384Skarels } else { 56535384Skarels sbfree(&so->so_rcv, m); 56635384Skarels if (controlp) { 56743097Ssklower if (pr->pr_domain->dom_externalize && 56843097Ssklower mtod(m, struct cmsghdr *)->cmsg_type == 56943097Ssklower SCM_RIGHTS) 57041908Skarels error = (*pr->pr_domain->dom_externalize)(m); 57135384Skarels *controlp = m; 57235384Skarels so->so_rcv.sb_mb = m->m_next; 57335384Skarels m->m_next = 0; 57435384Skarels m = so->so_rcv.sb_mb; 57535384Skarels } else { 57635384Skarels MFREE(m, so->so_rcv.sb_mb); 57735384Skarels m = so->so_rcv.sb_mb; 57835384Skarels } 57935384Skarels } 58041908Skarels if (controlp) 58141908Skarels controlp = &(*controlp)->m_next; 58235384Skarels } 58341908Skarels if (m) { 58444383Skarels if ((flags & MSG_PEEK) == 0) 58544383Skarels m->m_nextpkt = nextrecord; 58641908Skarels type = m->m_type; 58741908Skarels } 5888319Sroot moff = 0; 58932092Skarels offset = 0; 59043417Skarels while (m && m->m_type == type && uio->uio_resid > 0 && error == 0) { 59135384Skarels if (m->m_type == MT_OOBDATA) 59235384Skarels flags |= MSG_OOB; 59341908Skarels #ifdef DIAGNOSTIC 59435384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 59525629Skarels panic("receive 3"); 59641908Skarels #endif 59741908Skarels type = m->m_type; 5987747Sroot so->so_state &= ~SS_RCVATMARK; 59943417Skarels len = uio->uio_resid; 60032092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 60132092Skarels len = so->so_oobmark - offset; 60221767Skarels if (len > m->m_len - moff) 6038319Sroot len = m->m_len - moff; 60441908Skarels /* 60541908Skarels * If mp is set, just pass back the mbufs. 60641908Skarels * Otherwise copy them out via the uio, then free. 60741908Skarels * Sockbuf must be consistent here (points to current mbuf, 60841908Skarels * it points to next record) when we drop priority; 60941908Skarels * we must note any additions to the sockbuf when we 61041908Skarels * block interrupts again. 61141908Skarels */ 61241908Skarels if (mp == 0) { 61341908Skarels splx(s); 61441908Skarels error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 61541908Skarels s = splnet(); 61643417Skarels } else 61743417Skarels uio->uio_resid -= len; 61821767Skarels if (len == m->m_len - moff) { 61941908Skarels if (m->m_flags & M_EOR) 62041908Skarels flags |= MSG_EOR; 62125629Skarels if (flags & MSG_PEEK) { 62225629Skarels m = m->m_next; 62325629Skarels moff = 0; 62425629Skarels } else { 62535384Skarels nextrecord = m->m_nextpkt; 62625629Skarels sbfree(&so->so_rcv, m); 62741908Skarels if (mp) { 62841908Skarels *mp = m; 62941908Skarels mp = &m->m_next; 63043417Skarels so->so_rcv.sb_mb = m = m->m_next; 63143417Skarels *mp = (struct mbuf *)0; 63241908Skarels } else { 63341908Skarels MFREE(m, so->so_rcv.sb_mb); 63441908Skarels m = so->so_rcv.sb_mb; 63541908Skarels } 63626958Skarels if (m) 63735384Skarels m->m_nextpkt = nextrecord; 63825629Skarels } 6394786Swnj } else { 64012757Ssam if (flags & MSG_PEEK) 6418319Sroot moff += len; 6428319Sroot else { 64343417Skarels if (mp) 64443417Skarels *mp = m_copym(m, 0, len, M_WAIT); 64535384Skarels m->m_data += len; 6468319Sroot m->m_len -= len; 6478319Sroot so->so_rcv.sb_cc -= len; 6488319Sroot } 6494786Swnj } 65032092Skarels if (so->so_oobmark) { 65132092Skarels if ((flags & MSG_PEEK) == 0) { 65232092Skarels so->so_oobmark -= len; 65332092Skarels if (so->so_oobmark == 0) { 65432092Skarels so->so_state |= SS_RCVATMARK; 65532092Skarels break; 65632092Skarels } 65732092Skarels } else 65832092Skarels offset += len; 6597747Sroot } 66041908Skarels if (flags & MSG_EOR) 66140632Skarels break; 66241908Skarels /* 66341908Skarels * If the MSG_WAITALL flag is set (for non-atomic socket), 66443417Skarels * we must not quit until "uio->uio_resid == 0" or an error 66541908Skarels * termination. If a signal/timeout occurs, return 66643417Skarels * with a short count but without error. 66741908Skarels * Keep sockbuf locked against other readers. 66841908Skarels */ 66943417Skarels while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && 67041908Skarels !sosendallatonce(so)) { 67141908Skarels error = sbwait(&so->so_rcv); 67241908Skarels if (error) { 67341908Skarels sbunlock(&so->so_rcv); 67441908Skarels splx(s); 67541908Skarels return (0); 67641908Skarels } 67741908Skarels if (m = so->so_rcv.sb_mb) 67841908Skarels nextrecord = m->m_nextpkt; 67941908Skarels if (so->so_error || so->so_state & SS_CANTRCVMORE) 68041908Skarels break; 68141908Skarels continue; 68241908Skarels } 68316993Skarels } 68416993Skarels if ((flags & MSG_PEEK) == 0) { 68526500Skarels if (m == 0) 68616993Skarels so->so_rcv.sb_mb = nextrecord; 68735384Skarels else if (pr->pr_flags & PR_ATOMIC) { 68835384Skarels flags |= MSG_TRUNC; 68926958Skarels (void) sbdroprecord(&so->so_rcv); 69035384Skarels } 69116993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 69216993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 69337478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 69437478Ssklower (struct mbuf *)0); 69516993Skarels } 69635384Skarels if (flagsp) 69735384Skarels *flagsp |= flags; 6984890Swnj release: 6994916Swnj sbunlock(&so->so_rcv); 7004890Swnj splx(s); 7014916Swnj return (error); 7024786Swnj } 7034786Swnj 70410267Ssam soshutdown(so, how) 70512757Ssam register struct socket *so; 70612757Ssam register int how; 70710267Ssam { 70812757Ssam register struct protosw *pr = so->so_proto; 70910267Ssam 71010267Ssam how++; 71112757Ssam if (how & FREAD) 71212757Ssam sorflush(so); 71310267Ssam if (how & FWRITE) 71412757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 71512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 71610267Ssam return (0); 71710267Ssam } 71810267Ssam 71912757Ssam sorflush(so) 72012757Ssam register struct socket *so; 72112757Ssam { 72212757Ssam register struct sockbuf *sb = &so->so_rcv; 72312757Ssam register struct protosw *pr = so->so_proto; 72412757Ssam register int s; 72512757Ssam struct sockbuf asb; 72612757Ssam 72740706Skarels sb->sb_flags |= SB_NOINTR; 72840706Skarels (void) sblock(sb); 72912757Ssam s = splimp(); 73012757Ssam socantrcvmore(so); 73112757Ssam sbunlock(sb); 73212757Ssam asb = *sb; 73312757Ssam bzero((caddr_t)sb, sizeof (*sb)); 73412757Ssam splx(s); 73516993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 73616993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 73712757Ssam sbrelease(&asb); 73812757Ssam } 73912757Ssam 74018553Skarels sosetopt(so, level, optname, m0) 74112757Ssam register struct socket *so; 74210267Ssam int level, optname; 74318553Skarels struct mbuf *m0; 74410267Ssam { 74517158Ssam int error = 0; 74618553Skarels register struct mbuf *m = m0; 74710267Ssam 74817158Ssam if (level != SOL_SOCKET) { 74918369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 75018369Skarels return ((*so->so_proto->pr_ctloutput) 75118553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 75218369Skarels error = ENOPROTOOPT; 75318369Skarels } else { 75418369Skarels switch (optname) { 75510267Ssam 75618369Skarels case SO_LINGER: 75718369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 75818369Skarels error = EINVAL; 75918369Skarels goto bad; 76018369Skarels } 76118369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 76218369Skarels /* fall thru... */ 76317158Ssam 76418369Skarels case SO_DEBUG: 76518369Skarels case SO_KEEPALIVE: 76618369Skarels case SO_DONTROUTE: 76718369Skarels case SO_USELOOPBACK: 76818369Skarels case SO_BROADCAST: 76918369Skarels case SO_REUSEADDR: 77027191Skarels case SO_OOBINLINE: 77118369Skarels if (m == NULL || m->m_len < sizeof (int)) { 77218369Skarels error = EINVAL; 77318369Skarels goto bad; 77418369Skarels } 77518369Skarels if (*mtod(m, int *)) 77618369Skarels so->so_options |= optname; 77718369Skarels else 77818369Skarels so->so_options &= ~optname; 77918369Skarels break; 78018369Skarels 78118369Skarels case SO_SNDBUF: 78241908Skarels case SO_RCVBUF: 78340706Skarels case SO_SNDLOWAT: 78441908Skarels case SO_RCVLOWAT: 78540706Skarels case SO_SNDTIMEO: 78618369Skarels case SO_RCVTIMEO: 78718369Skarels if (m == NULL || m->m_len < sizeof (int)) { 78818369Skarels error = EINVAL; 78918369Skarels goto bad; 79018369Skarels } 79118369Skarels switch (optname) { 79218369Skarels 79318369Skarels case SO_SNDBUF: 79418369Skarels case SO_RCVBUF: 79541908Skarels if (sbreserve(optname == SO_SNDBUF ? 79641908Skarels &so->so_snd : &so->so_rcv, 79741908Skarels (u_long) *mtod(m, int *)) == 0) { 79818369Skarels error = ENOBUFS; 79918369Skarels goto bad; 80018369Skarels } 80118369Skarels break; 80218369Skarels 80318369Skarels case SO_SNDLOWAT: 80441908Skarels so->so_snd.sb_lowat = *mtod(m, int *); 80541908Skarels break; 80618369Skarels case SO_RCVLOWAT: 80741908Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 80818369Skarels break; 80918369Skarels case SO_SNDTIMEO: 81041908Skarels so->so_snd.sb_timeo = *mtod(m, int *); 81141908Skarels break; 81218369Skarels case SO_RCVTIMEO: 81341908Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 81418369Skarels break; 81518369Skarels } 81618369Skarels break; 81718369Skarels 81818369Skarels default: 81918369Skarels error = ENOPROTOOPT; 82018369Skarels break; 82117158Ssam } 82210267Ssam } 82317158Ssam bad: 82417158Ssam if (m) 82517158Ssam (void) m_free(m); 82617158Ssam return (error); 82710267Ssam } 82810267Ssam 82917158Ssam sogetopt(so, level, optname, mp) 83012757Ssam register struct socket *so; 83110267Ssam int level, optname; 83217158Ssam struct mbuf **mp; 83317158Ssam { 83412757Ssam register struct mbuf *m; 83510267Ssam 83618369Skarels if (level != SOL_SOCKET) { 83718369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 83818369Skarels return ((*so->so_proto->pr_ctloutput) 83918369Skarels (PRCO_GETOPT, so, level, optname, mp)); 84018369Skarels } else 84118369Skarels return (ENOPROTOOPT); 84218369Skarels } else { 84317158Ssam m = m_get(M_WAIT, MT_SOOPTS); 84425502Skarels m->m_len = sizeof (int); 84525502Skarels 84618369Skarels switch (optname) { 84717158Ssam 84818369Skarels case SO_LINGER: 84918369Skarels m->m_len = sizeof (struct linger); 85018369Skarels mtod(m, struct linger *)->l_onoff = 85118369Skarels so->so_options & SO_LINGER; 85218369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 85318369Skarels break; 85410267Ssam 85518369Skarels case SO_USELOOPBACK: 85618369Skarels case SO_DONTROUTE: 85718369Skarels case SO_DEBUG: 85818369Skarels case SO_KEEPALIVE: 85918369Skarels case SO_REUSEADDR: 86018369Skarels case SO_BROADCAST: 86127191Skarels case SO_OOBINLINE: 86218369Skarels *mtod(m, int *) = so->so_options & optname; 86318369Skarels break; 86418369Skarels 86525502Skarels case SO_TYPE: 86625502Skarels *mtod(m, int *) = so->so_type; 86725502Skarels break; 86825502Skarels 86924768Skarels case SO_ERROR: 87024768Skarels *mtod(m, int *) = so->so_error; 87124768Skarels so->so_error = 0; 87224768Skarels break; 87324768Skarels 87418369Skarels case SO_SNDBUF: 87518369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 87618369Skarels break; 87718369Skarels 87818369Skarels case SO_RCVBUF: 87918369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 88018369Skarels break; 88118369Skarels 88218369Skarels case SO_SNDLOWAT: 88318369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 88418369Skarels break; 88518369Skarels 88618369Skarels case SO_RCVLOWAT: 88718369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 88818369Skarels break; 88918369Skarels 89018369Skarels case SO_SNDTIMEO: 89118369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 89218369Skarels break; 89318369Skarels 89418369Skarels case SO_RCVTIMEO: 89518369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 89618369Skarels break; 89718369Skarels 89818369Skarels default: 89926362Skarels (void)m_free(m); 90018369Skarels return (ENOPROTOOPT); 90118369Skarels } 90218369Skarels *mp = m; 90318369Skarels return (0); 90410267Ssam } 90510267Ssam } 90610267Ssam 9075423Swnj sohasoutofband(so) 90812757Ssam register struct socket *so; 9095423Swnj { 91023233Skarels struct proc *p; 9115423Swnj 91237478Ssklower if (so->so_pgid < 0) 91337478Ssklower gsignal(-so->so_pgid, SIGURG); 91437478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 91523233Skarels psignal(p, SIGURG); 91624768Skarels if (so->so_rcv.sb_sel) { 91724768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 91824768Skarels so->so_rcv.sb_sel = 0; 91924768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 92024768Skarels } 9215423Swnj } 922