1*5281Sroot /* uipc_socket.c 4.20 81/12/21 */ 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" 16*5281Sroot #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 } 121*5281Sroot if (so->so_options & SO_LETDATADRAIN) { 122*5281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 123*5281Sroot (so->so_options & SO_NBIO)) { 124*5281Sroot u.u_error = EINPROGRESS; 125*5281Sroot splx(s); 126*5281Sroot return; 127*5281Sroot } 128*5281Sroot while (so->so_state & SS_ISCONNECTED) 129*5281Sroot 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); 1624890Swnj return (EOPNOTSUPP); 1634829Swnj } 1644829Swnj 1654829Swnj /* 1664927Swnj * Accept connection on a socket. 1674927Swnj */ 1684927Swnj soaccept(so, asa) 1694927Swnj struct socket *so; 1704927Swnj struct sockaddr *asa; 1714927Swnj { 1724927Swnj int s = splnet(); 1734927Swnj int error; 1744927Swnj 1754927Swnj COUNT(SOACCEPT); 1764927Swnj if ((so->so_options & SO_ACCEPTCONN) == 0) { 1774927Swnj error = EINVAL; /* XXX */ 1784927Swnj goto bad; 1794927Swnj } 1805265Swnj if ((so->so_state & SS_CONNAWAITING) == 0) { 1815265Swnj error = ENOTCONN; 1825265Swnj goto bad; 1835265Swnj } 1845265Swnj so->so_state &= ~SS_CONNAWAITING; 1854927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1864927Swnj bad: 1874927Swnj splx(s); 1884927Swnj return (error); 1894927Swnj } 1904927Swnj 1914927Swnj /* 1924890Swnj * Connect socket to a specified address. 1934890Swnj * If already connected or connecting, then avoid 1944890Swnj * the protocol entry, to keep its job simpler. 1954786Swnj */ 1964927Swnj soconnect(so, asa) 1974786Swnj struct socket *so; 1984927Swnj struct sockaddr *asa; 1994786Swnj { 2004890Swnj int s = splnet(); 2014890Swnj int error; 2024786Swnj 2034927Swnj COUNT(SOCONNECT); 2044890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2054890Swnj error = EISCONN; 2064890Swnj goto bad; 2074890Swnj } 2084927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2094890Swnj bad: 2104890Swnj splx(s); 2114890Swnj return (error); 2124786Swnj } 2134786Swnj 2144786Swnj /* 2154890Swnj * Disconnect from a socket. 2164890Swnj * Address parameter is from system call for later multicast 2174890Swnj * protocols. Check to make sure that connected and no disconnect 2184890Swnj * in progress (for protocol's sake), and then invoke protocol. 2194786Swnj */ 2204927Swnj sodisconnect(so, asa) 2214786Swnj struct socket *so; 2224927Swnj struct sockaddr *asa; 2234786Swnj { 2244890Swnj int s = splnet(); 2254890Swnj int error; 2264786Swnj 2274927Swnj COUNT(SODISCONNECT); 2284890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2294890Swnj error = ENOTCONN; 2304890Swnj goto bad; 2314890Swnj } 2324890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2334890Swnj error = EALREADY; 2344890Swnj goto bad; 2354890Swnj } 2364927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2374890Swnj bad: 2384890Swnj splx(s); 2394890Swnj return (error); 2404786Swnj } 2414786Swnj 2424786Swnj /* 2434890Swnj * Send on a socket. 2444890Swnj * If send must go all at once and message is larger than 2454890Swnj * send buffering, then hard error. 2464890Swnj * Lock against other senders. 2474890Swnj * If must go all at once and not enough room now, then 2484890Swnj * inform user that this would block and do nothing. 2494786Swnj */ 2504927Swnj sosend(so, asa) 2514786Swnj register struct socket *so; 2524927Swnj struct sockaddr *asa; 2534786Swnj { 2544890Swnj struct mbuf *top = 0; 2554890Swnj register struct mbuf *m, **mp = ⊤ 2564916Swnj register u_int len; 2574916Swnj int error = 0, space, s; 2584786Swnj 2594927Swnj COUNT(SOSEND); 2604890Swnj if (so->so_state & SS_CANTSENDMORE) 2614890Swnj return (EPIPE); 2624890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2634890Swnj return (EMSGSIZE); 2644890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2654890Swnj return (EWOULDBLOCK); 2664890Swnj sblock(&so->so_snd); 2674890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2684890Swnj 2694890Swnj s = splnet(); 2704890Swnj again: 2715168Swnj if (so->so_error) { 2725168Swnj error = so->so_error; 2735168Swnj so->so_error = 0; 2745168Swnj splx(s); 2755168Swnj goto release; 2765168Swnj } 2774890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2784890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2794890Swnj snderr(ENOTCONN); 2804927Swnj if (asa == 0) 2814890Swnj snderr(EDESTADDRREQ); 2824890Swnj } 2834890Swnj if (top) { 2844927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 2854890Swnj if (error) { 2864890Swnj splx(s); 2874786Swnj goto release; 2884786Swnj } 2894890Swnj top = 0; 2904890Swnj mp = ⊤ 2914786Swnj } 2924979Swnj if (u.u_count == 0) { 2934979Swnj splx(s); 2944979Swnj goto release; 2954979Swnj } 2965018Swnj space = sbspace(&so->so_snd); 2975018Swnj if (space == 0 || sosendallatonce(so) && space < u.u_count) { 2984890Swnj if (so->so_options & SO_NBIO) 2994890Swnj snderr(EWOULDBLOCK); 3004890Swnj sbunlock(&so->so_snd); 3014890Swnj sbwait(&so->so_snd); 3024890Swnj splx(s); 3034786Swnj goto again; 3044786Swnj } 3054890Swnj splx(s); 3065018Swnj while (u.u_count && space > 0) { 3074890Swnj MGET(m, 1); 3084890Swnj if (m == NULL) { 3094890Swnj error = ENOBUFS; 3104890Swnj m_freem(top); 3114890Swnj goto release; 3124786Swnj } 3135095Swnj if (u.u_count >= CLBYTES && space >= CLBYTES) { 3144890Swnj register struct mbuf *p; 3155095Swnj MCLGET(p, 1); 3164890Swnj if (p == 0) 3174890Swnj goto nopages; 3184890Swnj m->m_off = (int)p - (int)m; 3195095Swnj len = CLBYTES; 3204890Swnj } else { 3214786Swnj nopages: 3224890Swnj m->m_off = MMINOFF; 3234890Swnj len = MIN(MLEN, u.u_count); 3244786Swnj } 3254890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 3264890Swnj m->m_len = len; 3274890Swnj *mp = m; 3284890Swnj mp = &m->m_next; 3295018Swnj space = sbspace(&so->so_snd); 3304786Swnj } 3314890Swnj s = splnet(); 3324890Swnj goto again; 3334890Swnj 3344786Swnj release: 3354890Swnj sbunlock(&so->so_snd); 3364786Swnj return (error); 3374786Swnj } 3384786Swnj 3394927Swnj soreceive(so, asa) 3404786Swnj register struct socket *so; 3414927Swnj struct sockaddr *asa; 3424786Swnj { 3434786Swnj register struct mbuf *m, *n; 3444916Swnj u_int len; 3454890Swnj int eor, s, error = 0; 3464786Swnj 3474927Swnj COUNT(SORECEIVE); 3484890Swnj restart: 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) { 3545168Swnj if (so->so_error) { 3555168Swnj error = so->so_error; 3565168Swnj so->so_error = 0; 3575168Swnj splx(s); 3585168Swnj goto release; 3595168Swnj } 3604890Swnj if (so->so_state & SS_CANTRCVMORE) { 3614890Swnj splx(s); 3624890Swnj goto release; 3634890Swnj } 3645015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 3655015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3665015Sroot rcverr(ENOTCONN); 3674890Swnj if (so->so_options & SO_NBIO) 3685168Swnj rcverr(EWOULDBLOCK); 3694890Swnj sbunlock(&so->so_rcv); 3704971Swnj sbwait(&so->so_rcv); 3715012Swnj splx(s); 3724890Swnj goto restart; 3734786Swnj } 3744829Swnj m = so->so_rcv.sb_mb; 3754786Swnj if (m == 0) 3764786Swnj panic("receive"); 3775039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 3785039Swnj if (m->m_len != sizeof (struct sockaddr)) 3795039Swnj panic("soreceive addr"); 3805039Swnj if (asa) 3815039Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 3825039Swnj so->so_rcv.sb_cc -= m->m_len; 3835039Swnj so->so_rcv.sb_mbcnt -= MSIZE; 3845018Swnj m = m_free(m); 3854890Swnj if (m == 0) 3864890Swnj panic("receive 2"); 3875018Swnj so->so_rcv.sb_mb = m; 3884890Swnj } 3894786Swnj eor = 0; 3904786Swnj do { 3914786Swnj len = MIN(m->m_len, u.u_count); 3924786Swnj if (len == m->m_len) { 3934786Swnj eor = (int)m->m_act; 3944890Swnj sbfree(&so->so_rcv, m); 3954786Swnj } 3964786Swnj splx(s); 3974786Swnj iomove(mtod(m, caddr_t), len, B_READ); 3984786Swnj s = splnet(); 3994786Swnj if (len == m->m_len) { 4004786Swnj MFREE(m, n); 4015012Swnj so->so_rcv.sb_mb = n; 4024786Swnj } else { 4034786Swnj m->m_off += len; 4044786Swnj m->m_len -= len; 4054829Swnj so->so_rcv.sb_cc -= len; 4064786Swnj } 4074829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 4084786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 4094786Swnj do { 4104786Swnj if (m == 0) 4114890Swnj panic("receive 3"); 4124890Swnj sbfree(&so->so_rcv, m); 4134786Swnj eor = (int)m->m_act; 4144786Swnj so->so_rcv.sb_mb = m->m_next; 4154786Swnj MFREE(m, n); 4164890Swnj m = n; 4174786Swnj } while (eor == 0); 4184890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 4194890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 4204890Swnj release: 4214916Swnj sbunlock(&so->so_rcv); 4224890Swnj splx(s); 4234916Swnj return (error); 4244786Swnj } 4254786Swnj 4264916Swnj /*ARGSUSED*/ 4274916Swnj soioctl(so, cmd, cmdp) 4284829Swnj register struct socket *so; 4294829Swnj int cmd; 4304829Swnj register caddr_t cmdp; 4314786Swnj { 4324786Swnj 4334927Swnj COUNT(SOIOCTL); 4344829Swnj switch (cmdp) { 4354829Swnj 436*5281Sroot case SIOCDONE: { 437*5281Sroot int flags; 438*5281Sroot if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) { 439*5281Sroot u.u_error = EFAULT; 440*5281Sroot return; 441*5281Sroot } 442*5281Sroot if (flags & FREAD) { 443*5281Sroot int s = splimp(); 444*5281Sroot socantrcvmore(so); 445*5281Sroot sbflush(&so->so_rcv); 446*5281Sroot } 447*5281Sroot if (flags & FWRITE) 448*5281Sroot (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, (struct mbuf *)0, 0); 449*5281Sroot return; 4504829Swnj } 451*5281Sroot 452*5281Sroot } 4534829Swnj switch (so->so_type) { 4544829Swnj 4554829Swnj case SOCK_STREAM: 4564829Swnj break; 4574829Swnj 4584829Swnj case SOCK_DGRAM: 4594829Swnj break; 4604829Swnj 4614829Swnj case SOCK_RDM: 4624829Swnj break; 4634829Swnj 4644829Swnj case SOCK_RAW: 4654829Swnj break; 4664829Swnj 4674829Swnj } 4684786Swnj } 469