1 /* 2 * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 3 * 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 7.26 (Berkeley) 6/3/91 34 * $Id: uipc_usrreq.c,v 1.6 1993/09/14 03:35:08 mycroft Exp $ 35 */ 36 37 #include "param.h" 38 #include "proc.h" 39 #include "filedesc.h" 40 #include "domain.h" 41 #include "protosw.h" 42 #include "socket.h" 43 #include "socketvar.h" 44 #include "unpcb.h" 45 #include "un.h" 46 #include "namei.h" 47 #include "vnode.h" 48 #include "file.h" 49 #include "stat.h" 50 #include "mbuf.h" 51 52 void unp_scan __P((struct mbuf *m0, void (*op) __P((struct file *)))); 53 void unp_shutdown __P((struct unpcb *unp)); 54 void unp_drop __P((struct unpcb *unp, int errno)); 55 void unp_gc __P((void)); 56 57 /* 58 * Unix communications domain. 59 * 60 * TODO: 61 * SEQPACKET, RDM 62 * rethink name space problems 63 * need a proper out-of-band 64 */ 65 struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX }; 66 ino_t unp_ino; /* prototype for fake inode numbers */ 67 68 /*ARGSUSED*/ 69 int 70 uipc_usrreq(so, req, m, nam, control) 71 struct socket *so; 72 int req; 73 struct mbuf *m, *nam, *control; 74 { 75 struct unpcb *unp = sotounpcb(so); 76 register struct socket *so2; 77 register int error = 0; 78 struct proc *p = curproc; /* XXX */ 79 80 if (req == PRU_CONTROL) 81 return (EOPNOTSUPP); 82 if (req != PRU_SEND && control && control->m_len) { 83 error = EOPNOTSUPP; 84 goto release; 85 } 86 if (unp == 0 && req != PRU_ATTACH) { 87 error = EINVAL; 88 goto release; 89 } 90 switch (req) { 91 92 case PRU_ATTACH: 93 if (unp) { 94 error = EISCONN; 95 break; 96 } 97 error = unp_attach(so); 98 break; 99 100 case PRU_DETACH: 101 unp_detach(unp); 102 break; 103 104 case PRU_BIND: 105 error = unp_bind(unp, nam, p); 106 break; 107 108 case PRU_LISTEN: 109 if (unp->unp_vnode == 0) 110 error = EINVAL; 111 break; 112 113 case PRU_CONNECT: 114 error = unp_connect(so, nam, p); 115 break; 116 117 case PRU_CONNECT2: 118 error = unp_connect2(so, (struct socket *)nam); 119 break; 120 121 case PRU_DISCONNECT: 122 unp_disconnect(unp); 123 break; 124 125 case PRU_ACCEPT: 126 /* 127 * Pass back name of connected socket, 128 * if it was bound and we are still connected 129 * (our peer may have closed already!). 130 */ 131 if (unp->unp_conn && unp->unp_conn->unp_addr) { 132 nam->m_len = unp->unp_conn->unp_addr->m_len; 133 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 134 mtod(nam, caddr_t), (unsigned)nam->m_len); 135 } else { 136 nam->m_len = sizeof(sun_noname); 137 *(mtod(nam, struct sockaddr *)) = sun_noname; 138 } 139 break; 140 141 case PRU_SHUTDOWN: 142 socantsendmore(so); 143 unp_shutdown(unp); 144 break; 145 146 case PRU_RCVD: 147 switch (so->so_type) { 148 149 case SOCK_DGRAM: 150 panic("uipc 1"); 151 /*NOTREACHED*/ 152 153 case SOCK_STREAM: 154 #define rcv (&so->so_rcv) 155 #define snd (&so2->so_snd) 156 if (unp->unp_conn == 0) 157 break; 158 so2 = unp->unp_conn->unp_socket; 159 /* 160 * Adjust backpressure on sender 161 * and wakeup any waiting to write. 162 */ 163 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 164 unp->unp_mbcnt = rcv->sb_mbcnt; 165 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 166 unp->unp_cc = rcv->sb_cc; 167 sowwakeup(so2); 168 #undef snd 169 #undef rcv 170 break; 171 172 default: 173 panic("uipc 2"); 174 } 175 break; 176 177 case PRU_SEND: 178 if (control && (error = unp_internalize(control, p))) 179 break; 180 switch (so->so_type) { 181 182 case SOCK_DGRAM: { 183 struct sockaddr *from; 184 185 if (nam) { 186 if (unp->unp_conn) { 187 error = EISCONN; 188 break; 189 } 190 error = unp_connect(so, nam, p); 191 if (error) 192 break; 193 } else { 194 if (unp->unp_conn == 0) { 195 error = ENOTCONN; 196 break; 197 } 198 } 199 so2 = unp->unp_conn->unp_socket; 200 if (unp->unp_addr) 201 from = mtod(unp->unp_addr, struct sockaddr *); 202 else 203 from = &sun_noname; 204 if (sbappendaddr(&so2->so_rcv, from, m, control)) { 205 sorwakeup(so2); 206 m = 0; 207 control = 0; 208 } else 209 error = ENOBUFS; 210 if (nam) 211 unp_disconnect(unp); 212 break; 213 } 214 215 case SOCK_STREAM: 216 #define rcv (&so2->so_rcv) 217 #define snd (&so->so_snd) 218 if (so->so_state & SS_CANTSENDMORE) { 219 error = EPIPE; 220 break; 221 } 222 if (unp->unp_conn == 0) 223 panic("uipc 3"); 224 so2 = unp->unp_conn->unp_socket; 225 /* 226 * Send to paired receive port, and then reduce 227 * send buffer hiwater marks to maintain backpressure. 228 * Wake up readers. 229 */ 230 if (control) { 231 if (sbappendcontrol(rcv, m, control)) 232 control = 0; 233 } else 234 sbappend(rcv, m); 235 snd->sb_mbmax -= 236 rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 237 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 238 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 239 unp->unp_conn->unp_cc = rcv->sb_cc; 240 sorwakeup(so2); 241 m = 0; 242 #undef snd 243 #undef rcv 244 break; 245 246 default: 247 panic("uipc 4"); 248 } 249 break; 250 251 case PRU_ABORT: 252 unp_drop(unp, ECONNABORTED); 253 break; 254 255 case PRU_SENSE: 256 ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 257 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 258 so2 = unp->unp_conn->unp_socket; 259 ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 260 } 261 ((struct stat *) m)->st_dev = NODEV; 262 if (unp->unp_ino == 0) 263 unp->unp_ino = unp_ino++; 264 ((struct stat *) m)->st_ino = unp->unp_ino; 265 return (0); 266 267 case PRU_RCVOOB: 268 return (EOPNOTSUPP); 269 270 case PRU_SENDOOB: 271 error = EOPNOTSUPP; 272 break; 273 274 case PRU_SOCKADDR: 275 if (unp->unp_addr) { 276 nam->m_len = unp->unp_addr->m_len; 277 bcopy(mtod(unp->unp_addr, caddr_t), 278 mtod(nam, caddr_t), (unsigned)nam->m_len); 279 } else 280 nam->m_len = 0; 281 break; 282 283 case PRU_PEERADDR: 284 if (unp->unp_conn && unp->unp_conn->unp_addr) { 285 nam->m_len = unp->unp_conn->unp_addr->m_len; 286 bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 287 mtod(nam, caddr_t), (unsigned)nam->m_len); 288 } else 289 nam->m_len = 0; 290 break; 291 292 case PRU_SLOWTIMO: 293 break; 294 295 default: 296 panic("piusrreq"); 297 } 298 release: 299 if (control) 300 m_freem(control); 301 if (m) 302 m_freem(m); 303 return (error); 304 } 305 306 /* 307 * Both send and receive buffers are allocated PIPSIZ bytes of buffering 308 * for stream sockets, although the total for sender and receiver is 309 * actually only PIPSIZ. 310 * Datagram sockets really use the sendspace as the maximum datagram size, 311 * and don't really want to reserve the sendspace. Their recvspace should 312 * be large enough for at least one max-size datagram plus address. 313 */ 314 #define PIPSIZ 4096 315 u_long unpst_sendspace = PIPSIZ; 316 u_long unpst_recvspace = PIPSIZ; 317 u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 318 u_long unpdg_recvspace = 4*1024; 319 320 int unp_rights; /* file descriptors in flight */ 321 322 int 323 unp_attach(so) 324 struct socket *so; 325 { 326 register struct mbuf *m; 327 register struct unpcb *unp; 328 int error; 329 330 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 331 switch (so->so_type) { 332 333 case SOCK_STREAM: 334 error = soreserve(so, unpst_sendspace, unpst_recvspace); 335 break; 336 337 case SOCK_DGRAM: 338 error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 339 break; 340 } 341 if (error) 342 return (error); 343 } 344 m = m_getclr(M_DONTWAIT, MT_PCB); 345 if (m == NULL) 346 return (ENOBUFS); 347 unp = mtod(m, struct unpcb *); 348 so->so_pcb = (caddr_t)unp; 349 unp->unp_socket = so; 350 return (0); 351 } 352 353 int 354 unp_detach(unp) 355 register struct unpcb *unp; 356 { 357 358 if (unp->unp_vnode) { 359 unp->unp_vnode->v_socket = 0; 360 vrele(unp->unp_vnode); 361 unp->unp_vnode = 0; 362 } 363 if (unp->unp_conn) 364 unp_disconnect(unp); 365 while (unp->unp_refs) 366 unp_drop(unp->unp_refs, ECONNRESET); 367 soisdisconnected(unp->unp_socket); 368 unp->unp_socket->so_pcb = 0; 369 m_freem(unp->unp_addr); 370 (void) m_free(dtom(unp)); 371 if (unp_rights) 372 unp_gc(); 373 } 374 375 int 376 unp_bind(unp, nam, p) 377 struct unpcb *unp; 378 struct mbuf *nam; 379 struct proc *p; 380 { 381 struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 382 register struct vnode *vp; 383 register struct nameidata *ndp; 384 struct vattr vattr; 385 int error; 386 struct nameidata nd; 387 388 ndp = &nd; 389 ndp->ni_dirp = soun->sun_path; 390 if (unp->unp_vnode != NULL) 391 return (EINVAL); 392 if (nam->m_len == MLEN) { 393 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 394 return (EINVAL); 395 } else 396 *(mtod(nam, caddr_t) + nam->m_len) = 0; 397 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 398 ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT; 399 ndp->ni_segflg = UIO_SYSSPACE; 400 if (error = namei(ndp, p)) 401 return (error); 402 vp = ndp->ni_vp; 403 if (vp != NULL) { 404 VOP_ABORTOP(ndp); 405 if (ndp->ni_dvp == vp) 406 vrele(ndp->ni_dvp); 407 else 408 vput(ndp->ni_dvp); 409 vrele(vp); 410 return (EADDRINUSE); 411 } 412 VATTR_NULL(&vattr); 413 vattr.va_type = VSOCK; 414 vattr.va_mode = 0777; 415 if (error = VOP_CREATE(ndp, &vattr, p)) 416 return (error); 417 vp = ndp->ni_vp; 418 vp->v_socket = unp->unp_socket; 419 unp->unp_vnode = vp; 420 unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 421 VOP_UNLOCK(vp); 422 return (0); 423 } 424 425 int 426 unp_connect(so, nam, p) 427 struct socket *so; 428 struct mbuf *nam; 429 struct proc *p; 430 { 431 register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 432 register struct vnode *vp; 433 register struct socket *so2, *so3; 434 register struct nameidata *ndp; 435 struct unpcb *unp2, *unp3; 436 int error; 437 struct nameidata nd; 438 439 ndp = &nd; 440 ndp->ni_dirp = soun->sun_path; 441 if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 442 if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 443 return (EMSGSIZE); 444 } else 445 *(mtod(nam, caddr_t) + nam->m_len) = 0; 446 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 447 ndp->ni_segflg = UIO_SYSSPACE; 448 if (error = namei(ndp, p)) 449 return (error); 450 vp = ndp->ni_vp; 451 if (vp->v_type != VSOCK) { 452 error = ENOTSOCK; 453 goto bad; 454 } 455 if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) 456 goto bad; 457 so2 = vp->v_socket; 458 if (so2 == 0) { 459 error = ECONNREFUSED; 460 goto bad; 461 } 462 if (so->so_type != so2->so_type) { 463 error = EPROTOTYPE; 464 goto bad; 465 } 466 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 467 if ((so2->so_options & SO_ACCEPTCONN) == 0 || 468 (so3 = sonewconn(so2, 0)) == 0) { 469 error = ECONNREFUSED; 470 goto bad; 471 } 472 unp2 = sotounpcb(so2); 473 unp3 = sotounpcb(so3); 474 if (unp2->unp_addr) 475 unp3->unp_addr = 476 m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 477 so2 = so3; 478 } 479 error = unp_connect2(so, so2); 480 bad: 481 vput(vp); 482 return (error); 483 } 484 485 int 486 unp_connect2(so, so2) 487 register struct socket *so; 488 register struct socket *so2; 489 { 490 register struct unpcb *unp = sotounpcb(so); 491 register struct unpcb *unp2; 492 493 if (so2->so_type != so->so_type) 494 return (EPROTOTYPE); 495 unp2 = sotounpcb(so2); 496 unp->unp_conn = unp2; 497 switch (so->so_type) { 498 499 case SOCK_DGRAM: 500 unp->unp_nextref = unp2->unp_refs; 501 unp2->unp_refs = unp; 502 soisconnected(so); 503 break; 504 505 case SOCK_STREAM: 506 unp2->unp_conn = unp; 507 soisconnected(so); 508 soisconnected(so2); 509 break; 510 511 default: 512 panic("unp_connect2"); 513 } 514 return (0); 515 } 516 517 void 518 unp_disconnect(unp) 519 struct unpcb *unp; 520 { 521 register struct unpcb *unp2 = unp->unp_conn; 522 523 if (unp2 == 0) 524 return; 525 unp->unp_conn = 0; 526 switch (unp->unp_socket->so_type) { 527 528 case SOCK_DGRAM: 529 if (unp2->unp_refs == unp) 530 unp2->unp_refs = unp->unp_nextref; 531 else { 532 unp2 = unp2->unp_refs; 533 for (;;) { 534 if (unp2 == 0) 535 panic("unp_disconnect"); 536 if (unp2->unp_nextref == unp) 537 break; 538 unp2 = unp2->unp_nextref; 539 } 540 unp2->unp_nextref = unp->unp_nextref; 541 } 542 unp->unp_nextref = 0; 543 unp->unp_socket->so_state &= ~SS_ISCONNECTED; 544 break; 545 546 case SOCK_STREAM: 547 soisdisconnected(unp->unp_socket); 548 unp2->unp_conn = 0; 549 soisdisconnected(unp2->unp_socket); 550 break; 551 } 552 } 553 554 #ifdef notdef 555 unp_abort(unp) 556 struct unpcb *unp; 557 { 558 559 unp_detach(unp); 560 } 561 #endif 562 563 void 564 unp_shutdown(unp) 565 struct unpcb *unp; 566 { 567 struct socket *so; 568 569 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 570 (so = unp->unp_conn->unp_socket)) 571 socantrcvmore(so); 572 } 573 574 void 575 unp_drop(unp, errno) 576 struct unpcb *unp; 577 int errno; 578 { 579 struct socket *so = unp->unp_socket; 580 581 so->so_error = errno; 582 unp_disconnect(unp); 583 if (so->so_head) { 584 so->so_pcb = (caddr_t) 0; 585 m_freem(unp->unp_addr); 586 (void) m_free(dtom(unp)); 587 sofree(so); 588 } 589 } 590 591 #ifdef notdef 592 unp_drain() 593 { 594 595 } 596 #endif 597 598 int 599 unp_externalize(rights) 600 struct mbuf *rights; 601 { 602 struct proc *p = curproc; /* XXX */ 603 register int i; 604 register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 605 register struct file **rp = (struct file **)(cm + 1); 606 register struct file *fp; 607 int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 608 int f; 609 610 if (!fdavail(p, newfds)) { 611 for (i = 0; i < newfds; i++) { 612 fp = *rp; 613 unp_discard(fp); 614 *rp++ = 0; 615 } 616 return (EMSGSIZE); 617 } 618 for (i = 0; i < newfds; i++) { 619 if (fdalloc(p, 0, &f)) 620 panic("unp_externalize"); 621 fp = *rp; 622 p->p_fd->fd_ofiles[f] = fp; 623 fp->f_msgcount--; 624 unp_rights--; 625 *(int *)rp++ = f; 626 } 627 return (0); 628 } 629 630 int 631 unp_internalize(control, p) 632 struct mbuf *control; 633 struct proc *p; 634 { 635 struct filedesc *fdp = p->p_fd; 636 register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 637 register struct file **rp; 638 register struct file *fp; 639 register int i, fd; 640 int oldfds; 641 642 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 643 cm->cmsg_len != control->m_len) 644 return (EINVAL); 645 oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 646 rp = (struct file **)(cm + 1); 647 for (i = 0; i < oldfds; i++) { 648 fd = *(int *)rp++; 649 if ((unsigned)fd >= fdp->fd_nfiles || 650 fdp->fd_ofiles[fd] == NULL) 651 return (EBADF); 652 } 653 rp = (struct file **)(cm + 1); 654 for (i = 0; i < oldfds; i++) { 655 fp = fdp->fd_ofiles[*(int *)rp]; 656 *rp++ = fp; 657 fp->f_count++; 658 fp->f_msgcount++; 659 unp_rights++; 660 } 661 return (0); 662 } 663 664 int unp_defer, unp_gcing; 665 extern struct domain unixdomain; 666 void unp_mark __P((struct file *fp)); 667 void unp_discard __P((struct file *fp)); 668 669 void 670 unp_gc() 671 { 672 register struct file *fp; 673 register struct socket *so; 674 675 if (unp_gcing) 676 return; 677 unp_gcing = 1; 678 restart: 679 unp_defer = 0; 680 for (fp = filehead; fp; fp = fp->f_filef) 681 fp->f_flag &= ~(FMARK|FDEFER); 682 do { 683 for (fp = filehead; fp; fp = fp->f_filef) { 684 if (fp->f_count == 0) 685 continue; 686 if (fp->f_flag & FDEFER) { 687 fp->f_flag &= ~FDEFER; 688 unp_defer--; 689 } else { 690 if (fp->f_flag & FMARK) 691 continue; 692 if (fp->f_count == fp->f_msgcount) 693 continue; 694 fp->f_flag |= FMARK; 695 } 696 if (fp->f_type != DTYPE_SOCKET || 697 (so = (struct socket *)fp->f_data) == 0) 698 continue; 699 if (so->so_proto->pr_domain != &unixdomain || 700 (so->so_proto->pr_flags&PR_RIGHTS) == 0) 701 continue; 702 #ifdef notdef 703 if (so->so_rcv.sb_flags & SB_LOCK) { 704 /* 705 * This is problematical; it's not clear 706 * we need to wait for the sockbuf to be 707 * unlocked (on a uniprocessor, at least), 708 * and it's also not clear what to do 709 * if sbwait returns an error due to receipt 710 * of a signal. If sbwait does return 711 * an error, we'll go into an infinite 712 * loop. Delete all of this for now. 713 */ 714 (void) sbwait(&so->so_rcv); 715 goto restart; 716 } 717 #endif 718 unp_scan(so->so_rcv.sb_mb, unp_mark); 719 } 720 } while (unp_defer); 721 for (fp = filehead; fp; fp = fp->f_filef) { 722 if (fp->f_count == 0) 723 continue; 724 if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0) 725 while (fp->f_msgcount) 726 unp_discard(fp); 727 } 728 unp_gcing = 0; 729 } 730 731 void 732 unp_dispose(m) 733 struct mbuf *m; 734 { 735 if (m) 736 unp_scan(m, unp_discard); 737 } 738 739 void 740 unp_scan(m0, op) 741 register struct mbuf *m0; 742 void (*op) __P((struct file *)); 743 { 744 register struct mbuf *m; 745 register struct file **rp; 746 register struct cmsghdr *cm; 747 register int i; 748 int qfds; 749 750 while (m0) { 751 for (m = m0; m; m = m->m_next) 752 if (m->m_type == MT_CONTROL && 753 m->m_len >= sizeof(*cm)) { 754 cm = mtod(m, struct cmsghdr *); 755 if (cm->cmsg_level != SOL_SOCKET || 756 cm->cmsg_type != SCM_RIGHTS) 757 continue; 758 qfds = (cm->cmsg_len - sizeof *cm) 759 / sizeof (struct file *); 760 rp = (struct file **)(cm + 1); 761 for (i = 0; i < qfds; i++) 762 (*op)(*rp++); 763 break; /* XXX, but saves time */ 764 } 765 m0 = m0->m_act; 766 } 767 } 768 769 void 770 unp_mark(fp) 771 struct file *fp; 772 { 773 774 if (fp->f_flag & FMARK) 775 return; 776 unp_defer++; 777 fp->f_flag |= (FMARK|FDEFER); 778 } 779 780 void 781 unp_discard(fp) 782 struct file *fp; 783 { 784 if (fp->f_msgcount == 0) 785 return; 786 fp->f_msgcount--; 787 unp_rights--; 788 (void) closef(fp, curproc); 789 } 790