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 --- 17 unchanged lines hidden (view full) --- 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 83366 2001-09-12 08:38:13Z julian $ |
35 */ 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/fcntl.h> 41#include <sys/domain.h> 42#include <sys/filedesc.h> --- 32 unchanged lines hidden (view full) --- 75 * need a proper out-of-band 76 * lock pushdown 77 */ 78static struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 79static ino_t unp_ino; /* prototype for fake inode numbers */ 80 81static int unp_attach __P((struct socket *)); 82static void unp_detach __P((struct unpcb *)); |
83static int unp_bind __P((struct unpcb *,struct sockaddr *, struct thread *)); |
84static int unp_connect __P((struct socket *,struct sockaddr *, |
85 struct thread *)); |
86static void unp_disconnect __P((struct unpcb *)); 87static void unp_shutdown __P((struct unpcb *)); 88static void unp_drop __P((struct unpcb *, int)); 89static void unp_gc __P((void)); 90static void unp_scan __P((struct mbuf *, void (*)(struct file *))); 91static void unp_mark __P((struct file *)); 92static void unp_discard __P((struct file *)); |
93static int unp_internalize __P((struct mbuf *, struct thread *)); |
94static int unp_listen __P((struct unpcb *, struct proc *)); 95 96static int 97uipc_abort(struct socket *so) 98{ 99 struct unpcb *unp = sotounpcb(so); 100 101 if (unp == 0) --- 20 unchanged lines hidden (view full) --- 122 1); 123 } else { 124 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); 125 } 126 return 0; 127} 128 129static int |
130uipc_attach(struct socket *so, int proto, struct thread *td) |
131{ 132 struct unpcb *unp = sotounpcb(so); 133 134 if (unp != 0) 135 return EISCONN; 136 return unp_attach(so); 137} 138 139static int |
140uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) |
141{ 142 struct unpcb *unp = sotounpcb(so); 143 144 if (unp == 0) 145 return EINVAL; 146 |
147 return unp_bind(unp, nam, td); |
148} 149 150static int |
151uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) |
152{ 153 struct unpcb *unp = sotounpcb(so); 154 155 if (unp == 0) 156 return EINVAL; |
157 return unp_connect(so, nam, curthread); |
158} 159 160static int 161uipc_connect2(struct socket *so1, struct socket *so2) 162{ 163 struct unpcb *unp = sotounpcb(so1); 164 165 if (unp == 0) --- 23 unchanged lines hidden (view full) --- 189 190 if (unp == 0) 191 return EINVAL; 192 unp_disconnect(unp); 193 return 0; 194} 195 196static int |
197uipc_listen(struct socket *so, struct thread *td) |
198{ 199 struct unpcb *unp = sotounpcb(so); 200 201 if (unp == 0 || unp->unp_vnode == 0) 202 return EINVAL; |
203 return unp_listen(unp, td->td_proc); |
204} 205 206static int 207uipc_peeraddr(struct socket *so, struct sockaddr **nam) 208{ 209 struct unpcb *unp = sotounpcb(so); 210 211 if (unp == 0) --- 41 unchanged lines hidden (view full) --- 253 } 254 return 0; 255} 256 257/* pru_rcvoob is EOPNOTSUPP */ 258 259static int 260uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, |
261 struct mbuf *control, struct thread *td) |
262{ 263 int error = 0; 264 struct unpcb *unp = sotounpcb(so); 265 struct socket *so2; 266 u_long newhiwat; 267 268 if (unp == 0) { 269 error = EINVAL; 270 goto release; 271 } 272 if (flags & PRUS_OOB) { 273 error = EOPNOTSUPP; 274 goto release; 275 } 276 |
277 if (control && (error = unp_internalize(control, td))) |
278 goto release; 279 280 switch (so->so_type) { 281 case SOCK_DGRAM: 282 { 283 struct sockaddr *from; 284 285 if (nam) { 286 if (unp->unp_conn) { 287 error = EISCONN; 288 break; 289 } |
290 error = unp_connect(so, nam, td); |
291 if (error) 292 break; 293 } else { 294 if (unp->unp_conn == 0) { 295 error = ENOTCONN; 296 break; 297 } 298 } --- 16 unchanged lines hidden (view full) --- 315 case SOCK_STREAM: 316 /* Connect if not connected yet. */ 317 /* 318 * Note: A better implementation would complain 319 * if not equal to the peer's address. 320 */ 321 if ((so->so_state & SS_ISCONNECTED) == 0) { 322 if (nam) { |
323 error = unp_connect(so, nam, td); |
324 if (error) 325 break; /* XXX */ 326 } else { 327 error = ENOTCONN; 328 break; 329 } 330 } 331 --- 197 unchanged lines hidden (view full) --- 529 unp = zalloc(unp_zone); 530 if (unp == NULL) 531 return (ENOBUFS); 532 bzero(unp, sizeof *unp); 533 unp->unp_gencnt = ++unp_gencnt; 534 unp_count++; 535 LIST_INIT(&unp->unp_refs); 536 unp->unp_socket = so; |
537 unp->unp_rvnode = curthread->td_proc->p_fd->fd_rdir; |
538 LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead 539 : &unp_shead, unp, unp_link); 540 so->so_pcb = (caddr_t)unp; 541 return (0); 542} 543 544static void 545unp_detach(unp) --- 25 unchanged lines hidden (view full) --- 571 unp_gc(); 572 } 573 if (unp->unp_addr) 574 FREE(unp->unp_addr, M_SONAME); 575 zfree(unp_zone, unp); 576} 577 578static int |
579unp_bind(unp, nam, td) |
580 struct unpcb *unp; 581 struct sockaddr *nam; |
582 struct thread *td; |
583{ 584 struct sockaddr_un *soun = (struct sockaddr_un *)nam; 585 struct vnode *vp; 586 struct mount *mp; 587 struct vattr vattr; 588 int error, namelen; 589 struct nameidata nd; 590 char *buf; 591 592 if (unp->unp_vnode != NULL) 593 return (EINVAL); 594 namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); 595 if (namelen <= 0) 596 return EINVAL; 597 buf = malloc(SOCK_MAXADDRLEN, M_TEMP, M_WAITOK); 598 strncpy(buf, soun->sun_path, namelen); 599 buf[namelen] = 0; /* null-terminate the string */ 600restart: 601 NDINIT(&nd, CREATE, NOFOLLOW | LOCKPARENT, UIO_SYSSPACE, |
602 buf, td); |
603/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 604 error = namei(&nd); 605 if (error) { 606 free(buf, M_TEMP); 607 return (error); 608 } 609 vp = nd.ni_vp; 610 if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { --- 11 unchanged lines hidden (view full) --- 622 if (error) { 623 free(buf, M_TEMP); 624 return (error); 625 } 626 goto restart; 627 } 628 VATTR_NULL(&vattr); 629 vattr.va_type = VSOCK; |
630 vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask); 631 VOP_LEASE(nd.ni_dvp, td, td->td_proc->p_ucred, LEASE_WRITE); |
632 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 633 NDFREE(&nd, NDF_ONLY_PNBUF); 634 vput(nd.ni_dvp); 635 if (error) { 636 free(buf, M_TEMP); 637 return (error); 638 } 639 vp = nd.ni_vp; 640 vp->v_socket = unp->unp_socket; 641 unp->unp_vnode = vp; 642 unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1); |
643 VOP_UNLOCK(vp, 0, td); |
644 vn_finished_write(mp); 645 free(buf, M_TEMP); 646 return (0); 647} 648 649static int |
650unp_connect(so, nam, td) |
651 struct socket *so; 652 struct sockaddr *nam; |
653 struct thread *td; |
654{ 655 register struct sockaddr_un *soun = (struct sockaddr_un *)nam; 656 register struct vnode *vp; 657 register struct socket *so2, *so3; 658 struct unpcb *unp, *unp2, *unp3; 659 int error, len; 660 struct nameidata nd; 661 char buf[SOCK_MAXADDRLEN]; 662 663 len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); 664 if (len <= 0) 665 return EINVAL; 666 strncpy(buf, soun->sun_path, len); 667 buf[len] = 0; 668 |
669 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, td); |
670 error = namei(&nd); 671 if (error) 672 return (error); 673 vp = nd.ni_vp; 674 NDFREE(&nd, NDF_ONLY_PNBUF); 675 if (vp->v_type != VSOCK) { 676 error = ENOTSOCK; 677 goto bad; 678 } |
679 error = VOP_ACCESS(vp, VWRITE, td->td_proc->p_ucred, td); |
680 if (error) 681 goto bad; 682 so2 = vp->v_socket; 683 if (so2 == 0) { 684 error = ECONNREFUSED; 685 goto bad; 686 } 687 if (so->so_type != so2->so_type) { 688 error = EPROTOTYPE; 689 goto bad; 690 } 691 if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 692 if ((so2->so_options & SO_ACCEPTCONN) == 0 || |
693 (so3 = sonewconn3(so2, 0, td)) == 0) { |
694 error = ECONNREFUSED; 695 goto bad; 696 } 697 unp = sotounpcb(so); 698 unp2 = sotounpcb(so2); 699 unp3 = sotounpcb(so3); 700 if (unp2->unp_addr) 701 unp3->unp_addr = (struct sockaddr_un *) 702 dup_sockaddr((struct sockaddr *) 703 unp2->unp_addr, 1); 704 705 /* 706 * unp_peercred management: 707 * 708 * The connecter's (client's) credentials are copied 709 * from its process structure at the time of connect() 710 * (which is now). 711 */ 712 memset(&unp3->unp_peercred, '\0', sizeof(unp3->unp_peercred)); |
713 unp3->unp_peercred.cr_uid = td->td_proc->p_ucred->cr_uid; 714 unp3->unp_peercred.cr_ngroups = td->td_proc->p_ucred->cr_ngroups; 715 memcpy(unp3->unp_peercred.cr_groups, td->td_proc->p_ucred->cr_groups, |
716 sizeof(unp3->unp_peercred.cr_groups)); 717 unp3->unp_flags |= UNP_HAVEPC; 718 /* 719 * The receiver's (server's) credentials are copied 720 * from the unp_peercred member of socket on which the 721 * former called listen(); unp_listen() cached that 722 * process's credentials at that time so we can use 723 * them now. --- 227 unchanged lines hidden (view full) --- 951 952} 953#endif 954 955int 956unp_externalize(rights) 957 struct mbuf *rights; 958{ |
959 struct thread *td = curthread; /* XXX */ |
960 register int i; 961 register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 962 register int *fdp; 963 register struct file **rp; 964 register struct file *fp; 965 int newfds = (cm->cmsg_len - (CMSG_DATA(cm) - (u_char *)cm)) 966 / sizeof (struct file *); 967 int f; 968 969 /* 970 * if the new FD's will not fit, then we free them all 971 */ |
972 if (!fdavail(td, newfds)) { |
973 rp = (struct file **)CMSG_DATA(cm); 974 for (i = 0; i < newfds; i++) { 975 fp = *rp; 976 /* 977 * zero the pointer before calling unp_discard, 978 * since it may end up in unp_gc().. 979 */ 980 *rp++ = 0; --- 11 unchanged lines hidden (view full) --- 992 * struct file pointer. 993 * If sizeof (struct file *) is smaller than sizeof int, then 994 * do it in reverse order. 995 */ 996 if (sizeof (struct file *) >= sizeof (int)) { 997 fdp = (int *)(cm + 1); 998 rp = (struct file **)CMSG_DATA(cm); 999 for (i = 0; i < newfds; i++) { |
1000 if (fdalloc(td, 0, &f)) |
1001 panic("unp_externalize"); 1002 fp = *rp++; |
1003 td->td_proc->p_fd->fd_ofiles[f] = fp; |
1004 fp->f_msgcount--; 1005 unp_rights--; 1006 *fdp++ = f; 1007 } 1008 } else { 1009 fdp = (int *)(cm + 1) + newfds - 1; 1010 rp = (struct file **)CMSG_DATA(cm) + newfds - 1; 1011 for (i = 0; i < newfds; i++) { |
1012 if (fdalloc(td, 0, &f)) |
1013 panic("unp_externalize"); 1014 fp = *rp--; |
1015 td->td_proc->p_fd->fd_ofiles[f] = fp; |
1016 fp->f_msgcount--; 1017 unp_rights--; 1018 *fdp-- = f; 1019 } 1020 } 1021 1022 /* 1023 * Adjust length, in case sizeof(struct file *) and sizeof(int) --- 14 unchanged lines hidden (view full) --- 1038 LIST_INIT(&unp_shead); 1039} 1040 1041#ifndef MIN 1042#define MIN(a,b) (((a)<(b))?(a):(b)) 1043#endif 1044 1045static int |
1046unp_internalize(control, td) |
1047 struct mbuf *control; |
1048 struct thread *td; |
1049{ |
1050 struct proc *p = td->td_proc; |
1051 struct filedesc *fdescp = p->p_fd; 1052 register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 1053 register struct file **rp; 1054 register struct file *fp; 1055 register int i, fd, *fdp; 1056 register struct cmsgcred *cmcred; 1057 int oldfds; 1058 u_int newlen; --- 245 unchanged lines hidden (view full) --- 1304 * for each FD on our hit list, do the following two things 1305 */ 1306 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) { 1307 struct file *tfp = *fpp; 1308 if (tfp->f_type == DTYPE_SOCKET && tfp->f_data != NULL) 1309 sorflush((struct socket *)(tfp->f_data)); 1310 } 1311 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) |
1312 closef(*fpp, (struct thread *) NULL); |
1313 free((caddr_t)extra_ref, M_FILE); 1314 unp_gcing = 0; 1315} 1316 1317void 1318unp_dispose(m) 1319 struct mbuf *m; 1320{ --- 61 unchanged lines hidden (view full) --- 1382 1383static void 1384unp_discard(fp) 1385 struct file *fp; 1386{ 1387 1388 fp->f_msgcount--; 1389 unp_rights--; |
1390 (void) closef(fp, (struct thread *)NULL); |
1391} |