5917 User-mode SMB server
[unleashed.git] / usr / src / lib / smbsrv / libfksmbsrv / common / fksmb_kdoor.c
blob44c68ce2c52683c1169dc1bc106bd607e744aa55
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 * "Upcall" glue for the fake (user-mode) smbsrv module.
30 #include <sys/types.h>
31 #include <sys/kmem.h>
32 #include <sys/ddi.h>
33 #include <sys/sunddi.h>
34 #include <sys/cmn_err.h>
35 #include <sys/door.h>
36 #include <smbsrv/smb_kproto.h>
37 #include <smbsrv/smb_door.h>
39 static int smb_kdoor_encode(smb_doorarg_t *);
40 static int smb_kdoor_decode(smb_doorarg_t *);
41 static void smb_kdoor_sethdr(smb_doorarg_t *, uint32_t);
42 static boolean_t smb_kdoor_chkhdr(smb_doorarg_t *, smb_doorhdr_t *);
43 static void smb_kdoor_free(door_arg_t *);
45 void
46 smb_kdoor_init(smb_server_t *sv)
48 sv->sv_kdoor_id = -1;
49 mutex_init(&sv->sv_kdoor_mutex, NULL, MUTEX_DEFAULT, NULL);
50 cv_init(&sv->sv_kdoor_cv, NULL, CV_DEFAULT, NULL);
53 void
54 smb_kdoor_fini(smb_server_t *sv)
56 smb_kdoor_close(sv);
57 cv_destroy(&sv->sv_kdoor_cv);
58 mutex_destroy(&sv->sv_kdoor_mutex);
62 * In the "fake kernen", our "upcalls" don't use the
63 * real door, but just call via a function pointer.
64 * This is where we setup that pointer, which is
65 * fksmbd_door_dispatch()
67 void
68 fksmb_kdoor_open(smb_server_t *sv, void *varg)
70 sv->sv_kdoor_hd = varg;
73 void
74 smb_kdoor_close(smb_server_t *sv)
76 sv->sv_kdoor_hd = NULL;
77 sv->sv_kdoor_id = -1;
80 /* ARGSUSED */
81 int
82 smb_kdoor_upcall(smb_server_t *sv, uint32_t cmd,
83 void *req_data, xdrproc_t req_xdr,
84 void *rsp_data, xdrproc_t rsp_xdr)
86 smb_doorarg_t da;
87 fksmb_kdoor_disp_func_t *func;
88 int rc;
90 bzero(&da, sizeof (smb_doorarg_t));
91 da.da_opcode = cmd;
92 da.da_opname = smb_doorhdr_opname(cmd);
93 da.da_req_xdr = req_xdr;
94 da.da_rsp_xdr = rsp_xdr;
95 da.da_req_data = req_data;
96 da.da_rsp_data = rsp_data;
98 if ((req_data == NULL && req_xdr != NULL) ||
99 (rsp_data == NULL && rsp_xdr != NULL)) {
100 cmn_err(CE_WARN, "smb_kdoor_upcall[%s]: invalid param",
101 da.da_opname);
102 return (-1);
105 /* NB: no ASYNC, nor event stuff */
107 func = (fksmb_kdoor_disp_func_t *)(sv->sv_kdoor_hd);
108 if (func == NULL)
109 return (EFAULT);
111 if ((rc = smb_kdoor_encode(&da)) != 0)
112 goto out;
115 * The "upcall" (just call via function pointer)
116 * i.e. see: fksmbd_door_dispatch()
118 if ((rc = (*func)(&da)) != 0)
119 goto out;
121 rc = smb_kdoor_decode(&da);
122 out:
123 smb_kdoor_free(&da.da_arg);
125 return (rc);
128 /* no smb_kdoor_send, smb_kdoor_receive */
129 /* no smb_kdoor_upcall_private */
131 static int
132 smb_kdoor_encode(smb_doorarg_t *da)
134 XDR xdrs;
135 char *buf;
136 uint32_t len;
138 len = xdr_sizeof(smb_doorhdr_xdr, &da->da_hdr);
139 if (da->da_req_xdr != NULL)
140 len += xdr_sizeof(da->da_req_xdr, da->da_req_data);
142 smb_kdoor_sethdr(da, len);
144 buf = kmem_zalloc(len, KM_SLEEP);
145 xdrmem_create(&xdrs, buf, len, XDR_ENCODE);
147 if (!smb_doorhdr_xdr(&xdrs, &da->da_hdr)) {
148 cmn_err(CE_WARN, "smb_kdoor_encode[%s]: header encode failed",
149 da->da_opname);
150 kmem_free(buf, len);
151 xdr_destroy(&xdrs);
152 return (-1);
155 if (da->da_req_xdr != NULL) {
156 if (!da->da_req_xdr(&xdrs, da->da_req_data)) {
157 cmn_err(CE_WARN, "smb_kdoor_encode[%s]: encode failed",
158 da->da_opname);
159 kmem_free(buf, len);
160 xdr_destroy(&xdrs);
161 return (-1);
165 da->da_arg.data_ptr = buf;
166 da->da_arg.data_size = len;
167 da->da_arg.desc_ptr = NULL;
168 da->da_arg.desc_num = 0;
169 da->da_arg.rbuf = buf;
170 da->da_arg.rsize = len;
172 xdr_destroy(&xdrs);
173 return (0);
177 * Decode the response in rbuf and rsize.
179 static int
180 smb_kdoor_decode(smb_doorarg_t *da)
182 XDR xdrs;
183 smb_doorhdr_t hdr;
184 char *rbuf = da->da_arg.rbuf;
185 uint32_t rsize = da->da_arg.rsize;
187 if (rbuf == NULL || rsize == 0) {
188 cmn_err(CE_WARN, "smb_kdoor_decode[%s]: invalid param",
189 da->da_opname);
190 return (-1);
193 xdrmem_create(&xdrs, rbuf, rsize, XDR_DECODE);
195 if (!smb_doorhdr_xdr(&xdrs, &hdr)) {
196 cmn_err(CE_WARN, "smb_kdoor_decode[%s]: header decode failed",
197 da->da_opname);
198 xdr_destroy(&xdrs);
199 return (-1);
202 if (!smb_kdoor_chkhdr(da, &hdr)) {
203 xdr_destroy(&xdrs);
204 return (-1);
207 if (hdr.dh_datalen != 0 && da->da_rsp_xdr != NULL) {
208 if (!da->da_rsp_xdr(&xdrs, da->da_rsp_data)) {
209 cmn_err(CE_WARN, "smb_kdoor_decode[%s]: decode failed",
210 da->da_opname);
211 xdr_destroy(&xdrs);
212 return (-1);
216 xdr_destroy(&xdrs);
217 return (0);
220 static void
221 smb_kdoor_sethdr(smb_doorarg_t *da, uint32_t datalen)
223 smb_doorhdr_t *hdr = &da->da_hdr;
225 bzero(hdr, sizeof (smb_doorhdr_t));
226 hdr->dh_magic = SMB_DOOR_HDR_MAGIC;
227 hdr->dh_flags = da->da_flags | SMB_DF_FAKE_KERNEL;
228 hdr->dh_op = da->da_opcode;
229 /* hdr->dh_txid = 0 (not used) */
230 hdr->dh_datalen = datalen;
231 hdr->dh_door_rc = SMB_DOP_NOT_CALLED;
234 static boolean_t
235 smb_kdoor_chkhdr(smb_doorarg_t *da, smb_doorhdr_t *hdr)
237 if ((hdr->dh_magic != SMB_DOOR_HDR_MAGIC) ||
238 (hdr->dh_op != da->da_hdr.dh_op) ||
239 (hdr->dh_txid != da->da_hdr.dh_txid)) {
240 cmn_err(CE_WARN, "smb_kdoor_chkhdr[%s]: invalid header",
241 da->da_opname);
242 return (B_FALSE);
245 switch (hdr->dh_door_rc) {
246 case SMB_DOP_SUCCESS:
247 break;
249 /* SMB_DOP_EMPTYBUF is a "normal" error (silent). */
250 case SMB_DOP_EMPTYBUF:
251 return (B_FALSE);
253 default:
254 cmn_err(CE_WARN, "smb_kdoor_chkhdr[%s]: call failed: %u",
255 da->da_opname, hdr->dh_door_rc);
256 return (B_FALSE);
259 return (B_TRUE);
263 * Free both the argument and result door buffers regardless of the status
264 * of the up-call. The doorfs allocates a new buffer if the result buffer
265 * passed by the client is too small.
267 static void
268 smb_kdoor_free(door_arg_t *arg)
270 if (arg->rbuf != NULL && arg->rbuf != arg->data_ptr)
271 kmem_free(arg->rbuf, arg->rsize);
273 if (arg->data_ptr != NULL)
274 kmem_free(arg->data_ptr, arg->data_size);