1*4786Swnj /* uipc_socket.c 4.1 81/11/07 */ 2*4786Swnj 3*4786Swnj #include "../h/param.h" 4*4786Swnj #include "../h/dir.h" 5*4786Swnj #include "../h/user.h" 6*4786Swnj #include "file.h" 7*4786Swnj #include "../h/inode.h" 8*4786Swnj #include "../h/mbuf.h" 9*4786Swnj #include "protocol.h" 10*4786Swnj #include "protocolsw.h" 11*4786Swnj #include "socket.h" 12*4786Swnj #include "socketvar.h" 13*4786Swnj 14*4786Swnj struct socket zerosocket; 15*4786Swnj struct in_addr zeroin_addr; 16*4786Swnj 17*4786Swnj /* 18*4786Swnj * Socket system call interface. Copy in arguments 19*4786Swnj * set up file descriptor and call internal socket 20*4786Swnj * creation routine. 21*4786Swnj */ 22*4786Swnj ssocket() 23*4786Swnj { 24*4786Swnj register struct a { 25*4786Swnj int type; 26*4786Swnj in_addr *ain; 27*4786Swnj int flags; 28*4786Swnj } *uap = (struct a *)u.u_ap; 29*4786Swnj in_addr in; 30*4786Swnj struct socket *so0; 31*4786Swnj register struct socket *so; 32*4786Swnj register struct file *fp; 33*4786Swnj 34*4786Swnj if ((fp = falloc()) == NULL) 35*4786Swnj return; 36*4786Swnj fp->f_flag = FSOCKET|FREAD|FWRITE; 37*4786Swnj if (copyin((caddr_t)uap->ain, &in, sizeof (in))) { 38*4786Swnj u.u_error = EFAULT; 39*4786Swnj return; 40*4786Swnj } 41*4786Swnj u.u_error = socket(&so0, a->type, &in, a->flags); 42*4786Swnj if (u.u_error) 43*4786Swnj goto bad; 44*4786Swnj fp->f_socket = so; 45*4786Swnj return; 46*4786Swnj bad: 47*4786Swnj u.u_ofile[u.u_r.r_val1] = 0; 48*4786Swnj fp->f_count = 0; 49*4786Swnj } 50*4786Swnj 51*4786Swnj /* 52*4786Swnj * Create a socket. 53*4786Swnj */ 54*4786Swnj socket(aso, type, iap, flags) 55*4786Swnj struct socket **aso; 56*4786Swnj int type; 57*4786Swnj register struct in_addr *iap; 58*4786Swnj int flags; 59*4786Swnj { 60*4786Swnj register struct protosw *prp; 61*4786Swnj register struct socket *so; 62*4786Swnj struct mbuf *m; 63*4786Swnj int pf, proto; 64*4786Swnj 65*4786Swnj /* 66*4786Swnj * Pin down protocol if possible. 67*4786Swnj * If no address specified, use a generic protocol. 68*4786Swnj */ 69*4786Swnj if (iap == 0) { 70*4786Swnj pf = PF_GENERIC; 71*4786Swnj proto = 0; 72*4786Swnj } else { 73*4786Swnj pf = iap->ia_pf; 74*4786Swnj proto = iap->ia_proto; 75*4786Swnj } 76*4786Swnj if (proto) { 77*4786Swnj /* 78*4786Swnj * A specific protocol was requested. Look 79*4786Swnj * for the protocol. If not found, then we 80*4786Swnj * don't support it. 81*4786Swnj */ 82*4786Swnj prp = pf_findproto(pf, proto); 83*4786Swnj if (prp == 0) 84*4786Swnj return (EPROTONOTSUPP); 85*4786Swnj } else { 86*4786Swnj /* 87*4786Swnj * No specific protocol was requested. Look 88*4786Swnj * in the specified (or generic) protocol set 89*4786Swnj * for a protocol of this type. 90*4786Swnj */ 91*4786Swnj prp = pf_findtype(pf, type); 92*4786Swnj if (prp == 0) 93*4786Swnj return (ESOCKTYPENOTSUPP); 94*4786Swnj } 95*4786Swnj 96*4786Swnj /* 97*4786Swnj * Get a socket structure. 98*4786Swnj */ 99*4786Swnj m = m_get(M_WAIT); 100*4786Swnj if (m == 0) 101*4786Swnj return (ENOBUFS); 102*4786Swnj m->m_off = MMINOFF; 103*4786Swnj so = mtod(m, struct socket *); 104*4786Swnj *so = zerosocket; 105*4786Swnj so->so_flags = flags; 106*4786Swnj 107*4786Swnj /* 108*4786Swnj * An early call to protocol initialization. If protocol 109*4786Swnj * actually hasn't been decided on yet (till we know 110*4786Swnj * peer), then the generic protocol allocated so far can 111*4786Swnj * just make sure a reasonable amount of resources will 112*4786Swnj * be available to it (say by allocating liberally now 113*4786Swnj * and returning some of the resources later). 114*4786Swnj */ 115*4786Swnj so->so_proto = prp; 116*4786Swnj (*prp->pr_usrreq)(so, PRU_ATTACH, 0, 0); 117*4786Swnj if (so->so_error) { 118*4786Swnj m_free(dtom(so)); 119*4786Swnj return (u.u_error); 120*4786Swnj } 121*4786Swnj *aso = so; 122*4786Swnj return (0); 123*4786Swnj } 124*4786Swnj 125*4786Swnj /* 126*4786Swnj * Connect socket to foreign peer; system call 127*4786Swnj * interface. Copy in arguments and call internal routine. 128*4786Swnj */ 129*4786Swnj sconnect() 130*4786Swnj { 131*4786Swnj register struct a { 132*4786Swnj int fdes; 133*4786Swnj in_addr *a; 134*4786Swnj } *uap = (struct a *)u.u_ap; 135*4786Swnj in_addr in; 136*4786Swnj 137*4786Swnj if (copyin((caddr_t)uap->aaddr, &in, sizeof (in))) { 138*4786Swnj u.u_error = EFAULT; 139*4786Swnj return; 140*4786Swnj } 141*4786Swnj fp = getf(uap->fdes); 142*4786Swnj if (fp == 0) 143*4786Swnj return; 144*4786Swnj if ((fp->f_flag & FSOCKET) == 0) { 145*4786Swnj u.u_error = ENOTSOCK; 146*4786Swnj return; 147*4786Swnj } 148*4786Swnj u.u_error = connect(fp->f_socket, &in); 149*4786Swnj if (u.u_error) 150*4786Swnj return; 151*4786Swnj s = splnet(); 152*4786Swnj for (;;) { 153*4786Swnj /* should use tsleep here */ 154*4786Swnj if ((*so->so_proto->pr_usrreq)(so, PRU_ISCONN, 0, &in) == 0) 155*4786Swnj break; 156*4786Swnj sleep((caddr_t)&so->so_timeo, PZERO+1); 157*4786Swnj } 158*4786Swnj splx(s); 159*4786Swnj } 160*4786Swnj 161*4786Swnj connect(so, iap) 162*4786Swnj struct socket *so; 163*4786Swnj struct in_addr *iap; 164*4786Swnj { 165*4786Swnj 166*4786Swnj return ((*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, &in)); 167*4786Swnj } 168*4786Swnj 169*4786Swnj /* 170*4786Swnj * Disconnect socket from foreign peer; system call 171*4786Swnj * interface. Copy in arguments and call internal routine. 172*4786Swnj */ 173*4786Swnj sdisconnect() 174*4786Swnj { 175*4786Swnj register struct a { 176*4786Swnj int fdes; 177*4786Swnj in_addr *a; 178*4786Swnj } *uap = (struct a *)u.u_ap; 179*4786Swnj in_addr in; 180*4786Swnj 181*4786Swnj if (uap->a && copyin((caddr_t)uap->aaddr, &in, sizeof (in))) { 182*4786Swnj u.u_error = EFAULT; 183*4786Swnj return; 184*4786Swnj } 185*4786Swnj fp = getf(uap->fdes); 186*4786Swnj if (fp == 0) 187*4786Swnj return; 188*4786Swnj if ((fp->f_flag & FSOCKET) == 0) { 189*4786Swnj u.u_error = ENOTSOCK; 190*4786Swnj return; 191*4786Swnj } 192*4786Swnj disconnect(fp->f_socket, uap->a ? &in : 0); 193*4786Swnj } 194*4786Swnj 195*4786Swnj disconnect(so, iap) 196*4786Swnj struct socket *so; 197*4786Swnj struct in_addr *iap; 198*4786Swnj { 199*4786Swnj 200*4786Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, &in); 201*4786Swnj } 202*4786Swnj 203*4786Swnj /* 204*4786Swnj * Send data on socket. 205*4786Swnj */ 206*4786Swnj ssend() 207*4786Swnj { 208*4786Swnj register struct a { 209*4786Swnj int fdes; 210*4786Swnj in_addr *ain; 211*4786Swnj caddr_t cbuf; 212*4786Swnj int count; 213*4786Swnj } *uap = (struct a *)u.u_ap; 214*4786Swnj 215*4786Swnj fp = getf(uap->fdes); 216*4786Swnj if (fp == 0) 217*4786Swnj return; 218*4786Swnj if ((fp->f_flag & FSOCKET) == 0) { 219*4786Swnj u.u_error = ENOTSOCK; 220*4786Swnj return; 221*4786Swnj } 222*4786Swnj if (uap->count < 0) { 223*4786Swnj u.u_error = EINVAL; 224*4786Swnj return; 225*4786Swnj } 226*4786Swnj u.u_base = uap->buf; 227*4786Swnj u.u_count = uap->len; 228*4786Swnj u.u_segflg = 0; 229*4786Swnj if (useracc(u.u_base, u.u_count, B_READ) == 0 || 230*4786Swnj uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) { 231*4786Swnj u.u_error = EFAULT; 232*4786Swnj return; 233*4786Swnj } 234*4786Swnj u.u_error = send(fp->f_socket, uap->ain ? &in : 0); 235*4786Swnj } 236*4786Swnj 237*4786Swnj send(so, iap) 238*4786Swnj register struct socket *so; 239*4786Swnj struct in_addr *iap; 240*4786Swnj { 241*4786Swnj register struct mbuf *m, **mp; 242*4786Swnj struct mbuf *top; 243*4786Swnj int error = 0; 244*4786Swnj 245*4786Swnj if (so->so_proto->pr_flags & PR_ATOMIC) { 246*4786Swnj if (u.u_count > so->so_snd.sb_hiwat) { 247*4786Swnj error = EMSGSIZE; 248*4786Swnj goto release; 249*4786Swnj } 250*4786Swnj } 251*4786Swnj again: 252*4786Swnj while (so->so_snd.sb_flags & SB_LOCK) { 253*4786Swnj so->so_snd.sb_flags |= SB_WANT; 254*4786Swnj sleep((caddr_t)&so->so_snd.sb_flags, PZERO+1); 255*4786Swnj } 256*4786Swnj if (so->so_snd.sb_hiwat - so->so_snd.sb_cc < u.u_count) { 257*4786Swnj so->so_snd.sb_flags |= SB_WAIT; 258*4786Swnj sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1); 259*4786Swnj goto again; 260*4786Swnj } 261*4786Swnj so->so_snd.sb_flags |= SB_LOCK; 262*4786Swnj while (u.u_count > 0) { 263*4786Swnj bufs = so->so_snd.sb_mbmax - so->so_snd.sb_mbcnt; 264*4786Swnj while (bufs == 0) { 265*4786Swnj so->so_snd.sb_flags |= SB_WAIT; 266*4786Swnj sleep((caddr_t)&so->so_snd.sb_cc, PZERO+1); 267*4786Swnj } 268*4786Swnj mp = ⊤ 269*4786Swnj top = 0; 270*4786Swnj while (--bufs >= 0 && u.u_count > 0) { 271*4786Swnj MGET(m, 1); 272*4786Swnj if (m == NULL) { 273*4786Swnj error = ENOBUFS; 274*4786Swnj m_freem(top); 275*4786Swnj goto release; 276*4786Swnj } 277*4786Swnj if (u.u_count >= PGSIZE && bufs >= NMBPG) { 278*4786Swnj MPGET(p, 1); 279*4786Swnj if (p == 0) 280*4786Swnj goto nopage; 281*4786Swnj m->m_off = (int)p - (int)m; 282*4786Swnj len = PGSIZE; 283*4786Swnj } else { 284*4786Swnj nopages: 285*4786Swnj m->m_off = MMINOFF; 286*4786Swnj len = MIN(MLEN, u.u_count); 287*4786Swnj } 288*4786Swnj iomove(mtod(m, caddr_t), len, B_WRITE); 289*4786Swnj m->m_len = len; 290*4786Swnj *mp = m; 291*4786Swnj mp = &m->m_next; 292*4786Swnj } 293*4786Swnj s = splnet(); 294*4786Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, iap); 295*4786Swnj splx(s); 296*4786Swnj if (error) 297*4786Swnj break; 298*4786Swnj } 299*4786Swnj release: 300*4786Swnj so->so_snd.sb_flags &= ~SB_LOCK; 301*4786Swnj if (so->so_snd.sb_flags & SB_WANT) 302*4786Swnj wakeup((caddr_t)&so->so_sb.sb_flags); 303*4786Swnj return (error); 304*4786Swnj } 305*4786Swnj 306*4786Swnj /* 307*4786Swnj * Receive data on socket. 308*4786Swnj */ 309*4786Swnj sreceive() 310*4786Swnj { 311*4786Swnj register struct a { 312*4786Swnj int fdes; 313*4786Swnj in_addr *ain; 314*4786Swnj caddr_t cbuf; 315*4786Swnj int count; 316*4786Swnj } *uap = (struct a *)u.u_ap; 317*4786Swnj 318*4786Swnj fp = getf(uap->fdes); 319*4786Swnj if (fp == 0) 320*4786Swnj return; 321*4786Swnj if ((fp->f_flag & FSOCKET) == 0) { 322*4786Swnj u.u_error = ENOTSOCK; 323*4786Swnj return; 324*4786Swnj } 325*4786Swnj if (uap->count < 0) { 326*4786Swnj u.u_error = EINVAL; 327*4786Swnj return; 328*4786Swnj } 329*4786Swnj u.u_base = uap->buf; 330*4786Swnj u.u_count = uap->len; 331*4786Swnj u.u_segflg = 0; 332*4786Swnj if (useracc(u.u_base, u.u_count, B_WRITE) == 0 || 333*4786Swnj uap->ain && copyin((caddr_t)uap->ain, (caddr_t)&in, sizeof (in))) { 334*4786Swnj u.u_error = EFAULT; 335*4786Swnj return; 336*4786Swnj } 337*4786Swnj receive(fp->f_socket, uap->ain ? &in : 0); 338*4786Swnj } 339*4786Swnj 340*4786Swnj receive(so, iap) 341*4786Swnj register struct socket *so; 342*4786Swnj struct in_addr *iap; 343*4786Swnj { 344*4786Swnj register struct mbuf *m, *n; 345*4786Swnj register int eor, len, s; 346*4786Swnj 347*4786Swnj again: 348*4786Swnj while (so->so_rcv.sb_flags & SB_LOCK) { 349*4786Swnj so->so_rcv.sb_flags |= SB_WANT; 350*4786Swnj sleep((caddr_t)&so->so_rcv.sb_flags, PZERO+1); 351*4786Swnj } 352*4786Swnj if (so->so_rcv.sb_cc == 0) { 353*4786Swnj if ((so->so_proto->pr_usrreq)(so, PR_ISDISCONN, 0, 0) == 0) 354*4786Swnj return; 355*4786Swnj so->so_rcv.sb_flags |= SB_WAIT; 356*4786Swnj sleep((caddr_t)&so->so_rcv.sb_cc, PZERO+1); 357*4786Swnj goto again; 358*4786Swnj } 359*4786Swnj so->so_rcv.sb_flags |= SB_LOCK; 360*4786Swnj m = up->uc_rcv.sb_mb; 361*4786Swnj if (m == 0) 362*4786Swnj panic("receive"); 363*4786Swnj eor = 0; 364*4786Swnj do { 365*4786Swnj len = MIN(m->m_len, u.u_count); 366*4786Swnj if (len == m->m_len) { 367*4786Swnj eor = (int)m->m_act; 368*4786Swnj up->uc_rcv.sb_mb = m->m_next; 369*4786Swnj up->uc_rcv.sb_cc -= len; 370*4786Swnj if (up->uc_rcv.sb_cc < 0) 371*4786Swnj panic("receive 2"); 372*4786Swnj } 373*4786Swnj splx(s); 374*4786Swnj iomove(mtod(m, caddr_t), len, B_READ); 375*4786Swnj s = splnet(); 376*4786Swnj if (len == m->m_len) { 377*4786Swnj MFREE(m, n); 378*4786Swnj } else { 379*4786Swnj m->m_off += len; 380*4786Swnj m->m_len -= len; 381*4786Swnj up->uc_rcv.sb_cc -= len; 382*4786Swnj if (up->uc_rcv.sb_cc < 0) 383*4786Swnj panic("receive 3"); 384*4786Swnj } 385*4786Swnj } while ((m = up->uc_rcv.sb_mb) && u.u_count && !eor); 386*4786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 387*4786Swnj do { 388*4786Swnj m = so->so_rcv.sb_mb; 389*4786Swnj if (m == 0) 390*4786Swnj panic("receive 4"); 391*4786Swnj up->uc_rcv.sb_cc -= m->m_len; 392*4786Swnj if (up->uc_rcv.sb_cc < 0) 393*4786Swnj panic("receive 5"); 394*4786Swnj eor = (int)m->m_act; 395*4786Swnj so->so_rcv.sb_mb = m->m_next; 396*4786Swnj MFREE(m, n); 397*4786Swnj } while (eor == 0); 398*4786Swnj if (iap) 399*4786Swnj if ((so->so_proto->pr_flags & PR_PROVIDEADDR)) { 400*4786Swnj m = up->uc_rcv.sb_mb; 401*4786Swnj if (m == 0) 402*4786Swnj panic("receive 6"); 403*4786Swnj up->uc_rcv.sb_mb = m->m_next; 404*4786Swnj up->uc_rcv.sb_cc -= m->m_len; 405*4786Swnj len = MIN(m->m_len, sizeof (struct in_addr)); 406*4786Swnj bcopy(mtod(m, caddr_t), (caddr_t)iap, len); 407*4786Swnj } else 408*4786Swnj *iap = zeroin_addr; 409*4786Swnj (*so->so_proto->pr_usrreq)(up, PRU_RCVD, m, 0); 410*4786Swnj } 411*4786Swnj 412*4786Swnj skioctl() 413*4786Swnj { 414*4786Swnj 415*4786Swnj /* switch out based on socket type */ 416*4786Swnj } 417