static int uipc_rcvd(struct socket *so, int flags) { struct unpcb *unp = sotounpcb(so); struct socket *so2; if (unp == 0) return EINVAL; switch (so->so_type) { case SOCK_DGRAM: panic("uipc_rcvd DGRAM?"); /*NOTREACHED*/ case SOCK_STREAM: if (unp->unp_conn == 0) break; so2 = unp->unp_conn->unp_socket; /* * Adjust backpressure on sender * and wakeup any waiting to write. */ so2->so_snd.sb_mbmax += unp->unp_mbcnt - so->so_rcv.sb_mbcnt; unp->unp_mbcnt = so->so_rcv.sb_mbcnt; so2->so_snd.sb_hiwat += unp->unp_cc - so->so_rcv.sb_cc; (void)chgsbsize(so2->so_cred->cr_uid, (rlim_t)unp->unp_cc - so->so_rcv.sb_cc); unp->unp_cc = so->so_rcv.sb_cc; sowwakeup(so2); break; default: panic("uipc_rcvd unknown socktype"); } return 0; }
static int uipc_listen(struct socket *so, struct proc *p) { struct unpcb *unp = sotounpcb(so); if (unp == 0 || unp->unp_vnode == 0) return EINVAL; return unp_listen(unp, p); }
static int uipc_connect(struct socket *so, struct sockaddr *nam, struct proc *p) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; return unp_connect(so, nam, curproc); }
static int uipc_attach(struct socket *so, int proto, struct proc *p) { struct unpcb *unp = sotounpcb(so); if (unp != 0) return EISCONN; return unp_attach(so); }
static int uipc_disconnect(struct socket *so) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; unp_disconnect(unp); return 0; }
static int uipc_connect2(struct socket *so1, struct socket *so2) { struct unpcb *unp = sotounpcb(so1); if (unp == 0) return EINVAL; return unp_connect2(so1, so2); }
static int uipc_bind(struct socket *so, struct sockaddr *nam, struct proc *p) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; return unp_bind(unp, nam, p); }
static int uipc_abort(struct socket *so) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; unp_drop(unp, ECONNABORTED); return 0; }
static int uipc_sockaddr(struct socket *so, struct sockaddr **nam) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; if (unp->unp_addr) *nam = dup_sockaddr((struct sockaddr *)unp->unp_addr, 1); return 0; }
static int uipc_shutdown(struct socket *so) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; socantsendmore(so); unp_shutdown(unp); return 0; }
/* * sysctl helper to stuff PF_LOCAL pcbs into sysctl structures */ static void sysctl_dounpcb(struct kinfo_pcb *pcb, const struct socket *so) { struct unpcb *unp = sotounpcb(so); struct sockaddr_un *un = unp->unp_addr; memset(pcb, 0, sizeof(*pcb)); pcb->ki_family = so->so_proto->pr_domain->dom_family; pcb->ki_type = so->so_proto->pr_type; pcb->ki_protocol = so->so_proto->pr_protocol; pcb->ki_pflags = unp->unp_flags; pcb->ki_pcbaddr = PTRTOUINT64(unp); /* pcb->ki_ppcbaddr = unp has no ppcb... */ pcb->ki_sockaddr = PTRTOUINT64(so); pcb->ki_sostate = so->so_state; /* pcb->ki_prstate = unp has no state... */ pcb->ki_rcvq = so->so_rcv.sb_cc; pcb->ki_sndq = so->so_snd.sb_cc; un = (struct sockaddr_un *)&pcb->ki_src; /* * local domain sockets may bind without having a local * endpoint. bleah! */ if (unp->unp_addr != NULL) { un->sun_len = unp->unp_addr->sun_len; un->sun_family = unp->unp_addr->sun_family; strlcpy(un->sun_path, unp->unp_addr->sun_path, sizeof(pcb->ki_s)); } else { un->sun_len = offsetof(struct sockaddr_un, sun_path); un->sun_family = pcb->ki_family; } if (unp->unp_conn != NULL) { un = (struct sockaddr_un *)&pcb->ki_dst; if (unp->unp_conn->unp_addr != NULL) { un->sun_len = unp->unp_conn->unp_addr->sun_len; un->sun_family = unp->unp_conn->unp_addr->sun_family; un->sun_family = unp->unp_conn->unp_addr->sun_family; strlcpy(un->sun_path, unp->unp_conn->unp_addr->sun_path, sizeof(pcb->ki_d)); } else { un->sun_len = offsetof(struct sockaddr_un, sun_path); un->sun_family = pcb->ki_family; } }
/* * sysctl helper to stuff PF_LOCAL pcbs into sysctl structures */ static void sysctl_dounpcb(struct kinfo_pcb *pcb, const struct socket *so) { struct unpcb *unp = sotounpcb(so); struct sockaddr_un *un = unp->unp_addr; memset(pcb, 0, sizeof(*pcb)); pcb->ki_family = so->so_proto->pr_domain->dom_family; pcb->ki_type = so->so_proto->pr_type; pcb->ki_protocol = so->so_proto->pr_protocol; pcb->ki_pflags = unp->unp_flags; pcb->ki_pcbaddr = PTRTOUINT64(unp); /* pcb->ki_ppcbaddr = unp has no ppcb... */ pcb->ki_sockaddr = PTRTOUINT64(so); pcb->ki_sostate = so->so_state; /* pcb->ki_prstate = unp has no state... */ pcb->ki_rcvq = so->so_rcv.sb_cc; pcb->ki_sndq = so->so_snd.sb_cc; un = (struct sockaddr_un *)pcb->ki_spad; /* * local domain sockets may bind without having a local * endpoint. bleah! */ if (unp->unp_addr != NULL) { /* * We've added one to sun_len when allocating to * hold terminating NUL which we want here. See * makeun(). */ memcpy(un, unp->unp_addr, min(sizeof(pcb->ki_spad), unp->unp_addr->sun_len + 1)); } else { un->sun_len = offsetof(struct sockaddr_un, sun_path); un->sun_family = pcb->ki_family; } if (unp->unp_conn != NULL) { un = (struct sockaddr_un *)pcb->ki_dpad; if (unp->unp_conn->unp_addr != NULL) { memcpy(un, unp->unp_conn->unp_addr, min(sizeof(pcb->ki_dpad), unp->unp_conn->unp_addr->sun_len + 1)); } else { un->sun_len = offsetof(struct sockaddr_un, sun_path); un->sun_family = pcb->ki_family; } }
static int uipc_sense(struct socket *so, struct stat *sb) { struct unpcb *unp = sotounpcb(so); struct socket *so2; if (unp == 0) return EINVAL; sb->st_blksize = so->so_snd.sb_hiwat; if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { so2 = unp->unp_conn->unp_socket; sb->st_blksize += so2->so_rcv.sb_cc; } sb->st_dev = NOUDEV; if (unp->unp_ino == 0) /* make up a non-zero inode number */ unp->unp_ino = (++unp_ino == 0) ? ++unp_ino : unp_ino; sb->st_ino = unp->unp_ino; return (0); }
static int uipc_peeraddr(struct socket *so, struct sockaddr **nam) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; if (unp->unp_conn && unp->unp_conn->unp_addr) *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr, 1); else { /* * XXX: It seems that this test always fails even when * connection is established. So, this else clause is * added as workaround to return PF_LOCAL sockaddr. */ *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); } return 0; }
static int uipc_accept(struct socket *so, struct sockaddr **nam) { struct unpcb *unp = sotounpcb(so); if (unp == 0) return EINVAL; /* * Pass back name of connected socket, * if it was bound and we are still connected * (our peer may have closed already!). */ if (unp->unp_conn && unp->unp_conn->unp_addr) { *nam = dup_sockaddr((struct sockaddr *)unp->unp_conn->unp_addr, 1); } else { *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1); } return 0; }
static int uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p) { int error = 0; struct unpcb *unp = sotounpcb(so); struct socket *so2; u_long newhiwat; if (unp == 0) { error = EINVAL; goto release; } if (flags & PRUS_OOB) { error = EOPNOTSUPP; goto release; } if (control && (error = unp_internalize(control, p))) goto release; switch (so->so_type) { case SOCK_DGRAM: { struct sockaddr *from; if (nam) { if (unp->unp_conn) { error = EISCONN; break; } error = unp_connect(so, nam, p); if (error) break; } else { if (unp->unp_conn == 0) { error = ENOTCONN; break; } } so2 = unp->unp_conn->unp_socket; if (unp->unp_addr) from = (struct sockaddr *)unp->unp_addr; else from = &sun_noname; if (sbappendaddr(&so2->so_rcv, from, m, control)) { sorwakeup(so2); m = 0; control = 0; } else error = ENOBUFS; if (nam) unp_disconnect(unp); break; } case SOCK_STREAM: /* Connect if not connected yet. */ /* * Note: A better implementation would complain * if not equal to the peer's address. */ if ((so->so_state & SS_ISCONNECTED) == 0) { if (nam) { error = unp_connect(so, nam, p); if (error) break; /* XXX */ } else { error = ENOTCONN; break; } } if (so->so_state & SS_CANTSENDMORE) { error = EPIPE; break; } if (unp->unp_conn == 0) panic("uipc_send connected but no connection?"); so2 = unp->unp_conn->unp_socket; /* * Send to paired receive port, and then reduce * send buffer hiwater marks to maintain backpressure. * Wake up readers. */ if (control) { if (sbappendcontrol(&so2->so_rcv, m, control)) control = 0; } else sbappend(&so2->so_rcv, m); so->so_snd.sb_mbmax -= so2->so_rcv.sb_mbcnt - unp->unp_conn->unp_mbcnt; unp->unp_conn->unp_mbcnt = so2->so_rcv.sb_mbcnt; newhiwat = so->so_snd.sb_hiwat - (so2->so_rcv.sb_cc - unp->unp_conn->unp_cc); (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, newhiwat, RLIM_INFINITY); unp->unp_conn->unp_cc = so2->so_rcv.sb_cc; sorwakeup(so2); m = 0; break; default: panic("uipc_send unknown socktype"); } /* * SEND_EOF is equivalent to a SEND followed by * a SHUTDOWN. */ if (flags & PRUS_EOF) { socantsendmore(so); unp_shutdown(unp); } if (control && error != 0) unp_dispose(control); release: if (control) m_freem(control); if (m) m_freem(m); return error; }