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 2008 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 #include <sys/types.h> 30 #include <sys/door.h> 31 #include <sys/note.h> 32 #include <sys/drctl.h> 33 #include <sys/drctl_impl.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/dr_util.h> 37 38 static door_handle_t drctl_dh; /* Door for upcalls */ 39 40 41 int 42 i_drctl_ioctl(int cmd, intptr_t arg) 43 { 44 int rv; 45 drctl_setup_t setup_rqst; 46 47 switch (cmd) { 48 case DRCTL_IOCTL_CONNECT_SERVER: 49 if (ddi_copyin((caddr_t)arg, 50 &setup_rqst, sizeof (setup_rqst), 0) != 0) { 51 cmn_err(CE_WARN, "i_drctl_ioctl: ddi_copyin failed " 52 "for DRCTL_IOCTL_CONNECT_SERVER"); 53 rv = EFAULT; 54 break; 55 } 56 57 drctl_dh = door_ki_lookup(setup_rqst.did); 58 rv = 0; 59 break; 60 61 default: 62 rv = EIO; 63 } 64 65 return (rv); 66 } 67 68 int 69 i_drctl_send(void *msg, size_t size, void **obufp, size_t *osize) 70 { 71 int up_err; 72 int rv = 0; 73 door_arg_t door_args; 74 door_handle_t dh = drctl_dh; 75 static const char me[] = "i_drctl_send"; 76 77 retry: 78 if (dh) 79 door_ki_hold(dh); 80 else 81 return (EIO); 82 83 door_args.data_ptr = (char *)msg; 84 door_args.data_size = size; 85 door_args.desc_ptr = NULL; 86 door_args.desc_num = 0; 87 88 /* 89 * We don't know the size of the message the daemon 90 * will pass back to us. By setting rbuf to NULL, 91 * we force the door code to allocate a buf of the 92 * appropriate size. We must set rsize > 0, however, 93 * else the door code acts as if no response was 94 * expected and doesn't pass the data to us. 95 */ 96 door_args.rbuf = NULL; 97 door_args.rsize = 1; 98 DR_DBG_CTL("%s: msg %p size %ld obufp %p osize %p\n", 99 me, msg, size, (void *)obufp, (void *)osize); 100 101 up_err = door_ki_upcall_limited(dh, &door_args, NULL, SIZE_MAX, 0); 102 if (up_err == 0) { 103 if (door_args.rbuf == NULL) 104 goto done; 105 106 DR_DBG_CTL("%s: rbuf %p rsize %ld\n", me, 107 (void *)door_args.rbuf, door_args.rsize); 108 109 if (obufp != NULL) { 110 *obufp = door_args.rbuf; 111 *osize = door_args.rsize; 112 } else { 113 /* 114 * No output buffer pointer was passed in, 115 * so the response buffer allocated by the 116 * door code must be deallocated. 117 */ 118 kmem_free(door_args.rbuf, door_args.rsize); 119 } 120 } else { 121 switch (up_err) { 122 case EINTR: 123 DR_DBG_CTL("%s: door call returned EINTR\n", me); 124 _NOTE(FALLTHROUGH) 125 case EAGAIN: 126 /* 127 * Server process may be forking, try again. 128 */ 129 door_ki_rele(dh); 130 delay(hz); 131 goto retry; 132 case EBADF: 133 case EINVAL: 134 drctl_dh = NULL; 135 DR_DBG_CTL( 136 "%s: door call failed with %d\n", me, up_err); 137 rv = EIO; 138 break; 139 default: 140 DR_DBG_CTL("%s: unexpected return " 141 "code %d from door_ki_upcall\n", me, up_err); 142 rv = EIO; 143 break; 144 } 145 } 146 147 done: 148 door_ki_rele(dh); 149 return (rv); 150 } 151