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*40632Skarels * @(#)uipc_socket.c 7.16 (Berkeley) 03/25/90 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" 30*40632Skarels #include "tsleep.h" 314786Swnj 324786Swnj /* 338300Sroot * Socket operation routines. 348300Sroot * These routines are called by the routines in 358300Sroot * sys_socket.c or from a system process, and 368300Sroot * implement the semantics of socket operations by 378300Sroot * switching out to the protocol specific routines. 3812757Ssam * 3912757Ssam * TODO: 4012757Ssam * test socketpair 4121767Skarels * clean up async 4212757Ssam * out-of-band is a kludge 434786Swnj */ 448594Sroot /*ARGSUSED*/ 4510267Ssam socreate(dom, aso, type, proto) 464786Swnj struct socket **aso; 4712757Ssam register int type; 4812757Ssam int proto; 494786Swnj { 504786Swnj register struct protosw *prp; 514786Swnj register struct socket *so; 5212757Ssam register int error; 534786Swnj 544890Swnj if (proto) 5521767Skarels prp = pffindproto(dom, proto, type); 564890Swnj else 579168Ssam prp = pffindtype(dom, type); 584890Swnj if (prp == 0) 594890Swnj return (EPROTONOSUPPORT); 608300Sroot if (prp->pr_type != type) 618300Sroot return (EPROTOTYPE); 6237478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 6337478Ssklower bzero((caddr_t)so, sizeof(*so)); 649168Ssam so->so_type = type; 656214Swnj if (u.u_uid == 0) 666214Swnj so->so_state = SS_PRIV; 674786Swnj so->so_proto = prp; 6812757Ssam error = 6912757Ssam (*prp->pr_usrreq)(so, PRU_ATTACH, 7021767Skarels (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); 714979Swnj if (error) { 727507Sroot so->so_state |= SS_NOFDREF; 737180Swnj sofree(so); 744890Swnj return (error); 754786Swnj } 764786Swnj *aso = so; 774786Swnj return (0); 784786Swnj } 794786Swnj 8010267Ssam sobind(so, nam) 818300Sroot struct socket *so; 828300Sroot struct mbuf *nam; 838300Sroot { 848300Sroot int s = splnet(); 858300Sroot int error; 868300Sroot 878300Sroot error = 8812757Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8912757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 908300Sroot splx(s); 918300Sroot return (error); 928300Sroot } 938300Sroot 948300Sroot solisten(so, backlog) 9512757Ssam register struct socket *so; 968300Sroot int backlog; 978300Sroot { 9812757Ssam int s = splnet(), error; 998300Sroot 10012757Ssam error = 10112757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 10212757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1038300Sroot if (error) { 1048300Sroot splx(s); 1058300Sroot return (error); 1068300Sroot } 10738584Skarels if (so->so_q == 0) 1088300Sroot so->so_options |= SO_ACCEPTCONN; 1098300Sroot if (backlog < 0) 1108300Sroot backlog = 0; 11135384Skarels 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); 12937478Ssklower FREE(so, M_SOCKET); 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 */ 14133372Sbostic int error = 0; 1424829Swnj 1437507Sroot if (so->so_options & SO_ACCEPTCONN) { 14438584Skarels while (so->so_q0) 14510399Ssam (void) soabort(so->so_q0); 14638584Skarels while (so->so_q) 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) 162*40632Skarels tsleep((caddr_t)&so->so_timeo, PZERO+1, 163*40632Skarels SLP_SO_LINGER, 0); 1644890Swnj } 1654890Swnj } 1665580Sroot drop: 1676880Ssam if (so->so_pcb) { 16812757Ssam int error2 = 16912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17012757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17112757Ssam if (error == 0) 17212757Ssam error = error2; 1736880Ssam } 1744890Swnj discard: 17510399Ssam if (so->so_state & SS_NOFDREF) 17610399Ssam panic("soclose: NOFDREF"); 1777507Sroot so->so_state |= SS_NOFDREF; 1784950Swnj sofree(so); 1794890Swnj splx(s); 18012757Ssam return (error); 1814829Swnj } 1824829Swnj 18310399Ssam /* 18410399Ssam * Must be called at splnet... 18510399Ssam */ 18610399Ssam soabort(so) 18710399Ssam struct socket *so; 18810399Ssam { 18910399Ssam 19012757Ssam return ( 19112757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19212757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19310399Ssam } 19410399Ssam 19510267Ssam soaccept(so, nam) 19612757Ssam register struct socket *so; 1978300Sroot struct mbuf *nam; 1984927Swnj { 1994927Swnj int s = splnet(); 2004927Swnj int error; 2014927Swnj 20210399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20310399Ssam panic("soaccept: !NOFDREF"); 20410267Ssam so->so_state &= ~SS_NOFDREF; 2058300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20612757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2074927Swnj splx(s); 2084927Swnj return (error); 2094927Swnj } 2104927Swnj 21110267Ssam soconnect(so, nam) 21212757Ssam register struct socket *so; 2138300Sroot struct mbuf *nam; 2144786Swnj { 21530414Skarels int s; 2164890Swnj int error; 2174786Swnj 21830414Skarels if (so->so_options & SO_ACCEPTCONN) 21930414Skarels return (EOPNOTSUPP); 22030414Skarels s = splnet(); 22124768Skarels /* 22224768Skarels * If protocol is connection-based, can only connect once. 22324768Skarels * Otherwise, if connected, try to disconnect first. 22424768Skarels * This allows user to disconnect by connecting to, e.g., 22524768Skarels * a null address. 22624768Skarels */ 22724768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 22824768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 22924768Skarels (error = sodisconnect(so)))) 2304890Swnj error = EISCONN; 23124768Skarels else 23224768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23324768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2344890Swnj splx(s); 2354890Swnj return (error); 2364786Swnj } 2374786Swnj 23812757Ssam soconnect2(so1, so2) 23912757Ssam register struct socket *so1; 24012757Ssam struct socket *so2; 24112757Ssam { 24212757Ssam int s = splnet(); 24312757Ssam int error; 24412757Ssam 24513113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24613113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24712757Ssam splx(s); 24812757Ssam return (error); 24912757Ssam } 25012757Ssam 25126245Skarels sodisconnect(so) 25212757Ssam register struct socket *so; 2534786Swnj { 2544890Swnj int s = splnet(); 2554890Swnj int error; 2564786Swnj 2574890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2584890Swnj error = ENOTCONN; 2594890Swnj goto bad; 2604890Swnj } 2614890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2624890Swnj error = EALREADY; 2634890Swnj goto bad; 2644890Swnj } 2658300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26626245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2674890Swnj bad: 2684890Swnj splx(s); 2694890Swnj return (error); 2704786Swnj } 2714786Swnj 2724786Swnj /* 2734890Swnj * Send on a socket. 2744890Swnj * If send must go all at once and message is larger than 2754890Swnj * send buffering, then hard error. 2764890Swnj * Lock against other senders. 2774890Swnj * If must go all at once and not enough room now, then 2784890Swnj * inform user that this would block and do nothing. 27916412Skarels * Otherwise, if nonblocking, send as much as possible. 2804786Swnj */ 281*40632Skarels sosend(so, nam, uio, flags, control) 2824786Swnj register struct socket *so; 2838300Sroot struct mbuf *nam; 28412757Ssam register struct uio *uio; 2858319Sroot int flags; 286*40632Skarels struct mbuf *control; 2874786Swnj { 28835384Skarels struct mbuf *top = 0, **mp; 28935384Skarels register struct mbuf *m; 29035384Skarels register int space, len; 29135384Skarels int rlen = 0, error = 0, s, dontroute, first = 1, mlen; 29235384Skarels int atomic = sosendallatonce(so); 2934786Swnj 29435384Skarels if (atomic && uio->uio_resid > so->so_snd.sb_hiwat) 2954890Swnj return (EMSGSIZE); 29612757Ssam dontroute = 29712757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 29812757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 29916412Skarels u.u_ru.ru_msgsnd++; 300*40632Skarels if (control) 301*40632Skarels rlen = control->m_len; 30216412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30316412Skarels 3046419Sroot restart: 3054890Swnj sblock(&so->so_snd); 30616412Skarels do { 30716412Skarels s = splnet(); 30821108Skarels if (so->so_state & SS_CANTSENDMORE) 30916412Skarels snderr(EPIPE); 31037478Ssklower if (so->so_error) 31137478Ssklower snderr(so->so_error); 31216412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31337478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 31438584Skarels if ((so->so_state & SS_ISCONFIRMING) == 0) 31537478Ssklower snderr(ENOTCONN); 31637478Ssklower } else if (nam == 0) 31716412Skarels snderr(EDESTADDRREQ); 31816412Skarels } 31916412Skarels if (flags & MSG_OOB) 32016412Skarels space = 1024; 32116412Skarels else { 32216412Skarels space = sbspace(&so->so_snd); 32325629Skarels if (space <= rlen || 32435384Skarels (atomic && space < uio->uio_resid + rlen) || 32535384Skarels (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 32635384Skarels so->so_snd.sb_cc >= MCLBYTES && 32716992Skarels (so->so_state & SS_NBIO) == 0)) { 32816412Skarels if (so->so_state & SS_NBIO) { 32916412Skarels if (first) 33016412Skarels error = EWOULDBLOCK; 33116412Skarels splx(s); 33216412Skarels goto release; 33316412Skarels } 33416412Skarels sbunlock(&so->so_snd); 33516412Skarels sbwait(&so->so_snd); 33616412Skarels splx(s); 33716412Skarels goto restart; 33816412Skarels } 33916412Skarels } 34016412Skarels splx(s); 34116412Skarels mp = ⊤ 34225629Skarels space -= rlen; 34335384Skarels do { 34435384Skarels do { 34535384Skarels if (top == 0) { 34635384Skarels MGETHDR(m, M_WAIT, MT_DATA); 34735384Skarels mlen = MHLEN; 34835384Skarels m->m_pkthdr.len = 0; 34935384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35035384Skarels } else { 35135384Skarels MGET(m, M_WAIT, MT_DATA); 35235384Skarels mlen = MLEN; 35335384Skarels } 35435384Skarels if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 35535384Skarels MCLGET(m, M_WAIT); 35635384Skarels if ((m->m_flags & M_EXT) == 0) 35716412Skarels goto nopages; 35835384Skarels mlen = MCLBYTES; 35935384Skarels #ifdef MAPPED_MBUFS 36035384Skarels len = min(MCLBYTES, uio->uio_resid); 36135384Skarels if (len < mlen - max_hdr) 36235384Skarels m->m_data += max_hdr; 36335384Skarels #else 36435384Skarels len = min(MCLBYTES - max_hdr, uio->uio_resid); 36535384Skarels m->m_data += max_hdr; 36635384Skarels #endif 36735384Skarels space -= MCLBYTES; 36816412Skarels } else { 36916412Skarels nopages: 37035384Skarels len = min(min(mlen, uio->uio_resid), space); 37121767Skarels space -= len; 37235384Skarels /* 37335384Skarels * For datagram protocols, leave room 37435384Skarels * for protocol headers in first mbuf. 37535384Skarels */ 37635391Skarels if (atomic && top == 0 && len < mlen) 37735384Skarels MH_ALIGN(m, len); 37816412Skarels } 37937728Smckusick error = uiomove(mtod(m, caddr_t), len, uio); 38016412Skarels m->m_len = len; 38116412Skarels *mp = m; 38235384Skarels top->m_pkthdr.len += len; 38316412Skarels if (error) 38416412Skarels goto release; 38516412Skarels mp = &m->m_next; 38635384Skarels if (uio->uio_resid <= 0) { 38735384Skarels if ((flags & MSG_EOR) && top) 38835384Skarels top->m_flags |= M_EOR; 38921108Skarels break; 39035384Skarels } 39135384Skarels } while (space > 0 && atomic); 39235384Skarels if (dontroute) 39335384Skarels so->so_options |= SO_DONTROUTE; 39435384Skarels s = splnet(); /* XXX */ 39535384Skarels error = (*so->so_proto->pr_usrreq)(so, 39635384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 397*40632Skarels top, (caddr_t)nam, control); 39835384Skarels splx(s); 39935384Skarels if (dontroute) 40035384Skarels so->so_options &= ~SO_DONTROUTE; 40135384Skarels rlen = 0; 40235384Skarels top = 0; 40335384Skarels mp = ⊤ 40435384Skarels first = 0; 40535384Skarels if (error) 40635384Skarels goto release; 40735384Skarels } while (uio->uio_resid && space > 0); 40816412Skarels } while (uio->uio_resid); 4094890Swnj 4104786Swnj release: 4114890Swnj sbunlock(&so->so_snd); 4126419Sroot if (top) 4136419Sroot m_freem(top); 41421108Skarels if (error == EPIPE) 41521108Skarels psignal(u.u_procp, SIGPIPE); 4164786Swnj return (error); 4174786Swnj } 4184786Swnj 41925629Skarels /* 42025629Skarels * Implement receive operations on a socket. 42125629Skarels * We depend on the way that records are added to the sockbuf 42225629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 42325629Skarels * must begin with an address if the protocol so specifies, 42425629Skarels * followed by an optional mbuf containing access rights if supported 42525629Skarels * by the protocol, and then zero or more mbufs of data. 42625629Skarels * In order to avoid blocking network interrupts for the entire time here, 42725629Skarels * we splx() while doing the actual copy to user space. 42825629Skarels * Although the sockbuf is locked, new data may still be appended, 42925629Skarels * and thus we must maintain consistency of the sockbuf during that time. 43025629Skarels */ 43135384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp) 4324786Swnj register struct socket *so; 4338300Sroot struct mbuf **aname; 43412757Ssam register struct uio *uio; 43535384Skarels int *flagsp; 43635384Skarels struct mbuf **rightsp, **controlp; 4374786Swnj { 43826958Skarels register struct mbuf *m; 43935384Skarels register int flags, len, error = 0, s, offset; 44012757Ssam struct protosw *pr = so->so_proto; 441*40632Skarels struct mbuf *nextrecord, *m_with_eor; 44212757Ssam int moff; 4434786Swnj 44412757Ssam if (rightsp) 44512757Ssam *rightsp = 0; 44612757Ssam if (aname) 44712757Ssam *aname = 0; 44835384Skarels if (controlp) 44935384Skarels *controlp = 0; 45035384Skarels if (flagsp) 45135384Skarels flags = *flagsp &~ MSG_EOR; 45235384Skarels else 45335384Skarels flags = 0; 45412757Ssam if (flags & MSG_OOB) { 4559635Ssam m = m_get(M_WAIT, MT_DATA); 45612757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 45724768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4588594Sroot if (error) 45910137Ssam goto bad; 4608319Sroot do { 46110137Ssam len = uio->uio_resid; 4628319Sroot if (len > m->m_len) 4638319Sroot len = m->m_len; 46437728Smckusick error = uiomove(mtod(m, caddr_t), (int)len, uio); 4658319Sroot m = m_free(m); 4668594Sroot } while (uio->uio_resid && error == 0 && m); 46710137Ssam bad: 4688319Sroot if (m) 4698771Sroot m_freem(m); 4708594Sroot return (error); 4718319Sroot } 47237478Ssklower if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 47335384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 47435384Skarels (struct mbuf *)0, (struct mbuf *)0); 4758319Sroot 4764890Swnj restart: 4774890Swnj sblock(&so->so_rcv); 4788835Sroot s = splnet(); 4794890Swnj 48037478Ssklower m = so->so_rcv.sb_mb; 48137478Ssklower if (m == 0) { 48237478Ssklower if (so->so_rcv.sb_cc) 48337478Ssklower panic("receive 1"); 4845168Swnj if (so->so_error) { 4855168Swnj error = so->so_error; 4865168Swnj so->so_error = 0; 4875168Swnj goto release; 4885168Swnj } 48932567Sbostic if (so->so_state & SS_CANTRCVMORE) 4904890Swnj goto release; 49138584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 49232567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 49332567Sbostic error = ENOTCONN; 49432567Sbostic goto release; 4954890Swnj } 49625629Skarels if (uio->uio_resid == 0) 49725629Skarels goto release; 49832567Sbostic if (so->so_state & SS_NBIO) { 49932567Sbostic error = EWOULDBLOCK; 50032567Sbostic goto release; 50132567Sbostic } 5024890Swnj sbunlock(&so->so_rcv); 5034971Swnj sbwait(&so->so_rcv); 5045012Swnj splx(s); 5054890Swnj goto restart; 5064786Swnj } 5078041Sroot u.u_ru.ru_msgrcv++; 50835384Skarels if (m->m_type == 0) 50935384Skarels panic("receive 3a"); 51035384Skarels nextrecord = m->m_nextpkt; 51112757Ssam if (pr->pr_flags & PR_ADDR) { 51225629Skarels if (m->m_type != MT_SONAME) 51316993Skarels panic("receive 1a"); 51416993Skarels if (flags & MSG_PEEK) { 51516993Skarels if (aname) 5168319Sroot *aname = m_copy(m, 0, m->m_len); 51725629Skarels m = m->m_next; 51816993Skarels } else { 51925629Skarels sbfree(&so->so_rcv, m); 52016993Skarels if (aname) { 52116993Skarels *aname = m; 52235384Skarels so->so_rcv.sb_mb = m->m_next; 52335384Skarels m->m_next = 0; 52435384Skarels m = so->so_rcv.sb_mb; 52525629Skarels } else { 52626958Skarels MFREE(m, so->so_rcv.sb_mb); 52726958Skarels m = so->so_rcv.sb_mb; 52825629Skarels } 52916993Skarels } 53016993Skarels } 53116993Skarels if (m && m->m_type == MT_RIGHTS) { 53216993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 53326958Skarels panic("receive 2"); 53416993Skarels if (flags & MSG_PEEK) { 53516993Skarels if (rightsp) 53612757Ssam *rightsp = m_copy(m, 0, m->m_len); 53725629Skarels m = m->m_next; 53816993Skarels } else { 53925629Skarels sbfree(&so->so_rcv, m); 54016993Skarels if (rightsp) { 54116993Skarels *rightsp = m; 54226958Skarels so->so_rcv.sb_mb = m->m_next; 54325629Skarels m->m_next = 0; 54426958Skarels m = so->so_rcv.sb_mb; 54525629Skarels } else { 54626958Skarels MFREE(m, so->so_rcv.sb_mb); 54726958Skarels m = so->so_rcv.sb_mb; 54825629Skarels } 54912757Ssam } 5504890Swnj } 55135384Skarels if (m && m->m_type == MT_CONTROL) { 55235384Skarels if (flags & MSG_PEEK) { 55335384Skarels if (controlp) 55435384Skarels *controlp = m_copy(m, 0, m->m_len); 55535384Skarels m = m->m_next; 55635384Skarels } else { 55735384Skarels sbfree(&so->so_rcv, m); 55835384Skarels if (controlp) { 55935384Skarels *controlp = m; 56035384Skarels so->so_rcv.sb_mb = m->m_next; 56135384Skarels m->m_next = 0; 56235384Skarels m = so->so_rcv.sb_mb; 56335384Skarels } else { 56435384Skarels MFREE(m, so->so_rcv.sb_mb); 56535384Skarels m = so->so_rcv.sb_mb; 56635384Skarels } 56735384Skarels } 56835384Skarels } 56935384Skarels if (m) 57035384Skarels m->m_nextpkt = nextrecord; 5718319Sroot moff = 0; 57232092Skarels offset = 0; 573*40632Skarels m_with_eor = 0; 57416993Skarels while (m && uio->uio_resid > 0 && error == 0) { 57535384Skarels if (m->m_type == MT_OOBDATA) 57635384Skarels flags |= MSG_OOB; 57735384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 57825629Skarels panic("receive 3"); 57935384Skarels if (m->m_flags & M_EOR) 580*40632Skarels m_with_eor = m; 5817827Sroot len = uio->uio_resid; 5827747Sroot so->so_state &= ~SS_RCVATMARK; 58332092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 58432092Skarels len = so->so_oobmark - offset; 58521767Skarels if (len > m->m_len - moff) 5868319Sroot len = m->m_len - moff; 5874786Swnj splx(s); 58837728Smckusick error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 5894786Swnj s = splnet(); 59021767Skarels if (len == m->m_len - moff) { 59125629Skarels if (flags & MSG_PEEK) { 59225629Skarels m = m->m_next; 59325629Skarels moff = 0; 59425629Skarels } else { 59535384Skarels nextrecord = m->m_nextpkt; 59625629Skarels sbfree(&so->so_rcv, m); 59726958Skarels MFREE(m, so->so_rcv.sb_mb); 59826958Skarels m = so->so_rcv.sb_mb; 59926958Skarels if (m) 60035384Skarels m->m_nextpkt = nextrecord; 60125629Skarels } 6024786Swnj } else { 60312757Ssam if (flags & MSG_PEEK) 6048319Sroot moff += len; 6058319Sroot else { 60635384Skarels m->m_data += len; 6078319Sroot m->m_len -= len; 6088319Sroot so->so_rcv.sb_cc -= len; 6098319Sroot } 6104786Swnj } 61132092Skarels if (so->so_oobmark) { 61232092Skarels if ((flags & MSG_PEEK) == 0) { 61332092Skarels so->so_oobmark -= len; 61432092Skarels if (so->so_oobmark == 0) { 61532092Skarels so->so_state |= SS_RCVATMARK; 61632092Skarels break; 61732092Skarels } 61832092Skarels } else 61932092Skarels offset += len; 6207747Sroot } 621*40632Skarels if (m_with_eor) 622*40632Skarels break; 62316993Skarels } 624*40632Skarels if (m_with_eor) { 625*40632Skarels if (m != m_with_eor) 626*40632Skarels flags |= MSG_EOR; 627*40632Skarels /* else data not consumed from mbuf */ 62835384Skarels } 62916993Skarels if ((flags & MSG_PEEK) == 0) { 63026500Skarels if (m == 0) 63116993Skarels so->so_rcv.sb_mb = nextrecord; 63235384Skarels else if (pr->pr_flags & PR_ATOMIC) { 63335384Skarels flags |= MSG_TRUNC; 63426958Skarels (void) sbdroprecord(&so->so_rcv); 63535384Skarels } 63616993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 63716993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 63837478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 63937478Ssklower (struct mbuf *)0); 64025629Skarels if (error == 0 && rightsp && *rightsp && 64125629Skarels pr->pr_domain->dom_externalize) 64225629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 64316993Skarels } 64435384Skarels if (flagsp) 64535384Skarels *flagsp |= flags; 6464890Swnj release: 6474916Swnj sbunlock(&so->so_rcv); 6484890Swnj splx(s); 6494916Swnj return (error); 6504786Swnj } 6514786Swnj 65210267Ssam soshutdown(so, how) 65312757Ssam register struct socket *so; 65412757Ssam register int how; 65510267Ssam { 65612757Ssam register struct protosw *pr = so->so_proto; 65710267Ssam 65810267Ssam how++; 65912757Ssam if (how & FREAD) 66012757Ssam sorflush(so); 66110267Ssam if (how & FWRITE) 66212757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 66312757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 66410267Ssam return (0); 66510267Ssam } 66610267Ssam 66712757Ssam sorflush(so) 66812757Ssam register struct socket *so; 66912757Ssam { 67012757Ssam register struct sockbuf *sb = &so->so_rcv; 67112757Ssam register struct protosw *pr = so->so_proto; 67212757Ssam register int s; 67312757Ssam struct sockbuf asb; 67412757Ssam 67512757Ssam sblock(sb); 67612757Ssam s = splimp(); 67712757Ssam socantrcvmore(so); 67812757Ssam sbunlock(sb); 67912757Ssam asb = *sb; 68012757Ssam bzero((caddr_t)sb, sizeof (*sb)); 68112757Ssam splx(s); 68216993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 68316993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 68412757Ssam sbrelease(&asb); 68512757Ssam } 68612757Ssam 68718553Skarels sosetopt(so, level, optname, m0) 68812757Ssam register struct socket *so; 68910267Ssam int level, optname; 69018553Skarels struct mbuf *m0; 69110267Ssam { 69217158Ssam int error = 0; 69318553Skarels register struct mbuf *m = m0; 69410267Ssam 69517158Ssam if (level != SOL_SOCKET) { 69618369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 69718369Skarels return ((*so->so_proto->pr_ctloutput) 69818553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 69918369Skarels error = ENOPROTOOPT; 70018369Skarels } else { 70118369Skarels switch (optname) { 70210267Ssam 70318369Skarels case SO_LINGER: 70418369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 70518369Skarels error = EINVAL; 70618369Skarels goto bad; 70718369Skarels } 70818369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 70918369Skarels /* fall thru... */ 71017158Ssam 71118369Skarels case SO_DEBUG: 71218369Skarels case SO_KEEPALIVE: 71318369Skarels case SO_DONTROUTE: 71418369Skarels case SO_USELOOPBACK: 71518369Skarels case SO_BROADCAST: 71618369Skarels case SO_REUSEADDR: 71727191Skarels case SO_OOBINLINE: 71818369Skarels if (m == NULL || m->m_len < sizeof (int)) { 71918369Skarels error = EINVAL; 72018369Skarels goto bad; 72118369Skarels } 72218369Skarels if (*mtod(m, int *)) 72318369Skarels so->so_options |= optname; 72418369Skarels else 72518369Skarels so->so_options &= ~optname; 72618369Skarels break; 72718369Skarels 72818369Skarels case SO_SNDBUF: 72918369Skarels case SO_RCVBUF: 73018369Skarels case SO_SNDLOWAT: 73118369Skarels case SO_RCVLOWAT: 73218369Skarels case SO_SNDTIMEO: 73318369Skarels case SO_RCVTIMEO: 73418369Skarels if (m == NULL || m->m_len < sizeof (int)) { 73518369Skarels error = EINVAL; 73618369Skarels goto bad; 73718369Skarels } 73818369Skarels switch (optname) { 73918369Skarels 74018369Skarels case SO_SNDBUF: 74118369Skarels case SO_RCVBUF: 74234492Skarels if (sbreserve(optname == SO_SNDBUF ? 74334492Skarels &so->so_snd : &so->so_rcv, 74434492Skarels (u_long) *mtod(m, int *)) == 0) { 74518369Skarels error = ENOBUFS; 74618369Skarels goto bad; 74718369Skarels } 74818369Skarels break; 74918369Skarels 75018369Skarels case SO_SNDLOWAT: 75118369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 75218369Skarels break; 75318369Skarels case SO_RCVLOWAT: 75418369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 75518369Skarels break; 75618369Skarels case SO_SNDTIMEO: 75718369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 75818369Skarels break; 75918369Skarels case SO_RCVTIMEO: 76018369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 76118369Skarels break; 76218369Skarels } 76318369Skarels break; 76418369Skarels 76518369Skarels default: 76618369Skarels error = ENOPROTOOPT; 76718369Skarels break; 76817158Ssam } 76910267Ssam } 77017158Ssam bad: 77117158Ssam if (m) 77217158Ssam (void) m_free(m); 77317158Ssam return (error); 77410267Ssam } 77510267Ssam 77617158Ssam sogetopt(so, level, optname, mp) 77712757Ssam register struct socket *so; 77810267Ssam int level, optname; 77917158Ssam struct mbuf **mp; 78017158Ssam { 78112757Ssam register struct mbuf *m; 78210267Ssam 78318369Skarels if (level != SOL_SOCKET) { 78418369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 78518369Skarels return ((*so->so_proto->pr_ctloutput) 78618369Skarels (PRCO_GETOPT, so, level, optname, mp)); 78718369Skarels } else 78818369Skarels return (ENOPROTOOPT); 78918369Skarels } else { 79017158Ssam m = m_get(M_WAIT, MT_SOOPTS); 79125502Skarels m->m_len = sizeof (int); 79225502Skarels 79318369Skarels switch (optname) { 79417158Ssam 79518369Skarels case SO_LINGER: 79618369Skarels m->m_len = sizeof (struct linger); 79718369Skarels mtod(m, struct linger *)->l_onoff = 79818369Skarels so->so_options & SO_LINGER; 79918369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 80018369Skarels break; 80110267Ssam 80218369Skarels case SO_USELOOPBACK: 80318369Skarels case SO_DONTROUTE: 80418369Skarels case SO_DEBUG: 80518369Skarels case SO_KEEPALIVE: 80618369Skarels case SO_REUSEADDR: 80718369Skarels case SO_BROADCAST: 80827191Skarels case SO_OOBINLINE: 80918369Skarels *mtod(m, int *) = so->so_options & optname; 81018369Skarels break; 81118369Skarels 81225502Skarels case SO_TYPE: 81325502Skarels *mtod(m, int *) = so->so_type; 81425502Skarels break; 81525502Skarels 81624768Skarels case SO_ERROR: 81724768Skarels *mtod(m, int *) = so->so_error; 81824768Skarels so->so_error = 0; 81924768Skarels break; 82024768Skarels 82118369Skarels case SO_SNDBUF: 82218369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 82318369Skarels break; 82418369Skarels 82518369Skarels case SO_RCVBUF: 82618369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 82718369Skarels break; 82818369Skarels 82918369Skarels case SO_SNDLOWAT: 83018369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 83118369Skarels break; 83218369Skarels 83318369Skarels case SO_RCVLOWAT: 83418369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 83518369Skarels break; 83618369Skarels 83718369Skarels case SO_SNDTIMEO: 83818369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 83918369Skarels break; 84018369Skarels 84118369Skarels case SO_RCVTIMEO: 84218369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 84318369Skarels break; 84418369Skarels 84518369Skarels default: 84626362Skarels (void)m_free(m); 84718369Skarels return (ENOPROTOOPT); 84818369Skarels } 84918369Skarels *mp = m; 85018369Skarels return (0); 85110267Ssam } 85210267Ssam } 85310267Ssam 8545423Swnj sohasoutofband(so) 85512757Ssam register struct socket *so; 8565423Swnj { 85723233Skarels struct proc *p; 8585423Swnj 85937478Ssklower if (so->so_pgid < 0) 86037478Ssklower gsignal(-so->so_pgid, SIGURG); 86137478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 86223233Skarels psignal(p, SIGURG); 86324768Skarels if (so->so_rcv.sb_sel) { 86424768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 86524768Skarels so->so_rcv.sb_sel = 0; 86624768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 86724768Skarels } 8685423Swnj } 869