1*13050Ssam /* uipc_usrreq.c 1.11 83/06/12 */ 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" 1412760Ssam #include "../h/file.h" 158925Sroot 168925Sroot /* 178925Sroot * Unix communications domain. 1812760Ssam * 1912760Ssam * TODO: 2012760Ssam * SEQPACKET, RDM 2112760Ssam * change for names in file system 2212760Ssam * need a proper out-of-band 238925Sroot */ 248925Sroot 258925Sroot /*ARGSUSED*/ 2612760Ssam uipc_usrreq(so, req, m, nam, rights) 278925Sroot struct socket *so; 288925Sroot int req; 2912760Ssam struct mbuf *m, *nam, *rights; 308925Sroot { 318925Sroot struct unpcb *unp = sotounpcb(so); 328925Sroot register struct socket *so2; 338925Sroot int error = 0; 348925Sroot 3512760Ssam if (req != PRU_SEND && rights && rights->m_len) { 3612760Ssam error = EOPNOTSUPP; 3712760Ssam goto release; 3812760Ssam } 3912760Ssam if (unp == 0 && req != PRU_ATTACH) { 4012760Ssam error = EINVAL; 4112760Ssam goto release; 4212760Ssam } 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 7012760Ssam #ifdef notdef 7112760Ssam case PRU_CONNECT2: 7212760Ssam error = unp_connect2(so, (struct mbuf *)0, (struct socket *)nam); 7312760Ssam break; 7412760Ssam 7512760Ssam #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 */ 14212760Ssam if (rights) { 14312760Ssam error = unp_internalize(rights); 14412760Ssam if (error) 14512760Ssam break; 14612760Ssam } 14712760Ssam if (sbspace(&so2->so_rcv) > 0) { 1489169Ssam (void) sbappendaddr(&so2->so_rcv, 14912760Ssam mtod(nam, struct sockaddr *), m, 15012760Ssam rights); 15112760Ssam sbwakeup(&so2->so_rcv); 15212760Ssam m = 0; 15312760Ssam } 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) 16212760Ssam if (rights && rights->m_len) { 16312760Ssam error = EOPNOTSUPP; 16412760Ssam break; 16512760Ssam } 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 } 18712760Ssam 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: 196*13050Ssam return (EOPNOTSUPP); 1978925Sroot 1988925Sroot case PRU_SENSE: 1998925Sroot error = EOPNOTSUPP; 2008925Sroot break; 2018925Sroot /* END UNIMPLEMENTED HOOKS */ 2028925Sroot 2038925Sroot case PRU_RCVOOB: 2048925Sroot break; 2058925Sroot 2068925Sroot case PRU_SENDOOB: 2078925Sroot break; 2088925Sroot 2098925Sroot case PRU_SOCKADDR: 2108925Sroot break; 2118925Sroot 2128925Sroot case PRU_SLOWTIMO: 2138925Sroot break; 2148925Sroot 2158925Sroot default: 2168925Sroot panic("piusrreq"); 2178925Sroot } 21812760Ssam release: 21912760Ssam if (m) 22012760Ssam m_freem(m); 22111709Ssam return (error); 2228925Sroot } 2238925Sroot 22412760Ssam /* SHOULD BE PIPSIZ and 0 */ 2258925Sroot int unp_sendspace = 1024*2; 2268925Sroot int unp_recvspace = 1024*2; 2278925Sroot 2289169Ssam unp_attach(so) 2298925Sroot struct socket *so; 2308925Sroot { 2319169Ssam register struct mbuf *m; 2328925Sroot register struct unpcb *unp; 2338925Sroot int error; 2348925Sroot 2358925Sroot error = soreserve(so, unp_sendspace, unp_recvspace); 2368925Sroot if (error) 23710139Ssam return (error); 2389637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 23910139Ssam if (m == NULL) 24010139Ssam return (ENOBUFS); 2418925Sroot unp = mtod(m, struct unpcb *); 2428925Sroot so->so_pcb = (caddr_t)unp; 2438925Sroot unp->unp_socket = so; 2448925Sroot return (0); 2458925Sroot } 2468925Sroot 2478925Sroot unp_detach(unp) 2489169Ssam register struct unpcb *unp; 2498925Sroot { 2508925Sroot 2518925Sroot if (unp->unp_inode) { 2528925Sroot irele(unp->unp_inode); 2538925Sroot unp->unp_inode = 0; 2548925Sroot } 2558925Sroot if (unp->unp_conn) 2568925Sroot unp_disconnect(unp); 2578925Sroot while (unp->unp_refs) 2588925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2598925Sroot soisdisconnected(unp->unp_socket); 2608925Sroot unp->unp_socket->so_pcb = 0; 2619169Ssam m_freem(unp->unp_remaddr); 2629169Ssam (void) m_free(dtom(unp)); 2638925Sroot } 2648925Sroot 2659169Ssam unp_bind(unp, nam) 2668925Sroot struct unpcb *unp; 2679169Ssam struct mbuf *nam; 2688925Sroot { 2699169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2708925Sroot register struct inode *ip; 2719169Ssam extern schar(); 2728925Sroot int error; 2738925Sroot 2748925Sroot u.u_dirp = soun->sun_path; 27512760Ssam if (nam->m_len == MLEN) 27612760Ssam return (EINVAL); 27712760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 27812760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 2799169Ssam ip = namei(schar, CREATE, 1); 2808925Sroot if (ip) { 2818925Sroot iput(ip); 28210139Ssam return (EADDRINUSE); 2838925Sroot } 28411828Ssam if (error = u.u_error) { 28511828Ssam u.u_error = 0; /* XXX */ 28611828Ssam return (error); 28711828Ssam } 2888925Sroot ip = maknode(IFSOCK | 0777); 2898925Sroot if (ip == NULL) { 2908925Sroot error = u.u_error; /* XXX */ 2918925Sroot u.u_error = 0; /* XXX */ 2928925Sroot return (error); 2938925Sroot } 2948925Sroot ip->i_socket = unp->unp_socket; 2958925Sroot unp->unp_inode = ip; 2968925Sroot iunlock(ip); /* but keep reference */ 2978925Sroot return (0); 2988925Sroot } 2998925Sroot 3009169Ssam unp_connect(so, nam) 3018925Sroot struct socket *so; 3029169Ssam struct mbuf *nam; 3038925Sroot { 3049169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3059169Ssam register struct inode *ip; 3068925Sroot int error; 30712760Ssam register struct socket *so2; 3088925Sroot 3098925Sroot u.u_dirp = soun->sun_path; 31012760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 31112760Ssam return (EMSGSIZE); 31212760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 3139169Ssam ip = namei(schar, LOOKUP, 1); 3148925Sroot if (ip == 0) { 3158925Sroot error = u.u_error; 3168925Sroot u.u_error = 0; 31710139Ssam return (error); /* XXX */ 3188925Sroot } 3198925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3208925Sroot error = ENOTSOCK; 3218925Sroot goto bad; 3228925Sroot } 3238925Sroot so2 = ip->i_socket; 3248925Sroot if (so2 == 0) { 3258925Sroot error = ECONNREFUSED; 3268925Sroot goto bad; 3278925Sroot } 32812760Ssam error = unp_connect2(so, nam, so2); 32912760Ssam bad: 33012760Ssam iput(ip); 33112760Ssam return (error); 33212760Ssam } 33312760Ssam 33412760Ssam unp_connect2(so, sonam, so2) 33512760Ssam register struct socket *so; 33612760Ssam struct mbuf *sonam; 33712760Ssam register struct socket *so2; 33812760Ssam { 33912760Ssam register struct unpcb *unp = sotounpcb(so); 34012760Ssam register struct unpcb *unp2; 34112760Ssam 34212760Ssam if (so2->so_type != so->so_type) 34312760Ssam return (EPROTOTYPE); 3448925Sroot switch (so->so_type) { 3458925Sroot 3468925Sroot case SOCK_DGRAM: 3478925Sroot unp2 = sotounpcb(so2); 34812760Ssam unp->unp_conn = unp2; 3498925Sroot unp->unp_nextref = unp2->unp_refs; 3508925Sroot unp2->unp_refs = unp; 3518925Sroot break; 3528925Sroot 3538925Sroot case SOCK_STREAM: 3548925Sroot if ((so2->so_options&SO_ACCEPTCONN) == 0 || 35512760Ssam (so2 = sonewconn(so2)) == 0) 35612760Ssam return (ECONNREFUSED); 3579169Ssam unp2 = sotounpcb(so2); 3589169Ssam unp->unp_conn = unp2; 3599169Ssam unp2->unp_conn = unp; 36012760Ssam if (sonam) 36112760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 3628925Sroot break; 3638925Sroot 3648925Sroot default: 36512760Ssam panic("unp_connect2"); 3668925Sroot } 3679169Ssam soisconnected(so2); 3688925Sroot soisconnected(so); 3698925Sroot return (0); 3708925Sroot } 3719169Ssam 3729169Ssam unp_disconnect(unp) 3739169Ssam struct unpcb *unp; 3749169Ssam { 3759169Ssam register struct unpcb *unp2 = unp->unp_conn; 3769169Ssam 3779169Ssam if (unp2 == 0) 3789169Ssam return; 3799169Ssam unp->unp_conn = 0; 3809169Ssam soisdisconnected(unp->unp_socket); 3819169Ssam switch (unp->unp_socket->so_type) { 3829169Ssam 3839169Ssam case SOCK_DGRAM: 3849169Ssam if (unp2->unp_refs == unp) 3859169Ssam unp2->unp_refs = unp->unp_nextref; 3869169Ssam else { 3879169Ssam unp2 = unp2->unp_refs; 3889169Ssam for (;;) { 3899169Ssam if (unp2 == 0) 3909169Ssam panic("unp_disconnect"); 3919169Ssam if (unp2->unp_nextref == unp) 3929169Ssam break; 3939169Ssam unp2 = unp2->unp_nextref; 3949169Ssam } 3959169Ssam unp2->unp_nextref = unp->unp_nextref; 3969169Ssam } 3979169Ssam unp->unp_nextref = 0; 3989169Ssam break; 3999169Ssam 4009169Ssam case SOCK_STREAM: 4019169Ssam unp2->unp_conn = 0; 4029169Ssam soisdisconnected(unp2->unp_socket); 4039169Ssam break; 4049169Ssam } 4059169Ssam } 4069169Ssam 40712760Ssam #ifdef notdef 4089169Ssam unp_abort(unp) 4099169Ssam struct unpcb *unp; 4109169Ssam { 4119169Ssam 4129169Ssam unp_detach(unp); 4139169Ssam } 41412760Ssam #endif 4159169Ssam 4169169Ssam /*ARGSUSED*/ 4179169Ssam unp_usrclosed(unp) 4189169Ssam struct unpcb *unp; 4199169Ssam { 4209169Ssam 4219169Ssam } 4229169Ssam 4239169Ssam unp_drop(unp, errno) 4249169Ssam struct unpcb *unp; 4259169Ssam int errno; 4269169Ssam { 4279169Ssam 4289169Ssam unp->unp_socket->so_error = errno; 4299169Ssam unp_disconnect(unp); 4309169Ssam } 4319169Ssam 43212760Ssam #ifdef notdef 4339169Ssam unp_drain() 4349169Ssam { 4359169Ssam 4369169Ssam } 43712760Ssam #endif 43812760Ssam 43912760Ssam unp_externalize(rights) 44012760Ssam struct mbuf *rights; 44112760Ssam { 44212760Ssam int newfds = rights->m_len / sizeof (int); 44312760Ssam register int i; 44412760Ssam register struct file **rp = mtod(rights, struct file **); 44512760Ssam register struct file *fp; 44612760Ssam int f; 44712760Ssam 44812760Ssam if (newfds > ufavail()) { 44912760Ssam for (i = 0; i < newfds; i++) { 45012760Ssam fp = *rp; 45112760Ssam unp_discard(fp); 45212760Ssam *rp++ = 0; 45312760Ssam } 45412760Ssam return (EMSGSIZE); 45512760Ssam } 45612760Ssam for (i = 0; i < newfds; i++) { 45712760Ssam f = ufalloc(0); 45812760Ssam if (f < 0) 45912760Ssam panic("unp_externalize"); 46012760Ssam fp = *rp; 46112760Ssam u.u_ofile[f] = fp; 46212760Ssam fp->f_msgcount--; 46312760Ssam *(int *)rp = f; 46412760Ssam } 46512760Ssam return (0); 46612760Ssam } 46712760Ssam 46812760Ssam unp_internalize(rights) 46912760Ssam struct mbuf *rights; 47012760Ssam { 47112760Ssam register struct file **rp; 47212760Ssam int oldfds = rights->m_len / sizeof (int); 47312760Ssam register int i; 47412760Ssam register struct file *fp; 47512760Ssam 47612760Ssam rp = mtod(rights, struct file **); 47712760Ssam for (i = 0; i < oldfds; i++) { 47812760Ssam if (getf(*(int *)rp++) == 0) 47912760Ssam return (EBADF); 48012760Ssam rp = mtod(rights, struct file **); 48112760Ssam for (i = 0; i < oldfds; i++) 48212760Ssam fp = getf(*(int *)rp); 48312760Ssam *rp++ = fp; 48412760Ssam fp->f_count++; 48512760Ssam fp->f_msgcount++; 48612760Ssam } 48712760Ssam return (0); 48812760Ssam } 48912760Ssam 49012760Ssam int unp_defer, unp_gcing; 49112760Ssam int unp_mark(); 49212760Ssam 49312760Ssam unp_gc() 49412760Ssam { 49512760Ssam register struct file *fp; 49612760Ssam register struct socket *so; 49712760Ssam 49812760Ssam if (unp_gcing) 49912760Ssam return; 50012760Ssam unp_gcing = 1; 50112760Ssam restart: 50212760Ssam unp_defer = 0; 50312760Ssam for (fp = file; fp < fileNFILE; fp++) 50412760Ssam fp->f_flag &= ~(FMARK|FDEFER); 50512760Ssam do { 50612760Ssam for (fp = file; fp < fileNFILE; fp++) { 50712760Ssam if (fp->f_count == 0) 50812760Ssam continue; 50912760Ssam if (fp->f_flag & FDEFER) { 51012760Ssam fp->f_flag &= ~FDEFER; 51112760Ssam unp_defer--; 51212760Ssam } else { 51312760Ssam if (fp->f_flag & FMARK) 51412760Ssam continue; 51512760Ssam if (fp->f_count == fp->f_msgcount) 51612760Ssam continue; 51712760Ssam fp->f_flag |= FMARK; 51812760Ssam } 51912760Ssam if (fp->f_type != DTYPE_SOCKET) 52012760Ssam continue; 52112760Ssam so = (struct socket *)fp->f_data; 52212760Ssam if (so->so_proto->pr_family != AF_UNIX || 52312760Ssam (so->so_proto->pr_flags&PR_ADDR) == 0) 52412760Ssam continue; 52512760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 52612760Ssam sbwait(&so->so_rcv); 52712760Ssam goto restart; 52812760Ssam } 52912760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 53012760Ssam } 53112760Ssam } while (unp_defer); 53212760Ssam for (fp = file; fp < fileNFILE; fp++) { 53312760Ssam if (fp->f_count == 0) 53412760Ssam continue; 53512760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 53612760Ssam if (fp->f_type != DTYPE_SOCKET) 53712760Ssam panic("unp_gc"); 53812760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 53912760Ssam } 54012760Ssam } 54112760Ssam unp_gcing = 0; 54212760Ssam } 54312760Ssam 54412760Ssam unp_scan(m, op) 54512760Ssam register struct mbuf *m; 54612760Ssam int (*op)(); 54712760Ssam { 54812760Ssam register struct file **rp; 54912760Ssam register int i; 55012760Ssam int qfds; 55112760Ssam 55212760Ssam while (m) { 55312760Ssam m = m->m_next; 55412760Ssam if (m == 0) 55512760Ssam goto bad; 55612760Ssam if (m->m_len) { 55712760Ssam qfds = m->m_len / sizeof (struct file *); 55812760Ssam rp = mtod(m, struct file **); 55912760Ssam for (i = 0; i < qfds; i++) 56012760Ssam (*op)(*rp++); 56112760Ssam } 56212760Ssam do { 56312760Ssam m = m->m_next; 56412760Ssam if (m == 0) 56512760Ssam goto bad; 56612760Ssam } while (m->m_act == 0); 56712760Ssam m = m->m_next; 56812760Ssam } 56912760Ssam return; 57012760Ssam bad: 57112760Ssam panic("unp_gcscan"); 57212760Ssam } 57312760Ssam 57412760Ssam unp_mark(fp) 57512760Ssam struct file *fp; 57612760Ssam { 57712760Ssam 57812760Ssam if (fp->f_flag & FMARK) 57912760Ssam return; 58012760Ssam unp_defer++; 58112760Ssam fp->f_flag |= (FMARK|FDEFER); 58212760Ssam } 58312760Ssam 58412760Ssam unp_discard(fp) 58512760Ssam struct file *fp; 58612760Ssam { 58712760Ssam 58812760Ssam fp->f_msgcount--; 58912760Ssam closef(fp, 0); 59012760Ssam } 591