1*11828Ssam /* uipc_usrreq.c 1.9 83/04/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" 139169Ssam #include "../h/nami.h" 148925Sroot 158925Sroot /* 168925Sroot * Unix communications domain. 178925Sroot */ 188925Sroot 198925Sroot /*ARGSUSED*/ 2010265Ssam uipc_usrreq(so, req, m, nam) 218925Sroot struct socket *so; 228925Sroot int req; 239028Sroot struct mbuf *m, *nam; 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) { 359169Ssam error = EISCONN; 368925Sroot break; 378925Sroot } 389028Sroot error = unp_attach(so); 398925Sroot break; 408925Sroot 418925Sroot case PRU_DETACH: 428925Sroot unp_detach(unp); 438925Sroot break; 448925Sroot 459169Ssam case PRU_BIND: 469169Ssam error = unp_bind(unp, nam); 479169Ssam break; 489169Ssam 499169Ssam case PRU_LISTEN: 509169Ssam if (unp->unp_inode == 0) 519169Ssam error = EINVAL; 529169Ssam break; 539169Ssam 548925Sroot case PRU_CONNECT: 559028Sroot error = unp_connect(so, nam); 568925Sroot break; 578925Sroot 588925Sroot case PRU_DISCONNECT: 598925Sroot unp_disconnect(unp); 608925Sroot break; 618925Sroot 629169Ssam case PRU_ACCEPT: 639169Ssam nam->m_len = unp->unp_remaddr->m_len; 649169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 659169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 668925Sroot break; 678925Sroot 688925Sroot case PRU_SHUTDOWN: 698925Sroot socantsendmore(so); 708925Sroot unp_usrclosed(unp); 718925Sroot break; 728925Sroot 738925Sroot case PRU_RCVD: 748925Sroot switch (so->so_type) { 758925Sroot 768925Sroot case SOCK_DGRAM: 778925Sroot panic("uipc 1"); 7810139Ssam /*NOTREACHED*/ 798925Sroot 8010139Ssam case SOCK_STREAM: 818925Sroot #define rcv (&so->so_rcv) 828925Sroot #define snd (&so2->so_snd) 838925Sroot if (unp->unp_conn == 0) 848925Sroot break; 858925Sroot so2 = unp->unp_conn->unp_socket; 868925Sroot /* 878925Sroot * Transfer resources back to send port 888925Sroot * and wakeup any waiting to write. 898925Sroot */ 908925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 918925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 928925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 938925Sroot rcv->sb_hiwat = rcv->sb_cc; 948925Sroot sbwakeup(snd); 958925Sroot #undef snd 968925Sroot #undef rcv 978925Sroot break; 988925Sroot 998925Sroot default: 1008925Sroot panic("uipc 2"); 1018925Sroot } 1028925Sroot break; 1038925Sroot 1048925Sroot case PRU_SEND: 1058925Sroot switch (so->so_type) { 1068925Sroot 1078925Sroot case SOCK_DGRAM: 1089028Sroot if (nam) { 1098925Sroot if (unp->unp_conn) { 1108925Sroot error = EISCONN; 1118925Sroot break; 1128925Sroot } 1139028Sroot error = unp_connect(so, nam); 1148925Sroot if (error) 1158925Sroot break; 1168925Sroot } else { 1178925Sroot if (unp->unp_conn == 0) { 1188925Sroot error = ENOTCONN; 1198925Sroot break; 1208925Sroot } 1218925Sroot } 1228925Sroot so2 = unp->unp_conn->unp_socket; 1239169Ssam /* BEGIN XXX */ 1249169Ssam if (sbspace(&so2->so_rcv) > 0) 1259169Ssam (void) sbappendaddr(&so2->so_rcv, 1269169Ssam mtod(nam, struct sockaddr *), m); 1279169Ssam /* END XXX */ 1289028Sroot if (nam) 1299169Ssam unp_disconnect(unp); 1308925Sroot break; 1318925Sroot 1328925Sroot case SOCK_STREAM: 1338925Sroot #define rcv (&so2->so_rcv) 1348925Sroot #define snd (&so->so_snd) 1358925Sroot if (unp->unp_conn == 0) 1368925Sroot panic("uipc 3"); 1378925Sroot so2 = unp->unp_conn->unp_socket; 1388925Sroot /* 1398925Sroot * Send to paired receive port, and then 1408925Sroot * give it enough resources to hold what it already has. 1418925Sroot * Wake up readers. 1428925Sroot */ 1438925Sroot sbappend(rcv, m); 1448925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1458925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1468925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1478925Sroot rcv->sb_hiwat = rcv->sb_cc; 1488925Sroot sbwakeup(rcv); 1498925Sroot #undef snd 1508925Sroot #undef rcv 1518925Sroot break; 1528925Sroot 1538925Sroot default: 1548925Sroot panic("uipc 4"); 1558925Sroot } 1568925Sroot break; 1578925Sroot 1588925Sroot case PRU_ABORT: 1598925Sroot unp_drop(unp, ECONNABORTED); 1608925Sroot break; 1618925Sroot 1628925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 1638925Sroot case PRU_CONTROL: 1648925Sroot error = EOPNOTSUPP; 1658925Sroot break; 1668925Sroot 1678925Sroot case PRU_SENSE: 1688925Sroot error = EOPNOTSUPP; 1698925Sroot break; 1708925Sroot /* END UNIMPLEMENTED HOOKS */ 1718925Sroot 1728925Sroot case PRU_RCVOOB: 1738925Sroot break; 1748925Sroot 1758925Sroot case PRU_SENDOOB: 1768925Sroot break; 1778925Sroot 1788925Sroot case PRU_SOCKADDR: 1798925Sroot break; 1808925Sroot 1818925Sroot case PRU_SLOWTIMO: 1828925Sroot break; 1838925Sroot 1848925Sroot default: 1858925Sroot panic("piusrreq"); 1868925Sroot } 18711709Ssam return (error); 1888925Sroot } 1898925Sroot 1908925Sroot int unp_sendspace = 1024*2; 1918925Sroot int unp_recvspace = 1024*2; 1928925Sroot 1939169Ssam unp_attach(so) 1948925Sroot struct socket *so; 1958925Sroot { 1969169Ssam register struct mbuf *m; 1978925Sroot register struct unpcb *unp; 1988925Sroot int error; 1998925Sroot 2008925Sroot error = soreserve(so, unp_sendspace, unp_recvspace); 2018925Sroot if (error) 20210139Ssam return (error); 2039637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 20410139Ssam if (m == NULL) 20510139Ssam return (ENOBUFS); 2068925Sroot unp = mtod(m, struct unpcb *); 2078925Sroot so->so_pcb = (caddr_t)unp; 2088925Sroot unp->unp_socket = so; 2098925Sroot return (0); 2108925Sroot } 2118925Sroot 2128925Sroot unp_detach(unp) 2139169Ssam register struct unpcb *unp; 2148925Sroot { 2158925Sroot 2168925Sroot if (unp->unp_inode) { 2178925Sroot irele(unp->unp_inode); 2188925Sroot unp->unp_inode = 0; 2198925Sroot } 2208925Sroot if (unp->unp_conn) 2218925Sroot unp_disconnect(unp); 2228925Sroot while (unp->unp_refs) 2238925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2248925Sroot soisdisconnected(unp->unp_socket); 2258925Sroot unp->unp_socket->so_pcb = 0; 2269169Ssam m_freem(unp->unp_remaddr); 2279169Ssam (void) m_free(dtom(unp)); 2288925Sroot } 2298925Sroot 2309169Ssam unp_bind(unp, nam) 2318925Sroot struct unpcb *unp; 2329169Ssam struct mbuf *nam; 2338925Sroot { 2349169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2358925Sroot register struct inode *ip; 2369169Ssam extern schar(); 2378925Sroot int error; 2388925Sroot 2398925Sroot u.u_dirp = soun->sun_path; 2408925Sroot soun->sun_path[sizeof(soun->sun_path)-1] = 0; 2419169Ssam ip = namei(schar, CREATE, 1); 2428925Sroot if (ip) { 2438925Sroot iput(ip); 24410139Ssam return (EADDRINUSE); 2458925Sroot } 246*11828Ssam if (error = u.u_error) { 247*11828Ssam u.u_error = 0; /* XXX */ 248*11828Ssam return (error); 249*11828Ssam } 2508925Sroot ip = maknode(IFSOCK | 0777); 2518925Sroot if (ip == NULL) { 2528925Sroot error = u.u_error; /* XXX */ 2538925Sroot u.u_error = 0; /* XXX */ 2548925Sroot return (error); 2558925Sroot } 2568925Sroot ip->i_socket = unp->unp_socket; 2578925Sroot unp->unp_inode = ip; 2588925Sroot iunlock(ip); /* but keep reference */ 2598925Sroot return (0); 2608925Sroot } 2618925Sroot 2629169Ssam unp_connect(so, nam) 2638925Sroot struct socket *so; 2649169Ssam struct mbuf *nam; 2658925Sroot { 2669169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2679169Ssam struct unpcb *unp = sotounpcb(so); 2689169Ssam register struct inode *ip; 2698925Sroot int error; 2709169Ssam struct socket *so2; 2719169Ssam struct unpcb *unp2; 2728925Sroot 2738925Sroot u.u_dirp = soun->sun_path; 2748925Sroot soun->sun_path[sizeof(soun->sun_path)-1] = 0; 2759169Ssam ip = namei(schar, LOOKUP, 1); 2768925Sroot if (ip == 0) { 2778925Sroot error = u.u_error; 2788925Sroot u.u_error = 0; 27910139Ssam return (error); /* XXX */ 2808925Sroot } 2818925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 2828925Sroot error = ENOTSOCK; 2838925Sroot goto bad; 2848925Sroot } 2858925Sroot so2 = ip->i_socket; 2868925Sroot if (so2 == 0) { 2878925Sroot error = ECONNREFUSED; 2888925Sroot goto bad; 2898925Sroot } 2908925Sroot if (so2->so_type != so->so_type) { 2918925Sroot error = EPROTOTYPE; 2928925Sroot goto bad; 2938925Sroot } 2948925Sroot switch (so->so_type) { 2958925Sroot 2968925Sroot case SOCK_DGRAM: 2978925Sroot unp->unp_conn = sotounpcb(so2); 2988925Sroot unp2 = sotounpcb(so2); 2998925Sroot unp->unp_nextref = unp2->unp_refs; 3008925Sroot unp2->unp_refs = unp; 3018925Sroot break; 3028925Sroot 3038925Sroot case SOCK_STREAM: 3048925Sroot if ((so2->so_options&SO_ACCEPTCONN) == 0 || 3059169Ssam (so2 = sonewconn(so2)) == 0) { 3068925Sroot error = ECONNREFUSED; 3078925Sroot goto bad; 3088925Sroot } 3099169Ssam unp2 = sotounpcb(so2); 3109169Ssam unp->unp_conn = unp2; 3119169Ssam unp2->unp_conn = unp; 3129169Ssam unp2->unp_remaddr = m_copy(nam, 0, (int)M_COPYALL); 3138925Sroot break; 3148925Sroot 3158925Sroot default: 3168925Sroot panic("uipc connip"); 3178925Sroot } 3189169Ssam soisconnected(so2); 3198925Sroot soisconnected(so); 3208925Sroot iput(ip); 3218925Sroot return (0); 3228925Sroot bad: 3238925Sroot iput(ip); 3248925Sroot return (error); 3258925Sroot } 3269169Ssam 3279169Ssam unp_disconnect(unp) 3289169Ssam struct unpcb *unp; 3299169Ssam { 3309169Ssam register struct unpcb *unp2 = unp->unp_conn; 3319169Ssam 3329169Ssam if (unp2 == 0) 3339169Ssam return; 3349169Ssam unp->unp_conn = 0; 3359169Ssam soisdisconnected(unp->unp_socket); 3369169Ssam switch (unp->unp_socket->so_type) { 3379169Ssam 3389169Ssam case SOCK_DGRAM: 3399169Ssam if (unp2->unp_refs == unp) 3409169Ssam unp2->unp_refs = unp->unp_nextref; 3419169Ssam else { 3429169Ssam unp2 = unp2->unp_refs; 3439169Ssam for (;;) { 3449169Ssam if (unp2 == 0) 3459169Ssam panic("unp_disconnect"); 3469169Ssam if (unp2->unp_nextref == unp) 3479169Ssam break; 3489169Ssam unp2 = unp2->unp_nextref; 3499169Ssam } 3509169Ssam unp2->unp_nextref = unp->unp_nextref; 3519169Ssam } 3529169Ssam unp->unp_nextref = 0; 3539169Ssam break; 3549169Ssam 3559169Ssam case SOCK_STREAM: 3569169Ssam unp2->unp_conn = 0; 3579169Ssam soisdisconnected(unp2->unp_socket); 3589169Ssam break; 3599169Ssam } 3609169Ssam } 3619169Ssam 3629169Ssam unp_abort(unp) 3639169Ssam struct unpcb *unp; 3649169Ssam { 3659169Ssam 3669169Ssam unp_detach(unp); 3679169Ssam } 3689169Ssam 3699169Ssam /*ARGSUSED*/ 3709169Ssam unp_usrclosed(unp) 3719169Ssam struct unpcb *unp; 3729169Ssam { 3739169Ssam 3749169Ssam } 3759169Ssam 3769169Ssam unp_drop(unp, errno) 3779169Ssam struct unpcb *unp; 3789169Ssam int errno; 3799169Ssam { 3809169Ssam 3819169Ssam unp->unp_socket->so_error = errno; 3829169Ssam unp_disconnect(unp); 3839169Ssam } 3849169Ssam 3859169Ssam unp_drain() 3869169Ssam { 3879169Ssam 3889169Ssam } 389