1*4916Swnj /* uipc_socket.c 4.5 81/11/16 */ 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" 17*4916Swnj #include "../h/stat.h" 184829Swnj #include "../net/inet.h" 194829Swnj #include "../net/inet_systm.h" 204786Swnj 214786Swnj /* 224890Swnj * Socket support routines. 234890Swnj * 244890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 254890Swnj * DO NEWFD STUFF 264786Swnj */ 274786Swnj 284786Swnj /* 294786Swnj * Create a socket. 304786Swnj */ 314829Swnj socket(aso, type, iap, options) 324786Swnj struct socket **aso; 334786Swnj int type; 344786Swnj register struct in_addr *iap; 354829Swnj int options; 364786Swnj { 374786Swnj register struct protosw *prp; 384786Swnj register struct socket *so; 394786Swnj struct mbuf *m; 404890Swnj int pf, proto, error; 414786Swnj 424786Swnj /* 434890Swnj * Use process standard protocol/protocol family if none 444890Swnj * specified by address argument. 454786Swnj */ 464786Swnj if (iap == 0) { 474890Swnj pf = PF_INET; /* should be u.u_protof */ 484786Swnj proto = 0; 494786Swnj } else { 504786Swnj pf = iap->ia_pf; 514786Swnj proto = iap->ia_proto; 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; 794786Swnj (*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0); 804786Swnj if (so->so_error) { 814890Swnj error = so->so_error; 824786Swnj m_free(dtom(so)); 834890Swnj return (error); 844786Swnj } 854786Swnj *aso = so; 864786Swnj return (0); 874786Swnj } 884786Swnj 89*4916Swnj sofree(so) 90*4916Swnj struct socket *so; 91*4916Swnj { 92*4916Swnj 93*4916Swnj m_free(dtom(so)); 94*4916Swnj } 95*4916Swnj 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 1064890Swnj if (so->so_pcb == 0) 1074890Swnj goto discard; 1084890Swnj if (so->so_state & SS_ISCONNECTED) { 1094890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 110*4916Swnj u.u_error = disconnect(so, (struct in_addr *)0); 1114890Swnj if (u.u_error) { 1124890Swnj splx(s); 1134890Swnj return; 1144890Swnj } 1154890Swnj } 1164890Swnj if ((so->so_state & SS_ISDISCONNECTING) && 1174890Swnj (so->so_options & SO_NBIO)) { 1184890Swnj u.u_error = EINPROGRESS; 1194890Swnj splx(s); 1204890Swnj return; 1214890Swnj } 1224890Swnj while (so->so_state & SS_ISCONNECTED) 1234890Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 1244890Swnj } 1254890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1264890Swnj discard: 1274890Swnj if (so->so_pcb == 0) 1284890Swnj sofree(so); 1294890Swnj splx(s); 1304829Swnj } 1314829Swnj 132*4916Swnj /*ARGSUSED*/ 1334890Swnj sostat(so, sb) 1344829Swnj struct socket *so; 1354890Swnj struct stat *sb; 1364829Swnj { 1374829Swnj 1384890Swnj return (EOPNOTSUPP); 1394829Swnj } 1404829Swnj 1414829Swnj /* 1424890Swnj * Connect socket to a specified address. 1434890Swnj * If already connected or connecting, then avoid 1444890Swnj * the protocol entry, to keep its job simpler. 1454786Swnj */ 1464786Swnj connect(so, iap) 1474786Swnj struct socket *so; 1484786Swnj struct in_addr *iap; 1494786Swnj { 1504890Swnj int s = splnet(); 1514890Swnj int error; 1524786Swnj 1534890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 1544890Swnj error = EISCONN; 1554890Swnj goto bad; 1564890Swnj } 1574890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap); 1584890Swnj bad: 1594890Swnj splx(s); 1604890Swnj return (error); 1614786Swnj } 1624786Swnj 1634786Swnj /* 1644890Swnj * Disconnect from a socket. 1654890Swnj * Address parameter is from system call for later multicast 1664890Swnj * protocols. Check to make sure that connected and no disconnect 1674890Swnj * in progress (for protocol's sake), and then invoke protocol. 1684786Swnj */ 169*4916Swnj /*ARGSUSED*/ 1704786Swnj disconnect(so, iap) 1714786Swnj struct socket *so; 1724786Swnj struct in_addr *iap; 1734786Swnj { 1744890Swnj int s = splnet(); 1754890Swnj int error; 1764786Swnj 1774890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 1784890Swnj error = ENOTCONN; 1794890Swnj goto bad; 1804890Swnj } 1814890Swnj if (so->so_state & SS_ISDISCONNECTING) { 1824890Swnj error = EALREADY; 1834890Swnj goto bad; 1844890Swnj } 1854890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0); 1864890Swnj bad: 1874890Swnj splx(s); 1884890Swnj return (error); 1894786Swnj } 1904786Swnj 1914786Swnj /* 1924890Swnj * Send on a socket. 1934890Swnj * If send must go all at once and message is larger than 1944890Swnj * send buffering, then hard error. 1954890Swnj * Lock against other senders. 1964890Swnj * If must go all at once and not enough room now, then 1974890Swnj * inform user that this would block and do nothing. 1984786Swnj */ 1994786Swnj send(so, iap) 2004786Swnj register struct socket *so; 201*4916Swnj struct inaddr *iap; 2024786Swnj { 2034890Swnj struct mbuf *top = 0; 2044890Swnj register struct mbuf *m, **mp = ⊤ 205*4916Swnj register u_int len; 206*4916Swnj int error = 0, space, s; 2074786Swnj 2084890Swnj if (so->so_state & SS_CANTSENDMORE) 2094890Swnj return (EPIPE); 2104890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 2114890Swnj return (EMSGSIZE); 2124890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 2134890Swnj return (EWOULDBLOCK); 2144890Swnj sblock(&so->so_snd); 2154890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2164890Swnj 2174890Swnj s = splnet(); 2184890Swnj again: 2194890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2204890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2214890Swnj snderr(ENOTCONN); 2224890Swnj if (iap == 0) 2234890Swnj snderr(EDESTADDRREQ); 2244890Swnj } 2254890Swnj if (so->so_error) 2264890Swnj snderr(so->so_error); 2274890Swnj if (top) { 2284890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap); 2294890Swnj if (error) { 2304890Swnj splx(s); 2314786Swnj goto release; 2324786Swnj } 2334890Swnj top = 0; 2344890Swnj mp = ⊤ 2354786Swnj } 2364890Swnj if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { 2374890Swnj if (so->so_options & SO_NBIO) 2384890Swnj snderr(EWOULDBLOCK); 2394890Swnj sbunlock(&so->so_snd); 2404890Swnj sbwait(&so->so_snd); 2414890Swnj splx(s); 2424786Swnj goto again; 2434786Swnj } 2444890Swnj splx(s); 245*4916Swnj while (u.u_count && (space = sbspace(&so->so_snd)) > 0) { 2464890Swnj MGET(m, 1); 2474890Swnj if (m == NULL) { 2484890Swnj error = ENOBUFS; 2494890Swnj m_freem(top); 2504890Swnj goto release; 2514786Swnj } 252*4916Swnj if (u.u_count >= PGSIZE && space >= NMBPG) { 2534890Swnj register struct mbuf *p; 2544890Swnj MPGET(p, 1); 2554890Swnj if (p == 0) 2564890Swnj goto nopages; 2574890Swnj m->m_off = (int)p - (int)m; 2584890Swnj len = PGSIZE; 2594890Swnj } else { 2604786Swnj nopages: 2614890Swnj m->m_off = MMINOFF; 2624890Swnj len = MIN(MLEN, u.u_count); 2634786Swnj } 2644890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 2654890Swnj m->m_len = len; 2664890Swnj *mp = m; 2674890Swnj mp = &m->m_next; 2684786Swnj } 2694890Swnj s = splnet(); 2704890Swnj goto again; 2714890Swnj 2724786Swnj release: 2734890Swnj sbunlock(&so->so_snd); 2744786Swnj return (error); 2754786Swnj } 2764786Swnj 2774786Swnj receive(so, iap) 2784786Swnj register struct socket *so; 279*4916Swnj struct inaddr *iap; 2804786Swnj { 2814786Swnj register struct mbuf *m, *n; 282*4916Swnj u_int len; 2834890Swnj int eor, s, error = 0; 2844786Swnj 2854890Swnj restart: 2864890Swnj sblock(&so->so_rcv); 2874890Swnj s = splnet(); 2884890Swnj 2894890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 2904786Swnj if (so->so_rcv.sb_cc == 0) { 2914890Swnj if ((so->so_state & SS_ISCONNECTED) == 0 && 2924890Swnj (so->so_proto->pr_flags & PR_CONNREQUIRED)) 2934890Swnj rcverr(ENOTCONN); 2944890Swnj if (so->so_state & SS_CANTRCVMORE) { 2954890Swnj splx(s); 2964890Swnj goto release; 2974890Swnj } 2984890Swnj if (so->so_options & SO_NBIO) 299*4916Swnj rcverr (EWOULDBLOCK); 3004890Swnj sbunlock(&so->so_rcv); 3014786Swnj sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1); 3024890Swnj goto restart; 3034786Swnj } 3044829Swnj m = so->so_rcv.sb_mb; 3054786Swnj if (m == 0) 3064786Swnj panic("receive"); 3074890Swnj /* 3084890Swnj * Pull address off receive chain, if protocol 3094890Swnj * put one there. 3104890Swnj */ 3114890Swnj if ((so->so_proto->pr_flags & PR_ADDR)) { 3124890Swnj so->so_rcv.sb_mb = m->m_next; 3134890Swnj if (iap) { 3144890Swnj so->so_rcv.sb_cc -= m->m_len; 3154890Swnj len = MIN(m->m_len, sizeof (struct in_addr)); 3164890Swnj bcopy(mtod(m, caddr_t), (caddr_t)iap, len); 3174890Swnj } else 3184902Swnj bzero((caddr_t)iap, sizeof (*iap)); 3194890Swnj m = so->so_rcv.sb_mb; 3204890Swnj if (m == 0) 3214890Swnj panic("receive 2"); 3224890Swnj } 3234890Swnj 3244890Swnj /* 3254890Swnj * Next pull data off the chain. 3264890Swnj * Stop at eor or when run out of space in user buffer. 3274890Swnj */ 3284786Swnj eor = 0; 3294786Swnj do { 3304786Swnj len = MIN(m->m_len, u.u_count); 3314786Swnj if (len == m->m_len) { 3324786Swnj eor = (int)m->m_act; 3334890Swnj sbfree(&so->so_rcv, m); 3344786Swnj } 3354786Swnj splx(s); 3364786Swnj iomove(mtod(m, caddr_t), len, B_READ); 3374786Swnj s = splnet(); 3384786Swnj if (len == m->m_len) { 3394786Swnj MFREE(m, n); 3404786Swnj } else { 3414786Swnj m->m_off += len; 3424786Swnj m->m_len -= len; 3434829Swnj so->so_rcv.sb_cc -= len; 3444786Swnj } 3454829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 3464890Swnj 3474890Swnj /* 3484890Swnj * If atomic protocol discard rest of record. 3494890Swnj */ 3504786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 3514786Swnj do { 3524786Swnj if (m == 0) 3534890Swnj panic("receive 3"); 3544890Swnj sbfree(&so->so_rcv, m); 3554786Swnj eor = (int)m->m_act; 3564786Swnj so->so_rcv.sb_mb = m->m_next; 3574786Swnj MFREE(m, n); 3584890Swnj m = n; 3594786Swnj } while (eor == 0); 3604890Swnj 3614890Swnj /* 3624890Swnj * If protocol cares, inform it that 3634890Swnj * there is more space in the receive buffer. 3644890Swnj */ 3654890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 3664890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 3674890Swnj 3684890Swnj release: 369*4916Swnj sbunlock(&so->so_rcv); 3704890Swnj splx(s); 371*4916Swnj return (error); 3724786Swnj } 3734786Swnj 374*4916Swnj /*ARGSUSED*/ 375*4916Swnj soioctl(so, cmd, cmdp) 3764829Swnj register struct socket *so; 3774829Swnj int cmd; 3784829Swnj register caddr_t cmdp; 3794786Swnj { 3804786Swnj 3814829Swnj switch (cmdp) { 3824829Swnj 3834829Swnj } 3844829Swnj switch (so->so_type) { 3854829Swnj 3864829Swnj case SOCK_STREAM: 3874829Swnj break; 3884829Swnj 3894829Swnj case SOCK_DGRAM: 3904829Swnj break; 3914829Swnj 3924829Swnj case SOCK_RDM: 3934829Swnj break; 3944829Swnj 3954829Swnj case SOCK_RAW: 3964829Swnj break; 3974829Swnj 3984829Swnj } 3994786Swnj } 400