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

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/inet/ip/spd.c
          +++ new/usr/src/uts/common/inet/ip/spd.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright (c) 2012 Nexenta Systems, Inc. All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * IPsec Security Policy Database.
  28   29   *
  29   30   * This module maintains the SPD and provides routines used by ip and ip6
  30   31   * to apply IPsec policy to inbound and outbound datagrams.
  31   32   */
  32   33  
  33   34  #include <sys/types.h>
↓ open down ↓ 371 lines elided ↑ open up ↑
 405  406                  ipsec_action_free_table(ipss->ipsec_action_hash[i].hash_head);
 406  407                  ipss->ipsec_action_hash[i].hash_head = NULL;
 407  408                  mutex_destroy(&(ipss->ipsec_action_hash[i].hash_lock));
 408  409          }
 409  410  
 410  411          for (i = 0; i < ipss->ipsec_spd_hashsize; i++) {
 411  412                  ASSERT(ipss->ipsec_sel_hash[i].hash_head == NULL);
 412  413                  mutex_destroy(&(ipss->ipsec_sel_hash[i].hash_lock));
 413  414          }
 414  415  
 415      -        mutex_enter(&ipss->ipsec_alg_lock);
      416 +        rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
 416  417          for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype ++) {
 417  418                  int nalgs = ipss->ipsec_nalgs[algtype];
 418  419  
 419  420                  for (i = 0; i < nalgs; i++) {
 420  421                          if (ipss->ipsec_alglists[algtype][i] != NULL)
 421  422                                  ipsec_alg_unreg(algtype, i, ns);
 422  423                  }
 423  424          }
 424      -        mutex_exit(&ipss->ipsec_alg_lock);
 425      -        mutex_destroy(&ipss->ipsec_alg_lock);
      425 +        rw_exit(&ipss->ipsec_alg_lock);
      426 +        rw_destroy(&ipss->ipsec_alg_lock);
 426  427  
 427  428          ipsid_gc(ns);
 428  429          ipsid_fini(ns);
 429  430  
 430  431          (void) ipsec_free_tables(ipss);
 431  432          kmem_free(ipss, sizeof (*ipss));
 432  433  }
 433  434  
 434  435  void
 435  436  ipsec_policy_g_destroy(void)
↓ open down ↓ 211 lines elided ↑ open up ↑
 647  648          rw_init(&ipss->ipsec_inactive_policy.iph_lock, NULL, RW_DEFAULT, NULL);
 648  649  
 649  650          for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++)
 650  651                  mutex_init(&(ipss->ipsec_action_hash[i].hash_lock),
 651  652                      NULL, MUTEX_DEFAULT, NULL);
 652  653  
 653  654          for (i = 0; i < ipss->ipsec_spd_hashsize; i++)
 654  655                  mutex_init(&(ipss->ipsec_sel_hash[i].hash_lock),
 655  656                      NULL, MUTEX_DEFAULT, NULL);
 656  657  
 657      -        mutex_init(&ipss->ipsec_alg_lock, NULL, MUTEX_DEFAULT, NULL);
      658 +        rw_init(&ipss->ipsec_alg_lock, NULL, RW_DEFAULT, NULL);
 658  659          for (i = 0; i < IPSEC_NALGTYPES; i++) {
 659  660                  ipss->ipsec_nalgs[i] = 0;
 660  661          }
 661  662  
 662  663          ip_drop_init(ipss);
 663  664          ip_drop_register(&ipss->ipsec_spd_dropper, "IPsec SPD");
 664  665  
 665  666          /* IP's IPsec code calls the packet dropper */
 666  667          ip_drop_register(&ipss->ipsec_dropper, "IP IPsec processing");
 667  668  
↓ open down ↓ 42 lines elided ↑ open up ↑
 710  711  alg_insert_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 711  712  {
 712  713          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 713  714          ipsec_alginfo_t *ai = ipss->ipsec_alglists[at][algid];
 714  715          uint8_t holder, swap;
 715  716          uint_t i;
 716  717          uint_t count = ipss->ipsec_nalgs[at];
 717  718          ASSERT(ai != NULL);
 718  719          ASSERT(algid == ai->alg_id);
 719  720  
 720      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      721 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 721  722  
 722  723          holder = algid;
 723  724  
 724  725          for (i = 0; i < count - 1; i++) {
 725  726                  ipsec_alginfo_t *alt;
 726  727  
 727  728                  alt = ipss->ipsec_alglists[at][ipss->ipsec_sortlist[at][i]];
 728  729                  /*
 729  730                   * If you want to give precedence to newly added algs,
 730  731                   * add the = in the > comparison.
↓ open down ↓ 16 lines elided ↑ open up ↑
 747  748   * This should be considerably easier, even with complex sorting.
 748  749   */
 749  750  static void
 750  751  alg_remove_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
 751  752  {
 752  753          boolean_t copyback = B_FALSE;
 753  754          int i;
 754  755          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 755  756          int newcount = ipss->ipsec_nalgs[at];
 756  757  
 757      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      758 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 758  759  
 759  760          for (i = 0; i <= newcount; i++) {
 760  761                  if (copyback) {
 761  762                          ipss->ipsec_sortlist[at][i-1] =
 762  763                              ipss->ipsec_sortlist[at][i];
 763  764                  } else if (ipss->ipsec_sortlist[at][i] == algid) {
 764  765                          copyback = B_TRUE;
 765  766                  }
 766  767          }
 767  768  }
 768  769  
 769  770  /*
 770  771   * Add the specified algorithm to the algorithm tables.
 771  772   * Must be called while holding the algorithm table writer lock.
 772  773   */
 773  774  void
 774  775  ipsec_alg_reg(ipsec_algtype_t algtype, ipsec_alginfo_t *alg, netstack_t *ns)
 775  776  {
 776  777          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 777  778  
 778      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      779 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 779  780  
 780  781          ASSERT(ipss->ipsec_alglists[algtype][alg->alg_id] == NULL);
 781  782          ipsec_alg_fix_min_max(alg, algtype, ns);
 782  783          ipss->ipsec_alglists[algtype][alg->alg_id] = alg;
 783  784  
 784  785          ipss->ipsec_nalgs[algtype]++;
 785  786          alg_insert_sortlist(algtype, alg->alg_id, ns);
 786  787  }
 787  788  
 788  789  /*
 789  790   * Remove the specified algorithm from the algorithm tables.
 790  791   * Must be called while holding the algorithm table writer lock.
 791  792   */
 792  793  void
 793  794  ipsec_alg_unreg(ipsec_algtype_t algtype, uint8_t algid, netstack_t *ns)
 794  795  {
 795  796          ipsec_stack_t   *ipss = ns->netstack_ipsec;
 796  797  
 797      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
      798 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
 798  799  
 799  800          ASSERT(ipss->ipsec_alglists[algtype][algid] != NULL);
 800  801          ipsec_alg_free(ipss->ipsec_alglists[algtype][algid]);
 801  802          ipss->ipsec_alglists[algtype][algid] = NULL;
 802  803  
 803  804          ipss->ipsec_nalgs[algtype]--;
 804  805          alg_remove_sortlist(algtype, algid, ns);
 805  806  }
 806  807  
 807  808  /*
↓ open down ↓ 3872 lines elided ↑ open up ↑
4680 4681          ipsec_stack_t   *ipss = ns->netstack_ipsec;
4681 4682  
4682 4683          for (i = 0; i < IPSID_HASHSIZE; i++) {
4683 4684                  bucket = &ipss->ipsec_ipsid_buckets[i];
4684 4685                  ASSERT(bucket->ipsif_head == NULL);
4685 4686                  mutex_destroy(&bucket->ipsif_lock);
4686 4687          }
4687 4688  }
4688 4689  
4689 4690  /*
4690      - * Update the minimum and maximum supported key sizes for the
4691      - * specified algorithm. Must be called while holding the algorithms lock.
     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.
4692 4694   */
4693 4695  void
4694 4696  ipsec_alg_fix_min_max(ipsec_alginfo_t *alg, ipsec_algtype_t alg_type,
4695 4697      netstack_t *ns)
4696 4698  {
4697 4699          size_t crypto_min = (size_t)-1, crypto_max = 0;
4698 4700          size_t cur_crypto_min, cur_crypto_max;
4699 4701          boolean_t is_valid;
4700 4702          crypto_mechanism_info_t *mech_infos;
4701 4703          uint_t nmech_infos;
4702 4704          int crypto_rc, i;
4703 4705          crypto_mech_usage_t mask;
4704 4706          ipsec_stack_t   *ipss = ns->netstack_ipsec;
4705 4707  
4706      -        ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
     4708 +        ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
4707 4709  
4708 4710          /*
4709 4711           * Compute the min, max, and default key sizes (in number of
4710 4712           * increments to the default key size in bits) as defined
4711 4713           * by the algorithm mappings. This range of key sizes is used
4712 4714           * for policy related operations. The effective key sizes
4713 4715           * supported by the framework could be more limited than
4714 4716           * those defined for an algorithm.
4715 4717           */
4716 4718          alg->alg_default_bits = alg->alg_key_sizes[0];
↓ open down ↓ 332 lines elided ↑ open up ↑
5049 5051  
5050 5052          mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
5051 5053          if (mechs == NULL)
5052 5054                  return;
5053 5055  
5054 5056          /*
5055 5057           * Walk the list of currently defined IPsec algorithm. Update
5056 5058           * the algorithm valid flag and trigger an update of the
5057 5059           * SAs that depend on that algorithm.
5058 5060           */
5059      -        mutex_enter(&ipss->ipsec_alg_lock);
     5061 +        rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
5060 5062          for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
5061 5063                  for (algidx = 0; algidx < ipss->ipsec_nalgs[algtype];
5062 5064                      algidx++) {
5063 5065  
5064 5066                          algid = ipss->ipsec_sortlist[algtype][algidx];
5065 5067                          alg = ipss->ipsec_alglists[algtype][algid];
5066 5068                          ASSERT(alg != NULL);
5067 5069  
5068 5070                          /*
5069 5071                           * Skip the algorithms which do not map to the
↓ open down ↓ 42 lines elided ↑ open up ↑
5112 5114                           * Update the affected SAs if a software provider is
5113 5115                           * being added or removed.
5114 5116                           */
5115 5117                          if (prov_change->ec_provider_type ==
5116 5118                              CRYPTO_SW_PROVIDER)
5117 5119                                  sadb_alg_update(algtype, alg->alg_id,
5118 5120                                      prov_change->ec_change ==
5119 5121                                      CRYPTO_MECH_ADDED, ns);
5120 5122                  }
5121 5123          }
5122      -        mutex_exit(&ipss->ipsec_alg_lock);
     5124 +        rw_exit(&ipss->ipsec_alg_lock);
5123 5125          crypto_free_mech_list(mechs, mech_count);
5124 5126  
5125 5127          if (alg_changed) {
5126 5128                  /*
5127 5129                   * An algorithm has changed, i.e. it became valid or
5128 5130                   * invalid, or its support key sizes have changed.
5129 5131                   * Notify ipsecah and ipsecesp of this change so
5130 5132                   * that they can send a SADB_REGISTER to their consumers.
5131 5133                   */
5132 5134                  ipsecah_algs_changed(ns);
↓ open down ↓ 1779 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX