uipc_usrreq.c revision 110234
1/* 2 * Copyright (c) 1982, 1986, 1989, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 34 * $FreeBSD: head/sys/kern/uipc_usrreq.c 110234 2003-02-02 13:30:00Z alfred $ 35 */ 36 37#include "opt_mac.h" 38 39#include <sys/param.h> 40#include <sys/domain.h> 41#include <sys/fcntl.h> 42#include <sys/malloc.h> /* XXX must be before <sys/file.h> */ 43#include <sys/file.h> 44#include <sys/filedesc.h> 45#include <sys/jail.h> 46#include <sys/kernel.h> 47#include <sys/lock.h> 48#include <sys/mac.h> 49#include <sys/mbuf.h> 50#include <sys/mutex.h> 51#include <sys/namei.h> 52#include <sys/proc.h> 53#include <sys/protosw.h> 54#include <sys/resourcevar.h> 55#include <sys/socket.h> 56#include <sys/socketvar.h> 57#include <sys/signalvar.h> 58#include <sys/stat.h> 59#include <sys/sx.h> 60#include <sys/sysctl.h> 61#include <sys/systm.h> 62#include <sys/un.h> 63#include <sys/unpcb.h> 64#include <sys/vnode.h> 65 66#include <vm/uma.h> 67 68static uma_zone_t unp_zone; 69static unp_gen_t unp_gencnt; 70static u_int unp_count; 71 72static struct unp_head unp_shead, unp_dhead; 73 74/* 75 * Unix communications domain. 76 * 77 * TODO: 78 * SEQPACKET, RDM 79 * rethink name space problems 80 * need a proper out-of-band 81 * lock pushdown 82 */ 83static struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 84static ino_t unp_ino; /* prototype for fake inode numbers */ 85 86static int unp_attach(struct socket *); 87static void unp_detach(struct unpcb *); 88static int unp_bind(struct unpcb *,struct sockaddr *, struct thread *); 89static int unp_connect(struct socket *,struct sockaddr *, struct thread *); 90static void unp_disconnect(struct unpcb *); 91static void unp_shutdown(struct unpcb *); 92static void unp_drop(struct unpcb *, int); 93static void unp_gc(void); 94static void unp_scan(struct mbuf *, void (*)(struct file *)); 95static void unp_mark(struct file *); 96static void unp_discard(struct file *); 97static void unp_freerights(struct file **, int); 98static int unp_internalize(struct mbuf **, struct thread *); 99static int unp_listen(struct unpcb *, struct thread *); 100 101static int 102uipc_abort(struct socket *so) 103{ 104 struct unpcb *unp = sotounpcb(so); 105 106 if (unp == 0) 107 return EINVAL; 108 unp_drop(unp, ECONNABORTED); 109 unp_detach(unp); 110 sotryfree(so); 111 return 0; 112} 113 114static int 115uipc_accept(struct socket *so, struct sockaddr **nam) 116{ 117 struct unpcb *unp = sotounpcb(so); 118 119 if (unp == 0) 120 return EINVAL; 121 122 /* 123 * Pass back name of connected socket, 124 * if it was bound and we are still connected 125 * (our peer may have closed already!). 126 */ 127 if (unp->unp_conn && unp->unp_conn->unp_addr) { 128 *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr, 129 1); 130 } else { 131 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); 132 } 133 return 0; 134} 135 136static int 137uipc_attach(struct socket *so, int proto, struct thread *td) 138{ 139 struct unpcb *unp = sotounpcb(so); 140 141 if (unp != 0) 142 return EISCONN; 143 return unp_attach(so); 144} 145 146static int 147uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 148{ 149 struct unpcb *unp = sotounpcb(so); 150 151 if (unp == 0) 152 return EINVAL; 153 154 return unp_bind(unp, nam, td); 155} 156 157static int 158uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 159{ 160 struct unpcb *unp = sotounpcb(so); 161 162 if (unp == 0) 163 return EINVAL; 164 return unp_connect(so, nam, curthread); 165} 166 167static int 168uipc_connect2(struct socket *so1, struct socket *so2) 169{ 170 struct unpcb *unp = sotounpcb(so1); 171 172 if (unp == 0) 173 return EINVAL; 174 175 return unp_connect2(so1, so2); 176} 177 178/* control is EOPNOTSUPP */ 179 180static int 181uipc_detach(struct socket *so) 182{ 183 struct unpcb *unp = sotounpcb(so); 184 185 if (unp == 0) 186 return EINVAL; 187 188 unp_detach(unp); 189 return 0; 190} 191 192static int 193uipc_disconnect(struct socket *so) 194{ 195 struct unpcb *unp = sotounpcb(so); 196 197 if (unp == 0) 198 return EINVAL; 199 unp_disconnect(unp); 200 return 0; 201} 202 203static int 204uipc_listen(struct socket *so, struct thread *td) 205{ 206 struct unpcb *unp = sotounpcb(so); 207 208 if (unp == 0 || unp->unp_vnode == 0) 209 return EINVAL; 210 return unp_listen(unp, td); 211} 212 213static int 214uipc_peeraddr(struct socket *so, struct sockaddr **nam) 215{ 216 struct unpcb *unp = sotounpcb(so); 217 218 if (unp == 0) 219 return EINVAL; 220 if (unp->unp_conn && unp->unp_conn->unp_addr) 221 *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr, 222 1); 223 else { 224 /* 225 * XXX: It seems that this test always fails even when 226 * connection is established. So, this else clause is 227 * added as workaround to return PF_LOCAL sockaddr. 228 */ 229 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); 230 } 231 return 0; 232} 233 234static int 235uipc_rcvd(struct socket *so, int flags) 236{ 237 struct unpcb *unp = sotounpcb(so); 238 struct socket *so2; 239 u_long newhiwat; 240 241 if (unp == 0) 242 return EINVAL; 243 switch (so->so_type) { 244 case SOCK_DGRAM: 245 panic("uipc_rcvd DGRAM?"); 246 /*NOTREACHED*/ 247 248 case SOCK_STREAM: 249 if (unp->unp_conn == 0) 250 break; 251 so2 = unp->unp_conn->unp_socket; 252 /* 253 * Adjust backpressure on sender 254 * and wakeup any waiting to write. 255 */ 256 so2->so_snd.sb_mbmax += unp->unp_mbcnt - so->so_rcv.sb_mbcnt; 257 unp->unp_mbcnt = so->so_rcv.sb_mbcnt; 258 newhiwat = so2->so_snd.sb_hiwat + unp->unp_cc - 259 so->so_rcv.sb_cc; 260 (void)chgsbsize(so2->so_cred->cr_uidinfo, &so2->so_snd.sb_hiwat, 261 newhiwat, RLIM_INFINITY); 262 unp->unp_cc = so->so_rcv.sb_cc; 263 sowwakeup(so2); 264 break; 265 266 default: 267 panic("uipc_rcvd unknown socktype"); 268 } 269 return 0; 270} 271 272/* pru_rcvoob is EOPNOTSUPP */ 273 274static int 275uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 276 struct mbuf *control, struct thread *td) 277{ 278 int error = 0; 279 struct unpcb *unp = sotounpcb(so); 280 struct socket *so2; 281 u_long newhiwat; 282 283 if (unp == 0) { 284 error = EINVAL; 285 goto release; 286 } 287 if (flags & PRUS_OOB) { 288 error = EOPNOTSUPP; 289 goto release; 290 } 291 292 if (control && (error = unp_internalize(&control, td))) 293 goto release; 294 295 switch (so->so_type) { 296 case SOCK_DGRAM: 297 { 298 struct sockaddr *from; 299 300 if (nam) { 301 if (unp->unp_conn) { 302 error = EISCONN; 303 break; 304 } 305 error = unp_connect(so, nam, td); 306 if (error) 307 break; 308 } else { 309 if (unp->unp_conn == 0) { 310 error = ENOTCONN; 311 break; 312 } 313 } 314 so2 = unp->unp_conn->unp_socket; 315 if (unp->unp_addr) 316 from = (struct sockaddr *)unp->unp_addr; 317 else 318 from = &sun_noname; 319 if (sbappendaddr(&so2->so_rcv, from, m, control)) { 320 sorwakeup(so2); 321 m = 0; 322 control = 0; 323 } else 324 error = ENOBUFS; 325 if (nam) 326 unp_disconnect(unp); 327 break; 328 } 329 330 case SOCK_STREAM: 331 /* Connect if not connected yet. */ 332 /* 333 * Note: A better implementation would complain 334 * if not equal to the peer's address. 335 */ 336 if ((so->so_state & SS_ISCONNECTED) == 0) { 337 if (nam) { 338 error = unp_connect(so, nam, td); 339 if (error) 340 break; /* XXX */ 341 } else { 342 error = ENOTCONN; 343 break; 344 } 345 } 346 347 if (so->so_state & SS_CANTSENDMORE) { 348 error = EPIPE; 349 break; 350 } 351 if (unp->unp_conn == 0) 352 panic("uipc_send connected but no connection?"); 353 so2 = unp->unp_conn->unp_socket; 354 /* 355 * Send to paired receive port, and then reduce 356 * send buffer hiwater marks to maintain backpressure. 357 * Wake up readers. 358 */ 359 if (control) { 360 if (sbappendcontrol(&so2->so_rcv, m, control)) 361 control = 0; 362 } else 363 sbappend(&so2->so_rcv, m); 364 so->so_snd.sb_mbmax -= 365 so2->so_rcv.sb_mbcnt - unp->unp_conn->unp_mbcnt; 366 unp->unp_conn->unp_mbcnt = so2->so_rcv.sb_mbcnt; 367 newhiwat = so->so_snd.sb_hiwat - 368 (so2->so_rcv.sb_cc - unp->unp_conn->unp_cc); 369 (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, 370 newhiwat, RLIM_INFINITY); 371 unp->unp_conn->unp_cc = so2->so_rcv.sb_cc; 372 sorwakeup(so2); 373 m = 0; 374 break; 375 376 default: 377 panic("uipc_send unknown socktype"); 378 } 379 380 /* 381 * SEND_EOF is equivalent to a SEND followed by 382 * a SHUTDOWN. 383 */ 384 if (flags & PRUS_EOF) { 385 socantsendmore(so); 386 unp_shutdown(unp); 387 } 388 389 if (control && error != 0) 390 unp_dispose(control); 391 392release: 393 if (control) 394 m_freem(control); 395 if (m) 396 m_freem(m); 397 return error; 398} 399 400static int 401uipc_sense(struct socket *so, struct stat *sb) 402{ 403 struct unpcb *unp = sotounpcb(so); 404 struct socket *so2; 405 406 if (unp == 0) 407 return EINVAL; 408 sb->st_blksize = so->so_snd.sb_hiwat; 409 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 410 so2 = unp->unp_conn->unp_socket; 411 sb->st_blksize += so2->so_rcv.sb_cc; 412 } 413 sb->st_dev = NOUDEV; 414 if (unp->unp_ino == 0) 415 unp->unp_ino = (++unp_ino == 0) ? ++unp_ino : unp_ino; 416 sb->st_ino = unp->unp_ino; 417 return (0); 418} 419 420static int 421uipc_shutdown(struct socket *so) 422{ 423 struct unpcb *unp = sotounpcb(so); 424 425 if (unp == 0) 426 return EINVAL; 427 socantsendmore(so); 428 unp_shutdown(unp); 429 return 0; 430} 431 432static int 433uipc_sockaddr(struct socket *so, struct sockaddr **nam) 434{ 435 struct unpcb *unp = sotounpcb(so); 436 437 if (unp == 0) 438 return EINVAL; 439 if (unp->unp_addr) 440 *nam = dup_sockaddr((struct sockaddr *)unp->unp_addr, 1); 441 else 442 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); 443 return 0; 444} 445 446struct pr_usrreqs uipc_usrreqs = { 447 uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect, 448 uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect, 449 uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp, 450 uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr, 451 sosend, soreceive, sopoll 452}; 453 454int 455uipc_ctloutput(so, sopt) 456 struct socket *so; 457 struct sockopt *sopt; 458{ 459 struct unpcb *unp = sotounpcb(so); 460 int error; 461 462 switch (sopt->sopt_dir) { 463 case SOPT_GET: 464 switch (sopt->sopt_name) { 465 case LOCAL_PEERCRED: 466 if (unp->unp_flags & UNP_HAVEPC) 467 error = sooptcopyout(sopt, &unp->unp_peercred, 468 sizeof(unp->unp_peercred)); 469 else { 470 if (so->so_type == SOCK_STREAM) 471 error = ENOTCONN; 472 else 473 error = EINVAL; 474 } 475 break; 476 default: 477 error = EOPNOTSUPP; 478 break; 479 } 480 break; 481 case SOPT_SET: 482 default: 483 error = EOPNOTSUPP; 484 break; 485 } 486 return (error); 487} 488 489/* 490 * Both send and receive buffers are allocated PIPSIZ bytes of buffering 491 * for stream sockets, although the total for sender and receiver is 492 * actually only PIPSIZ. 493 * Datagram sockets really use the sendspace as the maximum datagram size, 494 * and don't really want to reserve the sendspace. Their recvspace should 495 * be large enough for at least one max-size datagram plus address. 496 */ 497#ifndef PIPSIZ 498#define PIPSIZ 8192 499#endif 500static u_long unpst_sendspace = PIPSIZ; 501static u_long unpst_recvspace = PIPSIZ; 502static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 503static u_long unpdg_recvspace = 4*1024; 504 505static int unp_rights; /* file descriptors in flight */ 506 507SYSCTL_DECL(_net_local_stream); 508SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, 509 &unpst_sendspace, 0, ""); 510SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, 511 &unpst_recvspace, 0, ""); 512SYSCTL_DECL(_net_local_dgram); 513SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, 514 &unpdg_sendspace, 0, ""); 515SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, 516 &unpdg_recvspace, 0, ""); 517SYSCTL_DECL(_net_local); 518SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, ""); 519 520static int 521unp_attach(so) 522 struct socket *so; 523{ 524 register struct unpcb *unp; 525 int error; 526 527 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 528 switch (so->so_type) { 529 530 case SOCK_STREAM: 531 error = soreserve(so, unpst_sendspace, unpst_recvspace); 532 break; 533 534 case SOCK_DGRAM: 535 error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 536 break; 537 538 default: 539 panic("unp_attach"); 540 } 541 if (error) 542 return (error); 543 } 544 unp = uma_zalloc(unp_zone, 0); 545 if (unp == NULL) 546 return (ENOBUFS); 547 bzero(unp, sizeof *unp); 548 unp->unp_gencnt = ++unp_gencnt; 549 unp_count++; 550 LIST_INIT(&unp->unp_refs); 551 unp->unp_socket = so; 552 unp->unp_rvnode = curthread->td_proc->p_fd->fd_rdir; 553 LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead 554 : &unp_shead, unp, unp_link); 555 so->so_pcb = unp; 556 return (0); 557} 558 559static void 560unp_detach(unp) 561 register struct unpcb *unp; 562{ 563 LIST_REMOVE(unp, unp_link); 564 unp->unp_gencnt = ++unp_gencnt; 565 --unp_count; 566 if (unp->unp_vnode) { 567 unp->unp_vnode->v_socket = 0; 568 vrele(unp->unp_vnode); 569 unp->unp_vnode = 0; 570 } 571 if (unp->unp_conn) 572 unp_disconnect(unp); 573 while (!LIST_EMPTY(&unp->unp_refs)) 574 unp_drop(LIST_FIRST(&unp->unp_refs), ECONNRESET); 575 soisdisconnected(unp->unp_socket); 576 unp->unp_socket->so_pcb = 0; 577 if (unp_rights) { 578 /* 579 * Normally the receive buffer is flushed later, 580 * in sofree, but if our receive buffer holds references 581 * to descriptors that are now garbage, we will dispose 582 * of those descriptor references after the garbage collector 583 * gets them (resulting in a "panic: closef: count < 0"). 584 */ 585 sorflush(unp->unp_socket); 586 unp_gc(); 587 } 588 if (unp->unp_addr) 589 FREE(unp->unp_addr, M_SONAME); 590 uma_zfree(unp_zone, unp); 591} 592 593static int 594unp_bind(unp, nam, td) 595 struct unpcb *unp; 596 struct sockaddr *nam; 597 struct thread *td; 598{ 599 struct sockaddr_un *soun = (struct sockaddr_un *)nam; 600 struct vnode *vp; 601 struct mount *mp; 602 struct vattr vattr; 603 int error, namelen; 604 struct nameidata nd; 605 char *buf; 606 607 if (unp->unp_vnode != NULL) 608 return (EINVAL); 609 610 namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); 611 if (namelen <= 0) 612 return EINVAL; 613 614 buf = malloc(namelen + 1, M_TEMP, 0); 615 strlcpy(buf, soun->sun_path, namelen + 1); 616 617restart: 618 NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME, UIO_SYSSPACE, 619 buf, td); 620/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 621 error = namei(&nd); 622 if (error) { 623 free(buf, M_TEMP); 624 return (error); 625 } 626 vp = nd.ni_vp; 627 if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 628 NDFREE(&nd, NDF_ONLY_PNBUF); 629 if (nd.ni_dvp == vp) 630 vrele(nd.ni_dvp); 631 else 632 vput(nd.ni_dvp); 633 if (vp != NULL) { 634 vrele(vp); 635 free(buf, M_TEMP); 636 return (EADDRINUSE); 637 } 638 error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH); 639 if (error) { 640 free(buf, M_TEMP); 641 return (error); 642 } 643 goto restart; 644 } 645 VATTR_NULL(&vattr); 646 vattr.va_type = VSOCK; 647 vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask); 648#ifdef MAC 649 error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, 650 &vattr); 651#endif 652 if (error == 0) { 653 VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 654 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 655 } 656 NDFREE(&nd, NDF_ONLY_PNBUF); 657 vput(nd.ni_dvp); 658 if (error) { 659 free(buf, M_TEMP); 660 return (error); 661 } 662 vp = nd.ni_vp; 663 vp->v_socket = unp->unp_socket; 664 unp->unp_vnode = vp; 665 unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1); 666 VOP_UNLOCK(vp, 0, td); 667 vn_finished_write(mp); 668 free(buf, M_TEMP); 669 return (0); 670} 671 672static int 673unp_connect(so, nam, td) 674 struct socket *so; 675 struct sockaddr *nam; 676 struct thread *td; 677{ 678 register struct sockaddr_un *soun = (struct sockaddr_un *)nam; 679 register struct vnode *vp; 680 register struct socket *so2, *so3; 681 struct unpcb *unp, *unp2, *unp3; 682 int error, len; 683 struct nameidata nd; 684 char buf[SOCK_MAXADDRLEN]; 685 686 len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); 687 if (len <= 0) 688 return EINVAL; 689 strlcpy(buf, soun->sun_path, len + 1); 690 691 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, td); 692 error = namei(&nd); 693 if (error) 694 return (error); 695 vp = nd.ni_vp; 696 NDFREE(&nd, NDF_ONLY_PNBUF); 697 if (vp->v_type != VSOCK) { 698 error = ENOTSOCK; 699 goto bad; 700 } 701 error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td); 702 if (error) 703 goto bad; 704 so2 = vp->v_socket; 705 if (so2 == 0) { 706 error = ECONNREFUSED; 707 goto bad; 708 } 709 if (so->so_type != so2->so_type) { 710 error = EPROTOTYPE; 711 goto bad; 712 } 713 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 714 if ((so2->so_options & SO_ACCEPTCONN) == 0 || 715 (so3 = sonewconn(so2, 0)) == 0) { 716 error = ECONNREFUSED; 717 goto bad; 718 } 719 unp = sotounpcb(so); 720 unp2 = sotounpcb(so2); 721 unp3 = sotounpcb(so3); 722 if (unp2->unp_addr) 723 unp3->unp_addr = (struct sockaddr_un *) 724 dup_sockaddr((struct sockaddr *) 725 unp2->unp_addr, 1); 726 727 /* 728 * unp_peercred management: 729 * 730 * The connecter's (client's) credentials are copied 731 * from its process structure at the time of connect() 732 * (which is now). 733 */ 734 cru2x(td->td_ucred, &unp3->unp_peercred); 735 unp3->unp_flags |= UNP_HAVEPC; 736 /* 737 * The receiver's (server's) credentials are copied 738 * from the unp_peercred member of socket on which the 739 * former called listen(); unp_listen() cached that 740 * process's credentials at that time so we can use 741 * them now. 742 */ 743 KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED, 744 ("unp_connect: listener without cached peercred")); 745 memcpy(&unp->unp_peercred, &unp2->unp_peercred, 746 sizeof(unp->unp_peercred)); 747 unp->unp_flags |= UNP_HAVEPC; 748#ifdef MAC 749 mac_set_socket_peer_from_socket(so, so3); 750 mac_set_socket_peer_from_socket(so3, so); 751#endif 752 753 so2 = so3; 754 } 755 error = unp_connect2(so, so2); 756bad: 757 vput(vp); 758 return (error); 759} 760 761int 762unp_connect2(so, so2) 763 register struct socket *so; 764 register struct socket *so2; 765{ 766 register struct unpcb *unp = sotounpcb(so); 767 register struct unpcb *unp2; 768 769 if (so2->so_type != so->so_type) 770 return (EPROTOTYPE); 771 unp2 = sotounpcb(so2); 772 unp->unp_conn = unp2; 773 switch (so->so_type) { 774 775 case SOCK_DGRAM: 776 LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); 777 soisconnected(so); 778 break; 779 780 case SOCK_STREAM: 781 unp2->unp_conn = unp; 782 soisconnected(so); 783 soisconnected(so2); 784 break; 785 786 default: 787 panic("unp_connect2"); 788 } 789 return (0); 790} 791 792static void 793unp_disconnect(unp) 794 struct unpcb *unp; 795{ 796 register struct unpcb *unp2 = unp->unp_conn; 797 798 if (unp2 == 0) 799 return; 800 unp->unp_conn = 0; 801 switch (unp->unp_socket->so_type) { 802 803 case SOCK_DGRAM: 804 LIST_REMOVE(unp, unp_reflink); 805 unp->unp_socket->so_state &= ~SS_ISCONNECTED; 806 break; 807 808 case SOCK_STREAM: 809 soisdisconnected(unp->unp_socket); 810 unp2->unp_conn = 0; 811 soisdisconnected(unp2->unp_socket); 812 break; 813 } 814} 815 816#ifdef notdef 817void 818unp_abort(unp) 819 struct unpcb *unp; 820{ 821 822 unp_detach(unp); 823} 824#endif 825 826static int 827unp_pcblist(SYSCTL_HANDLER_ARGS) 828{ 829 int error, i, n; 830 struct unpcb *unp, **unp_list; 831 unp_gen_t gencnt; 832 struct xunpgen *xug; 833 struct unp_head *head; 834 struct xunpcb *xu; 835 836 head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead); 837 838 /* 839 * The process of preparing the PCB list is too time-consuming and 840 * resource-intensive to repeat twice on every request. 841 */ 842 if (req->oldptr == 0) { 843 n = unp_count; 844 req->oldidx = 2 * (sizeof *xug) 845 + (n + n/8) * sizeof(struct xunpcb); 846 return 0; 847 } 848 849 if (req->newptr != 0) 850 return EPERM; 851 852 /* 853 * OK, now we're committed to doing something. 854 */ 855 xug = malloc(sizeof(*xug), M_TEMP, 0); 856 gencnt = unp_gencnt; 857 n = unp_count; 858 859 xug->xug_len = sizeof *xug; 860 xug->xug_count = n; 861 xug->xug_gen = gencnt; 862 xug->xug_sogen = so_gencnt; 863 error = SYSCTL_OUT(req, xug, sizeof *xug); 864 if (error) { 865 free(xug, M_TEMP); 866 return error; 867 } 868 869 unp_list = malloc(n * sizeof *unp_list, M_TEMP, 0); 870 871 for (unp = LIST_FIRST(head), i = 0; unp && i < n; 872 unp = LIST_NEXT(unp, unp_link)) { 873 if (unp->unp_gencnt <= gencnt) { 874 if (cr_cansee(req->td->td_ucred, 875 unp->unp_socket->so_cred)) 876 continue; 877 unp_list[i++] = unp; 878 } 879 } 880 n = i; /* in case we lost some during malloc */ 881 882 error = 0; 883 xu = malloc(sizeof(*xu), M_TEMP, 0); 884 for (i = 0; i < n; i++) { 885 unp = unp_list[i]; 886 if (unp->unp_gencnt <= gencnt) { 887 xu->xu_len = sizeof *xu; 888 xu->xu_unpp = unp; 889 /* 890 * XXX - need more locking here to protect against 891 * connect/disconnect races for SMP. 892 */ 893 if (unp->unp_addr) 894 bcopy(unp->unp_addr, &xu->xu_addr, 895 unp->unp_addr->sun_len); 896 if (unp->unp_conn && unp->unp_conn->unp_addr) 897 bcopy(unp->unp_conn->unp_addr, 898 &xu->xu_caddr, 899 unp->unp_conn->unp_addr->sun_len); 900 bcopy(unp, &xu->xu_unp, sizeof *unp); 901 sotoxsocket(unp->unp_socket, &xu->xu_socket); 902 error = SYSCTL_OUT(req, xu, sizeof *xu); 903 } 904 } 905 free(xu, M_TEMP); 906 if (!error) { 907 /* 908 * Give the user an updated idea of our state. 909 * If the generation differs from what we told 910 * her before, she knows that something happened 911 * while we were processing this request, and it 912 * might be necessary to retry. 913 */ 914 xug->xug_gen = unp_gencnt; 915 xug->xug_sogen = so_gencnt; 916 xug->xug_count = unp_count; 917 error = SYSCTL_OUT(req, xug, sizeof *xug); 918 } 919 free(unp_list, M_TEMP); 920 free(xug, M_TEMP); 921 return error; 922} 923 924SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD, 925 (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", 926 "List of active local datagram sockets"); 927SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD, 928 (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", 929 "List of active local stream sockets"); 930 931static void 932unp_shutdown(unp) 933 struct unpcb *unp; 934{ 935 struct socket *so; 936 937 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 938 (so = unp->unp_conn->unp_socket)) 939 socantrcvmore(so); 940} 941 942static void 943unp_drop(unp, errno) 944 struct unpcb *unp; 945 int errno; 946{ 947 struct socket *so = unp->unp_socket; 948 949 so->so_error = errno; 950 unp_disconnect(unp); 951} 952 953#ifdef notdef 954void 955unp_drain() 956{ 957 958} 959#endif 960 961static void 962unp_freerights(rp, fdcount) 963 struct file **rp; 964 int fdcount; 965{ 966 int i; 967 struct file *fp; 968 969 for (i = 0; i < fdcount; i++) { 970 fp = *rp; 971 /* 972 * zero the pointer before calling 973 * unp_discard since it may end up 974 * in unp_gc().. 975 */ 976 *rp++ = 0; 977 unp_discard(fp); 978 } 979} 980 981int 982unp_externalize(control, controlp) 983 struct mbuf *control, **controlp; 984{ 985 struct thread *td = curthread; /* XXX */ 986 struct cmsghdr *cm = mtod(control, struct cmsghdr *); 987 int i; 988 int *fdp; 989 struct file **rp; 990 struct file *fp; 991 void *data; 992 socklen_t clen = control->m_len, datalen; 993 int error, newfds; 994 int f; 995 u_int newlen; 996 997 error = 0; 998 if (controlp != NULL) /* controlp == NULL => free control messages */ 999 *controlp = NULL; 1000 1001 while (cm != NULL) { 1002 if (sizeof(*cm) > clen || cm->cmsg_len > clen) { 1003 error = EINVAL; 1004 break; 1005 } 1006 1007 data = CMSG_DATA(cm); 1008 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 1009 1010 if (cm->cmsg_level == SOL_SOCKET 1011 && cm->cmsg_type == SCM_RIGHTS) { 1012 newfds = datalen / sizeof(struct file *); 1013 rp = data; 1014 1015 /* If we're not outputting the discriptors free them. */ 1016 if (error || controlp == NULL) { 1017 unp_freerights(rp, newfds); 1018 goto next; 1019 } 1020 FILEDESC_LOCK(td->td_proc->p_fd); 1021 /* if the new FD's will not fit free them. */ 1022 if (!fdavail(td, newfds)) { 1023 FILEDESC_UNLOCK(td->td_proc->p_fd); 1024 error = EMSGSIZE; 1025 unp_freerights(rp, newfds); 1026 goto next; 1027 } 1028 /* 1029 * now change each pointer to an fd in the global 1030 * table to an integer that is the index to the 1031 * local fd table entry that we set up to point 1032 * to the global one we are transferring. 1033 */ 1034 newlen = newfds * sizeof(int); 1035 *controlp = sbcreatecontrol(NULL, newlen, 1036 SCM_RIGHTS, SOL_SOCKET); 1037 if (*controlp == NULL) { 1038 FILEDESC_UNLOCK(td->td_proc->p_fd); 1039 error = E2BIG; 1040 unp_freerights(rp, newfds); 1041 goto next; 1042 } 1043 1044 fdp = (int *) 1045 CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 1046 for (i = 0; i < newfds; i++) { 1047 if (fdalloc(td, 0, &f)) 1048 panic("unp_externalize fdalloc failed"); 1049 fp = *rp++; 1050 td->td_proc->p_fd->fd_ofiles[f] = fp; 1051 FILE_LOCK(fp); 1052 fp->f_msgcount--; 1053 FILE_UNLOCK(fp); 1054 unp_rights--; 1055 *fdp++ = f; 1056 } 1057 FILEDESC_UNLOCK(td->td_proc->p_fd); 1058 } else { /* We can just copy anything else across */ 1059 if (error || controlp == NULL) 1060 goto next; 1061 *controlp = sbcreatecontrol(NULL, datalen, 1062 cm->cmsg_type, cm->cmsg_level); 1063 if (*controlp == NULL) { 1064 error = ENOBUFS; 1065 goto next; 1066 } 1067 bcopy(data, 1068 CMSG_DATA(mtod(*controlp, struct cmsghdr *)), 1069 datalen); 1070 } 1071 1072 controlp = &(*controlp)->m_next; 1073 1074next: 1075 if (CMSG_SPACE(datalen) < clen) { 1076 clen -= CMSG_SPACE(datalen); 1077 cm = (struct cmsghdr *) 1078 ((caddr_t)cm + CMSG_SPACE(datalen)); 1079 } else { 1080 clen = 0; 1081 cm = NULL; 1082 } 1083 } 1084 1085 m_freem(control); 1086 1087 return (error); 1088} 1089 1090void 1091unp_init(void) 1092{ 1093 unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, NULL, 1094 NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); 1095 uma_zone_set_max(unp_zone, nmbclusters); 1096 if (unp_zone == 0) 1097 panic("unp_init"); 1098 LIST_INIT(&unp_dhead); 1099 LIST_INIT(&unp_shead); 1100} 1101 1102static int 1103unp_internalize(controlp, td) 1104 struct mbuf **controlp; 1105 struct thread *td; 1106{ 1107 struct mbuf *control = *controlp; 1108 struct proc *p = td->td_proc; 1109 struct filedesc *fdescp = p->p_fd; 1110 struct cmsghdr *cm = mtod(control, struct cmsghdr *); 1111 struct cmsgcred *cmcred; 1112 struct file **rp; 1113 struct file *fp; 1114 struct timeval *tv; 1115 int i, fd, *fdp; 1116 void *data; 1117 socklen_t clen = control->m_len, datalen; 1118 int error, oldfds; 1119 u_int newlen; 1120 1121 error = 0; 1122 *controlp = NULL; 1123 1124 while (cm != NULL) { 1125 if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET 1126 || cm->cmsg_len > clen) { 1127 error = EINVAL; 1128 goto out; 1129 } 1130 1131 data = CMSG_DATA(cm); 1132 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 1133 1134 switch (cm->cmsg_type) { 1135 /* 1136 * Fill in credential information. 1137 */ 1138 case SCM_CREDS: 1139 *controlp = sbcreatecontrol(NULL, sizeof(*cmcred), 1140 SCM_CREDS, SOL_SOCKET); 1141 if (*controlp == NULL) { 1142 error = ENOBUFS; 1143 goto out; 1144 } 1145 1146 cmcred = (struct cmsgcred *) 1147 CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 1148 cmcred->cmcred_pid = p->p_pid; 1149 cmcred->cmcred_uid = td->td_ucred->cr_ruid; 1150 cmcred->cmcred_gid = td->td_ucred->cr_rgid; 1151 cmcred->cmcred_euid = td->td_ucred->cr_uid; 1152 cmcred->cmcred_ngroups = MIN(td->td_ucred->cr_ngroups, 1153 CMGROUP_MAX); 1154 for (i = 0; i < cmcred->cmcred_ngroups; i++) 1155 cmcred->cmcred_groups[i] = 1156 td->td_ucred->cr_groups[i]; 1157 break; 1158 1159 case SCM_RIGHTS: 1160 oldfds = datalen / sizeof (int); 1161 /* 1162 * check that all the FDs passed in refer to legal files 1163 * If not, reject the entire operation. 1164 */ 1165 fdp = data; 1166 FILEDESC_LOCK(fdescp); 1167 for (i = 0; i < oldfds; i++) { 1168 fd = *fdp++; 1169 if ((unsigned)fd >= fdescp->fd_nfiles || 1170 fdescp->fd_ofiles[fd] == NULL) { 1171 FILEDESC_UNLOCK(fdescp); 1172 error = EBADF; 1173 goto out; 1174 } 1175 } 1176 /* 1177 * Now replace the integer FDs with pointers to 1178 * the associated global file table entry.. 1179 */ 1180 newlen = oldfds * sizeof(struct file *); 1181 *controlp = sbcreatecontrol(NULL, newlen, 1182 SCM_RIGHTS, SOL_SOCKET); 1183 if (*controlp == NULL) { 1184 FILEDESC_UNLOCK(fdescp); 1185 error = E2BIG; 1186 goto out; 1187 } 1188 1189 fdp = data; 1190 rp = (struct file **) 1191 CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 1192 for (i = 0; i < oldfds; i++) { 1193 fp = fdescp->fd_ofiles[*fdp++]; 1194 *rp++ = fp; 1195 FILE_LOCK(fp); 1196 fp->f_count++; 1197 fp->f_msgcount++; 1198 FILE_UNLOCK(fp); 1199 unp_rights++; 1200 } 1201 FILEDESC_UNLOCK(fdescp); 1202 break; 1203 1204 case SCM_TIMESTAMP: 1205 *controlp = sbcreatecontrol(NULL, sizeof(*tv), 1206 SCM_TIMESTAMP, SOL_SOCKET); 1207 if (*controlp == NULL) { 1208 error = ENOBUFS; 1209 goto out; 1210 } 1211 tv = (struct timeval *) 1212 CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 1213 microtime(tv); 1214 break; 1215 1216 default: 1217 error = EINVAL; 1218 goto out; 1219 } 1220 1221 controlp = &(*controlp)->m_next; 1222 1223 if (CMSG_SPACE(datalen) < clen) { 1224 clen -= CMSG_SPACE(datalen); 1225 cm = (struct cmsghdr *) 1226 ((caddr_t)cm + CMSG_SPACE(datalen)); 1227 } else { 1228 clen = 0; 1229 cm = NULL; 1230 } 1231 } 1232 1233out: 1234 m_freem(control); 1235 1236 return (error); 1237} 1238 1239static int unp_defer, unp_gcing; 1240 1241static void 1242unp_gc() 1243{ 1244 register struct file *fp, *nextfp; 1245 register struct socket *so; 1246 struct file **extra_ref, **fpp; 1247 int nunref, i; 1248 1249 if (unp_gcing) 1250 return; 1251 unp_gcing = 1; 1252 unp_defer = 0; 1253 /* 1254 * before going through all this, set all FDs to 1255 * be NOT defered and NOT externally accessible 1256 */ 1257 sx_slock(&filelist_lock); 1258 LIST_FOREACH(fp, &filehead, f_list) 1259 fp->f_gcflag &= ~(FMARK|FDEFER); 1260 do { 1261 LIST_FOREACH(fp, &filehead, f_list) { 1262 FILE_LOCK(fp); 1263 /* 1264 * If the file is not open, skip it 1265 */ 1266 if (fp->f_count == 0) { 1267 FILE_UNLOCK(fp); 1268 continue; 1269 } 1270 /* 1271 * If we already marked it as 'defer' in a 1272 * previous pass, then try process it this time 1273 * and un-mark it 1274 */ 1275 if (fp->f_gcflag & FDEFER) { 1276 fp->f_gcflag &= ~FDEFER; 1277 unp_defer--; 1278 } else { 1279 /* 1280 * if it's not defered, then check if it's 1281 * already marked.. if so skip it 1282 */ 1283 if (fp->f_gcflag & FMARK) { 1284 FILE_UNLOCK(fp); 1285 continue; 1286 } 1287 /* 1288 * If all references are from messages 1289 * in transit, then skip it. it's not 1290 * externally accessible. 1291 */ 1292 if (fp->f_count == fp->f_msgcount) { 1293 FILE_UNLOCK(fp); 1294 continue; 1295 } 1296 /* 1297 * If it got this far then it must be 1298 * externally accessible. 1299 */ 1300 fp->f_gcflag |= FMARK; 1301 } 1302 /* 1303 * either it was defered, or it is externally 1304 * accessible and not already marked so. 1305 * Now check if it is possibly one of OUR sockets. 1306 */ 1307 if (fp->f_type != DTYPE_SOCKET || 1308 (so = fp->f_data) == NULL) { 1309 FILE_UNLOCK(fp); 1310 continue; 1311 } 1312 FILE_UNLOCK(fp); 1313 if (so->so_proto->pr_domain != &localdomain || 1314 (so->so_proto->pr_flags&PR_RIGHTS) == 0) 1315 continue; 1316#ifdef notdef 1317 if (so->so_rcv.sb_flags & SB_LOCK) { 1318 /* 1319 * This is problematical; it's not clear 1320 * we need to wait for the sockbuf to be 1321 * unlocked (on a uniprocessor, at least), 1322 * and it's also not clear what to do 1323 * if sbwait returns an error due to receipt 1324 * of a signal. If sbwait does return 1325 * an error, we'll go into an infinite 1326 * loop. Delete all of this for now. 1327 */ 1328 (void) sbwait(&so->so_rcv); 1329 goto restart; 1330 } 1331#endif 1332 /* 1333 * So, Ok, it's one of our sockets and it IS externally 1334 * accessible (or was defered). Now we look 1335 * to see if we hold any file descriptors in its 1336 * message buffers. Follow those links and mark them 1337 * as accessible too. 1338 */ 1339 unp_scan(so->so_rcv.sb_mb, unp_mark); 1340 } 1341 } while (unp_defer); 1342 sx_sunlock(&filelist_lock); 1343 /* 1344 * We grab an extra reference to each of the file table entries 1345 * that are not otherwise accessible and then free the rights 1346 * that are stored in messages on them. 1347 * 1348 * The bug in the orginal code is a little tricky, so I'll describe 1349 * what's wrong with it here. 1350 * 1351 * It is incorrect to simply unp_discard each entry for f_msgcount 1352 * times -- consider the case of sockets A and B that contain 1353 * references to each other. On a last close of some other socket, 1354 * we trigger a gc since the number of outstanding rights (unp_rights) 1355 * is non-zero. If during the sweep phase the gc code un_discards, 1356 * we end up doing a (full) closef on the descriptor. A closef on A 1357 * results in the following chain. Closef calls soo_close, which 1358 * calls soclose. Soclose calls first (through the switch 1359 * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply 1360 * returns because the previous instance had set unp_gcing, and 1361 * we return all the way back to soclose, which marks the socket 1362 * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush 1363 * to free up the rights that are queued in messages on the socket A, 1364 * i.e., the reference on B. The sorflush calls via the dom_dispose 1365 * switch unp_dispose, which unp_scans with unp_discard. This second 1366 * instance of unp_discard just calls closef on B. 1367 * 1368 * Well, a similar chain occurs on B, resulting in a sorflush on B, 1369 * which results in another closef on A. Unfortunately, A is already 1370 * being closed, and the descriptor has already been marked with 1371 * SS_NOFDREF, and soclose panics at this point. 1372 * 1373 * Here, we first take an extra reference to each inaccessible 1374 * descriptor. Then, we call sorflush ourself, since we know 1375 * it is a Unix domain socket anyhow. After we destroy all the 1376 * rights carried in messages, we do a last closef to get rid 1377 * of our extra reference. This is the last close, and the 1378 * unp_detach etc will shut down the socket. 1379 * 1380 * 91/09/19, bsy@cs.cmu.edu 1381 */ 1382 extra_ref = malloc(nfiles * sizeof(struct file *), M_TEMP, 0); 1383 sx_slock(&filelist_lock); 1384 for (nunref = 0, fp = LIST_FIRST(&filehead), fpp = extra_ref; fp != 0; 1385 fp = nextfp) { 1386 nextfp = LIST_NEXT(fp, f_list); 1387 FILE_LOCK(fp); 1388 /* 1389 * If it's not open, skip it 1390 */ 1391 if (fp->f_count == 0) { 1392 FILE_UNLOCK(fp); 1393 continue; 1394 } 1395 /* 1396 * If all refs are from msgs, and it's not marked accessible 1397 * then it must be referenced from some unreachable cycle 1398 * of (shut-down) FDs, so include it in our 1399 * list of FDs to remove 1400 */ 1401 if (fp->f_count == fp->f_msgcount && !(fp->f_gcflag & FMARK)) { 1402 *fpp++ = fp; 1403 nunref++; 1404 fp->f_count++; 1405 } 1406 FILE_UNLOCK(fp); 1407 } 1408 sx_sunlock(&filelist_lock); 1409 /* 1410 * for each FD on our hit list, do the following two things 1411 */ 1412 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) { 1413 struct file *tfp = *fpp; 1414 FILE_LOCK(tfp); 1415 if (tfp->f_type == DTYPE_SOCKET && 1416 tfp->f_data != NULL) { 1417 FILE_UNLOCK(tfp); 1418 sorflush(tfp->f_data); 1419 } else 1420 FILE_UNLOCK(tfp); 1421 } 1422 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 1423 closef(*fpp, (struct thread *) NULL); 1424 free(extra_ref, M_TEMP); 1425 unp_gcing = 0; 1426} 1427 1428void 1429unp_dispose(m) 1430 struct mbuf *m; 1431{ 1432 1433 if (m) 1434 unp_scan(m, unp_discard); 1435} 1436 1437static int 1438unp_listen(unp, td) 1439 struct unpcb *unp; 1440 struct thread *td; 1441{ 1442 1443 cru2x(td->td_ucred, &unp->unp_peercred); 1444 unp->unp_flags |= UNP_HAVEPCCACHED; 1445 return (0); 1446} 1447 1448static void 1449unp_scan(m0, op) 1450 register struct mbuf *m0; 1451 void (*op)(struct file *); 1452{ 1453 struct mbuf *m; 1454 struct file **rp; 1455 struct cmsghdr *cm; 1456 void *data; 1457 int i; 1458 socklen_t clen, datalen; 1459 int qfds; 1460 1461 while (m0) { 1462 for (m = m0; m; m = m->m_next) { 1463 if (m->m_type != MT_CONTROL) 1464 continue; 1465 1466 cm = mtod(m, struct cmsghdr *); 1467 clen = m->m_len; 1468 1469 while (cm != NULL) { 1470 if (sizeof(*cm) > clen || cm->cmsg_len > clen) 1471 break; 1472 1473 data = CMSG_DATA(cm); 1474 datalen = (caddr_t)cm + cm->cmsg_len 1475 - (caddr_t)data; 1476 1477 if (cm->cmsg_level == SOL_SOCKET && 1478 cm->cmsg_type == SCM_RIGHTS) { 1479 qfds = datalen / sizeof (struct file *); 1480 rp = data; 1481 for (i = 0; i < qfds; i++) 1482 (*op)(*rp++); 1483 } 1484 1485 if (CMSG_SPACE(datalen) < clen) { 1486 clen -= CMSG_SPACE(datalen); 1487 cm = (struct cmsghdr *) 1488 ((caddr_t)cm + CMSG_SPACE(datalen)); 1489 } else { 1490 clen = 0; 1491 cm = NULL; 1492 } 1493 } 1494 } 1495 m0 = m0->m_act; 1496 } 1497} 1498 1499static void 1500unp_mark(fp) 1501 struct file *fp; 1502{ 1503 if (fp->f_gcflag & FMARK) 1504 return; 1505 unp_defer++; 1506 fp->f_gcflag |= (FMARK|FDEFER); 1507} 1508 1509static void 1510unp_discard(fp) 1511 struct file *fp; 1512{ 1513 FILE_LOCK(fp); 1514 fp->f_msgcount--; 1515 unp_rights--; 1516 FILE_UNLOCK(fp); 1517 (void) closef(fp, (struct thread *)NULL); 1518} 1519