123421Smckusick /* 235384Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 333185Sbostic * All rights reserved. 423421Smckusick * 533185Sbostic * Redistribution and use in source and binary forms are permitted 634861Sbostic * provided that the above copyright notice and this paragraph are 734861Sbostic * duplicated in all such forms and that any documentation, 834861Sbostic * advertising materials, and other materials related to such 934861Sbostic * distribution and use acknowledge that the software was developed 1034861Sbostic * by the University of California, Berkeley. The name of the 1134861Sbostic * University may not be used to endorse or promote products derived 1234861Sbostic * from this software without specific prior written permission. 1334861Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434861Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534861Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633185Sbostic * 17*37728Smckusick * @(#)uipc_socket.c 7.14 (Berkeley) 05/09/89 1823421Smckusick */ 194786Swnj 2017102Sbloom #include "param.h" 2117102Sbloom #include "user.h" 2217102Sbloom #include "proc.h" 2317102Sbloom #include "file.h" 2435384Skarels #include "malloc.h" 2517102Sbloom #include "mbuf.h" 2617102Sbloom #include "domain.h" 2717102Sbloom #include "protosw.h" 2817102Sbloom #include "socket.h" 2917102Sbloom #include "socketvar.h" 304786Swnj 314786Swnj /* 328300Sroot * Socket operation routines. 338300Sroot * These routines are called by the routines in 348300Sroot * sys_socket.c or from a system process, and 358300Sroot * implement the semantics of socket operations by 368300Sroot * switching out to the protocol specific routines. 3712757Ssam * 3812757Ssam * TODO: 3912757Ssam * test socketpair 4021767Skarels * clean up async 4112757Ssam * out-of-band is a kludge 424786Swnj */ 438594Sroot /*ARGSUSED*/ 4410267Ssam socreate(dom, aso, type, proto) 454786Swnj struct socket **aso; 4612757Ssam register int type; 4712757Ssam int proto; 484786Swnj { 494786Swnj register struct protosw *prp; 504786Swnj register struct socket *so; 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); 6137478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 6237478Ssklower bzero((caddr_t)so, sizeof(*so)); 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, 6921767Skarels (struct mbuf *)0, (struct mbuf *)proto, (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; 11335384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 11412493Ssam splx(s); 1158300Sroot return (0); 1168300Sroot } 1178300Sroot 1184916Swnj sofree(so) 11912757Ssam register struct socket *so; 1204916Swnj { 1214916Swnj 12231810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 12331810Skarels return; 1247507Sroot if (so->so_head) { 1257507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1267507Sroot panic("sofree dq"); 1277507Sroot so->so_head = 0; 1287507Sroot } 1294950Swnj sbrelease(&so->so_snd); 13012757Ssam sorflush(so); 13137478Ssklower FREE(so, M_SOCKET); 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 */ 14333372Sbostic int error = 0; 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) { 15526245Skarels error = sodisconnect(so); 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 { 21630414Skarels int s; 2174890Swnj int error; 2184786Swnj 21930414Skarels if (so->so_options & SO_ACCEPTCONN) 22030414Skarels return (EOPNOTSUPP); 22130414Skarels s = splnet(); 22224768Skarels /* 22324768Skarels * If protocol is connection-based, can only connect once. 22424768Skarels * Otherwise, if connected, try to disconnect first. 22524768Skarels * This allows user to disconnect by connecting to, e.g., 22624768Skarels * a null address. 22724768Skarels */ 22824768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 22924768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 23024768Skarels (error = sodisconnect(so)))) 2314890Swnj error = EISCONN; 23224768Skarels else 23324768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23424768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2354890Swnj splx(s); 2364890Swnj return (error); 2374786Swnj } 2384786Swnj 23912757Ssam soconnect2(so1, so2) 24012757Ssam register struct socket *so1; 24112757Ssam struct socket *so2; 24212757Ssam { 24312757Ssam int s = splnet(); 24412757Ssam int error; 24512757Ssam 24613113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24713113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24812757Ssam splx(s); 24912757Ssam return (error); 25012757Ssam } 25112757Ssam 25226245Skarels sodisconnect(so) 25312757Ssam register struct socket *so; 2544786Swnj { 2554890Swnj int s = splnet(); 2564890Swnj int error; 2574786Swnj 2584890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2594890Swnj error = ENOTCONN; 2604890Swnj goto bad; 2614890Swnj } 2624890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2634890Swnj error = EALREADY; 2644890Swnj goto bad; 2654890Swnj } 2668300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26726245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2684890Swnj bad: 2694890Swnj splx(s); 2704890Swnj return (error); 2714786Swnj } 2724786Swnj 2734786Swnj /* 2744890Swnj * Send on a socket. 2754890Swnj * If send must go all at once and message is larger than 2764890Swnj * send buffering, then hard error. 2774890Swnj * Lock against other senders. 2784890Swnj * If must go all at once and not enough room now, then 2794890Swnj * inform user that this would block and do nothing. 28016412Skarels * Otherwise, if nonblocking, send as much as possible. 2814786Swnj */ 28235384Skarels sosend(so, nam, uio, flags, rights, control) 2834786Swnj register struct socket *so; 2848300Sroot struct mbuf *nam; 28512757Ssam register struct uio *uio; 2868319Sroot int flags; 28735384Skarels struct mbuf *rights, *control; 2884786Swnj { 28935384Skarels struct mbuf *top = 0, **mp; 29035384Skarels register struct mbuf *m; 29135384Skarels register int space, len; 29235384Skarels int rlen = 0, error = 0, s, dontroute, first = 1, mlen; 29335384Skarels int atomic = sosendallatonce(so); 2944786Swnj 29535384Skarels if (atomic && uio->uio_resid > so->so_snd.sb_hiwat) 2964890Swnj return (EMSGSIZE); 29712757Ssam dontroute = 29812757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29912757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30016412Skarels u.u_ru.ru_msgsnd++; 30125629Skarels if (rights) 30225629Skarels rlen = rights->m_len; 30316412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30416412Skarels 3056419Sroot restart: 3064890Swnj sblock(&so->so_snd); 30716412Skarels do { 30816412Skarels s = splnet(); 30921108Skarels if (so->so_state & SS_CANTSENDMORE) 31016412Skarels snderr(EPIPE); 31137478Ssklower if (so->so_error) 31237478Ssklower snderr(so->so_error); 31316412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31437478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 31537478Ssklower if (!uio->uio_resid && !rights && control) { 31637478Ssklower snderr((*so->so_proto->pr_usrreq)(so, 31737478Ssklower (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 31837478Ssklower top, (caddr_t)0, rights, control)); 31937478Ssklower } else if (so->so_state & SS_ISCONFIRMING) 32037478Ssklower /* is ok */; 32137478Ssklower else 32237478Ssklower snderr(ENOTCONN); 32337478Ssklower } else if (nam == 0) 32416412Skarels snderr(EDESTADDRREQ); 32516412Skarels } 32616412Skarels if (flags & MSG_OOB) 32716412Skarels space = 1024; 32816412Skarels else { 32916412Skarels space = sbspace(&so->so_snd); 33025629Skarels if (space <= rlen || 33135384Skarels (atomic && space < uio->uio_resid + rlen) || 33235384Skarels (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 33335384Skarels so->so_snd.sb_cc >= MCLBYTES && 33416992Skarels (so->so_state & SS_NBIO) == 0)) { 33516412Skarels if (so->so_state & SS_NBIO) { 33616412Skarels if (first) 33716412Skarels error = EWOULDBLOCK; 33816412Skarels splx(s); 33916412Skarels goto release; 34016412Skarels } 34116412Skarels sbunlock(&so->so_snd); 34216412Skarels sbwait(&so->so_snd); 34316412Skarels splx(s); 34416412Skarels goto restart; 34516412Skarels } 34616412Skarels } 34716412Skarels splx(s); 34816412Skarels mp = ⊤ 34925629Skarels space -= rlen; 35035384Skarels do { 35135384Skarels do { 35235384Skarels if (top == 0) { 35335384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35435384Skarels mlen = MHLEN; 35535384Skarels m->m_pkthdr.len = 0; 35635384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35735384Skarels } else { 35835384Skarels MGET(m, M_WAIT, MT_DATA); 35935384Skarels mlen = MLEN; 36035384Skarels } 36135384Skarels if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 36235384Skarels MCLGET(m, M_WAIT); 36335384Skarels if ((m->m_flags & M_EXT) == 0) 36416412Skarels goto nopages; 36535384Skarels mlen = MCLBYTES; 36635384Skarels #ifdef MAPPED_MBUFS 36735384Skarels len = min(MCLBYTES, uio->uio_resid); 36835384Skarels if (len < mlen - max_hdr) 36935384Skarels m->m_data += max_hdr; 37035384Skarels #else 37135384Skarels len = min(MCLBYTES - max_hdr, uio->uio_resid); 37235384Skarels m->m_data += max_hdr; 37335384Skarels #endif 37435384Skarels space -= MCLBYTES; 37516412Skarels } else { 37616412Skarels nopages: 37735384Skarels len = min(min(mlen, uio->uio_resid), space); 37821767Skarels space -= len; 37935384Skarels /* 38035384Skarels * For datagram protocols, leave room 38135384Skarels * for protocol headers in first mbuf. 38235384Skarels */ 38335391Skarels if (atomic && top == 0 && len < mlen) 38435384Skarels MH_ALIGN(m, len); 38516412Skarels } 386*37728Smckusick error = uiomove(mtod(m, caddr_t), len, uio); 38716412Skarels m->m_len = len; 38816412Skarels *mp = m; 38935384Skarels top->m_pkthdr.len += len; 39016412Skarels if (error) 39116412Skarels goto release; 39216412Skarels mp = &m->m_next; 39335384Skarels if (uio->uio_resid <= 0) { 39435384Skarels if ((flags & MSG_EOR) && top) 39535384Skarels top->m_flags |= M_EOR; 39621108Skarels break; 39735384Skarels } 39835384Skarels } while (space > 0 && atomic); 39935384Skarels if (dontroute) 40035384Skarels so->so_options |= SO_DONTROUTE; 40135384Skarels s = splnet(); /* XXX */ 40235384Skarels error = (*so->so_proto->pr_usrreq)(so, 40335384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40435384Skarels top, (caddr_t)nam, rights, control); 40535384Skarels splx(s); 40635384Skarels if (dontroute) 40735384Skarels so->so_options &= ~SO_DONTROUTE; 40835384Skarels rights = 0; 40935384Skarels rlen = 0; 41035384Skarels top = 0; 41135384Skarels mp = ⊤ 41235384Skarels first = 0; 41335384Skarels if (error) 41435384Skarels goto release; 41535384Skarels } while (uio->uio_resid && space > 0); 41616412Skarels } while (uio->uio_resid); 4174890Swnj 4184786Swnj release: 4194890Swnj sbunlock(&so->so_snd); 4206419Sroot if (top) 4216419Sroot m_freem(top); 42221108Skarels if (error == EPIPE) 42321108Skarels psignal(u.u_procp, SIGPIPE); 4244786Swnj return (error); 4254786Swnj } 4264786Swnj 42725629Skarels /* 42825629Skarels * Implement receive operations on a socket. 42925629Skarels * We depend on the way that records are added to the sockbuf 43025629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 43125629Skarels * must begin with an address if the protocol so specifies, 43225629Skarels * followed by an optional mbuf containing access rights if supported 43325629Skarels * by the protocol, and then zero or more mbufs of data. 43425629Skarels * In order to avoid blocking network interrupts for the entire time here, 43525629Skarels * we splx() while doing the actual copy to user space. 43625629Skarels * Although the sockbuf is locked, new data may still be appended, 43725629Skarels * and thus we must maintain consistency of the sockbuf during that time. 43825629Skarels */ 43935384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp) 4404786Swnj register struct socket *so; 4418300Sroot struct mbuf **aname; 44212757Ssam register struct uio *uio; 44335384Skarels int *flagsp; 44435384Skarels struct mbuf **rightsp, **controlp; 4454786Swnj { 44626958Skarels register struct mbuf *m; 44735384Skarels register int flags, len, error = 0, s, offset; 44812757Ssam struct protosw *pr = so->so_proto; 44916993Skarels struct mbuf *nextrecord; 45012757Ssam int moff; 4514786Swnj 45212757Ssam if (rightsp) 45312757Ssam *rightsp = 0; 45412757Ssam if (aname) 45512757Ssam *aname = 0; 45635384Skarels if (controlp) 45735384Skarels *controlp = 0; 45835384Skarels if (flagsp) 45935384Skarels flags = *flagsp &~ MSG_EOR; 46035384Skarels else 46135384Skarels flags = 0; 46212757Ssam if (flags & MSG_OOB) { 4639635Ssam m = m_get(M_WAIT, MT_DATA); 46412757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 46524768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4668594Sroot if (error) 46710137Ssam goto bad; 4688319Sroot do { 46910137Ssam len = uio->uio_resid; 4708319Sroot if (len > m->m_len) 4718319Sroot len = m->m_len; 472*37728Smckusick error = uiomove(mtod(m, caddr_t), (int)len, uio); 4738319Sroot m = m_free(m); 4748594Sroot } while (uio->uio_resid && error == 0 && m); 47510137Ssam bad: 4768319Sroot if (m) 4778771Sroot m_freem(m); 4788594Sroot return (error); 4798319Sroot } 48037478Ssklower if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 48135384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 48235384Skarels (struct mbuf *)0, (struct mbuf *)0); 4838319Sroot 4844890Swnj restart: 4854890Swnj sblock(&so->so_rcv); 4868835Sroot s = splnet(); 4874890Swnj 48837478Ssklower m = so->so_rcv.sb_mb; 48937478Ssklower if (m == 0) { 49037478Ssklower if (so->so_rcv.sb_cc) 49137478Ssklower panic("receive 1"); 4925168Swnj if (so->so_error) { 4935168Swnj error = so->so_error; 4945168Swnj so->so_error = 0; 4955168Swnj goto release; 4965168Swnj } 49732567Sbostic if (so->so_state & SS_CANTRCVMORE) 4984890Swnj goto release; 49932567Sbostic if ((so->so_state & SS_ISCONNECTED) == 0 && 50032567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 50132567Sbostic error = ENOTCONN; 50232567Sbostic goto release; 5034890Swnj } 50425629Skarels if (uio->uio_resid == 0) 50525629Skarels goto release; 50632567Sbostic if (so->so_state & SS_NBIO) { 50732567Sbostic error = EWOULDBLOCK; 50832567Sbostic goto release; 50932567Sbostic } 5104890Swnj sbunlock(&so->so_rcv); 5114971Swnj sbwait(&so->so_rcv); 5125012Swnj splx(s); 5134890Swnj goto restart; 5144786Swnj } 5158041Sroot u.u_ru.ru_msgrcv++; 51635384Skarels if (m->m_type == 0) 51735384Skarels panic("receive 3a"); 51835384Skarels nextrecord = m->m_nextpkt; 51912757Ssam if (pr->pr_flags & PR_ADDR) { 52025629Skarels if (m->m_type != MT_SONAME) 52116993Skarels panic("receive 1a"); 52216993Skarels if (flags & MSG_PEEK) { 52316993Skarels if (aname) 5248319Sroot *aname = m_copy(m, 0, m->m_len); 52525629Skarels m = m->m_next; 52616993Skarels } else { 52725629Skarels sbfree(&so->so_rcv, m); 52816993Skarels if (aname) { 52916993Skarels *aname = m; 53035384Skarels so->so_rcv.sb_mb = m->m_next; 53135384Skarels m->m_next = 0; 53235384Skarels m = so->so_rcv.sb_mb; 53325629Skarels } else { 53426958Skarels MFREE(m, so->so_rcv.sb_mb); 53526958Skarels m = so->so_rcv.sb_mb; 53625629Skarels } 53716993Skarels } 53816993Skarels } 53916993Skarels if (m && m->m_type == MT_RIGHTS) { 54016993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 54126958Skarels panic("receive 2"); 54216993Skarels if (flags & MSG_PEEK) { 54316993Skarels if (rightsp) 54412757Ssam *rightsp = m_copy(m, 0, m->m_len); 54525629Skarels m = m->m_next; 54616993Skarels } else { 54725629Skarels sbfree(&so->so_rcv, m); 54816993Skarels if (rightsp) { 54916993Skarels *rightsp = m; 55026958Skarels so->so_rcv.sb_mb = m->m_next; 55125629Skarels m->m_next = 0; 55226958Skarels m = so->so_rcv.sb_mb; 55325629Skarels } else { 55426958Skarels MFREE(m, so->so_rcv.sb_mb); 55526958Skarels m = so->so_rcv.sb_mb; 55625629Skarels } 55712757Ssam } 5584890Swnj } 55935384Skarels if (m && m->m_type == MT_CONTROL) { 56035384Skarels if (flags & MSG_PEEK) { 56135384Skarels if (controlp) 56235384Skarels *controlp = m_copy(m, 0, m->m_len); 56335384Skarels m = m->m_next; 56435384Skarels } else { 56535384Skarels sbfree(&so->so_rcv, m); 56635384Skarels if (controlp) { 56735384Skarels *controlp = m; 56835384Skarels so->so_rcv.sb_mb = m->m_next; 56935384Skarels m->m_next = 0; 57035384Skarels m = so->so_rcv.sb_mb; 57135384Skarels } else { 57235384Skarels MFREE(m, so->so_rcv.sb_mb); 57335384Skarels m = so->so_rcv.sb_mb; 57435384Skarels } 57535384Skarels } 57635384Skarels } 57735384Skarels if (m) 57835384Skarels m->m_nextpkt = nextrecord; 5798319Sroot moff = 0; 58032092Skarels offset = 0; 58116993Skarels while (m && uio->uio_resid > 0 && error == 0) { 58235384Skarels if (m->m_type == MT_OOBDATA) 58335384Skarels flags |= MSG_OOB; 58435384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 58525629Skarels panic("receive 3"); 58635384Skarels if (m->m_flags & M_EOR) 58735384Skarels flags |= MSG_EOR; 5887827Sroot len = uio->uio_resid; 5897747Sroot so->so_state &= ~SS_RCVATMARK; 59032092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 59132092Skarels len = so->so_oobmark - offset; 59221767Skarels if (len > m->m_len - moff) 5938319Sroot len = m->m_len - moff; 5944786Swnj splx(s); 595*37728Smckusick error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 5964786Swnj s = splnet(); 59721767Skarels if (len == m->m_len - moff) { 59825629Skarels if (flags & MSG_PEEK) { 59925629Skarels m = m->m_next; 60025629Skarels moff = 0; 60125629Skarels } else { 60235384Skarels nextrecord = m->m_nextpkt; 60325629Skarels sbfree(&so->so_rcv, m); 60426958Skarels MFREE(m, so->so_rcv.sb_mb); 60526958Skarels m = so->so_rcv.sb_mb; 60626958Skarels if (m) 60735384Skarels m->m_nextpkt = nextrecord; 60825629Skarels } 6094786Swnj } else { 61012757Ssam if (flags & MSG_PEEK) 6118319Sroot moff += len; 6128319Sroot else { 61335384Skarels m->m_data += len; 6148319Sroot m->m_len -= len; 6158319Sroot so->so_rcv.sb_cc -= len; 6168319Sroot } 6174786Swnj } 61832092Skarels if (so->so_oobmark) { 61932092Skarels if ((flags & MSG_PEEK) == 0) { 62032092Skarels so->so_oobmark -= len; 62132092Skarels if (so->so_oobmark == 0) { 62232092Skarels so->so_state |= SS_RCVATMARK; 62332092Skarels break; 62432092Skarels } 62532092Skarels } else 62632092Skarels offset += len; 6277747Sroot } 62816993Skarels } 62935384Skarels if (m && (flags & MSG_EOR)) { 63035384Skarels flags &= ~MSG_EOR; 63135384Skarels if ((flags & MSG_PEEK) == 0) 63235384Skarels m->m_flags |= M_EOR; 63335384Skarels } 63416993Skarels if ((flags & MSG_PEEK) == 0) { 63526500Skarels if (m == 0) 63616993Skarels so->so_rcv.sb_mb = nextrecord; 63735384Skarels else if (pr->pr_flags & PR_ATOMIC) { 63835384Skarels flags |= MSG_TRUNC; 63926958Skarels (void) sbdroprecord(&so->so_rcv); 64035384Skarels } 64116993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 64216993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 64337478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 64437478Ssklower (struct mbuf *)0); 64525629Skarels if (error == 0 && rightsp && *rightsp && 64625629Skarels pr->pr_domain->dom_externalize) 64725629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 64816993Skarels } 64935384Skarels if (flagsp) 65035384Skarels *flagsp |= flags; 6514890Swnj release: 6524916Swnj sbunlock(&so->so_rcv); 6534890Swnj splx(s); 6544916Swnj return (error); 6554786Swnj } 6564786Swnj 65710267Ssam soshutdown(so, how) 65812757Ssam register struct socket *so; 65912757Ssam register int how; 66010267Ssam { 66112757Ssam register struct protosw *pr = so->so_proto; 66210267Ssam 66310267Ssam how++; 66412757Ssam if (how & FREAD) 66512757Ssam sorflush(so); 66610267Ssam if (how & FWRITE) 66712757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 66812757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 66910267Ssam return (0); 67010267Ssam } 67110267Ssam 67212757Ssam sorflush(so) 67312757Ssam register struct socket *so; 67412757Ssam { 67512757Ssam register struct sockbuf *sb = &so->so_rcv; 67612757Ssam register struct protosw *pr = so->so_proto; 67712757Ssam register int s; 67812757Ssam struct sockbuf asb; 67912757Ssam 68012757Ssam sblock(sb); 68112757Ssam s = splimp(); 68212757Ssam socantrcvmore(so); 68312757Ssam sbunlock(sb); 68412757Ssam asb = *sb; 68512757Ssam bzero((caddr_t)sb, sizeof (*sb)); 68612757Ssam splx(s); 68716993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 68816993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 68912757Ssam sbrelease(&asb); 69012757Ssam } 69112757Ssam 69218553Skarels sosetopt(so, level, optname, m0) 69312757Ssam register struct socket *so; 69410267Ssam int level, optname; 69518553Skarels struct mbuf *m0; 69610267Ssam { 69717158Ssam int error = 0; 69818553Skarels register struct mbuf *m = m0; 69910267Ssam 70017158Ssam if (level != SOL_SOCKET) { 70118369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 70218369Skarels return ((*so->so_proto->pr_ctloutput) 70318553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 70418369Skarels error = ENOPROTOOPT; 70518369Skarels } else { 70618369Skarels switch (optname) { 70710267Ssam 70818369Skarels case SO_LINGER: 70918369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 71018369Skarels error = EINVAL; 71118369Skarels goto bad; 71218369Skarels } 71318369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 71418369Skarels /* fall thru... */ 71517158Ssam 71618369Skarels case SO_DEBUG: 71718369Skarels case SO_KEEPALIVE: 71818369Skarels case SO_DONTROUTE: 71918369Skarels case SO_USELOOPBACK: 72018369Skarels case SO_BROADCAST: 72118369Skarels case SO_REUSEADDR: 72227191Skarels case SO_OOBINLINE: 72318369Skarels if (m == NULL || m->m_len < sizeof (int)) { 72418369Skarels error = EINVAL; 72518369Skarels goto bad; 72618369Skarels } 72718369Skarels if (*mtod(m, int *)) 72818369Skarels so->so_options |= optname; 72918369Skarels else 73018369Skarels so->so_options &= ~optname; 73118369Skarels break; 73218369Skarels 73318369Skarels case SO_SNDBUF: 73418369Skarels case SO_RCVBUF: 73518369Skarels case SO_SNDLOWAT: 73618369Skarels case SO_RCVLOWAT: 73718369Skarels case SO_SNDTIMEO: 73818369Skarels case SO_RCVTIMEO: 73918369Skarels if (m == NULL || m->m_len < sizeof (int)) { 74018369Skarels error = EINVAL; 74118369Skarels goto bad; 74218369Skarels } 74318369Skarels switch (optname) { 74418369Skarels 74518369Skarels case SO_SNDBUF: 74618369Skarels case SO_RCVBUF: 74734492Skarels if (sbreserve(optname == SO_SNDBUF ? 74834492Skarels &so->so_snd : &so->so_rcv, 74934492Skarels (u_long) *mtod(m, int *)) == 0) { 75018369Skarels error = ENOBUFS; 75118369Skarels goto bad; 75218369Skarels } 75318369Skarels break; 75418369Skarels 75518369Skarels case SO_SNDLOWAT: 75618369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 75718369Skarels break; 75818369Skarels case SO_RCVLOWAT: 75918369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 76018369Skarels break; 76118369Skarels case SO_SNDTIMEO: 76218369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 76318369Skarels break; 76418369Skarels case SO_RCVTIMEO: 76518369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 76618369Skarels break; 76718369Skarels } 76818369Skarels break; 76918369Skarels 77018369Skarels default: 77118369Skarels error = ENOPROTOOPT; 77218369Skarels break; 77317158Ssam } 77410267Ssam } 77517158Ssam bad: 77617158Ssam if (m) 77717158Ssam (void) m_free(m); 77817158Ssam return (error); 77910267Ssam } 78010267Ssam 78117158Ssam sogetopt(so, level, optname, mp) 78212757Ssam register struct socket *so; 78310267Ssam int level, optname; 78417158Ssam struct mbuf **mp; 78517158Ssam { 78612757Ssam register struct mbuf *m; 78710267Ssam 78818369Skarels if (level != SOL_SOCKET) { 78918369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 79018369Skarels return ((*so->so_proto->pr_ctloutput) 79118369Skarels (PRCO_GETOPT, so, level, optname, mp)); 79218369Skarels } else 79318369Skarels return (ENOPROTOOPT); 79418369Skarels } else { 79517158Ssam m = m_get(M_WAIT, MT_SOOPTS); 79625502Skarels m->m_len = sizeof (int); 79725502Skarels 79818369Skarels switch (optname) { 79917158Ssam 80018369Skarels case SO_LINGER: 80118369Skarels m->m_len = sizeof (struct linger); 80218369Skarels mtod(m, struct linger *)->l_onoff = 80318369Skarels so->so_options & SO_LINGER; 80418369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 80518369Skarels break; 80610267Ssam 80718369Skarels case SO_USELOOPBACK: 80818369Skarels case SO_DONTROUTE: 80918369Skarels case SO_DEBUG: 81018369Skarels case SO_KEEPALIVE: 81118369Skarels case SO_REUSEADDR: 81218369Skarels case SO_BROADCAST: 81327191Skarels case SO_OOBINLINE: 81418369Skarels *mtod(m, int *) = so->so_options & optname; 81518369Skarels break; 81618369Skarels 81725502Skarels case SO_TYPE: 81825502Skarels *mtod(m, int *) = so->so_type; 81925502Skarels break; 82025502Skarels 82124768Skarels case SO_ERROR: 82224768Skarels *mtod(m, int *) = so->so_error; 82324768Skarels so->so_error = 0; 82424768Skarels break; 82524768Skarels 82618369Skarels case SO_SNDBUF: 82718369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 82818369Skarels break; 82918369Skarels 83018369Skarels case SO_RCVBUF: 83118369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 83218369Skarels break; 83318369Skarels 83418369Skarels case SO_SNDLOWAT: 83518369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 83618369Skarels break; 83718369Skarels 83818369Skarels case SO_RCVLOWAT: 83918369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 84018369Skarels break; 84118369Skarels 84218369Skarels case SO_SNDTIMEO: 84318369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 84418369Skarels break; 84518369Skarels 84618369Skarels case SO_RCVTIMEO: 84718369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 84818369Skarels break; 84918369Skarels 85018369Skarels default: 85126362Skarels (void)m_free(m); 85218369Skarels return (ENOPROTOOPT); 85318369Skarels } 85418369Skarels *mp = m; 85518369Skarels return (0); 85610267Ssam } 85710267Ssam } 85810267Ssam 8595423Swnj sohasoutofband(so) 86012757Ssam register struct socket *so; 8615423Swnj { 86223233Skarels struct proc *p; 8635423Swnj 86437478Ssklower if (so->so_pgid < 0) 86537478Ssklower gsignal(-so->so_pgid, SIGURG); 86637478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 86723233Skarels psignal(p, SIGURG); 86824768Skarels if (so->so_rcv.sb_sel) { 86924768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 87024768Skarels so->so_rcv.sb_sel = 0; 87124768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 87224768Skarels } 8735423Swnj } 874