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*51022Ssklower * @(#)uipc_socket.c 7.30 (Berkeley) 09/06/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 2594786Swnj /* 2604890Swnj * Send on a socket. 2614890Swnj * If send must go all at once and message is larger than 2624890Swnj * send buffering, then hard error. 2634890Swnj * Lock against other senders. 2644890Swnj * If must go all at once and not enough room now, then 2654890Swnj * inform user that this would block and do nothing. 26616412Skarels * Otherwise, if nonblocking, send as much as possible. 26741908Skarels * The data to be sent is described by "uio" if nonzero, 26841908Skarels * otherwise by the mbuf chain "top" (which must be null 26941908Skarels * if uio is not). Data provided in mbuf chain must be small 27041908Skarels * enough to send all at once. 27141908Skarels * 27241908Skarels * Returns nonzero on error, timeout or signal; callers 27341908Skarels * must check for short counts if EINTR/ERESTART are returned. 27441908Skarels * Data and control buffers are freed on return. 2754786Swnj */ 27643417Skarels sosend(so, addr, uio, top, control, flags) 2774786Swnj register struct socket *so; 27841908Skarels struct mbuf *addr; 27941908Skarels struct uio *uio; 28041908Skarels struct mbuf *top; 28141908Skarels struct mbuf *control; 2828319Sroot int flags; 2834786Swnj { 28450942Ssklower struct proc *p = curproc; /* XXX */ 28541908Skarels struct mbuf **mp; 28635384Skarels register struct mbuf *m; 28741908Skarels register long space, len, resid; 28841908Skarels int clen = 0, error, s, dontroute, mlen; 28941908Skarels int atomic = sosendallatonce(so) || top; 2904786Swnj 29141908Skarels if (uio) 29241908Skarels resid = uio->uio_resid; 29341908Skarels else 29441908Skarels resid = top->m_pkthdr.len; 29512757Ssam dontroute = 29612757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29712757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 29850942Ssklower p->p_stats->p_ru.ru_msgsnd++; 29940632Skarels if (control) 30041908Skarels clen = control->m_len; 30116412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30216412Skarels 3036419Sroot restart: 30440706Skarels if (error = sblock(&so->so_snd)) 30541908Skarels goto out; 30616412Skarels do { 30716412Skarels s = splnet(); 30821108Skarels if (so->so_state & SS_CANTSENDMORE) 30916412Skarels snderr(EPIPE); 31037478Ssklower if (so->so_error) 31137478Ssklower snderr(so->so_error); 31216412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31337478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 31449059Ssklower if ((so->so_state & SS_ISCONFIRMING) == 0 && 31549059Ssklower !(resid == 0 && clen != 0)) 31637478Ssklower snderr(ENOTCONN); 31741908Skarels } else if (addr == 0) 31816412Skarels snderr(EDESTADDRREQ); 31916412Skarels } 32041908Skarels space = sbspace(&so->so_snd); 32116412Skarels if (flags & MSG_OOB) 32241908Skarels space += 1024; 32341908Skarels if (space < resid + clen && 32441908Skarels (atomic || space < so->so_snd.sb_lowat || space < clen)) { 32541908Skarels if (atomic && resid > so->so_snd.sb_hiwat || 32641908Skarels clen > so->so_snd.sb_hiwat) 32741908Skarels snderr(EMSGSIZE); 32841908Skarels if (so->so_state & SS_NBIO) 32941908Skarels snderr(EWOULDBLOCK); 33041908Skarels sbunlock(&so->so_snd); 33143417Skarels error = sbwait(&so->so_snd); 33241908Skarels splx(s); 33341908Skarels if (error) 33441908Skarels goto out; 33541908Skarels goto restart; 33616412Skarels } 33716412Skarels splx(s); 33816412Skarels mp = ⊤ 33941908Skarels space -= clen; 34043417Skarels do { 34143417Skarels if (uio == NULL) { 34241908Skarels /* 34341908Skarels * Data is prepackaged in "top". 34441908Skarels */ 34541908Skarels resid = 0; 34641908Skarels if (flags & MSG_EOR) 34741908Skarels top->m_flags |= M_EOR; 34843417Skarels } else do { 34935384Skarels if (top == 0) { 35035384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35135384Skarels mlen = MHLEN; 35235384Skarels m->m_pkthdr.len = 0; 35335384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35435384Skarels } else { 35535384Skarels MGET(m, M_WAIT, MT_DATA); 35635384Skarels mlen = MLEN; 35735384Skarels } 35841908Skarels if (resid >= MINCLSIZE && space >= MCLBYTES) { 35935384Skarels MCLGET(m, M_WAIT); 36035384Skarels if ((m->m_flags & M_EXT) == 0) 36116412Skarels goto nopages; 36235384Skarels mlen = MCLBYTES; 36335384Skarels #ifdef MAPPED_MBUFS 36441908Skarels len = min(MCLBYTES, resid); 36541908Skarels #else 36641908Skarels if (top == 0) { 36741908Skarels len = min(MCLBYTES - max_hdr, resid); 36835384Skarels m->m_data += max_hdr; 36946452Ssklower } else 37046452Ssklower len = min(MCLBYTES, resid); 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 } 38445515Skarels error = uiomove(mtod(m, caddr_t), (int)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. 43745515Skarels * 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 { 45050942Ssklower struct proc *p = curproc; /* XXX */ 45143417Skarels register struct mbuf *m, **mp; 45243417Skarels register int flags, len, error, s, offset; 45312757Ssam struct protosw *pr = so->so_proto; 45441908Skarels struct mbuf *nextrecord; 45541908Skarels int moff, type; 4564786Swnj 45743417Skarels mp = mp0; 45841908Skarels if (paddr) 45941908Skarels *paddr = 0; 46035384Skarels if (controlp) 46135384Skarels *controlp = 0; 46235384Skarels if (flagsp) 46335384Skarels flags = *flagsp &~ MSG_EOR; 46445515Skarels else 46535384Skarels flags = 0; 46612757Ssam if (flags & MSG_OOB) { 4679635Ssam m = m_get(M_WAIT, MT_DATA); 46812757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 46924768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4708594Sroot if (error) 47110137Ssam goto bad; 4728319Sroot do { 47341908Skarels error = uiomove(mtod(m, caddr_t), 47441908Skarels (int) min(uio->uio_resid, m->m_len), uio); 4758319Sroot m = m_free(m); 4768594Sroot } while (uio->uio_resid && error == 0 && m); 47710137Ssam bad: 4788319Sroot if (m) 4798771Sroot m_freem(m); 4808594Sroot return (error); 4818319Sroot } 48241908Skarels if (mp) 48341908Skarels *mp = (struct mbuf *)0; 48443417Skarels if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 48535384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 48635384Skarels (struct mbuf *)0, (struct mbuf *)0); 4878319Sroot 4884890Swnj restart: 48940706Skarels if (error = sblock(&so->so_rcv)) 49040706Skarels return (error); 4918835Sroot s = splnet(); 4924890Swnj 49337478Ssklower m = so->so_rcv.sb_mb; 49444383Skarels /* 49544383Skarels * If we have less data than requested, block awaiting more 49644383Skarels * (subject to any timeout) if: 49744383Skarels * 1. the current count is less than the low water mark, or 49844383Skarels * 2. MSG_WAITALL is set, and it is possible to do the entire 49944383Skarels * receive operation at once if we block (resid <= hiwat). 50044383Skarels * If MSG_WAITALL is set but resid is larger than the receive buffer, 50144383Skarels * we have to do the receive in sections, and thus risk returning 50244383Skarels * a short count if a timeout or signal occurs after we start. 50344383Skarels */ 504*51022Ssklower if (m == 0 || so->so_rcv.sb_cc < uio->uio_resid && 50544383Skarels (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || 50650942Ssklower ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && 50750942Ssklower m->m_nextpkt == 0) { 50841908Skarels #ifdef DIAGNOSTIC 50941908Skarels if (m == 0 && so->so_rcv.sb_cc) 51037478Ssklower panic("receive 1"); 51141908Skarels #endif 5125168Swnj if (so->so_error) { 51346479Skarels if (m) 514*51022Ssklower goto dontblock; 5155168Swnj error = so->so_error; 51646479Skarels if ((flags & MSG_PEEK) == 0) 51746479Skarels so->so_error = 0; 5185168Swnj goto release; 5195168Swnj } 52046479Skarels if (so->so_state & SS_CANTRCVMORE) { 52146479Skarels if (m) 522*51022Ssklower goto dontblock; 52346479Skarels else 52446479Skarels goto release; 52546479Skarels } 52650942Ssklower for (; m; m = m->m_next) 52750942Ssklower if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { 52850942Ssklower m = so->so_rcv.sb_mb; 52950942Ssklower goto dontblock; 53050942Ssklower } 53138584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 53232567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 53332567Sbostic error = ENOTCONN; 53432567Sbostic goto release; 5354890Swnj } 53643417Skarels if (uio->uio_resid == 0) 53725629Skarels goto release; 53832567Sbostic if (so->so_state & SS_NBIO) { 53932567Sbostic error = EWOULDBLOCK; 54032567Sbostic goto release; 54132567Sbostic } 5424890Swnj sbunlock(&so->so_rcv); 54343417Skarels error = sbwait(&so->so_rcv); 5445012Swnj splx(s); 54541908Skarels if (error) 54641908Skarels return (error); 5474890Swnj goto restart; 5484786Swnj } 54950942Ssklower dontblock: 55050942Ssklower p->p_stats->p_ru.ru_msgrcv++; 55135384Skarels nextrecord = m->m_nextpkt; 55212757Ssam if (pr->pr_flags & PR_ADDR) { 55341908Skarels #ifdef DIAGNOSTIC 55425629Skarels if (m->m_type != MT_SONAME) 55516993Skarels panic("receive 1a"); 55641908Skarels #endif 55716993Skarels if (flags & MSG_PEEK) { 55841908Skarels if (paddr) 55941908Skarels *paddr = m_copy(m, 0, m->m_len); 56025629Skarels m = m->m_next; 56116993Skarels } else { 56225629Skarels sbfree(&so->so_rcv, m); 56341908Skarels if (paddr) { 56441908Skarels *paddr = m; 56535384Skarels so->so_rcv.sb_mb = m->m_next; 56635384Skarels m->m_next = 0; 56735384Skarels m = so->so_rcv.sb_mb; 56825629Skarels } else { 56926958Skarels MFREE(m, so->so_rcv.sb_mb); 57026958Skarels m = so->so_rcv.sb_mb; 57125629Skarels } 57216993Skarels } 57316993Skarels } 57441908Skarels while (m && m->m_type == MT_CONTROL && error == 0) { 57516993Skarels if (flags & MSG_PEEK) { 57635384Skarels if (controlp) 57735384Skarels *controlp = m_copy(m, 0, m->m_len); 57835384Skarels m = m->m_next; 57935384Skarels } else { 58035384Skarels sbfree(&so->so_rcv, m); 58135384Skarels if (controlp) { 58243097Ssklower if (pr->pr_domain->dom_externalize && 58343097Ssklower mtod(m, struct cmsghdr *)->cmsg_type == 58443097Ssklower SCM_RIGHTS) 58541908Skarels error = (*pr->pr_domain->dom_externalize)(m); 58635384Skarels *controlp = m; 58735384Skarels so->so_rcv.sb_mb = m->m_next; 58835384Skarels m->m_next = 0; 58935384Skarels m = so->so_rcv.sb_mb; 59035384Skarels } else { 59135384Skarels MFREE(m, so->so_rcv.sb_mb); 59235384Skarels m = so->so_rcv.sb_mb; 59335384Skarels } 59435384Skarels } 59541908Skarels if (controlp) 59641908Skarels controlp = &(*controlp)->m_next; 59735384Skarels } 59841908Skarels if (m) { 59944383Skarels if ((flags & MSG_PEEK) == 0) 60044383Skarels m->m_nextpkt = nextrecord; 60141908Skarels type = m->m_type; 60246452Ssklower if (type == MT_OOBDATA) 60346452Ssklower flags |= MSG_OOB; 60441908Skarels } 6058319Sroot moff = 0; 60632092Skarels offset = 0; 60746452Ssklower while (m && uio->uio_resid > 0 && error == 0) { 60846452Ssklower if (m->m_type == MT_OOBDATA) { 60946452Ssklower if (type != MT_OOBDATA) 61046452Ssklower break; 61146452Ssklower } else if (type == MT_OOBDATA) 61246452Ssklower break; 61341908Skarels #ifdef DIAGNOSTIC 61435384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 61525629Skarels panic("receive 3"); 61641908Skarels #endif 6177747Sroot so->so_state &= ~SS_RCVATMARK; 61843417Skarels len = uio->uio_resid; 61932092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 62032092Skarels len = so->so_oobmark - offset; 62121767Skarels if (len > m->m_len - moff) 6228319Sroot len = m->m_len - moff; 62341908Skarels /* 62441908Skarels * If mp is set, just pass back the mbufs. 62541908Skarels * Otherwise copy them out via the uio, then free. 62641908Skarels * Sockbuf must be consistent here (points to current mbuf, 62741908Skarels * it points to next record) when we drop priority; 62841908Skarels * we must note any additions to the sockbuf when we 62941908Skarels * block interrupts again. 63041908Skarels */ 63141908Skarels if (mp == 0) { 63241908Skarels splx(s); 63341908Skarels error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 63441908Skarels s = splnet(); 63543417Skarels } else 63643417Skarels uio->uio_resid -= len; 63721767Skarels if (len == m->m_len - moff) { 63850942Ssklower if (m->m_flags & M_EOR) 63950942Ssklower flags |= MSG_EOR; 64025629Skarels if (flags & MSG_PEEK) { 64125629Skarels m = m->m_next; 64225629Skarels moff = 0; 64325629Skarels } else { 64435384Skarels nextrecord = m->m_nextpkt; 64525629Skarels sbfree(&so->so_rcv, m); 64641908Skarels if (mp) { 64741908Skarels *mp = m; 64841908Skarels mp = &m->m_next; 64943417Skarels so->so_rcv.sb_mb = m = m->m_next; 65043417Skarels *mp = (struct mbuf *)0; 65141908Skarels } else { 65241908Skarels MFREE(m, so->so_rcv.sb_mb); 65341908Skarels m = so->so_rcv.sb_mb; 65441908Skarels } 65526958Skarels if (m) 65635384Skarels m->m_nextpkt = nextrecord; 65725629Skarels } 6584786Swnj } else { 65912757Ssam if (flags & MSG_PEEK) 6608319Sroot moff += len; 6618319Sroot else { 66243417Skarels if (mp) 66343417Skarels *mp = m_copym(m, 0, len, M_WAIT); 66435384Skarels m->m_data += len; 6658319Sroot m->m_len -= len; 6668319Sroot so->so_rcv.sb_cc -= len; 6678319Sroot } 6684786Swnj } 66932092Skarels if (so->so_oobmark) { 67032092Skarels if ((flags & MSG_PEEK) == 0) { 67132092Skarels so->so_oobmark -= len; 67232092Skarels if (so->so_oobmark == 0) { 67332092Skarels so->so_state |= SS_RCVATMARK; 67432092Skarels break; 67532092Skarels } 67632092Skarels } else 67732092Skarels offset += len; 6787747Sroot } 67950942Ssklower if (flags & MSG_EOR) 68040632Skarels break; 68141908Skarels /* 68241908Skarels * If the MSG_WAITALL flag is set (for non-atomic socket), 68343417Skarels * we must not quit until "uio->uio_resid == 0" or an error 68441908Skarels * termination. If a signal/timeout occurs, return 68543417Skarels * with a short count but without error. 68641908Skarels * Keep sockbuf locked against other readers. 68741908Skarels */ 68843417Skarels while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && 68950942Ssklower !sosendallatonce(so)) { 69046479Skarels if (so->so_error || so->so_state & SS_CANTRCVMORE) 69146479Skarels break; 69241908Skarels error = sbwait(&so->so_rcv); 69341908Skarels if (error) { 69441908Skarels sbunlock(&so->so_rcv); 69541908Skarels splx(s); 69641908Skarels return (0); 69741908Skarels } 69850942Ssklower if (m = so->so_rcv.sb_mb) 69941908Skarels nextrecord = m->m_nextpkt; 70041908Skarels } 70116993Skarels } 70216993Skarels if ((flags & MSG_PEEK) == 0) { 70326500Skarels if (m == 0) 70416993Skarels so->so_rcv.sb_mb = nextrecord; 70535384Skarels else if (pr->pr_flags & PR_ATOMIC) { 70635384Skarels flags |= MSG_TRUNC; 70726958Skarels (void) sbdroprecord(&so->so_rcv); 70835384Skarels } 70916993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 71016993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 71137478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 71237478Ssklower (struct mbuf *)0); 71316993Skarels } 71435384Skarels if (flagsp) 71535384Skarels *flagsp |= flags; 7164890Swnj release: 7174916Swnj sbunlock(&so->so_rcv); 7184890Swnj splx(s); 7194916Swnj return (error); 7204786Swnj } 7214786Swnj 72210267Ssam soshutdown(so, how) 72312757Ssam register struct socket *so; 72412757Ssam register int how; 72510267Ssam { 72612757Ssam register struct protosw *pr = so->so_proto; 72710267Ssam 72810267Ssam how++; 72912757Ssam if (how & FREAD) 73012757Ssam sorflush(so); 73110267Ssam if (how & FWRITE) 73212757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 73312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 73410267Ssam return (0); 73510267Ssam } 73610267Ssam 73712757Ssam sorflush(so) 73812757Ssam register struct socket *so; 73912757Ssam { 74012757Ssam register struct sockbuf *sb = &so->so_rcv; 74112757Ssam register struct protosw *pr = so->so_proto; 74212757Ssam register int s; 74312757Ssam struct sockbuf asb; 74412757Ssam 74540706Skarels sb->sb_flags |= SB_NOINTR; 74640706Skarels (void) sblock(sb); 74712757Ssam s = splimp(); 74812757Ssam socantrcvmore(so); 74912757Ssam sbunlock(sb); 75012757Ssam asb = *sb; 75112757Ssam bzero((caddr_t)sb, sizeof (*sb)); 75212757Ssam splx(s); 75316993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 75416993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 75512757Ssam sbrelease(&asb); 75612757Ssam } 75712757Ssam 75818553Skarels sosetopt(so, level, optname, m0) 75912757Ssam register struct socket *so; 76010267Ssam int level, optname; 76118553Skarels struct mbuf *m0; 76210267Ssam { 76317158Ssam int error = 0; 76418553Skarels register struct mbuf *m = m0; 76510267Ssam 76617158Ssam if (level != SOL_SOCKET) { 76718369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 76818369Skarels return ((*so->so_proto->pr_ctloutput) 76918553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 77018369Skarels error = ENOPROTOOPT; 77118369Skarels } else { 77218369Skarels switch (optname) { 77310267Ssam 77418369Skarels case SO_LINGER: 77518369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 77618369Skarels error = EINVAL; 77718369Skarels goto bad; 77818369Skarels } 77918369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 78018369Skarels /* fall thru... */ 78117158Ssam 78218369Skarels case SO_DEBUG: 78318369Skarels case SO_KEEPALIVE: 78418369Skarels case SO_DONTROUTE: 78518369Skarels case SO_USELOOPBACK: 78618369Skarels case SO_BROADCAST: 78718369Skarels case SO_REUSEADDR: 78827191Skarels case SO_OOBINLINE: 78918369Skarels if (m == NULL || m->m_len < sizeof (int)) { 79018369Skarels error = EINVAL; 79118369Skarels goto bad; 79218369Skarels } 79318369Skarels if (*mtod(m, int *)) 79418369Skarels so->so_options |= optname; 79518369Skarels else 79618369Skarels so->so_options &= ~optname; 79718369Skarels break; 79818369Skarels 79918369Skarels case SO_SNDBUF: 80041908Skarels case SO_RCVBUF: 80140706Skarels case SO_SNDLOWAT: 80241908Skarels case SO_RCVLOWAT: 80318369Skarels if (m == NULL || m->m_len < sizeof (int)) { 80418369Skarels error = EINVAL; 80518369Skarels goto bad; 80618369Skarels } 80718369Skarels switch (optname) { 80818369Skarels 80918369Skarels case SO_SNDBUF: 81018369Skarels case SO_RCVBUF: 81141908Skarels if (sbreserve(optname == SO_SNDBUF ? 81241908Skarels &so->so_snd : &so->so_rcv, 81341908Skarels (u_long) *mtod(m, int *)) == 0) { 81418369Skarels error = ENOBUFS; 81518369Skarels goto bad; 81618369Skarels } 81718369Skarels break; 81818369Skarels 81918369Skarels case SO_SNDLOWAT: 82041908Skarels so->so_snd.sb_lowat = *mtod(m, int *); 82141908Skarels break; 82218369Skarels case SO_RCVLOWAT: 82341908Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 82418369Skarels break; 82544721Skarels } 82644721Skarels break; 82744721Skarels 82844721Skarels case SO_SNDTIMEO: 82944721Skarels case SO_RCVTIMEO: 83044721Skarels { 83144721Skarels struct timeval *tv; 83244721Skarels short val; 83344721Skarels 83444721Skarels if (m == NULL || m->m_len < sizeof (*tv)) { 83544721Skarels error = EINVAL; 83644721Skarels goto bad; 83744721Skarels } 83844721Skarels tv = mtod(m, struct timeval *); 83944721Skarels if (tv->tv_sec > SHRT_MAX / hz - hz) { 84044721Skarels error = EDOM; 84144721Skarels goto bad; 84244721Skarels } 84344721Skarels val = tv->tv_sec * hz + tv->tv_usec / tick; 84444721Skarels 84544721Skarels switch (optname) { 84644721Skarels 84718369Skarels case SO_SNDTIMEO: 84844721Skarels so->so_snd.sb_timeo = val; 84941908Skarels break; 85018369Skarels case SO_RCVTIMEO: 85144721Skarels so->so_rcv.sb_timeo = val; 85218369Skarels break; 85318369Skarels } 85418369Skarels break; 85544721Skarels } 85618369Skarels 85718369Skarels default: 85818369Skarels error = ENOPROTOOPT; 85918369Skarels break; 86017158Ssam } 861*51022Ssklower m = 0; 86250942Ssklower if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) 86350942Ssklower (void) ((*so->so_proto->pr_ctloutput) 86450942Ssklower (PRCO_SETOPT, so, level, optname, &m0)); 86510267Ssam } 86617158Ssam bad: 86717158Ssam if (m) 86817158Ssam (void) m_free(m); 86917158Ssam return (error); 87010267Ssam } 87110267Ssam 87217158Ssam sogetopt(so, level, optname, mp) 87312757Ssam register struct socket *so; 87410267Ssam int level, optname; 87517158Ssam struct mbuf **mp; 87617158Ssam { 87712757Ssam register struct mbuf *m; 87810267Ssam 87918369Skarels if (level != SOL_SOCKET) { 88018369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 88118369Skarels return ((*so->so_proto->pr_ctloutput) 88218369Skarels (PRCO_GETOPT, so, level, optname, mp)); 88345515Skarels } else 88418369Skarels return (ENOPROTOOPT); 88518369Skarels } else { 88617158Ssam m = m_get(M_WAIT, MT_SOOPTS); 88725502Skarels m->m_len = sizeof (int); 88825502Skarels 88918369Skarels switch (optname) { 89017158Ssam 89118369Skarels case SO_LINGER: 89218369Skarels m->m_len = sizeof (struct linger); 89318369Skarels mtod(m, struct linger *)->l_onoff = 89418369Skarels so->so_options & SO_LINGER; 89518369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 89618369Skarels break; 89710267Ssam 89818369Skarels case SO_USELOOPBACK: 89918369Skarels case SO_DONTROUTE: 90018369Skarels case SO_DEBUG: 90118369Skarels case SO_KEEPALIVE: 90218369Skarels case SO_REUSEADDR: 90318369Skarels case SO_BROADCAST: 90427191Skarels case SO_OOBINLINE: 90518369Skarels *mtod(m, int *) = so->so_options & optname; 90618369Skarels break; 90718369Skarels 90825502Skarels case SO_TYPE: 90925502Skarels *mtod(m, int *) = so->so_type; 91025502Skarels break; 91125502Skarels 91224768Skarels case SO_ERROR: 91324768Skarels *mtod(m, int *) = so->so_error; 91424768Skarels so->so_error = 0; 91524768Skarels break; 91624768Skarels 91718369Skarels case SO_SNDBUF: 91818369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 91918369Skarels break; 92018369Skarels 92118369Skarels case SO_RCVBUF: 92218369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 92318369Skarels break; 92418369Skarels 92518369Skarels case SO_SNDLOWAT: 92618369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 92718369Skarels break; 92818369Skarels 92918369Skarels case SO_RCVLOWAT: 93018369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 93118369Skarels break; 93218369Skarels 93318369Skarels case SO_SNDTIMEO: 93444721Skarels case SO_RCVTIMEO: 93544721Skarels { 93644721Skarels int val = (optname == SO_SNDTIMEO ? 93744721Skarels so->so_snd.sb_timeo : so->so_rcv.sb_timeo); 93818369Skarels 93944721Skarels m->m_len = sizeof(struct timeval); 94044721Skarels mtod(m, struct timeval *)->tv_sec = val / hz; 94144721Skarels mtod(m, struct timeval *)->tv_usec = 94244721Skarels (val % hz) / tick; 94318369Skarels break; 94444721Skarels } 94518369Skarels 94618369Skarels default: 94726362Skarels (void)m_free(m); 94818369Skarels return (ENOPROTOOPT); 94918369Skarels } 95018369Skarels *mp = m; 95118369Skarels return (0); 95210267Ssam } 95310267Ssam } 95410267Ssam 9555423Swnj sohasoutofband(so) 95612757Ssam register struct socket *so; 9575423Swnj { 95823233Skarels struct proc *p; 9595423Swnj 96037478Ssklower if (so->so_pgid < 0) 96137478Ssklower gsignal(-so->so_pgid, SIGURG); 96237478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 96323233Skarels psignal(p, SIGURG); 96424768Skarels if (so->so_rcv.sb_sel) { 96524768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 96624768Skarels so->so_rcv.sb_sel = 0; 96724768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 96824768Skarels } 9695423Swnj } 970