oplkmdrv.c revision 030f3a8fd60560aa3c096f68447cd7ea31457e6a
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* OPL IPSec Key Management Driver.
*
* This driver runs on a OPL Domain. It processes requests received
* from the OPL Service Processor (SP) via mailbox message. It passes
* these requests to the sckmd daemon by means of an /ioctl interface.
*
* Requests received from the SP consist of IPsec security associations
* (SAs) needed to secure the communication between SC and Domain daemons
* communicating using DSCP.
*/
#include <sys/ddi_impldefs.h>
#include <sys/ndi_impldefs.h>
#include <sys/byteorder.h>
#include <sys/oplkm_msg.h>
#define OKM_TARGET_ID 0 /* Target ID */
#ifdef DEBUG
#endif
/*
* Prototypes for the module related functions.
*/
/*
* Prototypes for the internal functions.
*/
struct cb_ops okm_cb_ops = {
okm_open, /* open */
okm_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
okm_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
0, /* streamtab */
};
DEVO_REV, /* devo_rev, */
0, /* refcnt */
okm_info, /* get_dev_info */
nulldev, /* identify */
nulldev, /* probe */
okm_attach, /* attach */
okm_detach, /* detach */
nodev, /* reset */
&okm_cb_ops, /* driver operations */
(struct bus_ops *)0 /* no bus operations */
};
"OPL Key Management Driver v%I%",
&okm_ops,
};
struct modlinkage modlinkage = {
&modldrv,
};
/*
* _init - Module's init routine.
*/
int
_init(void)
{
int ret;
}
return (ret);
}
/*
* _fini - Module's fini routine.
*/
int
_fini(void)
{
int ret;
return (ret);
}
return (ret);
}
/*
* _info - Module's info routine.
*/
int
{
}
/*
* okm_attach - Module's attach routine.
*
* Description: Initializes the modules state structure and create
* the minor device node.
*/
int
{
int instance;
/* Only one instance is supported. */
if (instance != 0) {
return (DDI_FAILURE);
}
if (cmd != DDI_ATTACH) {
return (DDI_FAILURE);
}
/*
* Get an interrupt block cookie corresponding to the
* interrupt priority of the event handler.
* Assert that the event priority is not redefined to
* some other priority.
*/
/* LINTED */
return (DDI_FAILURE);
}
(void *)okmsp->km_ibcookie);
/*
* set clean_node ahead as remove_node has to be called even
* if create node fails.
*/
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* okm_detach - Module's detach routine.
*
* Description: Cleans up the module's state structures and any other
* relevant data.
*/
int
{
if (cmd != DDI_DETACH) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/*
* Check if the mailbox is still in use.
*/
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* okm_info - Module's info routine.
*/
/* ARGSUSED */
int
{
int ret = DDI_FAILURE;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
} else {
ret = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
ret = DDI_SUCCESS;
default:
break;
}
return (ret);
}
/*
* okm_open - Device open routine.
*
* Description: Initializes the mailbox and waits until the mailbox
* gets connected. Only one open at a time is supported.
*/
/*ARGSUSED*/
int
{
int ret = 0;
/* Only one open supported */
return (EBUSY);
}
if (ret != 0) {
}
return (ret);
}
/*
* block_until_ready - Function to wait until the mailbox is ready to use.
*
* Description: It initializes the mailbox and waits for the mailbox
* state to transition to connected.
*/
int
{
int ret = 0;
}
return (0);
}
/*
* Initialize mailbox.
*/
("block_until_ready: mailbox init failed ret=%d\n", ret));
return (ret);
}
return (ret);
}
/*
* okm_close - Device close routine.
*
* Description: Closes the mailbox.
*/
/*ARGSUSED*/
int
{
/* Close the lower layer first */
return (0);
}
/*
* okm_ioctl - Device ioctl routine.
*
* Description: Processes ioctls from the daemon.
*/
/*ARGSUSED*/
int
{
int ret = 0;
switch (cmd) {
case SCKM_IOCTL_GETREQ:
return (EFAULT);
}
break;
case SCKM_IOCTL_STATUS:
sizeof (sckm_ioctl_status_t), flag)) {
return (EFAULT);
}
break;
default:
}
return (ret);
}
/*
* okm_get_req - Get a request from the mailbox.
*
* Description: It blocks until a message is received, then processes
* the message and returns it to the requestor.
*/
int
{
int ret;
return (ret);
}
} else {
while (OKM_MBOX_READY(okmsp) &&
"mbox failure=%d\n", ret));
return (EIO);
}
return (EINTR);
}
}
if (!OKM_MBOX_READY(okmsp)) {
return (EIO);
}
goto retry;
} else if (ret != 0) {
("okm_getreq: Unknown mbox failure=%d\n", ret));
return (EIO);
}
/* check message length */
if (len < sizeof (okm_req_hdr_t)) {
/* protocol error, drop message */
return (EBADMSG);
}
/* check version of the message received */
OKM_ERR_VERSION, 0, 0);
reqp->krq_version));
return (EBADMSG);
}
}
/* process message */
/*
* The message is not saved, so free the buffer.
*/
}
return (ret);
}
/*
* okm_process_req - Process the request.
*
* Description: Validate the request and then give the request to the
* daemon.
*/
int
{
case OKM_MSG_SADB:
/* sanity check request */
if (sadb_msglen <= 0) {
OKM_ERR_SADB_MSG, 0, 0);
return (EBADMSG);
}
/*
* Save the message, prior to giving it to the daemon.
*/
("okm_process_req: not enough space\n"));
return (ENOSPC);
}
("okm_process_req: copyout failed\n"));
return (EFAULT);
}
("okm_process_req: copyout failed\n"));
return (EFAULT);
}
break;
default:
/*
* Received an unknown command, send corresponding
* error message.
*/
return (EBADMSG);
}
return (0);
}
/*
* okm_process_status - Process the status from the daemon.
*
* Description: Processes the status received from the daemon and sends
* corresponding message to the SP.
*/
int
{
uint32_t sadb_msg_errno = 0;
uint32_t sadb_msg_version = 0;
int ret;
("okm_process_status: Unknown failure=%d\n", ret));
return (ret);
}
/* fail if no status is expected, or if it does not match */
return (EINVAL);
}
case SCKM_IOCTL_STAT_SUCCESS:
break;
break;
case SCKM_IOCTL_STAT_ERR_REQ:
break;
break;
break;
break;
break;
default:
}
/*
* Clean up the cached request now.
*/
if (ret == 0) {
}
return (ret);
}
/*
* okm_copyin_ioctl_getreq - copy-in the ioctl request from the daemon.
*/
static int
int flag)
{
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
sizeof (sckm_ioctl_getreq32_t), flag)) {
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE: {
sizeof (sckm_ioctl_getreq_t), flag)) {
return (EFAULT);
}
break;
}
}
#else /* ! _MULTI_DATAMODEL */
sizeof (sckm_ioctl_getreq_t), flag)) {
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
return (0);
}
/*
* okm_copyout_ioctl_getreq - copy-out the request to the daemon.
*/
static int
int flag)
{
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32: {
sizeof (sckm_ioctl_getreq32_t), flag)) {
return (EFAULT);
}
break;
}
case DDI_MODEL_NONE:
sizeof (sckm_ioctl_getreq_t), flag)) {
return (EFAULT);
}
break;
}
#else /* ! _MULTI_DATAMODEL */
sizeof (sckm_ioctl_getreq_t), flag)) {
return (EFAULT);
}
#endif /* _MULTI_DATAMODEL */
return (0);
}
/*
* okm_cleanup - Cleanup routine.
*/
static void
{
}
}
}
/*
* okm_mbox_init - Mailbox specific initialization.
*/
static int
{
int ret;
/* Iterate until mailbox gets connected */
okm_event_handler, (void *)okmsp);
if (ret != 0) {
("okm_mbox_init: failed ret =%d\n", ret));
} else {
/* Block until the mailbox is ready to communicate. */
(OKM_MB_CONN | OKM_MB_DISC))) {
/* interrupted */
break;
}
}
}
}
("okm_mbox_init: mbox DISC_ERROR\n"));
int, OKM_MB_DISC);
}
return (ret);
}
/*
* If there was failure, then wait for
* OKM_MB_TOUT secs and retry again.
*/
if (ret == 0) {
/* if interrupted, return immediately. */
("okm_mbox_init: interrupted\n"));
return (EINTR);
}
}
}
/*
* The max msg size should be at least the size of reply
* we need to send.
*/
}
if (ret != 0) {
}
return (ret);
}
/*
* okm_mbox_fini - Mailbox de-initialization.
*/
static void
{
int ret = 0;
if (ret != 0) {
"Failed to close the Mailbox error=%d", ret);
}
}
}
/*
* okm_event_handler - Mailbox event handler.
*
* Description: Implements a state machine to handle all the mailbox
* events. For each event, it sets the appropriate state
* flag and wakes up the threads waiting for that event.
*/
void
{
/*
* Ignore all events if the state flag indicates that the
* mailbox not initialized, this may happen during the close.
*/
("okm_event_handler: event=0x%X - mailbox not inited \n",
event));
return;
}
switch (event) {
case SCF_MB_CONN_OK:
/*
* Now the mailbox is ready to use, lets wake up
* any one waiting for this event.
*/
break;
case SCF_MB_MSG_DATA:
/*
* A message is available in the mailbox,
* wakeup if any one is ready to read the message.
*/
if (OKM_MBOX_READY(okmsp)) {
}
break;
case SCF_MB_SPACE:
/*
* Now the mailbox is ready to transmit, lets
* wakeup if any one is waiting to write.
*/
if (OKM_MBOX_READY(okmsp)) {
}
break;
case SCF_MB_DISC_ERROR:
break;
default:
}
}
/*
* okm_send_reply - Send a mailbox reply message.
*/
int
{
DUMP_REPLY(&reply);
while (OKM_MBOX_READY(okmsp)) {
/* interrupted */
("okm_send_reply: interrupted\n"));
break;
}
} else {
break;
}
}
return (ret);
}
/*
* okm_timeout_val -- Return appropriate timeout value.
*
* A small timeout value is returned for EBUSY as the mailbox busy
* condition may go away sooner and we are expected to poll.
*
* A larger timeout value is returned for ENOSPC case, as the condition
* depends on the peer to release buffer space.
* NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
* used for reliability purposes.
*/
static clock_t
okm_timeout_val(int error)
{
tval = OKM_SM_TOUT;
} else {
tval = OKM_LG_TOUT;
}
return (drv_usectohz(tval));
}
#ifdef DEBUG
static void
{
int i, j;
#define BYTES_PER_LINE 20
return;
printf("OKM: Request ver=%d transid=%d cmd=%s\n",
for (i = 0; i < msglen; ) {
for (j = 0; (j < BYTES_PER_LINE) && (i < msglen); j++, i++) {
}
if (j != 0) {
}
}
}
static void
{
return;
printf("OKM: Reply Ver=%d Transid=%d Status=%d ",
}
#endif