+sock_settclassopt(socket_t sock, const void *optval, size_t optlen)
+{
+ errno_t error = 0;
+ struct sockopt sopt;
+ int sotc;
+
+ if (sock == NULL || optval == NULL || optlen != sizeof (int))
+ return (EINVAL);
+
+ socket_lock(sock, 1);
+ if (!(sock->so_state & SS_ISCONNECTED)) {
+ /*
+ * If the socket is not connected then we don't know
+ * if the destination is on LAN or not. Skip
+ * setting traffic class in this case
+ */
+ error = ENOTCONN;
+ goto out;
+ }
+
+ if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL ||
+ sock->so_pcb == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ /*
+ * Set the socket traffic class based on the passed DSCP code point
+ * regardless of the scope of the destination
+ */
+ sotc = so_tc_from_dscp((*(const int *)optval) >> 2);
+
+ sopt.sopt_dir = SOPT_SET;
+ sopt.sopt_val = CAST_USER_ADDR_T(&sotc);
+ sopt.sopt_valsize = sizeof (sotc);
+ sopt.sopt_p = kernproc;
+ sopt.sopt_level = SOL_SOCKET;
+ sopt.sopt_name = SO_TRAFFIC_CLASS;
+
+ error = sosetoptlock(sock, &sopt, 0); /* already locked */
+
+ if (error != 0) {
+ printf("%s: sosetopt SO_TRAFFIC_CLASS failed %d\n",
+ __func__, error);
+ goto out;
+ }
+
+ /*
+ * Check if the destination address is LAN or link local address.
+ * We do not want to set traffic class bits if the destination
+ * is not local.
+ */
+ if (!so_isdstlocal(sock))
+ goto out;
+
+ sopt.sopt_dir = SOPT_SET;
+ sopt.sopt_val = CAST_USER_ADDR_T(optval);
+ sopt.sopt_valsize = optlen;
+ sopt.sopt_p = kernproc;
+
+ switch (SOCK_DOM(sock)) {
+ case PF_INET:
+ sopt.sopt_level = IPPROTO_IP;
+ sopt.sopt_name = IP_TOS;
+ break;
+ case PF_INET6:
+ sopt.sopt_level = IPPROTO_IPV6;
+ sopt.sopt_name = IPV6_TCLASS;
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ error = sosetoptlock(sock, &sopt, 0); /* already locked */
+ socket_unlock(sock, 1);
+ return (error);
+out:
+ socket_unlock(sock, 1);
+ return (error);
+}
+
+errno_t
+sock_gettclassopt(socket_t sock, void *optval, size_t *optlen)
+{
+ errno_t error = 0;
+ struct sockopt sopt;
+
+ if (sock == NULL || optval == NULL || optlen == NULL)
+ return (EINVAL);
+
+ sopt.sopt_dir = SOPT_GET;
+ sopt.sopt_val = CAST_USER_ADDR_T(optval);
+ sopt.sopt_valsize = *optlen;
+ sopt.sopt_p = kernproc;
+
+ socket_lock(sock, 1);
+ if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL) {
+ socket_unlock(sock, 1);
+ return (EINVAL);
+ }
+
+ switch (SOCK_DOM(sock)) {
+ case PF_INET:
+ sopt.sopt_level = IPPROTO_IP;
+ sopt.sopt_name = IP_TOS;
+ break;
+ case PF_INET6:
+ sopt.sopt_level = IPPROTO_IPV6;
+ sopt.sopt_name = IPV6_TCLASS;
+ break;
+ default:
+ socket_unlock(sock, 1);
+ return (EINVAL);
+
+ }
+ error = sogetoptlock(sock, &sopt, 0); /* already locked */
+ socket_unlock(sock, 1);
+ if (error == 0)
+ *optlen = sopt.sopt_valsize;
+ return (error);
+}
+
+errno_t
+sock_listen(socket_t sock, int backlog)
+{
+ if (sock == NULL)
+ return (EINVAL);
+
+ return (solisten(sock, backlog)); /* will lock socket */
+}
+
+errno_t
+sock_receive_internal(socket_t sock, struct msghdr *msg, mbuf_t *data,
+ int flags, size_t *recvdlen)
+{
+ uio_t auio;
+ struct mbuf *control = NULL;
+ int error = 0;
+ int length = 0;
+ struct sockaddr *fromsa = NULL;
+ char uio_buf[ UIO_SIZEOF((msg != NULL) ? msg->msg_iovlen : 0) ];
+
+ if (sock == NULL)
+ return (EINVAL);
+
+ auio = uio_createwithbuffer(((msg != NULL) ? msg->msg_iovlen : 0),
+ 0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof (uio_buf));
+ if (msg != NULL && data == NULL) {