1*9028Sroot /* uipc_usrreq.c 1.2 82/11/03 */ 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" 138925Sroot 148925Sroot /* 158925Sroot * Unix communications domain. 168925Sroot */ 178925Sroot 188925Sroot /*ARGSUSED*/ 19*9028Sroot uipc_usrreq(so, req, m, nam, opt) 208925Sroot struct socket *so; 218925Sroot int req; 22*9028Sroot struct mbuf *m, *nam; 23*9028Sroot struct socketopt *opt; 248925Sroot { 258925Sroot struct unpcb *unp = sotounpcb(so); 268925Sroot register struct socket *so2; 278925Sroot int error = 0; 288925Sroot 298925Sroot if (unp == 0 && req != PRU_ATTACH) 308925Sroot return (EINVAL); /* XXX */ 318925Sroot switch (req) { 328925Sroot 338925Sroot case PRU_ATTACH: 348925Sroot if (unp) { 358925Sroot error = EINVAL; 368925Sroot break; 378925Sroot } 38*9028Sroot error = unp_attach(so); 398925Sroot break; 408925Sroot 418925Sroot case PRU_DETACH: 428925Sroot unp_detach(unp); 438925Sroot break; 448925Sroot 458925Sroot case PRU_CONNECT: 46*9028Sroot error = unp_connect(so, nam); 478925Sroot break; 488925Sroot 498925Sroot case PRU_DISCONNECT: 508925Sroot unp_disconnect(unp); 518925Sroot break; 528925Sroot 538925Sroot /* BEGIN QUESTIONABLE */ 548925Sroot case PRU_ACCEPT: { 55*9028Sroot struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 568925Sroot 578925Sroot if (soun) { 588925Sroot bzero((caddr_t)soun, sizeof (*soun)); 598925Sroot soun->sun_family = AF_UNIX; 608925Sroot /* XXX */ 618925Sroot } 628925Sroot } 638925Sroot break; 648925Sroot 658925Sroot case PRU_SHUTDOWN: 668925Sroot socantsendmore(so); 678925Sroot unp_usrclosed(unp); 688925Sroot break; 698925Sroot /* END QUESTIONABLE */ 708925Sroot 718925Sroot case PRU_RCVD: 728925Sroot switch (so->so_type) { 738925Sroot 748925Sroot case SOCK_DGRAM: 758925Sroot panic("uipc 1"); 768925Sroot 778925Sroot case SOCK_STREAM: { 788925Sroot #define rcv (&so->so_rcv) 798925Sroot #define snd (&so2->so_snd) 808925Sroot if (unp->unp_conn == 0) 818925Sroot break; 828925Sroot so2 = unp->unp_conn->unp_socket; 838925Sroot /* 848925Sroot * Transfer resources back to send port 858925Sroot * and wakeup any waiting to write. 868925Sroot */ 878925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 888925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 898925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 908925Sroot rcv->sb_hiwat = rcv->sb_cc; 918925Sroot sbwakeup(snd); 928925Sroot #undef snd 938925Sroot #undef rcv 948925Sroot } 958925Sroot break; 968925Sroot 978925Sroot default: 988925Sroot panic("uipc 2"); 998925Sroot } 1008925Sroot break; 1018925Sroot 1028925Sroot case PRU_SEND: 1038925Sroot switch (so->so_type) { 1048925Sroot 1058925Sroot case SOCK_DGRAM: 106*9028Sroot if (nam) { 1078925Sroot if (unp->unp_conn) { 1088925Sroot error = EISCONN; 1098925Sroot break; 1108925Sroot } 111*9028Sroot error = unp_connect(so, nam); 1128925Sroot if (error) 1138925Sroot break; 1148925Sroot } else { 1158925Sroot if (unp->unp_conn == 0) { 1168925Sroot error = ENOTCONN; 1178925Sroot break; 1188925Sroot } 1198925Sroot } 1208925Sroot so2 = unp->unp_conn->unp_socket; 1218925Sroot if (sbspace(&so2->so_rcv) > 0) /* XXX */ 122*9028Sroot sbappendaddr(so2, m, nam); /* XXX */ 123*9028Sroot if (nam) 1248925Sroot unp_disconnect(so); 1258925Sroot break; 1268925Sroot 1278925Sroot case SOCK_STREAM: 1288925Sroot #define rcv (&so2->so_rcv) 1298925Sroot #define snd (&so->so_snd) 1308925Sroot if (unp->unp_conn == 0) 1318925Sroot panic("uipc 3"); 1328925Sroot so2 = unp->unp_conn->unp_socket; 1338925Sroot /* 1348925Sroot * Send to paired receive port, and then 1358925Sroot * give it enough resources to hold what it already has. 1368925Sroot * Wake up readers. 1378925Sroot */ 1388925Sroot sbappend(rcv, m); 1398925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1408925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1418925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1428925Sroot rcv->sb_hiwat = rcv->sb_cc; 1438925Sroot sbwakeup(rcv); 1448925Sroot #undef snd 1458925Sroot #undef rcv 1468925Sroot break; 1478925Sroot 1488925Sroot default: 1498925Sroot panic("uipc 4"); 1508925Sroot } 1518925Sroot break; 1528925Sroot 1538925Sroot case PRU_ABORT: 1548925Sroot unp_drop(unp, ECONNABORTED); 1558925Sroot break; 1568925Sroot 1578925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 1588925Sroot case PRU_CONTROL: 1598925Sroot error = EOPNOTSUPP; 1608925Sroot break; 1618925Sroot 1628925Sroot case PRU_SENSE: 1638925Sroot error = EOPNOTSUPP; 1648925Sroot break; 1658925Sroot /* END UNIMPLEMENTED HOOKS */ 1668925Sroot 1678925Sroot case PRU_RCVOOB: 1688925Sroot break; 1698925Sroot 1708925Sroot case PRU_SENDOOB: 1718925Sroot break; 1728925Sroot 1738925Sroot case PRU_SOCKADDR: 1748925Sroot break; 1758925Sroot 1768925Sroot case PRU_SLOWTIMO: 1778925Sroot break; 1788925Sroot 1798925Sroot default: 1808925Sroot panic("piusrreq"); 1818925Sroot } 1828925Sroot return (0); 1838925Sroot } 1848925Sroot 1858925Sroot int unp_sendspace = 1024*2; 1868925Sroot int unp_recvspace = 1024*2; 1878925Sroot 1888925Sroot unp_attach(so, soun) 1898925Sroot struct socket *so; 1908925Sroot struct sockaddr_un *soun; 1918925Sroot { 1928925Sroot register struct unpcb *unp; 1938925Sroot struct mbuf *m; 1948925Sroot int error; 1958925Sroot 1968925Sroot error = soreserve(so, unp_sendspace, unp_recvspace); 1978925Sroot if (error) 1988925Sroot goto bad; 1998925Sroot m = m_getclr(M_DONTWAIT); 2008925Sroot if (m == 0) { 2018925Sroot error = ENOBUFS; 2028925Sroot goto bad; 2038925Sroot } 2048925Sroot unp = mtod(m, struct unpcb *); 2058925Sroot so->so_pcb = (caddr_t)unp; 2068925Sroot unp->unp_socket = so; 2078925Sroot if (soun) { 2088925Sroot error = unp_bind(unp, soun); 2098925Sroot if (error) { 2108925Sroot unp_detach(unp); 2118925Sroot goto bad; 2128925Sroot } 2138925Sroot } 2148925Sroot return (0); 2158925Sroot bad: 2168925Sroot return (error); 2178925Sroot } 2188925Sroot 2198925Sroot unp_disconnect(unp) 2208925Sroot struct unpcb *unp; 2218925Sroot { 2228925Sroot register struct unpcb *unp2 = unp->unp_conn; 2238925Sroot 2248925Sroot if (unp2 == 0) 2258925Sroot return; 2268925Sroot unp->unp_conn = 0; 2278925Sroot soisdisconnected(unp->unp_socket); 2288925Sroot switch (unp->unp_socket->so_type) { 2298925Sroot 2308925Sroot case SOCK_DGRAM: 2318925Sroot if (unp2->unp_refs == unp) 2328925Sroot unp2->unp_refs = unp->unp_nextref; 2338925Sroot else { 2348925Sroot unp2 = unp2->unp_refs; 2358925Sroot for (;;) { 2368925Sroot if (unp2 == 0) 2378925Sroot panic("unp_disconnect"); 2388925Sroot if (unp2->unp_nextref == unp) 2398925Sroot break; 2408925Sroot unp2 = unp2->unp_nextref; 2418925Sroot } 2428925Sroot unp2->unp_nextref = unp->unp_nextref; 2438925Sroot } 2448925Sroot unp->unp_nextref = 0; 2458925Sroot break; 2468925Sroot 2478925Sroot case SOCK_STREAM: 2488925Sroot unp2->unp_conn = 0; 2498925Sroot soisdisconnected(unp2->unp_socket); 2508925Sroot unp_drop(unp2, ECONNRESET); 2518925Sroot break; 2528925Sroot } 2538925Sroot } 2548925Sroot 2558925Sroot unp_abort(unp) 2568925Sroot struct unpcb *unp; 2578925Sroot { 2588925Sroot 2598925Sroot unp_detach(unp); 2608925Sroot } 2618925Sroot 2628925Sroot unp_detach(unp) 2638925Sroot struct unpcb *unp; 2648925Sroot { 2658925Sroot 2668925Sroot if (unp->unp_inode) { 2678925Sroot irele(unp->unp_inode); 2688925Sroot unp->unp_inode = 0; 2698925Sroot } 2708925Sroot if (unp->unp_conn) 2718925Sroot unp_disconnect(unp); 2728925Sroot while (unp->unp_refs) 2738925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2748925Sroot soisdisconnected(unp->unp_socket); 2758925Sroot unp->unp_socket->so_pcb = 0; 2768925Sroot m_free(dtom(unp)); 2778925Sroot } 2788925Sroot 2798925Sroot unp_usrclosed(unp) 2808925Sroot struct unpcb *unp; 2818925Sroot { 2828925Sroot register struct socket *so = unp->unp_socket; 2838925Sroot 2848925Sroot #ifdef sometimes /* ??? */ 2858925Sroot soisdisconnected(unp->unp_socket); 2868925Sroot #endif 2878925Sroot } 2888925Sroot 2898925Sroot unp_drop(unp, errno) 2908925Sroot struct unpcb *unp; 2918925Sroot int errno; 2928925Sroot { 2938925Sroot 2948925Sroot unp->unp_socket->so_error = errno; 2958925Sroot unp_disconnect(unp); 2968925Sroot } 2978925Sroot 2988925Sroot unp_drain() 2998925Sroot { 3008925Sroot 3018925Sroot } 3028925Sroot 3038925Sroot unp_bind(unp, soun) 3048925Sroot struct unpcb *unp; 3058925Sroot struct sockaddr_un *soun; 3068925Sroot { 3078925Sroot register struct inode *ip; 3088925Sroot int error; 3098925Sroot extern schar(); 3108925Sroot 3118925Sroot u.u_dirp = soun->sun_path; 3128925Sroot soun->sun_path[sizeof(soun->sun_path)-1] = 0; 3138925Sroot ip = namei(schar, 1, 1); 3148925Sroot if (ip) { 3158925Sroot iput(ip); 3168925Sroot return (EEXIST); 3178925Sroot } 3188925Sroot ip = maknode(IFSOCK | 0777); 3198925Sroot if (ip == NULL) { 3208925Sroot error = u.u_error; /* XXX */ 3218925Sroot u.u_error = 0; /* XXX */ 3228925Sroot return (error); 3238925Sroot } 3248925Sroot ip->i_socket = unp->unp_socket; 3258925Sroot unp->unp_inode = ip; 3268925Sroot iunlock(ip); /* but keep reference */ 3278925Sroot return (0); 3288925Sroot } 3298925Sroot 3308925Sroot unp_connect(so, soun) 3318925Sroot struct socket *so; 3328925Sroot struct sockaddr_un *soun; 3338925Sroot { 3348925Sroot struct inode *ip; 3358925Sroot int error; 3368925Sroot 3378925Sroot u.u_dirp = soun->sun_path; 3388925Sroot soun->sun_path[sizeof(soun->sun_path)-1] = 0; 3398925Sroot ip = namei(schar, 0, 1); 3408925Sroot if (ip == 0) { 3418925Sroot error = u.u_error; 3428925Sroot u.u_error = 0; 3438925Sroot return (ENOENT); 3448925Sroot } 3458925Sroot error = unp_connectip(so, ip); 3468925Sroot return (error); 3478925Sroot } 3488925Sroot 3498925Sroot unp_connectip(so, ip) 3508925Sroot struct socket *so; 3518925Sroot struct inode *ip; 3528925Sroot { 3538925Sroot struct unpcb *unp = sotounpcb(so); 3548925Sroot struct socket *so2, *so3; 3558925Sroot int error; 3568925Sroot struct unpcb *unp2; 3578925Sroot 3588925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3598925Sroot error = ENOTSOCK; 3608925Sroot goto bad; 3618925Sroot } 3628925Sroot so2 = ip->i_socket; 3638925Sroot if (so2 == 0) { 3648925Sroot error = ECONNREFUSED; 3658925Sroot goto bad; 3668925Sroot } 3678925Sroot if (so2->so_type != so->so_type) { 3688925Sroot error = EPROTOTYPE; 3698925Sroot goto bad; 3708925Sroot } 3718925Sroot switch (so->so_type) { 3728925Sroot 3738925Sroot case SOCK_DGRAM: 3748925Sroot unp->unp_conn = sotounpcb(so2); 3758925Sroot unp2 = sotounpcb(so2); 3768925Sroot unp->unp_nextref = unp2->unp_refs; 3778925Sroot unp2->unp_refs = unp; 3788925Sroot break; 3798925Sroot 3808925Sroot case SOCK_STREAM: 3818925Sroot if ((so2->so_options&SO_ACCEPTCONN) == 0 || 3828925Sroot (so3 = sonewconn(so2)) == 0) { 3838925Sroot error = ECONNREFUSED; 3848925Sroot goto bad; 3858925Sroot } 3868925Sroot unp->unp_conn = sotounpcb(so3); 3878925Sroot break; 3888925Sroot 3898925Sroot default: 3908925Sroot panic("uipc connip"); 3918925Sroot } 3928925Sroot soisconnected(unp->unp_conn->unp_socket); 3938925Sroot soisconnected(so); 3948925Sroot iput(ip); 3958925Sroot return (0); 3968925Sroot bad: 3978925Sroot iput(ip); 3988925Sroot return (error); 3998925Sroot } 400