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


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


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


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


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


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


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