1*10269Ssam /* uipc_socket.c 4.69 83/01/13 */ 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) 1368713Sroot (void) soclose(so->so_q0, 1); 1377507Sroot while (so->so_q != so) 1388713Sroot (void) soclose(so->so_q, 1); 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: 1747507Sroot so->so_state |= SS_NOFDREF; 1754950Swnj sofree(so); 1764890Swnj splx(s); 1778713Sroot return (0); 1784829Swnj } 1794829Swnj 1804916Swnj /*ARGSUSED*/ 1819026Sroot sostat(so, ub) 1824829Swnj struct socket *so; 1839026Sroot struct stat *ub; 1844829Swnj { 1859026Sroot struct stat sb; 1864829Swnj 1879026Sroot bzero((caddr_t)&sb, sizeof (sb)); /* XXX */ 1889168Ssam (void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */ 1895303Sroot return (0); /* XXX */ 1904829Swnj } 1914829Swnj 19210267Ssam soaccept(so, nam) 1934927Swnj struct socket *so; 1948300Sroot struct mbuf *nam; 1954927Swnj { 1964927Swnj int s = splnet(); 1974927Swnj int error; 1984927Swnj 19910267Ssam so->so_state &= ~SS_NOFDREF; 2008300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 20110267Ssam (struct mbuf *)0, nam); 2024927Swnj splx(s); 2034927Swnj return (error); 2044927Swnj } 2054927Swnj 20610267Ssam soconnect(so, nam) 2074786Swnj struct socket *so; 2088300Sroot struct mbuf *nam; 2094786Swnj { 2104890Swnj int s = splnet(); 2114890Swnj int error; 2124786Swnj 2134890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2144890Swnj error = EISCONN; 2154890Swnj goto bad; 2164890Swnj } 2178300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 21810267Ssam (struct mbuf *)0, nam); 2194890Swnj bad: 2204890Swnj splx(s); 2214890Swnj return (error); 2224786Swnj } 2234786Swnj 2248300Sroot sodisconnect(so, nam) 2254786Swnj struct socket *so; 2268300Sroot struct mbuf *nam; 2274786Swnj { 2284890Swnj int s = splnet(); 2294890Swnj int error; 2304786Swnj 2314890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2324890Swnj error = ENOTCONN; 2334890Swnj goto bad; 2344890Swnj } 2354890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2364890Swnj error = EALREADY; 2374890Swnj goto bad; 2384890Swnj } 2398300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 24010267Ssam (struct mbuf *)0, nam); 2414890Swnj bad: 2424890Swnj splx(s); 2434890Swnj return (error); 2444786Swnj } 2454786Swnj 2464786Swnj /* 2474890Swnj * Send on a socket. 2484890Swnj * If send must go all at once and message is larger than 2494890Swnj * send buffering, then hard error. 2504890Swnj * Lock against other senders. 2514890Swnj * If must go all at once and not enough room now, then 2524890Swnj * inform user that this would block and do nothing. 2534786Swnj */ 2548319Sroot sosend(so, nam, uio, flags) 2554786Swnj register struct socket *so; 2568300Sroot struct mbuf *nam; 2577827Sroot struct uio *uio; 2588319Sroot int flags; 2594786Swnj { 2604890Swnj struct mbuf *top = 0; 2614890Swnj register struct mbuf *m, **mp = ⊤ 2628713Sroot register int len; 26310267Ssam int error = 0, space, s, dontroute; 2644786Swnj 2657827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2664890Swnj return (EMSGSIZE); 26710267Ssam dontroute = (flags & SOF_DONTROUTE) && 26810267Ssam (so->so_options & SO_DONTROUTE) == 0 && 26910267Ssam (so->so_proto->pr_flags & PR_ATOMIC); 2706419Sroot restart: 2714890Swnj sblock(&so->so_snd); 2724890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2734890Swnj 2748041Sroot u.u_ru.ru_msgsnd++; 2756419Sroot again: 2764890Swnj s = splnet(); 2776419Sroot if (so->so_state & SS_CANTSENDMORE) { 2786419Sroot psignal(u.u_procp, SIGPIPE); 2796419Sroot snderr(EPIPE); 2806419Sroot } 2815168Swnj if (so->so_error) { 2825168Swnj error = so->so_error; 2836419Sroot so->so_error = 0; /* ??? */ 2845168Swnj splx(s); 2855168Swnj goto release; 2865168Swnj } 2874890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2884890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2894890Swnj snderr(ENOTCONN); 2908300Sroot if (nam == 0) 2914890Swnj snderr(EDESTADDRREQ); 2924890Swnj } 2934890Swnj if (top) { 29410267Ssam if (dontroute) 29510267Ssam so->so_options |= SO_DONTROUTE; 2968319Sroot error = (*so->so_proto->pr_usrreq)(so, 2978319Sroot (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND, 29810267Ssam top, (caddr_t)nam); 29910267Ssam if (dontroute) 30010267Ssam so->so_options &= ~SO_DONTROUTE; 3016419Sroot top = 0; 3024890Swnj if (error) { 3034890Swnj splx(s); 3044786Swnj goto release; 3054786Swnj } 3064890Swnj mp = ⊤ 3074786Swnj } 3087827Sroot if (uio->uio_resid == 0) { 3094979Swnj splx(s); 3104979Swnj goto release; 3114979Swnj } 3128319Sroot if (flags & SOF_OOB) 3138319Sroot space = 1024; 3148319Sroot else { 3158319Sroot space = sbspace(&so->so_snd); 3168319Sroot if (space <= 0 || 3178319Sroot sosendallatonce(so) && space < uio->uio_resid) { 3188319Sroot if (so->so_state & SS_NBIO) 3198319Sroot snderr(EWOULDBLOCK); 3208319Sroot sbunlock(&so->so_snd); 3218319Sroot sbwait(&so->so_snd); 3228319Sroot splx(s); 3238319Sroot goto restart; 3248319Sroot } 3254786Swnj } 3264890Swnj splx(s); 3277827Sroot while (uio->uio_resid > 0 && space > 0) { 3287827Sroot register struct iovec *iov = uio->uio_iov; 3297827Sroot 3307827Sroot if (iov->iov_len == 0) { 3317827Sroot uio->uio_iov++; 3327827Sroot uio->uio_iovcnt--; 3337827Sroot if (uio->uio_iovcnt < 0) 3347827Sroot panic("sosend"); 3357827Sroot continue; 3367827Sroot } 3379635Ssam MGET(m, M_WAIT, MT_DATA); 3384890Swnj if (m == NULL) { 3396419Sroot error = ENOBUFS; /* SIGPIPE? */ 3404890Swnj goto release; 3414786Swnj } 3427827Sroot if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 3434890Swnj register struct mbuf *p; 3445095Swnj MCLGET(p, 1); 3454890Swnj if (p == 0) 3464890Swnj goto nopages; 3474890Swnj m->m_off = (int)p - (int)m; 3485095Swnj len = CLBYTES; 3494890Swnj } else { 3504786Swnj nopages: 3517827Sroot len = MIN(MLEN, iov->iov_len); 3524786Swnj } 3538771Sroot (void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 3544890Swnj m->m_len = len; 3554890Swnj *mp = m; 3564890Swnj mp = &m->m_next; 3578319Sroot if (flags & SOF_OOB) 3588319Sroot space -= len; 3598319Sroot else 3608319Sroot space = sbspace(&so->so_snd); 3614786Swnj } 3624890Swnj goto again; 3634890Swnj 3644786Swnj release: 3654890Swnj sbunlock(&so->so_snd); 3666419Sroot if (top) 3676419Sroot m_freem(top); 3684786Swnj return (error); 3694786Swnj } 3704786Swnj 3718319Sroot soreceive(so, aname, uio, flags) 3724786Swnj register struct socket *so; 3738300Sroot struct mbuf **aname; 3747747Sroot struct uio *uio; 3758319Sroot int flags; 3764786Swnj { 3774786Swnj register struct mbuf *m, *n; 3788713Sroot int len; 3798319Sroot int eor, s, error = 0, moff, tomark; 3804786Swnj 3818319Sroot if (flags & SOF_OOB) { 3829635Ssam m = m_get(M_WAIT, MT_DATA); 38310137Ssam if (m == NULL) 38410137Ssam return (ENOBUFS); 3858594Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, 38610267Ssam m, (struct mbuf *)0); 3878594Sroot if (error) 38810137Ssam goto bad; 3898319Sroot do { 39010137Ssam len = uio->uio_resid; 3918319Sroot if (len > m->m_len) 3928319Sroot len = m->m_len; 3938594Sroot error = 3948793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 3958319Sroot m = m_free(m); 3968594Sroot } while (uio->uio_resid && error == 0 && m); 39710137Ssam bad: 3988319Sroot if (m) 3998771Sroot m_freem(m); 4008594Sroot return (error); 4018319Sroot } 4028319Sroot 4034890Swnj restart: 4044890Swnj sblock(&so->so_rcv); 4058835Sroot s = splnet(); 4064890Swnj 4074890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4084786Swnj if (so->so_rcv.sb_cc == 0) { 4095168Swnj if (so->so_error) { 4105168Swnj error = so->so_error; 4115168Swnj so->so_error = 0; 4125168Swnj splx(s); 4135168Swnj goto release; 4145168Swnj } 4154890Swnj if (so->so_state & SS_CANTRCVMORE) { 4164890Swnj splx(s); 4174890Swnj goto release; 4184890Swnj } 4195015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4205015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4215015Sroot rcverr(ENOTCONN); 4226214Swnj if (so->so_state & SS_NBIO) 4235168Swnj rcverr(EWOULDBLOCK); 4244890Swnj sbunlock(&so->so_rcv); 4254971Swnj sbwait(&so->so_rcv); 4265012Swnj splx(s); 4274890Swnj goto restart; 4284786Swnj } 4298041Sroot u.u_ru.ru_msgrcv++; 4304829Swnj m = so->so_rcv.sb_mb; 4314786Swnj if (m == 0) 4324786Swnj panic("receive"); 4335039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 4348319Sroot if ((flags & SOF_PREVIEW) == 0) { 4358319Sroot so->so_rcv.sb_cc -= m->m_len; 4368319Sroot so->so_rcv.sb_mbcnt -= MSIZE; 4378319Sroot } 4388300Sroot if (aname) { 43910137Ssam if (flags & SOF_PREVIEW) { 4408319Sroot *aname = m_copy(m, 0, m->m_len); 44110137Ssam if (*aname == NULL) 44210137Ssam panic("receive 2"); 44310137Ssam } else 4448319Sroot *aname = m; 4458300Sroot m = m->m_next; 4468300Sroot (*aname)->m_next = 0; 4478300Sroot } else 4488319Sroot if (flags & SOF_PREVIEW) 4498319Sroot m = m->m_next; 4508319Sroot else 4518319Sroot m = m_free(m); 4524890Swnj if (m == 0) 45310137Ssam panic("receive 3"); 4548548Sroot if ((flags & SOF_PREVIEW) == 0) 4558548Sroot so->so_rcv.sb_mb = m; 4564890Swnj } 4574786Swnj eor = 0; 4588319Sroot moff = 0; 4598319Sroot tomark = so->so_oobmark; 4604786Swnj do { 4617827Sroot if (uio->uio_resid <= 0) 4627747Sroot break; 4637827Sroot len = uio->uio_resid; 4647747Sroot so->so_state &= ~SS_RCVATMARK; 4658319Sroot if (tomark && len > tomark) 4668319Sroot len = tomark; 4678548Sroot if (moff+len > m->m_len - moff) 4688319Sroot len = m->m_len - moff; 4694786Swnj splx(s); 4708594Sroot error = 4718793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 4724786Swnj s = splnet(); 4734786Swnj if (len == m->m_len) { 4746091Sroot eor = (int)m->m_act; 4758319Sroot if (flags & SOF_PREVIEW) 4768319Sroot m = m->m_next; 4778319Sroot else { 4788319Sroot sbfree(&so->so_rcv, m); 4798319Sroot MFREE(m, n); 4808319Sroot m = n; 4818548Sroot so->so_rcv.sb_mb = m; 4828319Sroot } 4838319Sroot moff = 0; 4844786Swnj } else { 4858319Sroot if (flags & SOF_PREVIEW) 4868319Sroot moff += len; 4878319Sroot else { 4888319Sroot m->m_off += len; 4898319Sroot m->m_len -= len; 4908319Sroot so->so_rcv.sb_cc -= len; 4918319Sroot } 4924786Swnj } 4938319Sroot if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) { 4947747Sroot so->so_oobmark -= len; 4957747Sroot if (so->so_oobmark == 0) { 4967747Sroot so->so_state |= SS_RCVATMARK; 4977747Sroot break; 4987747Sroot } 4997747Sroot } 5008319Sroot if (tomark) { 5018319Sroot tomark -= len; 5028319Sroot if (tomark == 0) 5038319Sroot break; 5048319Sroot } 5058594Sroot } while (m && error == 0 && !eor); 5068319Sroot if (flags & SOF_PREVIEW) 5078319Sroot goto release; 5084786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 5094786Swnj do { 5104786Swnj if (m == 0) 51110137Ssam panic("receive 4"); 5124890Swnj sbfree(&so->so_rcv, m); 5134786Swnj eor = (int)m->m_act; 5144786Swnj so->so_rcv.sb_mb = m->m_next; 5154786Swnj MFREE(m, n); 5164890Swnj m = n; 5174786Swnj } while (eor == 0); 5184890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 5198300Sroot (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 52010267Ssam (struct mbuf *)0, (struct mbuf *)0); 5214890Swnj release: 5224916Swnj sbunlock(&so->so_rcv); 5234890Swnj splx(s); 5244916Swnj return (error); 5254786Swnj } 5264786Swnj 52710267Ssam soshutdown(so, how) 52810267Ssam struct socket *so; 52910267Ssam int how; 53010267Ssam { 53110267Ssam 53210267Ssam how++; 53310267Ssam if (how & FREAD) { 53410267Ssam int s = splimp(); 53510267Ssam socantrcvmore(so); 53610267Ssam sbflush(&so->so_rcv); 53710267Ssam splx(s); 53810267Ssam } 53910267Ssam if (how & FWRITE) 54010267Ssam return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, 54110267Ssam (struct mbuf *)0, (struct mbuf *)0)); 54210267Ssam return (0); 54310267Ssam } 54410267Ssam 54510267Ssam sosetopt(so, level, optname, m) 54610267Ssam struct socket *so; 54710267Ssam int level, optname; 54810267Ssam struct mbuf *m; 54910267Ssam { 55010267Ssam 55110267Ssam if (level != SOL_SOCKET) 55210267Ssam return (EINVAL); /* XXX */ 55310267Ssam switch (optname) { 55410267Ssam 55510267Ssam case SO_DEBUG: 55610267Ssam so->so_options |= SO_DEBUG; 55710267Ssam break; 55810267Ssam 559*10269Ssam case SO_KEEPALIVE: 560*10269Ssam so->so_options |= SO_KEEPALIVE; 561*10269Ssam break; 562*10269Ssam 56310267Ssam case SO_LINGER: 564*10269Ssam if (m == NULL || m->m_len != sizeof (int)) 565*10269Ssam return (EINVAL); 56610267Ssam so->so_options |= SO_LINGER; 567*10269Ssam so->so_linger = *mtod(m, int *); 56810267Ssam break; 56910267Ssam 57010267Ssam case SO_DONTLINGER: 57110267Ssam so->so_options &= ~SO_LINGER; 57210267Ssam so->so_linger = 0; 57310267Ssam break; 57410267Ssam 57510267Ssam case SO_DONTROUTE: 57610267Ssam so->so_options |= SO_DONTROUTE; 57710267Ssam break; 57810267Ssam 57910267Ssam case SO_USELOOPBACK: 58010267Ssam so->so_options |= SO_USELOOPBACK; 58110267Ssam break; 58210267Ssam 58310267Ssam default: 58410267Ssam return (EINVAL); 58510267Ssam } 58610267Ssam return (0); 58710267Ssam } 58810267Ssam 58910267Ssam sogetopt(so, level, optname, m) 59010267Ssam struct socket *so; 59110267Ssam int level, optname; 59210267Ssam struct mbuf *m; 59310267Ssam { 59410267Ssam 59510267Ssam if (level != SOL_SOCKET) 59610267Ssam return (EINVAL); /* XXX */ 59710267Ssam switch (optname) { 59810267Ssam 59910267Ssam case SO_USELOOPBACK: 60010267Ssam case SO_DONTROUTE: 60110267Ssam case SO_DEBUG: 60210267Ssam case SO_KEEPALIVE: 60310267Ssam case SO_LINGER: 60410267Ssam if ((so->so_options & optname) == 0) 60510267Ssam return (ENOPROTOOPT); 606*10269Ssam if (optname == SO_LINGER && m != NULL) { 60710267Ssam *mtod(m, int *) = so->so_linger; 60810267Ssam m->m_len = sizeof (so->so_linger); 60910267Ssam } 61010267Ssam break; 61110267Ssam 61210267Ssam default: 61310267Ssam return (EINVAL); 61410267Ssam } 61510267Ssam return (0); 61610267Ssam } 61710267Ssam 6185423Swnj sohasoutofband(so) 6195423Swnj struct socket *so; 6205423Swnj { 6215423Swnj 6225423Swnj if (so->so_pgrp == 0) 6235423Swnj return; 6245423Swnj if (so->so_pgrp > 0) 6255423Swnj gsignal(so->so_pgrp, SIGURG); 6265429Swnj else { 6275429Swnj struct proc *p = pfind(-so->so_pgrp); 6285429Swnj 6295429Swnj if (p) 6305429Swnj psignal(p, SIGURG); 6315429Swnj } 6325423Swnj } 6335423Swnj 6344916Swnj /*ARGSUSED*/ 6357627Ssam soioctl(so, cmd, data) 6364829Swnj register struct socket *so; 6374829Swnj int cmd; 6387627Ssam register char *data; 6394786Swnj { 6404786Swnj 6415358Sroot switch (cmd) { 6424829Swnj 6437627Ssam case FIONBIO: 6447627Ssam if (*(int *)data) 6456214Swnj so->so_state |= SS_NBIO; 6465388Sroot else 6476214Swnj so->so_state &= ~SS_NBIO; 6488594Sroot break; 6495388Sroot 6507627Ssam case FIOASYNC: 6517627Ssam if (*(int *)data) 6526214Swnj so->so_state |= SS_ASYNC; 6535388Sroot else 6546214Swnj so->so_state &= ~SS_ASYNC; 6558594Sroot break; 6565388Sroot 6577627Ssam case SIOCSPGRP: 6587627Ssam so->so_pgrp = *(int *)data; 6598594Sroot break; 6605423Swnj 6617627Ssam case SIOCGPGRP: 6627627Ssam *(int *)data = so->so_pgrp; 6638594Sroot break; 6647627Ssam 6657627Ssam case SIOCATMARK: 6667627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 6678594Sroot break; 6686355Ssam 6696355Ssam /* routing table update calls */ 6706355Ssam case SIOCADDRT: 6716355Ssam case SIOCDELRT: 6726355Ssam if (!suser()) 67310137Ssam return (u.u_error); 6748560Sroot return (rtrequest(cmd, (struct rtentry *)data)); 6756355Ssam 6765445Swnj /* type/protocol specific ioctls */ 6778594Sroot default: 67810137Ssam return (ENOTTY); /* XXX */ 6795423Swnj } 6808594Sroot return (0); 6814786Swnj } 682