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*40706Skarels * @(#)uipc_socket.c 7.17 (Berkeley) 04/03/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 86*40706Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_BIND, 8712757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 888300Sroot splx(s); 898300Sroot return (error); 908300Sroot } 918300Sroot 928300Sroot solisten(so, backlog) 9312757Ssam register struct socket *so; 948300Sroot int backlog; 958300Sroot { 9612757Ssam int s = splnet(), error; 978300Sroot 9812757Ssam error = 9912757Ssam (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 10012757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 1018300Sroot if (error) { 1028300Sroot splx(s); 1038300Sroot return (error); 1048300Sroot } 10538584Skarels if (so->so_q == 0) 1068300Sroot so->so_options |= SO_ACCEPTCONN; 1078300Sroot if (backlog < 0) 1088300Sroot backlog = 0; 10935384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 11012493Ssam splx(s); 1118300Sroot return (0); 1128300Sroot } 1138300Sroot 1144916Swnj sofree(so) 11512757Ssam register struct socket *so; 1164916Swnj { 1174916Swnj 11831810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 11931810Skarels return; 1207507Sroot if (so->so_head) { 1217507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1227507Sroot panic("sofree dq"); 1237507Sroot so->so_head = 0; 1247507Sroot } 1254950Swnj sbrelease(&so->so_snd); 12612757Ssam sorflush(so); 12737478Ssklower FREE(so, M_SOCKET); 1284916Swnj } 1294916Swnj 1304786Swnj /* 1314890Swnj * Close a socket on last file table reference removal. 1324890Swnj * Initiate disconnect if connected. 1334890Swnj * Free socket when disconnect complete. 1344829Swnj */ 13512757Ssam soclose(so) 1364829Swnj register struct socket *so; 1374829Swnj { 1384890Swnj int s = splnet(); /* conservative */ 13933372Sbostic int error = 0; 1404829Swnj 1417507Sroot if (so->so_options & SO_ACCEPTCONN) { 14238584Skarels while (so->so_q0) 14310399Ssam (void) soabort(so->so_q0); 14438584Skarels while (so->so_q) 14510399Ssam (void) soabort(so->so_q); 1467507Sroot } 1474890Swnj if (so->so_pcb == 0) 1484890Swnj goto discard; 1494890Swnj if (so->so_state & SS_ISCONNECTED) { 1504890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 15126245Skarels error = sodisconnect(so); 15212757Ssam if (error) 15312757Ssam goto drop; 1544890Swnj } 15510267Ssam if (so->so_options & SO_LINGER) { 1565281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 15712757Ssam (so->so_state & SS_NBIO)) 15812757Ssam goto drop; 1595281Sroot while (so->so_state & SS_ISCONNECTED) 160*40706Skarels if (error = tsleep((caddr_t)&so->so_timeo, 161*40706Skarels PSOCK | PCATCH, netcls, so->so_linger)) 162*40706Skarels break; 1634890Swnj } 1644890Swnj } 165*40706Skarels /* 166*40706Skarels * If there is an error on the socket, disregard any 167*40706Skarels * error from tsleep and return the socket error. 168*40706Skarels */ 169*40706Skarels if (so->so_error) 170*40706Skarels error = so->so_error; 1715580Sroot drop: 1726880Ssam if (so->so_pcb) { 17312757Ssam int error2 = 17412757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17612757Ssam if (error == 0) 17712757Ssam error = error2; 1786880Ssam } 1794890Swnj discard: 18010399Ssam if (so->so_state & SS_NOFDREF) 18110399Ssam panic("soclose: NOFDREF"); 1827507Sroot so->so_state |= SS_NOFDREF; 1834950Swnj sofree(so); 1844890Swnj splx(s); 18512757Ssam return (error); 1864829Swnj } 1874829Swnj 18810399Ssam /* 18910399Ssam * Must be called at splnet... 19010399Ssam */ 19110399Ssam soabort(so) 19210399Ssam struct socket *so; 19310399Ssam { 19410399Ssam 19512757Ssam return ( 19612757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19712757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19810399Ssam } 19910399Ssam 20010267Ssam soaccept(so, nam) 20112757Ssam register struct socket *so; 2028300Sroot struct mbuf *nam; 2034927Swnj { 2044927Swnj int s = splnet(); 2054927Swnj int error; 2064927Swnj 20710399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20810399Ssam panic("soaccept: !NOFDREF"); 20910267Ssam so->so_state &= ~SS_NOFDREF; 2108300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 21112757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2124927Swnj splx(s); 2134927Swnj return (error); 2144927Swnj } 2154927Swnj 21610267Ssam soconnect(so, nam) 21712757Ssam register struct socket *so; 2188300Sroot struct mbuf *nam; 2194786Swnj { 22030414Skarels int s; 2214890Swnj int error; 2224786Swnj 22330414Skarels if (so->so_options & SO_ACCEPTCONN) 22430414Skarels return (EOPNOTSUPP); 22530414Skarels s = splnet(); 22624768Skarels /* 22724768Skarels * If protocol is connection-based, can only connect once. 22824768Skarels * Otherwise, if connected, try to disconnect first. 22924768Skarels * This allows user to disconnect by connecting to, e.g., 23024768Skarels * a null address. 23124768Skarels */ 23224768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 23324768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 23424768Skarels (error = sodisconnect(so)))) 2354890Swnj error = EISCONN; 23624768Skarels else 23724768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23824768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2394890Swnj splx(s); 2404890Swnj return (error); 2414786Swnj } 2424786Swnj 24312757Ssam soconnect2(so1, so2) 24412757Ssam register struct socket *so1; 24512757Ssam struct socket *so2; 24612757Ssam { 24712757Ssam int s = splnet(); 24812757Ssam int error; 24912757Ssam 25013113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 25113113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 25212757Ssam splx(s); 25312757Ssam return (error); 25412757Ssam } 25512757Ssam 25626245Skarels sodisconnect(so) 25712757Ssam register struct socket *so; 2584786Swnj { 2594890Swnj int s = splnet(); 2604890Swnj int error; 2614786Swnj 2624890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2634890Swnj error = ENOTCONN; 2644890Swnj goto bad; 2654890Swnj } 2664890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2674890Swnj error = EALREADY; 2684890Swnj goto bad; 2694890Swnj } 2708300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 27126245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2724890Swnj bad: 2734890Swnj splx(s); 2744890Swnj return (error); 2754786Swnj } 2764786Swnj 2774786Swnj /* 2784890Swnj * Send on a socket. 2794890Swnj * If send must go all at once and message is larger than 2804890Swnj * send buffering, then hard error. 2814890Swnj * Lock against other senders. 2824890Swnj * If must go all at once and not enough room now, then 2834890Swnj * inform user that this would block and do nothing. 28416412Skarels * Otherwise, if nonblocking, send as much as possible. 2854786Swnj */ 28640632Skarels sosend(so, nam, uio, flags, control) 2874786Swnj register struct socket *so; 2888300Sroot struct mbuf *nam; 28912757Ssam register struct uio *uio; 2908319Sroot int flags; 29140632Skarels struct mbuf *control; 2924786Swnj { 29335384Skarels struct mbuf *top = 0, **mp; 29435384Skarels register struct mbuf *m; 29535384Skarels register int space, len; 296*40706Skarels int rlen = 0, error, s, dontroute, mlen; 29735384Skarels int atomic = sosendallatonce(so); 2984786Swnj 29935384Skarels if (atomic && uio->uio_resid > so->so_snd.sb_hiwat) 3004890Swnj return (EMSGSIZE); 30112757Ssam dontroute = 30212757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 30312757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30416412Skarels u.u_ru.ru_msgsnd++; 30540632Skarels if (control) 30640632Skarels rlen = control->m_len; 30716412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30816412Skarels 3096419Sroot restart: 310*40706Skarels if (error = sblock(&so->so_snd)) 311*40706Skarels return (error); 31216412Skarels do { 31316412Skarels s = splnet(); 31421108Skarels if (so->so_state & SS_CANTSENDMORE) 31516412Skarels snderr(EPIPE); 31637478Ssklower if (so->so_error) 31737478Ssklower snderr(so->so_error); 31816412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 31937478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 32038584Skarels if ((so->so_state & SS_ISCONFIRMING) == 0) 32137478Ssklower snderr(ENOTCONN); 32237478Ssklower } else if (nam == 0) 32316412Skarels snderr(EDESTADDRREQ); 32416412Skarels } 32516412Skarels if (flags & MSG_OOB) 32616412Skarels space = 1024; 32716412Skarels else { 32816412Skarels space = sbspace(&so->so_snd); 32925629Skarels if (space <= rlen || 33035384Skarels (atomic && space < uio->uio_resid + rlen) || 33135384Skarels (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 33235384Skarels so->so_snd.sb_cc >= MCLBYTES && 33316992Skarels (so->so_state & SS_NBIO) == 0)) { 334*40706Skarels if (so->so_state & SS_NBIO) 335*40706Skarels snderr(EWOULDBLOCK); 33616412Skarels sbunlock(&so->so_snd); 337*40706Skarels if (error = sbwait(&so->so_snd)) 338*40706Skarels snderr(error); 33916412Skarels splx(s); 34016412Skarels goto restart; 34116412Skarels } 34216412Skarels } 34316412Skarels splx(s); 34416412Skarels mp = ⊤ 34525629Skarels space -= rlen; 34635384Skarels do { 34735384Skarels do { 34835384Skarels if (top == 0) { 34935384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35035384Skarels mlen = MHLEN; 35135384Skarels m->m_pkthdr.len = 0; 35235384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35335384Skarels } else { 35435384Skarels MGET(m, M_WAIT, MT_DATA); 35535384Skarels mlen = MLEN; 35635384Skarels } 35735384Skarels if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 35835384Skarels MCLGET(m, M_WAIT); 35935384Skarels if ((m->m_flags & M_EXT) == 0) 36016412Skarels goto nopages; 36135384Skarels mlen = MCLBYTES; 36235384Skarels #ifdef MAPPED_MBUFS 36335384Skarels len = min(MCLBYTES, uio->uio_resid); 36435384Skarels if (len < mlen - max_hdr) 36535384Skarels m->m_data += max_hdr; 36635384Skarels #else 36735384Skarels len = min(MCLBYTES - max_hdr, uio->uio_resid); 36835384Skarels m->m_data += max_hdr; 36935384Skarels #endif 37035384Skarels space -= MCLBYTES; 37116412Skarels } else { 37216412Skarels nopages: 37335384Skarels len = min(min(mlen, uio->uio_resid), space); 37421767Skarels space -= len; 37535384Skarels /* 37635384Skarels * For datagram protocols, leave room 37735384Skarels * for protocol headers in first mbuf. 37835384Skarels */ 37935391Skarels if (atomic && top == 0 && len < mlen) 38035384Skarels MH_ALIGN(m, len); 38116412Skarels } 38237728Smckusick error = uiomove(mtod(m, caddr_t), len, uio); 38316412Skarels m->m_len = len; 38416412Skarels *mp = m; 38535384Skarels top->m_pkthdr.len += len; 38616412Skarels if (error) 38716412Skarels goto release; 38816412Skarels mp = &m->m_next; 38935384Skarels if (uio->uio_resid <= 0) { 39035384Skarels if ((flags & MSG_EOR) && top) 39135384Skarels top->m_flags |= M_EOR; 39221108Skarels break; 39335384Skarels } 39435384Skarels } while (space > 0 && atomic); 39535384Skarels if (dontroute) 39635384Skarels so->so_options |= SO_DONTROUTE; 39735384Skarels s = splnet(); /* XXX */ 39835384Skarels error = (*so->so_proto->pr_usrreq)(so, 39935384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40040632Skarels top, (caddr_t)nam, control); 40135384Skarels splx(s); 40235384Skarels if (dontroute) 40335384Skarels so->so_options &= ~SO_DONTROUTE; 40435384Skarels rlen = 0; 40535384Skarels top = 0; 40635384Skarels mp = ⊤ 40735384Skarels if (error) 40835384Skarels goto release; 40935384Skarels } while (uio->uio_resid && space > 0); 41016412Skarels } while (uio->uio_resid); 4114890Swnj 4124786Swnj release: 4134890Swnj sbunlock(&so->so_snd); 4146419Sroot if (top) 4156419Sroot m_freem(top); 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; 439*40706Skarels register int flags, len, error, s, offset; 44012757Ssam struct protosw *pr = so->so_proto; 44140632Skarels 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: 477*40706Skarels if (error = sblock(&so->so_rcv)) 478*40706Skarels return (error); 4798835Sroot s = splnet(); 4804890Swnj 48137478Ssklower m = so->so_rcv.sb_mb; 48237478Ssklower if (m == 0) { 48337478Ssklower if (so->so_rcv.sb_cc) 48437478Ssklower panic("receive 1"); 4855168Swnj if (so->so_error) { 4865168Swnj error = so->so_error; 4875168Swnj so->so_error = 0; 4885168Swnj goto release; 4895168Swnj } 49032567Sbostic if (so->so_state & SS_CANTRCVMORE) 4914890Swnj goto release; 49238584Skarels if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && 49332567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 49432567Sbostic error = ENOTCONN; 49532567Sbostic goto release; 4964890Swnj } 49725629Skarels if (uio->uio_resid == 0) 49825629Skarels goto release; 49932567Sbostic if (so->so_state & SS_NBIO) { 50032567Sbostic error = EWOULDBLOCK; 50132567Sbostic goto release; 50232567Sbostic } 5034890Swnj sbunlock(&so->so_rcv); 504*40706Skarels if (error = sbwait(&so->so_rcv)) 505*40706Skarels goto release; 5065012Swnj splx(s); 5074890Swnj goto restart; 5084786Swnj } 5098041Sroot u.u_ru.ru_msgrcv++; 51035384Skarels if (m->m_type == 0) 51135384Skarels panic("receive 3a"); 51235384Skarels nextrecord = m->m_nextpkt; 51312757Ssam if (pr->pr_flags & PR_ADDR) { 51425629Skarels if (m->m_type != MT_SONAME) 51516993Skarels panic("receive 1a"); 51616993Skarels if (flags & MSG_PEEK) { 51716993Skarels if (aname) 5188319Sroot *aname = m_copy(m, 0, m->m_len); 51925629Skarels m = m->m_next; 52016993Skarels } else { 52125629Skarels sbfree(&so->so_rcv, m); 52216993Skarels if (aname) { 52316993Skarels *aname = m; 52435384Skarels so->so_rcv.sb_mb = m->m_next; 52535384Skarels m->m_next = 0; 52635384Skarels m = so->so_rcv.sb_mb; 52725629Skarels } else { 52826958Skarels MFREE(m, so->so_rcv.sb_mb); 52926958Skarels m = so->so_rcv.sb_mb; 53025629Skarels } 53116993Skarels } 53216993Skarels } 53316993Skarels if (m && m->m_type == MT_RIGHTS) { 53416993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 53526958Skarels panic("receive 2"); 53616993Skarels if (flags & MSG_PEEK) { 53716993Skarels if (rightsp) 53812757Ssam *rightsp = m_copy(m, 0, m->m_len); 53925629Skarels m = m->m_next; 54016993Skarels } else { 54125629Skarels sbfree(&so->so_rcv, m); 54216993Skarels if (rightsp) { 54316993Skarels *rightsp = m; 54426958Skarels so->so_rcv.sb_mb = m->m_next; 54525629Skarels m->m_next = 0; 54626958Skarels m = so->so_rcv.sb_mb; 54725629Skarels } else { 54826958Skarels MFREE(m, so->so_rcv.sb_mb); 54926958Skarels m = so->so_rcv.sb_mb; 55025629Skarels } 55112757Ssam } 5524890Swnj } 55335384Skarels if (m && m->m_type == MT_CONTROL) { 55435384Skarels if (flags & MSG_PEEK) { 55535384Skarels if (controlp) 55635384Skarels *controlp = m_copy(m, 0, m->m_len); 55735384Skarels m = m->m_next; 55835384Skarels } else { 55935384Skarels sbfree(&so->so_rcv, m); 56035384Skarels if (controlp) { 56135384Skarels *controlp = m; 56235384Skarels so->so_rcv.sb_mb = m->m_next; 56335384Skarels m->m_next = 0; 56435384Skarels m = so->so_rcv.sb_mb; 56535384Skarels } else { 56635384Skarels MFREE(m, so->so_rcv.sb_mb); 56735384Skarels m = so->so_rcv.sb_mb; 56835384Skarels } 56935384Skarels } 57035384Skarels } 57135384Skarels if (m) 57235384Skarels m->m_nextpkt = nextrecord; 5738319Sroot moff = 0; 57432092Skarels offset = 0; 57540632Skarels m_with_eor = 0; 57616993Skarels while (m && uio->uio_resid > 0 && error == 0) { 57735384Skarels if (m->m_type == MT_OOBDATA) 57835384Skarels flags |= MSG_OOB; 57935384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 58025629Skarels panic("receive 3"); 58135384Skarels if (m->m_flags & M_EOR) 58240632Skarels m_with_eor = m; 5837827Sroot len = uio->uio_resid; 5847747Sroot so->so_state &= ~SS_RCVATMARK; 58532092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 58632092Skarels len = so->so_oobmark - offset; 58721767Skarels if (len > m->m_len - moff) 5888319Sroot len = m->m_len - moff; 5894786Swnj splx(s); 59037728Smckusick error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); 5914786Swnj s = splnet(); 59221767Skarels if (len == m->m_len - moff) { 59325629Skarels if (flags & MSG_PEEK) { 59425629Skarels m = m->m_next; 59525629Skarels moff = 0; 59625629Skarels } else { 59735384Skarels nextrecord = m->m_nextpkt; 59825629Skarels sbfree(&so->so_rcv, m); 59926958Skarels MFREE(m, so->so_rcv.sb_mb); 60026958Skarels m = so->so_rcv.sb_mb; 60126958Skarels if (m) 60235384Skarels m->m_nextpkt = nextrecord; 60325629Skarels } 6044786Swnj } else { 60512757Ssam if (flags & MSG_PEEK) 6068319Sroot moff += len; 6078319Sroot else { 60835384Skarels m->m_data += len; 6098319Sroot m->m_len -= len; 6108319Sroot so->so_rcv.sb_cc -= len; 6118319Sroot } 6124786Swnj } 61332092Skarels if (so->so_oobmark) { 61432092Skarels if ((flags & MSG_PEEK) == 0) { 61532092Skarels so->so_oobmark -= len; 61632092Skarels if (so->so_oobmark == 0) { 61732092Skarels so->so_state |= SS_RCVATMARK; 61832092Skarels break; 61932092Skarels } 62032092Skarels } else 62132092Skarels offset += len; 6227747Sroot } 62340632Skarels if (m_with_eor) 62440632Skarels break; 62516993Skarels } 62640632Skarels if (m_with_eor) { 62740632Skarels if (m != m_with_eor) 62840632Skarels flags |= MSG_EOR; 62940632Skarels /* else data not consumed from mbuf */ 63035384Skarels } 63116993Skarels if ((flags & MSG_PEEK) == 0) { 63226500Skarels if (m == 0) 63316993Skarels so->so_rcv.sb_mb = nextrecord; 63435384Skarels else if (pr->pr_flags & PR_ATOMIC) { 63535384Skarels flags |= MSG_TRUNC; 63626958Skarels (void) sbdroprecord(&so->so_rcv); 63735384Skarels } 63816993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 63916993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 64037478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 64137478Ssklower (struct mbuf *)0); 64225629Skarels if (error == 0 && rightsp && *rightsp && 64325629Skarels pr->pr_domain->dom_externalize) 64425629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 64516993Skarels } 64635384Skarels if (flagsp) 64735384Skarels *flagsp |= flags; 6484890Swnj release: 6494916Swnj sbunlock(&so->so_rcv); 6504890Swnj splx(s); 6514916Swnj return (error); 6524786Swnj } 6534786Swnj 65410267Ssam soshutdown(so, how) 65512757Ssam register struct socket *so; 65612757Ssam register int how; 65710267Ssam { 65812757Ssam register struct protosw *pr = so->so_proto; 65910267Ssam 66010267Ssam how++; 66112757Ssam if (how & FREAD) 66212757Ssam sorflush(so); 66310267Ssam if (how & FWRITE) 66412757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 66512757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 66610267Ssam return (0); 66710267Ssam } 66810267Ssam 66912757Ssam sorflush(so) 67012757Ssam register struct socket *so; 67112757Ssam { 67212757Ssam register struct sockbuf *sb = &so->so_rcv; 67312757Ssam register struct protosw *pr = so->so_proto; 67412757Ssam register int s; 67512757Ssam struct sockbuf asb; 67612757Ssam 677*40706Skarels sb->sb_flags |= SB_NOINTR; 678*40706Skarels (void) sblock(sb); 67912757Ssam s = splimp(); 68012757Ssam socantrcvmore(so); 68112757Ssam sbunlock(sb); 68212757Ssam asb = *sb; 68312757Ssam bzero((caddr_t)sb, sizeof (*sb)); 68412757Ssam splx(s); 68516993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 68616993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 68712757Ssam sbrelease(&asb); 68812757Ssam } 68912757Ssam 69018553Skarels sosetopt(so, level, optname, m0) 69112757Ssam register struct socket *so; 69210267Ssam int level, optname; 69318553Skarels struct mbuf *m0; 69410267Ssam { 69517158Ssam int error = 0; 696*40706Skarels u_long val; 69718553Skarels register struct mbuf *m = m0; 698*40706Skarels register struct sockbuf *sb; 69910267Ssam 70017158Ssam if (level != SOL_SOCKET) { 70118369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 70218369Skarels return ((*so->so_proto->pr_ctloutput) 70318553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 70418369Skarels error = ENOPROTOOPT; 70518369Skarels } else { 70618369Skarels switch (optname) { 70710267Ssam 70818369Skarels case SO_LINGER: 70918369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 71018369Skarels error = EINVAL; 71118369Skarels goto bad; 71218369Skarels } 71318369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 71418369Skarels /* fall thru... */ 71517158Ssam 71618369Skarels case SO_DEBUG: 71718369Skarels case SO_KEEPALIVE: 71818369Skarels case SO_DONTROUTE: 71918369Skarels case SO_USELOOPBACK: 72018369Skarels case SO_BROADCAST: 72118369Skarels case SO_REUSEADDR: 72227191Skarels case SO_OOBINLINE: 72318369Skarels if (m == NULL || m->m_len < sizeof (int)) { 72418369Skarels error = EINVAL; 72518369Skarels goto bad; 72618369Skarels } 72718369Skarels if (*mtod(m, int *)) 72818369Skarels so->so_options |= optname; 72918369Skarels else 73018369Skarels so->so_options &= ~optname; 73118369Skarels break; 73218369Skarels 73318369Skarels case SO_SNDBUF: 734*40706Skarels case SO_SNDLOWAT: 735*40706Skarels case SO_SNDTIMEO: 736*40706Skarels sb = &so->so_snd; 737*40706Skarels goto bufopts; 738*40706Skarels 73918369Skarels case SO_RCVBUF: 74018369Skarels case SO_RCVLOWAT: 74118369Skarels case SO_RCVTIMEO: 742*40706Skarels sb = &so->so_rcv; 743*40706Skarels bufopts: 74418369Skarels if (m == NULL || m->m_len < sizeof (int)) { 74518369Skarels error = EINVAL; 74618369Skarels goto bad; 74718369Skarels } 74818369Skarels switch (optname) { 74918369Skarels 75018369Skarels case SO_SNDBUF: 75118369Skarels case SO_RCVBUF: 752*40706Skarels if ((val = (u_long) *mtod(m, int *)) == 0) { 753*40706Skarels error = EINVAL; 754*40706Skarels goto bad; 755*40706Skarels } 756*40706Skarels if (sbreserve(sb, val) == 0) { 75718369Skarels error = ENOBUFS; 75818369Skarels goto bad; 75918369Skarels } 760*40706Skarels if (sb->sb_lowat > sb->sb_hiwat) 761*40706Skarels sb->sb_lowat = sb->sb_hiwat; 76218369Skarels break; 76318369Skarels 76418369Skarels case SO_SNDLOWAT: 76518369Skarels case SO_RCVLOWAT: 766*40706Skarels if ((val = (u_long) *mtod(m, int *)) == 0 || 767*40706Skarels val > sb->sb_hiwat) { 768*40706Skarels error = EINVAL; 769*40706Skarels goto bad; 770*40706Skarels } 771*40706Skarels sb->sb_lowat = val; 77218369Skarels break; 773*40706Skarels 77418369Skarels case SO_SNDTIMEO: 77518369Skarels case SO_RCVTIMEO: 776*40706Skarels sb->sb_timeo = *mtod(m, int *); 77718369Skarels break; 77818369Skarels } 77918369Skarels break; 78018369Skarels 78118369Skarels default: 78218369Skarels error = ENOPROTOOPT; 78318369Skarels break; 78417158Ssam } 78510267Ssam } 78617158Ssam bad: 78717158Ssam if (m) 78817158Ssam (void) m_free(m); 78917158Ssam return (error); 79010267Ssam } 79110267Ssam 79217158Ssam sogetopt(so, level, optname, mp) 79312757Ssam register struct socket *so; 79410267Ssam int level, optname; 79517158Ssam struct mbuf **mp; 79617158Ssam { 79712757Ssam register struct mbuf *m; 79810267Ssam 79918369Skarels if (level != SOL_SOCKET) { 80018369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 80118369Skarels return ((*so->so_proto->pr_ctloutput) 80218369Skarels (PRCO_GETOPT, so, level, optname, mp)); 80318369Skarels } else 80418369Skarels return (ENOPROTOOPT); 80518369Skarels } else { 80617158Ssam m = m_get(M_WAIT, MT_SOOPTS); 80725502Skarels m->m_len = sizeof (int); 80825502Skarels 80918369Skarels switch (optname) { 81017158Ssam 81118369Skarels case SO_LINGER: 81218369Skarels m->m_len = sizeof (struct linger); 81318369Skarels mtod(m, struct linger *)->l_onoff = 81418369Skarels so->so_options & SO_LINGER; 81518369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 81618369Skarels break; 81710267Ssam 81818369Skarels case SO_USELOOPBACK: 81918369Skarels case SO_DONTROUTE: 82018369Skarels case SO_DEBUG: 82118369Skarels case SO_KEEPALIVE: 82218369Skarels case SO_REUSEADDR: 82318369Skarels case SO_BROADCAST: 82427191Skarels case SO_OOBINLINE: 82518369Skarels *mtod(m, int *) = so->so_options & optname; 82618369Skarels break; 82718369Skarels 82825502Skarels case SO_TYPE: 82925502Skarels *mtod(m, int *) = so->so_type; 83025502Skarels break; 83125502Skarels 83224768Skarels case SO_ERROR: 83324768Skarels *mtod(m, int *) = so->so_error; 83424768Skarels so->so_error = 0; 83524768Skarels break; 83624768Skarels 83718369Skarels case SO_SNDBUF: 83818369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 83918369Skarels break; 84018369Skarels 84118369Skarels case SO_RCVBUF: 84218369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 84318369Skarels break; 84418369Skarels 84518369Skarels case SO_SNDLOWAT: 84618369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 84718369Skarels break; 84818369Skarels 84918369Skarels case SO_RCVLOWAT: 85018369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 85118369Skarels break; 85218369Skarels 85318369Skarels case SO_SNDTIMEO: 85418369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 85518369Skarels break; 85618369Skarels 85718369Skarels case SO_RCVTIMEO: 85818369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 85918369Skarels break; 86018369Skarels 86118369Skarels default: 86226362Skarels (void)m_free(m); 86318369Skarels return (ENOPROTOOPT); 86418369Skarels } 86518369Skarels *mp = m; 86618369Skarels return (0); 86710267Ssam } 86810267Ssam } 86910267Ssam 8705423Swnj sohasoutofband(so) 87112757Ssam register struct socket *so; 8725423Swnj { 87323233Skarels struct proc *p; 8745423Swnj 87537478Ssklower if (so->so_pgid < 0) 87637478Ssklower gsignal(-so->so_pgid, SIGURG); 87737478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 87823233Skarels psignal(p, SIGURG); 87924768Skarels if (so->so_rcv.sb_sel) { 88024768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 88124768Skarels so->so_rcv.sb_sel = 0; 88224768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 88324768Skarels } 8845423Swnj } 885