1*4902Swnj /* uipc_socket.c 4.4 81/11/15 */ 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/protocol.h" 134829Swnj #include "../h/protosw.h" 144829Swnj #include "../h/socket.h" 154829Swnj #include "../h/socketvar.h" 164829Swnj #include "../h/inaddr.h" 174829Swnj #include "../net/inet.h" 184829Swnj #include "../net/inet_systm.h" 194786Swnj 204786Swnj /* 214890Swnj * Socket support routines. 224890Swnj * 234890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 244890Swnj * DO NEWFD STUFF 254786Swnj */ 264786Swnj 274786Swnj /* 284786Swnj * Create a socket. 294786Swnj */ 304829Swnj socket(aso, type, iap, options) 314786Swnj struct socket **aso; 324786Swnj int type; 334786Swnj register struct in_addr *iap; 344829Swnj int options; 354786Swnj { 364786Swnj register struct protosw *prp; 374786Swnj register struct socket *so; 384786Swnj struct mbuf *m; 394890Swnj int pf, proto, error; 404786Swnj 414786Swnj /* 424890Swnj * Use process standard protocol/protocol family if none 434890Swnj * specified by address argument. 444786Swnj */ 454786Swnj if (iap == 0) { 464890Swnj pf = PF_INET; /* should be u.u_protof */ 474786Swnj proto = 0; 484786Swnj } else { 494786Swnj pf = iap->ia_pf; 504786Swnj proto = iap->ia_proto; 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; 784786Swnj (*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0); 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 884786Swnj /* 894890Swnj * Close a socket on last file table reference removal. 904890Swnj * Initiate disconnect if connected. 914890Swnj * Free socket when disconnect complete. 924829Swnj */ 934890Swnj soclose(so) 944829Swnj register struct socket *so; 954829Swnj { 964890Swnj int s = splnet(); /* conservative */ 974829Swnj 984890Swnj if (so->so_pcb == 0) 994890Swnj goto discard; 1004890Swnj if (so->so_state & SS_ISCONNECTED) { 1014890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1024890Swnj u.u_error = disconnect(so, 0); 1034890Swnj if (u.u_error) { 1044890Swnj splx(s); 1054890Swnj return; 1064890Swnj } 1074890Swnj } 1084890Swnj if ((so->so_state & SS_ISDISCONNECTING) && 1094890Swnj (so->so_options & SO_NBIO)) { 1104890Swnj u.u_error = EINPROGRESS; 1114890Swnj splx(s); 1124890Swnj return; 1134890Swnj } 1144890Swnj while (so->so_state & SS_ISCONNECTED) 1154890Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 1164890Swnj } 1174890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1184890Swnj discard: 1194890Swnj if (so->so_pcb == 0) 1204890Swnj sofree(so); 1214890Swnj splx(s); 1224829Swnj } 1234829Swnj 1244890Swnj sostat(so, sb) 1254829Swnj struct socket *so; 1264890Swnj struct stat *sb; 1274829Swnj { 1284829Swnj 1294890Swnj return (EOPNOTSUPP); 1304829Swnj } 1314829Swnj 1324829Swnj /* 1334890Swnj * Connect socket to a specified address. 1344890Swnj * If already connected or connecting, then avoid 1354890Swnj * the protocol entry, to keep its job simpler. 1364786Swnj */ 1374786Swnj connect(so, iap) 1384786Swnj struct socket *so; 1394786Swnj struct in_addr *iap; 1404786Swnj { 1414890Swnj int s = splnet(); 1424890Swnj int error; 1434786Swnj 1444890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 1454890Swnj error = EISCONN; 1464890Swnj goto bad; 1474890Swnj } 1484890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap); 1494890Swnj bad: 1504890Swnj splx(s); 1514890Swnj return (error); 1524786Swnj } 1534786Swnj 1544786Swnj /* 1554890Swnj * Disconnect from a socket. 1564890Swnj * Address parameter is from system call for later multicast 1574890Swnj * protocols. Check to make sure that connected and no disconnect 1584890Swnj * in progress (for protocol's sake), and then invoke protocol. 1594786Swnj */ 1604786Swnj disconnect(so, iap) 1614786Swnj struct socket *so; 1624786Swnj struct in_addr *iap; 1634786Swnj { 1644890Swnj int s = splnet(); 1654890Swnj int error; 1664786Swnj 1674890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 1684890Swnj error = ENOTCONN; 1694890Swnj goto bad; 1704890Swnj } 1714890Swnj if (so->so_state & SS_ISDISCONNECTING) { 1724890Swnj error = EALREADY; 1734890Swnj goto bad; 1744890Swnj } 1754890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0); 1764890Swnj bad: 1774890Swnj splx(s); 1784890Swnj return (error); 1794786Swnj } 1804786Swnj 1814786Swnj /* 1824890Swnj * Send on a socket. 1834890Swnj * If send must go all at once and message is larger than 1844890Swnj * send buffering, then hard error. 1854890Swnj * Lock against other senders. 1864890Swnj * If must go all at once and not enough room now, then 1874890Swnj * inform user that this would block and do nothing. 1884786Swnj */ 1894786Swnj send(so, iap) 1904786Swnj register struct socket *so; 1914786Swnj struct in_addr *iap; 1924786Swnj { 1934890Swnj struct mbuf *top = 0; 1944890Swnj register struct mbuf *m, **mp = ⊤ 1954890Swnj register int bufs; 1964890Swnj register int len; 1974786Swnj int error = 0; 1984890Swnj int s; 1994786Swnj 2004890Swnj if (so->so_state & SS_CANTSENDMORE) 2014890Swnj return (EPIPE); 2024890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2034890Swnj return (EMSGSIZE); 2044890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2054890Swnj return (EWOULDBLOCK); 2064890Swnj sblock(&so->so_snd); 2074890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2084890Swnj 2094890Swnj s = splnet(); 2104890Swnj again: 2114890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2124890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2134890Swnj snderr(ENOTCONN); 2144890Swnj if (iap == 0) 2154890Swnj snderr(EDESTADDRREQ); 2164890Swnj } 2174890Swnj if (so->so_error) 2184890Swnj snderr(so->so_error); 2194890Swnj if (top) { 2204890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap); 2214890Swnj if (error) { 2224890Swnj splx(s); 2234786Swnj goto release; 2244786Swnj } 2254890Swnj top = 0; 2264890Swnj mp = ⊤ 2274786Swnj } 2284890Swnj if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { 2294890Swnj if (so->so_options & SO_NBIO) 2304890Swnj snderr(EWOULDBLOCK); 2314890Swnj sbunlock(&so->so_snd); 2324890Swnj sbwait(&so->so_snd); 2334890Swnj splx(s); 2344786Swnj goto again; 2354786Swnj } 2364890Swnj splx(s); 2374890Swnj while (u.u_count > 0 && sbspace(&so->so_snd) > 0) { 2384890Swnj MGET(m, 1); 2394890Swnj if (m == NULL) { 2404890Swnj error = ENOBUFS; 2414890Swnj m_freem(top); 2424890Swnj goto release; 2434786Swnj } 2444890Swnj if (u.u_count >= PGSIZE && bufs >= NMBPG) { 2454890Swnj register struct mbuf *p; 2464890Swnj MPGET(p, 1); 2474890Swnj if (p == 0) 2484890Swnj goto nopages; 2494890Swnj m->m_off = (int)p - (int)m; 2504890Swnj len = PGSIZE; 2514890Swnj } else { 2524786Swnj nopages: 2534890Swnj m->m_off = MMINOFF; 2544890Swnj len = MIN(MLEN, u.u_count); 2554786Swnj } 2564890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 2574890Swnj m->m_len = len; 2584890Swnj *mp = m; 2594890Swnj mp = &m->m_next; 2604786Swnj } 2614890Swnj s = splnet(); 2624890Swnj goto again; 2634890Swnj 2644786Swnj release: 2654890Swnj sbunlock(&so->so_snd); 2664786Swnj return (error); 2674786Swnj } 2684786Swnj 2694786Swnj receive(so, iap) 2704786Swnj register struct socket *so; 2714786Swnj struct in_addr *iap; 2724786Swnj { 2734786Swnj register struct mbuf *m, *n; 2744890Swnj register int len; 2754890Swnj int eor, s, error = 0; 2764786Swnj 2774890Swnj restart: 2784890Swnj sblock(&so->so_rcv); 2794890Swnj s = splnet(); 2804890Swnj 2814890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 2824786Swnj if (so->so_rcv.sb_cc == 0) { 2834890Swnj if ((so->so_state & SS_ISCONNECTED) == 0 && 2844890Swnj (so->so_proto->pr_flags & PR_CONNREQUIRED)) 2854890Swnj rcverr(ENOTCONN); 2864890Swnj if (so->so_state & SS_CANTRCVMORE) { 2874890Swnj splx(s); 2884890Swnj goto release; 2894890Swnj } 2904890Swnj if (so->so_options & SO_NBIO) 2914890Swnj rcverr(EWOULDBLOCK); 2924890Swnj sbunlock(&so->so_rcv); 2934786Swnj sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1); 2944890Swnj goto restart; 2954786Swnj } 2964829Swnj m = so->so_rcv.sb_mb; 2974786Swnj if (m == 0) 2984786Swnj panic("receive"); 2994890Swnj 3004890Swnj /* 3014890Swnj * Pull address off receive chain, if protocol 3024890Swnj * put one there. 3034890Swnj */ 3044890Swnj if ((so->so_proto->pr_flags & PR_ADDR)) { 3054890Swnj so->so_rcv.sb_mb = m->m_next; 3064890Swnj if (iap) { 3074890Swnj so->so_rcv.sb_cc -= m->m_len; 3084890Swnj len = MIN(m->m_len, sizeof (struct in_addr)); 3094890Swnj bcopy(mtod(m, caddr_t), (caddr_t)iap, len); 3104890Swnj } else 311*4902Swnj bzero((caddr_t)iap, sizeof (*iap)); 3124890Swnj m = so->so_rcv.sb_mb; 3134890Swnj if (m == 0) 3144890Swnj panic("receive 2"); 3154890Swnj } 3164890Swnj 3174890Swnj /* 3184890Swnj * Next pull data off the chain. 3194890Swnj * Stop at eor or when run out of space in user buffer. 3204890Swnj */ 3214786Swnj eor = 0; 3224786Swnj do { 3234786Swnj len = MIN(m->m_len, u.u_count); 3244786Swnj if (len == m->m_len) { 3254786Swnj eor = (int)m->m_act; 3264890Swnj sbfree(&so->so_rcv, m); 3274786Swnj } 3284786Swnj splx(s); 3294786Swnj iomove(mtod(m, caddr_t), len, B_READ); 3304786Swnj s = splnet(); 3314786Swnj if (len == m->m_len) { 3324786Swnj MFREE(m, n); 3334786Swnj } else { 3344786Swnj m->m_off += len; 3354786Swnj m->m_len -= len; 3364829Swnj so->so_rcv.sb_cc -= len; 3374786Swnj } 3384829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 3394890Swnj 3404890Swnj /* 3414890Swnj * If atomic protocol discard rest of record. 3424890Swnj */ 3434786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 3444786Swnj do { 3454786Swnj if (m == 0) 3464890Swnj panic("receive 3"); 3474890Swnj sbfree(&so->so_rcv, m); 3484786Swnj eor = (int)m->m_act; 3494786Swnj so->so_rcv.sb_mb = m->m_next; 3504786Swnj MFREE(m, n); 3514890Swnj m = n; 3524786Swnj } while (eor == 0); 3534890Swnj 3544890Swnj /* 3554890Swnj * If protocol cares, inform it that 3564890Swnj * there is more space in the receive buffer. 3574890Swnj */ 3584890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 3594890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 3604890Swnj 3614890Swnj release: 3624890Swnj sounlock(&so->so_rcv); 3634890Swnj splx(s); 3644786Swnj } 3654786Swnj 3664829Swnj skioctl(so, cmd, cmdp) 3674829Swnj register struct socket *so; 3684829Swnj int cmd; 3694829Swnj register caddr_t cmdp; 3704786Swnj { 3714786Swnj 3724829Swnj switch (cmdp) { 3734829Swnj 3744829Swnj } 3754829Swnj switch (so->so_type) { 3764829Swnj 3774829Swnj case SOCK_STREAM: 3784829Swnj break; 3794829Swnj 3804829Swnj case SOCK_DGRAM: 3814829Swnj break; 3824829Swnj 3834829Swnj case SOCK_RDM: 3844829Swnj break; 3854829Swnj 3864829Swnj case SOCK_RAW: 3874829Swnj break; 3884829Swnj 3894829Swnj } 3904786Swnj } 391