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*51755Smckusick * @(#)uipc_socket.c 7.31 (Berkeley) 11/19/91 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) 314786Swnj struct socket **aso; 3212757Ssam register int type; 3312757Ssam int proto; 344786Swnj { 3550942Ssklower struct proc *p = curproc; /* XXX */ 364786Swnj register struct protosw *prp; 374786Swnj register struct socket *so; 3812757Ssam register int error; 394786Swnj 404890Swnj if (proto) 4121767Skarels prp = pffindproto(dom, proto, type); 424890Swnj else 439168Ssam prp = pffindtype(dom, type); 444890Swnj if (prp == 0) 454890Swnj return (EPROTONOSUPPORT); 468300Sroot if (prp->pr_type != type) 478300Sroot return (EPROTOTYPE); 4837478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 4937478Ssklower bzero((caddr_t)so, sizeof(*so)); 509168Ssam so->so_type = type; 5150942Ssklower if (p->p_ucred->cr_uid == 0) 526214Swnj so->so_state = SS_PRIV; 534786Swnj so->so_proto = prp; 5412757Ssam error = 5512757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 5621767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 574979Swnj if (error) { 587507Sroot so->so_state |= SS_NOFDREF; 597180Swnj sofree(so); 604890Swnj return (error); 614786Swnj } 624786Swnj *aso = so; 634786Swnj return (0); 644786Swnj } 654786Swnj 6610267Ssam sobind(so, nam) 678300Sroot struct socket *so; 688300Sroot struct mbuf *nam; 698300Sroot { 708300Sroot int s = splnet(); 718300Sroot int error; 728300Sroot 7341908Skarels error = 7441908Skarels (*so->so_proto->pr_usrreq)(so, PRU_BIND, 7512757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 768300Sroot splx(s); 778300Sroot return (error); 788300Sroot } 798300Sroot 808300Sroot solisten(so, backlog) 8112757Ssam register struct socket *so; 828300Sroot int backlog; 838300Sroot { 8412757Ssam int s = splnet(), error; 858300Sroot 8612757Ssam error = 8712757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 8812757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 898300Sroot if (error) { 908300Sroot splx(s); 918300Sroot return (error); 928300Sroot } 9338584Skarels if (so->so_q == 0) 948300Sroot so->so_options |= SO_ACCEPTCONN; 958300Sroot if (backlog < 0) 968300Sroot backlog = 0; 9735384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 9812493Ssam splx(s); 998300Sroot return (0); 1008300Sroot } 1018300Sroot 1024916Swnj sofree(so) 10312757Ssam register struct socket *so; 1044916Swnj { 1054916Swnj 10631810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 10731810Skarels return; 1087507Sroot if (so->so_head) { 1097507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1107507Sroot panic("sofree dq"); 1117507Sroot so->so_head = 0; 1127507Sroot } 1134950Swnj sbrelease(&so->so_snd); 11412757Ssam sorflush(so); 11537478Ssklower FREE(so, M_SOCKET); 1164916Swnj } 1174916Swnj 1184786Swnj /* 1194890Swnj * Close a socket on last file table reference removal. 1204890Swnj * Initiate disconnect if connected. 1214890Swnj * Free socket when disconnect complete. 1224829Swnj */ 12312757Ssam soclose(so) 1244829Swnj register struct socket *so; 1254829Swnj { 1264890Swnj int s = splnet(); /* conservative */ 12733372Sbostic int error = 0; 1284829Swnj 1297507Sroot if (so->so_options & SO_ACCEPTCONN) { 13038584Skarels while (so->so_q0) 13110399Ssam (void) soabort(so->so_q0); 13238584Skarels while (so->so_q) 13310399Ssam (void) soabort(so->so_q); 1347507Sroot } 1354890Swnj if (so->so_pcb == 0) 1364890Swnj goto discard; 1374890Swnj if (so->so_state & SS_ISCONNECTED) { 1384890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 13926245Skarels error = sodisconnect(so); 14012757Ssam if (error) 14112757Ssam goto drop; 1424890Swnj } 14310267Ssam if (so->so_options & SO_LINGER) { 1445281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 14512757Ssam (so->so_state & SS_NBIO)) 14612757Ssam goto drop; 1475281Sroot while (so->so_state & SS_ISCONNECTED) 14840706Skarels if (error = tsleep((caddr_t)&so->so_timeo, 14940706Skarels PSOCK | PCATCH, netcls, so->so_linger)) 15040706Skarels break; 1514890Swnj } 1524890Swnj } 1535580Sroot drop: 1546880Ssam if (so->so_pcb) { 15512757Ssam int error2 = 15612757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 15712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 15812757Ssam if (error == 0) 15912757Ssam error = error2; 1606880Ssam } 1614890Swnj discard: 16210399Ssam if (so->so_state & SS_NOFDREF) 16310399Ssam panic("soclose: NOFDREF"); 1647507Sroot so->so_state |= SS_NOFDREF; 1654950Swnj sofree(so); 1664890Swnj splx(s); 16712757Ssam return (error); 1684829Swnj } 1694829Swnj 17010399Ssam /* 17110399Ssam * Must be called at splnet... 17210399Ssam */ 17310399Ssam soabort(so) 17410399Ssam struct socket *so; 17510399Ssam { 17610399Ssam 17712757Ssam return ( 17812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 17912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 18010399Ssam } 18110399Ssam 18210267Ssam soaccept(so, nam) 18312757Ssam register struct socket *so; 1848300Sroot struct mbuf *nam; 1854927Swnj { 1864927Swnj int s = splnet(); 1874927Swnj int error; 1884927Swnj 18910399Ssam if ((so->so_state & SS_NOFDREF) == 0) 19010399Ssam panic("soaccept: !NOFDREF"); 19110267Ssam so->so_state &= ~SS_NOFDREF; 1928300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 19312757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 1944927Swnj splx(s); 1954927Swnj return (error); 1964927Swnj } 1974927Swnj 19810267Ssam soconnect(so, nam) 19912757Ssam register struct socket *so; 2008300Sroot struct mbuf *nam; 2014786Swnj { 20230414Skarels int s; 2034890Swnj int error; 2044786Swnj 20530414Skarels if (so->so_options & SO_ACCEPTCONN) 20630414Skarels return (EOPNOTSUPP); 20730414Skarels s = splnet(); 20824768Skarels /* 20924768Skarels * If protocol is connection-based, can only connect once. 21024768Skarels * Otherwise, if connected, try to disconnect first. 21124768Skarels * This allows user to disconnect by connecting to, e.g., 21224768Skarels * a null address. 21324768Skarels */ 21424768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 21524768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 21624768Skarels (error = sodisconnect(so)))) 2174890Swnj error = EISCONN; 21824768Skarels else 21924768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22024768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2214890Swnj splx(s); 2224890Swnj return (error); 2234786Swnj } 2244786Swnj 22512757Ssam soconnect2(so1, so2) 22612757Ssam register struct socket *so1; 22712757Ssam struct socket *so2; 22812757Ssam { 22912757Ssam int s = splnet(); 23012757Ssam int error; 23112757Ssam 23213113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23313113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 23412757Ssam splx(s); 23512757Ssam return (error); 23612757Ssam } 23712757Ssam 23826245Skarels sodisconnect(so) 23912757Ssam register struct socket *so; 2404786Swnj { 2414890Swnj int s = splnet(); 2424890Swnj int error; 2434786Swnj 2444890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2454890Swnj error = ENOTCONN; 2464890Swnj goto bad; 2474890Swnj } 2484890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2494890Swnj error = EALREADY; 2504890Swnj goto bad; 2514890Swnj } 2528300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25326245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2544890Swnj bad: 2554890Swnj splx(s); 2564890Swnj return (error); 2574786Swnj } 2584786Swnj 259*51755Smckusick #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) 2604786Swnj /* 2614890Swnj * Send on a socket. 2624890Swnj * If send must go all at once and message is larger than 2634890Swnj * send buffering, then hard error. 2644890Swnj * Lock against other senders. 2654890Swnj * If must go all at once and not enough room now, then 2664890Swnj * inform user that this would block and do nothing. 26716412Skarels * Otherwise, if nonblocking, send as much as possible. 26841908Skarels * The data to be sent is described by "uio" if nonzero, 26941908Skarels * otherwise by the mbuf chain "top" (which must be null 27041908Skarels * if uio is not). Data provided in mbuf chain must be small 27141908Skarels * enough to send all at once. 27241908Skarels * 27341908Skarels * Returns nonzero on error, timeout or signal; callers 27441908Skarels * must check for short counts if EINTR/ERESTART are returned. 27541908Skarels * Data and control buffers are freed on return. 2764786Swnj */ 27743417Skarels sosend(so, addr, uio, top, control, flags) 2784786Swnj register struct socket *so; 27941908Skarels struct mbuf *addr; 28041908Skarels struct uio *uio; 28141908Skarels struct mbuf *top; 28241908Skarels struct mbuf *control; 2838319Sroot int flags; 2844786Swnj { 28550942Ssklower struct proc *p = curproc; /* XXX */ 28641908Skarels struct mbuf **mp; 28735384Skarels register struct mbuf *m; 28841908Skarels register long space, len, resid; 28941908Skarels int clen = 0, error, s, dontroute, mlen; 29041908Skarels int atomic = sosendallatonce(so) || top; 2914786Swnj 29241908Skarels if (uio) 29341908Skarels resid = uio->uio_resid; 29441908Skarels else 29541908Skarels resid = top->m_pkthdr.len; 29612757Ssam dontroute = 29712757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29812757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 29950942Ssklower p->p_stats->p_ru.ru_msgsnd++; 30040632Skarels if (control) 30141908Skarels clen = control->m_len; 30216412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30316412Skarels 3046419Sroot restart: 305*51755Smckusick if (error = sblock(&so->so_snd, SBLOCKWAIT(flags))) 30641908Skarels goto out; 30716412Skarels do { 30816412Skarels s = splnet(); 30921108Skarels if (so->so_state & SS_CANTSENDMORE) 31016412Skarels snderr(EPIPE); 31137478Ssklower if (so->so_error) 31237478Ssklower snderr(so->so_error); 31316412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31437478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 31549059Ssklower if ((so->so_state & SS_ISCONFIRMING) == 0 && 31649059Ssklower !(resid == 0 && clen != 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; 324*51755Smckusick if (atomic && resid > so->so_snd.sb_hiwat || 325*51755Smckusick clen > so->so_snd.sb_hiwat) 326*51755Smckusick snderr(EMSGSIZE); 327*51755Smckusick if (space < resid + clen && uio && 32841908Skarels (atomic || space < so->so_snd.sb_lowat || space < clen)) { 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; 37046452Ssklower } else 37146452Ssklower len = min(MCLBYTES, resid); 37235384Skarels #endif 37335384Skarels space -= MCLBYTES; 37416412Skarels } else { 37516412Skarels nopages: 37641908Skarels len = min(min(mlen, resid), space); 37721767Skarels space -= len; 37835384Skarels /* 37935384Skarels * For datagram protocols, leave room 38035384Skarels * for protocol headers in first mbuf. 38135384Skarels */ 38235391Skarels if (atomic && top == 0 && len < mlen) 38335384Skarels MH_ALIGN(m, len); 38416412Skarels } 38545515Skarels error = uiomove(mtod(m, caddr_t), (int)len, uio); 38641908Skarels resid = uio->uio_resid; 38716412Skarels m->m_len = len; 38816412Skarels *mp = m; 38935384Skarels top->m_pkthdr.len += len; 39016412Skarels if (error) 39116412Skarels goto release; 39216412Skarels mp = &m->m_next; 39341908Skarels if (resid <= 0) { 39441908Skarels if (flags & MSG_EOR) 39535384Skarels top->m_flags |= M_EOR; 39621108Skarels break; 39735384Skarels } 39835384Skarels } while (space > 0 && atomic); 39935384Skarels if (dontroute) 40035384Skarels so->so_options |= SO_DONTROUTE; 40135384Skarels s = splnet(); /* XXX */ 40235384Skarels error = (*so->so_proto->pr_usrreq)(so, 40335384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40441908Skarels top, addr, control); 40535384Skarels splx(s); 40635384Skarels if (dontroute) 40735384Skarels so->so_options &= ~SO_DONTROUTE; 40841908Skarels clen = 0; 40941908Skarels control = 0; 41035384Skarels top = 0; 41135384Skarels mp = ⊤ 41235384Skarels if (error) 41335384Skarels goto release; 41441908Skarels } while (resid && space > 0); 41541908Skarels } while (resid); 4164890Swnj 4174786Swnj release: 4184890Swnj sbunlock(&so->so_snd); 41941908Skarels out: 4206419Sroot if (top) 4216419Sroot m_freem(top); 42241908Skarels if (control) 42341908Skarels m_freem(control); 4244786Swnj return (error); 4254786Swnj } 4264786Swnj 42725629Skarels /* 42825629Skarels * Implement receive operations on a socket. 42925629Skarels * We depend on the way that records are added to the sockbuf 43025629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 43125629Skarels * must begin with an address if the protocol so specifies, 43241908Skarels * followed by an optional mbuf or mbufs containing ancillary data, 43341908Skarels * and then zero or more mbufs of data. 43425629Skarels * In order to avoid blocking network interrupts for the entire time here, 43525629Skarels * we splx() while doing the actual copy to user space. 43625629Skarels * Although the sockbuf is locked, new data may still be appended, 43725629Skarels * and thus we must maintain consistency of the sockbuf during that time. 43845515Skarels * 43941908Skarels * The caller may receive the data as a single mbuf chain by supplying 44043417Skarels * an mbuf **mp0 for use in returning the chain. The uio is then used 44141908Skarels * only for the count in uio_resid. 44225629Skarels */ 44343417Skarels soreceive(so, paddr, uio, mp0, controlp, flagsp) 4444786Swnj register struct socket *so; 44541908Skarels struct mbuf **paddr; 44641908Skarels struct uio *uio; 44743417Skarels struct mbuf **mp0; 44841908Skarels struct mbuf **controlp; 44935384Skarels int *flagsp; 4504786Swnj { 45150942Ssklower struct proc *p = curproc; /* XXX */ 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: 490*51755Smckusick 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). 501*51755Smckusick * 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 */ 506*51755Smckusick if (m == 0 || ((flags & MSG_DONTWAIT) == 0 && 507*51755Smckusick 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; 541*51755Smckusick 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: 55350942Ssklower p->p_stats->p_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) { 64150942Ssklower if (m->m_flags & M_EOR) 64250942Ssklower 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 } 68250942Ssklower 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 && 69250942Ssklower !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 } 70150942Ssklower 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; 749*51755Smckusick (void) sblock(sb, M_WAITOK); 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 } 86451022Ssklower m = 0; 86550942Ssklower if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) 86650942Ssklower (void) ((*so->so_proto->pr_ctloutput) 86750942Ssklower (PRCO_SETOPT, so, level, optname, &m0)); 86810267Ssam } 86917158Ssam bad: 87017158Ssam if (m) 87117158Ssam (void) m_free(m); 87217158Ssam return (error); 87310267Ssam } 87410267Ssam 87517158Ssam sogetopt(so, level, optname, mp) 87612757Ssam register struct socket *so; 87710267Ssam int level, optname; 87817158Ssam struct mbuf **mp; 87917158Ssam { 88012757Ssam register struct mbuf *m; 88110267Ssam 88218369Skarels if (level != SOL_SOCKET) { 88318369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 88418369Skarels return ((*so->so_proto->pr_ctloutput) 88518369Skarels (PRCO_GETOPT, so, level, optname, mp)); 88645515Skarels } else 88718369Skarels return (ENOPROTOOPT); 88818369Skarels } else { 88917158Ssam m = m_get(M_WAIT, MT_SOOPTS); 89025502Skarels m->m_len = sizeof (int); 89125502Skarels 89218369Skarels switch (optname) { 89317158Ssam 89418369Skarels case SO_LINGER: 89518369Skarels m->m_len = sizeof (struct linger); 89618369Skarels mtod(m, struct linger *)->l_onoff = 89718369Skarels so->so_options & SO_LINGER; 89818369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 89918369Skarels break; 90010267Ssam 90118369Skarels case SO_USELOOPBACK: 90218369Skarels case SO_DONTROUTE: 90318369Skarels case SO_DEBUG: 90418369Skarels case SO_KEEPALIVE: 90518369Skarels case SO_REUSEADDR: 90618369Skarels case SO_BROADCAST: 90727191Skarels case SO_OOBINLINE: 90818369Skarels *mtod(m, int *) = so->so_options & optname; 90918369Skarels break; 91018369Skarels 91125502Skarels case SO_TYPE: 91225502Skarels *mtod(m, int *) = so->so_type; 91325502Skarels break; 91425502Skarels 91524768Skarels case SO_ERROR: 91624768Skarels *mtod(m, int *) = so->so_error; 91724768Skarels so->so_error = 0; 91824768Skarels break; 91924768Skarels 92018369Skarels case SO_SNDBUF: 92118369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 92218369Skarels break; 92318369Skarels 92418369Skarels case SO_RCVBUF: 92518369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 92618369Skarels break; 92718369Skarels 92818369Skarels case SO_SNDLOWAT: 92918369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 93018369Skarels break; 93118369Skarels 93218369Skarels case SO_RCVLOWAT: 93318369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 93418369Skarels break; 93518369Skarels 93618369Skarels case SO_SNDTIMEO: 93744721Skarels case SO_RCVTIMEO: 93844721Skarels { 93944721Skarels int val = (optname == SO_SNDTIMEO ? 94044721Skarels so->so_snd.sb_timeo : so->so_rcv.sb_timeo); 94118369Skarels 94244721Skarels m->m_len = sizeof(struct timeval); 94344721Skarels mtod(m, struct timeval *)->tv_sec = val / hz; 94444721Skarels mtod(m, struct timeval *)->tv_usec = 94544721Skarels (val % hz) / tick; 94618369Skarels break; 94744721Skarels } 94818369Skarels 94918369Skarels default: 95026362Skarels (void)m_free(m); 95118369Skarels return (ENOPROTOOPT); 95218369Skarels } 95318369Skarels *mp = m; 95418369Skarels return (0); 95510267Ssam } 95610267Ssam } 95710267Ssam 9585423Swnj sohasoutofband(so) 95912757Ssam register struct socket *so; 9605423Swnj { 96123233Skarels struct proc *p; 9625423Swnj 96337478Ssklower if (so->so_pgid < 0) 96437478Ssklower gsignal(-so->so_pgid, SIGURG); 96537478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 96623233Skarels psignal(p, SIGURG); 96724768Skarels if (so->so_rcv.sb_sel) { 96824768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 96924768Skarels so->so_rcv.sb_sel = 0; 97024768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 97124768Skarels } 9725423Swnj } 973