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 2008 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 * Context functions to support the RPC interface library. 30 */ 31 32 #include <sys/errno.h> 33 #include <strings.h> 34 35 #include <smbsrv/libsmb.h> 36 #include <smbsrv/libsmbrdr.h> 37 #include <smbsrv/ndr.h> 38 #include <smbsrv/mlrpc.h> 39 #include <smbsrv/mlsvc_util.h> 40 41 static int mlsvc_xa_init(struct mlrpc_client *, struct mlrpc_xaction *, 42 mlrpc_heap_t *); 43 static int mlsvc_xa_exchange(struct mlrpc_client *, struct mlrpc_xaction *); 44 static int mlsvc_xa_read(struct mlrpc_client *, struct mlrpc_xaction *); 45 static int mlsvc_xa_preserve(struct mlrpc_client *, struct mlrpc_xaction *, 46 mlrpc_heapref_t *); 47 static int mlsvc_xa_destruct(struct mlrpc_client *, struct mlrpc_xaction *); 48 static void mlsvc_xa_release(struct mlrpc_client *, mlrpc_heapref_t *heapref); 49 50 /* 51 * mlsvc_rpc_bind 52 * 53 * This the entry point for all client RPC services. This call must be 54 * made to initialize an RPC context structure and bind to the remote 55 * service before any RPCs can be exchanged with that service. The 56 * descriptor is a wrapper that is used to associate an RPC handle with 57 * the context data for that specific instance of the interface. The 58 * handle is zeroed to ensure that it doesn't look like a valid handle. 59 * The context handle is assigned to point at the RPC handle so that we 60 * know when to free the context. As each handle is initialized it will 61 * include a pointer to this context but only when we close this initial 62 * RPC handle can the context be freed. 63 * 64 * On success, return a pointer to the descriptor. Otherwise return a 65 * null pointer. 66 */ 67 int 68 mlsvc_rpc_bind(mlsvc_handle_t *desc, int fid, char *service) 69 { 70 struct mlsvc_rpc_context *context; 71 int rc; 72 73 bzero(&desc->handle, sizeof (ms_handle_t)); 74 75 context = malloc(sizeof (struct mlsvc_rpc_context)); 76 if ((desc->context = context) == NULL) 77 return (-1); 78 79 bzero(context, sizeof (struct mlsvc_rpc_context)); 80 context->cli.context = context; 81 82 mlrpc_binding_pool_initialize(&context->cli.binding_list, 83 context->binding_pool, CTXT_N_BINDING_POOL); 84 85 context->fid = fid; 86 context->handle = &desc->handle; 87 context->cli.xa_init = mlsvc_xa_init; 88 context->cli.xa_exchange = mlsvc_xa_exchange; 89 context->cli.xa_read = mlsvc_xa_read; 90 context->cli.xa_preserve = mlsvc_xa_preserve; 91 context->cli.xa_destruct = mlsvc_xa_destruct; 92 context->cli.xa_release = mlsvc_xa_release; 93 94 rc = mlrpc_c_bind(&context->cli, service, &context->binding); 95 if (MLRPC_DRC_IS_FAULT(rc)) { 96 free(context); 97 desc->context = NULL; 98 return (-1); 99 } 100 101 return (rc); 102 } 103 104 /* 105 * mlsvc_rpc_init 106 * 107 * This function must be called by client side applications before 108 * calling mlsvc_rpc_call to allocate a heap. The heap must be 109 * destroyed by either calling mlrpc_heap_destroy or mlsvc_rpc_free. 110 * Use mlrpc_heap_destroy if mlsvc_rpc_call has not yet been called. 111 * Otherwise use mlsvc_rpc_free. 112 * 113 * Returns 0 on success. Otherwise returns -1 to indicate an error. 114 */ 115 int 116 mlsvc_rpc_init(mlrpc_heapref_t *heapref) 117 { 118 bzero(heapref, sizeof (mlrpc_heapref_t)); 119 120 if ((heapref->heap = mlrpc_heap_create()) == NULL) 121 return (-1); 122 123 return (0); 124 } 125 126 /* 127 * mlsvc_rpc_call 128 * 129 * This function should be called by the client RPC interface functions 130 * to make an RPC call. The remote service is identified by the context 131 * handle, which should have been initialized with by mlsvc_rpc_bind. 132 */ 133 int 134 mlsvc_rpc_call(struct mlsvc_rpc_context *context, int opnum, void *params, 135 mlrpc_heapref_t *heapref) 136 { 137 return (mlrpc_c_call(context->binding, opnum, params, heapref)); 138 } 139 140 /* 141 * mlsvc_rpc_free 142 * 143 * This function should be called by the client RPC interface functions 144 * to free the heap after an RPC call returns. 145 */ 146 void 147 mlsvc_rpc_free(struct mlsvc_rpc_context *context, mlrpc_heapref_t *heapref) 148 { 149 mlrpc_c_free_heap(context->binding, heapref); 150 } 151 152 /* 153 * The following functions provide the callback interface in the 154 * context handle. 155 */ 156 /*ARGSUSED*/ 157 static int 158 mlsvc_xa_init(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa, 159 mlrpc_heap_t *heap) 160 { 161 struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds; 162 struct mlndr_stream *send_mlnds = &mxa->send_mlnds; 163 164 /* 165 * If the caller hasn't provided a heap, create one here. 166 */ 167 if (heap == 0) { 168 if ((heap = mlrpc_heap_create()) == 0) 169 return (-1); 170 } 171 172 mxa->heap = heap; 173 174 mlnds_initialize(send_mlnds, 0, NDR_MODE_CALL_SEND, heap); 175 mlnds_initialize(recv_mlnds, 16 * 1024, NDR_MODE_RETURN_RECV, heap); 176 return (0); 177 } 178 179 /* 180 * mlsvc_xa_exchange 181 * 182 * This is the entry pointy for an RPC client call exchange with 183 * a server, which will result in an smbrdr SmbTransact request. 184 * 185 * SmbTransact should return the number of bytes received, which 186 * we record as the PDU size, or a negative error code. 187 */ 188 static int 189 mlsvc_xa_exchange(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 190 { 191 struct mlsvc_rpc_context *context = mcli->context; 192 struct mlndr_stream *recv_mlnds = &mxa->recv_mlnds; 193 struct mlndr_stream *send_mlnds = &mxa->send_mlnds; 194 int rc; 195 196 rc = smbrdr_transact(context->fid, 197 (char *)send_mlnds->pdu_base_offset, send_mlnds->pdu_size, 198 (char *)recv_mlnds->pdu_base_offset, recv_mlnds->pdu_max_size); 199 200 if (rc < 0) 201 recv_mlnds->pdu_size = 0; 202 else 203 recv_mlnds->pdu_size = rc; 204 205 return (rc); 206 } 207 208 /* 209 * mlsvc_xa_read 210 * 211 * This entry point will be invoked if the xa-exchange response contained 212 * only the first fragment of a multi-fragment response. The RPC client 213 * code will then make repeated xa-read requests to obtain the remaining 214 * fragments, which will result in smbrdr SmbReadX requests. 215 * 216 * SmbReadX should return the number of bytes received, in which case we 217 * expand the PDU size to include the received data, or a negative error 218 * code. 219 */ 220 static int 221 mlsvc_xa_read(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 222 { 223 struct mlsvc_rpc_context *context = mcli->context; 224 struct mlndr_stream *mlnds = &mxa->recv_mlnds; 225 int len; 226 int rc; 227 228 if ((len = (mlnds->pdu_max_size - mlnds->pdu_size)) < 0) 229 return (-1); 230 231 rc = smbrdr_readx(context->fid, 232 (char *)mlnds->pdu_base_offset + mlnds->pdu_size, len); 233 234 if (rc < 0) 235 return (-1); 236 237 mlnds->pdu_size += rc; 238 239 if (mlnds->pdu_size > mlnds->pdu_max_size) { 240 mlnds->pdu_size = mlnds->pdu_max_size; 241 return (-1); 242 } 243 244 return (rc); 245 } 246 247 /* 248 * mlsvc_xa_preserve 249 * 250 * This function is called to preserve the heap. We save a reference 251 * to the heap and set the mxa heap pointer to null so that the heap 252 * will not be discarded when mlsvc_xa_destruct is called. 253 */ 254 /*ARGSUSED*/ 255 static int 256 mlsvc_xa_preserve(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa, 257 mlrpc_heapref_t *heapref) 258 { 259 heapref->state = MLRPC_HRST_PRESERVED; 260 heapref->heap = mxa->heap; 261 heapref->recv_pdu_buf = (char *)mxa->recv_mlnds.pdu_base_addr; 262 heapref->send_pdu_buf = (char *)mxa->send_mlnds.pdu_base_addr; 263 264 mxa->heap = NULL; 265 return (0); 266 } 267 268 /* 269 * mlsvc_xa_destruct 270 * 271 * This function is called to dispose of the heap. If the heap has 272 * been preserved via mlsvc_xa_preserve, the mxa heap pointer will 273 * be null and we assume that the heap will be released later via 274 * a call to mlsvc_xa_release. Otherwise we free the memory here. 275 */ 276 /*ARGSUSED*/ 277 static int 278 mlsvc_xa_destruct(struct mlrpc_client *mcli, struct mlrpc_xaction *mxa) 279 { 280 if (mxa->heap) { 281 mlnds_destruct(&mxa->recv_mlnds); 282 mlnds_destruct(&mxa->send_mlnds); 283 mlrpc_heap_destroy(mxa->heap); 284 } 285 286 return (0); 287 } 288 289 /* 290 * mlsvc_xa_release 291 * 292 * This function is called, via some indirection, as a result of a 293 * call to mlsvc_rpc_free. This is where we free the heap memory 294 * that was preserved during an RPC call. 295 */ 296 /*ARGSUSED*/ 297 static void 298 mlsvc_xa_release(struct mlrpc_client *mcli, mlrpc_heapref_t *heapref) 299 { 300 if (heapref == NULL) 301 return; 302 303 if (heapref->state == MLRPC_HRST_PRESERVED) { 304 free(heapref->recv_pdu_buf); 305 free(heapref->send_pdu_buf); 306 mlrpc_heap_destroy(heapref->heap); 307 } 308 } 309