1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or https://opensource.org/licenses/CDDL-1.0. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/crypto/common.h> 27 #include <sys/crypto/impl.h> 28 #include <sys/crypto/sched_impl.h> 29 30 void 31 kcf_free_triedlist(kcf_prov_tried_t *list) 32 { 33 kcf_prov_tried_t *l; 34 35 while ((l = list) != NULL) { 36 list = list->pt_next; 37 KCF_PROV_REFRELE(l->pt_pd); 38 kmem_free(l, sizeof (kcf_prov_tried_t)); 39 } 40 } 41 42 kcf_prov_tried_t * 43 kcf_insert_triedlist(kcf_prov_tried_t **list, kcf_provider_desc_t *pd, 44 int kmflag) 45 { 46 kcf_prov_tried_t *l; 47 48 l = kmem_alloc(sizeof (kcf_prov_tried_t), kmflag); 49 if (l == NULL) 50 return (NULL); 51 52 l->pt_pd = pd; 53 l->pt_next = *list; 54 *list = l; 55 56 return (l); 57 } 58 59 static boolean_t 60 is_in_triedlist(kcf_provider_desc_t *pd, kcf_prov_tried_t *triedl) 61 { 62 while (triedl != NULL) { 63 if (triedl->pt_pd == pd) 64 return (B_TRUE); 65 triedl = triedl->pt_next; 66 } 67 68 return (B_FALSE); 69 } 70 71 /* 72 * Return the best provider for the specified mechanism. The provider 73 * is held and it is the caller's responsibility to release it when done. 74 * The fg input argument is used as a search criterion to pick a provider. 75 * A provider has to support this function group to be picked. 76 * 77 * Find the least loaded provider in the list of providers. We do a linear 78 * search to find one. This is fine as we assume there are only a few 79 * number of providers in this list. If this assumption ever changes, 80 * we should revisit this. 81 */ 82 kcf_provider_desc_t * 83 kcf_get_mech_provider(crypto_mech_type_t mech_type, kcf_mech_entry_t **mepp, 84 int *error, kcf_prov_tried_t *triedl, crypto_func_group_t fg) 85 { 86 kcf_provider_desc_t *pd = NULL; 87 kcf_prov_mech_desc_t *mdesc; 88 kcf_ops_class_t class; 89 int index; 90 kcf_mech_entry_t *me; 91 const kcf_mech_entry_tab_t *me_tab; 92 93 class = KCF_MECH2CLASS(mech_type); 94 if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) { 95 *error = CRYPTO_MECHANISM_INVALID; 96 return (NULL); 97 } 98 99 me_tab = &kcf_mech_tabs_tab[class]; 100 index = KCF_MECH2INDEX(mech_type); 101 if ((index < 0) || (index >= me_tab->met_size)) { 102 *error = CRYPTO_MECHANISM_INVALID; 103 return (NULL); 104 } 105 106 me = &((me_tab->met_tab)[index]); 107 if (mepp != NULL) 108 *mepp = me; 109 110 /* Is there a provider? */ 111 if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) { 112 pd = mdesc->pm_prov_desc; 113 if (!IS_FG_SUPPORTED(mdesc, fg) || 114 !KCF_IS_PROV_USABLE(pd) || 115 IS_PROVIDER_TRIED(pd, triedl)) 116 pd = NULL; 117 } 118 119 if (pd == NULL) { 120 /* 121 * We do not want to report CRYPTO_MECH_NOT_SUPPORTED, when 122 * we are in the "fallback to the next provider" case. Rather 123 * we preserve the error, so that the client gets the right 124 * error code. 125 */ 126 if (triedl == NULL) 127 *error = CRYPTO_MECH_NOT_SUPPORTED; 128 } else 129 KCF_PROV_REFHOLD(pd); 130 131 return (pd); 132 } 133