1*5358Sroot /* uipc_socket.c 4.22 82/01/07 */ 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" 194786Swnj 204786Swnj /* 214890Swnj * Socket support routines. 224890Swnj * 234890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 244786Swnj */ 254786Swnj 264786Swnj /* 274786Swnj * Create a socket. 284786Swnj */ 294927Swnj socreate(aso, type, asp, asa, options) 304786Swnj struct socket **aso; 314786Swnj int type; 324927Swnj struct sockproto *asp; 334927Swnj struct sockaddr *asa; 344829Swnj int options; 354786Swnj { 364786Swnj register struct protosw *prp; 374786Swnj register struct socket *so; 384786Swnj struct mbuf *m; 394890Swnj int pf, proto, error; 404927Swnj COUNT(SOCREATE); 414786Swnj 424786Swnj /* 434890Swnj * Use process standard protocol/protocol family if none 444890Swnj * specified by address argument. 454786Swnj */ 464927Swnj if (asp == 0) { 474890Swnj pf = PF_INET; /* should be u.u_protof */ 484786Swnj proto = 0; 494786Swnj } else { 504927Swnj pf = asp->sp_family; 514927Swnj proto = asp->sp_protocol; 524786Swnj } 534786Swnj 544786Swnj /* 554890Swnj * If protocol specified, look for it, otherwise 564890Swnj * for a protocol of the correct type in the right family. 574890Swnj */ 584890Swnj if (proto) 594890Swnj prp = pffindproto(pf, proto); 604890Swnj else 614890Swnj prp = pffindtype(pf, type); 624890Swnj if (prp == 0) 634890Swnj return (EPROTONOSUPPORT); 644890Swnj 654890Swnj /* 664786Swnj * Get a socket structure. 674786Swnj */ 684890Swnj m = m_getclr(M_WAIT); 694786Swnj if (m == 0) 704786Swnj return (ENOBUFS); 714786Swnj so = mtod(m, struct socket *); 724829Swnj so->so_options = options; 734786Swnj 744786Swnj /* 754890Swnj * Attach protocol to socket, initializing 764890Swnj * and reserving resources. 774786Swnj */ 784786Swnj so->so_proto = prp; 794979Swnj error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 804979Swnj if (error) { 814971Swnj (void) m_free(dtom(so)); 824890Swnj return (error); 834786Swnj } 844786Swnj *aso = so; 854786Swnj return (0); 864786Swnj } 874786Swnj 884916Swnj sofree(so) 894916Swnj struct socket *so; 904916Swnj { 914916Swnj 924927Swnj COUNT(SOFREE); 934950Swnj if (so->so_pcb || (so->so_state & SS_USERGONE) == 0) 944950Swnj return; 954950Swnj sbrelease(&so->so_snd); 964950Swnj sbrelease(&so->so_rcv); 974971Swnj (void) m_free(dtom(so)); 984916Swnj } 994916Swnj 1004786Swnj /* 1014890Swnj * Close a socket on last file table reference removal. 1024890Swnj * Initiate disconnect if connected. 1034890Swnj * Free socket when disconnect complete. 1044829Swnj */ 1054890Swnj soclose(so) 1064829Swnj register struct socket *so; 1074829Swnj { 1084890Swnj int s = splnet(); /* conservative */ 1094829Swnj 1104927Swnj COUNT(SOCLOSE); 1114890Swnj if (so->so_pcb == 0) 1124890Swnj goto discard; 1134890Swnj if (so->so_state & SS_ISCONNECTED) { 1144890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1154927Swnj u.u_error = sodisconnect(so, (struct sockaddr *)0); 1164890Swnj if (u.u_error) { 1174890Swnj splx(s); 1184890Swnj return; 1194890Swnj } 1204890Swnj } 1215281Sroot if (so->so_options & SO_LETDATADRAIN) { 1225281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 1235281Sroot (so->so_options & SO_NBIO)) { 1245281Sroot u.u_error = EINPROGRESS; 1255281Sroot splx(s); 1265281Sroot return; 1275281Sroot } 1285281Sroot while (so->so_state & SS_ISCONNECTED) 1295281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1304890Swnj } 1314890Swnj } 1324890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1334890Swnj discard: 1344950Swnj so->so_state |= SS_USERGONE; 1354950Swnj sofree(so); 1364890Swnj splx(s); 1374829Swnj } 1384829Swnj 1394927Swnj sosplice(pso, so) 1404927Swnj struct socket *pso, *so; 1414927Swnj { 1424927Swnj 1434927Swnj COUNT(SOSPLICE); 1445168Swnj if (pso->so_proto->pr_family != PF_UNIX) { 1454927Swnj struct socket *tso; 1464927Swnj tso = pso; pso = so; so = tso; 1474927Swnj } 1485168Swnj if (pso->so_proto->pr_family != PF_UNIX) 1494927Swnj return (EOPNOTSUPP); 1504927Swnj /* check types and buffer space */ 1514927Swnj /* merge buffers */ 1524927Swnj return (0); 1534927Swnj } 1544927Swnj 1554916Swnj /*ARGSUSED*/ 1564890Swnj sostat(so, sb) 1574829Swnj struct socket *so; 1584890Swnj struct stat *sb; 1594829Swnj { 1604829Swnj 1614927Swnj COUNT(SOSTAT); 1625303Sroot bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 1635303Sroot return (0); /* XXX */ 1644829Swnj } 1654829Swnj 1664829Swnj /* 1674927Swnj * Accept connection on a socket. 1684927Swnj */ 1694927Swnj soaccept(so, asa) 1704927Swnj struct socket *so; 1714927Swnj struct sockaddr *asa; 1724927Swnj { 1734927Swnj int s = splnet(); 1744927Swnj int error; 1754927Swnj 1764927Swnj COUNT(SOACCEPT); 1774927Swnj if ((so->so_options & SO_ACCEPTCONN) == 0) { 1784927Swnj error = EINVAL; /* XXX */ 1794927Swnj goto bad; 1804927Swnj } 1815265Swnj if ((so->so_state & SS_CONNAWAITING) == 0) { 1825265Swnj error = ENOTCONN; 1835265Swnj goto bad; 1845265Swnj } 1855265Swnj so->so_state &= ~SS_CONNAWAITING; 1864927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1874927Swnj bad: 1884927Swnj splx(s); 1894927Swnj return (error); 1904927Swnj } 1914927Swnj 1924927Swnj /* 1934890Swnj * Connect socket to a specified address. 1944890Swnj * If already connected or connecting, then avoid 1954890Swnj * the protocol entry, to keep its job simpler. 1964786Swnj */ 1974927Swnj soconnect(so, asa) 1984786Swnj struct socket *so; 1994927Swnj struct sockaddr *asa; 2004786Swnj { 2014890Swnj int s = splnet(); 2024890Swnj int error; 2034786Swnj 2044927Swnj COUNT(SOCONNECT); 2054890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2064890Swnj error = EISCONN; 2074890Swnj goto bad; 2084890Swnj } 2094927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2104890Swnj bad: 2114890Swnj splx(s); 2124890Swnj return (error); 2134786Swnj } 2144786Swnj 2154786Swnj /* 2164890Swnj * Disconnect from a socket. 2174890Swnj * Address parameter is from system call for later multicast 2184890Swnj * protocols. Check to make sure that connected and no disconnect 2194890Swnj * in progress (for protocol's sake), and then invoke protocol. 2204786Swnj */ 2214927Swnj sodisconnect(so, asa) 2224786Swnj struct socket *so; 2234927Swnj struct sockaddr *asa; 2244786Swnj { 2254890Swnj int s = splnet(); 2264890Swnj int error; 2274786Swnj 2284927Swnj COUNT(SODISCONNECT); 2294890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2304890Swnj error = ENOTCONN; 2314890Swnj goto bad; 2324890Swnj } 2334890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2344890Swnj error = EALREADY; 2354890Swnj goto bad; 2364890Swnj } 2374927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2384890Swnj bad: 2394890Swnj splx(s); 2404890Swnj return (error); 2414786Swnj } 2424786Swnj 2434786Swnj /* 2444890Swnj * Send on a socket. 2454890Swnj * If send must go all at once and message is larger than 2464890Swnj * send buffering, then hard error. 2474890Swnj * Lock against other senders. 2484890Swnj * If must go all at once and not enough room now, then 2494890Swnj * inform user that this would block and do nothing. 2504786Swnj */ 2514927Swnj sosend(so, asa) 2524786Swnj register struct socket *so; 2534927Swnj struct sockaddr *asa; 2544786Swnj { 2554890Swnj struct mbuf *top = 0; 2564890Swnj register struct mbuf *m, **mp = ⊤ 2574916Swnj register u_int len; 2584916Swnj int error = 0, space, s; 2594786Swnj 2604927Swnj COUNT(SOSEND); 2614890Swnj if (so->so_state & SS_CANTSENDMORE) 2624890Swnj return (EPIPE); 2634890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2644890Swnj return (EMSGSIZE); 2654890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2664890Swnj return (EWOULDBLOCK); 2674890Swnj sblock(&so->so_snd); 2684890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2694890Swnj 2704890Swnj s = splnet(); 2714890Swnj again: 2725168Swnj if (so->so_error) { 2735168Swnj error = so->so_error; 2745168Swnj so->so_error = 0; 2755168Swnj splx(s); 2765168Swnj goto release; 2775168Swnj } 2784890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2794890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2804890Swnj snderr(ENOTCONN); 2814927Swnj if (asa == 0) 2824890Swnj snderr(EDESTADDRREQ); 2834890Swnj } 2844890Swnj if (top) { 2854927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 2864890Swnj if (error) { 2874890Swnj splx(s); 2884786Swnj goto release; 2894786Swnj } 2904890Swnj top = 0; 2914890Swnj mp = ⊤ 2924786Swnj } 2934979Swnj if (u.u_count == 0) { 2944979Swnj splx(s); 2954979Swnj goto release; 2964979Swnj } 2975018Swnj space = sbspace(&so->so_snd); 2985018Swnj if (space == 0 || sosendallatonce(so) && space < u.u_count) { 2994890Swnj if (so->so_options & SO_NBIO) 3004890Swnj snderr(EWOULDBLOCK); 3014890Swnj sbunlock(&so->so_snd); 3024890Swnj sbwait(&so->so_snd); 3034890Swnj splx(s); 3044786Swnj goto again; 3054786Swnj } 3064890Swnj splx(s); 3075018Swnj while (u.u_count && space > 0) { 3084890Swnj MGET(m, 1); 3094890Swnj if (m == NULL) { 3104890Swnj error = ENOBUFS; 3114890Swnj m_freem(top); 3124890Swnj goto release; 3134786Swnj } 3145095Swnj if (u.u_count >= CLBYTES && space >= CLBYTES) { 3154890Swnj register struct mbuf *p; 3165095Swnj MCLGET(p, 1); 3174890Swnj if (p == 0) 3184890Swnj goto nopages; 3194890Swnj m->m_off = (int)p - (int)m; 3205095Swnj len = CLBYTES; 3214890Swnj } else { 3224786Swnj nopages: 3234890Swnj m->m_off = MMINOFF; 3244890Swnj len = MIN(MLEN, u.u_count); 3254786Swnj } 3264890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 3274890Swnj m->m_len = len; 3284890Swnj *mp = m; 3294890Swnj mp = &m->m_next; 3305018Swnj space = sbspace(&so->so_snd); 3314786Swnj } 3324890Swnj s = splnet(); 3334890Swnj goto again; 3344890Swnj 3354786Swnj release: 3364890Swnj sbunlock(&so->so_snd); 3374786Swnj return (error); 3384786Swnj } 3394786Swnj 3404927Swnj soreceive(so, asa) 3414786Swnj register struct socket *so; 3424927Swnj struct sockaddr *asa; 3434786Swnj { 3444786Swnj register struct mbuf *m, *n; 3454916Swnj u_int len; 3464890Swnj int eor, s, error = 0; 3474786Swnj 3484927Swnj COUNT(SORECEIVE); 3494890Swnj restart: 3504890Swnj sblock(&so->so_rcv); 3514890Swnj s = splnet(); 3524890Swnj 3534890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3544786Swnj if (so->so_rcv.sb_cc == 0) { 3555168Swnj if (so->so_error) { 3565168Swnj error = so->so_error; 3575168Swnj so->so_error = 0; 3585168Swnj splx(s); 3595168Swnj goto release; 3605168Swnj } 3614890Swnj if (so->so_state & SS_CANTRCVMORE) { 3624890Swnj splx(s); 3634890Swnj goto release; 3644890Swnj } 3655015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 3665015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3675015Sroot rcverr(ENOTCONN); 3684890Swnj if (so->so_options & SO_NBIO) 3695168Swnj rcverr(EWOULDBLOCK); 3704890Swnj sbunlock(&so->so_rcv); 3714971Swnj sbwait(&so->so_rcv); 3725012Swnj splx(s); 3734890Swnj goto restart; 3744786Swnj } 3754829Swnj m = so->so_rcv.sb_mb; 3764786Swnj if (m == 0) 3774786Swnj panic("receive"); 3785039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 3795039Swnj if (m->m_len != sizeof (struct sockaddr)) 3805039Swnj panic("soreceive addr"); 3815039Swnj if (asa) 3825039Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 3835039Swnj so->so_rcv.sb_cc -= m->m_len; 3845039Swnj so->so_rcv.sb_mbcnt -= MSIZE; 3855018Swnj m = m_free(m); 3864890Swnj if (m == 0) 3874890Swnj panic("receive 2"); 3885018Swnj so->so_rcv.sb_mb = m; 3894890Swnj } 3904786Swnj eor = 0; 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); 396*5358Sroot so->so_rcv.sb_mb = m->m_next; 3974786Swnj } 3984786Swnj splx(s); 3994786Swnj iomove(mtod(m, caddr_t), len, B_READ); 4004786Swnj s = splnet(); 4014786Swnj if (len == m->m_len) { 4024786Swnj MFREE(m, n); 4034786Swnj } else { 4044786Swnj m->m_off += len; 4054786Swnj m->m_len -= len; 4064829Swnj so->so_rcv.sb_cc -= len; 4074786Swnj } 4084829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 4094786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 4104786Swnj do { 4114786Swnj if (m == 0) 4124890Swnj panic("receive 3"); 4134890Swnj sbfree(&so->so_rcv, m); 4144786Swnj eor = (int)m->m_act; 4154786Swnj so->so_rcv.sb_mb = m->m_next; 4164786Swnj MFREE(m, n); 4174890Swnj m = n; 4184786Swnj } while (eor == 0); 4194890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 4204890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 4214890Swnj release: 4224916Swnj sbunlock(&so->so_rcv); 4234890Swnj splx(s); 4244916Swnj return (error); 4254786Swnj } 4264786Swnj 4274916Swnj /*ARGSUSED*/ 4284916Swnj soioctl(so, cmd, cmdp) 4294829Swnj register struct socket *so; 4304829Swnj int cmd; 4314829Swnj register caddr_t cmdp; 4324786Swnj { 4334786Swnj 4344927Swnj COUNT(SOIOCTL); 435*5358Sroot switch (cmd) { 4364829Swnj 4375281Sroot case SIOCDONE: { 4385281Sroot int flags; 4395281Sroot if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { 4405281Sroot u.u_error = EFAULT; 4415281Sroot return; 4425281Sroot } 4435281Sroot if (flags & FREAD) { 4445281Sroot int s = splimp(); 4455281Sroot socantrcvmore(so); 4465281Sroot sbflush(&so->so_rcv); 4475281Sroot } 4485281Sroot if (flags & FWRITE) 449*5358Sroot u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, (struct mbuf *)0, 0); 4505281Sroot return; 4514829Swnj } 4525281Sroot 4535281Sroot } 4544829Swnj switch (so->so_type) { 4554829Swnj 4564829Swnj case SOCK_STREAM: 4574829Swnj break; 4584829Swnj 4594829Swnj case SOCK_DGRAM: 4604829Swnj break; 4614829Swnj 4624829Swnj case SOCK_RDM: 4634829Swnj break; 4644829Swnj 4654829Swnj case SOCK_RAW: 4664829Swnj break; 4674829Swnj 4684829Swnj } 4694786Swnj } 470