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