1*45916cd2Sjpk /* 2*45916cd2Sjpk * CDDL HEADER START 3*45916cd2Sjpk * 4*45916cd2Sjpk * The contents of this file are subject to the terms of the 5*45916cd2Sjpk * Common Development and Distribution License (the "License"). 6*45916cd2Sjpk * You may not use this file except in compliance with the License. 7*45916cd2Sjpk * 8*45916cd2Sjpk * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*45916cd2Sjpk * or http://www.opensolaris.org/os/licensing. 10*45916cd2Sjpk * See the License for the specific language governing permissions 11*45916cd2Sjpk * and limitations under the License. 12*45916cd2Sjpk * 13*45916cd2Sjpk * When distributing Covered Code, include this CDDL HEADER in each 14*45916cd2Sjpk * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*45916cd2Sjpk * If applicable, add the following below this CDDL HEADER, with the 16*45916cd2Sjpk * fields enclosed by brackets "[]" replaced with your own identifying 17*45916cd2Sjpk * information: Portions Copyright [yyyy] [name of copyright owner] 18*45916cd2Sjpk * 19*45916cd2Sjpk * CDDL HEADER END 20*45916cd2Sjpk */ 21*45916cd2Sjpk /* 22*45916cd2Sjpk * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*45916cd2Sjpk * Use is subject to license terms. 24*45916cd2Sjpk */ 25*45916cd2Sjpk 26*45916cd2Sjpk #pragma ident "%Z%%M% %I% %E% SMI" 27*45916cd2Sjpk 28*45916cd2Sjpk #include <sys/systm.h> 29*45916cd2Sjpk #include <sys/types.h> 30*45916cd2Sjpk #include <sys/stream.h> 31*45916cd2Sjpk #include <sys/kmem.h> 32*45916cd2Sjpk #include <sys/strsubr.h> 33*45916cd2Sjpk #include <sys/cmn_err.h> 34*45916cd2Sjpk #include <sys/debug.h> 35*45916cd2Sjpk #include <sys/param.h> 36*45916cd2Sjpk #include <sys/model.h> 37*45916cd2Sjpk #include <sys/errno.h> 38*45916cd2Sjpk #include <sys/modhash.h> 39*45916cd2Sjpk 40*45916cd2Sjpk #include <sys/policy.h> 41*45916cd2Sjpk #include <sys/tsol/label.h> 42*45916cd2Sjpk #include <sys/tsol/tsyscall.h> 43*45916cd2Sjpk #include <sys/tsol/tndb.h> 44*45916cd2Sjpk #include <sys/tsol/tnet.h> 45*45916cd2Sjpk #include <sys/disp.h> 46*45916cd2Sjpk 47*45916cd2Sjpk #include <inet/ip.h> 48*45916cd2Sjpk #include <inet/ip6.h> 49*45916cd2Sjpk #include <sys/sdt.h> 50*45916cd2Sjpk 51*45916cd2Sjpk static mod_hash_t *tpc_name_hash; /* hash of cache entries by name */ 52*45916cd2Sjpk static kmutex_t tpc_lock; 53*45916cd2Sjpk 54*45916cd2Sjpk static tsol_tpc_t *tpc_unlab; 55*45916cd2Sjpk 56*45916cd2Sjpk /* 57*45916cd2Sjpk * tnrhc_table and tnrhc_table_v6 are similar to the IP forwarding tables 58*45916cd2Sjpk * in organization and search. The tnrhc_table[_v6] is an array of 33/129 59*45916cd2Sjpk * pointers to the 33/129 tnrhc tables indexed by the prefix length. 60*45916cd2Sjpk * A largest prefix match search is done by find_rhc_v[46] and it walks the 61*45916cd2Sjpk * tables from the most specific to the least specific table. Table 0 62*45916cd2Sjpk * corresponds to the single entry for 0.0.0.0/0 or ::0/0. 63*45916cd2Sjpk */ 64*45916cd2Sjpk tnrhc_hash_t *tnrhc_table[TSOL_MASK_TABLE_SIZE]; 65*45916cd2Sjpk tnrhc_hash_t *tnrhc_table_v6[TSOL_MASK_TABLE_SIZE_V6]; 66*45916cd2Sjpk kmutex_t tnrhc_g_lock; 67*45916cd2Sjpk 68*45916cd2Sjpk static void tsol_create_i_tmpls(void); 69*45916cd2Sjpk 70*45916cd2Sjpk static void tsol_create_i_tnrh(const tnaddr_t *); 71*45916cd2Sjpk 72*45916cd2Sjpk /* List of MLPs on valid on shared addresses */ 73*45916cd2Sjpk static tsol_mlp_list_t shared_mlps; 74*45916cd2Sjpk 75*45916cd2Sjpk /* 76*45916cd2Sjpk * Convert length for a mask to the mask. 77*45916cd2Sjpk */ 78*45916cd2Sjpk static ipaddr_t 79*45916cd2Sjpk tsol_plen_to_mask(uint_t masklen) 80*45916cd2Sjpk { 81*45916cd2Sjpk return (masklen == 0 ? 0 : htonl(IP_HOST_MASK << (IP_ABITS - masklen))); 82*45916cd2Sjpk } 83*45916cd2Sjpk 84*45916cd2Sjpk /* 85*45916cd2Sjpk * Convert a prefix length to the mask for that prefix. 86*45916cd2Sjpk * Returns the argument bitmask. 87*45916cd2Sjpk */ 88*45916cd2Sjpk static void 89*45916cd2Sjpk tsol_plen_to_mask_v6(uint_t plen, in6_addr_t *bitmask) 90*45916cd2Sjpk { 91*45916cd2Sjpk uint32_t *ptr; 92*45916cd2Sjpk 93*45916cd2Sjpk ASSERT(plen <= IPV6_ABITS); 94*45916cd2Sjpk 95*45916cd2Sjpk ptr = (uint32_t *)bitmask; 96*45916cd2Sjpk while (plen >= 32) { 97*45916cd2Sjpk *ptr++ = 0xffffffffU; 98*45916cd2Sjpk plen -= 32; 99*45916cd2Sjpk } 100*45916cd2Sjpk if (plen > 0) 101*45916cd2Sjpk *ptr++ = htonl(0xffffffff << (32 - plen)); 102*45916cd2Sjpk while (ptr < (uint32_t *)(bitmask + 1)) 103*45916cd2Sjpk *ptr++ = 0; 104*45916cd2Sjpk } 105*45916cd2Sjpk 106*45916cd2Sjpk boolean_t 107*45916cd2Sjpk tnrhc_init_table(tnrhc_hash_t *table[], short prefix_len, int kmflag) 108*45916cd2Sjpk { 109*45916cd2Sjpk int i; 110*45916cd2Sjpk 111*45916cd2Sjpk mutex_enter(&tnrhc_g_lock); 112*45916cd2Sjpk 113*45916cd2Sjpk if (table[prefix_len] == NULL) { 114*45916cd2Sjpk table[prefix_len] = (tnrhc_hash_t *) 115*45916cd2Sjpk kmem_zalloc(TNRHC_SIZE * sizeof (tnrhc_hash_t), kmflag); 116*45916cd2Sjpk if (table[prefix_len] == NULL) { 117*45916cd2Sjpk mutex_exit(&tnrhc_g_lock); 118*45916cd2Sjpk return (B_FALSE); 119*45916cd2Sjpk } 120*45916cd2Sjpk for (i = 0; i < TNRHC_SIZE; i++) { 121*45916cd2Sjpk mutex_init(&table[prefix_len][i].tnrh_lock, 122*45916cd2Sjpk NULL, MUTEX_DEFAULT, 0); 123*45916cd2Sjpk } 124*45916cd2Sjpk } 125*45916cd2Sjpk mutex_exit(&tnrhc_g_lock); 126*45916cd2Sjpk return (B_TRUE); 127*45916cd2Sjpk } 128*45916cd2Sjpk 129*45916cd2Sjpk void 130*45916cd2Sjpk tcache_init(void) 131*45916cd2Sjpk { 132*45916cd2Sjpk tnaddr_t address; 133*45916cd2Sjpk 134*45916cd2Sjpk /* 135*45916cd2Sjpk * Note: unable to use mod_hash_create_strhash here, since it's 136*45916cd2Sjpk * assymetric. It assumes that the user has allocated exactly 137*45916cd2Sjpk * strlen(key) + 1 bytes for the key when inserted, and attempts to 138*45916cd2Sjpk * kmem_free that memory on a delete. 139*45916cd2Sjpk */ 140*45916cd2Sjpk tpc_name_hash = mod_hash_create_extended("tnrhtpc_by_name", 256, 141*45916cd2Sjpk mod_hash_null_keydtor, mod_hash_null_valdtor, mod_hash_bystr, 142*45916cd2Sjpk NULL, mod_hash_strkey_cmp, KM_SLEEP); 143*45916cd2Sjpk mutex_init(&tpc_lock, NULL, MUTEX_DEFAULT, NULL); 144*45916cd2Sjpk 145*45916cd2Sjpk mutex_init(&tnrhc_g_lock, NULL, MUTEX_DEFAULT, NULL); 146*45916cd2Sjpk 147*45916cd2Sjpk /* label_init always called before tcache_init */ 148*45916cd2Sjpk ASSERT(l_admin_low != NULL && l_admin_high != NULL); 149*45916cd2Sjpk 150*45916cd2Sjpk /* Initialize the zeroth table prior to loading the 0.0.0.0 entry */ 151*45916cd2Sjpk (void) tnrhc_init_table(tnrhc_table, 0, KM_SLEEP); 152*45916cd2Sjpk (void) tnrhc_init_table(tnrhc_table_v6, 0, KM_SLEEP); 153*45916cd2Sjpk /* 154*45916cd2Sjpk * create an internal host template called "_unlab" 155*45916cd2Sjpk */ 156*45916cd2Sjpk tsol_create_i_tmpls(); 157*45916cd2Sjpk 158*45916cd2Sjpk /* 159*45916cd2Sjpk * create a host entry, 0.0.0.0 = _unlab 160*45916cd2Sjpk */ 161*45916cd2Sjpk bzero(&address, sizeof (tnaddr_t)); 162*45916cd2Sjpk address.ta_family = AF_INET; 163*45916cd2Sjpk tsol_create_i_tnrh(&address); 164*45916cd2Sjpk 165*45916cd2Sjpk /* 166*45916cd2Sjpk * create a host entry, ::0 = _unlab 167*45916cd2Sjpk */ 168*45916cd2Sjpk address.ta_family = AF_INET6; 169*45916cd2Sjpk tsol_create_i_tnrh(&address); 170*45916cd2Sjpk 171*45916cd2Sjpk rw_init(&shared_mlps.mlpl_rwlock, NULL, RW_DEFAULT, NULL); 172*45916cd2Sjpk } 173*45916cd2Sjpk 174*45916cd2Sjpk /* Called only by the TNRHC_RELE macro when the refcount goes to zero. */ 175*45916cd2Sjpk void 176*45916cd2Sjpk tnrhc_free(tsol_tnrhc_t *tnrhc) 177*45916cd2Sjpk { 178*45916cd2Sjpk /* 179*45916cd2Sjpk * We assert rhc_invalid here to make sure that no new thread could 180*45916cd2Sjpk * possibly end up finding this entry. If it could, then the 181*45916cd2Sjpk * mutex_destroy would panic. 182*45916cd2Sjpk */ 183*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l3__tnrhcfree, tsol_tnrhc_t *, tnrhc); 184*45916cd2Sjpk ASSERT(tnrhc->rhc_next == NULL && tnrhc->rhc_invalid); 185*45916cd2Sjpk mutex_exit(&tnrhc->rhc_lock); 186*45916cd2Sjpk mutex_destroy(&tnrhc->rhc_lock); 187*45916cd2Sjpk if (tnrhc->rhc_tpc != NULL) 188*45916cd2Sjpk TPC_RELE(tnrhc->rhc_tpc); 189*45916cd2Sjpk kmem_free(tnrhc, sizeof (*tnrhc)); 190*45916cd2Sjpk } 191*45916cd2Sjpk 192*45916cd2Sjpk /* Called only by the TPC_RELE macro when the refcount goes to zero. */ 193*45916cd2Sjpk void 194*45916cd2Sjpk tpc_free(tsol_tpc_t *tpc) 195*45916cd2Sjpk { 196*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l3__tpcfree, tsol_tpc_t *, tpc); 197*45916cd2Sjpk ASSERT(tpc->tpc_invalid); 198*45916cd2Sjpk mutex_exit(&tpc->tpc_lock); 199*45916cd2Sjpk mutex_destroy(&tpc->tpc_lock); 200*45916cd2Sjpk kmem_free(tpc, sizeof (*tpc)); 201*45916cd2Sjpk } 202*45916cd2Sjpk 203*45916cd2Sjpk /* 204*45916cd2Sjpk * Find and hold a reference to a template entry by name. Ignores entries that 205*45916cd2Sjpk * are being deleted. 206*45916cd2Sjpk */ 207*45916cd2Sjpk static tsol_tpc_t * 208*45916cd2Sjpk tnrhtp_find(const char *name, mod_hash_t *hash) 209*45916cd2Sjpk { 210*45916cd2Sjpk mod_hash_val_t hv; 211*45916cd2Sjpk tsol_tpc_t *tpc = NULL; 212*45916cd2Sjpk 213*45916cd2Sjpk mutex_enter(&tpc_lock); 214*45916cd2Sjpk if (mod_hash_find(hash, (mod_hash_key_t)name, &hv) == 0) { 215*45916cd2Sjpk tpc = (tsol_tpc_t *)hv; 216*45916cd2Sjpk if (tpc->tpc_invalid) 217*45916cd2Sjpk tpc = NULL; 218*45916cd2Sjpk else 219*45916cd2Sjpk TPC_HOLD(tpc); 220*45916cd2Sjpk } 221*45916cd2Sjpk mutex_exit(&tpc_lock); 222*45916cd2Sjpk return (tpc); 223*45916cd2Sjpk } 224*45916cd2Sjpk 225*45916cd2Sjpk static int 226*45916cd2Sjpk tnrh_delete(const tsol_rhent_t *rhent) 227*45916cd2Sjpk { 228*45916cd2Sjpk tsol_tnrhc_t *current; 229*45916cd2Sjpk tsol_tnrhc_t **prevp; 230*45916cd2Sjpk ipaddr_t tmpmask; 231*45916cd2Sjpk in6_addr_t tmpmask_v6; 232*45916cd2Sjpk tnrhc_hash_t *tnrhc_hash; 233*45916cd2Sjpk 234*45916cd2Sjpk if (rhent->rh_address.ta_family == AF_INET) { 235*45916cd2Sjpk if (rhent->rh_prefix < 0 || rhent->rh_prefix > IP_ABITS) 236*45916cd2Sjpk return (EINVAL); 237*45916cd2Sjpk if (tnrhc_table[rhent->rh_prefix] == NULL) 238*45916cd2Sjpk return (ENOENT); 239*45916cd2Sjpk tmpmask = tsol_plen_to_mask(rhent->rh_prefix); 240*45916cd2Sjpk tnrhc_hash = &tnrhc_table[rhent->rh_prefix][ 241*45916cd2Sjpk TSOL_ADDR_HASH(rhent->rh_address.ta_addr_v4.s_addr & 242*45916cd2Sjpk tmpmask, TNRHC_SIZE)]; 243*45916cd2Sjpk } else if (rhent->rh_address.ta_family == AF_INET6) { 244*45916cd2Sjpk if (rhent->rh_prefix < 0 || rhent->rh_prefix > IPV6_ABITS) 245*45916cd2Sjpk return (EINVAL); 246*45916cd2Sjpk if (tnrhc_table_v6[rhent->rh_prefix] == NULL) 247*45916cd2Sjpk return (ENOENT); 248*45916cd2Sjpk tsol_plen_to_mask_v6(rhent->rh_prefix, &tmpmask_v6); 249*45916cd2Sjpk tnrhc_hash = &tnrhc_table_v6[rhent->rh_prefix][ 250*45916cd2Sjpk TSOL_ADDR_MASK_HASH_V6(rhent->rh_address.ta_addr_v6, 251*45916cd2Sjpk tmpmask_v6, TNRHC_SIZE)]; 252*45916cd2Sjpk } else { 253*45916cd2Sjpk return (EAFNOSUPPORT); 254*45916cd2Sjpk } 255*45916cd2Sjpk 256*45916cd2Sjpk /* search for existing entry */ 257*45916cd2Sjpk mutex_enter(&tnrhc_hash->tnrh_lock); 258*45916cd2Sjpk prevp = &tnrhc_hash->tnrh_list; 259*45916cd2Sjpk while ((current = *prevp) != NULL) { 260*45916cd2Sjpk if (TNADDR_EQ(&rhent->rh_address, ¤t->rhc_host)) 261*45916cd2Sjpk break; 262*45916cd2Sjpk prevp = ¤t->rhc_next; 263*45916cd2Sjpk } 264*45916cd2Sjpk 265*45916cd2Sjpk if (current != NULL) { 266*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l2__tnrhdelete_existingrhentry); 267*45916cd2Sjpk *prevp = current->rhc_next; 268*45916cd2Sjpk mutex_enter(¤t->rhc_lock); 269*45916cd2Sjpk current->rhc_next = NULL; 270*45916cd2Sjpk current->rhc_invalid = 1; 271*45916cd2Sjpk mutex_exit(¤t->rhc_lock); 272*45916cd2Sjpk TNRHC_RELE(current); 273*45916cd2Sjpk } 274*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 275*45916cd2Sjpk return (current == NULL ? ENOENT : 0); 276*45916cd2Sjpk } 277*45916cd2Sjpk 278*45916cd2Sjpk /* 279*45916cd2Sjpk * Flush all remote host entries from the database. 280*45916cd2Sjpk * 281*45916cd2Sjpk * Note that the htable arrays themselves do not have reference counters, so, 282*45916cd2Sjpk * unlike the remote host entries, they cannot be freed. 283*45916cd2Sjpk */ 284*45916cd2Sjpk static void 285*45916cd2Sjpk flush_rh_table(tnrhc_hash_t **htable, int nbits) 286*45916cd2Sjpk { 287*45916cd2Sjpk tnrhc_hash_t *hent, *hend; 288*45916cd2Sjpk tsol_tnrhc_t *rhc, *rhnext; 289*45916cd2Sjpk 290*45916cd2Sjpk while (--nbits >= 0) { 291*45916cd2Sjpk if ((hent = htable[nbits]) == NULL) 292*45916cd2Sjpk continue; 293*45916cd2Sjpk hend = hent + TNRHC_SIZE; 294*45916cd2Sjpk while (hent < hend) { 295*45916cd2Sjpk /* 296*45916cd2Sjpk * List walkers hold this lock during the walk. It 297*45916cd2Sjpk * protects tnrh_list and rhc_next. 298*45916cd2Sjpk */ 299*45916cd2Sjpk mutex_enter(&hent->tnrh_lock); 300*45916cd2Sjpk rhnext = hent->tnrh_list; 301*45916cd2Sjpk hent->tnrh_list = NULL; 302*45916cd2Sjpk mutex_exit(&hent->tnrh_lock); 303*45916cd2Sjpk /* 304*45916cd2Sjpk * There may still be users of the rhcs at this point, 305*45916cd2Sjpk * but not of the list or its next pointer. Thus, the 306*45916cd2Sjpk * only thing that would need to be done under a lock 307*45916cd2Sjpk * is setting the invalid bit, but that's atomic 308*45916cd2Sjpk * anyway, so no locks needed here. 309*45916cd2Sjpk */ 310*45916cd2Sjpk while ((rhc = rhnext) != NULL) { 311*45916cd2Sjpk rhnext = rhc->rhc_next; 312*45916cd2Sjpk rhc->rhc_next = NULL; 313*45916cd2Sjpk rhc->rhc_invalid = 1; 314*45916cd2Sjpk TNRHC_RELE(rhc); 315*45916cd2Sjpk } 316*45916cd2Sjpk hent++; 317*45916cd2Sjpk } 318*45916cd2Sjpk } 319*45916cd2Sjpk } 320*45916cd2Sjpk 321*45916cd2Sjpk /* 322*45916cd2Sjpk * Load a remote host entry into kernel cache. Create a new one if a matching 323*45916cd2Sjpk * entry isn't found, otherwise replace the contents of the previous one by 324*45916cd2Sjpk * deleting it and recreating it. (Delete and recreate is used to avoid 325*45916cd2Sjpk * allowing other threads to see an unstable data structure.) 326*45916cd2Sjpk * 327*45916cd2Sjpk * A "matching" entry is the one whose address matches that of the one 328*45916cd2Sjpk * being loaded. 329*45916cd2Sjpk * 330*45916cd2Sjpk * Return 0 for success, error code for failure. 331*45916cd2Sjpk */ 332*45916cd2Sjpk int 333*45916cd2Sjpk tnrh_load(const tsol_rhent_t *rhent) 334*45916cd2Sjpk { 335*45916cd2Sjpk tsol_tnrhc_t **rhp; 336*45916cd2Sjpk tsol_tnrhc_t *rh, *new; 337*45916cd2Sjpk tsol_tpc_t *tpc; 338*45916cd2Sjpk ipaddr_t tmpmask; 339*45916cd2Sjpk in6_addr_t tmpmask_v6; 340*45916cd2Sjpk tnrhc_hash_t *tnrhc_hash; 341*45916cd2Sjpk 342*45916cd2Sjpk /* Find the existing entry, if any, leaving the hash locked */ 343*45916cd2Sjpk if (rhent->rh_address.ta_family == AF_INET) { 344*45916cd2Sjpk if (rhent->rh_prefix < 0 || rhent->rh_prefix > IP_ABITS) 345*45916cd2Sjpk return (EINVAL); 346*45916cd2Sjpk if (tnrhc_table[rhent->rh_prefix] == NULL && 347*45916cd2Sjpk !tnrhc_init_table(tnrhc_table, rhent->rh_prefix, 348*45916cd2Sjpk KM_NOSLEEP)) 349*45916cd2Sjpk return (ENOMEM); 350*45916cd2Sjpk tmpmask = tsol_plen_to_mask(rhent->rh_prefix); 351*45916cd2Sjpk tnrhc_hash = &tnrhc_table[rhent->rh_prefix][ 352*45916cd2Sjpk TSOL_ADDR_HASH(rhent->rh_address.ta_addr_v4.s_addr & 353*45916cd2Sjpk tmpmask, TNRHC_SIZE)]; 354*45916cd2Sjpk mutex_enter(&tnrhc_hash->tnrh_lock); 355*45916cd2Sjpk for (rhp = &tnrhc_hash->tnrh_list; (rh = *rhp) != NULL; 356*45916cd2Sjpk rhp = &rh->rhc_next) { 357*45916cd2Sjpk ASSERT(rh->rhc_host.ta_family == AF_INET); 358*45916cd2Sjpk if (((rh->rhc_host.ta_addr_v4.s_addr ^ 359*45916cd2Sjpk rhent->rh_address.ta_addr_v4.s_addr) & tmpmask) == 360*45916cd2Sjpk 0) 361*45916cd2Sjpk break; 362*45916cd2Sjpk } 363*45916cd2Sjpk } else if (rhent->rh_address.ta_family == AF_INET6) { 364*45916cd2Sjpk if (rhent->rh_prefix < 0 || rhent->rh_prefix > IPV6_ABITS) 365*45916cd2Sjpk return (EINVAL); 366*45916cd2Sjpk if (tnrhc_table_v6[rhent->rh_prefix] == NULL && 367*45916cd2Sjpk !tnrhc_init_table(tnrhc_table_v6, rhent->rh_prefix, 368*45916cd2Sjpk KM_NOSLEEP)) 369*45916cd2Sjpk return (ENOMEM); 370*45916cd2Sjpk tsol_plen_to_mask_v6(rhent->rh_prefix, &tmpmask_v6); 371*45916cd2Sjpk tnrhc_hash = &tnrhc_table_v6[rhent->rh_prefix][ 372*45916cd2Sjpk TSOL_ADDR_MASK_HASH_V6(rhent->rh_address.ta_addr_v6, 373*45916cd2Sjpk tmpmask_v6, TNRHC_SIZE)]; 374*45916cd2Sjpk mutex_enter(&tnrhc_hash->tnrh_lock); 375*45916cd2Sjpk for (rhp = &tnrhc_hash->tnrh_list; (rh = *rhp) != NULL; 376*45916cd2Sjpk rhp = &rh->rhc_next) { 377*45916cd2Sjpk ASSERT(rh->rhc_host.ta_family == AF_INET6); 378*45916cd2Sjpk if (V6_MASK_EQ_2(rh->rhc_host.ta_addr_v6, tmpmask_v6, 379*45916cd2Sjpk rhent->rh_address.ta_addr_v6)) 380*45916cd2Sjpk break; 381*45916cd2Sjpk } 382*45916cd2Sjpk } else { 383*45916cd2Sjpk return (EAFNOSUPPORT); 384*45916cd2Sjpk } 385*45916cd2Sjpk 386*45916cd2Sjpk if ((new = kmem_zalloc(sizeof (*new), KM_NOSLEEP)) == NULL) { 387*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 388*45916cd2Sjpk return (ENOMEM); 389*45916cd2Sjpk } 390*45916cd2Sjpk 391*45916cd2Sjpk /* Find and bump the reference count on the named template */ 392*45916cd2Sjpk if ((tpc = tnrhtp_find(rhent->rh_template, tpc_name_hash)) == NULL) { 393*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 394*45916cd2Sjpk kmem_free(new, sizeof (*new)); 395*45916cd2Sjpk return (EINVAL); 396*45916cd2Sjpk } 397*45916cd2Sjpk 398*45916cd2Sjpk /* Clobber the old remote host entry. */ 399*45916cd2Sjpk if (rh != NULL) { 400*45916cd2Sjpk ASSERT(!rh->rhc_invalid); 401*45916cd2Sjpk rh->rhc_invalid = 1; 402*45916cd2Sjpk *rhp = rh->rhc_next; 403*45916cd2Sjpk rh->rhc_next = NULL; 404*45916cd2Sjpk TNRHC_RELE(rh); 405*45916cd2Sjpk } 406*45916cd2Sjpk 407*45916cd2Sjpk /* Initialize the new entry. */ 408*45916cd2Sjpk mutex_init(&new->rhc_lock, NULL, MUTEX_DEFAULT, NULL); 409*45916cd2Sjpk new->rhc_host = rhent->rh_address; 410*45916cd2Sjpk 411*45916cd2Sjpk /* The rhc now owns this tpc reference, so no TPC_RELE past here */ 412*45916cd2Sjpk new->rhc_tpc = tpc; 413*45916cd2Sjpk 414*45916cd2Sjpk ASSERT(tpc->tpc_tp.host_type == UNLABELED || 415*45916cd2Sjpk tpc->tpc_tp.host_type == SUN_CIPSO); 416*45916cd2Sjpk 417*45916cd2Sjpk TNRHC_HOLD(new); 418*45916cd2Sjpk new->rhc_next = tnrhc_hash->tnrh_list; 419*45916cd2Sjpk tnrhc_hash->tnrh_list = new; 420*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l2__tnrhload__addedrh); 421*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 422*45916cd2Sjpk 423*45916cd2Sjpk return (0); 424*45916cd2Sjpk } 425*45916cd2Sjpk 426*45916cd2Sjpk static int 427*45916cd2Sjpk tnrh_get(tsol_rhent_t *rhent) 428*45916cd2Sjpk { 429*45916cd2Sjpk tsol_tpc_t *tpc; 430*45916cd2Sjpk 431*45916cd2Sjpk switch (rhent->rh_address.ta_family) { 432*45916cd2Sjpk case AF_INET: 433*45916cd2Sjpk tpc = find_tpc(&rhent->rh_address.ta_addr_v4, IPV4_VERSION, 434*45916cd2Sjpk B_TRUE); 435*45916cd2Sjpk break; 436*45916cd2Sjpk 437*45916cd2Sjpk case AF_INET6: 438*45916cd2Sjpk tpc = find_tpc(&rhent->rh_address.ta_addr_v6, IPV6_VERSION, 439*45916cd2Sjpk B_TRUE); 440*45916cd2Sjpk break; 441*45916cd2Sjpk 442*45916cd2Sjpk default: 443*45916cd2Sjpk return (EINVAL); 444*45916cd2Sjpk } 445*45916cd2Sjpk if (tpc == NULL) 446*45916cd2Sjpk return (ENOENT); 447*45916cd2Sjpk 448*45916cd2Sjpk DTRACE_PROBE2(tx__tndb__l4__tnrhget__foundtpc, tsol_rhent_t *, 449*45916cd2Sjpk rhent, tsol_tpc_t *, tpc); 450*45916cd2Sjpk bcopy(tpc->tpc_tp.name, rhent->rh_template, 451*45916cd2Sjpk sizeof (rhent->rh_template)); 452*45916cd2Sjpk TPC_RELE(tpc); 453*45916cd2Sjpk return (0); 454*45916cd2Sjpk } 455*45916cd2Sjpk 456*45916cd2Sjpk static boolean_t 457*45916cd2Sjpk template_name_ok(const char *name) 458*45916cd2Sjpk { 459*45916cd2Sjpk const char *name_end = name + TNTNAMSIZ; 460*45916cd2Sjpk 461*45916cd2Sjpk while (name < name_end) { 462*45916cd2Sjpk if (*name == '\0') 463*45916cd2Sjpk break; 464*45916cd2Sjpk name++; 465*45916cd2Sjpk } 466*45916cd2Sjpk return (name < name_end); 467*45916cd2Sjpk } 468*45916cd2Sjpk 469*45916cd2Sjpk static int 470*45916cd2Sjpk tnrh(int cmd, void *buf) 471*45916cd2Sjpk { 472*45916cd2Sjpk int retv; 473*45916cd2Sjpk tsol_rhent_t rhent; 474*45916cd2Sjpk 475*45916cd2Sjpk /* Make sure user has sufficient privilege */ 476*45916cd2Sjpk if (cmd != TNDB_GET && 477*45916cd2Sjpk (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0) 478*45916cd2Sjpk return (set_errno(retv)); 479*45916cd2Sjpk 480*45916cd2Sjpk /* 481*45916cd2Sjpk * Get arguments 482*45916cd2Sjpk */ 483*45916cd2Sjpk if (cmd != TNDB_FLUSH && 484*45916cd2Sjpk copyin(buf, &rhent, sizeof (rhent)) != 0) { 485*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyin); 486*45916cd2Sjpk return (set_errno(EFAULT)); 487*45916cd2Sjpk } 488*45916cd2Sjpk 489*45916cd2Sjpk switch (cmd) { 490*45916cd2Sjpk case TNDB_LOAD: 491*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbload); 492*45916cd2Sjpk if (!template_name_ok(rhent.rh_template)) { 493*45916cd2Sjpk retv = EINVAL; 494*45916cd2Sjpk } else { 495*45916cd2Sjpk retv = tnrh_load(&rhent); 496*45916cd2Sjpk } 497*45916cd2Sjpk break; 498*45916cd2Sjpk 499*45916cd2Sjpk case TNDB_DELETE: 500*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l2__tnrhdelete__tndbdelete); 501*45916cd2Sjpk retv = tnrh_delete(&rhent); 502*45916cd2Sjpk break; 503*45916cd2Sjpk 504*45916cd2Sjpk case TNDB_GET: 505*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l4__tnrhdelete__tndbget); 506*45916cd2Sjpk if (!template_name_ok(rhent.rh_template)) { 507*45916cd2Sjpk retv = EINVAL; 508*45916cd2Sjpk break; 509*45916cd2Sjpk } 510*45916cd2Sjpk 511*45916cd2Sjpk retv = tnrh_get(&rhent); 512*45916cd2Sjpk if (retv != 0) 513*45916cd2Sjpk break; 514*45916cd2Sjpk 515*45916cd2Sjpk /* 516*45916cd2Sjpk * Copy out result 517*45916cd2Sjpk */ 518*45916cd2Sjpk if (copyout(&rhent, buf, sizeof (rhent)) != 0) { 519*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l0__tnrhdelete__copyout); 520*45916cd2Sjpk retv = EFAULT; 521*45916cd2Sjpk } 522*45916cd2Sjpk break; 523*45916cd2Sjpk 524*45916cd2Sjpk case TNDB_FLUSH: 525*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l2__tnrhdelete__flush); 526*45916cd2Sjpk flush_rh_table(tnrhc_table, TSOL_MASK_TABLE_SIZE); 527*45916cd2Sjpk flush_rh_table(tnrhc_table_v6, TSOL_MASK_TABLE_SIZE_V6); 528*45916cd2Sjpk break; 529*45916cd2Sjpk 530*45916cd2Sjpk default: 531*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l0__tnrhdelete__unknowncmd, 532*45916cd2Sjpk int, cmd); 533*45916cd2Sjpk retv = EOPNOTSUPP; 534*45916cd2Sjpk break; 535*45916cd2Sjpk } 536*45916cd2Sjpk 537*45916cd2Sjpk if (retv != 0) 538*45916cd2Sjpk return (set_errno(retv)); 539*45916cd2Sjpk else 540*45916cd2Sjpk return (retv); 541*45916cd2Sjpk } 542*45916cd2Sjpk 543*45916cd2Sjpk static tsol_tpc_t * 544*45916cd2Sjpk tnrhtp_create(const tsol_tpent_t *tpent, int kmflags) 545*45916cd2Sjpk { 546*45916cd2Sjpk tsol_tpc_t *tpc; 547*45916cd2Sjpk mod_hash_val_t hv; 548*45916cd2Sjpk 549*45916cd2Sjpk /* 550*45916cd2Sjpk * We intentionally allocate a new entry before taking the lock on the 551*45916cd2Sjpk * entire database. 552*45916cd2Sjpk */ 553*45916cd2Sjpk if ((tpc = kmem_zalloc(sizeof (*tpc), kmflags)) == NULL) 554*45916cd2Sjpk return (NULL); 555*45916cd2Sjpk 556*45916cd2Sjpk mutex_enter(&tpc_lock); 557*45916cd2Sjpk if (mod_hash_find(tpc_name_hash, (mod_hash_key_t)tpent->name, 558*45916cd2Sjpk &hv) == 0) { 559*45916cd2Sjpk tsol_tpc_t *found_tpc = (tsol_tpc_t *)hv; 560*45916cd2Sjpk 561*45916cd2Sjpk found_tpc->tpc_invalid = 1; 562*45916cd2Sjpk (void) mod_hash_destroy(tpc_name_hash, 563*45916cd2Sjpk (mod_hash_key_t)tpent->name); 564*45916cd2Sjpk TPC_RELE(found_tpc); 565*45916cd2Sjpk } 566*45916cd2Sjpk 567*45916cd2Sjpk mutex_init(&tpc->tpc_lock, NULL, MUTEX_DEFAULT, NULL); 568*45916cd2Sjpk /* tsol_tpent_t is the same on LP64 and ILP32 */ 569*45916cd2Sjpk bcopy(tpent, &tpc->tpc_tp, sizeof (tpc->tpc_tp)); 570*45916cd2Sjpk (void) mod_hash_insert(tpc_name_hash, (mod_hash_key_t)tpc->tpc_tp.name, 571*45916cd2Sjpk (mod_hash_val_t)tpc); 572*45916cd2Sjpk TPC_HOLD(tpc); 573*45916cd2Sjpk mutex_exit(&tpc_lock); 574*45916cd2Sjpk 575*45916cd2Sjpk return (tpc); 576*45916cd2Sjpk } 577*45916cd2Sjpk 578*45916cd2Sjpk static int 579*45916cd2Sjpk tnrhtp_delete(const char *tname) 580*45916cd2Sjpk { 581*45916cd2Sjpk tsol_tpc_t *tpc; 582*45916cd2Sjpk mod_hash_val_t hv; 583*45916cd2Sjpk int retv = ENOENT; 584*45916cd2Sjpk 585*45916cd2Sjpk mutex_enter(&tpc_lock); 586*45916cd2Sjpk if (mod_hash_find(tpc_name_hash, (mod_hash_key_t)tname, &hv) == 0) { 587*45916cd2Sjpk tpc = (tsol_tpc_t *)hv; 588*45916cd2Sjpk ASSERT(!tpc->tpc_invalid); 589*45916cd2Sjpk tpc->tpc_invalid = 1; 590*45916cd2Sjpk (void) mod_hash_destroy(tpc_name_hash, 591*45916cd2Sjpk (mod_hash_key_t)tpc->tpc_tp.name); 592*45916cd2Sjpk TPC_RELE(tpc); 593*45916cd2Sjpk retv = 0; 594*45916cd2Sjpk } 595*45916cd2Sjpk mutex_exit(&tpc_lock); 596*45916cd2Sjpk return (retv); 597*45916cd2Sjpk } 598*45916cd2Sjpk 599*45916cd2Sjpk /* ARGSUSED */ 600*45916cd2Sjpk static uint_t 601*45916cd2Sjpk tpc_delete(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 602*45916cd2Sjpk { 603*45916cd2Sjpk tsol_tpc_t *tpc = (tsol_tpc_t *)val; 604*45916cd2Sjpk 605*45916cd2Sjpk ASSERT(!tpc->tpc_invalid); 606*45916cd2Sjpk tpc->tpc_invalid = 1; 607*45916cd2Sjpk TPC_RELE(tpc); 608*45916cd2Sjpk return (MH_WALK_CONTINUE); 609*45916cd2Sjpk } 610*45916cd2Sjpk 611*45916cd2Sjpk static void 612*45916cd2Sjpk tnrhtp_flush(void) 613*45916cd2Sjpk { 614*45916cd2Sjpk mutex_enter(&tpc_lock); 615*45916cd2Sjpk mod_hash_walk(tpc_name_hash, tpc_delete, NULL); 616*45916cd2Sjpk mod_hash_clear(tpc_name_hash); 617*45916cd2Sjpk mutex_exit(&tpc_lock); 618*45916cd2Sjpk } 619*45916cd2Sjpk 620*45916cd2Sjpk static int 621*45916cd2Sjpk tnrhtp(int cmd, void *buf) 622*45916cd2Sjpk { 623*45916cd2Sjpk int retv; 624*45916cd2Sjpk int type; 625*45916cd2Sjpk tsol_tpent_t rhtpent; 626*45916cd2Sjpk tsol_tpc_t *tpc; 627*45916cd2Sjpk 628*45916cd2Sjpk /* Make sure user has sufficient privilege */ 629*45916cd2Sjpk if (cmd != TNDB_GET && 630*45916cd2Sjpk (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0) 631*45916cd2Sjpk return (set_errno(retv)); 632*45916cd2Sjpk 633*45916cd2Sjpk /* 634*45916cd2Sjpk * Get argument. Note that tsol_tpent_t is the same on LP64 and ILP32, 635*45916cd2Sjpk * so no special handling is required. 636*45916cd2Sjpk */ 637*45916cd2Sjpk if (cmd != TNDB_FLUSH) { 638*45916cd2Sjpk if (copyin(buf, &rhtpent, sizeof (rhtpent)) != 0) { 639*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyin); 640*45916cd2Sjpk return (set_errno(EFAULT)); 641*45916cd2Sjpk } 642*45916cd2Sjpk 643*45916cd2Sjpk /* 644*45916cd2Sjpk * Don't let the user give us a bogus (unterminated) template 645*45916cd2Sjpk * name. 646*45916cd2Sjpk */ 647*45916cd2Sjpk if (!template_name_ok(rhtpent.name)) 648*45916cd2Sjpk return (set_errno(EINVAL)); 649*45916cd2Sjpk } 650*45916cd2Sjpk 651*45916cd2Sjpk switch (cmd) { 652*45916cd2Sjpk case TNDB_LOAD: 653*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l2__tnrhtp__tndbload, char *, 654*45916cd2Sjpk rhtpent.name); 655*45916cd2Sjpk type = rhtpent.host_type; 656*45916cd2Sjpk if (type != UNLABELED && type != SUN_CIPSO) { 657*45916cd2Sjpk retv = EINVAL; 658*45916cd2Sjpk break; 659*45916cd2Sjpk } 660*45916cd2Sjpk 661*45916cd2Sjpk if (tnrhtp_create(&rhtpent, KM_NOSLEEP) == NULL) 662*45916cd2Sjpk retv = ENOMEM; 663*45916cd2Sjpk else 664*45916cd2Sjpk retv = 0; 665*45916cd2Sjpk break; 666*45916cd2Sjpk 667*45916cd2Sjpk case TNDB_GET: 668*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbget, char *, 669*45916cd2Sjpk rhtpent.name); 670*45916cd2Sjpk tpc = tnrhtp_find(rhtpent.name, tpc_name_hash); 671*45916cd2Sjpk if (tpc == NULL) { 672*45916cd2Sjpk retv = ENOENT; 673*45916cd2Sjpk break; 674*45916cd2Sjpk } 675*45916cd2Sjpk 676*45916cd2Sjpk /* Copy out result */ 677*45916cd2Sjpk if (copyout(&tpc->tpc_tp, buf, sizeof (tpc->tpc_tp)) != 0) { 678*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l0__tnrhtp__copyout); 679*45916cd2Sjpk retv = EFAULT; 680*45916cd2Sjpk } else { 681*45916cd2Sjpk retv = 0; 682*45916cd2Sjpk } 683*45916cd2Sjpk TPC_RELE(tpc); 684*45916cd2Sjpk break; 685*45916cd2Sjpk 686*45916cd2Sjpk case TNDB_DELETE: 687*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l4__tnrhtp__tndbdelete, char *, 688*45916cd2Sjpk rhtpent.name); 689*45916cd2Sjpk retv = tnrhtp_delete(rhtpent.name); 690*45916cd2Sjpk break; 691*45916cd2Sjpk 692*45916cd2Sjpk case TNDB_FLUSH: 693*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l4__tnrhtp__flush); 694*45916cd2Sjpk tnrhtp_flush(); 695*45916cd2Sjpk retv = 0; 696*45916cd2Sjpk break; 697*45916cd2Sjpk 698*45916cd2Sjpk default: 699*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l0__tnrhtp__unknowncmd, int, 700*45916cd2Sjpk cmd); 701*45916cd2Sjpk retv = EOPNOTSUPP; 702*45916cd2Sjpk break; 703*45916cd2Sjpk } 704*45916cd2Sjpk 705*45916cd2Sjpk if (retv != 0) 706*45916cd2Sjpk return (set_errno(retv)); 707*45916cd2Sjpk else 708*45916cd2Sjpk return (retv); 709*45916cd2Sjpk } 710*45916cd2Sjpk 711*45916cd2Sjpk /* 712*45916cd2Sjpk * MLP entry ordering logic 713*45916cd2Sjpk * 714*45916cd2Sjpk * There are two loops in this routine. The first loop finds the entry that 715*45916cd2Sjpk * either logically follows the new entry to be inserted, or is the entry that 716*45916cd2Sjpk * precedes and overlaps the new entry, or is NULL to mean end-of-list. This 717*45916cd2Sjpk * is 'tme.' The second loop scans ahead from that point to find any overlap 718*45916cd2Sjpk * on the front or back of this new entry. 719*45916cd2Sjpk * 720*45916cd2Sjpk * For the first loop, we can have the following cases in the list (note that 721*45916cd2Sjpk * the port-portmax range is inclusive): 722*45916cd2Sjpk * 723*45916cd2Sjpk * port portmax 724*45916cd2Sjpk * +--------+ 725*45916cd2Sjpk * 1: +------+ ................... precedes; skip to next 726*45916cd2Sjpk * 2: +------+ ............. overlaps; stop here if same protocol 727*45916cd2Sjpk * 3: +------+ ......... overlaps; stop if same or higher protocol 728*45916cd2Sjpk * 4: +-------+ .... overlaps or succeeds; stop here 729*45916cd2Sjpk * 730*45916cd2Sjpk * For the second loop, we can have the following cases (note that we need not 731*45916cd2Sjpk * care about other protocol entries at this point, because we're only looking 732*45916cd2Sjpk * for overlap, not an insertion point): 733*45916cd2Sjpk * 734*45916cd2Sjpk * port portmax 735*45916cd2Sjpk * +--------+ 736*45916cd2Sjpk * 5: +------+ ............. overlaps; stop if same protocol 737*45916cd2Sjpk * 6: +------+ ......... overlaps; stop if same protocol 738*45916cd2Sjpk * 7: +-------+ .... overlaps; stop if same protocol 739*45916cd2Sjpk * 8: +---+ . follows; search is done 740*45916cd2Sjpk * 741*45916cd2Sjpk * In other words, this second search needs to consider only whether the entry 742*45916cd2Sjpk * has a starting port number that's greater than the end point of the new 743*45916cd2Sjpk * entry. All others are overlaps. 744*45916cd2Sjpk */ 745*45916cd2Sjpk static int 746*45916cd2Sjpk mlp_add_del(tsol_mlp_list_t *mlpl, zoneid_t zoneid, uint8_t proto, 747*45916cd2Sjpk uint16_t port, uint16_t portmax, boolean_t addflag) 748*45916cd2Sjpk { 749*45916cd2Sjpk int retv; 750*45916cd2Sjpk tsol_mlp_entry_t *tme, *tme2, *newent; 751*45916cd2Sjpk 752*45916cd2Sjpk if (addflag) { 753*45916cd2Sjpk if ((newent = kmem_zalloc(sizeof (*newent), KM_NOSLEEP)) == 754*45916cd2Sjpk NULL) 755*45916cd2Sjpk return (ENOMEM); 756*45916cd2Sjpk } else { 757*45916cd2Sjpk newent = NULL; 758*45916cd2Sjpk } 759*45916cd2Sjpk rw_enter(&mlpl->mlpl_rwlock, RW_WRITER); 760*45916cd2Sjpk 761*45916cd2Sjpk /* 762*45916cd2Sjpk * First loop: find logical insertion point or overlap. Table is kept 763*45916cd2Sjpk * in order of port number first, and then, within that, by protocol 764*45916cd2Sjpk * number. 765*45916cd2Sjpk */ 766*45916cd2Sjpk for (tme = mlpl->mlpl_first; tme != NULL; tme = tme->mlpe_next) { 767*45916cd2Sjpk /* logically next (case 4) */ 768*45916cd2Sjpk if (tme->mlpe_mlp.mlp_port > port) 769*45916cd2Sjpk break; 770*45916cd2Sjpk /* if this is logically next or overlap, then stop (case 3) */ 771*45916cd2Sjpk if (tme->mlpe_mlp.mlp_port == port && 772*45916cd2Sjpk tme->mlpe_mlp.mlp_ipp >= proto) 773*45916cd2Sjpk break; 774*45916cd2Sjpk /* earlier or same port sequence; check for overlap (case 2) */ 775*45916cd2Sjpk if (tme->mlpe_mlp.mlp_ipp == proto && 776*45916cd2Sjpk tme->mlpe_mlp.mlp_port_upper >= port) 777*45916cd2Sjpk break; 778*45916cd2Sjpk /* otherwise, loop again (case 1) */ 779*45916cd2Sjpk } 780*45916cd2Sjpk 781*45916cd2Sjpk /* Second loop: scan ahead for overlap */ 782*45916cd2Sjpk for (tme2 = tme; tme2 != NULL; tme2 = tme2->mlpe_next) { 783*45916cd2Sjpk /* check if entry follows; no overlap (case 8) */ 784*45916cd2Sjpk if (tme2->mlpe_mlp.mlp_port > portmax) { 785*45916cd2Sjpk tme2 = NULL; 786*45916cd2Sjpk break; 787*45916cd2Sjpk } 788*45916cd2Sjpk /* only exact protocol matches at this point (cases 5-7) */ 789*45916cd2Sjpk if (tme2->mlpe_mlp.mlp_ipp == proto) 790*45916cd2Sjpk break; 791*45916cd2Sjpk } 792*45916cd2Sjpk 793*45916cd2Sjpk retv = 0; 794*45916cd2Sjpk if (addflag) { 795*45916cd2Sjpk if (tme2 != NULL) { 796*45916cd2Sjpk retv = EEXIST; 797*45916cd2Sjpk } else { 798*45916cd2Sjpk newent->mlpe_zoneid = zoneid; 799*45916cd2Sjpk newent->mlpe_mlp.mlp_ipp = proto; 800*45916cd2Sjpk newent->mlpe_mlp.mlp_port = port; 801*45916cd2Sjpk newent->mlpe_mlp.mlp_port_upper = portmax; 802*45916cd2Sjpk newent->mlpe_next = tme; 803*45916cd2Sjpk if (tme == NULL) { 804*45916cd2Sjpk tme2 = mlpl->mlpl_last; 805*45916cd2Sjpk mlpl->mlpl_last = newent; 806*45916cd2Sjpk } else { 807*45916cd2Sjpk tme2 = tme->mlpe_prev; 808*45916cd2Sjpk tme->mlpe_prev = newent; 809*45916cd2Sjpk } 810*45916cd2Sjpk newent->mlpe_prev = tme2; 811*45916cd2Sjpk if (tme2 == NULL) 812*45916cd2Sjpk mlpl->mlpl_first = newent; 813*45916cd2Sjpk else 814*45916cd2Sjpk tme2->mlpe_next = newent; 815*45916cd2Sjpk newent = NULL; 816*45916cd2Sjpk } 817*45916cd2Sjpk } else { 818*45916cd2Sjpk if (tme2 == NULL || tme2->mlpe_mlp.mlp_port != port || 819*45916cd2Sjpk tme2->mlpe_mlp.mlp_port_upper != portmax) { 820*45916cd2Sjpk retv = ENOENT; 821*45916cd2Sjpk } else { 822*45916cd2Sjpk if ((tme2 = tme->mlpe_prev) == NULL) 823*45916cd2Sjpk mlpl->mlpl_first = tme->mlpe_next; 824*45916cd2Sjpk else 825*45916cd2Sjpk tme2->mlpe_next = tme->mlpe_next; 826*45916cd2Sjpk if ((tme2 = tme->mlpe_next) == NULL) 827*45916cd2Sjpk mlpl->mlpl_last = tme->mlpe_prev; 828*45916cd2Sjpk else 829*45916cd2Sjpk tme2->mlpe_prev = tme->mlpe_prev; 830*45916cd2Sjpk newent = tme; 831*45916cd2Sjpk } 832*45916cd2Sjpk } 833*45916cd2Sjpk rw_exit(&mlpl->mlpl_rwlock); 834*45916cd2Sjpk 835*45916cd2Sjpk if (newent != NULL) 836*45916cd2Sjpk kmem_free(newent, sizeof (*newent)); 837*45916cd2Sjpk 838*45916cd2Sjpk return (retv); 839*45916cd2Sjpk } 840*45916cd2Sjpk 841*45916cd2Sjpk /* 842*45916cd2Sjpk * Add or remove an MLP entry from the database so that the classifier can find 843*45916cd2Sjpk * it. 844*45916cd2Sjpk * 845*45916cd2Sjpk * Note: port number is in host byte order. 846*45916cd2Sjpk */ 847*45916cd2Sjpk int 848*45916cd2Sjpk tsol_mlp_anon(zone_t *zone, mlp_type_t mlptype, uchar_t proto, uint16_t port, 849*45916cd2Sjpk boolean_t addflag) 850*45916cd2Sjpk { 851*45916cd2Sjpk int retv = 0; 852*45916cd2Sjpk 853*45916cd2Sjpk if (mlptype == mlptBoth || mlptype == mlptPrivate) 854*45916cd2Sjpk retv = mlp_add_del(&zone->zone_mlps, zone->zone_id, proto, 855*45916cd2Sjpk port, port, addflag); 856*45916cd2Sjpk if ((retv == 0 || !addflag) && 857*45916cd2Sjpk (mlptype == mlptBoth || mlptype == mlptShared)) { 858*45916cd2Sjpk retv = mlp_add_del(&shared_mlps, zone->zone_id, proto, port, 859*45916cd2Sjpk port, addflag); 860*45916cd2Sjpk if (retv != 0 && addflag) 861*45916cd2Sjpk (void) mlp_add_del(&zone->zone_mlps, zone->zone_id, 862*45916cd2Sjpk proto, port, port, B_FALSE); 863*45916cd2Sjpk } 864*45916cd2Sjpk return (retv); 865*45916cd2Sjpk } 866*45916cd2Sjpk 867*45916cd2Sjpk static void 868*45916cd2Sjpk mlp_flush(tsol_mlp_list_t *mlpl, zoneid_t zoneid) 869*45916cd2Sjpk { 870*45916cd2Sjpk tsol_mlp_entry_t *tme, *tme2, *tmnext; 871*45916cd2Sjpk 872*45916cd2Sjpk rw_enter(&mlpl->mlpl_rwlock, RW_WRITER); 873*45916cd2Sjpk for (tme = mlpl->mlpl_first; tme != NULL; tme = tmnext) { 874*45916cd2Sjpk tmnext = tme->mlpe_next; 875*45916cd2Sjpk if (zoneid == ALL_ZONES || tme->mlpe_zoneid == zoneid) { 876*45916cd2Sjpk if ((tme2 = tme->mlpe_prev) == NULL) 877*45916cd2Sjpk mlpl->mlpl_first = tmnext; 878*45916cd2Sjpk else 879*45916cd2Sjpk tme2->mlpe_next = tmnext; 880*45916cd2Sjpk if (tmnext == NULL) 881*45916cd2Sjpk mlpl->mlpl_last = tme2; 882*45916cd2Sjpk else 883*45916cd2Sjpk tmnext->mlpe_prev = tme2; 884*45916cd2Sjpk kmem_free(tme, sizeof (*tme)); 885*45916cd2Sjpk } 886*45916cd2Sjpk } 887*45916cd2Sjpk rw_exit(&mlpl->mlpl_rwlock); 888*45916cd2Sjpk } 889*45916cd2Sjpk 890*45916cd2Sjpk /* 891*45916cd2Sjpk * Note: user supplies port numbers in host byte order. 892*45916cd2Sjpk */ 893*45916cd2Sjpk static int 894*45916cd2Sjpk tnmlp(int cmd, void *buf) 895*45916cd2Sjpk { 896*45916cd2Sjpk int retv; 897*45916cd2Sjpk tsol_mlpent_t tsme; 898*45916cd2Sjpk zone_t *zone; 899*45916cd2Sjpk tsol_mlp_list_t *mlpl; 900*45916cd2Sjpk tsol_mlp_entry_t *tme; 901*45916cd2Sjpk 902*45916cd2Sjpk /* Make sure user has sufficient privilege */ 903*45916cd2Sjpk if (cmd != TNDB_GET && 904*45916cd2Sjpk (retv = secpolicy_net_config(CRED(), B_FALSE)) != 0) 905*45916cd2Sjpk return (set_errno(retv)); 906*45916cd2Sjpk 907*45916cd2Sjpk /* 908*45916cd2Sjpk * Get argument. Note that tsol_mlpent_t is the same on LP64 and 909*45916cd2Sjpk * ILP32, so no special handling is required. 910*45916cd2Sjpk */ 911*45916cd2Sjpk if (copyin(buf, &tsme, sizeof (tsme)) != 0) { 912*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l0__tnmlp__copyin); 913*45916cd2Sjpk return (set_errno(EFAULT)); 914*45916cd2Sjpk } 915*45916cd2Sjpk 916*45916cd2Sjpk /* MLPs on shared IP addresses */ 917*45916cd2Sjpk if (tsme.tsme_flags & TSOL_MEF_SHARED) { 918*45916cd2Sjpk zone = NULL; 919*45916cd2Sjpk mlpl = &shared_mlps; 920*45916cd2Sjpk } else { 921*45916cd2Sjpk zone = zone_find_by_id(tsme.tsme_zoneid); 922*45916cd2Sjpk if (zone == NULL) 923*45916cd2Sjpk return (set_errno(EINVAL)); 924*45916cd2Sjpk mlpl = &zone->zone_mlps; 925*45916cd2Sjpk } 926*45916cd2Sjpk if (tsme.tsme_mlp.mlp_port_upper == 0) 927*45916cd2Sjpk tsme.tsme_mlp.mlp_port_upper = tsme.tsme_mlp.mlp_port; 928*45916cd2Sjpk 929*45916cd2Sjpk switch (cmd) { 930*45916cd2Sjpk case TNDB_LOAD: 931*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbload, 932*45916cd2Sjpk tsol_mlpent_t *, &tsme); 933*45916cd2Sjpk if (tsme.tsme_mlp.mlp_ipp == 0 || tsme.tsme_mlp.mlp_port == 0 || 934*45916cd2Sjpk tsme.tsme_mlp.mlp_port > tsme.tsme_mlp.mlp_port_upper) { 935*45916cd2Sjpk retv = EINVAL; 936*45916cd2Sjpk break; 937*45916cd2Sjpk } 938*45916cd2Sjpk retv = mlp_add_del(mlpl, tsme.tsme_zoneid, 939*45916cd2Sjpk tsme.tsme_mlp.mlp_ipp, tsme.tsme_mlp.mlp_port, 940*45916cd2Sjpk tsme.tsme_mlp.mlp_port_upper, B_TRUE); 941*45916cd2Sjpk break; 942*45916cd2Sjpk 943*45916cd2Sjpk case TNDB_GET: 944*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l2__tnmlp__tndbget, 945*45916cd2Sjpk tsol_mlpent_t *, &tsme); 946*45916cd2Sjpk 947*45916cd2Sjpk /* 948*45916cd2Sjpk * Search for the requested element or, failing that, the one 949*45916cd2Sjpk * that's logically next in the sequence. 950*45916cd2Sjpk */ 951*45916cd2Sjpk rw_enter(&mlpl->mlpl_rwlock, RW_READER); 952*45916cd2Sjpk for (tme = mlpl->mlpl_first; tme != NULL; 953*45916cd2Sjpk tme = tme->mlpe_next) { 954*45916cd2Sjpk if (tsme.tsme_zoneid != ALL_ZONES && 955*45916cd2Sjpk tme->mlpe_zoneid != tsme.tsme_zoneid) 956*45916cd2Sjpk continue; 957*45916cd2Sjpk if (tme->mlpe_mlp.mlp_ipp >= tsme.tsme_mlp.mlp_ipp && 958*45916cd2Sjpk tme->mlpe_mlp.mlp_port == tsme.tsme_mlp.mlp_port) 959*45916cd2Sjpk break; 960*45916cd2Sjpk if (tme->mlpe_mlp.mlp_port > tsme.tsme_mlp.mlp_port) 961*45916cd2Sjpk break; 962*45916cd2Sjpk } 963*45916cd2Sjpk if (tme == NULL) { 964*45916cd2Sjpk retv = ENOENT; 965*45916cd2Sjpk } else { 966*45916cd2Sjpk tsme.tsme_zoneid = tme->mlpe_zoneid; 967*45916cd2Sjpk tsme.tsme_mlp = tme->mlpe_mlp; 968*45916cd2Sjpk retv = 0; 969*45916cd2Sjpk } 970*45916cd2Sjpk rw_exit(&mlpl->mlpl_rwlock); 971*45916cd2Sjpk break; 972*45916cd2Sjpk 973*45916cd2Sjpk case TNDB_DELETE: 974*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbdelete, 975*45916cd2Sjpk tsol_mlpent_t *, &tsme); 976*45916cd2Sjpk retv = mlp_add_del(mlpl, tsme.tsme_zoneid, 977*45916cd2Sjpk tsme.tsme_mlp.mlp_ipp, tsme.tsme_mlp.mlp_port, 978*45916cd2Sjpk tsme.tsme_mlp.mlp_port_upper, B_FALSE); 979*45916cd2Sjpk break; 980*45916cd2Sjpk 981*45916cd2Sjpk case TNDB_FLUSH: 982*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l4__tnmlp__tndbflush, 983*45916cd2Sjpk tsol_mlpent_t *, &tsme); 984*45916cd2Sjpk mlp_flush(mlpl, ALL_ZONES); 985*45916cd2Sjpk mlp_flush(&shared_mlps, tsme.tsme_zoneid); 986*45916cd2Sjpk retv = 0; 987*45916cd2Sjpk break; 988*45916cd2Sjpk 989*45916cd2Sjpk default: 990*45916cd2Sjpk DTRACE_PROBE1(tx__tndb__l0__tnmlp__unknowncmd, int, 991*45916cd2Sjpk cmd); 992*45916cd2Sjpk retv = EOPNOTSUPP; 993*45916cd2Sjpk break; 994*45916cd2Sjpk } 995*45916cd2Sjpk 996*45916cd2Sjpk if (zone != NULL) 997*45916cd2Sjpk zone_rele(zone); 998*45916cd2Sjpk 999*45916cd2Sjpk if (cmd == TNDB_GET && retv == 0) { 1000*45916cd2Sjpk /* Copy out result */ 1001*45916cd2Sjpk if (copyout(&tsme, buf, sizeof (tsme)) != 0) { 1002*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l0__tnmlp__copyout); 1003*45916cd2Sjpk retv = EFAULT; 1004*45916cd2Sjpk } 1005*45916cd2Sjpk } 1006*45916cd2Sjpk 1007*45916cd2Sjpk if (retv != 0) 1008*45916cd2Sjpk return (set_errno(retv)); 1009*45916cd2Sjpk else 1010*45916cd2Sjpk return (retv); 1011*45916cd2Sjpk } 1012*45916cd2Sjpk 1013*45916cd2Sjpk /* 1014*45916cd2Sjpk * Returns a tnrhc matching the addr address. 1015*45916cd2Sjpk * The returned rhc's refcnt is incremented. 1016*45916cd2Sjpk */ 1017*45916cd2Sjpk tsol_tnrhc_t * 1018*45916cd2Sjpk find_rhc_v4(const in_addr_t *in4) 1019*45916cd2Sjpk { 1020*45916cd2Sjpk tsol_tnrhc_t *rh = NULL; 1021*45916cd2Sjpk tnrhc_hash_t *tnrhc_hash; 1022*45916cd2Sjpk ipaddr_t tmpmask; 1023*45916cd2Sjpk int i; 1024*45916cd2Sjpk 1025*45916cd2Sjpk for (i = (TSOL_MASK_TABLE_SIZE - 1); i >= 0; i--) { 1026*45916cd2Sjpk 1027*45916cd2Sjpk if ((tnrhc_table[i]) == NULL) 1028*45916cd2Sjpk continue; 1029*45916cd2Sjpk 1030*45916cd2Sjpk tmpmask = tsol_plen_to_mask(i); 1031*45916cd2Sjpk tnrhc_hash = &tnrhc_table[i][ 1032*45916cd2Sjpk TSOL_ADDR_HASH(*in4 & tmpmask, TNRHC_SIZE)]; 1033*45916cd2Sjpk 1034*45916cd2Sjpk mutex_enter(&tnrhc_hash->tnrh_lock); 1035*45916cd2Sjpk for (rh = tnrhc_hash->tnrh_list; rh != NULL; 1036*45916cd2Sjpk rh = rh->rhc_next) { 1037*45916cd2Sjpk if ((rh->rhc_host.ta_family == AF_INET) && 1038*45916cd2Sjpk ((rh->rhc_host.ta_addr_v4.s_addr & tmpmask) == 1039*45916cd2Sjpk (*in4 & tmpmask))) { 1040*45916cd2Sjpk TNRHC_HOLD(rh); 1041*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 1042*45916cd2Sjpk return (rh); 1043*45916cd2Sjpk } 1044*45916cd2Sjpk } 1045*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 1046*45916cd2Sjpk } 1047*45916cd2Sjpk 1048*45916cd2Sjpk return (NULL); 1049*45916cd2Sjpk } 1050*45916cd2Sjpk 1051*45916cd2Sjpk /* 1052*45916cd2Sjpk * Returns a tnrhc matching the addr address. 1053*45916cd2Sjpk * The returned rhc's refcnt is incremented. 1054*45916cd2Sjpk */ 1055*45916cd2Sjpk tsol_tnrhc_t * 1056*45916cd2Sjpk find_rhc_v6(const in6_addr_t *in6) 1057*45916cd2Sjpk { 1058*45916cd2Sjpk tsol_tnrhc_t *rh = NULL; 1059*45916cd2Sjpk tnrhc_hash_t *tnrhc_hash; 1060*45916cd2Sjpk in6_addr_t tmpmask; 1061*45916cd2Sjpk int i; 1062*45916cd2Sjpk 1063*45916cd2Sjpk if (IN6_IS_ADDR_V4MAPPED(in6)) { 1064*45916cd2Sjpk in_addr_t in4; 1065*45916cd2Sjpk 1066*45916cd2Sjpk IN6_V4MAPPED_TO_IPADDR(in6, in4); 1067*45916cd2Sjpk return (find_rhc_v4(&in4)); 1068*45916cd2Sjpk } 1069*45916cd2Sjpk 1070*45916cd2Sjpk for (i = (TSOL_MASK_TABLE_SIZE_V6 - 1); i >= 0; i--) { 1071*45916cd2Sjpk if ((tnrhc_table_v6[i]) == NULL) 1072*45916cd2Sjpk continue; 1073*45916cd2Sjpk 1074*45916cd2Sjpk tsol_plen_to_mask_v6(i, &tmpmask); 1075*45916cd2Sjpk tnrhc_hash = &tnrhc_table_v6[i][ 1076*45916cd2Sjpk TSOL_ADDR_MASK_HASH_V6(*in6, tmpmask, TNRHC_SIZE)]; 1077*45916cd2Sjpk 1078*45916cd2Sjpk mutex_enter(&tnrhc_hash->tnrh_lock); 1079*45916cd2Sjpk for (rh = tnrhc_hash->tnrh_list; rh != NULL; 1080*45916cd2Sjpk rh = rh->rhc_next) { 1081*45916cd2Sjpk if ((rh->rhc_host.ta_family == AF_INET6) && 1082*45916cd2Sjpk V6_MASK_EQ_2(rh->rhc_host.ta_addr_v6, tmpmask, 1083*45916cd2Sjpk *in6)) { 1084*45916cd2Sjpk TNRHC_HOLD(rh); 1085*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 1086*45916cd2Sjpk return (rh); 1087*45916cd2Sjpk } 1088*45916cd2Sjpk } 1089*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 1090*45916cd2Sjpk } 1091*45916cd2Sjpk 1092*45916cd2Sjpk return (NULL); 1093*45916cd2Sjpk } 1094*45916cd2Sjpk 1095*45916cd2Sjpk tsol_tpc_t * 1096*45916cd2Sjpk find_tpc(const void *addr, uchar_t version, boolean_t staleok) 1097*45916cd2Sjpk { 1098*45916cd2Sjpk tsol_tpc_t *tpc; 1099*45916cd2Sjpk tsol_tnrhc_t *rhc; 1100*45916cd2Sjpk 1101*45916cd2Sjpk if (version == IPV4_VERSION) 1102*45916cd2Sjpk rhc = find_rhc_v4(addr); 1103*45916cd2Sjpk else 1104*45916cd2Sjpk rhc = find_rhc_v6(addr); 1105*45916cd2Sjpk 1106*45916cd2Sjpk if (rhc != NULL) { 1107*45916cd2Sjpk tpc = rhc->rhc_tpc; 1108*45916cd2Sjpk if (!staleok && tpc->tpc_invalid) { 1109*45916cd2Sjpk /* 1110*45916cd2Sjpk * This should not happen unless the user deletes 1111*45916cd2Sjpk * templates without recreating them. Try to find the 1112*45916cd2Sjpk * new version of template. If there is none, then 1113*45916cd2Sjpk * just give up. 1114*45916cd2Sjpk */ 1115*45916cd2Sjpk tpc = tnrhtp_find(tpc->tpc_tp.name, tpc_name_hash); 1116*45916cd2Sjpk if (tpc != NULL) { 1117*45916cd2Sjpk TPC_RELE(rhc->rhc_tpc); 1118*45916cd2Sjpk rhc->rhc_tpc = tpc; 1119*45916cd2Sjpk } 1120*45916cd2Sjpk } 1121*45916cd2Sjpk if (tpc != NULL) 1122*45916cd2Sjpk TPC_HOLD(tpc); 1123*45916cd2Sjpk TNRHC_RELE(rhc); 1124*45916cd2Sjpk return (tpc); 1125*45916cd2Sjpk } 1126*45916cd2Sjpk DTRACE_PROBE(tx__tndb__l1__findtpc__notemplate); 1127*45916cd2Sjpk return (NULL); 1128*45916cd2Sjpk } 1129*45916cd2Sjpk 1130*45916cd2Sjpk /* 1131*45916cd2Sjpk * create an internal template called "_unlab": 1132*45916cd2Sjpk * 1133*45916cd2Sjpk * _unlab;\ 1134*45916cd2Sjpk * host_type = unlabeled;\ 1135*45916cd2Sjpk * def_label = ADMIN_LOW[ADMIN_LOW];\ 1136*45916cd2Sjpk * min_sl = ADMIN_LOW;\ 1137*45916cd2Sjpk * max_sl = ADMIN_HIGH; 1138*45916cd2Sjpk */ 1139*45916cd2Sjpk static void 1140*45916cd2Sjpk tsol_create_i_tmpls(void) 1141*45916cd2Sjpk { 1142*45916cd2Sjpk tsol_tpent_t rhtpent; 1143*45916cd2Sjpk 1144*45916cd2Sjpk bzero(&rhtpent, sizeof (rhtpent)); 1145*45916cd2Sjpk 1146*45916cd2Sjpk /* create _unlab */ 1147*45916cd2Sjpk (void) strcpy(rhtpent.name, "_unlab"); 1148*45916cd2Sjpk 1149*45916cd2Sjpk rhtpent.host_type = UNLABELED; 1150*45916cd2Sjpk rhtpent.tp_mask_unl = TSOL_MSK_DEF_LABEL | TSOL_MSK_DEF_CL | 1151*45916cd2Sjpk TSOL_MSK_SL_RANGE_TSOL; 1152*45916cd2Sjpk 1153*45916cd2Sjpk rhtpent.tp_gw_sl_range.lower_bound = *label2bslabel(l_admin_low); 1154*45916cd2Sjpk rhtpent.tp_def_label = rhtpent.tp_gw_sl_range.lower_bound; 1155*45916cd2Sjpk rhtpent.tp_gw_sl_range.upper_bound = *label2bslabel(l_admin_high); 1156*45916cd2Sjpk rhtpent.tp_cipso_doi_unl = default_doi; 1157*45916cd2Sjpk tpc_unlab = tnrhtp_create(&rhtpent, KM_SLEEP); 1158*45916cd2Sjpk } 1159*45916cd2Sjpk 1160*45916cd2Sjpk /* 1161*45916cd2Sjpk * set up internal host template, called from kernel only. 1162*45916cd2Sjpk */ 1163*45916cd2Sjpk static void 1164*45916cd2Sjpk tsol_create_i_tnrh(const tnaddr_t *sa) 1165*45916cd2Sjpk { 1166*45916cd2Sjpk tsol_tnrhc_t *rh, *new; 1167*45916cd2Sjpk tnrhc_hash_t *tnrhc_hash; 1168*45916cd2Sjpk 1169*45916cd2Sjpk /* Allocate a new entry before taking the lock */ 1170*45916cd2Sjpk new = kmem_zalloc(sizeof (*new), KM_SLEEP); 1171*45916cd2Sjpk 1172*45916cd2Sjpk tnrhc_hash = (sa->ta_family == AF_INET) ? &tnrhc_table[0][0] : 1173*45916cd2Sjpk &tnrhc_table_v6[0][0]; 1174*45916cd2Sjpk 1175*45916cd2Sjpk mutex_enter(&tnrhc_hash->tnrh_lock); 1176*45916cd2Sjpk rh = tnrhc_hash->tnrh_list; 1177*45916cd2Sjpk 1178*45916cd2Sjpk if (rh == NULL) { 1179*45916cd2Sjpk /* We're keeping the new entry. */ 1180*45916cd2Sjpk rh = new; 1181*45916cd2Sjpk new = NULL; 1182*45916cd2Sjpk rh->rhc_host = *sa; 1183*45916cd2Sjpk mutex_init(&rh->rhc_lock, NULL, MUTEX_DEFAULT, NULL); 1184*45916cd2Sjpk TNRHC_HOLD(rh); 1185*45916cd2Sjpk tnrhc_hash->tnrh_list = rh; 1186*45916cd2Sjpk } 1187*45916cd2Sjpk 1188*45916cd2Sjpk /* 1189*45916cd2Sjpk * Link the entry to internal_unlab 1190*45916cd2Sjpk */ 1191*45916cd2Sjpk if (rh->rhc_tpc != tpc_unlab) { 1192*45916cd2Sjpk if (rh->rhc_tpc != NULL) 1193*45916cd2Sjpk TPC_RELE(rh->rhc_tpc); 1194*45916cd2Sjpk rh->rhc_tpc = tpc_unlab; 1195*45916cd2Sjpk TPC_HOLD(tpc_unlab); 1196*45916cd2Sjpk } 1197*45916cd2Sjpk mutex_exit(&tnrhc_hash->tnrh_lock); 1198*45916cd2Sjpk if (new != NULL) 1199*45916cd2Sjpk kmem_free(new, sizeof (*new)); 1200*45916cd2Sjpk } 1201*45916cd2Sjpk 1202*45916cd2Sjpk /* 1203*45916cd2Sjpk * Returns 0 if the port is known to be SLP. Returns next possible port number 1204*45916cd2Sjpk * (wrapping through 1) if port is MLP on shared or global. Administrator 1205*45916cd2Sjpk * should not make all ports MLP. If that's done, then we'll just pretend 1206*45916cd2Sjpk * everything is SLP to avoid looping forever. 1207*45916cd2Sjpk * 1208*45916cd2Sjpk * Note: port is in host byte order. 1209*45916cd2Sjpk */ 1210*45916cd2Sjpk in_port_t 1211*45916cd2Sjpk tsol_next_port(zone_t *zone, in_port_t port, int proto, boolean_t upward) 1212*45916cd2Sjpk { 1213*45916cd2Sjpk boolean_t loop; 1214*45916cd2Sjpk tsol_mlp_entry_t *tme; 1215*45916cd2Sjpk int newport = port; 1216*45916cd2Sjpk 1217*45916cd2Sjpk loop = B_FALSE; 1218*45916cd2Sjpk for (;;) { 1219*45916cd2Sjpk if (zone != NULL && zone->zone_mlps.mlpl_first != NULL) { 1220*45916cd2Sjpk rw_enter(&zone->zone_mlps.mlpl_rwlock, RW_READER); 1221*45916cd2Sjpk for (tme = zone->zone_mlps.mlpl_first; tme != NULL; 1222*45916cd2Sjpk tme = tme->mlpe_next) { 1223*45916cd2Sjpk if (proto == tme->mlpe_mlp.mlp_ipp && 1224*45916cd2Sjpk newport >= tme->mlpe_mlp.mlp_port && 1225*45916cd2Sjpk newport <= tme->mlpe_mlp.mlp_port_upper) 1226*45916cd2Sjpk newport = upward ? 1227*45916cd2Sjpk tme->mlpe_mlp.mlp_port_upper + 1 : 1228*45916cd2Sjpk tme->mlpe_mlp.mlp_port - 1; 1229*45916cd2Sjpk } 1230*45916cd2Sjpk rw_exit(&zone->zone_mlps.mlpl_rwlock); 1231*45916cd2Sjpk } 1232*45916cd2Sjpk if (shared_mlps.mlpl_first != NULL) { 1233*45916cd2Sjpk rw_enter(&shared_mlps.mlpl_rwlock, RW_READER); 1234*45916cd2Sjpk for (tme = shared_mlps.mlpl_first; tme != NULL; 1235*45916cd2Sjpk tme = tme->mlpe_next) { 1236*45916cd2Sjpk if (proto == tme->mlpe_mlp.mlp_ipp && 1237*45916cd2Sjpk newport >= tme->mlpe_mlp.mlp_port && 1238*45916cd2Sjpk newport <= tme->mlpe_mlp.mlp_port_upper) 1239*45916cd2Sjpk newport = upward ? 1240*45916cd2Sjpk tme->mlpe_mlp.mlp_port_upper + 1 : 1241*45916cd2Sjpk tme->mlpe_mlp.mlp_port - 1; 1242*45916cd2Sjpk } 1243*45916cd2Sjpk rw_exit(&shared_mlps.mlpl_rwlock); 1244*45916cd2Sjpk } 1245*45916cd2Sjpk if (newport <= 65535 && newport > 0) 1246*45916cd2Sjpk break; 1247*45916cd2Sjpk if (loop) 1248*45916cd2Sjpk return (0); 1249*45916cd2Sjpk loop = B_TRUE; 1250*45916cd2Sjpk newport = upward ? 1 : 65535; 1251*45916cd2Sjpk } 1252*45916cd2Sjpk return (newport == port ? 0 : newport); 1253*45916cd2Sjpk } 1254*45916cd2Sjpk 1255*45916cd2Sjpk /* 1256*45916cd2Sjpk * tsol_mlp_port_type will check if the given (zone, proto, port) is a 1257*45916cd2Sjpk * multilevel port. If it is, return the type (shared, private, or both), or 1258*45916cd2Sjpk * indicate that it's single-level. 1259*45916cd2Sjpk * 1260*45916cd2Sjpk * Note: port is given in host byte order, not network byte order. 1261*45916cd2Sjpk */ 1262*45916cd2Sjpk mlp_type_t 1263*45916cd2Sjpk tsol_mlp_port_type(zone_t *zone, uchar_t proto, uint16_t port, 1264*45916cd2Sjpk mlp_type_t mlptype) 1265*45916cd2Sjpk { 1266*45916cd2Sjpk tsol_mlp_entry_t *tme; 1267*45916cd2Sjpk 1268*45916cd2Sjpk if (mlptype == mlptBoth || mlptype == mlptPrivate) { 1269*45916cd2Sjpk tme = NULL; 1270*45916cd2Sjpk if (zone->zone_mlps.mlpl_first != NULL) { 1271*45916cd2Sjpk rw_enter(&zone->zone_mlps.mlpl_rwlock, RW_READER); 1272*45916cd2Sjpk for (tme = zone->zone_mlps.mlpl_first; tme != NULL; 1273*45916cd2Sjpk tme = tme->mlpe_next) { 1274*45916cd2Sjpk if (proto == tme->mlpe_mlp.mlp_ipp && 1275*45916cd2Sjpk port >= tme->mlpe_mlp.mlp_port && 1276*45916cd2Sjpk port <= tme->mlpe_mlp.mlp_port_upper) 1277*45916cd2Sjpk break; 1278*45916cd2Sjpk } 1279*45916cd2Sjpk rw_exit(&zone->zone_mlps.mlpl_rwlock); 1280*45916cd2Sjpk } 1281*45916cd2Sjpk if (tme == NULL) { 1282*45916cd2Sjpk if (mlptype == mlptBoth) 1283*45916cd2Sjpk mlptype = mlptShared; 1284*45916cd2Sjpk else if (mlptype == mlptPrivate) 1285*45916cd2Sjpk mlptype = mlptSingle; 1286*45916cd2Sjpk } 1287*45916cd2Sjpk } 1288*45916cd2Sjpk if (mlptype == mlptBoth || mlptype == mlptShared) { 1289*45916cd2Sjpk tme = NULL; 1290*45916cd2Sjpk if (shared_mlps.mlpl_first != NULL) { 1291*45916cd2Sjpk rw_enter(&shared_mlps.mlpl_rwlock, RW_READER); 1292*45916cd2Sjpk for (tme = shared_mlps.mlpl_first; tme != NULL; 1293*45916cd2Sjpk tme = tme->mlpe_next) { 1294*45916cd2Sjpk if (proto == tme->mlpe_mlp.mlp_ipp && 1295*45916cd2Sjpk port >= tme->mlpe_mlp.mlp_port && 1296*45916cd2Sjpk port <= tme->mlpe_mlp.mlp_port_upper) 1297*45916cd2Sjpk break; 1298*45916cd2Sjpk } 1299*45916cd2Sjpk rw_exit(&shared_mlps.mlpl_rwlock); 1300*45916cd2Sjpk } 1301*45916cd2Sjpk if (tme == NULL) { 1302*45916cd2Sjpk if (mlptype == mlptBoth) 1303*45916cd2Sjpk mlptype = mlptPrivate; 1304*45916cd2Sjpk else if (mlptype == mlptShared) 1305*45916cd2Sjpk mlptype = mlptSingle; 1306*45916cd2Sjpk } 1307*45916cd2Sjpk } 1308*45916cd2Sjpk return (mlptype); 1309*45916cd2Sjpk } 1310*45916cd2Sjpk 1311*45916cd2Sjpk /* 1312*45916cd2Sjpk * tsol_mlp_findzone will check if the given (proto, port) is a multilevel port 1313*45916cd2Sjpk * on a shared address. If it is, return the owning zone. 1314*45916cd2Sjpk * 1315*45916cd2Sjpk * Note: lport is in network byte order, unlike the other MLP functions, 1316*45916cd2Sjpk * because the callers of this function are all dealing with packets off the 1317*45916cd2Sjpk * wire. 1318*45916cd2Sjpk */ 1319*45916cd2Sjpk zoneid_t 1320*45916cd2Sjpk tsol_mlp_findzone(uchar_t proto, uint16_t lport) 1321*45916cd2Sjpk { 1322*45916cd2Sjpk tsol_mlp_entry_t *tme; 1323*45916cd2Sjpk zoneid_t zoneid; 1324*45916cd2Sjpk uint16_t port; 1325*45916cd2Sjpk 1326*45916cd2Sjpk if (shared_mlps.mlpl_first == NULL) 1327*45916cd2Sjpk return (ALL_ZONES); 1328*45916cd2Sjpk port = ntohs(lport); 1329*45916cd2Sjpk rw_enter(&shared_mlps.mlpl_rwlock, RW_READER); 1330*45916cd2Sjpk for (tme = shared_mlps.mlpl_first; tme != NULL; tme = tme->mlpe_next) { 1331*45916cd2Sjpk if (proto == tme->mlpe_mlp.mlp_ipp && 1332*45916cd2Sjpk port >= tme->mlpe_mlp.mlp_port && 1333*45916cd2Sjpk port <= tme->mlpe_mlp.mlp_port_upper) 1334*45916cd2Sjpk break; 1335*45916cd2Sjpk } 1336*45916cd2Sjpk zoneid = tme == NULL ? ALL_ZONES : tme->mlpe_zoneid; 1337*45916cd2Sjpk rw_exit(&shared_mlps.mlpl_rwlock); 1338*45916cd2Sjpk return (zoneid); 1339*45916cd2Sjpk } 1340*45916cd2Sjpk 1341*45916cd2Sjpk /* Debug routine */ 1342*45916cd2Sjpk void 1343*45916cd2Sjpk tsol_print_label(const blevel_t *blev, const char *name) 1344*45916cd2Sjpk { 1345*45916cd2Sjpk const _blevel_impl_t *bli = (const _blevel_impl_t *)blev; 1346*45916cd2Sjpk 1347*45916cd2Sjpk /* We really support only sensitivity labels */ 1348*45916cd2Sjpk cmn_err(CE_NOTE, "%s %x:%x:%08x%08x%08x%08x%08x%08x%08x%08x", 1349*45916cd2Sjpk name, bli->id, LCLASS(bli), ntohl(bli->_comps.c1), 1350*45916cd2Sjpk ntohl(bli->_comps.c2), ntohl(bli->_comps.c3), ntohl(bli->_comps.c4), 1351*45916cd2Sjpk ntohl(bli->_comps.c5), ntohl(bli->_comps.c6), ntohl(bli->_comps.c7), 1352*45916cd2Sjpk ntohl(bli->_comps.c8)); 1353*45916cd2Sjpk } 1354*45916cd2Sjpk 1355*45916cd2Sjpk /* 1356*45916cd2Sjpk * Name: labelsys() 1357*45916cd2Sjpk * 1358*45916cd2Sjpk * Normal: Routes TSOL syscalls. 1359*45916cd2Sjpk * 1360*45916cd2Sjpk * Output: As defined for each TSOL syscall. 1361*45916cd2Sjpk * Returns ENOSYS for unrecognized calls. 1362*45916cd2Sjpk */ 1363*45916cd2Sjpk /* ARGSUSED */ 1364*45916cd2Sjpk int 1365*45916cd2Sjpk labelsys(int op, void *a1, void *a2, void *a3, void *a4, void *a5) 1366*45916cd2Sjpk { 1367*45916cd2Sjpk switch (op) { 1368*45916cd2Sjpk case TSOL_SYSLABELING: 1369*45916cd2Sjpk return (sys_labeling); 1370*45916cd2Sjpk case TSOL_TNRH: 1371*45916cd2Sjpk return (tnrh((int)(uintptr_t)a1, a2)); 1372*45916cd2Sjpk case TSOL_TNRHTP: 1373*45916cd2Sjpk return (tnrhtp((int)(uintptr_t)a1, a2)); 1374*45916cd2Sjpk case TSOL_TNMLP: 1375*45916cd2Sjpk return (tnmlp((int)(uintptr_t)a1, a2)); 1376*45916cd2Sjpk case TSOL_GETLABEL: 1377*45916cd2Sjpk return (getlabel((char *)a1, (bslabel_t *)a2)); 1378*45916cd2Sjpk case TSOL_FGETLABEL: 1379*45916cd2Sjpk return (fgetlabel((int)(uintptr_t)a1, (bslabel_t *)a2)); 1380*45916cd2Sjpk default: 1381*45916cd2Sjpk return (set_errno(ENOSYS)); 1382*45916cd2Sjpk } 1383*45916cd2Sjpk /* NOTREACHED */ 1384*45916cd2Sjpk } 1385