1*13115Ssam /* uipc_usrreq.c 1.13 83/06/14 */ 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 case PRU_CONNECT2: 71*13115Ssam error = unp_connect2(so, (struct mbuf *)0, 72*13115Ssam (struct socket *)nam); 7312760Ssam break; 7412760Ssam 758925Sroot case PRU_DISCONNECT: 768925Sroot unp_disconnect(unp); 778925Sroot break; 788925Sroot 799169Ssam case PRU_ACCEPT: 809169Ssam nam->m_len = unp->unp_remaddr->m_len; 819169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 829169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 838925Sroot break; 848925Sroot 858925Sroot case PRU_SHUTDOWN: 868925Sroot socantsendmore(so); 878925Sroot unp_usrclosed(unp); 888925Sroot break; 898925Sroot 908925Sroot case PRU_RCVD: 918925Sroot switch (so->so_type) { 928925Sroot 938925Sroot case SOCK_DGRAM: 948925Sroot panic("uipc 1"); 9510139Ssam /*NOTREACHED*/ 968925Sroot 9710139Ssam case SOCK_STREAM: 988925Sroot #define rcv (&so->so_rcv) 998925Sroot #define snd (&so2->so_snd) 1008925Sroot if (unp->unp_conn == 0) 1018925Sroot break; 1028925Sroot so2 = unp->unp_conn->unp_socket; 1038925Sroot /* 1048925Sroot * Transfer resources back to send port 1058925Sroot * and wakeup any waiting to write. 1068925Sroot */ 1078925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 1088925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1098925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 1108925Sroot rcv->sb_hiwat = rcv->sb_cc; 1118925Sroot sbwakeup(snd); 1128925Sroot #undef snd 1138925Sroot #undef rcv 1148925Sroot break; 1158925Sroot 1168925Sroot default: 1178925Sroot panic("uipc 2"); 1188925Sroot } 1198925Sroot break; 1208925Sroot 1218925Sroot case PRU_SEND: 1228925Sroot switch (so->so_type) { 1238925Sroot 1248925Sroot case SOCK_DGRAM: 1259028Sroot if (nam) { 1268925Sroot if (unp->unp_conn) { 1278925Sroot error = EISCONN; 1288925Sroot break; 1298925Sroot } 1309028Sroot error = unp_connect(so, nam); 1318925Sroot if (error) 1328925Sroot break; 1338925Sroot } else { 1348925Sroot if (unp->unp_conn == 0) { 1358925Sroot error = ENOTCONN; 1368925Sroot break; 1378925Sroot } 1388925Sroot } 1398925Sroot so2 = unp->unp_conn->unp_socket; 1409169Ssam /* BEGIN XXX */ 14112760Ssam if (rights) { 14212760Ssam error = unp_internalize(rights); 14312760Ssam if (error) 14412760Ssam break; 14512760Ssam } 14612760Ssam if (sbspace(&so2->so_rcv) > 0) { 1479169Ssam (void) sbappendaddr(&so2->so_rcv, 14812760Ssam mtod(nam, struct sockaddr *), m, 14912760Ssam rights); 15012760Ssam sbwakeup(&so2->so_rcv); 15112760Ssam m = 0; 15212760Ssam } 1539169Ssam /* END XXX */ 1549028Sroot if (nam) 1559169Ssam unp_disconnect(unp); 1568925Sroot break; 1578925Sroot 1588925Sroot case SOCK_STREAM: 1598925Sroot #define rcv (&so2->so_rcv) 1608925Sroot #define snd (&so->so_snd) 16112760Ssam if (rights && rights->m_len) { 16212760Ssam error = EOPNOTSUPP; 16312760Ssam break; 16412760Ssam } 1658925Sroot if (unp->unp_conn == 0) 1668925Sroot panic("uipc 3"); 1678925Sroot so2 = unp->unp_conn->unp_socket; 1688925Sroot /* 1698925Sroot * Send to paired receive port, and then 1708925Sroot * give it enough resources to hold what it already has. 1718925Sroot * Wake up readers. 1728925Sroot */ 1738925Sroot sbappend(rcv, m); 1748925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1758925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1768925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1778925Sroot rcv->sb_hiwat = rcv->sb_cc; 1788925Sroot sbwakeup(rcv); 1798925Sroot #undef snd 1808925Sroot #undef rcv 1818925Sroot break; 1828925Sroot 1838925Sroot default: 1848925Sroot panic("uipc 4"); 1858925Sroot } 18612760Ssam m = 0; 1878925Sroot break; 1888925Sroot 1898925Sroot case PRU_ABORT: 1908925Sroot unp_drop(unp, ECONNABORTED); 1918925Sroot break; 1928925Sroot 1938925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 1948925Sroot case PRU_CONTROL: 19513050Ssam return (EOPNOTSUPP); 1968925Sroot 1978925Sroot case PRU_SENSE: 1988925Sroot error = EOPNOTSUPP; 1998925Sroot break; 2008925Sroot /* END UNIMPLEMENTED HOOKS */ 2018925Sroot 2028925Sroot case PRU_RCVOOB: 2038925Sroot break; 2048925Sroot 2058925Sroot case PRU_SENDOOB: 2068925Sroot break; 2078925Sroot 2088925Sroot case PRU_SOCKADDR: 2098925Sroot break; 2108925Sroot 2118925Sroot case PRU_SLOWTIMO: 2128925Sroot break; 2138925Sroot 2148925Sroot default: 2158925Sroot panic("piusrreq"); 2168925Sroot } 21712760Ssam release: 21812760Ssam if (m) 21912760Ssam m_freem(m); 22011709Ssam return (error); 2218925Sroot } 2228925Sroot 22312760Ssam /* SHOULD BE PIPSIZ and 0 */ 2248925Sroot int unp_sendspace = 1024*2; 2258925Sroot int unp_recvspace = 1024*2; 2268925Sroot 2279169Ssam unp_attach(so) 2288925Sroot struct socket *so; 2298925Sroot { 2309169Ssam register struct mbuf *m; 2318925Sroot register struct unpcb *unp; 2328925Sroot int error; 2338925Sroot 2348925Sroot error = soreserve(so, unp_sendspace, unp_recvspace); 2358925Sroot if (error) 23610139Ssam return (error); 2379637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 23810139Ssam if (m == NULL) 23910139Ssam return (ENOBUFS); 2408925Sroot unp = mtod(m, struct unpcb *); 2418925Sroot so->so_pcb = (caddr_t)unp; 2428925Sroot unp->unp_socket = so; 2438925Sroot return (0); 2448925Sroot } 2458925Sroot 2468925Sroot unp_detach(unp) 2479169Ssam register struct unpcb *unp; 2488925Sroot { 2498925Sroot 2508925Sroot if (unp->unp_inode) { 2518925Sroot irele(unp->unp_inode); 2528925Sroot unp->unp_inode = 0; 2538925Sroot } 2548925Sroot if (unp->unp_conn) 2558925Sroot unp_disconnect(unp); 2568925Sroot while (unp->unp_refs) 2578925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2588925Sroot soisdisconnected(unp->unp_socket); 2598925Sroot unp->unp_socket->so_pcb = 0; 2609169Ssam m_freem(unp->unp_remaddr); 2619169Ssam (void) m_free(dtom(unp)); 2628925Sroot } 2638925Sroot 2649169Ssam unp_bind(unp, nam) 2658925Sroot struct unpcb *unp; 2669169Ssam struct mbuf *nam; 2678925Sroot { 2689169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 2698925Sroot register struct inode *ip; 2709169Ssam extern schar(); 2718925Sroot int error; 2728925Sroot 2738925Sroot u.u_dirp = soun->sun_path; 27412760Ssam if (nam->m_len == MLEN) 27512760Ssam return (EINVAL); 27612760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 27712760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 2789169Ssam ip = namei(schar, CREATE, 1); 2798925Sroot if (ip) { 2808925Sroot iput(ip); 28110139Ssam return (EADDRINUSE); 2828925Sroot } 28311828Ssam if (error = u.u_error) { 28411828Ssam u.u_error = 0; /* XXX */ 28511828Ssam return (error); 28611828Ssam } 2878925Sroot ip = maknode(IFSOCK | 0777); 2888925Sroot if (ip == NULL) { 2898925Sroot error = u.u_error; /* XXX */ 2908925Sroot u.u_error = 0; /* XXX */ 2918925Sroot return (error); 2928925Sroot } 2938925Sroot ip->i_socket = unp->unp_socket; 2948925Sroot unp->unp_inode = ip; 2958925Sroot iunlock(ip); /* but keep reference */ 2968925Sroot return (0); 2978925Sroot } 2988925Sroot 2999169Ssam unp_connect(so, nam) 3008925Sroot struct socket *so; 3019169Ssam struct mbuf *nam; 3028925Sroot { 3039169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3049169Ssam register struct inode *ip; 3058925Sroot int error; 30612760Ssam register struct socket *so2; 3078925Sroot 3088925Sroot u.u_dirp = soun->sun_path; 30912760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 31012760Ssam return (EMSGSIZE); 31112760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 3129169Ssam ip = namei(schar, LOOKUP, 1); 3138925Sroot if (ip == 0) { 3148925Sroot error = u.u_error; 3158925Sroot u.u_error = 0; 31610139Ssam return (error); /* XXX */ 3178925Sroot } 3188925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3198925Sroot error = ENOTSOCK; 3208925Sroot goto bad; 3218925Sroot } 3228925Sroot so2 = ip->i_socket; 3238925Sroot if (so2 == 0) { 3248925Sroot error = ECONNREFUSED; 3258925Sroot goto bad; 3268925Sroot } 327*13115Ssam if (so->so_type != so2->so_type) { 328*13115Ssam error = EPROTOTYPE; 329*13115Ssam goto bad; 330*13115Ssam } 331*13115Ssam if (so->so_proto->pr_flags & PR_CONNREQUIRED && 332*13115Ssam ((so2->so_options&SO_ACCEPTCONN) == 0 || 333*13115Ssam (so2 = sonewconn(so2)) == 0)) { 334*13115Ssam error = ECONNREFUSED; 335*13115Ssam goto bad; 336*13115Ssam } 33712760Ssam error = unp_connect2(so, nam, so2); 33812760Ssam bad: 33912760Ssam iput(ip); 34012760Ssam return (error); 34112760Ssam } 34212760Ssam 34312760Ssam unp_connect2(so, sonam, so2) 34412760Ssam register struct socket *so; 34512760Ssam struct mbuf *sonam; 34612760Ssam register struct socket *so2; 34712760Ssam { 34812760Ssam register struct unpcb *unp = sotounpcb(so); 34912760Ssam register struct unpcb *unp2; 35012760Ssam 35112760Ssam if (so2->so_type != so->so_type) 35212760Ssam return (EPROTOTYPE); 3538925Sroot switch (so->so_type) { 3548925Sroot 3558925Sroot case SOCK_DGRAM: 3568925Sroot unp2 = sotounpcb(so2); 35712760Ssam unp->unp_conn = unp2; 3588925Sroot unp->unp_nextref = unp2->unp_refs; 3598925Sroot unp2->unp_refs = unp; 3608925Sroot break; 3618925Sroot 3628925Sroot case SOCK_STREAM: 3639169Ssam unp2 = sotounpcb(so2); 3649169Ssam unp->unp_conn = unp2; 3659169Ssam unp2->unp_conn = unp; 36612760Ssam if (sonam) 36712760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 3688925Sroot break; 3698925Sroot 3708925Sroot default: 37112760Ssam panic("unp_connect2"); 3728925Sroot } 3739169Ssam soisconnected(so2); 3748925Sroot soisconnected(so); 3758925Sroot return (0); 3768925Sroot } 3779169Ssam 3789169Ssam unp_disconnect(unp) 3799169Ssam struct unpcb *unp; 3809169Ssam { 3819169Ssam register struct unpcb *unp2 = unp->unp_conn; 3829169Ssam 3839169Ssam if (unp2 == 0) 3849169Ssam return; 3859169Ssam unp->unp_conn = 0; 3869169Ssam soisdisconnected(unp->unp_socket); 3879169Ssam switch (unp->unp_socket->so_type) { 3889169Ssam 3899169Ssam case SOCK_DGRAM: 3909169Ssam if (unp2->unp_refs == unp) 3919169Ssam unp2->unp_refs = unp->unp_nextref; 3929169Ssam else { 3939169Ssam unp2 = unp2->unp_refs; 3949169Ssam for (;;) { 3959169Ssam if (unp2 == 0) 3969169Ssam panic("unp_disconnect"); 3979169Ssam if (unp2->unp_nextref == unp) 3989169Ssam break; 3999169Ssam unp2 = unp2->unp_nextref; 4009169Ssam } 4019169Ssam unp2->unp_nextref = unp->unp_nextref; 4029169Ssam } 4039169Ssam unp->unp_nextref = 0; 4049169Ssam break; 4059169Ssam 4069169Ssam case SOCK_STREAM: 4079169Ssam unp2->unp_conn = 0; 4089169Ssam soisdisconnected(unp2->unp_socket); 4099169Ssam break; 4109169Ssam } 4119169Ssam } 4129169Ssam 41312760Ssam #ifdef notdef 4149169Ssam unp_abort(unp) 4159169Ssam struct unpcb *unp; 4169169Ssam { 4179169Ssam 4189169Ssam unp_detach(unp); 4199169Ssam } 42012760Ssam #endif 4219169Ssam 4229169Ssam /*ARGSUSED*/ 4239169Ssam unp_usrclosed(unp) 4249169Ssam struct unpcb *unp; 4259169Ssam { 4269169Ssam 4279169Ssam } 4289169Ssam 4299169Ssam unp_drop(unp, errno) 4309169Ssam struct unpcb *unp; 4319169Ssam int errno; 4329169Ssam { 4339169Ssam 4349169Ssam unp->unp_socket->so_error = errno; 4359169Ssam unp_disconnect(unp); 4369169Ssam } 4379169Ssam 43812760Ssam #ifdef notdef 4399169Ssam unp_drain() 4409169Ssam { 4419169Ssam 4429169Ssam } 44312760Ssam #endif 44412760Ssam 44512760Ssam unp_externalize(rights) 44612760Ssam struct mbuf *rights; 44712760Ssam { 44812760Ssam int newfds = rights->m_len / sizeof (int); 44912760Ssam register int i; 45012760Ssam register struct file **rp = mtod(rights, struct file **); 45112760Ssam register struct file *fp; 45212760Ssam int f; 45312760Ssam 45412760Ssam if (newfds > ufavail()) { 45512760Ssam for (i = 0; i < newfds; i++) { 45612760Ssam fp = *rp; 45712760Ssam unp_discard(fp); 45812760Ssam *rp++ = 0; 45912760Ssam } 46012760Ssam return (EMSGSIZE); 46112760Ssam } 46212760Ssam for (i = 0; i < newfds; i++) { 46312760Ssam f = ufalloc(0); 46412760Ssam if (f < 0) 46512760Ssam panic("unp_externalize"); 46612760Ssam fp = *rp; 46712760Ssam u.u_ofile[f] = fp; 46812760Ssam fp->f_msgcount--; 46912760Ssam *(int *)rp = f; 47012760Ssam } 47112760Ssam return (0); 47212760Ssam } 47312760Ssam 47412760Ssam unp_internalize(rights) 47512760Ssam struct mbuf *rights; 47612760Ssam { 47712760Ssam register struct file **rp; 47812760Ssam int oldfds = rights->m_len / sizeof (int); 47912760Ssam register int i; 48012760Ssam register struct file *fp; 48112760Ssam 48212760Ssam rp = mtod(rights, struct file **); 48313084Ssam for (i = 0; i < oldfds; i++) 48412760Ssam if (getf(*(int *)rp++) == 0) 48512760Ssam return (EBADF); 48612760Ssam rp = mtod(rights, struct file **); 48713084Ssam for (i = 0; i < oldfds; i++) { 48812760Ssam fp = getf(*(int *)rp); 48912760Ssam *rp++ = fp; 49012760Ssam fp->f_count++; 49112760Ssam fp->f_msgcount++; 49212760Ssam } 49312760Ssam return (0); 49412760Ssam } 49512760Ssam 49612760Ssam int unp_defer, unp_gcing; 49712760Ssam int unp_mark(); 49812760Ssam 49912760Ssam unp_gc() 50012760Ssam { 50112760Ssam register struct file *fp; 50212760Ssam register struct socket *so; 50312760Ssam 50412760Ssam if (unp_gcing) 50512760Ssam return; 50612760Ssam unp_gcing = 1; 50712760Ssam restart: 50812760Ssam unp_defer = 0; 50912760Ssam for (fp = file; fp < fileNFILE; fp++) 51012760Ssam fp->f_flag &= ~(FMARK|FDEFER); 51112760Ssam do { 51212760Ssam for (fp = file; fp < fileNFILE; fp++) { 51312760Ssam if (fp->f_count == 0) 51412760Ssam continue; 51512760Ssam if (fp->f_flag & FDEFER) { 51612760Ssam fp->f_flag &= ~FDEFER; 51712760Ssam unp_defer--; 51812760Ssam } else { 51912760Ssam if (fp->f_flag & FMARK) 52012760Ssam continue; 52112760Ssam if (fp->f_count == fp->f_msgcount) 52212760Ssam continue; 52312760Ssam fp->f_flag |= FMARK; 52412760Ssam } 52512760Ssam if (fp->f_type != DTYPE_SOCKET) 52612760Ssam continue; 52712760Ssam so = (struct socket *)fp->f_data; 52812760Ssam if (so->so_proto->pr_family != AF_UNIX || 52912760Ssam (so->so_proto->pr_flags&PR_ADDR) == 0) 53012760Ssam continue; 53112760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 53212760Ssam sbwait(&so->so_rcv); 53312760Ssam goto restart; 53412760Ssam } 53512760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 53612760Ssam } 53712760Ssam } while (unp_defer); 53812760Ssam for (fp = file; fp < fileNFILE; fp++) { 53912760Ssam if (fp->f_count == 0) 54012760Ssam continue; 54112760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 54212760Ssam if (fp->f_type != DTYPE_SOCKET) 54312760Ssam panic("unp_gc"); 54412760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 54512760Ssam } 54612760Ssam } 54712760Ssam unp_gcing = 0; 54812760Ssam } 54912760Ssam 55012760Ssam unp_scan(m, op) 55112760Ssam register struct mbuf *m; 55212760Ssam int (*op)(); 55312760Ssam { 55412760Ssam register struct file **rp; 55512760Ssam register int i; 55612760Ssam int qfds; 55712760Ssam 55812760Ssam while (m) { 55912760Ssam m = m->m_next; 56012760Ssam if (m == 0) 56112760Ssam goto bad; 56212760Ssam if (m->m_len) { 56312760Ssam qfds = m->m_len / sizeof (struct file *); 56412760Ssam rp = mtod(m, struct file **); 56512760Ssam for (i = 0; i < qfds; i++) 56612760Ssam (*op)(*rp++); 56712760Ssam } 56812760Ssam do { 56912760Ssam m = m->m_next; 57012760Ssam if (m == 0) 57112760Ssam goto bad; 57212760Ssam } while (m->m_act == 0); 57312760Ssam m = m->m_next; 57412760Ssam } 57512760Ssam return; 57612760Ssam bad: 57712760Ssam panic("unp_gcscan"); 57812760Ssam } 57912760Ssam 58012760Ssam unp_mark(fp) 58112760Ssam struct file *fp; 58212760Ssam { 58312760Ssam 58412760Ssam if (fp->f_flag & FMARK) 58512760Ssam return; 58612760Ssam unp_defer++; 58712760Ssam fp->f_flag |= (FMARK|FDEFER); 58812760Ssam } 58912760Ssam 59012760Ssam unp_discard(fp) 59112760Ssam struct file *fp; 59212760Ssam { 59312760Ssam 59412760Ssam fp->f_msgcount--; 59513084Ssam closef(fp); 59612760Ssam } 597