123443Smckusick /* 223443Smckusick * Copyright (c) 1982 Regents of the University of California. 323443Smckusick * All rights reserved. The Berkeley software License Agreement 423443Smckusick * specifies the terms and conditions for redistribution. 523443Smckusick * 6*25555Skarels * @(#)uipc_usrreq.c 6.17 (Berkeley) 11/30/85 723443Smckusick */ 88925Sroot 917105Sbloom #include "param.h" 1017105Sbloom #include "dir.h" 1117105Sbloom #include "user.h" 1217105Sbloom #include "mbuf.h" 1317105Sbloom #include "domain.h" 1417105Sbloom #include "protosw.h" 1517105Sbloom #include "socket.h" 1617105Sbloom #include "socketvar.h" 1717105Sbloom #include "unpcb.h" 1817105Sbloom #include "un.h" 1917105Sbloom #include "inode.h" 2017105Sbloom #include "file.h" 2117105Sbloom #include "stat.h" 228925Sroot 238925Sroot /* 248925Sroot * Unix communications domain. 2512760Ssam * 2612760Ssam * TODO: 2712760Ssam * SEQPACKET, RDM 2813119Ssam * rethink name space problems 2912760Ssam * need a proper out-of-band 308925Sroot */ 3113119Ssam struct sockaddr sun_noname = { AF_UNIX }; 3221110Skarels ino_t unp_ino; /* fake inode numbers */ 338925Sroot 348925Sroot /*ARGSUSED*/ 3512760Ssam uipc_usrreq(so, req, m, nam, rights) 368925Sroot struct socket *so; 378925Sroot int req; 3812760Ssam struct mbuf *m, *nam, *rights; 398925Sroot { 408925Sroot struct unpcb *unp = sotounpcb(so); 418925Sroot register struct socket *so2; 428925Sroot int error = 0; 438925Sroot 44*25555Skarels if (req == PRU_CONTROL) 45*25555Skarels return (EOPNOTSUPP); 4612760Ssam if (req != PRU_SEND && rights && rights->m_len) { 4712760Ssam error = EOPNOTSUPP; 4812760Ssam goto release; 4912760Ssam } 5012760Ssam if (unp == 0 && req != PRU_ATTACH) { 5112760Ssam error = EINVAL; 5212760Ssam goto release; 5312760Ssam } 548925Sroot switch (req) { 558925Sroot 568925Sroot case PRU_ATTACH: 578925Sroot if (unp) { 589169Ssam error = EISCONN; 598925Sroot break; 608925Sroot } 619028Sroot error = unp_attach(so); 628925Sroot break; 638925Sroot 648925Sroot case PRU_DETACH: 658925Sroot unp_detach(unp); 668925Sroot break; 678925Sroot 689169Ssam case PRU_BIND: 699169Ssam error = unp_bind(unp, nam); 709169Ssam break; 719169Ssam 729169Ssam case PRU_LISTEN: 739169Ssam if (unp->unp_inode == 0) 749169Ssam error = EINVAL; 759169Ssam break; 769169Ssam 778925Sroot case PRU_CONNECT: 789028Sroot error = unp_connect(so, nam); 798925Sroot break; 808925Sroot 8112760Ssam case PRU_CONNECT2: 8213115Ssam error = unp_connect2(so, (struct mbuf *)0, 8313115Ssam (struct socket *)nam); 8412760Ssam break; 8512760Ssam 868925Sroot case PRU_DISCONNECT: 878925Sroot unp_disconnect(unp); 888925Sroot break; 898925Sroot 909169Ssam case PRU_ACCEPT: 919169Ssam nam->m_len = unp->unp_remaddr->m_len; 929169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 939169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 948925Sroot break; 958925Sroot 968925Sroot case PRU_SHUTDOWN: 978925Sroot socantsendmore(so); 988925Sroot unp_usrclosed(unp); 998925Sroot break; 1008925Sroot 1018925Sroot case PRU_RCVD: 1028925Sroot switch (so->so_type) { 1038925Sroot 1048925Sroot case SOCK_DGRAM: 1058925Sroot panic("uipc 1"); 10610139Ssam /*NOTREACHED*/ 1078925Sroot 10810139Ssam case SOCK_STREAM: 1098925Sroot #define rcv (&so->so_rcv) 1108925Sroot #define snd (&so2->so_snd) 1118925Sroot if (unp->unp_conn == 0) 1128925Sroot break; 1138925Sroot so2 = unp->unp_conn->unp_socket; 1148925Sroot /* 1158925Sroot * Transfer resources back to send port 1168925Sroot * and wakeup any waiting to write. 1178925Sroot */ 1188925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 1198925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1208925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 1218925Sroot rcv->sb_hiwat = rcv->sb_cc; 12217543Skarels sowwakeup(so2); 1238925Sroot #undef snd 1248925Sroot #undef rcv 1258925Sroot break; 1268925Sroot 1278925Sroot default: 1288925Sroot panic("uipc 2"); 1298925Sroot } 1308925Sroot break; 1318925Sroot 1328925Sroot case PRU_SEND: 1338925Sroot switch (so->so_type) { 1348925Sroot 1358925Sroot case SOCK_DGRAM: 1369028Sroot if (nam) { 1378925Sroot if (unp->unp_conn) { 1388925Sroot error = EISCONN; 1398925Sroot break; 1408925Sroot } 1419028Sroot error = unp_connect(so, nam); 1428925Sroot if (error) 1438925Sroot break; 1448925Sroot } else { 1458925Sroot if (unp->unp_conn == 0) { 1468925Sroot error = ENOTCONN; 1478925Sroot break; 1488925Sroot } 1498925Sroot } 1508925Sroot so2 = unp->unp_conn->unp_socket; 1519169Ssam /* BEGIN XXX */ 15212760Ssam if (rights) { 15312760Ssam error = unp_internalize(rights); 15412760Ssam if (error) 15512760Ssam break; 15612760Ssam } 15712760Ssam if (sbspace(&so2->so_rcv) > 0) { 15813119Ssam /* 15913119Ssam * There's no record of source socket's 16013119Ssam * name, so send null name for the moment. 16113119Ssam */ 16217543Skarels if (sbappendaddr(&so2->so_rcv, 16317543Skarels &sun_noname, m, rights)) { 16417543Skarels sorwakeup(so2); 16517543Skarels m = 0; 16623524Skarels } else 16723524Skarels error = ENOBUFS; 16812760Ssam } 1699169Ssam /* END XXX */ 1709028Sroot if (nam) 1719169Ssam unp_disconnect(unp); 1728925Sroot break; 1738925Sroot 1748925Sroot case SOCK_STREAM: 1758925Sroot #define rcv (&so2->so_rcv) 1768925Sroot #define snd (&so->so_snd) 17712760Ssam if (rights && rights->m_len) { 17812760Ssam error = EOPNOTSUPP; 17912760Ssam break; 18012760Ssam } 18123524Skarels if (so->so_state & SS_CANTSENDMORE) { 18223524Skarels error = EPIPE; 18323524Skarels break; 18423524Skarels } 1858925Sroot if (unp->unp_conn == 0) 1868925Sroot panic("uipc 3"); 1878925Sroot so2 = unp->unp_conn->unp_socket; 1888925Sroot /* 1898925Sroot * Send to paired receive port, and then 1908925Sroot * give it enough resources to hold what it already has. 1918925Sroot * Wake up readers. 1928925Sroot */ 1938925Sroot sbappend(rcv, m); 1948925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1958925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1968925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1978925Sroot rcv->sb_hiwat = rcv->sb_cc; 19817543Skarels sorwakeup(so2); 19917543Skarels m = 0; 2008925Sroot #undef snd 2018925Sroot #undef rcv 2028925Sroot break; 2038925Sroot 2048925Sroot default: 2058925Sroot panic("uipc 4"); 2068925Sroot } 2078925Sroot break; 2088925Sroot 2098925Sroot case PRU_ABORT: 2108925Sroot unp_drop(unp, ECONNABORTED); 2118925Sroot break; 2128925Sroot 2138925Sroot case PRU_SENSE: 21416973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 21516973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 21616973Skarels so2 = unp->unp_conn->unp_socket; 21716973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 21816973Skarels } 21921110Skarels ((struct stat *) m)->st_dev = NODEV; 22021110Skarels ((struct stat *) m)->st_ino = unp_ino++; 22116973Skarels return (0); 2228925Sroot 2238925Sroot case PRU_RCVOOB: 22416774Sbloom return (EOPNOTSUPP); 2258925Sroot 2268925Sroot case PRU_SENDOOB: 22717543Skarels error = EOPNOTSUPP; 2288925Sroot break; 2298925Sroot 2308925Sroot case PRU_SOCKADDR: 2318925Sroot break; 2328925Sroot 23314121Ssam case PRU_PEERADDR: 23414121Ssam break; 23514121Ssam 2368925Sroot case PRU_SLOWTIMO: 2378925Sroot break; 2388925Sroot 2398925Sroot default: 2408925Sroot panic("piusrreq"); 2418925Sroot } 24212760Ssam release: 24312760Ssam if (m) 24412760Ssam m_freem(m); 24511709Ssam return (error); 2468925Sroot } 2478925Sroot 24816973Skarels /* 24916973Skarels * We assign all buffering for stream sockets to the source, 25016973Skarels * as that is where the flow control is implemented. 25116973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 25216973Skarels * and don't really want to reserve the sendspace. Their recvspace should 25316973Skarels * be large enough for at least one max-size datagram plus address. 25416973Skarels */ 25516973Skarels #define PIPSIZ 4096 25616973Skarels int unpst_sendspace = PIPSIZ; 25716973Skarels int unpst_recvspace = 0; 25816973Skarels int unpdg_sendspace = 2*1024; /* really max datagram size */ 25916973Skarels int unpdg_recvspace = 4*1024; 2608925Sroot 2619169Ssam unp_attach(so) 2628925Sroot struct socket *so; 2638925Sroot { 2649169Ssam register struct mbuf *m; 2658925Sroot register struct unpcb *unp; 2668925Sroot int error; 2678925Sroot 26816973Skarels switch (so->so_type) { 26916973Skarels 27016973Skarels case SOCK_STREAM: 27116973Skarels error = soreserve(so, unpst_sendspace, unpst_recvspace); 27216973Skarels break; 27316973Skarels 27416973Skarels case SOCK_DGRAM: 27516973Skarels error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 27616973Skarels break; 27716973Skarels } 2788925Sroot if (error) 27910139Ssam return (error); 2809637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 28110139Ssam if (m == NULL) 28210139Ssam return (ENOBUFS); 2838925Sroot unp = mtod(m, struct unpcb *); 2848925Sroot so->so_pcb = (caddr_t)unp; 2858925Sroot unp->unp_socket = so; 2868925Sroot return (0); 2878925Sroot } 2888925Sroot 2898925Sroot unp_detach(unp) 2909169Ssam register struct unpcb *unp; 2918925Sroot { 2928925Sroot 2938925Sroot if (unp->unp_inode) { 29417020Skarels unp->unp_inode->i_socket = 0; 2958925Sroot irele(unp->unp_inode); 2968925Sroot unp->unp_inode = 0; 2978925Sroot } 2988925Sroot if (unp->unp_conn) 2998925Sroot unp_disconnect(unp); 3008925Sroot while (unp->unp_refs) 3018925Sroot unp_drop(unp->unp_refs, ECONNRESET); 3028925Sroot soisdisconnected(unp->unp_socket); 3038925Sroot unp->unp_socket->so_pcb = 0; 3049169Ssam m_freem(unp->unp_remaddr); 3059169Ssam (void) m_free(dtom(unp)); 3068925Sroot } 3078925Sroot 3089169Ssam unp_bind(unp, nam) 3098925Sroot struct unpcb *unp; 3109169Ssam struct mbuf *nam; 3118925Sroot { 3129169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3138925Sroot register struct inode *ip; 31416695Smckusick register struct nameidata *ndp = &u.u_nd; 3158925Sroot int error; 3168925Sroot 31716695Smckusick ndp->ni_dirp = soun->sun_path; 31825232Smckusick if (unp->unp_inode != NULL || nam->m_len == MLEN) 31912760Ssam return (EINVAL); 32012760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 32112760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 32216695Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 32316695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 32416695Smckusick ip = namei(ndp); 3258925Sroot if (ip) { 3268925Sroot iput(ip); 32710139Ssam return (EADDRINUSE); 3288925Sroot } 32911828Ssam if (error = u.u_error) { 33011828Ssam u.u_error = 0; /* XXX */ 33111828Ssam return (error); 33211828Ssam } 33316695Smckusick ip = maknode(IFSOCK | 0777, ndp); 3348925Sroot if (ip == NULL) { 3358925Sroot error = u.u_error; /* XXX */ 3368925Sroot u.u_error = 0; /* XXX */ 3378925Sroot return (error); 3388925Sroot } 3398925Sroot ip->i_socket = unp->unp_socket; 3408925Sroot unp->unp_inode = ip; 3418925Sroot iunlock(ip); /* but keep reference */ 3428925Sroot return (0); 3438925Sroot } 3448925Sroot 3459169Ssam unp_connect(so, nam) 3468925Sroot struct socket *so; 3479169Ssam struct mbuf *nam; 3488925Sroot { 3499169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3509169Ssam register struct inode *ip; 3518925Sroot int error; 35212760Ssam register struct socket *so2; 35316695Smckusick register struct nameidata *ndp = &u.u_nd; 3548925Sroot 35516695Smckusick ndp->ni_dirp = soun->sun_path; 35612760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 35712760Ssam return (EMSGSIZE); 35812760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 35916695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 36016695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 36116695Smckusick ip = namei(ndp); 3628925Sroot if (ip == 0) { 3638925Sroot error = u.u_error; 3648925Sroot u.u_error = 0; 36510139Ssam return (error); /* XXX */ 3668925Sroot } 36717543Skarels if (access(ip, IWRITE)) { 36817543Skarels error = u.u_error; 36917543Skarels u.u_error = 0; /* XXX */ 37017543Skarels goto bad; 37117543Skarels } 3728925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3738925Sroot error = ENOTSOCK; 3748925Sroot goto bad; 3758925Sroot } 3768925Sroot so2 = ip->i_socket; 3778925Sroot if (so2 == 0) { 3788925Sroot error = ECONNREFUSED; 3798925Sroot goto bad; 3808925Sroot } 38113115Ssam if (so->so_type != so2->so_type) { 38213115Ssam error = EPROTOTYPE; 38313115Ssam goto bad; 38413115Ssam } 38513115Ssam if (so->so_proto->pr_flags & PR_CONNREQUIRED && 38613115Ssam ((so2->so_options&SO_ACCEPTCONN) == 0 || 38713115Ssam (so2 = sonewconn(so2)) == 0)) { 38813115Ssam error = ECONNREFUSED; 38913115Ssam goto bad; 39013115Ssam } 39112760Ssam error = unp_connect2(so, nam, so2); 39212760Ssam bad: 39312760Ssam iput(ip); 39412760Ssam return (error); 39512760Ssam } 39612760Ssam 39712760Ssam unp_connect2(so, sonam, so2) 39812760Ssam register struct socket *so; 39912760Ssam struct mbuf *sonam; 40012760Ssam register struct socket *so2; 40112760Ssam { 40212760Ssam register struct unpcb *unp = sotounpcb(so); 40312760Ssam register struct unpcb *unp2; 40412760Ssam 40512760Ssam if (so2->so_type != so->so_type) 40612760Ssam return (EPROTOTYPE); 40714049Ssam unp2 = sotounpcb(so2); 40814049Ssam unp->unp_conn = unp2; 4098925Sroot switch (so->so_type) { 4108925Sroot 4118925Sroot case SOCK_DGRAM: 4128925Sroot unp->unp_nextref = unp2->unp_refs; 4138925Sroot unp2->unp_refs = unp; 41417543Skarels soisconnected(so); 4158925Sroot break; 4168925Sroot 4178925Sroot case SOCK_STREAM: 4189169Ssam unp2->unp_conn = unp; 41912760Ssam if (sonam) 42012760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 42114049Ssam soisconnected(so2); 42214049Ssam soisconnected(so); 4238925Sroot break; 4248925Sroot 4258925Sroot default: 42612760Ssam panic("unp_connect2"); 4278925Sroot } 4288925Sroot return (0); 4298925Sroot } 4309169Ssam 4319169Ssam unp_disconnect(unp) 4329169Ssam struct unpcb *unp; 4339169Ssam { 4349169Ssam register struct unpcb *unp2 = unp->unp_conn; 4359169Ssam 4369169Ssam if (unp2 == 0) 4379169Ssam return; 4389169Ssam unp->unp_conn = 0; 4399169Ssam switch (unp->unp_socket->so_type) { 4409169Ssam 4419169Ssam case SOCK_DGRAM: 4429169Ssam if (unp2->unp_refs == unp) 4439169Ssam unp2->unp_refs = unp->unp_nextref; 4449169Ssam else { 4459169Ssam unp2 = unp2->unp_refs; 4469169Ssam for (;;) { 4479169Ssam if (unp2 == 0) 4489169Ssam panic("unp_disconnect"); 4499169Ssam if (unp2->unp_nextref == unp) 4509169Ssam break; 4519169Ssam unp2 = unp2->unp_nextref; 4529169Ssam } 4539169Ssam unp2->unp_nextref = unp->unp_nextref; 4549169Ssam } 4559169Ssam unp->unp_nextref = 0; 45621768Skarels unp->unp_socket->so_state &= ~SS_ISCONNECTED; 4579169Ssam break; 4589169Ssam 4599169Ssam case SOCK_STREAM: 46014049Ssam soisdisconnected(unp->unp_socket); 4619169Ssam unp2->unp_conn = 0; 4629169Ssam soisdisconnected(unp2->unp_socket); 4639169Ssam break; 4649169Ssam } 4659169Ssam } 4669169Ssam 46712760Ssam #ifdef notdef 4689169Ssam unp_abort(unp) 4699169Ssam struct unpcb *unp; 4709169Ssam { 4719169Ssam 4729169Ssam unp_detach(unp); 4739169Ssam } 47412760Ssam #endif 4759169Ssam 4769169Ssam /*ARGSUSED*/ 4779169Ssam unp_usrclosed(unp) 4789169Ssam struct unpcb *unp; 4799169Ssam { 4809169Ssam 4819169Ssam } 4829169Ssam 4839169Ssam unp_drop(unp, errno) 4849169Ssam struct unpcb *unp; 4859169Ssam int errno; 4869169Ssam { 48716054Skarels struct socket *so = unp->unp_socket; 4889169Ssam 48916054Skarels so->so_error = errno; 4909169Ssam unp_disconnect(unp); 49116054Skarels if (so->so_head) { 49216054Skarels so->so_pcb = (caddr_t) 0; 49316431Skarels m_freem(unp->unp_remaddr); 49416054Skarels (void) m_free(dtom(unp)); 49516054Skarels sofree(so); 49616054Skarels } 4979169Ssam } 4989169Ssam 49912760Ssam #ifdef notdef 5009169Ssam unp_drain() 5019169Ssam { 5029169Ssam 5039169Ssam } 50412760Ssam #endif 50512760Ssam 50612760Ssam unp_externalize(rights) 50712760Ssam struct mbuf *rights; 50812760Ssam { 50912760Ssam int newfds = rights->m_len / sizeof (int); 51012760Ssam register int i; 51112760Ssam register struct file **rp = mtod(rights, struct file **); 51212760Ssam register struct file *fp; 51312760Ssam int f; 51412760Ssam 51512760Ssam if (newfds > ufavail()) { 51612760Ssam for (i = 0; i < newfds; i++) { 51712760Ssam fp = *rp; 51812760Ssam unp_discard(fp); 51912760Ssam *rp++ = 0; 52012760Ssam } 52112760Ssam return (EMSGSIZE); 52212760Ssam } 52312760Ssam for (i = 0; i < newfds; i++) { 52412760Ssam f = ufalloc(0); 52512760Ssam if (f < 0) 52612760Ssam panic("unp_externalize"); 52712760Ssam fp = *rp; 52812760Ssam u.u_ofile[f] = fp; 52912760Ssam fp->f_msgcount--; 53014927Smckusick *(int *)rp++ = f; 53112760Ssam } 53212760Ssam return (0); 53312760Ssam } 53412760Ssam 53512760Ssam unp_internalize(rights) 53612760Ssam struct mbuf *rights; 53712760Ssam { 53812760Ssam register struct file **rp; 53912760Ssam int oldfds = rights->m_len / sizeof (int); 54012760Ssam register int i; 54112760Ssam register struct file *fp; 54212760Ssam 54312760Ssam rp = mtod(rights, struct file **); 54413084Ssam for (i = 0; i < oldfds; i++) 54512760Ssam if (getf(*(int *)rp++) == 0) 54612760Ssam return (EBADF); 54712760Ssam rp = mtod(rights, struct file **); 54813084Ssam for (i = 0; i < oldfds; i++) { 54912760Ssam fp = getf(*(int *)rp); 55012760Ssam *rp++ = fp; 55112760Ssam fp->f_count++; 55212760Ssam fp->f_msgcount++; 55312760Ssam } 55412760Ssam return (0); 55512760Ssam } 55612760Ssam 55712760Ssam int unp_defer, unp_gcing; 55812760Ssam int unp_mark(); 55916995Skarels extern struct domain unixdomain; 56012760Ssam 56112760Ssam unp_gc() 56212760Ssam { 56312760Ssam register struct file *fp; 56412760Ssam register struct socket *so; 56512760Ssam 56612760Ssam if (unp_gcing) 56712760Ssam return; 56812760Ssam unp_gcing = 1; 56912760Ssam restart: 57012760Ssam unp_defer = 0; 57112760Ssam for (fp = file; fp < fileNFILE; fp++) 57212760Ssam fp->f_flag &= ~(FMARK|FDEFER); 57312760Ssam do { 57412760Ssam for (fp = file; fp < fileNFILE; fp++) { 57512760Ssam if (fp->f_count == 0) 57612760Ssam continue; 57712760Ssam if (fp->f_flag & FDEFER) { 57812760Ssam fp->f_flag &= ~FDEFER; 57912760Ssam unp_defer--; 58012760Ssam } else { 58112760Ssam if (fp->f_flag & FMARK) 58212760Ssam continue; 58312760Ssam if (fp->f_count == fp->f_msgcount) 58412760Ssam continue; 58512760Ssam fp->f_flag |= FMARK; 58612760Ssam } 58712760Ssam if (fp->f_type != DTYPE_SOCKET) 58812760Ssam continue; 58912760Ssam so = (struct socket *)fp->f_data; 59016995Skarels if (so->so_proto->pr_domain != &unixdomain || 59121768Skarels (so->so_proto->pr_flags&PR_RIGHTS) == 0) 59212760Ssam continue; 59312760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 59412760Ssam sbwait(&so->so_rcv); 59512760Ssam goto restart; 59612760Ssam } 59712760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 59812760Ssam } 59912760Ssam } while (unp_defer); 60012760Ssam for (fp = file; fp < fileNFILE; fp++) { 60112760Ssam if (fp->f_count == 0) 60212760Ssam continue; 60312760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 60412760Ssam if (fp->f_type != DTYPE_SOCKET) 60512760Ssam panic("unp_gc"); 60612760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 60712760Ssam } 60812760Ssam } 60912760Ssam unp_gcing = 0; 61012760Ssam } 61112760Ssam 61216995Skarels unp_dispose(m) 61316995Skarels struct mbuf *m; 61416995Skarels { 61516995Skarels int unp_discard(); 61616995Skarels 61717020Skarels if (m) 61817020Skarels unp_scan(m, unp_discard); 61916995Skarels } 62016995Skarels 62116995Skarels unp_scan(m0, op) 62216995Skarels register struct mbuf *m0; 62312760Ssam int (*op)(); 62412760Ssam { 62516995Skarels register struct mbuf *m; 62612760Ssam register struct file **rp; 62712760Ssam register int i; 62817020Skarels int qfds; 62912760Ssam 63016995Skarels while (m0) { 63116995Skarels for (m = m0; m; m = m->m_next) 63216995Skarels if (m->m_type == MT_RIGHTS && m->m_len) { 63316995Skarels qfds = m->m_len / sizeof (struct file *); 63416995Skarels rp = mtod(m, struct file **); 63516995Skarels for (i = 0; i < qfds; i++) 63616995Skarels (*op)(*rp++); 63716995Skarels break; /* XXX, but saves time */ 63816995Skarels } 63917020Skarels m0 = m0->m_act; 64012760Ssam } 64112760Ssam } 64212760Ssam 64312760Ssam unp_mark(fp) 64412760Ssam struct file *fp; 64512760Ssam { 64612760Ssam 64712760Ssam if (fp->f_flag & FMARK) 64812760Ssam return; 64912760Ssam unp_defer++; 65012760Ssam fp->f_flag |= (FMARK|FDEFER); 65112760Ssam } 65212760Ssam 65312760Ssam unp_discard(fp) 65412760Ssam struct file *fp; 65512760Ssam { 65612760Ssam 65712760Ssam fp->f_msgcount--; 65813084Ssam closef(fp); 65912760Ssam } 660