static int do_sys_recvmsg_so(struct lwp *l, int s, struct socket *so, struct msghdr *mp, struct mbuf **from, struct mbuf **control, register_t *retsize) { struct iovec aiov[UIO_SMALLIOV], *iov = aiov, *tiov, *ktriov = NULL; struct uio auio; size_t len, iovsz; int i, error; ktrkuser("msghdr", mp, sizeof *mp); *from = NULL; if (control != NULL) *control = NULL; iovsz = mp->msg_iovlen * sizeof(struct iovec); if (mp->msg_flags & MSG_IOVUSRSPACE) { if ((unsigned int)mp->msg_iovlen > UIO_SMALLIOV) { if ((unsigned int)mp->msg_iovlen > IOV_MAX) { error = EMSGSIZE; goto out; } iov = kmem_alloc(iovsz, KM_SLEEP); } if (mp->msg_iovlen != 0) { error = copyin(mp->msg_iov, iov, iovsz); if (error) goto out; } auio.uio_iov = iov; } else auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_rw = UIO_READ; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; KASSERT(l == curlwp); auio.uio_vmspace = l->l_proc->p_vmspace; tiov = auio.uio_iov; for (i = 0; i < mp->msg_iovlen; i++, tiov++) { /* * Reads return ssize_t because -1 is returned on error. * Therefore we must restrict the length to SSIZE_MAX to * avoid garbage return values. */ auio.uio_resid += tiov->iov_len; if (tiov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { error = EINVAL; goto out; } } if (ktrpoint(KTR_GENIO) && iovsz > 0) { ktriov = kmem_alloc(iovsz, KM_SLEEP); memcpy(ktriov, auio.uio_iov, iovsz); } len = auio.uio_resid; mp->msg_flags &= MSG_USERFLAGS; error = (*so->so_receive)(so, from, &auio, NULL, control, &mp->msg_flags); len -= auio.uio_resid; *retsize = len; if (error != 0 && len != 0 && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) /* Some data transferred */ error = 0; if (ktriov != NULL) { ktrgeniov(s, UIO_READ, ktriov, len, error); kmem_free(ktriov, iovsz); } if (error != 0) { m_freem(*from); *from = NULL; if (control != NULL) { free_control_mbuf(l, *control, *control); *control = NULL; } } out: if (iov != aiov) kmem_free(iov, iovsz); return error; }
int recvit32(struct lwp *l, int s, struct netbsd32_msghdr *mp, struct iovec *iov, void *namelenp, register_t *retsize) { struct uio auio; int i, len, error, iovlen; struct mbuf *from = 0, *control = 0; struct socket *so; struct proc *p; struct iovec *ktriov = NULL; p = l->l_proc; /* fd_getsock() will use the descriptor for us */ if ((error = fd_getsock(s, &so)) != 0) return (error); auio.uio_iov = iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_rw = UIO_READ; auio.uio_vmspace = l->l_proc->p_vmspace; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; for (i = 0; i < mp->msg_iovlen; i++, iov++) { #if 0 /* cannot happen iov_len is unsigned */ if (iov->iov_len < 0) { error = EINVAL; goto out1; } #endif /* * Reads return ssize_t because -1 is returned on error. * Therefore we must restrict the length to SSIZE_MAX to * avoid garbage return values. */ auio.uio_resid += iov->iov_len; if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { error = EINVAL; goto out1; } } if (ktrpoint(KTR_GENIO)) { iovlen = auio.uio_iovcnt * sizeof(struct iovec); ktriov = (struct iovec *)malloc(iovlen, M_TEMP, M_WAITOK); memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); } len = auio.uio_resid; error = (*so->so_receive)(so, &from, &auio, NULL, NETBSD32PTR64(mp->msg_control) ? &control : NULL, &mp->msg_flags); if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; } if (ktriov != NULL) { ktrgeniov(s, UIO_READ, ktriov, len - auio.uio_resid, error); FREE(ktriov, M_TEMP); } if (error) goto out; *retsize = len - auio.uio_resid; if (NETBSD32PTR64(mp->msg_name)) { len = mp->msg_namelen; if (len <= 0 || from == 0) len = 0; else { if (len > from->m_len) len = from->m_len; /* else if len < from->m_len ??? */ error = copyout(mtod(from, void *), (void *)NETBSD32PTR64(mp->msg_name), (unsigned)len); if (error) goto out; } mp->msg_namelen = len; if (namelenp && (error = copyout((void *)&len, namelenp, sizeof(int)))) goto out; }
static int do_sys_sendmsg_so(struct lwp *l, int s, struct socket *so, file_t *fp, struct msghdr *mp, int flags, register_t *retsize) { struct iovec aiov[UIO_SMALLIOV], *iov = aiov, *tiov, *ktriov = NULL; struct mbuf *to, *control; struct uio auio; size_t len, iovsz; int i, error; ktrkuser("msghdr", mp, sizeof *mp); /* If the caller passed us stuff in mbufs, we must free them. */ to = (mp->msg_flags & MSG_NAMEMBUF) ? mp->msg_name : NULL; control = (mp->msg_flags & MSG_CONTROLMBUF) ? mp->msg_control : NULL; iovsz = mp->msg_iovlen * sizeof(struct iovec); if (mp->msg_flags & MSG_IOVUSRSPACE) { if ((unsigned int)mp->msg_iovlen > UIO_SMALLIOV) { if ((unsigned int)mp->msg_iovlen > IOV_MAX) { error = EMSGSIZE; goto bad; } iov = kmem_alloc(iovsz, KM_SLEEP); } if (mp->msg_iovlen != 0) { error = copyin(mp->msg_iov, iov, iovsz); if (error) goto bad; } mp->msg_iov = iov; } auio.uio_iov = mp->msg_iov; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_rw = UIO_WRITE; auio.uio_offset = 0; /* XXX */ auio.uio_resid = 0; KASSERT(l == curlwp); auio.uio_vmspace = l->l_proc->p_vmspace; for (i = 0, tiov = mp->msg_iov; i < mp->msg_iovlen; i++, tiov++) { /* * Writes return ssize_t because -1 is returned on error. * Therefore, we must restrict the length to SSIZE_MAX to * avoid garbage return values. */ auio.uio_resid += tiov->iov_len; if (tiov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { error = EINVAL; goto bad; } } if (mp->msg_name && to == NULL) { error = sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME); if (error) goto bad; } if (mp->msg_control) { if (mp->msg_controllen < CMSG_ALIGN(sizeof(struct cmsghdr))) { error = EINVAL; goto bad; } if (control == NULL) { error = sockargs(&control, mp->msg_control, mp->msg_controllen, MT_CONTROL); if (error) goto bad; } } if (ktrpoint(KTR_GENIO) && iovsz > 0) { ktriov = kmem_alloc(iovsz, KM_SLEEP); memcpy(ktriov, auio.uio_iov, iovsz); } if (mp->msg_name) MCLAIM(to, so->so_mowner); if (mp->msg_control) MCLAIM(control, so->so_mowner); len = auio.uio_resid; error = (*so->so_send)(so, to, &auio, NULL, control, flags, l); /* Protocol is responsible for freeing 'control' */ control = NULL; if (error) { if (auio.uio_resid != len && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; if (error == EPIPE && (fp->f_flag & FNOSIGPIPE) == 0 && (flags & MSG_NOSIGNAL) == 0) { mutex_enter(proc_lock); psignal(l->l_proc, SIGPIPE); mutex_exit(proc_lock); } } if (error == 0) *retsize = len - auio.uio_resid; bad: if (ktriov != NULL) { ktrgeniov(s, UIO_WRITE, ktriov, *retsize, error); kmem_free(ktriov, iovsz); } if (iov != aiov) kmem_free(iov, iovsz); if (to) m_freem(to); if (control) m_freem(control); return error; }