1*7747Sroot /* uipc_socket.c 4.47 82/08/14 */ 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" 20*7747Sroot #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 */ 1247507Sroot register struct socket *so2; 1254829Swnj 1267507Sroot if (so->so_options & SO_ACCEPTCONN) { 1277507Sroot while (so->so_q0 != so) 1287507Sroot soclose(so->so_q0, 1); 1297507Sroot while (so->so_q != so) 1307507Sroot soclose(so->so_q, 1); 1317507Sroot } 1324890Swnj if (so->so_pcb == 0) 1334890Swnj goto discard; 1346259Sroot if (exiting) 1356259Sroot so->so_options |= SO_KEEPALIVE; 1364890Swnj if (so->so_state & SS_ISCONNECTED) { 1374890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1384927Swnj u.u_error = sodisconnect(so, (struct sockaddr *)0); 1394890Swnj if (u.u_error) { 1405580Sroot if (exiting) 1415580Sroot goto drop; 1424890Swnj splx(s); 1434890Swnj return; 1444890Swnj } 1454890Swnj } 1465388Sroot if ((so->so_options & SO_DONTLINGER) == 0) { 1475281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 1486214Swnj (so->so_state & SS_NBIO) && 1495580Sroot exiting == 0) { 1505281Sroot u.u_error = EINPROGRESS; 1515281Sroot splx(s); 1525281Sroot return; 1535281Sroot } 1545580Sroot /* should use tsleep here, for at most linger */ 1555281Sroot while (so->so_state & SS_ISCONNECTED) 1565281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1574890Swnj } 1584890Swnj } 1595580Sroot drop: 1606880Ssam if (so->so_pcb) { 1616880Ssam u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1626880Ssam if (exiting == 0 && u.u_error) { 1636880Ssam splx(s); 1646880Ssam return; 1656880Ssam } 1666880Ssam } 1674890Swnj discard: 1687507Sroot so->so_state |= SS_NOFDREF; 1694950Swnj sofree(so); 1704890Swnj splx(s); 1714829Swnj } 1724829Swnj 1734916Swnj /*ARGSUSED*/ 1744890Swnj sostat(so, sb) 1754829Swnj struct socket *so; 1764890Swnj struct stat *sb; 1774829Swnj { 1784829Swnj 1795303Sroot bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 1805303Sroot return (0); /* XXX */ 1814829Swnj } 1824829Swnj 1834829Swnj /* 1844927Swnj * Accept connection on a socket. 1854927Swnj */ 1864927Swnj soaccept(so, asa) 1874927Swnj struct socket *so; 1884927Swnj struct sockaddr *asa; 1894927Swnj { 1904927Swnj int s = splnet(); 1914927Swnj int error; 1924927Swnj 1934927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1944927Swnj splx(s); 1954927Swnj return (error); 1964927Swnj } 1974927Swnj 1984927Swnj /* 1994890Swnj * Connect socket to a specified address. 2004890Swnj * If already connected or connecting, then avoid 2014890Swnj * the protocol entry, to keep its job simpler. 2024786Swnj */ 2034927Swnj soconnect(so, asa) 2044786Swnj struct socket *so; 2054927Swnj struct sockaddr *asa; 2064786Swnj { 2074890Swnj int s = splnet(); 2084890Swnj int error; 2094786Swnj 2104890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2114890Swnj error = EISCONN; 2124890Swnj goto bad; 2134890Swnj } 2144927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2154890Swnj bad: 2164890Swnj splx(s); 2174890Swnj return (error); 2184786Swnj } 2194786Swnj 2204786Swnj /* 2214890Swnj * Disconnect from a socket. 2224890Swnj * Address parameter is from system call for later multicast 2234890Swnj * protocols. Check to make sure that connected and no disconnect 2244890Swnj * in progress (for protocol's sake), and then invoke protocol. 2254786Swnj */ 2264927Swnj sodisconnect(so, asa) 2274786Swnj struct socket *so; 2284927Swnj struct sockaddr *asa; 2294786Swnj { 2304890Swnj int s = splnet(); 2314890Swnj int error; 2324786Swnj 2334890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2344890Swnj error = ENOTCONN; 2354890Swnj goto bad; 2364890Swnj } 2374890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2384890Swnj error = EALREADY; 2394890Swnj goto bad; 2404890Swnj } 2414927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2424890Swnj bad: 2434890Swnj splx(s); 2444890Swnj return (error); 2454786Swnj } 2464786Swnj 2474786Swnj /* 2484890Swnj * Send on a socket. 2494890Swnj * If send must go all at once and message is larger than 2504890Swnj * send buffering, then hard error. 2514890Swnj * Lock against other senders. 2524890Swnj * If must go all at once and not enough room now, then 2534890Swnj * inform user that this would block and do nothing. 2544786Swnj */ 2554927Swnj sosend(so, asa) 2564786Swnj register struct socket *so; 2574927Swnj struct sockaddr *asa; 2584786Swnj { 2594890Swnj struct mbuf *top = 0; 2604890Swnj register struct mbuf *m, **mp = ⊤ 2614916Swnj register u_int len; 2624916Swnj int error = 0, space, s; 2634786Swnj 2644890Swnj if (sosendallatonce(so) && u.u_count > 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 } 3024979Swnj if (u.u_count == 0) { 3034979Swnj splx(s); 3044979Swnj goto release; 3054979Swnj } 3065018Swnj space = sbspace(&so->so_snd); 3075610Swnj if (space <= 0 || sosendallatonce(so) && space < u.u_count) { 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); 3165018Swnj while (u.u_count && space > 0) { 3174890Swnj MGET(m, 1); 3184890Swnj if (m == NULL) { 3196419Sroot error = ENOBUFS; /* SIGPIPE? */ 3204890Swnj goto release; 3214786Swnj } 3225095Swnj if (u.u_count >= CLBYTES && space >= CLBYTES) { 3234890Swnj register struct mbuf *p; 3245095Swnj MCLGET(p, 1); 3254890Swnj if (p == 0) 3264890Swnj goto nopages; 3274890Swnj m->m_off = (int)p - (int)m; 3285095Swnj len = CLBYTES; 3294890Swnj } else { 3304786Swnj nopages: 3314890Swnj m->m_off = MMINOFF; 3324890Swnj len = MIN(MLEN, u.u_count); 3334786Swnj } 3344890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 3354890Swnj m->m_len = len; 3364890Swnj *mp = m; 3374890Swnj mp = &m->m_next; 3385018Swnj space = sbspace(&so->so_snd); 3394786Swnj } 3404890Swnj goto again; 3414890Swnj 3424786Swnj release: 3434890Swnj sbunlock(&so->so_snd); 3446419Sroot if (top) 3456419Sroot m_freem(top); 3464786Swnj return (error); 3474786Swnj } 3484786Swnj 349*7747Sroot soreceive(so, asa, uio) 3504786Swnj register struct socket *so; 3514927Swnj struct sockaddr *asa; 352*7747Sroot struct uio *uio; 3534786Swnj { 354*7747Sroot register struct iovec *iov; 3554786Swnj register struct mbuf *m, *n; 3564916Swnj u_int len; 357*7747Sroot int eor, s, error = 0, resid = uio->uio_resid; 358*7747Sroot int cnt; 3594786Swnj 3604890Swnj restart: 3614890Swnj sblock(&so->so_rcv); 3624890Swnj s = splnet(); 3634890Swnj 3644890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3654786Swnj if (so->so_rcv.sb_cc == 0) { 3665168Swnj if (so->so_error) { 3675168Swnj error = so->so_error; 3685168Swnj so->so_error = 0; 3695168Swnj splx(s); 3705168Swnj goto release; 3715168Swnj } 3724890Swnj if (so->so_state & SS_CANTRCVMORE) { 3734890Swnj splx(s); 3744890Swnj goto release; 3754890Swnj } 3765015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 3775015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3785015Sroot rcverr(ENOTCONN); 3796214Swnj if (so->so_state & SS_NBIO) 3805168Swnj rcverr(EWOULDBLOCK); 3814890Swnj sbunlock(&so->so_rcv); 3824971Swnj sbwait(&so->so_rcv); 3835012Swnj splx(s); 3844890Swnj goto restart; 3854786Swnj } 3864829Swnj m = so->so_rcv.sb_mb; 3874786Swnj if (m == 0) 3884786Swnj panic("receive"); 3895039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 3905039Swnj if (m->m_len != sizeof (struct sockaddr)) 3915039Swnj panic("soreceive addr"); 3925039Swnj if (asa) 3935039Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 3945039Swnj so->so_rcv.sb_cc -= m->m_len; 3955039Swnj so->so_rcv.sb_mbcnt -= MSIZE; 3965018Swnj m = m_free(m); 3974890Swnj if (m == 0) 3984890Swnj panic("receive 2"); 3995018Swnj so->so_rcv.sb_mb = m; 4004890Swnj } 4014786Swnj eor = 0; 4024786Swnj do { 403*7747Sroot if (uio->uio_iovcnt == 0) 404*7747Sroot break; 405*7747Sroot iov = uio->uio_iov; 406*7747Sroot len = iov->iov_len; 407*7747Sroot so->so_state &= ~SS_RCVATMARK; 408*7747Sroot if (so->so_oobmark && len > so->so_oobmark) 409*7747Sroot len = so->so_oobmark; 410*7747Sroot if (len > m->m_len) 411*7747Sroot len = m->m_len; 4124786Swnj splx(s); 413*7747Sroot uiomove(mtod(m, caddr_t), len, UIO_WRITETO, uio); 4144786Swnj s = splnet(); 4154786Swnj if (len == m->m_len) { 4166091Sroot eor = (int)m->m_act; 4176091Sroot sbfree(&so->so_rcv, m); 4186091Sroot so->so_rcv.sb_mb = m->m_next; 4194786Swnj MFREE(m, n); 4204786Swnj } else { 4214786Swnj m->m_off += len; 4224786Swnj m->m_len -= len; 4234829Swnj so->so_rcv.sb_cc -= len; 4244786Swnj } 425*7747Sroot if (so->so_oobmark) { 426*7747Sroot so->so_oobmark -= len; 427*7747Sroot if (so->so_oobmark == 0) { 428*7747Sroot so->so_state |= SS_RCVATMARK; 429*7747Sroot break; 430*7747Sroot } 431*7747Sroot } 432*7747Sroot } while ((m = so->so_rcv.sb_mb) && !eor); 4334786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 4344786Swnj do { 4354786Swnj if (m == 0) 4364890Swnj panic("receive 3"); 4374890Swnj sbfree(&so->so_rcv, m); 4384786Swnj eor = (int)m->m_act; 4394786Swnj so->so_rcv.sb_mb = m->m_next; 4404786Swnj MFREE(m, n); 4414890Swnj m = n; 4424786Swnj } while (eor == 0); 4434890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 4444890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 4454890Swnj release: 4464916Swnj sbunlock(&so->so_rcv); 4474890Swnj splx(s); 4484916Swnj return (error); 4494786Swnj } 4504786Swnj 4515423Swnj sohasoutofband(so) 4525423Swnj struct socket *so; 4535423Swnj { 4545423Swnj 4555423Swnj if (so->so_pgrp == 0) 4565423Swnj return; 4575423Swnj if (so->so_pgrp > 0) 4585423Swnj gsignal(so->so_pgrp, SIGURG); 4595429Swnj else { 4605429Swnj struct proc *p = pfind(-so->so_pgrp); 4615429Swnj 4625429Swnj if (p) 4635429Swnj psignal(p, SIGURG); 4645429Swnj } 4655423Swnj } 4665423Swnj 4674916Swnj /*ARGSUSED*/ 4687627Ssam soioctl(so, cmd, data) 4694829Swnj register struct socket *so; 4704829Swnj int cmd; 4717627Ssam register char *data; 4724786Swnj { 4734786Swnj 4745358Sroot switch (cmd) { 4754829Swnj 4767627Ssam case FIONBIO: 4777627Ssam if (*(int *)data) 4786214Swnj so->so_state |= SS_NBIO; 4795388Sroot else 4806214Swnj so->so_state &= ~SS_NBIO; 4815388Sroot return; 4825388Sroot 4837627Ssam case FIOASYNC: 4847627Ssam if (*(int *)data) 4856214Swnj so->so_state |= SS_ASYNC; 4865388Sroot else 4876214Swnj so->so_state &= ~SS_ASYNC; 4885388Sroot return; 4895388Sroot 4907627Ssam case SIOCSKEEP: 4917627Ssam if (*(int *)data) 4927507Sroot so->so_options &= ~SO_KEEPALIVE; 4937507Sroot else 4947491Ssam so->so_options |= SO_KEEPALIVE; 4955388Sroot return; 4965388Sroot 4977627Ssam case SIOCGKEEP: 4987627Ssam *(int *)data = (so->so_options & SO_KEEPALIVE) != 0; 4995388Sroot return; 5005388Sroot 5017627Ssam case SIOCSLINGER: 5027627Ssam so->so_linger = *(int *)data; 5035388Sroot if (so->so_linger) 5045388Sroot so->so_options &= ~SO_DONTLINGER; 5055388Sroot else 5065388Sroot so->so_options |= SO_DONTLINGER; 5075388Sroot return; 5085388Sroot 5097627Ssam case SIOCGLINGER: 5107627Ssam *(int *)data = so->so_linger; 5115423Swnj return; 5125388Sroot 5137627Ssam case SIOCSPGRP: 5147627Ssam so->so_pgrp = *(int *)data; 5157627Ssam return; 5165423Swnj 5177627Ssam case SIOCGPGRP: 5187627Ssam *(int *)data = so->so_pgrp; 5197627Ssam return; 5207627Ssam 5215281Sroot case SIOCDONE: { 5227627Ssam int flags = *(int *)data; 5237627Ssam 5245388Sroot flags++; 5255281Sroot if (flags & FREAD) { 5265281Sroot int s = splimp(); 5275281Sroot socantrcvmore(so); 5285281Sroot sbflush(&so->so_rcv); 5296140Ssam splx(s); 5305281Sroot } 5315281Sroot if (flags & FWRITE) 5325404Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); 5335281Sroot return; 5344829Swnj } 5355281Sroot 5365423Swnj case SIOCSENDOOB: { 5377627Ssam char oob = *(char *)data; 5385423Swnj struct mbuf *m; 5397627Ssam 5405423Swnj m = m_get(M_DONTWAIT); 5415423Swnj if (m == 0) { 5425423Swnj u.u_error = ENOBUFS; 5435423Swnj return; 5445423Swnj } 5455423Swnj m->m_off = MMINOFF; 5467627Ssam m->m_len = sizeof (char); 5477627Ssam *mtod(m, char *) = oob; 5485423Swnj (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); 5495423Swnj return; 5505281Sroot } 5515423Swnj 5525423Swnj case SIOCRCVOOB: { 5535423Swnj struct mbuf *m = m_get(M_DONTWAIT); 5547627Ssam 5555423Swnj if (m == 0) { 5565423Swnj u.u_error = ENOBUFS; 5575423Swnj return; 5585423Swnj } 5595423Swnj m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; 5605423Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); 5617627Ssam *(char *)data = *mtod(m, char *); 5627627Ssam (void) m_free(m); 5635423Swnj return; 5645423Swnj } 5655423Swnj 5667627Ssam case SIOCATMARK: 5677627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 5685423Swnj return; 5696355Ssam 5706355Ssam /* routing table update calls */ 5716355Ssam case SIOCADDRT: 5726355Ssam case SIOCDELRT: 5736355Ssam if (!suser()) 5746355Ssam return; 5757627Ssam u.u_error = rtrequest(cmd, (struct rtentry *)data); 5766355Ssam return; 5776355Ssam 5785445Swnj /* type/protocol specific ioctls */ 5795423Swnj } 5805445Swnj u.u_error = EOPNOTSUPP; 5814786Swnj } 582