123421Smckusick /* 229126Smckusick * Copyright (c) 1982, 1986 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*32092Skarels * @(#)uipc_socket.c 7.5 (Berkeley) 09/01/87 723421Smckusick */ 84786Swnj 917102Sbloom #include "param.h" 1017102Sbloom #include "dir.h" 1117102Sbloom #include "user.h" 1217102Sbloom #include "proc.h" 1317102Sbloom #include "file.h" 1417102Sbloom #include "mbuf.h" 1517102Sbloom #include "domain.h" 1617102Sbloom #include "protosw.h" 1717102Sbloom #include "socket.h" 1817102Sbloom #include "socketvar.h" 194786Swnj 204786Swnj /* 218300Sroot * Socket operation routines. 228300Sroot * These routines are called by the routines in 238300Sroot * sys_socket.c or from a system process, and 248300Sroot * implement the semantics of socket operations by 258300Sroot * switching out to the protocol specific routines. 2612757Ssam * 2712757Ssam * TODO: 2812757Ssam * test socketpair 2921767Skarels * clean up async 3012757Ssam * out-of-band is a kludge 314786Swnj */ 328594Sroot /*ARGSUSED*/ 3310267Ssam socreate(dom, aso, type, proto) 344786Swnj struct socket **aso; 3512757Ssam register int type; 3612757Ssam int proto; 374786Swnj { 384786Swnj register struct protosw *prp; 394786Swnj register struct socket *so; 4012757Ssam register struct mbuf *m; 4112757Ssam register int error; 424786Swnj 434890Swnj if (proto) 4421767Skarels prp = pffindproto(dom, proto, type); 454890Swnj else 469168Ssam prp = pffindtype(dom, type); 474890Swnj if (prp == 0) 484890Swnj return (EPROTONOSUPPORT); 498300Sroot if (prp->pr_type != type) 508300Sroot return (EPROTOTYPE); 519635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 524786Swnj so = mtod(m, struct socket *); 5312757Ssam so->so_options = 0; 546214Swnj so->so_state = 0; 559168Ssam so->so_type = type; 566214Swnj if (u.u_uid == 0) 576214Swnj so->so_state = SS_PRIV; 584786Swnj so->so_proto = prp; 5912757Ssam error = 6012757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 6121767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 624979Swnj if (error) { 637507Sroot so->so_state |= SS_NOFDREF; 647180Swnj sofree(so); 654890Swnj return (error); 664786Swnj } 674786Swnj *aso = so; 684786Swnj return (0); 694786Swnj } 704786Swnj 7110267Ssam sobind(so, nam) 728300Sroot struct socket *so; 738300Sroot struct mbuf *nam; 748300Sroot { 758300Sroot int s = splnet(); 768300Sroot int error; 778300Sroot 788300Sroot error = 7912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8012757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 818300Sroot splx(s); 828300Sroot return (error); 838300Sroot } 848300Sroot 858300Sroot solisten(so, backlog) 8612757Ssam register struct socket *so; 878300Sroot int backlog; 888300Sroot { 8912757Ssam int s = splnet(), error; 908300Sroot 9112757Ssam error = 9212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 9312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 948300Sroot if (error) { 958300Sroot splx(s); 968300Sroot return (error); 978300Sroot } 988300Sroot if (so->so_q == 0) { 998300Sroot so->so_q = so; 1008300Sroot so->so_q0 = so; 1018300Sroot so->so_options |= SO_ACCEPTCONN; 1028300Sroot } 1038300Sroot if (backlog < 0) 1048300Sroot backlog = 0; 10510137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 10612493Ssam splx(s); 1078300Sroot return (0); 1088300Sroot } 1098300Sroot 1104916Swnj sofree(so) 11112757Ssam register struct socket *so; 1124916Swnj { 1134916Swnj 11431810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 11531810Skarels return; 1167507Sroot if (so->so_head) { 1177507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1187507Sroot panic("sofree dq"); 1197507Sroot so->so_head = 0; 1207507Sroot } 1214950Swnj sbrelease(&so->so_snd); 12212757Ssam sorflush(so); 1234971Swnj (void) m_free(dtom(so)); 1244916Swnj } 1254916Swnj 1264786Swnj /* 1274890Swnj * Close a socket on last file table reference removal. 1284890Swnj * Initiate disconnect if connected. 1294890Swnj * Free socket when disconnect complete. 1304829Swnj */ 13112757Ssam soclose(so) 1324829Swnj register struct socket *so; 1334829Swnj { 1344890Swnj int s = splnet(); /* conservative */ 1358713Sroot int error; 1364829Swnj 1377507Sroot if (so->so_options & SO_ACCEPTCONN) { 1387507Sroot while (so->so_q0 != so) 13910399Ssam (void) soabort(so->so_q0); 1407507Sroot while (so->so_q != so) 14110399Ssam (void) soabort(so->so_q); 1427507Sroot } 1434890Swnj if (so->so_pcb == 0) 1444890Swnj goto discard; 1454890Swnj if (so->so_state & SS_ISCONNECTED) { 1464890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 14726245Skarels error = sodisconnect(so); 14812757Ssam if (error) 14912757Ssam goto drop; 1504890Swnj } 15110267Ssam if (so->so_options & SO_LINGER) { 1525281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15312757Ssam (so->so_state & SS_NBIO)) 15412757Ssam goto drop; 1555281Sroot while (so->so_state & SS_ISCONNECTED) 1565281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1574890Swnj } 1584890Swnj } 1595580Sroot drop: 1606880Ssam if (so->so_pcb) { 16112757Ssam int error2 = 16212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 16412757Ssam if (error == 0) 16512757Ssam error = error2; 1666880Ssam } 1674890Swnj discard: 16810399Ssam if (so->so_state & SS_NOFDREF) 16910399Ssam panic("soclose: NOFDREF"); 1707507Sroot so->so_state |= SS_NOFDREF; 1714950Swnj sofree(so); 1724890Swnj splx(s); 17312757Ssam return (error); 1744829Swnj } 1754829Swnj 17610399Ssam /* 17710399Ssam * Must be called at splnet... 17810399Ssam */ 17910399Ssam soabort(so) 18010399Ssam struct socket *so; 18110399Ssam { 18210399Ssam 18312757Ssam return ( 18412757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 18512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 18610399Ssam } 18710399Ssam 18810267Ssam soaccept(so, nam) 18912757Ssam register struct socket *so; 1908300Sroot struct mbuf *nam; 1914927Swnj { 1924927Swnj int s = splnet(); 1934927Swnj int error; 1944927Swnj 19510399Ssam if ((so->so_state & SS_NOFDREF) == 0) 19610399Ssam panic("soaccept: !NOFDREF"); 19710267Ssam so->so_state &= ~SS_NOFDREF; 1988300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 19912757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2004927Swnj splx(s); 2014927Swnj return (error); 2024927Swnj } 2034927Swnj 20410267Ssam soconnect(so, nam) 20512757Ssam register struct socket *so; 2068300Sroot struct mbuf *nam; 2074786Swnj { 20830414Skarels int s; 2094890Swnj int error; 2104786Swnj 21130414Skarels if (so->so_options & SO_ACCEPTCONN) 21230414Skarels return (EOPNOTSUPP); 21330414Skarels s = splnet(); 21424768Skarels /* 21524768Skarels * If protocol is connection-based, can only connect once. 21624768Skarels * Otherwise, if connected, try to disconnect first. 21724768Skarels * This allows user to disconnect by connecting to, e.g., 21824768Skarels * a null address. 21924768Skarels */ 22024768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 22124768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 22224768Skarels (error = sodisconnect(so)))) 2234890Swnj error = EISCONN; 22424768Skarels else 22524768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 22624768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2274890Swnj splx(s); 2284890Swnj return (error); 2294786Swnj } 2304786Swnj 23112757Ssam soconnect2(so1, so2) 23212757Ssam register struct socket *so1; 23312757Ssam struct socket *so2; 23412757Ssam { 23512757Ssam int s = splnet(); 23612757Ssam int error; 23712757Ssam 23813113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 23913113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24012757Ssam splx(s); 24112757Ssam return (error); 24212757Ssam } 24312757Ssam 24426245Skarels sodisconnect(so) 24512757Ssam register struct socket *so; 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, 25926245Skarels (struct mbuf *)0, (struct mbuf *)0, (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; 28425629Skarels int len, rlen = 0, 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++; 29225629Skarels if (rights) 29325629Skarels rlen = rights->m_len; 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); 31825629Skarels if (space <= rlen || 31925629Skarels (sosendallatonce(so) && 32025629Skarels space < uio->uio_resid + rlen) || 32116992Skarels (uio->uio_resid >= CLBYTES && space < CLBYTES && 32216992Skarels so->so_snd.sb_cc >= CLBYTES && 32316992Skarels (so->so_state & SS_NBIO) == 0)) { 32416412Skarels if (so->so_state & SS_NBIO) { 32516412Skarels if (first) 32616412Skarels error = EWOULDBLOCK; 32716412Skarels splx(s); 32816412Skarels goto release; 32916412Skarels } 33016412Skarels sbunlock(&so->so_snd); 33116412Skarels sbwait(&so->so_snd); 33216412Skarels splx(s); 33316412Skarels goto restart; 33416412Skarels } 33516412Skarels } 33616412Skarels splx(s); 33716412Skarels mp = ⊤ 33825629Skarels space -= rlen; 33921108Skarels while (space > 0) { 34016412Skarels MGET(m, M_WAIT, MT_DATA); 34126958Skarels if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) { 34226228Skarels MCLGET(m); 34326228Skarels if (m->m_len != CLBYTES) 34416412Skarels goto nopages; 34526958Skarels len = MIN(CLBYTES, uio->uio_resid); 34621767Skarels space -= CLBYTES; 34716412Skarels } else { 34816412Skarels nopages: 34926958Skarels len = MIN(MIN(MLEN, uio->uio_resid), space); 35021767Skarels space -= len; 35116412Skarels } 35216412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 35316412Skarels m->m_len = len; 35416412Skarels *mp = m; 35516412Skarels if (error) 35616412Skarels goto release; 35716412Skarels mp = &m->m_next; 35821108Skarels if (uio->uio_resid <= 0) 35921108Skarels break; 36016412Skarels } 36121108Skarels if (dontroute) 36221108Skarels so->so_options |= SO_DONTROUTE; 36321108Skarels s = splnet(); /* XXX */ 36421108Skarels error = (*so->so_proto->pr_usrreq)(so, 36521108Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 36621108Skarels top, (caddr_t)nam, rights); 36721108Skarels splx(s); 36821108Skarels if (dontroute) 36921108Skarels so->so_options &= ~SO_DONTROUTE; 37021767Skarels rights = 0; 37125629Skarels rlen = 0; 3726419Sroot top = 0; 37316412Skarels first = 0; 37414781Ssam if (error) 37516412Skarels break; 37616412Skarels } while (uio->uio_resid); 3774890Swnj 3784786Swnj release: 3794890Swnj sbunlock(&so->so_snd); 3806419Sroot if (top) 3816419Sroot m_freem(top); 38221108Skarels if (error == EPIPE) 38321108Skarels psignal(u.u_procp, SIGPIPE); 3844786Swnj return (error); 3854786Swnj } 3864786Swnj 38725629Skarels /* 38825629Skarels * Implement receive operations on a socket. 38925629Skarels * We depend on the way that records are added to the sockbuf 39025629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 39125629Skarels * must begin with an address if the protocol so specifies, 39225629Skarels * followed by an optional mbuf containing access rights if supported 39325629Skarels * by the protocol, and then zero or more mbufs of data. 39425629Skarels * In order to avoid blocking network interrupts for the entire time here, 39525629Skarels * we splx() while doing the actual copy to user space. 39625629Skarels * Although the sockbuf is locked, new data may still be appended, 39725629Skarels * and thus we must maintain consistency of the sockbuf during that time. 39825629Skarels */ 39912757Ssam soreceive(so, aname, uio, flags, rightsp) 4004786Swnj register struct socket *so; 4018300Sroot struct mbuf **aname; 40212757Ssam register struct uio *uio; 4038319Sroot int flags; 40412757Ssam struct mbuf **rightsp; 4054786Swnj { 40626958Skarels register struct mbuf *m; 407*32092Skarels register int len, error = 0, s, offset; 40812757Ssam struct protosw *pr = so->so_proto; 40916993Skarels struct mbuf *nextrecord; 41012757Ssam int moff; 4114786Swnj 41212757Ssam if (rightsp) 41312757Ssam *rightsp = 0; 41412757Ssam if (aname) 41512757Ssam *aname = 0; 41612757Ssam if (flags & MSG_OOB) { 4179635Ssam m = m_get(M_WAIT, MT_DATA); 41812757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 41924768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4208594Sroot if (error) 42110137Ssam goto bad; 4228319Sroot do { 42310137Ssam len = uio->uio_resid; 4248319Sroot if (len > m->m_len) 4258319Sroot len = m->m_len; 4268594Sroot error = 4278793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4288319Sroot m = m_free(m); 4298594Sroot } while (uio->uio_resid && error == 0 && m); 43010137Ssam bad: 4318319Sroot if (m) 4328771Sroot m_freem(m); 4338594Sroot return (error); 4348319Sroot } 4358319Sroot 4364890Swnj restart: 4374890Swnj sblock(&so->so_rcv); 4388835Sroot s = splnet(); 4394890Swnj 4404890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4414786Swnj if (so->so_rcv.sb_cc == 0) { 4425168Swnj if (so->so_error) { 4435168Swnj error = so->so_error; 4445168Swnj so->so_error = 0; 4455168Swnj splx(s); 4465168Swnj goto release; 4475168Swnj } 4484890Swnj if (so->so_state & SS_CANTRCVMORE) { 4494890Swnj splx(s); 4504890Swnj goto release; 4514890Swnj } 4525015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4535015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4545015Sroot rcverr(ENOTCONN); 45525629Skarels if (uio->uio_resid == 0) 45625629Skarels goto release; 4576214Swnj if (so->so_state & SS_NBIO) 4585168Swnj rcverr(EWOULDBLOCK); 4594890Swnj sbunlock(&so->so_rcv); 4604971Swnj sbwait(&so->so_rcv); 4615012Swnj splx(s); 4624890Swnj goto restart; 4634786Swnj } 4648041Sroot u.u_ru.ru_msgrcv++; 4654829Swnj m = so->so_rcv.sb_mb; 46625629Skarels if (m == 0) 46725629Skarels panic("receive 1"); 46825629Skarels nextrecord = m->m_act; 46912757Ssam if (pr->pr_flags & PR_ADDR) { 47025629Skarels if (m->m_type != MT_SONAME) 47116993Skarels panic("receive 1a"); 47216993Skarels if (flags & MSG_PEEK) { 47316993Skarels if (aname) 4748319Sroot *aname = m_copy(m, 0, m->m_len); 47525629Skarels m = m->m_next; 47616993Skarels } else { 47725629Skarels sbfree(&so->so_rcv, m); 47816993Skarels if (aname) { 47916993Skarels *aname = m; 48025629Skarels m = m->m_next; 48125629Skarels (*aname)->m_next = 0; 48226958Skarels so->so_rcv.sb_mb = m; 48325629Skarels } else { 48426958Skarels MFREE(m, so->so_rcv.sb_mb); 48526958Skarels m = so->so_rcv.sb_mb; 48625629Skarels } 48726958Skarels if (m) 48826958Skarels m->m_act = nextrecord; 48916993Skarels } 49016993Skarels } 49116993Skarels if (m && m->m_type == MT_RIGHTS) { 49216993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 49326958Skarels panic("receive 2"); 49416993Skarels if (flags & MSG_PEEK) { 49516993Skarels if (rightsp) 49612757Ssam *rightsp = m_copy(m, 0, m->m_len); 49725629Skarels m = m->m_next; 49816993Skarels } else { 49925629Skarels sbfree(&so->so_rcv, m); 50016993Skarels if (rightsp) { 50116993Skarels *rightsp = m; 50226958Skarels so->so_rcv.sb_mb = m->m_next; 50325629Skarels m->m_next = 0; 50426958Skarels m = so->so_rcv.sb_mb; 50525629Skarels } else { 50626958Skarels MFREE(m, so->so_rcv.sb_mb); 50726958Skarels m = so->so_rcv.sb_mb; 50825629Skarels } 50926958Skarels if (m) 51026958Skarels m->m_act = nextrecord; 51112757Ssam } 5124890Swnj } 5138319Sroot moff = 0; 514*32092Skarels offset = 0; 51516993Skarels while (m && uio->uio_resid > 0 && error == 0) { 51625629Skarels if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 51725629Skarels panic("receive 3"); 5187827Sroot len = uio->uio_resid; 5197747Sroot so->so_state &= ~SS_RCVATMARK; 520*32092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 521*32092Skarels len = so->so_oobmark - offset; 52221767Skarels if (len > m->m_len - moff) 5238319Sroot len = m->m_len - moff; 5244786Swnj splx(s); 5258594Sroot error = 5268793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5274786Swnj s = splnet(); 52821767Skarels if (len == m->m_len - moff) { 52925629Skarels if (flags & MSG_PEEK) { 53025629Skarels m = m->m_next; 53125629Skarels moff = 0; 53225629Skarels } else { 53326958Skarels nextrecord = m->m_act; 53425629Skarels sbfree(&so->so_rcv, m); 53526958Skarels MFREE(m, so->so_rcv.sb_mb); 53626958Skarels m = so->so_rcv.sb_mb; 53726958Skarels if (m) 53826958Skarels m->m_act = nextrecord; 53925629Skarels } 5404786Swnj } else { 54112757Ssam if (flags & MSG_PEEK) 5428319Sroot moff += len; 5438319Sroot else { 5448319Sroot m->m_off += len; 5458319Sroot m->m_len -= len; 5468319Sroot so->so_rcv.sb_cc -= len; 5478319Sroot } 5484786Swnj } 549*32092Skarels if (so->so_oobmark) { 550*32092Skarels if ((flags & MSG_PEEK) == 0) { 551*32092Skarels so->so_oobmark -= len; 552*32092Skarels if (so->so_oobmark == 0) { 553*32092Skarels so->so_state |= SS_RCVATMARK; 554*32092Skarels break; 555*32092Skarels } 556*32092Skarels } else 557*32092Skarels offset += len; 5587747Sroot } 55916993Skarels } 56016993Skarels if ((flags & MSG_PEEK) == 0) { 56126500Skarels if (m == 0) 56216993Skarels so->so_rcv.sb_mb = nextrecord; 56326958Skarels else if (pr->pr_flags & PR_ATOMIC) 56426958Skarels (void) sbdroprecord(&so->so_rcv); 56516993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 56616993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 56716993Skarels (struct mbuf *)0, (struct mbuf *)0); 56825629Skarels if (error == 0 && rightsp && *rightsp && 56925629Skarels pr->pr_domain->dom_externalize) 57025629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 57116993Skarels } 5724890Swnj release: 5734916Swnj sbunlock(&so->so_rcv); 5744890Swnj splx(s); 5754916Swnj return (error); 5764786Swnj } 5774786Swnj 57810267Ssam soshutdown(so, how) 57912757Ssam register struct socket *so; 58012757Ssam register int how; 58110267Ssam { 58212757Ssam register struct protosw *pr = so->so_proto; 58310267Ssam 58410267Ssam how++; 58512757Ssam if (how & FREAD) 58612757Ssam sorflush(so); 58710267Ssam if (how & FWRITE) 58812757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 58912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 59010267Ssam return (0); 59110267Ssam } 59210267Ssam 59312757Ssam sorflush(so) 59412757Ssam register struct socket *so; 59512757Ssam { 59612757Ssam register struct sockbuf *sb = &so->so_rcv; 59712757Ssam register struct protosw *pr = so->so_proto; 59812757Ssam register int s; 59912757Ssam struct sockbuf asb; 60012757Ssam 60112757Ssam sblock(sb); 60212757Ssam s = splimp(); 60312757Ssam socantrcvmore(so); 60412757Ssam sbunlock(sb); 60512757Ssam asb = *sb; 60612757Ssam bzero((caddr_t)sb, sizeof (*sb)); 60712757Ssam splx(s); 60816993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 60916993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 61012757Ssam sbrelease(&asb); 61112757Ssam } 61212757Ssam 61318553Skarels sosetopt(so, level, optname, m0) 61412757Ssam register struct socket *so; 61510267Ssam int level, optname; 61618553Skarels struct mbuf *m0; 61710267Ssam { 61817158Ssam int error = 0; 61918553Skarels register struct mbuf *m = m0; 62010267Ssam 62117158Ssam if (level != SOL_SOCKET) { 62218369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 62318369Skarels return ((*so->so_proto->pr_ctloutput) 62418553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 62518369Skarels error = ENOPROTOOPT; 62618369Skarels } else { 62718369Skarels switch (optname) { 62810267Ssam 62918369Skarels case SO_LINGER: 63018369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 63118369Skarels error = EINVAL; 63218369Skarels goto bad; 63318369Skarels } 63418369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 63518369Skarels /* fall thru... */ 63617158Ssam 63718369Skarels case SO_DEBUG: 63818369Skarels case SO_KEEPALIVE: 63918369Skarels case SO_DONTROUTE: 64018369Skarels case SO_USELOOPBACK: 64118369Skarels case SO_BROADCAST: 64218369Skarels case SO_REUSEADDR: 64327191Skarels case SO_OOBINLINE: 64418369Skarels if (m == NULL || m->m_len < sizeof (int)) { 64518369Skarels error = EINVAL; 64618369Skarels goto bad; 64718369Skarels } 64818369Skarels if (*mtod(m, int *)) 64918369Skarels so->so_options |= optname; 65018369Skarels else 65118369Skarels so->so_options &= ~optname; 65218369Skarels break; 65318369Skarels 65418369Skarels case SO_SNDBUF: 65518369Skarels case SO_RCVBUF: 65618369Skarels case SO_SNDLOWAT: 65718369Skarels case SO_RCVLOWAT: 65818369Skarels case SO_SNDTIMEO: 65918369Skarels case SO_RCVTIMEO: 66018369Skarels if (m == NULL || m->m_len < sizeof (int)) { 66118369Skarels error = EINVAL; 66218369Skarels goto bad; 66318369Skarels } 66418369Skarels switch (optname) { 66518369Skarels 66618369Skarels case SO_SNDBUF: 66718369Skarels case SO_RCVBUF: 66818369Skarels if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : 66918369Skarels &so->so_rcv, *mtod(m, int *)) == 0) { 67018369Skarels error = ENOBUFS; 67118369Skarels goto bad; 67218369Skarels } 67318369Skarels break; 67418369Skarels 67518369Skarels case SO_SNDLOWAT: 67618369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 67718369Skarels break; 67818369Skarels case SO_RCVLOWAT: 67918369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 68018369Skarels break; 68118369Skarels case SO_SNDTIMEO: 68218369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 68318369Skarels break; 68418369Skarels case SO_RCVTIMEO: 68518369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 68618369Skarels break; 68718369Skarels } 68818369Skarels break; 68918369Skarels 69018369Skarels default: 69118369Skarels error = ENOPROTOOPT; 69218369Skarels break; 69317158Ssam } 69410267Ssam } 69517158Ssam bad: 69617158Ssam if (m) 69717158Ssam (void) m_free(m); 69817158Ssam return (error); 69910267Ssam } 70010267Ssam 70117158Ssam sogetopt(so, level, optname, mp) 70212757Ssam register struct socket *so; 70310267Ssam int level, optname; 70417158Ssam struct mbuf **mp; 70517158Ssam { 70612757Ssam register struct mbuf *m; 70710267Ssam 70818369Skarels if (level != SOL_SOCKET) { 70918369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 71018369Skarels return ((*so->so_proto->pr_ctloutput) 71118369Skarels (PRCO_GETOPT, so, level, optname, mp)); 71218369Skarels } else 71318369Skarels return (ENOPROTOOPT); 71418369Skarels } else { 71517158Ssam m = m_get(M_WAIT, MT_SOOPTS); 71625502Skarels m->m_len = sizeof (int); 71725502Skarels 71818369Skarels switch (optname) { 71917158Ssam 72018369Skarels case SO_LINGER: 72118369Skarels m->m_len = sizeof (struct linger); 72218369Skarels mtod(m, struct linger *)->l_onoff = 72318369Skarels so->so_options & SO_LINGER; 72418369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 72518369Skarels break; 72610267Ssam 72718369Skarels case SO_USELOOPBACK: 72818369Skarels case SO_DONTROUTE: 72918369Skarels case SO_DEBUG: 73018369Skarels case SO_KEEPALIVE: 73118369Skarels case SO_REUSEADDR: 73218369Skarels case SO_BROADCAST: 73327191Skarels case SO_OOBINLINE: 73418369Skarels *mtod(m, int *) = so->so_options & optname; 73518369Skarels break; 73618369Skarels 73725502Skarels case SO_TYPE: 73825502Skarels *mtod(m, int *) = so->so_type; 73925502Skarels break; 74025502Skarels 74124768Skarels case SO_ERROR: 74224768Skarels *mtod(m, int *) = so->so_error; 74324768Skarels so->so_error = 0; 74424768Skarels break; 74524768Skarels 74618369Skarels case SO_SNDBUF: 74718369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 74818369Skarels break; 74918369Skarels 75018369Skarels case SO_RCVBUF: 75118369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 75218369Skarels break; 75318369Skarels 75418369Skarels case SO_SNDLOWAT: 75518369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 75618369Skarels break; 75718369Skarels 75818369Skarels case SO_RCVLOWAT: 75918369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 76018369Skarels break; 76118369Skarels 76218369Skarels case SO_SNDTIMEO: 76318369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 76418369Skarels break; 76518369Skarels 76618369Skarels case SO_RCVTIMEO: 76718369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 76818369Skarels break; 76918369Skarels 77018369Skarels default: 77126362Skarels (void)m_free(m); 77218369Skarels return (ENOPROTOOPT); 77318369Skarels } 77418369Skarels *mp = m; 77518369Skarels return (0); 77610267Ssam } 77710267Ssam } 77810267Ssam 7795423Swnj sohasoutofband(so) 78012757Ssam register struct socket *so; 7815423Swnj { 78223233Skarels struct proc *p; 7835423Swnj 78423233Skarels if (so->so_pgrp < 0) 78523233Skarels gsignal(-so->so_pgrp, SIGURG); 78623233Skarels else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) 78723233Skarels psignal(p, SIGURG); 78824768Skarels if (so->so_rcv.sb_sel) { 78924768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 79024768Skarels so->so_rcv.sb_sel = 0; 79124768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 79224768Skarels } 7935423Swnj } 794