+ struct uio auio;
+ register struct iovec *iov;
+ register int i;
+ int len, error;
+ struct mbuf *from = 0, *control = 0;
+#ifdef KTRACE
+ struct iovec *ktriov = NULL;
+#endif
+
+ fp = getsock(s, &error);
+ if (fp == 0)
+ return (error);
+ auio.uio_iov = mp->msg_iov;
+ auio.uio_iovcnt = mp->msg_iovlen;
+ auio.uio_segflg = UIO_USERSPACE;
+ auio.uio_rw = UIO_READ;
+ auio.uio_offset = 0; /* XXX */
+ auio.uio_resid = 0;
+ iov = mp->msg_iov;
+ for (i = 0; i < mp->msg_iovlen; i++, iov++) {
+ if (iov->iov_len < 0)
+ return (EINVAL);
+ if ((auio.uio_resid += iov->iov_len) < 0)
+ return (EINVAL);
+ }
+#ifdef KTRACE
+ if (KTRPOINT(u.u_procp, KTR_GENIO)) {
+ int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
+
+ MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
+ bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
+ }
+#endif
+ len = auio.uio_resid;
+ if (error = soreceive((struct socket *)fp->f_data, &from, &auio,
+ (struct mbuf **)0, &control, &mp->msg_flags)) {
+ if (auio.uio_resid != len && (error == ERESTART ||
+ error == EINTR || error == EWOULDBLOCK))
+ error = 0;
+ }
+#ifdef KTRACE
+ if (ktriov != NULL) {
+ if (error == 0)
+ ktrgenio(u.u_procp->p_tracep, s, UIO_READ,
+ ktriov, len - auio.uio_resid);
+ FREE(ktriov, M_TEMP);
+ }
+#endif
+ if (error)
+ goto out;
+ *retsize = len - auio.uio_resid;
+ if (mp->msg_name) {
+ len = mp->msg_namelen;
+ if (len <= 0 || from == 0)
+ len = 0;
+ else {
+#ifdef COMPAT_43
+ if (mp->msg_flags & MSG_COMPAT)
+ mtod(from, struct osockaddr *)->sa_family =
+ mtod(from, struct sockaddr *)->sa_family;
+#endif
+ if (len > from->m_len)
+ len = from->m_len;
+ /* else if len < from->m_len ??? */
+ if (error = copyout(mtod(from, caddr_t),
+ (caddr_t)mp->msg_name, (unsigned)len))
+ goto out;
+ }
+ mp->msg_namelen = len;
+ if (namelenp &&
+ (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
+#ifdef COMPAT_43
+ if (mp->msg_flags & MSG_COMPAT)
+ error = 0; /* old recvfrom didn't check */
+ else
+#endif
+ goto out;
+ }
+ }
+ if (mp->msg_control) {
+#ifdef COMPAT_43
+ /*
+ * We assume that old recvmsg calls won't receive access
+ * rights and other control info, esp. as control info
+ * is always optional and those options didn't exist in 4.3.
+ * If we receive rights, trim the cmsghdr; anything else
+ * is tossed.
+ */
+ if (control && mp->msg_flags & MSG_COMPAT) {
+ if (mtod(control, struct cmsghdr *)->cmsg_level !=
+ SOL_SOCKET ||
+ mtod(control, struct cmsghdr *)->cmsg_type !=
+ SCM_RIGHTS) {
+ mp->msg_controllen = 0;
+ goto out;
+ }
+ control->m_len -= sizeof (struct cmsghdr);
+ control->m_data += sizeof (struct cmsghdr);
+ }
+#endif
+ len = mp->msg_controllen;
+ if (len <= 0 || control == 0)
+ len = 0;
+ else {
+ if (len >= control->m_len)
+ len = control->m_len;
+ else
+ mp->msg_flags |= MSG_CTRUNC;
+ error = copyout((caddr_t)mtod(control, caddr_t),
+ (caddr_t)mp->msg_control, (unsigned)len);
+ }
+ mp->msg_controllen = len;
+ }
+out:
+ if (from)
+ m_freem(from);
+ if (control)
+ m_freem(control);
+ return (error);
+}
+
+/* ARGSUSED */
+shutdown(p, uap, retval)
+ struct proc *p;
+ register struct args {
+ int s;
+ int how;
+ } *uap;
+ int *retval;
+{
+ struct file *fp;
+ int error;