1*18369Skarels /* uipc_socket.c 6.9 85/03/18 */ 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 if (m == 0) 594786Swnj return (ENOBUFS); 604786Swnj so = mtod(m, struct socket *); 6112757Ssam so->so_options = 0; 626214Swnj so->so_state = 0; 639168Ssam so->so_type = type; 646214Swnj if (u.u_uid == 0) 656214Swnj so->so_state = SS_PRIV; 664786Swnj so->so_proto = prp; 6712757Ssam error = 6812757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 6912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 704979Swnj if (error) { 717507Sroot so->so_state |= SS_NOFDREF; 727180Swnj sofree(so); 734890Swnj return (error); 744786Swnj } 754786Swnj *aso = so; 764786Swnj return (0); 774786Swnj } 784786Swnj 7910267Ssam sobind(so, nam) 808300Sroot struct socket *so; 818300Sroot struct mbuf *nam; 828300Sroot { 838300Sroot int s = splnet(); 848300Sroot int error; 858300Sroot 868300Sroot error = 8712757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8812757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 898300Sroot splx(s); 908300Sroot return (error); 918300Sroot } 928300Sroot 938300Sroot solisten(so, backlog) 9412757Ssam register struct socket *so; 958300Sroot int backlog; 968300Sroot { 9712757Ssam int s = splnet(), error; 988300Sroot 9912757Ssam error = 10012757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 10112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1028300Sroot if (error) { 1038300Sroot splx(s); 1048300Sroot return (error); 1058300Sroot } 1068300Sroot if (so->so_q == 0) { 1078300Sroot so->so_q = so; 1088300Sroot so->so_q0 = so; 1098300Sroot so->so_options |= SO_ACCEPTCONN; 1108300Sroot } 1118300Sroot if (backlog < 0) 1128300Sroot backlog = 0; 11310137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 11412493Ssam splx(s); 1158300Sroot return (0); 1168300Sroot } 1178300Sroot 1184916Swnj sofree(so) 11912757Ssam register struct socket *so; 1204916Swnj { 1214916Swnj 1227507Sroot if (so->so_head) { 1237507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1247507Sroot panic("sofree dq"); 1257507Sroot so->so_head = 0; 1267507Sroot } 1277507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1284950Swnj return; 1294950Swnj sbrelease(&so->so_snd); 13012757Ssam sorflush(so); 1314971Swnj (void) m_free(dtom(so)); 1324916Swnj } 1334916Swnj 1344786Swnj /* 1354890Swnj * Close a socket on last file table reference removal. 1364890Swnj * Initiate disconnect if connected. 1374890Swnj * Free socket when disconnect complete. 1384829Swnj */ 13912757Ssam soclose(so) 1404829Swnj register struct socket *so; 1414829Swnj { 1424890Swnj int s = splnet(); /* conservative */ 1438713Sroot int error; 1444829Swnj 1457507Sroot if (so->so_options & SO_ACCEPTCONN) { 1467507Sroot while (so->so_q0 != so) 14710399Ssam (void) soabort(so->so_q0); 1487507Sroot while (so->so_q != so) 14910399Ssam (void) soabort(so->so_q); 1507507Sroot } 1514890Swnj if (so->so_pcb == 0) 1524890Swnj goto discard; 1534890Swnj if (so->so_state & SS_ISCONNECTED) { 1544890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1558725Sroot error = sodisconnect(so, (struct mbuf *)0); 15612757Ssam if (error) 15712757Ssam goto drop; 1584890Swnj } 15910267Ssam if (so->so_options & SO_LINGER) { 1605281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 16112757Ssam (so->so_state & SS_NBIO)) 16212757Ssam goto drop; 1635281Sroot while (so->so_state & SS_ISCONNECTED) 1645281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1654890Swnj } 1664890Swnj } 1675580Sroot drop: 1686880Ssam if (so->so_pcb) { 16912757Ssam int error2 = 17012757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17212757Ssam if (error == 0) 17312757Ssam error = error2; 1746880Ssam } 1754890Swnj discard: 17610399Ssam if (so->so_state & SS_NOFDREF) 17710399Ssam panic("soclose: NOFDREF"); 1787507Sroot so->so_state |= SS_NOFDREF; 1794950Swnj sofree(so); 1804890Swnj splx(s); 18112757Ssam return (error); 1824829Swnj } 1834829Swnj 18410399Ssam /* 18510399Ssam * Must be called at splnet... 18610399Ssam */ 18710399Ssam soabort(so) 18810399Ssam struct socket *so; 18910399Ssam { 19010399Ssam 19112757Ssam return ( 19212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19410399Ssam } 19510399Ssam 19610267Ssam soaccept(so, nam) 19712757Ssam register struct socket *so; 1988300Sroot struct mbuf *nam; 1994927Swnj { 2004927Swnj int s = splnet(); 2014927Swnj int error; 2024927Swnj 20310399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20410399Ssam panic("soaccept: !NOFDREF"); 20510267Ssam so->so_state &= ~SS_NOFDREF; 2068300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20712757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2084927Swnj splx(s); 2094927Swnj return (error); 2104927Swnj } 2114927Swnj 21210267Ssam soconnect(so, nam) 21312757Ssam register struct socket *so; 2148300Sroot struct mbuf *nam; 2154786Swnj { 2164890Swnj int s = splnet(); 2174890Swnj int error; 2184786Swnj 2194890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2204890Swnj error = EISCONN; 2214890Swnj goto bad; 2224890Swnj } 2238300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22412757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2254890Swnj bad: 2264890Swnj splx(s); 2274890Swnj return (error); 2284786Swnj } 2294786Swnj 23012757Ssam soconnect2(so1, so2) 23112757Ssam register struct socket *so1; 23212757Ssam struct socket *so2; 23312757Ssam { 23412757Ssam int s = splnet(); 23512757Ssam int error; 23612757Ssam 23713113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23813113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 23912757Ssam splx(s); 24012757Ssam return (error); 24112757Ssam } 24212757Ssam 2438300Sroot sodisconnect(so, nam) 24412757Ssam register struct socket *so; 2458300Sroot struct mbuf *nam; 2464786Swnj { 2474890Swnj int s = splnet(); 2484890Swnj int error; 2494786Swnj 2504890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2514890Swnj error = ENOTCONN; 2524890Swnj goto bad; 2534890Swnj } 2544890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2554890Swnj error = EALREADY; 2564890Swnj goto bad; 2574890Swnj } 2588300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25912757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2604890Swnj bad: 2614890Swnj splx(s); 2624890Swnj return (error); 2634786Swnj } 2644786Swnj 2654786Swnj /* 2664890Swnj * Send on a socket. 2674890Swnj * If send must go all at once and message is larger than 2684890Swnj * send buffering, then hard error. 2694890Swnj * Lock against other senders. 2704890Swnj * If must go all at once and not enough room now, then 2714890Swnj * inform user that this would block and do nothing. 27216412Skarels * Otherwise, if nonblocking, send as much as possible. 2734786Swnj */ 27412757Ssam sosend(so, nam, uio, flags, rights) 2754786Swnj register struct socket *so; 2768300Sroot struct mbuf *nam; 27712757Ssam register struct uio *uio; 2788319Sroot int flags; 27912757Ssam struct mbuf *rights; 2804786Swnj { 2814890Swnj struct mbuf *top = 0; 28216412Skarels register struct mbuf *m, **mp; 28312757Ssam register int space; 28416412Skarels int len, error = 0, s, dontroute, first = 1; 2854786Swnj 2867827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2874890Swnj return (EMSGSIZE); 28812757Ssam dontroute = 28912757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29012757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 29116412Skarels u.u_ru.ru_msgsnd++; 29216412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 29316412Skarels 2946419Sroot restart: 2954890Swnj sblock(&so->so_snd); 29616412Skarels do { 29716412Skarels s = splnet(); 29816412Skarels if (so->so_state & SS_CANTSENDMORE) { 29916412Skarels psignal(u.u_procp, SIGPIPE); 30016412Skarels snderr(EPIPE); 30116412Skarels } 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 = ⊤ 33716412Skarels while (uio->uio_resid > 0 && space > 0) { 33816412Skarels register struct iovec *iov = uio->uio_iov; 3394890Swnj 34016412Skarels if (iov->iov_len == 0) { 34116412Skarels uio->uio_iov++; 34216412Skarels uio->uio_iovcnt--; 34316412Skarels if (uio->uio_iovcnt < 0) 34416412Skarels panic("sosend"); 34516412Skarels continue; 34616412Skarels } 34716412Skarels MGET(m, M_WAIT, MT_DATA); 348*18369Skarels if (m == NULL) { 349*18369Skarels error = ENOBUFS; /* SIGPIPE? */ 350*18369Skarels goto release; 351*18369Skarels } 35216412Skarels if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 35316412Skarels register struct mbuf *p; 35416412Skarels MCLGET(p, 1); 35516412Skarels if (p == 0) 35616412Skarels goto nopages; 35716412Skarels m->m_off = (int)p - (int)m; 35816412Skarels len = CLBYTES; 35916412Skarels } else { 36016412Skarels nopages: 36116412Skarels len = MIN(MLEN, iov->iov_len); 36216412Skarels } 36316412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 36416412Skarels m->m_len = len; 36516412Skarels *mp = m; 36616412Skarels if (error) 36716412Skarels goto release; 36816412Skarels mp = &m->m_next; 36916412Skarels space -= len; 37016412Skarels } 37116992Skarels if (top) { 37216992Skarels if (dontroute) 37316992Skarels so->so_options |= SO_DONTROUTE; 37416992Skarels s = splnet(); 37516992Skarels error = (*so->so_proto->pr_usrreq)(so, 37616992Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 37716992Skarels top, (caddr_t)nam, rights); 37816992Skarels splx(s); 37916992Skarels if (dontroute) 38016992Skarels so->so_options &= ~SO_DONTROUTE; 38116992Skarels } 3826419Sroot top = 0; 38316412Skarels first = 0; 38414781Ssam if (error) 38516412Skarels break; 38616412Skarels } while (uio->uio_resid); 3874890Swnj 3884786Swnj release: 3894890Swnj sbunlock(&so->so_snd); 3906419Sroot if (top) 3916419Sroot m_freem(top); 3924786Swnj return (error); 3934786Swnj } 3944786Swnj 39512757Ssam soreceive(so, aname, uio, flags, rightsp) 3964786Swnj register struct socket *so; 3978300Sroot struct mbuf **aname; 39812757Ssam register struct uio *uio; 3998319Sroot int flags; 40012757Ssam struct mbuf **rightsp; 4014786Swnj { 4024786Swnj register struct mbuf *m, *n; 40316993Skarels register int len, error = 0, s, tomark; 40412757Ssam struct protosw *pr = so->so_proto; 40516993Skarels struct mbuf *nextrecord; 40612757Ssam int moff; 4074786Swnj 40812757Ssam if (rightsp) 40912757Ssam *rightsp = 0; 41012757Ssam if (aname) 41112757Ssam *aname = 0; 41212757Ssam if (flags & MSG_OOB) { 4139635Ssam m = m_get(M_WAIT, MT_DATA); 41412757Ssam if (m == 0) 41510137Ssam return (ENOBUFS); 41612757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 41712757Ssam m, (struct mbuf *)0, (struct mbuf *)0); 4188594Sroot if (error) 41910137Ssam goto bad; 4208319Sroot do { 42110137Ssam len = uio->uio_resid; 4228319Sroot if (len > m->m_len) 4238319Sroot len = m->m_len; 4248594Sroot error = 4258793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4268319Sroot m = m_free(m); 4278594Sroot } while (uio->uio_resid && error == 0 && m); 42810137Ssam bad: 4298319Sroot if (m) 4308771Sroot m_freem(m); 4318594Sroot return (error); 4328319Sroot } 4338319Sroot 4344890Swnj restart: 4354890Swnj sblock(&so->so_rcv); 4368835Sroot s = splnet(); 4374890Swnj 4384890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4394786Swnj if (so->so_rcv.sb_cc == 0) { 4405168Swnj if (so->so_error) { 4415168Swnj error = so->so_error; 4425168Swnj so->so_error = 0; 4435168Swnj splx(s); 4445168Swnj goto release; 4455168Swnj } 4464890Swnj if (so->so_state & SS_CANTRCVMORE) { 4474890Swnj splx(s); 4484890Swnj goto release; 4494890Swnj } 4505015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4515015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4525015Sroot rcverr(ENOTCONN); 4536214Swnj if (so->so_state & SS_NBIO) 4545168Swnj rcverr(EWOULDBLOCK); 4554890Swnj sbunlock(&so->so_rcv); 4564971Swnj sbwait(&so->so_rcv); 4575012Swnj splx(s); 4584890Swnj goto restart; 4594786Swnj } 4608041Sroot u.u_ru.ru_msgrcv++; 4614829Swnj m = so->so_rcv.sb_mb; 46212757Ssam if (pr->pr_flags & PR_ADDR) { 46316993Skarels if (m == 0 || m->m_type != MT_SONAME) 46416993Skarels panic("receive 1a"); 46516993Skarels if (flags & MSG_PEEK) { 46616993Skarels if (aname) 4678319Sroot *aname = m_copy(m, 0, m->m_len); 46816993Skarels else 46916993Skarels m = m->m_act; 47016993Skarels } else { 47116993Skarels if (aname) { 47216993Skarels *aname = m; 47316993Skarels sbfree(&so->so_rcv, m); 47416993Skarels if(m->m_next) panic("receive 1b"); 47516993Skarels so->so_rcv.sb_mb = m = m->m_act; 47610137Ssam } else 47716993Skarels m = sbdroprecord(&so->so_rcv); 47816993Skarels } 47916993Skarels } 48016993Skarels if (m && m->m_type == MT_RIGHTS) { 48116993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 48212757Ssam panic("receive 2a"); 48316993Skarels if (flags & MSG_PEEK) { 48416993Skarels if (rightsp) 48512757Ssam *rightsp = m_copy(m, 0, m->m_len); 48616993Skarels else 48716993Skarels m = m->m_act; 48816993Skarels } else { 48916993Skarels if (rightsp) { 49016993Skarels *rightsp = m; 49116993Skarels sbfree(&so->so_rcv, m); 49216993Skarels if(m->m_next) panic("receive 2b"); 49316993Skarels so->so_rcv.sb_mb = m = m->m_act; 49416993Skarels } else 49516993Skarels m = sbdroprecord(&so->so_rcv); 49612757Ssam } 4974890Swnj } 49816993Skarels if (m == 0) 49916993Skarels panic("receive 3"); 5008319Sroot moff = 0; 5018319Sroot tomark = so->so_oobmark; 50216993Skarels while (m && uio->uio_resid > 0 && error == 0) { 5037827Sroot len = uio->uio_resid; 5047747Sroot so->so_state &= ~SS_RCVATMARK; 5058319Sroot if (tomark && len > tomark) 5068319Sroot len = tomark; 5078548Sroot if (moff+len > m->m_len - moff) 5088319Sroot len = m->m_len - moff; 5094786Swnj splx(s); 5108594Sroot error = 5118793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5124786Swnj s = splnet(); 5134786Swnj if (len == m->m_len) { 51416993Skarels if ((flags & MSG_PEEK) == 0) { 51516993Skarels nextrecord = m->m_act; 5168319Sroot sbfree(&so->so_rcv, m); 5178319Sroot MFREE(m, n); 51816993Skarels if (m = n) 51916993Skarels m->m_act = nextrecord; 5208548Sroot so->so_rcv.sb_mb = m; 52116993Skarels } else 52216993Skarels m = m->m_next; 5238319Sroot moff = 0; 5244786Swnj } else { 52512757Ssam if (flags & MSG_PEEK) 5268319Sroot moff += len; 5278319Sroot else { 5288319Sroot m->m_off += len; 5298319Sroot m->m_len -= len; 5308319Sroot so->so_rcv.sb_cc -= len; 5318319Sroot } 5324786Swnj } 53312757Ssam if ((flags & MSG_PEEK) == 0 && so->so_oobmark) { 5347747Sroot so->so_oobmark -= len; 5357747Sroot if (so->so_oobmark == 0) { 5367747Sroot so->so_state |= SS_RCVATMARK; 5377747Sroot break; 5387747Sroot } 5397747Sroot } 5408319Sroot if (tomark) { 5418319Sroot tomark -= len; 5428319Sroot if (tomark == 0) 5438319Sroot break; 5448319Sroot } 54516993Skarels } 54616993Skarels if ((flags & MSG_PEEK) == 0) { 54716993Skarels if (m == 0) 54816993Skarels so->so_rcv.sb_mb = nextrecord; 54916993Skarels else if (pr->pr_flags & PR_ATOMIC) 55016993Skarels (void) sbdroprecord(&so->so_rcv); 55116993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 55216993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 55316993Skarels (struct mbuf *)0, (struct mbuf *)0); 55416993Skarels } 5554890Swnj release: 5564916Swnj sbunlock(&so->so_rcv); 55716993Skarels if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize) 55816993Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 5594890Swnj splx(s); 5604916Swnj return (error); 5614786Swnj } 5624786Swnj 56310267Ssam soshutdown(so, how) 56412757Ssam register struct socket *so; 56512757Ssam register int how; 56610267Ssam { 56712757Ssam register struct protosw *pr = so->so_proto; 56810267Ssam 56910267Ssam how++; 57012757Ssam if (how & FREAD) 57112757Ssam sorflush(so); 57210267Ssam if (how & FWRITE) 57312757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 57412757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 57510267Ssam return (0); 57610267Ssam } 57710267Ssam 57812757Ssam sorflush(so) 57912757Ssam register struct socket *so; 58012757Ssam { 58112757Ssam register struct sockbuf *sb = &so->so_rcv; 58212757Ssam register struct protosw *pr = so->so_proto; 58312757Ssam register int s; 58412757Ssam struct sockbuf asb; 58512757Ssam 58612757Ssam sblock(sb); 58712757Ssam s = splimp(); 58812757Ssam socantrcvmore(so); 58912757Ssam sbunlock(sb); 59012757Ssam asb = *sb; 59112757Ssam bzero((caddr_t)sb, sizeof (*sb)); 59212757Ssam splx(s); 59316993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 59416993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 59512757Ssam sbrelease(&asb); 59612757Ssam } 59712757Ssam 59810267Ssam sosetopt(so, level, optname, m) 59912757Ssam register struct socket *so; 60010267Ssam int level, optname; 60112757Ssam register struct mbuf *m; 60210267Ssam { 60317158Ssam int error = 0; 60410267Ssam 60517158Ssam if (level != SOL_SOCKET) { 606*18369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 607*18369Skarels return ((*so->so_proto->pr_ctloutput) 608*18369Skarels (PRCO_SETOPT, so, level, optname, m)); 609*18369Skarels error = ENOPROTOOPT; 610*18369Skarels } else { 611*18369Skarels switch (optname) { 61210267Ssam 613*18369Skarels case SO_LINGER: 614*18369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 615*18369Skarels error = EINVAL; 616*18369Skarels goto bad; 617*18369Skarels } 618*18369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 619*18369Skarels /* fall thru... */ 62017158Ssam 621*18369Skarels case SO_DEBUG: 622*18369Skarels case SO_KEEPALIVE: 623*18369Skarels case SO_DONTROUTE: 624*18369Skarels case SO_USELOOPBACK: 625*18369Skarels case SO_BROADCAST: 626*18369Skarels case SO_REUSEADDR: 627*18369Skarels if (m == NULL || m->m_len < sizeof (int)) { 628*18369Skarels error = EINVAL; 629*18369Skarels goto bad; 630*18369Skarels } 631*18369Skarels if (*mtod(m, int *)) 632*18369Skarels so->so_options |= optname; 633*18369Skarels else 634*18369Skarels so->so_options &= ~optname; 635*18369Skarels break; 636*18369Skarels 637*18369Skarels case SO_SNDBUF: 638*18369Skarels case SO_RCVBUF: 639*18369Skarels case SO_SNDLOWAT: 640*18369Skarels case SO_RCVLOWAT: 641*18369Skarels case SO_SNDTIMEO: 642*18369Skarels case SO_RCVTIMEO: 643*18369Skarels if (m == NULL || m->m_len < sizeof (int)) { 644*18369Skarels error = EINVAL; 645*18369Skarels goto bad; 646*18369Skarels } 647*18369Skarels switch (optname) { 648*18369Skarels 649*18369Skarels case SO_SNDBUF: 650*18369Skarels case SO_RCVBUF: 651*18369Skarels if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : 652*18369Skarels &so->so_rcv, *mtod(m, int *)) == 0) { 653*18369Skarels error = ENOBUFS; 654*18369Skarels goto bad; 655*18369Skarels } 656*18369Skarels break; 657*18369Skarels 658*18369Skarels case SO_SNDLOWAT: 659*18369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 660*18369Skarels break; 661*18369Skarels case SO_RCVLOWAT: 662*18369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 663*18369Skarels break; 664*18369Skarels case SO_SNDTIMEO: 665*18369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 666*18369Skarels break; 667*18369Skarels case SO_RCVTIMEO: 668*18369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 669*18369Skarels break; 670*18369Skarels } 671*18369Skarels break; 672*18369Skarels 673*18369Skarels default: 674*18369Skarels error = ENOPROTOOPT; 675*18369Skarels break; 67617158Ssam } 67710267Ssam } 67817158Ssam bad: 67917158Ssam if (m) 68017158Ssam (void) m_free(m); 68117158Ssam return (error); 68210267Ssam } 68310267Ssam 68417158Ssam sogetopt(so, level, optname, mp) 68512757Ssam register struct socket *so; 68610267Ssam int level, optname; 68717158Ssam struct mbuf **mp; 68817158Ssam { 68912757Ssam register struct mbuf *m; 69010267Ssam 691*18369Skarels if (level != SOL_SOCKET) { 692*18369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 693*18369Skarels return ((*so->so_proto->pr_ctloutput) 694*18369Skarels (PRCO_GETOPT, so, level, optname, mp)); 695*18369Skarels } else 696*18369Skarels return (ENOPROTOOPT); 697*18369Skarels } else { 69817158Ssam m = m_get(M_WAIT, MT_SOOPTS); 69917158Ssam if (m == NULL) 70017158Ssam return (ENOBUFS); 701*18369Skarels switch (optname) { 70217158Ssam 703*18369Skarels case SO_LINGER: 704*18369Skarels m->m_len = sizeof (struct linger); 705*18369Skarels mtod(m, struct linger *)->l_onoff = 706*18369Skarels so->so_options & SO_LINGER; 707*18369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 708*18369Skarels break; 70910267Ssam 710*18369Skarels case SO_USELOOPBACK: 711*18369Skarels case SO_DONTROUTE: 712*18369Skarels case SO_DEBUG: 713*18369Skarels case SO_KEEPALIVE: 714*18369Skarels case SO_REUSEADDR: 715*18369Skarels case SO_BROADCAST: 716*18369Skarels m->m_len = sizeof (int); 717*18369Skarels *mtod(m, int *) = so->so_options & optname; 718*18369Skarels break; 719*18369Skarels 720*18369Skarels case SO_SNDBUF: 721*18369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 722*18369Skarels break; 723*18369Skarels 724*18369Skarels case SO_RCVBUF: 725*18369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 726*18369Skarels break; 727*18369Skarels 728*18369Skarels case SO_SNDLOWAT: 729*18369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 730*18369Skarels break; 731*18369Skarels 732*18369Skarels case SO_RCVLOWAT: 733*18369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 734*18369Skarels break; 735*18369Skarels 736*18369Skarels case SO_SNDTIMEO: 737*18369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 738*18369Skarels break; 739*18369Skarels 740*18369Skarels case SO_RCVTIMEO: 741*18369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 742*18369Skarels break; 743*18369Skarels 744*18369Skarels default: 745*18369Skarels m_free(m); 746*18369Skarels return (ENOPROTOOPT); 747*18369Skarels } 748*18369Skarels *mp = m; 749*18369Skarels return (0); 75010267Ssam } 75110267Ssam } 75210267Ssam 7535423Swnj sohasoutofband(so) 75412757Ssam register struct socket *so; 7555423Swnj { 7565423Swnj 7575423Swnj if (so->so_pgrp == 0) 7585423Swnj return; 7595423Swnj if (so->so_pgrp > 0) 7605423Swnj gsignal(so->so_pgrp, SIGURG); 7615429Swnj else { 7625429Swnj struct proc *p = pfind(-so->so_pgrp); 7635429Swnj 7645429Swnj if (p) 7655429Swnj psignal(p, SIGURG); 7665429Swnj } 7675423Swnj } 768