1*4890Swnj /* uipc_socket.c 4.3 81/11/14 */ 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 /* 21*4890Swnj * Socket support routines. 22*4890Swnj * 23*4890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 24*4890Swnj * 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; 39*4890Swnj int pf, proto, error; 404786Swnj 414786Swnj /* 42*4890Swnj * Use process standard protocol/protocol family if none 43*4890Swnj * specified by address argument. 444786Swnj */ 454786Swnj if (iap == 0) { 46*4890Swnj 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 /* 54*4890Swnj * If protocol specified, look for it, otherwise 55*4890Swnj * for a protocol of the correct type in the right family. 56*4890Swnj */ 57*4890Swnj if (proto) 58*4890Swnj prp = pffindproto(pf, proto); 59*4890Swnj else 60*4890Swnj prp = pffindtype(pf, type); 61*4890Swnj if (prp == 0) 62*4890Swnj return (EPROTONOSUPPORT); 63*4890Swnj 64*4890Swnj /* 654786Swnj * Get a socket structure. 664786Swnj */ 67*4890Swnj 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 /* 74*4890Swnj * Attach protocol to socket, initializing 75*4890Swnj * and reserving resources. 764786Swnj */ 774786Swnj so->so_proto = prp; 784786Swnj (*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0); 794786Swnj if (so->so_error) { 80*4890Swnj /*###80 [cc] operands of = have incompatible types %%%*/ 81*4890Swnj /*###80 [cc] zerosocket undefined %%%*/ 82*4890Swnj error = so->so_error; 834786Swnj m_free(dtom(so)); 84*4890Swnj return (error); 854786Swnj } 864786Swnj *aso = so; 874786Swnj return (0); 884786Swnj } 894786Swnj 904786Swnj /* 91*4890Swnj * Close a socket on last file table reference removal. 92*4890Swnj * Initiate disconnect if connected. 93*4890Swnj * Free socket when disconnect complete. 944829Swnj */ 95*4890Swnj soclose(so) 964829Swnj register struct socket *so; 974829Swnj { 98*4890Swnj int s = splnet(); /* conservative */ 994829Swnj 100*4890Swnj if (so->so_pcb == 0) 101*4890Swnj goto discard; 102*4890Swnj if (so->so_state & SS_ISCONNECTED) { 103*4890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 104*4890Swnj u.u_error = disconnect(so, 0); 105*4890Swnj if (u.u_error) { 106*4890Swnj splx(s); 107*4890Swnj return; 108*4890Swnj } 109*4890Swnj } 110*4890Swnj if ((so->so_state & SS_ISDISCONNECTING) && 111*4890Swnj (so->so_options & SO_NBIO)) { 112*4890Swnj u.u_error = EINPROGRESS; 113*4890Swnj splx(s); 114*4890Swnj return; 115*4890Swnj } 116*4890Swnj while (so->so_state & SS_ISCONNECTED) 117*4890Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 118*4890Swnj } 119*4890Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 120*4890Swnj discard: 121*4890Swnj if (so->so_pcb == 0) 122*4890Swnj sofree(so); 123*4890Swnj splx(s); 1244829Swnj } 1254829Swnj 126*4890Swnj sostat(so, sb) 1274829Swnj struct socket *so; 128*4890Swnj struct stat *sb; 1294829Swnj { 1304829Swnj 131*4890Swnj return (EOPNOTSUPP); 1324829Swnj } 1334829Swnj 1344829Swnj /* 135*4890Swnj * Connect socket to a specified address. 136*4890Swnj * If already connected or connecting, then avoid 137*4890Swnj * the protocol entry, to keep its job simpler. 1384786Swnj */ 1394786Swnj connect(so, iap) 1404786Swnj struct socket *so; 1414786Swnj struct in_addr *iap; 1424786Swnj { 143*4890Swnj int s = splnet(); 144*4890Swnj int error; 1454786Swnj 146*4890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 147*4890Swnj error = EISCONN; 148*4890Swnj goto bad; 149*4890Swnj } 150*4890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)iap); 151*4890Swnj bad: 152*4890Swnj splx(s); 153*4890Swnj return (error); 1544786Swnj } 1554786Swnj 1564786Swnj /* 157*4890Swnj * Disconnect from a socket. 158*4890Swnj * Address parameter is from system call for later multicast 159*4890Swnj * protocols. Check to make sure that connected and no disconnect 160*4890Swnj * in progress (for protocol's sake), and then invoke protocol. 1614786Swnj */ 1624786Swnj disconnect(so, iap) 1634786Swnj struct socket *so; 1644786Swnj struct in_addr *iap; 1654786Swnj { 166*4890Swnj int s = splnet(); 167*4890Swnj int error; 1684786Swnj 169*4890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 170*4890Swnj error = ENOTCONN; 171*4890Swnj goto bad; 172*4890Swnj } 173*4890Swnj if (so->so_state & SS_ISDISCONNECTING) { 174*4890Swnj error = EALREADY; 175*4890Swnj goto bad; 176*4890Swnj } 177*4890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, 0); 178*4890Swnj bad: 179*4890Swnj splx(s); 180*4890Swnj return (error); 1814786Swnj } 1824786Swnj 1834786Swnj /* 184*4890Swnj * Send on a socket. 185*4890Swnj * If send must go all at once and message is larger than 186*4890Swnj * send buffering, then hard error. 187*4890Swnj * Lock against other senders. 188*4890Swnj * If must go all at once and not enough room now, then 189*4890Swnj * inform user that this would block and do nothing. 1904786Swnj */ 1914786Swnj send(so, iap) 1924786Swnj register struct socket *so; 1934786Swnj struct in_addr *iap; 1944786Swnj { 195*4890Swnj struct mbuf *top = 0; 196*4890Swnj register struct mbuf *m, **mp = ⊤ 197*4890Swnj register int bufs; 198*4890Swnj register int len; 1994786Swnj int error = 0; 200*4890Swnj int s; 2014786Swnj 202*4890Swnj if (so->so_state & SS_CANTSENDMORE) 203*4890Swnj return (EPIPE); 204*4890Swnj if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat) 205*4890Swnj return (EMSGSIZE); 206*4890Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_options & SO_NBIO)) 207*4890Swnj return (EWOULDBLOCK); 208*4890Swnj sblock(&so->so_snd); 209*4890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 210*4890Swnj 211*4890Swnj s = splnet(); 212*4890Swnj again: 213*4890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 214*4890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 215*4890Swnj snderr(ENOTCONN); 216*4890Swnj if (iap == 0) 217*4890Swnj snderr(EDESTADDRREQ); 218*4890Swnj } 219*4890Swnj if (so->so_error) 220*4890Swnj snderr(so->so_error); 221*4890Swnj if (top) { 222*4890Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap); 223*4890Swnj if (error) { 224*4890Swnj splx(s); 2254786Swnj goto release; 2264786Swnj } 227*4890Swnj top = 0; 228*4890Swnj mp = ⊤ 2294786Swnj } 230*4890Swnj if (sosendallatonce(so) && sbspace(&so->so_snd) < u.u_count) { 231*4890Swnj if (so->so_options & SO_NBIO) 232*4890Swnj snderr(EWOULDBLOCK); 233*4890Swnj sbunlock(&so->so_snd); 234*4890Swnj sbwait(&so->so_snd); 235*4890Swnj splx(s); 2364786Swnj goto again; 2374786Swnj } 238*4890Swnj splx(s); 239*4890Swnj while (u.u_count > 0 && sbspace(&so->so_snd) > 0) { 240*4890Swnj MGET(m, 1); 241*4890Swnj if (m == NULL) { 242*4890Swnj error = ENOBUFS; 243*4890Swnj m_freem(top); 244*4890Swnj goto release; 2454786Swnj } 246*4890Swnj if (u.u_count >= PGSIZE && bufs >= NMBPG) { 247*4890Swnj register struct mbuf *p; 248*4890Swnj MPGET(p, 1); 249*4890Swnj if (p == 0) 250*4890Swnj goto nopages; 251*4890Swnj m->m_off = (int)p - (int)m; 252*4890Swnj len = PGSIZE; 253*4890Swnj } else { 2544786Swnj nopages: 255*4890Swnj m->m_off = MMINOFF; 256*4890Swnj len = MIN(MLEN, u.u_count); 2574786Swnj } 258*4890Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 259*4890Swnj m->m_len = len; 260*4890Swnj *mp = m; 261*4890Swnj mp = &m->m_next; 2624786Swnj } 263*4890Swnj s = splnet(); 264*4890Swnj goto again; 265*4890Swnj 2664786Swnj release: 267*4890Swnj sbunlock(&so->so_snd); 2684786Swnj return (error); 2694786Swnj } 2704786Swnj 2714786Swnj receive(so, iap) 2724786Swnj register struct socket *so; 2734786Swnj struct in_addr *iap; 2744786Swnj { 2754786Swnj register struct mbuf *m, *n; 276*4890Swnj register int len; 277*4890Swnj int eor, s, error = 0; 2784786Swnj 279*4890Swnj restart: 280*4890Swnj sblock(&so->so_rcv); 281*4890Swnj s = splnet(); 282*4890Swnj 283*4890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 2844786Swnj if (so->so_rcv.sb_cc == 0) { 285*4890Swnj if ((so->so_state & SS_ISCONNECTED) == 0 && 286*4890Swnj (so->so_proto->pr_flags & PR_CONNREQUIRED)) 287*4890Swnj rcverr(ENOTCONN); 288*4890Swnj if (so->so_state & SS_CANTRCVMORE) { 289*4890Swnj splx(s); 290*4890Swnj goto release; 291*4890Swnj } 292*4890Swnj if (so->so_options & SO_NBIO) 293*4890Swnj rcverr(EWOULDBLOCK); 294*4890Swnj sbunlock(&so->so_rcv); 2954786Swnj sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1); 296*4890Swnj goto restart; 2974786Swnj } 2984829Swnj m = so->so_rcv.sb_mb; 2994786Swnj if (m == 0) 3004786Swnj panic("receive"); 301*4890Swnj 302*4890Swnj /* 303*4890Swnj * Pull address off receive chain, if protocol 304*4890Swnj * put one there. 305*4890Swnj */ 306*4890Swnj if ((so->so_proto->pr_flags & PR_ADDR)) { 307*4890Swnj so->so_rcv.sb_mb = m->m_next; 308*4890Swnj if (iap) { 309*4890Swnj so->so_rcv.sb_cc -= m->m_len; 310*4890Swnj len = MIN(m->m_len, sizeof (struct in_addr)); 311*4890Swnj bcopy(mtod(m, caddr_t), (caddr_t)iap, len); 312*4890Swnj } else 313*4890Swnj *iap = zeroin_addr; 314*4890Swnj m = so->so_rcv.sb_mb; 315*4890Swnj if (m == 0) 316*4890Swnj panic("receive 2"); 317*4890Swnj } 318*4890Swnj 319*4890Swnj /* 320*4890Swnj * Next pull data off the chain. 321*4890Swnj * Stop at eor or when run out of space in user buffer. 322*4890Swnj */ 3234786Swnj eor = 0; 3244786Swnj do { 3254786Swnj len = MIN(m->m_len, u.u_count); 3264786Swnj if (len == m->m_len) { 3274786Swnj eor = (int)m->m_act; 328*4890Swnj sbfree(&so->so_rcv, m); 3294786Swnj } 3304786Swnj splx(s); 3314786Swnj iomove(mtod(m, caddr_t), len, B_READ); 3324786Swnj s = splnet(); 3334786Swnj if (len == m->m_len) { 3344786Swnj MFREE(m, n); 3354786Swnj } else { 3364786Swnj m->m_off += len; 3374786Swnj m->m_len -= len; 3384829Swnj so->so_rcv.sb_cc -= len; 3394786Swnj } 3404829Swnj } while ((m = so->so_rcv.sb_mb) && u.u_count && !eor); 341*4890Swnj 342*4890Swnj /* 343*4890Swnj * If atomic protocol discard rest of record. 344*4890Swnj */ 3454786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 3464786Swnj do { 3474786Swnj if (m == 0) 348*4890Swnj panic("receive 3"); 349*4890Swnj sbfree(&so->so_rcv, m); 3504786Swnj eor = (int)m->m_act; 3514786Swnj so->so_rcv.sb_mb = m->m_next; 3524786Swnj MFREE(m, n); 353*4890Swnj m = n; 3544786Swnj } while (eor == 0); 355*4890Swnj 356*4890Swnj /* 357*4890Swnj * If protocol cares, inform it that 358*4890Swnj * there is more space in the receive buffer. 359*4890Swnj */ 360*4890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 361*4890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 362*4890Swnj 363*4890Swnj release: 364*4890Swnj sounlock(&so->so_rcv); 365*4890Swnj splx(s); 3664786Swnj } 3674786Swnj 3684829Swnj skioctl(so, cmd, cmdp) 3694829Swnj register struct socket *so; 3704829Swnj int cmd; 3714829Swnj register caddr_t cmdp; 3724786Swnj { 3734786Swnj 3744829Swnj switch (cmdp) { 3754829Swnj 3764829Swnj } 3774829Swnj switch (so->so_type) { 3784829Swnj 3794829Swnj case SOCK_STREAM: 3804829Swnj break; 3814829Swnj 3824829Swnj case SOCK_DGRAM: 3834829Swnj break; 3844829Swnj 3854829Swnj case SOCK_RDM: 3864829Swnj break; 3874829Swnj 3884829Swnj case SOCK_RAW: 3894829Swnj break; 3904829Swnj 3914829Swnj } 3924786Swnj } 393*4890Swnj /*###417 [cc] operands of = have incompatible types %%%*/ 394*4890Swnj /*###417 [cc] zeroin_addr undefined %%%*/ 395