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