spdsock.c revision 6a1829206270722d52261c82871dbf78c72732b4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#define _SUN_TPI_VERSION 2
#include <net/pfpolicy.h>
#include <inet/ipsec_info.h>
#include <inet/ipsec_impl.h>
#include <sys/isa_defs.h>
/*
* This is a transport provider for the PF_POLICY IPsec policy
* management socket, which provides a management interface into the
* SPD, allowing policy rules to be added, deleted, and queried.
*
* This effectively replaces the old private SIOC*IPSECONFIG ioctls
* with an extensible interface which will hopefully be public some
* day.
*
* See <net/pfpolicy.h> for more details on the protocol.
*
* SPD; see ipsec_impl.h for the policy data structures and spd.c for
* the code which maintains them.
*
* The MT model of this is QPAIR with the addition of some explicit
* locking to protect system-wide policy data structures.
*/
/* Default structure copied into T_INFO_ACK messages (from rts.c...) */
static struct T_info_ack spdsock_g_t_info_ack = {
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. spdsock allows maximum size messages. */
T_COTS, /* SERV_type. spdsock supports connection oriented. */
TS_UNBND, /* CURRENT_state. This is set from spdsock_state. */
(XPG4_1) /* Provider flags */
};
/* Named Dispatch Parameter Management Structure */
typedef struct spdsockpparam_s {
char *spdsock_param_name;
/*
* Table of NDD variables supported by spdsock. These are loaded into
* spdsock_g_nd in spdsock_init_nd.
*/
static spdsockparam_t spdsock_param_arr[] = {
/* min max value name */
{ 4096, 65536, 8192, "spdsock_xmit_hiwat"},
{ 0, 65536, 1024, "spdsock_xmit_lowat"},
{ 4096, 65536, 8192, "spdsock_recv_hiwat"},
{ 65536, 1024*1024*1024, 256*1024, "spdsock_max_buf"},
{ 0, 3, 0, "spdsock_debug"},
};
/*
* To save algorithm update messages that are processed only after IPsec
* is loaded.
*/
static kmutex_t spdsock_alg_lock;
/* NOTE: != 0 instead of > 0 so lint doesn't complain. */
static IDP spdsock_g_nd;
static int spdsock_close(queue_t *);
static void spdsock_wsrv(queue_t *);
static void spdsock_rsrv(queue_t *);
static void spdsock_loadcheck(void *);
static void spdsock_merge_algs(void);
static struct module_info info = {
};
};
};
struct streamtab spdsockinfo = {
};
/* mapping from alg type to protocol number, as per RFC 2407 */
};
/* mapping from kernel exec mode to spdsock exec mode */
};
/* ARGSUSED */
static int
queue_t *q;
{
return (0);
}
/* This routine sets an NDD variable in a spdsockparam_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);
}
spdsock_ddi_init(void)
{
if (!spdsock_g_nd) {
if (!nd_load(&spdsock_g_nd,
return (B_FALSE);
}
}
}
}
return (B_TRUE);
}
void
spdsock_ddi_destroy(void)
{
}
/*
* NOTE: large quantities of this should be shared with keysock.
* Would be nice to combine some of this into a common module, but
* not possible given time pressures.
*/
/*
* High-level reality checking of extensions.
*/
/* ARGSUSED */ /* XXX */
static boolean_t
{
return (B_TRUE); /* For now... */
}
/* Return values for spdsock_get_ext(). */
#define KGE_OK 0
#define KGE_DUP 1
#define KGE_UNK 2
#define KGE_LEN 3
#define KGE_CHK 4
/*
* 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]->spd_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]->spd_ext_len == 0 ||
return (KGE_LEN);
/* Check for redundant headers. */
return (KGE_DUP);
/*
* Reality check the extension if possible at the spdsock
* level.
*/
return (KGE_CHK);
/* If I make it here, assign the appropriate bin. */
/* Advance pointer (See above for uint64_t ptr reasoning.) */
}
/* 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);
}
static const int bad_ext_diag[] = {
};
static const int dup_ext_diag[] = {
};
/*
* Transmit a PF_POLICY 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.
*/
}
static void
{
}
static void
{
}
/* ARGSUSED */
static void
{
}
static boolean_t
{
}
struct spd_portrange *pr =
}
struct spd_portrange *pr =
}
struct spd_typecode *tc=
else
else
}
}
struct spd_address *ap = \
IPV6_ADDR_LEN : IP_ADDR_LEN; \
return (B_FALSE); \
} \
}
return (B_FALSE);
}
return (B_TRUE);
}
static boolean_t
{
switch (type) {
case SPD_ACTTYPE_DROP:
return (B_TRUE);
case SPD_ACTTYPE_PASS:
return (B_TRUE);
case SPD_ACTTYPE_IPSEC:
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
{
/*
* Note use of !! for boolean canonicalization.
*/
return (B_TRUE);
}
static void
{
}
/*
* Sanity check action against reality, and shrink-wrap key sizes..
*/
static boolean_t
{
return (B_FALSE);
}
return (B_FALSE);
}
}
/*
* We may be short a few error checks here..
*/
static boolean_t
int *diag)
{
struct spd_ext_actions *sactp =
int nact;
*nactp = 0;
return (B_FALSE);
}
/*
* Parse the "action" extension and convert into an action chain.
*/
return (B_FALSE);
}
switch (attrp->spd_attr_tag) {
case SPD_ATTR_NOP:
break;
case SPD_ATTR_EMPTY:
break;
case SPD_ATTR_END:
/* FALLTHRU */
case SPD_ATTR_NEXT:
goto fail;
}
goto fail;
break;
case SPD_ATTR_TYPE:
goto fail;
}
break;
case SPD_ATTR_FLAGS:
goto fail;
}
break;
case SPD_ATTR_AH_AUTH:
break;
case SPD_ATTR_ESP_ENCR:
break;
case SPD_ATTR_ESP_AUTH:
break;
case SPD_ATTR_ENCR_MINBITS:
break;
case SPD_ATTR_ENCR_MAXBITS:
break;
case SPD_ATTR_AH_MINBITS:
break;
case SPD_ATTR_AH_MAXBITS:
break;
case SPD_ATTR_ESPA_MINBITS:
break;
case SPD_ATTR_ESPA_MAXBITS:
break;
case SPD_ATTR_LIFE_SOFT_TIME:
case SPD_ATTR_LIFE_HARD_TIME:
case SPD_ATTR_LIFE_SOFT_BYTES:
case SPD_ATTR_LIFE_HARD_BYTES:
break;
case SPD_ATTR_KM_PROTO:
break;
case SPD_ATTR_KM_COOKIE:
break;
case SPD_ATTR_REPLAY_DEPTH:
break;
}
}
goto fail;
}
return (B_TRUE);
fail:
return (B_FALSE);
}
typedef struct
{
int dir;
} tmprule_t;
static int
{
return (ENOMEM);
(*rp)++;
return (EEXIST);
return (0);
}
static int
{
int error;
if (error != 0)
return (error);
}
if (error != 0)
return (error);
}
return (0);
}
static void
{
return;
}
if (rule->spd_rule_index != 0) {
return;
}
return;
}
return;
}
/*
* If no addresses were specified, add both.
*/
if (afs == 0)
if (error != 0)
goto fail;
}
if (error != 0)
goto fail;
}
return;
fail:
}
}
void
{
int diag;
return;
}
if (rule->spd_rule_index != 0) {
return;
}
} else {
return;
}
goto fail;
}
goto fail;
}
}
return;
fail:
}
void
{
ipsec_swap_policy(); /* can't fail */
}
/*
* Unimplemented feature
*/
/* ARGSUSED */
static void
{
}
static mblk_t *
{
if (m == NULL) {
return (NULL);
}
return (m);
}
static mblk_t *
{
mblk_t *m;
return (m);
}
/*
* Rule encoding functions.
* We do a two-pass encode.
* If base != NULL, fill in encoded rule part starting at base+offset.
* Always return "offset" plus length of to-be-encoded data.
*/
static uint_t
{
struct spd_typecode *tcp;
}
return (offset);
}
static uint_t
{
spp->spd_proto_reserved1 = 0;
spp->spd_proto_reserved2 = 0;
}
return (offset);
}
static uint_t
{
struct spd_portrange *spp;
}
return (offset);
}
static uint_t
{
struct spd_address *sae;
} else {
}
sae->spd_address_reserved2 = 0;
}
return (offset);
}
static uint_t
{
selkey->ipsl_lport);
selkey->ipsl_rport);
}
return (offset);
}
static uint_t
{
struct spd_attribute *attr;
}
offset += sizeof (struct spd_attribute);
return (offset);
}
static uint_t
{
EMIT(SPD_ATTR_EMPTY, 0);
case IPSEC_ACT_DISCARD:
case IPSEC_ACT_REJECT:
break;
case IPSEC_ACT_BYPASS:
case IPSEC_ACT_CLEAR:
break;
case IPSEC_ACT_APPLY:
flags = 0;
flags |= SPD_APPLY_AH;
flags |= SPD_APPLY_ESP;
flags |= SPD_APPLY_ESPA;
flags |= SPD_APPLY_SE;
if (flags & SPD_APPLY_AH) {
}
if (flags & SPD_APPLY_ESP) {
if (flags & SPD_APPLY_ESPA) {
}
}
/* Add more here */
break;
}
return (offset);
}
static uint_t
const ipsec_action_t *ap)
{
struct spd_ext_actions *act;
act->spd_actions_len = 0;
act->spd_actions_count = 0;
act->spd_actions_reserved = 0;
}
nact++;
EMIT(SPD_ATTR_NEXT, 0);
}
}
EMIT(SPD_ATTR_END, 0);
}
return (offset);
}
/* ARGSUSED */
static uint_t
{
if (dir == IPSEC_TYPE_INBOUND)
if (dir == IPSEC_TYPE_OUTBOUND)
return (flags);
}
static uint_t
{
}
spr->spd_rule_unused = 0;
}
}
return (offset);
}
/* ARGSUSED */
static mblk_t *
{
mblk_t *m;
/*
* Figure out how much space we'll need.
*/
/*
* Allocate mblk.
*/
if (m == NULL)
return (NULL);
/*
* Fill it in..
*/
return (m);
}
static ipsec_policy_t *
{
ss->spdsock_dump_count++;
return (cur);
}
static ipsec_policy_t *
{
next:
chain++;
}
}
af++;
}
}
type++;
if (type >= IPSEC_NTYPES)
return (NULL);
ss->spdsock_dump_cur_chain = 0;
goto next;
}
static mblk_t *
{
mblk_t *m;
}
if (!rule) {
return (spdsock_dump_finish(ss, 0));
}
if (m == NULL)
return (m);
}
/*
* Dump records until we run into flow-control back-pressure.
*/
static void
{
m = spdsock_dump_next_record(ss);
if (m == NULL)
return;
freemsg(m);
return;
}
}
}
/*
* Start dumping.
* Format a start-of-dump record, and set up the stream and kick the rsrv
* procedure to continue the job..
*/
/* ARGSUSED */
static void
{
if (!mr) {
return;
}
ss->spdsock_dump_cur_type = 0;
ss->spdsock_dump_count = 0;
ss->spdsock_dump_cur_chain = 0;
}
void
{
int error = ipsec_clone_system_policy();
if (error != 0)
else
}
/*
* Process a SPD_ALGLIST request. The caller expects separate alg entries
* for AH authentication, ESP authentication, and ESP encryption.
* The same distinction is then used when setting the min and max key
* sizes when defining policies.
*/
#define SPDSOCK_AH_AUTH 0
#define SPDSOCK_ESP_AUTH 1
#define SPDSOCK_ESP_ENCR 2
#define SPDSOCK_NTYPES 3
};
};
};
};
};
void
{
mblk_t *m;
struct spd_ext_actions *act;
struct spd_attribute *attr;
/*
* The SPD client expects to receive separate entries for
* AH authentication and ESP authentication supported algorithms.
*
* Don't return the "any" algorithms, if defined, as no
* kernel policies can be set for these algorithms.
*/
algcount--;
algcount--;
/*
* For each algorithm, we encode:
* ALG / MINBITS / MAXBITS / DEFBITS / INCRBITS / {END, NEXT}
*/
if (m == NULL) {
return;
}
msg->spd_msg_errno = 0;
msg->spd_msg_diagnostic = 0;
act->spd_actions_reserved = 0;
attr++; \
}
/*
* If you change the number of EMIT's here, change
* ATTRPERALG above to match
*/
#define EMITALGATTRS(_type) { \
}
if (algtype == IPSEC_ALG_AUTH) {
if (algid == SADB_AALG_NONE)
continue;
} else {
if (algid == SADB_EALG_NONE)
continue;
}
}
}
attr--;
qreply(q, m);
}
/*
* Process a SPD_DUMPALGS request.
*/
void
{
mblk_t *m;
struct spd_ext_actions *act;
struct spd_attribute *attr;
uint_t i;
/*
* For each algorithm, we encode:
* ALG / MINBITS / MAXBITS / DEFBITS / INCRBITS / {END, NEXT}
*
* ALG_ID / ALG_PROTO / ALG_INCRBITS / ALG_NKEYSIZES / ALG_KEYSIZE*
* ALG_NBLOCKSIZES / ALG_BLOCKSIZE* / ALG_MECHNAME / {END, NEXT}
*/
/*
* Compute the size of the SPD message.
*/
alg_size = sizeof (struct spd_attribute) *
}
}
if (m == NULL) {
return;
}
msg->spd_msg_errno = 0;
msg->spd_msg_diagnostic = 0;
act->spd_actions_reserved = 0;
attr++; \
}
/*
* If you change the number of EMIT's here, change
* ATTRPERALG above to match
*/
for (i = 0; i < alg->alg_nkey_sizes; i++)
alg->alg_key_sizes[i]);
for (i = 0; i < alg->alg_nblock_sizes; i++)
alg->alg_block_sizes[i]);
EMIT(SPD_ATTR_NEXT, 0);
}
}
attr--;
qreply(q, m);
}
/*
* Do the actual work of processing an SPD_UPDATEALGS request. Can
* be invoked either once IPsec is loaded on a cached request, or
* when a request is received while IPsec is loaded.
*/
static void
{
struct spd_ext_actions *actp;
ipsec_algtype_t alg_type = 0;
*diag = -1;
/* parse the message, building the list of algorithms */
return;
}
sizeof (ipsec_alginfo_t *));
switch (attr->spd_attr_tag) {
case SPD_ATTR_NOP:
case SPD_ATTR_EMPTY:
break;
case SPD_ATTR_END:
/* FALLTHRU */
case SPD_ATTR_NEXT:
if (doing_proto) {
break;
}
if (skip_alg) {
} else {
}
break;
case SPD_ATTR_ALG_ID:
ss1dbg(("spdsock_do_updatealg: "
"invalid alg id %d\n",
attr->spd_attr_value));
goto bail;
}
break;
case SPD_ATTR_ALG_PROTO:
/* find the alg type */
for (i = 0; i < NALGPROTOS; i++)
break;
skip_alg = (i == NALGPROTOS);
if (!skip_alg)
alg_type = i;
break;
case SPD_ATTR_ALG_INCRBITS:
break;
case SPD_ATTR_ALG_NKEYSIZES:
ALG_KEY_SIZES(alg));
}
/*
* Allocate room for the trailing zero key size
* value as well.
*/
KM_SLEEP);
cur_key = 0;
break;
case SPD_ATTR_ALG_KEYSIZE:
ss1dbg(("spdsock_do_updatealg: "
"too many key sizes\n"));
goto bail;
}
break;
case SPD_ATTR_ALG_NBLOCKSIZES:
}
/*
* Allocate room for the trailing zero block size
* value as well.
*/
KM_SLEEP);
cur_block = 0;
break;
case SPD_ATTR_ALG_BLOCKSIZE:
ss1dbg(("spdsock_do_updatealg: "
"too many block sizes\n"));
goto bail;
}
break;
case SPD_ATTR_ALG_MECHNAME: {
char *mech_name;
ss1dbg(("spdsock_do_updatealg: "
"mech name too long\n"));
goto bail;
}
break;
}
case SPD_ATTR_PROTO_ID:
for (i = 0; i < NALGPROTOS; i++) {
alg_type = i;
break;
}
}
break;
case SPD_ATTR_PROTO_EXEC_MODE:
if (!doing_proto)
break;
for (i = 0; i < NEXECMODES; i++) {
break;
}
}
break;
}
attr++;
}
/* update the algorithm tables */
bail:
/* cleanup */
}
/*
* Process an SPD_UPDATEALGS request. If IPsec is not loaded, queue
* the request until IPsec loads. If IPsec is loaded, act on it
* immediately.
*/
static void
{
if (!ipsec_loaded()) {
/*
* IPsec is not loaded, save request and return nicely,
* the message will be processed once IPsec loads.
*/
/* last update message wins */
return;
}
if (spdsock_mp_algs != NULL)
} else {
/*
* IPsec is loaded, act on the message immediately.
*/
int diag;
if (diag == -1)
else
}
}
static void
{
/* Make sure nothing's below me. */
/*
* 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 spd_msg_type is hosed,
* I need to set it to SPD_RESERVED to get delivery to
* do the right thing. Then again, maybe just letting
* the error delivery do the right thing.
*/
ss2dbg(("mblk (%lu) and base (%d) message sizes don't jibe.\n",
return;
}
/* Get all message into one mblk. */
/*
* Something screwy happened.
*/
ss3dbg(("spdsock_parse: pullupmsg() failed.\n"));
return;
} else {
}
}
case KGE_DUP:
/* Handle duplicate extension. */
ss1dbg(("Got duplicate extension of type %d.\n",
extv[0]->spd_ext_type));
return;
case KGE_UNK:
/* Handle unknown extension. */
ss1dbg(("Got unknown extension of type %d.\n",
extv[0]->spd_ext_type));
return;
case KGE_LEN:
/* Length error. */
ss1dbg(("Length %d on extension type %d overrun or 0.\n",
return;
case KGE_CHK:
/* Reality check failed. */
ss1dbg(("Reality check failed on extension type %d.\n",
extv[0]->spd_ext_type));
return;
default:
/* Default case is no errors. */
break;
}
/*
* Which rule set are we operating on today?
*/
switch (spmsg->spd_msg_spdid) {
case SPD_ACTIVE:
iph = ipsec_system_policy();
break;
case SPD_STANDBY:
iph = ipsec_inactive_policy();
break;
default:
return;
}
/*
* Special-case SPD_UPDATEALGS so as not to load IPsec.
*/
q, LOADCHECK_INTERVAL);
return;
}
switch (spmsg->spd_msg_type) {
case SPD_UPDATEALGS:
return;
case SPD_FLUSH:
return;
case SPD_ADDRULE:
return;
case SPD_DELETERULE:
return;
case SPD_FLIP:
spdsock_flip(q, mp);
return;
case SPD_LOOKUP:
return;
case SPD_DUMP:
return;
case SPD_CLONE:
spdsock_clone(q, mp);
return;
case SPD_ALGLIST:
spdsock_alglist(q, mp);
return;
case SPD_DUMPALGS:
spdsock_dumpalgs(q, mp);
return;
default:
return;
}
}
/*
* If an algorithm mapping was received before IPsec was loaded, process it.
* Called from the IPsec loader.
*/
void
{
if (spdsock_algs_pending) {
int diag;
}
}
static void
spdsock_loadcheck(void *arg)
{
ss->spdsock_timeout = 0;
if (ipsec_failed())
else
spdsock_parse(q, mp);
}
/*
* Copy relevant state bits.
*/
static void
{
}
/*
* This routine responds to T_CAPABILITY_REQ messages. It is called by
* spdsock_wput. Much of the T_CAPABILITY_ACK information is copied from
* spdsock_g_t_info_ack. The current state of the stream is copied from
* spdsock_state.
*/
static void
{
struct T_capability_ack *tcap;
return;
}
}
/*
* This routine responds to T_INFO_REQ messages. It is called by
* spdsock_wput_other.
* Most of the T_INFO_ACK information is copied from spdsock_g_t_info_ack.
* The current state of the stream is copied from spdsock_state.
*/
static void
spdsock_info_req(q, mp)
queue_t *q;
{
return;
}
/*
* spdsock_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;
/*
* 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_SNDBUF:
if (*i1 > spdsock_max_buf)
return (ENOBUFS);
break;
case SO_RCVBUF:
if (*i1 > spdsock_max_buf)
return (ENOBUFS);
break;
}
break;
}
return (0);
}
/*
* Handle STREAMS messages.
*/
static void
{
int error;
case M_PROTO:
case M_PCPROTO:
ss3dbg((
"spdsock_wput_other: Not big enough M_PROTO\n"));
return;
}
case T_CAPABILITY_REQ:
spdsock_capability_req(q, mp);
return;
case T_INFO_REQ:
spdsock_info_req(q, mp);
return;
case T_SVR4_OPTMGMT_REQ:
return;
case T_OPTMGMT_REQ:
return;
case T_DATA_REQ:
case T_EXDATA_REQ:
case T_ORDREL_REQ:
/* Illegal for spdsock. */
return;
default:
/* Not supported by spdsock. */
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. */
}
static void
{
/*
* If we're dumping, defer processing other messages until the
* dump completes.
*/
return;
}
case M_DATA:
/*
* Silently discard.
*/
ss2dbg(("raw M_DATA in spdsock.\n"));
return;
case M_PROTO:
case M_PCPROTO:
/* No data after T_DATA_REQ. */
ss2dbg(("No data after DATA_REQ.\n"));
return;
}
ss2dbg(("T_DATA_REQ\n"));
break; /* Out of switch. */
}
}
/* FALLTHRU */
default:
ss3dbg(("In default wput case (%d %d).\n",
spdsock_wput_other(q, mp);
return;
}
/* I now have a PF_POLICY message in an M_DATA block. */
spdsock_parse(q, mp);
}
/*
* Device open procedure, called when new queue pair created.
* We are passed the read-side queue.
*/
/* ARGSUSED */
static int
{
return (EPERM);
return (0); /* Re-open of an already open instance. */
return (EINVAL);
ss2dbg(("Made it into PF_POLICY socket open.\n"));
if (ssminor == 0)
return (ENOMEM);
return (ENOMEM);
}
q->q_hiwat = spdsock_recv_hiwat;
qprocson(q);
(void) mi_set_sth_hiwat(q, spdsock_recv_hiwat);
return (0);
}
/*
* Read-side service procedure, invoked when we get back-enabled
* when buffer space becomes available.
*
* Dump another chunk if we were dumping before; when we finish, kick
* the write-side queue in case it's waiting for read queue space.
*/
void
spdsock_rsrv(queue_t *q)
{
spdsock_dump_some(q, ss);
}
/*
* Write-side service procedure, invoked when we defer processing
* if another message is received while a dump is in progress.
*/
void
spdsock_wsrv(queue_t *q)
{
return;
}
if (ipsec_loaded()) {
spdsock_wput(q, mp);
return;
} else if (!ipsec_failed()) {
} else {
}
}
}
static int
spdsock_close(queue_t *q)
{
qprocsoff(q);
/* Safe assumption. */
if (ss->spdsock_timeout != 0)
ss3dbg(("Driver close, PF_POLICY socket is going away.\n"));
return (0);
}
/*
* Merge the IPsec algorithms tables with the received algorithm information.
*/
void
spdsock_merge_algs(void)
{
/*
* Get the list of supported mechanisms from the crypto framework.
* If a mechanism is supported by KCF, resolve its mechanism
* id and mark it as being valid. This operation must be done
* without holding alg_lock, since it can cause a provider
* module to be loaded and the provider notification callback to
* be invoked.
*/
int algflags = 0;
continue;
/*
* The NULL encryption algorithm is a special
* case because there are no mechanisms, yet
* the algorithm is still valid.
*/
continue;
}
CRYPTO_MAX_MECH_NAME) == 0) {
break;
}
}
}
}
/*
* For each algorithm currently defined, check if it is
* present in the new tables created from the SPD_UPDATEALGS
* message received from user-space.
* Delete the algorithm entries that are currently defined
* but not part of the new tables.
*/
}
}
/*
* For each algorithm we just received, check if it is
* present in the currently defined tables. If it is, swap
* the entry with the one we just allocated.
* If the new algorithm is not in the current tables,
* add it.
*/
continue;
/*
* New algorithm, add it to the algorithm
* table.
*/
} else {
/*
* Algorithm is already in the table. Swap
* the existing entry with the new one.
*/
}
}
}
}