1*4927Swnj /* uipc_socket.c 4.6 81/11/18 */ 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 */ 28*4927Swnj socreate(aso, type, asp, asa, options) 294786Swnj struct socket **aso; 304786Swnj int type; 31*4927Swnj struct sockproto *asp; 32*4927Swnj 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; 39*4927Swnj COUNT(SOCREATE); 404786Swnj 414786Swnj /* 424890Swnj * Use process standard protocol/protocol family if none 434890Swnj * specified by address argument. 444786Swnj */ 45*4927Swnj if (asp == 0) { 464890Swnj pf = PF_INET; /* should be u.u_protof */ 474786Swnj proto = 0; 484786Swnj } else { 49*4927Swnj pf = asp->sp_family; 50*4927Swnj 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; 78*4927Swnj (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 794786Swnj if (so->so_error) { 804890Swnj error = so->so_error; 814786Swnj 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 92*4927Swnj COUNT(SOFREE); 934916Swnj m_free(dtom(so)); 944916Swnj } 954916Swnj 964786Swnj /* 974890Swnj * Close a socket on last file table reference removal. 984890Swnj * Initiate disconnect if connected. 994890Swnj * Free socket when disconnect complete. 1004829Swnj */ 1014890Swnj soclose(so) 1024829Swnj register struct socket *so; 1034829Swnj { 1044890Swnj int s = splnet(); /* conservative */ 1054829Swnj 106*4927Swnj COUNT(SOCLOSE); 1074890Swnj if (so->so_pcb == 0) 1084890Swnj goto discard; 1094890Swnj if (so->so_state & SS_ISCONNECTED) { 1104890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 111*4927Swnj u.u_error = sodisconnect(so, (struct sockaddr *)0); 1124890Swnj if (u.u_error) { 1134890Swnj splx(s); 1144890Swnj return; 1154890Swnj } 1164890Swnj } 1174890Swnj if ((so->so_state & SS_ISDISCONNECTING) && 1184890Swnj (so->so_options & SO_NBIO)) { 1194890Swnj u.u_error = EINPROGRESS; 1204890Swnj splx(s); 1214890Swnj return; 1224890Swnj } 1234890Swnj while (so->so_state & SS_ISCONNECTED) 1244890Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 1254890Swnj } 1264890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1274890Swnj discard: 1284890Swnj if (so->so_pcb == 0) 1294890Swnj sofree(so); 1304890Swnj splx(s); 1314829Swnj } 1324829Swnj 133*4927Swnj sosplice(pso, so) 134*4927Swnj struct socket *pso, *so; 135*4927Swnj { 136*4927Swnj 137*4927Swnj COUNT(SOSPLICE); 138*4927Swnj if (pso->so_proto->pr_family != PF_LOCAL) { 139*4927Swnj struct socket *tso; 140*4927Swnj tso = pso; pso = so; so = tso; 141*4927Swnj } 142*4927Swnj if (pso->so_proto->pr_family != PF_LOCAL) 143*4927Swnj return (EOPNOTSUPP); 144*4927Swnj /* check types and buffer space */ 145*4927Swnj /* merge buffers */ 146*4927Swnj return (0); 147*4927Swnj } 148*4927Swnj 1494916Swnj /*ARGSUSED*/ 1504890Swnj sostat(so, sb) 1514829Swnj struct socket *so; 1524890Swnj struct stat *sb; 1534829Swnj { 1544829Swnj 155*4927Swnj COUNT(SOSTAT); 1564890Swnj return (EOPNOTSUPP); 1574829Swnj } 1584829Swnj 1594829Swnj /* 160*4927Swnj * Accept connection on a socket. 161*4927Swnj */ 162*4927Swnj soaccept(so, asa) 163*4927Swnj struct socket *so; 164*4927Swnj struct sockaddr *asa; 165*4927Swnj { 166*4927Swnj int s = splnet(); 167*4927Swnj int error; 168*4927Swnj 169*4927Swnj COUNT(SOACCEPT); 170*4927Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 171*4927Swnj error = EISCONN; 172*4927Swnj goto bad; 173*4927Swnj } 174*4927Swnj if ((so->so_options & SO_ACCEPTCONN) == 0) { 175*4927Swnj error = EINVAL; /* XXX */ 176*4927Swnj goto bad; 177*4927Swnj } 178*4927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 179*4927Swnj bad: 180*4927Swnj splx(s); 181*4927Swnj return (error); 182*4927Swnj } 183*4927Swnj 184*4927Swnj /* 1854890Swnj * Connect socket to a specified address. 1864890Swnj * If already connected or connecting, then avoid 1874890Swnj * the protocol entry, to keep its job simpler. 1884786Swnj */ 189*4927Swnj soconnect(so, asa) 1904786Swnj struct socket *so; 191*4927Swnj struct sockaddr *asa; 1924786Swnj { 1934890Swnj int s = splnet(); 1944890Swnj int error; 1954786Swnj 196*4927Swnj COUNT(SOCONNECT); 1974890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 1984890Swnj error = EISCONN; 1994890Swnj goto bad; 2004890Swnj } 201*4927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2024890Swnj bad: 2034890Swnj splx(s); 2044890Swnj return (error); 2054786Swnj } 2064786Swnj 2074786Swnj /* 2084890Swnj * Disconnect from a socket. 2094890Swnj * Address parameter is from system call for later multicast 2104890Swnj * protocols. Check to make sure that connected and no disconnect 2114890Swnj * in progress (for protocol's sake), and then invoke protocol. 2124786Swnj */ 213*4927Swnj sodisconnect(so, asa) 2144786Swnj struct socket *so; 215*4927Swnj struct sockaddr *asa; 2164786Swnj { 2174890Swnj int s = splnet(); 2184890Swnj int error; 2194786Swnj 220*4927Swnj COUNT(SODISCONNECT); 2214890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2224890Swnj error = ENOTCONN; 2234890Swnj goto bad; 2244890Swnj } 2254890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2264890Swnj error = EALREADY; 2274890Swnj goto bad; 2284890Swnj } 229*4927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2304890Swnj bad: 2314890Swnj splx(s); 2324890Swnj return (error); 2334786Swnj } 2344786Swnj 2354786Swnj /* 2364890Swnj * Send on a socket. 2374890Swnj * If send must go all at once and message is larger than 2384890Swnj * send buffering, then hard error. 2394890Swnj * Lock against other senders. 2404890Swnj * If must go all at once and not enough room now, then 2414890Swnj * inform user that this would block and do nothing. 2424786Swnj */ 243*4927Swnj sosend(so, asa) 2444786Swnj register struct socket *so; 245*4927Swnj struct sockaddr *asa; 2464786Swnj { 2474890Swnj struct mbuf *top = 0; 2484890Swnj register struct mbuf *m, **mp = ⊤ 2494916Swnj register u_int len; 2504916Swnj int error = 0, space, s; 2514786Swnj 252*4927Swnj COUNT(SOSEND); 2534890Swnj if (so->so_state & SS_CANTSENDMORE) 2544890Swnj return (EPIPE); 2554890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2564890Swnj return (EMSGSIZE); 2574890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2584890Swnj return (EWOULDBLOCK); 2594890Swnj sblock(&so->so_snd); 2604890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2614890Swnj 2624890Swnj s = splnet(); 2634890Swnj again: 2644890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2654890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2664890Swnj snderr(ENOTCONN); 267*4927Swnj if (asa == 0) 2684890Swnj snderr(EDESTADDRREQ); 2694890Swnj } 2704890Swnj if (so->so_error) 2714890Swnj snderr(so->so_error); 2724890Swnj if (top) { 273*4927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 2744890Swnj if (error) { 2754890Swnj splx(s); 2764786Swnj goto release; 2774786Swnj } 2784890Swnj top = 0; 2794890Swnj mp = ⊤ 2804786Swnj } 2814890Swnj if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { 2824890Swnj if (so->so_options & SO_NBIO) 2834890Swnj snderr(EWOULDBLOCK); 2844890Swnj sbunlock(&so->so_snd); 2854890Swnj sbwait(&so->so_snd); 2864890Swnj splx(s); 2874786Swnj goto again; 2884786Swnj } 2894890Swnj splx(s); 2904916Swnj while (u.u_count && (space = sbspace(&so->so_snd)) > 0) { 2914890Swnj MGET(m, 1); 2924890Swnj if (m == NULL) { 2934890Swnj error = ENOBUFS; 2944890Swnj m_freem(top); 2954890Swnj goto release; 2964786Swnj } 2974916Swnj if (u.u_count >= PGSIZE && space >= NMBPG) { 2984890Swnj register struct mbuf *p; 2994890Swnj MPGET(p, 1); 3004890Swnj if (p == 0) 3014890Swnj goto nopages; 3024890Swnj m->m_off = (int)p - (int)m; 3034890Swnj len = PGSIZE; 3044890Swnj } else { 3054786Swnj nopages: 3064890Swnj m->m_off = MMINOFF; 3074890Swnj len = MIN(MLEN, u.u_count); 3084786Swnj } 3094890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 3104890Swnj m->m_len = len; 3114890Swnj *mp = m; 3124890Swnj mp = &m->m_next; 3134786Swnj } 3144890Swnj s = splnet(); 3154890Swnj goto again; 3164890Swnj 3174786Swnj release: 3184890Swnj sbunlock(&so->so_snd); 3194786Swnj return (error); 3204786Swnj } 3214786Swnj 322*4927Swnj soreceive(so, asa) 3234786Swnj register struct socket *so; 324*4927Swnj struct sockaddr *asa; 3254786Swnj { 3264786Swnj register struct mbuf *m, *n; 3274916Swnj u_int len; 3284890Swnj int eor, s, error = 0; 3294786Swnj 330*4927Swnj COUNT(SORECEIVE); 3314890Swnj restart: 3324890Swnj sblock(&so->so_rcv); 3334890Swnj s = splnet(); 3344890Swnj 3354890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3364786Swnj if (so->so_rcv.sb_cc == 0) { 3374890Swnj if ((so->so_state & SS_ISCONNECTED) == 0 && 3384890Swnj (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3394890Swnj rcverr(ENOTCONN); 3404890Swnj if (so->so_state & SS_CANTRCVMORE) { 3414890Swnj splx(s); 3424890Swnj goto release; 3434890Swnj } 3444890Swnj if (so->so_options & SO_NBIO) 3454916Swnj rcverr (EWOULDBLOCK); 3464890Swnj sbunlock(&so->so_rcv); 3474786Swnj sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1); 3484890Swnj goto restart; 3494786Swnj } 3504829Swnj m = so->so_rcv.sb_mb; 3514786Swnj if (m == 0) 3524786Swnj panic("receive"); 3534890Swnj if ((so->so_proto->pr_flags & PR_ADDR)) { 3544890Swnj so->so_rcv.sb_mb = m->m_next; 355*4927Swnj if (asa) { 3564890Swnj so->so_rcv.sb_cc -= m->m_len; 357*4927Swnj len = MIN(m->m_len, sizeof (struct sockaddr)); 358*4927Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, len); 3594890Swnj } else 360*4927Swnj bzero((caddr_t)asa, sizeof (*asa)); 3614890Swnj m = so->so_rcv.sb_mb; 3624890Swnj if (m == 0) 3634890Swnj panic("receive 2"); 3644890Swnj } 3654786Swnj eor = 0; 3664786Swnj do { 3674786Swnj len = MIN(m->m_len, u.u_count); 3684786Swnj if (len == m->m_len) { 3694786Swnj eor = (int)m->m_act; 3704890Swnj sbfree(&so->so_rcv, m); 3714786Swnj } 3724786Swnj splx(s); 3734786Swnj iomove(mtod(m, caddr_t), len, B_READ); 3744786Swnj s = splnet(); 3754786Swnj if (len == m->m_len) { 3764786Swnj MFREE(m, n); 3774786Swnj } else { 3784786Swnj m->m_off += len; 3794786Swnj m->m_len -= len; 3804829Swnj so->so_rcv.sb_cc -= len; 3814786Swnj } 3824829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 3834786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 3844786Swnj do { 3854786Swnj if (m == 0) 3864890Swnj panic("receive 3"); 3874890Swnj sbfree(&so->so_rcv, m); 3884786Swnj eor = (int)m->m_act; 3894786Swnj so->so_rcv.sb_mb = m->m_next; 3904786Swnj MFREE(m, n); 3914890Swnj m = n; 3924786Swnj } while (eor == 0); 3934890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 3944890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 3954890Swnj release: 3964916Swnj sbunlock(&so->so_rcv); 3974890Swnj splx(s); 3984916Swnj return (error); 3994786Swnj } 4004786Swnj 4014916Swnj /*ARGSUSED*/ 4024916Swnj soioctl(so, cmd, cmdp) 4034829Swnj register struct socket *so; 4044829Swnj int cmd; 4054829Swnj register caddr_t cmdp; 4064786Swnj { 4074786Swnj 408*4927Swnj COUNT(SOIOCTL); 4094829Swnj switch (cmdp) { 4104829Swnj 4114829Swnj } 4124829Swnj switch (so->so_type) { 4134829Swnj 4144829Swnj case SOCK_STREAM: 4154829Swnj break; 4164829Swnj 4174829Swnj case SOCK_DGRAM: 4184829Swnj break; 4194829Swnj 4204829Swnj case SOCK_RDM: 4214829Swnj break; 4224829Swnj 4234829Swnj case SOCK_RAW: 4244829Swnj break; 4254829Swnj 4264829Swnj } 4274786Swnj } 428