123421Smckusick /* 223421Smckusick * Copyright (c) 1982 Regents of the University of California. 323421Smckusick * All rights reserved. The Berkeley software License Agreement 423421Smckusick * specifies the terms and conditions for redistribution. 523421Smckusick * 6*24518Skarels * @(#)uipc_socket.c 6.16 (Berkeley) 09/04/85 723421Smckusick */ 84786Swnj 917102Sbloom #include "param.h" 1017102Sbloom #include "systm.h" 1117102Sbloom #include "dir.h" 1217102Sbloom #include "user.h" 1317102Sbloom #include "proc.h" 1417102Sbloom #include "file.h" 1517102Sbloom #include "inode.h" 1617102Sbloom #include "buf.h" 1717102Sbloom #include "mbuf.h" 1817102Sbloom #include "un.h" 1917102Sbloom #include "domain.h" 2017102Sbloom #include "protosw.h" 2117102Sbloom #include "socket.h" 2217102Sbloom #include "socketvar.h" 2317102Sbloom #include "stat.h" 2417102Sbloom #include "ioctl.h" 2517102Sbloom #include "uio.h" 266355Ssam #include "../net/route.h" 2712757Ssam #include "../netinet/in.h" 2811571Ssam #include "../net/if.h" 294786Swnj 304786Swnj /* 318300Sroot * Socket operation routines. 328300Sroot * These routines are called by the routines in 338300Sroot * sys_socket.c or from a system process, and 348300Sroot * implement the semantics of socket operations by 358300Sroot * switching out to the protocol specific routines. 3612757Ssam * 3712757Ssam * TODO: 3812757Ssam * test socketpair 3921767Skarels * clean up async 4012757Ssam * out-of-band is a kludge 414786Swnj */ 428594Sroot /*ARGSUSED*/ 4310267Ssam socreate(dom, aso, type, proto) 444786Swnj struct socket **aso; 4512757Ssam register int type; 4612757Ssam int proto; 474786Swnj { 484786Swnj register struct protosw *prp; 494786Swnj register struct socket *so; 5012757Ssam register struct mbuf *m; 5112757Ssam register int error; 524786Swnj 534890Swnj if (proto) 5421767Skarels prp = pffindproto(dom, proto, type); 554890Swnj else 569168Ssam prp = pffindtype(dom, type); 574890Swnj if (prp == 0) 584890Swnj return (EPROTONOSUPPORT); 598300Sroot if (prp->pr_type != type) 608300Sroot return (EPROTOTYPE); 619635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 624786Swnj so = mtod(m, struct socket *); 6312757Ssam so->so_options = 0; 646214Swnj so->so_state = 0; 659168Ssam so->so_type = type; 666214Swnj if (u.u_uid == 0) 676214Swnj so->so_state = SS_PRIV; 684786Swnj so->so_proto = prp; 6912757Ssam error = 7012757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 7121767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 724979Swnj if (error) { 737507Sroot so->so_state |= SS_NOFDREF; 747180Swnj sofree(so); 754890Swnj return (error); 764786Swnj } 774786Swnj *aso = so; 784786Swnj return (0); 794786Swnj } 804786Swnj 8110267Ssam sobind(so, nam) 828300Sroot struct socket *so; 838300Sroot struct mbuf *nam; 848300Sroot { 858300Sroot int s = splnet(); 868300Sroot int error; 878300Sroot 888300Sroot error = 8912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 9012757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 918300Sroot splx(s); 928300Sroot return (error); 938300Sroot } 948300Sroot 958300Sroot solisten(so, backlog) 9612757Ssam register struct socket *so; 978300Sroot int backlog; 988300Sroot { 9912757Ssam int s = splnet(), error; 1008300Sroot 10112757Ssam error = 10212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 10312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1048300Sroot if (error) { 1058300Sroot splx(s); 1068300Sroot return (error); 1078300Sroot } 1088300Sroot if (so->so_q == 0) { 1098300Sroot so->so_q = so; 1108300Sroot so->so_q0 = so; 1118300Sroot so->so_options |= SO_ACCEPTCONN; 1128300Sroot } 1138300Sroot if (backlog < 0) 1148300Sroot backlog = 0; 11510137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 11612493Ssam splx(s); 1178300Sroot return (0); 1188300Sroot } 1198300Sroot 1204916Swnj sofree(so) 12112757Ssam register struct socket *so; 1224916Swnj { 1234916Swnj 1247507Sroot if (so->so_head) { 1257507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1267507Sroot panic("sofree dq"); 1277507Sroot so->so_head = 0; 1287507Sroot } 1297507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1304950Swnj return; 1314950Swnj sbrelease(&so->so_snd); 13212757Ssam sorflush(so); 1334971Swnj (void) m_free(dtom(so)); 1344916Swnj } 1354916Swnj 1364786Swnj /* 1374890Swnj * Close a socket on last file table reference removal. 1384890Swnj * Initiate disconnect if connected. 1394890Swnj * Free socket when disconnect complete. 1404829Swnj */ 14112757Ssam soclose(so) 1424829Swnj register struct socket *so; 1434829Swnj { 1444890Swnj int s = splnet(); /* conservative */ 1458713Sroot int error; 1464829Swnj 1477507Sroot if (so->so_options & SO_ACCEPTCONN) { 1487507Sroot while (so->so_q0 != so) 14910399Ssam (void) soabort(so->so_q0); 1507507Sroot while (so->so_q != so) 15110399Ssam (void) soabort(so->so_q); 1527507Sroot } 1534890Swnj if (so->so_pcb == 0) 1544890Swnj goto discard; 1554890Swnj if (so->so_state & SS_ISCONNECTED) { 1564890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1578725Sroot error = sodisconnect(so, (struct mbuf *)0); 15812757Ssam if (error) 15912757Ssam goto drop; 1604890Swnj } 16110267Ssam if (so->so_options & SO_LINGER) { 1625281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 16312757Ssam (so->so_state & SS_NBIO)) 16412757Ssam goto drop; 1655281Sroot while (so->so_state & SS_ISCONNECTED) 1665281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1674890Swnj } 1684890Swnj } 1695580Sroot drop: 1706880Ssam if (so->so_pcb) { 17112757Ssam int error2 = 17212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17412757Ssam if (error == 0) 17512757Ssam error = error2; 1766880Ssam } 1774890Swnj discard: 17810399Ssam if (so->so_state & SS_NOFDREF) 17910399Ssam panic("soclose: NOFDREF"); 1807507Sroot so->so_state |= SS_NOFDREF; 1814950Swnj sofree(so); 1824890Swnj splx(s); 18312757Ssam return (error); 1844829Swnj } 1854829Swnj 18610399Ssam /* 18710399Ssam * Must be called at splnet... 18810399Ssam */ 18910399Ssam soabort(so) 19010399Ssam struct socket *so; 19110399Ssam { 19210399Ssam 19312757Ssam return ( 19412757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19610399Ssam } 19710399Ssam 19810267Ssam soaccept(so, nam) 19912757Ssam register struct socket *so; 2008300Sroot struct mbuf *nam; 2014927Swnj { 2024927Swnj int s = splnet(); 2034927Swnj int error; 2044927Swnj 20510399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20610399Ssam panic("soaccept: !NOFDREF"); 20710267Ssam so->so_state &= ~SS_NOFDREF; 2088300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20912757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2104927Swnj splx(s); 2114927Swnj return (error); 2124927Swnj } 2134927Swnj 21410267Ssam soconnect(so, nam) 21512757Ssam register struct socket *so; 2168300Sroot struct mbuf *nam; 2174786Swnj { 2184890Swnj int s = splnet(); 2194890Swnj int error; 2204786Swnj 2214890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2224890Swnj error = EISCONN; 2234890Swnj goto bad; 2244890Swnj } 2258300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22612757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2274890Swnj bad: 2284890Swnj splx(s); 2294890Swnj return (error); 2304786Swnj } 2314786Swnj 23212757Ssam soconnect2(so1, so2) 23312757Ssam register struct socket *so1; 23412757Ssam struct socket *so2; 23512757Ssam { 23612757Ssam int s = splnet(); 23712757Ssam int error; 23812757Ssam 23913113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24013113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24112757Ssam splx(s); 24212757Ssam return (error); 24312757Ssam } 24412757Ssam 2458300Sroot sodisconnect(so, nam) 24612757Ssam register struct socket *so; 2478300Sroot struct mbuf *nam; 2484786Swnj { 2494890Swnj int s = splnet(); 2504890Swnj int error; 2514786Swnj 2524890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2534890Swnj error = ENOTCONN; 2544890Swnj goto bad; 2554890Swnj } 2564890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2574890Swnj error = EALREADY; 2584890Swnj goto bad; 2594890Swnj } 2608300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26112757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2624890Swnj bad: 2634890Swnj splx(s); 2644890Swnj return (error); 2654786Swnj } 2664786Swnj 2674786Swnj /* 2684890Swnj * Send on a socket. 2694890Swnj * If send must go all at once and message is larger than 2704890Swnj * send buffering, then hard error. 2714890Swnj * Lock against other senders. 2724890Swnj * If must go all at once and not enough room now, then 2734890Swnj * inform user that this would block and do nothing. 27416412Skarels * Otherwise, if nonblocking, send as much as possible. 2754786Swnj */ 27612757Ssam sosend(so, nam, uio, flags, rights) 2774786Swnj register struct socket *so; 2788300Sroot struct mbuf *nam; 27912757Ssam register struct uio *uio; 2808319Sroot int flags; 28112757Ssam struct mbuf *rights; 2824786Swnj { 2834890Swnj struct mbuf *top = 0; 28416412Skarels register struct mbuf *m, **mp; 28512757Ssam register int space; 28616412Skarels int len, error = 0, s, dontroute, first = 1; 2874786Swnj 2887827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2894890Swnj return (EMSGSIZE); 29012757Ssam dontroute = 29112757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29212757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 29316412Skarels u.u_ru.ru_msgsnd++; 29416412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 29516412Skarels 2966419Sroot restart: 2974890Swnj sblock(&so->so_snd); 29816412Skarels do { 29916412Skarels s = splnet(); 30021108Skarels if (so->so_state & SS_CANTSENDMORE) 30116412Skarels snderr(EPIPE); 30216412Skarels if (so->so_error) { 30316412Skarels error = so->so_error; 30416412Skarels so->so_error = 0; /* ??? */ 30516412Skarels splx(s); 30616412Skarels goto release; 30716412Skarels } 30816412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 30916412Skarels if (so->so_proto->pr_flags & PR_CONNREQUIRED) 31016412Skarels snderr(ENOTCONN); 31116412Skarels if (nam == 0) 31216412Skarels snderr(EDESTADDRREQ); 31316412Skarels } 31416412Skarels if (flags & MSG_OOB) 31516412Skarels space = 1024; 31616412Skarels else { 31716412Skarels space = sbspace(&so->so_snd); 31816412Skarels if (space <= 0 || 31916992Skarels (sosendallatonce(so) && space < uio->uio_resid) || 32016992Skarels (uio->uio_resid >= CLBYTES && space < CLBYTES && 32116992Skarels so->so_snd.sb_cc >= CLBYTES && 32216992Skarels (so->so_state & SS_NBIO) == 0)) { 32316412Skarels if (so->so_state & SS_NBIO) { 32416412Skarels if (first) 32516412Skarels error = EWOULDBLOCK; 32616412Skarels splx(s); 32716412Skarels goto release; 32816412Skarels } 32916412Skarels sbunlock(&so->so_snd); 33016412Skarels sbwait(&so->so_snd); 33116412Skarels splx(s); 33216412Skarels goto restart; 33316412Skarels } 33416412Skarels } 33516412Skarels splx(s); 33616412Skarels mp = ⊤ 33721108Skarels while (space > 0) { 33816412Skarels register struct iovec *iov = uio->uio_iov; 3394890Swnj 34016412Skarels MGET(m, M_WAIT, MT_DATA); 34121767Skarels if (iov->iov_len >= NBPG && space >= CLBYTES) { 34216412Skarels register struct mbuf *p; 34316412Skarels MCLGET(p, 1); 34416412Skarels if (p == 0) 34516412Skarels goto nopages; 34616412Skarels m->m_off = (int)p - (int)m; 347*24518Skarels len = MIN(CLBYTES, iov->iov_len); 34821767Skarels space -= CLBYTES; 34916412Skarels } else { 35016412Skarels nopages: 35116412Skarels len = MIN(MLEN, iov->iov_len); 35221767Skarels space -= len; 35316412Skarels } 35416412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 35516412Skarels m->m_len = len; 35616412Skarels *mp = m; 35716412Skarels if (error) 35816412Skarels goto release; 35916412Skarels mp = &m->m_next; 36021108Skarels if (uio->uio_resid <= 0) 36121108Skarels break; 36221108Skarels while (uio->uio_iov->iov_len == 0) { 36321108Skarels uio->uio_iov++; 36421108Skarels uio->uio_iovcnt--; 36521108Skarels if (uio->uio_iovcnt <= 0) 36621108Skarels panic("sosend"); 36721108Skarels } 36816412Skarels } 36921108Skarels if (dontroute) 37021108Skarels so->so_options |= SO_DONTROUTE; 37121108Skarels s = splnet(); /* XXX */ 37221108Skarels error = (*so->so_proto->pr_usrreq)(so, 37321108Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 37421108Skarels top, (caddr_t)nam, rights); 37521108Skarels splx(s); 37621108Skarels if (dontroute) 37721108Skarels so->so_options &= ~SO_DONTROUTE; 37821767Skarels rights = 0; 3796419Sroot top = 0; 38016412Skarels first = 0; 38114781Ssam if (error) 38216412Skarels break; 38316412Skarels } while (uio->uio_resid); 3844890Swnj 3854786Swnj release: 3864890Swnj sbunlock(&so->so_snd); 3876419Sroot if (top) 3886419Sroot m_freem(top); 38921108Skarels if (error == EPIPE) 39021108Skarels psignal(u.u_procp, SIGPIPE); 3914786Swnj return (error); 3924786Swnj } 3934786Swnj 39412757Ssam soreceive(so, aname, uio, flags, rightsp) 3954786Swnj register struct socket *so; 3968300Sroot struct mbuf **aname; 39712757Ssam register struct uio *uio; 3988319Sroot int flags; 39912757Ssam struct mbuf **rightsp; 4004786Swnj { 4014786Swnj register struct mbuf *m, *n; 40216993Skarels register int len, error = 0, s, tomark; 40312757Ssam struct protosw *pr = so->so_proto; 40416993Skarels struct mbuf *nextrecord; 40512757Ssam int moff; 4064786Swnj 40712757Ssam if (rightsp) 40812757Ssam *rightsp = 0; 40912757Ssam if (aname) 41012757Ssam *aname = 0; 41112757Ssam if (flags & MSG_OOB) { 4129635Ssam m = m_get(M_WAIT, MT_DATA); 41312757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 41412757Ssam m, (struct mbuf *)0, (struct mbuf *)0); 4158594Sroot if (error) 41610137Ssam goto bad; 4178319Sroot do { 41810137Ssam len = uio->uio_resid; 4198319Sroot if (len > m->m_len) 4208319Sroot len = m->m_len; 4218594Sroot error = 4228793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4238319Sroot m = m_free(m); 4248594Sroot } while (uio->uio_resid && error == 0 && m); 42510137Ssam bad: 4268319Sroot if (m) 4278771Sroot m_freem(m); 4288594Sroot return (error); 4298319Sroot } 4308319Sroot 4314890Swnj restart: 4324890Swnj sblock(&so->so_rcv); 4338835Sroot s = splnet(); 4344890Swnj 4354890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4364786Swnj if (so->so_rcv.sb_cc == 0) { 4375168Swnj if (so->so_error) { 4385168Swnj error = so->so_error; 4395168Swnj so->so_error = 0; 4405168Swnj splx(s); 4415168Swnj goto release; 4425168Swnj } 4434890Swnj if (so->so_state & SS_CANTRCVMORE) { 4444890Swnj splx(s); 4454890Swnj goto release; 4464890Swnj } 4475015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4485015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4495015Sroot rcverr(ENOTCONN); 4506214Swnj if (so->so_state & SS_NBIO) 4515168Swnj rcverr(EWOULDBLOCK); 4524890Swnj sbunlock(&so->so_rcv); 4534971Swnj sbwait(&so->so_rcv); 4545012Swnj splx(s); 4554890Swnj goto restart; 4564786Swnj } 4578041Sroot u.u_ru.ru_msgrcv++; 4584829Swnj m = so->so_rcv.sb_mb; 45912757Ssam if (pr->pr_flags & PR_ADDR) { 46016993Skarels if (m == 0 || m->m_type != MT_SONAME) 46116993Skarels panic("receive 1a"); 46216993Skarels if (flags & MSG_PEEK) { 46316993Skarels if (aname) 4648319Sroot *aname = m_copy(m, 0, m->m_len); 46516993Skarels else 46616993Skarels m = m->m_act; 46716993Skarels } else { 46816993Skarels if (aname) { 46916993Skarels *aname = m; 47016993Skarels sbfree(&so->so_rcv, m); 47116993Skarels if(m->m_next) panic("receive 1b"); 47216993Skarels so->so_rcv.sb_mb = m = m->m_act; 47310137Ssam } else 47416993Skarels m = sbdroprecord(&so->so_rcv); 47516993Skarels } 47616993Skarels } 47716993Skarels if (m && m->m_type == MT_RIGHTS) { 47816993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 47912757Ssam panic("receive 2a"); 48016993Skarels if (flags & MSG_PEEK) { 48116993Skarels if (rightsp) 48212757Ssam *rightsp = m_copy(m, 0, m->m_len); 48316993Skarels else 48416993Skarels m = m->m_act; 48516993Skarels } else { 48616993Skarels if (rightsp) { 48716993Skarels *rightsp = m; 48816993Skarels sbfree(&so->so_rcv, m); 48916993Skarels if(m->m_next) panic("receive 2b"); 49016993Skarels so->so_rcv.sb_mb = m = m->m_act; 49116993Skarels } else 49216993Skarels m = sbdroprecord(&so->so_rcv); 49312757Ssam } 4944890Swnj } 49521783Skarels if (m == 0 || (m->m_type != MT_DATA && m->m_type != MT_HEADER)) 49616993Skarels panic("receive 3"); 4978319Sroot moff = 0; 4988319Sroot tomark = so->so_oobmark; 49916993Skarels while (m && uio->uio_resid > 0 && error == 0) { 5007827Sroot len = uio->uio_resid; 5017747Sroot so->so_state &= ~SS_RCVATMARK; 5028319Sroot if (tomark && len > tomark) 5038319Sroot len = tomark; 50421767Skarels if (len > m->m_len - moff) 5058319Sroot len = m->m_len - moff; 5064786Swnj splx(s); 5078594Sroot error = 5088793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5094786Swnj s = splnet(); 51021767Skarels if (len == m->m_len - moff) { 51116993Skarels if ((flags & MSG_PEEK) == 0) { 51216993Skarels nextrecord = m->m_act; 5138319Sroot sbfree(&so->so_rcv, m); 5148319Sroot MFREE(m, n); 51516993Skarels if (m = n) 51616993Skarels m->m_act = nextrecord; 5178548Sroot so->so_rcv.sb_mb = m; 51816993Skarels } else 51916993Skarels m = m->m_next; 5208319Sroot moff = 0; 5214786Swnj } else { 52212757Ssam if (flags & MSG_PEEK) 5238319Sroot moff += len; 5248319Sroot else { 5258319Sroot m->m_off += len; 5268319Sroot m->m_len -= len; 5278319Sroot so->so_rcv.sb_cc -= len; 5288319Sroot } 5294786Swnj } 53012757Ssam if ((flags & MSG_PEEK) == 0 && so->so_oobmark) { 5317747Sroot so->so_oobmark -= len; 5327747Sroot if (so->so_oobmark == 0) { 5337747Sroot so->so_state |= SS_RCVATMARK; 5347747Sroot break; 5357747Sroot } 5367747Sroot } 5378319Sroot if (tomark) { 5388319Sroot tomark -= len; 5398319Sroot if (tomark == 0) 5408319Sroot break; 5418319Sroot } 54216993Skarels } 54316993Skarels if ((flags & MSG_PEEK) == 0) { 54416993Skarels if (m == 0) 54516993Skarels so->so_rcv.sb_mb = nextrecord; 54616993Skarels else if (pr->pr_flags & PR_ATOMIC) 54716993Skarels (void) sbdroprecord(&so->so_rcv); 54816993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 54916993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 55016993Skarels (struct mbuf *)0, (struct mbuf *)0); 55116993Skarels } 5524890Swnj release: 5534916Swnj sbunlock(&so->so_rcv); 55416993Skarels if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize) 55516993Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 5564890Swnj splx(s); 5574916Swnj return (error); 5584786Swnj } 5594786Swnj 56010267Ssam soshutdown(so, how) 56112757Ssam register struct socket *so; 56212757Ssam register int how; 56310267Ssam { 56412757Ssam register struct protosw *pr = so->so_proto; 56510267Ssam 56610267Ssam how++; 56712757Ssam if (how & FREAD) 56812757Ssam sorflush(so); 56910267Ssam if (how & FWRITE) 57012757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 57112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 57210267Ssam return (0); 57310267Ssam } 57410267Ssam 57512757Ssam sorflush(so) 57612757Ssam register struct socket *so; 57712757Ssam { 57812757Ssam register struct sockbuf *sb = &so->so_rcv; 57912757Ssam register struct protosw *pr = so->so_proto; 58012757Ssam register int s; 58112757Ssam struct sockbuf asb; 58212757Ssam 58312757Ssam sblock(sb); 58412757Ssam s = splimp(); 58512757Ssam socantrcvmore(so); 58612757Ssam sbunlock(sb); 58712757Ssam asb = *sb; 58812757Ssam bzero((caddr_t)sb, sizeof (*sb)); 58912757Ssam splx(s); 59016993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 59116993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 59212757Ssam sbrelease(&asb); 59312757Ssam } 59412757Ssam 59518553Skarels sosetopt(so, level, optname, m0) 59612757Ssam register struct socket *so; 59710267Ssam int level, optname; 59818553Skarels struct mbuf *m0; 59910267Ssam { 60017158Ssam int error = 0; 60118553Skarels register struct mbuf *m = m0; 60210267Ssam 60317158Ssam if (level != SOL_SOCKET) { 60418369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 60518369Skarels return ((*so->so_proto->pr_ctloutput) 60618553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 60718369Skarels error = ENOPROTOOPT; 60818369Skarels } else { 60918369Skarels switch (optname) { 61010267Ssam 61118369Skarels case SO_LINGER: 61218369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 61318369Skarels error = EINVAL; 61418369Skarels goto bad; 61518369Skarels } 61618369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 61718369Skarels /* fall thru... */ 61817158Ssam 61918369Skarels case SO_DEBUG: 62018369Skarels case SO_KEEPALIVE: 62118369Skarels case SO_DONTROUTE: 62218369Skarels case SO_USELOOPBACK: 62318369Skarels case SO_BROADCAST: 62418369Skarels case SO_REUSEADDR: 62518369Skarels if (m == NULL || m->m_len < sizeof (int)) { 62618369Skarels error = EINVAL; 62718369Skarels goto bad; 62818369Skarels } 62918369Skarels if (*mtod(m, int *)) 63018369Skarels so->so_options |= optname; 63118369Skarels else 63218369Skarels so->so_options &= ~optname; 63318369Skarels break; 63418369Skarels 63518369Skarels case SO_SNDBUF: 63618369Skarels case SO_RCVBUF: 63718369Skarels case SO_SNDLOWAT: 63818369Skarels case SO_RCVLOWAT: 63918369Skarels case SO_SNDTIMEO: 64018369Skarels case SO_RCVTIMEO: 64118369Skarels if (m == NULL || m->m_len < sizeof (int)) { 64218369Skarels error = EINVAL; 64318369Skarels goto bad; 64418369Skarels } 64518369Skarels switch (optname) { 64618369Skarels 64718369Skarels case SO_SNDBUF: 64818369Skarels case SO_RCVBUF: 64918369Skarels if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : 65018369Skarels &so->so_rcv, *mtod(m, int *)) == 0) { 65118369Skarels error = ENOBUFS; 65218369Skarels goto bad; 65318369Skarels } 65418369Skarels break; 65518369Skarels 65618369Skarels case SO_SNDLOWAT: 65718369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 65818369Skarels break; 65918369Skarels case SO_RCVLOWAT: 66018369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 66118369Skarels break; 66218369Skarels case SO_SNDTIMEO: 66318369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 66418369Skarels break; 66518369Skarels case SO_RCVTIMEO: 66618369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 66718369Skarels break; 66818369Skarels } 66918369Skarels break; 67018369Skarels 67118369Skarels default: 67218369Skarels error = ENOPROTOOPT; 67318369Skarels break; 67417158Ssam } 67510267Ssam } 67617158Ssam bad: 67717158Ssam if (m) 67817158Ssam (void) m_free(m); 67917158Ssam return (error); 68010267Ssam } 68110267Ssam 68217158Ssam sogetopt(so, level, optname, mp) 68312757Ssam register struct socket *so; 68410267Ssam int level, optname; 68517158Ssam struct mbuf **mp; 68617158Ssam { 68712757Ssam register struct mbuf *m; 68810267Ssam 68918369Skarels if (level != SOL_SOCKET) { 69018369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 69118369Skarels return ((*so->so_proto->pr_ctloutput) 69218369Skarels (PRCO_GETOPT, so, level, optname, mp)); 69318369Skarels } else 69418369Skarels return (ENOPROTOOPT); 69518369Skarels } else { 69617158Ssam m = m_get(M_WAIT, MT_SOOPTS); 69718369Skarels switch (optname) { 69817158Ssam 69918369Skarels case SO_LINGER: 70018369Skarels m->m_len = sizeof (struct linger); 70118369Skarels mtod(m, struct linger *)->l_onoff = 70218369Skarels so->so_options & SO_LINGER; 70318369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 70418369Skarels break; 70510267Ssam 70618369Skarels case SO_USELOOPBACK: 70718369Skarels case SO_DONTROUTE: 70818369Skarels case SO_DEBUG: 70918369Skarels case SO_KEEPALIVE: 71018369Skarels case SO_REUSEADDR: 71118369Skarels case SO_BROADCAST: 71218369Skarels m->m_len = sizeof (int); 71318369Skarels *mtod(m, int *) = so->so_options & optname; 71418369Skarels break; 71518369Skarels 71618369Skarels case SO_SNDBUF: 71718369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 71818369Skarels break; 71918369Skarels 72018369Skarels case SO_RCVBUF: 72118369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 72218369Skarels break; 72318369Skarels 72418369Skarels case SO_SNDLOWAT: 72518369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 72618369Skarels break; 72718369Skarels 72818369Skarels case SO_RCVLOWAT: 72918369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 73018369Skarels break; 73118369Skarels 73218369Skarels case SO_SNDTIMEO: 73318369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 73418369Skarels break; 73518369Skarels 73618369Skarels case SO_RCVTIMEO: 73718369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 73818369Skarels break; 73918369Skarels 74018369Skarels default: 74118369Skarels m_free(m); 74218369Skarels return (ENOPROTOOPT); 74318369Skarels } 74418369Skarels *mp = m; 74518369Skarels return (0); 74610267Ssam } 74710267Ssam } 74810267Ssam 7495423Swnj sohasoutofband(so) 75012757Ssam register struct socket *so; 7515423Swnj { 75223233Skarels struct proc *p; 7535423Swnj 75423233Skarels if (so->so_pgrp < 0) 75523233Skarels gsignal(-so->so_pgrp, SIGURG); 75623233Skarels else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) 75723233Skarels psignal(p, SIGURG); 7585423Swnj } 759