1*5039Swnj /* uipc_socket.c 4.13 81/11/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" 164829Swnj #include "../net/inet.h" 174829Swnj #include "../net/inet_systm.h" 184786Swnj 194786Swnj /* 204890Swnj * Socket support routines. 214890Swnj * 224890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 234786Swnj */ 244786Swnj 254786Swnj /* 264786Swnj * Create a socket. 274786Swnj */ 284927Swnj socreate(aso, type, asp, asa, options) 294786Swnj struct socket **aso; 304786Swnj int type; 314927Swnj struct sockproto *asp; 324927Swnj struct sockaddr *asa; 334829Swnj int options; 344786Swnj { 354786Swnj register struct protosw *prp; 364786Swnj register struct socket *so; 374786Swnj struct mbuf *m; 384890Swnj int pf, proto, error; 394927Swnj COUNT(SOCREATE); 404786Swnj 414786Swnj /* 424890Swnj * Use process standard protocol/protocol family if none 434890Swnj * specified by address argument. 444786Swnj */ 454927Swnj if (asp == 0) { 464890Swnj pf = PF_INET; /* should be u.u_protof */ 474786Swnj proto = 0; 484786Swnj } else { 494927Swnj pf = asp->sp_family; 504927Swnj proto = asp->sp_protocol; 514786Swnj } 524786Swnj 534786Swnj /* 544890Swnj * If protocol specified, look for it, otherwise 554890Swnj * for a protocol of the correct type in the right family. 564890Swnj */ 574890Swnj if (proto) 584890Swnj prp = pffindproto(pf, proto); 594890Swnj else 604890Swnj prp = pffindtype(pf, type); 614890Swnj if (prp == 0) 624890Swnj return (EPROTONOSUPPORT); 634890Swnj 644890Swnj /* 654786Swnj * Get a socket structure. 664786Swnj */ 674890Swnj m = m_getclr(M_WAIT); 684786Swnj if (m == 0) 694786Swnj return (ENOBUFS); 704786Swnj so = mtod(m, struct socket *); 714829Swnj so->so_options = options; 724786Swnj 734786Swnj /* 744890Swnj * Attach protocol to socket, initializing 754890Swnj * and reserving resources. 764786Swnj */ 774786Swnj so->so_proto = prp; 784979Swnj error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 794979Swnj if (error) { 804971Swnj (void) m_free(dtom(so)); 814890Swnj return (error); 824786Swnj } 834786Swnj *aso = so; 844786Swnj return (0); 854786Swnj } 864786Swnj 874916Swnj sofree(so) 884916Swnj struct socket *so; 894916Swnj { 904916Swnj 914927Swnj COUNT(SOFREE); 924950Swnj if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) 934950Swnj return; 944950Swnj sbrelease(&so->so_snd); 954950Swnj sbrelease(&so->so_rcv); 964971Swnj (void) m_free(dtom(so)); 974916Swnj } 984916Swnj 994786Swnj /* 1004890Swnj * Close a socket on last file table reference removal. 1014890Swnj * Initiate disconnect if connected. 1024890Swnj * Free socket when disconnect complete. 1034829Swnj */ 1044890Swnj soclose(so) 1054829Swnj register struct socket *so; 1064829Swnj { 1074890Swnj int s = splnet(); /* conservative */ 1084829Swnj 1094927Swnj COUNT(SOCLOSE); 1104890Swnj if (so->so_pcb == 0) 1114890Swnj goto discard; 1124890Swnj if (so->so_state & SS_ISCONNECTED) { 1134890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1144927Swnj u.u_error = sodisconnect(so, (struct sockaddr *)0); 1154890Swnj if (u.u_error) { 1164890Swnj splx(s); 1174890Swnj return; 1184890Swnj } 1194890Swnj } 1204890Swnj if ((so->so_state & SS_ISDISCONNECTING) && 1214890Swnj (so->so_options & SO_NBIO)) { 1224890Swnj u.u_error = EINPROGRESS; 1234890Swnj splx(s); 1244890Swnj return; 1254890Swnj } 1264890Swnj while (so->so_state & SS_ISCONNECTED) 1274890Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 1284890Swnj } 1294890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1304890Swnj discard: 1314950Swnj so->so_state |= SS_USERGONE; 1324950Swnj sofree(so); 1334890Swnj splx(s); 1344829Swnj } 1354829Swnj 1364927Swnj sosplice(pso, so) 1374927Swnj struct socket *pso, *so; 1384927Swnj { 1394927Swnj 1404927Swnj COUNT(SOSPLICE); 1414927Swnj if (pso->so_proto->pr_family != PF_LOCAL) { 1424927Swnj struct socket *tso; 1434927Swnj tso = pso; pso = so; so = tso; 1444927Swnj } 1454927Swnj if (pso->so_proto->pr_family != PF_LOCAL) 1464927Swnj return (EOPNOTSUPP); 1474927Swnj /* check types and buffer space */ 1484927Swnj /* merge buffers */ 1494927Swnj return (0); 1504927Swnj } 1514927Swnj 1524916Swnj /*ARGSUSED*/ 1534890Swnj sostat(so, sb) 1544829Swnj struct socket *so; 1554890Swnj struct stat *sb; 1564829Swnj { 1574829Swnj 1584927Swnj COUNT(SOSTAT); 1594890Swnj return (EOPNOTSUPP); 1604829Swnj } 1614829Swnj 1624829Swnj /* 1634927Swnj * Accept connection on a socket. 1644927Swnj */ 1654927Swnj soaccept(so, asa) 1664927Swnj struct socket *so; 1674927Swnj struct sockaddr *asa; 1684927Swnj { 1694927Swnj int s = splnet(); 1704927Swnj int error; 1714927Swnj 1724927Swnj COUNT(SOACCEPT); 1734927Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 1744927Swnj error = EISCONN; 1754927Swnj goto bad; 1764927Swnj } 1774927Swnj if ((so->so_options & SO_ACCEPTCONN) == 0) { 1784927Swnj error = EINVAL; /* XXX */ 1794927Swnj goto bad; 1804927Swnj } 1814927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1824927Swnj bad: 1834927Swnj splx(s); 1844927Swnj return (error); 1854927Swnj } 1864927Swnj 1874927Swnj /* 1884890Swnj * Connect socket to a specified address. 1894890Swnj * If already connected or connecting, then avoid 1904890Swnj * the protocol entry, to keep its job simpler. 1914786Swnj */ 1924927Swnj soconnect(so, asa) 1934786Swnj struct socket *so; 1944927Swnj struct sockaddr *asa; 1954786Swnj { 1964890Swnj int s = splnet(); 1974890Swnj int error; 1984786Swnj 1994927Swnj COUNT(SOCONNECT); 2004890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2014890Swnj error = EISCONN; 2024890Swnj goto bad; 2034890Swnj } 2044927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2054890Swnj bad: 2064890Swnj splx(s); 2074890Swnj return (error); 2084786Swnj } 2094786Swnj 2104786Swnj /* 2114890Swnj * Disconnect from a socket. 2124890Swnj * Address parameter is from system call for later multicast 2134890Swnj * protocols. Check to make sure that connected and no disconnect 2144890Swnj * in progress (for protocol's sake), and then invoke protocol. 2154786Swnj */ 2164927Swnj sodisconnect(so, asa) 2174786Swnj struct socket *so; 2184927Swnj struct sockaddr *asa; 2194786Swnj { 2204890Swnj int s = splnet(); 2214890Swnj int error; 2224786Swnj 2234927Swnj COUNT(SODISCONNECT); 2244890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2254890Swnj error = ENOTCONN; 2264890Swnj goto bad; 2274890Swnj } 2284890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2294890Swnj error = EALREADY; 2304890Swnj goto bad; 2314890Swnj } 2324927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2334890Swnj bad: 2344890Swnj splx(s); 2354890Swnj return (error); 2364786Swnj } 2374786Swnj 2384786Swnj /* 2394890Swnj * Send on a socket. 2404890Swnj * If send must go all at once and message is larger than 2414890Swnj * send buffering, then hard error. 2424890Swnj * Lock against other senders. 2434890Swnj * If must go all at once and not enough room now, then 2444890Swnj * inform user that this would block and do nothing. 2454786Swnj */ 2464927Swnj sosend(so, asa) 2474786Swnj register struct socket *so; 2484927Swnj struct sockaddr *asa; 2494786Swnj { 2504890Swnj struct mbuf *top = 0; 2514890Swnj register struct mbuf *m, **mp = ⊤ 2524916Swnj register u_int len; 2534916Swnj int error = 0, space, s; 2544786Swnj 2554927Swnj COUNT(SOSEND); 2564890Swnj if (so->so_state & SS_CANTSENDMORE) 2574890Swnj return (EPIPE); 2584890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2594890Swnj return (EMSGSIZE); 2604890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2614890Swnj return (EWOULDBLOCK); 2624890Swnj sblock(&so->so_snd); 2634890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2644890Swnj 2654890Swnj s = splnet(); 266*5039Swnj nullchk("sosend in", so->so_snd.sb_mb); 2674890Swnj again: 2684890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2694890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2704890Swnj snderr(ENOTCONN); 2714927Swnj if (asa == 0) 2724890Swnj snderr(EDESTADDRREQ); 2734890Swnj } 2744890Swnj if (so->so_error) 2754890Swnj snderr(so->so_error); 2764890Swnj if (top) { 2774927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 278*5039Swnj nullchk("sosend after PRU_SEND", so->so_snd.sb_mb); 2794890Swnj if (error) { 2804890Swnj splx(s); 2814786Swnj goto release; 2824786Swnj } 2834890Swnj top = 0; 2844890Swnj mp = ⊤ 2854786Swnj } 2864979Swnj if (u.u_count == 0) { 2874979Swnj splx(s); 2884979Swnj goto release; 2894979Swnj } 2905018Swnj space = sbspace(&so->so_snd); 2915018Swnj if (space == 0 || sosendallatonce(so) && space < u.u_count) { 2924890Swnj if (so->so_options & SO_NBIO) 2934890Swnj snderr(EWOULDBLOCK); 2944890Swnj sbunlock(&so->so_snd); 2954890Swnj sbwait(&so->so_snd); 2964890Swnj splx(s); 2974786Swnj goto again; 2984786Swnj } 2994890Swnj splx(s); 3005018Swnj while (u.u_count && space > 0) { 3014890Swnj MGET(m, 1); 3024890Swnj if (m == NULL) { 3034890Swnj error = ENOBUFS; 3044890Swnj m_freem(top); 3054890Swnj goto release; 3064786Swnj } 3074916Swnj if (u.u_count >= PGSIZE && space >= NMBPG) { 3084890Swnj register struct mbuf *p; 3094890Swnj MPGET(p, 1); 3104890Swnj if (p == 0) 3114890Swnj goto nopages; 3124890Swnj m->m_off = (int)p - (int)m; 3134890Swnj len = PGSIZE; 3144890Swnj } else { 3154786Swnj nopages: 3164890Swnj m->m_off = MMINOFF; 3174890Swnj len = MIN(MLEN, u.u_count); 3184786Swnj } 3194890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 320*5039Swnj nullblk("sosend", m, len); 3214890Swnj m->m_len = len; 3224890Swnj *mp = m; 3234890Swnj mp = &m->m_next; 3245018Swnj space = sbspace(&so->so_snd); 3254786Swnj } 326*5039Swnj nullchk("sosend top", top); 3274890Swnj s = splnet(); 3284890Swnj goto again; 3294890Swnj 3304786Swnj release: 3314890Swnj sbunlock(&so->so_snd); 3324786Swnj return (error); 3334786Swnj } 3344786Swnj 3354927Swnj soreceive(so, asa) 3364786Swnj register struct socket *so; 3374927Swnj struct sockaddr *asa; 3384786Swnj { 3394786Swnj register struct mbuf *m, *n; 3404916Swnj u_int len; 3414890Swnj int eor, s, error = 0; 3424786Swnj 3434927Swnj COUNT(SORECEIVE); 3444890Swnj restart: 345*5039Swnj nullchk("soreceive restart", so->so_rcv.sb_mb); 346*5039Swnj for (m = so->so_rcv.sb_mb; m; m = m->m_next) 347*5039Swnj printf("%d ", m->m_len); 348*5039Swnj printf("\n"); 3494890Swnj sblock(&so->so_rcv); 3504890Swnj s = splnet(); 3514890Swnj 3524890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3534786Swnj if (so->so_rcv.sb_cc == 0) { 3544890Swnj if (so->so_state & SS_CANTRCVMORE) { 3554890Swnj splx(s); 3564890Swnj goto release; 3574890Swnj } 3585015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 3595015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3605015Sroot rcverr(ENOTCONN); 3614890Swnj if (so->so_options & SO_NBIO) 3624916Swnj rcverr (EWOULDBLOCK); 3634890Swnj sbunlock(&so->so_rcv); 3644971Swnj sbwait(&so->so_rcv); 3655012Swnj splx(s); 3664890Swnj goto restart; 3674786Swnj } 368*5039Swnj printf("soreceive about to\n"); 369*5039Swnj psndrcv(&so->so_snd, &so->so_rcv); 3704829Swnj m = so->so_rcv.sb_mb; 3714786Swnj if (m == 0) 3724786Swnj panic("receive"); 373*5039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 374*5039Swnj printf("m_len %d\n", m->m_len); 375*5039Swnj if (m->m_len != sizeof (struct sockaddr)) 376*5039Swnj panic("soreceive addr"); 377*5039Swnj if (asa) 378*5039Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 379*5039Swnj else 3804927Swnj bzero((caddr_t)asa, sizeof (*asa)); 381*5039Swnj so->so_rcv.sb_cc -= m->m_len; 382*5039Swnj so->so_rcv.sb_mbcnt -= MSIZE; 3835018Swnj m = m_free(m); 3844890Swnj if (m == 0) 3854890Swnj panic("receive 2"); 3865018Swnj so->so_rcv.sb_mb = m; 3874890Swnj } 3884786Swnj eor = 0; 389*5039Swnj printf("soreceive before receive loop\n"); 390*5039Swnj psndrcv(&so->so_snd, &so->so_rcv); 3914786Swnj do { 3924786Swnj len = MIN(m->m_len, u.u_count); 3934786Swnj if (len == m->m_len) { 3944786Swnj eor = (int)m->m_act; 3954890Swnj sbfree(&so->so_rcv, m); 3964786Swnj } 3974786Swnj splx(s); 398*5039Swnj nullblk("soreceive", m, len); 399*5039Swnj if (len) 400*5039Swnj printf("%o\n", *mtod(m, caddr_t)); 4014786Swnj iomove(mtod(m, caddr_t), len, B_READ); 4024786Swnj s = splnet(); 4034786Swnj if (len == m->m_len) { 4044786Swnj MFREE(m, n); 4055012Swnj so->so_rcv.sb_mb = n; 4064786Swnj } else { 4074786Swnj m->m_off += len; 4084786Swnj m->m_len -= len; 4094829Swnj so->so_rcv.sb_cc -= len; 4104786Swnj } 4114829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 412*5039Swnj printf("after receive loop\n"); 413*5039Swnj psndrcv(&so->so_snd, &so->so_rcv); 4144786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 4154786Swnj do { 4164786Swnj if (m == 0) 4174890Swnj panic("receive 3"); 4184890Swnj sbfree(&so->so_rcv, m); 4194786Swnj eor = (int)m->m_act; 4204786Swnj so->so_rcv.sb_mb = m->m_next; 4214786Swnj MFREE(m, n); 4224890Swnj m = n; 4234786Swnj } while (eor == 0); 424*5039Swnj printf("soreceive after drop remnants\n"); 425*5039Swnj psndrcv(&so->so_snd, &so->so_rcv); 4264890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 4274890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 428*5039Swnj nullchk("receive after PRU_RCVD", so->so_rcv.sb_mb); 4294890Swnj release: 4304916Swnj sbunlock(&so->so_rcv); 4314890Swnj splx(s); 4324916Swnj return (error); 4334786Swnj } 4344786Swnj 4354916Swnj /*ARGSUSED*/ 4364916Swnj soioctl(so, cmd, cmdp) 4374829Swnj register struct socket *so; 4384829Swnj int cmd; 4394829Swnj register caddr_t cmdp; 4404786Swnj { 4414786Swnj 4424927Swnj COUNT(SOIOCTL); 4434829Swnj switch (cmdp) { 4444829Swnj 4454829Swnj } 4464829Swnj switch (so->so_type) { 4474829Swnj 4484829Swnj case SOCK_STREAM: 4494829Swnj break; 4504829Swnj 4514829Swnj case SOCK_DGRAM: 4524829Swnj break; 4534829Swnj 4544829Swnj case SOCK_RDM: 4554829Swnj break; 4564829Swnj 4574829Swnj case SOCK_RAW: 4584829Swnj break; 4594829Swnj 4604829Swnj } 4614786Swnj } 462*5039Swnj 463*5039Swnj nullchk(where, m0) 464*5039Swnj char *where; 465*5039Swnj struct mbuf *m0; 466*5039Swnj { 467*5039Swnj register struct mbuf *m; 468*5039Swnj 469*5039Swnj for (m = m0; m; m = m->m_next) 470*5039Swnj if (nullany(mtod(m, caddr_t), m->m_len)) 471*5039Swnj goto bad; 472*5039Swnj return; 473*5039Swnj bad: 474*5039Swnj printf("nullchk: %s\n", where); 475*5039Swnj for (m = m0; m; m = m->m_next) 476*5039Swnj printf("\t%x len %d: %s\n", m, m->m_len, 477*5039Swnj nullany(mtod(m, caddr_t), m->m_len) ? "BAD" : "OK"); 478*5039Swnj } 479*5039Swnj 480*5039Swnj nullblk(where, m, len) 481*5039Swnj char *where; 482*5039Swnj struct mbuf *m; 483*5039Swnj int len; 484*5039Swnj { 485*5039Swnj 486*5039Swnj if (nullany(mtod(m, caddr_t), len)) 487*5039Swnj printf("nullblk: %s m=%x len=%d\n", where, m, len); 488*5039Swnj } 489*5039Swnj 490*5039Swnj nullany(cp, len) 491*5039Swnj char *cp; 492*5039Swnj int len; 493*5039Swnj { 494*5039Swnj for (; len > 0; len--) 495*5039Swnj if (*cp++ == 0) 496*5039Swnj return (0); /* XXX */ 497*5039Swnj return (0); 498*5039Swnj } 499