1*21108Skarels /* uipc_socket.c 6.11 85/05/27 */ 24786Swnj 317102Sbloom #include "param.h" 417102Sbloom #include "systm.h" 517102Sbloom #include "dir.h" 617102Sbloom #include "user.h" 717102Sbloom #include "proc.h" 817102Sbloom #include "file.h" 917102Sbloom #include "inode.h" 1017102Sbloom #include "buf.h" 1117102Sbloom #include "mbuf.h" 1217102Sbloom #include "un.h" 1317102Sbloom #include "domain.h" 1417102Sbloom #include "protosw.h" 1517102Sbloom #include "socket.h" 1617102Sbloom #include "socketvar.h" 1717102Sbloom #include "stat.h" 1817102Sbloom #include "ioctl.h" 1917102Sbloom #include "uio.h" 206355Ssam #include "../net/route.h" 2112757Ssam #include "../netinet/in.h" 2211571Ssam #include "../net/if.h" 234786Swnj 244786Swnj /* 258300Sroot * Socket operation routines. 268300Sroot * These routines are called by the routines in 278300Sroot * sys_socket.c or from a system process, and 288300Sroot * implement the semantics of socket operations by 298300Sroot * switching out to the protocol specific routines. 3012757Ssam * 3112757Ssam * TODO: 3212757Ssam * sostat 3312757Ssam * test socketpair 3412757Ssam * PR_RIGHTS 3512757Ssam * clean up select, async 3612757Ssam * out-of-band is a kludge 374786Swnj */ 388594Sroot /*ARGSUSED*/ 3910267Ssam socreate(dom, aso, type, proto) 404786Swnj struct socket **aso; 4112757Ssam register int type; 4212757Ssam int proto; 434786Swnj { 444786Swnj register struct protosw *prp; 454786Swnj register struct socket *so; 4612757Ssam register struct mbuf *m; 4712757Ssam register int error; 484786Swnj 494890Swnj if (proto) 509168Ssam prp = pffindproto(dom, proto); 514890Swnj else 529168Ssam prp = pffindtype(dom, type); 534890Swnj if (prp == 0) 544890Swnj return (EPROTONOSUPPORT); 558300Sroot if (prp->pr_type != type) 568300Sroot return (EPROTOTYPE); 579635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 584786Swnj so = mtod(m, struct socket *); 5912757Ssam so->so_options = 0; 606214Swnj so->so_state = 0; 619168Ssam so->so_type = type; 626214Swnj if (u.u_uid == 0) 636214Swnj so->so_state = SS_PRIV; 644786Swnj so->so_proto = prp; 6512757Ssam error = 6612757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 6712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 684979Swnj if (error) { 697507Sroot so->so_state |= SS_NOFDREF; 707180Swnj sofree(so); 714890Swnj return (error); 724786Swnj } 734786Swnj *aso = so; 744786Swnj return (0); 754786Swnj } 764786Swnj 7710267Ssam sobind(so, nam) 788300Sroot struct socket *so; 798300Sroot struct mbuf *nam; 808300Sroot { 818300Sroot int s = splnet(); 828300Sroot int error; 838300Sroot 848300Sroot error = 8512757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8612757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 878300Sroot splx(s); 888300Sroot return (error); 898300Sroot } 908300Sroot 918300Sroot solisten(so, backlog) 9212757Ssam register struct socket *so; 938300Sroot int backlog; 948300Sroot { 9512757Ssam int s = splnet(), error; 968300Sroot 9712757Ssam error = 9812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 9912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1008300Sroot if (error) { 1018300Sroot splx(s); 1028300Sroot return (error); 1038300Sroot } 1048300Sroot if (so->so_q == 0) { 1058300Sroot so->so_q = so; 1068300Sroot so->so_q0 = so; 1078300Sroot so->so_options |= SO_ACCEPTCONN; 1088300Sroot } 1098300Sroot if (backlog < 0) 1108300Sroot backlog = 0; 11110137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 11212493Ssam splx(s); 1138300Sroot return (0); 1148300Sroot } 1158300Sroot 1164916Swnj sofree(so) 11712757Ssam register struct socket *so; 1184916Swnj { 1194916Swnj 1207507Sroot if (so->so_head) { 1217507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1227507Sroot panic("sofree dq"); 1237507Sroot so->so_head = 0; 1247507Sroot } 1257507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1264950Swnj return; 1274950Swnj sbrelease(&so->so_snd); 12812757Ssam sorflush(so); 1294971Swnj (void) m_free(dtom(so)); 1304916Swnj } 1314916Swnj 1324786Swnj /* 1334890Swnj * Close a socket on last file table reference removal. 1344890Swnj * Initiate disconnect if connected. 1354890Swnj * Free socket when disconnect complete. 1364829Swnj */ 13712757Ssam soclose(so) 1384829Swnj register struct socket *so; 1394829Swnj { 1404890Swnj int s = splnet(); /* conservative */ 1418713Sroot int error; 1424829Swnj 1437507Sroot if (so->so_options & SO_ACCEPTCONN) { 1447507Sroot while (so->so_q0 != so) 14510399Ssam (void) soabort(so->so_q0); 1467507Sroot while (so->so_q != so) 14710399Ssam (void) soabort(so->so_q); 1487507Sroot } 1494890Swnj if (so->so_pcb == 0) 1504890Swnj goto discard; 1514890Swnj if (so->so_state & SS_ISCONNECTED) { 1524890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1538725Sroot error = sodisconnect(so, (struct mbuf *)0); 15412757Ssam if (error) 15512757Ssam goto drop; 1564890Swnj } 15710267Ssam if (so->so_options & SO_LINGER) { 1585281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15912757Ssam (so->so_state & SS_NBIO)) 16012757Ssam goto drop; 1615281Sroot while (so->so_state & SS_ISCONNECTED) 1625281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1634890Swnj } 1644890Swnj } 1655580Sroot drop: 1666880Ssam if (so->so_pcb) { 16712757Ssam int error2 = 16812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17012757Ssam if (error == 0) 17112757Ssam error = error2; 1726880Ssam } 1734890Swnj discard: 17410399Ssam if (so->so_state & SS_NOFDREF) 17510399Ssam panic("soclose: NOFDREF"); 1767507Sroot so->so_state |= SS_NOFDREF; 1774950Swnj sofree(so); 1784890Swnj splx(s); 17912757Ssam return (error); 1804829Swnj } 1814829Swnj 18210399Ssam /* 18310399Ssam * Must be called at splnet... 18410399Ssam */ 18510399Ssam soabort(so) 18610399Ssam struct socket *so; 18710399Ssam { 18810399Ssam 18912757Ssam return ( 19012757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19210399Ssam } 19310399Ssam 19410267Ssam soaccept(so, nam) 19512757Ssam register struct socket *so; 1968300Sroot struct mbuf *nam; 1974927Swnj { 1984927Swnj int s = splnet(); 1994927Swnj int error; 2004927Swnj 20110399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20210399Ssam panic("soaccept: !NOFDREF"); 20310267Ssam so->so_state &= ~SS_NOFDREF; 2048300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20512757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2064927Swnj splx(s); 2074927Swnj return (error); 2084927Swnj } 2094927Swnj 21010267Ssam soconnect(so, nam) 21112757Ssam register struct socket *so; 2128300Sroot struct mbuf *nam; 2134786Swnj { 2144890Swnj int s = splnet(); 2154890Swnj int error; 2164786Swnj 2174890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2184890Swnj error = EISCONN; 2194890Swnj goto bad; 2204890Swnj } 2218300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22212757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2234890Swnj bad: 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 2418300Sroot sodisconnect(so, nam) 24212757Ssam register struct socket *so; 2438300Sroot struct mbuf *nam; 2444786Swnj { 2454890Swnj int s = splnet(); 2464890Swnj int error; 2474786Swnj 2484890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2494890Swnj error = ENOTCONN; 2504890Swnj goto bad; 2514890Swnj } 2524890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2534890Swnj error = EALREADY; 2544890Swnj goto bad; 2554890Swnj } 2568300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25712757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2584890Swnj bad: 2594890Swnj splx(s); 2604890Swnj return (error); 2614786Swnj } 2624786Swnj 2634786Swnj /* 2644890Swnj * Send on a socket. 2654890Swnj * If send must go all at once and message is larger than 2664890Swnj * send buffering, then hard error. 2674890Swnj * Lock against other senders. 2684890Swnj * If must go all at once and not enough room now, then 2694890Swnj * inform user that this would block and do nothing. 27016412Skarels * Otherwise, if nonblocking, send as much as possible. 2714786Swnj */ 27212757Ssam sosend(so, nam, uio, flags, rights) 2734786Swnj register struct socket *so; 2748300Sroot struct mbuf *nam; 27512757Ssam register struct uio *uio; 2768319Sroot int flags; 27712757Ssam struct mbuf *rights; 2784786Swnj { 2794890Swnj struct mbuf *top = 0; 28016412Skarels register struct mbuf *m, **mp; 28112757Ssam register int space; 28216412Skarels int len, error = 0, s, dontroute, first = 1; 2834786Swnj 2847827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2854890Swnj return (EMSGSIZE); 28612757Ssam dontroute = 28712757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 28812757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 28916412Skarels u.u_ru.ru_msgsnd++; 29016412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 29116412Skarels 2926419Sroot restart: 2934890Swnj sblock(&so->so_snd); 29416412Skarels do { 29516412Skarels s = splnet(); 296*21108Skarels if (so->so_state & SS_CANTSENDMORE) 29716412Skarels snderr(EPIPE); 29816412Skarels if (so->so_error) { 29916412Skarels error = so->so_error; 30016412Skarels so->so_error = 0; /* ??? */ 30116412Skarels splx(s); 30216412Skarels goto release; 30316412Skarels } 30416412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 30516412Skarels if (so->so_proto->pr_flags & PR_CONNREQUIRED) 30616412Skarels snderr(ENOTCONN); 30716412Skarels if (nam == 0) 30816412Skarels snderr(EDESTADDRREQ); 30916412Skarels } 31016412Skarels if (flags & MSG_OOB) 31116412Skarels space = 1024; 31216412Skarels else { 31316412Skarels space = sbspace(&so->so_snd); 31416412Skarels if (space <= 0 || 31516992Skarels (sosendallatonce(so) && space < uio->uio_resid) || 31616992Skarels (uio->uio_resid >= CLBYTES && space < CLBYTES && 31716992Skarels so->so_snd.sb_cc >= CLBYTES && 31816992Skarels (so->so_state & SS_NBIO) == 0)) { 31916412Skarels if (so->so_state & SS_NBIO) { 32016412Skarels if (first) 32116412Skarels error = EWOULDBLOCK; 32216412Skarels splx(s); 32316412Skarels goto release; 32416412Skarels } 32516412Skarels sbunlock(&so->so_snd); 32616412Skarels sbwait(&so->so_snd); 32716412Skarels splx(s); 32816412Skarels goto restart; 32916412Skarels } 33016412Skarels } 33116412Skarels splx(s); 33216412Skarels mp = ⊤ 333*21108Skarels while (space > 0) { 33416412Skarels register struct iovec *iov = uio->uio_iov; 3354890Swnj 33616412Skarels MGET(m, M_WAIT, MT_DATA); 33716412Skarels if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 33816412Skarels register struct mbuf *p; 33916412Skarels MCLGET(p, 1); 34016412Skarels if (p == 0) 34116412Skarels goto nopages; 34216412Skarels m->m_off = (int)p - (int)m; 34316412Skarels len = CLBYTES; 34416412Skarels } else { 34516412Skarels nopages: 34616412Skarels len = MIN(MLEN, iov->iov_len); 34716412Skarels } 34816412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 34916412Skarels m->m_len = len; 35016412Skarels *mp = m; 35116412Skarels if (error) 35216412Skarels goto release; 35316412Skarels mp = &m->m_next; 35416412Skarels space -= len; 355*21108Skarels if (uio->uio_resid <= 0) 356*21108Skarels break; 357*21108Skarels while (uio->uio_iov->iov_len == 0) { 358*21108Skarels uio->uio_iov++; 359*21108Skarels uio->uio_iovcnt--; 360*21108Skarels if (uio->uio_iovcnt <= 0) 361*21108Skarels panic("sosend"); 362*21108Skarels } 36316412Skarels } 364*21108Skarels if (dontroute) 365*21108Skarels so->so_options |= SO_DONTROUTE; 366*21108Skarels s = splnet(); /* XXX */ 367*21108Skarels error = (*so->so_proto->pr_usrreq)(so, 368*21108Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 369*21108Skarels top, (caddr_t)nam, rights); 370*21108Skarels splx(s); 371*21108Skarels if (dontroute) 372*21108Skarels so->so_options &= ~SO_DONTROUTE; 3736419Sroot top = 0; 37416412Skarels first = 0; 37514781Ssam if (error) 37616412Skarels break; 37716412Skarels } while (uio->uio_resid); 3784890Swnj 3794786Swnj release: 3804890Swnj sbunlock(&so->so_snd); 3816419Sroot if (top) 3826419Sroot m_freem(top); 383*21108Skarels if (error == EPIPE) 384*21108Skarels psignal(u.u_procp, SIGPIPE); 3854786Swnj return (error); 3864786Swnj } 3874786Swnj 38812757Ssam soreceive(so, aname, uio, flags, rightsp) 3894786Swnj register struct socket *so; 3908300Sroot struct mbuf **aname; 39112757Ssam register struct uio *uio; 3928319Sroot int flags; 39312757Ssam struct mbuf **rightsp; 3944786Swnj { 3954786Swnj register struct mbuf *m, *n; 39616993Skarels register int len, error = 0, s, tomark; 39712757Ssam struct protosw *pr = so->so_proto; 39816993Skarels struct mbuf *nextrecord; 39912757Ssam int moff; 4004786Swnj 40112757Ssam if (rightsp) 40212757Ssam *rightsp = 0; 40312757Ssam if (aname) 40412757Ssam *aname = 0; 40512757Ssam if (flags & MSG_OOB) { 4069635Ssam m = m_get(M_WAIT, MT_DATA); 40712757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 40812757Ssam m, (struct mbuf *)0, (struct mbuf *)0); 4098594Sroot if (error) 41010137Ssam goto bad; 4118319Sroot do { 41210137Ssam len = uio->uio_resid; 4138319Sroot if (len > m->m_len) 4148319Sroot len = m->m_len; 4158594Sroot error = 4168793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4178319Sroot m = m_free(m); 4188594Sroot } while (uio->uio_resid && error == 0 && m); 41910137Ssam bad: 4208319Sroot if (m) 4218771Sroot m_freem(m); 4228594Sroot return (error); 4238319Sroot } 4248319Sroot 4254890Swnj restart: 4264890Swnj sblock(&so->so_rcv); 4278835Sroot s = splnet(); 4284890Swnj 4294890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4304786Swnj if (so->so_rcv.sb_cc == 0) { 4315168Swnj if (so->so_error) { 4325168Swnj error = so->so_error; 4335168Swnj so->so_error = 0; 4345168Swnj splx(s); 4355168Swnj goto release; 4365168Swnj } 4374890Swnj if (so->so_state & SS_CANTRCVMORE) { 4384890Swnj splx(s); 4394890Swnj goto release; 4404890Swnj } 4415015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4425015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4435015Sroot rcverr(ENOTCONN); 4446214Swnj if (so->so_state & SS_NBIO) 4455168Swnj rcverr(EWOULDBLOCK); 4464890Swnj sbunlock(&so->so_rcv); 4474971Swnj sbwait(&so->so_rcv); 4485012Swnj splx(s); 4494890Swnj goto restart; 4504786Swnj } 4518041Sroot u.u_ru.ru_msgrcv++; 4524829Swnj m = so->so_rcv.sb_mb; 45312757Ssam if (pr->pr_flags & PR_ADDR) { 45416993Skarels if (m == 0 || m->m_type != MT_SONAME) 45516993Skarels panic("receive 1a"); 45616993Skarels if (flags & MSG_PEEK) { 45716993Skarels if (aname) 4588319Sroot *aname = m_copy(m, 0, m->m_len); 45916993Skarels else 46016993Skarels m = m->m_act; 46116993Skarels } else { 46216993Skarels if (aname) { 46316993Skarels *aname = m; 46416993Skarels sbfree(&so->so_rcv, m); 46516993Skarels if(m->m_next) panic("receive 1b"); 46616993Skarels so->so_rcv.sb_mb = m = m->m_act; 46710137Ssam } else 46816993Skarels m = sbdroprecord(&so->so_rcv); 46916993Skarels } 47016993Skarels } 47116993Skarels if (m && m->m_type == MT_RIGHTS) { 47216993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 47312757Ssam panic("receive 2a"); 47416993Skarels if (flags & MSG_PEEK) { 47516993Skarels if (rightsp) 47612757Ssam *rightsp = m_copy(m, 0, m->m_len); 47716993Skarels else 47816993Skarels m = m->m_act; 47916993Skarels } else { 48016993Skarels if (rightsp) { 48116993Skarels *rightsp = m; 48216993Skarels sbfree(&so->so_rcv, m); 48316993Skarels if(m->m_next) panic("receive 2b"); 48416993Skarels so->so_rcv.sb_mb = m = m->m_act; 48516993Skarels } else 48616993Skarels m = sbdroprecord(&so->so_rcv); 48712757Ssam } 4884890Swnj } 48916993Skarels if (m == 0) 49016993Skarels panic("receive 3"); 4918319Sroot moff = 0; 4928319Sroot tomark = so->so_oobmark; 49316993Skarels while (m && uio->uio_resid > 0 && error == 0) { 4947827Sroot len = uio->uio_resid; 4957747Sroot so->so_state &= ~SS_RCVATMARK; 4968319Sroot if (tomark && len > tomark) 4978319Sroot len = tomark; 4988548Sroot if (moff+len > m->m_len - moff) 4998319Sroot len = m->m_len - moff; 5004786Swnj splx(s); 5018594Sroot error = 5028793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5034786Swnj s = splnet(); 5044786Swnj if (len == m->m_len) { 50516993Skarels if ((flags & MSG_PEEK) == 0) { 50616993Skarels nextrecord = m->m_act; 5078319Sroot sbfree(&so->so_rcv, m); 5088319Sroot MFREE(m, n); 50916993Skarels if (m = n) 51016993Skarels m->m_act = nextrecord; 5118548Sroot so->so_rcv.sb_mb = m; 51216993Skarels } else 51316993Skarels m = m->m_next; 5148319Sroot moff = 0; 5154786Swnj } else { 51612757Ssam if (flags & MSG_PEEK) 5178319Sroot moff += len; 5188319Sroot else { 5198319Sroot m->m_off += len; 5208319Sroot m->m_len -= len; 5218319Sroot so->so_rcv.sb_cc -= len; 5228319Sroot } 5234786Swnj } 52412757Ssam if ((flags & MSG_PEEK) == 0 && so->so_oobmark) { 5257747Sroot so->so_oobmark -= len; 5267747Sroot if (so->so_oobmark == 0) { 5277747Sroot so->so_state |= SS_RCVATMARK; 5287747Sroot break; 5297747Sroot } 5307747Sroot } 5318319Sroot if (tomark) { 5328319Sroot tomark -= len; 5338319Sroot if (tomark == 0) 5348319Sroot break; 5358319Sroot } 53616993Skarels } 53716993Skarels if ((flags & MSG_PEEK) == 0) { 53816993Skarels if (m == 0) 53916993Skarels so->so_rcv.sb_mb = nextrecord; 54016993Skarels else if (pr->pr_flags & PR_ATOMIC) 54116993Skarels (void) sbdroprecord(&so->so_rcv); 54216993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 54316993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 54416993Skarels (struct mbuf *)0, (struct mbuf *)0); 54516993Skarels } 5464890Swnj release: 5474916Swnj sbunlock(&so->so_rcv); 54816993Skarels if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize) 54916993Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 5504890Swnj splx(s); 5514916Swnj return (error); 5524786Swnj } 5534786Swnj 55410267Ssam soshutdown(so, how) 55512757Ssam register struct socket *so; 55612757Ssam register int how; 55710267Ssam { 55812757Ssam register struct protosw *pr = so->so_proto; 55910267Ssam 56010267Ssam how++; 56112757Ssam if (how & FREAD) 56212757Ssam sorflush(so); 56310267Ssam if (how & FWRITE) 56412757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 56512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 56610267Ssam return (0); 56710267Ssam } 56810267Ssam 56912757Ssam sorflush(so) 57012757Ssam register struct socket *so; 57112757Ssam { 57212757Ssam register struct sockbuf *sb = &so->so_rcv; 57312757Ssam register struct protosw *pr = so->so_proto; 57412757Ssam register int s; 57512757Ssam struct sockbuf asb; 57612757Ssam 57712757Ssam sblock(sb); 57812757Ssam s = splimp(); 57912757Ssam socantrcvmore(so); 58012757Ssam sbunlock(sb); 58112757Ssam asb = *sb; 58212757Ssam bzero((caddr_t)sb, sizeof (*sb)); 58312757Ssam splx(s); 58416993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 58516993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 58612757Ssam sbrelease(&asb); 58712757Ssam } 58812757Ssam 58918553Skarels sosetopt(so, level, optname, m0) 59012757Ssam register struct socket *so; 59110267Ssam int level, optname; 59218553Skarels struct mbuf *m0; 59310267Ssam { 59417158Ssam int error = 0; 59518553Skarels register struct mbuf *m = m0; 59610267Ssam 59717158Ssam if (level != SOL_SOCKET) { 59818369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 59918369Skarels return ((*so->so_proto->pr_ctloutput) 60018553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 60118369Skarels error = ENOPROTOOPT; 60218369Skarels } else { 60318369Skarels switch (optname) { 60410267Ssam 60518369Skarels case SO_LINGER: 60618369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 60718369Skarels error = EINVAL; 60818369Skarels goto bad; 60918369Skarels } 61018369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 61118369Skarels /* fall thru... */ 61217158Ssam 61318369Skarels case SO_DEBUG: 61418369Skarels case SO_KEEPALIVE: 61518369Skarels case SO_DONTROUTE: 61618369Skarels case SO_USELOOPBACK: 61718369Skarels case SO_BROADCAST: 61818369Skarels case SO_REUSEADDR: 61918369Skarels if (m == NULL || m->m_len < sizeof (int)) { 62018369Skarels error = EINVAL; 62118369Skarels goto bad; 62218369Skarels } 62318369Skarels if (*mtod(m, int *)) 62418369Skarels so->so_options |= optname; 62518369Skarels else 62618369Skarels so->so_options &= ~optname; 62718369Skarels break; 62818369Skarels 62918369Skarels case SO_SNDBUF: 63018369Skarels case SO_RCVBUF: 63118369Skarels case SO_SNDLOWAT: 63218369Skarels case SO_RCVLOWAT: 63318369Skarels case SO_SNDTIMEO: 63418369Skarels case SO_RCVTIMEO: 63518369Skarels if (m == NULL || m->m_len < sizeof (int)) { 63618369Skarels error = EINVAL; 63718369Skarels goto bad; 63818369Skarels } 63918369Skarels switch (optname) { 64018369Skarels 64118369Skarels case SO_SNDBUF: 64218369Skarels case SO_RCVBUF: 64318369Skarels if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : 64418369Skarels &so->so_rcv, *mtod(m, int *)) == 0) { 64518369Skarels error = ENOBUFS; 64618369Skarels goto bad; 64718369Skarels } 64818369Skarels break; 64918369Skarels 65018369Skarels case SO_SNDLOWAT: 65118369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 65218369Skarels break; 65318369Skarels case SO_RCVLOWAT: 65418369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 65518369Skarels break; 65618369Skarels case SO_SNDTIMEO: 65718369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 65818369Skarels break; 65918369Skarels case SO_RCVTIMEO: 66018369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 66118369Skarels break; 66218369Skarels } 66318369Skarels break; 66418369Skarels 66518369Skarels default: 66618369Skarels error = ENOPROTOOPT; 66718369Skarels break; 66817158Ssam } 66910267Ssam } 67017158Ssam bad: 67117158Ssam if (m) 67217158Ssam (void) m_free(m); 67317158Ssam return (error); 67410267Ssam } 67510267Ssam 67617158Ssam sogetopt(so, level, optname, mp) 67712757Ssam register struct socket *so; 67810267Ssam int level, optname; 67917158Ssam struct mbuf **mp; 68017158Ssam { 68112757Ssam register struct mbuf *m; 68210267Ssam 68318369Skarels if (level != SOL_SOCKET) { 68418369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 68518369Skarels return ((*so->so_proto->pr_ctloutput) 68618369Skarels (PRCO_GETOPT, so, level, optname, mp)); 68718369Skarels } else 68818369Skarels return (ENOPROTOOPT); 68918369Skarels } else { 69017158Ssam m = m_get(M_WAIT, MT_SOOPTS); 69118369Skarels switch (optname) { 69217158Ssam 69318369Skarels case SO_LINGER: 69418369Skarels m->m_len = sizeof (struct linger); 69518369Skarels mtod(m, struct linger *)->l_onoff = 69618369Skarels so->so_options & SO_LINGER; 69718369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 69818369Skarels break; 69910267Ssam 70018369Skarels case SO_USELOOPBACK: 70118369Skarels case SO_DONTROUTE: 70218369Skarels case SO_DEBUG: 70318369Skarels case SO_KEEPALIVE: 70418369Skarels case SO_REUSEADDR: 70518369Skarels case SO_BROADCAST: 70618369Skarels m->m_len = sizeof (int); 70718369Skarels *mtod(m, int *) = so->so_options & optname; 70818369Skarels break; 70918369Skarels 71018369Skarels case SO_SNDBUF: 71118369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 71218369Skarels break; 71318369Skarels 71418369Skarels case SO_RCVBUF: 71518369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 71618369Skarels break; 71718369Skarels 71818369Skarels case SO_SNDLOWAT: 71918369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 72018369Skarels break; 72118369Skarels 72218369Skarels case SO_RCVLOWAT: 72318369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 72418369Skarels break; 72518369Skarels 72618369Skarels case SO_SNDTIMEO: 72718369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 72818369Skarels break; 72918369Skarels 73018369Skarels case SO_RCVTIMEO: 73118369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 73218369Skarels break; 73318369Skarels 73418369Skarels default: 73518369Skarels m_free(m); 73618369Skarels return (ENOPROTOOPT); 73718369Skarels } 73818369Skarels *mp = m; 73918369Skarels return (0); 74010267Ssam } 74110267Ssam } 74210267Ssam 7435423Swnj sohasoutofband(so) 74412757Ssam register struct socket *so; 7455423Swnj { 7465423Swnj 7475423Swnj if (so->so_pgrp == 0) 7485423Swnj return; 7495423Swnj if (so->so_pgrp > 0) 7505423Swnj gsignal(so->so_pgrp, SIGURG); 7515429Swnj else { 7525429Swnj struct proc *p = pfind(-so->so_pgrp); 7535429Swnj 7545429Swnj if (p) 7555429Swnj psignal(p, SIGURG); 7565429Swnj } 7575423Swnj } 758