123421Smckusick /* 229126Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 333185Sbostic * All rights reserved. 423421Smckusick * 533185Sbostic * Redistribution and use in source and binary forms are permitted 633185Sbostic * provided that this notice is preserved and that due credit is given 733185Sbostic * to the University of California at Berkeley. The name of the University 833185Sbostic * may not be used to endorse or promote products derived from this 933185Sbostic * software without specific prior written permission. This software 1033185Sbostic * is provided ``as is'' without express or implied warranty. 1133185Sbostic * 12*33372Sbostic * @(#)uipc_socket.c 7.8 (Berkeley) 01/20/88 1323421Smckusick */ 144786Swnj 1517102Sbloom #include "param.h" 1617102Sbloom #include "dir.h" 1717102Sbloom #include "user.h" 1817102Sbloom #include "proc.h" 1917102Sbloom #include "file.h" 2017102Sbloom #include "mbuf.h" 2117102Sbloom #include "domain.h" 2217102Sbloom #include "protosw.h" 2317102Sbloom #include "socket.h" 2417102Sbloom #include "socketvar.h" 254786Swnj 264786Swnj /* 278300Sroot * Socket operation routines. 288300Sroot * These routines are called by the routines in 298300Sroot * sys_socket.c or from a system process, and 308300Sroot * implement the semantics of socket operations by 318300Sroot * switching out to the protocol specific routines. 3212757Ssam * 3312757Ssam * TODO: 3412757Ssam * test socketpair 3521767Skarels * clean up 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) 5021767Skarels prp = pffindproto(dom, proto, type); 514890Swnj else 529168Ssam prp = pffindtype(dom, type); 534890Swnj if (prp == 0) 544890Swnj return (EPROTONOSUPPORT); 558300Sroot if (prp->pr_type != type) 568300Sroot return (EPROTOTYPE); 579635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 584786Swnj so = mtod(m, struct socket *); 5912757Ssam so->so_options = 0; 606214Swnj so->so_state = 0; 619168Ssam so->so_type = type; 626214Swnj if (u.u_uid == 0) 636214Swnj so->so_state = SS_PRIV; 644786Swnj so->so_proto = prp; 6512757Ssam error = 6612757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 6721767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 684979Swnj if (error) { 697507Sroot so->so_state |= SS_NOFDREF; 707180Swnj sofree(so); 714890Swnj return (error); 724786Swnj } 734786Swnj *aso = so; 744786Swnj return (0); 754786Swnj } 764786Swnj 7710267Ssam sobind(so, nam) 788300Sroot struct socket *so; 798300Sroot struct mbuf *nam; 808300Sroot { 818300Sroot int s = splnet(); 828300Sroot int error; 838300Sroot 848300Sroot error = 8512757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8612757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 878300Sroot splx(s); 888300Sroot return (error); 898300Sroot } 908300Sroot 918300Sroot solisten(so, backlog) 9212757Ssam register struct socket *so; 938300Sroot int backlog; 948300Sroot { 9512757Ssam int s = splnet(), error; 968300Sroot 9712757Ssam error = 9812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 9912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1008300Sroot if (error) { 1018300Sroot splx(s); 1028300Sroot return (error); 1038300Sroot } 1048300Sroot if (so->so_q == 0) { 1058300Sroot so->so_q = so; 1068300Sroot so->so_q0 = so; 1078300Sroot so->so_options |= SO_ACCEPTCONN; 1088300Sroot } 1098300Sroot if (backlog < 0) 1108300Sroot backlog = 0; 11110137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 11212493Ssam splx(s); 1138300Sroot return (0); 1148300Sroot } 1158300Sroot 1164916Swnj sofree(so) 11712757Ssam register struct socket *so; 1184916Swnj { 1194916Swnj 12031810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 12131810Skarels return; 1227507Sroot if (so->so_head) { 1237507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1247507Sroot panic("sofree dq"); 1257507Sroot so->so_head = 0; 1267507Sroot } 1274950Swnj sbrelease(&so->so_snd); 12812757Ssam sorflush(so); 1294971Swnj (void) m_free(dtom(so)); 1304916Swnj } 1314916Swnj 1324786Swnj /* 1334890Swnj * Close a socket on last file table reference removal. 1344890Swnj * Initiate disconnect if connected. 1354890Swnj * Free socket when disconnect complete. 1364829Swnj */ 13712757Ssam soclose(so) 1384829Swnj register struct socket *so; 1394829Swnj { 1404890Swnj int s = splnet(); /* conservative */ 141*33372Sbostic int error = 0; 1424829Swnj 1437507Sroot if (so->so_options & SO_ACCEPTCONN) { 1447507Sroot while (so->so_q0 != so) 14510399Ssam (void) soabort(so->so_q0); 1467507Sroot while (so->so_q != so) 14710399Ssam (void) soabort(so->so_q); 1487507Sroot } 1494890Swnj if (so->so_pcb == 0) 1504890Swnj goto discard; 1514890Swnj if (so->so_state & SS_ISCONNECTED) { 1524890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 15326245Skarels error = sodisconnect(so); 15412757Ssam if (error) 15512757Ssam goto drop; 1564890Swnj } 15710267Ssam if (so->so_options & SO_LINGER) { 1585281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15912757Ssam (so->so_state & SS_NBIO)) 16012757Ssam goto drop; 1615281Sroot while (so->so_state & SS_ISCONNECTED) 1625281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1634890Swnj } 1644890Swnj } 1655580Sroot drop: 1666880Ssam if (so->so_pcb) { 16712757Ssam int error2 = 16812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17012757Ssam if (error == 0) 17112757Ssam error = error2; 1726880Ssam } 1734890Swnj discard: 17410399Ssam if (so->so_state & SS_NOFDREF) 17510399Ssam panic("soclose: NOFDREF"); 1767507Sroot so->so_state |= SS_NOFDREF; 1774950Swnj sofree(so); 1784890Swnj splx(s); 17912757Ssam return (error); 1804829Swnj } 1814829Swnj 18210399Ssam /* 18310399Ssam * Must be called at splnet... 18410399Ssam */ 18510399Ssam soabort(so) 18610399Ssam struct socket *so; 18710399Ssam { 18810399Ssam 18912757Ssam return ( 19012757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19210399Ssam } 19310399Ssam 19410267Ssam soaccept(so, nam) 19512757Ssam register struct socket *so; 1968300Sroot struct mbuf *nam; 1974927Swnj { 1984927Swnj int s = splnet(); 1994927Swnj int error; 2004927Swnj 20110399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20210399Ssam panic("soaccept: !NOFDREF"); 20310267Ssam so->so_state &= ~SS_NOFDREF; 2048300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20512757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2064927Swnj splx(s); 2074927Swnj return (error); 2084927Swnj } 2094927Swnj 21010267Ssam soconnect(so, nam) 21112757Ssam register struct socket *so; 2128300Sroot struct mbuf *nam; 2134786Swnj { 21430414Skarels int s; 2154890Swnj int error; 2164786Swnj 21730414Skarels if (so->so_options & SO_ACCEPTCONN) 21830414Skarels return (EOPNOTSUPP); 21930414Skarels s = splnet(); 22024768Skarels /* 22124768Skarels * If protocol is connection-based, can only connect once. 22224768Skarels * Otherwise, if connected, try to disconnect first. 22324768Skarels * This allows user to disconnect by connecting to, e.g., 22424768Skarels * a null address. 22524768Skarels */ 22624768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 22724768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 22824768Skarels (error = sodisconnect(so)))) 2294890Swnj error = EISCONN; 23024768Skarels else 23124768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23224768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2334890Swnj splx(s); 2344890Swnj return (error); 2354786Swnj } 2364786Swnj 23712757Ssam soconnect2(so1, so2) 23812757Ssam register struct socket *so1; 23912757Ssam struct socket *so2; 24012757Ssam { 24112757Ssam int s = splnet(); 24212757Ssam int error; 24312757Ssam 24413113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24513113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24612757Ssam splx(s); 24712757Ssam return (error); 24812757Ssam } 24912757Ssam 25026245Skarels sodisconnect(so) 25112757Ssam register struct socket *so; 2524786Swnj { 2534890Swnj int s = splnet(); 2544890Swnj int error; 2554786Swnj 2564890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2574890Swnj error = ENOTCONN; 2584890Swnj goto bad; 2594890Swnj } 2604890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2614890Swnj error = EALREADY; 2624890Swnj goto bad; 2634890Swnj } 2648300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26526245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2664890Swnj bad: 2674890Swnj splx(s); 2684890Swnj return (error); 2694786Swnj } 2704786Swnj 2714786Swnj /* 2724890Swnj * Send on a socket. 2734890Swnj * If send must go all at once and message is larger than 2744890Swnj * send buffering, then hard error. 2754890Swnj * Lock against other senders. 2764890Swnj * If must go all at once and not enough room now, then 2774890Swnj * inform user that this would block and do nothing. 27816412Skarels * Otherwise, if nonblocking, send as much as possible. 2794786Swnj */ 28012757Ssam sosend(so, nam, uio, flags, rights) 2814786Swnj register struct socket *so; 2828300Sroot struct mbuf *nam; 28312757Ssam register struct uio *uio; 2848319Sroot int flags; 28512757Ssam struct mbuf *rights; 2864786Swnj { 2874890Swnj struct mbuf *top = 0; 28816412Skarels register struct mbuf *m, **mp; 28912757Ssam register int space; 29025629Skarels int len, rlen = 0, error = 0, s, dontroute, first = 1; 2914786Swnj 2927827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2934890Swnj return (EMSGSIZE); 29412757Ssam dontroute = 29512757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29612757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 29716412Skarels u.u_ru.ru_msgsnd++; 29825629Skarels if (rights) 29925629Skarels rlen = rights->m_len; 30016412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30116412Skarels 3026419Sroot restart: 3034890Swnj sblock(&so->so_snd); 30416412Skarels do { 30516412Skarels s = splnet(); 30621108Skarels if (so->so_state & SS_CANTSENDMORE) 30716412Skarels snderr(EPIPE); 30816412Skarels if (so->so_error) { 30916412Skarels error = so->so_error; 31016412Skarels so->so_error = 0; /* ??? */ 31116412Skarels splx(s); 31216412Skarels goto release; 31316412Skarels } 31416412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31516412Skarels if (so->so_proto->pr_flags & PR_CONNREQUIRED) 31616412Skarels snderr(ENOTCONN); 31716412Skarels if (nam == 0) 31816412Skarels snderr(EDESTADDRREQ); 31916412Skarels } 32016412Skarels if (flags & MSG_OOB) 32116412Skarels space = 1024; 32216412Skarels else { 32316412Skarels space = sbspace(&so->so_snd); 32425629Skarels if (space <= rlen || 32525629Skarels (sosendallatonce(so) && 32625629Skarels space < uio->uio_resid + rlen) || 32716992Skarels (uio->uio_resid >= CLBYTES && space < CLBYTES && 32816992Skarels so->so_snd.sb_cc >= CLBYTES && 32916992Skarels (so->so_state & SS_NBIO) == 0)) { 33016412Skarels if (so->so_state & SS_NBIO) { 33116412Skarels if (first) 33216412Skarels error = EWOULDBLOCK; 33316412Skarels splx(s); 33416412Skarels goto release; 33516412Skarels } 33616412Skarels sbunlock(&so->so_snd); 33716412Skarels sbwait(&so->so_snd); 33816412Skarels splx(s); 33916412Skarels goto restart; 34016412Skarels } 34116412Skarels } 34216412Skarels splx(s); 34316412Skarels mp = ⊤ 34425629Skarels space -= rlen; 34521108Skarels while (space > 0) { 34616412Skarels MGET(m, M_WAIT, MT_DATA); 34726958Skarels if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) { 34826228Skarels MCLGET(m); 34926228Skarels if (m->m_len != CLBYTES) 35016412Skarels goto nopages; 35126958Skarels len = MIN(CLBYTES, uio->uio_resid); 35221767Skarels space -= CLBYTES; 35316412Skarels } else { 35416412Skarels nopages: 35526958Skarels len = MIN(MIN(MLEN, uio->uio_resid), space); 35621767Skarels space -= len; 35716412Skarels } 35816412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 35916412Skarels m->m_len = len; 36016412Skarels *mp = m; 36116412Skarels if (error) 36216412Skarels goto release; 36316412Skarels mp = &m->m_next; 36421108Skarels if (uio->uio_resid <= 0) 36521108Skarels break; 36616412Skarels } 36721108Skarels if (dontroute) 36821108Skarels so->so_options |= SO_DONTROUTE; 36921108Skarels s = splnet(); /* XXX */ 37021108Skarels error = (*so->so_proto->pr_usrreq)(so, 37121108Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 37221108Skarels top, (caddr_t)nam, rights); 37321108Skarels splx(s); 37421108Skarels if (dontroute) 37521108Skarels so->so_options &= ~SO_DONTROUTE; 37621767Skarels rights = 0; 37725629Skarels rlen = 0; 3786419Sroot top = 0; 37916412Skarels first = 0; 38014781Ssam if (error) 38116412Skarels break; 38216412Skarels } while (uio->uio_resid); 3834890Swnj 3844786Swnj release: 3854890Swnj sbunlock(&so->so_snd); 3866419Sroot if (top) 3876419Sroot m_freem(top); 38821108Skarels if (error == EPIPE) 38921108Skarels psignal(u.u_procp, SIGPIPE); 3904786Swnj return (error); 3914786Swnj } 3924786Swnj 39325629Skarels /* 39425629Skarels * Implement receive operations on a socket. 39525629Skarels * We depend on the way that records are added to the sockbuf 39625629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 39725629Skarels * must begin with an address if the protocol so specifies, 39825629Skarels * followed by an optional mbuf containing access rights if supported 39925629Skarels * by the protocol, and then zero or more mbufs of data. 40025629Skarels * In order to avoid blocking network interrupts for the entire time here, 40125629Skarels * we splx() while doing the actual copy to user space. 40225629Skarels * Although the sockbuf is locked, new data may still be appended, 40325629Skarels * and thus we must maintain consistency of the sockbuf during that time. 40425629Skarels */ 40512757Ssam soreceive(so, aname, uio, flags, rightsp) 4064786Swnj register struct socket *so; 4078300Sroot struct mbuf **aname; 40812757Ssam register struct uio *uio; 4098319Sroot int flags; 41012757Ssam struct mbuf **rightsp; 4114786Swnj { 41226958Skarels register struct mbuf *m; 41332092Skarels register int len, error = 0, s, offset; 41412757Ssam struct protosw *pr = so->so_proto; 41516993Skarels struct mbuf *nextrecord; 41612757Ssam int moff; 4174786Swnj 41812757Ssam if (rightsp) 41912757Ssam *rightsp = 0; 42012757Ssam if (aname) 42112757Ssam *aname = 0; 42212757Ssam if (flags & MSG_OOB) { 4239635Ssam m = m_get(M_WAIT, MT_DATA); 42412757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 42524768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4268594Sroot if (error) 42710137Ssam goto bad; 4288319Sroot do { 42910137Ssam len = uio->uio_resid; 4308319Sroot if (len > m->m_len) 4318319Sroot len = m->m_len; 4328594Sroot error = 4338793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4348319Sroot m = m_free(m); 4358594Sroot } while (uio->uio_resid && error == 0 && m); 43610137Ssam bad: 4378319Sroot if (m) 4388771Sroot m_freem(m); 4398594Sroot return (error); 4408319Sroot } 4418319Sroot 4424890Swnj restart: 4434890Swnj sblock(&so->so_rcv); 4448835Sroot s = splnet(); 4454890Swnj 4464786Swnj if (so->so_rcv.sb_cc == 0) { 4475168Swnj if (so->so_error) { 4485168Swnj error = so->so_error; 4495168Swnj so->so_error = 0; 4505168Swnj goto release; 4515168Swnj } 45232567Sbostic if (so->so_state & SS_CANTRCVMORE) 4534890Swnj goto release; 45432567Sbostic if ((so->so_state & SS_ISCONNECTED) == 0 && 45532567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 45632567Sbostic error = ENOTCONN; 45732567Sbostic goto release; 4584890Swnj } 45925629Skarels if (uio->uio_resid == 0) 46025629Skarels goto release; 46132567Sbostic if (so->so_state & SS_NBIO) { 46232567Sbostic error = EWOULDBLOCK; 46332567Sbostic goto release; 46432567Sbostic } 4654890Swnj sbunlock(&so->so_rcv); 4664971Swnj sbwait(&so->so_rcv); 4675012Swnj splx(s); 4684890Swnj goto restart; 4694786Swnj } 4708041Sroot u.u_ru.ru_msgrcv++; 4714829Swnj m = so->so_rcv.sb_mb; 47225629Skarels if (m == 0) 47325629Skarels panic("receive 1"); 47425629Skarels nextrecord = m->m_act; 47512757Ssam if (pr->pr_flags & PR_ADDR) { 47625629Skarels if (m->m_type != MT_SONAME) 47716993Skarels panic("receive 1a"); 47816993Skarels if (flags & MSG_PEEK) { 47916993Skarels if (aname) 4808319Sroot *aname = m_copy(m, 0, m->m_len); 48125629Skarels m = m->m_next; 48216993Skarels } else { 48325629Skarels sbfree(&so->so_rcv, m); 48416993Skarels if (aname) { 48516993Skarels *aname = m; 48625629Skarels m = m->m_next; 48725629Skarels (*aname)->m_next = 0; 48826958Skarels so->so_rcv.sb_mb = m; 48925629Skarels } else { 49026958Skarels MFREE(m, so->so_rcv.sb_mb); 49126958Skarels m = so->so_rcv.sb_mb; 49225629Skarels } 49326958Skarels if (m) 49426958Skarels m->m_act = nextrecord; 49516993Skarels } 49616993Skarels } 49716993Skarels if (m && m->m_type == MT_RIGHTS) { 49816993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 49926958Skarels panic("receive 2"); 50016993Skarels if (flags & MSG_PEEK) { 50116993Skarels if (rightsp) 50212757Ssam *rightsp = m_copy(m, 0, m->m_len); 50325629Skarels m = m->m_next; 50416993Skarels } else { 50525629Skarels sbfree(&so->so_rcv, m); 50616993Skarels if (rightsp) { 50716993Skarels *rightsp = m; 50826958Skarels so->so_rcv.sb_mb = m->m_next; 50925629Skarels m->m_next = 0; 51026958Skarels m = so->so_rcv.sb_mb; 51125629Skarels } else { 51226958Skarels MFREE(m, so->so_rcv.sb_mb); 51326958Skarels m = so->so_rcv.sb_mb; 51425629Skarels } 51526958Skarels if (m) 51626958Skarels m->m_act = nextrecord; 51712757Ssam } 5184890Swnj } 5198319Sroot moff = 0; 52032092Skarels offset = 0; 52116993Skarels while (m && uio->uio_resid > 0 && error == 0) { 52225629Skarels if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 52325629Skarels panic("receive 3"); 5247827Sroot len = uio->uio_resid; 5257747Sroot so->so_state &= ~SS_RCVATMARK; 52632092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 52732092Skarels len = so->so_oobmark - offset; 52821767Skarels if (len > m->m_len - moff) 5298319Sroot len = m->m_len - moff; 5304786Swnj splx(s); 5318594Sroot error = 5328793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5334786Swnj s = splnet(); 53421767Skarels if (len == m->m_len - moff) { 53525629Skarels if (flags & MSG_PEEK) { 53625629Skarels m = m->m_next; 53725629Skarels moff = 0; 53825629Skarels } else { 53926958Skarels nextrecord = m->m_act; 54025629Skarels sbfree(&so->so_rcv, m); 54126958Skarels MFREE(m, so->so_rcv.sb_mb); 54226958Skarels m = so->so_rcv.sb_mb; 54326958Skarels if (m) 54426958Skarels m->m_act = nextrecord; 54525629Skarels } 5464786Swnj } else { 54712757Ssam if (flags & MSG_PEEK) 5488319Sroot moff += len; 5498319Sroot else { 5508319Sroot m->m_off += len; 5518319Sroot m->m_len -= len; 5528319Sroot so->so_rcv.sb_cc -= len; 5538319Sroot } 5544786Swnj } 55532092Skarels if (so->so_oobmark) { 55632092Skarels if ((flags & MSG_PEEK) == 0) { 55732092Skarels so->so_oobmark -= len; 55832092Skarels if (so->so_oobmark == 0) { 55932092Skarels so->so_state |= SS_RCVATMARK; 56032092Skarels break; 56132092Skarels } 56232092Skarels } else 56332092Skarels offset += len; 5647747Sroot } 56516993Skarels } 56616993Skarels if ((flags & MSG_PEEK) == 0) { 56726500Skarels if (m == 0) 56816993Skarels so->so_rcv.sb_mb = nextrecord; 56926958Skarels else if (pr->pr_flags & PR_ATOMIC) 57026958Skarels (void) sbdroprecord(&so->so_rcv); 57116993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 57216993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 57316993Skarels (struct mbuf *)0, (struct mbuf *)0); 57425629Skarels if (error == 0 && rightsp && *rightsp && 57525629Skarels pr->pr_domain->dom_externalize) 57625629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 57716993Skarels } 5784890Swnj release: 5794916Swnj sbunlock(&so->so_rcv); 5804890Swnj splx(s); 5814916Swnj return (error); 5824786Swnj } 5834786Swnj 58410267Ssam soshutdown(so, how) 58512757Ssam register struct socket *so; 58612757Ssam register int how; 58710267Ssam { 58812757Ssam register struct protosw *pr = so->so_proto; 58910267Ssam 59010267Ssam how++; 59112757Ssam if (how & FREAD) 59212757Ssam sorflush(so); 59310267Ssam if (how & FWRITE) 59412757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 59512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 59610267Ssam return (0); 59710267Ssam } 59810267Ssam 59912757Ssam sorflush(so) 60012757Ssam register struct socket *so; 60112757Ssam { 60212757Ssam register struct sockbuf *sb = &so->so_rcv; 60312757Ssam register struct protosw *pr = so->so_proto; 60412757Ssam register int s; 60512757Ssam struct sockbuf asb; 60612757Ssam 60712757Ssam sblock(sb); 60812757Ssam s = splimp(); 60912757Ssam socantrcvmore(so); 61012757Ssam sbunlock(sb); 61112757Ssam asb = *sb; 61212757Ssam bzero((caddr_t)sb, sizeof (*sb)); 61312757Ssam splx(s); 61416993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 61516993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 61612757Ssam sbrelease(&asb); 61712757Ssam } 61812757Ssam 61918553Skarels sosetopt(so, level, optname, m0) 62012757Ssam register struct socket *so; 62110267Ssam int level, optname; 62218553Skarels struct mbuf *m0; 62310267Ssam { 62417158Ssam int error = 0; 62518553Skarels register struct mbuf *m = m0; 62610267Ssam 62717158Ssam if (level != SOL_SOCKET) { 62818369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 62918369Skarels return ((*so->so_proto->pr_ctloutput) 63018553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 63118369Skarels error = ENOPROTOOPT; 63218369Skarels } else { 63318369Skarels switch (optname) { 63410267Ssam 63518369Skarels case SO_LINGER: 63618369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 63718369Skarels error = EINVAL; 63818369Skarels goto bad; 63918369Skarels } 64018369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 64118369Skarels /* fall thru... */ 64217158Ssam 64318369Skarels case SO_DEBUG: 64418369Skarels case SO_KEEPALIVE: 64518369Skarels case SO_DONTROUTE: 64618369Skarels case SO_USELOOPBACK: 64718369Skarels case SO_BROADCAST: 64818369Skarels case SO_REUSEADDR: 64927191Skarels case SO_OOBINLINE: 65018369Skarels if (m == NULL || m->m_len < sizeof (int)) { 65118369Skarels error = EINVAL; 65218369Skarels goto bad; 65318369Skarels } 65418369Skarels if (*mtod(m, int *)) 65518369Skarels so->so_options |= optname; 65618369Skarels else 65718369Skarels so->so_options &= ~optname; 65818369Skarels break; 65918369Skarels 66018369Skarels case SO_SNDBUF: 66118369Skarels case SO_RCVBUF: 66218369Skarels case SO_SNDLOWAT: 66318369Skarels case SO_RCVLOWAT: 66418369Skarels case SO_SNDTIMEO: 66518369Skarels case SO_RCVTIMEO: 66618369Skarels if (m == NULL || m->m_len < sizeof (int)) { 66718369Skarels error = EINVAL; 66818369Skarels goto bad; 66918369Skarels } 67018369Skarels switch (optname) { 67118369Skarels 67218369Skarels case SO_SNDBUF: 67318369Skarels case SO_RCVBUF: 67418369Skarels if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : 67518369Skarels &so->so_rcv, *mtod(m, int *)) == 0) { 67618369Skarels error = ENOBUFS; 67718369Skarels goto bad; 67818369Skarels } 67918369Skarels break; 68018369Skarels 68118369Skarels case SO_SNDLOWAT: 68218369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 68318369Skarels break; 68418369Skarels case SO_RCVLOWAT: 68518369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 68618369Skarels break; 68718369Skarels case SO_SNDTIMEO: 68818369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 68918369Skarels break; 69018369Skarels case SO_RCVTIMEO: 69118369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 69218369Skarels break; 69318369Skarels } 69418369Skarels break; 69518369Skarels 69618369Skarels default: 69718369Skarels error = ENOPROTOOPT; 69818369Skarels break; 69917158Ssam } 70010267Ssam } 70117158Ssam bad: 70217158Ssam if (m) 70317158Ssam (void) m_free(m); 70417158Ssam return (error); 70510267Ssam } 70610267Ssam 70717158Ssam sogetopt(so, level, optname, mp) 70812757Ssam register struct socket *so; 70910267Ssam int level, optname; 71017158Ssam struct mbuf **mp; 71117158Ssam { 71212757Ssam register struct mbuf *m; 71310267Ssam 71418369Skarels if (level != SOL_SOCKET) { 71518369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 71618369Skarels return ((*so->so_proto->pr_ctloutput) 71718369Skarels (PRCO_GETOPT, so, level, optname, mp)); 71818369Skarels } else 71918369Skarels return (ENOPROTOOPT); 72018369Skarels } else { 72117158Ssam m = m_get(M_WAIT, MT_SOOPTS); 72225502Skarels m->m_len = sizeof (int); 72325502Skarels 72418369Skarels switch (optname) { 72517158Ssam 72618369Skarels case SO_LINGER: 72718369Skarels m->m_len = sizeof (struct linger); 72818369Skarels mtod(m, struct linger *)->l_onoff = 72918369Skarels so->so_options & SO_LINGER; 73018369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 73118369Skarels break; 73210267Ssam 73318369Skarels case SO_USELOOPBACK: 73418369Skarels case SO_DONTROUTE: 73518369Skarels case SO_DEBUG: 73618369Skarels case SO_KEEPALIVE: 73718369Skarels case SO_REUSEADDR: 73818369Skarels case SO_BROADCAST: 73927191Skarels case SO_OOBINLINE: 74018369Skarels *mtod(m, int *) = so->so_options & optname; 74118369Skarels break; 74218369Skarels 74325502Skarels case SO_TYPE: 74425502Skarels *mtod(m, int *) = so->so_type; 74525502Skarels break; 74625502Skarels 74724768Skarels case SO_ERROR: 74824768Skarels *mtod(m, int *) = so->so_error; 74924768Skarels so->so_error = 0; 75024768Skarels break; 75124768Skarels 75218369Skarels case SO_SNDBUF: 75318369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 75418369Skarels break; 75518369Skarels 75618369Skarels case SO_RCVBUF: 75718369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 75818369Skarels break; 75918369Skarels 76018369Skarels case SO_SNDLOWAT: 76118369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 76218369Skarels break; 76318369Skarels 76418369Skarels case SO_RCVLOWAT: 76518369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 76618369Skarels break; 76718369Skarels 76818369Skarels case SO_SNDTIMEO: 76918369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 77018369Skarels break; 77118369Skarels 77218369Skarels case SO_RCVTIMEO: 77318369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 77418369Skarels break; 77518369Skarels 77618369Skarels default: 77726362Skarels (void)m_free(m); 77818369Skarels return (ENOPROTOOPT); 77918369Skarels } 78018369Skarels *mp = m; 78118369Skarels return (0); 78210267Ssam } 78310267Ssam } 78410267Ssam 7855423Swnj sohasoutofband(so) 78612757Ssam register struct socket *so; 7875423Swnj { 78823233Skarels struct proc *p; 7895423Swnj 79023233Skarels if (so->so_pgrp < 0) 79123233Skarels gsignal(-so->so_pgrp, SIGURG); 79223233Skarels else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) 79323233Skarels psignal(p, SIGURG); 79424768Skarels if (so->so_rcv.sb_sel) { 79524768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 79624768Skarels so->so_rcv.sb_sel = 0; 79724768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 79824768Skarels } 7995423Swnj } 800