1*4971Swnj /* uipc_socket.c 4.8 81/11/20 */ 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; 784927Swnj (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 794786Swnj if (so->so_error) { 804890Swnj error = so->so_error; 81*4971Swnj (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); 97*4971Swnj (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 } 1214890Swnj if ((so->so_state & SS_ISDISCONNECTING) && 1224890Swnj (so->so_options & SO_NBIO)) { 1234890Swnj u.u_error = EINPROGRESS; 1244890Swnj splx(s); 1254890Swnj return; 1264890Swnj } 1274890Swnj while (so->so_state & SS_ISCONNECTED) 1284890Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 1294890Swnj } 1304890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1314890Swnj discard: 1324950Swnj so->so_state |= SS_USERGONE; 1334950Swnj sofree(so); 1344890Swnj splx(s); 1354829Swnj } 1364829Swnj 1374927Swnj sosplice(pso, so) 1384927Swnj struct socket *pso, *so; 1394927Swnj { 1404927Swnj 1414927Swnj COUNT(SOSPLICE); 1424927Swnj if (pso->so_proto->pr_family != PF_LOCAL) { 1434927Swnj struct socket *tso; 1444927Swnj tso = pso; pso = so; so = tso; 1454927Swnj } 1464927Swnj if (pso->so_proto->pr_family != PF_LOCAL) 1474927Swnj return (EOPNOTSUPP); 1484927Swnj /* check types and buffer space */ 1494927Swnj /* merge buffers */ 1504927Swnj return (0); 1514927Swnj } 1524927Swnj 1534916Swnj /*ARGSUSED*/ 1544890Swnj sostat(so, sb) 1554829Swnj struct socket *so; 1564890Swnj struct stat *sb; 1574829Swnj { 1584829Swnj 1594927Swnj COUNT(SOSTAT); 1604890Swnj return (EOPNOTSUPP); 1614829Swnj } 1624829Swnj 1634829Swnj /* 1644927Swnj * Accept connection on a socket. 1654927Swnj */ 1664927Swnj soaccept(so, asa) 1674927Swnj struct socket *so; 1684927Swnj struct sockaddr *asa; 1694927Swnj { 1704927Swnj int s = splnet(); 1714927Swnj int error; 1724927Swnj 1734927Swnj COUNT(SOACCEPT); 1744927Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 1754927Swnj error = EISCONN; 1764927Swnj goto bad; 1774927Swnj } 1784927Swnj if ((so->so_options & SO_ACCEPTCONN) == 0) { 1794927Swnj error = EINVAL; /* XXX */ 1804927Swnj goto bad; 1814927Swnj } 1824927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1834927Swnj bad: 1844927Swnj splx(s); 1854927Swnj return (error); 1864927Swnj } 1874927Swnj 1884927Swnj /* 1894890Swnj * Connect socket to a specified address. 1904890Swnj * If already connected or connecting, then avoid 1914890Swnj * the protocol entry, to keep its job simpler. 1924786Swnj */ 1934927Swnj soconnect(so, asa) 1944786Swnj struct socket *so; 1954927Swnj struct sockaddr *asa; 1964786Swnj { 1974890Swnj int s = splnet(); 1984890Swnj int error; 1994786Swnj 2004927Swnj COUNT(SOCONNECT); 2014890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2024890Swnj error = EISCONN; 2034890Swnj goto bad; 2044890Swnj } 2054927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2064890Swnj bad: 2074890Swnj splx(s); 2084890Swnj return (error); 2094786Swnj } 2104786Swnj 2114786Swnj /* 2124890Swnj * Disconnect from a socket. 2134890Swnj * Address parameter is from system call for later multicast 2144890Swnj * protocols. Check to make sure that connected and no disconnect 2154890Swnj * in progress (for protocol's sake), and then invoke protocol. 2164786Swnj */ 2174927Swnj sodisconnect(so, asa) 2184786Swnj struct socket *so; 2194927Swnj struct sockaddr *asa; 2204786Swnj { 2214890Swnj int s = splnet(); 2224890Swnj int error; 2234786Swnj 2244927Swnj COUNT(SODISCONNECT); 2254890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2264890Swnj error = ENOTCONN; 2274890Swnj goto bad; 2284890Swnj } 2294890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2304890Swnj error = EALREADY; 2314890Swnj goto bad; 2324890Swnj } 2334927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2344890Swnj bad: 2354890Swnj splx(s); 2364890Swnj return (error); 2374786Swnj } 2384786Swnj 2394786Swnj /* 2404890Swnj * Send on a socket. 2414890Swnj * If send must go all at once and message is larger than 2424890Swnj * send buffering, then hard error. 2434890Swnj * Lock against other senders. 2444890Swnj * If must go all at once and not enough room now, then 2454890Swnj * inform user that this would block and do nothing. 2464786Swnj */ 2474927Swnj sosend(so, asa) 2484786Swnj register struct socket *so; 2494927Swnj struct sockaddr *asa; 2504786Swnj { 2514890Swnj struct mbuf *top = 0; 2524890Swnj register struct mbuf *m, **mp = ⊤ 2534916Swnj register u_int len; 2544916Swnj int error = 0, space, s; 2554786Swnj 2564927Swnj COUNT(SOSEND); 2574890Swnj if (so->so_state & SS_CANTSENDMORE) 2584890Swnj return (EPIPE); 2594890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2604890Swnj return (EMSGSIZE); 2614890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2624890Swnj return (EWOULDBLOCK); 2634890Swnj sblock(&so->so_snd); 2644890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2654890Swnj 2664890Swnj s = splnet(); 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); 2784890Swnj if (error) { 2794890Swnj splx(s); 2804786Swnj goto release; 2814786Swnj } 2824890Swnj top = 0; 2834890Swnj mp = ⊤ 2844786Swnj } 2854890Swnj if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { 2864890Swnj if (so->so_options & SO_NBIO) 2874890Swnj snderr(EWOULDBLOCK); 2884890Swnj sbunlock(&so->so_snd); 2894890Swnj sbwait(&so->so_snd); 2904890Swnj splx(s); 2914786Swnj goto again; 2924786Swnj } 2934890Swnj splx(s); 2944916Swnj while (u.u_count && (space = sbspace(&so->so_snd)) > 0) { 2954890Swnj MGET(m, 1); 2964890Swnj if (m == NULL) { 2974890Swnj error = ENOBUFS; 2984890Swnj m_freem(top); 2994890Swnj goto release; 3004786Swnj } 3014916Swnj if (u.u_count >= PGSIZE && space >= NMBPG) { 3024890Swnj register struct mbuf *p; 3034890Swnj MPGET(p, 1); 3044890Swnj if (p == 0) 3054890Swnj goto nopages; 3064890Swnj m->m_off = (int)p - (int)m; 3074890Swnj len = PGSIZE; 3084890Swnj } else { 3094786Swnj nopages: 3104890Swnj m->m_off = MMINOFF; 3114890Swnj len = MIN(MLEN, u.u_count); 3124786Swnj } 3134890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 3144890Swnj m->m_len = len; 3154890Swnj *mp = m; 3164890Swnj mp = &m->m_next; 3174786Swnj } 3184890Swnj s = splnet(); 3194890Swnj goto again; 3204890Swnj 3214786Swnj release: 3224890Swnj sbunlock(&so->so_snd); 3234786Swnj return (error); 3244786Swnj } 3254786Swnj 3264927Swnj soreceive(so, asa) 3274786Swnj register struct socket *so; 3284927Swnj struct sockaddr *asa; 3294786Swnj { 3304786Swnj register struct mbuf *m, *n; 3314916Swnj u_int len; 3324890Swnj int eor, s, error = 0; 3334786Swnj 3344927Swnj COUNT(SORECEIVE); 3354890Swnj restart: 3364890Swnj sblock(&so->so_rcv); 3374890Swnj s = splnet(); 3384890Swnj 3394890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3404786Swnj if (so->so_rcv.sb_cc == 0) { 3414890Swnj if ((so->so_state & SS_ISCONNECTED) == 0 && 3424890Swnj (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3434890Swnj rcverr(ENOTCONN); 3444890Swnj if (so->so_state & SS_CANTRCVMORE) { 3454890Swnj splx(s); 3464890Swnj goto release; 3474890Swnj } 3484890Swnj if (so->so_options & SO_NBIO) 3494916Swnj rcverr (EWOULDBLOCK); 3504890Swnj sbunlock(&so->so_rcv); 351*4971Swnj sbwait(&so->so_rcv); 3524890Swnj goto restart; 3534786Swnj } 3544829Swnj m = so->so_rcv.sb_mb; 3554786Swnj if (m == 0) 3564786Swnj panic("receive"); 3574890Swnj if ((so->so_proto->pr_flags & PR_ADDR)) { 3584890Swnj so->so_rcv.sb_mb = m->m_next; 3594927Swnj if (asa) { 3604890Swnj so->so_rcv.sb_cc -= m->m_len; 3614927Swnj len = MIN(m->m_len, sizeof (struct sockaddr)); 3624927Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, len); 3634890Swnj } else 3644927Swnj bzero((caddr_t)asa, sizeof (*asa)); 3654890Swnj m = so->so_rcv.sb_mb; 3664890Swnj if (m == 0) 3674890Swnj panic("receive 2"); 3684890Swnj } 3694786Swnj eor = 0; 3704786Swnj do { 3714786Swnj len = MIN(m->m_len, u.u_count); 3724786Swnj if (len == m->m_len) { 3734786Swnj eor = (int)m->m_act; 3744890Swnj sbfree(&so->so_rcv, m); 3754786Swnj } 3764786Swnj splx(s); 3774786Swnj iomove(mtod(m, caddr_t), len, B_READ); 3784786Swnj s = splnet(); 3794786Swnj if (len == m->m_len) { 3804786Swnj MFREE(m, n); 3814786Swnj } else { 3824786Swnj m->m_off += len; 3834786Swnj m->m_len -= len; 3844829Swnj so->so_rcv.sb_cc -= len; 3854786Swnj } 3864829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 3874786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 3884786Swnj do { 3894786Swnj if (m == 0) 3904890Swnj panic("receive 3"); 3914890Swnj sbfree(&so->so_rcv, m); 3924786Swnj eor = (int)m->m_act; 3934786Swnj so->so_rcv.sb_mb = m->m_next; 3944786Swnj MFREE(m, n); 3954890Swnj m = n; 3964786Swnj } while (eor == 0); 3974890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 3984890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 3994890Swnj release: 4004916Swnj sbunlock(&so->so_rcv); 4014890Swnj splx(s); 4024916Swnj return (error); 4034786Swnj } 4044786Swnj 4054916Swnj /*ARGSUSED*/ 4064916Swnj soioctl(so, cmd, cmdp) 4074829Swnj register struct socket *so; 4084829Swnj int cmd; 4094829Swnj register caddr_t cmdp; 4104786Swnj { 4114786Swnj 4124927Swnj COUNT(SOIOCTL); 4134829Swnj switch (cmdp) { 4144829Swnj 4154829Swnj } 4164829Swnj switch (so->so_type) { 4174829Swnj 4184829Swnj case SOCK_STREAM: 4194829Swnj break; 4204829Swnj 4214829Swnj case SOCK_DGRAM: 4224829Swnj break; 4234829Swnj 4244829Swnj case SOCK_RDM: 4254829Swnj break; 4264829Swnj 4274829Swnj case SOCK_RAW: 4284829Swnj break; 4294829Swnj 4304829Swnj } 4314786Swnj } 432