1*12760Ssam /* uipc_usrreq.c 1.10 83/05/27 */ 28925Sroot 38925Sroot #include "../h/param.h" 48925Sroot #include "../h/dir.h" 58925Sroot #include "../h/user.h" 68925Sroot #include "../h/mbuf.h" 78925Sroot #include "../h/protosw.h" 88925Sroot #include "../h/socket.h" 98925Sroot #include "../h/socketvar.h" 108925Sroot #include "../h/unpcb.h" 118925Sroot #include "../h/un.h" 128925Sroot #include "../h/inode.h" 139169Ssam #include "../h/nami.h" 14*12760Ssam #include "../h/file.h" 158925Sroot 168925Sroot /* 178925Sroot * Unix communications domain. 18*12760Ssam * 19*12760Ssam * TODO: 20*12760Ssam * SEQPACKET, RDM 21*12760Ssam * change for names in file system 22*12760Ssam * need a proper out-of-band 238925Sroot */ 248925Sroot 258925Sroot /*ARGSUSED*/ 26*12760Ssam uipc_usrreq(so, req, m, nam, rights) 278925Sroot struct socket *so; 288925Sroot int req; 29*12760Ssam struct mbuf *m, *nam, *rights; 308925Sroot { 318925Sroot struct unpcb *unp = sotounpcb(so); 328925Sroot register struct socket *so2; 338925Sroot int error = 0; 348925Sroot 35*12760Ssam if (req != PRU_SEND && rights && rights->m_len) { 36*12760Ssam error = EOPNOTSUPP; 37*12760Ssam goto release; 38*12760Ssam } 39*12760Ssam if (unp == 0 && req != PRU_ATTACH) { 40*12760Ssam error = EINVAL; 41*12760Ssam goto release; 42*12760Ssam } 438925Sroot switch (req) { 448925Sroot 458925Sroot case PRU_ATTACH: 468925Sroot if (unp) { 479169Ssam error = EISCONN; 488925Sroot break; 498925Sroot } 509028Sroot error = unp_attach(so); 518925Sroot break; 528925Sroot 538925Sroot case PRU_DETACH: 548925Sroot unp_detach(unp); 558925Sroot break; 568925Sroot 579169Ssam case PRU_BIND: 589169Ssam error = unp_bind(unp, nam); 599169Ssam break; 609169Ssam 619169Ssam case PRU_LISTEN: 629169Ssam if (unp->unp_inode == 0) 639169Ssam error = EINVAL; 649169Ssam break; 659169Ssam 668925Sroot case PRU_CONNECT: 679028Sroot error = unp_connect(so, nam); 688925Sroot break; 698925Sroot 70*12760Ssam #ifdef notdef 71*12760Ssam case PRU_CONNECT2: 72*12760Ssam error = unp_connect2(so, (struct mbuf *)0, (struct socket *)nam); 73*12760Ssam break; 74*12760Ssam 75*12760Ssam #endif 768925Sroot case PRU_DISCONNECT: 778925Sroot unp_disconnect(unp); 788925Sroot break; 798925Sroot 809169Ssam case PRU_ACCEPT: 819169Ssam nam->m_len = unp->unp_remaddr->m_len; 829169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 839169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 848925Sroot break; 858925Sroot 868925Sroot case PRU_SHUTDOWN: 878925Sroot socantsendmore(so); 888925Sroot unp_usrclosed(unp); 898925Sroot break; 908925Sroot 918925Sroot case PRU_RCVD: 928925Sroot switch (so->so_type) { 938925Sroot 948925Sroot case SOCK_DGRAM: 958925Sroot panic("uipc 1"); 9610139Ssam /*NOTREACHED*/ 978925Sroot 9810139Ssam case SOCK_STREAM: 998925Sroot #define rcv (&so->so_rcv) 1008925Sroot #define snd (&so2->so_snd) 1018925Sroot if (unp->unp_conn == 0) 1028925Sroot break; 1038925Sroot so2 = unp->unp_conn->unp_socket; 1048925Sroot /* 1058925Sroot * Transfer resources back to send port 1068925Sroot * and wakeup any waiting to write. 1078925Sroot */ 1088925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 1098925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1108925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 1118925Sroot rcv->sb_hiwat = rcv->sb_cc; 1128925Sroot sbwakeup(snd); 1138925Sroot #undef snd 1148925Sroot #undef rcv 1158925Sroot break; 1168925Sroot 1178925Sroot default: 1188925Sroot panic("uipc 2"); 1198925Sroot } 1208925Sroot break; 1218925Sroot 1228925Sroot case PRU_SEND: 1238925Sroot switch (so->so_type) { 1248925Sroot 1258925Sroot case SOCK_DGRAM: 1269028Sroot if (nam) { 1278925Sroot if (unp->unp_conn) { 1288925Sroot error = EISCONN; 1298925Sroot break; 1308925Sroot } 1319028Sroot error = unp_connect(so, nam); 1328925Sroot if (error) 1338925Sroot break; 1348925Sroot } else { 1358925Sroot if (unp->unp_conn == 0) { 1368925Sroot error = ENOTCONN; 1378925Sroot break; 1388925Sroot } 1398925Sroot } 1408925Sroot so2 = unp->unp_conn->unp_socket; 1419169Ssam /* BEGIN XXX */ 142*12760Ssam if (rights) { 143*12760Ssam error = unp_internalize(rights); 144*12760Ssam if (error) 145*12760Ssam break; 146*12760Ssam } 147*12760Ssam if (sbspace(&so2->so_rcv) > 0) { 1489169Ssam (void) sbappendaddr(&so2->so_rcv, 149*12760Ssam mtod(nam, struct sockaddr *), m, 150*12760Ssam rights); 151*12760Ssam sbwakeup(&so2->so_rcv); 152*12760Ssam m = 0; 153*12760Ssam } 1549169Ssam /* END XXX */ 1559028Sroot if (nam) 1569169Ssam unp_disconnect(unp); 1578925Sroot break; 1588925Sroot 1598925Sroot case SOCK_STREAM: 1608925Sroot #define rcv (&so2->so_rcv) 1618925Sroot #define snd (&so->so_snd) 162*12760Ssam if (rights && rights->m_len) { 163*12760Ssam error = EOPNOTSUPP; 164*12760Ssam break; 165*12760Ssam } 1668925Sroot if (unp->unp_conn == 0) 1678925Sroot panic("uipc 3"); 1688925Sroot so2 = unp->unp_conn->unp_socket; 1698925Sroot /* 1708925Sroot * Send to paired receive port, and then 1718925Sroot * give it enough resources to hold what it already has. 1728925Sroot * Wake up readers. 1738925Sroot */ 1748925Sroot sbappend(rcv, m); 1758925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1768925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1778925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1788925Sroot rcv->sb_hiwat = rcv->sb_cc; 1798925Sroot sbwakeup(rcv); 1808925Sroot #undef snd 1818925Sroot #undef rcv 1828925Sroot break; 1838925Sroot 1848925Sroot default: 1858925Sroot panic("uipc 4"); 1868925Sroot } 187*12760Ssam m = 0; 1888925Sroot break; 1898925Sroot 1908925Sroot case PRU_ABORT: 1918925Sroot unp_drop(unp, ECONNABORTED); 1928925Sroot break; 1938925Sroot 1948925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 1958925Sroot case PRU_CONTROL: 1968925Sroot error = EOPNOTSUPP; 1978925Sroot break; 1988925Sroot 1998925Sroot case PRU_SENSE: 2008925Sroot error = EOPNOTSUPP; 2018925Sroot break; 2028925Sroot /* END UNIMPLEMENTED HOOKS */ 2038925Sroot 2048925Sroot case PRU_RCVOOB: 2058925Sroot break; 2068925Sroot 2078925Sroot case PRU_SENDOOB: 2088925Sroot break; 2098925Sroot 2108925Sroot case PRU_SOCKADDR: 2118925Sroot break; 2128925Sroot 2138925Sroot case PRU_SLOWTIMO: 2148925Sroot break; 2158925Sroot 2168925Sroot default: 2178925Sroot panic("piusrreq"); 2188925Sroot } 219*12760Ssam release: 220*12760Ssam if (m) 221*12760Ssam m_freem(m); 22211709Ssam return (error); 2238925Sroot } 2248925Sroot 225*12760Ssam /* SHOULD BE PIPSIZ and 0 */ 2268925Sroot int unp_sendspace = 1024*2; 2278925Sroot int unp_recvspace = 1024*2; 2288925Sroot 2299169Ssam unp_attach(so) 2308925Sroot struct socket *so; 2318925Sroot { 2329169Ssam register struct mbuf *m; 2338925Sroot register struct unpcb *unp; 2348925Sroot int error; 2358925Sroot 2368925Sroot error = soreserve(so, unp_sendspace, unp_recvspace); 2378925Sroot if (error) 23810139Ssam return (error); 2399637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 24010139Ssam if (m == NULL) 24110139Ssam return (ENOBUFS); 2428925Sroot unp = mtod(m, struct unpcb *); 2438925Sroot so->so_pcb = (caddr_t)unp; 2448925Sroot unp->unp_socket = so; 2458925Sroot return (0); 2468925Sroot } 2478925Sroot 2488925Sroot unp_detach(unp) 2499169Ssam register struct unpcb *unp; 2508925Sroot { 2518925Sroot 2528925Sroot if (unp->unp_inode) { 2538925Sroot irele(unp->unp_inode); 2548925Sroot unp->unp_inode = 0; 2558925Sroot } 2568925Sroot if (unp->unp_conn) 2578925Sroot unp_disconnect(unp); 2588925Sroot while (unp->unp_refs) 2598925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2608925Sroot soisdisconnected(unp->unp_socket); 2618925Sroot unp->unp_socket->so_pcb = 0; 2629169Ssam m_freem(unp->unp_remaddr); 2639169Ssam (void) m_free(dtom(unp)); 2648925Sroot } 2658925Sroot 2669169Ssam unp_bind(unp, nam) 2678925Sroot struct unpcb *unp; 2689169Ssam struct mbuf *nam; 2698925Sroot { 2709169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2718925Sroot register struct inode *ip; 2729169Ssam extern schar(); 2738925Sroot int error; 2748925Sroot 2758925Sroot u.u_dirp = soun->sun_path; 276*12760Ssam if (nam->m_len == MLEN) 277*12760Ssam return (EINVAL); 278*12760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 279*12760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 2809169Ssam ip = namei(schar, CREATE, 1); 2818925Sroot if (ip) { 2828925Sroot iput(ip); 28310139Ssam return (EADDRINUSE); 2848925Sroot } 28511828Ssam if (error = u.u_error) { 28611828Ssam u.u_error = 0; /* XXX */ 28711828Ssam return (error); 28811828Ssam } 2898925Sroot ip = maknode(IFSOCK | 0777); 2908925Sroot if (ip == NULL) { 2918925Sroot error = u.u_error; /* XXX */ 2928925Sroot u.u_error = 0; /* XXX */ 2938925Sroot return (error); 2948925Sroot } 2958925Sroot ip->i_socket = unp->unp_socket; 2968925Sroot unp->unp_inode = ip; 2978925Sroot iunlock(ip); /* but keep reference */ 2988925Sroot return (0); 2998925Sroot } 3008925Sroot 3019169Ssam unp_connect(so, nam) 3028925Sroot struct socket *so; 3039169Ssam struct mbuf *nam; 3048925Sroot { 3059169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3069169Ssam register struct inode *ip; 3078925Sroot int error; 308*12760Ssam register struct socket *so2; 3098925Sroot 3108925Sroot u.u_dirp = soun->sun_path; 311*12760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 312*12760Ssam return (EMSGSIZE); 313*12760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 3149169Ssam ip = namei(schar, LOOKUP, 1); 3158925Sroot if (ip == 0) { 3168925Sroot error = u.u_error; 3178925Sroot u.u_error = 0; 31810139Ssam return (error); /* XXX */ 3198925Sroot } 3208925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3218925Sroot error = ENOTSOCK; 3228925Sroot goto bad; 3238925Sroot } 3248925Sroot so2 = ip->i_socket; 3258925Sroot if (so2 == 0) { 3268925Sroot error = ECONNREFUSED; 3278925Sroot goto bad; 3288925Sroot } 329*12760Ssam error = unp_connect2(so, nam, so2); 330*12760Ssam bad: 331*12760Ssam iput(ip); 332*12760Ssam return (error); 333*12760Ssam } 334*12760Ssam 335*12760Ssam unp_connect2(so, sonam, so2) 336*12760Ssam register struct socket *so; 337*12760Ssam struct mbuf *sonam; 338*12760Ssam register struct socket *so2; 339*12760Ssam { 340*12760Ssam register struct unpcb *unp = sotounpcb(so); 341*12760Ssam register struct unpcb *unp2; 342*12760Ssam 343*12760Ssam if (so2->so_type != so->so_type) 344*12760Ssam return (EPROTOTYPE); 3458925Sroot switch (so->so_type) { 3468925Sroot 3478925Sroot case SOCK_DGRAM: 3488925Sroot unp2 = sotounpcb(so2); 349*12760Ssam unp->unp_conn = unp2; 3508925Sroot unp->unp_nextref = unp2->unp_refs; 3518925Sroot unp2->unp_refs = unp; 3528925Sroot break; 3538925Sroot 3548925Sroot case SOCK_STREAM: 3558925Sroot if ((so2->so_options&SO_ACCEPTCONN) == 0 || 356*12760Ssam (so2 = sonewconn(so2)) == 0) 357*12760Ssam return (ECONNREFUSED); 3589169Ssam unp2 = sotounpcb(so2); 3599169Ssam unp->unp_conn = unp2; 3609169Ssam unp2->unp_conn = unp; 361*12760Ssam if (sonam) 362*12760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 3638925Sroot break; 3648925Sroot 3658925Sroot default: 366*12760Ssam panic("unp_connect2"); 3678925Sroot } 3689169Ssam soisconnected(so2); 3698925Sroot soisconnected(so); 3708925Sroot return (0); 3718925Sroot } 3729169Ssam 3739169Ssam unp_disconnect(unp) 3749169Ssam struct unpcb *unp; 3759169Ssam { 3769169Ssam register struct unpcb *unp2 = unp->unp_conn; 3779169Ssam 3789169Ssam if (unp2 == 0) 3799169Ssam return; 3809169Ssam unp->unp_conn = 0; 3819169Ssam soisdisconnected(unp->unp_socket); 3829169Ssam switch (unp->unp_socket->so_type) { 3839169Ssam 3849169Ssam case SOCK_DGRAM: 3859169Ssam if (unp2->unp_refs == unp) 3869169Ssam unp2->unp_refs = unp->unp_nextref; 3879169Ssam else { 3889169Ssam unp2 = unp2->unp_refs; 3899169Ssam for (;;) { 3909169Ssam if (unp2 == 0) 3919169Ssam panic("unp_disconnect"); 3929169Ssam if (unp2->unp_nextref == unp) 3939169Ssam break; 3949169Ssam unp2 = unp2->unp_nextref; 3959169Ssam } 3969169Ssam unp2->unp_nextref = unp->unp_nextref; 3979169Ssam } 3989169Ssam unp->unp_nextref = 0; 3999169Ssam break; 4009169Ssam 4019169Ssam case SOCK_STREAM: 4029169Ssam unp2->unp_conn = 0; 4039169Ssam soisdisconnected(unp2->unp_socket); 4049169Ssam break; 4059169Ssam } 4069169Ssam } 4079169Ssam 408*12760Ssam #ifdef notdef 4099169Ssam unp_abort(unp) 4109169Ssam struct unpcb *unp; 4119169Ssam { 4129169Ssam 4139169Ssam unp_detach(unp); 4149169Ssam } 415*12760Ssam #endif 4169169Ssam 4179169Ssam /*ARGSUSED*/ 4189169Ssam unp_usrclosed(unp) 4199169Ssam struct unpcb *unp; 4209169Ssam { 4219169Ssam 4229169Ssam } 4239169Ssam 4249169Ssam unp_drop(unp, errno) 4259169Ssam struct unpcb *unp; 4269169Ssam int errno; 4279169Ssam { 4289169Ssam 4299169Ssam unp->unp_socket->so_error = errno; 4309169Ssam unp_disconnect(unp); 4319169Ssam } 4329169Ssam 433*12760Ssam #ifdef notdef 4349169Ssam unp_drain() 4359169Ssam { 4369169Ssam 4379169Ssam } 438*12760Ssam #endif 439*12760Ssam 440*12760Ssam unp_externalize(rights) 441*12760Ssam struct mbuf *rights; 442*12760Ssam { 443*12760Ssam int newfds = rights->m_len / sizeof (int); 444*12760Ssam register int i; 445*12760Ssam register struct file **rp = mtod(rights, struct file **); 446*12760Ssam register struct file *fp; 447*12760Ssam int f; 448*12760Ssam 449*12760Ssam if (newfds > ufavail()) { 450*12760Ssam for (i = 0; i < newfds; i++) { 451*12760Ssam fp = *rp; 452*12760Ssam unp_discard(fp); 453*12760Ssam *rp++ = 0; 454*12760Ssam } 455*12760Ssam return (EMSGSIZE); 456*12760Ssam } 457*12760Ssam for (i = 0; i < newfds; i++) { 458*12760Ssam f = ufalloc(0); 459*12760Ssam if (f < 0) 460*12760Ssam panic("unp_externalize"); 461*12760Ssam fp = *rp; 462*12760Ssam u.u_ofile[f] = fp; 463*12760Ssam fp->f_msgcount--; 464*12760Ssam *(int *)rp = f; 465*12760Ssam } 466*12760Ssam return (0); 467*12760Ssam } 468*12760Ssam 469*12760Ssam unp_internalize(rights) 470*12760Ssam struct mbuf *rights; 471*12760Ssam { 472*12760Ssam register struct file **rp; 473*12760Ssam int oldfds = rights->m_len / sizeof (int); 474*12760Ssam register int i; 475*12760Ssam register struct file *fp; 476*12760Ssam 477*12760Ssam rp = mtod(rights, struct file **); 478*12760Ssam for (i = 0; i < oldfds; i++) { 479*12760Ssam if (getf(*(int *)rp++) == 0) 480*12760Ssam return (EBADF); 481*12760Ssam rp = mtod(rights, struct file **); 482*12760Ssam for (i = 0; i < oldfds; i++) 483*12760Ssam fp = getf(*(int *)rp); 484*12760Ssam *rp++ = fp; 485*12760Ssam fp->f_count++; 486*12760Ssam fp->f_msgcount++; 487*12760Ssam } 488*12760Ssam return (0); 489*12760Ssam } 490*12760Ssam 491*12760Ssam int unp_defer, unp_gcing; 492*12760Ssam int unp_mark(); 493*12760Ssam 494*12760Ssam unp_gc() 495*12760Ssam { 496*12760Ssam register struct file *fp; 497*12760Ssam register struct socket *so; 498*12760Ssam 499*12760Ssam if (unp_gcing) 500*12760Ssam return; 501*12760Ssam unp_gcing = 1; 502*12760Ssam restart: 503*12760Ssam unp_defer = 0; 504*12760Ssam for (fp = file; fp < fileNFILE; fp++) 505*12760Ssam fp->f_flag &= ~(FMARK|FDEFER); 506*12760Ssam do { 507*12760Ssam for (fp = file; fp < fileNFILE; fp++) { 508*12760Ssam if (fp->f_count == 0) 509*12760Ssam continue; 510*12760Ssam if (fp->f_flag & FDEFER) { 511*12760Ssam fp->f_flag &= ~FDEFER; 512*12760Ssam unp_defer--; 513*12760Ssam } else { 514*12760Ssam if (fp->f_flag & FMARK) 515*12760Ssam continue; 516*12760Ssam if (fp->f_count == fp->f_msgcount) 517*12760Ssam continue; 518*12760Ssam fp->f_flag |= FMARK; 519*12760Ssam } 520*12760Ssam if (fp->f_type != DTYPE_SOCKET) 521*12760Ssam continue; 522*12760Ssam so = (struct socket *)fp->f_data; 523*12760Ssam if (so->so_proto->pr_family != AF_UNIX || 524*12760Ssam (so->so_proto->pr_flags&PR_ADDR) == 0) 525*12760Ssam continue; 526*12760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 527*12760Ssam sbwait(&so->so_rcv); 528*12760Ssam goto restart; 529*12760Ssam } 530*12760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 531*12760Ssam } 532*12760Ssam } while (unp_defer); 533*12760Ssam for (fp = file; fp < fileNFILE; fp++) { 534*12760Ssam if (fp->f_count == 0) 535*12760Ssam continue; 536*12760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 537*12760Ssam if (fp->f_type != DTYPE_SOCKET) 538*12760Ssam panic("unp_gc"); 539*12760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 540*12760Ssam } 541*12760Ssam } 542*12760Ssam unp_gcing = 0; 543*12760Ssam } 544*12760Ssam 545*12760Ssam unp_scan(m, op) 546*12760Ssam register struct mbuf *m; 547*12760Ssam int (*op)(); 548*12760Ssam { 549*12760Ssam register struct file **rp; 550*12760Ssam register int i; 551*12760Ssam int qfds; 552*12760Ssam 553*12760Ssam while (m) { 554*12760Ssam m = m->m_next; 555*12760Ssam if (m == 0) 556*12760Ssam goto bad; 557*12760Ssam if (m->m_len) { 558*12760Ssam qfds = m->m_len / sizeof (struct file *); 559*12760Ssam rp = mtod(m, struct file **); 560*12760Ssam for (i = 0; i < qfds; i++) 561*12760Ssam (*op)(*rp++); 562*12760Ssam } 563*12760Ssam do { 564*12760Ssam m = m->m_next; 565*12760Ssam if (m == 0) 566*12760Ssam goto bad; 567*12760Ssam } while (m->m_act == 0); 568*12760Ssam m = m->m_next; 569*12760Ssam } 570*12760Ssam return; 571*12760Ssam bad: 572*12760Ssam panic("unp_gcscan"); 573*12760Ssam } 574*12760Ssam 575*12760Ssam unp_mark(fp) 576*12760Ssam struct file *fp; 577*12760Ssam { 578*12760Ssam 579*12760Ssam if (fp->f_flag & FMARK) 580*12760Ssam return; 581*12760Ssam unp_defer++; 582*12760Ssam fp->f_flag |= (FMARK|FDEFER); 583*12760Ssam } 584*12760Ssam 585*12760Ssam unp_discard(fp) 586*12760Ssam struct file *fp; 587*12760Ssam { 588*12760Ssam 589*12760Ssam fp->f_msgcount--; 590*12760Ssam closef(fp, 0); 591*12760Ssam } 592