1*7827Sroot /* uipc_socket.c 4.48 82/08/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" 175095Swnj #include "../net/in.h" 185095Swnj #include "../net/in_systm.h" 196355Ssam #include "../net/route.h" 207747Sroot #include "../h/uio.h" 214786Swnj 224786Swnj /* 234890Swnj * Socket support routines. 244890Swnj * 254890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 264786Swnj */ 274786Swnj 284786Swnj /* 294786Swnj * Create a socket. 304786Swnj */ 314927Swnj socreate(aso, type, asp, asa, options) 324786Swnj struct socket **aso; 334786Swnj int type; 344927Swnj struct sockproto *asp; 354927Swnj struct sockaddr *asa; 364829Swnj int options; 374786Swnj { 384786Swnj register struct protosw *prp; 394786Swnj register struct socket *so; 404786Swnj struct mbuf *m; 414890Swnj int pf, proto, error; 424786Swnj 434786Swnj /* 444890Swnj * Use process standard protocol/protocol family if none 454890Swnj * specified by address argument. 464786Swnj */ 474927Swnj if (asp == 0) { 484890Swnj pf = PF_INET; /* should be u.u_protof */ 494786Swnj proto = 0; 504786Swnj } else { 514927Swnj pf = asp->sp_family; 524927Swnj proto = asp->sp_protocol; 534786Swnj } 544786Swnj 554786Swnj /* 564890Swnj * If protocol specified, look for it, otherwise 574890Swnj * for a protocol of the correct type in the right family. 584890Swnj */ 594890Swnj if (proto) 604890Swnj prp = pffindproto(pf, proto); 614890Swnj else 624890Swnj prp = pffindtype(pf, type); 634890Swnj if (prp == 0) 644890Swnj return (EPROTONOSUPPORT); 654890Swnj 664890Swnj /* 674786Swnj * Get a socket structure. 684786Swnj */ 694890Swnj m = m_getclr(M_WAIT); 704786Swnj if (m == 0) 714786Swnj return (ENOBUFS); 724786Swnj so = mtod(m, struct socket *); 734829Swnj so->so_options = options; 747507Sroot if (options & SO_ACCEPTCONN) { 757507Sroot so->so_q = so; 767507Sroot so->so_q0 = so; 777507Sroot so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1; 787507Sroot } 796214Swnj so->so_state = 0; 806214Swnj if (u.u_uid == 0) 816214Swnj so->so_state = SS_PRIV; 824786Swnj 834786Swnj /* 844890Swnj * Attach protocol to socket, initializing 854890Swnj * and reserving resources. 864786Swnj */ 874786Swnj so->so_proto = prp; 884979Swnj error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 894979Swnj if (error) { 907507Sroot so->so_state |= SS_NOFDREF; 917180Swnj sofree(so); 924890Swnj return (error); 934786Swnj } 944786Swnj *aso = so; 954786Swnj return (0); 964786Swnj } 974786Swnj 984916Swnj sofree(so) 994916Swnj struct socket *so; 1004916Swnj { 1014916Swnj 1027507Sroot if (so->so_head) { 1037507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1047507Sroot panic("sofree dq"); 1057507Sroot so->so_head = 0; 1067507Sroot } 1077507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1084950Swnj return; 1094950Swnj sbrelease(&so->so_snd); 1104950Swnj sbrelease(&so->so_rcv); 1114971Swnj (void) m_free(dtom(so)); 1124916Swnj } 1134916Swnj 1144786Swnj /* 1154890Swnj * Close a socket on last file table reference removal. 1164890Swnj * Initiate disconnect if connected. 1174890Swnj * Free socket when disconnect complete. 1184829Swnj */ 1195580Sroot soclose(so, exiting) 1204829Swnj register struct socket *so; 1215580Sroot int exiting; 1224829Swnj { 1234890Swnj int s = splnet(); /* conservative */ 1244829Swnj 1257507Sroot if (so->so_options & SO_ACCEPTCONN) { 1267507Sroot while (so->so_q0 != so) 1277507Sroot soclose(so->so_q0, 1); 1287507Sroot while (so->so_q != so) 1297507Sroot soclose(so->so_q, 1); 1307507Sroot } 1314890Swnj if (so->so_pcb == 0) 1324890Swnj goto discard; 1336259Sroot if (exiting) 1346259Sroot so->so_options |= SO_KEEPALIVE; 1354890Swnj if (so->so_state & SS_ISCONNECTED) { 1364890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1374927Swnj u.u_error = sodisconnect(so, (struct sockaddr *)0); 1384890Swnj if (u.u_error) { 1395580Sroot if (exiting) 1405580Sroot goto drop; 1414890Swnj splx(s); 1424890Swnj return; 1434890Swnj } 1444890Swnj } 1455388Sroot if ((so->so_options & SO_DONTLINGER) == 0) { 1465281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 1476214Swnj (so->so_state & SS_NBIO) && 1485580Sroot exiting == 0) { 1495281Sroot u.u_error = EINPROGRESS; 1505281Sroot splx(s); 1515281Sroot return; 1525281Sroot } 1535580Sroot /* should use tsleep here, for at most linger */ 1545281Sroot while (so->so_state & SS_ISCONNECTED) 1555281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1564890Swnj } 1574890Swnj } 1585580Sroot drop: 1596880Ssam if (so->so_pcb) { 1606880Ssam u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1616880Ssam if (exiting == 0 && u.u_error) { 1626880Ssam splx(s); 1636880Ssam return; 1646880Ssam } 1656880Ssam } 1664890Swnj discard: 1677507Sroot so->so_state |= SS_NOFDREF; 1684950Swnj sofree(so); 1694890Swnj splx(s); 1704829Swnj } 1714829Swnj 1724916Swnj /*ARGSUSED*/ 1734890Swnj sostat(so, sb) 1744829Swnj struct socket *so; 1754890Swnj struct stat *sb; 1764829Swnj { 1774829Swnj 1785303Sroot bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 1795303Sroot return (0); /* XXX */ 1804829Swnj } 1814829Swnj 1824829Swnj /* 1834927Swnj * Accept connection on a socket. 1844927Swnj */ 1854927Swnj soaccept(so, asa) 1864927Swnj struct socket *so; 1874927Swnj struct sockaddr *asa; 1884927Swnj { 1894927Swnj int s = splnet(); 1904927Swnj int error; 1914927Swnj 1924927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1934927Swnj splx(s); 1944927Swnj return (error); 1954927Swnj } 1964927Swnj 1974927Swnj /* 1984890Swnj * Connect socket to a specified address. 1994890Swnj * If already connected or connecting, then avoid 2004890Swnj * the protocol entry, to keep its job simpler. 2014786Swnj */ 2024927Swnj soconnect(so, asa) 2034786Swnj struct socket *so; 2044927Swnj struct sockaddr *asa; 2054786Swnj { 2064890Swnj int s = splnet(); 2074890Swnj int error; 2084786Swnj 2094890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2104890Swnj error = EISCONN; 2114890Swnj goto bad; 2124890Swnj } 2134927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2144890Swnj bad: 2154890Swnj splx(s); 2164890Swnj return (error); 2174786Swnj } 2184786Swnj 2194786Swnj /* 2204890Swnj * Disconnect from a socket. 2214890Swnj * Address parameter is from system call for later multicast 2224890Swnj * protocols. Check to make sure that connected and no disconnect 2234890Swnj * in progress (for protocol's sake), and then invoke protocol. 2244786Swnj */ 2254927Swnj sodisconnect(so, asa) 2264786Swnj struct socket *so; 2274927Swnj struct sockaddr *asa; 2284786Swnj { 2294890Swnj int s = splnet(); 2304890Swnj int error; 2314786Swnj 2324890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2334890Swnj error = ENOTCONN; 2344890Swnj goto bad; 2354890Swnj } 2364890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2374890Swnj error = EALREADY; 2384890Swnj goto bad; 2394890Swnj } 2404927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 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 */ 254*7827Sroot sosend(so, asa, uio) 2554786Swnj register struct socket *so; 2564927Swnj struct sockaddr *asa; 257*7827Sroot struct uio *uio; 2584786Swnj { 2594890Swnj struct mbuf *top = 0; 2604890Swnj register struct mbuf *m, **mp = ⊤ 2614916Swnj register u_int len; 2624916Swnj int error = 0, space, s; 2634786Swnj 264*7827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2654890Swnj return (EMSGSIZE); 2666419Sroot #ifdef notdef 2676419Sroot /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ 2686214Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) 2694890Swnj return (EWOULDBLOCK); 2706419Sroot #endif 2716419Sroot restart: 2724890Swnj sblock(&so->so_snd); 2734890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2744890Swnj 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); 2904927Swnj if (asa == 0) 2914890Swnj snderr(EDESTADDRREQ); 2924890Swnj } 2934890Swnj if (top) { 2944927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 2956419Sroot top = 0; 2964890Swnj if (error) { 2974890Swnj splx(s); 2984786Swnj goto release; 2994786Swnj } 3004890Swnj mp = ⊤ 3014786Swnj } 302*7827Sroot if (uio->uio_resid == 0) { 3034979Swnj splx(s); 3044979Swnj goto release; 3054979Swnj } 3065018Swnj space = sbspace(&so->so_snd); 307*7827Sroot if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) { 3086214Swnj if (so->so_state & SS_NBIO) 3094890Swnj snderr(EWOULDBLOCK); 3104890Swnj sbunlock(&so->so_snd); 3114890Swnj sbwait(&so->so_snd); 3124890Swnj splx(s); 3136419Sroot goto restart; 3144786Swnj } 3154890Swnj splx(s); 316*7827Sroot while (uio->uio_resid > 0 && space > 0) { 317*7827Sroot register struct iovec *iov = uio->uio_iov; 318*7827Sroot 319*7827Sroot if (iov->iov_len == 0) { 320*7827Sroot uio->uio_iov++; 321*7827Sroot uio->uio_iovcnt--; 322*7827Sroot if (uio->uio_iovcnt < 0) 323*7827Sroot panic("sosend"); 324*7827Sroot continue; 325*7827Sroot } 3264890Swnj MGET(m, 1); 3274890Swnj if (m == NULL) { 3286419Sroot error = ENOBUFS; /* SIGPIPE? */ 3294890Swnj goto release; 3304786Swnj } 331*7827Sroot if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 3324890Swnj register struct mbuf *p; 3335095Swnj MCLGET(p, 1); 3344890Swnj if (p == 0) 3354890Swnj goto nopages; 3364890Swnj m->m_off = (int)p - (int)m; 3375095Swnj len = CLBYTES; 3384890Swnj } else { 3394786Swnj nopages: 3404890Swnj m->m_off = MMINOFF; 341*7827Sroot len = MIN(MLEN, iov->iov_len); 3424786Swnj } 343*7827Sroot uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 3444890Swnj m->m_len = len; 3454890Swnj *mp = m; 3464890Swnj mp = &m->m_next; 3475018Swnj space = sbspace(&so->so_snd); 3484786Swnj } 3494890Swnj goto again; 3504890Swnj 3514786Swnj release: 3524890Swnj sbunlock(&so->so_snd); 3536419Sroot if (top) 3546419Sroot m_freem(top); 3554786Swnj return (error); 3564786Swnj } 3574786Swnj 3587747Sroot soreceive(so, asa, uio) 3594786Swnj register struct socket *so; 3604927Swnj struct sockaddr *asa; 3617747Sroot struct uio *uio; 3624786Swnj { 3637747Sroot register struct iovec *iov; 3644786Swnj register struct mbuf *m, *n; 3654916Swnj u_int len; 366*7827Sroot int eor, s, error = 0; 3674786Swnj 3684890Swnj restart: 3694890Swnj sblock(&so->so_rcv); 3704890Swnj s = splnet(); 3714890Swnj 3724890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3734786Swnj if (so->so_rcv.sb_cc == 0) { 3745168Swnj if (so->so_error) { 3755168Swnj error = so->so_error; 3765168Swnj so->so_error = 0; 3775168Swnj splx(s); 3785168Swnj goto release; 3795168Swnj } 3804890Swnj if (so->so_state & SS_CANTRCVMORE) { 3814890Swnj splx(s); 3824890Swnj goto release; 3834890Swnj } 3845015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 3855015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3865015Sroot rcverr(ENOTCONN); 3876214Swnj if (so->so_state & SS_NBIO) 3885168Swnj rcverr(EWOULDBLOCK); 3894890Swnj sbunlock(&so->so_rcv); 3904971Swnj sbwait(&so->so_rcv); 3915012Swnj splx(s); 3924890Swnj goto restart; 3934786Swnj } 3944829Swnj m = so->so_rcv.sb_mb; 3954786Swnj if (m == 0) 3964786Swnj panic("receive"); 3975039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 3985039Swnj if (m->m_len != sizeof (struct sockaddr)) 3995039Swnj panic("soreceive addr"); 4005039Swnj if (asa) 4015039Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 4025039Swnj so->so_rcv.sb_cc -= m->m_len; 4035039Swnj so->so_rcv.sb_mbcnt -= MSIZE; 4045018Swnj m = m_free(m); 4054890Swnj if (m == 0) 4064890Swnj panic("receive 2"); 4075018Swnj so->so_rcv.sb_mb = m; 4084890Swnj } 4094786Swnj eor = 0; 4104786Swnj do { 411*7827Sroot if (uio->uio_resid <= 0) 4127747Sroot break; 413*7827Sroot len = uio->uio_resid; 4147747Sroot so->so_state &= ~SS_RCVATMARK; 4157747Sroot if (so->so_oobmark && len > so->so_oobmark) 4167747Sroot len = so->so_oobmark; 4177747Sroot if (len > m->m_len) 4187747Sroot len = m->m_len; 4194786Swnj splx(s); 420*7827Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4214786Swnj s = splnet(); 4224786Swnj if (len == m->m_len) { 4236091Sroot eor = (int)m->m_act; 4246091Sroot sbfree(&so->so_rcv, m); 4256091Sroot so->so_rcv.sb_mb = m->m_next; 4264786Swnj MFREE(m, n); 4274786Swnj } else { 4284786Swnj m->m_off += len; 4294786Swnj m->m_len -= len; 4304829Swnj so->so_rcv.sb_cc -= len; 4314786Swnj } 4327747Sroot if (so->so_oobmark) { 4337747Sroot so->so_oobmark -= len; 4347747Sroot if (so->so_oobmark == 0) { 4357747Sroot so->so_state |= SS_RCVATMARK; 4367747Sroot break; 4377747Sroot } 4387747Sroot } 4397747Sroot } while ((m = so->so_rcv.sb_mb) && !eor); 4404786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 4414786Swnj do { 4424786Swnj if (m == 0) 4434890Swnj panic("receive 3"); 4444890Swnj sbfree(&so->so_rcv, m); 4454786Swnj eor = (int)m->m_act; 4464786Swnj so->so_rcv.sb_mb = m->m_next; 4474786Swnj MFREE(m, n); 4484890Swnj m = n; 4494786Swnj } while (eor == 0); 4504890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 4514890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 4524890Swnj release: 4534916Swnj sbunlock(&so->so_rcv); 4544890Swnj splx(s); 4554916Swnj return (error); 4564786Swnj } 4574786Swnj 4585423Swnj sohasoutofband(so) 4595423Swnj struct socket *so; 4605423Swnj { 4615423Swnj 4625423Swnj if (so->so_pgrp == 0) 4635423Swnj return; 4645423Swnj if (so->so_pgrp > 0) 4655423Swnj gsignal(so->so_pgrp, SIGURG); 4665429Swnj else { 4675429Swnj struct proc *p = pfind(-so->so_pgrp); 4685429Swnj 4695429Swnj if (p) 4705429Swnj psignal(p, SIGURG); 4715429Swnj } 4725423Swnj } 4735423Swnj 4744916Swnj /*ARGSUSED*/ 4757627Ssam soioctl(so, cmd, data) 4764829Swnj register struct socket *so; 4774829Swnj int cmd; 4787627Ssam register char *data; 4794786Swnj { 4804786Swnj 4815358Sroot switch (cmd) { 4824829Swnj 4837627Ssam case FIONBIO: 4847627Ssam if (*(int *)data) 4856214Swnj so->so_state |= SS_NBIO; 4865388Sroot else 4876214Swnj so->so_state &= ~SS_NBIO; 4885388Sroot return; 4895388Sroot 4907627Ssam case FIOASYNC: 4917627Ssam if (*(int *)data) 4926214Swnj so->so_state |= SS_ASYNC; 4935388Sroot else 4946214Swnj so->so_state &= ~SS_ASYNC; 4955388Sroot return; 4965388Sroot 4977627Ssam case SIOCSKEEP: 4987627Ssam if (*(int *)data) 4997507Sroot so->so_options &= ~SO_KEEPALIVE; 5007507Sroot else 5017491Ssam so->so_options |= SO_KEEPALIVE; 5025388Sroot return; 5035388Sroot 5047627Ssam case SIOCGKEEP: 5057627Ssam *(int *)data = (so->so_options & SO_KEEPALIVE) != 0; 5065388Sroot return; 5075388Sroot 5087627Ssam case SIOCSLINGER: 5097627Ssam so->so_linger = *(int *)data; 5105388Sroot if (so->so_linger) 5115388Sroot so->so_options &= ~SO_DONTLINGER; 5125388Sroot else 5135388Sroot so->so_options |= SO_DONTLINGER; 5145388Sroot return; 5155388Sroot 5167627Ssam case SIOCGLINGER: 5177627Ssam *(int *)data = so->so_linger; 5185423Swnj return; 5195388Sroot 5207627Ssam case SIOCSPGRP: 5217627Ssam so->so_pgrp = *(int *)data; 5227627Ssam return; 5235423Swnj 5247627Ssam case SIOCGPGRP: 5257627Ssam *(int *)data = so->so_pgrp; 5267627Ssam return; 5277627Ssam 5285281Sroot case SIOCDONE: { 5297627Ssam int flags = *(int *)data; 5307627Ssam 5315388Sroot flags++; 5325281Sroot if (flags & FREAD) { 5335281Sroot int s = splimp(); 5345281Sroot socantrcvmore(so); 5355281Sroot sbflush(&so->so_rcv); 5366140Ssam splx(s); 5375281Sroot } 5385281Sroot if (flags & FWRITE) 5395404Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); 5405281Sroot return; 5414829Swnj } 5425281Sroot 5435423Swnj case SIOCSENDOOB: { 5447627Ssam char oob = *(char *)data; 5455423Swnj struct mbuf *m; 5467627Ssam 5475423Swnj m = m_get(M_DONTWAIT); 5485423Swnj if (m == 0) { 5495423Swnj u.u_error = ENOBUFS; 5505423Swnj return; 5515423Swnj } 5525423Swnj m->m_off = MMINOFF; 5537627Ssam m->m_len = sizeof (char); 5547627Ssam *mtod(m, char *) = oob; 5555423Swnj (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); 5565423Swnj return; 5575281Sroot } 5585423Swnj 5595423Swnj case SIOCRCVOOB: { 5605423Swnj struct mbuf *m = m_get(M_DONTWAIT); 5617627Ssam 5625423Swnj if (m == 0) { 5635423Swnj u.u_error = ENOBUFS; 5645423Swnj return; 5655423Swnj } 5665423Swnj m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; 5675423Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); 5687627Ssam *(char *)data = *mtod(m, char *); 5697627Ssam (void) m_free(m); 5705423Swnj return; 5715423Swnj } 5725423Swnj 5737627Ssam case SIOCATMARK: 5747627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 5755423Swnj return; 5766355Ssam 5776355Ssam /* routing table update calls */ 5786355Ssam case SIOCADDRT: 5796355Ssam case SIOCDELRT: 5806355Ssam if (!suser()) 5816355Ssam return; 5827627Ssam u.u_error = rtrequest(cmd, (struct rtentry *)data); 5836355Ssam return; 5846355Ssam 5855445Swnj /* type/protocol specific ioctls */ 5865423Swnj } 5875445Swnj u.u_error = EOPNOTSUPP; 5884786Swnj } 589