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*37478Ssklower * @(#)uipc_socket.c 7.13 (Berkeley) 04/22/89 1823421Smckusick */ 194786Swnj 2017102Sbloom #include "param.h" 2117102Sbloom #include "dir.h" 2217102Sbloom #include "user.h" 2317102Sbloom #include "proc.h" 2417102Sbloom #include "file.h" 2535384Skarels #include "malloc.h" 2617102Sbloom #include "mbuf.h" 2717102Sbloom #include "domain.h" 2817102Sbloom #include "protosw.h" 2917102Sbloom #include "socket.h" 3017102Sbloom #include "socketvar.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); 62*37478Ssklower MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); 63*37478Ssklower 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 } 1078300Sroot if (so->so_q == 0) { 1088300Sroot so->so_q = so; 1098300Sroot so->so_q0 = so; 1108300Sroot so->so_options |= SO_ACCEPTCONN; 1118300Sroot } 1128300Sroot if (backlog < 0) 1138300Sroot backlog = 0; 11435384Skarels so->so_qlimit = min(backlog, SOMAXCONN); 11512493Ssam splx(s); 1168300Sroot return (0); 1178300Sroot } 1188300Sroot 1194916Swnj sofree(so) 12012757Ssam register struct socket *so; 1214916Swnj { 1224916Swnj 12331810Skarels if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 12431810Skarels return; 1257507Sroot if (so->so_head) { 1267507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1277507Sroot panic("sofree dq"); 1287507Sroot so->so_head = 0; 1297507Sroot } 1304950Swnj sbrelease(&so->so_snd); 13112757Ssam sorflush(so); 132*37478Ssklower FREE(so, M_SOCKET); 1334916Swnj } 1344916Swnj 1354786Swnj /* 1364890Swnj * Close a socket on last file table reference removal. 1374890Swnj * Initiate disconnect if connected. 1384890Swnj * Free socket when disconnect complete. 1394829Swnj */ 14012757Ssam soclose(so) 1414829Swnj register struct socket *so; 1424829Swnj { 1434890Swnj int s = splnet(); /* conservative */ 14433372Sbostic int error = 0; 1454829Swnj 1467507Sroot if (so->so_options & SO_ACCEPTCONN) { 1477507Sroot while (so->so_q0 != so) 14810399Ssam (void) soabort(so->so_q0); 1497507Sroot while (so->so_q != so) 15010399Ssam (void) soabort(so->so_q); 1517507Sroot } 1524890Swnj if (so->so_pcb == 0) 1534890Swnj goto discard; 1544890Swnj if (so->so_state & SS_ISCONNECTED) { 1554890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 15626245Skarels error = sodisconnect(so); 15712757Ssam if (error) 15812757Ssam goto drop; 1594890Swnj } 16010267Ssam if (so->so_options & SO_LINGER) { 1615281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 16212757Ssam (so->so_state & SS_NBIO)) 16312757Ssam goto drop; 1645281Sroot while (so->so_state & SS_ISCONNECTED) 1655281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1664890Swnj } 1674890Swnj } 1685580Sroot drop: 1696880Ssam if (so->so_pcb) { 17012757Ssam int error2 = 17112757Ssam (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 17212757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 17312757Ssam if (error == 0) 17412757Ssam error = error2; 1756880Ssam } 1764890Swnj discard: 17710399Ssam if (so->so_state & SS_NOFDREF) 17810399Ssam panic("soclose: NOFDREF"); 1797507Sroot so->so_state |= SS_NOFDREF; 1804950Swnj sofree(so); 1814890Swnj splx(s); 18212757Ssam return (error); 1834829Swnj } 1844829Swnj 18510399Ssam /* 18610399Ssam * Must be called at splnet... 18710399Ssam */ 18810399Ssam soabort(so) 18910399Ssam struct socket *so; 19010399Ssam { 19110399Ssam 19212757Ssam return ( 19312757Ssam (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19412757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 19510399Ssam } 19610399Ssam 19710267Ssam soaccept(so, nam) 19812757Ssam register struct socket *so; 1998300Sroot struct mbuf *nam; 2004927Swnj { 2014927Swnj int s = splnet(); 2024927Swnj int error; 2034927Swnj 20410399Ssam if ((so->so_state & SS_NOFDREF) == 0) 20510399Ssam panic("soaccept: !NOFDREF"); 20610267Ssam so->so_state &= ~SS_NOFDREF; 2078300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20812757Ssam (struct mbuf *)0, nam, (struct mbuf *)0); 2094927Swnj splx(s); 2104927Swnj return (error); 2114927Swnj } 2124927Swnj 21310267Ssam soconnect(so, nam) 21412757Ssam register struct socket *so; 2158300Sroot struct mbuf *nam; 2164786Swnj { 21730414Skarels int s; 2184890Swnj int error; 2194786Swnj 22030414Skarels if (so->so_options & SO_ACCEPTCONN) 22130414Skarels return (EOPNOTSUPP); 22230414Skarels s = splnet(); 22324768Skarels /* 22424768Skarels * If protocol is connection-based, can only connect once. 22524768Skarels * Otherwise, if connected, try to disconnect first. 22624768Skarels * This allows user to disconnect by connecting to, e.g., 22724768Skarels * a null address. 22824768Skarels */ 22924768Skarels if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && 23024768Skarels ((so->so_proto->pr_flags & PR_CONNREQUIRED) || 23124768Skarels (error = sodisconnect(so)))) 2324890Swnj error = EISCONN; 23324768Skarels else 23424768Skarels error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23524768Skarels (struct mbuf *)0, nam, (struct mbuf *)0); 2364890Swnj splx(s); 2374890Swnj return (error); 2384786Swnj } 2394786Swnj 24012757Ssam soconnect2(so1, so2) 24112757Ssam register struct socket *so1; 24212757Ssam struct socket *so2; 24312757Ssam { 24412757Ssam int s = splnet(); 24512757Ssam int error; 24612757Ssam 24713113Ssam error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, 24813113Ssam (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); 24912757Ssam splx(s); 25012757Ssam return (error); 25112757Ssam } 25212757Ssam 25326245Skarels sodisconnect(so) 25412757Ssam register struct socket *so; 2554786Swnj { 2564890Swnj int s = splnet(); 2574890Swnj int error; 2584786Swnj 2594890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2604890Swnj error = ENOTCONN; 2614890Swnj goto bad; 2624890Swnj } 2634890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2644890Swnj error = EALREADY; 2654890Swnj goto bad; 2664890Swnj } 2678300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 26826245Skarels (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); 2694890Swnj bad: 2704890Swnj splx(s); 2714890Swnj return (error); 2724786Swnj } 2734786Swnj 2744786Swnj /* 2754890Swnj * Send on a socket. 2764890Swnj * If send must go all at once and message is larger than 2774890Swnj * send buffering, then hard error. 2784890Swnj * Lock against other senders. 2794890Swnj * If must go all at once and not enough room now, then 2804890Swnj * inform user that this would block and do nothing. 28116412Skarels * Otherwise, if nonblocking, send as much as possible. 2824786Swnj */ 28335384Skarels sosend(so, nam, uio, flags, rights, control) 2844786Swnj register struct socket *so; 2858300Sroot struct mbuf *nam; 28612757Ssam register struct uio *uio; 2878319Sroot int flags; 28835384Skarels struct mbuf *rights, *control; 2894786Swnj { 29035384Skarels struct mbuf *top = 0, **mp; 29135384Skarels register struct mbuf *m; 29235384Skarels register int space, len; 29335384Skarels int rlen = 0, error = 0, s, dontroute, first = 1, mlen; 29435384Skarels int atomic = sosendallatonce(so); 2954786Swnj 29635384Skarels if (atomic && uio->uio_resid > so->so_snd.sb_hiwat) 2974890Swnj return (EMSGSIZE); 29812757Ssam dontroute = 29912757Ssam (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && 30012757Ssam (so->so_proto->pr_flags & PR_ATOMIC); 30116412Skarels u.u_ru.ru_msgsnd++; 30225629Skarels if (rights) 30325629Skarels rlen = rights->m_len; 30416412Skarels #define snderr(errno) { error = errno; splx(s); goto release; } 30516412Skarels 3066419Sroot restart: 3074890Swnj sblock(&so->so_snd); 30816412Skarels do { 30916412Skarels s = splnet(); 31021108Skarels if (so->so_state & SS_CANTSENDMORE) 31116412Skarels snderr(EPIPE); 312*37478Ssklower if (so->so_error) 313*37478Ssklower snderr(so->so_error); 31416412Skarels if ((so->so_state & SS_ISCONNECTED) == 0) { 315*37478Ssklower if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 316*37478Ssklower if (!uio->uio_resid && !rights && control) { 317*37478Ssklower snderr((*so->so_proto->pr_usrreq)(so, 318*37478Ssklower (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 319*37478Ssklower top, (caddr_t)0, rights, control)); 320*37478Ssklower } else if (so->so_state & SS_ISCONFIRMING) 321*37478Ssklower /* is ok */; 322*37478Ssklower else 323*37478Ssklower snderr(ENOTCONN); 324*37478Ssklower } else if (nam == 0) 32516412Skarels snderr(EDESTADDRREQ); 32616412Skarels } 32716412Skarels if (flags & MSG_OOB) 32816412Skarels space = 1024; 32916412Skarels else { 33016412Skarels space = sbspace(&so->so_snd); 33125629Skarels if (space <= rlen || 33235384Skarels (atomic && space < uio->uio_resid + rlen) || 33335384Skarels (uio->uio_resid >= MCLBYTES && space < MCLBYTES && 33435384Skarels so->so_snd.sb_cc >= MCLBYTES && 33516992Skarels (so->so_state & SS_NBIO) == 0)) { 33616412Skarels if (so->so_state & SS_NBIO) { 33716412Skarels if (first) 33816412Skarels error = EWOULDBLOCK; 33916412Skarels splx(s); 34016412Skarels goto release; 34116412Skarels } 34216412Skarels sbunlock(&so->so_snd); 34316412Skarels sbwait(&so->so_snd); 34416412Skarels splx(s); 34516412Skarels goto restart; 34616412Skarels } 34716412Skarels } 34816412Skarels splx(s); 34916412Skarels mp = ⊤ 35025629Skarels space -= rlen; 35135384Skarels do { 35235384Skarels do { 35335384Skarels if (top == 0) { 35435384Skarels MGETHDR(m, M_WAIT, MT_DATA); 35535384Skarels mlen = MHLEN; 35635384Skarels m->m_pkthdr.len = 0; 35735384Skarels m->m_pkthdr.rcvif = (struct ifnet *)0; 35835384Skarels } else { 35935384Skarels MGET(m, M_WAIT, MT_DATA); 36035384Skarels mlen = MLEN; 36135384Skarels } 36235384Skarels if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) { 36335384Skarels MCLGET(m, M_WAIT); 36435384Skarels if ((m->m_flags & M_EXT) == 0) 36516412Skarels goto nopages; 36635384Skarels mlen = MCLBYTES; 36735384Skarels #ifdef MAPPED_MBUFS 36835384Skarels len = min(MCLBYTES, uio->uio_resid); 36935384Skarels if (len < mlen - max_hdr) 37035384Skarels m->m_data += max_hdr; 37135384Skarels #else 37235384Skarels len = min(MCLBYTES - max_hdr, uio->uio_resid); 37335384Skarels m->m_data += max_hdr; 37435384Skarels #endif 37535384Skarels space -= MCLBYTES; 37616412Skarels } else { 37716412Skarels nopages: 37835384Skarels len = min(min(mlen, uio->uio_resid), space); 37921767Skarels space -= len; 38035384Skarels /* 38135384Skarels * For datagram protocols, leave room 38235384Skarels * for protocol headers in first mbuf. 38335384Skarels */ 38435391Skarels if (atomic && top == 0 && len < mlen) 38535384Skarels MH_ALIGN(m, len); 38616412Skarels } 38716412Skarels error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 38816412Skarels m->m_len = len; 38916412Skarels *mp = m; 39035384Skarels top->m_pkthdr.len += len; 39116412Skarels if (error) 39216412Skarels goto release; 39316412Skarels mp = &m->m_next; 39435384Skarels if (uio->uio_resid <= 0) { 39535384Skarels if ((flags & MSG_EOR) && top) 39635384Skarels top->m_flags |= M_EOR; 39721108Skarels break; 39835384Skarels } 39935384Skarels } while (space > 0 && atomic); 40035384Skarels if (dontroute) 40135384Skarels so->so_options |= SO_DONTROUTE; 40235384Skarels s = splnet(); /* XXX */ 40335384Skarels error = (*so->so_proto->pr_usrreq)(so, 40435384Skarels (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, 40535384Skarels top, (caddr_t)nam, rights, control); 40635384Skarels splx(s); 40735384Skarels if (dontroute) 40835384Skarels so->so_options &= ~SO_DONTROUTE; 40935384Skarels rights = 0; 41035384Skarels rlen = 0; 41135384Skarels top = 0; 41235384Skarels mp = ⊤ 41335384Skarels first = 0; 41435384Skarels if (error) 41535384Skarels goto release; 41635384Skarels } while (uio->uio_resid && space > 0); 41716412Skarels } while (uio->uio_resid); 4184890Swnj 4194786Swnj release: 4204890Swnj sbunlock(&so->so_snd); 4216419Sroot if (top) 4226419Sroot m_freem(top); 42321108Skarels if (error == EPIPE) 42421108Skarels psignal(u.u_procp, SIGPIPE); 4254786Swnj return (error); 4264786Swnj } 4274786Swnj 42825629Skarels /* 42925629Skarels * Implement receive operations on a socket. 43025629Skarels * We depend on the way that records are added to the sockbuf 43125629Skarels * by sbappend*. In particular, each record (mbufs linked through m_next) 43225629Skarels * must begin with an address if the protocol so specifies, 43325629Skarels * followed by an optional mbuf containing access rights if supported 43425629Skarels * by the protocol, and then zero or more mbufs of data. 43525629Skarels * In order to avoid blocking network interrupts for the entire time here, 43625629Skarels * we splx() while doing the actual copy to user space. 43725629Skarels * Although the sockbuf is locked, new data may still be appended, 43825629Skarels * and thus we must maintain consistency of the sockbuf during that time. 43925629Skarels */ 44035384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp) 4414786Swnj register struct socket *so; 4428300Sroot struct mbuf **aname; 44312757Ssam register struct uio *uio; 44435384Skarels int *flagsp; 44535384Skarels struct mbuf **rightsp, **controlp; 4464786Swnj { 44726958Skarels register struct mbuf *m; 44835384Skarels register int flags, len, error = 0, s, offset; 44912757Ssam struct protosw *pr = so->so_proto; 45016993Skarels struct mbuf *nextrecord; 45112757Ssam int moff; 4524786Swnj 45312757Ssam if (rightsp) 45412757Ssam *rightsp = 0; 45512757Ssam if (aname) 45612757Ssam *aname = 0; 45735384Skarels if (controlp) 45835384Skarels *controlp = 0; 45935384Skarels if (flagsp) 46035384Skarels flags = *flagsp &~ MSG_EOR; 46135384Skarels else 46235384Skarels flags = 0; 46312757Ssam if (flags & MSG_OOB) { 4649635Ssam m = m_get(M_WAIT, MT_DATA); 46512757Ssam error = (*pr->pr_usrreq)(so, PRU_RCVOOB, 46624768Skarels m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); 4678594Sroot if (error) 46810137Ssam goto bad; 4698319Sroot do { 47010137Ssam len = uio->uio_resid; 4718319Sroot if (len > m->m_len) 4728319Sroot len = m->m_len; 4738594Sroot error = 4748793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4758319Sroot m = m_free(m); 4768594Sroot } while (uio->uio_resid && error == 0 && m); 47710137Ssam bad: 4788319Sroot if (m) 4798771Sroot m_freem(m); 4808594Sroot return (error); 4818319Sroot } 482*37478Ssklower if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) 48335384Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 48435384Skarels (struct mbuf *)0, (struct mbuf *)0); 4858319Sroot 4864890Swnj restart: 4874890Swnj sblock(&so->so_rcv); 4888835Sroot s = splnet(); 4894890Swnj 490*37478Ssklower m = so->so_rcv.sb_mb; 491*37478Ssklower if (m == 0) { 492*37478Ssklower if (so->so_rcv.sb_cc) 493*37478Ssklower panic("receive 1"); 4945168Swnj if (so->so_error) { 4955168Swnj error = so->so_error; 4965168Swnj so->so_error = 0; 4975168Swnj goto release; 4985168Swnj } 49932567Sbostic if (so->so_state & SS_CANTRCVMORE) 5004890Swnj goto release; 50132567Sbostic if ((so->so_state & SS_ISCONNECTED) == 0 && 50232567Sbostic (so->so_proto->pr_flags & PR_CONNREQUIRED)) { 50332567Sbostic error = ENOTCONN; 50432567Sbostic goto release; 5054890Swnj } 50625629Skarels if (uio->uio_resid == 0) 50725629Skarels goto release; 50832567Sbostic if (so->so_state & SS_NBIO) { 50932567Sbostic error = EWOULDBLOCK; 51032567Sbostic goto release; 51132567Sbostic } 5124890Swnj sbunlock(&so->so_rcv); 5134971Swnj sbwait(&so->so_rcv); 5145012Swnj splx(s); 5154890Swnj goto restart; 5164786Swnj } 5178041Sroot u.u_ru.ru_msgrcv++; 51835384Skarels if (m->m_type == 0) 51935384Skarels panic("receive 3a"); 52035384Skarels nextrecord = m->m_nextpkt; 52112757Ssam if (pr->pr_flags & PR_ADDR) { 52225629Skarels if (m->m_type != MT_SONAME) 52316993Skarels panic("receive 1a"); 52416993Skarels if (flags & MSG_PEEK) { 52516993Skarels if (aname) 5268319Sroot *aname = m_copy(m, 0, m->m_len); 52725629Skarels m = m->m_next; 52816993Skarels } else { 52925629Skarels sbfree(&so->so_rcv, m); 53016993Skarels if (aname) { 53116993Skarels *aname = m; 53235384Skarels so->so_rcv.sb_mb = m->m_next; 53335384Skarels m->m_next = 0; 53435384Skarels m = so->so_rcv.sb_mb; 53525629Skarels } else { 53626958Skarels MFREE(m, so->so_rcv.sb_mb); 53726958Skarels m = so->so_rcv.sb_mb; 53825629Skarels } 53916993Skarels } 54016993Skarels } 54116993Skarels if (m && m->m_type == MT_RIGHTS) { 54216993Skarels if ((pr->pr_flags & PR_RIGHTS) == 0) 54326958Skarels panic("receive 2"); 54416993Skarels if (flags & MSG_PEEK) { 54516993Skarels if (rightsp) 54612757Ssam *rightsp = m_copy(m, 0, m->m_len); 54725629Skarels m = m->m_next; 54816993Skarels } else { 54925629Skarels sbfree(&so->so_rcv, m); 55016993Skarels if (rightsp) { 55116993Skarels *rightsp = m; 55226958Skarels so->so_rcv.sb_mb = m->m_next; 55325629Skarels m->m_next = 0; 55426958Skarels m = so->so_rcv.sb_mb; 55525629Skarels } else { 55626958Skarels MFREE(m, so->so_rcv.sb_mb); 55726958Skarels m = so->so_rcv.sb_mb; 55825629Skarels } 55912757Ssam } 5604890Swnj } 56135384Skarels if (m && m->m_type == MT_CONTROL) { 56235384Skarels if (flags & MSG_PEEK) { 56335384Skarels if (controlp) 56435384Skarels *controlp = m_copy(m, 0, m->m_len); 56535384Skarels m = m->m_next; 56635384Skarels } else { 56735384Skarels sbfree(&so->so_rcv, m); 56835384Skarels if (controlp) { 56935384Skarels *controlp = m; 57035384Skarels so->so_rcv.sb_mb = m->m_next; 57135384Skarels m->m_next = 0; 57235384Skarels m = so->so_rcv.sb_mb; 57335384Skarels } else { 57435384Skarels MFREE(m, so->so_rcv.sb_mb); 57535384Skarels m = so->so_rcv.sb_mb; 57635384Skarels } 57735384Skarels } 57835384Skarels } 57935384Skarels if (m) 58035384Skarels m->m_nextpkt = nextrecord; 5818319Sroot moff = 0; 58232092Skarels offset = 0; 58316993Skarels while (m && uio->uio_resid > 0 && error == 0) { 58435384Skarels if (m->m_type == MT_OOBDATA) 58535384Skarels flags |= MSG_OOB; 58635384Skarels else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) 58725629Skarels panic("receive 3"); 58835384Skarels if (m->m_flags & M_EOR) 58935384Skarels flags |= MSG_EOR; 5907827Sroot len = uio->uio_resid; 5917747Sroot so->so_state &= ~SS_RCVATMARK; 59232092Skarels if (so->so_oobmark && len > so->so_oobmark - offset) 59332092Skarels len = so->so_oobmark - offset; 59421767Skarels if (len > m->m_len - moff) 5958319Sroot len = m->m_len - moff; 5964786Swnj splx(s); 5978594Sroot error = 5988793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 5994786Swnj s = splnet(); 60021767Skarels if (len == m->m_len - moff) { 60125629Skarels if (flags & MSG_PEEK) { 60225629Skarels m = m->m_next; 60325629Skarels moff = 0; 60425629Skarels } else { 60535384Skarels nextrecord = m->m_nextpkt; 60625629Skarels sbfree(&so->so_rcv, m); 60726958Skarels MFREE(m, so->so_rcv.sb_mb); 60826958Skarels m = so->so_rcv.sb_mb; 60926958Skarels if (m) 61035384Skarels m->m_nextpkt = nextrecord; 61125629Skarels } 6124786Swnj } else { 61312757Ssam if (flags & MSG_PEEK) 6148319Sroot moff += len; 6158319Sroot else { 61635384Skarels m->m_data += len; 6178319Sroot m->m_len -= len; 6188319Sroot so->so_rcv.sb_cc -= len; 6198319Sroot } 6204786Swnj } 62132092Skarels if (so->so_oobmark) { 62232092Skarels if ((flags & MSG_PEEK) == 0) { 62332092Skarels so->so_oobmark -= len; 62432092Skarels if (so->so_oobmark == 0) { 62532092Skarels so->so_state |= SS_RCVATMARK; 62632092Skarels break; 62732092Skarels } 62832092Skarels } else 62932092Skarels offset += len; 6307747Sroot } 63116993Skarels } 63235384Skarels if (m && (flags & MSG_EOR)) { 63335384Skarels flags &= ~MSG_EOR; 63435384Skarels if ((flags & MSG_PEEK) == 0) 63535384Skarels m->m_flags |= M_EOR; 63635384Skarels } 63716993Skarels if ((flags & MSG_PEEK) == 0) { 63826500Skarels if (m == 0) 63916993Skarels so->so_rcv.sb_mb = nextrecord; 64035384Skarels else if (pr->pr_flags & PR_ATOMIC) { 64135384Skarels flags |= MSG_TRUNC; 64226958Skarels (void) sbdroprecord(&so->so_rcv); 64335384Skarels } 64416993Skarels if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) 64516993Skarels (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, 646*37478Ssklower (struct mbuf *)flags, (struct mbuf *)0, 647*37478Ssklower (struct mbuf *)0); 64825629Skarels if (error == 0 && rightsp && *rightsp && 64925629Skarels pr->pr_domain->dom_externalize) 65025629Skarels error = (*pr->pr_domain->dom_externalize)(*rightsp); 65116993Skarels } 65235384Skarels if (flagsp) 65335384Skarels *flagsp |= flags; 6544890Swnj release: 6554916Swnj sbunlock(&so->so_rcv); 6564890Swnj splx(s); 6574916Swnj return (error); 6584786Swnj } 6594786Swnj 66010267Ssam soshutdown(so, how) 66112757Ssam register struct socket *so; 66212757Ssam register int how; 66310267Ssam { 66412757Ssam register struct protosw *pr = so->so_proto; 66510267Ssam 66610267Ssam how++; 66712757Ssam if (how & FREAD) 66812757Ssam sorflush(so); 66910267Ssam if (how & FWRITE) 67012757Ssam return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, 67112757Ssam (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); 67210267Ssam return (0); 67310267Ssam } 67410267Ssam 67512757Ssam sorflush(so) 67612757Ssam register struct socket *so; 67712757Ssam { 67812757Ssam register struct sockbuf *sb = &so->so_rcv; 67912757Ssam register struct protosw *pr = so->so_proto; 68012757Ssam register int s; 68112757Ssam struct sockbuf asb; 68212757Ssam 68312757Ssam sblock(sb); 68412757Ssam s = splimp(); 68512757Ssam socantrcvmore(so); 68612757Ssam sbunlock(sb); 68712757Ssam asb = *sb; 68812757Ssam bzero((caddr_t)sb, sizeof (*sb)); 68912757Ssam splx(s); 69016993Skarels if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) 69116993Skarels (*pr->pr_domain->dom_dispose)(asb.sb_mb); 69212757Ssam sbrelease(&asb); 69312757Ssam } 69412757Ssam 69518553Skarels sosetopt(so, level, optname, m0) 69612757Ssam register struct socket *so; 69710267Ssam int level, optname; 69818553Skarels struct mbuf *m0; 69910267Ssam { 70017158Ssam int error = 0; 70118553Skarels register struct mbuf *m = m0; 70210267Ssam 70317158Ssam if (level != SOL_SOCKET) { 70418369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) 70518369Skarels return ((*so->so_proto->pr_ctloutput) 70618553Skarels (PRCO_SETOPT, so, level, optname, &m0)); 70718369Skarels error = ENOPROTOOPT; 70818369Skarels } else { 70918369Skarels switch (optname) { 71010267Ssam 71118369Skarels case SO_LINGER: 71218369Skarels if (m == NULL || m->m_len != sizeof (struct linger)) { 71318369Skarels error = EINVAL; 71418369Skarels goto bad; 71518369Skarels } 71618369Skarels so->so_linger = mtod(m, struct linger *)->l_linger; 71718369Skarels /* fall thru... */ 71817158Ssam 71918369Skarels case SO_DEBUG: 72018369Skarels case SO_KEEPALIVE: 72118369Skarels case SO_DONTROUTE: 72218369Skarels case SO_USELOOPBACK: 72318369Skarels case SO_BROADCAST: 72418369Skarels case SO_REUSEADDR: 72527191Skarels case SO_OOBINLINE: 72618369Skarels if (m == NULL || m->m_len < sizeof (int)) { 72718369Skarels error = EINVAL; 72818369Skarels goto bad; 72918369Skarels } 73018369Skarels if (*mtod(m, int *)) 73118369Skarels so->so_options |= optname; 73218369Skarels else 73318369Skarels so->so_options &= ~optname; 73418369Skarels break; 73518369Skarels 73618369Skarels case SO_SNDBUF: 73718369Skarels case SO_RCVBUF: 73818369Skarels case SO_SNDLOWAT: 73918369Skarels case SO_RCVLOWAT: 74018369Skarels case SO_SNDTIMEO: 74118369Skarels case SO_RCVTIMEO: 74218369Skarels if (m == NULL || m->m_len < sizeof (int)) { 74318369Skarels error = EINVAL; 74418369Skarels goto bad; 74518369Skarels } 74618369Skarels switch (optname) { 74718369Skarels 74818369Skarels case SO_SNDBUF: 74918369Skarels case SO_RCVBUF: 75034492Skarels if (sbreserve(optname == SO_SNDBUF ? 75134492Skarels &so->so_snd : &so->so_rcv, 75234492Skarels (u_long) *mtod(m, int *)) == 0) { 75318369Skarels error = ENOBUFS; 75418369Skarels goto bad; 75518369Skarels } 75618369Skarels break; 75718369Skarels 75818369Skarels case SO_SNDLOWAT: 75918369Skarels so->so_snd.sb_lowat = *mtod(m, int *); 76018369Skarels break; 76118369Skarels case SO_RCVLOWAT: 76218369Skarels so->so_rcv.sb_lowat = *mtod(m, int *); 76318369Skarels break; 76418369Skarels case SO_SNDTIMEO: 76518369Skarels so->so_snd.sb_timeo = *mtod(m, int *); 76618369Skarels break; 76718369Skarels case SO_RCVTIMEO: 76818369Skarels so->so_rcv.sb_timeo = *mtod(m, int *); 76918369Skarels break; 77018369Skarels } 77118369Skarels break; 77218369Skarels 77318369Skarels default: 77418369Skarels error = ENOPROTOOPT; 77518369Skarels break; 77617158Ssam } 77710267Ssam } 77817158Ssam bad: 77917158Ssam if (m) 78017158Ssam (void) m_free(m); 78117158Ssam return (error); 78210267Ssam } 78310267Ssam 78417158Ssam sogetopt(so, level, optname, mp) 78512757Ssam register struct socket *so; 78610267Ssam int level, optname; 78717158Ssam struct mbuf **mp; 78817158Ssam { 78912757Ssam register struct mbuf *m; 79010267Ssam 79118369Skarels if (level != SOL_SOCKET) { 79218369Skarels if (so->so_proto && so->so_proto->pr_ctloutput) { 79318369Skarels return ((*so->so_proto->pr_ctloutput) 79418369Skarels (PRCO_GETOPT, so, level, optname, mp)); 79518369Skarels } else 79618369Skarels return (ENOPROTOOPT); 79718369Skarels } else { 79817158Ssam m = m_get(M_WAIT, MT_SOOPTS); 79925502Skarels m->m_len = sizeof (int); 80025502Skarels 80118369Skarels switch (optname) { 80217158Ssam 80318369Skarels case SO_LINGER: 80418369Skarels m->m_len = sizeof (struct linger); 80518369Skarels mtod(m, struct linger *)->l_onoff = 80618369Skarels so->so_options & SO_LINGER; 80718369Skarels mtod(m, struct linger *)->l_linger = so->so_linger; 80818369Skarels break; 80910267Ssam 81018369Skarels case SO_USELOOPBACK: 81118369Skarels case SO_DONTROUTE: 81218369Skarels case SO_DEBUG: 81318369Skarels case SO_KEEPALIVE: 81418369Skarels case SO_REUSEADDR: 81518369Skarels case SO_BROADCAST: 81627191Skarels case SO_OOBINLINE: 81718369Skarels *mtod(m, int *) = so->so_options & optname; 81818369Skarels break; 81918369Skarels 82025502Skarels case SO_TYPE: 82125502Skarels *mtod(m, int *) = so->so_type; 82225502Skarels break; 82325502Skarels 82424768Skarels case SO_ERROR: 82524768Skarels *mtod(m, int *) = so->so_error; 82624768Skarels so->so_error = 0; 82724768Skarels break; 82824768Skarels 82918369Skarels case SO_SNDBUF: 83018369Skarels *mtod(m, int *) = so->so_snd.sb_hiwat; 83118369Skarels break; 83218369Skarels 83318369Skarels case SO_RCVBUF: 83418369Skarels *mtod(m, int *) = so->so_rcv.sb_hiwat; 83518369Skarels break; 83618369Skarels 83718369Skarels case SO_SNDLOWAT: 83818369Skarels *mtod(m, int *) = so->so_snd.sb_lowat; 83918369Skarels break; 84018369Skarels 84118369Skarels case SO_RCVLOWAT: 84218369Skarels *mtod(m, int *) = so->so_rcv.sb_lowat; 84318369Skarels break; 84418369Skarels 84518369Skarels case SO_SNDTIMEO: 84618369Skarels *mtod(m, int *) = so->so_snd.sb_timeo; 84718369Skarels break; 84818369Skarels 84918369Skarels case SO_RCVTIMEO: 85018369Skarels *mtod(m, int *) = so->so_rcv.sb_timeo; 85118369Skarels break; 85218369Skarels 85318369Skarels default: 85426362Skarels (void)m_free(m); 85518369Skarels return (ENOPROTOOPT); 85618369Skarels } 85718369Skarels *mp = m; 85818369Skarels return (0); 85910267Ssam } 86010267Ssam } 86110267Ssam 8625423Swnj sohasoutofband(so) 86312757Ssam register struct socket *so; 8645423Swnj { 86523233Skarels struct proc *p; 8665423Swnj 867*37478Ssklower if (so->so_pgid < 0) 868*37478Ssklower gsignal(-so->so_pgid, SIGURG); 869*37478Ssklower else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) 87023233Skarels psignal(p, SIGURG); 87124768Skarels if (so->so_rcv.sb_sel) { 87224768Skarels selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL); 87324768Skarels so->so_rcv.sb_sel = 0; 87424768Skarels so->so_rcv.sb_flags &= ~SB_COLL; 87524768Skarels } 8765423Swnj } 877