/*
* CDDL HEADER START
*
* 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
* 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]
*
* CDDL HEADER END
*/
/*
*/
/* Copyright (c) 1990 Mentat Inc. */
#include <sys/xti_inet.h>
#include <sys/ethernet.h>
#include <net/if_types.h>
#include <inet/kstatcom.h>
#include <netinet/igmp_var.h>
#include <inet/ip_multi.h>
#include <inet/ip_ftable.h>
#include <inet/ip_listutils.h>
#include <netinet/ip_mroute.h>
#include <inet/ipp_common.h>
#include <inet/ipsec_impl.h>
#include <inet/ip_netinfo.h>
#include <inet/ipclassifier.h>
#include <inet/udp_impl.h>
/*
* Return how much size is needed for the different ancillary data items
*/
{
/*
* If IP_RECVDSTADDR is set we include the destination IP
* address as an option. With IP_RECVOPTS we include all
* the IP options.
*/
ancil_size = 0;
if (recv_ancillary.crb_recvdstaddr &&
ancil_size += sizeof (struct T_opthdr) +
sizeof (struct in_addr);
}
/*
* ip_recvpktinfo is used for both AF_INET and AF_INET6 but
* are different
*/
if (recv_ancillary.crb_ip_recvpktinfo &&
ancil_size += sizeof (struct T_opthdr) +
sizeof (struct in_pktinfo);
}
if ((recv_ancillary.crb_recvopts) &&
ancil_size += sizeof (struct T_opthdr) +
}
if (recv_ancillary.crb_recvslla) {
/* Make sure ira_l2src is setup if not already */
ipst);
}
}
ancil_size += sizeof (struct T_opthdr) +
sizeof (struct sockaddr_dl);
}
if (recv_ancillary.crb_recvif) {
}
/*
* ip_recvpktinfo is used for both AF_INET and AF_INET6 but
* are different
*/
if (recv_ancillary.crb_ip_recvpktinfo &&
ancil_size += sizeof (struct T_opthdr) +
sizeof (struct in6_pktinfo);
}
ancil_size += sizeof (struct T_opthdr) + sizeof (int);
}
ancil_size += sizeof (struct T_opthdr) + sizeof (int);
}
}
/*
* To honor RFC3542 when an application asks for both IPV6_RECVDSTOPTS
* and IPV6_RECVRTHDR, we pass up the item rthdrdstopts (the destination
* options that appear before a routing header.
* We also pass them up if IPV6_RECVRTHDRDSTOPTS is set.
*/
ancil_size += sizeof (struct T_opthdr) +
}
}
if ((recv_ancillary.crb_ipv6_recvrthdr) &&
}
if ((recv_ancillary.crb_ipv6_recvdstopts ||
}
ancil_size += sizeof (struct T_opthdr) +
}
/*
* If SO_TIMESTAMP is set allocate the appropriate sized
* buffer. Since gethrestime() expects a pointer aligned
* argument, we allocate space necessary for extra
* alignment (even though it might not be used).
*/
if (recv_ancillary.crb_timestamp) {
ancil_size += sizeof (struct T_opthdr) +
sizeof (timestruc_t) + _POINTER_ALIGNMENT;
}
/*
* If IP_RECVTTL is set allocate the appropriate sized buffer
*/
if (recv_ancillary.crb_recvttl &&
}
return (ancil_size);
}
/*
* Lay down the ancillary data items at "ancil_buf".
* Assumes caller has used conn_recvancillary_size to allocate a sufficiently
* large buffer - ancil_size.
*/
void
{
/*
* Copy in destination address before options to avoid
* any padding issues.
*/
if (recv_ancillary.crb_recvdstaddr &&
}
/*
* ip_recvpktinfo is used for both AF_INET and AF_INET6 but
* are different
*/
if (recv_ancillary.crb_ip_recvpktinfo &&
/* Find a good address to report */
}
}
ancil_buf += sizeof (struct in_pktinfo);
}
if ((recv_ancillary.crb_recvopts) &&
}
if (recv_ancillary.crb_recvslla) {
int alen = 0;
/*
* For loopback multicast and broadcast the packet arrives
* with ira_ruifdex being the physical interface, but
* ira_l2src is all zero since ip_postfrag_loopback doesn't
* know our l2src. We don't report the address in that case.
*/
alen = 0;
sizeof (struct sockaddr_dl);
else
ancil_buf += sizeof (struct sockaddr_dl);
}
if (recv_ancillary.crb_recvif) {
}
/*
* ip_recvpktinfo is used for both AF_INET and AF_INET6 but
* are different
*/
if (recv_ancillary.crb_ip_recvpktinfo &&
} else {
}
}
}
else
}
}
/*
* To honor RFC3542 when an application asks for both IPV6_RECVDSTOPTS
* and IPV6_RECVRTHDR, we pass up the item rthdrdstopts (the destination
* options that appear before a routing header.
* We also pass them up if IPV6_RECVRTHDRDSTOPTS is set.
*/
}
}
if (recv_ancillary.crb_ipv6_recvrthdr &&
}
if ((recv_ancillary.crb_ipv6_recvdstopts ||
}
}
if (recv_ancillary.crb_timestamp) {
sizeof (timestruc_t) + _POINTER_ALIGNMENT;
/* Align for gethrestime() */
sizeof (intptr_t));
}
/*
* 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_recvttl &&
}
/* Consumed all of allocated space */
ASSERT(ancil_size == 0);
}
/*
* This routine retrieves the current status of socket options.
* It returns the size of the option retrieved, or -1.
*/
int
{
switch (level) {
case SOL_SOCKET:
switch (name) {
case SO_DEBUG:
break; /* goto sizeof (int) option return */
case SO_KEEPALIVE:
break;
case SO_LINGER: {
}
return (sizeof (struct linger));
case SO_OOBINLINE:
break;
case SO_REUSEADDR:
break; /* goto sizeof (int) option return */
case SO_TYPE:
break; /* goto sizeof (int) option return */
case SO_DONTROUTE:
SO_DONTROUTE : 0;
break; /* goto sizeof (int) option return */
case SO_USELOOPBACK:
break; /* goto sizeof (int) option return */
case SO_BROADCAST:
break; /* goto sizeof (int) option return */
case SO_SNDBUF:
break; /* goto sizeof (int) option return */
case SO_RCVBUF:
break; /* goto sizeof (int) option return */
case SO_RCVTIMEO:
case SO_SNDTIMEO:
/*
* Pass these two options in order for third part
* protocol usage. Here just return directly.
*/
*i1 = 0;
break;
case SO_DGRAM_ERRIND:
break; /* goto sizeof (int) option return */
case SO_RECVUCRED:
break; /* goto sizeof (int) option return */
case SO_TIMESTAMP:
break; /* goto sizeof (int) option return */
case SO_VRRP:
break; /* goto sizeof (int) option return */
case SO_ANON_MLP:
break; /* goto sizeof (int) option return */
case SO_MAC_EXEMPT:
break; /* goto sizeof (int) option return */
case SO_MAC_IMPLICIT:
break; /* goto sizeof (int) option return */
case SO_ALLZONES:
break; /* goto sizeof (int) option return */
case SO_EXCLBIND:
break;
case SO_PROTOTYPE:
break;
case SO_DOMAIN:
break;
default:
return (-1);
}
break;
case IPPROTO_IP:
return (-1);
switch (name) {
case IP_OPTIONS:
case T_IP_OPTIONS:
return (0);
if (len > 0) {
}
return (len);
case IP_PKTINFO: {
/*
* This also handles IP_RECVPKTINFO.
* IP_PKTINFO and IP_RECVPKTINFO have same value.
* Differentiation is based on the size of the
* argument passed in.
*/
#ifdef notdef
/* optcom doesn't provide a length with "get" */
if (inlen == sizeof (int)) {
/* This is IP_RECVPKTINFO option. */
return (sizeof (int));
}
#endif
/* XXX assumes that caller has room for max size! */
else
return (sizeof (struct in_pktinfo));
}
case IP_DONTFRAG:
return (sizeof (int));
case IP_TOS:
case T_IP_TOS:
break; /* goto sizeof (int) option return */
case IP_TTL:
break; /* goto sizeof (int) option return */
case IP_DHCPINIT_IF:
return (-1);
case IP_NEXTHOP:
return (sizeof (ipaddr_t));
} else {
return (0);
}
case IP_MULTICAST_IF:
/* 0 address if not set */
return (sizeof (ipaddr_t));
case IP_MULTICAST_TTL:
return (sizeof (uchar_t));
case IP_MULTICAST_LOOP:
return (sizeof (uint8_t));
case IP_RECVOPTS:
break; /* goto sizeof (int) option return */
case IP_RECVDSTADDR:
break; /* goto sizeof (int) option return */
case IP_RECVIF:
break; /* goto sizeof (int) option return */
case IP_RECVSLLA:
break; /* goto sizeof (int) option return */
case IP_RECVTTL:
break; /* goto sizeof (int) option return */
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case IP_BLOCK_SOURCE:
case IP_UNBLOCK_SOURCE:
case IP_ADD_SOURCE_MEMBERSHIP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
case MRT_INIT:
case MRT_DONE:
case MRT_ADD_VIF:
case MRT_DEL_VIF:
case MRT_ADD_MFC:
case MRT_DEL_MFC:
/* cannot "get" the value for these */
return (-1);
case MRT_VERSION:
case MRT_ASSERT:
return (sizeof (int));
case IP_SEC_OPT:
IPSEC_AF_V4));
case IP_BOUND_IF:
/* Zero if not set */
break; /* goto sizeof (int) option return */
case IP_UNSPEC_SRC:
break; /* goto sizeof (int) option return */
case IP_BROADCAST_TTL:
else
return (sizeof (uchar_t));
default:
return (-1);
}
break;
case IPPROTO_IPV6:
return (-1);
switch (name) {
case IPV6_UNICAST_HOPS:
break; /* goto sizeof (int) option return */
case IPV6_MULTICAST_IF:
/* 0 index if not set */
break; /* goto sizeof (int) option return */
case IPV6_MULTICAST_HOPS:
break; /* goto sizeof (int) option return */
case IPV6_MULTICAST_LOOP:
break; /* goto sizeof (int) option return */
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
/* cannot "get" the value for these */
return (-1);
case IPV6_BOUND_IF:
/* Zero if not set */
break; /* goto sizeof (int) option return */
case IPV6_UNSPEC_SRC:
break; /* goto sizeof (int) option return */
case IPV6_RECVPKTINFO:
break; /* goto sizeof (int) option return */
case IPV6_RECVTCLASS:
break; /* goto sizeof (int) option return */
case IPV6_RECVPATHMTU:
break; /* goto sizeof (int) option return */
case IPV6_RECVHOPLIMIT:
break; /* goto sizeof (int) option return */
case IPV6_RECVHOPOPTS:
break; /* goto sizeof (int) option return */
case IPV6_RECVDSTOPTS:
break; /* goto sizeof (int) option return */
case _OLD_IPV6_RECVDSTOPTS:
*i1 =
break; /* goto sizeof (int) option return */
case IPV6_RECVRTHDRDSTOPTS:
break; /* goto sizeof (int) option return */
case IPV6_RECVRTHDR:
break; /* goto sizeof (int) option return */
case IPV6_PKTINFO: {
/* XXX assumes that caller has room for max size! */
else
return (sizeof (struct in6_pktinfo));
}
case IPV6_TCLASS:
break; /* goto sizeof (int) option return */
case IPV6_NEXTHOP: {
return (0);
return (sizeof (sin6_t));
}
case IPV6_HOPOPTS:
return (0);
return (ipp->ipp_hopoptslen);
case IPV6_RTHDRDSTOPTS:
return (0);
return (ipp->ipp_rthdrdstoptslen);
case IPV6_RTHDR:
return (0);
return (ipp->ipp_rthdrlen);
case IPV6_DSTOPTS:
return (0);
return (ipp->ipp_dstoptslen);
case IPV6_PATHMTU:
(struct ip6_mtuinfo *)ptr));
case IPV6_SEC_OPT:
IPSEC_AF_V6));
case IPV6_SRC_PREFERENCES:
case IPV6_DONTFRAG:
return (sizeof (int));
case IPV6_USE_MIN_MTU:
else
break;
case IPV6_V6ONLY:
return (sizeof (int));
default:
return (-1);
}
break;
case IPPROTO_UDP:
switch (name) {
case UDP_ANONPRIVBIND:
break;
case UDP_EXCLBIND:
break;
default:
return (-1);
}
break;
case IPPROTO_TCP:
switch (name) {
case TCP_RECVDSTADDR:
break;
case TCP_ANONPRIVBIND:
break;
case TCP_EXCLBIND:
break;
default:
return (-1);
}
break;
default:
return (-1);
}
return (sizeof (int));
}
/*
* This routine sets the most common socket options including some
* It returns errno or zero.
*
* For fixed length options, there is no sanity check
* of passed in length is done. It is assumed *_optcom_req()
* routines do the right thing.
*/
int
{
/* We have different functions for different levels */
switch (level) {
case SOL_SOCKET:
case IPPROTO_IP:
case IPPROTO_IPV6:
case IPPROTO_UDP:
case IPPROTO_TCP:
default:
return (0);
}
}
/*
* Handle SOL_SOCKET
* Note that we do not handle SO_PROTOTYPE here. The ULPs that support
* it implement their own checks and setting of conn_proto.
*/
/* ARGSUSED1 */
static int
{
switch (name) {
case SO_ALLZONES:
if (IPCL_IS_BOUND(connp))
return (EINVAL);
break;
case SO_VRRP:
return (EACCES);
break;
case SO_MAC_EXEMPT:
if (secpolicy_net_mac_aware(cr) != 0)
return (EACCES);
if (IPCL_IS_BOUND(connp))
return (EINVAL);
break;
case SO_MAC_IMPLICIT:
if (secpolicy_net_mac_implicit(cr) != 0)
return (EACCES);
break;
}
if (checkonly)
return (0);
/* Here we set the actual option value */
switch (name) {
case SO_DEBUG:
break;
case SO_KEEPALIVE:
break;
case SO_LINGER: {
} else {
connp->conn_linger = 0;
connp->conn_lingertime = 0;
}
break;
}
case SO_OOBINLINE:
break;
case SO_REUSEADDR:
break;
case SO_DONTROUTE:
if (onoff)
else
break;
case SO_USELOOPBACK:
break;
case SO_BROADCAST:
break;
case SO_SNDBUF:
/* ULP has range checked the value */
break;
case SO_RCVBUF:
/* ULP has range checked the value */
break;
case SO_RCVTIMEO:
case SO_SNDTIMEO:
/*
* Pass these two options in order for third part
* protocol usage.
*/
break;
case SO_DGRAM_ERRIND:
break;
case SO_RECVUCRED:
break;
case SO_ALLZONES:
if (onoff)
else
break;
case SO_TIMESTAMP:
break;
case SO_VRRP:
break;
case SO_ANON_MLP:
break;
case SO_MAC_EXEMPT:
break;
case SO_MAC_IMPLICIT:
break;
case SO_EXCLBIND:
break;
}
return (0);
}
/* Handle IPPROTO_IP */
static int
{
int error;
return (EINVAL);
switch (name) {
case IP_TTL:
/* Don't allow zero */
return (EINVAL);
break;
case IP_MULTICAST_IF:
if (addr == INADDR_ANY) {
/* Clear */
ifindex = 0;
break;
}
return (EHOSTUNREACH);
/* not supported by the virtual network iface */
return (EINVAL);
}
break;
case IP_NEXTHOP: {
if (addr == INADDR_ANY) {
/* Clear */
break;
}
/* Verify that the next-hop is on-link */
return (EHOSTUNREACH);
break;
}
case IP_OPTIONS:
case T_IP_OPTIONS: {
else
return (EINVAL);
}
break;
}
case IP_PKTINFO: {
/* Two different valid lengths */
if (inlen != sizeof (int) &&
inlen != sizeof (struct in_pktinfo))
return (EINVAL);
if (inlen == sizeof (int))
break;
case IPVL_UNICAST_UP:
case IPVL_UNICAST_DOWN:
break;
default:
return (EADDRNOTAVAIL);
}
}
return (ENXIO);
break;
}
case IP_BOUND_IF:
/* Just check it is ok. */
return (ENXIO);
break;
}
if (checkonly)
return (0);
/* Here we set the actual option value */
/*
* conn_lock protects the bitfields, and is used to
* set the fields atomically. Not needed for ixa settings since
* the caller has an exclusive copy of the ixa.
* We can not hold conn_lock across the multicast options though.
*/
switch (name) {
case IP_OPTIONS:
case T_IP_OPTIONS:
/* Save options for use by IP. */
if (error != 0) {
return (error);
}
if (ipp->ipp_ipv4_options_len == 0) {
} else {
}
break;
case IP_TTL:
break;
case IP_TOS:
case T_IP_TOS:
if (*i1 == -1) {
ipp->ipp_type_of_service = 0;
} else {
}
break;
case IP_MULTICAST_IF:
break;
case IP_MULTICAST_TTL:
/* Handled automatically by ip_output */
break;
case IP_MULTICAST_LOOP:
if (*invalp != 0)
else
/* Handled automatically by ip_output */
break;
case IP_RECVOPTS:
break;
case IP_RECVDSTADDR:
break;
case IP_RECVIF:
break;
case IP_RECVSLLA:
break;
case IP_RECVTTL:
break;
case IP_PKTINFO: {
/*
* This also handles IP_RECVPKTINFO.
* IP_PKTINFO and IP_RECVPKTINFO have same value.
* Differentiation is based on the size of the
* argument passed in.
*/
if (inlen == sizeof (int)) {
/* This is IP_RECVPKTINFO option. */
break;
}
/* This is IP_PKTINFO option. */
} else {
}
break;
}
case IP_DONTFRAG:
if (onoff) {
} else {
}
/* Need to redo ip_attr_connect */
break;
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case IP_BLOCK_SOURCE:
case IP_UNBLOCK_SOURCE:
case IP_ADD_SOURCE_MEMBERSHIP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
case IP_SEC_OPT:
if (error != 0) {
return (error);
}
/* This is an IPsec policy change - redo ip_attr_connect */
break;
case IP_NEXTHOP:
if (addr != INADDR_ANY)
else
break;
case IP_BOUND_IF:
break;
case IP_UNSPEC_SRC:
if (onoff)
else
break;
case IP_BROADCAST_TTL:
/* Handled automatically by ip_output */
break;
case MRT_INIT:
case MRT_DONE:
case MRT_ADD_VIF:
case MRT_DEL_VIF:
case MRT_ADD_MFC:
case MRT_DEL_MFC:
case MRT_ASSERT:
return (error);
}
if (error) {
return (error);
}
return (0);
}
return (0);
}
/* Handle IPPROTO_IPV6 */
static int
{
int error;
return (EINVAL);
switch (name) {
case IPV6_MULTICAST_IF:
/*
* The only possible error is EINVAL.
* We call this option on both V4 and V6
* If both fail, then this call returns
* EINVAL. If at least one of them succeeds we
* return success.
*/
return (EINVAL);
break;
case IPV6_UNICAST_HOPS:
/* Don't allow zero. -1 means to use default */
return (EINVAL);
break;
case IPV6_MULTICAST_HOPS:
/* -1 means use default */
return (EINVAL);
break;
case IPV6_MULTICAST_LOOP:
return (EINVAL);
break;
case IPV6_BOUND_IF:
return (ENXIO);
break;
case IPV6_PKTINFO: {
return (EINVAL);
if (inlen == 0)
break; /* Clear values below */
/*
* Verify the source address and ifindex. Privileged users
* can use any source address.
*/
/*
* For link-local addresses we use the ipi6_ifindex when
* we verify the local address.
* If net_rawaccess then any source address can be used.
*/
secpolicy_net_rawaccess(cr) != 0) {
if (IN6_IS_ADDR_V4MAPPED(v6src)) {
if (v4src != INADDR_ANY) {
}
} else {
if (IN6_IS_ADDR_LINKSCOPE(v6src))
}
switch (laddr_type) {
case IPVL_UNICAST_UP:
case IPVL_UNICAST_DOWN:
break;
default:
return (EADDRNOTAVAIL);
}
/* Allow any source */
}
ipst))
return (ENXIO);
break;
}
case IPV6_HOPLIMIT:
/* It is only allowed as ancilary data */
if (!coa->coa_ancillary)
return (EINVAL);
return (EINVAL);
if (inlen == sizeof (int)) {
return (EINVAL);
}
break;
case IPV6_TCLASS:
return (EINVAL);
if (inlen == sizeof (int)) {
return (EINVAL);
}
break;
case IPV6_NEXTHOP:
return (EINVAL);
return (EAFNOSUPPORT);
return (EADDRNOTAVAIL);
/* Verify that the next-hop is on-link */
return (EHOSTUNREACH);
break;
}
break;
case IPV6_RTHDR:
case IPV6_DSTOPTS:
case IPV6_RTHDRDSTOPTS:
case IPV6_HOPOPTS: {
/* All have the length field in the same place */
/*
* Sanity checks - minimum size, size a multiple of
* eight bytes, and matching size passed in.
*/
if (inlen != 0 &&
return (EINVAL);
break;
}
case IPV6_PATHMTU:
/* Can't be set */
return (EINVAL);
case IPV6_USE_MIN_MTU:
if (inlen != sizeof (int))
return (EINVAL);
return (EINVAL);
break;
case IPV6_SRC_PREFERENCES:
return (EINVAL);
break;
case IPV6_V6ONLY:
return (EINVAL);
}
break;
}
if (checkonly)
return (0);
/* Here we set the actual option value */
/*
* conn_lock protects the bitfields, and is used to
* set the fields atomically. Not needed for ixa settings since
* the caller has an exclusive copy of the ixa.
* We can not hold conn_lock across the multicast options though.
*/
switch (name) {
case IPV6_MULTICAST_IF:
/* Need to redo ip_attr_connect */
break;
case IPV6_UNICAST_HOPS:
/* -1 means use default */
if (*i1 == -1) {
} else {
}
break;
case IPV6_MULTICAST_HOPS:
/* -1 means use default */
if (*i1 == -1) {
} else {
}
/* Handled automatically by ip_output */
break;
case IPV6_MULTICAST_LOOP:
if (*i1 != 0)
else
/* Handled automatically by ip_output */
break;
case IPV6_JOIN_GROUP:
case IPV6_LEAVE_GROUP:
case MCAST_JOIN_GROUP:
case MCAST_LEAVE_GROUP:
case MCAST_BLOCK_SOURCE:
case MCAST_UNBLOCK_SOURCE:
case MCAST_JOIN_SOURCE_GROUP:
case MCAST_LEAVE_SOURCE_GROUP:
case IPV6_BOUND_IF:
break;
case IPV6_UNSPEC_SRC:
if (onoff)
else
break;
case IPV6_RECVPKTINFO:
break;
case IPV6_RECVTCLASS:
break;
case IPV6_RECVPATHMTU:
break;
case IPV6_RECVHOPLIMIT:
break;
case IPV6_RECVHOPOPTS:
break;
case IPV6_RECVDSTOPTS:
break;
case _OLD_IPV6_RECVDSTOPTS:
break;
case IPV6_RECVRTHDRDSTOPTS:
break;
case IPV6_RECVRTHDR:
break;
case IPV6_PKTINFO:
if (inlen == 0) {
ixa->ixa_ifindex = 0;
} else {
else
}
/* Source and ifindex might have changed */
break;
case IPV6_HOPLIMIT:
/* Revert to default */
} else {
/* Ensure that it sticks for multicast packets */
}
break;
case IPV6_TCLASS:
/*
* IPV6_TCLASS accepts -1 as use kernel default
* and [0, 255] as the actualy traffic class.
*/
ipp->ipp_tclass = 0;
} else {
}
break;
case IPV6_NEXTHOP:
if (inlen == 0) {
} else {
else
}
break;
case IPV6_HOPOPTS:
if (error != 0) {
return (error);
}
if (ipp->ipp_hopoptslen == 0) {
} else {
}
break;
case IPV6_RTHDRDSTOPTS:
if (error != 0) {
return (error);
}
if (ipp->ipp_rthdrdstoptslen == 0) {
} else {
}
break;
case IPV6_DSTOPTS:
if (error != 0) {
return (error);
}
if (ipp->ipp_dstoptslen == 0) {
} else {
}
break;
case IPV6_RTHDR:
if (error != 0) {
return (error);
}
if (ipp->ipp_rthdrlen == 0) {
} else {
}
break;
case IPV6_DONTFRAG:
if (onoff) {
} else {
}
/* Need to redo ip_attr_connect */
break;
case IPV6_USE_MIN_MTU:
/* Need to redo ip_attr_connect */
break;
case IPV6_SEC_OPT:
if (error != 0) {
return (error);
}
/* This is an IPsec policy change - redo ip_attr_connect */
break;
case IPV6_SRC_PREFERENCES:
/*
* This socket option only affects connected
* sockets that haven't already bound to a specific
* IPv6 address. In other words, sockets that
* don't call bind() with an address other than the
* unspecified address and that call connect().
* ip_set_destination_v6() passes these preferences
* to the ipif_select_source_v6() function.
*/
if (error != 0) {
return (error);
}
break;
case IPV6_V6ONLY:
break;
}
return (0);
}
/* Handle IPPROTO_UDP */
/* ARGSUSED1 */
static int
{
int error;
switch (name) {
case UDP_ANONPRIVBIND:
return (error);
}
break;
}
if (checkonly)
return (0);
/* Here we set the actual option value */
switch (name) {
case UDP_ANONPRIVBIND:
break;
case UDP_EXCLBIND:
break;
}
return (0);
}
/* Handle IPPROTO_TCP */
/* ARGSUSED1 */
static int
{
int error;
switch (name) {
case TCP_ANONPRIVBIND:
return (error);
}
break;
}
if (checkonly)
return (0);
/* Here we set the actual option value */
switch (name) {
case TCP_ANONPRIVBIND:
break;
case TCP_EXCLBIND:
break;
case TCP_RECVDSTADDR:
break;
}
return (0);
}
int
{
return (EINVAL);
/* Fill zeroes and then initialize non-zero fields */
} else {
/*
* INADDR_ANY
* conn_saddr is not set, we might be bound to
* local address instead (that could
* also still be INADDR_ANY)
*/
}
} else {
return (EINVAL);
/* Fill zeroes and then initialize non-zero fields */
} else {
/*
* conn_saddr is not set, we might be bound to
* local address instead (which could
* also still be unspecified)
*/
}
}
return (0);
}
int
{
return (EINVAL);
/* initialize */
} else {
return (EINVAL);
/* initialize */
}
return (0);
}
/*
* Allocate and fill in conn_ht_iphc based on the current information
* in the conn.
* Normally used when we bind() and connect().
* Returns failure if can't allocate memory, or if there is a problem
*
* We allocate space for the transport header (ulp_hdr_len + extra) and
* indicate the offset of the ulp header by setting ixa_ip_hdr_length.
* The extra is there for transports that want some spare room for future
* options. conn_ht_iphc_allocated is what was allocated; conn_ht_iphc_len
* excludes the extra part.
*
* in conn_sum.
*
* Caller needs to update conn_wroff if desired.
*/
int
{
/* In case of TX label and IP options it can be too much */
if (ip_hdr_length > IP_MAX_HDR_LENGTH) {
/* Preserves existing TX errno for this */
return (EHOSTUNREACH);
}
} else {
}
/* Allocate new before we free any old */
return (ENOMEM);
}
} else {
}
else
} else {
}
} else {
flowinfo);
/*
* Verify that the first hop isn't a mapped address.
* Routers along the path need to do this verification
* for subsequent hops.
*/
return (EADDRNOTAVAIL);
} else {
}
}
return (0);
}
/*
* Prepend a header template to data_mp based on the ip_pkt_t
* and the passed in source, destination and protocol.
*
* Returns failure if can't allocate memory, in which case data_mp is freed.
* We allocate space for the transport header (ulp_hdr_len) and
* indicate the offset of the ulp header by setting ixa_ip_hdr_length.
*
* in *sump. This is in host byte order.
*
* Caller needs to update conn_wroff if desired.
*/
mblk_t *
{
} else {
}
/* Can we prepend to data_mp? */
} else {
return (NULL);
}
}
/*
* Set the source in the header. ip_build_hdrs_v4/v6 will overwrite it
* if PKTINFO (aka IPPF_ADDR) was set.
*/
else
} else {
*sump = 0;
}
} else {
/*
* Verify that the first hop isn't a mapped address.
* Routers along the path need to do this verification
* for subsequent hops.
*/
*errorp = EADDRNOTAVAIL;
return (NULL);
}
} else {
*sump = 0;
}
}
return (mp);
}
/*
* Massage a source route if any putting the first hop
* in ipha_dst. Compute a starting value for the checksum which
* takes into account that the original ipha_dst should be
* included in the checksum but that IP will include the
* first hop from the source route in the tcp checksum.
*/
static uint32_t
{
/* Get last hop then diff against first hop */
if ((int)cksum < 0)
cksum--;
}
static uint32_t
{
return (0);
}
/*
* ULPs that change the destination address need to call this for each
* change to discard any state about a previous destination that might
* have been multicast or multirt.
*/
void
{
}
/*
* Determine the nexthop which will be used.
* Normally this is just the destination, but if a IPv4 source route, or
* IPv6 routing header, is in the ip_pkt_t then we extract the nexthop from
* there.
*/
void
{
return;
}
if (v4nexthop == INADDR_ANY)
} else {
}
}
/*
* Update the ip_xmit_attr_t based the addresses, conn_xmit_ipp and conn_ixa.
* If IPDF_IPSEC is set we cache the IPsec policy to handle the unconnected
* case (connected latching is done in conn_connect).
* Note that IPsec policy lookup requires conn_proto and conn_laddr to be
* set, but doesn't otherwise use the conn_t.
*
* Caller must use ip_attr_nexthop() to determine the nexthop argument.
*
* The caller must NOT hold conn_lock (to avoid problems with ill_refrele
* causing the squeue to run doing ipcl_walk grabbing conn_lock.)
*
* Updates laddrp and uinfo if they are non-NULL.
*
* TSOL notes: The callers if ip_attr_connect must check if the destination
* is different than before and in that case redo conn_update_label.
* The callers of conn_connect do not need that since conn_connect
* performs the conn_update_label.
*/
int
{
int error;
if (connp->conn_zone_is_global)
else
flags &= ~IPDF_ZONE_IS_GLOBAL;
/*
* Lookup the route to determine a source address and the uinfo.
* If the ULP has a source route option then the caller will
* have set v6nexthop to be the first hop.
*/
flags &= ~IPDF_SELECT_SRC;
else
flags |= IPDF_SELECT_SRC;
} else {
flags &= ~IPDF_SELECT_SRC;
else
flags |= IPDF_SELECT_SRC;
}
/* Pass out some address even if we hit a RTF_REJECT etc */
if (error != 0)
return (error);
if (flags & IPDF_IPSEC) {
/*
* Set any IPsec policy in ixa. Routine also looks at ULP
* ports.
*/
}
return (0);
}
/*
* Connect the conn based on the addresses, conn_xmit_ipp and conn_ixa.
* Assumes that conn_faddr and conn_fport are already set. As such it is not
* usable for SCTP, since SCTP has multiple faddrs.
*
* Caller must hold conn_lock to provide atomic constency between the
* conn_t's addresses and the ixa.
* NOTE: this function drops and reaquires conn_lock since it can't be
* held across ip_attr_connect/ip_set_destination.
*
* The caller needs to handle inserting in the receive-side fanout when
* appropriate after conn_connect returns.
*/
int
{
int error;
else
/* We do IPsec latching below - hence no caching in ip_attr_connect */
flags &= ~IPDF_IPSEC;
/* In case we had previously done an ip_attr_connect */
/*
* Determine the nexthop and copy the addresses before dropping
* conn_lock.
*/
/* Could have changed even if an error */
if (error != 0)
return (error);
/*
* Check whether Trusted Solaris policy allows communication with this
* host, and pretend that the destination is unreachable if not.
* Compute any needed label and place it in ipp_label_v4/v6.
*
* Later conn_build_hdr_template() takes ipp_label_v4/v6 to form
* the packet.
*
* TSOL Note: Any concurrent threads would pick a different ixa
* (and ipp if they are to change the ipp) so we
* don't have to worry about concurrent threads.
*/
if (is_system_labeled()) {
return (ECONNREFUSED);
/*
* conn_update_label will set ipp_label* which will later
* be used by conn_build_hdr_template.
*/
if (error != 0)
return (error);
}
/*
* Ensure that we match on the selected local address.
* This overrides conn_laddr in the case we had earlier bound to a
* multicast or broadcast address.
*/
/*
* Allow setting new policies.
* can handle their passed-in conn's.
*/
/*
* Cache IPsec policy in this conn. If we have per-socket policy,
* we'll cache that. If we don't, we'll inherit global policy.
*
* This is done before the caller inserts in the receive-side fanout.
* Note that conn_policy_cached is set by ipsec_conn_cache_policy() even
* for connections where we don't have a policy. This is to prevent
* global policy lookups in the inbound path.
*
* If we insert before we set conn_policy_cached,
* CONN_INBOUND_POLICY_PRESENT() check can still evaluate true
* because global policy cound be non-empty. We normally call
* ipsec_check_policy() for conn_policy_cached connections only if
* conn_in_enforce_policy is set. But in this case,
* conn_policy_cached can get set anytime since we made the
* CONN_INBOUND_POLICY_PRESENT() check and ipsec_check_policy() is
* called, which will make the above assumption false. Thus, we
* need to insert after we set conn_policy_cached.
*/
if (error != 0)
return (error);
/*
* We defer to do LSO check until here since now we have better idea
* whether IPsec is present. If the underlying ill is LSO capable,
* copy its capability in so the ULP can decide whether to enable LSO
* claim LSO for IPv6.
*
* Currently, won't enable LSO for IRE_LOOPBACK or IRE_LOCAL, because
* the receiver can not handle it. Also not to enable LSO for MULTIRT.
*/
}
/* Check whether ZEROCOPY capability is usable for this connection. */
if ((flags & IPDF_ZCOPY) &&
}
return (0);
}
/*
* Predicates to check if the addresses match conn_last*
*/
/*
* Compare the conn against an address.
* If using mapped addresses on AF_INET6 sockets, use the _v6 function
*/
{
}
/*
* Compare, including for mapped addresses
*/
{
}
/*
* Compute a label and place it in the ip_packet_t.
* Handles IPv4 and IPv6.
* The caller should have a correct ixa_tsl and ixa_zoneid and have
* already called conn_connect or ip_attr_connect to ensure that tsol_check_dest
* has been called.
*/
int
{
int err;
if (IN6_IS_ADDR_V4MAPPED(v6dst)) {
if (err == 0) {
/* Length contained in opt_storage[IPOPT_OLEN] */
&ipp->ipp_label_len_v4);
}
if (err != 0) {
char *, "conn(1) failed to update options(2) "
"on ixa(3)",
ip_xmit_attr_t *, ixa);
}
if (ipp->ipp_label_len_v4 != 0)
else
} else {
if (err == 0) {
/*
* Note that ipp_label_v6 is just the option - not
* the hopopts extension header.
*
* Length contained in opt_storage[IPOPT_OLEN], but
* that doesn't include the two byte options header.
*/
if (optlen != 0)
optlen += 2;
&ipp->ipp_label_len_v6);
}
if (err != 0) {
char *, "conn(1) failed to update options(2) "
"on ixa(3)",
ip_xmit_attr_t *, ixa);
}
if (ipp->ipp_label_len_v6 != 0)
else
}
return (err);
}
/*
* Returns zero on success; ENOMEM if memory allocation failed.
*
* We assume that the eager has not had any work done i.e., the conn_ixa
* and conn_xmit_ipp are all zero.
* Furthermore we assume that no other thread can access the eager (because
* it isn't inserted in any fanout list).
*/
int
{
int err;
void *notify_cookie;
/*
* Make a safe copy of the transmit attributes.
* conn_connect will later be used by the caller to setup the ire etc.
*/
/* Preserve ixa_notify_cookie and xmit_hint */
/* Inherit all RECV options */
if (err != 0)
return (err);
/* This is odd. Pick a flowlabel for each connection instead? */
/*
* TSOL: tsol_input_proc() needs the eager's cred before the
* eager is accepted
*/
/*
* Cache things in the ixa without any refhold.
* Listener might not have set up ixa_cred
*/
if (is_system_labeled())
/*
* If the caller has the process-wide flag set, then default to MAC
* exempt mode. This allows read-down to unlabeled hosts.
*/
/*
* We eliminate the need for sockfs to send down a T_SVR4_OPTMGMT_REQ
* via soaccept()->soinheritoptions() which essentially applies
* all the listener options to the new connection. The options that we
* need to take care of are:
* SO_DEBUG, SO_REUSEADDR, SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST,
* SO_USELOOPBACK, SO_OOBINLINE, SO_DGRAM_ERRIND, SO_LINGER,
* SO_SNDBUF, SO_RCVBUF.
*
* SO_RCVBUF: conn_rcvbuf is set.
* SO_SNDBUF: conn_sndbuf is set.
*/
/* Could we define a struct and use a struct copy for this? */
/* Set the IP options */
return (0);
}