changeset 25436:19710a8ace43

[illumos-gate merge] commit 221e47fb90c5fcfe7add9a33f6c915ee5253ece9 13175 Add support for IP_RECVTOS 13182 CMSG_ macros should have man pages
author Jerry Jelinek <jerry.jelinek@joyent.com>
date Fri, 02 Oct 2020 11:46:54 +0000
parents 1cdaa18973ab (current diff) 5f0b225deed1 (diff)
children 95e44660f7a9
files manifest usr/src/pkg/manifests/system-header.mf usr/src/pkg/manifests/system-test-ostest.mf usr/src/test/os-tests/runfiles/default.run usr/src/uts/common/fs/sockfs/socksubr.c usr/src/uts/common/inet/ip/conn_opt.c usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip_stack.h usr/src/uts/common/inet/ipclassifier.h usr/src/uts/common/inet/tcp.h usr/src/uts/common/inet/tcp/tcp_input.c usr/src/uts/common/inet/tcp/tcp_opt_data.c usr/src/uts/common/inet/udp/udp.c usr/src/uts/common/inet/udp/udp_opt_data.c usr/src/uts/common/netinet/in.h
diffstat 20 files changed, 906 insertions(+), 235 deletions(-) [+]
line wrap: on
line diff
--- a/manifest	Thu Oct 01 11:31:50 2020 +0000
+++ b/manifest	Fri Oct 02 11:46:54 2020 +0000
@@ -15847,6 +15847,11 @@
 f usr/share/man/man3gss/gss_wrap.3gss 0444 root bin
 f usr/share/man/man3gss/gss_wrap_size_limit.3gss 0444 root bin
 d usr/share/man/man3head 0755 root bin
+s usr/share/man/man3head/CMSG_DATA.3head=socket.h.3head
+s usr/share/man/man3head/CMSG_FIRSTHDR.3head=socket.h.3head
+s usr/share/man/man3head/CMSG_LEN.3head=socket.h.3head
+s usr/share/man/man3head/CMSG_NXTHDR.3head=socket.h.3head
+s usr/share/man/man3head/CMSG_SPACE.3head=socket.h.3head
 s usr/share/man/man3head/LIST_CLASS_ENTRY.3head=queue.h.3head
 s usr/share/man/man3head/LIST_CLASS_HEAD.3head=queue.h.3head
 s usr/share/man/man3head/LIST_CONCAT.3head=queue.h.3head
--- a/usr/src/man/man3head/Makefile	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/man/man3head/Makefile	Fri Oct 02 11:46:54 2020 +0000
@@ -114,6 +114,11 @@
 		xlocale.h.3head
 
 MANLINKS=	\
+		CMSG_DATA.3head \
+		CMSG_FIRSTHDR.3head \
+		CMSG_LEN.3head \
+		CMSG_NXTHDR.3head \
+		CMSG_SPACE.3head \
 		LIST_CLASS_ENTRY.3head \
 		LIST_CLASS_HEAD.3head \
 		LIST_CONCAT.3head \
@@ -295,6 +300,11 @@
 		wordexp.3head		\
 		xlocale.3head
 
+CMSG_DATA.3head := LINKSRC = socket.h.3head
+CMSG_FIRSTHDR.3head := LINKSRC = socket.h.3head
+CMSG_LEN.3head := LINKSRC = socket.h.3head
+CMSG_NXTHDR.3head := LINKSRC = socket.h.3head
+CMSG_SPACE.3head := LINKSRC = socket.h.3head
 LIST_CLASS_ENTRY.3head := LINKSRC = queue.h.3head
 LIST_CLASS_HEAD.3head := LINKSRC = queue.h.3head
 LIST_CONCAT.3head := LINKSRC = queue.h.3head
--- a/usr/src/man/man3head/socket.h.3head	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/man/man3head/socket.h.3head	Fri Oct 02 11:46:54 2020 +0000
@@ -42,18 +42,17 @@
 .\"
 .\" Copyright (c) 1992, X/Open Company Limited All Rights Reserved.
 .\" Portions Copyright (c) 2009, Sun Microsystems, Inc.  All Rights Reserved.
+.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
 .\"
-.TH SOCKET.H 3HEAD "Jun 18, 2017"
+.TH SOCKET.H 3HEAD "Sep 18, 2020"
 .SH NAME
-socket.h, socket \- Internet Protocol family
+socket.h, socket, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE \- Internet Protocol family
 .SH SYNOPSIS
-.LP
 .nf
 \fB#include <sys/socket.h>\fR
 .fi
 
 .SH DESCRIPTION
-.LP
 The \fB<sys/socket.h>\fR header defines the unsigned integral type
 \fBsa_family_t\fR through \fBtypedef\fR.
 .sp
@@ -70,7 +69,6 @@
 .in -2
 
 .SS "\fBlibxnet\fR Interfaces"
-.LP
 The \fB<sys/socket.h>\fR header defines the \fBmsghdr\fR structure for
 \fBlibxnet\fR interfaces that includes the following members:
 .sp
@@ -118,17 +116,17 @@
 .sp
 .ne 2
 .na
-\fB\fBSCM_RIGHTS\fR\fR
+\fBSCM_RIGHTS\fR
 .ad
 .RS 14n
-Indicates that the data array contains the access rights to be sent or
-received.
+Indicates that the data array contains the access rights (set of open file
+descriptors) to be sent or received.
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBSCM_UCRED\fR\fR
+\fBSCM_UCRED\fR
 .ad
 .RS 14n
 Indicates that the data array contains a \fBucred_t\fR to be received. The
@@ -138,17 +136,12 @@
 
 .sp
 .LP
-The IPv4 data formats generally use the same values for data passed back in
-\fBcmsghdr\fR as for \fBsetsockopt()\fR to enable the feature. The IPv4 data
-formats are listed below with the associated payload for each.
+The IPv4 ancillary data formats are listed below by \fBcmsg_level\fR and
+\fBcmsg_type\fR, along with the associated payload for each.
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IP\fR\fR
-.ad
-.br
-.na
-\fB\fBIP_RECVDSTADDR\fR\fR
+\fBIPPROTO_IP\fR, \fBIP_RECVDSTADDR\fR \(em \fBSOCK_DGRAM\fR only
 .ad
 .sp .6
 .RS 4n
@@ -158,11 +151,17 @@
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IP\fR\fR
+\fBIPPROTO_IP\fR, \fBIP_RECVIF\fR
 .ad
-.br
+.sp .6
+.RS 4n
+\fBuint_t\fR, \fBifIndex\fR number
+.RE
+
+.sp
+.ne 2
 .na
-\fB\fBIP_RECVOPTS\fR\fR
+\fBIPPROTO_IP\fR, \fBIP_RECVOPTS\fR \(em \fBSOCK_DGRAM\fR only
 .ad
 .sp .6
 .RS 4n
@@ -172,25 +171,17 @@
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IP\fR\fR
-.ad
-.br
-.na
-\fB\fBIP_RECVIF\fR\fR
+\fBIPPROTO_IP\fR, \fBIP_RECVPKTINFO\fR \(em \fBSOCK_DGRAM\fR only
 .ad
 .sp .6
 .RS 4n
-\fBuint_t\fR, \fBifIndex\fR number
+\fBin_pktinfo_t\fR
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IP\fR\fR
-.ad
-.br
-.na
-\fB\fBIP_RECVSLLA\fR\fR
+\fBIPPROTO_IP\fR, \fBIP_RECVSLLA\fR \(em \fBSOCK_DGRAM\fR only
 .ad
 .sp .6
 .RS 4n
@@ -200,147 +191,115 @@
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IP\fR\fR
-.ad
-.br
-.na
-\fB\fBIP_RECVTTL\fR\fR
+\fBIPPROTO_IP\fR, \fBIP_RECVTTL\fR \(em \fBSOCK_DGRAM\fR only
 .ad
 .sp .6
 .RS 4n
-\fBuint8_t\fR
+\fBuint8_t\fR, the IP TTL (time to live)
+.RE
+
+.sp
+.ne 2
+.na
+\fBIPPROTO_IP\fR, \fBIP_RECVTOS\fR
+.ad
+.sp .6
+.RS 4n
+\fBuint8_t\fR, the IP TOS (type of service)
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBSOL_SOCKET\fR\fR
-.ad
-.br
-.na
-\fB\fBSO_RECVUCRED\fR\fR
+\fBSOL_SOCKET\fR, \fBSO_UCRED\fR
 .ad
 .sp .6
 .RS 4n
-\fBucred_t\fR \(em \fBcmsghdr.cmsg_type\fR is \fBSCM_UCRED\fR, not
-\fBSO_RECVUCRED\fR
+\fBucred_t\fR
 .RE
 
 .sp
 .LP
-The IPv6 data formats use different values for enabling the option and for
-passing the value back to the application. The IPv6 data formats are listed
-below with the associated payload for each.
+The IPv6 ancillary data formats are listed below by \fBcmsg_level\fR and
+\fBcmsg_type\fR, along with the associated payload for each.
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVPKTINFO\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_PKTINFO\fR
 .ad
 .sp .6
 .RS 4n
-\fBin_pktinfo\fR, \fBcmsg_type\fR \fBIPV6_PKTINFO\fR
+\fBin_pktinfo_t\fR
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVTCLASS\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_TCLASS\fR
 .ad
 .sp .6
 .RS 4n
-\fBuint_t\fR, \fBcmsg_type\fR \fBIPV6_TCLASS\fR
+\fBuint_t\fR
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVPATHMTU\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_PATHMTU\fR
 .ad
 .sp .6
 .RS 4n
-\fBip6_mtuinfo\fR, \fBcmsg_type\fR \fBIPV6_PATHMTU\fR
+\fBip6_mtuinfo\fR
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVHOPLIMIT\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_HOPLIMIT\fR
 .ad
 .sp .6
 .RS 4n
-\fBuint_t\fR, \fBcmsg_type\fR \fBIPV6_HOPLIMIT\fR
+\fBuint_t\fR
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVHOPOPTS\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_HOPOPTS\fR
 .ad
 .sp .6
 .RS 4n
-variable-length IPv6 options, \fBcmsg_type\fR \fBIPV6_HOPOPTS\fR
+variable-length IPv6 options
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVDSTOPTS\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_DSTOPTS\fR
 .ad
 .sp .6
 .RS 4n
-variable-length IPv6 options, \fBcmsg_type\fR \fBIPV6_DSTOPTS\fR
+variable-length IPv6 options
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVRTHDR\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_RTHDR\fR
 .ad
 .sp .6
 .RS 4n
-variable-length IPv6 options, \fBcmsg_type\fR \fBIPV6_RTHDR\fR
+variable-length IPv6 options
 .RE
 
 .sp
 .ne 2
 .na
-\fB\fBIPPROTO_IPV6\fR\fR
-.ad
-.br
-.na
-\fB\fBIPV6_RECVRTHDRDSTOPTS\fR\fR
+\fBIPPROTO_IPV6\fR, \fBIPV6_DSTOPTS\fR
 .ad
 .sp .6
 .RS 4n
-variable-length IPv6 options, \fBcmsg_type\fR \fBIPV6_DSTOPTS\fR
+variable-length IPv6 options
 .RE
 
 .sp
@@ -431,7 +390,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSOCK_DGRAM\fR\fR
+\fBSOCK_DGRAM\fR
 .ad
 .RS 18n
 Datagram socket
@@ -440,7 +399,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSOCK_STREAM\fR\fR
+\fBSOCK_STREAM\fR
 .ad
 .RS 18n
 Byte-stream socket
@@ -449,7 +408,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSOCK_SEQPACKET\fR\fR
+\fBSOCK_SEQPACKET\fR
 .ad
 .RS 18n
 Sequenced-packet socket
@@ -462,7 +421,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSOL_SOCKET\fR\fR
+\fBSOL_SOCKET\fR
 .ad
 .RS 14n
 Options to be accessed at the socket level, not the protocol level.
@@ -471,7 +430,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSOL_ROUTE\fR\fR
+\fBSOL_ROUTE\fR
 .ad
 .RS 14n
 Options to be accessed at the routing socket level, not the protocol level.
@@ -484,7 +443,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_DEBUG\fR\fR
+\fBSO_DEBUG\fR
 .ad
 .RS 17n
 Debugging information is being recorded.
@@ -493,7 +452,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_ACCEPTCONN\fR\fR
+\fBSO_ACCEPTCONN\fR
 .ad
 .RS 17n
 Socket is accepting connections.
@@ -502,7 +461,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_BROADCAST\fR\fR
+\fBSO_BROADCAST\fR
 .ad
 .RS 17n
 Transmission of broadcast messages is supported.
@@ -511,7 +470,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_REUSEADDR\fR\fR
+\fBSO_REUSEADDR\fR
 .ad
 .RS 17n
 Reuse of local addresses is supported.
@@ -520,7 +479,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_KEEPALIVE\fR\fR
+\fBSO_KEEPALIVE\fR
 .ad
 .RS 17n
 Connections are kept alive with periodic messages.
@@ -529,7 +488,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_LINGER\fR\fR
+\fBSO_LINGER\fR
 .ad
 .RS 17n
 Socket lingers on close.
@@ -538,7 +497,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_OOBINLINE\fR\fR
+\fBSO_OOBINLINE\fR
 .ad
 .RS 17n
 Out-of-band data is transmitted in line.
@@ -547,7 +506,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_SNDBUF\fR\fR
+\fBSO_SNDBUF\fR
 .ad
 .RS 17n
 Send buffer size.
@@ -556,7 +515,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_RCVBUF\fR\fR
+\fBSO_RCVBUF\fR
 .ad
 .RS 17n
 Receive buffer size.
@@ -565,7 +524,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_ERROR\fR\fR
+\fBSO_ERROR\fR
 .ad
 .RS 17n
 Socket error status.
@@ -574,7 +533,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_TYPE\fR\fR
+\fBSO_TYPE\fR
 .ad
 .RS 17n
 Socket type.
@@ -583,7 +542,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_RECVUCRED\fR\fR
+\fBSO_RECVUCRED\fR
 .ad
 .RS 17n
 Request the reception of user credential ancillary data. This is a
@@ -593,7 +552,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_MAC_EXEMPT\fR\fR
+\fBSO_MAC_EXEMPT\fR
 .ad
 .RS 17n
 Mandatory Access Control (\fBMAC\fR) exemption for unlabeled peers. This option
@@ -603,7 +562,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSO_ALLZONES\fR\fR
+\fBSO_ALLZONES\fR
 .ad
 .RS 17n
 Bypass zone boundaries (privileged).
@@ -618,7 +577,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_CTRUNC\fR\fR
+\fBMSG_CTRUNC\fR
 .ad
 .RS 15n
 Control data truncated.
@@ -627,7 +586,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_EOR\fR\fR
+\fBMSG_EOR\fR
 .ad
 .RS 15n
 Terminates a record (if supported by the protocol).
@@ -636,7 +595,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_OOB\fR\fR
+\fBMSG_OOB\fR
 .ad
 .RS 15n
 Out-of-band data.
@@ -645,7 +604,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_PEEK\fR\fR
+\fBMSG_PEEK\fR
 .ad
 .RS 15n
 Leave received data in queue.
@@ -654,7 +613,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_TRUNC\fR\fR
+\fBMSG_TRUNC\fR
 .ad
 .RS 15n
 Normal data truncated.
@@ -663,7 +622,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_WAITALL\fR\fR
+\fBMSG_WAITALL\fR
 .ad
 .RS 15n
 Wait for complete message.
@@ -672,7 +631,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMSG_NOSIGNAL\fR\fR
+\fBMSG_NOSIGNAL\fR
 .ad
 .RS 15n
 Do not generate \fBSIGPIPE\fR signal.
@@ -684,7 +643,7 @@
 .sp
 .ne 2
 .na
-\fB\fBAF_UNIX\fR\fR
+\fBAF_UNIX\fR
 .ad
 .RS 11n
 UNIX domain sockets
@@ -693,7 +652,7 @@
 .sp
 .ne 2
 .na
-\fB\fBAF_INET\fR\fR
+\fBAF_INET\fR
 .ad
 .RS 11n
 Internet domain sockets
@@ -705,7 +664,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSHUT_RD\fR\fR
+\fBSHUT_RD\fR
 .ad
 .RS 13n
 Disables further receive operations.
@@ -714,7 +673,7 @@
 .sp
 .ne 2
 .na
-\fB\fBSHUT_WR\fR\fR
+\fBSHUT_WR\fR
 .ad
 .RS 13n
 Disables further send operations.
@@ -723,14 +682,13 @@
 .sp
 .ne 2
 .na
-\fB\fBSHUT_RDWR\fR\fR
+\fBSHUT_RDWR\fR
 .ad
 .RS 13n
 Disables further send and receive operations.
 .RE
 
 .SS "\fBlibsocket\fR Interfaces"
-.LP
 The \fB<sys/socket.h>\fR header defines the \fBmsghdr\fR structure for
 \fBlibsocket\fR interfaces that includes the following members:
 .sp
@@ -754,7 +712,6 @@
 which access rights sent along with the message are received. The
 \fImsg_accrightslen\fR specifies the length of the buffer.
 .SH ATTRIBUTES
-.LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
 .sp
 
@@ -769,7 +726,6 @@
 .TE
 
 .SH SEE ALSO
-.LP
 \fBaccept\fR(3SOCKET), \fBaccept\fR(3XNET), \fBbind\fR(3SOCKET),
 \fBbind\fR(3XNET), \fBconnect\fR(3SOCKET), \fBconnect\fR(3XNET),
 \fBgetpeername\fR(3SOCKET), \fBgetpeername\fR(3XNET), \fBgetpeerucred\fR(3C),
--- a/usr/src/man/man7p/ip.7p	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/man/man7p/ip.7p	Fri Oct 02 11:46:54 2020 +0000
@@ -1,14 +1,14 @@
 '\" te
+.\" Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
 .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved.
 .\" Copyright 2008 AT&T
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH IP 7P "Dec 3, 2008"
+.TH IP 7P "Sep 18, 2020"
 .SH NAME
 ip, IP \- Internet Protocol
 .SH SYNOPSIS
-.LP
 .nf
 \fB#include <sys/socket.h>\fR
 .fi
@@ -29,8 +29,6 @@
 .fi
 
 .SH DESCRIPTION
-.sp
-.LP
 IP is the internetwork datagram delivery protocol that is central to the
 Internet protocol family. Programs may use \fBIP\fR through higher-level
 protocols such as the Transmission Control Protocol (TCP) or the User Datagram
@@ -43,8 +41,6 @@
 Packets sent to or from this system may be subject to IPsec policy. See
 \fBipsec\fR(7P) for more information.
 .SH APPLICATION PROGRAMMING INTERFACE
-.sp
-.LP
 The STREAMS driver \fB/dev/rawip\fR is the TLI transport provider that provides
 raw access to IP.
 .sp
@@ -79,7 +75,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_OPTIONS\fR\fR
+\fBIP_OPTIONS\fR
 .ad
 .RS 22n
 IP options for outgoing datagrams. This socket option may be used to set IP
@@ -99,7 +95,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_SEC_OPT\fR\fR
+\fBIP_SEC_OPT\fR
 .ad
 .RS 22n
 Enable or obtain IPsec security settings for this socket. For more details on
@@ -109,7 +105,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_ADD_MEMBERSHIP\fR\fR
+\fBIP_ADD_MEMBERSHIP\fR
 .ad
 .RS 22n
 Join a multicast group.
@@ -118,7 +114,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_DROP_MEMBERSHIP\fR\fR
+\fBIP_DROP_MEMBERSHIP\fR
 .ad
 .RS 22n
 Leave a multicast group.
@@ -127,7 +123,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_BOUND_IF\fR\fR
+\fBIP_BOUND_IF\fR
 .ad
 .RS 22n
 Limit  reception and transmission of packets to this interface. Takes an
@@ -136,11 +132,11 @@
 
 .sp
 .LP
-The following options take \fBin_pktinfo_t\fR as the parameter:
+The following option takes \fBin_pktinfo_t\fR as the parameter:
 .sp
 .ne 2
 .na
-\fB\fBIP_PKTINFO\fR\fR
+\fBIP_PKTINFO\fR
 .ad
 .sp .6
 .RS 4n
@@ -164,16 +160,88 @@
 .RE
 
 .sp
+.LP
+The following options are boolean switches controlling the reception of
+ancillary data. The option value is type \fBint\fR; a non-zero value
+enables the option whilst a zero value disables it.
+
+.sp
+.ne 2
+.na
+\fBIP_RECVDSTADDR\fR
+.ad
+.RS 22n
+When enabled on a SOCK_DGRAM socket, enables receipt of the destination
+IP address of the incoming packet. Returns \fBinaddr_t\fR as ancillary
+data.
+.RE
+
+.sp
+.ne 2
+.na
+\fBIP_RECVIF\fR
+.ad
+.RS 22n
+Enable/disable receipt of the inbound interface index. Returns \fBuint_t\fR as
+ancillary data.
+.RE
+
+.sp
+.ne 2
+.na
+\fBIP_RECVOPTS\fR
+.ad
+.RS 22n
+When enabled on a SOCK_DGRAM socket, enables receipt of the IP options
+from the incoming packet. Returns variable-length IP options, up to 40
+bytes, as ancillary data.
+.RE
+
+.sp
 .ne 2
 .na
-\fB\fBIP_RECVPKTINFO\fR\fR
+\fBIP_RECVPKTINFO\fR
 .ad
-.sp .6
-.RS 4n
+.RS 22n
 Enable/disable receipt of the index of the interface the packet arrived on, the
 local address that was matched for reception, and the inbound packet's actual
-destination address. Takes boolean as the parameter.  Returns struct
-in_pktinfo_t as ancillary data.
+destination address. Takes boolean as the parameter.  Returns
+\fBin_pktinfo_t\fR as ancillary data.
+.RE
+
+.sp
+.ne 2
+.na
+\fBIP_RECVSLLA\fR
+.ad
+.RS 22n
+When enabled on a SOCK_DGRAM socket, enables receipt of the source link-layer
+address for the incoming packet. Returns \fBstruct sockaddr_dl\fR as
+ancillary data.
+.RE
+
+.sp
+.ne 2
+.na
+\fBIP_RECVTTL\fR
+.ad
+.RS 22n
+When enabled on a SOCK_DGRAM socket, the IP TTL (time to live) field for an
+incoming datagram is returned as \fBuint8_t\fR in ancillary data.
+.RE
+
+.sp
+.ne 2
+.na
+\fBIP_RECVTOS\fR
+.ad
+.RS 22n
+When enabled, the IP TOS (type of service) field is returned as \fBuint8_t\fR
+in ancillary data. For \fBSOCK_DGRAM\fR sockets, the ancillary data item is
+included for every call to \fBrecvmsg()\fR. For \fBSOCK_STREAM\fR sockets,
+where there is no direct mapping between received TCP segments and receive
+operations, the ancillary data item will only be present when this option
+is first enabled, and subsequently only if the value changes.
 .RE
 
 .sp
@@ -186,7 +254,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_BLOCK_SOURCE\fR\fR
+\fBIP_BLOCK_SOURCE\fR
 .ad
 .RS 29n
 Block multicast packets whose source address matches the given source address.
@@ -197,7 +265,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_UNBLOCK_SOURCE\fR\fR
+\fBIP_UNBLOCK_SOURCE\fR
 .ad
 .RS 29n
 Unblock (begin receiving) multicast packets which were previously blocked using
@@ -207,7 +275,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_ADD_SOURCE_MEMBERSHIP\fR\fR
+\fBIP_ADD_SOURCE_MEMBERSHIP\fR
 .ad
 .RS 29n
 Begin receiving packets for the given multicast group whose source address
@@ -217,7 +285,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_DROP_SOURCE_MEMBERSHIP\fR\fR
+\fBIP_DROP_SOURCE_MEMBERSHIP\fR
 .ad
 .RS 29n
 Stop receiving packets for the given multicast group whose source address
@@ -232,7 +300,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMCAST_JOIN_GROUP\fR\fR
+\fBMCAST_JOIN_GROUP\fR
 .ad
 .RS 28n
 Join a multicast group. Functionally equivalent to IP_ADD_MEMBERSHIP.
@@ -241,7 +309,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMCAST_BLOCK_SOURCE\fR\fR
+\fBMCAST_BLOCK_SOURCE\fR
 .ad
 .RS 28n
 Block multicast packets whose source address matches the given source address.
@@ -252,7 +320,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMCAST_UNBLOCK_SOURCE\fR\fR
+\fBMCAST_UNBLOCK_SOURCE\fR
 .ad
 .RS 28n
 Unblock (begin receiving) multicast packets which were previously blocked using
@@ -262,7 +330,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMCAST_LEAVE_GROUP\fR\fR
+\fBMCAST_LEAVE_GROUP\fR
 .ad
 .RS 28n
 Leave a multicast group. Functionally equivalent to IP_DROP_MEMBERSHIP.
@@ -271,7 +339,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMCAST_JOIN_SOURCE_GROUP\fR\fR
+\fBMCAST_JOIN_SOURCE_GROUP\fR
 .ad
 .RS 28n
 Begin receiving packets for the given multicast group whose source address
@@ -281,7 +349,7 @@
 .sp
 .ne 2
 .na
-\fB\fBMCAST_LEAVE_SOURCE_GROUP\fR\fR
+\fBMCAST_LEAVE_SOURCE_GROUP\fR
 .ad
 .RS 28n
 Stop receiving packets for the given multicast group whose source address
@@ -299,7 +367,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_MULTICAST_IF\fR\fR
+\fBIP_MULTICAST_IF\fR
 .ad
 .RS 21n
 The outgoing interface for multicast packets. This option takes a \fBstruct\fR
@@ -312,7 +380,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_MULTICAST_TTL\fR\fR
+\fBIP_MULTICAST_TTL\fR
 .ad
 .RS 21n
 Time to live for multicast datagrams. This option takes an unsigned character
@@ -323,7 +391,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_MULTICAST_LOOP\fR\fR
+\fBIP_MULTICAST_LOOP\fR
 .ad
 .RS 21n
 Loopback for multicast  datagrams. Normally multicast  datagrams are delivered
@@ -336,16 +404,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_RECVIF\fR\fR
-.ad
-.RS 21n
-Receive the inbound interface index.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBIP_TOS\fR\fR
+\fBIP_TOS\fR
 .ad
 .RS 21n
 This option takes an integer argument as its input value. The least significant
@@ -356,7 +415,7 @@
 .sp
 .ne 2
 .na
-\fB\fBIP_NEXTHOP\fR\fR
+\fBIP_NEXTHOP\fR
 .ad
 .RS 21n
 This option specifies the address of the onlink nexthop for traffic originating
@@ -474,8 +533,6 @@
 will only initiate Multi-Data Transmit if the network interface driver supports
 it.
 .SH PACKET EVENTS
-.sp
-.LP
 Through the netinfo framework, this driver provides the following packet
 events:
 .sp
@@ -585,8 +642,6 @@
 .RE
 
 .SH NETWORK INTERFACE EVENTS
-.sp
-.LP
 In addition to events describing packets as they move through the system, it is
 also possible to receive notification of events relating to network interfaces.
 These events are all reported back through the same callback. The list of
@@ -637,14 +692,13 @@
 .RE
 
 .SH SEE ALSO
-.sp
-.LP
 \fBifconfig\fR(1M), \fBrouteadm\fR(1M), \fBndd\fR(1M), \fBread\fR(2),
-\fBwrite\fR(2), \fBbind\fR(3SOCKET), \fBconnect\fR(3SOCKET),
-\fBgetsockopt\fR(3SOCKET), \fBrecv\fR(3SOCKET), \fBsend\fR(3SOCKET),
-\fBdefaultrouter\fR(4), \fBicmp\fR(7P), \fBif_tcp\fR(7P), \fBinet\fR(7P),
-\fBip6\fR(7P), \fBipsec\fR(7P), \fBrouting\fR(7P), \fBtcp\fR(7P),
-\fBudp\fR(7P), \fBnet_hook_register\fR(9F), \fBhook_pkt_event\fR(9S)
+\fBwrite\fR(2), \fBsocket.h\fR(3HEAD), \fBbind\fR(3SOCKET),
+\fBconnect\fR(3SOCKET), \fBgetsockopt\fR(3SOCKET), \fBrecv\fR(3SOCKET),
+\fBsend\fR(3SOCKET), \fBsetsockopt\fR(3SOCKET), \fBdefaultrouter\fR(4),
+\fBicmp\fR(7P), \fBif_tcp\fR(7P), \fBinet\fR(7P), \fBip\fR(7P), \fBip6\fR(7P),
+\fBipsec\fR(7P), \fBrouting\fR(7P), \fBtcp\fR(7P), \fBudp\fR(7P),
+\fBnet_hook_register\fR(9F), \fBhook_pkt_event\fR(9S)
 .sp
 .LP
 Braden, R., \fIRFC 1122, Requirements for Internet Hosts \(mi Communication
@@ -656,13 +710,11 @@
 Specification\fR, Information Sciences Institute, University of Southern
 California, September 1981.
 .SH DIAGNOSTICS
-.sp
-.LP
 A socket operation may fail with one of the following errors returned:
 .sp
 .ne 2
 .na
-\fB\fBEACCES\fR\fR
+\fBEACCES\fR
 .ad
 .RS 17n
 A \fBbind()\fR operation was attempted with a "reserved" port number and the
@@ -675,7 +727,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEADDRINUSE\fR\fR
+\fBEADDRINUSE\fR
 .ad
 .RS 17n
 A \fBbind()\fR operation was attempted on a socket with a network address/port
@@ -685,7 +737,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEADDRNOTAVAIL\fR\fR
+\fBEADDRNOTAVAIL\fR
 .ad
 .RS 17n
 A \fBbind()\fR operation was attempted for an address that is not configured on
@@ -695,7 +747,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEINVAL\fR\fR
+\fBEINVAL\fR
 .ad
 .RS 17n
 A \fBsendmsg()\fR operation with a non-NULL \fBmsg_accrights\fR was attempted.
@@ -704,7 +756,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEINVAL\fR\fR
+\fBEINVAL\fR
 .ad
 .RS 17n
 A \fBgetsockopt()\fR or \fBsetsockopt()\fR operation with an unknown socket
@@ -714,7 +766,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEINVAL\fR\fR
+\fBEINVAL\fR
 .ad
 .RS 17n
 A \fBgetsockopt()\fR or \fBsetsockopt()\fR operation was attempted with the
@@ -725,7 +777,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEISCONN\fR\fR
+\fBEISCONN\fR
 .ad
 .RS 17n
 A \fBconnect()\fR operation was attempted on a socket on which a
@@ -736,7 +788,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEISCONN\fR\fR
+\fBEISCONN\fR
 .ad
 .RS 17n
 A \fBsendto()\fR or \fBsendmsg()\fR operation specifying an address to which
@@ -747,7 +799,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEMSGSIZE\fR\fR
+\fBEMSGSIZE\fR
 .ad
 .RS 17n
 A \fBsend()\fR, \fBsendto()\fR, or \fBsendmsg()\fR operation was attempted to
@@ -758,7 +810,7 @@
 .sp
 .ne 2
 .na
-\fB\fBENETUNREACH\fR\fR
+\fBENETUNREACH\fR
 .ad
 .RS 17n
 An attempt was made to establish a connection by means of \fBconnect()\fR, or
@@ -770,7 +822,7 @@
 .sp
 .ne 2
 .na
-\fB\fBENOTCONN\fR\fR
+\fBENOTCONN\fR
 .ad
 .RS 17n
 A \fBsend()\fR or \fBwrite()\fR operation, or a \fBsendto()\fR or
@@ -782,7 +834,7 @@
 .sp
 .ne 2
 .na
-\fB\fBENOBUFS\fR\fR
+\fBENOBUFS\fR
 .ad
 .RS 17n
 The system ran out of memory for fragmentation buffers or other internal data
@@ -792,7 +844,7 @@
 .sp
 .ne 2
 .na
-\fB\fBENOBUFS\fR\fR
+\fBENOBUFS\fR
 .ad
 .RS 17n
 \fBSO_SNDBUF\fR or \fBSO_RCVBUF\fR exceeds a system limit.
@@ -801,7 +853,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEINVAL\fR\fR
+\fBEINVAL\fR
 .ad
 .RS 17n
 Invalid length for \fBIP_OPTIONS\fR.
@@ -810,7 +862,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEHOSTUNREACH\fR\fR
+\fBEHOSTUNREACH\fR
 .ad
 .RS 17n
 Invalid address for \fBIP_MULTICAST_IF\fR.
@@ -821,7 +873,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEINVAL\fR\fR
+\fBEINVAL\fR
 .ad
 .RS 17n
 Not a multicast address for \fBIP_ADD_MEMBERSHIP\fR and
@@ -831,7 +883,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEADDRNOTAVAIL\fR\fR
+\fBEADDRNOTAVAIL\fR
 .ad
 .RS 17n
 Bad interface address for \fBIP_ADD_MEMBERSHIP\fR and \fBIP_DROP_MEMBERSHIP\fR.
@@ -840,7 +892,7 @@
 .sp
 .ne 2
 .na
-\fB\fBEADDRINUSE\fR\fR
+\fBEADDRINUSE\fR
 .ad
 .RS 17n
 Address already joined for \fBIP_ADD_MEMBERSHIP\fR.
@@ -849,7 +901,7 @@
 .sp
 .ne 2
 .na
-\fB\fBENOENT\fR\fR
+\fBENOENT\fR
 .ad
 .RS 17n
 Address not joined for \fBIP_DROP_MEMBERSHIP\fR.
@@ -858,7 +910,7 @@
 .sp
 .ne 2
 .na
-\fB\fBENOPROTOOPT\fR\fR
+\fBENOPROTOOPT\fR
 .ad
 .RS 17n
 Invalid socket type.
@@ -867,15 +919,13 @@
 .sp
 .ne 2
 .na
-\fB\fBEPERM\fR\fR
+\fBEPERM\fR
 .ad
 .RS 17n
 No permissions.
 .RE
 
 .SH NOTES
-.sp
-.LP
 Raw sockets should receive \fBICMP\fR error packets relating to the protocol;
 currently such packets are simply discarded.
 .sp
--- a/usr/src/pkg/manifests/system-header.mf	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/pkg/manifests/system-header.mf	Fri Oct 02 11:46:54 2020 +0000
@@ -2011,6 +2011,11 @@
     target=../sun4u/include
 $(sparc_ONLY)link path=usr/platform/SUNW,Ultra-Enterprise/include \
     target=../sun4u/include
+link path=usr/share/man/man3head/CMSG_DATA.3head target=socket.h.3head
+link path=usr/share/man/man3head/CMSG_FIRSTHDR.3head target=socket.h.3head
+link path=usr/share/man/man3head/CMSG_LEN.3head target=socket.h.3head
+link path=usr/share/man/man3head/CMSG_NXTHDR.3head target=socket.h.3head
+link path=usr/share/man/man3head/CMSG_SPACE.3head target=socket.h.3head
 link path=usr/share/man/man3head/LIST_CLASS_ENTRY.3head target=queue.h.3head
 link path=usr/share/man/man3head/LIST_CLASS_HEAD.3head target=queue.h.3head
 link path=usr/share/man/man3head/LIST_CONCAT.3head target=queue.h.3head
--- a/usr/src/pkg/manifests/system-test-ostest.mf	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/pkg/manifests/system-test-ostest.mf	Fri Oct 02 11:46:54 2020 +0000
@@ -108,6 +108,8 @@
 file path=opt/os-tests/tests/sockfs/dgram mode=0555
 file path=opt/os-tests/tests/sockfs/drop_priv mode=0555
 file path=opt/os-tests/tests/sockfs/nosignal mode=0555
+file path=opt/os-tests/tests/sockfs/recvmsg.32 mode=0555
+file path=opt/os-tests/tests/sockfs/recvmsg.64 mode=0555
 file path=opt/os-tests/tests/sockfs/rights.32 mode=0555
 file path=opt/os-tests/tests/sockfs/rights.64 mode=0555
 file path=opt/os-tests/tests/sockfs/sockpair mode=0555
--- a/usr/src/test/os-tests/runfiles/default.run	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/test/os-tests/runfiles/default.run	Fri Oct 02 11:46:54 2020 +0000
@@ -74,7 +74,7 @@
 [/opt/os-tests/tests/sockfs]
 user = root
 tests = ['conn', 'dgram', 'drop_priv', 'nosignal', 'rights.32', 'rights.64',
-         'sockpair']
+         'sockpair', 'recvmsg.32', 'recvmsg.64']
 
 [/opt/os-tests/tests/syscall]
 tests = ['open.32', 'open.64']
--- a/usr/src/test/os-tests/tests/sockfs/Makefile	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/test/os-tests/tests/sockfs/Makefile	Fri Oct 02 11:46:54 2020 +0000
@@ -19,8 +19,11 @@
 include $(SRC)/cmd/Makefile.cmd
 include $(SRC)/test/Makefile.com
 
+# These test programs are built as both 32- and 64-bit variants
+PROGDA = rights recvmsg
+
 PROG =	conn dgram drop_priv nosignal sockpair \
-	rights.32 rights.64
+	$(PROGDA:%=%.32) $(PROGDA:%=%.64)
 
 LDLIBS += -lsocket
 LDLIBS64 += -lsocket
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/test/os-tests/tests/sockfs/recvmsg.c	Fri Oct 02 11:46:54 2020 +0000
@@ -0,0 +1,539 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
+ */
+
+/*
+ * Test ancillary data receipt via recvmsg()
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <err.h>
+
+static boolean_t debug;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t cmutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t ccv = PTHREAD_COND_INITIALIZER;
+static boolean_t server_ready = _B_FALSE;
+static boolean_t client_done = _B_FALSE;
+
+static in_addr_t testip;
+
+#define	DEBUG(x) if (debug) printf x
+
+#define	TESTPORT	32123
+
+#define	RT_RECVTOS	0x1
+#define	RT_RECVTTL	0x2
+#define	RT_RECVPKTINFO	0x4
+#define	RT_RECVMASK	0x7
+
+#define	RT_SETTOS	0x10
+#define	RT_SETTTL	0x20
+#define	RT_STREAM	0x40
+#define	RT_SKIP		0x80
+
+typedef struct recvmsg_test {
+	char *name;		/* Name of the test */
+	uint8_t tos;		/* TOS to set */
+	uint8_t ttl;		/* TTL to set */
+	uint8_t flags;		/* Test flags, RT_ */
+} recvmsg_test_t;
+
+static recvmsg_test_t tests[] = {
+	{
+		.name = "baseline",
+		.flags = 0,
+	},
+
+	/* Combinations of receive flags */
+	{
+		.name = "recv TOS",
+		.flags = RT_RECVTOS,
+	},
+
+	{
+		.name = "recv TTL",
+		.flags = RT_RECVTTL,
+	},
+
+	{
+		.name = "recv PKTINFO",
+		.flags = RT_RECVPKTINFO,
+	},
+
+	{
+		.name = "recv TOS,TTL",
+		.flags = RT_RECVTOS | RT_RECVTTL,
+	},
+
+	{
+		.name = "recv TTL,PKTINFO",
+		.flags = RT_RECVTTL | RT_RECVPKTINFO,
+	},
+
+	{
+		.name = "recv TOS,PKTINFO",
+		.flags = RT_RECVTOS | RT_RECVPKTINFO,
+	},
+
+	{
+		.name = "recv TOS,TTL,PKTINFO",
+		.flags = RT_RECVTOS | RT_RECVTTL | RT_RECVPKTINFO,
+	},
+
+	/* Manually set TTL and TOS */
+
+	{
+		.name = "set TOS,TTL",
+		.flags = RT_SETTOS | RT_SETTTL,
+		.ttl = 11,
+		.tos = 0xe0
+	},
+
+	{
+		.name = "set/recv TOS,TTL",
+		.flags = RT_SETTOS | RT_SETTTL | RT_RECVTOS | RT_RECVTTL,
+		.ttl = 32,
+		.tos = 0x48
+	},
+
+	{
+		.name = "set TOS,TTL, recv PKTINFO",
+		.flags = RT_SETTOS | RT_SETTTL | RT_RECVPKTINFO,
+		.ttl = 173,
+		.tos = 0x78
+	},
+
+	{
+		.name = "set TOS,TTL, recv TOS,TTL,PKTINFO",
+		.flags = RT_SETTOS | RT_SETTTL | RT_RECVTOS | RT_RECVTTL |
+		    RT_RECVPKTINFO,
+		.ttl = 54,
+		.tos = 0x90
+	},
+
+	/* STREAM socket */
+
+	{
+		.name = "STREAM set TOS",
+		.flags = RT_STREAM | RT_SETTOS,
+		.tos = 0xe0
+	},
+
+	/*
+	 * The ancillary data are not returned for the loopback TCP path,
+	 * so these tests are skipped by default.
+	 * To run them, use two different zones (or machines) and run:
+	 *	recvmsg.64 -s 'test name'
+	 * on the first, and:
+	 *	recvmsg.64 -c <first machine IP> 'test name'
+	 * on the second.
+	 */
+	{
+		.name = "STREAM recv TOS",
+		.flags = RT_STREAM | RT_RECVTOS | RT_SKIP,
+	},
+
+	{
+		.name = "STREAM set/recv TOS",
+		.flags = RT_STREAM | RT_SETTOS | RT_RECVTOS | RT_SKIP,
+		.tos = 0x48
+	},
+
+	/* End of tests */
+
+	{
+		.name = NULL
+	}
+};
+
+static boolean_t
+servertest(recvmsg_test_t *t)
+{
+	struct sockaddr_in addr;
+	boolean_t pass = _B_TRUE;
+	int sockfd, readfd, acceptfd = -1, c = 1;
+
+	DEBUG(("\nserver %s: starting\n", t->name));
+
+	sockfd = socket(AF_INET,
+	    t->flags & RT_STREAM ? SOCK_STREAM : SOCK_DGRAM, 0);
+	if (sockfd == -1)
+		err(EXIT_FAILURE, "failed to create server socket");
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = INADDR_ANY;
+	addr.sin_port = htons(TESTPORT);
+
+	if (bind(sockfd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
+		err(EXIT_FAILURE, "server socket bind failed");
+
+	if (t->flags & RT_RECVTOS) {
+		DEBUG((" : setting RECVTOS\n"));
+		if (setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, &c,
+		    sizeof (c)) == -1) {
+			printf("[FAIL] %s - "
+			    "couldn't set TOS on server socket: %s\n",
+			    t->name, strerror(errno));
+			pass = _B_FALSE;
+		}
+	}
+
+	if (t->flags & RT_RECVTTL) {
+		DEBUG((" : setting RECVTTL\n"));
+		if (setsockopt(sockfd, IPPROTO_IP, IP_RECVTTL, &c,
+		    sizeof (c)) == -1) {
+			printf("[FAIL] %s - "
+			    "couldn't set TTL on server socket: %s\n",
+			    t->name, strerror(errno));
+			pass = _B_FALSE;
+		}
+	}
+
+	if (t->flags & RT_RECVPKTINFO) {
+		DEBUG((" : setting RECVPKTINFO\n"));
+		if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &c,
+		    sizeof (c)) == -1) {
+			printf("[FAIL] %s - "
+			    "couldn't set PKTINFO on server socket: %s\n",
+			    t->name, strerror(errno));
+			pass = _B_FALSE;
+		}
+	}
+
+	if (t->flags & RT_STREAM) {
+		if (listen(sockfd, 1) == -1)
+			err(EXIT_FAILURE, "Could not listen on sever socket");
+	}
+
+	/* Signal the client that the server is ready for the next test */
+	if (debug)
+		printf(" : signalling client\n");
+	(void) pthread_mutex_lock(&mutex);
+	server_ready = _B_TRUE;
+	(void) pthread_cond_signal(&cv);
+	(void) pthread_mutex_unlock(&mutex);
+
+	if (t->flags & RT_STREAM) {
+		struct sockaddr_in caddr;
+		socklen_t sl = sizeof (caddr);
+
+		if ((acceptfd = accept(sockfd, (struct sockaddr *)&caddr,
+		    &sl)) == -1) {
+			err(EXIT_FAILURE, "socket accept failed");
+		}
+		readfd = acceptfd;
+	} else {
+		readfd = sockfd;
+	}
+
+	/* Receive the datagram */
+
+	struct msghdr msg;
+	char buf[0x100];
+	char cbuf[CMSG_SPACE(0x400)];
+	struct iovec iov[1] = {0};
+	ssize_t r;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = sizeof (buf);
+
+	bzero(&msg, sizeof (msg));
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof (cbuf);
+
+	DEBUG((" : waiting for message\n"));
+
+	r = recvmsg(readfd, &msg, 0);
+	if (r <= 0) {
+		printf("[FAIL] %s - recvmsg returned %d (%s)\n",
+		    t->name, r, strerror(errno));
+		pass = _B_FALSE;
+		goto out;
+	}
+
+	DEBUG((" : recvmsg returned %d (flags=0x%x, controllen=%d)\n",
+	    r, msg.msg_flags, msg.msg_controllen));
+
+	if (r != strlen(t->name)) {
+		printf("[FAIL] %s - got '%.*s' (%d bytes), expected '%s'\n",
+		    t->name, r, buf, r, t->name);
+		pass = _B_FALSE;
+	}
+
+	DEBUG((" : Received '%.*s'\n", r, buf));
+
+	if (msg.msg_flags != 0) {
+		printf("[FAIL] %s - received flags 0x%x\n",
+		    t->name, msg.msg_flags);
+		pass = _B_FALSE;
+	}
+
+	uint8_t flags = 0;
+
+	for (struct cmsghdr *cm = CMSG_FIRSTHDR(&msg); cm != NULL;
+	    cm = CMSG_NXTHDR(&msg, cm)) {
+		uint8_t d;
+
+		DEBUG((" : >> Got cmsg %x/%x - length %u\n",
+		    cm->cmsg_level, cm->cmsg_type, cm->cmsg_len));
+
+		if (cm->cmsg_level != IPPROTO_IP)
+			continue;
+
+		switch (cm->cmsg_type) {
+		case IP_PKTINFO:
+			flags |= RT_RECVPKTINFO;
+			if (debug) {
+				struct in_pktinfo *pi =
+				    (struct in_pktinfo *)CMSG_DATA(cm);
+				printf(" : ifIndex: %u\n", pi->ipi_ifindex);
+			}
+			break;
+		case IP_RECVTTL:
+			if (cm->cmsg_len != CMSG_LEN(sizeof (uint8_t))) {
+				printf(
+				    "[FAIL] %s - cmsg_len was %u expected %u\n",
+				    t->name, cm->cmsg_len,
+				    CMSG_LEN(sizeof (uint8_t)));
+				pass = _B_FALSE;
+				break;
+			}
+			flags |= RT_RECVTTL;
+			memcpy(&d, CMSG_DATA(cm), sizeof (d));
+			DEBUG((" : RECVTTL = %u\n", d));
+			if (t->flags & RT_SETTTL && d != t->ttl) {
+				printf("[FAIL] %s - TTL was %u, expected %u\n",
+				    t->name, d, t->ttl);
+				pass = _B_FALSE;
+			}
+			break;
+		case IP_RECVTOS:
+			if (cm->cmsg_len != CMSG_LEN(sizeof (uint8_t))) {
+				printf(
+				    "[FAIL] %s - cmsg_len was %u expected %u\n",
+				    t->name, cm->cmsg_len,
+				    CMSG_LEN(sizeof (uint8_t)));
+				pass = _B_FALSE;
+				break;
+			}
+			flags |= RT_RECVTOS;
+			memcpy(&d, CMSG_DATA(cm), sizeof (d));
+			DEBUG((" : RECVTOS = %u\n", d));
+			if (t->flags & RT_SETTOS && d != t->tos) {
+				printf("[FAIL] %s - TOS was %u, expected %u\n",
+				    t->name, d, t->tos);
+				pass = _B_FALSE;
+			}
+			break;
+		}
+	}
+
+	if ((t->flags & RT_RECVMASK) != flags) {
+		printf("[FAIL] %s - Did not receive everything expected, "
+		    "flags %#x vs. %#x\n", t->name,
+		    flags, t->flags & RT_RECVMASK);
+		pass = _B_FALSE;
+	}
+
+	/* Wait for the client to finish */
+	(void) pthread_mutex_lock(&cmutex);
+	while (!client_done)
+		(void) pthread_cond_wait(&ccv, &cmutex);
+	client_done = _B_FALSE;
+	(void) pthread_mutex_unlock(&cmutex);
+
+out:
+	if (acceptfd != -1)
+		(void) close(acceptfd);
+	(void) close(sockfd);
+
+	if (pass)
+		printf("[PASS] %s\n", t->name);
+
+	return (pass);
+}
+
+static int
+server(const char *test)
+{
+	int ret = EXIT_SUCCESS;
+	recvmsg_test_t *t;
+
+	for (t = tests; t->name != NULL; t++) {
+		if (test != NULL) {
+			if (strcmp(test, t->name) != 0)
+				continue;
+			client_done = _B_TRUE;
+			return (servertest(t));
+		}
+		if (t->flags & RT_SKIP) {
+			printf("[SKIP] %s - (requires two separate zones)\n",
+			    t->name);
+			continue;
+		}
+		if (!servertest(t))
+			ret = EXIT_FAILURE;
+	}
+
+	return (ret);
+}
+
+static void
+clienttest(recvmsg_test_t *t)
+{
+	struct sockaddr_in addr;
+	int s, ret;
+
+	DEBUG(("client %s: starting\n", t->name));
+
+	s = socket(AF_INET, t->flags & RT_STREAM ? SOCK_STREAM : SOCK_DGRAM, 0);
+	if (s == -1)
+		err(EXIT_FAILURE, "failed to create client socket");
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = testip;
+	addr.sin_port = htons(TESTPORT);
+
+	if (t->flags & RT_STREAM) {
+		if (connect(s, (struct sockaddr *)&addr, sizeof (addr)) == -1)
+			err(EXIT_FAILURE, "failed to connect to server");
+	}
+
+	if (t->flags & RT_SETTOS) {
+		int c = t->tos;
+
+		DEBUG(("client %s: setting TOS = 0x%x\n", t->name, c));
+		if (setsockopt(s, IPPROTO_IP, IP_TOS, &c, sizeof (c)) == -1)
+			err(EXIT_FAILURE, "could not set TOS on client socket");
+	}
+
+	if (t->flags & RT_SETTTL) {
+		int c = t->ttl;
+
+		DEBUG(("client %s: setting TTL = 0x%x\n", t->name, c));
+		if (setsockopt(s, IPPROTO_IP, IP_TTL, &c, sizeof (c)) == -1)
+			err(EXIT_FAILURE, "could not set TTL on client socket");
+	}
+
+	DEBUG(("client %s: sending\n", t->name));
+
+	if (t->flags & RT_STREAM) {
+		ret = send(s, t->name, strlen(t->name), 0);
+		shutdown(s, SHUT_RDWR);
+	} else {
+		ret = sendto(s, t->name, strlen(t->name), 0,
+		    (struct sockaddr *)&addr, sizeof (addr));
+	}
+
+	if (ret == -1)
+		err(EXIT_FAILURE, "sendto failed to send data to server");
+
+	DEBUG(("client %s: done\n", t->name));
+
+	close(s);
+}
+
+static void *
+client(void *arg)
+{
+	char *test = (char *)arg;
+	recvmsg_test_t *t;
+
+	for (t = tests; t->name != NULL; t++) {
+		if (test != NULL) {
+			if (strcmp(test, t->name) != 0)
+				continue;
+			clienttest(t);
+			return (NULL);
+		}
+		if (t->flags & RT_SKIP)
+			continue;
+		/* Wait for the server to be ready to receive */
+		(void) pthread_mutex_lock(&mutex);
+		while (!server_ready)
+			(void) pthread_cond_wait(&cv, &mutex);
+		server_ready = _B_FALSE;
+		(void) pthread_mutex_unlock(&mutex);
+		clienttest(t);
+		/* Tell the server we are done */
+		(void) pthread_mutex_lock(&cmutex);
+		client_done = _B_TRUE;
+		(void) pthread_cond_signal(&ccv);
+		(void) pthread_mutex_unlock(&cmutex);
+	}
+
+	return (NULL);
+}
+
+int
+main(int argc, const char **argv)
+{
+	int ret = EXIT_SUCCESS;
+	pthread_t cthread;
+
+	if (argc > 1 && strcmp(argv[1], "-d") == 0) {
+		debug = _B_TRUE;
+		argc--, argv++;
+	}
+
+	/* -c <server IP> <test name> */
+	if (argc == 4 && strcmp(argv[1], "-c") == 0) {
+		testip = inet_addr(argv[2]);
+		printf("TEST IP: %s\n", argv[2]);
+		if (testip == INADDR_NONE) {
+			err(EXIT_FAILURE,
+			    "Could not parse destination IP address");
+		}
+		client((void *)argv[3]);
+		return (ret);
+	}
+
+	/* -s <test name> */
+	if (argc == 3 && strcmp(argv[1], "-s") == 0)
+		return (server(argv[2]));
+
+	testip = inet_addr("127.0.0.1");
+	if (testip == INADDR_NONE)
+		err(EXIT_FAILURE, "Could not parse destination IP address");
+
+	if (pthread_create(&cthread, NULL, client, NULL) == -1)
+		err(EXIT_FAILURE, "Could not create client thread");
+
+	ret = server(NULL);
+
+	if (pthread_join(cthread, NULL) != 0)
+		err(EXIT_FAILURE, "join client thread failed");
+
+	return (ret);
+}
--- a/usr/src/uts/common/fs/sockfs/socksubr.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/fs/sockfs/socksubr.c	Fri Oct 02 11:46:54 2020 +0000
@@ -1321,8 +1321,24 @@
 
 			cmsg->cmsg_level = tohp->level;
 			cmsg->cmsg_type = tohp->name;
-			cmsg->cmsg_len = (socklen_t)(_TPI_TOPT_DATALEN(tohp) +
-			    sizeof (struct cmsghdr));
+			cmsg->cmsg_len = (socklen_t)sizeof (struct cmsghdr);
+			if (tohp->level == IPPROTO_IP &&
+			    (tohp->name == IP_RECVTOS ||
+			    tohp->name == IP_RECVTTL)) {
+				/*
+				 * The data for these is a uint8_t but, in
+				 * order to maintain alignment for any
+				 * following TPI primitives in the message,
+				 * there will be some trailing padding bytes
+				 * which are included in the TPI_TOPT_DATALEN.
+				 * For these types, we set the cmsg_len
+				 * explicitly to the correct value.
+				 */
+				cmsg->cmsg_len += (socklen_t)sizeof (uint8_t);
+			} else {
+				cmsg->cmsg_len +=
+				    (socklen_t)(_TPI_TOPT_DATALEN(tohp));
+			}
 
 			/* copy content to control data part */
 			bcopy(&tohp[1], CMSG_CONTENT(cmsg),
--- a/usr/src/uts/common/inet/ip/conn_opt.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/ip/conn_opt.c	Fri Oct 02 11:46:54 2020 +0000
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2016 Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
@@ -236,11 +237,22 @@
 	}
 
 	/*
+	 * If IP_RECVTOS is set allocate the appropriately sized buffer
+	 */
+	if (recv_ancillary.crb_recvtos &&
+	    (ira->ira_flags & IRAF_IS_IPV4)) {
+		ancil_size += sizeof (struct T_opthdr) +
+		    P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
+		IP_STAT(ipst, conn_in_recvtos);
+	}
+
+	/*
 	 * If IP_RECVTTL is set allocate the appropriate sized buffer
 	 */
 	if (recv_ancillary.crb_recvttl &&
 	    (ira->ira_flags & IRAF_IS_IPV4)) {
-		ancil_size += sizeof (struct T_opthdr) + sizeof (uint8_t);
+		ancil_size += sizeof (struct T_opthdr) +
+		    P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
 		IP_STAT(ipst, conn_in_recvttl);
 	}
 
@@ -550,14 +562,25 @@
 		ancil_size -= toh->len;
 	}
 
-	/*
-	 * CAUTION:
-	 * Due to aligment issues
-	 * Processing of IP_RECVTTL option
-	 * should always be the last. Adding
-	 * any option processing after this will
-	 * cause alignment panic.
-	 */
+	if (recv_ancillary.crb_recvtos &&
+	    (ira->ira_flags & IRAF_IS_IPV4)) {
+		struct	T_opthdr *toh;
+		uint8_t	*dstptr;
+
+		toh = (struct T_opthdr *)ancil_buf;
+		toh->level = IPPROTO_IP;
+		toh->name = IP_RECVTOS;
+		toh->len = sizeof (struct T_opthdr) +
+		    P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
+		toh->status = 0;
+		ancil_buf += sizeof (struct T_opthdr);
+		dstptr = (uint8_t *)ancil_buf;
+		*dstptr = ipp->ipp_type_of_service;
+		ancil_buf = (uchar_t *)toh + toh->len;
+		ancil_size -= toh->len;
+		ASSERT(__TPI_TOPT_ISALIGNED(toh));
+	}
+
 	if (recv_ancillary.crb_recvttl &&
 	    (ira->ira_flags & IRAF_IS_IPV4)) {
 		struct	T_opthdr *toh;
@@ -566,13 +589,15 @@
 		toh = (struct T_opthdr *)ancil_buf;
 		toh->level = IPPROTO_IP;
 		toh->name = IP_RECVTTL;
-		toh->len = sizeof (struct T_opthdr) + sizeof (uint8_t);
+		toh->len = sizeof (struct T_opthdr) +
+		    P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
 		toh->status = 0;
 		ancil_buf += sizeof (struct T_opthdr);
 		dstptr = (uint8_t *)ancil_buf;
 		*dstptr = ipp->ipp_hoplimit;
-		ancil_buf += sizeof (uint8_t);
+		ancil_buf = (uchar_t *)toh + toh->len;
 		ancil_size -= toh->len;
+		ASSERT(__TPI_TOPT_ISALIGNED(toh));
 	}
 
 	/* Consumed all of allocated space */
@@ -777,6 +802,9 @@
 		case IP_RECVTTL:
 			*i1 = connp->conn_recv_ancillary.crb_recvttl;
 			break;	/* goto sizeof (int) option return */
+		case IP_RECVTOS:
+			*i1 = connp->conn_recv_ancillary.crb_recvtos;
+			break;	/* goto sizeof (int) option return */
 		case IP_ADD_MEMBERSHIP:
 		case IP_DROP_MEMBERSHIP:
 		case MCAST_JOIN_GROUP:
@@ -1385,6 +1413,11 @@
 		connp->conn_recv_ancillary.crb_recvttl = onoff;
 		mutex_exit(&connp->conn_lock);
 		break;
+	case IP_RECVTOS:
+		mutex_enter(&connp->conn_lock);
+		connp->conn_recv_ancillary.crb_recvtos = onoff;
+		mutex_exit(&connp->conn_lock);
+		break;
 	case IP_PKTINFO: {
 		/*
 		 * This also handles IP_RECVPKTINFO.
--- a/usr/src/uts/common/inet/ip/ip.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/ip/ip.c	Fri Oct 02 11:46:54 2020 +0000
@@ -25,6 +25,7 @@
  * Copyright (c) 2017 OmniTI Computer Consulting, Inc. All rights reserved.
  * Copyright (c) 2016 by Delphix. All rights reserved.
  * Copyright (c) 2019 Joyent, Inc. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #include <sys/types.h>
@@ -13923,6 +13924,7 @@
 		{ "conn_in_recvslla",		KSTAT_DATA_UINT64 },
 		{ "conn_in_recvucred",		KSTAT_DATA_UINT64 },
 		{ "conn_in_recvttl",		KSTAT_DATA_UINT64 },
+		{ "conn_in_recvtos",		KSTAT_DATA_UINT64 },
 		{ "conn_in_recvhopopts",	KSTAT_DATA_UINT64 },
 		{ "conn_in_recvhoplimit",	KSTAT_DATA_UINT64 },
 		{ "conn_in_recvdstopts",	KSTAT_DATA_UINT64 },
--- a/usr/src/uts/common/inet/ip_stack.h	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/ip_stack.h	Fri Oct 02 11:46:54 2020 +0000
@@ -26,6 +26,7 @@
 
 /*
  * Copyright 2019 Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #ifndef	_INET_IP_STACK_H
@@ -85,6 +86,7 @@
 	kstat_named_t	conn_in_recvslla;
 	kstat_named_t	conn_in_recvucred;
 	kstat_named_t	conn_in_recvttl;
+	kstat_named_t	conn_in_recvtos;
 	kstat_named_t	conn_in_recvhopopts;
 	kstat_named_t	conn_in_recvhoplimit;
 	kstat_named_t	conn_in_recvdstopts;
--- a/usr/src/uts/common/inet/ipclassifier.h	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/ipclassifier.h	Fri Oct 02 11:46:54 2020 +0000
@@ -25,7 +25,7 @@
  */
 
 /*
- * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #ifndef	_INET_IPCLASSIFIER_H
@@ -186,6 +186,7 @@
 	crbb_recvslla : 1,		/* IP_RECVSLLA option */
 
 	crbb_recvttl : 1,		/* IP_RECVTTL option */
+	crbb_recvtos : 1,		/* IP_RECVTOS option */
 	crbb_ip_recvpktinfo : 1,	/* IP*_RECVPKTINFO option  */
 	crbb_ipv6_recvhoplimit : 1,	/* IPV6_RECVHOPLIMIT option */
 	crbb_ipv6_recvhopopts : 1,	/* IPV6_RECVHOPOPTS option */
@@ -209,6 +210,7 @@
 #define	crb_recvif			crbu.crbb.crbb_recvif
 #define	crb_recvslla			crbu.crbb.crbb_recvslla
 #define	crb_recvttl			crbu.crbb.crbb_recvttl
+#define	crb_recvtos			crbu.crbb.crbb_recvtos
 #define	crb_ip_recvpktinfo		crbu.crbb.crbb_ip_recvpktinfo
 #define	crb_ipv6_recvhoplimit		crbu.crbb.crbb_ipv6_recvhoplimit
 #define	crb_ipv6_recvhopopts		crbu.crbb.crbb_ipv6_recvhopopts
--- a/usr/src/uts/common/inet/tcp.h	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/tcp.h	Fri Oct 02 11:46:54 2020 +0000
@@ -23,6 +23,7 @@
  * Copyright 2015 Joyent, Inc.
  * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2014, 2017 by Delphix. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
@@ -377,6 +378,7 @@
 
 	int		tcp_ipsec_overhead;
 
+	uint_t		tcp_recvtos;	/* Last received IP_RECVTOS */
 	uint_t		tcp_recvifindex; /* Last received IPV6_RCVPKTINFO */
 	uint_t		tcp_recvhops;	/* Last received IPV6_RECVHOPLIMIT */
 	uint_t		tcp_recvtclass;	/* Last received IPV6_RECVTCLASS */
--- a/usr/src/uts/common/inet/tcp/tcp_input.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp_input.c	Fri Oct 02 11:46:54 2020 +0000
@@ -24,6 +24,7 @@
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright 2019 Joyent, Inc.
  * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 /* This file contains all TCP input processing functions. */
@@ -5108,6 +5109,15 @@
 
 	optlen = 0;
 	addflag.crb_all = 0;
+
+	/* If app asked for TOS and it has changed ... */
+	if (connp->conn_recv_ancillary.crb_recvtos &&
+	    ipp->ipp_type_of_service != tcp->tcp_recvtos &&
+	    (ira->ira_flags & IRAF_IS_IPV4)) {
+		optlen += sizeof (struct T_opthdr) +
+		    P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
+		addflag.crb_recvtos = 1;
+	}
 	/* If app asked for pktinfo and the index has changed ... */
 	if (connp->conn_recv_ancillary.crb_ip_recvpktinfo &&
 	    ira->ira_ruifindex != tcp->tcp_recvifindex) {
@@ -5127,8 +5137,9 @@
 		optlen += sizeof (struct T_opthdr) + sizeof (uint_t);
 		addflag.crb_ipv6_recvtclass = 1;
 	}
+
 	/*
-	 * If app asked for hopbyhop headers and it has changed ...
+	 * If app asked for hop-by-hop headers and it has changed ...
 	 * For security labels, note that (1) security labels can't change on
 	 * a connected socket at all, (2) we're connected to at most one peer,
 	 * (3) if anything changes, then it must be some other extra option.
@@ -5206,6 +5217,23 @@
 	todi->OPT_length = optlen;
 	todi->OPT_offset = sizeof (*todi);
 	optptr = (uchar_t *)&todi[1];
+
+	/* If app asked for TOS and it has changed ... */
+	if (addflag.crb_recvtos) {
+		toh = (struct T_opthdr *)optptr;
+		toh->level = IPPROTO_IP;
+		toh->name = IP_RECVTOS;
+		toh->len = sizeof (*toh) +
+		    P2ROUNDUP(sizeof (uint8_t), __TPI_ALIGN_SIZE);
+		toh->status = 0;
+		optptr += sizeof (*toh);
+		*(uint8_t *)optptr = ipp->ipp_type_of_service;
+		optptr = (uchar_t *)toh + toh->len;
+		ASSERT(__TPI_TOPT_ISALIGNED(optptr));
+		/* Save as "last" value */
+		tcp->tcp_recvtos = ipp->ipp_type_of_service;
+	}
+
 	/*
 	 * If app asked for pktinfo and the index has changed ...
 	 * Note that the local address never changes for the connection.
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c	Fri Oct 02 11:46:54 2020 +0000
@@ -23,6 +23,7 @@
  * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright 2019 Joyent, Inc.
  * Copyright (c) 2016 by Delphix. All rights reserved.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #include <sys/types.h>
@@ -157,6 +158,7 @@
 { T_IP_TOS,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 { IP_TTL,	IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_DEF_FN,
 	sizeof (int), -1 /* not initialized */ },
+{ IP_RECVTOS,	IPPROTO_IP,  OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 
 { IP_SEC_OPT, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_NODEFAULT,
 	sizeof (ipsec_req_t), -1 /* not initialized */ },
@@ -626,9 +628,9 @@
 		/*
 		 * Note: Implies T_CHECK semantics for T_OPTCOM_REQ
 		 * inlen != 0 implies value supplied and
-		 * 	we have to "pretend" to set it.
+		 *	we have to "pretend" to set it.
 		 * inlen == 0 implies that there is no
-		 * 	value part in T_CHECK request and just validation
+		 *	value part in T_CHECK request and just validation
 		 * done elsewhere should be enough, we just return here.
 		 */
 		if (inlen == 0) {
@@ -1132,6 +1134,16 @@
 				return (EINVAL);
 			}
 			break;
+		case IP_RECVTOS:
+			if (!checkonly) {
+				/*
+				 * Force it to be sent up with the next msg
+				 * by setting it to a value which cannot
+				 * appear in a packet (TOS is only 8-bits)
+				 */
+				tcp->tcp_recvtos = 0xffffffffU;
+			}
+			break;
 		}
 		break;
 	case IPPROTO_IPV6:
--- a/usr/src/uts/common/inet/udp/udp.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/udp/udp.c	Fri Oct 02 11:46:54 2020 +0000
@@ -23,6 +23,7 @@
  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  * Copyright 2018, Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
@@ -2479,8 +2480,8 @@
 		*(uint32_t *)&sin->sin_zero[4] = 0;
 
 		/*
-		 * Add options if IP_RECVDSTADDR, IP_RECVIF, IP_RECVSLLA or
-		 * IP_RECVTTL has been set.
+		 * Add options if IP_RECVDSTADDR, IP_RECVIF, IP_RECVSLLA,
+		 * IP_RECVTTL or IP_RECVTOS has been set.
 		 */
 		if (udi_size != 0) {
 			conn_recvancillary_add(connp, recv_ancillary, ira,
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/inet/udp/udp_opt_data.c	Fri Oct 02 11:46:54 2020 +0000
@@ -22,6 +22,7 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  * Copyright 2015, Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 
 #include <sys/types.h>
@@ -112,8 +113,8 @@
 	},
 { IP_RECVIF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 { IP_RECVSLLA, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
-{ IP_RECVTTL,	IPPROTO_IP,  OA_RW, OA_RW, OP_NP, 0, sizeof (int),
-	0 },
+{ IP_RECVTTL,	IPPROTO_IP,  OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+{ IP_RECVTOS,	IPPROTO_IP,  OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
 { IP_MULTICAST_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
 	sizeof (struct in_addr),	0 /* INADDR_ANY */ },
 
--- a/usr/src/uts/common/netinet/in.h	Thu Oct 01 11:31:50 2020 +0000
+++ b/usr/src/uts/common/netinet/in.h	Fri Oct 02 11:46:54 2020 +0000
@@ -4,6 +4,7 @@
  *
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright 2015, Joyent, Inc.
+ * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  */
 /*
  * Copyright (c) 1982, 1986 Regents of the University of California.
@@ -388,7 +389,7 @@
 
 /* Well known 6to4 Relay Router Anycast address defined in RFC 3068 */
 #if !defined(_XPG4_2) || !defined(__EXTENSIONS__)
-#define	INADDR_6TO4RRANYCAST	0xc0586301U 	/* 192.88.99.1 */
+#define	INADDR_6TO4RRANYCAST	0xc0586301U	/* 192.88.99.1 */
 #endif	/* !defined(_XPG4_2) || !defined(__EXTENSIONS__) */
 
 #define	IN_LOOPBACKNET		127			/* official! */
@@ -473,7 +474,7 @@
 
 #define	IN6ADDR_ANY_INIT	    {	0, 0, 0, 0,	\
 					0, 0, 0, 0,	\
-					0, 0, 0, 0, 	\
+					0, 0, 0, 0,	\
 					0, 0, 0, 0 }
 
 #define	IN6ADDR_LOOPBACK_INIT	    {	0, 0, 0, 0,	\
@@ -912,6 +913,7 @@
 #define	IP_RECVIF	0x9	/* int; receive the inbound interface index */
 #define	IP_RECVSLLA	0xa	/* sockaddr_dl; get source link layer address */
 #define	IP_RECVTTL	0xb	/* uint8_t; get TTL for inbound packet */
+#define	IP_RECVTOS	0xc	/* uint8_t; get TOS for inbound packet */
 
 #define	IP_MULTICAST_IF		0x10	/* set/get IP multicast interface  */
 #define	IP_MULTICAST_TTL	0x11	/* set/get IP multicast timetolive */
@@ -946,8 +948,8 @@
  */
 
 typedef struct ipsec_req {
-	uint_t 		ipsr_ah_req;		/* AH request */
-	uint_t 		ipsr_esp_req;		/* ESP request */
+	uint_t		ipsr_ah_req;		/* AH request */
+	uint_t		ipsr_esp_req;		/* ESP request */
 	uint_t		ipsr_self_encap_req;	/* Self-Encap request */
 	uint8_t		ipsr_auth_alg;		/* Auth algs for AH */
 	uint8_t		ipsr_esp_alg;		/* Encr algs for ESP */
@@ -1253,7 +1255,7 @@
 #define	IPV6_RECVRTHDRDSTOPTS	0x17
 
 #define	IPV6_CHECKSUM		0x18	/* Control checksum on raw sockets */
-#define	IPV6_RECVTCLASS		0x19	/* enable/disable IPV6_CLASS */
+#define	IPV6_RECVTCLASS		0x19	/* enable/disable IPV6_TCLASS */
 #define	IPV6_USE_MIN_MTU	0x20	/* send packets with minimum MTU */
 #define	IPV6_DONTFRAG		0x21	/* don't fragment packets */
 #define	IPV6_SEC_OPT		0x22	/* Used to set IPSEC options */