/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/sysmacros.h>
#include <inet/proto_set.h>
#include <inet/ipsec_info.h>
#include <inet/ipsec_impl.h>
#include <sys/isa_defs.h>
/*
* This is a transport provider for the PF_KEY key mangement socket.
* (See RFC 2367 for details.)
* Downstream messages are wrapped in a keysock consumer interface KEYSOCK_IN
* messages (see ipsec_info.h), and passed to the appropriate consumer.
* Upstream messages are generated for all open PF_KEY sockets, when
* appropriate, as well as the sender (as long as SO_USELOOPBACK is enabled)
* in reply to downstream messages.
*
* Upstream messages must be created asynchronously for the following
* situations:
*
* 1.) A keysock consumer requires an SA, and there is currently none.
* 2.) An SA expires, either hard or soft lifetime.
* 3.) Other events a consumer deems fit.
*
* The MT model of this is PERMOD, with shared put procedures. Two types of
* messages, SADB_FLUSH and SADB_DUMP, need to lock down the perimeter to send
* down the *multiple* messages they create.
*/
/* Default structure copied into T_INFO_ACK messages (from rts.c...) */
T_INFINITE, /* TSDU_size. Maximum size messages. */
T_INVALID, /* ETSDU_size. No expedited data. */
T_INVALID, /* CDATA_size. No connect data. */
T_INVALID, /* DDATA_size. No disconnect data. */
0, /* ADDR_size. */
0, /* OPT_size. No user-settable options */
64 * 1024, /* TIDU_size. keysock allows maximum size messages. */
T_COTS, /* SERV_type. keysock supports connection oriented. */
TS_UNBND, /* CURRENT_state. This is set from keysock_state. */
(XPG4_1) /* Provider flags */
};
/* Named Dispatch Parameter Management Structure */
typedef struct keysockparam_s {
char *keysock_param_name;
/*
* Table of NDD variables supported by keysock. These are loaded into
* keysock_g_nd in keysock_init_nd.
*/
/* min max value name */
{ 4096, 65536, 8192, "keysock_xmit_hiwat"},
{ 0, 65536, 1024, "keysock_xmit_lowat"},
{ 4096, 65536, 8192, "keysock_recv_hiwat"},
{ 65536, 1024*1024*1024, 256*1024, "keysock_max_buf"},
{ 0, 3, 0, "keysock_debug"},
};
/* NOTE: != 0 instead of > 0 so lint doesn't complain. */
static int keysock_close(queue_t *);
static void keysock_rsrv(queue_t *);
};
};
};
};
extern struct modlinkage *keysock_modlp;
/*
* Plumb IPsec.
*
* NOTE: New "default" modules will need to be loaded here if needed before
* boot time.
*/
/* Keep these in global space to keep the lint from complaining. */
/*
* Load the other ipsec modules and plumb them together.
*/
int
{
int err = 0;
#ifdef NS_DEBUG
(void) printf("keysock_plumb_ipsec(%d)\n",
#endif
/*
*
* I do this separately from the actual plumbing in case this function
* ever gets called from a diskless boot before the root filesystem is
* up. I don't have to worry about "keysock" because, well, if I'm
* here, keysock must've loaded successfully.
*/
ks0dbg(("IPsec: AH failed to attach.\n"));
goto bail;
}
ks0dbg(("IPsec: ESP failed to attach.\n"));
}
/*
* Set up the IP streams for AH and ESP, as well as tacking keysock
* on top of them. Assume keysock has set the autopushes up already.
*/
/* Open IP. */
if (err) {
ks0dbg(("IPsec: lid_ident_from_mod failed (err %d).\n",
err));
goto bail;
}
if (err) {
goto bail;
}
if (err) {
goto bail;
}
if (err) {
ks0dbg(("IPsec: Push of KEYSOCK onto AH failed (err %d).\n",
err));
goto bail;
}
if (err) {
goto bail;
}
if (esp_present) {
if (err) {
goto bail;
}
if (err) {
ks0dbg(("IPsec: "
"Push of KEYSOCK onto ESP failed (err %d).\n",
err));
goto bail;
}
if (err) {
ks0dbg(("IPsec: "
goto bail;
}
}
bail:
}
#ifdef NS_DEBUG
(void) printf("keysock_plumb_ipsec -> %d\n",
#endif
return (err);
}
/* ARGSUSED */
static int
queue_t *q;
{
return (0);
}
/* This routine sets an NDD variable in a keysockparam_t structure. */
/* ARGSUSED */
static int
queue_t *q;
char *value;
{
/* Convert the value from a string into a long integer. */
return (EINVAL);
/*
* Fail the request if the new value does not lie within the
* required bounds.
*/
return (EINVAL);
}
/* Set the new value */
return (0);
}
/*
* Initialize keysock at module load time
*/
keysock_ddi_init(void)
{
/*
* We want to be informed each time a stack is created or
* destroyed in the kernel, so we can maintain the
* set of keysock_stack_t's.
*/
return (B_TRUE);
}
/*
* Walk through the param array specified registering each element with the
* named dispatch handler.
*/
static boolean_t
{
ksp->keysock_param_name[0]) {
return (B_FALSE);
}
}
}
return (B_TRUE);
}
/*
* Initialize keysock for one stack instance
*/
/* ARGSUSED */
static void *
{
return (keystack);
}
/*
* Free NDD variable space, and other destructors, for keysock.
*/
void
keysock_ddi_destroy(void)
{
}
/*
* Remove one stack instance from keysock
*/
/* ARGSUSED */
static void
{
}
/*
* Close routine for keysock.
*/
static int
{
int size;
qprocsoff(q);
/* Safe assumption. */
kc->kc_sa_type));
/*
* can inspect KC_FLUSHING w/o locking down kc->kc_lock.
*/
/*
* If this decrement was the last one, send
* down the next pending one, if any.
*
* With a PERMOD perimeter, the mutexes ops aren't
* really necessary, but if we ever loosen up, we will
* have this bit covered already.
*/
if (keystack->keystack_flushdump == 0) {
/*
* consumer go away. I need to send up to the
* appropriate keysock all of the relevant
* information. Unfortunately, I don't
* have that handy.
*/
ks0dbg(("Consumer went away while flushing or"
" dumping.\n"));
}
}
size = sizeof (keysock_consumer_t);
} else {
("Driver close, PF_KEY socket is going away.\n"));
1);
}
/* Now I'm free. */
return (0);
}
/*
* Open routine for keysock.
*/
/* ARGSUSED */
static int
{
/* Privilege debugging will log the error */
return (EPERM);
}
return (0); /* Re-open of an already open instance. */
keystack->keystack_plumbed = 0;
#ifdef NS_DEBUG
printf("keysock_open(%d) - plumb\n",
#endif
/*
* Don't worry about ipsec_failure being true here.
* (See ip.c). An open of keysock should try and force
* the issue. Maybe it was a transient failure.
*/
}
/* Initialize keysock_consumer state here. */
return (ENOMEM);
}
qprocson(q);
/*
* Send down initial message to whatever I was pushed on top
* of asking for its consumer type. The reply will set it.
*/
/* Allocate it. */
"keysock_open: Cannot allocate KEYSOCK_HELLO.\n"));
/* Do I need to set these to null? */
return (ENOMEM);
}
/* If I allocated okay, putnext to what I was pushed atop. */
} else {
/* Initialize keysock state. */
if (ksminor == 0) {
return (ENOMEM);
}
return (ENOMEM);
}
ks->keysock_rq = q;
/*
* The receive hiwat is only looked at on the stream head
* queue. Store in q_hiwat in order to return on SO_RCVBUF
* getsockopts.
*/
/*
* SO_SNDBUF/SO_SNDLOWAT getsockopts.
*/
/*
* Thread keysock into the global keysock list.
*/
&ks->keysock_next;
}
qprocson(q);
(void) proto_set_rx_hiwat(q, NULL,
/*
* Wait outside the keysock module perimeter for IPsec
* plumbing to be completed. If it fails, keysock_close()
* undoes everything we just did.
*/
if (!ipsec_loader_wait(q,
(void) keysock_close(q);
return (EPFNOSUPPORT);
}
}
return (0);
}
/* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_wput(). */
/*
* Copy relevant state bits.
*/
static void
{
}
/*
* This routine responds to T_CAPABILITY_REQ messages. It is called by
* keysock_wput. Much of the T_CAPABILITY_ACK information is copied from
* keysock_g_t_info_ack. The current state of the stream is copied from
* keysock_state.
*/
static void
{
return;
}
}
/*
* This routine responds to T_INFO_REQ messages. It is called by
* keysock_wput_other.
* Most of the T_INFO_ACK information is copied from keysock_g_t_info_ack.
* The current state of the stream is copied from keysock_state.
*/
static void
queue_t *q;
{
return;
}
/*
* keysock_err_ack. This routine creates a
* T_ERROR_ACK message and passes it
* upstream.
*/
static void
queue_t *q;
int t_error;
int sys_error;
{
}
/*
* This routine retrieves the current status of socket options.
* It returns the size of the option retrieved.
*/
/* ARGSUSED */
int
{
switch (level) {
case SOL_SOCKET:
switch (name) {
case SO_TYPE:
break;
case SO_USELOOPBACK:
break;
/*
* The following two items can be manipulated,
* but changing them should do nothing.
*/
case SO_SNDBUF:
break;
case SO_RCVBUF:
break;
}
break;
default:
return (0);
}
return (sizeof (int));
}
/*
* This routine sets socket options.
*/
/* ARGSUSED */
int
{
switch (level) {
case SOL_SOCKET:
switch (name) {
case SO_USELOOPBACK:
if (!(*i1))
break;
case SO_SNDBUF:
break;
case SO_RCVBUF:
} else {
}
break;
default:
}
break;
default:
}
return (errno);
}
/*
* Handle STREAMS messages.
*/
static void
{
int error;
case M_PROTO:
case M_PCPROTO:
"keysock_wput_other: Not big enough M_PROTO\n"));
return;
}
case T_CAPABILITY_REQ:
keysock_capability_req(q, mp);
break;
case T_INFO_REQ:
keysock_info_req(q, mp);
break;
case T_SVR4_OPTMGMT_REQ:
case T_OPTMGMT_REQ:
/*
* All Solaris components should pass a db_credp
* for this TPI message, hence we ASSERT.
* But in case there is some other M_PROTO that looks
* like a TPI message sent by some other kernel
* component, we check and return an error.
*/
return;
}
} else {
}
break;
case T_DATA_REQ:
case T_EXDATA_REQ:
case T_ORDREL_REQ:
/* Illegal for keysock. */
break;
default:
/* Not supported by keysock. */
break;
}
return;
case M_IOCTL:
case ND_SET:
case ND_GET:
return;
} else
/* FALLTHRU */
default:
return;
}
case M_FLUSH:
}
return;
}
/* Else FALLTHRU */
}
/* If fell through, just black-hole the message. */
}
/*
* Transmit a PF_KEY error message to the instance either pointed to
* by ks, the instance with serial number serial, or more, depending.
*
* The faulty message (or a reasonable facsimile thereof) is in mp.
* This function will free mp or recycle it for delivery, thereby causing
* the stream head to free it.
*/
static void
{
/*
* Strip out extension headers.
*/
}
/*
* Pass down a message to a consumer. Wrap it in KEYSOCK_IN, and copy
* in the extv if passed in.
*/
static void
{
int i;
if (flushmsg) {
ks0dbg((
/* If this is true, I hold the perimeter. */
}
return;
}
for (i = 0; i <= SADB_EXT_MAX; i++)
/*
* Find the appropriate consumer where the message is passed down.
*/
if (flushmsg) {
ks0dbg((
/* If this is true, I hold the perimeter. */
}
return;
}
/*
* NOTE: There used to be code in here to spin while a flush or
* dump finished. Keysock now assumes that consumers have enough
* MT-savviness to deal with that.
*/
/*
* Current consumers (AH and ESP) are guaranteed to return a
* FLUSH or DUMP message back, so when we reach here, we don't
* have to worry about keysock_flushdumps.
*/
}
/*
* High-level reality checking of extensions.
*/
static boolean_t
{
int i;
char *idstr;
switch (ext->sadb_ext_type) {
case SADB_EXT_ADDRESS_SRC:
case SADB_EXT_ADDRESS_DST:
/* Check for at least enough addtl length for a sockaddr. */
return (B_FALSE);
break;
case SADB_EXT_LIFETIME_HARD:
case SADB_EXT_LIFETIME_SOFT:
return (B_FALSE);
break;
case SADB_EXT_SPIRANGE:
/* See if the SPI range is legit. */
return (B_FALSE);
break;
case SADB_EXT_KEY_AUTH:
case SADB_EXT_KEY_ENCRYPT:
/* Key length check. */
return (B_FALSE);
/*
* Check to see if the key length (in bits) is less than the
* extension length (in 8-bits words).
*/
return (B_FALSE);
}
/* All-zeroes key check. */
for (i = 0;
i++)
if (lp[i] != 0)
break; /* Out of for loop. */
/* If finished the loop naturally, it's an all zero key. */
if (lp[i] == 0)
return (B_FALSE);
break;
case SADB_EXT_IDENTITY_SRC:
case SADB_EXT_IDENTITY_DST:
/*
* Make sure the strings in these identities are
* null-terminated. RFC 2367 underspecified how to handle
* such a case. I "proactively" null-terminate the string
* at the last byte if it's not terminated sooner.
*/
i -= sizeof (sadb_ident_t);
while (*idstr != '\0' && i > 0) {
i--;
idstr++;
}
if (i == 0) {
/*
* I.e., if the bozo user didn't NULL-terminate the
* string...
*/
idstr--;
*idstr = '\0';
}
break;
}
return (B_TRUE); /* For now... */
}
/* Return values for keysock_get_ext(). */
#define KGE_OK 0
/*
* Parse basic extension headers and return in the passed-in pointer vector.
* Return values include:
*
* KGE_OK Everything's nice and parsed out.
* If there are no extensions, place NULL in extv[0].
* KGE_DUP There is a duplicate extension.
* First instance in appropriate bin. First duplicate in
* extv[0].
* KGE_UNK Unknown extension type encountered. extv[0] contains
* unknown header.
* KGE_LEN Extension length error.
* KGE_CHK High-level reality check failed on specific extension.
*
* My apologies for some of the pointer arithmetic in here. I'm thinking
* like an assembly programmer, yet trying to make the compiler happy.
*/
static int
{
/* Use extv[0] as the "current working pointer". */
/* Check for unknown headers. */
if (extv[0]->sadb_ext_type == 0 ||
return (KGE_UNK);
/*
* Check length. Use uint64_t because extlen is in units
* of 64-bit words. If length goes beyond the msgsize,
* return an error. (Zero length also qualifies here.)
*/
if (extv[0]->sadb_ext_len == 0 ||
return (KGE_LEN);
/* Check for redundant headers. */
return (KGE_DUP);
/*
* Reality check the extension if possible at the keysock
* level.
*/
return (KGE_CHK);
/* If I make it here, assign the appropriate bin. */
/* Advance pointer (See above for uint64_t ptr reasoning.) */
extv[0] = (sadb_ext_t *)
}
/* Everything's cool. */
/*
* If extv[0] == NULL, then there are no extension headers in this
* message. Ensure that this is the case.
*/
return (KGE_OK);
}
/*
* qwriter() callback to handle flushes and dumps. This routine will hold
* the inner perimeter.
*/
void
{
/*
* I am guaranteed this will work. I did the work in keysock_parse()
* already.
*/
keystack);
/*
* I hold the perimeter, therefore I don't need to use atomic ops.
*/
if (keystack->keystack_flushdump != 0) {
/* XXX Should I instead use EBUSY? */
/* XXX Or is there a way to queue these up? */
return;
}
start = 0;
} else {
}
/*
* Fill up keysock_flushdump with the number of outstanding dumps
*/
/*
* Okay, I hold the perimeter. Eventually keysock_flushdump will
* contain the number of consumers with outstanding flush operations.
*
* SO, here's the plan:
* * For each relevant consumer (Might be one, might be all)
* * Twiddle on the FLUSHING flag.
*
* keysock_flushdump. When I decrement it to 0, I will pass the
* pass down the right SA type to the consumer (either its own, or
* that of UNSPEC), the right one will be reflected from each consumer,
* and accordingly back to the socket.
*/
ks0dbg(("SADB_FLUSH copymsg() failed.\n"));
/*
* Error? And what about outstanding
* flushes? Oh, yeah, they get sucked up and
* the counter is decremented. Consumers
* (see keysock_passdown()) are guaranteed
* to deliver back a flush request, even if
* it's an error.
*/
return;
}
/*
* Because my entry conditions are met above, the
* following assertion should hold true.
*/
KC_FLUSHING) == 0);
/* Always increment the number of flushes... */
/* Guaranteed to return a message. */
/*
* In case where start == finish, and there's no
* consumer, should we force an error? Yes.
*/
return;
}
}
if (keystack->keystack_flushdump == 0) {
/*
* There were no consumers at all for this message.
* XXX For now return ESRCH.
*/
} else {
/* Otherwise, free the original message. */
}
}
/*
* Get the right diagnostic for a duplicate. Should probably use a static
* table lookup.
*/
int
{
int rc = 0;
switch (ext_type) {
case SADB_EXT_ADDRESS_SRC:
break;
case SADB_EXT_ADDRESS_DST:
break;
break;
break;
case SADB_EXT_SA:
break;
case SADB_EXT_SPIRANGE:
break;
case SADB_EXT_KEY_AUTH:
break;
case SADB_EXT_KEY_ENCRYPT:
break;
}
return (rc);
}
/*
* Get the right diagnostic for a reality check failure. Should probably use
* a static table lookup.
*/
int
{
int rc = 0;
switch (ext_type) {
case SADB_EXT_ADDRESS_SRC:
break;
case SADB_EXT_ADDRESS_DST:
break;
break;
break;
case SADB_EXT_SA:
break;
case SADB_EXT_SPIRANGE:
break;
case SADB_EXT_KEY_AUTH:
break;
case SADB_EXT_KEY_ENCRYPT:
break;
}
return (rc);
}
/*
* Keysock massaging of an inverse ACQUIRE. Consult policy,
* and construct an appropriate response.
*/
static void
{
/*
* Reality check things...
*/
return;
}
return;
}
return;
}
return;
}
} else {
}
}
/*
* Spew an extended REGISTER down to the relevant consumers.
*/
static void
{
}
} else {
return;
}
/*
* Since we've made it here, keysock_get_ext will work!
*/
(void) keysock_get_ext(downextv,
keystack);
B_FALSE);
++satypes;
}
}
/*
* Set global to indicate we prefer an extended ACQUIRE.
*/
}
static void
{
start = 0;
return;
}
}
}
}
/*
* Handle PF_KEY messages.
*/
static void
{
/* Make sure I'm a PF_KEY socket. (i.e. nothing's below me) */
samsg->sadb_msg_type));
/*
* Message len incorrect w.r.t. actual size. Send an error
* (EMSGSIZE). It may be necessary to massage things a
* bit. For example, if the sadb_msg_type is hosed,
* I need to set it to SADB_RESERVED to get delivery to
* do the right thing. Then again, maybe just letting
* the error delivery do the right thing.
*/
("mblk (%lu) and base (%d) message sizes don't jibe.\n",
return;
}
/* Get all message into one mblk. */
/*
* Something screwy happened.
*/
("keysock_parse: pullupmsg() failed.\n"));
return;
} else {
}
}
case KGE_DUP:
/* Handle duplicate extension. */
extv[0]->sadb_ext_type));
return;
case KGE_UNK:
/* Handle unknown extension. */
extv[0]->sadb_ext_type));
return;
case KGE_LEN:
/* Length error. */
("Length %d on extension type %d overrun or 0.\n",
return;
case KGE_CHK:
/* Reality check failed. */
("Reality check failed on extension type %d.\n",
extv[0]->sadb_ext_type));
return;
default:
/* Default case is no errors. */
break;
}
switch (samsg->sadb_msg_type) {
case SADB_REGISTER:
/*
* There's a semantic weirdness in that a message OTHER than
* the return REGISTER message may be passed up if I set the
* registered bit BEFORE I pass it down.
*
* SOOOO, I'll not twiddle any registered bits until I see
* the upbound REGISTER (with a serial number in it).
*/
/* Handle extended register here. */
return;
return;
}
/* FALLTHRU */
case SADB_GETSPI:
case SADB_ADD:
case SADB_UPDATE:
case SADB_X_UPDATEPAIR:
case SADB_DELETE:
case SADB_X_DELPAIR:
case SADB_GET:
/*
* Pass down to appropriate consumer.
*/
B_FALSE);
return;
case SADB_X_DELPAIR_STATE:
} else {
B_FALSE);
}
return;
case SADB_ACQUIRE:
/*
* If I _receive_ an acquire, this means I should spread it
* out to registered sockets. Unless there's an errno...
*
* Need ADDRESS, may have ID, SENS, and PROP, unless errno,
* in which case there should be NO extensions.
*
* Return to registered.
*/
if (samsg->sadb_msg_errno != 0) {
if (satype == SADB_SATYPE_UNSPEC) {
return;
}
/*
* Reassign satype based on the first
* flags that KEYSOCK_SETREG says.
*/
while (satype <= SADB_SATYPE_MAX) {
break;
satype++;
}
if (satype > SADB_SATYPE_MAX) {
return;
}
}
} else {
} else {
keystack);
}
}
return;
case SADB_EXPIRE:
/*
* If someone sends this in, then send out to all senders.
* (Save maybe ESP or AH, I have to be careful here.)
*
* Need ADDRESS, may have ID and SENS.
*
* XXX for now this is unsupported.
*/
break;
case SADB_FLUSH:
/*
* Nuke all SAs.
*
* No extensions at all. Return to all listeners.
*
* Question: Should I hold a lock here to prevent
* Answer: No. (See keysock_passdown() for details.)
*/
/*
* FLUSH messages shouldn't have extensions.
* Return EINVAL.
*/
return;
}
return;
case SADB_DUMP: /* not used by normal applications */
((msgsize >
(sizeof (sadb_msg_t) + sizeof (sadb_x_edump_t))) ||
return;
}
return;
case SADB_X_PROMISC:
/*
* Promiscuous processing message.
*/
if (samsg->sadb_msg_satype == 0)
else
keystack);
return;
case SADB_X_INVERSE_ACQUIRE:
return;
default:
samsg->sadb_msg_type));
return;
}
/* As a placeholder... */
ks0dbg(("keysock_parse(): Hit EOPNOTSUPP\n"));
}
/*
* I don't convert to ioctl()'s for IP. I am the end-all driver as far
* as PF_KEY sockets are concerned. I do some conversion, but not as much
*/
static void
{
/*
* We shouldn't get writes on a consumer instance.
* But for now, just passthru.
*/
kc->kc_sa_type));
return;
}
case M_DATA:
/*
* Silently discard.
*/
return;
case M_PROTO:
case M_PCPROTO:
/* No data after T_DATA_REQ. */
("No data after DATA_REQ.\n"));
return;
}
break; /* Out of switch. */
}
}
/* FALLTHRU */
default:
keysock_wput_other(q, mp);
return;
}
/* I now have a PF_KEY message in an M_DATA block, pointed to by mp. */
keysock_parse(q, mp);
}
/* BELOW THIS LINE ARE ROUTINES INCLUDING AND RELATED TO keysock_rput(). */
/*
* Called upon receipt of a KEYSOCK_HELLO_ACK to set up the appropriate
* state vectors.
*/
static void
{
ks0dbg((
"Hmmmm, someone closed %d before the HELLO_ACK happened.\n",
satype));
/*
* Perhaps updating the new below-me consumer with what I have
* so far would work too?
*/
} else {
/* Add new below-me consumer. */
/* Scan the keysock list. */
/*
* XXX Perhaps send an SADB_REGISTER down on
* the socket's behalf.
*/
("Socket %u registered already for "
}
}
}
}
/*
* Generate a KEYSOCK_OUT_ERR message for my consumer.
*/
static void
{
return;
}
/* Is serial necessary? */
kse->ks_err_serial = 0;
/*
* XXX What else do I need to do here w.r.t. information
* to tell the consumer what caused this error?
*
* I believe the answer is the PF_KEY ACQUIRE (or other) message
* attached in mp, which is appended at the end. I believe the
* db_ref won't matter here, because the PF_KEY message is only read
* for KEYSOCK_OUT_ERR.
*/
}
/* XXX this is a hack errno. */
/*
* Route message (pointed by mp, header in samsg) toward appropriate
* sockets. Assume the message's creator did its job correctly.
*
* This should be a function that is followed by a return in its caller.
* The compiler _should_ be able to use tail-call optimizations to make the
* large ## of parameters not a huge deal.
*/
static void
{
/* Convert mp, which is M_DATA, into an M_PROTO of type T_DATA_IND */
goto error;
}
switch (samsg->sadb_msg_type) {
case SADB_FLUSH:
case SADB_GETSPI:
case SADB_UPDATE:
case SADB_X_UPDATEPAIR:
case SADB_ADD:
case SADB_DELETE:
case SADB_X_DELPAIR:
case SADB_EXPIRE:
/*
* These are most likely replies. Don't worry about
* KEYSOCK_OUT_ERR handling. Deliver to all sockets.
*/
("Delivering normal message (%d) to all sockets.\n",
samsg->sadb_msg_type));
break;
case SADB_REGISTER:
/*
* REGISTERs come up for one of three reasons:
*
* 1.) In response to a normal SADB_REGISTER
* (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
* serial != 0)
* Deliver to normal SADB_REGISTERed sockets.
* 2.) In response to an extended REGISTER
* (samsg->sadb_msg_satype == SADB_SATYPE_UNSPEC)
* Deliver to extended REGISTERed socket.
* 3.) Spontaneous algorithm changes
* (samsg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
* serial == 0)
* Deliver to REGISTERed sockets of all sorts.
*/
/* Here because of keysock_error() call. */
break; /* Out of switch. */
}
if (satype == SADB_SATYPE_UNSPEC) {
/* REGISTER Reason #2 */
/*
* Rewhack SA type so PF_KEY socket holder knows what
* consumer generated this algorithm list.
*/
} else if (serial == 0) {
/* REGISTER Reason #3 */
} else {
/* REGISTER Reason #1 */
}
break;
case SADB_ACQUIRE:
/*
* ACQUIREs are either extended (sadb_msg_satype == 0) or
* regular (sadb_msg_satype != 0). And we're guaranteed
* that serial == 0 for an ACQUIRE.
*/
/*
* Corner case - if we send a regular ACQUIRE and there's
* extended ones registered, don't send an error down to
* consumers if nobody's listening and prematurely destroy
* their ACQUIRE record. This might be too hackish of a
* solution.
*/
err = 0;
break;
case SADB_X_PROMISC:
case SADB_X_INVERSE_ACQUIRE:
case SADB_DUMP:
case SADB_GET:
default:
/*
* Deliver to the sender and promiscuous only.
*/
samsg->sadb_msg_type));
break;
}
/* Delivery loop. */
/*
* Check special keysock-setting cases (REGISTER replies)
* here.
*/
}
/*
* NOLOOP takes precedence over PROMISC. So if you've set
* !SO_USELOOPBACK, don't expect to see any data...
*/
continue;
/*
* Messages to all, or promiscuous sockets just GET the
* message. Perform rules-type checking iff it's not for all
* listeners or the socket is in promiscuous mode.
*
* NOTE:Because of the (kc != NULL && ISREG()), make sure
* extended ACQUIREs arrive off a consumer that is
* part of the extended REGISTER set of consumers.
*/
!toall &&
continue;
"keysock_passup(): dupmsg() failed.\n"));
}
/*
* At this point, we can deliver or attempt to deliver
* this message. We're free of obligation to report
* no listening PF_KEY sockets. So set err to 0.
*/
err = 0;
/*
* See if we canputnext(), as well as see if the message
* needs to be queued if we can't.
*/
if (persistent) {
"keysock_passup: putq failed.\n"));
} else {
continue;
}
}
continue;
}
/*
* Unlike the specific keysock instance case, this
* will only hit for listeners, so we will only
* putnext() if we can.
*/
break; /* out of for loop. */
}
/*
* Generate KEYSOCK_OUT_ERR for consumer.
* Basically, I send this back if I have not been able to
* transmit (for whatever reason)
*/
("keysock_passup(): No registered of type %d.\n",
satype));
}
/*
* Do a copymsg() because people who get
* KEYSOCK_OUT_ERR may alter the message contents.
*/
("keysock_passup: copymsg() failed.\n"));
}
}
}
/*
* XXX Blank the message somehow. This is difficult because we don't
* know at this point if the message has db_ref > 1, etc.
*
* Optimally, keysock messages containing actual keying material would
* be allocated with esballoc(), with a zeroing free function.
*/
}
/*
* Keysock's read service procedure is there only for PF_KEY reply
* messages that really need to reach the top.
*/
static void
{
if (canputnext(q)) {
} else {
return;
}
}
}
/*
* The read procedure should only be invoked by a keysock consumer, like
* ESP, AH, etc. I should only see KEYSOCK_OUT and KEYSOCK_HELLO_ACK
* messages on my read queues.
*/
static void
{
/* Make sure I'm a consumer instance. (i.e. something's below me) */
/*
* Keysock should only see keysock consumer interface
* messages (see ipsec_info.h) on its read procedure.
* To be robust, however, putnext() up so the STREAM head can
* deal with it appropriately.
*/
("Hmmm, a non M_CTL (%d, 0x%x) on keysock_rput.\n",
return;
}
switch (ii->ipsec_info_type) {
case KEYSOCK_OUT:
/*
* A consumer needs to pass a response message or an ACQUIRE
* UP. I assume that the consumer has done the right
* thing w.r.t. message creation, etc.
*/
/*
* If I'm an end-of-FLUSH or an end-of-DUMP marker...
*/
/* Am I flushing? */
if (samsg->sadb_msg_errno != 0)
/*
* Lower the atomic "flushing" count. If it's
* the last one, send up the end-of-{FLUSH,DUMP} to
* the appropriate PF_KEY socket.
*/
0) {
return;
}
samsg->sadb_msg_seq = 0;
}
}
return;
case KEYSOCK_HELLO_ACK:
/* Aha, now we can link in the consumer! */
return;
default:
ii->ipsec_info_type));
}
}
/*
* So we can avoid external linking problems....
*/
{
return (keystack->keystack_num_extended != 0);
}
{
}