1*21783Skarels /* uipc_socket.c 6.13 85/06/03 */ 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 * test socketpair 3321767Skarels * clean up async 3412757Ssam * out-of-band is a kludge 354786Swnj */ 368594Sroot /*ARGSUSED*/ 3710267Ssam socreate(dom, aso, type, proto) 384786Swnj struct socket **aso; 3912757Ssam register int type; 4012757Ssam int proto; 414786Swnj { 424786Swnj register struct protosw *prp; 434786Swnj register struct socket *so; 4412757Ssam register struct mbuf *m; 4512757Ssam register int error; 464786Swnj 474890Swnj if (proto) 4821767Skarels prp = pffindproto(dom, proto, type); 494890Swnj else 509168Ssam prp = pffindtype(dom, type); 514890Swnj if (prp == 0) 524890Swnj return (EPROTONOSUPPORT); 538300Sroot if (prp->pr_type != type) 548300Sroot return (EPROTOTYPE); 559635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 564786Swnj so = mtod(m, struct socket *); 5712757Ssam so->so_options = 0; 586214Swnj so->so_state = 0; 599168Ssam so->so_type = type; 606214Swnj if (u.u_uid == 0) 616214Swnj so->so_state = SS_PRIV; 624786Swnj so->so_proto = prp; 6312757Ssam error = 6412757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 6521767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 664979Swnj if (error) { 677507Sroot so->so_state |= SS_NOFDREF; 687180Swnj sofree(so); 694890Swnj return (error); 704786Swnj } 714786Swnj *aso = so; 724786Swnj return (0); 734786Swnj } 744786Swnj 7510267Ssam sobind(so, nam) 768300Sroot struct socket *so; 778300Sroot struct mbuf *nam; 788300Sroot { 798300Sroot int s = splnet(); 808300Sroot int error; 818300Sroot 828300Sroot error = 8312757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8412757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 858300Sroot splx(s); 868300Sroot return (error); 878300Sroot } 888300Sroot 898300Sroot solisten(so, backlog) 9012757Ssam register struct socket *so; 918300Sroot int backlog; 928300Sroot { 9312757Ssam int s = splnet(), error; 948300Sroot 9512757Ssam error = 9612757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 9712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 988300Sroot if (error) { 998300Sroot splx(s); 1008300Sroot return (error); 1018300Sroot } 1028300Sroot if (so->so_q == 0) { 1038300Sroot so->so_q = so; 1048300Sroot so->so_q0 = so; 1058300Sroot so->so_options |= SO_ACCEPTCONN; 1068300Sroot } 1078300Sroot if (backlog < 0) 1088300Sroot backlog = 0; 10910137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 11012493Ssam splx(s); 1118300Sroot return (0); 1128300Sroot } 1138300Sroot 1144916Swnj sofree(so) 11512757Ssam register struct socket *so; 1164916Swnj { 1174916Swnj 1187507Sroot if (so->so_head) { 1197507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1207507Sroot panic("sofree dq"); 1217507Sroot so->so_head = 0; 1227507Sroot } 1237507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1244950Swnj return; 1254950Swnj sbrelease(&so->so_snd); 12612757Ssam sorflush(so); 1274971Swnj (void) m_free(dtom(so)); 1284916Swnj } 1294916Swnj 1304786Swnj /* 1314890Swnj * Close a socket on last file table reference removal. 1324890Swnj * Initiate disconnect if connected. 1334890Swnj * Free socket when disconnect complete. 1344829Swnj */ 13512757Ssam soclose(so) 1364829Swnj register struct socket *so; 1374829Swnj { 1384890Swnj int s = splnet(); /* conservative */ 1398713Sroot int error; 1404829Swnj 1417507Sroot if (so->so_options & SO_ACCEPTCONN) { 1427507Sroot while (so->so_q0 != so) 14310399Ssam (void) soabort(so->so_q0); 1447507Sroot while (so->so_q != so) 14510399Ssam (void) soabort(so->so_q); 1467507Sroot } 1474890Swnj if (so->so_pcb == 0) 1484890Swnj goto discard; 1494890Swnj if (so->so_state & SS_ISCONNECTED) { 1504890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1518725Sroot error = sodisconnect(so, (struct mbuf *)0); 15212757Ssam if (error) 15312757Ssam goto drop; 1544890Swnj } 15510267Ssam if (so->so_options & SO_LINGER) { 1565281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15712757Ssam (so->so_state & SS_NBIO)) 15812757Ssam goto drop; 1595281Sroot while (so->so_state & SS_ISCONNECTED) 1605281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1614890Swnj } 1624890Swnj } 1635580Sroot drop: 1646880Ssam if (so->so_pcb) { 16512757Ssam int error2 = 16612757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 16812757Ssam if (error == 0) 16912757Ssam error = error2; 1706880Ssam } 1714890Swnj discard: 17210399Ssam if (so->so_state & SS_NOFDREF) 17310399Ssam panic("soclose: NOFDREF"); 1747507Sroot so->so_state |= SS_NOFDREF; 1754950Swnj sofree(so); 1764890Swnj splx(s); 17712757Ssam return (error); 1784829Swnj } 1794829Swnj 18010399Ssam /* 18110399Ssam * Must be called at splnet... 18210399Ssam */ 18310399Ssam soabort(so) 18410399Ssam struct socket *so; 18510399Ssam { 18610399Ssam 18712757Ssam return ( 18812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 18912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19010399Ssam } 19110399Ssam 19210267Ssam soaccept(so, nam) 19312757Ssam register struct socket *so; 1948300Sroot struct mbuf *nam; 1954927Swnj { 1964927Swnj int s = splnet(); 1974927Swnj int error; 1984927Swnj 19910399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20010399Ssam panic("soaccept: !NOFDREF"); 20110267Ssam so->so_state &= ~SS_NOFDREF; 2028300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20312757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2044927Swnj splx(s); 2054927Swnj return (error); 2064927Swnj } 2074927Swnj 20810267Ssam soconnect(so, nam) 20912757Ssam register struct socket *so; 2108300Sroot struct mbuf *nam; 2114786Swnj { 2124890Swnj int s = splnet(); 2134890Swnj int error; 2144786Swnj 2154890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2164890Swnj error = EISCONN; 2174890Swnj goto bad; 2184890Swnj } 2198300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22012757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2214890Swnj bad: 2224890Swnj splx(s); 2234890Swnj return (error); 2244786Swnj } 2254786Swnj 22612757Ssam soconnect2(so1, so2) 22712757Ssam register struct socket *so1; 22812757Ssam struct socket *so2; 22912757Ssam { 23012757Ssam int s = splnet(); 23112757Ssam int error; 23212757Ssam 23313113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23413113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 23512757Ssam splx(s); 23612757Ssam return (error); 23712757Ssam } 23812757Ssam 2398300Sroot sodisconnect(so, nam) 24012757Ssam register struct socket *so; 2418300Sroot struct mbuf *nam; 2424786Swnj { 2434890Swnj int s = splnet(); 2444890Swnj int error; 2454786Swnj 2464890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2474890Swnj error = ENOTCONN; 2484890Swnj goto bad; 2494890Swnj } 2504890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2514890Swnj error = EALREADY; 2524890Swnj goto bad; 2534890Swnj } 2548300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25512757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2564890Swnj bad: 2574890Swnj splx(s); 2584890Swnj return (error); 2594786Swnj } 2604786Swnj 2614786Swnj /* 2624890Swnj * Send on a socket. 2634890Swnj * If send must go all at once and message is larger than 2644890Swnj * send buffering, then hard error. 2654890Swnj * Lock against other senders. 2664890Swnj * If must go all at once and not enough room now, then 2674890Swnj * inform user that this would block and do nothing. 26816412Skarels * Otherwise, if nonblocking, send as much as possible. 2694786Swnj */ 27012757Ssam sosend(so, nam, uio, flags, rights) 2714786Swnj register struct socket *so; 2728300Sroot struct mbuf *nam; 27312757Ssam register struct uio *uio; 2748319Sroot int flags; 27512757Ssam struct mbuf *rights; 2764786Swnj { 2774890Swnj struct mbuf *top = 0; 27816412Skarels register struct mbuf *m, **mp; 27912757Ssam register int space; 28016412Skarels int len, error = 0, s, dontroute, first = 1; 2814786Swnj 2827827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2834890Swnj return (EMSGSIZE); 28412757Ssam dontroute = 28512757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 28612757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 28716412Skarels u.u_ru.ru_msgsnd++; 28816412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 28916412Skarels 2906419Sroot restart: 2914890Swnj sblock(&so->so_snd); 29216412Skarels do { 29316412Skarels s = splnet(); 29421108Skarels if (so->so_state & SS_CANTSENDMORE) 29516412Skarels snderr(EPIPE); 29616412Skarels if (so->so_error) { 29716412Skarels error = so->so_error; 29816412Skarels so->so_error = 0; /* ??? */ 29916412Skarels splx(s); 30016412Skarels goto release; 30116412Skarels } 30216412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 30316412Skarels if (so->so_proto->pr_flags & PR_CONNREQUIRED) 30416412Skarels snderr(ENOTCONN); 30516412Skarels if (nam == 0) 30616412Skarels snderr(EDESTADDRREQ); 30716412Skarels } 30816412Skarels if (flags & MSG_OOB) 30916412Skarels space = 1024; 31016412Skarels else { 31116412Skarels space = sbspace(&so->so_snd); 31216412Skarels if (space <= 0 || 31316992Skarels (sosendallatonce(so) && space < uio->uio_resid) || 31416992Skarels (uio->uio_resid >= CLBYTES && space < CLBYTES && 31516992Skarels so->so_snd.sb_cc >= CLBYTES && 31616992Skarels (so->so_state & SS_NBIO) == 0)) { 31716412Skarels if (so->so_state & SS_NBIO) { 31816412Skarels if (first) 31916412Skarels error = EWOULDBLOCK; 32016412Skarels splx(s); 32116412Skarels goto release; 32216412Skarels } 32316412Skarels sbunlock(&so->so_snd); 32416412Skarels sbwait(&so->so_snd); 32516412Skarels splx(s); 32616412Skarels goto restart; 32716412Skarels } 32816412Skarels } 32916412Skarels splx(s); 33016412Skarels mp = ⊤ 33121108Skarels while (space > 0) { 33216412Skarels register struct iovec *iov = uio->uio_iov; 3334890Swnj 33416412Skarels MGET(m, M_WAIT, MT_DATA); 33521767Skarels if (iov->iov_len >= NBPG && space >= CLBYTES) { 33616412Skarels register struct mbuf *p; 33716412Skarels MCLGET(p, 1); 33816412Skarels if (p == 0) 33916412Skarels goto nopages; 34016412Skarels m->m_off = (int)p - (int)m; 34121767Skarels len = min(CLBYTES, iov->iov_len); 34221767Skarels space -= CLBYTES; 34316412Skarels } else { 34416412Skarels nopages: 34516412Skarels len = MIN(MLEN, iov->iov_len); 34621767Skarels space -= 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; 35421108Skarels if (uio->uio_resid <= 0) 35521108Skarels break; 35621108Skarels while (uio->uio_iov->iov_len == 0) { 35721108Skarels uio->uio_iov++; 35821108Skarels uio->uio_iovcnt--; 35921108Skarels if (uio->uio_iovcnt <= 0) 36021108Skarels panic("sosend"); 36121108Skarels } 36216412Skarels } 36321108Skarels if (dontroute) 36421108Skarels so->so_options |= SO_DONTROUTE; 36521108Skarels s = splnet(); /* XXX */ 36621108Skarels error = (*so->so_proto->pr_usrreq)(so, 36721108Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 36821108Skarels top, (caddr_t)nam, rights); 36921108Skarels splx(s); 37021108Skarels if (dontroute) 37121108Skarels so->so_options &= ~SO_DONTROUTE; 37221767Skarels rights = 0; 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); 38321108Skarels if (error == EPIPE) 38421108Skarels 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 } 489*21783Skarels if (m == 0 || (m->m_type != MT_DATA && m->m_type != MT_HEADER)) 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; 49821767Skarels if (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(); 50421767Skarels if (len == m->m_len - moff) { 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