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*25232Smckusick * @(#)uipc_usrreq.c 6.16 (Berkeley) 10/18/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 4412760Ssam if (req != PRU_SEND && rights && rights->m_len) { 4512760Ssam error = EOPNOTSUPP; 4612760Ssam goto release; 4712760Ssam } 4812760Ssam if (unp == 0 && req != PRU_ATTACH) { 4912760Ssam error = EINVAL; 5012760Ssam goto release; 5112760Ssam } 528925Sroot switch (req) { 538925Sroot 548925Sroot case PRU_ATTACH: 558925Sroot if (unp) { 569169Ssam error = EISCONN; 578925Sroot break; 588925Sroot } 599028Sroot error = unp_attach(so); 608925Sroot break; 618925Sroot 628925Sroot case PRU_DETACH: 638925Sroot unp_detach(unp); 648925Sroot break; 658925Sroot 669169Ssam case PRU_BIND: 679169Ssam error = unp_bind(unp, nam); 689169Ssam break; 699169Ssam 709169Ssam case PRU_LISTEN: 719169Ssam if (unp->unp_inode == 0) 729169Ssam error = EINVAL; 739169Ssam break; 749169Ssam 758925Sroot case PRU_CONNECT: 769028Sroot error = unp_connect(so, nam); 778925Sroot break; 788925Sroot 7912760Ssam case PRU_CONNECT2: 8013115Ssam error = unp_connect2(so, (struct mbuf *)0, 8113115Ssam (struct socket *)nam); 8212760Ssam break; 8312760Ssam 848925Sroot case PRU_DISCONNECT: 858925Sroot unp_disconnect(unp); 868925Sroot break; 878925Sroot 889169Ssam case PRU_ACCEPT: 899169Ssam nam->m_len = unp->unp_remaddr->m_len; 909169Ssam bcopy(mtod(unp->unp_remaddr, caddr_t), 919169Ssam mtod(nam, caddr_t), (unsigned)nam->m_len); 928925Sroot break; 938925Sroot 948925Sroot case PRU_SHUTDOWN: 958925Sroot socantsendmore(so); 968925Sroot unp_usrclosed(unp); 978925Sroot break; 988925Sroot 998925Sroot case PRU_RCVD: 1008925Sroot switch (so->so_type) { 1018925Sroot 1028925Sroot case SOCK_DGRAM: 1038925Sroot panic("uipc 1"); 10410139Ssam /*NOTREACHED*/ 1058925Sroot 10610139Ssam case SOCK_STREAM: 1078925Sroot #define rcv (&so->so_rcv) 1088925Sroot #define snd (&so2->so_snd) 1098925Sroot if (unp->unp_conn == 0) 1108925Sroot break; 1118925Sroot so2 = unp->unp_conn->unp_socket; 1128925Sroot /* 1138925Sroot * Transfer resources back to send port 1148925Sroot * and wakeup any waiting to write. 1158925Sroot */ 1168925Sroot snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt; 1178925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1188925Sroot snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc; 1198925Sroot rcv->sb_hiwat = rcv->sb_cc; 12017543Skarels sowwakeup(so2); 1218925Sroot #undef snd 1228925Sroot #undef rcv 1238925Sroot break; 1248925Sroot 1258925Sroot default: 1268925Sroot panic("uipc 2"); 1278925Sroot } 1288925Sroot break; 1298925Sroot 1308925Sroot case PRU_SEND: 1318925Sroot switch (so->so_type) { 1328925Sroot 1338925Sroot case SOCK_DGRAM: 1349028Sroot if (nam) { 1358925Sroot if (unp->unp_conn) { 1368925Sroot error = EISCONN; 1378925Sroot break; 1388925Sroot } 1399028Sroot error = unp_connect(so, nam); 1408925Sroot if (error) 1418925Sroot break; 1428925Sroot } else { 1438925Sroot if (unp->unp_conn == 0) { 1448925Sroot error = ENOTCONN; 1458925Sroot break; 1468925Sroot } 1478925Sroot } 1488925Sroot so2 = unp->unp_conn->unp_socket; 1499169Ssam /* BEGIN XXX */ 15012760Ssam if (rights) { 15112760Ssam error = unp_internalize(rights); 15212760Ssam if (error) 15312760Ssam break; 15412760Ssam } 15512760Ssam if (sbspace(&so2->so_rcv) > 0) { 15613119Ssam /* 15713119Ssam * There's no record of source socket's 15813119Ssam * name, so send null name for the moment. 15913119Ssam */ 16017543Skarels if (sbappendaddr(&so2->so_rcv, 16117543Skarels &sun_noname, m, rights)) { 16217543Skarels sorwakeup(so2); 16317543Skarels m = 0; 16423524Skarels } else 16523524Skarels error = ENOBUFS; 16612760Ssam } 1679169Ssam /* END XXX */ 1689028Sroot if (nam) 1699169Ssam unp_disconnect(unp); 1708925Sroot break; 1718925Sroot 1728925Sroot case SOCK_STREAM: 1738925Sroot #define rcv (&so2->so_rcv) 1748925Sroot #define snd (&so->so_snd) 17512760Ssam if (rights && rights->m_len) { 17612760Ssam error = EOPNOTSUPP; 17712760Ssam break; 17812760Ssam } 17923524Skarels if (so->so_state & SS_CANTSENDMORE) { 18023524Skarels error = EPIPE; 18123524Skarels break; 18223524Skarels } 1838925Sroot if (unp->unp_conn == 0) 1848925Sroot panic("uipc 3"); 1858925Sroot so2 = unp->unp_conn->unp_socket; 1868925Sroot /* 1878925Sroot * Send to paired receive port, and then 1888925Sroot * give it enough resources to hold what it already has. 1898925Sroot * Wake up readers. 1908925Sroot */ 1918925Sroot sbappend(rcv, m); 1928925Sroot snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax; 1938925Sroot rcv->sb_mbmax = rcv->sb_mbcnt; 1948925Sroot snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat; 1958925Sroot rcv->sb_hiwat = rcv->sb_cc; 19617543Skarels sorwakeup(so2); 19717543Skarels m = 0; 1988925Sroot #undef snd 1998925Sroot #undef rcv 2008925Sroot break; 2018925Sroot 2028925Sroot default: 2038925Sroot panic("uipc 4"); 2048925Sroot } 2058925Sroot break; 2068925Sroot 2078925Sroot case PRU_ABORT: 2088925Sroot unp_drop(unp, ECONNABORTED); 2098925Sroot break; 2108925Sroot 2118925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */ 2128925Sroot case PRU_CONTROL: 21313050Ssam return (EOPNOTSUPP); 2148925Sroot 21516973Skarels /* END UNIMPLEMENTED HOOKS */ 2168925Sroot case PRU_SENSE: 21716973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 21816973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 21916973Skarels so2 = unp->unp_conn->unp_socket; 22016973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 22116973Skarels } 22221110Skarels ((struct stat *) m)->st_dev = NODEV; 22321110Skarels ((struct stat *) m)->st_ino = unp_ino++; 22416973Skarels return (0); 2258925Sroot 2268925Sroot case PRU_RCVOOB: 22716774Sbloom return (EOPNOTSUPP); 2288925Sroot 2298925Sroot case PRU_SENDOOB: 23017543Skarels error = EOPNOTSUPP; 2318925Sroot break; 2328925Sroot 2338925Sroot case PRU_SOCKADDR: 2348925Sroot break; 2358925Sroot 23614121Ssam case PRU_PEERADDR: 23714121Ssam break; 23814121Ssam 2398925Sroot case PRU_SLOWTIMO: 2408925Sroot break; 2418925Sroot 2428925Sroot default: 2438925Sroot panic("piusrreq"); 2448925Sroot } 24512760Ssam release: 24612760Ssam if (m) 24712760Ssam m_freem(m); 24811709Ssam return (error); 2498925Sroot } 2508925Sroot 25116973Skarels /* 25216973Skarels * We assign all buffering for stream sockets to the source, 25316973Skarels * as that is where the flow control is implemented. 25416973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 25516973Skarels * and don't really want to reserve the sendspace. Their recvspace should 25616973Skarels * be large enough for at least one max-size datagram plus address. 25716973Skarels */ 25816973Skarels #define PIPSIZ 4096 25916973Skarels int unpst_sendspace = PIPSIZ; 26016973Skarels int unpst_recvspace = 0; 26116973Skarels int unpdg_sendspace = 2*1024; /* really max datagram size */ 26216973Skarels int unpdg_recvspace = 4*1024; 2638925Sroot 2649169Ssam unp_attach(so) 2658925Sroot struct socket *so; 2668925Sroot { 2679169Ssam register struct mbuf *m; 2688925Sroot register struct unpcb *unp; 2698925Sroot int error; 2708925Sroot 27116973Skarels switch (so->so_type) { 27216973Skarels 27316973Skarels case SOCK_STREAM: 27416973Skarels error = soreserve(so, unpst_sendspace, unpst_recvspace); 27516973Skarels break; 27616973Skarels 27716973Skarels case SOCK_DGRAM: 27816973Skarels error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 27916973Skarels break; 28016973Skarels } 2818925Sroot if (error) 28210139Ssam return (error); 2839637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 28410139Ssam if (m == NULL) 28510139Ssam return (ENOBUFS); 2868925Sroot unp = mtod(m, struct unpcb *); 2878925Sroot so->so_pcb = (caddr_t)unp; 2888925Sroot unp->unp_socket = so; 2898925Sroot return (0); 2908925Sroot } 2918925Sroot 2928925Sroot unp_detach(unp) 2939169Ssam register struct unpcb *unp; 2948925Sroot { 2958925Sroot 2968925Sroot if (unp->unp_inode) { 29717020Skarels unp->unp_inode->i_socket = 0; 2988925Sroot irele(unp->unp_inode); 2998925Sroot unp->unp_inode = 0; 3008925Sroot } 3018925Sroot if (unp->unp_conn) 3028925Sroot unp_disconnect(unp); 3038925Sroot while (unp->unp_refs) 3048925Sroot unp_drop(unp->unp_refs, ECONNRESET); 3058925Sroot soisdisconnected(unp->unp_socket); 3068925Sroot unp->unp_socket->so_pcb = 0; 3079169Ssam m_freem(unp->unp_remaddr); 3089169Ssam (void) m_free(dtom(unp)); 3098925Sroot } 3108925Sroot 3119169Ssam unp_bind(unp, nam) 3128925Sroot struct unpcb *unp; 3139169Ssam struct mbuf *nam; 3148925Sroot { 3159169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3168925Sroot register struct inode *ip; 31716695Smckusick register struct nameidata *ndp = &u.u_nd; 3188925Sroot int error; 3198925Sroot 32016695Smckusick ndp->ni_dirp = soun->sun_path; 321*25232Smckusick if (unp->unp_inode != NULL || nam->m_len == MLEN) 32212760Ssam return (EINVAL); 32312760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 32412760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 32516695Smckusick ndp->ni_nameiop = CREATE | FOLLOW; 32616695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 32716695Smckusick ip = namei(ndp); 3288925Sroot if (ip) { 3298925Sroot iput(ip); 33010139Ssam return (EADDRINUSE); 3318925Sroot } 33211828Ssam if (error = u.u_error) { 33311828Ssam u.u_error = 0; /* XXX */ 33411828Ssam return (error); 33511828Ssam } 33616695Smckusick ip = maknode(IFSOCK | 0777, ndp); 3378925Sroot if (ip == NULL) { 3388925Sroot error = u.u_error; /* XXX */ 3398925Sroot u.u_error = 0; /* XXX */ 3408925Sroot return (error); 3418925Sroot } 3428925Sroot ip->i_socket = unp->unp_socket; 3438925Sroot unp->unp_inode = ip; 3448925Sroot iunlock(ip); /* but keep reference */ 3458925Sroot return (0); 3468925Sroot } 3478925Sroot 3489169Ssam unp_connect(so, nam) 3498925Sroot struct socket *so; 3509169Ssam struct mbuf *nam; 3518925Sroot { 3529169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 3539169Ssam register struct inode *ip; 3548925Sroot int error; 35512760Ssam register struct socket *so2; 35616695Smckusick register struct nameidata *ndp = &u.u_nd; 3578925Sroot 35816695Smckusick ndp->ni_dirp = soun->sun_path; 35912760Ssam if (nam->m_len + (nam->m_off - MMINOFF) == MLEN) 36012760Ssam return (EMSGSIZE); 36112760Ssam *(mtod(nam, caddr_t) + nam->m_len) = 0; 36216695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 36316695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 36416695Smckusick ip = namei(ndp); 3658925Sroot if (ip == 0) { 3668925Sroot error = u.u_error; 3678925Sroot u.u_error = 0; 36810139Ssam return (error); /* XXX */ 3698925Sroot } 37017543Skarels if (access(ip, IWRITE)) { 37117543Skarels error = u.u_error; 37217543Skarels u.u_error = 0; /* XXX */ 37317543Skarels goto bad; 37417543Skarels } 3758925Sroot if ((ip->i_mode&IFMT) != IFSOCK) { 3768925Sroot error = ENOTSOCK; 3778925Sroot goto bad; 3788925Sroot } 3798925Sroot so2 = ip->i_socket; 3808925Sroot if (so2 == 0) { 3818925Sroot error = ECONNREFUSED; 3828925Sroot goto bad; 3838925Sroot } 38413115Ssam if (so->so_type != so2->so_type) { 38513115Ssam error = EPROTOTYPE; 38613115Ssam goto bad; 38713115Ssam } 38813115Ssam if (so->so_proto->pr_flags & PR_CONNREQUIRED && 38913115Ssam ((so2->so_options&SO_ACCEPTCONN) == 0 || 39013115Ssam (so2 = sonewconn(so2)) == 0)) { 39113115Ssam error = ECONNREFUSED; 39213115Ssam goto bad; 39313115Ssam } 39412760Ssam error = unp_connect2(so, nam, so2); 39512760Ssam bad: 39612760Ssam iput(ip); 39712760Ssam return (error); 39812760Ssam } 39912760Ssam 40012760Ssam unp_connect2(so, sonam, so2) 40112760Ssam register struct socket *so; 40212760Ssam struct mbuf *sonam; 40312760Ssam register struct socket *so2; 40412760Ssam { 40512760Ssam register struct unpcb *unp = sotounpcb(so); 40612760Ssam register struct unpcb *unp2; 40712760Ssam 40812760Ssam if (so2->so_type != so->so_type) 40912760Ssam return (EPROTOTYPE); 41014049Ssam unp2 = sotounpcb(so2); 41114049Ssam unp->unp_conn = unp2; 4128925Sroot switch (so->so_type) { 4138925Sroot 4148925Sroot case SOCK_DGRAM: 4158925Sroot unp->unp_nextref = unp2->unp_refs; 4168925Sroot unp2->unp_refs = unp; 41717543Skarels soisconnected(so); 4188925Sroot break; 4198925Sroot 4208925Sroot case SOCK_STREAM: 4219169Ssam unp2->unp_conn = unp; 42212760Ssam if (sonam) 42312760Ssam unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL); 42414049Ssam soisconnected(so2); 42514049Ssam soisconnected(so); 4268925Sroot break; 4278925Sroot 4288925Sroot default: 42912760Ssam panic("unp_connect2"); 4308925Sroot } 4318925Sroot return (0); 4328925Sroot } 4339169Ssam 4349169Ssam unp_disconnect(unp) 4359169Ssam struct unpcb *unp; 4369169Ssam { 4379169Ssam register struct unpcb *unp2 = unp->unp_conn; 4389169Ssam 4399169Ssam if (unp2 == 0) 4409169Ssam return; 4419169Ssam unp->unp_conn = 0; 4429169Ssam switch (unp->unp_socket->so_type) { 4439169Ssam 4449169Ssam case SOCK_DGRAM: 4459169Ssam if (unp2->unp_refs == unp) 4469169Ssam unp2->unp_refs = unp->unp_nextref; 4479169Ssam else { 4489169Ssam unp2 = unp2->unp_refs; 4499169Ssam for (;;) { 4509169Ssam if (unp2 == 0) 4519169Ssam panic("unp_disconnect"); 4529169Ssam if (unp2->unp_nextref == unp) 4539169Ssam break; 4549169Ssam unp2 = unp2->unp_nextref; 4559169Ssam } 4569169Ssam unp2->unp_nextref = unp->unp_nextref; 4579169Ssam } 4589169Ssam unp->unp_nextref = 0; 45921768Skarels unp->unp_socket->so_state &= ~SS_ISCONNECTED; 4609169Ssam break; 4619169Ssam 4629169Ssam case SOCK_STREAM: 46314049Ssam soisdisconnected(unp->unp_socket); 4649169Ssam unp2->unp_conn = 0; 4659169Ssam soisdisconnected(unp2->unp_socket); 4669169Ssam break; 4679169Ssam } 4689169Ssam } 4699169Ssam 47012760Ssam #ifdef notdef 4719169Ssam unp_abort(unp) 4729169Ssam struct unpcb *unp; 4739169Ssam { 4749169Ssam 4759169Ssam unp_detach(unp); 4769169Ssam } 47712760Ssam #endif 4789169Ssam 4799169Ssam /*ARGSUSED*/ 4809169Ssam unp_usrclosed(unp) 4819169Ssam struct unpcb *unp; 4829169Ssam { 4839169Ssam 4849169Ssam } 4859169Ssam 4869169Ssam unp_drop(unp, errno) 4879169Ssam struct unpcb *unp; 4889169Ssam int errno; 4899169Ssam { 49016054Skarels struct socket *so = unp->unp_socket; 4919169Ssam 49216054Skarels so->so_error = errno; 4939169Ssam unp_disconnect(unp); 49416054Skarels if (so->so_head) { 49516054Skarels so->so_pcb = (caddr_t) 0; 49616431Skarels m_freem(unp->unp_remaddr); 49716054Skarels (void) m_free(dtom(unp)); 49816054Skarels sofree(so); 49916054Skarels } 5009169Ssam } 5019169Ssam 50212760Ssam #ifdef notdef 5039169Ssam unp_drain() 5049169Ssam { 5059169Ssam 5069169Ssam } 50712760Ssam #endif 50812760Ssam 50912760Ssam unp_externalize(rights) 51012760Ssam struct mbuf *rights; 51112760Ssam { 51212760Ssam int newfds = rights->m_len / sizeof (int); 51312760Ssam register int i; 51412760Ssam register struct file **rp = mtod(rights, struct file **); 51512760Ssam register struct file *fp; 51612760Ssam int f; 51712760Ssam 51812760Ssam if (newfds > ufavail()) { 51912760Ssam for (i = 0; i < newfds; i++) { 52012760Ssam fp = *rp; 52112760Ssam unp_discard(fp); 52212760Ssam *rp++ = 0; 52312760Ssam } 52412760Ssam return (EMSGSIZE); 52512760Ssam } 52612760Ssam for (i = 0; i < newfds; i++) { 52712760Ssam f = ufalloc(0); 52812760Ssam if (f < 0) 52912760Ssam panic("unp_externalize"); 53012760Ssam fp = *rp; 53112760Ssam u.u_ofile[f] = fp; 53212760Ssam fp->f_msgcount--; 53314927Smckusick *(int *)rp++ = f; 53412760Ssam } 53512760Ssam return (0); 53612760Ssam } 53712760Ssam 53812760Ssam unp_internalize(rights) 53912760Ssam struct mbuf *rights; 54012760Ssam { 54112760Ssam register struct file **rp; 54212760Ssam int oldfds = rights->m_len / sizeof (int); 54312760Ssam register int i; 54412760Ssam register struct file *fp; 54512760Ssam 54612760Ssam rp = mtod(rights, struct file **); 54713084Ssam for (i = 0; i < oldfds; i++) 54812760Ssam if (getf(*(int *)rp++) == 0) 54912760Ssam return (EBADF); 55012760Ssam rp = mtod(rights, struct file **); 55113084Ssam for (i = 0; i < oldfds; i++) { 55212760Ssam fp = getf(*(int *)rp); 55312760Ssam *rp++ = fp; 55412760Ssam fp->f_count++; 55512760Ssam fp->f_msgcount++; 55612760Ssam } 55712760Ssam return (0); 55812760Ssam } 55912760Ssam 56012760Ssam int unp_defer, unp_gcing; 56112760Ssam int unp_mark(); 56216995Skarels extern struct domain unixdomain; 56312760Ssam 56412760Ssam unp_gc() 56512760Ssam { 56612760Ssam register struct file *fp; 56712760Ssam register struct socket *so; 56812760Ssam 56912760Ssam if (unp_gcing) 57012760Ssam return; 57112760Ssam unp_gcing = 1; 57212760Ssam restart: 57312760Ssam unp_defer = 0; 57412760Ssam for (fp = file; fp < fileNFILE; fp++) 57512760Ssam fp->f_flag &= ~(FMARK|FDEFER); 57612760Ssam do { 57712760Ssam for (fp = file; fp < fileNFILE; fp++) { 57812760Ssam if (fp->f_count == 0) 57912760Ssam continue; 58012760Ssam if (fp->f_flag & FDEFER) { 58112760Ssam fp->f_flag &= ~FDEFER; 58212760Ssam unp_defer--; 58312760Ssam } else { 58412760Ssam if (fp->f_flag & FMARK) 58512760Ssam continue; 58612760Ssam if (fp->f_count == fp->f_msgcount) 58712760Ssam continue; 58812760Ssam fp->f_flag |= FMARK; 58912760Ssam } 59012760Ssam if (fp->f_type != DTYPE_SOCKET) 59112760Ssam continue; 59212760Ssam so = (struct socket *)fp->f_data; 59316995Skarels if (so->so_proto->pr_domain != &unixdomain || 59421768Skarels (so->so_proto->pr_flags&PR_RIGHTS) == 0) 59512760Ssam continue; 59612760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 59712760Ssam sbwait(&so->so_rcv); 59812760Ssam goto restart; 59912760Ssam } 60012760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 60112760Ssam } 60212760Ssam } while (unp_defer); 60312760Ssam for (fp = file; fp < fileNFILE; fp++) { 60412760Ssam if (fp->f_count == 0) 60512760Ssam continue; 60612760Ssam if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) { 60712760Ssam if (fp->f_type != DTYPE_SOCKET) 60812760Ssam panic("unp_gc"); 60912760Ssam (void) soshutdown((struct socket *)fp->f_data, 0); 61012760Ssam } 61112760Ssam } 61212760Ssam unp_gcing = 0; 61312760Ssam } 61412760Ssam 61516995Skarels unp_dispose(m) 61616995Skarels struct mbuf *m; 61716995Skarels { 61816995Skarels int unp_discard(); 61916995Skarels 62017020Skarels if (m) 62117020Skarels unp_scan(m, unp_discard); 62216995Skarels } 62316995Skarels 62416995Skarels unp_scan(m0, op) 62516995Skarels register struct mbuf *m0; 62612760Ssam int (*op)(); 62712760Ssam { 62816995Skarels register struct mbuf *m; 62912760Ssam register struct file **rp; 63012760Ssam register int i; 63117020Skarels int qfds; 63212760Ssam 63316995Skarels while (m0) { 63416995Skarels for (m = m0; m; m = m->m_next) 63516995Skarels if (m->m_type == MT_RIGHTS && m->m_len) { 63616995Skarels qfds = m->m_len / sizeof (struct file *); 63716995Skarels rp = mtod(m, struct file **); 63816995Skarels for (i = 0; i < qfds; i++) 63916995Skarels (*op)(*rp++); 64016995Skarels break; /* XXX, but saves time */ 64116995Skarels } 64217020Skarels m0 = m0->m_act; 64312760Ssam } 64412760Ssam } 64512760Ssam 64612760Ssam unp_mark(fp) 64712760Ssam struct file *fp; 64812760Ssam { 64912760Ssam 65012760Ssam if (fp->f_flag & FMARK) 65112760Ssam return; 65212760Ssam unp_defer++; 65312760Ssam fp->f_flag |= (FMARK|FDEFER); 65412760Ssam } 65512760Ssam 65612760Ssam unp_discard(fp) 65712760Ssam struct file *fp; 65812760Ssam { 65912760Ssam 66012760Ssam fp->f_msgcount--; 66113084Ssam closef(fp); 66212760Ssam } 663