Print this page
Bayard's initial drop, needs finishing, or at least testing.


   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 http://www.opensolaris.org/os/licensing.
  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 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.

  24  * Copyright (c) 2016 by Delphix. All rights reserved.

  25  */
  26 
  27 /*
  28  * IPsec Security Policy Database.
  29  *
  30  * This module maintains the SPD and provides routines used by ip and ip6
  31  * to apply IPsec policy to inbound and outbound datagrams.
  32  */
  33 
  34 #include <sys/types.h>
  35 #include <sys/stream.h>
  36 #include <sys/stropts.h>
  37 #include <sys/sysmacros.h>
  38 #include <sys/strsubr.h>
  39 #include <sys/strsun.h>
  40 #include <sys/strlog.h>
  41 #include <sys/strsun.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/zone.h>
  44 


 396         /*
 397          * Globals start with ref == 1 to prevent IPPH_REFRELE() from
 398          * attempting to free them, hence they should have 1 now.
 399          */
 400         ipsec_polhead_destroy(&ipss->ipsec_system_policy);
 401         ASSERT(ipss->ipsec_system_policy.iph_refs == 1);
 402         ipsec_polhead_destroy(&ipss->ipsec_inactive_policy);
 403         ASSERT(ipss->ipsec_inactive_policy.iph_refs == 1);
 404 
 405         for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++) {
 406                 ipsec_action_free_table(ipss->ipsec_action_hash[i].hash_head);
 407                 ipss->ipsec_action_hash[i].hash_head = NULL;
 408                 mutex_destroy(&(ipss->ipsec_action_hash[i].hash_lock));
 409         }
 410 
 411         for (i = 0; i < ipss->ipsec_spd_hashsize; i++) {
 412                 ASSERT(ipss->ipsec_sel_hash[i].hash_head == NULL);
 413                 mutex_destroy(&(ipss->ipsec_sel_hash[i].hash_lock));
 414         }
 415 
 416         mutex_enter(&ipss->ipsec_alg_lock);
 417         for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype ++) {
 418                 int nalgs = ipss->ipsec_nalgs[algtype];
 419 
 420                 for (i = 0; i < nalgs; i++) {
 421                         if (ipss->ipsec_alglists[algtype][i] != NULL)
 422                                 ipsec_alg_unreg(algtype, i, ns);
 423                 }
 424         }
 425         mutex_exit(&ipss->ipsec_alg_lock);
 426         mutex_destroy(&ipss->ipsec_alg_lock);
 427 
 428         ipsid_gc(ns);
 429         ipsid_fini(ns);
 430 
 431         (void) ipsec_free_tables(ipss);
 432         kmem_free(ipss, sizeof (*ipss));
 433 }
 434 
 435 void
 436 ipsec_policy_g_destroy(void)
 437 {
 438         kmem_cache_destroy(ipsec_action_cache);
 439         kmem_cache_destroy(ipsec_sel_cache);
 440         kmem_cache_destroy(ipsec_pol_cache);
 441 
 442         ipsec_unregister_prov_update();
 443 
 444         netstack_unregister(NS_IPSEC);
 445 }
 446 


 638             ipss->ipsec_spd_hashsize);
 639         ipsec_polhead_init(&ipss->ipsec_inactive_policy,
 640             ipss->ipsec_spd_hashsize);
 641         rw_init(&ipss->ipsec_tunnel_policy_lock, NULL, RW_DEFAULT, NULL);
 642         avl_create(&ipss->ipsec_tunnel_policies, tunnel_compare,
 643             sizeof (ipsec_tun_pol_t), 0);
 644 
 645         ipss->ipsec_next_policy_index = 1;
 646 
 647         rw_init(&ipss->ipsec_system_policy.iph_lock, NULL, RW_DEFAULT, NULL);
 648         rw_init(&ipss->ipsec_inactive_policy.iph_lock, NULL, RW_DEFAULT, NULL);
 649 
 650         for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++)
 651                 mutex_init(&(ipss->ipsec_action_hash[i].hash_lock),
 652                     NULL, MUTEX_DEFAULT, NULL);
 653 
 654         for (i = 0; i < ipss->ipsec_spd_hashsize; i++)
 655                 mutex_init(&(ipss->ipsec_sel_hash[i].hash_lock),
 656                     NULL, MUTEX_DEFAULT, NULL);
 657 
 658         mutex_init(&ipss->ipsec_alg_lock, NULL, MUTEX_DEFAULT, NULL);
 659         for (i = 0; i < IPSEC_NALGTYPES; i++) {
 660                 ipss->ipsec_nalgs[i] = 0;
 661         }
 662 
 663         ip_drop_init(ipss);
 664         ip_drop_register(&ipss->ipsec_spd_dropper, "IPsec SPD");
 665 
 666         /* IP's IPsec code calls the packet dropper */
 667         ip_drop_register(&ipss->ipsec_dropper, "IP IPsec processing");
 668 
 669         (void) ipsec_kstat_init(ipss);
 670 
 671         ipsec_loader_init(ipss);
 672         ipsec_loader_start(ipss);
 673 
 674         return (ipss);
 675 }
 676 
 677 /* Global across all stack instances */
 678 void


 701  *
 702  * I may need to split this based on
 703  * authentication/encryption, and I may wish to have an administrator
 704  * configure this list.  Hold on to some NDD variables...
 705  *
 706  * XXX For now, sort on minimum key size (GAG!).  While minimum key size is
 707  * not the ideal metric, it's the only quantifiable measure available.
 708  * We need a better metric for sorting algorithms by preference.
 709  */
 710 static void
 711 alg_insert_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 712 {
 713         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 714         ipsec_alginfo_t *ai = ipss->ipsec_alglists[at][algid];
 715         uint8_t holder, swap;
 716         uint_t i;
 717         uint_t count = ipss->ipsec_nalgs[at];
 718         ASSERT(ai != NULL);
 719         ASSERT(algid == ai->alg_id);
 720 
 721         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
 722 
 723         holder = algid;
 724 
 725         for (i = 0; i < count - 1; i++) {
 726                 ipsec_alginfo_t *alt;
 727 
 728                 alt = ipss->ipsec_alglists[at][ipss->ipsec_sortlist[at][i]];
 729                 /*
 730                  * If you want to give precedence to newly added algs,
 731                  * add the = in the > comparison.
 732                  */
 733                 if ((holder != algid) || (ai->alg_minbits > alt->alg_minbits)) {
 734                         /* Swap sortlist[i] and holder. */
 735                         swap = ipss->ipsec_sortlist[at][i];
 736                         ipss->ipsec_sortlist[at][i] = holder;
 737                         holder = swap;
 738                         ai = alt;
 739                 } /* Else just continue. */
 740         }
 741 
 742         /* Store holder in last slot. */
 743         ipss->ipsec_sortlist[at][i] = holder;
 744 }
 745 
 746 /*
 747  * Remove an algorithm from a sorted algorithm list.
 748  * This should be considerably easier, even with complex sorting.
 749  */
 750 static void
 751 alg_remove_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 752 {
 753         boolean_t copyback = B_FALSE;
 754         int i;
 755         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 756         int newcount = ipss->ipsec_nalgs[at];
 757 
 758         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
 759 
 760         for (i = 0; i <= newcount; i++) {
 761                 if (copyback) {
 762                         ipss->ipsec_sortlist[at][i-1] =
 763                             ipss->ipsec_sortlist[at][i];
 764                 } else if (ipss->ipsec_sortlist[at][i] == algid) {
 765                         copyback = B_TRUE;
 766                 }
 767         }
 768 }
 769 
 770 /*
 771  * Add the specified algorithm to the algorithm tables.
 772  * Must be called while holding the algorithm table writer lock.
 773  */
 774 void
 775 ipsec_alg_reg(ipsec_algtype_t algtype, ipsec_alginfo_t *alg, netstack_t *ns)
 776 {
 777         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 778 
 779         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
 780 
 781         ASSERT(ipss->ipsec_alglists[algtype][alg->alg_id] == NULL);
 782         ipsec_alg_fix_min_max(alg, algtype, ns);
 783         ipss->ipsec_alglists[algtype][alg->alg_id] = alg;
 784 
 785         ipss->ipsec_nalgs[algtype]++;
 786         alg_insert_sortlist(algtype, alg->alg_id, ns);
 787 }
 788 
 789 /*
 790  * Remove the specified algorithm from the algorithm tables.
 791  * Must be called while holding the algorithm table writer lock.
 792  */
 793 void
 794 ipsec_alg_unreg(ipsec_algtype_t algtype, uint8_t algid, netstack_t *ns)
 795 {
 796         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 797 
 798         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
 799 
 800         ASSERT(ipss->ipsec_alglists[algtype][algid] != NULL);
 801         ipsec_alg_free(ipss->ipsec_alglists[algtype][algid]);
 802         ipss->ipsec_alglists[algtype][algid] = NULL;
 803 
 804         ipss->ipsec_nalgs[algtype]--;
 805         alg_remove_sortlist(algtype, algid, ns);
 806 }
 807 
 808 /*
 809  * Hooks for spdsock to get a grip on system policy.
 810  */
 811 
 812 ipsec_policy_head_t *
 813 ipsec_system_policy(netstack_t *ns)
 814 {
 815         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 816         ipsec_policy_head_t *h = &ipss->ipsec_system_policy;
 817 
 818         IPPH_REFHOLD(h);


4670 }
4671 
4672 /*
4673  * Free identity table (preparatory to module unload)
4674  */
4675 static void
4676 ipsid_fini(netstack_t *ns)
4677 {
4678         ipsif_t *bucket;
4679         int i;
4680         ipsec_stack_t   *ipss = ns->netstack_ipsec;
4681 
4682         for (i = 0; i < IPSID_HASHSIZE; i++) {
4683                 bucket = &ipss->ipsec_ipsid_buckets[i];
4684                 ASSERT(bucket->ipsif_head == NULL);
4685                 mutex_destroy(&bucket->ipsif_lock);
4686         }
4687 }
4688 
4689 /*
4690  * Update the minimum and maximum supported key sizes for the
4691  * specified algorithm. Must be called while holding the algorithms lock.

4692  */
4693 void
4694 ipsec_alg_fix_min_max(ipsec_alginfo_t *alg, ipsec_algtype_t alg_type,
4695     netstack_t *ns)
4696 {
4697         size_t crypto_min = (size_t)-1, crypto_max = 0;
4698         size_t cur_crypto_min, cur_crypto_max;
4699         boolean_t is_valid;
4700         crypto_mechanism_info_t *mech_infos;
4701         uint_t nmech_infos;
4702         int crypto_rc, i;
4703         crypto_mech_usage_t mask;
4704         ipsec_stack_t   *ipss = ns->netstack_ipsec;
4705 
4706         ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
4707 
4708         /*
4709          * Compute the min, max, and default key sizes (in number of
4710          * increments to the default key size in bits) as defined
4711          * by the algorithm mappings. This range of key sizes is used
4712          * for policy related operations. The effective key sizes
4713          * supported by the framework could be more limited than
4714          * those defined for an algorithm.
4715          */
4716         alg->alg_default_bits = alg->alg_key_sizes[0];
4717         alg->alg_default = 0;
4718         if (alg->alg_increment != 0) {
4719                 /* key sizes are defined by range & increment */
4720                 alg->alg_minbits = alg->alg_key_sizes[1];
4721                 alg->alg_maxbits = alg->alg_key_sizes[2];
4722         } else if (alg->alg_nkey_sizes == 0) {
4723                 /* no specified key size for algorithm */
4724                 alg->alg_minbits = alg->alg_maxbits = 0;
4725         } else {
4726                 /* key sizes are defined by enumeration */


5039         crypto_mech_name_t *mechs;
5040         boolean_t alg_changed = B_FALSE;
5041         ipsec_stack_t   *ipss = ns->netstack_ipsec;
5042 
5043         /* ignore events for which we didn't register */
5044         if (event != CRYPTO_EVENT_MECHS_CHANGED) {
5045                 ip1dbg(("ipsec_prov_update_callback: unexpected event 0x%x "
5046                     " received from crypto framework\n", event));
5047                 return;
5048         }
5049 
5050         mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
5051         if (mechs == NULL)
5052                 return;
5053 
5054         /*
5055          * Walk the list of currently defined IPsec algorithm. Update
5056          * the algorithm valid flag and trigger an update of the
5057          * SAs that depend on that algorithm.
5058          */
5059         mutex_enter(&ipss->ipsec_alg_lock);
5060         for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
5061                 for (algidx = 0; algidx < ipss->ipsec_nalgs[algtype];
5062                     algidx++) {
5063 
5064                         algid = ipss->ipsec_sortlist[algtype][algidx];
5065                         alg = ipss->ipsec_alglists[algtype][algid];
5066                         ASSERT(alg != NULL);
5067 
5068                         /*
5069                          * Skip the algorithms which do not map to the
5070                          * crypto framework provider being added or removed.
5071                          */
5072                         if (strncmp(alg->alg_mech_name,
5073                             prov_change->ec_mech_name,
5074                             CRYPTO_MAX_MECH_NAME) != 0)
5075                                 continue;
5076 
5077                         /*
5078                          * Determine if the mechanism is valid. If it
5079                          * is not, mark the algorithm as being invalid. If


5102                         ipsec_alg_fix_min_max(alg, algtype, ns);
5103                         if (!alg_changed &&
5104                             alg->alg_ef_minbits != oalg.alg_ef_minbits ||
5105                             alg->alg_ef_maxbits != oalg.alg_ef_maxbits ||
5106                             alg->alg_ef_default != oalg.alg_ef_default ||
5107                             alg->alg_ef_default_bits !=
5108                             oalg.alg_ef_default_bits)
5109                                 alg_changed = B_TRUE;
5110 
5111                         /*
5112                          * Update the affected SAs if a software provider is
5113                          * being added or removed.
5114                          */
5115                         if (prov_change->ec_provider_type ==
5116                             CRYPTO_SW_PROVIDER)
5117                                 sadb_alg_update(algtype, alg->alg_id,
5118                                     prov_change->ec_change ==
5119                                     CRYPTO_MECH_ADDED, ns);
5120                 }
5121         }
5122         mutex_exit(&ipss->ipsec_alg_lock);
5123         crypto_free_mech_list(mechs, mech_count);
5124 
5125         if (alg_changed) {
5126                 /*
5127                  * An algorithm has changed, i.e. it became valid or
5128                  * invalid, or its support key sizes have changed.
5129                  * Notify ipsecah and ipsecesp of this change so
5130                  * that they can send a SADB_REGISTER to their consumers.
5131                  */
5132                 ipsecah_algs_changed(ns);
5133                 ipsecesp_algs_changed(ns);
5134         }
5135 }
5136 
5137 /*
5138  * Registers with the crypto framework to be notified of crypto
5139  * providers changes. Used to update the algorithm tables and
5140  * to free or create context templates if needed. Invoked after IPsec
5141  * is loaded successfully.
5142  *




   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 http://www.opensolaris.org/os/licensing.
  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 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright (c) 2012 Nexenta Systems, Inc. All rights reserved.
  25  * Copyright (c) 2016 by Delphix. All rights reserved.
  26  * Copyright (c) 2017, Joyent, Inc.
  27  */
  28 
  29 /*
  30  * IPsec Security Policy Database.
  31  *
  32  * This module maintains the SPD and provides routines used by ip and ip6
  33  * to apply IPsec policy to inbound and outbound datagrams.
  34  */
  35 
  36 #include <sys/types.h>
  37 #include <sys/stream.h>
  38 #include <sys/stropts.h>
  39 #include <sys/sysmacros.h>
  40 #include <sys/strsubr.h>
  41 #include <sys/strsun.h>
  42 #include <sys/strlog.h>
  43 #include <sys/strsun.h>
  44 #include <sys/cmn_err.h>
  45 #include <sys/zone.h>
  46 


 398         /*
 399          * Globals start with ref == 1 to prevent IPPH_REFRELE() from
 400          * attempting to free them, hence they should have 1 now.
 401          */
 402         ipsec_polhead_destroy(&ipss->ipsec_system_policy);
 403         ASSERT(ipss->ipsec_system_policy.iph_refs == 1);
 404         ipsec_polhead_destroy(&ipss->ipsec_inactive_policy);
 405         ASSERT(ipss->ipsec_inactive_policy.iph_refs == 1);
 406 
 407         for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++) {
 408                 ipsec_action_free_table(ipss->ipsec_action_hash[i].hash_head);
 409                 ipss->ipsec_action_hash[i].hash_head = NULL;
 410                 mutex_destroy(&(ipss->ipsec_action_hash[i].hash_lock));
 411         }
 412 
 413         for (i = 0; i < ipss->ipsec_spd_hashsize; i++) {
 414                 ASSERT(ipss->ipsec_sel_hash[i].hash_head == NULL);
 415                 mutex_destroy(&(ipss->ipsec_sel_hash[i].hash_lock));
 416         }
 417 
 418         rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
 419         for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype ++) {
 420                 int nalgs = ipss->ipsec_nalgs[algtype];
 421 
 422                 for (i = 0; i < nalgs; i++) {
 423                         if (ipss->ipsec_alglists[algtype][i] != NULL)
 424                                 ipsec_alg_unreg(algtype, i, ns);
 425                 }
 426         }
 427         rw_exit(&ipss->ipsec_alg_lock);
 428         rw_destroy(&ipss->ipsec_alg_lock);
 429 
 430         ipsid_gc(ns);
 431         ipsid_fini(ns);
 432 
 433         (void) ipsec_free_tables(ipss);
 434         kmem_free(ipss, sizeof (*ipss));
 435 }
 436 
 437 void
 438 ipsec_policy_g_destroy(void)
 439 {
 440         kmem_cache_destroy(ipsec_action_cache);
 441         kmem_cache_destroy(ipsec_sel_cache);
 442         kmem_cache_destroy(ipsec_pol_cache);
 443 
 444         ipsec_unregister_prov_update();
 445 
 446         netstack_unregister(NS_IPSEC);
 447 }
 448 


 640             ipss->ipsec_spd_hashsize);
 641         ipsec_polhead_init(&ipss->ipsec_inactive_policy,
 642             ipss->ipsec_spd_hashsize);
 643         rw_init(&ipss->ipsec_tunnel_policy_lock, NULL, RW_DEFAULT, NULL);
 644         avl_create(&ipss->ipsec_tunnel_policies, tunnel_compare,
 645             sizeof (ipsec_tun_pol_t), 0);
 646 
 647         ipss->ipsec_next_policy_index = 1;
 648 
 649         rw_init(&ipss->ipsec_system_policy.iph_lock, NULL, RW_DEFAULT, NULL);
 650         rw_init(&ipss->ipsec_inactive_policy.iph_lock, NULL, RW_DEFAULT, NULL);
 651 
 652         for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++)
 653                 mutex_init(&(ipss->ipsec_action_hash[i].hash_lock),
 654                     NULL, MUTEX_DEFAULT, NULL);
 655 
 656         for (i = 0; i < ipss->ipsec_spd_hashsize; i++)
 657                 mutex_init(&(ipss->ipsec_sel_hash[i].hash_lock),
 658                     NULL, MUTEX_DEFAULT, NULL);
 659 
 660         rw_init(&ipss->ipsec_alg_lock, NULL, RW_DEFAULT, NULL);
 661         for (i = 0; i < IPSEC_NALGTYPES; i++) {
 662                 ipss->ipsec_nalgs[i] = 0;
 663         }
 664 
 665         ip_drop_init(ipss);
 666         ip_drop_register(&ipss->ipsec_spd_dropper, "IPsec SPD");
 667 
 668         /* IP's IPsec code calls the packet dropper */
 669         ip_drop_register(&ipss->ipsec_dropper, "IP IPsec processing");
 670 
 671         (void) ipsec_kstat_init(ipss);
 672 
 673         ipsec_loader_init(ipss);
 674         ipsec_loader_start(ipss);
 675 
 676         return (ipss);
 677 }
 678 
 679 /* Global across all stack instances */
 680 void


 703  *
 704  * I may need to split this based on
 705  * authentication/encryption, and I may wish to have an administrator
 706  * configure this list.  Hold on to some NDD variables...
 707  *
 708  * XXX For now, sort on minimum key size (GAG!).  While minimum key size is
 709  * not the ideal metric, it's the only quantifiable measure available.
 710  * We need a better metric for sorting algorithms by preference.
 711  */
 712 static void
 713 alg_insert_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 714 {
 715         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 716         ipsec_alginfo_t *ai = ipss->ipsec_alglists[at][algid];
 717         uint8_t holder, swap;
 718         uint_t i;
 719         uint_t count = ipss->ipsec_nalgs[at];
 720         ASSERT(ai != NULL);
 721         ASSERT(algid == ai->alg_id);
 722 
 723         ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 724 
 725         holder = algid;
 726 
 727         for (i = 0; i < count - 1; i++) {
 728                 ipsec_alginfo_t *alt;
 729 
 730                 alt = ipss->ipsec_alglists[at][ipss->ipsec_sortlist[at][i]];
 731                 /*
 732                  * If you want to give precedence to newly added algs,
 733                  * add the = in the > comparison.
 734                  */
 735                 if ((holder != algid) || (ai->alg_minbits > alt->alg_minbits)) {
 736                         /* Swap sortlist[i] and holder. */
 737                         swap = ipss->ipsec_sortlist[at][i];
 738                         ipss->ipsec_sortlist[at][i] = holder;
 739                         holder = swap;
 740                         ai = alt;
 741                 } /* Else just continue. */
 742         }
 743 
 744         /* Store holder in last slot. */
 745         ipss->ipsec_sortlist[at][i] = holder;
 746 }
 747 
 748 /*
 749  * Remove an algorithm from a sorted algorithm list.
 750  * This should be considerably easier, even with complex sorting.
 751  */
 752 static void
 753 alg_remove_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 754 {
 755         boolean_t copyback = B_FALSE;
 756         int i;
 757         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 758         int newcount = ipss->ipsec_nalgs[at];
 759 
 760         ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 761 
 762         for (i = 0; i <= newcount; i++) {
 763                 if (copyback) {
 764                         ipss->ipsec_sortlist[at][i-1] =
 765                             ipss->ipsec_sortlist[at][i];
 766                 } else if (ipss->ipsec_sortlist[at][i] == algid) {
 767                         copyback = B_TRUE;
 768                 }
 769         }
 770 }
 771 
 772 /*
 773  * Add the specified algorithm to the algorithm tables.
 774  * Must be called while holding the algorithm table writer lock.
 775  */
 776 void
 777 ipsec_alg_reg(ipsec_algtype_t algtype, ipsec_alginfo_t *alg, netstack_t *ns)
 778 {
 779         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 780 
 781         ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 782 
 783         ASSERT(ipss->ipsec_alglists[algtype][alg->alg_id] == NULL);
 784         ipsec_alg_fix_min_max(alg, algtype, ns);
 785         ipss->ipsec_alglists[algtype][alg->alg_id] = alg;
 786 
 787         ipss->ipsec_nalgs[algtype]++;
 788         alg_insert_sortlist(algtype, alg->alg_id, ns);
 789 }
 790 
 791 /*
 792  * Remove the specified algorithm from the algorithm tables.
 793  * Must be called while holding the algorithm table writer lock.
 794  */
 795 void
 796 ipsec_alg_unreg(ipsec_algtype_t algtype, uint8_t algid, netstack_t *ns)
 797 {
 798         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 799 
 800         ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 801 
 802         ASSERT(ipss->ipsec_alglists[algtype][algid] != NULL);
 803         ipsec_alg_free(ipss->ipsec_alglists[algtype][algid]);
 804         ipss->ipsec_alglists[algtype][algid] = NULL;
 805 
 806         ipss->ipsec_nalgs[algtype]--;
 807         alg_remove_sortlist(algtype, algid, ns);
 808 }
 809 
 810 /*
 811  * Hooks for spdsock to get a grip on system policy.
 812  */
 813 
 814 ipsec_policy_head_t *
 815 ipsec_system_policy(netstack_t *ns)
 816 {
 817         ipsec_stack_t   *ipss = ns->netstack_ipsec;
 818         ipsec_policy_head_t *h = &ipss->ipsec_system_policy;
 819 
 820         IPPH_REFHOLD(h);


4672 }
4673 
4674 /*
4675  * Free identity table (preparatory to module unload)
4676  */
4677 static void
4678 ipsid_fini(netstack_t *ns)
4679 {
4680         ipsif_t *bucket;
4681         int i;
4682         ipsec_stack_t   *ipss = ns->netstack_ipsec;
4683 
4684         for (i = 0; i < IPSID_HASHSIZE; i++) {
4685                 bucket = &ipss->ipsec_ipsid_buckets[i];
4686                 ASSERT(bucket->ipsif_head == NULL);
4687                 mutex_destroy(&bucket->ipsif_lock);
4688         }
4689 }
4690 
4691 /*
4692  * Update the minimum and maximum supported key sizes for the specified
4693  * algorithm, which is either a member of a netstack alg array or about to be,
4694  * and therefore must be called holding ipsec_alg_lock for write.
4695  */
4696 void
4697 ipsec_alg_fix_min_max(ipsec_alginfo_t *alg, ipsec_algtype_t alg_type,
4698     netstack_t *ns)
4699 {
4700         size_t crypto_min = (size_t)-1, crypto_max = 0;
4701         size_t cur_crypto_min, cur_crypto_max;
4702         boolean_t is_valid;
4703         crypto_mechanism_info_t *mech_infos;
4704         uint_t nmech_infos;
4705         int crypto_rc, i;
4706         crypto_mech_usage_t mask;
4707         ipsec_stack_t   *ipss = ns->netstack_ipsec;
4708 
4709         ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
4710 
4711         /*
4712          * Compute the min, max, and default key sizes (in number of
4713          * increments to the default key size in bits) as defined
4714          * by the algorithm mappings. This range of key sizes is used
4715          * for policy related operations. The effective key sizes
4716          * supported by the framework could be more limited than
4717          * those defined for an algorithm.
4718          */
4719         alg->alg_default_bits = alg->alg_key_sizes[0];
4720         alg->alg_default = 0;
4721         if (alg->alg_increment != 0) {
4722                 /* key sizes are defined by range & increment */
4723                 alg->alg_minbits = alg->alg_key_sizes[1];
4724                 alg->alg_maxbits = alg->alg_key_sizes[2];
4725         } else if (alg->alg_nkey_sizes == 0) {
4726                 /* no specified key size for algorithm */
4727                 alg->alg_minbits = alg->alg_maxbits = 0;
4728         } else {
4729                 /* key sizes are defined by enumeration */


5042         crypto_mech_name_t *mechs;
5043         boolean_t alg_changed = B_FALSE;
5044         ipsec_stack_t   *ipss = ns->netstack_ipsec;
5045 
5046         /* ignore events for which we didn't register */
5047         if (event != CRYPTO_EVENT_MECHS_CHANGED) {
5048                 ip1dbg(("ipsec_prov_update_callback: unexpected event 0x%x "
5049                     " received from crypto framework\n", event));
5050                 return;
5051         }
5052 
5053         mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
5054         if (mechs == NULL)
5055                 return;
5056 
5057         /*
5058          * Walk the list of currently defined IPsec algorithm. Update
5059          * the algorithm valid flag and trigger an update of the
5060          * SAs that depend on that algorithm.
5061          */
5062         rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
5063         for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
5064                 for (algidx = 0; algidx < ipss->ipsec_nalgs[algtype];
5065                     algidx++) {
5066 
5067                         algid = ipss->ipsec_sortlist[algtype][algidx];
5068                         alg = ipss->ipsec_alglists[algtype][algid];
5069                         ASSERT(alg != NULL);
5070 
5071                         /*
5072                          * Skip the algorithms which do not map to the
5073                          * crypto framework provider being added or removed.
5074                          */
5075                         if (strncmp(alg->alg_mech_name,
5076                             prov_change->ec_mech_name,
5077                             CRYPTO_MAX_MECH_NAME) != 0)
5078                                 continue;
5079 
5080                         /*
5081                          * Determine if the mechanism is valid. If it
5082                          * is not, mark the algorithm as being invalid. If


5105                         ipsec_alg_fix_min_max(alg, algtype, ns);
5106                         if (!alg_changed &&
5107                             alg->alg_ef_minbits != oalg.alg_ef_minbits ||
5108                             alg->alg_ef_maxbits != oalg.alg_ef_maxbits ||
5109                             alg->alg_ef_default != oalg.alg_ef_default ||
5110                             alg->alg_ef_default_bits !=
5111                             oalg.alg_ef_default_bits)
5112                                 alg_changed = B_TRUE;
5113 
5114                         /*
5115                          * Update the affected SAs if a software provider is
5116                          * being added or removed.
5117                          */
5118                         if (prov_change->ec_provider_type ==
5119                             CRYPTO_SW_PROVIDER)
5120                                 sadb_alg_update(algtype, alg->alg_id,
5121                                     prov_change->ec_change ==
5122                                     CRYPTO_MECH_ADDED, ns);
5123                 }
5124         }
5125         rw_exit(&ipss->ipsec_alg_lock);
5126         crypto_free_mech_list(mechs, mech_count);
5127 
5128         if (alg_changed) {
5129                 /*
5130                  * An algorithm has changed, i.e. it became valid or
5131                  * invalid, or its support key sizes have changed.
5132                  * Notify ipsecah and ipsecesp of this change so
5133                  * that they can send a SADB_REGISTER to their consumers.
5134                  */
5135                 ipsecah_algs_changed(ns);
5136                 ipsecesp_algs_changed(ns);
5137         }
5138 }
5139 
5140 /*
5141  * Registers with the crypto framework to be notified of crypto
5142  * providers changes. Used to update the algorithm tables and
5143  * to free or create context templates if needed. Invoked after IPsec
5144  * is loaded successfully.
5145  *