1*10599Ssam /* uipc_socket.c 4.71 83/01/22 */ 24786Swnj 34786Swnj #include "../h/param.h" 44829Swnj #include "../h/systm.h" 54786Swnj #include "../h/dir.h" 64786Swnj #include "../h/user.h" 74829Swnj #include "../h/proc.h" 84829Swnj #include "../h/file.h" 94786Swnj #include "../h/inode.h" 104829Swnj #include "../h/buf.h" 114786Swnj #include "../h/mbuf.h" 124829Swnj #include "../h/protosw.h" 134829Swnj #include "../h/socket.h" 144829Swnj #include "../h/socketvar.h" 154916Swnj #include "../h/stat.h" 165281Sroot #include "../h/ioctl.h" 178391Swnj #include "../h/uio.h" 186355Ssam #include "../net/route.h" 194786Swnj 204786Swnj /* 218300Sroot * Socket operation routines. 228300Sroot * These routines are called by the routines in 238300Sroot * sys_socket.c or from a system process, and 248300Sroot * implement the semantics of socket operations by 258300Sroot * switching out to the protocol specific routines. 264786Swnj */ 274786Swnj 288594Sroot /*ARGSUSED*/ 2910267Ssam socreate(dom, aso, type, proto) 304786Swnj struct socket **aso; 318300Sroot int type, proto; 324786Swnj { 334786Swnj register struct protosw *prp; 344786Swnj register struct socket *so; 354786Swnj struct mbuf *m; 369168Ssam int error; 374786Swnj 384890Swnj if (proto) 399168Ssam prp = pffindproto(dom, proto); 404890Swnj else 419168Ssam prp = pffindtype(dom, type); 424890Swnj if (prp == 0) 434890Swnj return (EPROTONOSUPPORT); 448300Sroot if (prp->pr_type != type) 458300Sroot return (EPROTOTYPE); 469635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 474786Swnj if (m == 0) 484786Swnj return (ENOBUFS); 494786Swnj so = mtod(m, struct socket *); 5010267Ssam so->so_options = SO_LINGER; 516214Swnj so->so_state = 0; 529168Ssam so->so_type = type; 536214Swnj if (u.u_uid == 0) 546214Swnj so->so_state = SS_PRIV; 554786Swnj so->so_proto = prp; 568300Sroot error = (*prp->pr_usrreq)(so, PRU_ATTACH, 5710267Ssam (struct mbuf *)0, (struct mbuf *)0); 584979Swnj if (error) { 597507Sroot so->so_state |= SS_NOFDREF; 607180Swnj sofree(so); 614890Swnj return (error); 624786Swnj } 634786Swnj *aso = so; 644786Swnj return (0); 654786Swnj } 664786Swnj 6710267Ssam sobind(so, nam) 688300Sroot struct socket *so; 698300Sroot struct mbuf *nam; 708300Sroot { 718300Sroot int s = splnet(); 728300Sroot int error; 738300Sroot 748300Sroot error = 7510267Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, (struct mbuf *)0, nam); 768300Sroot splx(s); 778300Sroot return (error); 788300Sroot } 798300Sroot 808300Sroot solisten(so, backlog) 818300Sroot struct socket *so; 828300Sroot int backlog; 838300Sroot { 848300Sroot int s = splnet(); 858300Sroot int error; 868300Sroot 878300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 8810267Ssam (struct mbuf *)0, (struct mbuf *)0); 898300Sroot if (error) { 908300Sroot splx(s); 918300Sroot return (error); 928300Sroot } 938300Sroot if (so->so_q == 0) { 948300Sroot so->so_q = so; 958300Sroot so->so_q0 = so; 968300Sroot so->so_options |= SO_ACCEPTCONN; 978300Sroot } 988300Sroot if (backlog < 0) 998300Sroot backlog = 0; 10010137Ssam #define SOMAXCONN 5 10110137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 1028300Sroot so->so_options |= SO_NEWFDONCONN; 1038300Sroot return (0); 1048300Sroot } 1058300Sroot 1064916Swnj sofree(so) 1074916Swnj struct socket *so; 1084916Swnj { 1094916Swnj 1107507Sroot if (so->so_head) { 1117507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1127507Sroot panic("sofree dq"); 1137507Sroot so->so_head = 0; 1147507Sroot } 1157507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1164950Swnj return; 1174950Swnj sbrelease(&so->so_snd); 1184950Swnj sbrelease(&so->so_rcv); 1194971Swnj (void) m_free(dtom(so)); 1204916Swnj } 1214916Swnj 1224786Swnj /* 1234890Swnj * Close a socket on last file table reference removal. 1244890Swnj * Initiate disconnect if connected. 1254890Swnj * Free socket when disconnect complete. 1264829Swnj */ 1275580Sroot soclose(so, exiting) 1284829Swnj register struct socket *so; 1295580Sroot int exiting; 1304829Swnj { 1314890Swnj int s = splnet(); /* conservative */ 1328713Sroot int error; 1334829Swnj 1347507Sroot if (so->so_options & SO_ACCEPTCONN) { 1357507Sroot while (so->so_q0 != so) 13610399Ssam (void) soabort(so->so_q0); 1377507Sroot while (so->so_q != so) 13810399Ssam (void) soabort(so->so_q); 1397507Sroot } 1404890Swnj if (so->so_pcb == 0) 1414890Swnj goto discard; 1426259Sroot if (exiting) 1436259Sroot so->so_options |= SO_KEEPALIVE; 1444890Swnj if (so->so_state & SS_ISCONNECTED) { 1454890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1468725Sroot error = sodisconnect(so, (struct mbuf *)0); 1478713Sroot if (error) { 1485580Sroot if (exiting) 1495580Sroot goto drop; 1504890Swnj splx(s); 1518713Sroot return (error); 1524890Swnj } 1534890Swnj } 15410267Ssam if (so->so_options & SO_LINGER) { 1555281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 1566214Swnj (so->so_state & SS_NBIO) && 1578713Sroot exiting == 0) 1588713Sroot return (EINPROGRESS); 1595580Sroot /* should use tsleep here, for at most linger */ 1605281Sroot while (so->so_state & SS_ISCONNECTED) 1615281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1624890Swnj } 1634890Swnj } 1645580Sroot drop: 1656880Ssam if (so->so_pcb) { 1668713Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16710267Ssam (struct mbuf *)0, (struct mbuf *)0); 1688713Sroot if (exiting == 0 && error) { 1696880Ssam splx(s); 1708713Sroot return (error); 1716880Ssam } 1726880Ssam } 1734890Swnj discard: 17410399Ssam if (so->so_state & SS_NOFDREF) 17510399Ssam panic("soclose: NOFDREF"); 1767507Sroot so->so_state |= SS_NOFDREF; 1774950Swnj sofree(so); 1784890Swnj splx(s); 1798713Sroot return (0); 1804829Swnj } 1814829Swnj 18210399Ssam /* 18310399Ssam * Must be called at splnet... 18410399Ssam */ 18510399Ssam soabort(so) 18610399Ssam struct socket *so; 18710399Ssam { 18810399Ssam int error; 18910399Ssam 19010399Ssam error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19110399Ssam (struct mbuf *)0, (struct mbuf *)0); 19210399Ssam return (error); 19310399Ssam } 19410399Ssam 1954916Swnj /*ARGSUSED*/ 1969026Sroot sostat(so, ub) 1974829Swnj struct socket *so; 1989026Sroot struct stat *ub; 1994829Swnj { 2009026Sroot struct stat sb; 2014829Swnj 2029026Sroot bzero((caddr_t)&sb, sizeof (sb)); /* XXX */ 2039168Ssam (void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */ 2045303Sroot return (0); /* XXX */ 2054829Swnj } 2064829Swnj 20710267Ssam soaccept(so, nam) 2084927Swnj struct socket *so; 2098300Sroot struct mbuf *nam; 2104927Swnj { 2114927Swnj int s = splnet(); 2124927Swnj int error; 2134927Swnj 21410399Ssam if ((so->so_state & SS_NOFDREF) == 0) 21510399Ssam panic("soaccept: !NOFDREF"); 21610267Ssam so->so_state &= ~SS_NOFDREF; 2178300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 21810267Ssam (struct mbuf *)0, nam); 2194927Swnj splx(s); 2204927Swnj return (error); 2214927Swnj } 2224927Swnj 22310267Ssam soconnect(so, nam) 2244786Swnj struct socket *so; 2258300Sroot struct mbuf *nam; 2264786Swnj { 2274890Swnj int s = splnet(); 2284890Swnj int error; 2294786Swnj 2304890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2314890Swnj error = EISCONN; 2324890Swnj goto bad; 2334890Swnj } 2348300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23510267Ssam (struct mbuf *)0, nam); 2364890Swnj bad: 2374890Swnj splx(s); 2384890Swnj return (error); 2394786Swnj } 2404786Swnj 2418300Sroot sodisconnect(so, nam) 2424786Swnj struct socket *so; 2438300Sroot struct mbuf *nam; 2444786Swnj { 2454890Swnj int s = splnet(); 2464890Swnj int error; 2474786Swnj 2484890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2494890Swnj error = ENOTCONN; 2504890Swnj goto bad; 2514890Swnj } 2524890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2534890Swnj error = EALREADY; 2544890Swnj goto bad; 2554890Swnj } 2568300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25710267Ssam (struct mbuf *)0, nam); 2584890Swnj bad: 2594890Swnj splx(s); 2604890Swnj return (error); 2614786Swnj } 2624786Swnj 2634786Swnj /* 2644890Swnj * Send on a socket. 2654890Swnj * If send must go all at once and message is larger than 2664890Swnj * send buffering, then hard error. 2674890Swnj * Lock against other senders. 2684890Swnj * If must go all at once and not enough room now, then 2694890Swnj * inform user that this would block and do nothing. 2704786Swnj */ 2718319Sroot sosend(so, nam, uio, flags) 2724786Swnj register struct socket *so; 2738300Sroot struct mbuf *nam; 2747827Sroot struct uio *uio; 2758319Sroot int flags; 2764786Swnj { 2774890Swnj struct mbuf *top = 0; 2784890Swnj register struct mbuf *m, **mp = ⊤ 2798713Sroot register int len; 28010267Ssam int error = 0, space, s, dontroute; 2814786Swnj 2827827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2834890Swnj return (EMSGSIZE); 28410267Ssam dontroute = (flags & SOF_DONTROUTE) && 28510267Ssam (so->so_options & SO_DONTROUTE) == 0 && 28610267Ssam (so->so_proto->pr_flags & PR_ATOMIC); 2876419Sroot restart: 2884890Swnj sblock(&so->so_snd); 2894890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2904890Swnj 2918041Sroot u.u_ru.ru_msgsnd++; 2926419Sroot again: 2934890Swnj s = splnet(); 2946419Sroot if (so->so_state & SS_CANTSENDMORE) { 2956419Sroot psignal(u.u_procp, SIGPIPE); 2966419Sroot snderr(EPIPE); 2976419Sroot } 2985168Swnj if (so->so_error) { 2995168Swnj error = so->so_error; 3006419Sroot so->so_error = 0; /* ??? */ 3015168Swnj splx(s); 3025168Swnj goto release; 3035168Swnj } 3044890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 3054890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 3064890Swnj snderr(ENOTCONN); 3078300Sroot if (nam == 0) 3084890Swnj snderr(EDESTADDRREQ); 3094890Swnj } 3104890Swnj if (top) { 31110267Ssam if (dontroute) 31210267Ssam so->so_options |= SO_DONTROUTE; 3138319Sroot error = (*so->so_proto->pr_usrreq)(so, 3148319Sroot (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND, 31510267Ssam top, (caddr_t)nam); 31610267Ssam if (dontroute) 31710267Ssam so->so_options &= ~SO_DONTROUTE; 3186419Sroot top = 0; 3194890Swnj if (error) { 3204890Swnj splx(s); 3214786Swnj goto release; 3224786Swnj } 3234890Swnj mp = ⊤ 3244786Swnj } 3257827Sroot if (uio->uio_resid == 0) { 3264979Swnj splx(s); 3274979Swnj goto release; 3284979Swnj } 3298319Sroot if (flags & SOF_OOB) 3308319Sroot space = 1024; 3318319Sroot else { 3328319Sroot space = sbspace(&so->so_snd); 3338319Sroot if (space <= 0 || 3348319Sroot sosendallatonce(so) && space < uio->uio_resid) { 3358319Sroot if (so->so_state & SS_NBIO) 3368319Sroot snderr(EWOULDBLOCK); 3378319Sroot sbunlock(&so->so_snd); 3388319Sroot sbwait(&so->so_snd); 3398319Sroot splx(s); 3408319Sroot goto restart; 3418319Sroot } 3424786Swnj } 3434890Swnj splx(s); 3447827Sroot while (uio->uio_resid > 0 && space > 0) { 3457827Sroot register struct iovec *iov = uio->uio_iov; 3467827Sroot 3477827Sroot if (iov->iov_len == 0) { 3487827Sroot uio->uio_iov++; 3497827Sroot uio->uio_iovcnt--; 3507827Sroot if (uio->uio_iovcnt < 0) 3517827Sroot panic("sosend"); 3527827Sroot continue; 3537827Sroot } 3549635Ssam MGET(m, M_WAIT, MT_DATA); 3554890Swnj if (m == NULL) { 3566419Sroot error = ENOBUFS; /* SIGPIPE? */ 3574890Swnj goto release; 3584786Swnj } 3597827Sroot if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 3604890Swnj register struct mbuf *p; 3615095Swnj MCLGET(p, 1); 3624890Swnj if (p == 0) 3634890Swnj goto nopages; 3644890Swnj m->m_off = (int)p - (int)m; 3655095Swnj len = CLBYTES; 3664890Swnj } else { 3674786Swnj nopages: 3687827Sroot len = MIN(MLEN, iov->iov_len); 3694786Swnj } 3708771Sroot (void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 3714890Swnj m->m_len = len; 3724890Swnj *mp = m; 3734890Swnj mp = &m->m_next; 3748319Sroot if (flags & SOF_OOB) 3758319Sroot space -= len; 3768319Sroot else 3778319Sroot space = sbspace(&so->so_snd); 3784786Swnj } 3794890Swnj goto again; 3804890Swnj 3814786Swnj release: 3824890Swnj sbunlock(&so->so_snd); 3836419Sroot if (top) 3846419Sroot m_freem(top); 3854786Swnj return (error); 3864786Swnj } 3874786Swnj 3888319Sroot soreceive(so, aname, uio, flags) 3894786Swnj register struct socket *so; 3908300Sroot struct mbuf **aname; 3917747Sroot struct uio *uio; 3928319Sroot int flags; 3934786Swnj { 3944786Swnj register struct mbuf *m, *n; 3958713Sroot int len; 3968319Sroot int eor, s, error = 0, moff, tomark; 3974786Swnj 3988319Sroot if (flags & SOF_OOB) { 3999635Ssam m = m_get(M_WAIT, MT_DATA); 40010137Ssam if (m == NULL) 40110137Ssam return (ENOBUFS); 4028594Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, 40310267Ssam m, (struct mbuf *)0); 4048594Sroot if (error) 40510137Ssam goto bad; 4068319Sroot do { 40710137Ssam len = uio->uio_resid; 4088319Sroot if (len > m->m_len) 4098319Sroot len = m->m_len; 4108594Sroot error = 4118793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4128319Sroot m = m_free(m); 4138594Sroot } while (uio->uio_resid && error == 0 && m); 41410137Ssam bad: 4158319Sroot if (m) 4168771Sroot m_freem(m); 4178594Sroot return (error); 4188319Sroot } 4198319Sroot 4204890Swnj restart: 4214890Swnj sblock(&so->so_rcv); 4228835Sroot s = splnet(); 4234890Swnj 4244890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4254786Swnj if (so->so_rcv.sb_cc == 0) { 4265168Swnj if (so->so_error) { 4275168Swnj error = so->so_error; 4285168Swnj so->so_error = 0; 4295168Swnj splx(s); 4305168Swnj goto release; 4315168Swnj } 4324890Swnj if (so->so_state & SS_CANTRCVMORE) { 4334890Swnj splx(s); 4344890Swnj goto release; 4354890Swnj } 4365015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4375015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4385015Sroot rcverr(ENOTCONN); 4396214Swnj if (so->so_state & SS_NBIO) 4405168Swnj rcverr(EWOULDBLOCK); 4414890Swnj sbunlock(&so->so_rcv); 4424971Swnj sbwait(&so->so_rcv); 4435012Swnj splx(s); 4444890Swnj goto restart; 4454786Swnj } 4468041Sroot u.u_ru.ru_msgrcv++; 4474829Swnj m = so->so_rcv.sb_mb; 4484786Swnj if (m == 0) 4494786Swnj panic("receive"); 4505039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 4518319Sroot if ((flags & SOF_PREVIEW) == 0) { 4528319Sroot so->so_rcv.sb_cc -= m->m_len; 4538319Sroot so->so_rcv.sb_mbcnt -= MSIZE; 4548319Sroot } 4558300Sroot if (aname) { 45610137Ssam if (flags & SOF_PREVIEW) { 4578319Sroot *aname = m_copy(m, 0, m->m_len); 45810137Ssam if (*aname == NULL) 45910137Ssam panic("receive 2"); 46010137Ssam } else 4618319Sroot *aname = m; 4628300Sroot m = m->m_next; 4638300Sroot (*aname)->m_next = 0; 4648300Sroot } else 4658319Sroot if (flags & SOF_PREVIEW) 4668319Sroot m = m->m_next; 4678319Sroot else 4688319Sroot m = m_free(m); 4694890Swnj if (m == 0) 47010137Ssam panic("receive 3"); 4718548Sroot if ((flags & SOF_PREVIEW) == 0) 4728548Sroot so->so_rcv.sb_mb = m; 4734890Swnj } 4744786Swnj eor = 0; 4758319Sroot moff = 0; 4768319Sroot tomark = so->so_oobmark; 4774786Swnj do { 4787827Sroot if (uio->uio_resid <= 0) 4797747Sroot break; 4807827Sroot len = uio->uio_resid; 4817747Sroot so->so_state &= ~SS_RCVATMARK; 4828319Sroot if (tomark && len > tomark) 4838319Sroot len = tomark; 4848548Sroot if (moff+len > m->m_len - moff) 4858319Sroot len = m->m_len - moff; 4864786Swnj splx(s); 4878594Sroot error = 4888793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 4894786Swnj s = splnet(); 4904786Swnj if (len == m->m_len) { 4916091Sroot eor = (int)m->m_act; 4928319Sroot if (flags & SOF_PREVIEW) 4938319Sroot m = m->m_next; 4948319Sroot else { 4958319Sroot sbfree(&so->so_rcv, m); 4968319Sroot MFREE(m, n); 4978319Sroot m = n; 4988548Sroot so->so_rcv.sb_mb = m; 4998319Sroot } 5008319Sroot moff = 0; 5014786Swnj } else { 5028319Sroot if (flags & SOF_PREVIEW) 5038319Sroot moff += len; 5048319Sroot else { 5058319Sroot m->m_off += len; 5068319Sroot m->m_len -= len; 5078319Sroot so->so_rcv.sb_cc -= len; 5088319Sroot } 5094786Swnj } 5108319Sroot if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) { 5117747Sroot so->so_oobmark -= len; 5127747Sroot if (so->so_oobmark == 0) { 5137747Sroot so->so_state |= SS_RCVATMARK; 5147747Sroot break; 5157747Sroot } 5167747Sroot } 5178319Sroot if (tomark) { 5188319Sroot tomark -= len; 5198319Sroot if (tomark == 0) 5208319Sroot break; 5218319Sroot } 5228594Sroot } while (m && error == 0 && !eor); 5238319Sroot if (flags & SOF_PREVIEW) 5248319Sroot goto release; 5254786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 5264786Swnj do { 5274786Swnj if (m == 0) 52810137Ssam panic("receive 4"); 5294890Swnj sbfree(&so->so_rcv, m); 5304786Swnj eor = (int)m->m_act; 5314786Swnj so->so_rcv.sb_mb = m->m_next; 5324786Swnj MFREE(m, n); 5334890Swnj m = n; 5344786Swnj } while (eor == 0); 5354890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 5368300Sroot (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 53710267Ssam (struct mbuf *)0, (struct mbuf *)0); 5384890Swnj release: 5394916Swnj sbunlock(&so->so_rcv); 5404890Swnj splx(s); 5414916Swnj return (error); 5424786Swnj } 5434786Swnj 54410267Ssam soshutdown(so, how) 54510267Ssam struct socket *so; 54610267Ssam int how; 54710267Ssam { 54810267Ssam 54910267Ssam how++; 55010267Ssam if (how & FREAD) { 55110267Ssam int s = splimp(); 55210267Ssam socantrcvmore(so); 55310267Ssam sbflush(&so->so_rcv); 55410267Ssam splx(s); 55510267Ssam } 55610267Ssam if (how & FWRITE) 55710267Ssam return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, 55810267Ssam (struct mbuf *)0, (struct mbuf *)0)); 55910267Ssam return (0); 56010267Ssam } 56110267Ssam 56210267Ssam sosetopt(so, level, optname, m) 56310267Ssam struct socket *so; 56410267Ssam int level, optname; 56510267Ssam struct mbuf *m; 56610267Ssam { 56710267Ssam 56810267Ssam if (level != SOL_SOCKET) 56910267Ssam return (EINVAL); /* XXX */ 57010267Ssam switch (optname) { 57110267Ssam 57210267Ssam case SO_DEBUG: 57310269Ssam case SO_KEEPALIVE: 574*10599Ssam case SO_DONTROUTE: 575*10599Ssam case SO_USELOOPBACK: 576*10599Ssam case SO_REUSEADDR: 577*10599Ssam so->so_options |= optname; 57810269Ssam break; 57910269Ssam 58010267Ssam case SO_LINGER: 58110269Ssam if (m == NULL || m->m_len != sizeof (int)) 58210269Ssam return (EINVAL); 58310267Ssam so->so_options |= SO_LINGER; 58410269Ssam so->so_linger = *mtod(m, int *); 58510267Ssam break; 58610267Ssam 58710267Ssam case SO_DONTLINGER: 58810267Ssam so->so_options &= ~SO_LINGER; 58910267Ssam so->so_linger = 0; 59010267Ssam break; 59110267Ssam 59210267Ssam default: 59310267Ssam return (EINVAL); 59410267Ssam } 59510267Ssam return (0); 59610267Ssam } 59710267Ssam 59810267Ssam sogetopt(so, level, optname, m) 59910267Ssam struct socket *so; 60010267Ssam int level, optname; 60110267Ssam struct mbuf *m; 60210267Ssam { 60310267Ssam 60410267Ssam if (level != SOL_SOCKET) 60510267Ssam return (EINVAL); /* XXX */ 60610267Ssam switch (optname) { 60710267Ssam 60810267Ssam case SO_USELOOPBACK: 60910267Ssam case SO_DONTROUTE: 61010267Ssam case SO_DEBUG: 61110267Ssam case SO_KEEPALIVE: 61210267Ssam case SO_LINGER: 613*10599Ssam case SO_REUSEADDR: 61410267Ssam if ((so->so_options & optname) == 0) 61510267Ssam return (ENOPROTOOPT); 61610269Ssam if (optname == SO_LINGER && m != NULL) { 61710267Ssam *mtod(m, int *) = so->so_linger; 61810267Ssam m->m_len = sizeof (so->so_linger); 61910267Ssam } 62010267Ssam break; 62110267Ssam 62210267Ssam default: 62310267Ssam return (EINVAL); 62410267Ssam } 62510267Ssam return (0); 62610267Ssam } 62710267Ssam 6285423Swnj sohasoutofband(so) 6295423Swnj struct socket *so; 6305423Swnj { 6315423Swnj 6325423Swnj if (so->so_pgrp == 0) 6335423Swnj return; 6345423Swnj if (so->so_pgrp > 0) 6355423Swnj gsignal(so->so_pgrp, SIGURG); 6365429Swnj else { 6375429Swnj struct proc *p = pfind(-so->so_pgrp); 6385429Swnj 6395429Swnj if (p) 6405429Swnj psignal(p, SIGURG); 6415429Swnj } 6425423Swnj } 6435423Swnj 6444916Swnj /*ARGSUSED*/ 6457627Ssam soioctl(so, cmd, data) 6464829Swnj register struct socket *so; 6474829Swnj int cmd; 6487627Ssam register char *data; 6494786Swnj { 6504786Swnj 6515358Sroot switch (cmd) { 6524829Swnj 6537627Ssam case FIONBIO: 6547627Ssam if (*(int *)data) 6556214Swnj so->so_state |= SS_NBIO; 6565388Sroot else 6576214Swnj so->so_state &= ~SS_NBIO; 6588594Sroot break; 6595388Sroot 6607627Ssam case FIOASYNC: 6617627Ssam if (*(int *)data) 6626214Swnj so->so_state |= SS_ASYNC; 6635388Sroot else 6646214Swnj so->so_state &= ~SS_ASYNC; 6658594Sroot break; 6665388Sroot 6677627Ssam case SIOCSPGRP: 6687627Ssam so->so_pgrp = *(int *)data; 6698594Sroot break; 6705423Swnj 6717627Ssam case SIOCGPGRP: 6727627Ssam *(int *)data = so->so_pgrp; 6738594Sroot break; 6747627Ssam 6757627Ssam case SIOCATMARK: 6767627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 6778594Sroot break; 6786355Ssam 6796355Ssam /* routing table update calls */ 6806355Ssam case SIOCADDRT: 6816355Ssam case SIOCDELRT: 6826355Ssam if (!suser()) 68310137Ssam return (u.u_error); 6848560Sroot return (rtrequest(cmd, (struct rtentry *)data)); 6856355Ssam 6865445Swnj /* type/protocol specific ioctls */ 6878594Sroot default: 68810137Ssam return (ENOTTY); /* XXX */ 6895423Swnj } 6908594Sroot return (0); 6914786Swnj } 692