1*10267Ssam /* uipc_socket.c 4.68 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*/ 29*10267Ssam 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 *); 50*10267Ssam 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, 57*10267Ssam (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 67*10267Ssam sobind(so, nam) 688300Sroot struct socket *so; 698300Sroot struct mbuf *nam; 708300Sroot { 718300Sroot int s = splnet(); 728300Sroot int error; 738300Sroot 748300Sroot error = 75*10267Ssam (*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, 88*10267Ssam (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 } 154*10267Ssam 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, 167*10267Ssam (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 192*10267Ssam soaccept(so, nam) 1934927Swnj struct socket *so; 1948300Sroot struct mbuf *nam; 1954927Swnj { 1964927Swnj int s = splnet(); 1974927Swnj int error; 1984927Swnj 199*10267Ssam so->so_state &= ~SS_NOFDREF; 2008300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 201*10267Ssam (struct mbuf *)0, nam); 2024927Swnj splx(s); 2034927Swnj return (error); 2044927Swnj } 2054927Swnj 206*10267Ssam 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, 218*10267Ssam (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, 240*10267Ssam (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; 263*10267Ssam int error = 0, space, s, dontroute; 2644786Swnj 2657827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2664890Swnj return (EMSGSIZE); 267*10267Ssam dontroute = (flags & SOF_DONTROUTE) && 268*10267Ssam (so->so_options & SO_DONTROUTE) == 0 && 269*10267Ssam (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) { 294*10267Ssam if (dontroute) 295*10267Ssam so->so_options |= SO_DONTROUTE; 2968319Sroot error = (*so->so_proto->pr_usrreq)(so, 2978319Sroot (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND, 298*10267Ssam top, (caddr_t)nam); 299*10267Ssam if (dontroute) 300*10267Ssam 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, 386*10267Ssam 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, 520*10267Ssam (struct mbuf *)0, (struct mbuf *)0); 5214890Swnj release: 5224916Swnj sbunlock(&so->so_rcv); 5234890Swnj splx(s); 5244916Swnj return (error); 5254786Swnj } 5264786Swnj 527*10267Ssam soshutdown(so, how) 528*10267Ssam struct socket *so; 529*10267Ssam int how; 530*10267Ssam { 531*10267Ssam 532*10267Ssam how++; 533*10267Ssam if (how & FREAD) { 534*10267Ssam int s = splimp(); 535*10267Ssam socantrcvmore(so); 536*10267Ssam sbflush(&so->so_rcv); 537*10267Ssam splx(s); 538*10267Ssam } 539*10267Ssam if (how & FWRITE) 540*10267Ssam return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, 541*10267Ssam (struct mbuf *)0, (struct mbuf *)0)); 542*10267Ssam return (0); 543*10267Ssam } 544*10267Ssam 545*10267Ssam sosetopt(so, level, optname, m) 546*10267Ssam struct socket *so; 547*10267Ssam int level, optname; 548*10267Ssam struct mbuf *m; 549*10267Ssam { 550*10267Ssam int optval; 551*10267Ssam 552*10267Ssam if (level != SOL_SOCKET) 553*10267Ssam return (EINVAL); /* XXX */ 554*10267Ssam if (m->m_len != sizeof (int)) 555*10267Ssam return (EINVAL); 556*10267Ssam optval = *mtod(m, int *); 557*10267Ssam switch (optname) { 558*10267Ssam 559*10267Ssam case SO_DEBUG: 560*10267Ssam so->so_options |= SO_DEBUG; 561*10267Ssam break; 562*10267Ssam 563*10267Ssam case SO_LINGER: 564*10267Ssam so->so_options |= SO_LINGER; 565*10267Ssam so->so_linger = optval; 566*10267Ssam break; 567*10267Ssam 568*10267Ssam case SO_DONTLINGER: 569*10267Ssam so->so_options &= ~SO_LINGER; 570*10267Ssam so->so_linger = 0; 571*10267Ssam break; 572*10267Ssam 573*10267Ssam case SO_DONTROUTE: 574*10267Ssam so->so_options |= SO_DONTROUTE; 575*10267Ssam break; 576*10267Ssam 577*10267Ssam case SO_USELOOPBACK: 578*10267Ssam so->so_options |= SO_USELOOPBACK; 579*10267Ssam break; 580*10267Ssam 581*10267Ssam default: 582*10267Ssam return (EINVAL); 583*10267Ssam } 584*10267Ssam return (0); 585*10267Ssam } 586*10267Ssam 587*10267Ssam sogetopt(so, level, optname, m) 588*10267Ssam struct socket *so; 589*10267Ssam int level, optname; 590*10267Ssam struct mbuf *m; 591*10267Ssam { 592*10267Ssam int *optval; 593*10267Ssam 594*10267Ssam if (level != SOL_SOCKET) 595*10267Ssam return (EINVAL); /* XXX */ 596*10267Ssam switch (optname) { 597*10267Ssam 598*10267Ssam case SO_USELOOPBACK: 599*10267Ssam case SO_DONTROUTE: 600*10267Ssam case SO_DEBUG: 601*10267Ssam case SO_KEEPALIVE: 602*10267Ssam case SO_LINGER: 603*10267Ssam if ((so->so_options & optname) == 0) 604*10267Ssam return (ENOPROTOOPT); 605*10267Ssam if (optname == SO_LINGER) { 606*10267Ssam *mtod(m, int *) = so->so_linger; 607*10267Ssam m->m_len = sizeof (so->so_linger); 608*10267Ssam } 609*10267Ssam break; 610*10267Ssam 611*10267Ssam default: 612*10267Ssam return (EINVAL); 613*10267Ssam } 614*10267Ssam return (0); 615*10267Ssam } 616*10267Ssam 6175423Swnj sohasoutofband(so) 6185423Swnj struct socket *so; 6195423Swnj { 6205423Swnj 6215423Swnj if (so->so_pgrp == 0) 6225423Swnj return; 6235423Swnj if (so->so_pgrp > 0) 6245423Swnj gsignal(so->so_pgrp, SIGURG); 6255429Swnj else { 6265429Swnj struct proc *p = pfind(-so->so_pgrp); 6275429Swnj 6285429Swnj if (p) 6295429Swnj psignal(p, SIGURG); 6305429Swnj } 6315423Swnj } 6325423Swnj 6334916Swnj /*ARGSUSED*/ 6347627Ssam soioctl(so, cmd, data) 6354829Swnj register struct socket *so; 6364829Swnj int cmd; 6377627Ssam register char *data; 6384786Swnj { 6394786Swnj 6405358Sroot switch (cmd) { 6414829Swnj 6427627Ssam case FIONBIO: 6437627Ssam if (*(int *)data) 6446214Swnj so->so_state |= SS_NBIO; 6455388Sroot else 6466214Swnj so->so_state &= ~SS_NBIO; 6478594Sroot break; 6485388Sroot 6497627Ssam case FIOASYNC: 6507627Ssam if (*(int *)data) 6516214Swnj so->so_state |= SS_ASYNC; 6525388Sroot else 6536214Swnj so->so_state &= ~SS_ASYNC; 6548594Sroot break; 6555388Sroot 6567627Ssam case SIOCSPGRP: 6577627Ssam so->so_pgrp = *(int *)data; 6588594Sroot break; 6595423Swnj 6607627Ssam case SIOCGPGRP: 6617627Ssam *(int *)data = so->so_pgrp; 6628594Sroot break; 6637627Ssam 6647627Ssam case SIOCATMARK: 6657627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 6668594Sroot break; 6676355Ssam 6686355Ssam /* routing table update calls */ 6696355Ssam case SIOCADDRT: 6706355Ssam case SIOCDELRT: 6716355Ssam if (!suser()) 67210137Ssam return (u.u_error); 6738560Sroot return (rtrequest(cmd, (struct rtentry *)data)); 6746355Ssam 6755445Swnj /* type/protocol specific ioctls */ 6768594Sroot default: 67710137Ssam return (ENOTTY); /* XXX */ 6785423Swnj } 6798594Sroot return (0); 6804786Swnj } 681