+ KERNEL_DEBUG(DBG_FNC_SENDMSG | DBG_FUNC_END, error, 0, 0, 0, 0);
+
+ return (error);
+}
+
+int
+sendmsg_x(struct proc *p, struct sendmsg_x_args *uap, user_ssize_t *retval)
+{
+ int error = 0;
+ struct user_msghdr_x *user_msg = NULL;
+ struct uio **uiop = NULL;
+ struct socket *so;
+ u_int i;
+ struct sockaddr *to = NULL;
+ struct mbuf *control = NULL;
+ user_ssize_t len_before = 0, len_after;
+ int need_drop = 0;
+ size_t size_of_msghdr;
+ void *umsgp = NULL;
+ u_int uiocnt;
+
+ KERNEL_DEBUG(DBG_FNC_SENDMSG_X | DBG_FUNC_START, 0, 0, 0, 0, 0);
+
+ error = file_socket(uap->s, &so);
+ if (error) {
+ goto out;
+ }
+ need_drop = 1;
+ if (so == NULL) {
+ error = EBADF;
+ goto out;
+ }
+ if (so->so_proto->pr_usrreqs->pru_sosend_list == NULL) {
+ printf("%s no pru_sosend_list\n", __func__);
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
+ /*
+ * Input parameter range check
+ */
+ if (uap->cnt == 0 || uap->cnt > UIO_MAXIOV) {
+ error = EINVAL;
+ goto out;
+ }
+ user_msg = _MALLOC(uap->cnt * sizeof(struct user_msghdr_x),
+ M_TEMP, M_WAITOK | M_ZERO);
+ if (user_msg == NULL) {
+ printf("%s _MALLOC() user_msg failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ uiop = _MALLOC(uap->cnt * sizeof(struct uio *),
+ M_TEMP, M_WAITOK | M_ZERO);
+ if (uiop == NULL) {
+ printf("%s _MALLOC() uiop failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+
+ size_of_msghdr = IS_64BIT_PROCESS(p) ?
+ sizeof(struct user64_msghdr_x) : sizeof(struct user32_msghdr_x);
+
+ umsgp = _MALLOC(uap->cnt * size_of_msghdr,
+ M_TEMP, M_WAITOK | M_ZERO);
+ if (umsgp == NULL) {
+ printf("%s _MALLOC() user_msg failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ error = copyin(uap->msgp, umsgp, uap->cnt * size_of_msghdr);
+ if (error) {
+ printf("%s copyin() failed\n", __func__);
+ goto out;
+ }
+ error = internalize_user_msghdr_array(umsgp,
+ IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32,
+ UIO_WRITE, uap->cnt, user_msg, uiop);
+ if (error) {
+ printf("%s copyin_user_msghdr_array() failed\n", __func__);
+ goto out;
+ }
+ /*
+ * Make sure the size of each message iovec and
+ * the aggregate size of all the iovec is valid
+ */
+ if (uio_array_is_valid(uiop, uap->cnt) == 0) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /*
+ * Sanity check on passed arguments
+ */
+ for (i = 0; i < uap->cnt; i++) {
+ struct user_msghdr_x *mp = &user_msg[i];
+
+ /*
+ * No flags on send message
+ */
+ if (mp->msg_flags != 0) {
+ error = EINVAL;
+ goto out;
+ }
+ /*
+ * No support for address or ancillary data (yet)
+ */
+ if (mp->msg_name != USER_ADDR_NULL || mp->msg_namelen != 0) {
+ error = EINVAL;
+ goto out;
+ }
+ if (mp->msg_control != USER_ADDR_NULL ||
+ mp->msg_controllen != 0) {
+ error = EINVAL;
+ goto out;
+ }
+#if CONFIG_MACF_SOCKET_SUBSET
+ /*
+ * We check the state without holding the socket lock;
+ * if a race condition occurs, it would simply result
+ * in an extra call to the MAC check function.
+ *
+ * Note: The following check is never true taken with the
+ * current limitation that we do not accept to pass an address,
+ * this is effectively placeholder code. If we add support for addresses,
+ * we will have to check every address.
+ */
+ if ( to != NULL &&
+ !(so->so_state & SS_DEFUNCT) &&
+ (error = mac_socket_check_send(kauth_cred_get(), so, to)) != 0)
+ goto out;
+#endif /* MAC_SOCKET_SUBSET */
+ }
+
+ len_before = uio_array_resid(uiop, uap->cnt);
+
+ error = so->so_proto->pr_usrreqs->pru_sosend_list(so, to, uiop,
+ uap->cnt, 0, control, uap->flags);
+
+ len_after = uio_array_resid(uiop, uap->cnt);
+
+ if (error != 0) {
+ if (len_after != len_before && (error == ERESTART ||
+ error == EINTR || error == EWOULDBLOCK))
+ error = 0;
+ /* Generation of SIGPIPE can be controlled per socket */
+ if (error == EPIPE && !(so->so_flags & SOF_NOSIGPIPE))
+ psignal(p, SIGPIPE);
+ }
+ if (error == 0) {
+ uiocnt = externalize_user_msghdr_array(umsgp,
+ IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32,
+ UIO_WRITE, uap->cnt, user_msg, uiop);
+
+ *retval = (int)(uiocnt);
+ }
+out:
+ if (need_drop)
+ file_drop(uap->s);
+ if (umsgp != NULL)
+ _FREE(umsgp, M_TEMP);
+ if (uiop != NULL) {
+ free_uio_array(uiop, uap->cnt);
+ _FREE(uiop, M_TEMP);
+ }
+ if (user_msg != NULL)
+ _FREE(user_msg, M_TEMP);
+
+ KERNEL_DEBUG(DBG_FNC_SENDMSG_X | DBG_FUNC_END, error, 0, 0, 0, 0);