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*30414Skarels * @(#)uipc_socket.c 7.2 (Berkeley) 01/18/87 723421Smckusick */ 84786Swnj 917102Sbloom #include "param.h" 1017102Sbloom #include "systm.h" 1117102Sbloom #include "dir.h" 1217102Sbloom #include "user.h" 1317102Sbloom #include "proc.h" 1417102Sbloom #include "file.h" 1517102Sbloom #include "inode.h" 1617102Sbloom #include "buf.h" 1717102Sbloom #include "mbuf.h" 1817102Sbloom #include "un.h" 1917102Sbloom #include "domain.h" 2017102Sbloom #include "protosw.h" 2117102Sbloom #include "socket.h" 2217102Sbloom #include "socketvar.h" 2317102Sbloom #include "stat.h" 2417102Sbloom #include "ioctl.h" 2517102Sbloom #include "uio.h" 266355Ssam #include "../net/route.h" 2712757Ssam #include "../netinet/in.h" 2811571Ssam #include "../net/if.h" 294786Swnj 304786Swnj /* 318300Sroot * Socket operation routines. 328300Sroot * These routines are called by the routines in 338300Sroot * sys_socket.c or from a system process, and 348300Sroot * implement the semantics of socket operations by 358300Sroot * switching out to the protocol specific routines. 3612757Ssam * 3712757Ssam * TODO: 3812757Ssam * test socketpair 3921767Skarels * clean up async 4012757Ssam * out-of-band is a kludge 414786Swnj */ 428594Sroot /*ARGSUSED*/ 4310267Ssam socreate(dom, aso, type, proto) 444786Swnj struct socket **aso; 4512757Ssam register int type; 4612757Ssam int proto; 474786Swnj { 484786Swnj register struct protosw *prp; 494786Swnj register struct socket *so; 5012757Ssam register struct mbuf *m; 5112757Ssam register int error; 524786Swnj 534890Swnj if (proto) 5421767Skarels prp = pffindproto(dom, proto, type); 554890Swnj else 569168Ssam prp = pffindtype(dom, type); 574890Swnj if (prp == 0) 584890Swnj return (EPROTONOSUPPORT); 598300Sroot if (prp->pr_type != type) 608300Sroot return (EPROTOTYPE); 619635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 624786Swnj so = mtod(m, struct socket *); 6312757Ssam so->so_options = 0; 646214Swnj so->so_state = 0; 659168Ssam so->so_type = type; 666214Swnj if (u.u_uid == 0) 676214Swnj so->so_state = SS_PRIV; 684786Swnj so->so_proto = prp; 6912757Ssam error = 7012757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 7121767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 724979Swnj if (error) { 737507Sroot so->so_state |= SS_NOFDREF; 747180Swnj sofree(so); 754890Swnj return (error); 764786Swnj } 774786Swnj *aso = so; 784786Swnj return (0); 794786Swnj } 804786Swnj 8110267Ssam sobind(so, nam) 828300Sroot struct socket *so; 838300Sroot struct mbuf *nam; 848300Sroot { 858300Sroot int s = splnet(); 868300Sroot int error; 878300Sroot 888300Sroot error = 8912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 9012757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 918300Sroot splx(s); 928300Sroot return (error); 938300Sroot } 948300Sroot 958300Sroot solisten(so, backlog) 9612757Ssam register struct socket *so; 978300Sroot int backlog; 988300Sroot { 9912757Ssam int s = splnet(), error; 1008300Sroot 10112757Ssam error = 10212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 10312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1048300Sroot if (error) { 1058300Sroot splx(s); 1068300Sroot return (error); 1078300Sroot } 1088300Sroot if (so->so_q == 0) { 1098300Sroot so->so_q = so; 1108300Sroot so->so_q0 = so; 1118300Sroot so->so_options |= SO_ACCEPTCONN; 1128300Sroot } 1138300Sroot if (backlog < 0) 1148300Sroot backlog = 0; 11510137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 11612493Ssam splx(s); 1178300Sroot return (0); 1188300Sroot } 1198300Sroot 1204916Swnj sofree(so) 12112757Ssam register struct socket *so; 1224916Swnj { 1234916Swnj 1247507Sroot if (so->so_head) { 1257507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1267507Sroot panic("sofree dq"); 1277507Sroot so->so_head = 0; 1287507Sroot } 1297507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1304950Swnj return; 1314950Swnj sbrelease(&so->so_snd); 13212757Ssam sorflush(so); 1334971Swnj (void) m_free(dtom(so)); 1344916Swnj } 1354916Swnj 1364786Swnj /* 1374890Swnj * Close a socket on last file table reference removal. 1384890Swnj * Initiate disconnect if connected. 1394890Swnj * Free socket when disconnect complete. 1404829Swnj */ 14112757Ssam soclose(so) 1424829Swnj register struct socket *so; 1434829Swnj { 1444890Swnj int s = splnet(); /* conservative */ 1458713Sroot int error; 1464829Swnj 1477507Sroot if (so->so_options & SO_ACCEPTCONN) { 1487507Sroot while (so->so_q0 != so) 14910399Ssam (void) soabort(so->so_q0); 1507507Sroot while (so->so_q != so) 15110399Ssam (void) soabort(so->so_q); 1527507Sroot } 1534890Swnj if (so->so_pcb == 0) 1544890Swnj goto discard; 1554890Swnj if (so->so_state & SS_ISCONNECTED) { 1564890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 15726245Skarels error = sodisconnect(so); 15812757Ssam if (error) 15912757Ssam goto drop; 1604890Swnj } 16110267Ssam if (so->so_options & SO_LINGER) { 1625281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 16312757Ssam (so->so_state & SS_NBIO)) 16412757Ssam goto drop; 1655281Sroot while (so->so_state & SS_ISCONNECTED) 1665281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1674890Swnj } 1684890Swnj } 1695580Sroot drop: 1706880Ssam if (so->so_pcb) { 17112757Ssam int error2 = 17212757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17412757Ssam if (error == 0) 17512757Ssam error = error2; 1766880Ssam } 1774890Swnj discard: 17810399Ssam if (so->so_state & SS_NOFDREF) 17910399Ssam panic("soclose: NOFDREF"); 1807507Sroot so->so_state |= SS_NOFDREF; 1814950Swnj sofree(so); 1824890Swnj splx(s); 18312757Ssam return (error); 1844829Swnj } 1854829Swnj 18610399Ssam /* 18710399Ssam * Must be called at splnet... 18810399Ssam */ 18910399Ssam soabort(so) 19010399Ssam struct socket *so; 19110399Ssam { 19210399Ssam 19312757Ssam return ( 19412757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19610399Ssam } 19710399Ssam 19810267Ssam soaccept(so, nam) 19912757Ssam register struct socket *so; 2008300Sroot struct mbuf *nam; 2014927Swnj { 2024927Swnj int s = splnet(); 2034927Swnj int error; 2044927Swnj 20510399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20610399Ssam panic("soaccept: !NOFDREF"); 20710267Ssam so->so_state &= ~SS_NOFDREF; 2088300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20912757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2104927Swnj splx(s); 2114927Swnj return (error); 2124927Swnj } 2134927Swnj 21410267Ssam soconnect(so, nam) 21512757Ssam register struct socket *so; 2168300Sroot struct mbuf *nam; 2174786Swnj { 218*30414Skarels int s; 2194890Swnj int error; 2204786Swnj 221*30414Skarels if (so->so_options & SO_ACCEPTCONN) 222*30414Skarels return (EOPNOTSUPP); 223*30414Skarels s = splnet(); 22424768Skarels /* 22524768Skarels * If protocol is connection-based, can only connect once. 22624768Skarels * Otherwise, if connected, try to disconnect first. 22724768Skarels * This allows user to disconnect by connecting to, e.g., 22824768Skarels * a null address. 22924768Skarels */ 23024768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 23124768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 23224768Skarels (error = sodisconnect(so)))) 2334890Swnj error = EISCONN; 23424768Skarels else 23524768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23624768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2374890Swnj splx(s); 2384890Swnj return (error); 2394786Swnj } 2404786Swnj 24112757Ssam soconnect2(so1, so2) 24212757Ssam register struct socket *so1; 24312757Ssam struct socket *so2; 24412757Ssam { 24512757Ssam int s = splnet(); 24612757Ssam int error; 24712757Ssam 24813113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24913113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 25012757Ssam splx(s); 25112757Ssam return (error); 25212757Ssam } 25312757Ssam 25426245Skarels sodisconnect(so) 25512757Ssam register struct socket *so; 2564786Swnj { 2574890Swnj int s = splnet(); 2584890Swnj int error; 2594786Swnj 2604890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2614890Swnj error = ENOTCONN; 2624890Swnj goto bad; 2634890Swnj } 2644890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2654890Swnj error = EALREADY; 2664890Swnj goto bad; 2674890Swnj } 2688300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26926245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2704890Swnj bad: 2714890Swnj splx(s); 2724890Swnj return (error); 2734786Swnj } 2744786Swnj 2754786Swnj /* 2764890Swnj * Send on a socket. 2774890Swnj * If send must go all at once and message is larger than 2784890Swnj * send buffering, then hard error. 2794890Swnj * Lock against other senders. 2804890Swnj * If must go all at once and not enough room now, then 2814890Swnj * inform user that this would block and do nothing. 28216412Skarels * Otherwise, if nonblocking, send as much as possible. 2834786Swnj */ 28412757Ssam sosend(so, nam, uio, flags, rights) 2854786Swnj register struct socket *so; 2868300Sroot struct mbuf *nam; 28712757Ssam register struct uio *uio; 2888319Sroot int flags; 28912757Ssam struct mbuf *rights; 2904786Swnj { 2914890Swnj struct mbuf *top = 0; 29216412Skarels register struct mbuf *m, **mp; 29312757Ssam register int space; 29425629Skarels int len, rlen = 0, error = 0, s, dontroute, first = 1; 2954786Swnj 2967827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2974890Swnj return (EMSGSIZE); 29812757Ssam dontroute = 29912757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 30012757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30116412Skarels u.u_ru.ru_msgsnd++; 30225629Skarels if (rights) 30325629Skarels rlen = rights->m_len; 30416412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30516412Skarels 3066419Sroot restart: 3074890Swnj sblock(&so->so_snd); 30816412Skarels do { 30916412Skarels s = splnet(); 31021108Skarels if (so->so_state & SS_CANTSENDMORE) 31116412Skarels snderr(EPIPE); 31216412Skarels if (so->so_error) { 31316412Skarels error = so->so_error; 31416412Skarels so->so_error = 0; /* ??? */ 31516412Skarels splx(s); 31616412Skarels goto release; 31716412Skarels } 31816412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31916412Skarels if (so->so_proto->pr_flags & PR_CONNREQUIRED) 32016412Skarels snderr(ENOTCONN); 32116412Skarels if (nam == 0) 32216412Skarels snderr(EDESTADDRREQ); 32316412Skarels } 32416412Skarels if (flags & MSG_OOB) 32516412Skarels space = 1024; 32616412Skarels else { 32716412Skarels space = sbspace(&so->so_snd); 32825629Skarels if (space <= rlen || 32925629Skarels (sosendallatonce(so) && 33025629Skarels space < uio->uio_resid + rlen) || 33116992Skarels (uio->uio_resid >= CLBYTES && space < CLBYTES && 33216992Skarels so->so_snd.sb_cc >= CLBYTES && 33316992Skarels (so->so_state & SS_NBIO) == 0)) { 33416412Skarels if (so->so_state & SS_NBIO) { 33516412Skarels if (first) 33616412Skarels error = EWOULDBLOCK; 33716412Skarels splx(s); 33816412Skarels goto release; 33916412Skarels } 34016412Skarels sbunlock(&so->so_snd); 34116412Skarels sbwait(&so->so_snd); 34216412Skarels splx(s); 34316412Skarels goto restart; 34416412Skarels } 34516412Skarels } 34616412Skarels splx(s); 34716412Skarels mp = ⊤ 34825629Skarels space -= rlen; 34921108Skarels while (space > 0) { 35016412Skarels MGET(m, M_WAIT, MT_DATA); 35126958Skarels if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) { 35226228Skarels MCLGET(m); 35326228Skarels if (m->m_len != CLBYTES) 35416412Skarels goto nopages; 35526958Skarels len = MIN(CLBYTES, uio->uio_resid); 35621767Skarels space -= CLBYTES; 35716412Skarels } else { 35816412Skarels nopages: 35926958Skarels len = MIN(MIN(MLEN, uio->uio_resid), space); 36021767Skarels space -= len; 36116412Skarels } 36216412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 36316412Skarels m->m_len = len; 36416412Skarels *mp = m; 36516412Skarels if (error) 36616412Skarels goto release; 36716412Skarels mp = &m->m_next; 36821108Skarels if (uio->uio_resid <= 0) 36921108Skarels break; 37016412Skarels } 37121108Skarels if (dontroute) 37221108Skarels so->so_options |= SO_DONTROUTE; 37321108Skarels s = splnet(); /* XXX */ 37421108Skarels error = (*so->so_proto->pr_usrreq)(so, 37521108Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 37621108Skarels top, (caddr_t)nam, rights); 37721108Skarels splx(s); 37821108Skarels if (dontroute) 37921108Skarels so->so_options &= ~SO_DONTROUTE; 38021767Skarels rights = 0; 38125629Skarels rlen = 0; 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); 39221108Skarels if (error == EPIPE) 39321108Skarels psignal(u.u_procp, SIGPIPE); 3944786Swnj return (error); 3954786Swnj } 3964786Swnj 39725629Skarels /* 39825629Skarels * Implement receive operations on a socket. 39925629Skarels * We depend on the way that records are added to the sockbuf 40025629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 40125629Skarels * must begin with an address if the protocol so specifies, 40225629Skarels * followed by an optional mbuf containing access rights if supported 40325629Skarels * by the protocol, and then zero or more mbufs of data. 40425629Skarels * In order to avoid blocking network interrupts for the entire time here, 40525629Skarels * we splx() while doing the actual copy to user space. 40625629Skarels * Although the sockbuf is locked, new data may still be appended, 40725629Skarels * and thus we must maintain consistency of the sockbuf during that time. 40825629Skarels */ 40912757Ssam soreceive(so, aname, uio, flags, rightsp) 4104786Swnj register struct socket *so; 4118300Sroot struct mbuf **aname; 41212757Ssam register struct uio *uio; 4138319Sroot int flags; 41412757Ssam struct mbuf **rightsp; 4154786Swnj { 41626958Skarels register struct mbuf *m; 41716993Skarels register int len, error = 0, s, tomark; 41812757Ssam struct protosw *pr = so->so_proto; 41916993Skarels struct mbuf *nextrecord; 42012757Ssam int moff; 4214786Swnj 42212757Ssam if (rightsp) 42312757Ssam *rightsp = 0; 42412757Ssam if (aname) 42512757Ssam *aname = 0; 42612757Ssam if (flags & MSG_OOB) { 4279635Ssam m = m_get(M_WAIT, MT_DATA); 42812757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 42924768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4308594Sroot if (error) 43110137Ssam goto bad; 4328319Sroot do { 43310137Ssam len = uio->uio_resid; 4348319Sroot if (len > m->m_len) 4358319Sroot len = m->m_len; 4368594Sroot error = 4378793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4388319Sroot m = m_free(m); 4398594Sroot } while (uio->uio_resid && error == 0 && m); 44010137Ssam bad: 4418319Sroot if (m) 4428771Sroot m_freem(m); 4438594Sroot return (error); 4448319Sroot } 4458319Sroot 4464890Swnj restart: 4474890Swnj sblock(&so->so_rcv); 4488835Sroot s = splnet(); 4494890Swnj 4504890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4514786Swnj if (so->so_rcv.sb_cc == 0) { 4525168Swnj if (so->so_error) { 4535168Swnj error = so->so_error; 4545168Swnj so->so_error = 0; 4555168Swnj splx(s); 4565168Swnj goto release; 4575168Swnj } 4584890Swnj if (so->so_state & SS_CANTRCVMORE) { 4594890Swnj splx(s); 4604890Swnj goto release; 4614890Swnj } 4625015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4635015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4645015Sroot rcverr(ENOTCONN); 46525629Skarels if (uio->uio_resid == 0) 46625629Skarels goto release; 4676214Swnj if (so->so_state & SS_NBIO) 4685168Swnj rcverr(EWOULDBLOCK); 4694890Swnj sbunlock(&so->so_rcv); 4704971Swnj sbwait(&so->so_rcv); 4715012Swnj splx(s); 4724890Swnj goto restart; 4734786Swnj } 4748041Sroot u.u_ru.ru_msgrcv++; 4754829Swnj m = so->so_rcv.sb_mb; 47625629Skarels if (m == 0) 47725629Skarels panic("receive 1"); 47825629Skarels nextrecord = m->m_act; 47912757Ssam if (pr->pr_flags & PR_ADDR) { 48025629Skarels if (m->m_type != MT_SONAME) 48116993Skarels panic("receive 1a"); 48216993Skarels if (flags & MSG_PEEK) { 48316993Skarels if (aname) 4848319Sroot *aname = m_copy(m, 0, m->m_len); 48525629Skarels m = m->m_next; 48616993Skarels } else { 48725629Skarels sbfree(&so->so_rcv, m); 48816993Skarels if (aname) { 48916993Skarels *aname = m; 49025629Skarels m = m->m_next; 49125629Skarels (*aname)->m_next = 0; 49226958Skarels so->so_rcv.sb_mb = m; 49325629Skarels } else { 49426958Skarels MFREE(m, so->so_rcv.sb_mb); 49526958Skarels m = so->so_rcv.sb_mb; 49625629Skarels } 49726958Skarels if (m) 49826958Skarels m->m_act = nextrecord; 49916993Skarels } 50016993Skarels } 50116993Skarels if (m && m->m_type == MT_RIGHTS) { 50216993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 50326958Skarels panic("receive 2"); 50416993Skarels if (flags & MSG_PEEK) { 50516993Skarels if (rightsp) 50612757Ssam *rightsp = m_copy(m, 0, m->m_len); 50725629Skarels m = m->m_next; 50816993Skarels } else { 50925629Skarels sbfree(&so->so_rcv, m); 51016993Skarels if (rightsp) { 51116993Skarels *rightsp = m; 51226958Skarels so->so_rcv.sb_mb = m->m_next; 51325629Skarels m->m_next = 0; 51426958Skarels m = so->so_rcv.sb_mb; 51525629Skarels } else { 51626958Skarels MFREE(m, so->so_rcv.sb_mb); 51726958Skarels m = so->so_rcv.sb_mb; 51825629Skarels } 51926958Skarels if (m) 52026958Skarels m->m_act = nextrecord; 52112757Ssam } 5224890Swnj } 5238319Sroot moff = 0; 5248319Sroot tomark = so->so_oobmark; 52516993Skarels while (m && uio->uio_resid > 0 && error == 0) { 52625629Skarels if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 52725629Skarels panic("receive 3"); 5287827Sroot len = uio->uio_resid; 5297747Sroot so->so_state &= ~SS_RCVATMARK; 5308319Sroot if (tomark && len > tomark) 5318319Sroot len = tomark; 53221767Skarels if (len > m->m_len - moff) 5338319Sroot len = m->m_len - moff; 5344786Swnj splx(s); 5358594Sroot error = 5368793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5374786Swnj s = splnet(); 53821767Skarels if (len == m->m_len - moff) { 53925629Skarels if (flags & MSG_PEEK) { 54025629Skarels m = m->m_next; 54125629Skarels moff = 0; 54225629Skarels } else { 54326958Skarels nextrecord = m->m_act; 54425629Skarels sbfree(&so->so_rcv, m); 54526958Skarels MFREE(m, so->so_rcv.sb_mb); 54626958Skarels m = so->so_rcv.sb_mb; 54726958Skarels if (m) 54826958Skarels m->m_act = nextrecord; 54925629Skarels } 5504786Swnj } else { 55112757Ssam if (flags & MSG_PEEK) 5528319Sroot moff += len; 5538319Sroot else { 5548319Sroot m->m_off += len; 5558319Sroot m->m_len -= len; 5568319Sroot so->so_rcv.sb_cc -= len; 5578319Sroot } 5584786Swnj } 55912757Ssam if ((flags & MSG_PEEK) == 0 && so->so_oobmark) { 5607747Sroot so->so_oobmark -= len; 5617747Sroot if (so->so_oobmark == 0) { 5627747Sroot so->so_state |= SS_RCVATMARK; 5637747Sroot break; 5647747Sroot } 5657747Sroot } 5668319Sroot if (tomark) { 5678319Sroot tomark -= len; 5688319Sroot if (tomark == 0) 5698319Sroot break; 5708319Sroot } 57116993Skarels } 57216993Skarels if ((flags & MSG_PEEK) == 0) { 57326500Skarels if (m == 0) 57416993Skarels so->so_rcv.sb_mb = nextrecord; 57526958Skarels else if (pr->pr_flags & PR_ATOMIC) 57626958Skarels (void) sbdroprecord(&so->so_rcv); 57716993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 57816993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 57916993Skarels (struct mbuf *)0, (struct mbuf *)0); 58025629Skarels if (error == 0 && rightsp && *rightsp && 58125629Skarels pr->pr_domain->dom_externalize) 58225629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 58316993Skarels } 5844890Swnj release: 5854916Swnj sbunlock(&so->so_rcv); 5864890Swnj splx(s); 5874916Swnj return (error); 5884786Swnj } 5894786Swnj 59010267Ssam soshutdown(so, how) 59112757Ssam register struct socket *so; 59212757Ssam register int how; 59310267Ssam { 59412757Ssam register struct protosw *pr = so->so_proto; 59510267Ssam 59610267Ssam how++; 59712757Ssam if (how & FREAD) 59812757Ssam sorflush(so); 59910267Ssam if (how & FWRITE) 60012757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 60112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 60210267Ssam return (0); 60310267Ssam } 60410267Ssam 60512757Ssam sorflush(so) 60612757Ssam register struct socket *so; 60712757Ssam { 60812757Ssam register struct sockbuf *sb = &so->so_rcv; 60912757Ssam register struct protosw *pr = so->so_proto; 61012757Ssam register int s; 61112757Ssam struct sockbuf asb; 61212757Ssam 61312757Ssam sblock(sb); 61412757Ssam s = splimp(); 61512757Ssam socantrcvmore(so); 61612757Ssam sbunlock(sb); 61712757Ssam asb = *sb; 61812757Ssam bzero((caddr_t)sb, sizeof (*sb)); 61912757Ssam splx(s); 62016993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 62116993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 62212757Ssam sbrelease(&asb); 62312757Ssam } 62412757Ssam 62518553Skarels sosetopt(so, level, optname, m0) 62612757Ssam register struct socket *so; 62710267Ssam int level, optname; 62818553Skarels struct mbuf *m0; 62910267Ssam { 63017158Ssam int error = 0; 63118553Skarels register struct mbuf *m = m0; 63210267Ssam 63317158Ssam if (level != SOL_SOCKET) { 63418369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 63518369Skarels return ((*so->so_proto->pr_ctloutput) 63618553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 63718369Skarels error = ENOPROTOOPT; 63818369Skarels } else { 63918369Skarels switch (optname) { 64010267Ssam 64118369Skarels case SO_LINGER: 64218369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 64318369Skarels error = EINVAL; 64418369Skarels goto bad; 64518369Skarels } 64618369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 64718369Skarels /* fall thru... */ 64817158Ssam 64918369Skarels case SO_DEBUG: 65018369Skarels case SO_KEEPALIVE: 65118369Skarels case SO_DONTROUTE: 65218369Skarels case SO_USELOOPBACK: 65318369Skarels case SO_BROADCAST: 65418369Skarels case SO_REUSEADDR: 65527191Skarels case SO_OOBINLINE: 65618369Skarels if (m == NULL || m->m_len < sizeof (int)) { 65718369Skarels error = EINVAL; 65818369Skarels goto bad; 65918369Skarels } 66018369Skarels if (*mtod(m, int *)) 66118369Skarels so->so_options |= optname; 66218369Skarels else 66318369Skarels so->so_options &= ~optname; 66418369Skarels break; 66518369Skarels 66618369Skarels case SO_SNDBUF: 66718369Skarels case SO_RCVBUF: 66818369Skarels case SO_SNDLOWAT: 66918369Skarels case SO_RCVLOWAT: 67018369Skarels case SO_SNDTIMEO: 67118369Skarels case SO_RCVTIMEO: 67218369Skarels if (m == NULL || m->m_len < sizeof (int)) { 67318369Skarels error = EINVAL; 67418369Skarels goto bad; 67518369Skarels } 67618369Skarels switch (optname) { 67718369Skarels 67818369Skarels case SO_SNDBUF: 67918369Skarels case SO_RCVBUF: 68018369Skarels if (sbreserve(optname == SO_SNDBUF ? &so->so_snd : 68118369Skarels &so->so_rcv, *mtod(m, int *)) == 0) { 68218369Skarels error = ENOBUFS; 68318369Skarels goto bad; 68418369Skarels } 68518369Skarels break; 68618369Skarels 68718369Skarels case SO_SNDLOWAT: 68818369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 68918369Skarels break; 69018369Skarels case SO_RCVLOWAT: 69118369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 69218369Skarels break; 69318369Skarels case SO_SNDTIMEO: 69418369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 69518369Skarels break; 69618369Skarels case SO_RCVTIMEO: 69718369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 69818369Skarels break; 69918369Skarels } 70018369Skarels break; 70118369Skarels 70218369Skarels default: 70318369Skarels error = ENOPROTOOPT; 70418369Skarels break; 70517158Ssam } 70610267Ssam } 70717158Ssam bad: 70817158Ssam if (m) 70917158Ssam (void) m_free(m); 71017158Ssam return (error); 71110267Ssam } 71210267Ssam 71317158Ssam sogetopt(so, level, optname, mp) 71412757Ssam register struct socket *so; 71510267Ssam int level, optname; 71617158Ssam struct mbuf **mp; 71717158Ssam { 71812757Ssam register struct mbuf *m; 71910267Ssam 72018369Skarels if (level != SOL_SOCKET) { 72118369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 72218369Skarels return ((*so->so_proto->pr_ctloutput) 72318369Skarels (PRCO_GETOPT, so, level, optname, mp)); 72418369Skarels } else 72518369Skarels return (ENOPROTOOPT); 72618369Skarels } else { 72717158Ssam m = m_get(M_WAIT, MT_SOOPTS); 72825502Skarels m->m_len = sizeof (int); 72925502Skarels 73018369Skarels switch (optname) { 73117158Ssam 73218369Skarels case SO_LINGER: 73318369Skarels m->m_len = sizeof (struct linger); 73418369Skarels mtod(m, struct linger *)->l_onoff = 73518369Skarels so->so_options & SO_LINGER; 73618369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 73718369Skarels break; 73810267Ssam 73918369Skarels case SO_USELOOPBACK: 74018369Skarels case SO_DONTROUTE: 74118369Skarels case SO_DEBUG: 74218369Skarels case SO_KEEPALIVE: 74318369Skarels case SO_REUSEADDR: 74418369Skarels case SO_BROADCAST: 74527191Skarels case SO_OOBINLINE: 74618369Skarels *mtod(m, int *) = so->so_options & optname; 74718369Skarels break; 74818369Skarels 74925502Skarels case SO_TYPE: 75025502Skarels *mtod(m, int *) = so->so_type; 75125502Skarels break; 75225502Skarels 75324768Skarels case SO_ERROR: 75424768Skarels *mtod(m, int *) = so->so_error; 75524768Skarels so->so_error = 0; 75624768Skarels break; 75724768Skarels 75818369Skarels case SO_SNDBUF: 75918369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 76018369Skarels break; 76118369Skarels 76218369Skarels case SO_RCVBUF: 76318369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 76418369Skarels break; 76518369Skarels 76618369Skarels case SO_SNDLOWAT: 76718369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 76818369Skarels break; 76918369Skarels 77018369Skarels case SO_RCVLOWAT: 77118369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 77218369Skarels break; 77318369Skarels 77418369Skarels case SO_SNDTIMEO: 77518369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 77618369Skarels break; 77718369Skarels 77818369Skarels case SO_RCVTIMEO: 77918369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 78018369Skarels break; 78118369Skarels 78218369Skarels default: 78326362Skarels (void)m_free(m); 78418369Skarels return (ENOPROTOOPT); 78518369Skarels } 78618369Skarels *mp = m; 78718369Skarels return (0); 78810267Ssam } 78910267Ssam } 79010267Ssam 7915423Swnj sohasoutofband(so) 79212757Ssam register struct socket *so; 7935423Swnj { 79423233Skarels struct proc *p; 7955423Swnj 79623233Skarels if (so->so_pgrp < 0) 79723233Skarels gsignal(-so->so_pgrp, SIGURG); 79823233Skarels else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0) 79923233Skarels psignal(p, SIGURG); 80024768Skarels if (so->so_rcv.sb_sel) { 80124768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 80224768Skarels so->so_rcv.sb_sel = 0; 80324768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 80424768Skarels } 8055423Swnj } 806