summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/inet/ip/ipsecesp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/inet/ip/ipsecesp.c')
-rw-r--r--usr/src/uts/common/inet/ip/ipsecesp.c1604
1 files changed, 676 insertions, 928 deletions
diff --git a/usr/src/uts/common/inet/ip/ipsecesp.c b/usr/src/uts/common/inet/ip/ipsecesp.c
index 089e23e937..8af449384f 100644
--- a/usr/src/uts/common/inet/ip/ipsecesp.c
+++ b/usr/src/uts/common/inet/ip/ipsecesp.c
@@ -53,6 +53,8 @@
#include <inet/ip.h>
#include <inet/ip_impl.h>
#include <inet/ip6.h>
+#include <inet/ip_if.h>
+#include <inet/ip_ndp.h>
#include <inet/sadb.h>
#include <inet/ipsec_info.h>
#include <inet/ipsec_impl.h>
@@ -67,8 +69,6 @@
#include <sys/taskq.h>
#include <sys/note.h>
-#include <sys/iphada.h>
-
#include <sys/tsol/tnet.h>
/*
@@ -130,26 +130,23 @@ static ipsecespparam_t lcl_param_arr[] = {
static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *);
static int ipsecesp_close(queue_t *);
-static void ipsecesp_rput(queue_t *, mblk_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 ipsec_status_t esp_outbound_accelerated(mblk_t *, uint_t);
-static ipsec_status_t esp_inbound_accelerated(mblk_t *, mblk_t *,
- boolean_t, ipsa_t *);
+static void esp_outbound_finish(mblk_t *, ip_xmit_attr_t *);
+static void esp_inbound_restart(mblk_t *, ip_recv_attr_t *);
static boolean_t esp_register_out(uint32_t, uint32_t, uint_t,
- ipsecesp_stack_t *, mblk_t *);
+ ipsecesp_stack_t *, cred_t *);
static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t,
kstat_named_t **, ipsecesp_stack_t *);
-static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t);
-static ipsec_status_t esp_submit_req_outbound(mblk_t *, ipsa_t *, uchar_t *,
- uint_t);
-extern void (*cl_inet_getspi)(netstackid_t, uint8_t, uint8_t *, size_t,
- void *);
+static mblk_t *esp_submit_req_inbound(mblk_t *, ip_recv_attr_t *,
+ ipsa_t *, uint_t);
+static mblk_t *esp_submit_req_outbound(mblk_t *, ip_xmit_attr_t *,
+ ipsa_t *, uchar_t *, uint_t);
/* Setable in /etc/system */
uint32_t esp_hash_size = IPSEC_DEFAULT_HASH_SIZE;
@@ -159,7 +156,7 @@ static struct module_info info = {
};
static struct qinit rinit = {
- (pfi_t)ipsecesp_rput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
+ (pfi_t)putnext, NULL, ipsecesp_open, ipsecesp_close, NULL, &info,
NULL
};
@@ -201,9 +198,6 @@ typedef struct esp_kstats_s {
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_in_accelerated;
- kstat_named_t esp_stat_out_accelerated;
- kstat_named_t esp_stat_noaccel;
kstat_named_t esp_stat_crypto_sync;
kstat_named_t esp_stat_crypto_async;
kstat_named_t esp_stat_crypto_failures;
@@ -266,9 +260,6 @@ esp_kstat_init(ipsecesp_stack_t *espstack, netstackid_t stackid)
KI(acquire_requests);
KI(bytes_expired);
KI(out_discards);
- KI(in_accelerated);
- KI(out_accelerated);
- KI(noaccel);
KI(crypto_sync);
KI(crypto_async);
KI(crypto_failures);
@@ -384,9 +375,9 @@ esp_ager(void *arg)
hrtime_t begin = gethrtime();
sadb_ager(&espstack->esp_sadb.s_v4, espstack->esp_pfkey_q,
- espstack->esp_sadb.s_ip_q, espstack->ipsecesp_reap_delay, ns);
+ espstack->ipsecesp_reap_delay, ns);
sadb_ager(&espstack->esp_sadb.s_v6, espstack->esp_pfkey_q,
- espstack->esp_sadb.s_ip_q, espstack->ipsecesp_reap_delay, ns);
+ espstack->ipsecesp_reap_delay, ns);
espstack->esp_event = sadb_retimeout(begin, espstack->esp_pfkey_q,
esp_ager, espstack,
@@ -583,7 +574,13 @@ ipsecesp_stack_fini(netstackid_t stackid, void *arg)
}
/*
- * ESP module open routine.
+ * ESP module open routine, which is here for keysock plumbing.
+ * Keysock is pushed over {AH,ESP} which is an artifact from the Bad Old
+ * Days of export control, and fears that ESP would not be allowed
+ * to be shipped at all by default. Eventually, keysock should
+ * either access AH and ESP via modstubs or krtld dependencies, or
+ * perhaps be folded in with AH and ESP into a single IPsec/netsec
+ * module ("netsec" if PF_KEY provides more than AH/ESP keying tables).
*/
/* ARGSUSED */
static int
@@ -606,56 +603,10 @@ ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
espstack = ns->netstack_ipsecesp;
ASSERT(espstack != NULL);
- /*
- * ASSUMPTIONS (because I'm MT_OCEXCL):
- *
- * * I'm being pushed on top of IP for all my opens (incl. #1).
- * * Only ipsecesp_open() can write into esp_sadb.s_ip_q.
- * * Because of this, I can check lazily for esp_sadb.s_ip_q.
- *
- * If these assumptions are wrong, I'm in BIG trouble...
- */
-
q->q_ptr = espstack;
WR(q)->q_ptr = q->q_ptr;
- if (espstack->esp_sadb.s_ip_q == NULL) {
- struct T_unbind_req *tur;
-
- espstack->esp_sadb.s_ip_q = WR(q);
- /* Allocate an unbind... */
- espstack->esp_ip_unbind = allocb(sizeof (struct T_unbind_req),
- BPRI_HI);
-
- /*
- * Send down T_BIND_REQ to bind IPPROTO_ESP.
- * Handle the ACK here in ESP.
- */
- qprocson(q);
- if (espstack->esp_ip_unbind == NULL ||
- !sadb_t_bind_req(espstack->esp_sadb.s_ip_q, IPPROTO_ESP)) {
- if (espstack->esp_ip_unbind != NULL) {
- freeb(espstack->esp_ip_unbind);
- espstack->esp_ip_unbind = NULL;
- }
- q->q_ptr = NULL;
- netstack_rele(espstack->ipsecesp_netstack);
- return (ENOMEM);
- }
-
- espstack->esp_ip_unbind->b_datap->db_type = M_PROTO;
- tur = (struct T_unbind_req *)espstack->esp_ip_unbind->b_rptr;
- tur->PRIM_type = T_UNBIND_REQ;
- } else {
- qprocson(q);
- }
-
- /*
- * For now, there's not much I can do. I'll be getting a message
- * passed down to me from keysock (in my wput), and a T_BIND_ACK
- * up from IP (in my rput).
- */
-
+ qprocson(q);
return (0);
}
@@ -668,17 +619,6 @@ ipsecesp_close(queue_t *q)
ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr;
/*
- * If esp_sadb.s_ip_q is attached to this instance, send a
- * T_UNBIND_REQ to IP for the instance before doing
- * a qprocsoff().
- */
- if (WR(q) == espstack->esp_sadb.s_ip_q &&
- espstack->esp_ip_unbind != NULL) {
- putnext(WR(q), espstack->esp_ip_unbind);
- espstack->esp_ip_unbind = NULL;
- }
-
- /*
* Clean up q_ptr, if needed.
*/
qprocsoff(q);
@@ -693,45 +633,6 @@ ipsecesp_close(queue_t *q)
(void) quntimeout(q, espstack->esp_event);
}
- if (WR(q) == espstack->esp_sadb.s_ip_q) {
- /*
- * If the esp_sadb.s_ip_q is attached to this instance, find
- * another. The OCEXCL outer perimeter helps us here.
- */
- espstack->esp_sadb.s_ip_q = NULL;
-
- /*
- * Find a replacement queue for esp_sadb.s_ip_q.
- */
- if (espstack->esp_pfkey_q != NULL &&
- espstack->esp_pfkey_q != RD(q)) {
- /*
- * See if we can use the pfkey_q.
- */
- espstack->esp_sadb.s_ip_q = WR(espstack->esp_pfkey_q);
- }
-
- if (espstack->esp_sadb.s_ip_q == NULL ||
- !sadb_t_bind_req(espstack->esp_sadb.s_ip_q, IPPROTO_ESP)) {
- esp1dbg(espstack, ("ipsecesp: Can't reassign ip_q.\n"));
- espstack->esp_sadb.s_ip_q = NULL;
- } else {
- espstack->esp_ip_unbind =
- allocb(sizeof (struct T_unbind_req), BPRI_HI);
-
- if (espstack->esp_ip_unbind != NULL) {
- struct T_unbind_req *tur;
-
- espstack->esp_ip_unbind->b_datap->db_type =
- M_PROTO;
- tur = (struct T_unbind_req *)
- espstack->esp_ip_unbind->b_rptr;
- tur->PRIM_type = T_UNBIND_REQ;
- }
- /* If it's NULL, I can't do much here. */
- }
- }
-
netstack_rele(espstack->ipsecesp_netstack);
return (0);
}
@@ -834,26 +735,27 @@ esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound)
/*
* Do incoming NAT-T manipulations for packet.
+ * Returns NULL if the mblk chain is consumed.
*/
-static ipsec_status_t
+static mblk_t *
esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc)
{
ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
- tcpha_t *tcph;
+ tcpha_t *tcpha;
udpha_t *udpha;
/* Initialize to our inbound cksum adjustment... */
uint32_t sum = assoc->ipsa_inbound_cksum;
switch (ipha->ipha_protocol) {
case IPPROTO_TCP:
- tcph = (tcpha_t *)(data_mp->b_rptr +
+ tcpha = (tcpha_t *)(data_mp->b_rptr +
IPH_HDR_LENGTH(ipha));
#define DOWN_SUM(x) (x) = ((x) & 0xFFFF) + ((x) >> 16)
- sum += ~ntohs(tcph->tha_sum) & 0xFFFF;
+ sum += ~ntohs(tcpha->tha_sum) & 0xFFFF;
DOWN_SUM(sum);
DOWN_SUM(sum);
- tcph->tha_sum = ~htons(sum);
+ tcpha->tha_sum = ~htons(sum);
break;
case IPPROTO_UDP:
udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha));
@@ -876,7 +778,7 @@ esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc)
*/
break;
}
- return (IPSEC_STATUS_SUCCESS);
+ return (data_mp);
}
@@ -968,10 +870,11 @@ esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen,
if (ip6h->ip6_nxt == IPPROTO_ESP) {
ip6h->ip6_nxt = nexthdr;
} else {
- ip6_pkt_t ipp;
+ ip_pkt_t ipp;
bzero(&ipp, sizeof (ipp));
- (void) ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL);
+ (void) ip_find_hdr_v6(data_mp, ip6h, B_FALSE, &ipp,
+ NULL);
if (ipp.ipp_dstopts != NULL) {
ipp.ipp_dstopts->ip6d_nxt = nexthdr;
} else if (ipp.ipp_rthdr != NULL) {
@@ -1227,16 +1130,14 @@ esp_set_usetime(ipsa_t *assoc, boolean_t inbound)
/*
* Handle ESP inbound data for IPv4 and IPv6.
* On success returns B_TRUE, on failure returns B_FALSE and frees the
- * mblk chain ipsec_in_mp.
+ * mblk chain data_mp.
*/
-ipsec_status_t
-esp_inbound(mblk_t *ipsec_in_mp, void *arg)
+mblk_t *
+esp_inbound(mblk_t *data_mp, void *arg, ip_recv_attr_t *ira)
{
- mblk_t *data_mp = ipsec_in_mp->b_cont;
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr;
esph_t *esph = (esph_t *)arg;
- ipsa_t *ipsa = ii->ipsec_in_esp_sa;
- netstack_t *ns = ii->ipsec_in_ns;
+ ipsa_t *ipsa = ira->ira_ipsec_esp_sa;
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
ipsec_stack_t *ipss = ns->netstack_ipsec;
@@ -1254,36 +1155,18 @@ esp_inbound(mblk_t *ipsec_in_mp, void *arg)
if (!sadb_replay_peek(ipsa, esph->esph_replay)) {
ESP_BUMP_STAT(espstack, replay_early_failures);
IP_ESP_BUMP_STAT(ipss, in_discards);
- /*
- * TODO: Extract inbound interface from the IPSEC_IN
- * message's ii->ipsec_in_rill_index.
- */
- ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL,
+ ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
DROPPER(ipss, ipds_esp_early_replay),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
+ return (NULL);
}
/*
- * Has this packet already been processed by a hardware
- * IPsec accelerator?
- */
- if (ii->ipsec_in_accelerated) {
- ipsec_status_t rv;
- esp3dbg(espstack,
- ("esp_inbound: pkt processed by ill=%d isv6=%d\n",
- ii->ipsec_in_ill_index, !ii->ipsec_in_v4));
- rv = esp_inbound_accelerated(ipsec_in_mp,
- data_mp, ii->ipsec_in_v4, ipsa);
- return (rv);
- }
- ESP_BUMP_STAT(espstack, noaccel);
-
- /*
* Adjust the IP header's payload length to reflect the removal
* of the ICV.
*/
- if (!ii->ipsec_in_v4) {
+ if (!(ira->ira_flags & IRAF_IS_IPV4)) {
ip6_t *ip6h = (ip6_t *)data_mp->b_rptr;
ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) -
ipsa->ipsa_mac_len);
@@ -1294,7 +1177,7 @@ esp_inbound(mblk_t *ipsec_in_mp, void *arg)
}
/* submit the request to the crypto framework */
- return (esp_submit_req_inbound(ipsec_in_mp, ipsa,
+ return (esp_submit_req_inbound(data_mp, ira, ipsa,
(uint8_t *)esph - data_mp->b_rptr));
}
@@ -1303,21 +1186,15 @@ esp_inbound(mblk_t *ipsec_in_mp, void *arg)
* Called while holding the algorithm lock.
*/
static void
-esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs)
+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_out_t *io;
ipsec_action_t *ap;
ipsec_prot_t *prot;
- netstack_t *ns;
- ipsecesp_stack_t *espstack;
- ipsec_stack_t *ipss;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
- io = (ipsec_out_t *)acqrec->ipsacq_mp->b_rptr;
- ASSERT(io->ipsec_out_type == IPSEC_OUT);
- ns = io->ipsec_out_ns;
- espstack = ns->netstack_ipsecesp;
- ipss = ns->netstack_ipsec;
ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
@@ -1327,9 +1204,10 @@ esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs)
prop->sadb_prop_replay = espstack->ipsecesp_replay_size;
/*
- * Based upon algorithm properties, and what-not, prioritize
- * a proposal. If the IPSEC_OUT message has an algorithm specified,
- * use it first and foremost.
+ * 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.
@@ -1456,7 +1334,7 @@ esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns)
/* Insert proposal here. */
prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len);
- esp_insert_prop(prop, acqrec, combs);
+ esp_insert_prop(prop, acqrec, combs, ns);
samsg->sadb_msg_len += prop->sadb_prop_len;
msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len);
@@ -1756,13 +1634,11 @@ esp_port_freshness(uint32_t ports, ipsa_t *assoc)
* If authentication was performed on the packet, this function is called
* only if the authentication succeeded.
* On success returns B_TRUE, on failure returns B_FALSE and frees the
- * mblk chain ipsec_in_mp.
+ * mblk chain data_mp.
*/
-static ipsec_status_t
-esp_in_done(mblk_t *ipsec_in_mp)
+static mblk_t *
+esp_in_done(mblk_t *data_mp, ip_recv_attr_t *ira, ipsec_crypto_t *ic)
{
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr;
- mblk_t *data_mp;
ipsa_t *assoc;
uint_t espstart;
uint32_t ivlen = 0;
@@ -1770,11 +1646,11 @@ esp_in_done(mblk_t *ipsec_in_mp)
esph_t *esph;
kstat_named_t *counter;
boolean_t is_natt;
- netstack_t *ns = ii->ipsec_in_ns;
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
ipsec_stack_t *ipss = ns->netstack_ipsec;
- assoc = ii->ipsec_in_esp_sa;
+ assoc = ira->ira_ipsec_esp_sa;
ASSERT(assoc != NULL);
is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0);
@@ -1782,26 +1658,25 @@ esp_in_done(mblk_t *ipsec_in_mp)
/* get the pointer to the ESP header */
if (assoc->ipsa_encr_alg == SADB_EALG_NULL) {
/* authentication-only ESP */
- espstart = ii->ipsec_in_crypto_data.cd_offset;
- processed_len = ii->ipsec_in_crypto_data.cd_length;
+ espstart = ic->ic_crypto_data.cd_offset;
+ processed_len = ic->ic_crypto_data.cd_length;
} else {
/* encryption present */
ivlen = assoc->ipsa_iv_len;
if (assoc->ipsa_auth_alg == SADB_AALG_NONE) {
/* encryption-only ESP */
- espstart = ii->ipsec_in_crypto_data.cd_offset -
+ espstart = ic->ic_crypto_data.cd_offset -
sizeof (esph_t) - assoc->ipsa_iv_len;
- processed_len = ii->ipsec_in_crypto_data.cd_length +
+ processed_len = ic->ic_crypto_data.cd_length +
ivlen;
} else {
/* encryption with authentication */
- espstart = ii->ipsec_in_crypto_dual_data.dd_offset1;
- processed_len = ii->ipsec_in_crypto_dual_data.dd_len2 +
+ espstart = ic->ic_crypto_dual_data.dd_offset1;
+ processed_len = ic->ic_crypto_dual_data.dd_len2 +
ivlen;
}
}
- data_mp = ipsec_in_mp->b_cont;
esph = (esph_t *)(data_mp->b_rptr + espstart);
if (assoc->ipsa_auth_alg != IPSA_AALG_NONE ||
@@ -1840,8 +1715,11 @@ esp_in_done(mblk_t *ipsec_in_mp)
goto drop_and_bail;
}
- if (is_natt)
- esp_port_freshness(ii->ipsec_in_esp_udp_ports, assoc);
+ if (is_natt) {
+ ASSERT(ira->ira_flags & IRAF_ESP_UDP_PORTS);
+ ASSERT(ira->ira_esp_udp_ports != 0);
+ esp_port_freshness(ira->ira_esp_udp_ports, assoc);
+ }
}
esp_set_usetime(assoc, B_TRUE);
@@ -1863,44 +1741,41 @@ esp_in_done(mblk_t *ipsec_in_mp)
* spews "branch, predict taken" code for this.
*/
- if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter,
- espstack)) {
-
- if (is_system_labeled()) {
- cred_t *cr = assoc->ipsa_cred;
+ if (esp_strip_header(data_mp, (ira->ira_flags & IRAF_IS_IPV4),
+ ivlen, &counter, espstack)) {
- if (cr != NULL) {
- mblk_setcred(data_mp, cr, NOPID);
+ if (is_system_labeled() && assoc->ipsa_tsl != NULL) {
+ if (!ip_recv_attr_replace_label(ira, assoc->ipsa_tsl)) {
+ ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
+ DROPPER(ipss, ipds_ah_nomem),
+ &espstack->esp_dropper);
+ BUMP_MIB(ira->ira_ill->ill_ip_mib,
+ ipIfStatsInDiscards);
+ return (NULL);
}
-
}
if (is_natt)
return (esp_fix_natt_checksums(data_mp, assoc));
- ASSERT(!is_system_labeled() || (DB_CRED(data_mp) != NULL));
-
if (assoc->ipsa_state == IPSA_STATE_IDLE) {
/*
* Cluster buffering case. Tell caller that we're
* handling the packet.
*/
- sadb_buf_pkt(assoc, ipsec_in_mp, ns);
- return (IPSEC_STATUS_PENDING);
+ sadb_buf_pkt(assoc, data_mp, ira);
+ return (NULL);
}
- return (IPSEC_STATUS_SUCCESS);
+ return (data_mp);
}
esp1dbg(espstack, ("esp_in_done: esp_strip_header() failed\n"));
drop_and_bail:
IP_ESP_BUMP_STAT(ipss, in_discards);
- /*
- * TODO: Extract inbound interface from the IPSEC_IN message's
- * ii->ipsec_in_rill_index.
- */
- ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, counter,
+ ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, counter,
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
+ return (NULL);
}
/*
@@ -1908,11 +1783,10 @@ drop_and_bail:
* argument is freed.
*/
static void
-esp_log_bad_auth(mblk_t *ipsec_in)
+esp_log_bad_auth(mblk_t *mp, ip_recv_attr_t *ira)
{
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr;
- ipsa_t *assoc = ii->ipsec_in_esp_sa;
- netstack_t *ns = ii->ipsec_in_ns;
+ ipsa_t *assoc = ira->ira_ipsec_esp_sa;
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
ipsec_stack_t *ipss = ns->netstack_ipsec;
@@ -1928,11 +1802,7 @@ esp_log_bad_auth(mblk_t *ipsec_in)
espstack->ipsecesp_netstack);
IP_ESP_BUMP_STAT(ipss, in_discards);
- /*
- * TODO: Extract inbound interface from the IPSEC_IN
- * message's ii->ipsec_in_rill_index.
- */
- ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL,
+ ip_drop_packet(mp, B_TRUE, ira->ira_ill,
DROPPER(ipss, ipds_esp_bad_auth),
&espstack->esp_dropper);
}
@@ -1944,148 +1814,205 @@ esp_log_bad_auth(mblk_t *ipsec_in)
* Returns B_TRUE if the AH processing was not needed or if it was
* performed successfully. Returns B_FALSE and consumes the passed mblk
* if AH processing was required but could not be performed.
+ *
+ * Returns data_mp unless data_mp was consumed/queued.
*/
-static boolean_t
-esp_do_outbound_ah(mblk_t *ipsec_mp)
+static mblk_t *
+esp_do_outbound_ah(mblk_t *data_mp, ip_xmit_attr_t *ixa)
{
- ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
- ipsec_status_t ipsec_rc;
ipsec_action_t *ap;
- ap = io->ipsec_out_act;
+ ap = ixa->ixa_ipsec_action;
if (ap == NULL) {
- ipsec_policy_t *pp = io->ipsec_out_policy;
+ ipsec_policy_t *pp = ixa->ixa_ipsec_policy;
ap = pp->ipsp_act;
}
if (!ap->ipa_want_ah)
- return (B_TRUE);
+ return (data_mp);
- ASSERT(io->ipsec_out_ah_done == B_FALSE);
-
- if (io->ipsec_out_ah_sa == NULL) {
- if (!ipsec_outbound_sa(ipsec_mp, IPPROTO_AH)) {
- sadb_acquire(ipsec_mp, io, B_TRUE, B_FALSE);
- return (B_FALSE);
+ /*
+ * Normally the AH SA would have already been put in place
+ * but it could have been flushed so we need to look for it.
+ */
+ if (ixa->ixa_ipsec_ah_sa == NULL) {
+ if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_AH)) {
+ sadb_acquire(data_mp, ixa, B_TRUE, B_FALSE);
+ return (NULL);
}
}
- ASSERT(io->ipsec_out_ah_sa != NULL);
+ ASSERT(ixa->ixa_ipsec_ah_sa != NULL);
- io->ipsec_out_ah_done = B_TRUE;
- ipsec_rc = io->ipsec_out_ah_sa->ipsa_output_func(ipsec_mp);
- return (ipsec_rc == IPSEC_STATUS_SUCCESS);
+ data_mp = ixa->ixa_ipsec_ah_sa->ipsa_output_func(data_mp, ixa);
+ return (data_mp);
}
/*
* Kernel crypto framework callback invoked after completion of async
- * crypto requests.
+ * crypto requests for outbound packets.
*/
static void
-esp_kcf_callback(void *arg, int status)
+esp_kcf_callback_outbound(void *arg, int status)
{
- mblk_t *ipsec_mp = (mblk_t *)arg;
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
- ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
- boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN);
- netstackid_t stackid;
- netstack_t *ns, *ns_arg;
- ipsecesp_stack_t *espstack;
+ mblk_t *mp = (mblk_t *)arg;
+ mblk_t *async_mp;
+ netstack_t *ns;
ipsec_stack_t *ipss;
+ ipsecesp_stack_t *espstack;
+ mblk_t *data_mp;
+ ip_xmit_attr_t ixas;
+ ipsec_crypto_t *ic;
+ ill_t *ill;
- ASSERT(ipsec_mp->b_cont != NULL);
+ /*
+ * First remove the ipsec_crypto_t mblk
+ * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
+ */
+ async_mp = ipsec_remove_crypto_data(mp, &ic);
+ ASSERT(async_mp != NULL);
- if (is_inbound) {
- stackid = ii->ipsec_in_stackid;
- ns_arg = ii->ipsec_in_ns;
+ /*
+ * Extract the ip_xmit_attr_t from the first mblk.
+ * Verifies that the netstack and ill is still around; could
+ * have vanished while kEf was doing its work.
+ * On succesful return we have a nce_t and the ill/ipst can't
+ * disappear until we do the nce_refrele in ixa_cleanup.
+ */
+ data_mp = async_mp->b_cont;
+ async_mp->b_cont = NULL;
+ if (!ip_xmit_attr_from_mblk(async_mp, &ixas)) {
+ /* Disappeared on us - no ill/ipst for MIB */
+ /* We have nowhere to do stats since ixa_ipst could be NULL */
+ if (ixas.ixa_nce != NULL) {
+ ill = ixas.ixa_nce->nce_ill;
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
+ }
+ freemsg(data_mp);
+ goto done;
+ }
+ ns = ixas.ixa_ipst->ips_netstack;
+ espstack = ns->netstack_ipsecesp;
+ ipss = ns->netstack_ipsec;
+ ill = ixas.ixa_nce->nce_ill;
+
+ if (status == CRYPTO_SUCCESS) {
+ /*
+ * If a ICV was computed, it was stored by the
+ * crypto framework at the end of the packet.
+ */
+ ipha_t *ipha = (ipha_t *)data_mp->b_rptr;
+
+ esp_set_usetime(ixas.ixa_ipsec_esp_sa, B_FALSE);
+ /* NAT-T packet. */
+ if (IPH_HDR_VERSION(ipha) == IP_VERSION &&
+ ipha->ipha_protocol == IPPROTO_UDP)
+ esp_prepare_udp(ns, data_mp, ipha);
+
+ /* do AH processing if needed */
+ data_mp = esp_do_outbound_ah(data_mp, &ixas);
+ if (data_mp == NULL)
+ goto done;
+
+ (void) ip_output_post_ipsec(data_mp, &ixas);
} else {
- stackid = io->ipsec_out_stackid;
- ns_arg = io->ipsec_out_ns;
+ /* Outbound shouldn't see invalid MAC */
+ ASSERT(status != CRYPTO_INVALID_MAC);
+
+ esp1dbg(espstack,
+ ("esp_kcf_callback_outbound: crypto failed with 0x%x\n",
+ status));
+ ESP_BUMP_STAT(espstack, crypto_failures);
+ ESP_BUMP_STAT(espstack, out_discards);
+ ip_drop_packet(data_mp, B_FALSE, ill,
+ DROPPER(ipss, ipds_esp_crypto_failed),
+ &espstack->esp_dropper);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
}
+done:
+ ixa_cleanup(&ixas);
+ (void) ipsec_free_crypto_data(mp);
+}
+
+/*
+ * Kernel crypto framework callback invoked after completion of async
+ * crypto requests for inbound packets.
+ */
+static void
+esp_kcf_callback_inbound(void *arg, int status)
+{
+ mblk_t *mp = (mblk_t *)arg;
+ mblk_t *async_mp;
+ netstack_t *ns;
+ ipsecesp_stack_t *espstack;
+ ipsec_stack_t *ipss;
+ mblk_t *data_mp;
+ ip_recv_attr_t iras;
+ ipsec_crypto_t *ic;
/*
- * Verify that the netstack is still around; could have vanished
- * while kEf was doing its work.
+ * First remove the ipsec_crypto_t mblk
+ * Note that we need to ipsec_free_crypto_data(mp) once done with ic.
*/
- ns = netstack_find_by_stackid(stackid);
- if (ns == NULL || ns != ns_arg) {
- /* Disappeared on us */
- if (ns != NULL)
- netstack_rele(ns);
- freemsg(ipsec_mp);
- return;
+ async_mp = ipsec_remove_crypto_data(mp, &ic);
+ ASSERT(async_mp != NULL);
+
+ /*
+ * Extract the ip_recv_attr_t from the first mblk.
+ * Verifies that the netstack and ill is still around; could
+ * have vanished while kEf was doing its work.
+ */
+ data_mp = async_mp->b_cont;
+ async_mp->b_cont = NULL;
+ if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
+ /* The ill or ip_stack_t disappeared on us */
+ ip_drop_input("ip_recv_attr_from_mblk", data_mp, NULL);
+ freemsg(data_mp);
+ goto done;
}
+ ns = iras.ira_ill->ill_ipst->ips_netstack;
espstack = ns->netstack_ipsecesp;
ipss = ns->netstack_ipsec;
if (status == CRYPTO_SUCCESS) {
- if (is_inbound) {
- if (esp_in_done(ipsec_mp) != IPSEC_STATUS_SUCCESS) {
- netstack_rele(ns);
- return;
- }
- /* finish IPsec processing */
- ip_fanout_proto_again(ipsec_mp, NULL, NULL, NULL);
- } else {
- /*
- * If a ICV was computed, it was stored by the
- * crypto framework at the end of the packet.
- */
- ipha_t *ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr;
-
- esp_set_usetime(io->ipsec_out_esp_sa, B_FALSE);
- /* NAT-T packet. */
- if (ipha->ipha_protocol == IPPROTO_UDP)
- esp_prepare_udp(ns, ipsec_mp->b_cont, ipha);
-
- /* do AH processing if needed */
- if (!esp_do_outbound_ah(ipsec_mp)) {
- netstack_rele(ns);
- return;
- }
- /* finish IPsec processing */
- if (IPH_HDR_VERSION(ipha) == IP_VERSION) {
- ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL,
- NULL);
- } else {
- ip6_t *ip6h = (ip6_t *)ipha;
- ip_wput_ipsec_out_v6(NULL, ipsec_mp, ip6h,
- NULL, NULL);
- }
- }
+ data_mp = esp_in_done(data_mp, &iras, ic);
+ if (data_mp == NULL)
+ goto done;
+ /* finish IPsec processing */
+ ip_input_post_ipsec(data_mp, &iras);
} else if (status == CRYPTO_INVALID_MAC) {
- esp_log_bad_auth(ipsec_mp);
-
+ esp_log_bad_auth(data_mp, &iras);
} else {
esp1dbg(espstack,
("esp_kcf_callback: crypto failed with 0x%x\n",
status));
ESP_BUMP_STAT(espstack, crypto_failures);
- if (is_inbound)
- IP_ESP_BUMP_STAT(ipss, in_discards);
- else
- ESP_BUMP_STAT(espstack, out_discards);
- ip_drop_packet(ipsec_mp, is_inbound, NULL, NULL,
+ IP_ESP_BUMP_STAT(ipss, in_discards);
+ ip_drop_packet(data_mp, B_TRUE, iras.ira_ill,
DROPPER(ipss, ipds_esp_crypto_failed),
&espstack->esp_dropper);
+ BUMP_MIB(iras.ira_ill->ill_ip_mib, ipIfStatsInDiscards);
}
- netstack_rele(ns);
+done:
+ ira_cleanup(&iras, B_TRUE);
+ (void) ipsec_free_crypto_data(mp);
}
/*
* Invoked on crypto framework failure during inbound and outbound processing.
*/
static void
-esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc,
- ipsecesp_stack_t *espstack)
+esp_crypto_failed(mblk_t *data_mp, boolean_t is_inbound, int kef_rc,
+ ill_t *ill, ipsecesp_stack_t *espstack)
{
ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec;
esp1dbg(espstack, ("crypto failed for %s ESP with 0x%x\n",
is_inbound ? "inbound" : "outbound", kef_rc));
- ip_drop_packet(mp, is_inbound, NULL, NULL,
+ ip_drop_packet(data_mp, is_inbound, ill,
DROPPER(ipss, ipds_esp_crypto_failed),
&espstack->esp_dropper);
ESP_BUMP_STAT(espstack, crypto_failures);
@@ -2095,11 +2022,14 @@ esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc,
ESP_BUMP_STAT(espstack, out_discards);
}
-#define ESP_INIT_CALLREQ(_cr) { \
- (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_RESTRICTED; \
- (_cr)->cr_callback_arg = ipsec_mp; \
- (_cr)->cr_callback_func = esp_kcf_callback; \
-}
+/*
+ * A statement-equivalent macro, _cr MUST point to a modifiable
+ * crypto_call_req_t.
+ */
+#define ESP_INIT_CALLREQ(_cr, _mp, _callback) \
+ (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_ALWAYS_QUEUE; \
+ (_cr)->cr_callback_arg = (_mp); \
+ (_cr)->cr_callback_func = (_callback)
#define ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) { \
(mac)->cd_format = CRYPTO_DATA_RAW; \
@@ -2132,44 +2062,45 @@ esp_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc,
(data)->dd_offset2 = off2; \
}
-static ipsec_status_t
-esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset)
+/*
+ * Returns data_mp if successfully completed the request. Returns
+ * NULL if it failed (and increments InDiscards) or if it is pending.
+ */
+static mblk_t *
+esp_submit_req_inbound(mblk_t *esp_mp, ip_recv_attr_t *ira,
+ ipsa_t *assoc, uint_t esph_offset)
{
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
- boolean_t do_auth;
uint_t auth_offset, msg_len, auth_len;
- crypto_call_req_t call_req;
- mblk_t *esp_mp;
+ crypto_call_req_t call_req, *callrp;
+ mblk_t *mp;
esph_t *esph_ptr;
- int kef_rc = CRYPTO_FAILED;
+ int kef_rc;
uint_t icv_len = assoc->ipsa_mac_len;
crypto_ctx_template_t auth_ctx_tmpl;
- boolean_t do_encr;
+ boolean_t do_auth, do_encr, force;
uint_t encr_offset, encr_len;
uint_t iv_len = assoc->ipsa_iv_len;
crypto_ctx_template_t encr_ctx_tmpl;
- netstack_t *ns = ii->ipsec_in_ns;
- ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
- ipsec_stack_t *ipss = ns->netstack_ipsec;
+ ipsec_crypto_t *ic, icstack;
uchar_t *iv_ptr;
-
- ASSERT(ii->ipsec_in_type == IPSEC_IN);
-
- /*
- * In case kEF queues and calls back, keep netstackid_t for
- * verification that the IP instance is still around in
- * esp_kcf_callback().
- */
- ASSERT(ii->ipsec_in_stackid == ns->netstack_stackid);
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE;
do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL;
+ force = (assoc->ipsa_flags & IPSA_F_ASYNC);
+
+#ifdef IPSEC_LATENCY_TEST
+ kef_rc = CRYPTO_SUCCESS;
+#else
+ kef_rc = CRYPTO_FAILED;
+#endif
/*
* An inbound packet is of the form:
- * IPSEC_IN -> [IP,options,ESP,IV,data,ICV,pad]
+ * [IP,options,ESP,IV,data,ICV,pad]
*/
- esp_mp = ipsec_mp->b_cont;
esph_ptr = (esph_t *)(esp_mp->b_rptr + esph_offset);
iv_ptr = (uchar_t *)(esph_ptr + 1);
/* Packet length starting at IP header ending after ESP ICV. */
@@ -2178,8 +2109,6 @@ esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset)
encr_offset = esph_offset + sizeof (esph_t) + iv_len;
encr_len = msg_len - encr_offset;
- ESP_INIT_CALLREQ(&call_req);
-
/*
* Counter mode algs need a nonce. This is setup in sadb_common_add().
* If for some reason we are using a SA which does not have a nonce
@@ -2187,23 +2116,40 @@ esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset)
*/
if ((assoc->ipsa_flags & IPSA_F_COUNTERMODE) &&
(assoc->ipsa_nonce == NULL)) {
- ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(esp_mp, B_TRUE, ira->ira_ill,
DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ return (NULL);
}
- if (do_auth) {
- /* force asynchronous processing? */
- if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_AUTH] ==
- IPSEC_ALGS_EXEC_ASYNC)
- call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
+ if (force) {
+ /* We are doing asynch; allocate mblks to hold state */
+ if ((mp = ip_recv_attr_to_mblk(ira)) == NULL ||
+ (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
+ BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
+ ip_drop_input("ipIfStatsInDiscards", esp_mp,
+ ira->ira_ill);
+ return (NULL);
+ }
+ linkb(mp, esp_mp);
+ callrp = &call_req;
+ ESP_INIT_CALLREQ(callrp, mp, esp_kcf_callback_inbound);
+ } else {
+ /*
+ * If we know we are going to do sync then ipsec_crypto_t
+ * should be on the stack.
+ */
+ ic = &icstack;
+ bzero(ic, sizeof (*ic));
+ callrp = NULL;
+ }
+ if (do_auth) {
/* authentication context template */
IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH,
auth_ctx_tmpl);
/* ICV to be verified */
- ESP_INIT_CRYPTO_MAC(&ii->ipsec_in_crypto_mac,
+ ESP_INIT_CRYPTO_MAC(&ic->ic_crypto_mac,
icv_len, esp_mp->b_wptr - icv_len);
/* authentication starts at the ESP header */
@@ -2212,79 +2158,90 @@ esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset)
if (!do_encr) {
/* authentication only */
/* initialize input data argument */
- ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data,
+ ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
esp_mp, auth_offset, auth_len);
/* call the crypto framework */
kef_rc = crypto_mac_verify(&assoc->ipsa_amech,
- &ii->ipsec_in_crypto_data,
+ &ic->ic_crypto_data,
&assoc->ipsa_kcfauthkey, auth_ctx_tmpl,
- &ii->ipsec_in_crypto_mac, &call_req);
+ &ic->ic_crypto_mac, callrp);
}
}
if (do_encr) {
- /* force asynchronous processing? */
- if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
- IPSEC_ALGS_EXEC_ASYNC)
- call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
-
/* encryption template */
IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR,
encr_ctx_tmpl);
/* Call the nonce update function. Also passes in IV */
(assoc->ipsa_noncefunc)(assoc, (uchar_t *)esph_ptr, encr_len,
- iv_ptr, &ii->ipsec_in_cmm, &ii->ipsec_in_crypto_data);
+ iv_ptr, &ic->ic_cmm, &ic->ic_crypto_data);
if (!do_auth) {
/* decryption only */
/* initialize input data argument */
- ESP_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data,
+ ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
esp_mp, encr_offset, encr_len);
/* call the crypto framework */
kef_rc = crypto_decrypt((crypto_mechanism_t *)
- &ii->ipsec_in_cmm, &ii->ipsec_in_crypto_data,
+ &ic->ic_cmm, &ic->ic_crypto_data,
&assoc->ipsa_kcfencrkey, encr_ctx_tmpl,
- NULL, &call_req);
+ NULL, callrp);
}
}
if (do_auth && do_encr) {
/* dual operation */
/* initialize input data argument */
- ESP_INIT_CRYPTO_DUAL_DATA(&ii->ipsec_in_crypto_dual_data,
+ ESP_INIT_CRYPTO_DUAL_DATA(&ic->ic_crypto_dual_data,
esp_mp, auth_offset, auth_len,
encr_offset, encr_len - icv_len);
/* specify IV */
- ii->ipsec_in_crypto_dual_data.dd_miscdata = (char *)iv_ptr;
+ ic->ic_crypto_dual_data.dd_miscdata = (char *)iv_ptr;
/* call the framework */
kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech,
- &assoc->ipsa_emech, &ii->ipsec_in_crypto_dual_data,
+ &assoc->ipsa_emech, &ic->ic_crypto_dual_data,
&assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey,
- auth_ctx_tmpl, encr_ctx_tmpl, &ii->ipsec_in_crypto_mac,
- NULL, &call_req);
+ auth_ctx_tmpl, encr_ctx_tmpl, &ic->ic_crypto_mac,
+ NULL, callrp);
}
switch (kef_rc) {
case CRYPTO_SUCCESS:
ESP_BUMP_STAT(espstack, crypto_sync);
- return (esp_in_done(ipsec_mp));
+ esp_mp = esp_in_done(esp_mp, ira, ic);
+ if (force) {
+ /* Free mp after we are done with ic */
+ mp = ipsec_free_crypto_data(mp);
+ (void) ip_recv_attr_free_mblk(mp);
+ }
+ return (esp_mp);
case CRYPTO_QUEUED:
- /* esp_kcf_callback() will be invoked on completion */
+ /* esp_kcf_callback_inbound() will be invoked on completion */
ESP_BUMP_STAT(espstack, crypto_async);
- return (IPSEC_STATUS_PENDING);
+ return (NULL);
case CRYPTO_INVALID_MAC:
+ if (force) {
+ mp = ipsec_free_crypto_data(mp);
+ esp_mp = ip_recv_attr_free_mblk(mp);
+ }
ESP_BUMP_STAT(espstack, crypto_sync);
- esp_log_bad_auth(ipsec_mp);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
+ esp_log_bad_auth(esp_mp, ira);
+ /* esp_mp was passed to ip_drop_packet */
+ return (NULL);
}
- esp_crypto_failed(ipsec_mp, B_TRUE, kef_rc, espstack);
- return (IPSEC_STATUS_FAILED);
+ mp = ipsec_free_crypto_data(mp);
+ esp_mp = ip_recv_attr_free_mblk(mp);
+ BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards);
+ esp_crypto_failed(esp_mp, B_TRUE, kef_rc, ira->ira_ill, espstack);
+ /* esp_mp was passed to ip_drop_packet */
+ return (NULL);
}
/*
@@ -2293,6 +2250,9 @@ esp_submit_req_inbound(mblk_t *ipsec_mp, ipsa_t *assoc, uint_t esph_offset)
* uses mblk-insertion to insert the UDP header.
* TODO - If there is an easy way to prep a packet for HW checksums, make
* it happen here.
+ * Note that this is used before both before calling ip_output_simple and
+ * in the esp datapath. The former could use IXAF_SET_ULP_CKSUM but not the
+ * latter.
*/
static void
esp_prepare_udp(netstack_t *ns, mblk_t *mp, ipha_t *ipha)
@@ -2313,7 +2273,7 @@ esp_prepare_udp(netstack_t *ns, mblk_t *mp, ipha_t *ipha)
/* arr points to the IP header. */
arr = (uint16_t *)ipha;
IP_STAT(ns->netstack_ip, ip_out_sw_cksum);
- IP_STAT_UPDATE(ns->netstack_ip, ip_udp_out_sw_cksum_bytes,
+ IP_STAT_UPDATE(ns->netstack_ip, ip_out_sw_cksum_bytes,
ntohs(htons(ipha->ipha_length) - hlen));
/* arr[6-9] are the IP addresses. */
cksum = IP_UDP_CSUM_COMP + arr[6] + arr[7] + arr[8] + arr[9] +
@@ -2336,41 +2296,45 @@ esp_prepare_udp(netstack_t *ns, mblk_t *mp, ipha_t *ipha)
static void
actually_send_keepalive(void *arg)
{
- mblk_t *ipsec_mp = (mblk_t *)arg;
- ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
- ipha_t *ipha;
- netstack_t *ns;
-
- ASSERT(DB_TYPE(ipsec_mp) == M_CTL);
- ASSERT(io->ipsec_out_type == IPSEC_OUT);
- ASSERT(ipsec_mp->b_cont != NULL);
- ASSERT(DB_TYPE(ipsec_mp->b_cont) == M_DATA);
-
- ns = netstack_find_by_stackid(io->ipsec_out_stackid);
- if (ns == NULL || ns != io->ipsec_out_ns) {
- /* Just freemsg(). */
- if (ns != NULL)
- netstack_rele(ns);
- freemsg(ipsec_mp);
+ mblk_t *mp = (mblk_t *)arg;
+ ip_xmit_attr_t ixas;
+ netstack_t *ns;
+ netstackid_t stackid;
+
+ stackid = (netstackid_t)(uintptr_t)mp->b_prev;
+ mp->b_prev = NULL;
+ ns = netstack_find_by_stackid(stackid);
+ if (ns == NULL) {
+ /* Disappeared */
+ ip_drop_output("ipIfStatsOutDiscards", mp, NULL);
+ freemsg(mp);
return;
}
- ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr;
- ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL, NULL);
+ bzero(&ixas, sizeof (ixas));
+ ixas.ixa_zoneid = ALL_ZONES;
+ ixas.ixa_cred = kcred;
+ ixas.ixa_cpid = NOPID;
+ ixas.ixa_tsl = NULL;
+ ixas.ixa_ipst = ns->netstack_ip;
+ /* No ULP checksum; done by esp_prepare_udp */
+ ixas.ixa_flags = IXAF_IS_IPV4 | IXAF_NO_IPSEC;
+
+ (void) ip_output_simple(mp, &ixas);
+ ixa_cleanup(&ixas);
netstack_rele(ns);
}
/*
- * Send a one-byte UDP NAT-T keepalive. Construct an IPSEC_OUT too that'll
- * get fed into esp_send_udp/ip_wput_ipsec_out.
+ * Send a one-byte UDP NAT-T keepalive.
*/
void
ipsecesp_send_keepalive(ipsa_t *assoc)
{
- mblk_t *mp = NULL, *ipsec_mp = NULL;
- ipha_t *ipha;
- udpha_t *udpha;
- ipsec_out_t *io;
+ mblk_t *mp;
+ ipha_t *ipha;
+ udpha_t *udpha;
+ netstack_t *ns = assoc->ipsa_netstack;
ASSERT(MUTEX_NOT_HELD(&assoc->ipsa_lock));
@@ -2399,85 +2363,78 @@ ipsecesp_send_keepalive(ipsa_t *assoc)
mp->b_wptr = (uint8_t *)(udpha + 1);
*(mp->b_wptr++) = 0xFF;
- ipsec_mp = ipsec_alloc_ipsec_out(assoc->ipsa_netstack);
- if (ipsec_mp == NULL) {
- freeb(mp);
- return;
- }
- ipsec_mp->b_cont = mp;
- io = (ipsec_out_t *)ipsec_mp->b_rptr;
- io->ipsec_out_zoneid =
- netstackid_to_zoneid(assoc->ipsa_netstack->netstack_stackid);
- io->ipsec_out_stackid = assoc->ipsa_netstack->netstack_stackid;
+ esp_prepare_udp(ns, mp, ipha);
- esp_prepare_udp(assoc->ipsa_netstack, mp, ipha);
/*
* We're holding an isaf_t bucket lock, so pawn off the actual
* packet transmission to another thread. Just in case syncq
* processing causes a same-bucket packet to be processed.
*/
- if (taskq_dispatch(esp_taskq, actually_send_keepalive, ipsec_mp,
+ mp->b_prev = (mblk_t *)(uintptr_t)ns->netstack_stackid;
+
+ if (taskq_dispatch(esp_taskq, actually_send_keepalive, mp,
TQ_NOSLEEP) == 0) {
/* Assume no memory if taskq_dispatch() fails. */
- ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL,
- DROPPER(assoc->ipsa_netstack->netstack_ipsec,
- ipds_esp_nomem),
- &assoc->ipsa_netstack->netstack_ipsecesp->esp_dropper);
+ mp->b_prev = NULL;
+ ip_drop_packet(mp, B_FALSE, NULL,
+ DROPPER(ns->netstack_ipsec, ipds_esp_nomem),
+ &ns->netstack_ipsecesp->esp_dropper);
}
}
-static ipsec_status_t
-esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf,
- uint_t payload_len)
+/*
+ * Returns mp if successfully completed the request. Returns
+ * NULL if it failed (and increments InDiscards) or if it is pending.
+ */
+static mblk_t *
+esp_submit_req_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa, ipsa_t *assoc,
+ uchar_t *icv_buf, uint_t payload_len)
{
- ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
uint_t auth_len;
- crypto_call_req_t call_req;
- mblk_t *esp_mp, *data_mp, *ip_mp;
+ crypto_call_req_t call_req, *callrp;
+ mblk_t *esp_mp;
esph_t *esph_ptr;
+ mblk_t *mp;
int kef_rc = CRYPTO_FAILED;
uint_t icv_len = assoc->ipsa_mac_len;
crypto_ctx_template_t auth_ctx_tmpl;
- boolean_t do_auth;
- boolean_t do_encr;
+ boolean_t do_auth, do_encr, force;
uint_t iv_len = assoc->ipsa_iv_len;
crypto_ctx_template_t encr_ctx_tmpl;
boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0);
size_t esph_offset = (is_natt ? UDPH_SIZE : 0);
- netstack_t *ns = io->ipsec_out_ns;
+ netstack_t *ns = ixa->ixa_ipst->ips_netstack;
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
+ ipsec_crypto_t *ic, icstack;
+ uchar_t *iv_ptr;
+ crypto_data_t *cd_ptr = NULL;
+ ill_t *ill = ixa->ixa_nce->nce_ill;
ipsec_stack_t *ipss = ns->netstack_ipsec;
- uchar_t *iv_ptr;
- crypto_data_t *cd_ptr = NULL;
esp3dbg(espstack, ("esp_submit_req_outbound:%s",
is_natt ? "natt" : "not natt"));
- ASSERT(io->ipsec_out_type == IPSEC_OUT);
-
- /*
- * In case kEF queues and calls back, keep netstackid_t for
- * verification that the IP instance is still around in
- * esp_kcf_callback().
- */
- io->ipsec_out_stackid = ns->netstack_stackid;
-
do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL;
do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE;
+ force = (assoc->ipsa_flags & IPSA_F_ASYNC);
+
+#ifdef IPSEC_LATENCY_TEST
+ kef_rc = CRYPTO_SUCCESS;
+#else
+ kef_rc = CRYPTO_FAILED;
+#endif
/*
* Outbound IPsec packets are of the form:
- * IPSEC_OUT -> [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV]
+ * [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV]
* unless it's NATT, then it's
- * IPSEC_OUT -> [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV]
+ * [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV]
* Get a pointer to the mblk containing the ESP header.
*/
- ip_mp = ipsec_mp->b_cont;
- esp_mp = ipsec_mp->b_cont->b_cont;
- ASSERT(ip_mp != NULL && esp_mp != NULL);
+ ASSERT(data_mp->b_cont != NULL);
+ esp_mp = data_mp->b_cont;
esph_ptr = (esph_t *)(esp_mp->b_rptr + esph_offset);
iv_ptr = (uchar_t *)(esph_ptr + 1);
- data_mp = ipsec_mp->b_cont->b_cont->b_cont;
/*
* Combined mode algs need a nonce. This is setup in sadb_common_add().
@@ -2486,25 +2443,42 @@ esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf,
*/
if ((assoc->ipsa_flags & IPSA_F_COUNTERMODE) &&
(assoc->ipsa_nonce == NULL)) {
- ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, NULL,
DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ return (NULL);
}
- ESP_INIT_CALLREQ(&call_req);
+ if (force) {
+ /* We are doing asynch; allocate mblks to hold state */
+ if ((mp = ip_xmit_attr_to_mblk(ixa)) == NULL ||
+ (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) {
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ ip_drop_output("ipIfStatsOutDiscards", data_mp, ill);
+ freemsg(data_mp);
+ return (NULL);
+ }
+
+ linkb(mp, data_mp);
+ callrp = &call_req;
+ ESP_INIT_CALLREQ(callrp, mp, esp_kcf_callback_outbound);
+ } else {
+ /*
+ * If we know we are going to do sync then ipsec_crypto_t
+ * should be on the stack.
+ */
+ ic = &icstack;
+ bzero(ic, sizeof (*ic));
+ callrp = NULL;
+ }
- if (do_auth) {
- /* force asynchronous processing? */
- if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_AUTH] ==
- IPSEC_ALGS_EXEC_ASYNC)
- call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
+ if (do_auth) {
/* authentication context template */
IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH,
auth_ctx_tmpl);
/* where to store the computed mac */
- ESP_INIT_CRYPTO_MAC(&io->ipsec_out_crypto_mac,
+ ESP_INIT_CRYPTO_MAC(&ic->ic_crypto_mac,
icv_len, icv_buf);
/* authentication starts at the ESP header */
@@ -2512,35 +2486,30 @@ esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf,
if (!do_encr) {
/* authentication only */
/* initialize input data argument */
- ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data,
+ ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
esp_mp, esph_offset, auth_len);
/* call the crypto framework */
kef_rc = crypto_mac(&assoc->ipsa_amech,
- &io->ipsec_out_crypto_data,
+ &ic->ic_crypto_data,
&assoc->ipsa_kcfauthkey, auth_ctx_tmpl,
- &io->ipsec_out_crypto_mac, &call_req);
+ &ic->ic_crypto_mac, callrp);
}
}
if (do_encr) {
- /* force asynchronous processing? */
- if (ipss->ipsec_algs_exec_mode[IPSEC_ALG_ENCR] ==
- IPSEC_ALGS_EXEC_ASYNC)
- call_req.cr_flag |= CRYPTO_ALWAYS_QUEUE;
-
/* encryption context template */
IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR,
encr_ctx_tmpl);
/* Call the nonce update function. */
(assoc->ipsa_noncefunc)(assoc, (uchar_t *)esph_ptr, payload_len,
- iv_ptr, &io->ipsec_out_cmm, &io->ipsec_out_crypto_data);
+ iv_ptr, &ic->ic_cmm, &ic->ic_crypto_data);
if (!do_auth) {
/* encryption only, skip mblk that contains ESP hdr */
/* initialize input data argument */
- ESP_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data,
- data_mp, 0, payload_len);
+ ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data,
+ esp_mp->b_cont, 0, payload_len);
/*
* For combined mode ciphers, the ciphertext is the same
@@ -2556,20 +2525,19 @@ esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf,
* for the cipher to use.
*/
if (assoc->ipsa_flags & IPSA_F_COMBINED) {
- bcopy(&io->ipsec_out_crypto_data,
- &io->ipsec_out_crypto_mac,
+ bcopy(&ic->ic_crypto_data,
+ &ic->ic_crypto_mac,
sizeof (crypto_data_t));
- io->ipsec_out_crypto_mac.cd_length =
+ ic->ic_crypto_mac.cd_length =
payload_len + icv_len;
- cd_ptr = &io->ipsec_out_crypto_mac;
+ cd_ptr = &ic->ic_crypto_mac;
}
/* call the crypto framework */
kef_rc = crypto_encrypt((crypto_mechanism_t *)
- &io->ipsec_out_cmm,
- &io->ipsec_out_crypto_data,
+ &ic->ic_cmm, &ic->ic_crypto_data,
&assoc->ipsa_kcfencrkey, encr_ctx_tmpl,
- cd_ptr, &call_req);
+ cd_ptr, callrp);
}
}
@@ -2584,49 +2552,58 @@ esp_submit_req_outbound(mblk_t *ipsec_mp, ipsa_t *assoc, uchar_t *icv_buf,
* the authentication at the ESP header, i.e. use an
* authentication offset of zero.
*/
- ESP_INIT_CRYPTO_DUAL_DATA(&io->ipsec_out_crypto_dual_data,
+ ESP_INIT_CRYPTO_DUAL_DATA(&ic->ic_crypto_dual_data,
esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len);
/* specify IV */
- io->ipsec_out_crypto_dual_data.dd_miscdata = (char *)iv_ptr;
+ ic->ic_crypto_dual_data.dd_miscdata = (char *)iv_ptr;
/* call the framework */
kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech,
&assoc->ipsa_amech, NULL,
&assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey,
encr_ctx_tmpl, auth_ctx_tmpl,
- &io->ipsec_out_crypto_dual_data,
- &io->ipsec_out_crypto_mac, &call_req);
+ &ic->ic_crypto_dual_data,
+ &ic->ic_crypto_mac, callrp);
}
switch (kef_rc) {
case CRYPTO_SUCCESS:
ESP_BUMP_STAT(espstack, crypto_sync);
esp_set_usetime(assoc, B_FALSE);
+ if (force) {
+ mp = ipsec_free_crypto_data(mp);
+ data_mp = ip_xmit_attr_free_mblk(mp);
+ }
if (is_natt)
- esp_prepare_udp(ns, ipsec_mp->b_cont,
- (ipha_t *)ipsec_mp->b_cont->b_rptr);
- return (IPSEC_STATUS_SUCCESS);
+ esp_prepare_udp(ns, data_mp, (ipha_t *)data_mp->b_rptr);
+ return (data_mp);
case CRYPTO_QUEUED:
- /* esp_kcf_callback() will be invoked on completion */
+ /* esp_kcf_callback_outbound() will be invoked on completion */
ESP_BUMP_STAT(espstack, crypto_async);
- return (IPSEC_STATUS_PENDING);
+ return (NULL);
}
- esp_crypto_failed(ipsec_mp, B_FALSE, kef_rc, espstack);
- return (IPSEC_STATUS_FAILED);
+ if (force) {
+ mp = ipsec_free_crypto_data(mp);
+ data_mp = ip_xmit_attr_free_mblk(mp);
+ }
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ esp_crypto_failed(data_mp, B_FALSE, kef_rc, NULL, espstack);
+ /* data_mp was passed to ip_drop_packet */
+ return (NULL);
}
/*
* Handle outbound IPsec processing for IPv4 and IPv6
- * On success returns B_TRUE, on failure returns B_FALSE and frees the
- * mblk chain ipsec_in_mp.
+ *
+ * Returns data_mp if successfully completed the request. Returns
+ * NULL if it failed (and increments InDiscards) or if it is pending.
*/
-static ipsec_status_t
-esp_outbound(mblk_t *mp)
+static mblk_t *
+esp_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa)
{
- mblk_t *ipsec_out_mp, *data_mp, *espmp, *tailmp;
- ipsec_out_t *io;
+ mblk_t *espmp, *tailmp;
ipha_t *ipha;
ip6_t *ip6h;
esph_t *esph_ptr, *iv_ptr;
@@ -2640,17 +2617,11 @@ esp_outbound(mblk_t *mp)
uchar_t *icv_buf;
udpha_t *udpha;
boolean_t is_natt = B_FALSE;
- netstack_t *ns;
- ipsecesp_stack_t *espstack;
- ipsec_stack_t *ipss;
-
- ipsec_out_mp = mp;
- data_mp = ipsec_out_mp->b_cont;
-
- io = (ipsec_out_t *)ipsec_out_mp->b_rptr;
- ns = io->ipsec_out_ns;
- espstack = ns->netstack_ipsecesp;
- ipss = ns->netstack_ipsec;
+ netstack_t *ns = ixa->ixa_ipst->ips_netstack;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
+ ill_t *ill = ixa->ixa_nce->nce_ill;
+ boolean_t need_refrele = B_FALSE;
ESP_BUMP_STAT(espstack, out_requests);
@@ -2662,65 +2633,73 @@ esp_outbound(mblk_t *mp)
* we might as well make use of msgpullup() and get the mblk into one
* contiguous piece!
*/
- ipsec_out_mp->b_cont = msgpullup(data_mp, -1);
- if (ipsec_out_mp->b_cont == NULL) {
+ tailmp = msgpullup(data_mp, -1);
+ if (tailmp == NULL) {
esp0dbg(("esp_outbound: msgpullup() failed, "
"dropping packet.\n"));
- ipsec_out_mp->b_cont = data_mp;
- /*
- * TODO: Find the outbound IRE for this packet and
- * pass it to ip_drop_packet().
- */
- ip_drop_packet(ipsec_out_mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_nomem),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
- } else {
- freemsg(data_mp);
- data_mp = ipsec_out_mp->b_cont;
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ return (NULL);
}
+ freemsg(data_mp);
+ data_mp = tailmp;
- assoc = io->ipsec_out_esp_sa;
+ assoc = ixa->ixa_ipsec_esp_sa;
ASSERT(assoc != NULL);
/*
* Get the outer IP header in shape to escape this system..
*/
- if (is_system_labeled() && (assoc->ipsa_ocred != NULL)) {
- int whack;
-
- mblk_setcred(data_mp, assoc->ipsa_ocred, NOPID);
- if (io->ipsec_out_v4)
- whack = sadb_whack_label(&data_mp, assoc);
- else
- whack = sadb_whack_label_v6(&data_mp, assoc);
- if (whack != 0) {
- ip_drop_packet(ipsec_out_mp, B_FALSE, NULL,
- NULL, DROPPER(ipss, ipds_esp_nomem),
+ if (is_system_labeled() && (assoc->ipsa_otsl != NULL)) {
+ /*
+ * Need to update packet with any CIPSO option and update
+ * ixa_tsl to capture the new label.
+ * We allocate a separate ixa for that purpose.
+ */
+ ixa = ip_xmit_attr_duplicate(ixa);
+ if (ixa == NULL) {
+ ip_drop_packet(data_mp, B_FALSE, ill,
+ DROPPER(ipss, ipds_esp_nomem),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ return (NULL);
}
- ipsec_out_mp->b_cont = data_mp;
- }
+ need_refrele = B_TRUE;
+ label_hold(assoc->ipsa_otsl);
+ ip_xmit_attr_replace_tsl(ixa, assoc->ipsa_otsl);
+
+ data_mp = sadb_whack_label(data_mp, assoc, ixa,
+ DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper);
+ if (data_mp == NULL) {
+ /* Packet dropped by sadb_whack_label */
+ ixa_refrele(ixa);
+ return (NULL);
+ }
+ }
/*
* Reality check....
*/
ipha = (ipha_t *)data_mp->b_rptr; /* So we can call esp_acquire(). */
- if (io->ipsec_out_v4) {
+ if (ixa->ixa_flags & IXAF_IS_IPV4) {
+ ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION);
+
af = AF_INET;
divpoint = IPH_HDR_LENGTH(ipha);
datalen = ntohs(ipha->ipha_length) - divpoint;
nhp = (uint8_t *)&ipha->ipha_protocol;
} else {
- ip6_pkt_t ipp;
+ ip_pkt_t ipp;
+
+ ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION);
af = AF_INET6;
ip6h = (ip6_t *)ipha;
bzero(&ipp, sizeof (ipp));
- divpoint = ip_find_hdr_v6(data_mp, ip6h, &ipp, NULL);
+ divpoint = ip_find_hdr_v6(data_mp, ip6h, B_FALSE, &ipp, NULL);
if (ipp.ipp_dstopts != NULL &&
ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) {
/*
@@ -2795,28 +2774,26 @@ esp_outbound(mblk_t *mp)
*/
if (!esp_age_bytes(assoc, datalen + padlen + iv_len + 2, B_FALSE)) {
- /*
- * TODO: Find the outbound IRE for this packet and
- * pass it to ip_drop_packet().
- */
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_bytes_expire),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (NULL);
}
espmp = allocb(esplen, BPRI_HI);
if (espmp == NULL) {
ESP_BUMP_STAT(espstack, out_discards);
esp1dbg(espstack, ("esp_outbound: can't allocate espmp.\n"));
- /*
- * TODO: Find the outbound IRE for this packet and
- * pass it to ip_drop_packet().
- */
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_nomem),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (NULL);
}
espmp->b_wptr += esplen;
esph_ptr = (esph_t *)espmp->b_rptr;
@@ -2853,14 +2830,13 @@ esp_outbound(mblk_t *mp)
ESP_BUMP_STAT(espstack, out_discards);
sadb_replay_delete(assoc);
- /*
- * TODO: Find the outbound IRE for this packet and
- * pass it to ip_drop_packet().
- */
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_replay),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (NULL);
}
iv_ptr = (esph_ptr + 1);
@@ -2887,9 +2863,11 @@ esp_outbound(mblk_t *mp)
*/
if (!update_iv((uint8_t *)iv_ptr, espstack->esp_pfkey_q, assoc,
espstack)) {
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_iv_wrap), &espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (NULL);
}
/* Fix the IP header. */
@@ -2898,7 +2876,7 @@ esp_outbound(mblk_t *mp)
protocol = *nhp;
- if (io->ipsec_out_v4) {
+ if (ixa->ixa_flags & IXAF_IS_IPV4) {
ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj);
if (is_natt) {
*nhp = IPPROTO_UDP;
@@ -2922,15 +2900,14 @@ esp_outbound(mblk_t *mp)
if (!esp_insert_esp(data_mp, espmp, divpoint, espstack)) {
ESP_BUMP_STAT(espstack, out_discards);
/* NOTE: esp_insert_esp() only fails if there's no memory. */
- /*
- * TODO: Find the outbound IRE for this packet and
- * pass it to ip_drop_packet().
- */
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_nomem),
&espstack->esp_dropper);
freeb(espmp);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (NULL);
}
/* Append padding (and leave room for ICV). */
@@ -2941,14 +2918,13 @@ esp_outbound(mblk_t *mp)
if (tailmp->b_cont == NULL) {
ESP_BUMP_STAT(espstack, out_discards);
esp0dbg(("esp_outbound: Can't allocate tailmp.\n"));
- /*
- * TODO: Find the outbound IRE for this packet and
- * pass it to ip_drop_packet().
- */
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_esp_nomem),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (NULL);
}
tailmp = tailmp->b_cont;
}
@@ -2968,29 +2944,6 @@ esp_outbound(mblk_t *mp)
esp2dbg(espstack, (dump_msg(data_mp)));
/*
- * The packet is eligible for hardware acceleration if the
- * following conditions are satisfied:
- *
- * 1. the packet will not be fragmented
- * 2. the provider supports the algorithms specified by SA
- * 3. there is no pending control message being exchanged
- * 4. snoop is not attached
- * 5. the destination address is not a multicast address
- *
- * All five of these conditions are checked by IP prior to
- * sending the packet to ESP.
- *
- * But We, and We Alone, can, nay MUST check if the packet
- * is over NATT, and then disqualify it from hardware
- * acceleration.
- */
-
- if (io->ipsec_out_is_capab_ill && !(assoc->ipsa_flags & IPSA_F_NATT)) {
- return (esp_outbound_accelerated(ipsec_out_mp, mac_len));
- }
- ESP_BUMP_STAT(espstack, noaccel);
-
- /*
* Okay. I've set up the pre-encryption ESP. Let's do it!
*/
@@ -3002,32 +2955,23 @@ esp_outbound(mblk_t *mp)
icv_buf = NULL;
}
- return (esp_submit_req_outbound(ipsec_out_mp, assoc, icv_buf,
- datalen + padlen + 2));
+ data_mp = esp_submit_req_outbound(data_mp, ixa, assoc, icv_buf,
+ datalen + padlen + 2);
+ if (need_refrele)
+ ixa_refrele(ixa);
+ return (data_mp);
}
/*
* IP calls this to validate the ICMP errors that
* we got from the network.
*/
-ipsec_status_t
-ipsecesp_icmp_error(mblk_t *ipsec_mp)
+mblk_t *
+ipsecesp_icmp_error(mblk_t *data_mp, ip_recv_attr_t *ira)
{
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
- boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN);
- netstack_t *ns;
- ipsecesp_stack_t *espstack;
- ipsec_stack_t *ipss;
-
- if (is_inbound) {
- ns = ii->ipsec_in_ns;
- } else {
- ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr;
-
- ns = io->ipsec_out_ns;
- }
- espstack = ns->netstack_ipsecesp;
- ipss = ns->netstack_ipsec;
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
/*
* Unless we get an entire packet back, this function is useless.
@@ -3044,55 +2988,10 @@ ipsecesp_icmp_error(mblk_t *ipsec_mp)
* very small, we discard here.
*/
IP_ESP_BUMP_STAT(ipss, in_discards);
- ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL,
+ ip_drop_packet(data_mp, B_TRUE, ira->ira_ill,
DROPPER(ipss, ipds_esp_icmp),
&espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
-}
-
-/*
- * ESP module read put routine.
- */
-/* ARGSUSED */
-static void
-ipsecesp_rput(queue_t *q, mblk_t *mp)
-{
- ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr;
-
- ASSERT(mp->b_datap->db_type != M_CTL); /* No more IRE_DB_REQ. */
-
- switch (mp->b_datap->db_type) {
- case M_PROTO:
- case M_PCPROTO:
- /* TPI message of some sort. */
- switch (*((t_scalar_t *)mp->b_rptr)) {
- case T_BIND_ACK:
- esp3dbg(espstack,
- ("Thank you IP from ESP for T_BIND_ACK\n"));
- break;
- case T_ERROR_ACK:
- cmn_err(CE_WARN,
- "ipsecesp: ESP received T_ERROR_ACK from IP.");
- /*
- * Make esp_sadb.s_ip_q NULL, and in the
- * future, perhaps try again.
- */
- espstack->esp_sadb.s_ip_q = NULL;
- break;
- case T_OK_ACK:
- /* Probably from a (rarely sent) T_UNBIND_REQ. */
- break;
- default:
- esp0dbg(("Unknown M_{,PC}PROTO message.\n"));
- }
- freemsg(mp);
- break;
- default:
- /* For now, passthru message. */
- esp2dbg(espstack, ("ESP got unknown mblk type %d.\n",
- mp->b_datap->db_type));
- putnext(q, mp);
- }
+ return (NULL);
}
/*
@@ -3102,7 +3001,7 @@ ipsecesp_rput(queue_t *q, mblk_t *mp)
*/
static boolean_t
esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
- ipsecesp_stack_t *espstack, mblk_t *in_mp)
+ ipsecesp_stack_t *espstack, cred_t *cr)
{
mblk_t *pfkey_msg_mp, *keysock_out_mp;
sadb_msg_t *samsg;
@@ -3121,7 +3020,7 @@ esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
sadb_sens_t *sens;
size_t sens_len = 0;
sadb_ext_t *nextext;
- cred_t *sens_cr = NULL;
+ ts_label_t *sens_tsl = NULL;
/* Allocate the KEYSOCK_OUT. */
keysock_out_mp = sadb_keysock_out(serial);
@@ -3130,11 +3029,10 @@ esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
return (B_FALSE);
}
- if (is_system_labeled() && (in_mp != NULL)) {
- sens_cr = msg_getcred(in_mp, NULL);
-
- if (sens_cr != NULL) {
- sens_len = sadb_sens_len_from_cred(sens_cr);
+ if (is_system_labeled() && (cr != NULL)) {
+ sens_tsl = crgetlabel(cr);
+ if (sens_tsl != NULL) {
+ sens_len = sadb_sens_len_from_label(sens_tsl);
allocsize += sens_len;
}
}
@@ -3268,10 +3166,10 @@ esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
mutex_exit(&ipss->ipsec_alg_lock);
- if (sens_cr != NULL) {
+ if (sens_tsl != NULL) {
sens = (sadb_sens_t *)nextext;
- sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
- sens_cr, sens_len);
+ sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY,
+ sens_tsl, sens_len);
nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
}
@@ -3336,40 +3234,61 @@ ipsecesp_algs_changed(netstack_t *ns)
/*
* Stub function that taskq_dispatch() invokes to take the mblk (in arg)
- * and put() it into AH and STREAMS again.
+ * and send() it into ESP and IP again.
*/
static void
inbound_task(void *arg)
{
- esph_t *esph;
- mblk_t *mp = (mblk_t *)arg;
- ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr;
- netstack_t *ns;
- ipsecesp_stack_t *espstack;
- int ipsec_rc;
-
- ns = netstack_find_by_stackid(ii->ipsec_in_stackid);
- if (ns == NULL || ns != ii->ipsec_in_ns) {
- /* Just freemsg(). */
- if (ns != NULL)
- netstack_rele(ns);
+ mblk_t *mp = (mblk_t *)arg;
+ mblk_t *async_mp;
+ ip_recv_attr_t iras;
+
+ async_mp = mp;
+ mp = async_mp->b_cont;
+ async_mp->b_cont = NULL;
+ if (!ip_recv_attr_from_mblk(async_mp, &iras)) {
+ /* The ill or ip_stack_t disappeared on us */
+ ip_drop_input("ip_recv_attr_from_mblk", mp, NULL);
freemsg(mp);
- return;
+ goto done;
}
- espstack = ns->netstack_ipsecesp;
+ esp_inbound_restart(mp, &iras);
+done:
+ ira_cleanup(&iras, B_TRUE);
+}
+
+/*
+ * Restart ESP after the SA has been added.
+ */
+static void
+esp_inbound_restart(mblk_t *mp, ip_recv_attr_t *ira)
+{
+ esph_t *esph;
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
esp2dbg(espstack, ("in ESP inbound_task"));
ASSERT(espstack != NULL);
- esph = ipsec_inbound_esp_sa(mp, ns);
- if (esph != NULL) {
- ASSERT(ii->ipsec_in_esp_sa != NULL);
- ipsec_rc = ii->ipsec_in_esp_sa->ipsa_input_func(mp, esph);
- if (ipsec_rc == IPSEC_STATUS_SUCCESS)
- ip_fanout_proto_again(mp, NULL, NULL, NULL);
+ mp = ipsec_inbound_esp_sa(mp, ira, &esph);
+ if (mp == NULL)
+ return;
+
+ ASSERT(esph != NULL);
+ ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE);
+ ASSERT(ira->ira_ipsec_esp_sa != NULL);
+
+ mp = ira->ira_ipsec_esp_sa->ipsa_input_func(mp, esph, ira);
+ if (mp == NULL) {
+ /*
+ * Either it failed or is pending. In the former case
+ * ipIfStatsInDiscards was increased.
+ */
+ return;
}
- netstack_rele(ns);
+
+ ip_input_post_ipsec(mp, ira);
}
/*
@@ -3533,17 +3452,21 @@ esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
if (larval != NULL)
lpkt = sadb_clear_lpkt(larval);
- rc = sadb_common_add(espstack->esp_sadb.s_ip_q, espstack->esp_pfkey_q,
+ rc = sadb_common_add(espstack->esp_pfkey_q,
mp, samsg, ksi, primary, secondary, larval, clone, is_inbound,
diagnostic, espstack->ipsecesp_netstack, &espstack->esp_sadb);
- if (rc == 0 && lpkt != NULL)
- rc = !taskq_dispatch(esp_taskq, inbound_task, lpkt, TQ_NOSLEEP);
-
- if (rc != 0) {
- ip_drop_packet(lpkt, B_TRUE, NULL, NULL,
- DROPPER(ipss, ipds_sadb_inlarval_timeout),
- &espstack->esp_dropper);
+ if (lpkt != NULL) {
+ if (rc == 0) {
+ rc = !taskq_dispatch(esp_taskq, inbound_task,
+ lpkt, TQ_NOSLEEP);
+ }
+ if (rc != 0) {
+ lpkt = ip_recv_attr_free_mblk(lpkt);
+ ip_drop_packet(lpkt, B_TRUE, NULL,
+ DROPPER(ipss, ipds_sadb_inlarval_timeout),
+ &espstack->esp_dropper);
+ }
}
/*
@@ -3551,45 +3474,78 @@ esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
* esp_outbound() calls?
*/
+ /* Handle the packets queued waiting for the SA */
while (acq_msgs != NULL) {
- mblk_t *mp = acq_msgs;
+ mblk_t *asyncmp;
+ mblk_t *data_mp;
+ ip_xmit_attr_t ixas;
+ ill_t *ill;
+ asyncmp = acq_msgs;
acq_msgs = acq_msgs->b_next;
- mp->b_next = NULL;
- if (rc == 0) {
- if (ipsec_outbound_sa(mp, IPPROTO_ESP)) {
- ((ipsec_out_t *)(mp->b_rptr))->
- ipsec_out_esp_done = B_TRUE;
- if (esp_outbound(mp) == IPSEC_STATUS_SUCCESS) {
- ipha_t *ipha;
-
- /* do AH processing if needed */
- if (!esp_do_outbound_ah(mp))
- continue;
-
- ipha = (ipha_t *)mp->b_cont->b_rptr;
-
- /* finish IPsec processing */
- if (IPH_HDR_VERSION(ipha) ==
- IP_VERSION) {
- ip_wput_ipsec_out(NULL, mp,
- ipha, NULL, NULL);
- } else {
- ip6_t *ip6h = (ip6_t *)ipha;
- ip_wput_ipsec_out_v6(NULL,
- mp, ip6h, NULL, NULL);
- }
- }
- continue;
- }
+ asyncmp->b_next = NULL;
+
+ /*
+ * Extract the ip_xmit_attr_t from the first mblk.
+ * Verifies that the netstack and ill is still around; could
+ * have vanished while iked was doing its work.
+ * On succesful return we have a nce_t and the ill/ipst can't
+ * disappear until we do the nce_refrele in ixa_cleanup.
+ */
+ data_mp = asyncmp->b_cont;
+ asyncmp->b_cont = NULL;
+ if (!ip_xmit_attr_from_mblk(asyncmp, &ixas)) {
+ ESP_BUMP_STAT(espstack, out_discards);
+ ip_drop_packet(data_mp, B_FALSE, NULL,
+ DROPPER(ipss, ipds_sadb_acquire_timeout),
+ &espstack->esp_dropper);
+ } else if (rc != 0) {
+ ill = ixas.ixa_nce->nce_ill;
+ ESP_BUMP_STAT(espstack, out_discards);
+ ip_drop_packet(data_mp, B_FALSE, ill,
+ DROPPER(ipss, ipds_sadb_acquire_timeout),
+ &espstack->esp_dropper);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ } else {
+ esp_outbound_finish(data_mp, &ixas);
}
+ ixa_cleanup(&ixas);
+ }
+
+ return (rc);
+}
+
+/*
+ * Process one of the queued messages (from ipsacq_mp) once the SA
+ * has been added.
+ */
+static void
+esp_outbound_finish(mblk_t *data_mp, ip_xmit_attr_t *ixa)
+{
+ netstack_t *ns = ixa->ixa_ipst->ips_netstack;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
+ ill_t *ill = ixa->ixa_nce->nce_ill;
+
+ if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_ESP)) {
ESP_BUMP_STAT(espstack, out_discards);
- ip_drop_packet(mp, B_FALSE, NULL, NULL,
+ ip_drop_packet(data_mp, B_FALSE, ill,
DROPPER(ipss, ipds_sadb_acquire_timeout),
&espstack->esp_dropper);
+ BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards);
+ return;
}
- return (rc);
+ data_mp = esp_outbound(data_mp, ixa);
+ if (data_mp == NULL)
+ return;
+
+ /* do AH processing if needed */
+ data_mp = esp_do_outbound_ah(data_mp, ixa);
+ if (data_mp == NULL)
+ return;
+
+ (void) ip_output_post_ipsec(data_mp, ixa);
}
/*
@@ -3674,11 +3630,13 @@ esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
return (EINVAL);
}
+#ifndef IPSEC_LATENCY_TEST
if (assoc->sadb_sa_encrypt == SADB_EALG_NULL &&
assoc->sadb_sa_auth == SADB_AALG_NONE) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG;
return (EINVAL);
}
+#endif
if (assoc->sadb_sa_flags & ~espstack->esp_sadb.s_addflags) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
@@ -3734,7 +3692,11 @@ esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns)
/*
* First locate the authentication algorithm.
*/
+#ifdef IPSEC_LATENCY_TEST
+ if (akey != NULL && assoc->sadb_sa_auth != SADB_AALG_NONE) {
+#else
if (akey != NULL) {
+#endif
ipsec_alginfo_t *aalg;
aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH]
@@ -3883,7 +3845,7 @@ esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic,
return (sadb_purge_sa(mp, ksi,
(sin->sin_family == AF_INET6) ? &espstack->esp_sadb.s_v6 :
&espstack->esp_sadb.s_v4, diagnostic,
- espstack->esp_pfkey_q, espstack->esp_sadb.s_ip_q));
+ espstack->esp_pfkey_q));
}
return (sadb_delget_sa(mp, ksi, &espstack->esp_sadb, diagnostic,
@@ -4024,7 +3986,7 @@ esp_parse_pfkey(mblk_t *mp, ipsecesp_stack_t *espstack)
* Keysock takes care of the PF_KEY bookkeeping for this.
*/
if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
- ksi->ks_in_serial, espstack, mp)) {
+ ksi->ks_in_serial, espstack, msg_getcred(mp, NULL))) {
freemsg(mp);
} else {
/*
@@ -4109,8 +4071,7 @@ esp_keysock_no_socket(mblk_t *mp, ipsecesp_stack_t *espstack)
samsg->sadb_msg_errno = kse->ks_err_errno;
samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg));
/*
- * Use the write-side of the esp_pfkey_q, in case there is
- * no esp_sadb.s_ip_q.
+ * Use the write-side of the esp_pfkey_q
*/
sadb_in_acquire(samsg, &espstack->esp_sadb,
WR(espstack->esp_pfkey_q), espstack->ipsecesp_netstack);
@@ -4197,236 +4158,23 @@ ipsecesp_wput(queue_t *q, mblk_t *mp)
}
/*
- * Process an outbound ESP packet that can be accelerated by a IPsec
- * hardware acceleration capable Provider.
- * The caller already inserted and initialized the ESP header.
- * This function allocates a tagging M_CTL, and adds room at the end
- * of the packet to hold the ICV if authentication is needed.
- *
- * On success returns B_TRUE, on failure returns B_FALSE and frees the
- * mblk chain ipsec_out.
- */
-static ipsec_status_t
-esp_outbound_accelerated(mblk_t *ipsec_out, uint_t icv_len)
-{
- ipsec_out_t *io;
- mblk_t *lastmp;
- netstack_t *ns;
- ipsecesp_stack_t *espstack;
- ipsec_stack_t *ipss;
-
- io = (ipsec_out_t *)ipsec_out->b_rptr;
- ns = io->ipsec_out_ns;
- espstack = ns->netstack_ipsecesp;
- ipss = ns->netstack_ipsec;
-
- ESP_BUMP_STAT(espstack, out_accelerated);
-
- /* mark packet as being accelerated in IPSEC_OUT */
- ASSERT(io->ipsec_out_accelerated == B_FALSE);
- io->ipsec_out_accelerated = B_TRUE;
-
- /*
- * add room at the end of the packet for the ICV if needed
- */
- if (icv_len > 0) {
- /* go to last mblk */
- lastmp = ipsec_out; /* For following while loop. */
- do {
- lastmp = lastmp->b_cont;
- } while (lastmp->b_cont != NULL);
-
- /* if not enough available room, allocate new mblk */
- if ((lastmp->b_wptr + icv_len) > lastmp->b_datap->db_lim) {
- lastmp->b_cont = allocb(icv_len, BPRI_HI);
- if (lastmp->b_cont == NULL) {
- ESP_BUMP_STAT(espstack, out_discards);
- ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL,
- DROPPER(ipss, ipds_esp_nomem),
- &espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
- }
- lastmp = lastmp->b_cont;
- }
- lastmp->b_wptr += icv_len;
- }
-
- return (IPSEC_STATUS_SUCCESS);
-}
-
-/*
- * Process an inbound accelerated ESP packet.
- * On success returns B_TRUE, on failure returns B_FALSE and frees the
- * mblk chain ipsec_in.
- */
-static ipsec_status_t
-esp_inbound_accelerated(mblk_t *ipsec_in, mblk_t *data_mp, boolean_t isv4,
- ipsa_t *assoc)
-{
- ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr;
- mblk_t *hada_mp;
- uint32_t icv_len = 0;
- da_ipsec_t *hada;
- ipha_t *ipha;
- ip6_t *ip6h;
- kstat_named_t *counter;
- netstack_t *ns = ii->ipsec_in_ns;
- ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
- ipsec_stack_t *ipss = ns->netstack_ipsec;
-
- ESP_BUMP_STAT(espstack, in_accelerated);
-
- hada_mp = ii->ipsec_in_da;
- ASSERT(hada_mp != NULL);
- hada = (da_ipsec_t *)hada_mp->b_rptr;
-
- /*
- * We only support one level of decapsulation in hardware, so
- * nuke the pointer.
- */
- ii->ipsec_in_da = NULL;
- ii->ipsec_in_accelerated = B_FALSE;
-
- if (assoc->ipsa_auth_alg != IPSA_AALG_NONE) {
- /*
- * ESP with authentication. We expect the Provider to have
- * computed the ICV and placed it in the hardware acceleration
- * data attributes.
- *
- * Extract ICV length from attributes M_CTL and sanity check
- * its value. We allow the mblk to be smaller than da_ipsec_t
- * for a small ICV, as long as the entire ICV fits within the
- * mblk.
- *
- * Also ensures that the ICV length computed by Provider
- * corresponds to the ICV length of the agorithm specified by
- * the SA.
- */
- icv_len = hada->da_icv_len;
- if ((icv_len != assoc->ipsa_mac_len) ||
- (icv_len > DA_ICV_MAX_LEN) || (MBLKL(hada_mp) <
- (sizeof (da_ipsec_t) - DA_ICV_MAX_LEN + icv_len))) {
- esp0dbg(("esp_inbound_accelerated: "
- "ICV len (%u) incorrect or mblk too small (%u)\n",
- icv_len, (uint32_t)(MBLKL(hada_mp))));
- counter = DROPPER(ipss, ipds_esp_bad_auth);
- goto esp_in_discard;
- }
- }
-
- /* get pointers to IP header */
- if (isv4) {
- ipha = (ipha_t *)data_mp->b_rptr;
- } else {
- ip6h = (ip6_t *)data_mp->b_rptr;
- }
-
- /*
- * Compare ICV in ESP packet vs ICV computed by adapter.
- * We also remove the ICV from the end of the packet since
- * it will no longer be needed.
- *
- * Assume that esp_inbound() already ensured that the pkt
- * was in one mblk.
- */
- ASSERT(data_mp->b_cont == NULL);
- data_mp->b_wptr -= icv_len;
- /* adjust IP header */
- if (isv4)
- ipha->ipha_length = htons(ntohs(ipha->ipha_length) - icv_len);
- else
- ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - icv_len);
- if (icv_len && bcmp(hada->da_icv, data_mp->b_wptr, icv_len)) {
- int af;
- void *addr;
-
- if (isv4) {
- addr = &ipha->ipha_dst;
- af = AF_INET;
- } else {
- addr = &ip6h->ip6_dst;
- af = AF_INET6;
- }
-
- /*
- * Log the event. Don't print to the console, block
- * potential denial-of-service attack.
- */
- ESP_BUMP_STAT(espstack, bad_auth);
- ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
- "ESP Authentication failed spi %x, dst_addr %s",
- assoc->ipsa_spi, addr, af, espstack->ipsecesp_netstack);
- counter = DROPPER(ipss, ipds_esp_bad_auth);
- goto esp_in_discard;
- }
-
- esp3dbg(espstack, ("esp_inbound_accelerated: ESP authentication "
- "succeeded, checking replay\n"));
-
- ipsec_in->b_cont = data_mp;
-
- /*
- * Remove ESP header and padding from packet.
- */
- if (!esp_strip_header(data_mp, ii->ipsec_in_v4, assoc->ipsa_iv_len,
- &counter, espstack)) {
- esp1dbg(espstack, ("esp_inbound_accelerated: "
- "esp_strip_header() failed\n"));
- goto esp_in_discard;
- }
-
- freeb(hada_mp);
-
- if (is_system_labeled() && (assoc->ipsa_cred != NULL))
- mblk_setcred(data_mp, assoc->ipsa_cred, NOPID);
-
- /*
- * Account for usage..
- */
- if (!esp_age_bytes(assoc, msgdsize(data_mp), B_TRUE)) {
- /* The ipsa has hit hard expiration, LOG and AUDIT. */
- ESP_BUMP_STAT(espstack, bytes_expired);
- IP_ESP_BUMP_STAT(ipss, in_discards);
- ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN,
- "ESP association 0x%x, dst %s had bytes expire.\n",
- assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam,
- espstack->ipsecesp_netstack);
- ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL,
- DROPPER(ipss, ipds_esp_bytes_expire),
- &espstack->esp_dropper);
- return (IPSEC_STATUS_FAILED);
- }
-
- /* done processing the packet */
- return (IPSEC_STATUS_SUCCESS);
-
-esp_in_discard:
- IP_ESP_BUMP_STAT(ipss, in_discards);
- freeb(hada_mp);
-
- ipsec_in->b_cont = data_mp; /* For ip_drop_packet()'s sake... */
- ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter,
- &espstack->esp_dropper);
-
- return (IPSEC_STATUS_FAILED);
-}
-
-/*
* Wrapper to allow IP to trigger an ESP association failure message
* during inbound SA selection.
*/
void
ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt,
- uint32_t spi, void *addr, int af, ipsecesp_stack_t *espstack)
+ uint32_t spi, void *addr, int af, ip_recv_attr_t *ira)
{
- ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec;
+ netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack;
+ ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
+ ipsec_stack_t *ipss = ns->netstack_ipsec;
if (espstack->ipsecesp_log_unknown_spi) {
ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi,
addr, af, espstack->ipsecesp_netstack);
}
- ip_drop_packet(mp, B_TRUE, NULL, NULL,
+ ip_drop_packet(mp, B_TRUE, ira->ira_ill,
DROPPER(ipss, ipds_esp_no_sa),
&espstack->esp_dropper);
}