File: kcf_mech_tabs.c

package info (click to toggle)
zfs-linux 2.1.11-1%2Bdeb12u1
  • links: PTS, VCS
  • area: contrib
  • in suites: bookworm
  • size: 77,344 kB
  • sloc: ansic: 376,447; sh: 59,625; python: 7,872; asm: 6,476; makefile: 5,812; perl: 770; sed: 41; awk: 5
file content (791 lines) | stat: -rw-r--r-- 23,119 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <sys/zfs_context.h>
#include <sys/crypto/common.h>
#include <sys/crypto/api.h>
#include <sys/crypto/impl.h>
#include <sys/modhash.h>

/* Cryptographic mechanisms tables and their access functions */

/*
 * Internal numbers assigned to mechanisms are coded as follows:
 *
 * +----------------+----------------+
 * | mech. class    | mech. index    |
 * <--- 32-bits --->+<--- 32-bits --->
 *
 * the mech_class identifies the table the mechanism belongs to.
 * mech_index  is the index for that mechanism in the table.
 * A mechanism belongs to exactly 1 table.
 * The tables are:
 * . digest_mechs_tab[] for the msg digest mechs.
 * . cipher_mechs_tab[] for encrypt/decrypt and wrap/unwrap mechs.
 * . mac_mechs_tab[] for MAC mechs.
 * . sign_mechs_tab[] for sign & verify mechs.
 * . keyops_mechs_tab[] for key/key pair generation, and key derivation.
 * . misc_mechs_tab[] for mechs that don't belong to any of the above.
 *
 * There are no holes in the tables.
 */

/*
 * Locking conventions:
 * --------------------
 * A global mutex, kcf_mech_tabs_lock, serializes writes to the
 * mechanism table via kcf_create_mech_entry().
 *
 * A mutex is associated with every entry of the tables.
 * The mutex is acquired whenever the entry is accessed for
 * 1) retrieving the mech_id (comparing the mech name)
 * 2) finding a provider for an xxx_init() or atomic operation.
 * 3) altering the mechs entry to add or remove a provider.
 *
 * In 2), after a provider is chosen, its prov_desc is held and the
 * entry's mutex must be dropped. The provider's working function (SPI) is
 * called outside the mech_entry's mutex.
 *
 * The number of providers for a particular mechanism is not expected to be
 * long enough to justify the cost of using rwlocks, so the per-mechanism
 * entry mutex won't be very *hot*.
 *
 * When both kcf_mech_tabs_lock and a mech_entry mutex need to be held,
 * kcf_mech_tabs_lock must always be acquired first.
 *
 */

		/* Mechanisms tables */


/* RFE 4687834 Will deal with the extensibility of these tables later */

kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];

kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
	{0, NULL},				/* No class zero */
	{KCF_MAXDIGEST, kcf_digest_mechs_tab},
	{KCF_MAXCIPHER, kcf_cipher_mechs_tab},
	{KCF_MAXMAC, kcf_mac_mechs_tab},
	{KCF_MAXSIGN, kcf_sign_mechs_tab},
	{KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
	{KCF_MAXMISC, kcf_misc_mechs_tab}
};

/*
 * Per-algorithm internal thresholds for the minimum input size of before
 * offloading to hardware provider.
 * Dispatching a crypto operation  to a hardware provider entails paying the
 * cost of an additional context switch.  Measurements with Sun Accelerator 4000
 * shows that 512-byte jobs or smaller are better handled in software.
 * There is room for refinement here.
 *
 */
int kcf_md5_threshold = 512;
int kcf_sha1_threshold = 512;
int kcf_des_threshold = 512;
int kcf_des3_threshold = 512;
int kcf_aes_threshold = 512;
int kcf_bf_threshold = 512;
int kcf_rc4_threshold = 512;

kmutex_t kcf_mech_tabs_lock;
static uint32_t kcf_gen_swprov = 0;

int kcf_mech_hash_size = 256;
mod_hash_t *kcf_mech_hash;	/* mech name to id hash */

static crypto_mech_type_t
kcf_mech_hash_find(char *mechname)
{
	mod_hash_val_t hv;
	crypto_mech_type_t mt;

	mt = CRYPTO_MECH_INVALID;
	if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
		mt = *(crypto_mech_type_t *)hv;
		ASSERT(mt != CRYPTO_MECH_INVALID);
	}

	return (mt);
}

void
kcf_destroy_mech_tabs(void)
{
	int i, max;
	kcf_ops_class_t class;
	kcf_mech_entry_t *me_tab;

	if (kcf_mech_hash)
		mod_hash_destroy_hash(kcf_mech_hash);

	mutex_destroy(&kcf_mech_tabs_lock);

	for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
		max = kcf_mech_tabs_tab[class].met_size;
		me_tab = kcf_mech_tabs_tab[class].met_tab;
		for (i = 0; i < max; i++)
			mutex_destroy(&(me_tab[i].me_mutex));
	}
}

/*
 * kcf_init_mech_tabs()
 *
 * Called by the misc/kcf's _init() routine to initialize the tables
 * of mech_entry's.
 */
void
kcf_init_mech_tabs(void)
{
	int i, max;
	kcf_ops_class_t class;
	kcf_mech_entry_t *me_tab;

	/* Initializes the mutex locks. */

	mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);

	/* Then the pre-defined mechanism entries */

	/* Two digests */
	(void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
	    CRYPTO_MAX_MECH_NAME);
	kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;

	(void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
	    CRYPTO_MAX_MECH_NAME);
	kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;

	/* The symmetric ciphers in various modes */
	(void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;

	(void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
	    CRYPTO_MAX_MECH_NAME);
	kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;


	/* 4 HMACs */
	(void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
	    CRYPTO_MAX_MECH_NAME);
	kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;

	(void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
	    CRYPTO_MAX_MECH_NAME);
	kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;

	(void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
	    CRYPTO_MAX_MECH_NAME);
	kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;

	(void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
	    CRYPTO_MAX_MECH_NAME);
	kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;


	/* 1 random number generation pseudo mechanism */
	(void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
	    CRYPTO_MAX_MECH_NAME);

	kcf_mech_hash = mod_hash_create_strhash_nodtr("kcf mech2id hash",
	    kcf_mech_hash_size, mod_hash_null_valdtor);

	for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
		max = kcf_mech_tabs_tab[class].met_size;
		me_tab = kcf_mech_tabs_tab[class].met_tab;
		for (i = 0; i < max; i++) {
			mutex_init(&(me_tab[i].me_mutex), NULL,
			    MUTEX_DEFAULT, NULL);
			if (me_tab[i].me_name[0] != 0) {
				me_tab[i].me_mechid = KCF_MECHID(class, i);
				(void) mod_hash_insert(kcf_mech_hash,
				    (mod_hash_key_t)me_tab[i].me_name,
				    (mod_hash_val_t)&(me_tab[i].me_mechid));
			}
		}
	}
}

/*
 * kcf_create_mech_entry()
 *
 * Arguments:
 *	. The class of mechanism.
 *	. the name of the new mechanism.
 *
 * Description:
 *	Creates a new mech_entry for a mechanism not yet known to the
 *	framework.
 *	This routine is called by kcf_add_mech_provider, which is
 *	in turn invoked for each mechanism supported by a provider.
 *	The'class' argument depends on the crypto_func_group_t bitmask
 *	in the registering provider's mech_info struct for this mechanism.
 *	When there is ambiguity in the mapping between the crypto_func_group_t
 *	and a class (dual ops, ...) the KCF_MISC_CLASS should be used.
 *
 * Context:
 *	User context only.
 *
 * Returns:
 *	KCF_INVALID_MECH_CLASS or KCF_INVALID_MECH_NAME if the class or
 *	the mechname is bogus.
 *	KCF_MECH_TAB_FULL when there is no room left in the mech. tabs.
 *	KCF_SUCCESS otherwise.
 */
static int
kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
{
	crypto_mech_type_t mt;
	kcf_mech_entry_t *me_tab;
	int i = 0, size;

	if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
		return (KCF_INVALID_MECH_CLASS);

	if ((mechname == NULL) || (mechname[0] == 0))
		return (KCF_INVALID_MECH_NAME);
	/*
	 * First check if the mechanism is already in one of the tables.
	 * The mech_entry could be in another class.
	 */
	mutex_enter(&kcf_mech_tabs_lock);
	mt = kcf_mech_hash_find(mechname);
	if (mt != CRYPTO_MECH_INVALID) {
		/* Nothing to do, regardless the suggested class. */
		mutex_exit(&kcf_mech_tabs_lock);
		return (KCF_SUCCESS);
	}
	/* Now take the next unused mech entry in the class's tab */
	me_tab = kcf_mech_tabs_tab[class].met_tab;
	size = kcf_mech_tabs_tab[class].met_size;

	while (i < size) {
		mutex_enter(&(me_tab[i].me_mutex));
		if (me_tab[i].me_name[0] == 0) {
			/* Found an empty spot */
			(void) strlcpy(me_tab[i].me_name, mechname,
			    CRYPTO_MAX_MECH_NAME);
			me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
			me_tab[i].me_mechid = KCF_MECHID(class, i);
			/*
			 * No a-priori information about the new mechanism, so
			 * the threshold is set to zero.
			 */
			me_tab[i].me_threshold = 0;

			mutex_exit(&(me_tab[i].me_mutex));
			/* Add the new mechanism to the hash table */
			(void) mod_hash_insert(kcf_mech_hash,
			    (mod_hash_key_t)me_tab[i].me_name,
			    (mod_hash_val_t)&(me_tab[i].me_mechid));
			break;
		}
		mutex_exit(&(me_tab[i].me_mutex));
		i++;
	}

	mutex_exit(&kcf_mech_tabs_lock);

	if (i == size) {
		return (KCF_MECH_TAB_FULL);
	}

	return (KCF_SUCCESS);
}

/*
 * kcf_add_mech_provider()
 *
 * Arguments:
 *	. An index in to  the provider mechanism array
 *      . A pointer to the provider descriptor
 *	. A storage for the kcf_prov_mech_desc_t the entry was added at.
 *
 * Description:
 *      Adds  a new provider of a mechanism to the mechanism's mech_entry
 *	chain.
 *
 * Context:
 *      User context only.
 *
 * Returns
 *      KCF_SUCCESS on success
 *      KCF_MECH_TAB_FULL otherwise.
 */
int
kcf_add_mech_provider(short mech_indx,
    kcf_provider_desc_t *prov_desc, kcf_prov_mech_desc_t **pmdpp)
{
	int error;
	kcf_mech_entry_t *mech_entry = NULL;
	crypto_mech_info_t *mech_info;
	crypto_mech_type_t kcf_mech_type, mt;
	kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
	crypto_func_group_t simple_fg_mask, dual_fg_mask;
	crypto_mech_info_t *dmi;
	crypto_mech_info_list_t *mil, *mil2;
	kcf_mech_entry_t *me;
	int i;

	ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);

	mech_info = &prov_desc->pd_mechanisms[mech_indx];

	/*
	 * A mechanism belongs to exactly one mechanism table.
	 * Find the class corresponding to the function group flag of
	 * the mechanism.
	 */
	kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
	if (kcf_mech_type == CRYPTO_MECH_INVALID) {
		crypto_func_group_t fg = mech_info->cm_func_group_mask;
		kcf_ops_class_t class;

		if (fg & CRYPTO_FG_DIGEST || fg & CRYPTO_FG_DIGEST_ATOMIC)
			class = KCF_DIGEST_CLASS;
		else if (fg & CRYPTO_FG_ENCRYPT || fg & CRYPTO_FG_DECRYPT ||
		    fg & CRYPTO_FG_ENCRYPT_ATOMIC ||
		    fg & CRYPTO_FG_DECRYPT_ATOMIC)
			class = KCF_CIPHER_CLASS;
		else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
			class = KCF_MAC_CLASS;
		else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
		    fg & CRYPTO_FG_SIGN_ATOMIC ||
		    fg & CRYPTO_FG_VERIFY_ATOMIC ||
		    fg & CRYPTO_FG_SIGN_RECOVER ||
		    fg & CRYPTO_FG_VERIFY_RECOVER)
			class = KCF_SIGN_CLASS;
		else if (fg & CRYPTO_FG_GENERATE ||
		    fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
		    fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
		    fg & CRYPTO_FG_DERIVE)
			class = KCF_KEYOPS_CLASS;
		else
			class = KCF_MISC_CLASS;

		/*
		 * Attempt to create a new mech_entry for the specified
		 * mechanism. kcf_create_mech_entry() can handle the case
		 * where such an entry already exists.
		 */
		if ((error = kcf_create_mech_entry(class,
		    mech_info->cm_mech_name)) != KCF_SUCCESS) {
			return (error);
		}
		/* get the KCF mech type that was assigned to the mechanism */
		kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
		ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
	}

	error = kcf_get_mech_entry(kcf_mech_type, &mech_entry);
	ASSERT(error == KCF_SUCCESS);

	/* allocate and initialize new kcf_prov_mech_desc */
	prov_mech = kmem_zalloc(sizeof (kcf_prov_mech_desc_t), KM_SLEEP);
	bcopy(mech_info, &prov_mech->pm_mech_info, sizeof (crypto_mech_info_t));
	prov_mech->pm_prov_desc = prov_desc;
	prov_desc->pd_mech_indx[KCF_MECH2CLASS(kcf_mech_type)]
	    [KCF_MECH2INDEX(kcf_mech_type)] = mech_indx;

	KCF_PROV_REFHOLD(prov_desc);
	KCF_PROV_IREFHOLD(prov_desc);

	dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;

	if (dual_fg_mask == ((crypto_func_group_t)0))
		goto add_entry;

	simple_fg_mask = (mech_info->cm_func_group_mask &
	    CRYPTO_FG_SIMPLEOP_MASK) | CRYPTO_FG_RANDOM;

	for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
		dmi = &prov_desc->pd_mechanisms[i];

		/* skip self */
		if (dmi->cm_mech_number == mech_info->cm_mech_number)
			continue;

		/* skip if not a dual operation mechanism */
		if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
		    (dmi->cm_func_group_mask & simple_fg_mask))
			continue;

		mt = kcf_mech_hash_find(dmi->cm_mech_name);
		if (mt == CRYPTO_MECH_INVALID)
			continue;

		if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
			continue;

		mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
		mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);

		/*
		 * Ignore hard-coded entries in the mech table
		 * if the provider hasn't registered.
		 */
		mutex_enter(&me->me_mutex);
		if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
			mutex_exit(&me->me_mutex);
			kmem_free(mil, sizeof (*mil));
			kmem_free(mil2, sizeof (*mil2));
			continue;
		}

		/*
		 * Add other dual mechanisms that have registered
		 * with the framework to this mechanism's
		 * cross-reference list.
		 */
		mil->ml_mech_info = *dmi; /* struct assignment */
		mil->ml_kcf_mechid = mt;

		/* add to head of list */
		mil->ml_next = prov_mech->pm_mi_list;
		prov_mech->pm_mi_list = mil;

		if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
			prov_mech2 = me->me_hw_prov_chain;
		else
			prov_mech2 = me->me_sw_prov;

		if (prov_mech2 == NULL) {
			kmem_free(mil2, sizeof (*mil2));
			mutex_exit(&me->me_mutex);
			continue;
		}

		/*
		 * Update all other cross-reference lists by
		 * adding this new mechanism.
		 */
		while (prov_mech2 != NULL) {
			if (prov_mech2->pm_prov_desc == prov_desc) {
				/* struct assignment */
				mil2->ml_mech_info = *mech_info;
				mil2->ml_kcf_mechid = kcf_mech_type;

				/* add to head of list */
				mil2->ml_next = prov_mech2->pm_mi_list;
				prov_mech2->pm_mi_list = mil2;
				break;
			}
			prov_mech2 = prov_mech2->pm_next;
		}
		if (prov_mech2 == NULL)
			kmem_free(mil2, sizeof (*mil2));

		mutex_exit(&me->me_mutex);
	}

add_entry:
	/*
	 * Add new kcf_prov_mech_desc at the front of HW providers
	 * chain.
	 */
	switch (prov_desc->pd_prov_type) {

	case CRYPTO_HW_PROVIDER:
		mutex_enter(&mech_entry->me_mutex);
		prov_mech->pm_me = mech_entry;
		prov_mech->pm_next = mech_entry->me_hw_prov_chain;
		mech_entry->me_hw_prov_chain = prov_mech;
		mech_entry->me_num_hwprov++;
		mutex_exit(&mech_entry->me_mutex);
		break;

	case CRYPTO_SW_PROVIDER:
		mutex_enter(&mech_entry->me_mutex);
		if (mech_entry->me_sw_prov != NULL) {
			/*
			 * There is already a SW provider for this mechanism.
			 * Since we allow only one SW provider per mechanism,
			 * report this condition.
			 */
			cmn_err(CE_WARN, "The cryptographic software provider "
			    "\"%s\" will not be used for %s. The provider "
			    "\"%s\" will be used for this mechanism "
			    "instead.", prov_desc->pd_description,
			    mech_info->cm_mech_name,
			    mech_entry->me_sw_prov->pm_prov_desc->
			    pd_description);
			KCF_PROV_REFRELE(prov_desc);
			kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
			prov_mech = NULL;
		} else {
			/*
			 * Set the provider as the software provider for
			 * this mechanism.
			 */
			mech_entry->me_sw_prov = prov_mech;

			/* We'll wrap around after 4 billion registrations! */
			mech_entry->me_gen_swprov = kcf_gen_swprov++;
		}
		mutex_exit(&mech_entry->me_mutex);
		break;
	default:
		break;
	}

	*pmdpp = prov_mech;

	return (KCF_SUCCESS);
}

/*
 * kcf_remove_mech_provider()
 *
 * Arguments:
 *      . mech_name: the name of the mechanism.
 *      . prov_desc: The provider descriptor
 *
 * Description:
 *      Removes a provider from chain of provider descriptors.
 *	The provider is made unavailable to kernel consumers for the specified
 *	mechanism.
 *
 * Context:
 *      User context only.
 */
void
kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
{
	crypto_mech_type_t mech_type;
	kcf_prov_mech_desc_t *prov_mech = NULL, *prov_chain;
	kcf_prov_mech_desc_t **prev_entry_next;
	kcf_mech_entry_t *mech_entry;
	crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;

	ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);

	/* get the KCF mech type that was assigned to the mechanism */
	if ((mech_type = kcf_mech_hash_find(mech_name)) ==
	    CRYPTO_MECH_INVALID) {
		/*
		 * Provider was not allowed for this mech due to policy or
		 * configuration.
		 */
		return;
	}

	/* get a ptr to the mech_entry that was created */
	if (kcf_get_mech_entry(mech_type, &mech_entry) != KCF_SUCCESS) {
		/*
		 * Provider was not allowed for this mech due to policy or
		 * configuration.
		 */
		return;
	}

	mutex_enter(&mech_entry->me_mutex);

	switch (prov_desc->pd_prov_type) {

	case CRYPTO_HW_PROVIDER:
		/* find the provider in the mech_entry chain */
		prev_entry_next = &mech_entry->me_hw_prov_chain;
		prov_mech = mech_entry->me_hw_prov_chain;
		while (prov_mech != NULL &&
		    prov_mech->pm_prov_desc != prov_desc) {
			prev_entry_next = &prov_mech->pm_next;
			prov_mech = prov_mech->pm_next;
		}

		if (prov_mech == NULL) {
			/* entry not found, simply return */
			mutex_exit(&mech_entry->me_mutex);
			return;
		}

		/* remove provider entry from mech_entry chain */
		*prev_entry_next = prov_mech->pm_next;
		ASSERT(mech_entry->me_num_hwprov > 0);
		mech_entry->me_num_hwprov--;
		break;

	case CRYPTO_SW_PROVIDER:
		if (mech_entry->me_sw_prov == NULL ||
		    mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
			/* not the software provider for this mechanism */
			mutex_exit(&mech_entry->me_mutex);
			return;
		}
		prov_mech = mech_entry->me_sw_prov;
		mech_entry->me_sw_prov = NULL;
		break;
	default:
		/* unexpected crypto_provider_type_t */
		mutex_exit(&mech_entry->me_mutex);
		return;
	}

	mutex_exit(&mech_entry->me_mutex);

	/* Free the dual ops cross-reference lists  */
	mil = prov_mech->pm_mi_list;
	while (mil != NULL) {
		next = mil->ml_next;
		if (kcf_get_mech_entry(mil->ml_kcf_mechid,
		    &mech_entry) != KCF_SUCCESS) {
			mil = next;
			continue;
		}

		mutex_enter(&mech_entry->me_mutex);
		if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
			prov_chain = mech_entry->me_hw_prov_chain;
		else
			prov_chain = mech_entry->me_sw_prov;

		while (prov_chain != NULL) {
			if (prov_chain->pm_prov_desc == prov_desc) {
				prev_next = &prov_chain->pm_mi_list;
				mil2 = prov_chain->pm_mi_list;
				while (mil2 != NULL &&
				    mil2->ml_kcf_mechid != mech_type) {
					prev_next = &mil2->ml_next;
					mil2 = mil2->ml_next;
				}
				if (mil2 != NULL) {
					*prev_next = mil2->ml_next;
					kmem_free(mil2, sizeof (*mil2));
				}
				break;
			}
			prov_chain = prov_chain->pm_next;
		}

		mutex_exit(&mech_entry->me_mutex);
		kmem_free(mil, sizeof (crypto_mech_info_list_t));
		mil = next;
	}

	/* free entry  */
	KCF_PROV_IREFRELE(prov_mech->pm_prov_desc);
	KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
	kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
}

/*
 * kcf_get_mech_entry()
 *
 * Arguments:
 *      . The framework mechanism type
 *      . Storage for the mechanism entry
 *
 * Description:
 *      Retrieves the mechanism entry for the mech.
 *
 * Context:
 *      User and interrupt contexts.
 *
 * Returns:
 *      KCF_MECHANISM_XXX appropriate error code.
 *      KCF_SUCCESS otherwise.
 */
int
kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
{
	kcf_ops_class_t		class;
	int			index;
	kcf_mech_entry_tab_t	*me_tab;

	ASSERT(mep != NULL);

	class = KCF_MECH2CLASS(mech_type);

	if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
		/* the caller won't need to know it's an invalid class */
		return (KCF_INVALID_MECH_NUMBER);
	}

	me_tab = &kcf_mech_tabs_tab[class];
	index = KCF_MECH2INDEX(mech_type);

	if ((index < 0) || (index >= me_tab->met_size)) {
		return (KCF_INVALID_MECH_NUMBER);
	}

	*mep = &((me_tab->met_tab)[index]);

	return (KCF_SUCCESS);
}

/* CURRENTLY UNSUPPORTED: attempting to load the module if it isn't found */
/*
 * Lookup the hash table for an entry that matches the mechname.
 * If there are no hardware or software providers for the mechanism,
 * but there is an unloaded software provider, this routine will attempt
 * to load it.
 *
 * If the MOD_NOAUTOUNLOAD flag is not set, a software provider is
 * in constant danger of being unloaded.  For consumers that call
 * crypto_mech2id() only once, the provider will not be reloaded
 * if it becomes unloaded.  If a provider gets loaded elsewhere
 * without the MOD_NOAUTOUNLOAD flag being set, we set it now.
 */
crypto_mech_type_t
crypto_mech2id_common(char *mechname, boolean_t load_module)
{
	crypto_mech_type_t mt = kcf_mech_hash_find(mechname);
	return (mt);
}