xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb2_rq.c (revision 48e11a6ea0245c522078ddb86a73f16c8c28b949)
1adee6784SGordon Ross /*
2adee6784SGordon Ross  * Copyright (c) 2011  Apple Inc. All rights reserved.
3adee6784SGordon Ross  *
4adee6784SGordon Ross  * @APPLE_LICENSE_HEADER_START@
5adee6784SGordon Ross  *
6adee6784SGordon Ross  * This file contains Original Code and/or Modifications of Original Code
7adee6784SGordon Ross  * as defined in and that are subject to the Apple Public Source License
8adee6784SGordon Ross  * Version 2.0 (the 'License'). You may not use this file except in
9adee6784SGordon Ross  * compliance with the License. Please obtain a copy of the License at
10adee6784SGordon Ross  * http://www.opensource.apple.com/apsl/ and read it before using this
11adee6784SGordon Ross  * file.
12adee6784SGordon Ross  *
13adee6784SGordon Ross  * The Original Code and all software distributed under the License are
14adee6784SGordon Ross  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15adee6784SGordon Ross  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16adee6784SGordon Ross  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17adee6784SGordon Ross  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18adee6784SGordon Ross  * Please see the License for the specific language governing rights and
19adee6784SGordon Ross  * limitations under the License.
20adee6784SGordon Ross  *
21adee6784SGordon Ross  * @APPLE_LICENSE_HEADER_END@
22adee6784SGordon Ross  */
23adee6784SGordon Ross 
24adee6784SGordon Ross /*
25adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
26*48e11a6eSGordon Ross  * Copyright 2024 RackTop Systems, Inc.
27adee6784SGordon Ross  */
28adee6784SGordon Ross 
29adee6784SGordon Ross #include <sys/param.h>
30adee6784SGordon Ross #include <sys/systm.h>
31adee6784SGordon Ross #include <sys/time.h>
32adee6784SGordon Ross #include <sys/kmem.h>
33adee6784SGordon Ross #include <sys/proc.h>
34adee6784SGordon Ross #include <sys/lock.h>
35adee6784SGordon Ross #include <sys/socket.h>
36adee6784SGordon Ross #include <sys/mount.h>
37adee6784SGordon Ross #include <sys/sunddi.h>
38adee6784SGordon Ross #include <sys/cmn_err.h>
39adee6784SGordon Ross #include <sys/atomic.h>
40adee6784SGordon Ross #include <sys/sdt.h>
41adee6784SGordon Ross 
42adee6784SGordon Ross #include <netsmb/smb_osdep.h>
43adee6784SGordon Ross 
44adee6784SGordon Ross #include <netsmb/smb.h>
45adee6784SGordon Ross #include <netsmb/smb2.h>
46adee6784SGordon Ross #include <netsmb/smb_conn.h>
47adee6784SGordon Ross #include <netsmb/smb_subr.h>
48adee6784SGordon Ross #include <netsmb/smb_tran.h>
49adee6784SGordon Ross #include <netsmb/smb_rq.h>
50adee6784SGordon Ross #include <netsmb/smb2_rq.h>
51adee6784SGordon Ross 
52adee6784SGordon Ross static const uint8_t SMB2_SIGNATURE[4] = SMB2_PROTOCOL_ID;
53adee6784SGordon Ross 
54adee6784SGordon Ross static int  smb2_rq_enqueue(struct smb_rq *rqp);
55adee6784SGordon Ross static int  smb2_rq_reply(struct smb_rq *rqp);
56adee6784SGordon Ross 
57adee6784SGordon Ross /*
58adee6784SGordon Ross  * Given a request with it's body already composed,
59adee6784SGordon Ross  * rewind to the start and fill in the SMB2 header.
60adee6784SGordon Ross  * This is called when the request is enqueued,
61adee6784SGordon Ross  * so we have the final message ID etc.
62adee6784SGordon Ross  */
63adee6784SGordon Ross void
smb2_rq_fillhdr(struct smb_rq * rqp)64adee6784SGordon Ross smb2_rq_fillhdr(struct smb_rq *rqp)
65adee6784SGordon Ross {
66adee6784SGordon Ross 	struct mbchain mbtmp, *mbp = &mbtmp;
67adee6784SGordon Ross 	uint16_t creditcharge, creditrequest;
68adee6784SGordon Ross 	size_t len;
69adee6784SGordon Ross 	mblk_t *m;
70adee6784SGordon Ross 
71adee6784SGordon Ross 	ASSERT((rqp->sr2_nextcmd & 7) == 0);
72adee6784SGordon Ross 	if (rqp->sr2_nextcmd != 0) {
73adee6784SGordon Ross 		len = msgdsize(rqp->sr_rq.mb_top);
74adee6784SGordon Ross 		ASSERT((len & 7) == 0);
75adee6784SGordon Ross 	}
76adee6784SGordon Ross 
77adee6784SGordon Ross 	/*
78adee6784SGordon Ross 	 * When sending negotiate, we don't technically know yet
79adee6784SGordon Ross 	 * if the server handles SMB 2.1 or later and credits.
80adee6784SGordon Ross 	 * Negotiate is supposed to set these to zero.
81adee6784SGordon Ross 	 */
82adee6784SGordon Ross 	if (rqp->sr2_command == SMB2_NEGOTIATE) {
83adee6784SGordon Ross 		creditcharge = creditrequest = 0;
84adee6784SGordon Ross 	} else {
85adee6784SGordon Ross 		creditcharge = rqp->sr2_creditcharge;
86adee6784SGordon Ross 		creditrequest = rqp->sr2_creditsrequested;
87adee6784SGordon Ross 	}
88adee6784SGordon Ross 
89adee6784SGordon Ross 	/*
90adee6784SGordon Ross 	 * Fill in the SMB2 header using a dup of the first mblk,
91adee6784SGordon Ross 	 * which points at the same data but has its own wptr,
92adee6784SGordon Ross 	 * so we can rewind without trashing the message.
93adee6784SGordon Ross 	 */
94adee6784SGordon Ross 	m = dupb(rqp->sr_rq.mb_top);
95adee6784SGordon Ross 	m->b_wptr = m->b_rptr;	/* rewind */
96adee6784SGordon Ross 	mb_initm(mbp, m);
97adee6784SGordon Ross 
98adee6784SGordon Ross 	mb_put_mem(mbp, SMB2_SIGNATURE, 4, MB_MSYSTEM);
99adee6784SGordon Ross 	mb_put_uint16le(mbp, SMB2_HDR_SIZE);		/* Struct Size */
100adee6784SGordon Ross 	mb_put_uint16le(mbp, creditcharge);
101adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);	/* Status */
102adee6784SGordon Ross 	mb_put_uint16le(mbp, rqp->sr2_command);
103adee6784SGordon Ross 	mb_put_uint16le(mbp, creditrequest);
104adee6784SGordon Ross 	mb_put_uint32le(mbp, rqp->sr2_rqflags);
105adee6784SGordon Ross 	mb_put_uint32le(mbp, rqp->sr2_nextcmd);
106adee6784SGordon Ross 	mb_put_uint64le(mbp, rqp->sr2_messageid);
107adee6784SGordon Ross 
108adee6784SGordon Ross 	mb_put_uint32le(mbp, rqp->sr_pid);		/* Process ID */
109adee6784SGordon Ross 	mb_put_uint32le(mbp, rqp->sr2_rqtreeid);	/* Tree ID */
110adee6784SGordon Ross 	mb_put_uint64le(mbp, rqp->sr2_rqsessionid);	/* Session ID */
111adee6784SGordon Ross 	/* The MAC signature is filled in by smb2_vc_sign() */
112adee6784SGordon Ross 
113adee6784SGordon Ross 	/* This will free the mblk from dupb. */
114adee6784SGordon Ross 	mb_done(mbp);
115adee6784SGordon Ross }
116adee6784SGordon Ross 
117adee6784SGordon Ross int
smb2_rq_simple(struct smb_rq * rqp)118adee6784SGordon Ross smb2_rq_simple(struct smb_rq *rqp)
119adee6784SGordon Ross {
120adee6784SGordon Ross 	return (smb2_rq_simple_timed(rqp, smb2_timo_default));
121adee6784SGordon Ross }
122adee6784SGordon Ross 
123adee6784SGordon Ross /*
124adee6784SGordon Ross  * Simple request-reply exchange
125adee6784SGordon Ross  */
126adee6784SGordon Ross int
smb2_rq_simple_timed(struct smb_rq * rqp,int timeout)127adee6784SGordon Ross smb2_rq_simple_timed(struct smb_rq *rqp, int timeout)
128adee6784SGordon Ross {
129adee6784SGordon Ross 	int error;
130adee6784SGordon Ross 
131adee6784SGordon Ross 	rqp->sr_flags &= ~SMBR_RESTART;
132adee6784SGordon Ross 	rqp->sr_timo = timeout;	/* in seconds */
133adee6784SGordon Ross 	rqp->sr_state = SMBRQ_NOTSENT;
134adee6784SGordon Ross 
135adee6784SGordon Ross 	error = smb2_rq_enqueue(rqp);
136adee6784SGordon Ross 	if (error == 0)
137adee6784SGordon Ross 		error = smb2_rq_reply(rqp);
138adee6784SGordon Ross 
139adee6784SGordon Ross 	return (error);
140adee6784SGordon Ross }
141adee6784SGordon Ross 
142adee6784SGordon Ross 
143adee6784SGordon Ross static int
smb2_rq_enqueue(struct smb_rq * rqp)144adee6784SGordon Ross smb2_rq_enqueue(struct smb_rq *rqp)
145adee6784SGordon Ross {
146adee6784SGordon Ross 	struct smb_vc *vcp = rqp->sr_vc;
147adee6784SGordon Ross 	struct smb_share *ssp = rqp->sr_share;
148adee6784SGordon Ross 	int error = 0;
149adee6784SGordon Ross 
150adee6784SGordon Ross 	ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
151adee6784SGordon Ross 
152adee6784SGordon Ross 	/*
153adee6784SGordon Ross 	 * Normal requests may initiate a reconnect,
154adee6784SGordon Ross 	 * and/or wait for state changes to finish.
155adee6784SGordon Ross 	 * Some requests set the NORECONNECT flag
156adee6784SGordon Ross 	 * to avoid all that (i.e. tree discon)
157adee6784SGordon Ross 	 */
158adee6784SGordon Ross 	if (rqp->sr_flags & SMBR_NORECONNECT) {
159adee6784SGordon Ross 		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
160adee6784SGordon Ross 			SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
161adee6784SGordon Ross 			return (ENOTCONN);
162adee6784SGordon Ross 		}
163adee6784SGordon Ross 		if (ssp != NULL &&
164adee6784SGordon Ross 		    ((ssp->ss_flags & SMBS_CONNECTED) == 0))
165adee6784SGordon Ross 			return (ENOTCONN);
166adee6784SGordon Ross 		goto ok_out;
167adee6784SGordon Ross 	}
168adee6784SGordon Ross 
169adee6784SGordon Ross 	/*
170adee6784SGordon Ross 	 * If we're not connected, initiate a reconnect
171adee6784SGordon Ross 	 * and/or wait for an existing one to finish.
172adee6784SGordon Ross 	 */
173adee6784SGordon Ross 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
174adee6784SGordon Ross 		error = smb_iod_reconnect(vcp);
175adee6784SGordon Ross 		if (error != 0)
176adee6784SGordon Ross 			return (error);
177adee6784SGordon Ross 	}
178adee6784SGordon Ross 
179adee6784SGordon Ross 	/*
180adee6784SGordon Ross 	 * If this request has a "share" object
181adee6784SGordon Ross 	 * that needs a tree connect, do it now.
182adee6784SGordon Ross 	 */
183adee6784SGordon Ross 	if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
184adee6784SGordon Ross 		error = smb_share_tcon(ssp, rqp->sr_cred);
185adee6784SGordon Ross 		if (error)
186adee6784SGordon Ross 			return (error);
187adee6784SGordon Ross 	}
188adee6784SGordon Ross 
189adee6784SGordon Ross 	/*
190adee6784SGordon Ross 	 * We now know what UID + TID to use.
191adee6784SGordon Ross 	 * Store them in the request.
192adee6784SGordon Ross 	 */
193adee6784SGordon Ross ok_out:
194adee6784SGordon Ross 	rqp->sr2_rqsessionid = vcp->vc2_session_id;
195adee6784SGordon Ross 	rqp->sr2_rqtreeid = ssp ? ssp->ss2_tree_id : SMB2_TID_UNKNOWN;
196adee6784SGordon Ross 	error = smb2_iod_addrq(rqp);
197adee6784SGordon Ross 
198adee6784SGordon Ross 	return (error);
199adee6784SGordon Ross }
200adee6784SGordon Ross 
201adee6784SGordon Ross /*
202adee6784SGordon Ross  * Used by the IOD thread during connection setup,
203adee6784SGordon Ross  * and for smb2_echo after network timeouts.  Note that
204adee6784SGordon Ross  * unlike smb2_rq_simple, callers must check sr_error.
205adee6784SGordon Ross  */
206adee6784SGordon Ross int
smb2_rq_internal(struct smb_rq * rqp,int timeout)207adee6784SGordon Ross smb2_rq_internal(struct smb_rq *rqp, int timeout)
208adee6784SGordon Ross {
209adee6784SGordon Ross 	struct smb_vc *vcp = rqp->sr_vc;
210adee6784SGordon Ross 	int error;
211adee6784SGordon Ross 
212adee6784SGordon Ross 	ASSERT((vcp->vc_flags & SMBV_SMB2) != 0);
213adee6784SGordon Ross 
214adee6784SGordon Ross 	rqp->sr_flags &= ~SMBR_RESTART;
215adee6784SGordon Ross 	rqp->sr_timo = timeout;	/* in seconds */
216adee6784SGordon Ross 	rqp->sr_state = SMBRQ_NOTSENT;
217adee6784SGordon Ross 
218adee6784SGordon Ross 	/*
219adee6784SGordon Ross 	 * In-line smb2_rq_enqueue(rqp) here, as we don't want it
220adee6784SGordon Ross 	 * trying to reconnect etc. for an internal request.
221adee6784SGordon Ross 	 */
222adee6784SGordon Ross 	rqp->sr2_rqsessionid = vcp->vc2_session_id;
223adee6784SGordon Ross 	rqp->sr2_rqtreeid = SMB2_TID_UNKNOWN;
224adee6784SGordon Ross 	rqp->sr_flags |= SMBR_INTERNAL;
225adee6784SGordon Ross 	error = smb2_iod_addrq(rqp);
226adee6784SGordon Ross 	if (error != 0)
227adee6784SGordon Ross 		return (error);
228adee6784SGordon Ross 
229adee6784SGordon Ross 	/*
230adee6784SGordon Ross 	 * In-line a variant of smb2_rq_reply(rqp) here as we may
231adee6784SGordon Ross 	 * need to do custom parsing for SMB1-to-SMB2 negotiate.
232adee6784SGordon Ross 	 */
233adee6784SGordon Ross 	if (rqp->sr_timo == SMBNOREPLYWAIT) {
234adee6784SGordon Ross 		smb_iod_removerq(rqp);
235adee6784SGordon Ross 		return (0);
236adee6784SGordon Ross 	}
237adee6784SGordon Ross 
238adee6784SGordon Ross 	error = smb_iod_waitrq_int(rqp);
239adee6784SGordon Ross 	if (error)
240adee6784SGordon Ross 		return (error);
241adee6784SGordon Ross 
242adee6784SGordon Ross 	/*
243*48e11a6eSGordon Ross 	 * If the request was signed (and reply not encrypted)
244*48e11a6eSGordon Ross 	 * validate the signature on the response.
245adee6784SGordon Ross 	 */
246*48e11a6eSGordon Ross 	if ((rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) != 0 &&
247*48e11a6eSGordon Ross 	    (rqp->sr_flags & SMBR_ENCRYPTED) == 0) {
248adee6784SGordon Ross 		error = smb2_rq_verify(rqp);
249adee6784SGordon Ross 		if (error)
250adee6784SGordon Ross 			return (error);
251adee6784SGordon Ross 	}
252adee6784SGordon Ross 
253adee6784SGordon Ross 	/*
254adee6784SGordon Ross 	 * Parse the SMB2 header.
255adee6784SGordon Ross 	 */
256adee6784SGordon Ross 	error = smb2_rq_parsehdr(rqp);
257adee6784SGordon Ross 
258adee6784SGordon Ross 	/*
259adee6784SGordon Ross 	 * Skip the error translation smb2_rq_reply does.
260adee6784SGordon Ross 	 * Callers of this expect "raw" NT status.
261adee6784SGordon Ross 	 */
262adee6784SGordon Ross 
263adee6784SGordon Ross 	return (error);
264adee6784SGordon Ross }
265adee6784SGordon Ross 
266adee6784SGordon Ross /*
267adee6784SGordon Ross  * Wait for a reply to this request, then parse it.
268adee6784SGordon Ross  */
269adee6784SGordon Ross static int
smb2_rq_reply(struct smb_rq * rqp)270adee6784SGordon Ross smb2_rq_reply(struct smb_rq *rqp)
271adee6784SGordon Ross {
272adee6784SGordon Ross 	int error;
273adee6784SGordon Ross 
274adee6784SGordon Ross 	if (rqp->sr_timo == SMBNOREPLYWAIT) {
275adee6784SGordon Ross 		smb_iod_removerq(rqp);
276adee6784SGordon Ross 		return (0);
277adee6784SGordon Ross 	}
278adee6784SGordon Ross 
279adee6784SGordon Ross 	error = smb_iod_waitrq(rqp);
280adee6784SGordon Ross 	if (error)
281adee6784SGordon Ross 		return (error);
282adee6784SGordon Ross 
283adee6784SGordon Ross 	/*
284*48e11a6eSGordon Ross 	 * If the request was signed (and reply not encrypted)
285*48e11a6eSGordon Ross 	 * validate the signature on the response.
286adee6784SGordon Ross 	 */
287*48e11a6eSGordon Ross 	if ((rqp->sr2_rqflags & SMB2_FLAGS_SIGNED) != 0 &&
288*48e11a6eSGordon Ross 	    (rqp->sr_flags & SMBR_ENCRYPTED) == 0) {
289adee6784SGordon Ross 		error = smb2_rq_verify(rqp);
290adee6784SGordon Ross 		if (error)
291adee6784SGordon Ross 			return (error);
292adee6784SGordon Ross 	}
293adee6784SGordon Ross 
294adee6784SGordon Ross 	/*
295adee6784SGordon Ross 	 * Parse the SMB2 header
296adee6784SGordon Ross 	 */
297adee6784SGordon Ross 	error = smb2_rq_parsehdr(rqp);
298adee6784SGordon Ross 	if (error != 0)
299adee6784SGordon Ross 		return (error);
300adee6784SGordon Ross 
301adee6784SGordon Ross 	if (rqp->sr_error != 0) {
302adee6784SGordon Ross 		error = smb_maperr32(rqp->sr_error);
303adee6784SGordon Ross 	}
304adee6784SGordon Ross 
305adee6784SGordon Ross 	if (error != 0) {
306adee6784SGordon Ross 		/*
307adee6784SGordon Ross 		 * Do a special check for STATUS_BUFFER_OVERFLOW;
308adee6784SGordon Ross 		 * it's not an error.
309adee6784SGordon Ross 		 */
310adee6784SGordon Ross 		if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) {
311adee6784SGordon Ross 			/*
312adee6784SGordon Ross 			 * Don't report it as an error to our caller;
313adee6784SGordon Ross 			 * they can look at rqp->sr_error if they
314adee6784SGordon Ross 			 * need to know whether we got a
315adee6784SGordon Ross 			 * STATUS_BUFFER_OVERFLOW.
316adee6784SGordon Ross 			 */
317adee6784SGordon Ross 			rqp->sr_flags |= SMBR_MOREDATA;
318adee6784SGordon Ross 			error = 0;
319adee6784SGordon Ross 		}
320adee6784SGordon Ross 	} else {
321adee6784SGordon Ross 		rqp->sr_flags &= ~SMBR_MOREDATA;
322adee6784SGordon Ross 	}
323adee6784SGordon Ross 
324adee6784SGordon Ross 	return (error);
325adee6784SGordon Ross }
326adee6784SGordon Ross 
327adee6784SGordon Ross /*
328adee6784SGordon Ross  * Parse the SMB 2+ Header
329adee6784SGordon Ross  */
330adee6784SGordon Ross int
smb2_rq_parsehdr(struct smb_rq * rqp)331adee6784SGordon Ross smb2_rq_parsehdr(struct smb_rq *rqp)
332adee6784SGordon Ross {
333adee6784SGordon Ross 	struct mdchain *mdp = &rqp->sr_rp;
334adee6784SGordon Ross 	uint32_t protocol_id;
335adee6784SGordon Ross 	uint16_t length = 0;
336adee6784SGordon Ross 	uint16_t credit_charge;
337adee6784SGordon Ross 	uint16_t command;
338adee6784SGordon Ross 	uint64_t message_id = 0;
339adee6784SGordon Ross 	int error = 0;
340adee6784SGordon Ross 
341adee6784SGordon Ross 	/* Get Protocol ID */
342adee6784SGordon Ross 	md_get_uint32le(mdp, &protocol_id);
343adee6784SGordon Ross 
344adee6784SGordon Ross 	/* Get/Check structure size is 64 */
345adee6784SGordon Ross 	md_get_uint16le(mdp, &length);
346adee6784SGordon Ross 	if (length != 64)
347adee6784SGordon Ross 		return (EBADRPC);
348adee6784SGordon Ross 
349adee6784SGordon Ross 	md_get_uint16le(mdp, &credit_charge);
350adee6784SGordon Ross 	md_get_uint32le(mdp, &rqp->sr_error);
351adee6784SGordon Ross 	md_get_uint16le(mdp, &command);
352adee6784SGordon Ross 	md_get_uint16le(mdp, &rqp->sr2_rspcreditsgranted);
353adee6784SGordon Ross 	md_get_uint32le(mdp, &rqp->sr2_rspflags);
354adee6784SGordon Ross 	md_get_uint32le(mdp, &rqp->sr2_rspnextcmd);
355adee6784SGordon Ross 	md_get_uint64le(mdp, &message_id);
356adee6784SGordon Ross 
357adee6784SGordon Ross 	if ((rqp->sr2_rspflags & SMB2_FLAGS_ASYNC_COMMAND) == 0) {
358adee6784SGordon Ross 		/*
359adee6784SGordon Ross 		 * Sync Header
360adee6784SGordon Ross 		 */
361adee6784SGordon Ross 
362adee6784SGordon Ross 		/* Get Process ID */
363adee6784SGordon Ross 		md_get_uint32le(mdp, &rqp->sr2_rsppid);
364adee6784SGordon Ross 
365adee6784SGordon Ross 		/* Get Tree ID */
366adee6784SGordon Ross 		md_get_uint32le(mdp, &rqp->sr2_rsptreeid);
367adee6784SGordon Ross 	} else {
368adee6784SGordon Ross 		/*
369adee6784SGordon Ross 		 * Async Header
370adee6784SGordon Ross 		 */
371adee6784SGordon Ross 
372adee6784SGordon Ross 		/* Get Async ID */
373adee6784SGordon Ross 		md_get_uint64le(mdp, &rqp->sr2_rspasyncid);
374adee6784SGordon Ross 	}
375adee6784SGordon Ross 
376adee6784SGordon Ross 	/* Get Session ID */
377adee6784SGordon Ross 	error = md_get_uint64le(mdp, &rqp->sr2_rspsessionid);
378adee6784SGordon Ross 	if (error)
379adee6784SGordon Ross 		return (error);
380adee6784SGordon Ross 
381adee6784SGordon Ross 	/* Skip MAC Signature */
382adee6784SGordon Ross 	error = md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
383adee6784SGordon Ross 
384adee6784SGordon Ross 	return (error);
385adee6784SGordon Ross }
386