tnet.c revision 222c5bce8762079550e5ccd485a12de1fff5a82e
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <netinet/in_systm.h>
#include <inet/ipclassifier.h>
/* tunable for strict error-reply behavior (TCP RST and ICMP Unreachable) */
int tsol_strict_error;
/*
* Some notes on the Trusted Solaris IRE gateway security attributes:
*
* When running in Trusted mode, the routing subsystem determines whether or
* not a packet can be delivered to an off-link host (not directly reachable
* through an interface) based on the accreditation checks of the packet's
* security attributes against those associated with the next-hop gateway.
*
* The next-hop gateway's security attributes can be derived from two sources
* (in order of preference): route-related and the host database. A Trusted
* system must be configured with at least the host database containing an
* entry for the next-hop gateway, or otherwise no accreditation checks can
* be performed, which may result in the inability to send packets to any
* off-link destination host.
*
* The major differences between the two sources are the number and type of
* security attributes used for accreditation checks. A host database entry
* can contain at most one set of security attributes, specific only to the
* next-hop gateway. On contrast, route-related security attributes are made
* up of a collection of security attributes for the distant networks, and
* are grouped together per next-hop gateway used to reach those networks.
* This is the preferred method, and the routing subsystem will fallback to
* the host database entry only if there are no route-related attributes
* associated with the next-hop gateway.
*
* INTERFACE type) are initialized to contain a placeholder to store this
* information. The ire_gw_secattr structure gets allocated, initialized
* and associated with the IRE during the time of the IRE creation. The
* initialization process also includes resolving the host database entry
* of the next-hop gateway for fallback purposes. It does not include any
* route-related attribute setup, as that process comes separately as part
*
* The underlying logic which involves associating IREs with the gateway
* security attributes are represented by the following data structures:
*
* tsol_gcdb_t, or "gcdb"
*
* - This is a system-wide collection of records containing the
* currently used route-related security attributes, which are fed
*
* tsol_gc_t, or "gc"
*
* - This is the gateway credential structure, and it provides for the
* only mechanism to access the contents of gcdb. More than one gc
* entries may refer to the same gcdb record. gc's in the system are
* grouped according to the next-hop gateway address.
*
* tsol_gcgrp_t, or "gcgrp"
*
* - Group of gateway credentials, and is unique per next-hop gateway
* address. When the group is not empty, i.e. when gcgrp_count is
* greater than zero, it contains one or more gc's, each pointing to
* a gcdb record which indicates the gateway security attributes
* associated with the next-hop gateway.
*
* The fields of the tsol_ire_gw_secattr_t used from within the IRE are:
*
* igsa_lock
*
* - Lock that protects all fields within tsol_ire_gw_secattr_t.
*
* igsa_rhc
*
* - Remote host cache database entry of next-hop gateway. This is
* used in the case when there are no route-related attributes
* configured for the IRE.
*
* igsa_gc
*
* - A set of route-related attributes that only get set for prefix
* IREs. If this is non-NULL, the prefix IRE has been associated
* with a set of gateway security attributes by way of route add/
* change functionality. This field stays NULL for IRE_CACHEs.
*
* igsa_gcgrp
*
* - Group of gc's which only gets set for IRE_CACHEs. Each of the gc
* points to a gcdb record that contains the security attributes
* used to perform the credential checks of the packet which uses
* the IRE. If the group is not empty, the list of gc's can be
* traversed starting at gcgrp_head. This field stays NULL for
* prefix IREs.
*/
static kmem_cache_t *ire_gw_secattr_cache;
#define GCDB_HASH_SIZE 101
#define GCGRP_HASH_SIZE 101
#define GCDB_REFRELE(p) { \
mutex_enter(&gcdb_lock); \
ASSERT((p)->gcdb_refcnt > 0); \
if (--((p)->gcdb_refcnt) == 0) \
gcdb_inactive(p); \
mutex_exit(&gcdb_lock); \
}
static int gcdb_hash_size = GCDB_HASH_SIZE;
static int gcgrp_hash_size = GCGRP_HASH_SIZE;
static mod_hash_t *gcdb_hash;
static mod_hash_t *gcgrp4_hash;
static mod_hash_t *gcgrp6_hash;
static void gcdb_inactive(tsol_gcdb_t *);
static int ire_gw_secattr_constructor(void *, void *, int);
static void ire_gw_secattr_destructor(void *, void *);
void
tnet_init(void)
{
}
void
tnet_fini(void)
{
}
/* ARGSUSED */
static int
{
return (0);
}
/* ARGSUSED */
static void
{
}
{
}
void
{
}
}
}
}
/* ARGSUSED */
static uint_t
{
int i;
/* See comments in hash_bylabel in zone.c for details */
i = 1;
/* using 2^n + 1, 1 <= n <= 16 as source of many primes */
up++;
i++;
}
return (hash);
}
static int
{
return (0);
/* No match; not found */
return (-1);
}
/* ARGSUSED */
static uint_t
{
return (idx);
}
static int
{
/* Address family must match */
return (-1);
return (0);
/* No match; not found */
return (-1);
}
#define RTSAFLAGS "\20\11cipso\3doi\2max_sl\1min_sl"
int
{
/* RTSA_CIPSO must be set, and DOI must not be zero */
"rtsa(1) lacks flag or has 0 doi.",
return (EINVAL);
}
/*
* SL range must be specified, and it must have its
* upper bound dominating its lower bound.
*/
"rtsa(1) min_sl and max_sl not set or max_sl is "
return (EINVAL);
}
return (0);
}
/*
* A brief explanation of the reference counting scheme:
*
* Prefix IREs have a non-NULL igsa_gc and a NULL igsa_gcgrp;
* IRE_CACHEs have it vice-versa.
*
* Apart from dynamic references due to to reference holds done
* actively by threads, we have the following references:
*
* gcdb_refcnt:
* - Every tsol_gc_t pointing to a tsol_gcdb_t contributes a reference
* to the gcdb_refcnt.
*
* gc_refcnt:
* - A prefix IRE that points to an igsa_gc contributes a reference
* to the gc_refcnt.
*
* gcgrp_refcnt:
* - An IRE_CACHE that points to an igsa_gcgrp contributes a reference
* to the gcgrp_refcnt of the associated tsol_gcgrp_t.
* - Every tsol_gc_t in the chain headed by tsol_gcgrp_t contributes
* a reference to the gcgrp_refcnt.
*/
static tsol_gcdb_t *
{
if (rtsa_validate(rp) != 0)
return (NULL);
/* Find a copy in the cache; otherwise, create one and cache it */
(mod_hash_val_t *)&gcdb) == 0) {
gcdb->gcdb_refcnt++;
} else if (alloc) {
if (mod_hash_insert(gcdb_hash,
(mod_hash_val_t)gcdb) != 0) {
return (NULL);
}
"gcdb(1) inserted in gcdb_hash(global)",
tsol_gcdb_t *, gcdb);
}
}
return (gcdb);
}
static void
{
(mod_hash_val_t *)&gcdb);
"gcdb(1) removed from gcdb_hash(global)",
tsol_gcdb_t *, gcdb);
}
{
*gcgrp_xtrarefp = B_TRUE;
return (NULL);
}
char *, "found gc(1) in gcgrp(2)",
return (gc);
}
}
} else {
}
gcgrp->gcgrp_count++;
/* caller has incremented gcgrp reference for us */
tsol_gcgrp_t *, gcgrp);
}
return (gc);
}
void
{
else
else
gcgrp->gcgrp_count--;
/* drop lock before it's destroyed */
"removed inactive gc(1) from gcgrp(2)",
}
{
(mod_hash_val_t *)&gcgrp) == 0) {
gcgrp->gcgrp_refcnt++;
mod_hash_t *, hashp);
} else if (alloc) {
if (mod_hash_insert(hashp,
(mod_hash_val_t)gcgrp) != 0) {
return (NULL);
}
char *, "inserted gcgrp(1) in hash(2)",
}
}
return (gcgrp);
}
void
{
(mod_hash_val_t *)&gcgrp);
"removed inactive gcgrp(1) from hash(2)",
}
/*
* Converts CIPSO option to sensitivity label.
* Validity checks based on restrictions defined in
* COMMERCIAL IP SECURITY OPTION (CIPSO 2.2) (draft-ietf-cipso-ipsecurity)
*/
static boolean_t
{
const struct cipso_tag_type_1 *tt1;
return (B_FALSE);
return (B_TRUE);
}
/*
* Parse the CIPSO label in the incoming packet and construct a ts_label_t
* that reflects the CIPSO label and attach it to the dblk cred. Later as
* the mblk flows up through the stack any code that needs to examine the
* packet label can inspect the label from the dblk cred. This function is
* called right in ip_rput for all packets, i.e. locally destined and
* to be forwarded packets. The forwarding path needs to examine the label
* to determine how to forward the packet.
*
* For IPv4, IP header options have been pulled up, but other headers might not
* have been. For IPv6, any hop-by-hop options have been pulled up, but any
* other headers might not be present.
*/
{
const cipso_option_t *co;
const void *src;
if (version == IPV4_VERSION) {
} else {
&after_secopt, &hbh_needed);
/* tsol_find_secopt_v6 guarantees some sanity */
opt_ptr += 2;
if (doi == IP6LS_DOI_V4 &&
}
}
}
}
switch (label_type) {
case OPT_CIPSO:
/*
* Convert the CIPSO label to the internal format
* and attach it to the dblk cred.
* Validity checks based on restrictions defined in
* COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
* (draft-ietf-cipso-ipsecurity)
*/
return (B_FALSE);
if ((co->cipso_length <
return (B_FALSE);
return (B_FALSE);
break;
case OPT_NONE:
/*
* Handle special cases that are not currently labeled, even
* though the sending system may otherwise be configured as
* labeled.
* - IGMP
* - IPv4 ICMP Router Discovery
* - IPv6 Neighbor Discovery
*/
if (version == IPV4_VERSION) {
return (B_TRUE);
return (B_FALSE);
}
return (B_TRUE);
}
} else {
return (B_FALSE);
}
return (B_TRUE);
}
}
/*
* Look up the tnrhtp database and get the implicit label
* that is associated with this unlabeled host and attach
* it to the packet.
*/
return (B_FALSE);
/* If the sender is labeled, drop the unlabeled packet. */
pr_addr_dbg("unlabeled packet forged from %s\n",
return (B_FALSE);
}
break;
default:
return (B_FALSE);
}
/* Make sure no other thread is messing with this mblk */
return (B_FALSE);
} else {
return (B_FALSE);
}
/*
* If the source was unlabeled, then flag as such,
* while remembering that CIPSO routers add headers.
*/
if (label_type == OPT_NONE)
else if (label_type == OPT_CIPSO) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* This routine determines whether the given packet should be accepted locally.
* address in the remote host database.
*/
{
tsol_tpc_t *tp;
/*
* The cases in which this can happen are:
* - IPv6 Router Alert, where ip_rput_data_v6 deliberately skips
* over the label attachment process.
* - MLD output looped-back to ourselves.
* - IPv4 Router Discovery, where tsol_get_pkt_label intentionally
* avoids the labeling process.
* We trust that all valid paths in the code set the cred pointer when
* needed.
*/
return (B_TRUE);
/*
* If this packet is from the inside (not a remote host) and has the
* same zoneid as the selected destination, then no checks are
* necessary. Membership in the zone is enough proof. This is
* intended to be a hot path through this function.
*/
if (!crisremote(credp) &&
return (B_TRUE);
/*
* MLPs are always validated using the range and set of the local
* address, even when the remote host is unlabeled.
*/
/* LINTED: no consequent */
;
/*
* If this is a packet from an unlabeled sender, then we must apply
* different rules. If the label is equal to the zone's label, then
* it's allowed. If it's not equal, but the zone is either the global
* zone or the label is dominated by the zone's label, then allow it
* as long as it's in the range configured for the destination.
*/
return (B_TRUE);
/*
* conn_zoneid is global for an exclusive stack, thus we use
* conn_cred to get the zoneid
*/
if (!connp->conn_mac_exempt ||
char *,
"unlabeled packet mp(1) fails mac for conn(2)",
return (B_FALSE);
}
/*
* If this is a packet from a labeled sender, verify the
* label on the packet matches the connection label.
*/
} else {
char *,
"packet mp(1) failed label match to SLP conn(2)",
return (B_FALSE);
}
/*
* No further checks will be needed if this is a zone-
* specific address because (1) The process for bringing up
* the interface ensures the zone's label is within the zone-
* specific address's valid label range; (2) For cases where
* the conn is bound to the unspecified addresses, ip fanout
* logic ensures conn's zoneid equals the dest addr's zoneid;
* (3) Mac-exempt and mlp logic above already handle all
* cases where the zone label may not be the same as the
* conn label.
*/
if (!shared_addr)
return (B_TRUE);
}
char *, "dropping mp(1), host(2) lacks entry",
return (B_FALSE);
}
/*
* The local host address should not be unlabeled at this point. The
* only way this can happen is that the destination isn't unicast. We
* assume that the packet should not have had a label, and thus should
* have been handled by the TSLF_UNLABELED logic above.
*/
"mp(1) unlabeled source, but tp is not unlabeled.",
"delivering mp(1), found unrecognized tpc(2) type.",
"mp(1) could not be delievered to tp(2), doi mismatch",
"mp(1) could not be delievered to tp(2), bad mac",
} else {
}
return (retv);
}
{
/* We are bootstrapping or the internal template was never deleted */
return (B_TRUE);
B_FALSE);
return (B_FALSE);
B_FALSE);
} else {
B_FALSE);
return (B_FALSE);
B_FALSE);
}
return (B_FALSE);
}
/*
* Check that the packet's label is in the correct range for labeled
* sender, or is equal to the default label for unlabeled sender.
*/
} else if (check_host) {
/*
* Until we have SL range in the Zone structure, pass it
* when our own address lookup returned an internal entry.
*/
case UNLABELED:
break;
case SUN_CIPSO:
break;
default:
}
return (retv);
}
/*
* This routine determines whether a response to a failed packet delivery or
* connection should be sent back. By default, the policy is to allow such
* messages to be sent at all times, as these messages reveal little useful
*
* If tsol_strict_error is set, then we do strict tests: if the packet label is
* return B_FALSE, which causes the packet to be dropped silently.
*
* Note that tsol_get_pkt_label will cause the packet to drop if the sender is
* marked as labeled in the remote host database, but the packet lacks a label.
* This means that we don't need to do a lookup on the source; the
* TSLF_UNLABELED flag is sufficient.
*/
{
/* Caller must pull up at least the IP header */
if (!tsol_strict_error)
return (B_TRUE);
/* We are bootstrapping or the internal template was never deleted */
return (B_TRUE);
} else {
}
} else {
/*
* If we're in the midst of forwarding, then the destination
* address might not be labeled. In that case, allow unlabeled
* packets through only if the default label is the same, and
* labeled ones if they dominate.
*/
case UNLABELED:
} else {
}
break;
case SUN_CIPSO:
break;
default:
break;
}
}
return (retv);
}
/*
* Finds the zone associated with the given packet. Returns GLOBAL_ZONEID if
* the zone cannot be located.
*
* This is used by the classifier when the packet matches an ALL_ZONES IRE, and
* there's no MLP defined.
*
* Note that we assume that this is only invoked in the ALL_ZONES case.
* Handling other cases would require handle exclusive stack zones where either
* this routine or the callers would have to map from
* the zoneid (zone->zone_id) to what IP uses in conn_zoneid etc.
*/
{
return (zoneid);
}
}
}
return (GLOBAL_ZONEID);
}
int
{
int error = 0;
if (!is_system_labeled() ||
goto done;
/*
* If we don't have a label to compare with, or the IRE does not
* contain any gateway security attributes, there's not much that
* we can do. We let the former case pass, and the latter fail,
* since the IRE doesn't qualify for a match due to the lack of
* security attributes.
*/
char *,
"ire(1) lacks ire_gw_secattr matching label(2)",
}
goto done;
}
/*
* The possible lock order scenarios related to the tsol gateway
* attribute locks are documented at the beginning of ip.c in the
* lock order scenario section.
*/
/*
* Depending on the IRE type (prefix vs. cache), we seek the group
* structure which contains all security credentials of the gateway.
* A prefix IRE is associated with at most one gateway credential,
* while a cache IRE is associated with every credentials that the
* gateway has.
*/
/* gc group is empty, so the drop lock now */
}
}
/*
* If our cached entry has grown stale, then discard it so we
* can get a new one.
*/
} else {
}
}
/* Last attempt at loading the template had failed; try again */
} else {
}
}
/* We've found a gateway address to do the template lookup */
/*
* Note that if the lookup above returned an
* internal template, we'll use it for the
* time being, and do another lookup next
* time around.
*/
/* Another thread has loaded the template? */
/* reload, it could be different */
} else {
}
/*
* Hold an extra reference just like we did
* above prior to dropping the igsa_lock.
*/
}
}
}
/* Gateway template not found */
/*
* If destination address is directly reachable through an
* interface rather than through a learned route, pass it.
*/
"ire(1), label(2) off-link with no gw_rhc",
}
goto done;
}
/*
* In the case of IRE_CACHE we've got one or more gateway
* security credentials to compare against the passed in label.
* Perform label range comparison against each security
* credential of the gateway. In the case of a prefix ire
* we need to match against the security attributes of
* just the route itself, so the loop is executed only once.
*/
do {
break;
else
char *, "ire(1), tsl(2): all gc failed match",
}
} else {
/*
* We didn't find any gateway credentials in the IRE
* attributes; fall back to the gateway's template for
* label range checks, if we are required to do so.
*/
case SUN_CIPSO:
char *, "ire(1), tsl(2), gw_rhc(3) "
"failed match (cipso gw)",
tsol_tnrhc_t *, gw_rhc);
}
break;
case UNLABELED:
char *, "ire(1), tsl(2), gw_rhc(3) "
"failed match (unlabeled gw)",
tsol_tnrhc_t *, gw_rhc);
}
break;
}
}
done:
}
return (error);
}
/*
* Performs label accreditation checks for packet forwarding.
*
* Returns a pointer to the modified mblk if allowed for forwarding,
* or NULL if the packet must be dropped.
*/
mblk_t *
{
const void *pdst;
const void *psrc;
/*
* off_link is TRUE if destination not directly reachable.
* Surya note: we avoid creation of per-dst IRE_CACHE entries
* for forwarded packets, so we set off_link to be TRUE
* if the packet dst is different from the ire_addr of
* the ire for the nexthop.
*/
} else {
proto != IPPROTO_ICMPV6) {
&nexthdrp)) {
/* malformed packet; drop it */
return (NULL);
}
}
/* destination not directly reachable? */
}
return (mp);
/*
* Without a template we do not know if forwarding
* violates MAC
*/
"mp(1) dropped, no template for destination ip4|6(2)",
return (NULL);
}
/*
* Gateway template must have existed for off-link destinations,
* since tsol_ire_match_gwattr has ensured such condition.
*/
/*
* Surya note: first check if we can get the gw_rhtp from
* the ire_gw_secattr->igsa_rhc; if this is null, then
* do a lookup based on the ire_addr (address of gw)
*/
} else {
/*
* use the ire_addr if this is the IRE_CACHE of nexthop
*/
&ire->ire_gateway_addr);
}
"mp(1) dropped, no gateway in ire attributes(2)",
goto keep_label;
}
}
"mp(1) dropped, no gateway in ire attributes(2)",
goto keep_label;
}
/*
* Check that the label for the packet is acceptable
* by destination host; otherwise, drop it.
*/
case SUN_CIPSO:
"labeled packet mp(1) dropped, label(2) fails "
"destination(3) accredation check",
tsol_tpc_t *, dst_rhtp);
goto keep_label;
}
break;
case UNLABELED:
"unlabeled packet mp(1) dropped, label(2) fails "
"destination(3) accredation check",
tsol_tpc_t *, dst_rhtp);
goto keep_label;
}
break;
}
if (label_type == OPT_CIPSO) {
/*
* We keep the label on any of the following cases:
*
* 2. The unlabeled destination is off-link,
* and the next hop gateway is labeled.
*/
(off_link &&
goto keep_label;
/*
* Strip off the CIPSO option from the packet because: the
* unlabeled destination host is directly reachable through
* an interface (on-link); or, the unlabeled destination host
* is not directly reachable (off-link), and the next hop
* gateway is unlabeled.
*/
if (adjust != 0) {
/* adjust is negative */
ipha->ipha_hdr_checksum = 0;
}
char *,
"mp(1) adjusted(2) for CIPSO option removal",
}
goto keep_label;
}
/*
* We need to add CIPSO option if the destination or the next hop
* gateway is labeled. Otherwise, pass the packet as is.
*/
goto keep_label;
goto keep_label;
}
ipha->ipha_hdr_checksum = 0;
}
return (mp);
}
/*
* Name: tsol_pmtu_adjust()
*
* Returns the adjusted mtu after removing security option.
* sender or if pkt_diff indicates this system enlarged the packet.
*/
{
int label_adj = 0;
void *src;
/*
* Note: label_adj is non-positive, indicating the number of
* bytes removed by removing the security option from the
* header.
*/
return (mtu);
}
} else {
return (mtu);
}
/*
* Make pkt_diff non-negative and the larger of the bytes
* previously added (if any) or just removed, since label
* addition + subtraction may not be completely idempotent.
*/
}
/*
* Name: tsol_rtsa_init()
*
* Normal: Sanity checks on the route security attributes provided by
* user. Convert it into a route security parameter list to
* be returned to caller.
*
* Output: EINVAL if bad security attributes in the routing message
* ENOMEM if unable to allocate data structures
* 0 otherwise.
*
* Note: On input, cp must point to the end of any addresses in
* the rt_msghdr_t structure.
*/
int
{
int err;
/*
* In theory, we could accept as many security attributes configured
* per route destination. However, the current design is limited
* such that at most only one set security attributes is allowed to
* be associated with a prefix IRE. We therefore assert for now.
*/
/* LINTED */
return (0);
return (EINVAL);
return (EINVAL);
/*
* Trying to add route security attributes when system
* labeling service is not available, or when user supllies
* more than the maximum number of security attributes
* allowed per request.
*/
if ((sacnt > 0 && !is_system_labeled()) ||
return (EINVAL);
/* Ensure valid credentials */
rtsa_attr[0])) != 0) {
return (err);
}
return (0);
}
int
{
/*
* The only time that attrp can be NULL is when this routine is
* called for the first time during the creation/initialization
* of the corresponding IRE. It will only get cleared when the
* IRE is deleted.
*/
return (ENOMEM);
} else {
}
}
/*
* References already held by caller and we keep them;
* note that both gc and gcgrp may be set to NULL to
* clear out igsa_gc and igsa_gcgrp, respectively.
*/
}
/*
* Intialize the template for gateway; we use the gateway's
* address found in either the passed in gateway credential
* or group pointer, or the ire_gateway_addr{_v6} field.
*/
/*
* Caller is holding a reference, and that we don't
* need to hold any lock to access the address.
*/
if (ipversion == IPV4_VERSION) {
} else {
}
} else if (ipversion == IPV6_VERSION &&
} else if (ipversion == IPV4_VERSION &&
}
/*
* Lookup the gateway template; note that we could get an internal
* template here, which we cache anyway. During IRE matching, we'll
* try to update this gateway template cache and hopefully get a
* real one.
*/
}
if (exists)
return (0);
}
/*
* This function figures the type of MLP that we'll be using based on the
* address that the user is binding and the zone. If the address is
* unspecified, then we're looking at both private and shared. If it's one
* of the zone's private addresses, then it's private only. If it's one
* of the global addresses, then it's shared only.
*
* If we can't figure out what it is, then return mlptSingle. That's actually
* an error case.
*
* The callers are assume to pass in zone->zone_id and not the zoneid that
* is stored in a conn_t (since the latter will be GLOBAL_ZONEID in an
* exclusive stack zone).
*/
{
/*
* For exclusive stacks we set the zoneid to zero
* to operate as if in the global zone for IRE and conn_t comparisons.
*/
else
if (version == IPV6_VERSION &&
}
if (version == IPV4_VERSION) {
if (in4 == INADDR_ANY) {
return (mlptBoth);
}
} else {
return (mlptBoth);
}
}
/*
* If we can't find the IRE, then we have to behave exactly like
* ip_bind_laddr{,_v6}. That means looking up the IPIF so that users
* can bind to addresses on "down" interfaces.
*
* If we can't find that either, then the bind is going to fail, so
* just give up. Note that there's a miniscule chance that the address
* is in transition, but we don't bother handling that.
*/
if (version == IPV4_VERSION)
else
return (mlptSingle);
}
} else {
}
}
/*
* Since we are configuring local interfaces, and we know trusted
* extension CDE requires local interfaces to be cipso host type in
* order to function correctly, we'll associate a cipso template
* to each local interface and let the interface come up. Configuring
* a local interface to be "unlabeled" host type is a configuration error.
* We'll override that error and make the interface host type to be cipso
* here.
*
* The code is optimized for the usual "success" case and unwinds things on
* error. We don't want to go to the trouble and expense of formatting the
* interface name for the usual case where everything is configured correctly.
*/
{
tsol_tpc_t *tp;
char addrbuf[INET6_ADDRSTRLEN];
int af;
const void *addr;
const char *ifname;
} else {
}
/* assumes that ALL_ZONES implies that there is no exclusive stack */
/* Shared stack case */
} else {
/* Exclusive stack case */
}
}
/*
* If it's CIPSO and an all-zones address, then we're done.
* If it's a CIPSO zone specific address, the zone's label
* must be in the range or set specified in the template.
* When the remote host entry is missing or the template
* type is incorrect for this interface, we create a
* CIPSO host entry in kernel and allow the interface to be
* brought up as CIPSO type.
*/
/* The all-zones case */
/* The local-zone case */
return (B_TRUE);
}
}
} else {
}
} else {
}
if (retval) {
/*
* we've corrected a config error and let the interface
* come up as cipso. Need to insert an rhent.
*/
} else {
}
}
}
return (retval);
}