1*21110Skarels /* uipc_usrreq.c 6.12 85/05/27 */ 28925Sroot 317105Sbloom #include "param.h" 417105Sbloom #include "dir.h" 517105Sbloom #include "user.h" 617105Sbloom #include "mbuf.h" 717105Sbloom #include "domain.h" 817105Sbloom #include "protosw.h" 917105Sbloom #include "socket.h" 1017105Sbloom #include "socketvar.h" 1117105Sbloom #include "unpcb.h" 1217105Sbloom #include "un.h" 1317105Sbloom #include "inode.h" 1417105Sbloom #include "file.h" 1517105Sbloom #include "stat.h" 168925Sroot 178925Sroot /* 188925Sroot * Unix communications domain. 1912760Ssam * 2012760Ssam * TODO: 2112760Ssam * SEQPACKET, RDM 2213119Ssam * rethink name space problems 2312760Ssam * need a proper out-of-band 248925Sroot */ 2513119Ssam struct sockaddr sun_noname = { AF_UNIX }; 26*21110Skarels ino_t unp_ino; /* fake inode numbers */ 278925Sroot 288925Sroot /*ARGSUSED*/ 2912760Ssam uipc_usrreq(so, req, m, nam, rights) 308925Sroot struct socket *so; 318925Sroot int req; 3212760Ssam struct mbuf *m, *nam, *rights; 338925Sroot { 348925Sroot struct unpcb *unp = sotounpcb(so); 358925Sroot register struct socket *so2; 368925Sroot int error = 0; 378925Sroot 3812760Ssam if (req != PRU_SEND && rights && rights->m_len) { 3912760Ssam error = EOPNOTSUPP; 4012760Ssam goto release; 4112760Ssam } 4212760Ssam if (unp == 0 && req != PRU_ATTACH) { 4312760Ssam error = EINVAL; 4412760Ssam goto release; 4512760Ssam } 468925Sroot switch (req) { 478925Sroot 488925Sroot case PRU_ATTACH: 498925Sroot if (unp) { 509169Ssam error = EISCONN; 518925Sroot break; 528925Sroot } 539028Sroot error = unp_attach(so); 548925Sroot break; 558925Sroot 568925Sroot case PRU_DETACH: 578925Sroot unp_detach(unp); 588925Sroot break; 598925Sroot 609169Ssam case PRU_BIND: 619169Ssam error = unp_bind(unp, nam); 629169Ssam break; 639169Ssam 649169Ssam case PRU_LISTEN: 659169Ssam if (unp->unp_inode == 0) 669169Ssam error = EINVAL; 679169Ssam break; 689169Ssam 698925Sroot case PRU_CONNECT: 709028Sroot error = unp_connect(so, nam); 718925Sroot break; 728925Sroot 7312760Ssam case PRU_CONNECT2: 7413115Ssam error = unp_connect2(so, (struct mbuf *)0, 7513115Ssam (struct socket *)nam); 7612760Ssam break; 7712760Ssam 788925Sroot case PRU_DISCONNECT: 798925Sroot unp_disconnect(unp); 808925Sroot break; 818925Sroot 829169Ssam case PRU_ACCEPT: 839169Ssam nam->m_len = unp->unp_remaddr->m_len; 849169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 859169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 868925Sroot break; 878925Sroot 888925Sroot case PRU_SHUTDOWN: 898925Sroot socantsendmore(so); 908925Sroot unp_usrclosed(unp); 918925Sroot break; 928925Sroot 938925Sroot case PRU_RCVD: 948925Sroot switch (so->so_type) { 958925Sroot 968925Sroot case SOCK_DGRAM: 978925Sroot panic("uipc 1"); 9810139Ssam /*NOTREACHED*/ 998925Sroot 10010139Ssam case SOCK_STREAM: 1018925Sroot #define rcv (&so->so_rcv) 1028925Sroot #define snd (&so2->so_snd) 1038925Sroot if (unp->unp_conn == 0) 1048925Sroot break; 1058925Sroot so2 = unp->unp_conn->unp_socket; 1068925Sroot /* 1078925Sroot * Transfer resources back to send port 1088925Sroot * and wakeup any waiting to write. 1098925Sroot */ 1108925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 1118925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1128925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 1138925Sroot rcv->sb_hiwat = rcv->sb_cc; 11417543Skarels sowwakeup(so2); 1158925Sroot #undef snd 1168925Sroot #undef rcv 1178925Sroot break; 1188925Sroot 1198925Sroot default: 1208925Sroot panic("uipc 2"); 1218925Sroot } 1228925Sroot break; 1238925Sroot 1248925Sroot case PRU_SEND: 1258925Sroot switch (so->so_type) { 1268925Sroot 1278925Sroot case SOCK_DGRAM: 1289028Sroot if (nam) { 1298925Sroot if (unp->unp_conn) { 1308925Sroot error = EISCONN; 1318925Sroot break; 1328925Sroot } 1339028Sroot error = unp_connect(so, nam); 1348925Sroot if (error) 1358925Sroot break; 1368925Sroot } else { 1378925Sroot if (unp->unp_conn == 0) { 1388925Sroot error = ENOTCONN; 1398925Sroot break; 1408925Sroot } 1418925Sroot } 1428925Sroot so2 = unp->unp_conn->unp_socket; 1439169Ssam /* BEGIN XXX */ 14412760Ssam if (rights) { 14512760Ssam error = unp_internalize(rights); 14612760Ssam if (error) 14712760Ssam break; 14812760Ssam } 14912760Ssam if (sbspace(&so2->so_rcv) > 0) { 15013119Ssam /* 15113119Ssam * There's no record of source socket's 15213119Ssam * name, so send null name for the moment. 15313119Ssam */ 15417543Skarels if (sbappendaddr(&so2->so_rcv, 15517543Skarels &sun_noname, m, rights)) { 15617543Skarels sorwakeup(so2); 15717543Skarels m = 0; 15817543Skarels } 15912760Ssam } 1609169Ssam /* END XXX */ 1619028Sroot if (nam) 1629169Ssam unp_disconnect(unp); 1638925Sroot break; 1648925Sroot 1658925Sroot case SOCK_STREAM: 1668925Sroot #define rcv (&so2->so_rcv) 1678925Sroot #define snd (&so->so_snd) 16812760Ssam if (rights && rights->m_len) { 16912760Ssam error = EOPNOTSUPP; 17012760Ssam break; 17112760Ssam } 172*21110Skarels if (so->so_state & SS_CANTSENDMORE) 173*21110Skarels return (EPIPE); 1748925Sroot if (unp->unp_conn == 0) 1758925Sroot panic("uipc 3"); 1768925Sroot so2 = unp->unp_conn->unp_socket; 1778925Sroot /* 1788925Sroot * Send to paired receive port, and then 1798925Sroot * give it enough resources to hold what it already has. 1808925Sroot * Wake up readers. 1818925Sroot */ 1828925Sroot sbappend(rcv, m); 1838925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1848925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1858925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1868925Sroot rcv->sb_hiwat = rcv->sb_cc; 18717543Skarels sorwakeup(so2); 18817543Skarels m = 0; 1898925Sroot #undef snd 1908925Sroot #undef rcv 1918925Sroot break; 1928925Sroot 1938925Sroot default: 1948925Sroot panic("uipc 4"); 1958925Sroot } 1968925Sroot break; 1978925Sroot 1988925Sroot case PRU_ABORT: 1998925Sroot unp_drop(unp, ECONNABORTED); 2008925Sroot break; 2018925Sroot 2028925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 2038925Sroot case PRU_CONTROL: 20413050Ssam return (EOPNOTSUPP); 2058925Sroot 20616973Skarels /* END UNIMPLEMENTED HOOKS */ 2078925Sroot case PRU_SENSE: 20816973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 20916973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 21016973Skarels so2 = unp->unp_conn->unp_socket; 21116973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 21216973Skarels } 213*21110Skarels ((struct stat *) m)->st_dev = NODEV; 214*21110Skarels ((struct stat *) m)->st_ino = unp_ino++; 21516973Skarels return (0); 2168925Sroot 2178925Sroot case PRU_RCVOOB: 21816774Sbloom return (EOPNOTSUPP); 2198925Sroot 2208925Sroot case PRU_SENDOOB: 22117543Skarels error = EOPNOTSUPP; 2228925Sroot break; 2238925Sroot 2248925Sroot case PRU_SOCKADDR: 2258925Sroot break; 2268925Sroot 22714121Ssam case PRU_PEERADDR: 22814121Ssam break; 22914121Ssam 2308925Sroot case PRU_SLOWTIMO: 2318925Sroot break; 2328925Sroot 2338925Sroot default: 2348925Sroot panic("piusrreq"); 2358925Sroot } 23612760Ssam release: 23712760Ssam if (m) 23812760Ssam m_freem(m); 23911709Ssam return (error); 2408925Sroot } 2418925Sroot 24216973Skarels /* 24316973Skarels * We assign all buffering for stream sockets to the source, 24416973Skarels * as that is where the flow control is implemented. 24516973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 24616973Skarels * and don't really want to reserve the sendspace. Their recvspace should 24716973Skarels * be large enough for at least one max-size datagram plus address. 24816973Skarels */ 24916973Skarels #define PIPSIZ 4096 25016973Skarels int unpst_sendspace = PIPSIZ; 25116973Skarels int unpst_recvspace = 0; 25216973Skarels int unpdg_sendspace = 2*1024; /* really max datagram size */ 25316973Skarels int unpdg_recvspace = 4*1024; 2548925Sroot 2559169Ssam unp_attach(so) 2568925Sroot struct socket *so; 2578925Sroot { 2589169Ssam register struct mbuf *m; 2598925Sroot register struct unpcb *unp; 2608925Sroot int error; 2618925Sroot 26216973Skarels switch (so->so_type) { 26316973Skarels 26416973Skarels case SOCK_STREAM: 26516973Skarels error = soreserve(so, unpst_sendspace, unpst_recvspace); 26616973Skarels break; 26716973Skarels 26816973Skarels case SOCK_DGRAM: 26916973Skarels error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 27016973Skarels break; 27116973Skarels } 2728925Sroot if (error) 27310139Ssam return (error); 2749637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 27510139Ssam if (m == NULL) 27610139Ssam return (ENOBUFS); 2778925Sroot unp = mtod(m, struct unpcb *); 2788925Sroot so->so_pcb = (caddr_t)unp; 2798925Sroot unp->unp_socket = so; 2808925Sroot return (0); 2818925Sroot } 2828925Sroot 2838925Sroot unp_detach(unp) 2849169Ssam register struct unpcb *unp; 2858925Sroot { 2868925Sroot 2878925Sroot if (unp->unp_inode) { 28817020Skarels unp->unp_inode->i_socket = 0; 2898925Sroot irele(unp->unp_inode); 2908925Sroot unp->unp_inode = 0; 2918925Sroot } 2928925Sroot if (unp->unp_conn) 2938925Sroot unp_disconnect(unp); 2948925Sroot while (unp->unp_refs) 2958925Sroot unp_drop(unp->unp_refs, ECONNRESET); 2968925Sroot soisdisconnected(unp->unp_socket); 2978925Sroot unp->unp_socket->so_pcb = 0; 2989169Ssam m_freem(unp->unp_remaddr); 2999169Ssam (void) m_free(dtom(unp)); 3008925Sroot } 3018925Sroot 3029169Ssam unp_bind(unp, nam) 3038925Sroot struct unpcb *unp; 3049169Ssam struct mbuf *nam; 3058925Sroot { 3069169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3078925Sroot register struct inode *ip; 30816695Smckusick register struct nameidata *ndp = &u.u_nd; 3098925Sroot int error; 3108925Sroot 31116695Smckusick ndp->ni_dirp = soun->sun_path; 31212760Ssam if (nam->m_len == MLEN) 31312760Ssam return (EINVAL); 31412760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 31512760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 31616695Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 31716695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 31816695Smckusick ip = namei(ndp); 3198925Sroot if (ip) { 3208925Sroot iput(ip); 32110139Ssam return (EADDRINUSE); 3228925Sroot } 32311828Ssam if (error = u.u_error) { 32411828Ssam u.u_error = 0; /* XXX */ 32511828Ssam return (error); 32611828Ssam } 32716695Smckusick ip = maknode(IFSOCK | 0777, ndp); 3288925Sroot if (ip == NULL) { 3298925Sroot error = u.u_error; /* XXX */ 3308925Sroot u.u_error = 0; /* XXX */ 3318925Sroot return (error); 3328925Sroot } 3338925Sroot ip->i_socket = unp->unp_socket; 3348925Sroot unp->unp_inode = ip; 3358925Sroot iunlock(ip); /* but keep reference */ 3368925Sroot return (0); 3378925Sroot } 3388925Sroot 3399169Ssam unp_connect(so, nam) 3408925Sroot struct socket *so; 3419169Ssam struct mbuf *nam; 3428925Sroot { 3439169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3449169Ssam register struct inode *ip; 3458925Sroot int error; 34612760Ssam register struct socket *so2; 34716695Smckusick register struct nameidata *ndp = &u.u_nd; 3488925Sroot 34916695Smckusick ndp->ni_dirp = soun->sun_path; 35012760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 35112760Ssam return (EMSGSIZE); 35212760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 35316695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 35416695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 35516695Smckusick ip = namei(ndp); 3568925Sroot if (ip == 0) { 3578925Sroot error = u.u_error; 3588925Sroot u.u_error = 0; 35910139Ssam return (error); /* XXX */ 3608925Sroot } 36117543Skarels if (access(ip, IWRITE)) { 36217543Skarels error = u.u_error; 36317543Skarels u.u_error = 0; /* XXX */ 36417543Skarels goto bad; 36517543Skarels } 3668925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3678925Sroot error = ENOTSOCK; 3688925Sroot goto bad; 3698925Sroot } 3708925Sroot so2 = ip->i_socket; 3718925Sroot if (so2 == 0) { 3728925Sroot error = ECONNREFUSED; 3738925Sroot goto bad; 3748925Sroot } 37513115Ssam if (so->so_type != so2->so_type) { 37613115Ssam error = EPROTOTYPE; 37713115Ssam goto bad; 37813115Ssam } 37913115Ssam if (so->so_proto->pr_flags & PR_CONNREQUIRED && 38013115Ssam ((so2->so_options&SO_ACCEPTCONN) == 0 || 38113115Ssam (so2 = sonewconn(so2)) == 0)) { 38213115Ssam error = ECONNREFUSED; 38313115Ssam goto bad; 38413115Ssam } 38512760Ssam error = unp_connect2(so, nam, so2); 38612760Ssam bad: 38712760Ssam iput(ip); 38812760Ssam return (error); 38912760Ssam } 39012760Ssam 39112760Ssam unp_connect2(so, sonam, so2) 39212760Ssam register struct socket *so; 39312760Ssam struct mbuf *sonam; 39412760Ssam register struct socket *so2; 39512760Ssam { 39612760Ssam register struct unpcb *unp = sotounpcb(so); 39712760Ssam register struct unpcb *unp2; 39812760Ssam 39912760Ssam if (so2->so_type != so->so_type) 40012760Ssam return (EPROTOTYPE); 40114049Ssam unp2 = sotounpcb(so2); 40214049Ssam unp->unp_conn = unp2; 4038925Sroot switch (so->so_type) { 4048925Sroot 4058925Sroot case SOCK_DGRAM: 4068925Sroot unp->unp_nextref = unp2->unp_refs; 4078925Sroot unp2->unp_refs = unp; 40817543Skarels soisconnected(so); 4098925Sroot break; 4108925Sroot 4118925Sroot case SOCK_STREAM: 4129169Ssam unp2->unp_conn = unp; 41312760Ssam if (sonam) 41412760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 41514049Ssam soisconnected(so2); 41614049Ssam soisconnected(so); 4178925Sroot break; 4188925Sroot 4198925Sroot default: 42012760Ssam panic("unp_connect2"); 4218925Sroot } 4228925Sroot return (0); 4238925Sroot } 4249169Ssam 4259169Ssam unp_disconnect(unp) 4269169Ssam struct unpcb *unp; 4279169Ssam { 4289169Ssam register struct unpcb *unp2 = unp->unp_conn; 4299169Ssam 4309169Ssam if (unp2 == 0) 4319169Ssam return; 4329169Ssam unp->unp_conn = 0; 4339169Ssam switch (unp->unp_socket->so_type) { 4349169Ssam 4359169Ssam case SOCK_DGRAM: 4369169Ssam if (unp2->unp_refs == unp) 4379169Ssam unp2->unp_refs = unp->unp_nextref; 4389169Ssam else { 4399169Ssam unp2 = unp2->unp_refs; 4409169Ssam for (;;) { 4419169Ssam if (unp2 == 0) 4429169Ssam panic("unp_disconnect"); 4439169Ssam if (unp2->unp_nextref == unp) 4449169Ssam break; 4459169Ssam unp2 = unp2->unp_nextref; 4469169Ssam } 4479169Ssam unp2->unp_nextref = unp->unp_nextref; 4489169Ssam } 4499169Ssam unp->unp_nextref = 0; 4509169Ssam break; 4519169Ssam 4529169Ssam case SOCK_STREAM: 45314049Ssam soisdisconnected(unp->unp_socket); 4549169Ssam unp2->unp_conn = 0; 4559169Ssam soisdisconnected(unp2->unp_socket); 4569169Ssam break; 4579169Ssam } 4589169Ssam } 4599169Ssam 46012760Ssam #ifdef notdef 4619169Ssam unp_abort(unp) 4629169Ssam struct unpcb *unp; 4639169Ssam { 4649169Ssam 4659169Ssam unp_detach(unp); 4669169Ssam } 46712760Ssam #endif 4689169Ssam 4699169Ssam /*ARGSUSED*/ 4709169Ssam unp_usrclosed(unp) 4719169Ssam struct unpcb *unp; 4729169Ssam { 4739169Ssam 4749169Ssam } 4759169Ssam 4769169Ssam unp_drop(unp, errno) 4779169Ssam struct unpcb *unp; 4789169Ssam int errno; 4799169Ssam { 48016054Skarels struct socket *so = unp->unp_socket; 4819169Ssam 48216054Skarels so->so_error = errno; 4839169Ssam unp_disconnect(unp); 48416054Skarels if (so->so_head) { 48516054Skarels so->so_pcb = (caddr_t) 0; 48616431Skarels m_freem(unp->unp_remaddr); 48716054Skarels (void) m_free(dtom(unp)); 48816054Skarels sofree(so); 48916054Skarels } 4909169Ssam } 4919169Ssam 49212760Ssam #ifdef notdef 4939169Ssam unp_drain() 4949169Ssam { 4959169Ssam 4969169Ssam } 49712760Ssam #endif 49812760Ssam 49912760Ssam unp_externalize(rights) 50012760Ssam struct mbuf *rights; 50112760Ssam { 50212760Ssam int newfds = rights->m_len / sizeof (int); 50312760Ssam register int i; 50412760Ssam register struct file **rp = mtod(rights, struct file **); 50512760Ssam register struct file *fp; 50612760Ssam int f; 50712760Ssam 50812760Ssam if (newfds > ufavail()) { 50912760Ssam for (i = 0; i < newfds; i++) { 51012760Ssam fp = *rp; 51112760Ssam unp_discard(fp); 51212760Ssam *rp++ = 0; 51312760Ssam } 51412760Ssam return (EMSGSIZE); 51512760Ssam } 51612760Ssam for (i = 0; i < newfds; i++) { 51712760Ssam f = ufalloc(0); 51812760Ssam if (f < 0) 51912760Ssam panic("unp_externalize"); 52012760Ssam fp = *rp; 52112760Ssam u.u_ofile[f] = fp; 52212760Ssam fp->f_msgcount--; 52314927Smckusick *(int *)rp++ = f; 52412760Ssam } 52512760Ssam return (0); 52612760Ssam } 52712760Ssam 52812760Ssam unp_internalize(rights) 52912760Ssam struct mbuf *rights; 53012760Ssam { 53112760Ssam register struct file **rp; 53212760Ssam int oldfds = rights->m_len / sizeof (int); 53312760Ssam register int i; 53412760Ssam register struct file *fp; 53512760Ssam 53612760Ssam rp = mtod(rights, struct file **); 53713084Ssam for (i = 0; i < oldfds; i++) 53812760Ssam if (getf(*(int *)rp++) == 0) 53912760Ssam return (EBADF); 54012760Ssam rp = mtod(rights, struct file **); 54113084Ssam for (i = 0; i < oldfds; i++) { 54212760Ssam fp = getf(*(int *)rp); 54312760Ssam *rp++ = fp; 54412760Ssam fp->f_count++; 54512760Ssam fp->f_msgcount++; 54612760Ssam } 54712760Ssam return (0); 54812760Ssam } 54912760Ssam 55012760Ssam int unp_defer, unp_gcing; 55112760Ssam int unp_mark(); 55216995Skarels extern struct domain unixdomain; 55312760Ssam 55412760Ssam unp_gc() 55512760Ssam { 55612760Ssam register struct file *fp; 55712760Ssam register struct socket *so; 55812760Ssam 55912760Ssam if (unp_gcing) 56012760Ssam return; 56112760Ssam unp_gcing = 1; 56212760Ssam restart: 56312760Ssam unp_defer = 0; 56412760Ssam for (fp = file; fp < fileNFILE; fp++) 56512760Ssam fp->f_flag &= ~(FMARK|FDEFER); 56612760Ssam do { 56712760Ssam for (fp = file; fp < fileNFILE; fp++) { 56812760Ssam if (fp->f_count == 0) 56912760Ssam continue; 57012760Ssam if (fp->f_flag & FDEFER) { 57112760Ssam fp->f_flag &= ~FDEFER; 57212760Ssam unp_defer--; 57312760Ssam } else { 57412760Ssam if (fp->f_flag & FMARK) 57512760Ssam continue; 57612760Ssam if (fp->f_count == fp->f_msgcount) 57712760Ssam continue; 57812760Ssam fp->f_flag |= FMARK; 57912760Ssam } 58012760Ssam if (fp->f_type != DTYPE_SOCKET) 58112760Ssam continue; 58212760Ssam so = (struct socket *)fp->f_data; 58316995Skarels if (so->so_proto->pr_domain != &unixdomain || 58412760Ssam (so->so_proto->pr_flags&PR_ADDR) == 0) 58512760Ssam continue; 58612760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 58712760Ssam sbwait(&so->so_rcv); 58812760Ssam goto restart; 58912760Ssam } 59012760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 59112760Ssam } 59212760Ssam } while (unp_defer); 59312760Ssam for (fp = file; fp < fileNFILE; fp++) { 59412760Ssam if (fp->f_count == 0) 59512760Ssam continue; 59612760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 59712760Ssam if (fp->f_type != DTYPE_SOCKET) 59812760Ssam panic("unp_gc"); 59912760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 60012760Ssam } 60112760Ssam } 60212760Ssam unp_gcing = 0; 60312760Ssam } 60412760Ssam 60516995Skarels unp_dispose(m) 60616995Skarels struct mbuf *m; 60716995Skarels { 60816995Skarels int unp_discard(); 60916995Skarels 61017020Skarels if (m) 61117020Skarels unp_scan(m, unp_discard); 61216995Skarels } 61316995Skarels 61416995Skarels unp_scan(m0, op) 61516995Skarels register struct mbuf *m0; 61612760Ssam int (*op)(); 61712760Ssam { 61816995Skarels register struct mbuf *m; 61912760Ssam register struct file **rp; 62012760Ssam register int i; 62117020Skarels int qfds; 62212760Ssam 62316995Skarels while (m0) { 62416995Skarels for (m = m0; m; m = m->m_next) 62516995Skarels if (m->m_type == MT_RIGHTS && m->m_len) { 62616995Skarels qfds = m->m_len / sizeof (struct file *); 62716995Skarels rp = mtod(m, struct file **); 62816995Skarels for (i = 0; i < qfds; i++) 62916995Skarels (*op)(*rp++); 63016995Skarels break; /* XXX, but saves time */ 63116995Skarels } 63217020Skarels m0 = m0->m_act; 63312760Ssam } 63412760Ssam } 63512760Ssam 63612760Ssam unp_mark(fp) 63712760Ssam struct file *fp; 63812760Ssam { 63912760Ssam 64012760Ssam if (fp->f_flag & FMARK) 64112760Ssam return; 64212760Ssam unp_defer++; 64312760Ssam fp->f_flag |= (FMARK|FDEFER); 64412760Ssam } 64512760Ssam 64612760Ssam unp_discard(fp) 64712760Ssam struct file *fp; 64812760Ssam { 64912760Ssam 65012760Ssam fp->f_msgcount--; 65113084Ssam closef(fp); 65212760Ssam } 653