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*38584Skarels * @(#)uipc_socket.c 7.15 (Berkeley) 08/11/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 } 106*38584Skarels if (so->so_q == 0) 1078300Sroot so->so_options |= SO_ACCEPTCONN; 1088300Sroot if (backlog < 0) 1098300Sroot backlog = 0; 11035384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 11112493Ssam splx(s); 1128300Sroot return (0); 1138300Sroot } 1148300Sroot 1154916Swnj sofree(so) 11612757Ssam register struct socket *so; 1174916Swnj { 1184916Swnj 11931810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 12031810Skarels return; 1217507Sroot if (so->so_head) { 1227507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1237507Sroot panic("sofree dq"); 1247507Sroot so->so_head = 0; 1257507Sroot } 1264950Swnj sbrelease(&so->so_snd); 12712757Ssam sorflush(so); 12837478Ssklower FREE(so, M_SOCKET); 1294916Swnj } 1304916Swnj 1314786Swnj /* 1324890Swnj * Close a socket on last file table reference removal. 1334890Swnj * Initiate disconnect if connected. 1344890Swnj * Free socket when disconnect complete. 1354829Swnj */ 13612757Ssam soclose(so) 1374829Swnj register struct socket *so; 1384829Swnj { 1394890Swnj int s = splnet(); /* conservative */ 14033372Sbostic int error = 0; 1414829Swnj 1427507Sroot if (so->so_options & SO_ACCEPTCONN) { 143*38584Skarels while (so->so_q0) 14410399Ssam (void) soabort(so->so_q0); 145*38584Skarels while (so->so_q) 14610399Ssam (void) soabort(so->so_q); 1477507Sroot } 1484890Swnj if (so->so_pcb == 0) 1494890Swnj goto discard; 1504890Swnj if (so->so_state & SS_ISCONNECTED) { 1514890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 15226245Skarels error = sodisconnect(so); 15312757Ssam if (error) 15412757Ssam goto drop; 1554890Swnj } 15610267Ssam if (so->so_options & SO_LINGER) { 1575281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15812757Ssam (so->so_state & SS_NBIO)) 15912757Ssam goto drop; 1605281Sroot while (so->so_state & SS_ISCONNECTED) 1615281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1624890Swnj } 1634890Swnj } 1645580Sroot drop: 1656880Ssam if (so->so_pcb) { 16612757Ssam int error2 = 16712757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16812757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 16912757Ssam if (error == 0) 17012757Ssam error = error2; 1716880Ssam } 1724890Swnj discard: 17310399Ssam if (so->so_state & SS_NOFDREF) 17410399Ssam panic("soclose: NOFDREF"); 1757507Sroot so->so_state |= SS_NOFDREF; 1764950Swnj sofree(so); 1774890Swnj splx(s); 17812757Ssam return (error); 1794829Swnj } 1804829Swnj 18110399Ssam /* 18210399Ssam * Must be called at splnet... 18310399Ssam */ 18410399Ssam soabort(so) 18510399Ssam struct socket *so; 18610399Ssam { 18710399Ssam 18812757Ssam return ( 18912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19012757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19110399Ssam } 19210399Ssam 19310267Ssam soaccept(so, nam) 19412757Ssam register struct socket *so; 1958300Sroot struct mbuf *nam; 1964927Swnj { 1974927Swnj int s = splnet(); 1984927Swnj int error; 1994927Swnj 20010399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20110399Ssam panic("soaccept: !NOFDREF"); 20210267Ssam so->so_state &= ~SS_NOFDREF; 2038300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20412757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2054927Swnj splx(s); 2064927Swnj return (error); 2074927Swnj } 2084927Swnj 20910267Ssam soconnect(so, nam) 21012757Ssam register struct socket *so; 2118300Sroot struct mbuf *nam; 2124786Swnj { 21330414Skarels int s; 2144890Swnj int error; 2154786Swnj 21630414Skarels if (so->so_options & SO_ACCEPTCONN) 21730414Skarels return (EOPNOTSUPP); 21830414Skarels s = splnet(); 21924768Skarels /* 22024768Skarels * If protocol is connection-based, can only connect once. 22124768Skarels * Otherwise, if connected, try to disconnect first. 22224768Skarels * This allows user to disconnect by connecting to, e.g., 22324768Skarels * a null address. 22424768Skarels */ 22524768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 22624768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 22724768Skarels (error = sodisconnect(so)))) 2284890Swnj error = EISCONN; 22924768Skarels else 23024768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23124768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2324890Swnj splx(s); 2334890Swnj return (error); 2344786Swnj } 2354786Swnj 23612757Ssam soconnect2(so1, so2) 23712757Ssam register struct socket *so1; 23812757Ssam struct socket *so2; 23912757Ssam { 24012757Ssam int s = splnet(); 24112757Ssam int error; 24212757Ssam 24313113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24413113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24512757Ssam splx(s); 24612757Ssam return (error); 24712757Ssam } 24812757Ssam 24926245Skarels sodisconnect(so) 25012757Ssam register struct socket *so; 2514786Swnj { 2524890Swnj int s = splnet(); 2534890Swnj int error; 2544786Swnj 2554890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2564890Swnj error = ENOTCONN; 2574890Swnj goto bad; 2584890Swnj } 2594890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2604890Swnj error = EALREADY; 2614890Swnj goto bad; 2624890Swnj } 2638300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26426245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2654890Swnj bad: 2664890Swnj splx(s); 2674890Swnj return (error); 2684786Swnj } 2694786Swnj 2704786Swnj /* 2714890Swnj * Send on a socket. 2724890Swnj * If send must go all at once and message is larger than 2734890Swnj * send buffering, then hard error. 2744890Swnj * Lock against other senders. 2754890Swnj * If must go all at once and not enough room now, then 2764890Swnj * inform user that this would block and do nothing. 27716412Skarels * Otherwise, if nonblocking, send as much as possible. 2784786Swnj */ 27935384Skarels sosend(so, nam, uio, flags, rights, control) 2804786Swnj register struct socket *so; 2818300Sroot struct mbuf *nam; 28212757Ssam register struct uio *uio; 2838319Sroot int flags; 28435384Skarels struct mbuf *rights, *control; 2854786Swnj { 28635384Skarels struct mbuf *top = 0, **mp; 28735384Skarels register struct mbuf *m; 28835384Skarels register int space, len; 28935384Skarels int rlen = 0, error = 0, s, dontroute, first = 1, mlen; 29035384Skarels int atomic = sosendallatonce(so); 2914786Swnj 29235384Skarels if (atomic && 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); 30837478Ssklower if (so->so_error) 30937478Ssklower snderr(so->so_error); 31016412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31137478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 312*38584Skarels if ((so->so_state & SS_ISCONFIRMING) == 0) 31337478Ssklower snderr(ENOTCONN); 31437478Ssklower } else if (nam == 0) 31516412Skarels snderr(EDESTADDRREQ); 31616412Skarels } 31716412Skarels if (flags & MSG_OOB) 31816412Skarels space = 1024; 31916412Skarels else { 32016412Skarels space = sbspace(&so->so_snd); 32125629Skarels if (space <= rlen || 32235384Skarels (atomic && space < uio->uio_resid + rlen) || 32335384Skarels (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 32435384Skarels so->so_snd.sb_cc >= MCLBYTES && 32516992Skarels (so->so_state & SS_NBIO) == 0)) { 32616412Skarels if (so->so_state & SS_NBIO) { 32716412Skarels if (first) 32816412Skarels error = EWOULDBLOCK; 32916412Skarels splx(s); 33016412Skarels goto release; 33116412Skarels } 33216412Skarels sbunlock(&so->so_snd); 33316412Skarels sbwait(&so->so_snd); 33416412Skarels splx(s); 33516412Skarels goto restart; 33616412Skarels } 33716412Skarels } 33816412Skarels splx(s); 33916412Skarels mp = ⊤ 34025629Skarels space -= rlen; 34135384Skarels do { 34235384Skarels do { 34335384Skarels if (top == 0) { 34435384Skarels MGETHDR(m, M_WAIT, MT_DATA); 34535384Skarels mlen = MHLEN; 34635384Skarels m->m_pkthdr.len = 0; 34735384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 34835384Skarels } else { 34935384Skarels MGET(m, M_WAIT, MT_DATA); 35035384Skarels mlen = MLEN; 35135384Skarels } 35235384Skarels if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 35335384Skarels MCLGET(m, M_WAIT); 35435384Skarels if ((m->m_flags & M_EXT) == 0) 35516412Skarels goto nopages; 35635384Skarels mlen = MCLBYTES; 35735384Skarels #ifdef MAPPED_MBUFS 35835384Skarels len = min(MCLBYTES, uio->uio_resid); 35935384Skarels if (len < mlen - max_hdr) 36035384Skarels m->m_data += max_hdr; 36135384Skarels #else 36235384Skarels len = min(MCLBYTES - max_hdr, uio->uio_resid); 36335384Skarels m->m_data += max_hdr; 36435384Skarels #endif 36535384Skarels space -= MCLBYTES; 36616412Skarels } else { 36716412Skarels nopages: 36835384Skarels len = min(min(mlen, uio->uio_resid), space); 36921767Skarels space -= len; 37035384Skarels /* 37135384Skarels * For datagram protocols, leave room 37235384Skarels * for protocol headers in first mbuf. 37335384Skarels */ 37435391Skarels if (atomic && top == 0 && len < mlen) 37535384Skarels MH_ALIGN(m, len); 37616412Skarels } 37737728Smckusick error = uiomove(mtod(m, caddr_t), len, uio); 37816412Skarels m->m_len = len; 37916412Skarels *mp = m; 38035384Skarels top->m_pkthdr.len += len; 38116412Skarels if (error) 38216412Skarels goto release; 38316412Skarels mp = &m->m_next; 38435384Skarels if (uio->uio_resid <= 0) { 38535384Skarels if ((flags & MSG_EOR) && top) 38635384Skarels top->m_flags |= M_EOR; 38721108Skarels break; 38835384Skarels } 38935384Skarels } while (space > 0 && atomic); 39035384Skarels if (dontroute) 39135384Skarels so->so_options |= SO_DONTROUTE; 39235384Skarels s = splnet(); /* XXX */ 39335384Skarels error = (*so->so_proto->pr_usrreq)(so, 39435384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 39535384Skarels top, (caddr_t)nam, rights, control); 39635384Skarels splx(s); 39735384Skarels if (dontroute) 39835384Skarels so->so_options &= ~SO_DONTROUTE; 39935384Skarels rights = 0; 40035384Skarels rlen = 0; 40135384Skarels top = 0; 40235384Skarels mp = ⊤ 40335384Skarels first = 0; 40435384Skarels if (error) 40535384Skarels goto release; 40635384Skarels } while (uio->uio_resid && space > 0); 40716412Skarels } while (uio->uio_resid); 4084890Swnj 4094786Swnj release: 4104890Swnj sbunlock(&so->so_snd); 4116419Sroot if (top) 4126419Sroot m_freem(top); 41321108Skarels if (error == EPIPE) 41421108Skarels psignal(u.u_procp, SIGPIPE); 4154786Swnj return (error); 4164786Swnj } 4174786Swnj 41825629Skarels /* 41925629Skarels * Implement receive operations on a socket. 42025629Skarels * We depend on the way that records are added to the sockbuf 42125629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 42225629Skarels * must begin with an address if the protocol so specifies, 42325629Skarels * followed by an optional mbuf containing access rights if supported 42425629Skarels * by the protocol, and then zero or more mbufs of data. 42525629Skarels * In order to avoid blocking network interrupts for the entire time here, 42625629Skarels * we splx() while doing the actual copy to user space. 42725629Skarels * Although the sockbuf is locked, new data may still be appended, 42825629Skarels * and thus we must maintain consistency of the sockbuf during that time. 42925629Skarels */ 43035384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp) 4314786Swnj register struct socket *so; 4328300Sroot struct mbuf **aname; 43312757Ssam register struct uio *uio; 43435384Skarels int *flagsp; 43535384Skarels struct mbuf **rightsp, **controlp; 4364786Swnj { 43726958Skarels register struct mbuf *m; 43835384Skarels register int flags, len, error = 0, s, offset; 43912757Ssam struct protosw *pr = so->so_proto; 44016993Skarels struct mbuf *nextrecord; 44112757Ssam int moff; 4424786Swnj 44312757Ssam if (rightsp) 44412757Ssam *rightsp = 0; 44512757Ssam if (aname) 44612757Ssam *aname = 0; 44735384Skarels if (controlp) 44835384Skarels *controlp = 0; 44935384Skarels if (flagsp) 45035384Skarels flags = *flagsp &~ MSG_EOR; 45135384Skarels else 45235384Skarels flags = 0; 45312757Ssam if (flags & MSG_OOB) { 4549635Ssam m = m_get(M_WAIT, MT_DATA); 45512757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 45624768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4578594Sroot if (error) 45810137Ssam goto bad; 4598319Sroot do { 46010137Ssam len = uio->uio_resid; 4618319Sroot if (len > m->m_len) 4628319Sroot len = m->m_len; 46337728Smckusick error = uiomove(mtod(m, caddr_t), (int)len, uio); 4648319Sroot m = m_free(m); 4658594Sroot } while (uio->uio_resid && error == 0 && m); 46610137Ssam bad: 4678319Sroot if (m) 4688771Sroot m_freem(m); 4698594Sroot return (error); 4708319Sroot } 47137478Ssklower if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 47235384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 47335384Skarels (struct mbuf *)0, (struct mbuf *)0); 4748319Sroot 4754890Swnj restart: 4764890Swnj sblock(&so->so_rcv); 4778835Sroot s = splnet(); 4784890Swnj 47937478Ssklower m = so->so_rcv.sb_mb; 48037478Ssklower if (m == 0) { 48137478Ssklower if (so->so_rcv.sb_cc) 48237478Ssklower panic("receive 1"); 4835168Swnj if (so->so_error) { 4845168Swnj error = so->so_error; 4855168Swnj so->so_error = 0; 4865168Swnj goto release; 4875168Swnj } 48832567Sbostic if (so->so_state & SS_CANTRCVMORE) 4894890Swnj goto release; 490*38584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 49132567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 49232567Sbostic error = ENOTCONN; 49332567Sbostic goto release; 4944890Swnj } 49525629Skarels if (uio->uio_resid == 0) 49625629Skarels goto release; 49732567Sbostic if (so->so_state & SS_NBIO) { 49832567Sbostic error = EWOULDBLOCK; 49932567Sbostic goto release; 50032567Sbostic } 5014890Swnj sbunlock(&so->so_rcv); 5024971Swnj sbwait(&so->so_rcv); 5035012Swnj splx(s); 5044890Swnj goto restart; 5054786Swnj } 5068041Sroot u.u_ru.ru_msgrcv++; 50735384Skarels if (m->m_type == 0) 50835384Skarels panic("receive 3a"); 50935384Skarels nextrecord = m->m_nextpkt; 51012757Ssam if (pr->pr_flags & PR_ADDR) { 51125629Skarels if (m->m_type != MT_SONAME) 51216993Skarels panic("receive 1a"); 51316993Skarels if (flags & MSG_PEEK) { 51416993Skarels if (aname) 5158319Sroot *aname = m_copy(m, 0, m->m_len); 51625629Skarels m = m->m_next; 51716993Skarels } else { 51825629Skarels sbfree(&so->so_rcv, m); 51916993Skarels if (aname) { 52016993Skarels *aname = m; 52135384Skarels so->so_rcv.sb_mb = m->m_next; 52235384Skarels m->m_next = 0; 52335384Skarels m = so->so_rcv.sb_mb; 52425629Skarels } else { 52526958Skarels MFREE(m, so->so_rcv.sb_mb); 52626958Skarels m = so->so_rcv.sb_mb; 52725629Skarels } 52816993Skarels } 52916993Skarels } 53016993Skarels if (m && m->m_type == MT_RIGHTS) { 53116993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 53226958Skarels panic("receive 2"); 53316993Skarels if (flags & MSG_PEEK) { 53416993Skarels if (rightsp) 53512757Ssam *rightsp = m_copy(m, 0, m->m_len); 53625629Skarels m = m->m_next; 53716993Skarels } else { 53825629Skarels sbfree(&so->so_rcv, m); 53916993Skarels if (rightsp) { 54016993Skarels *rightsp = m; 54126958Skarels so->so_rcv.sb_mb = m->m_next; 54225629Skarels m->m_next = 0; 54326958Skarels m = so->so_rcv.sb_mb; 54425629Skarels } else { 54526958Skarels MFREE(m, so->so_rcv.sb_mb); 54626958Skarels m = so->so_rcv.sb_mb; 54725629Skarels } 54812757Ssam } 5494890Swnj } 55035384Skarels if (m && m->m_type == MT_CONTROL) { 55135384Skarels if (flags & MSG_PEEK) { 55235384Skarels if (controlp) 55335384Skarels *controlp = m_copy(m, 0, m->m_len); 55435384Skarels m = m->m_next; 55535384Skarels } else { 55635384Skarels sbfree(&so->so_rcv, m); 55735384Skarels if (controlp) { 55835384Skarels *controlp = m; 55935384Skarels so->so_rcv.sb_mb = m->m_next; 56035384Skarels m->m_next = 0; 56135384Skarels m = so->so_rcv.sb_mb; 56235384Skarels } else { 56335384Skarels MFREE(m, so->so_rcv.sb_mb); 56435384Skarels m = so->so_rcv.sb_mb; 56535384Skarels } 56635384Skarels } 56735384Skarels } 56835384Skarels if (m) 56935384Skarels m->m_nextpkt = nextrecord; 5708319Sroot moff = 0; 57132092Skarels offset = 0; 57216993Skarels while (m && uio->uio_resid > 0 && error == 0) { 57335384Skarels if (m->m_type == MT_OOBDATA) 57435384Skarels flags |= MSG_OOB; 57535384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 57625629Skarels panic("receive 3"); 57735384Skarels if (m->m_flags & M_EOR) 57835384Skarels flags |= MSG_EOR; 5797827Sroot len = uio->uio_resid; 5807747Sroot so->so_state &= ~SS_RCVATMARK; 58132092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 58232092Skarels len = so->so_oobmark - offset; 58321767Skarels if (len > m->m_len - moff) 5848319Sroot len = m->m_len - moff; 5854786Swnj splx(s); 58637728Smckusick error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 5874786Swnj s = splnet(); 58821767Skarels if (len == m->m_len - moff) { 58925629Skarels if (flags & MSG_PEEK) { 59025629Skarels m = m->m_next; 59125629Skarels moff = 0; 59225629Skarels } else { 59335384Skarels nextrecord = m->m_nextpkt; 59425629Skarels sbfree(&so->so_rcv, m); 59526958Skarels MFREE(m, so->so_rcv.sb_mb); 59626958Skarels m = so->so_rcv.sb_mb; 59726958Skarels if (m) 59835384Skarels m->m_nextpkt = nextrecord; 59925629Skarels } 6004786Swnj } else { 60112757Ssam if (flags & MSG_PEEK) 6028319Sroot moff += len; 6038319Sroot else { 60435384Skarels m->m_data += len; 6058319Sroot m->m_len -= len; 6068319Sroot so->so_rcv.sb_cc -= len; 6078319Sroot } 6084786Swnj } 60932092Skarels if (so->so_oobmark) { 61032092Skarels if ((flags & MSG_PEEK) == 0) { 61132092Skarels so->so_oobmark -= len; 61232092Skarels if (so->so_oobmark == 0) { 61332092Skarels so->so_state |= SS_RCVATMARK; 61432092Skarels break; 61532092Skarels } 61632092Skarels } else 61732092Skarels offset += len; 6187747Sroot } 61916993Skarels } 62035384Skarels if (m && (flags & MSG_EOR)) { 62135384Skarels flags &= ~MSG_EOR; 62235384Skarels if ((flags & MSG_PEEK) == 0) 62335384Skarels m->m_flags |= M_EOR; 62435384Skarels } 62516993Skarels if ((flags & MSG_PEEK) == 0) { 62626500Skarels if (m == 0) 62716993Skarels so->so_rcv.sb_mb = nextrecord; 62835384Skarels else if (pr->pr_flags & PR_ATOMIC) { 62935384Skarels flags |= MSG_TRUNC; 63026958Skarels (void) sbdroprecord(&so->so_rcv); 63135384Skarels } 63216993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 63316993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 63437478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 63537478Ssklower (struct mbuf *)0); 63625629Skarels if (error == 0 && rightsp && *rightsp && 63725629Skarels pr->pr_domain->dom_externalize) 63825629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 63916993Skarels } 64035384Skarels if (flagsp) 64135384Skarels *flagsp |= flags; 6424890Swnj release: 6434916Swnj sbunlock(&so->so_rcv); 6444890Swnj splx(s); 6454916Swnj return (error); 6464786Swnj } 6474786Swnj 64810267Ssam soshutdown(so, how) 64912757Ssam register struct socket *so; 65012757Ssam register int how; 65110267Ssam { 65212757Ssam register struct protosw *pr = so->so_proto; 65310267Ssam 65410267Ssam how++; 65512757Ssam if (how & FREAD) 65612757Ssam sorflush(so); 65710267Ssam if (how & FWRITE) 65812757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 65912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 66010267Ssam return (0); 66110267Ssam } 66210267Ssam 66312757Ssam sorflush(so) 66412757Ssam register struct socket *so; 66512757Ssam { 66612757Ssam register struct sockbuf *sb = &so->so_rcv; 66712757Ssam register struct protosw *pr = so->so_proto; 66812757Ssam register int s; 66912757Ssam struct sockbuf asb; 67012757Ssam 67112757Ssam sblock(sb); 67212757Ssam s = splimp(); 67312757Ssam socantrcvmore(so); 67412757Ssam sbunlock(sb); 67512757Ssam asb = *sb; 67612757Ssam bzero((caddr_t)sb, sizeof (*sb)); 67712757Ssam splx(s); 67816993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 67916993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 68012757Ssam sbrelease(&asb); 68112757Ssam } 68212757Ssam 68318553Skarels sosetopt(so, level, optname, m0) 68412757Ssam register struct socket *so; 68510267Ssam int level, optname; 68618553Skarels struct mbuf *m0; 68710267Ssam { 68817158Ssam int error = 0; 68918553Skarels register struct mbuf *m = m0; 69010267Ssam 69117158Ssam if (level != SOL_SOCKET) { 69218369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 69318369Skarels return ((*so->so_proto->pr_ctloutput) 69418553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 69518369Skarels error = ENOPROTOOPT; 69618369Skarels } else { 69718369Skarels switch (optname) { 69810267Ssam 69918369Skarels case SO_LINGER: 70018369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 70118369Skarels error = EINVAL; 70218369Skarels goto bad; 70318369Skarels } 70418369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 70518369Skarels /* fall thru... */ 70617158Ssam 70718369Skarels case SO_DEBUG: 70818369Skarels case SO_KEEPALIVE: 70918369Skarels case SO_DONTROUTE: 71018369Skarels case SO_USELOOPBACK: 71118369Skarels case SO_BROADCAST: 71218369Skarels case SO_REUSEADDR: 71327191Skarels case SO_OOBINLINE: 71418369Skarels if (m == NULL || m->m_len < sizeof (int)) { 71518369Skarels error = EINVAL; 71618369Skarels goto bad; 71718369Skarels } 71818369Skarels if (*mtod(m, int *)) 71918369Skarels so->so_options |= optname; 72018369Skarels else 72118369Skarels so->so_options &= ~optname; 72218369Skarels break; 72318369Skarels 72418369Skarels case SO_SNDBUF: 72518369Skarels case SO_RCVBUF: 72618369Skarels case SO_SNDLOWAT: 72718369Skarels case SO_RCVLOWAT: 72818369Skarels case SO_SNDTIMEO: 72918369Skarels case SO_RCVTIMEO: 73018369Skarels if (m == NULL || m->m_len < sizeof (int)) { 73118369Skarels error = EINVAL; 73218369Skarels goto bad; 73318369Skarels } 73418369Skarels switch (optname) { 73518369Skarels 73618369Skarels case SO_SNDBUF: 73718369Skarels case SO_RCVBUF: 73834492Skarels if (sbreserve(optname == SO_SNDBUF ? 73934492Skarels &so->so_snd : &so->so_rcv, 74034492Skarels (u_long) *mtod(m, int *)) == 0) { 74118369Skarels error = ENOBUFS; 74218369Skarels goto bad; 74318369Skarels } 74418369Skarels break; 74518369Skarels 74618369Skarels case SO_SNDLOWAT: 74718369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 74818369Skarels break; 74918369Skarels case SO_RCVLOWAT: 75018369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 75118369Skarels break; 75218369Skarels case SO_SNDTIMEO: 75318369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 75418369Skarels break; 75518369Skarels case SO_RCVTIMEO: 75618369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 75718369Skarels break; 75818369Skarels } 75918369Skarels break; 76018369Skarels 76118369Skarels default: 76218369Skarels error = ENOPROTOOPT; 76318369Skarels break; 76417158Ssam } 76510267Ssam } 76617158Ssam bad: 76717158Ssam if (m) 76817158Ssam (void) m_free(m); 76917158Ssam return (error); 77010267Ssam } 77110267Ssam 77217158Ssam sogetopt(so, level, optname, mp) 77312757Ssam register struct socket *so; 77410267Ssam int level, optname; 77517158Ssam struct mbuf **mp; 77617158Ssam { 77712757Ssam register struct mbuf *m; 77810267Ssam 77918369Skarels if (level != SOL_SOCKET) { 78018369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 78118369Skarels return ((*so->so_proto->pr_ctloutput) 78218369Skarels (PRCO_GETOPT, so, level, optname, mp)); 78318369Skarels } else 78418369Skarels return (ENOPROTOOPT); 78518369Skarels } else { 78617158Ssam m = m_get(M_WAIT, MT_SOOPTS); 78725502Skarels m->m_len = sizeof (int); 78825502Skarels 78918369Skarels switch (optname) { 79017158Ssam 79118369Skarels case SO_LINGER: 79218369Skarels m->m_len = sizeof (struct linger); 79318369Skarels mtod(m, struct linger *)->l_onoff = 79418369Skarels so->so_options & SO_LINGER; 79518369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 79618369Skarels break; 79710267Ssam 79818369Skarels case SO_USELOOPBACK: 79918369Skarels case SO_DONTROUTE: 80018369Skarels case SO_DEBUG: 80118369Skarels case SO_KEEPALIVE: 80218369Skarels case SO_REUSEADDR: 80318369Skarels case SO_BROADCAST: 80427191Skarels case SO_OOBINLINE: 80518369Skarels *mtod(m, int *) = so->so_options & optname; 80618369Skarels break; 80718369Skarels 80825502Skarels case SO_TYPE: 80925502Skarels *mtod(m, int *) = so->so_type; 81025502Skarels break; 81125502Skarels 81224768Skarels case SO_ERROR: 81324768Skarels *mtod(m, int *) = so->so_error; 81424768Skarels so->so_error = 0; 81524768Skarels break; 81624768Skarels 81718369Skarels case SO_SNDBUF: 81818369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 81918369Skarels break; 82018369Skarels 82118369Skarels case SO_RCVBUF: 82218369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 82318369Skarels break; 82418369Skarels 82518369Skarels case SO_SNDLOWAT: 82618369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 82718369Skarels break; 82818369Skarels 82918369Skarels case SO_RCVLOWAT: 83018369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 83118369Skarels break; 83218369Skarels 83318369Skarels case SO_SNDTIMEO: 83418369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 83518369Skarels break; 83618369Skarels 83718369Skarels case SO_RCVTIMEO: 83818369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 83918369Skarels break; 84018369Skarels 84118369Skarels default: 84226362Skarels (void)m_free(m); 84318369Skarels return (ENOPROTOOPT); 84418369Skarels } 84518369Skarels *mp = m; 84618369Skarels return (0); 84710267Ssam } 84810267Ssam } 84910267Ssam 8505423Swnj sohasoutofband(so) 85112757Ssam register struct socket *so; 8525423Swnj { 85323233Skarels struct proc *p; 8545423Swnj 85537478Ssklower if (so->so_pgid < 0) 85637478Ssklower gsignal(-so->so_pgid, SIGURG); 85737478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 85823233Skarels psignal(p, SIGURG); 85924768Skarels if (so->so_rcv.sb_sel) { 86024768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 86124768Skarels so->so_rcv.sb_sel = 0; 86224768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 86324768Skarels } 8645423Swnj } 865