Print this page
8381 Convert ipsec_alg_lock from mutex to rwlock


   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>


 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);


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


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


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


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


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


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


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