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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Starcat IPSec Key Management Driver. 31 * 32 * This driver runs on a Starcat Domain. It processes requests received 33 * from the System Controller (SC) from IOSRAM, passes these requests 34 * to the sckmd daemon by means of an open/close/ioctl interface, and 35 * sends corresponding status information back to the SC. 36 * 37 * Requests received from the SC consist of IPsec security associations 38 * (SAs) needed to secure the communication between SC and Domain daemons 39 * communicating using the Management Network (MAN). 40 */ 41 42 #include <sys/types.h> 43 #include <sys/cmn_err.h> 44 #include <sys/kmem.h> 45 #include <sys/errno.h> 46 #include <sys/file.h> 47 #include <sys/open.h> 48 #include <sys/stat.h> 49 #include <sys/conf.h> 50 #include <sys/ddi.h> 51 #include <sys/cmn_err.h> 52 #include <sys/sunddi.h> 53 #include <sys/sunndi.h> 54 #include <sys/ddi_impldefs.h> 55 #include <sys/ndi_impldefs.h> 56 #include <sys/modctl.h> 57 #include <sys/disp.h> 58 #include <sys/async.h> 59 #include <sys/mboxsc.h> 60 #include <sys/sckm_msg.h> 61 #include <sys/sckm_io.h> 62 #include <sys/taskq.h> 63 #include <sys/note.h> 64 65 #ifdef DEBUG 66 static uint_t sckm_debug_flags = 0x0; 67 #define SCKM_DEBUG0(f, s) if ((f)& sckm_debug_flags) \ 68 cmn_err(CE_CONT, s) 69 #define SCKM_DEBUG1(f, s, a) if ((f)& sckm_debug_flags) \ 70 cmn_err(CE_CONT, s, a) 71 #define SCKM_DEBUG2(f, s, a, b) if ((f)& sckm_debug_flags) \ 72 cmn_err(CE_CONT, s, a, b) 73 #define SCKM_DEBUG3(f, s, a, b, c) if ((f)& sckm_debug_flags) \ 74 cmn_err(CE_CONT, s, a, b, c) 75 #define SCKM_DEBUG4(f, s, a, b, c, d) if ((f)& sckm_debug_flags) \ 76 cmn_err(CE_CONT, s, a, b, c, d) 77 #define SCKM_DEBUG5(f, s, a, b, c, d, e) if ((f)& sckm_debug_flags) \ 78 cmn_err(CE_CONT, s, a, b, c, d, e) 79 #define SCKM_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& sckm_debug_flags) \ 80 cmn_err(CE_CONT, s, a, b, c, d, e, ff) 81 #else 82 #define SCKM_DEBUG0(f, s) 83 #define SCKM_DEBUG1(f, s, a) 84 #define SCKM_DEBUG2(f, s, a, b) 85 #define SCKM_DEBUG3(f, s, a, b, c) 86 #define SCKM_DEBUG4(f, s, a, b, c, d) 87 #define SCKM_DEBUG5(f, s, a, b, c, d, e) 88 #define SCKM_DEBUG6(f, s, a, b, c, d, e, ff) 89 #endif /* DEBUG */ 90 91 #define D_INIT 0x00000001 /* _init/_fini/_info */ 92 #define D_ATTACH 0x00000002 /* attach/detach */ 93 #define D_OPEN 0x00000008 /* open/close */ 94 #define D_IOCTL 0x00010000 /* ioctl */ 95 #define D_TASK 0x00100000 /* mailbox task processing */ 96 #define D_CALLBACK 0x00200000 /* mailbox callback */ 97 98 static int sckm_open(dev_t *, int, int, struct cred *); 99 static int sckm_close(dev_t, int, int, struct cred *); 100 static int sckm_ioctl(dev_t, int, intptr_t, int, struct cred *, int *); 101 102 static struct cb_ops sckm_cb_ops = { 103 sckm_open, /* open */ 104 sckm_close, /* close */ 105 nodev, /* strategy */ 106 nodev, /* print */ 107 nodev, /* dump */ 108 nodev, /* read */ 109 nodev, /* write */ 110 sckm_ioctl, /* ioctl */ 111 nodev, /* devmap */ 112 nodev, /* mmap */ 113 nodev, /* segmap */ 114 nochpoll, /* poll */ 115 ddi_prop_op, /* prop_op */ 116 0, /* streamtab */ 117 D_NEW | D_MP /* Driver compatibility flag */ 118 }; 119 120 static int sckm_attach(dev_info_t *, ddi_attach_cmd_t); 121 static int sckm_detach(dev_info_t *, ddi_detach_cmd_t); 122 static int sckm_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 123 124 static struct dev_ops sckm_ops = { 125 DEVO_REV, /* devo_rev, */ 126 0, /* refcnt */ 127 sckm_info, /* get_dev_info */ 128 nulldev, /* identify */ 129 nulldev, /* probe */ 130 sckm_attach, /* attach */ 131 sckm_detach, /* detach */ 132 nodev, /* reset */ 133 &sckm_cb_ops, /* driver operations */ 134 (struct bus_ops *)0 /* no bus operations */ 135 }; 136 137 static struct modldrv modldrv = { 138 &mod_driverops, 139 "Key Management Driver v%I%", 140 &sckm_ops, 141 }; 142 143 static struct modlinkage modlinkage = { 144 MODREV_1, 145 &modldrv, 146 NULL 147 }; 148 149 /* 150 * Private definitions. 151 */ 152 #define SCKM_DEF_GETMSG_TIMEOUT 60 /* in seconds */ 153 #define SCKM_DAEMON_TIMEOUT 4000000 /* in microseconds */ 154 #define SCKM_NUM_TASKQ 2 /* # of task queue entries */ 155 156 /* 157 * For processing mailbox layer events. 158 */ 159 static kmutex_t sckm_task_mutex; 160 static kmutex_t sckm_taskq_ptr_mutex; 161 static clock_t sckm_getmsg_timeout = SCKM_DEF_GETMSG_TIMEOUT*1000; 162 static taskq_t *sckm_taskq = NULL; 163 static sckm_mbox_req_hdr_t *req_data = NULL; 164 static sckm_mbox_rep_hdr_t *rep_data = NULL; 165 166 167 /* 168 * For synchronization with key management daemon. 169 */ 170 static kmutex_t sckm_umutex; 171 static kcondvar_t sckm_udata_cv; /* daemon waits on data */ 172 static kcondvar_t sckm_cons_cv; /* wait for daemon to consume data */ 173 static boolean_t sckm_udata_req = B_FALSE; /* data available for daemon */ 174 static sckm_ioctl_getreq_t sckm_udata; /* request for daemon */ 175 static sckm_ioctl_status_t sckm_udata_status; /* status from daemon */ 176 177 /* 178 * Other misc private variables. 179 */ 180 static dev_info_t *sckm_devi = NULL; 181 static boolean_t sckm_oflag = B_FALSE; 182 183 /* 184 * Private functions prototypes. 185 */ 186 static void sckm_mbox_callback(void); 187 static void sckm_mbox_task(void *arg); 188 static void sckm_process_msg(uint32_t cmd, uint64_t transid, 189 uint32_t len, sckm_mbox_req_hdr_t *req_data, 190 sckm_mbox_rep_hdr_t *rep_data); 191 192 193 int 194 _init(void) 195 { 196 mboxsc_timeout_range_t timeout_range; 197 int ret; 198 199 SCKM_DEBUG0(D_INIT, "in _init"); 200 201 /* 202 * Initialize outgoing mailbox (KDSC) 203 */ 204 if ((ret = mboxsc_init(KEY_KDSC, MBOXSC_MBOX_OUT, NULL)) != 0) { 205 cmn_err(CE_WARN, "failed initializing outgoing mailbox " 206 "(%d)", ret); 207 return (ret); 208 } 209 210 /* 211 * Initialize incoming mailbox (SCKD) 212 */ 213 if ((ret = mboxsc_init(KEY_SCKD, MBOXSC_MBOX_IN, 214 sckm_mbox_callback)) != 0) { 215 cmn_err(CE_WARN, "failed initializing incoming mailbox " 216 "(%d)\n", ret); 217 mboxsc_fini(KEY_KDSC); 218 return (ret); 219 } 220 221 if ((ret = mboxsc_ctrl(KEY_SCKD, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE, 222 (void *)&timeout_range)) != 0) { 223 mboxsc_fini(KEY_SCKD); 224 mboxsc_fini(KEY_KDSC); 225 return (ret); 226 } 227 228 if (sckm_getmsg_timeout < timeout_range.min_timeout) { 229 sckm_getmsg_timeout = timeout_range.min_timeout; 230 cmn_err(CE_WARN, "resetting getmsg timeout to %lx", 231 sckm_getmsg_timeout); 232 } 233 234 if (sckm_getmsg_timeout > timeout_range.max_timeout) { 235 sckm_getmsg_timeout = timeout_range.max_timeout; 236 cmn_err(CE_WARN, "resetting getmsg timeout to %lx", 237 sckm_getmsg_timeout); 238 } 239 240 if ((ret = mod_install(&modlinkage)) != 0) { 241 mboxsc_fini(KEY_KDSC); 242 mboxsc_fini(KEY_SCKD); 243 return (ret); 244 } 245 246 /* 247 * Initialize variables needed for synchronization with daemon. 248 */ 249 sckm_udata.buf = kmem_alloc(SCKM_SCKD_MAXDATA, KM_SLEEP); 250 req_data = (sckm_mbox_req_hdr_t *)kmem_alloc(SCKM_SCKD_MAXDATA, 251 KM_SLEEP); 252 rep_data = (sckm_mbox_rep_hdr_t *)kmem_alloc(SCKM_KDSC_MAXDATA, 253 KM_SLEEP); 254 255 if ((sckm_udata.buf == NULL) || (req_data == NULL) || 256 (rep_data == NULL)) { 257 cmn_err(CE_WARN, "not enough memory during _init"); 258 259 /* free what was successfully allocated */ 260 if (sckm_udata.buf != NULL) 261 kmem_free(sckm_udata.buf, SCKM_SCKD_MAXDATA); 262 if (req_data != NULL) 263 kmem_free(req_data, SCKM_SCKD_MAXDATA); 264 if (rep_data != NULL) 265 kmem_free(rep_data, SCKM_KDSC_MAXDATA); 266 sckm_udata.buf = NULL; 267 req_data = NULL; 268 rep_data = NULL; 269 270 /* uninitialize mailboxes, remove module, and return error */ 271 mboxsc_fini(KEY_KDSC); 272 mboxsc_fini(KEY_SCKD); 273 mod_remove(&modlinkage); 274 return (-1); 275 } 276 277 cv_init(&sckm_udata_cv, NULL, CV_DRIVER, NULL); 278 cv_init(&sckm_cons_cv, NULL, CV_DRIVER, NULL); 279 mutex_init(&sckm_umutex, NULL, MUTEX_DRIVER, NULL); 280 281 /* 282 * Create mutex for task processing, protection of taskq 283 * pointer, and create taskq. 284 */ 285 mutex_init(&sckm_task_mutex, NULL, MUTEX_DRIVER, NULL); 286 mutex_init(&sckm_taskq_ptr_mutex, NULL, MUTEX_DRIVER, NULL); 287 sckm_taskq = taskq_create("sckm_taskq", 1, minclsyspri, 288 SCKM_NUM_TASKQ, SCKM_NUM_TASKQ, TASKQ_PREPOPULATE); 289 290 SCKM_DEBUG1(D_INIT, "out _init ret=%d\n", ret); 291 return (ret); 292 } 293 294 int 295 _fini(void) 296 { 297 int ret; 298 299 SCKM_DEBUG0(D_INIT, "in _fini"); 300 301 if ((ret = mod_remove(&modlinkage)) != 0) { 302 return (ret); 303 } 304 305 /* 306 * Wait for scheduled tasks to complete, then destroy task queue. 307 */ 308 mutex_enter(&sckm_taskq_ptr_mutex); 309 if (sckm_taskq != NULL) { 310 taskq_destroy(sckm_taskq); 311 sckm_taskq = NULL; 312 } 313 mutex_exit(&sckm_taskq_ptr_mutex); 314 315 /* 316 * Terminate incoming and outgoing IOSRAM mailboxes 317 */ 318 mboxsc_fini(KEY_KDSC); 319 mboxsc_fini(KEY_SCKD); 320 321 /* 322 * Destroy module synchronization objects and free memory 323 */ 324 mutex_destroy(&sckm_task_mutex); 325 mutex_destroy(&sckm_taskq_ptr_mutex); 326 mutex_destroy(&sckm_umutex); 327 cv_destroy(&sckm_cons_cv); 328 329 if (sckm_udata.buf != NULL) { 330 kmem_free(sckm_udata.buf, SCKM_SCKD_MAXDATA); 331 sckm_udata.buf = NULL; 332 } 333 if (rep_data != NULL) { 334 kmem_free(rep_data, SCKM_KDSC_MAXDATA); 335 rep_data = NULL; 336 } 337 if (req_data != NULL) { 338 kmem_free(req_data, SCKM_SCKD_MAXDATA); 339 req_data = NULL; 340 } 341 342 return (ret); 343 } 344 345 int 346 _info(struct modinfo *modinfop) 347 { 348 SCKM_DEBUG0(D_INIT, "in _info"); 349 return (mod_info(&modlinkage, modinfop)); 350 } 351 352 static int 353 sckm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 354 { 355 SCKM_DEBUG1(D_ATTACH, "in sckm_attach, cmd=%d", cmd); 356 357 switch (cmd) { 358 case DDI_ATTACH: 359 SCKM_DEBUG0(D_ATTACH, "sckm_attach: DDI_ATTACH"); 360 if (ddi_create_minor_node(devi, "sckmdrv", S_IFCHR, 361 0, NULL, NULL) == DDI_FAILURE) { 362 cmn_err(CE_WARN, "ddi_create_minor_node failed"); 363 ddi_remove_minor_node(devi, NULL); 364 return (DDI_FAILURE); 365 } 366 sckm_devi = devi; 367 break; 368 case DDI_SUSPEND: 369 SCKM_DEBUG0(D_ATTACH, "sckm_attach: DDI_SUSPEND"); 370 break; 371 default: 372 cmn_err(CE_WARN, "sckm_attach: bad cmd %d\n", cmd); 373 return (DDI_FAILURE); 374 } 375 376 SCKM_DEBUG0(D_ATTACH, "out sckm_attach (DDI_SUCCESS)"); 377 return (DDI_SUCCESS); 378 } 379 380 static int 381 sckm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 382 { 383 SCKM_DEBUG1(D_ATTACH, "in sckm_detach, cmd=%d", cmd); 384 385 switch (cmd) { 386 case DDI_DETACH: 387 SCKM_DEBUG0(D_ATTACH, "sckm_detach: DDI_DETACH"); 388 ddi_remove_minor_node(devi, NULL); 389 break; 390 case DDI_SUSPEND: 391 SCKM_DEBUG0(D_ATTACH, "sckm_detach: DDI_DETACH"); 392 break; 393 default: 394 cmn_err(CE_WARN, "sckm_detach: bad cmd %d\n", cmd); 395 return (DDI_FAILURE); 396 } 397 398 SCKM_DEBUG0(D_ATTACH, "out sckm_detach (DDI_SUCCESS)"); 399 return (DDI_SUCCESS); 400 } 401 402 /* ARGSUSED */ 403 static int 404 sckm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 405 void **result) 406 { 407 int rv; 408 409 SCKM_DEBUG1(D_ATTACH, "in sckm_info, infocmd=%d", infocmd); 410 411 switch (infocmd) { 412 case DDI_INFO_DEVT2DEVINFO: 413 *result = (void *)sckm_devi; 414 rv = DDI_SUCCESS; 415 break; 416 case DDI_INFO_DEVT2INSTANCE: 417 *result = (void *)0; 418 rv = DDI_SUCCESS; 419 break; 420 default: 421 rv = DDI_FAILURE; 422 } 423 424 SCKM_DEBUG1(D_ATTACH, "out sckm_info, rv=%d", rv); 425 return (rv); 426 } 427 428 /*ARGSUSED*/ 429 static int 430 sckm_open(dev_t *devp, int flag, int otyp, struct cred *cred) 431 { 432 SCKM_DEBUG0(D_OPEN, "in sckm_open"); 433 434 /* check credentials of calling process */ 435 if (drv_priv(cred)) { 436 SCKM_DEBUG0(D_OPEN, "sckm_open: attempt by non-root proc"); 437 return (EPERM); 438 } 439 440 /* enforce exclusive access */ 441 mutex_enter(&sckm_umutex); 442 if (sckm_oflag == B_TRUE) { 443 SCKM_DEBUG0(D_OPEN, "sckm_open: already open"); 444 mutex_exit(&sckm_umutex); 445 return (EBUSY); 446 } 447 sckm_oflag = B_TRUE; 448 mutex_exit(&sckm_umutex); 449 450 SCKM_DEBUG0(D_OPEN, "sckm_open: succcess"); 451 return (0); 452 } 453 454 /*ARGSUSED*/ 455 static int 456 sckm_close(dev_t dev, int flag, int otyp, struct cred *cred) 457 { 458 SCKM_DEBUG0(D_OPEN, "in sckm_close"); 459 460 mutex_enter(&sckm_umutex); 461 sckm_oflag = B_FALSE; 462 mutex_exit(&sckm_umutex); 463 464 return (0); 465 } 466 467 468 static int 469 sckm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg, 470 int flag) 471 { 472 #ifdef _MULTI_DATAMODEL 473 switch (ddi_model_convert_from(flag & FMODELS)) { 474 case DDI_MODEL_ILP32: { 475 sckm_ioctl_getreq32_t driverarg32; 476 if (ddi_copyin((caddr_t)userarg, &driverarg32, 477 sizeof (sckm_ioctl_getreq32_t), flag)) { 478 return (EFAULT); 479 } 480 driverarg->transid = driverarg32.transid; 481 driverarg->type = driverarg32.type; 482 driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf; 483 driverarg->buf_len = driverarg32.buf_len; 484 break; 485 } 486 case DDI_MODEL_NONE: { 487 if (ddi_copyin((caddr_t)userarg, &driverarg, 488 sizeof (sckm_ioctl_getreq_t), flag)) { 489 return (EFAULT); 490 } 491 break; 492 } 493 } 494 #else /* ! _MULTI_DATAMODEL */ 495 if (ddi_copyin((caddr_t)userarg, &driverarg, 496 sizeof (sckm_ioctl_getreq_t), flag)) { 497 return (EFAULT); 498 } 499 #endif /* _MULTI_DATAMODEL */ 500 return (0); 501 } 502 503 504 static int 505 sckm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg, 506 int flag) 507 { 508 #ifdef _MULTI_DATAMODEL 509 switch (ddi_model_convert_from(flag & FMODELS)) { 510 case DDI_MODEL_ILP32: { 511 sckm_ioctl_getreq32_t driverarg32; 512 driverarg32.transid = driverarg->transid; 513 driverarg32.type = driverarg->type; 514 driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf; 515 driverarg32.buf_len = driverarg->buf_len; 516 if (ddi_copyout(&driverarg32, (caddr_t)userarg, 517 sizeof (sckm_ioctl_getreq32_t), flag)) { 518 return (EFAULT); 519 } 520 break; 521 } 522 case DDI_MODEL_NONE: 523 if (ddi_copyout(driverarg, (caddr_t)userarg, 524 sizeof (sckm_ioctl_getreq_t), flag)) { 525 return (EFAULT); 526 } 527 break; 528 } 529 #else /* ! _MULTI_DATAMODEL */ 530 if (ddi_copyout(driverarg, (caddr_t)userarg, 531 sizeof (sckm_ioctl_getreq_t), flag)) { 532 return (EFAULT); 533 } 534 #endif /* _MULTI_DATAMODEL */ 535 return (0); 536 } 537 538 539 /*ARGSUSED*/ 540 static int 541 sckm_ioctl(dev_t dev, int cmd, intptr_t data, int flag, 542 cred_t *cred, int *rvalp) 543 { 544 int rval = 0; 545 546 SCKM_DEBUG0(D_IOCTL, "in sckm_ioctl"); 547 548 switch (cmd) { 549 case SCKM_IOCTL_GETREQ: { 550 sckm_ioctl_getreq_t arg; 551 552 SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: got SCKM_IOCTL_GETREQ"); 553 if (sckm_copyin_ioctl_getreq(data, &arg, flag)) { 554 return (EFAULT); 555 } 556 557 /* sanity check argument */ 558 if (arg.buf_len < SCKM_SCKD_MAXDATA) { 559 SCKM_DEBUG2(D_IOCTL, "sckm_ioctl: usr buffer too " 560 "small (%d < %d)", arg.buf_len, SCKM_SCKD_MAXDATA); 561 return (ENOSPC); 562 } 563 564 mutex_enter(&sckm_umutex); 565 566 /* wait for request from SC */ 567 while (!sckm_udata_req) { 568 SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: waiting for msg"); 569 if (cv_wait_sig(&sckm_udata_cv, &sckm_umutex) == 0) { 570 mutex_exit(&sckm_umutex); 571 return (EINTR); 572 } 573 } 574 SCKM_DEBUG1(D_IOCTL, "sckm_ioctl: msg available " 575 "transid = 0x%lx", sckm_udata.transid); 576 577 arg.transid = sckm_udata.transid; 578 arg.type = sckm_udata.type; 579 if (ddi_copyout(sckm_udata.buf, arg.buf, 580 sckm_udata.buf_len, flag)) { 581 mutex_exit(&sckm_umutex); 582 return (EFAULT); 583 } 584 arg.buf_len = sckm_udata.buf_len; 585 586 mutex_exit(&sckm_umutex); 587 if (sckm_copyout_ioctl_getreq(&arg, data, flag)) { 588 return (EFAULT); 589 } 590 break; 591 } 592 case SCKM_IOCTL_STATUS: { 593 sckm_ioctl_status_t arg; 594 SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: got SCKM_IOCTL_STATUS"); 595 if (ddi_copyin((caddr_t)data, &arg, 596 sizeof (sckm_ioctl_status_t), flag)) { 597 cmn_err(CE_WARN, "sckm_ioctl: ddi_copyin failed"); 598 return (EFAULT); 599 } 600 SCKM_DEBUG3(D_IOCTL, "sckm_ioctl: arg transid=0x%lx, " 601 "status=%d, sadb_msg_errno=%d", arg.transid, arg.status, 602 arg.sadb_msg_errno); 603 604 mutex_enter(&sckm_umutex); 605 606 /* fail if no status is expected, or if it does not match */ 607 if (!sckm_udata_req || sckm_udata.transid != arg.transid) { 608 mutex_exit(&sckm_umutex); 609 return (EINVAL); 610 } 611 612 /* update status information for event handler */ 613 bcopy(&arg, &sckm_udata_status, sizeof (sckm_ioctl_status_t)); 614 615 /* signal event handler that request has been processed */ 616 SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: signaling event handler" 617 " that data has been processed"); 618 cv_signal(&sckm_cons_cv); 619 sckm_udata_req = B_FALSE; 620 621 mutex_exit(&sckm_umutex); 622 break; 623 } 624 default: 625 SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: unknown command"); 626 rval = EINVAL; 627 } 628 629 SCKM_DEBUG1(D_IOCTL, "out sckm_ioctl, rval=%d", rval); 630 return (rval); 631 } 632 633 634 /* 635 * sckm_mbox_callback 636 * 637 * Callback routine registered with the IOSRAM mailbox protocol driver. 638 * Invoked when a message is received on the mailbox. 639 */ 640 static void 641 sckm_mbox_callback(void) 642 { 643 SCKM_DEBUG0(D_CALLBACK, "in sckm_mbox_callback()"); 644 645 mutex_enter(&sckm_taskq_ptr_mutex); 646 647 if (sckm_taskq == NULL) { 648 mutex_exit(&sckm_taskq_ptr_mutex); 649 return; 650 } 651 652 if (!taskq_dispatch(sckm_taskq, sckm_mbox_task, NULL, KM_NOSLEEP)) { 653 /* 654 * Too many tasks already pending. Do not queue a new 655 * request. 656 */ 657 SCKM_DEBUG0(D_CALLBACK, "failed dispatching task"); 658 } 659 660 mutex_exit(&sckm_taskq_ptr_mutex); 661 662 SCKM_DEBUG0(D_CALLBACK, "out sckm_mbox_callback()"); 663 } 664 665 666 /* 667 * sckm_mbox_task 668 * 669 * Dispatched on taskq from the IOSRAM mailbox callback 670 * sckm_mbox_callback when a message is received on the incoming 671 * mailbox. 672 */ 673 static void 674 sckm_mbox_task(void *ignored) 675 { 676 _NOTE(ARGUNUSED(ignored)) 677 uint32_t type, cmd, length; 678 uint64_t transid; 679 int rval; 680 681 SCKM_DEBUG0(D_TASK, "in sckm_mbox_task\n"); 682 683 mutex_enter(&sckm_task_mutex); 684 685 if (req_data == NULL || rep_data == NULL) { 686 SCKM_DEBUG0(D_TASK, "sckm_mbox_task: no buffers"); 687 mutex_exit(&sckm_task_mutex); 688 return; 689 } 690 691 /* 692 * Get mailbox message. 693 */ 694 695 type = MBOXSC_MSG_REQUEST; 696 length = SCKM_SCKD_MAXDATA; 697 cmd = 0; 698 transid = 0; 699 700 SCKM_DEBUG0(D_TASK, "sckm_mbox_task: " 701 "calling mboxsc_getmsg()\n"); 702 rval = mboxsc_getmsg(KEY_SCKD, &type, &cmd, &transid, 703 &length, req_data, sckm_getmsg_timeout); 704 705 if (rval != 0) { 706 SCKM_DEBUG1(D_TASK, "sckm_mbox_task: " 707 "mboxsc_getmsg() failed (%d)\n", rval); 708 mutex_exit(&sckm_task_mutex); 709 return; 710 } 711 712 SCKM_DEBUG4(D_TASK, "sckm_mbox_task: " 713 "type=0x%x cmd=0x%x length=%d transid=0x%lx\n", 714 type, cmd, length, transid); 715 716 /* check message length */ 717 if (length < sizeof (sckm_mbox_req_hdr_t)) { 718 /* protocol error, drop message */ 719 SCKM_DEBUG2(D_TASK, "received short " 720 "message of length %d, min %lu", 721 length, sizeof (sckm_mbox_req_hdr_t)); 722 mutex_exit(&sckm_task_mutex); 723 return; 724 } 725 726 /* check version of message received */ 727 if (req_data->sckm_version != SCKM_PROTOCOL_VERSION) { 728 SCKM_DEBUG2(D_TASK, "received protocol " 729 "version %d, expected %d", 730 req_data->sckm_version, SCKM_PROTOCOL_VERSION); 731 /* 732 * Send reply with SCKM_SADB_ERR_VERSION error 733 * so that SC can adopt correct protocol version 734 * for this domain. 735 */ 736 rep_data->sckm_version = SCKM_PROTOCOL_VERSION; 737 rep_data->status = SCKM_ERR_VERSION; 738 739 rval = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY, 740 cmd, &transid, sizeof (sckm_mbox_rep_hdr_t), 741 rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT); 742 743 if (rval != 0) { 744 SCKM_DEBUG1(D_TASK, "sckm_mbox_task: " 745 "mboxsc_putmsg() failed (%d)\n", rval); 746 mutex_exit(&sckm_task_mutex); 747 return; 748 } 749 } 750 751 /* process message */ 752 sckm_process_msg(cmd, transid, length, 753 req_data, rep_data); 754 755 mutex_exit(&sckm_task_mutex); 756 } 757 758 /* 759 * sckm_process_msg 760 * 761 * Process a message received from the SC. Invoked by sckm_event_task(). 762 */ 763 static void 764 sckm_process_msg(uint32_t cmd, uint64_t transid, 765 uint32_t len, sckm_mbox_req_hdr_t *req_data, 766 sckm_mbox_rep_hdr_t *rep_data) 767 { 768 int rv; 769 770 mutex_enter(&sckm_umutex); 771 772 switch (cmd) { 773 case SCKM_MSG_SADB: { 774 int sadb_msglen; 775 776 sadb_msglen = len-sizeof (sckm_mbox_req_hdr_t); 777 SCKM_DEBUG1(D_TASK, "received SCKM_MSG_SADB len=%d", 778 sadb_msglen); 779 780 /* sanity check request */ 781 if (len-sizeof (sckm_mbox_req_hdr_t) <= 0) { 782 SCKM_DEBUG0(D_TASK, "bad SADB message, " 783 "zero length"); 784 /* 785 * SADB message is too short, send corresponding 786 * error message to SC. 787 */ 788 rep_data->sckm_version = SCKM_PROTOCOL_VERSION; 789 rep_data->status = SCKM_ERR_SADB_MSG; 790 791 if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY, 792 cmd, &transid, sizeof (sckm_mbox_rep_hdr_t), 793 rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) { 794 SCKM_DEBUG1(D_TASK, "sckm_mbox_task: " 795 "mboxsc_putmsg() failed (%d)\n", rv); 796 } 797 mutex_exit(&sckm_umutex); 798 return; 799 } 800 801 /* initialize request for daemon */ 802 sckm_udata.transid = transid; 803 sckm_udata.type = SCKM_IOCTL_REQ_SADB; 804 sckm_udata.buf_len = len-sizeof (sckm_mbox_req_hdr_t); 805 bcopy(req_data+1, sckm_udata.buf, sckm_udata.buf_len); 806 807 break; 808 } 809 default: 810 cmn_err(CE_WARN, "unknown cmd %x received from SC", cmd); 811 /* 812 * Received unknown command from SC. Send corresponding 813 * error message to SC. 814 */ 815 rep_data->sckm_version = SCKM_PROTOCOL_VERSION; 816 rep_data->status = SCKM_ERR_BAD_CMD; 817 818 if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY, 819 cmd, &transid, sizeof (sckm_mbox_rep_hdr_t), 820 rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) { 821 SCKM_DEBUG1(D_TASK, "sckm_mbox_task: " 822 "mboxsc_putmsg() failed (%d)\n", rv); 823 } 824 mutex_exit(&sckm_umutex); 825 return; 826 } 827 828 /* 829 * At this point, we know that the request is valid, so pass 830 * the request to the daemon. 831 */ 832 SCKM_DEBUG0(D_TASK, "waking up daemon"); 833 sckm_udata_req = B_TRUE; 834 cv_signal(&sckm_udata_cv); 835 836 /* wait for daemon to process request */ 837 if (cv_timedwait(&sckm_cons_cv, &sckm_umutex, 838 ddi_get_lbolt()+drv_usectohz(SCKM_DAEMON_TIMEOUT)) == -1) { 839 /* 840 * Daemon did not process the data, report this 841 * error to the SC. 842 */ 843 SCKM_DEBUG0(D_TASK, "daemon timeout!!"); 844 rep_data->sckm_version = SCKM_PROTOCOL_VERSION; 845 rep_data->status = SCKM_ERR_DAEMON; 846 } else { 847 /* Daemon processed data, return status to SC */ 848 SCKM_DEBUG0(D_TASK, "daemon processed data"); 849 rep_data->sckm_version = SCKM_PROTOCOL_VERSION; 850 switch (sckm_udata_status.status) { 851 case SCKM_IOCTL_STAT_SUCCESS: 852 SCKM_DEBUG0(D_TASK, "daemon returned success"); 853 rep_data->status = SCKM_SUCCESS; 854 break; 855 case SCKM_IOCTL_STAT_ERR_PFKEY: 856 SCKM_DEBUG1(D_TASK, "daemon returned PF_KEY " 857 "error, errno=%d", 858 sckm_udata_status.sadb_msg_errno); 859 rep_data->status = SCKM_ERR_SADB_PFKEY; 860 rep_data->sadb_msg_errno = 861 sckm_udata_status.sadb_msg_errno; 862 break; 863 case SCKM_IOCTL_STAT_ERR_REQ: 864 SCKM_DEBUG0(D_TASK, "daemon returned " 865 "bad request"); 866 rep_data->status = SCKM_ERR_DAEMON; 867 break; 868 case SCKM_IOCTL_STAT_ERR_VERSION: 869 SCKM_DEBUG0(D_TASK, "PF_KEY version not " 870 "supported"); 871 rep_data->status = SCKM_ERR_SADB_VERSION; 872 rep_data->sadb_msg_version = 873 sckm_udata_status.sadb_msg_version; 874 break; 875 case SCKM_IOCTL_STAT_ERR_TIMEOUT: 876 SCKM_DEBUG0(D_TASK, "no response received " 877 "from key engine"); 878 rep_data->status = SCKM_ERR_SADB_TIMEOUT; 879 break; 880 case SCKM_IOCTL_STAT_ERR_OTHER: 881 SCKM_DEBUG0(D_TASK, "daemon encountered " 882 "an error"); 883 rep_data->status = SCKM_ERR_DAEMON; 884 break; 885 case SCKM_IOCTL_STAT_ERR_SADB_TYPE: 886 SCKM_DEBUG0(D_TASK, "daemon returned bad " 887 "SADB message type"); 888 rep_data->status = SCKM_ERR_SADB_BAD_TYPE; 889 break; 890 default: 891 cmn_err(CE_WARN, "SCKM daemon returned " 892 "invalid status %d", sckm_udata_status.status); 893 rep_data->status = SCKM_ERR_DAEMON; 894 } 895 } 896 897 /* send reply back to SC */ 898 if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY, 899 cmd, &transid, sizeof (sckm_mbox_rep_hdr_t), 900 rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) { 901 SCKM_DEBUG1(D_TASK, "failed sending reply to SC (%d)", rv); 902 } else { 903 SCKM_DEBUG0(D_TASK, "reply sent to SC"); 904 } 905 906 sckm_udata_req = B_FALSE; 907 mutex_exit(&sckm_umutex); 908 } 909