Print this page
Bayard's initial drop, needs finishing, or at least testing.
@@ -19,10 +19,11 @@
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright (c) 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/stropts.h>
@@ -93,35 +94,10 @@
{ 0, 0xffffffffU, 0, "ipsecesp_default_hard_usetime"},
{ 0, 1, 0, "ipsecesp_log_unknown_spi"},
{ 0, 2, 1, "ipsecesp_padding_check"},
{ 0, 600, 20, "ipsecesp_nat_keepalive_interval"},
};
-#define ipsecesp_debug ipsecesp_params[0].ipsecesp_param_value
-#define ipsecesp_age_interval ipsecesp_params[1].ipsecesp_param_value
-#define ipsecesp_age_int_max ipsecesp_params[1].ipsecesp_param_max
-#define ipsecesp_reap_delay ipsecesp_params[2].ipsecesp_param_value
-#define ipsecesp_replay_size ipsecesp_params[3].ipsecesp_param_value
-#define ipsecesp_acquire_timeout \
- ipsecesp_params[4].ipsecesp_param_value
-#define ipsecesp_larval_timeout \
- ipsecesp_params[5].ipsecesp_param_value
-#define ipsecesp_default_soft_bytes \
- ipsecesp_params[6].ipsecesp_param_value
-#define ipsecesp_default_hard_bytes \
- ipsecesp_params[7].ipsecesp_param_value
-#define ipsecesp_default_soft_addtime \
- ipsecesp_params[8].ipsecesp_param_value
-#define ipsecesp_default_hard_addtime \
- ipsecesp_params[9].ipsecesp_param_value
-#define ipsecesp_default_soft_usetime \
- ipsecesp_params[10].ipsecesp_param_value
-#define ipsecesp_default_hard_usetime \
- ipsecesp_params[11].ipsecesp_param_value
-#define ipsecesp_log_unknown_spi \
- ipsecesp_params[12].ipsecesp_param_value
-#define ipsecesp_padding_check \
- ipsecesp_params[13].ipsecesp_param_value
/* For ipsecesp_nat_keepalive_interval, see ipsecesp.h. */
#define esp0dbg(a) printf a
/* NOTE: != 0 instead of > 0 so lint doesn't complain. */
#define esp1dbg(espstack, a) if (espstack->ipsecesp_debug != 0) printf a
@@ -131,11 +107,10 @@
static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *);
static int ipsecesp_close(queue_t *);
static void ipsecesp_wput(queue_t *, mblk_t *);
static void *ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns);
static void ipsecesp_stack_fini(netstackid_t stackid, void *arg);
-static void esp_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
static void esp_prepare_udp(netstack_t *, mblk_t *, ipha_t *);
static void esp_outbound_finish(mblk_t *, ip_xmit_attr_t *);
static void esp_inbound_restart(mblk_t *, ip_recv_attr_t *);
@@ -179,56 +154,10 @@
*
* Answer: Yes, because I need to know which queue is BOUND to
* IPPROTO_ESP
*/
-/*
- * Stats. This may eventually become a full-blown SNMP MIB once that spec
- * stabilizes.
- */
-
-typedef struct esp_kstats_s {
- kstat_named_t esp_stat_num_aalgs;
- kstat_named_t esp_stat_good_auth;
- kstat_named_t esp_stat_bad_auth;
- kstat_named_t esp_stat_bad_padding;
- kstat_named_t esp_stat_replay_failures;
- kstat_named_t esp_stat_replay_early_failures;
- kstat_named_t esp_stat_keysock_in;
- kstat_named_t esp_stat_out_requests;
- kstat_named_t esp_stat_acquire_requests;
- kstat_named_t esp_stat_bytes_expired;
- kstat_named_t esp_stat_out_discards;
- kstat_named_t esp_stat_crypto_sync;
- kstat_named_t esp_stat_crypto_async;
- kstat_named_t esp_stat_crypto_failures;
- kstat_named_t esp_stat_num_ealgs;
- kstat_named_t esp_stat_bad_decrypt;
- kstat_named_t esp_stat_sa_port_renumbers;
-} esp_kstats_t;
-
-/*
- * espstack->esp_kstats is equal to espstack->esp_ksp->ks_data if
- * kstat_create_netstack for espstack->esp_ksp succeeds, but when it
- * fails, it will be NULL. Note this is done for all stack instances,
- * so it *could* fail. hence a non-NULL checking is done for
- * ESP_BUMP_STAT and ESP_DEBUMP_STAT
- */
-#define ESP_BUMP_STAT(espstack, x) \
-do { \
- if (espstack->esp_kstats != NULL) \
- (espstack->esp_kstats->esp_stat_ ## x).value.ui64++; \
-_NOTE(CONSTCOND) \
-} while (0)
-
-#define ESP_DEBUMP_STAT(espstack, x) \
-do { \
- if (espstack->esp_kstats != NULL) \
- (espstack->esp_kstats->esp_stat_ ## x).value.ui64--; \
-_NOTE(CONSTCOND) \
-} while (0)
-
static int esp_kstat_update(kstat_t *, int);
static boolean_t
esp_kstat_init(ipsecesp_stack_t *espstack, netstackid_t stackid)
{
@@ -296,16 +225,16 @@
netstack_rele(ns);
return (-1);
}
ekp = (esp_kstats_t *)kp->ks_data;
- mutex_enter(&ipss->ipsec_alg_lock);
+ rw_enter(&ipss->ipsec_alg_lock, RW_READER);
ekp->esp_stat_num_aalgs.value.ui64 =
ipss->ipsec_nalgs[IPSEC_ALG_AUTH];
ekp->esp_stat_num_ealgs.value.ui64 =
ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
netstack_rele(ns);
return (0);
}
@@ -501,10 +430,11 @@
}
}
}
return (B_TRUE);
}
+
/*
* Initialize things for ESP for each stack instance
*/
static void *
ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns)
@@ -525,11 +455,10 @@
(void) esp_kstat_init(espstack, stackid);
espstack->esp_sadb.s_acquire_timeout =
&espstack->ipsecesp_acquire_timeout;
- espstack->esp_sadb.s_acqfn = esp_send_acquire;
sadbp_init("ESP", &espstack->esp_sadb, SADB_SATYPE_ESP, esp_hash_size,
espstack->ipsecesp_netstack);
mutex_init(&espstack->ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0);
@@ -556,11 +485,10 @@
ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg;
if (espstack->esp_pfkey_q != NULL) {
(void) quntimeout(espstack->esp_pfkey_q, espstack->esp_event);
}
- espstack->esp_sadb.s_acqfn = NULL;
espstack->esp_sadb.s_acquire_timeout = NULL;
sadbp_destroy(&espstack->esp_sadb, espstack->ipsecesp_netstack);
ip_drop_unregister(&espstack->esp_dropper);
mutex_destroy(&espstack->ipsecesp_param_lock);
nd_free(&espstack->ipsecesp_g_nd);
@@ -1179,183 +1107,10 @@
/* submit the request to the crypto framework */
return (esp_submit_req_inbound(data_mp, ira, ipsa,
(uint8_t *)esph - data_mp->b_rptr));
}
-/*
- * Perform the really difficult work of inserting the proposed situation.
- * Called while holding the algorithm lock.
- */
-static void
-esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs,
- netstack_t *ns)
-{
- sadb_comb_t *comb = (sadb_comb_t *)(prop + 1);
- ipsec_action_t *ap;
- ipsec_prot_t *prot;
- ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
- ipsec_stack_t *ipss = ns->netstack_ipsec;
-
- ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
-
- prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
- prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t));
- *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */
-
- prop->sadb_prop_replay = espstack->ipsecesp_replay_size;
-
- /*
- * Based upon algorithm properties, and what-not, prioritize a
- * proposal, based on the ordering of the ESP algorithms in the
- * alternatives in the policy rule or socket that was placed
- * in the acquire record.
- *
- * For each action in policy list
- * Add combination. If I've hit limit, return.
- */
-
- for (ap = acqrec->ipsacq_act; ap != NULL;
- ap = ap->ipa_next) {
- ipsec_alginfo_t *ealg = NULL;
- ipsec_alginfo_t *aalg = NULL;
-
- if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY)
- continue;
-
- prot = &ap->ipa_act.ipa_apply;
-
- if (!(prot->ipp_use_esp))
- continue;
-
- if (prot->ipp_esp_auth_alg != 0) {
- aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
- [prot->ipp_esp_auth_alg];
- if (aalg == NULL || !ALG_VALID(aalg))
- continue;
- }
-
- ASSERT(prot->ipp_encr_alg > 0);
- ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
- [prot->ipp_encr_alg];
- if (ealg == NULL || !ALG_VALID(ealg))
- continue;
-
- comb->sadb_comb_flags = 0;
- comb->sadb_comb_reserved = 0;
- comb->sadb_comb_encrypt = ealg->alg_id;
- comb->sadb_comb_encrypt_minbits =
- MAX(prot->ipp_espe_minbits, ealg->alg_ef_minbits);
- comb->sadb_comb_encrypt_maxbits =
- MIN(prot->ipp_espe_maxbits, ealg->alg_ef_maxbits);
-
- if (aalg == NULL) {
- comb->sadb_comb_auth = 0;
- comb->sadb_comb_auth_minbits = 0;
- comb->sadb_comb_auth_maxbits = 0;
- } else {
- comb->sadb_comb_auth = aalg->alg_id;
- comb->sadb_comb_auth_minbits =
- MAX(prot->ipp_espa_minbits, aalg->alg_ef_minbits);
- comb->sadb_comb_auth_maxbits =
- MIN(prot->ipp_espa_maxbits, aalg->alg_ef_maxbits);
- }
-
- /*
- * The following may be based on algorithm
- * properties, but in the meantime, we just pick
- * some good, sensible numbers. Key mgmt. can
- * (and perhaps should) be the place to finalize
- * such decisions.
- */
-
- /*
- * No limits on allocations, since we really don't
- * support that concept currently.
- */
- comb->sadb_comb_soft_allocations = 0;
- comb->sadb_comb_hard_allocations = 0;
-
- /*
- * These may want to come from policy rule..
- */
- comb->sadb_comb_soft_bytes =
- espstack->ipsecesp_default_soft_bytes;
- comb->sadb_comb_hard_bytes =
- espstack->ipsecesp_default_hard_bytes;
- comb->sadb_comb_soft_addtime =
- espstack->ipsecesp_default_soft_addtime;
- comb->sadb_comb_hard_addtime =
- espstack->ipsecesp_default_hard_addtime;
- comb->sadb_comb_soft_usetime =
- espstack->ipsecesp_default_soft_usetime;
- comb->sadb_comb_hard_usetime =
- espstack->ipsecesp_default_hard_usetime;
-
- prop->sadb_prop_len += SADB_8TO64(sizeof (*comb));
- if (--combs == 0)
- break; /* out of space.. */
- comb++;
- }
-}
-
-/*
- * Prepare and actually send the SADB_ACQUIRE message to PF_KEY.
- */
-static void
-esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns)
-{
- uint_t combs;
- sadb_msg_t *samsg;
- sadb_prop_t *prop;
- mblk_t *pfkeymp, *msgmp;
- ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
- ipsec_stack_t *ipss = ns->netstack_ipsec;
-
- ESP_BUMP_STAT(espstack, acquire_requests);
-
- if (espstack->esp_pfkey_q == NULL) {
- mutex_exit(&acqrec->ipsacq_lock);
- return;
- }
-
- /* Set up ACQUIRE. */
- pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_ESP,
- ns->netstack_ipsec);
- if (pfkeymp == NULL) {
- esp0dbg(("sadb_setup_acquire failed.\n"));
- mutex_exit(&acqrec->ipsacq_lock);
- return;
- }
- ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
- combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH] *
- ipss->ipsec_nalgs[IPSEC_ALG_ENCR];
- msgmp = pfkeymp->b_cont;
- samsg = (sadb_msg_t *)(msgmp->b_rptr);
-
- /* Insert proposal here. */
-
- prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
- esp_insert_prop(prop, acqrec, combs, ns);
- samsg->sadb_msg_len += prop->sadb_prop_len;
- msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
-
- mutex_exit(&ipss->ipsec_alg_lock);
-
- /*
- * Must mutex_exit() before sending PF_KEY message up, in
- * order to avoid recursive mutex_enter() if there are no registered
- * listeners.
- *
- * Once I've sent the message, I'm cool anyway.
- */
- mutex_exit(&acqrec->ipsacq_lock);
- if (extended != NULL) {
- putnext(espstack->esp_pfkey_q, extended);
- }
- putnext(espstack->esp_pfkey_q, pfkeymp);
-}
-
/* XXX refactor me */
/*
* Handle the SADB_GETSPI message. Create a larval SA.
*/
static void
@@ -3041,11 +2796,11 @@
/*
* Allocate the PF_KEY message that follows KEYSOCK_OUT.
*/
- mutex_enter(&ipss->ipsec_alg_lock);
+ rw_enter(&ipss->ipsec_alg_lock, RW_READER);
/*
* Fill SADB_REGISTER message's algorithm descriptors. Hold
* down the lock while filling it.
*
* Return only valid algorithms, so the number of algorithms
@@ -3070,11 +2825,11 @@
allocsize += (num_ealgs * sizeof (*saalg));
allocsize += sizeof (*sasupp_encr);
}
keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI);
if (keysock_out_mp->b_cont == NULL) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
freemsg(keysock_out_mp);
return (B_FALSE);
}
pfkey_msg_mp = keysock_out_mp->b_cont;
pfkey_msg_mp->b_wptr += allocsize;
@@ -3164,11 +2919,11 @@
}
current_aalgs = num_aalgs;
current_ealgs = num_ealgs;
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
if (sens_tsl != NULL) {
sens = (sadb_sens_t *)nextext;
sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
sens_tsl, sens_len);
@@ -3689,11 +3444,11 @@
* XXX Policy : I'm not checking identities at this time,
* but if I did, I'd do them here, before I sent
* the weak key check up to the algorithm.
*/
- mutex_enter(&ipss->ipsec_alg_lock);
+ rw_enter(&ipss->ipsec_alg_lock, RW_READER);
/*
* First locate the authentication algorithm.
*/
#ifdef IPSEC_LATENCY_TEST
@@ -3704,11 +3459,11 @@
ipsec_alginfo_t *aalg;
aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
[assoc->sadb_sa_auth];
if (aalg == NULL || !ALG_VALID(aalg)) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
esp1dbg(espstack, ("Couldn't find auth alg #%d.\n",
assoc->sadb_sa_auth));
*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
return (EINVAL);
}
@@ -3719,20 +3474,20 @@
* this auth_alg is not defined with ALG_FLAG_VALID. If this
* ever changes, the same check for SADB_AALG_NONE and
* a auth_key != NULL should be made here ( see below).
*/
if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
*diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS;
return (EINVAL);
}
ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
/* check key and fix parity if needed */
if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE,
diagnostic) != 0) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
return (EINVAL);
}
}
/*
@@ -3743,11 +3498,11 @@
ipsec_alginfo_t *ealg;
ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR]
[assoc->sadb_sa_encrypt];
if (ealg == NULL || !ALG_VALID(ealg)) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
esp1dbg(espstack, ("Couldn't find encr alg #%d.\n",
assoc->sadb_sa_encrypt));
*diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG;
return (EINVAL);
}
@@ -3764,24 +3519,24 @@
keybits = ekey->sadb_key_bits;
keybits -= ekey->sadb_key_reserved;
keybits -= SADB_8TO1(ealg->alg_saltlen);
if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) ||
(!ipsec_valid_key_size(keybits, ealg))) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
*diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS;
return (EINVAL);
}
ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID);
/* check key */
if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE,
diagnostic) != 0) {
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
return (EINVAL);
}
}
- mutex_exit(&ipss->ipsec_alg_lock);
+ rw_exit(&ipss->ipsec_alg_lock);
return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi,
diagnostic, espstack));
}