123421Smckusick /* 241908Skarels * Copyright (c) 1982, 1986, 1988, 1990 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*43417Skarels * @(#)uipc_socket.c 7.20 (Berkeley) 06/22/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" 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 8641908Skarels error = 8741908Skarels (*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 } 10638584Skarels 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) { 14338584Skarels while (so->so_q0) 14410399Ssam (void) soabort(so->so_q0); 14538584Skarels 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) 16140706Skarels if (error = tsleep((caddr_t)&so->so_timeo, 16240706Skarels PSOCK | PCATCH, netcls, so->so_linger)) 16340706Skarels break; 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. 28041908Skarels * The data to be sent is described by "uio" if nonzero, 28141908Skarels * otherwise by the mbuf chain "top" (which must be null 28241908Skarels * if uio is not). Data provided in mbuf chain must be small 28341908Skarels * enough to send all at once. 28441908Skarels * 28541908Skarels * Returns nonzero on error, timeout or signal; callers 28641908Skarels * must check for short counts if EINTR/ERESTART are returned. 28741908Skarels * Data and control buffers are freed on return. 2884786Swnj */ 289*43417Skarels sosend(so, addr, uio, top, control, flags) 2904786Swnj register struct socket *so; 29141908Skarels struct mbuf *addr; 29241908Skarels struct uio *uio; 29341908Skarels struct mbuf *top; 29441908Skarels struct mbuf *control; 2958319Sroot int flags; 2964786Swnj { 29741908Skarels struct mbuf **mp; 29835384Skarels register struct mbuf *m; 29941908Skarels register long space, len, resid; 30041908Skarels int clen = 0, error, s, dontroute, mlen; 30141908Skarels int atomic = sosendallatonce(so) || top; 3024786Swnj 30341908Skarels if (uio) 30441908Skarels resid = uio->uio_resid; 30541908Skarels else 30641908Skarels resid = top->m_pkthdr.len; 30712757Ssam dontroute = 30812757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 30912757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 31016412Skarels u.u_ru.ru_msgsnd++; 31140632Skarels if (control) 31241908Skarels clen = control->m_len; 31316412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 31416412Skarels 3156419Sroot restart: 31640706Skarels if (error = sblock(&so->so_snd)) 31741908Skarels goto out; 31816412Skarels do { 31916412Skarels s = splnet(); 32021108Skarels if (so->so_state & SS_CANTSENDMORE) 32116412Skarels snderr(EPIPE); 32237478Ssklower if (so->so_error) 32337478Ssklower snderr(so->so_error); 32416412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 32537478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 32638584Skarels if ((so->so_state & SS_ISCONFIRMING) == 0) 32737478Ssklower snderr(ENOTCONN); 32841908Skarels } else if (addr == 0) 32916412Skarels snderr(EDESTADDRREQ); 33016412Skarels } 33141908Skarels space = sbspace(&so->so_snd); 33216412Skarels if (flags & MSG_OOB) 33341908Skarels space += 1024; 33441908Skarels if (space < resid + clen && 33541908Skarels (atomic || space < so->so_snd.sb_lowat || space < clen)) { 33641908Skarels if (atomic && resid > so->so_snd.sb_hiwat || 33741908Skarels clen > so->so_snd.sb_hiwat) 33841908Skarels snderr(EMSGSIZE); 33941908Skarels if (so->so_state & SS_NBIO) 34041908Skarels snderr(EWOULDBLOCK); 34141908Skarels sbunlock(&so->so_snd); 342*43417Skarels error = sbwait(&so->so_snd); 34341908Skarels splx(s); 34441908Skarels if (error) 34541908Skarels goto out; 34641908Skarels goto restart; 34716412Skarels } 34816412Skarels splx(s); 34916412Skarels mp = ⊤ 35041908Skarels space -= clen; 351*43417Skarels do { 352*43417Skarels if (uio == NULL) { 35341908Skarels /* 35441908Skarels * Data is prepackaged in "top". 35541908Skarels */ 35641908Skarels resid = 0; 35741908Skarels if (flags & MSG_EOR) 35841908Skarels top->m_flags |= M_EOR; 359*43417Skarels } else do { 36035384Skarels if (top == 0) { 36135384Skarels MGETHDR(m, M_WAIT, MT_DATA); 36235384Skarels mlen = MHLEN; 36335384Skarels m->m_pkthdr.len = 0; 36435384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 36535384Skarels } else { 36635384Skarels MGET(m, M_WAIT, MT_DATA); 36735384Skarels mlen = MLEN; 36835384Skarels } 36941908Skarels if (resid >= MINCLSIZE && space >= MCLBYTES) { 37035384Skarels MCLGET(m, M_WAIT); 37135384Skarels if ((m->m_flags & M_EXT) == 0) 37216412Skarels goto nopages; 37335384Skarels mlen = MCLBYTES; 37435384Skarels #ifdef MAPPED_MBUFS 37541908Skarels len = min(MCLBYTES, resid); 37641908Skarels #else 37741908Skarels if (top == 0) { 37841908Skarels len = min(MCLBYTES - max_hdr, resid); 37935384Skarels m->m_data += max_hdr; 38041908Skarels } 38135384Skarels #endif 38235384Skarels space -= MCLBYTES; 38316412Skarels } else { 38416412Skarels nopages: 38541908Skarels len = min(min(mlen, resid), space); 38621767Skarels space -= len; 38735384Skarels /* 38835384Skarels * For datagram protocols, leave room 38935384Skarels * for protocol headers in first mbuf. 39035384Skarels */ 39135391Skarels if (atomic && top == 0 && len < mlen) 39235384Skarels MH_ALIGN(m, len); 39316412Skarels } 39437728Smckusick error = uiomove(mtod(m, caddr_t), len, uio); 39541908Skarels resid = uio->uio_resid; 39616412Skarels m->m_len = len; 39716412Skarels *mp = m; 39835384Skarels top->m_pkthdr.len += len; 39916412Skarels if (error) 40016412Skarels goto release; 40116412Skarels mp = &m->m_next; 40241908Skarels if (resid <= 0) { 40341908Skarels if (flags & MSG_EOR) 40435384Skarels top->m_flags |= M_EOR; 40521108Skarels break; 40635384Skarels } 40735384Skarels } while (space > 0 && atomic); 40835384Skarels if (dontroute) 40935384Skarels so->so_options |= SO_DONTROUTE; 41035384Skarels s = splnet(); /* XXX */ 41135384Skarels error = (*so->so_proto->pr_usrreq)(so, 41235384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 41341908Skarels top, addr, control); 41435384Skarels splx(s); 41535384Skarels if (dontroute) 41635384Skarels so->so_options &= ~SO_DONTROUTE; 41741908Skarels clen = 0; 41841908Skarels control = 0; 41935384Skarels top = 0; 42035384Skarels mp = ⊤ 42135384Skarels if (error) 42235384Skarels goto release; 42341908Skarels } while (resid && space > 0); 42441908Skarels } while (resid); 4254890Swnj 4264786Swnj release: 4274890Swnj sbunlock(&so->so_snd); 42841908Skarels out: 4296419Sroot if (top) 4306419Sroot m_freem(top); 43141908Skarels if (control) 43241908Skarels m_freem(control); 4334786Swnj return (error); 4344786Swnj } 4354786Swnj 43625629Skarels /* 43725629Skarels * Implement receive operations on a socket. 43825629Skarels * We depend on the way that records are added to the sockbuf 43925629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 44025629Skarels * must begin with an address if the protocol so specifies, 44141908Skarels * followed by an optional mbuf or mbufs containing ancillary data, 44241908Skarels * and then zero or more mbufs of data. 44325629Skarels * In order to avoid blocking network interrupts for the entire time here, 44425629Skarels * we splx() while doing the actual copy to user space. 44525629Skarels * Although the sockbuf is locked, new data may still be appended, 44625629Skarels * and thus we must maintain consistency of the sockbuf during that time. 44741908Skarels * 44841908Skarels * The caller may receive the data as a single mbuf chain by supplying 449*43417Skarels * an mbuf **mp0 for use in returning the chain. The uio is then used 45041908Skarels * only for the count in uio_resid. 45125629Skarels */ 452*43417Skarels soreceive(so, paddr, uio, mp0, controlp, flagsp) 4534786Swnj register struct socket *so; 45441908Skarels struct mbuf **paddr; 45541908Skarels struct uio *uio; 456*43417Skarels struct mbuf **mp0; 45741908Skarels struct mbuf **controlp; 45835384Skarels int *flagsp; 4594786Swnj { 460*43417Skarels register struct mbuf *m, **mp; 461*43417Skarels register int flags, len, error, s, offset; 46212757Ssam struct protosw *pr = so->so_proto; 46341908Skarels struct mbuf *nextrecord; 46441908Skarels int moff, type; 4654786Swnj 466*43417Skarels mp = mp0; 46741908Skarels if (paddr) 46841908Skarels *paddr = 0; 46935384Skarels if (controlp) 47035384Skarels *controlp = 0; 47135384Skarels if (flagsp) 47235384Skarels flags = *flagsp &~ MSG_EOR; 47335384Skarels else 47435384Skarels flags = 0; 47512757Ssam if (flags & MSG_OOB) { 4769635Ssam m = m_get(M_WAIT, MT_DATA); 47712757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 47824768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4798594Sroot if (error) 48010137Ssam goto bad; 4818319Sroot do { 48241908Skarels error = uiomove(mtod(m, caddr_t), 48341908Skarels (int) min(uio->uio_resid, m->m_len), uio); 4848319Sroot m = m_free(m); 4858594Sroot } while (uio->uio_resid && error == 0 && m); 48610137Ssam bad: 4878319Sroot if (m) 4888771Sroot m_freem(m); 4898594Sroot return (error); 4908319Sroot } 49141908Skarels if (mp) 49241908Skarels *mp = (struct mbuf *)0; 493*43417Skarels if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 49435384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 49535384Skarels (struct mbuf *)0, (struct mbuf *)0); 4968319Sroot 4974890Swnj restart: 49840706Skarels if (error = sblock(&so->so_rcv)) 49940706Skarels return (error); 5008835Sroot s = splnet(); 5014890Swnj 50237478Ssklower m = so->so_rcv.sb_mb; 503*43417Skarels if (m == 0 || (so->so_rcv.sb_cc < uio->uio_resid && 504*43417Skarels so->so_rcv.sb_cc < so->so_rcv.sb_lowat) || 505*43417Skarels ((flags & MSG_WAITALL) && so->so_rcv.sb_cc < uio->uio_resid && 506*43417Skarels so->so_rcv.sb_hiwat >= uio->uio_resid && !sosendallatonce(so))) { 50741908Skarels #ifdef DIAGNOSTIC 50841908Skarels if (m == 0 && so->so_rcv.sb_cc) 50937478Ssklower panic("receive 1"); 51041908Skarels #endif 5115168Swnj if (so->so_error) { 5125168Swnj error = so->so_error; 5135168Swnj so->so_error = 0; 5145168Swnj goto release; 5155168Swnj } 51632567Sbostic if (so->so_state & SS_CANTRCVMORE) 5174890Swnj goto release; 51838584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 51932567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 52032567Sbostic error = ENOTCONN; 52132567Sbostic goto release; 5224890Swnj } 523*43417Skarels if (uio->uio_resid == 0) 52425629Skarels goto release; 52532567Sbostic if (so->so_state & SS_NBIO) { 52632567Sbostic error = EWOULDBLOCK; 52732567Sbostic goto release; 52832567Sbostic } 5294890Swnj sbunlock(&so->so_rcv); 530*43417Skarels error = sbwait(&so->so_rcv); 5315012Swnj splx(s); 53241908Skarels if (error) 53341908Skarels return (error); 5344890Swnj goto restart; 5354786Swnj } 5368041Sroot u.u_ru.ru_msgrcv++; 53741908Skarels #ifdef DIAGNOSTIC 53835384Skarels if (m->m_type == 0) 53935384Skarels panic("receive 3a"); 54041908Skarels #endif 54135384Skarels nextrecord = m->m_nextpkt; 54212757Ssam if (pr->pr_flags & PR_ADDR) { 54341908Skarels #ifdef DIAGNOSTIC 54425629Skarels if (m->m_type != MT_SONAME) 54516993Skarels panic("receive 1a"); 54641908Skarels #endif 54716993Skarels if (flags & MSG_PEEK) { 54841908Skarels if (paddr) 54941908Skarels *paddr = m_copy(m, 0, m->m_len); 55025629Skarels m = m->m_next; 55116993Skarels } else { 55225629Skarels sbfree(&so->so_rcv, m); 55341908Skarels if (paddr) { 55441908Skarels *paddr = m; 55535384Skarels so->so_rcv.sb_mb = m->m_next; 55635384Skarels m->m_next = 0; 55735384Skarels m = so->so_rcv.sb_mb; 55825629Skarels } else { 55926958Skarels MFREE(m, so->so_rcv.sb_mb); 56026958Skarels m = so->so_rcv.sb_mb; 56125629Skarels } 56216993Skarels } 56316993Skarels } 56441908Skarels while (m && m->m_type == MT_CONTROL && error == 0) { 56516993Skarels if (flags & MSG_PEEK) { 56635384Skarels if (controlp) 56735384Skarels *controlp = m_copy(m, 0, m->m_len); 56835384Skarels m = m->m_next; 56935384Skarels } else { 57035384Skarels sbfree(&so->so_rcv, m); 57135384Skarels if (controlp) { 57243097Ssklower if (pr->pr_domain->dom_externalize && 57343097Ssklower mtod(m, struct cmsghdr *)->cmsg_type == 57443097Ssklower SCM_RIGHTS) 57541908Skarels error = (*pr->pr_domain->dom_externalize)(m); 57635384Skarels *controlp = m; 57735384Skarels so->so_rcv.sb_mb = m->m_next; 57835384Skarels m->m_next = 0; 57935384Skarels m = so->so_rcv.sb_mb; 58035384Skarels } else { 58135384Skarels MFREE(m, so->so_rcv.sb_mb); 58235384Skarels m = so->so_rcv.sb_mb; 58335384Skarels } 58435384Skarels } 58541908Skarels if (controlp) 58641908Skarels controlp = &(*controlp)->m_next; 58735384Skarels } 58841908Skarels if (m) { 58935384Skarels m->m_nextpkt = nextrecord; 59041908Skarels type = m->m_type; 59141908Skarels } 5928319Sroot moff = 0; 59332092Skarels offset = 0; 594*43417Skarels while (m && m->m_type == type && uio->uio_resid > 0 && error == 0) { 59535384Skarels if (m->m_type == MT_OOBDATA) 59635384Skarels flags |= MSG_OOB; 59741908Skarels #ifdef DIAGNOSTIC 59835384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 59925629Skarels panic("receive 3"); 60041908Skarels #endif 60141908Skarels type = m->m_type; 6027747Sroot so->so_state &= ~SS_RCVATMARK; 603*43417Skarels len = uio->uio_resid; 60432092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 60532092Skarels len = so->so_oobmark - offset; 60621767Skarels if (len > m->m_len - moff) 6078319Sroot len = m->m_len - moff; 60841908Skarels /* 60941908Skarels * If mp is set, just pass back the mbufs. 61041908Skarels * Otherwise copy them out via the uio, then free. 61141908Skarels * Sockbuf must be consistent here (points to current mbuf, 61241908Skarels * it points to next record) when we drop priority; 61341908Skarels * we must note any additions to the sockbuf when we 61441908Skarels * block interrupts again. 61541908Skarels */ 61641908Skarels if (mp == 0) { 61741908Skarels splx(s); 61841908Skarels error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 61941908Skarels s = splnet(); 620*43417Skarels } else 621*43417Skarels uio->uio_resid -= len; 62221767Skarels if (len == m->m_len - moff) { 62341908Skarels if (m->m_flags & M_EOR) 62441908Skarels flags |= MSG_EOR; 62525629Skarels if (flags & MSG_PEEK) { 62625629Skarels m = m->m_next; 62725629Skarels moff = 0; 62825629Skarels } else { 62935384Skarels nextrecord = m->m_nextpkt; 63025629Skarels sbfree(&so->so_rcv, m); 63141908Skarels if (mp) { 63241908Skarels *mp = m; 63341908Skarels mp = &m->m_next; 634*43417Skarels so->so_rcv.sb_mb = m = m->m_next; 635*43417Skarels *mp = (struct mbuf *)0; 63641908Skarels } else { 63741908Skarels MFREE(m, so->so_rcv.sb_mb); 63841908Skarels m = so->so_rcv.sb_mb; 63941908Skarels } 64026958Skarels if (m) 64135384Skarels m->m_nextpkt = nextrecord; 64225629Skarels } 6434786Swnj } else { 64412757Ssam if (flags & MSG_PEEK) 6458319Sroot moff += len; 6468319Sroot else { 647*43417Skarels if (mp) 648*43417Skarels *mp = m_copym(m, 0, len, M_WAIT); 64935384Skarels m->m_data += len; 6508319Sroot m->m_len -= len; 6518319Sroot so->so_rcv.sb_cc -= len; 6528319Sroot } 6534786Swnj } 65432092Skarels if (so->so_oobmark) { 65532092Skarels if ((flags & MSG_PEEK) == 0) { 65632092Skarels so->so_oobmark -= len; 65732092Skarels if (so->so_oobmark == 0) { 65832092Skarels so->so_state |= SS_RCVATMARK; 65932092Skarels break; 66032092Skarels } 66132092Skarels } else 66232092Skarels offset += len; 6637747Sroot } 66441908Skarels if (flags & MSG_EOR) 66540632Skarels break; 66641908Skarels /* 66741908Skarels * If the MSG_WAITALL flag is set (for non-atomic socket), 668*43417Skarels * we must not quit until "uio->uio_resid == 0" or an error 66941908Skarels * termination. If a signal/timeout occurs, return 670*43417Skarels * with a short count but without error. 67141908Skarels * Keep sockbuf locked against other readers. 67241908Skarels */ 673*43417Skarels while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && 67441908Skarels !sosendallatonce(so)) { 67541908Skarels error = sbwait(&so->so_rcv); 67641908Skarels if (error) { 67741908Skarels sbunlock(&so->so_rcv); 67841908Skarels splx(s); 67941908Skarels return (0); 68041908Skarels } 68141908Skarels if (m = so->so_rcv.sb_mb) 68241908Skarels nextrecord = m->m_nextpkt; 68341908Skarels if (so->so_error || so->so_state & SS_CANTRCVMORE) 68441908Skarels break; 68541908Skarels continue; 68641908Skarels } 68716993Skarels } 68816993Skarels if ((flags & MSG_PEEK) == 0) { 68926500Skarels if (m == 0) 69016993Skarels so->so_rcv.sb_mb = nextrecord; 69135384Skarels else if (pr->pr_flags & PR_ATOMIC) { 69235384Skarels flags |= MSG_TRUNC; 69326958Skarels (void) sbdroprecord(&so->so_rcv); 69435384Skarels } 69516993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 69616993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 69737478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 69837478Ssklower (struct mbuf *)0); 69916993Skarels } 70035384Skarels if (flagsp) 70135384Skarels *flagsp |= flags; 7024890Swnj release: 7034916Swnj sbunlock(&so->so_rcv); 7044890Swnj splx(s); 7054916Swnj return (error); 7064786Swnj } 7074786Swnj 70810267Ssam soshutdown(so, how) 70912757Ssam register struct socket *so; 71012757Ssam register int how; 71110267Ssam { 71212757Ssam register struct protosw *pr = so->so_proto; 71310267Ssam 71410267Ssam how++; 71512757Ssam if (how & FREAD) 71612757Ssam sorflush(so); 71710267Ssam if (how & FWRITE) 71812757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 71912757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 72010267Ssam return (0); 72110267Ssam } 72210267Ssam 72312757Ssam sorflush(so) 72412757Ssam register struct socket *so; 72512757Ssam { 72612757Ssam register struct sockbuf *sb = &so->so_rcv; 72712757Ssam register struct protosw *pr = so->so_proto; 72812757Ssam register int s; 72912757Ssam struct sockbuf asb; 73012757Ssam 73140706Skarels sb->sb_flags |= SB_NOINTR; 73240706Skarels (void) sblock(sb); 73312757Ssam s = splimp(); 73412757Ssam socantrcvmore(so); 73512757Ssam sbunlock(sb); 73612757Ssam asb = *sb; 73712757Ssam bzero((caddr_t)sb, sizeof (*sb)); 73812757Ssam splx(s); 73916993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 74016993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 74112757Ssam sbrelease(&asb); 74212757Ssam } 74312757Ssam 74418553Skarels sosetopt(so, level, optname, m0) 74512757Ssam register struct socket *so; 74610267Ssam int level, optname; 74718553Skarels struct mbuf *m0; 74810267Ssam { 74917158Ssam int error = 0; 75018553Skarels register struct mbuf *m = m0; 75110267Ssam 75217158Ssam if (level != SOL_SOCKET) { 75318369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 75418369Skarels return ((*so->so_proto->pr_ctloutput) 75518553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 75618369Skarels error = ENOPROTOOPT; 75718369Skarels } else { 75818369Skarels switch (optname) { 75910267Ssam 76018369Skarels case SO_LINGER: 76118369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 76218369Skarels error = EINVAL; 76318369Skarels goto bad; 76418369Skarels } 76518369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 76618369Skarels /* fall thru... */ 76717158Ssam 76818369Skarels case SO_DEBUG: 76918369Skarels case SO_KEEPALIVE: 77018369Skarels case SO_DONTROUTE: 77118369Skarels case SO_USELOOPBACK: 77218369Skarels case SO_BROADCAST: 77318369Skarels case SO_REUSEADDR: 77427191Skarels case SO_OOBINLINE: 77518369Skarels if (m == NULL || m->m_len < sizeof (int)) { 77618369Skarels error = EINVAL; 77718369Skarels goto bad; 77818369Skarels } 77918369Skarels if (*mtod(m, int *)) 78018369Skarels so->so_options |= optname; 78118369Skarels else 78218369Skarels so->so_options &= ~optname; 78318369Skarels break; 78418369Skarels 78518369Skarels case SO_SNDBUF: 78641908Skarels case SO_RCVBUF: 78740706Skarels case SO_SNDLOWAT: 78841908Skarels case SO_RCVLOWAT: 78940706Skarels case SO_SNDTIMEO: 79018369Skarels case SO_RCVTIMEO: 79118369Skarels if (m == NULL || m->m_len < sizeof (int)) { 79218369Skarels error = EINVAL; 79318369Skarels goto bad; 79418369Skarels } 79518369Skarels switch (optname) { 79618369Skarels 79718369Skarels case SO_SNDBUF: 79818369Skarels case SO_RCVBUF: 79941908Skarels if (sbreserve(optname == SO_SNDBUF ? 80041908Skarels &so->so_snd : &so->so_rcv, 80141908Skarels (u_long) *mtod(m, int *)) == 0) { 80218369Skarels error = ENOBUFS; 80318369Skarels goto bad; 80418369Skarels } 80518369Skarels break; 80618369Skarels 80718369Skarels case SO_SNDLOWAT: 80841908Skarels so->so_snd.sb_lowat = *mtod(m, int *); 80941908Skarels break; 81018369Skarels case SO_RCVLOWAT: 81141908Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 81218369Skarels break; 81318369Skarels case SO_SNDTIMEO: 81441908Skarels so->so_snd.sb_timeo = *mtod(m, int *); 81541908Skarels break; 81618369Skarels case SO_RCVTIMEO: 81741908Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 81818369Skarels break; 81918369Skarels } 82018369Skarels break; 82118369Skarels 82218369Skarels default: 82318369Skarels error = ENOPROTOOPT; 82418369Skarels break; 82517158Ssam } 82610267Ssam } 82717158Ssam bad: 82817158Ssam if (m) 82917158Ssam (void) m_free(m); 83017158Ssam return (error); 83110267Ssam } 83210267Ssam 83317158Ssam sogetopt(so, level, optname, mp) 83412757Ssam register struct socket *so; 83510267Ssam int level, optname; 83617158Ssam struct mbuf **mp; 83717158Ssam { 83812757Ssam register struct mbuf *m; 83910267Ssam 84018369Skarels if (level != SOL_SOCKET) { 84118369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 84218369Skarels return ((*so->so_proto->pr_ctloutput) 84318369Skarels (PRCO_GETOPT, so, level, optname, mp)); 84418369Skarels } else 84518369Skarels return (ENOPROTOOPT); 84618369Skarels } else { 84717158Ssam m = m_get(M_WAIT, MT_SOOPTS); 84825502Skarels m->m_len = sizeof (int); 84925502Skarels 85018369Skarels switch (optname) { 85117158Ssam 85218369Skarels case SO_LINGER: 85318369Skarels m->m_len = sizeof (struct linger); 85418369Skarels mtod(m, struct linger *)->l_onoff = 85518369Skarels so->so_options & SO_LINGER; 85618369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 85718369Skarels break; 85810267Ssam 85918369Skarels case SO_USELOOPBACK: 86018369Skarels case SO_DONTROUTE: 86118369Skarels case SO_DEBUG: 86218369Skarels case SO_KEEPALIVE: 86318369Skarels case SO_REUSEADDR: 86418369Skarels case SO_BROADCAST: 86527191Skarels case SO_OOBINLINE: 86618369Skarels *mtod(m, int *) = so->so_options & optname; 86718369Skarels break; 86818369Skarels 86925502Skarels case SO_TYPE: 87025502Skarels *mtod(m, int *) = so->so_type; 87125502Skarels break; 87225502Skarels 87324768Skarels case SO_ERROR: 87424768Skarels *mtod(m, int *) = so->so_error; 87524768Skarels so->so_error = 0; 87624768Skarels break; 87724768Skarels 87818369Skarels case SO_SNDBUF: 87918369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 88018369Skarels break; 88118369Skarels 88218369Skarels case SO_RCVBUF: 88318369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 88418369Skarels break; 88518369Skarels 88618369Skarels case SO_SNDLOWAT: 88718369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 88818369Skarels break; 88918369Skarels 89018369Skarels case SO_RCVLOWAT: 89118369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 89218369Skarels break; 89318369Skarels 89418369Skarels case SO_SNDTIMEO: 89518369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 89618369Skarels break; 89718369Skarels 89818369Skarels case SO_RCVTIMEO: 89918369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 90018369Skarels break; 90118369Skarels 90218369Skarels default: 90326362Skarels (void)m_free(m); 90418369Skarels return (ENOPROTOOPT); 90518369Skarels } 90618369Skarels *mp = m; 90718369Skarels return (0); 90810267Ssam } 90910267Ssam } 91010267Ssam 9115423Swnj sohasoutofband(so) 91212757Ssam register struct socket *so; 9135423Swnj { 91423233Skarels struct proc *p; 9155423Swnj 91637478Ssklower if (so->so_pgid < 0) 91737478Ssklower gsignal(-so->so_pgid, SIGURG); 91837478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 91923233Skarels psignal(p, SIGURG); 92024768Skarels if (so->so_rcv.sb_sel) { 92124768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 92224768Skarels so->so_rcv.sb_sel = 0; 92324768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 92424768Skarels } 9255423Swnj } 926