1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * OPL IPSec Key Management Driver. 29 * 30 * This driver runs on a OPL Domain. It processes requests received 31 * from the OPL Service Processor (SP) via mailbox message. It passes 32 * these requests to the sckmd daemon by means of an /ioctl interface. 33 * 34 * Requests received from the SP consist of IPsec security associations 35 * (SAs) needed to secure the communication between SC and Domain daemons 36 * communicating using DSCP. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/cmn_err.h> 41 #include <sys/kmem.h> 42 #include <sys/errno.h> 43 #include <sys/file.h> 44 #include <sys/open.h> 45 #include <sys/stat.h> 46 #include <sys/conf.h> 47 #include <sys/ddi.h> 48 #include <sys/cmn_err.h> 49 #include <sys/sunddi.h> 50 #include <sys/sunndi.h> 51 #include <sys/ddi_impldefs.h> 52 #include <sys/ndi_impldefs.h> 53 #include <sys/modctl.h> 54 #include <sys/disp.h> 55 #include <sys/note.h> 56 #include <sys/byteorder.h> 57 #include <sys/sdt.h> 58 59 #include <sys/scfd/scfdscpif.h> 60 #include <sys/oplkm_msg.h> 61 #include <sys/sckm_io.h> 62 #include <sys/oplkm.h> 63 64 #define OKM_NODENAME "oplkmdrv" /* Node name */ 65 #define OKM_TARGET_ID 0 /* Target ID */ 66 #define OKM_SM_TOUT 5000 /* small timeout (5msec) */ 67 #define OKM_LG_TOUT 50000 /* large timeout (50msec) */ 68 #define OKM_MB_TOUT 10000000 /* Mailbox timeout (10sec) */ 69 70 okms_t okms_global; /* Global instance structure */ 71 72 #ifdef DEBUG 73 uint32_t okm_debug = DBG_WARN; 74 #endif 75 76 /* 77 * Prototypes for the module related functions. 78 */ 79 int okm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 80 int okm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 81 int okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result); 82 int okm_open(dev_t *devp, int flag, int otyp, struct cred *cred); 83 int okm_close(dev_t dev, int flag, int otyp, struct cred *cred); 84 int okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, 85 cred_t *cred, int *rvalp); 86 87 /* 88 * Prototypes for the internal functions. 89 */ 90 int okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp, 91 intptr_t data, int flag); 92 int okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len, 93 sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag); 94 int okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply); 95 void okm_event_handler(scf_event_t event, void *arg); 96 int okm_send_reply(okms_t *okmsp, uint32_t transid, uint32_t status, 97 uint32_t sadb_err, uint32_t sadb_ver); 98 int block_until_ready(okms_t *okmsp); 99 static int okm_copyin_ioctl_getreq(intptr_t userarg, 100 sckm_ioctl_getreq_t *driverarg, int flag); 101 static int okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, 102 intptr_t userarg, int flag); 103 static void okm_cleanup(okms_t *okmsp); 104 static int okm_mbox_init(okms_t *okmsp); 105 static void okm_mbox_fini(okms_t *okmsp); 106 static clock_t okm_timeout_val(int error); 107 108 109 struct cb_ops okm_cb_ops = { 110 okm_open, /* open */ 111 okm_close, /* close */ 112 nodev, /* strategy */ 113 nodev, /* print */ 114 nodev, /* dump */ 115 nodev, /* read */ 116 nodev, /* write */ 117 okm_ioctl, /* ioctl */ 118 nodev, /* devmap */ 119 nodev, /* mmap */ 120 nodev, /* segmap */ 121 nochpoll, /* poll */ 122 ddi_prop_op, /* prop_op */ 123 0, /* streamtab */ 124 D_NEW | D_MP /* Driver compatibility flag */ 125 }; 126 127 struct dev_ops okm_ops = { 128 DEVO_REV, /* devo_rev, */ 129 0, /* refcnt */ 130 okm_info, /* get_dev_info */ 131 nulldev, /* identify */ 132 nulldev, /* probe */ 133 okm_attach, /* attach */ 134 okm_detach, /* detach */ 135 nodev, /* reset */ 136 &okm_cb_ops, /* driver operations */ 137 (struct bus_ops *)0, /* no bus operations */ 138 NULL, /* power */ 139 ddi_quiesce_not_needed, /* quiesce */ 140 }; 141 142 struct modldrv modldrv = { 143 &mod_driverops, 144 "OPL Key Management Driver", 145 &okm_ops, 146 }; 147 148 struct modlinkage modlinkage = { 149 MODREV_1, 150 &modldrv, 151 NULL 152 }; 153 154 155 /* 156 * _init - Module's init routine. 157 */ 158 int 159 _init(void) 160 { 161 int ret; 162 163 if ((ret = mod_install(&modlinkage)) != 0) { 164 cmn_err(CE_WARN, "mod_install failed, error = %d", ret); 165 } 166 return (ret); 167 } 168 169 /* 170 * _fini - Module's fini routine. 171 */ 172 int 173 _fini(void) 174 { 175 int ret; 176 177 if ((ret = mod_remove(&modlinkage)) != 0) { 178 return (ret); 179 } 180 return (ret); 181 } 182 183 /* 184 * _info - Module's info routine. 185 */ 186 int 187 _info(struct modinfo *modinfop) 188 { 189 return (mod_info(&modlinkage, modinfop)); 190 } 191 192 /* 193 * okm_attach - Module's attach routine. 194 * 195 * Description: Initializes the modules state structure and create 196 * the minor device node. 197 */ 198 int 199 okm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 200 { 201 int instance; 202 okms_t *okmsp = &okms_global; 203 204 instance = ddi_get_instance(dip); 205 206 /* Only one instance is supported. */ 207 if (instance != 0) { 208 return (DDI_FAILURE); 209 } 210 211 if (cmd != DDI_ATTACH) { 212 return (DDI_FAILURE); 213 } 214 215 okmsp->km_dip = dip; 216 okmsp->km_major = ddi_driver_major(dip); 217 okmsp->km_inst = instance; 218 219 /* 220 * Get an interrupt block cookie corresponding to the 221 * interrupt priority of the event handler. 222 * Assert that the event priority is not redefined to 223 * some other priority. 224 */ 225 /* LINTED */ 226 ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW); 227 if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI, 228 &okmsp->km_ibcookie) != DDI_SUCCESS) { 229 cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed."); 230 return (DDI_FAILURE); 231 } 232 mutex_init(&okmsp->km_lock, NULL, MUTEX_DRIVER, 233 (void *)okmsp->km_ibcookie); 234 okmsp->km_clean |= OKM_CLEAN_LOCK; 235 cv_init(&okmsp->km_wait, NULL, CV_DRIVER, NULL); 236 okmsp->km_clean |= OKM_CLEAN_CV; 237 238 /* 239 * set clean_node ahead as remove_node has to be called even 240 * if create node fails. 241 */ 242 okmsp->km_clean |= OKM_CLEAN_NODE; 243 if (ddi_create_minor_node(dip, OKM_NODENAME, S_IFCHR, 244 instance, NULL, NULL) == DDI_FAILURE) { 245 cmn_err(CE_WARN, "Device node creation failed"); 246 okm_cleanup(okmsp); 247 return (DDI_FAILURE); 248 } 249 250 ddi_set_driver_private(dip, (caddr_t)okmsp); 251 ddi_report_dev(dip); 252 return (DDI_SUCCESS); 253 } 254 255 /* 256 * okm_detach - Module's detach routine. 257 * 258 * Description: Cleans up the module's state structures and any other 259 * relevant data. 260 */ 261 int 262 okm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 263 { 264 okms_t *okmsp; 265 266 if (cmd != DDI_DETACH) { 267 return (DDI_FAILURE); 268 } 269 270 if ((okmsp = ddi_get_driver_private(dip)) == NULL) { 271 return (DDI_FAILURE); 272 } 273 274 mutex_enter(&okmsp->km_lock); 275 /* 276 * Check if the mailbox is still in use. 277 */ 278 if (okmsp->km_state & OKM_MB_INITED) { 279 mutex_exit(&okmsp->km_lock); 280 cmn_err(CE_WARN, "Detach failure: Mailbox in use"); 281 return (DDI_FAILURE); 282 } 283 mutex_exit(&okmsp->km_lock); 284 okm_cleanup(okmsp); 285 ddi_set_driver_private(dip, NULL); 286 return (DDI_SUCCESS); 287 } 288 289 /* 290 * okm_info - Module's info routine. 291 */ 292 /* ARGSUSED */ 293 int 294 okm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 295 { 296 okms_t *okmsp = &okms_global; 297 minor_t minor; 298 int ret = DDI_FAILURE; 299 300 switch (infocmd) { 301 case DDI_INFO_DEVT2DEVINFO: 302 /* 303 * We have the case here where the minor number 304 * is the same as the instance number. So, just 305 * make sure we have the right minor node in our 306 * global state. If we don't, set the result to NULL. 307 */ 308 minor = getminor((dev_t)arg); 309 if (okmsp->km_inst != minor) { 310 *result = NULL; 311 } else { 312 *result = okmsp->km_dip; 313 ret = DDI_SUCCESS; 314 } 315 break; 316 317 case DDI_INFO_DEVT2INSTANCE: 318 minor = getminor((dev_t)arg); 319 *result = (void *)(uintptr_t)minor; 320 ret = DDI_SUCCESS; 321 322 default: 323 break; 324 } 325 return (ret); 326 } 327 328 /* 329 * okm_open - Device open routine. 330 * 331 * Description: Initializes the mailbox and waits until the mailbox 332 * gets connected. Only one open at a time is supported. 333 */ 334 /*ARGSUSED*/ 335 int 336 okm_open(dev_t *devp, int flag, int otyp, struct cred *cred) 337 { 338 okms_t *okmsp = &okms_global; 339 int ret = 0; 340 341 DPRINTF(DBG_DRV, ("okm_open: called\n")); 342 mutex_enter(&okmsp->km_lock); 343 if (okmsp->km_state & OKM_OPENED) { 344 /* Only one open supported */ 345 mutex_exit(&okmsp->km_lock); 346 DPRINTF(DBG_WARN, ("okm_open: already opened\n")); 347 return (EBUSY); 348 } 349 okmsp->km_state |= OKM_OPENED; 350 ret = block_until_ready(okmsp); 351 if (ret != 0) { 352 okmsp->km_state &= ~OKM_OPENED; 353 } 354 mutex_exit(&okmsp->km_lock); 355 DPRINTF(DBG_DRV, ("okm_open: ret=%d\n", ret)); 356 return (ret); 357 } 358 359 /* 360 * block_until_ready - Function to wait until the mailbox is ready to use. 361 * 362 * Description: It initializes the mailbox and waits for the mailbox 363 * state to transition to connected. 364 */ 365 int 366 block_until_ready(okms_t *okmsp) 367 { 368 int ret = 0; 369 370 DPRINTF(DBG_DRV, ("block_until_ready: called\n")); 371 ASSERT(MUTEX_HELD(&okmsp->km_lock)); 372 373 if (okmsp->km_state & OKM_MB_DISC) { 374 DPRINTF(DBG_DRV, ("block_until_ready: closing the mailbox\n")); 375 okm_mbox_fini(okmsp); 376 } 377 if (okmsp->km_state & OKM_MB_CONN) { 378 DPRINTF(DBG_DRV, ("block_until_ready: mailbox connected\n")); 379 return (0); 380 } 381 /* 382 * Initialize mailbox. 383 */ 384 if ((ret = okm_mbox_init(okmsp)) != 0) { 385 DPRINTF(DBG_MBOX, 386 ("block_until_ready: mailbox init failed ret=%d\n", ret)); 387 return (ret); 388 } 389 DPRINTF(DBG_DRV, ("block_until_ready: ret=%d", ret)); 390 return (ret); 391 } 392 393 /* 394 * okm_close - Device close routine. 395 * 396 * Description: Closes the mailbox. 397 */ 398 /*ARGSUSED*/ 399 int 400 okm_close(dev_t dev, int flag, int otyp, struct cred *cred) 401 { 402 okms_t *okmsp = &okms_global; 403 404 DPRINTF(DBG_DRV, ("okm_close: called\n")); 405 /* Close the lower layer first */ 406 mutex_enter(&okmsp->km_lock); 407 okm_mbox_fini(okmsp); 408 okmsp->km_state = 0; 409 mutex_exit(&okmsp->km_lock); 410 return (0); 411 } 412 413 414 /* 415 * okm_ioctl - Device ioctl routine. 416 * 417 * Description: Processes ioctls from the daemon. 418 */ 419 /*ARGSUSED*/ 420 int 421 okm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp) 422 { 423 okms_t *okmsp = &okms_global; 424 sckm_ioctl_getreq_t ireq; 425 sckm_ioctl_status_t istatus; 426 int ret = 0; 427 428 switch (cmd) { 429 case SCKM_IOCTL_GETREQ: 430 431 DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ\n")); 432 if (okm_copyin_ioctl_getreq(data, &ireq, flag)) { 433 return (EFAULT); 434 } 435 436 ret = okm_get_req(okmsp, &ireq, data, flag); 437 DPRINTF(DBG_DRV, ("okm_ioctl: GETREQ ret=%d\n", ret)); 438 break; 439 440 case SCKM_IOCTL_STATUS: 441 442 DPRINTF(DBG_DRV, ("okm_ioctl: STATUS\n")); 443 if (ddi_copyin((caddr_t)data, &istatus, 444 sizeof (sckm_ioctl_status_t), flag)) { 445 return (EFAULT); 446 } 447 ret = okm_process_status(okmsp, &istatus); 448 DPRINTF(DBG_DRV, ("okm_ioctl: STATUS ret=%d\n", ret)); 449 break; 450 451 default: 452 DPRINTF(DBG_DRV, ("okm_ioctl: UNKNOWN ioctl\n")); 453 ret = EINVAL; 454 } 455 return (ret); 456 } 457 458 /* 459 * okm_get_req - Get a request from the mailbox. 460 * 461 * Description: It blocks until a message is received, then processes 462 * the message and returns it to the requestor. 463 */ 464 int 465 okm_get_req(okms_t *okmsp, sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag) 466 { 467 okm_req_hdr_t *reqp; 468 caddr_t msgbuf; 469 uint32_t len; 470 int ret; 471 472 DPRINTF(DBG_DRV, ("okm_getreq: called\n")); 473 mutex_enter(&okmsp->km_lock); 474 if ((ret = block_until_ready(okmsp)) != 0) { 475 mutex_exit(&okmsp->km_lock); 476 DPRINTF(DBG_WARN, ("okm_getreq: failed ret=%d\n", ret)); 477 return (ret); 478 } 479 480 if (okmsp->km_reqp != NULL) { 481 DPRINTF(DBG_DRV, ("okm_getreq: req cached\n")); 482 reqp = okmsp->km_reqp; 483 len = okmsp->km_reqlen; 484 okmsp->km_reqp = NULL; 485 okmsp->km_reqlen = 0; 486 } else { 487 retry: 488 while (OKM_MBOX_READY(okmsp) && 489 ((ret = scf_mb_canget(okmsp->km_target, 490 okmsp->km_key, &len)) != 0)) { 491 if (ret != ENOMSG) { 492 DPRINTF(DBG_WARN, ("okm_getreq: Unknown " 493 "mbox failure=%d\n", ret)); 494 mutex_exit(&okmsp->km_lock); 495 return (EIO); 496 } 497 DPRINTF(DBG_MBOX, ("okm_getreq: waiting for mesg\n")); 498 if (cv_wait_sig(&okmsp->km_wait, 499 &okmsp->km_lock) <= 0) { 500 mutex_exit(&okmsp->km_lock); 501 DPRINTF(DBG_DRV, ("okm_getreq:interrupted\n")); 502 return (EINTR); 503 } 504 } 505 if (!OKM_MBOX_READY(okmsp)) { 506 mutex_exit(&okmsp->km_lock); 507 DPRINTF(DBG_WARN, ("okm_getreq: mailbox not ready\n")); 508 return (EIO); 509 } 510 ASSERT(len != 0); 511 msgbuf = kmem_alloc(len, KM_SLEEP); 512 okmsp->km_sg_rcv.msc_dptr = msgbuf; 513 okmsp->km_sg_rcv.msc_len = len; 514 515 DPRINTF(DBG_MBOX, ("okm_getreq: getmsg\n")); 516 ret = scf_mb_getmsg(okmsp->km_target, okmsp->km_key, len, 1, 517 &okmsp->km_sg_rcv, 0); 518 if (ret == ENOMSG || ret == EMSGSIZE) { 519 kmem_free(msgbuf, len); 520 DPRINTF(DBG_MBOX, ("okm_getreq: nomsg ret=%d\n", ret)); 521 goto retry; 522 } else if (ret != 0) { 523 kmem_free(msgbuf, len); 524 mutex_exit(&okmsp->km_lock); 525 DPRINTF(DBG_WARN, 526 ("okm_getreq: Unknown mbox failure=%d\n", ret)); 527 return (EIO); 528 } 529 530 /* check message length */ 531 if (len < sizeof (okm_req_hdr_t)) { 532 /* protocol error, drop message */ 533 kmem_free(msgbuf, len); 534 mutex_exit(&okmsp->km_lock); 535 DPRINTF(DBG_WARN, ("okm_getreq: Bad message\n")); 536 return (EBADMSG); 537 } 538 539 reqp = (okm_req_hdr_t *)msgbuf; 540 reqp->krq_version = ntohl(reqp->krq_version); 541 reqp->krq_transid = ntohl(reqp->krq_transid); 542 reqp->krq_cmd = ntohl(reqp->krq_cmd); 543 reqp->krq_reserved = ntohl(reqp->krq_reserved); 544 545 /* check version of the message received */ 546 if (reqp->krq_version != OKM_PROTOCOL_VERSION) { 547 (void) okm_send_reply(okmsp, reqp->krq_transid, 548 OKM_ERR_VERSION, 0, 0); 549 kmem_free(msgbuf, len); 550 mutex_exit(&okmsp->km_lock); 551 DPRINTF(DBG_WARN, ("okm_getreq: Unknown version=%d\n", 552 reqp->krq_version)); 553 return (EBADMSG); 554 } 555 } 556 557 /* process message */ 558 ret = okm_process_req(okmsp, reqp, len, ireqp, data, flag); 559 if (okmsp->km_reqp == NULL) { 560 /* 561 * The message is not saved, so free the buffer. 562 */ 563 kmem_free(reqp, len); 564 } 565 mutex_exit(&okmsp->km_lock); 566 DPRINTF(DBG_DRV, ("okm_getreq: ret=%d\n", ret)); 567 return (ret); 568 } 569 570 571 /* 572 * okm_process_req - Process the request. 573 * 574 * Description: Validate the request and then give the request to the 575 * daemon. 576 */ 577 int 578 okm_process_req(okms_t *okmsp, okm_req_hdr_t *reqp, uint32_t len, 579 sckm_ioctl_getreq_t *ireqp, intptr_t data, int flag) 580 { 581 void *req_datap = (void *)(((char *)reqp) + sizeof (okm_req_hdr_t)); 582 int sadb_msglen = len - sizeof (okm_req_hdr_t); 583 584 DPRINTF(DBG_DRV, ("okm_process_req: called\n")); 585 DUMP_REQ(reqp, len); 586 587 switch (reqp->krq_cmd) { 588 case OKM_MSG_SADB: 589 /* sanity check request */ 590 if (sadb_msglen <= 0) { 591 (void) okm_send_reply(okmsp, reqp->krq_transid, 592 OKM_ERR_SADB_MSG, 0, 0); 593 DPRINTF(DBG_WARN, ("okm_process_req: bad message\n")); 594 return (EBADMSG); 595 } 596 597 /* 598 * Save the message, prior to giving it to the daemon. 599 */ 600 okmsp->km_reqp = reqp; 601 okmsp->km_reqlen = len; 602 603 if (ireqp->buf_len < len) { 604 DPRINTF(DBG_WARN, 605 ("okm_process_req: not enough space\n")); 606 return (ENOSPC); 607 } 608 609 ireqp->transid = reqp->krq_transid; 610 ireqp->type = SCKM_IOCTL_REQ_SADB; 611 if (ddi_copyout(req_datap, ireqp->buf, sadb_msglen, flag)) { 612 DPRINTF(DBG_WARN, 613 ("okm_process_req: copyout failed\n")); 614 return (EFAULT); 615 } 616 ireqp->buf_len = sadb_msglen; 617 if (okm_copyout_ioctl_getreq(ireqp, data, flag)) { 618 DPRINTF(DBG_WARN, 619 ("okm_process_req: copyout failed\n")); 620 return (EFAULT); 621 } 622 break; 623 624 default: 625 cmn_err(CE_WARN, "Unknown cmd 0x%x received", reqp->krq_cmd); 626 /* 627 * Received an unknown command, send corresponding 628 * error message. 629 */ 630 (void) okm_send_reply(okmsp, reqp->krq_transid, 631 OKM_ERR_BAD_CMD, 0, 0); 632 return (EBADMSG); 633 } 634 DPRINTF(DBG_DRV, ("okm_process_req: ret=0\n")); 635 return (0); 636 } 637 638 /* 639 * okm_process_status - Process the status from the daemon. 640 * 641 * Description: Processes the status received from the daemon and sends 642 * corresponding message to the SP. 643 */ 644 int 645 okm_process_status(okms_t *okmsp, sckm_ioctl_status_t *ireply) 646 { 647 uint32_t status; 648 uint32_t sadb_msg_errno = 0; 649 uint32_t sadb_msg_version = 0; 650 okm_req_hdr_t *reqp = okmsp->km_reqp; 651 int ret; 652 653 DPRINTF(DBG_DRV, ("okm_process_status: called\n")); 654 mutex_enter(&okmsp->km_lock); 655 if ((ret = block_until_ready(okmsp)) != 0) { 656 mutex_exit(&okmsp->km_lock); 657 DPRINTF(DBG_WARN, 658 ("okm_process_status: Unknown failure=%d\n", ret)); 659 return (ret); 660 } 661 662 /* fail if no status is expected, or if it does not match */ 663 if (!okmsp->km_reqp || (reqp->krq_transid != ireply->transid)) { 664 mutex_exit(&okmsp->km_lock); 665 DPRINTF(DBG_WARN, 666 ("okm_process_status: req/transid mismatch\n")); 667 return (EINVAL); 668 } 669 670 switch (ireply->status) { 671 case SCKM_IOCTL_STAT_SUCCESS: 672 DPRINTF(DBG_DRV, ("okm_process_status: SUCCESS\n")); 673 status = OKM_SUCCESS; 674 break; 675 case SCKM_IOCTL_STAT_ERR_PFKEY: 676 DPRINTF(DBG_DRV, ("okm_process_status: PFKEY ERROR\n")); 677 status = OKM_ERR_SADB_PFKEY; 678 sadb_msg_errno = ireply->sadb_msg_errno; 679 break; 680 case SCKM_IOCTL_STAT_ERR_REQ: 681 DPRINTF(DBG_DRV, ("okm_process_status: REQ ERROR\n")); 682 status = OKM_ERR_DAEMON; 683 break; 684 case SCKM_IOCTL_STAT_ERR_VERSION: 685 DPRINTF(DBG_DRV, ("okm_process_status: SADB VERSION ERROR\n")); 686 status = OKM_ERR_SADB_VERSION; 687 sadb_msg_version = ireply->sadb_msg_version; 688 break; 689 case SCKM_IOCTL_STAT_ERR_TIMEOUT: 690 DPRINTF(DBG_DRV, ("okm_process_status: TIMEOUT ERR\n")); 691 status = OKM_ERR_SADB_TIMEOUT; 692 break; 693 case SCKM_IOCTL_STAT_ERR_OTHER: 694 DPRINTF(DBG_DRV, ("okm_process_status: OTHER ERR\n")); 695 status = OKM_ERR_DAEMON; 696 break; 697 case SCKM_IOCTL_STAT_ERR_SADB_TYPE: 698 DPRINTF(DBG_DRV, ("okm_process_status: SADB TYPE ERR\n")); 699 status = OKM_ERR_SADB_BAD_TYPE; 700 break; 701 default: 702 cmn_err(CE_WARN, "SCKM daemon returned invalid status %d\n", 703 ireply->status); 704 status = OKM_ERR_DAEMON; 705 } 706 ret = okm_send_reply(okmsp, ireply->transid, status, 707 sadb_msg_errno, sadb_msg_version); 708 /* 709 * Clean up the cached request now. 710 */ 711 if (ret == 0) { 712 kmem_free(okmsp->km_reqp, okmsp->km_reqlen); 713 okmsp->km_reqp = NULL; 714 okmsp->km_reqlen = 0; 715 } 716 mutex_exit(&okmsp->km_lock); 717 DPRINTF(DBG_DRV, ("okm_process_status: ret=%d\n", ret)); 718 return (ret); 719 } 720 721 /* 722 * okm_copyin_ioctl_getreq - copy-in the ioctl request from the daemon. 723 */ 724 725 static int 726 okm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg, 727 int flag) 728 { 729 #ifdef _MULTI_DATAMODEL 730 switch (ddi_model_convert_from(flag & FMODELS)) { 731 case DDI_MODEL_ILP32: { 732 sckm_ioctl_getreq32_t driverarg32; 733 if (ddi_copyin((caddr_t)userarg, &driverarg32, 734 sizeof (sckm_ioctl_getreq32_t), flag)) { 735 return (EFAULT); 736 } 737 driverarg->transid = driverarg32.transid; 738 driverarg->type = driverarg32.type; 739 driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf; 740 driverarg->buf_len = driverarg32.buf_len; 741 break; 742 } 743 case DDI_MODEL_NONE: { 744 if (ddi_copyin((caddr_t)userarg, &driverarg, 745 sizeof (sckm_ioctl_getreq_t), flag)) { 746 return (EFAULT); 747 } 748 break; 749 } 750 } 751 #else /* ! _MULTI_DATAMODEL */ 752 if (ddi_copyin((caddr_t)userarg, &driverarg, 753 sizeof (sckm_ioctl_getreq_t), flag)) { 754 return (EFAULT); 755 } 756 #endif /* _MULTI_DATAMODEL */ 757 return (0); 758 } 759 760 761 /* 762 * okm_copyout_ioctl_getreq - copy-out the request to the daemon. 763 */ 764 static int 765 okm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg, 766 int flag) 767 { 768 #ifdef _MULTI_DATAMODEL 769 switch (ddi_model_convert_from(flag & FMODELS)) { 770 case DDI_MODEL_ILP32: { 771 sckm_ioctl_getreq32_t driverarg32; 772 driverarg32.transid = driverarg->transid; 773 driverarg32.type = driverarg->type; 774 driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf; 775 driverarg32.buf_len = driverarg->buf_len; 776 if (ddi_copyout(&driverarg32, (caddr_t)userarg, 777 sizeof (sckm_ioctl_getreq32_t), flag)) { 778 return (EFAULT); 779 } 780 break; 781 } 782 case DDI_MODEL_NONE: 783 if (ddi_copyout(driverarg, (caddr_t)userarg, 784 sizeof (sckm_ioctl_getreq_t), flag)) { 785 return (EFAULT); 786 } 787 break; 788 } 789 #else /* ! _MULTI_DATAMODEL */ 790 if (ddi_copyout(driverarg, (caddr_t)userarg, 791 sizeof (sckm_ioctl_getreq_t), flag)) { 792 return (EFAULT); 793 } 794 #endif /* _MULTI_DATAMODEL */ 795 return (0); 796 } 797 798 /* 799 * okm_cleanup - Cleanup routine. 800 */ 801 static void 802 okm_cleanup(okms_t *okmsp) 803 { 804 805 ASSERT(okmsp != NULL); 806 if (okmsp->km_clean & OKM_CLEAN_NODE) { 807 ddi_remove_minor_node(okmsp->km_dip, NULL); 808 } 809 if (okmsp->km_clean & OKM_CLEAN_LOCK) 810 mutex_destroy(&okmsp->km_lock); 811 if (okmsp->km_clean & OKM_CLEAN_CV) 812 cv_destroy(&okmsp->km_wait); 813 if (okmsp->km_reqp != NULL) { 814 kmem_free(okmsp->km_reqp, okmsp->km_reqlen); 815 okmsp->km_reqp = NULL; 816 okmsp->km_reqlen = 0; 817 } 818 ddi_set_driver_private(okmsp->km_dip, NULL); 819 } 820 821 /* 822 * okm_mbox_init - Mailbox specific initialization. 823 */ 824 static int 825 okm_mbox_init(okms_t *okmsp) 826 { 827 int ret; 828 clock_t tout; 829 830 ASSERT(MUTEX_HELD(&okmsp->km_lock)); 831 okmsp->km_target = OKM_TARGET_ID; 832 okmsp->km_key = DKMD_KEY; 833 okmsp->km_state &= ~OKM_MB_INITED; 834 835 /* Iterate until mailbox gets connected */ 836 while (!(okmsp->km_state & OKM_MB_CONN)) { 837 DPRINTF(DBG_MBOX, ("okm_mbox_init: calling mb_init\n")); 838 ret = scf_mb_init(okmsp->km_target, okmsp->km_key, 839 okm_event_handler, (void *)okmsp); 840 DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret)); 841 842 if (ret != 0) { 843 DPRINTF(DBG_MBOX, 844 ("okm_mbox_init: failed ret =%d\n", ret)); 845 DTRACE_PROBE1(okm_mbox_fail, int, ret); 846 } else { 847 okmsp->km_state |= OKM_MB_INITED; 848 849 /* Block until the mailbox is ready to communicate. */ 850 while (!(okmsp->km_state & 851 (OKM_MB_CONN | OKM_MB_DISC))) { 852 853 if (cv_wait_sig(&okmsp->km_wait, 854 &okmsp->km_lock) <= 0) { 855 /* interrupted */ 856 ret = EINTR; 857 break; 858 } 859 } 860 } 861 862 if ((ret != 0) || (okmsp->km_state & OKM_MB_DISC)) { 863 864 if (okmsp->km_state & OKM_MB_INITED) { 865 (void) scf_mb_fini(okmsp->km_target, 866 okmsp->km_key); 867 } 868 if (okmsp->km_state & OKM_MB_DISC) { 869 DPRINTF(DBG_WARN, 870 ("okm_mbox_init: mbox DISC_ERROR\n")); 871 DTRACE_PROBE1(okm_mbox_fail, 872 int, OKM_MB_DISC); 873 } 874 875 okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_DISC | 876 OKM_MB_CONN); 877 878 if (ret == EINTR) { 879 return (ret); 880 } 881 882 /* 883 * If there was failure, then wait for 884 * OKM_MB_TOUT secs and retry again. 885 */ 886 887 DPRINTF(DBG_MBOX, ("okm_mbox_init: waiting...\n")); 888 tout = drv_usectohz(OKM_MB_TOUT); 889 ret = cv_reltimedwait_sig(&okmsp->km_wait, 890 &okmsp->km_lock, tout, TR_CLOCK_TICK); 891 if (ret == 0) { 892 /* if interrupted, return immediately. */ 893 DPRINTF(DBG_MBOX, 894 ("okm_mbox_init: interrupted\n")); 895 return (EINTR); 896 } 897 } 898 } 899 900 ret = scf_mb_ctrl(okmsp->km_target, okmsp->km_key, 901 SCF_MBOP_MAXMSGSIZE, &okmsp->km_maxsz); 902 903 /* 904 * The max msg size should be at least the size of reply 905 * we need to send. 906 */ 907 if ((ret == 0) && (okmsp->km_maxsz < sizeof (okm_rep_hdr_t))) { 908 cmn_err(CE_WARN, "Max message size expected >= %ld " 909 "but found %d\n", sizeof (okm_rep_hdr_t), okmsp->km_maxsz); 910 ret = EIO; 911 } 912 if (ret != 0) { 913 okmsp->km_state &= ~OKM_MB_INITED; 914 (void) scf_mb_fini(okmsp->km_target, okmsp->km_key); 915 } 916 DPRINTF(DBG_MBOX, ("okm_mbox_init: mb_init ret=%d\n", ret)); 917 return (ret); 918 } 919 920 /* 921 * okm_mbox_fini - Mailbox de-initialization. 922 */ 923 static void 924 okm_mbox_fini(okms_t *okmsp) 925 { 926 int ret = 0; 927 928 ASSERT(MUTEX_HELD(&okmsp->km_lock)); 929 if (okmsp->km_state & OKM_MB_INITED) { 930 DPRINTF(DBG_MBOX, ("okm_mbox_fini: calling mb_fini\n")); 931 ret = scf_mb_fini(okmsp->km_target, okmsp->km_key); 932 DPRINTF(DBG_MBOX, ("okm_mbox_fini: mb_fini ret=%d\n", ret)); 933 if (ret != 0) { 934 cmn_err(CE_WARN, 935 "Failed to close the Mailbox error=%d", ret); 936 } 937 okmsp->km_state &= ~(OKM_MB_INITED | OKM_MB_CONN | OKM_MB_DISC); 938 } 939 } 940 941 /* 942 * okm_event_handler - Mailbox event handler. 943 * 944 * Description: Implements a state machine to handle all the mailbox 945 * events. For each event, it sets the appropriate state 946 * flag and wakes up the threads waiting for that event. 947 */ 948 void 949 okm_event_handler(scf_event_t event, void *arg) 950 { 951 okms_t *okmsp = (okms_t *)arg; 952 953 DPRINTF(DBG_MBOX, ("okm_event_handler: called\n")); 954 ASSERT(okmsp != NULL); 955 mutex_enter(&okmsp->km_lock); 956 if (!(okmsp->km_state & OKM_MB_INITED)) { 957 /* 958 * Ignore all events if the state flag indicates that the 959 * mailbox not initialized, this may happen during the close. 960 */ 961 mutex_exit(&okmsp->km_lock); 962 DPRINTF(DBG_MBOX, 963 ("okm_event_handler: event=0x%X - mailbox not inited \n", 964 event)); 965 return; 966 } 967 switch (event) { 968 case SCF_MB_CONN_OK: 969 DPRINTF(DBG_MBOX, ("okm_event_handler: Event CONN_OK\n")); 970 /* 971 * Now the mailbox is ready to use, lets wake up 972 * any one waiting for this event. 973 */ 974 okmsp->km_state |= OKM_MB_CONN; 975 cv_broadcast(&okmsp->km_wait); 976 break; 977 978 case SCF_MB_MSG_DATA: 979 DPRINTF(DBG_MBOX, ("okm_event_handler: Event MSG_DATA\n")); 980 /* 981 * A message is available in the mailbox, 982 * wakeup if any one is ready to read the message. 983 */ 984 if (OKM_MBOX_READY(okmsp)) { 985 cv_broadcast(&okmsp->km_wait); 986 } 987 break; 988 989 case SCF_MB_SPACE: 990 DPRINTF(DBG_MBOX, ("okm_event_handler: Event MB_SPACE\n")); 991 /* 992 * Now the mailbox is ready to transmit, lets 993 * wakeup if any one is waiting to write. 994 */ 995 if (OKM_MBOX_READY(okmsp)) { 996 cv_broadcast(&okmsp->km_wait); 997 } 998 break; 999 case SCF_MB_DISC_ERROR: 1000 DPRINTF(DBG_MBOX, ("okm_event_handler: Event DISC_ERROR\n")); 1001 okmsp->km_state &= ~OKM_MB_CONN; 1002 okmsp->km_state |= OKM_MB_DISC; 1003 cv_broadcast(&okmsp->km_wait); 1004 break; 1005 default: 1006 cmn_err(CE_WARN, "Unexpected event received\n"); 1007 } 1008 mutex_exit(&okmsp->km_lock); 1009 } 1010 1011 /* 1012 * okm_send_reply - Send a mailbox reply message. 1013 */ 1014 int 1015 okm_send_reply(okms_t *okmsp, uint32_t transid, 1016 uint32_t status, uint32_t sadb_err, uint32_t sadb_ver) 1017 { 1018 okm_rep_hdr_t reply; 1019 int ret = EIO; 1020 1021 DPRINTF(DBG_DRV, ("okm_send_reply: called\n")); 1022 ASSERT(MUTEX_HELD(&okmsp->km_lock)); 1023 reply.krp_version = htonl(OKM_PROTOCOL_VERSION); 1024 reply.krp_transid = htonl(transid); 1025 reply.krp_status = htonl(status); 1026 reply.krp_sadb_errno = htonl(sadb_err); 1027 reply.krp_sadb_version = htonl(sadb_ver); 1028 okmsp->km_sg_tx.msc_dptr = (caddr_t)&reply; 1029 okmsp->km_sg_tx.msc_len = sizeof (reply); 1030 DUMP_REPLY(&reply); 1031 1032 while (OKM_MBOX_READY(okmsp)) { 1033 DPRINTF(DBG_MBOX, ("okm_send_reply: sending reply\n")); 1034 ret = scf_mb_putmsg(okmsp->km_target, okmsp->km_key, 1035 sizeof (reply), 1, &okmsp->km_sg_tx, 0); 1036 DPRINTF(DBG_MBOX, ("okm_send_reply: putmsg ret=%d\n", ret)); 1037 if (ret == EBUSY || ret == ENOSPC) { 1038 /* mailbox is busy, poll/retry */ 1039 if (cv_timedwait_sig(&okmsp->km_wait, 1040 &okmsp->km_lock, okm_timeout_val(ret)) == 0) { 1041 /* interrupted */ 1042 ret = EINTR; 1043 DPRINTF(DBG_DRV, 1044 ("okm_send_reply: interrupted\n")); 1045 break; 1046 } 1047 } else { 1048 break; 1049 } 1050 } 1051 DPRINTF(DBG_DRV, ("okm_send_reply: ret=%d\n", ret)); 1052 return (ret); 1053 } 1054 1055 /* 1056 * okm_timeout_val -- Return appropriate timeout value. 1057 * 1058 * A small timeout value is returned for EBUSY as the mailbox busy 1059 * condition may go away sooner and we are expected to poll. 1060 * 1061 * A larger timeout value is returned for ENOSPC case, as the condition 1062 * depends on the peer to release buffer space. 1063 * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is 1064 * used for reliability purposes. 1065 */ 1066 static clock_t 1067 okm_timeout_val(int error) 1068 { 1069 clock_t tval; 1070 1071 ASSERT(error == EBUSY || error == ENOSPC); 1072 1073 if (error == EBUSY) { 1074 tval = OKM_SM_TOUT; 1075 } else { 1076 tval = OKM_LG_TOUT; 1077 } 1078 return (drv_usectohz(tval)); 1079 } 1080 1081 #ifdef DEBUG 1082 static void 1083 okm_print_req(okm_req_hdr_t *reqp, uint32_t len) 1084 { 1085 uint8_t *datap = (uint8_t *)(((char *)reqp) + sizeof (okm_req_hdr_t)); 1086 int msglen = len - sizeof (okm_req_hdr_t); 1087 int i, j; 1088 #define BYTES_PER_LINE 20 1089 char bytestr[BYTES_PER_LINE * 3 + 1]; 1090 1091 if (!(okm_debug & DBG_MESG)) 1092 return; 1093 printf("OKM: Request ver=%d transid=%d cmd=%s\n", 1094 reqp->krq_version, reqp->krq_transid, 1095 ((reqp->krq_cmd == OKM_MSG_SADB) ? "MSG_SADB" : "UNKNOWN")); 1096 for (i = 0; i < msglen; ) { 1097 for (j = 0; (j < BYTES_PER_LINE) && (i < msglen); j++, i++) { 1098 (void) sprintf(&bytestr[j * 3], "%02X ", datap[i]); 1099 } 1100 if (j != 0) { 1101 printf("\t%s\n", bytestr); 1102 } 1103 } 1104 } 1105 1106 static void 1107 okm_print_rep(okm_rep_hdr_t *repp) 1108 { 1109 if (!(okm_debug & DBG_MESG)) 1110 return; 1111 printf("OKM: Reply Ver=%d Transid=%d Status=%d ", 1112 repp->krp_version, repp->krp_transid, repp->krp_status); 1113 printf("Sadb_errno=%d Sadb_ver=%d\n", repp->krp_sadb_errno, 1114 repp->krp_sadb_version); 1115 } 1116 #endif 1117