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