1*12493Ssam /* uipc_socket.c 4.74 83/05/18 */ 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" 1911571Ssam #include "../net/if.h" 204786Swnj 214786Swnj /* 228300Sroot * Socket operation routines. 238300Sroot * These routines are called by the routines in 248300Sroot * sys_socket.c or from a system process, and 258300Sroot * implement the semantics of socket operations by 268300Sroot * switching out to the protocol specific routines. 274786Swnj */ 284786Swnj 298594Sroot /*ARGSUSED*/ 3010267Ssam socreate(dom, aso, type, proto) 314786Swnj struct socket **aso; 328300Sroot int type, proto; 334786Swnj { 344786Swnj register struct protosw *prp; 354786Swnj register struct socket *so; 364786Swnj struct mbuf *m; 379168Ssam int error; 384786Swnj 394890Swnj if (proto) 409168Ssam prp = pffindproto(dom, proto); 414890Swnj else 429168Ssam prp = pffindtype(dom, type); 434890Swnj if (prp == 0) 444890Swnj return (EPROTONOSUPPORT); 458300Sroot if (prp->pr_type != type) 468300Sroot return (EPROTOTYPE); 479635Ssam m = m_getclr(M_WAIT, MT_SOCKET); 484786Swnj if (m == 0) 494786Swnj return (ENOBUFS); 504786Swnj so = mtod(m, struct socket *); 5110267Ssam so->so_options = SO_LINGER; 526214Swnj so->so_state = 0; 539168Ssam so->so_type = type; 546214Swnj if (u.u_uid == 0) 556214Swnj so->so_state = SS_PRIV; 564786Swnj so->so_proto = prp; 578300Sroot error = (*prp->pr_usrreq)(so, PRU_ATTACH, 5810267Ssam (struct mbuf *)0, (struct mbuf *)0); 594979Swnj if (error) { 607507Sroot so->so_state |= SS_NOFDREF; 617180Swnj sofree(so); 624890Swnj return (error); 634786Swnj } 644786Swnj *aso = so; 654786Swnj return (0); 664786Swnj } 674786Swnj 6810267Ssam sobind(so, nam) 698300Sroot struct socket *so; 708300Sroot struct mbuf *nam; 718300Sroot { 728300Sroot int s = splnet(); 738300Sroot int error; 748300Sroot 758300Sroot error = 7610267Ssam (*so->so_proto->pr_usrreq)(so, PRU_BIND, (struct mbuf *)0, nam); 778300Sroot splx(s); 788300Sroot return (error); 798300Sroot } 808300Sroot 818300Sroot solisten(so, backlog) 828300Sroot struct socket *so; 838300Sroot int backlog; 848300Sroot { 858300Sroot int s = splnet(); 868300Sroot int error; 878300Sroot 888300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, 8910267Ssam (struct mbuf *)0, (struct mbuf *)0); 908300Sroot if (error) { 918300Sroot splx(s); 928300Sroot return (error); 938300Sroot } 948300Sroot if (so->so_q == 0) { 958300Sroot so->so_q = so; 968300Sroot so->so_q0 = so; 978300Sroot so->so_options |= SO_ACCEPTCONN; 988300Sroot } 998300Sroot if (backlog < 0) 1008300Sroot backlog = 0; 10110137Ssam #define SOMAXCONN 5 10210137Ssam so->so_qlimit = MIN(backlog, SOMAXCONN); 1038300Sroot so->so_options |= SO_NEWFDONCONN; 104*12493Ssam splx(s); 1058300Sroot return (0); 1068300Sroot } 1078300Sroot 1084916Swnj sofree(so) 1094916Swnj struct socket *so; 1104916Swnj { 1114916Swnj 1127507Sroot if (so->so_head) { 1137507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1147507Sroot panic("sofree dq"); 1157507Sroot so->so_head = 0; 1167507Sroot } 1177507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1184950Swnj return; 1194950Swnj sbrelease(&so->so_snd); 1204950Swnj sbrelease(&so->so_rcv); 1214971Swnj (void) m_free(dtom(so)); 1224916Swnj } 1234916Swnj 1244786Swnj /* 1254890Swnj * Close a socket on last file table reference removal. 1264890Swnj * Initiate disconnect if connected. 1274890Swnj * Free socket when disconnect complete. 1284829Swnj */ 1295580Sroot soclose(so, exiting) 1304829Swnj register struct socket *so; 1315580Sroot int exiting; 1324829Swnj { 1334890Swnj int s = splnet(); /* conservative */ 1348713Sroot int error; 1354829Swnj 1367507Sroot if (so->so_options & SO_ACCEPTCONN) { 1377507Sroot while (so->so_q0 != so) 13810399Ssam (void) soabort(so->so_q0); 1397507Sroot while (so->so_q != so) 14010399Ssam (void) soabort(so->so_q); 1417507Sroot } 1424890Swnj if (so->so_pcb == 0) 1434890Swnj goto discard; 1446259Sroot if (exiting) 1456259Sroot so->so_options |= SO_KEEPALIVE; 1464890Swnj if (so->so_state & SS_ISCONNECTED) { 1474890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1488725Sroot error = sodisconnect(so, (struct mbuf *)0); 1498713Sroot if (error) { 1505580Sroot if (exiting) 1515580Sroot goto drop; 1524890Swnj splx(s); 1538713Sroot return (error); 1544890Swnj } 1554890Swnj } 15610267Ssam if (so->so_options & SO_LINGER) { 1575281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 1586214Swnj (so->so_state & SS_NBIO) && 1598713Sroot exiting == 0) 1608713Sroot return (EINPROGRESS); 1615580Sroot /* should use tsleep here, for at most linger */ 1625281Sroot while (so->so_state & SS_ISCONNECTED) 1635281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1644890Swnj } 1654890Swnj } 1665580Sroot drop: 1676880Ssam if (so->so_pcb) { 1688713Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 16910267Ssam (struct mbuf *)0, (struct mbuf *)0); 1708713Sroot if (exiting == 0 && error) { 1716880Ssam splx(s); 1728713Sroot return (error); 1736880Ssam } 1746880Ssam } 1754890Swnj discard: 17610399Ssam if (so->so_state & SS_NOFDREF) 17710399Ssam panic("soclose: NOFDREF"); 1787507Sroot so->so_state |= SS_NOFDREF; 1794950Swnj sofree(so); 1804890Swnj splx(s); 1818713Sroot return (0); 1824829Swnj } 1834829Swnj 18410399Ssam /* 18510399Ssam * Must be called at splnet... 18610399Ssam */ 18710399Ssam soabort(so) 18810399Ssam struct socket *so; 18910399Ssam { 19010399Ssam int error; 19110399Ssam 19210399Ssam error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT, 19310399Ssam (struct mbuf *)0, (struct mbuf *)0); 19410399Ssam return (error); 19510399Ssam } 19610399Ssam 1974916Swnj /*ARGSUSED*/ 1989026Sroot sostat(so, ub) 1994829Swnj struct socket *so; 2009026Sroot struct stat *ub; 2014829Swnj { 2029026Sroot struct stat sb; 2034829Swnj 2049026Sroot bzero((caddr_t)&sb, sizeof (sb)); /* XXX */ 2059168Ssam (void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */ 2065303Sroot return (0); /* XXX */ 2074829Swnj } 2084829Swnj 20910267Ssam soaccept(so, nam) 2104927Swnj struct socket *so; 2118300Sroot struct mbuf *nam; 2124927Swnj { 2134927Swnj int s = splnet(); 2144927Swnj int error; 2154927Swnj 21610399Ssam if ((so->so_state & SS_NOFDREF) == 0) 21710399Ssam panic("soaccept: !NOFDREF"); 21810267Ssam so->so_state &= ~SS_NOFDREF; 2198300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 22010267Ssam (struct mbuf *)0, nam); 2214927Swnj splx(s); 2224927Swnj return (error); 2234927Swnj } 2244927Swnj 22510267Ssam soconnect(so, nam) 2264786Swnj struct socket *so; 2278300Sroot struct mbuf *nam; 2284786Swnj { 2294890Swnj int s = splnet(); 2304890Swnj int error; 2314786Swnj 2324890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2334890Swnj error = EISCONN; 2344890Swnj goto bad; 2354890Swnj } 2368300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 23710267Ssam (struct mbuf *)0, nam); 2384890Swnj bad: 2394890Swnj splx(s); 2404890Swnj return (error); 2414786Swnj } 2424786Swnj 2438300Sroot sodisconnect(so, nam) 2444786Swnj struct socket *so; 2458300Sroot struct mbuf *nam; 2464786Swnj { 2474890Swnj int s = splnet(); 2484890Swnj int error; 2494786Swnj 2504890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2514890Swnj error = ENOTCONN; 2524890Swnj goto bad; 2534890Swnj } 2544890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2554890Swnj error = EALREADY; 2564890Swnj goto bad; 2574890Swnj } 2588300Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 25910267Ssam (struct mbuf *)0, nam); 2604890Swnj bad: 2614890Swnj splx(s); 2624890Swnj return (error); 2634786Swnj } 2644786Swnj 2654786Swnj /* 2664890Swnj * Send on a socket. 2674890Swnj * If send must go all at once and message is larger than 2684890Swnj * send buffering, then hard error. 2694890Swnj * Lock against other senders. 2704890Swnj * If must go all at once and not enough room now, then 2714890Swnj * inform user that this would block and do nothing. 2724786Swnj */ 2738319Sroot sosend(so, nam, uio, flags) 2744786Swnj register struct socket *so; 2758300Sroot struct mbuf *nam; 2767827Sroot struct uio *uio; 2778319Sroot int flags; 2784786Swnj { 2794890Swnj struct mbuf *top = 0; 2804890Swnj register struct mbuf *m, **mp = ⊤ 2818713Sroot register int len; 28210267Ssam int error = 0, space, s, dontroute; 2834786Swnj 2847827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2854890Swnj return (EMSGSIZE); 28610267Ssam dontroute = (flags & SOF_DONTROUTE) && 28710267Ssam (so->so_options & SO_DONTROUTE) == 0 && 28810267Ssam (so->so_proto->pr_flags & PR_ATOMIC); 2896419Sroot restart: 2904890Swnj sblock(&so->so_snd); 2914890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2924890Swnj 2938041Sroot u.u_ru.ru_msgsnd++; 2946419Sroot again: 2954890Swnj s = splnet(); 2966419Sroot if (so->so_state & SS_CANTSENDMORE) { 2976419Sroot psignal(u.u_procp, SIGPIPE); 2986419Sroot snderr(EPIPE); 2996419Sroot } 3005168Swnj if (so->so_error) { 3015168Swnj error = so->so_error; 3026419Sroot so->so_error = 0; /* ??? */ 3035168Swnj splx(s); 3045168Swnj goto release; 3055168Swnj } 3064890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 3074890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 3084890Swnj snderr(ENOTCONN); 3098300Sroot if (nam == 0) 3104890Swnj snderr(EDESTADDRREQ); 3114890Swnj } 3124890Swnj if (top) { 31310267Ssam if (dontroute) 31410267Ssam so->so_options |= SO_DONTROUTE; 3158319Sroot error = (*so->so_proto->pr_usrreq)(so, 3168319Sroot (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND, 31710267Ssam top, (caddr_t)nam); 31810267Ssam if (dontroute) 31910267Ssam so->so_options &= ~SO_DONTROUTE; 3206419Sroot top = 0; 3214890Swnj if (error) { 3224890Swnj splx(s); 3234786Swnj goto release; 3244786Swnj } 3254890Swnj mp = ⊤ 3264786Swnj } 3277827Sroot if (uio->uio_resid == 0) { 3284979Swnj splx(s); 3294979Swnj goto release; 3304979Swnj } 3318319Sroot if (flags & SOF_OOB) 3328319Sroot space = 1024; 3338319Sroot else { 3348319Sroot space = sbspace(&so->so_snd); 3358319Sroot if (space <= 0 || 3368319Sroot sosendallatonce(so) && space < uio->uio_resid) { 3378319Sroot if (so->so_state & SS_NBIO) 3388319Sroot snderr(EWOULDBLOCK); 3398319Sroot sbunlock(&so->so_snd); 3408319Sroot sbwait(&so->so_snd); 3418319Sroot splx(s); 3428319Sroot goto restart; 3438319Sroot } 3444786Swnj } 3454890Swnj splx(s); 3467827Sroot while (uio->uio_resid > 0 && space > 0) { 3477827Sroot register struct iovec *iov = uio->uio_iov; 3487827Sroot 3497827Sroot if (iov->iov_len == 0) { 3507827Sroot uio->uio_iov++; 3517827Sroot uio->uio_iovcnt--; 3527827Sroot if (uio->uio_iovcnt < 0) 3537827Sroot panic("sosend"); 3547827Sroot continue; 3557827Sroot } 3569635Ssam MGET(m, M_WAIT, MT_DATA); 3574890Swnj if (m == NULL) { 3586419Sroot error = ENOBUFS; /* SIGPIPE? */ 3594890Swnj goto release; 3604786Swnj } 3617827Sroot if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 3624890Swnj register struct mbuf *p; 3635095Swnj MCLGET(p, 1); 3644890Swnj if (p == 0) 3654890Swnj goto nopages; 3664890Swnj m->m_off = (int)p - (int)m; 3675095Swnj len = CLBYTES; 3684890Swnj } else { 3694786Swnj nopages: 3707827Sroot len = MIN(MLEN, iov->iov_len); 3714786Swnj } 3728771Sroot (void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 3734890Swnj m->m_len = len; 3744890Swnj *mp = m; 3754890Swnj mp = &m->m_next; 3768319Sroot if (flags & SOF_OOB) 3778319Sroot space -= len; 3788319Sroot else 3798319Sroot space = sbspace(&so->so_snd); 3804786Swnj } 3814890Swnj goto again; 3824890Swnj 3834786Swnj release: 3844890Swnj sbunlock(&so->so_snd); 3856419Sroot if (top) 3866419Sroot m_freem(top); 3874786Swnj return (error); 3884786Swnj } 3894786Swnj 3908319Sroot soreceive(so, aname, uio, flags) 3914786Swnj register struct socket *so; 3928300Sroot struct mbuf **aname; 3937747Sroot struct uio *uio; 3948319Sroot int flags; 3954786Swnj { 3964786Swnj register struct mbuf *m, *n; 3978713Sroot int len; 3988319Sroot int eor, s, error = 0, moff, tomark; 3994786Swnj 4008319Sroot if (flags & SOF_OOB) { 4019635Ssam m = m_get(M_WAIT, MT_DATA); 40210137Ssam if (m == NULL) 40310137Ssam return (ENOBUFS); 4048594Sroot error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, 40510267Ssam m, (struct mbuf *)0); 4068594Sroot if (error) 40710137Ssam goto bad; 4088319Sroot do { 40910137Ssam len = uio->uio_resid; 4108319Sroot if (len > m->m_len) 4118319Sroot len = m->m_len; 4128594Sroot error = 4138793Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4148319Sroot m = m_free(m); 4158594Sroot } while (uio->uio_resid && error == 0 && m); 41610137Ssam bad: 4178319Sroot if (m) 4188771Sroot m_freem(m); 4198594Sroot return (error); 4208319Sroot } 4218319Sroot 4224890Swnj restart: 4234890Swnj sblock(&so->so_rcv); 4248835Sroot s = splnet(); 4254890Swnj 4264890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 4274786Swnj if (so->so_rcv.sb_cc == 0) { 4285168Swnj if (so->so_error) { 4295168Swnj error = so->so_error; 4305168Swnj so->so_error = 0; 4315168Swnj splx(s); 4325168Swnj goto release; 4335168Swnj } 4344890Swnj if (so->so_state & SS_CANTRCVMORE) { 4354890Swnj splx(s); 4364890Swnj goto release; 4374890Swnj } 4385015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 4395015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 4405015Sroot rcverr(ENOTCONN); 4416214Swnj if (so->so_state & SS_NBIO) 4425168Swnj rcverr(EWOULDBLOCK); 4434890Swnj sbunlock(&so->so_rcv); 4444971Swnj sbwait(&so->so_rcv); 4455012Swnj splx(s); 4464890Swnj goto restart; 4474786Swnj } 4488041Sroot u.u_ru.ru_msgrcv++; 4494829Swnj m = so->so_rcv.sb_mb; 4504786Swnj if (m == 0) 4514786Swnj panic("receive"); 4525039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 4538319Sroot if ((flags & SOF_PREVIEW) == 0) { 4548319Sroot so->so_rcv.sb_cc -= m->m_len; 4558319Sroot so->so_rcv.sb_mbcnt -= MSIZE; 4568319Sroot } 4578300Sroot if (aname) { 45810137Ssam if (flags & SOF_PREVIEW) { 4598319Sroot *aname = m_copy(m, 0, m->m_len); 46010137Ssam if (*aname == NULL) 46110137Ssam panic("receive 2"); 46210137Ssam } else 4638319Sroot *aname = m; 4648300Sroot m = m->m_next; 4658300Sroot (*aname)->m_next = 0; 4668300Sroot } else 4678319Sroot if (flags & SOF_PREVIEW) 4688319Sroot m = m->m_next; 4698319Sroot else 4708319Sroot m = m_free(m); 4714890Swnj if (m == 0) 47210137Ssam panic("receive 3"); 4738548Sroot if ((flags & SOF_PREVIEW) == 0) 4748548Sroot so->so_rcv.sb_mb = m; 4754890Swnj } 4764786Swnj eor = 0; 4778319Sroot moff = 0; 4788319Sroot tomark = so->so_oobmark; 4794786Swnj do { 4807827Sroot if (uio->uio_resid <= 0) 4817747Sroot break; 4827827Sroot len = uio->uio_resid; 4837747Sroot so->so_state &= ~SS_RCVATMARK; 4848319Sroot if (tomark && len > tomark) 4858319Sroot len = tomark; 4868548Sroot if (moff+len > m->m_len - moff) 4878319Sroot len = m->m_len - moff; 4884786Swnj splx(s); 4898594Sroot error = 4908793Sroot uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); 4914786Swnj s = splnet(); 4924786Swnj if (len == m->m_len) { 4936091Sroot eor = (int)m->m_act; 4948319Sroot if (flags & SOF_PREVIEW) 4958319Sroot m = m->m_next; 4968319Sroot else { 4978319Sroot sbfree(&so->so_rcv, m); 4988319Sroot MFREE(m, n); 4998319Sroot m = n; 5008548Sroot so->so_rcv.sb_mb = m; 5018319Sroot } 5028319Sroot moff = 0; 5034786Swnj } else { 5048319Sroot if (flags & SOF_PREVIEW) 5058319Sroot moff += len; 5068319Sroot else { 5078319Sroot m->m_off += len; 5088319Sroot m->m_len -= len; 5098319Sroot so->so_rcv.sb_cc -= len; 5108319Sroot } 5114786Swnj } 5128319Sroot if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) { 5137747Sroot so->so_oobmark -= len; 5147747Sroot if (so->so_oobmark == 0) { 5157747Sroot so->so_state |= SS_RCVATMARK; 5167747Sroot break; 5177747Sroot } 5187747Sroot } 5198319Sroot if (tomark) { 5208319Sroot tomark -= len; 5218319Sroot if (tomark == 0) 5228319Sroot break; 5238319Sroot } 5248594Sroot } while (m && error == 0 && !eor); 5258319Sroot if (flags & SOF_PREVIEW) 5268319Sroot goto release; 5274786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 5284786Swnj do { 5294786Swnj if (m == 0) 53010137Ssam panic("receive 4"); 5314890Swnj sbfree(&so->so_rcv, m); 5324786Swnj eor = (int)m->m_act; 5334786Swnj so->so_rcv.sb_mb = m->m_next; 5344786Swnj MFREE(m, n); 5354890Swnj m = n; 5364786Swnj } while (eor == 0); 5374890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 5388300Sroot (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 53910267Ssam (struct mbuf *)0, (struct mbuf *)0); 5404890Swnj release: 5414916Swnj sbunlock(&so->so_rcv); 5424890Swnj splx(s); 5434916Swnj return (error); 5444786Swnj } 5454786Swnj 54610267Ssam soshutdown(so, how) 54710267Ssam struct socket *so; 54810267Ssam int how; 54910267Ssam { 55010267Ssam 55110267Ssam how++; 55210267Ssam if (how & FREAD) { 55310267Ssam int s = splimp(); 55410267Ssam socantrcvmore(so); 55510267Ssam sbflush(&so->so_rcv); 55610267Ssam splx(s); 55710267Ssam } 55810267Ssam if (how & FWRITE) 55910267Ssam return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, 56010267Ssam (struct mbuf *)0, (struct mbuf *)0)); 56110267Ssam return (0); 56210267Ssam } 56310267Ssam 56410267Ssam sosetopt(so, level, optname, m) 56510267Ssam struct socket *so; 56610267Ssam int level, optname; 56710267Ssam struct mbuf *m; 56810267Ssam { 56910267Ssam 57010267Ssam if (level != SOL_SOCKET) 57110267Ssam return (EINVAL); /* XXX */ 57210267Ssam switch (optname) { 57310267Ssam 57410267Ssam case SO_DEBUG: 57510269Ssam case SO_KEEPALIVE: 57610599Ssam case SO_DONTROUTE: 57710599Ssam case SO_USELOOPBACK: 57810599Ssam case SO_REUSEADDR: 57910599Ssam so->so_options |= optname; 58010269Ssam break; 58110269Ssam 58210267Ssam case SO_LINGER: 58310269Ssam if (m == NULL || m->m_len != sizeof (int)) 58410269Ssam return (EINVAL); 58510267Ssam so->so_options |= SO_LINGER; 58610269Ssam so->so_linger = *mtod(m, int *); 58710267Ssam break; 58810267Ssam 58910267Ssam case SO_DONTLINGER: 59010267Ssam so->so_options &= ~SO_LINGER; 59110267Ssam so->so_linger = 0; 59210267Ssam break; 59310267Ssam 59410267Ssam default: 59510267Ssam return (EINVAL); 59610267Ssam } 59710267Ssam return (0); 59810267Ssam } 59910267Ssam 60010267Ssam sogetopt(so, level, optname, m) 60110267Ssam struct socket *so; 60210267Ssam int level, optname; 60310267Ssam struct mbuf *m; 60410267Ssam { 60510267Ssam 60610267Ssam if (level != SOL_SOCKET) 60710267Ssam return (EINVAL); /* XXX */ 60810267Ssam switch (optname) { 60910267Ssam 61010267Ssam case SO_USELOOPBACK: 61110267Ssam case SO_DONTROUTE: 61210267Ssam case SO_DEBUG: 61310267Ssam case SO_KEEPALIVE: 61410267Ssam case SO_LINGER: 61510599Ssam case SO_REUSEADDR: 61610267Ssam if ((so->so_options & optname) == 0) 61710267Ssam return (ENOPROTOOPT); 61810269Ssam if (optname == SO_LINGER && m != NULL) { 61910267Ssam *mtod(m, int *) = so->so_linger; 62010267Ssam m->m_len = sizeof (so->so_linger); 62110267Ssam } 62210267Ssam break; 62310267Ssam 62410267Ssam default: 62510267Ssam return (EINVAL); 62610267Ssam } 62710267Ssam return (0); 62810267Ssam } 62910267Ssam 6305423Swnj sohasoutofband(so) 6315423Swnj struct socket *so; 6325423Swnj { 6335423Swnj 6345423Swnj if (so->so_pgrp == 0) 6355423Swnj return; 6365423Swnj if (so->so_pgrp > 0) 6375423Swnj gsignal(so->so_pgrp, SIGURG); 6385429Swnj else { 6395429Swnj struct proc *p = pfind(-so->so_pgrp); 6405429Swnj 6415429Swnj if (p) 6425429Swnj psignal(p, SIGURG); 6435429Swnj } 6445423Swnj } 6455423Swnj 6464916Swnj /*ARGSUSED*/ 6477627Ssam soioctl(so, cmd, data) 6484829Swnj register struct socket *so; 6494829Swnj int cmd; 6507627Ssam register char *data; 6514786Swnj { 6524786Swnj 6535358Sroot switch (cmd) { 6544829Swnj 6557627Ssam case FIONBIO: 6567627Ssam if (*(int *)data) 6576214Swnj so->so_state |= SS_NBIO; 6585388Sroot else 6596214Swnj so->so_state &= ~SS_NBIO; 6608594Sroot break; 6615388Sroot 6627627Ssam case FIOASYNC: 6637627Ssam if (*(int *)data) 6646214Swnj so->so_state |= SS_ASYNC; 6655388Sroot else 6666214Swnj so->so_state &= ~SS_ASYNC; 6678594Sroot break; 6685388Sroot 6697627Ssam case SIOCSPGRP: 6707627Ssam so->so_pgrp = *(int *)data; 6718594Sroot break; 6725423Swnj 6737627Ssam case SIOCGPGRP: 6747627Ssam *(int *)data = so->so_pgrp; 6758594Sroot break; 6767627Ssam 6777627Ssam case SIOCATMARK: 6787627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 6798594Sroot break; 6806355Ssam 6816355Ssam /* routing table update calls */ 6826355Ssam case SIOCADDRT: 6836355Ssam case SIOCDELRT: 6846355Ssam if (!suser()) 68510137Ssam return (u.u_error); 6868560Sroot return (rtrequest(cmd, (struct rtentry *)data)); 6876355Ssam 68811571Ssam /* interface parameter requests */ 68911571Ssam case SIOCSIFADDR: 69011571Ssam case SIOCSIFFLAGS: 69111632Ssam case SIOCSIFDSTADDR: 69211571Ssam if (!suser()) 69311571Ssam return (u.u_error); 69411571Ssam return (ifrequest(cmd, data)); 69511571Ssam 69611571Ssam case SIOCGIFADDR: 69711571Ssam case SIOCGIFFLAGS: 69811632Ssam case SIOCGIFDSTADDR: 69911571Ssam return (ifrequest(cmd, data)); 70011571Ssam 70111571Ssam case SIOCGIFCONF: 70211571Ssam return (ifconf(cmd, data)); 70311571Ssam 7045445Swnj /* type/protocol specific ioctls */ 7058594Sroot default: 70610137Ssam return (ENOTTY); /* XXX */ 7075423Swnj } 7088594Sroot return (0); 7094786Swnj } 710