xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_create.c (revision 94047d49916b669576decf2f622a1ee718646882)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * Dispatch function for SMB2_CREATE
18  * [MS-SMB2] 2.2.13
19  */
20 
21 #include <smbsrv/smb2_kproto.h>
22 #include <smbsrv/smb_fsops.h>
23 
24 #define	DH_PERSISTENT	SMB2_DHANDLE_FLAG_PERSISTENT
25 
26 /*
27  * Compile-time check that the SMB2_LEASE_... definitions
28  * match the (internal) equivalents from ntifs.h
29  */
30 #if SMB2_LEASE_NONE != OPLOCK_LEVEL_NONE
31 #error "SMB2_LEASE_NONE"
32 #endif
33 #if SMB2_LEASE_READ_CACHING != OPLOCK_LEVEL_CACHE_READ
34 #error "SMB2_LEASE_READ_CACHING"
35 #endif
36 #if SMB2_LEASE_HANDLE_CACHING != OPLOCK_LEVEL_CACHE_HANDLE
37 #error "SMB2_LEASE_HANDLE_CACHING"
38 #endif
39 #if SMB2_LEASE_WRITE_CACHING != OPLOCK_LEVEL_CACHE_WRITE
40 #error "SMB2_LEASE_WRITE_CACHING"
41 #endif
42 
43 /*
44  * Some flags used locally to keep track of which Create Context
45  * names have been provided and/or requested.
46  */
47 #define	CCTX_EA_BUFFER			1
48 #define	CCTX_SD_BUFFER			2
49 #define	CCTX_DH_REQUEST			4
50 #define	CCTX_DH_RECONNECT		8
51 #define	CCTX_ALLOCATION_SIZE		0x10
52 #define	CCTX_QUERY_MAX_ACCESS		0x20
53 #define	CCTX_TIMEWARP_TOKEN		0x40
54 #define	CCTX_QUERY_ON_DISK_ID		0x80
55 #define	CCTX_REQUEST_LEASE		0x100
56 #define	CCTX_AAPL_EXT			0x200
57 #define	CCTX_DH_REQUEST_V2		0x400
58 #define	CCTX_DH_RECONNECT_V2		0x800
59 
60 typedef struct smb2_create_ctx_elem {
61 	uint32_t cce_len;
62 	mbuf_chain_t cce_mbc;
63 } smb2_create_ctx_elem_t;
64 
65 typedef struct smb2_create_ctx {
66 	mbuf_chain_t cc_in_mbc;
67 	uint_t	cc_in_flags;	/* CCTX_... */
68 	uint_t	cc_out_flags;	/* CCTX_... */
69 	/* Elements we may see in the request. */
70 	smb2_create_ctx_elem_t cc_in_ext_attr;
71 	smb2_create_ctx_elem_t cc_in_sec_desc;
72 	smb2_create_ctx_elem_t cc_in_dh_request;
73 	smb2_create_ctx_elem_t cc_in_dh_reconnect;
74 	smb2_create_ctx_elem_t cc_in_alloc_size;
75 	smb2_create_ctx_elem_t cc_in_time_warp;
76 	smb2_create_ctx_elem_t cc_in_req_lease;
77 	smb2_create_ctx_elem_t cc_in_aapl;
78 	smb2_create_ctx_elem_t cc_in_dh_request_v2;
79 	smb2_create_ctx_elem_t cc_in_dh_reconnect_v2;
80 	/* Elements we my place in the response */
81 	smb2_create_ctx_elem_t cc_out_max_access;
82 	smb2_create_ctx_elem_t cc_out_file_id;
83 	smb2_create_ctx_elem_t cc_out_aapl;
84 	smb2_create_ctx_elem_t cc_out_req_lease;
85 	smb2_create_ctx_elem_t cc_out_dh_request;
86 	smb2_create_ctx_elem_t cc_out_dh_request_v2;
87 } smb2_create_ctx_t;
88 
89 static uint32_t smb2_decode_create_ctx(
90 	smb_request_t *, smb2_create_ctx_t *);
91 static uint32_t smb2_encode_create_ctx(
92 	smb_request_t *, smb2_create_ctx_t *);
93 static int smb2_encode_create_ctx_elem(
94 	mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
95 static void smb2_free_create_ctx(smb2_create_ctx_t *);
96 
97 int smb2_enable_dh = 1;
98 
99 smb_sdrc_t
100 smb2_create(smb_request_t *sr)
101 {
102 	smb_attr_t *attr;
103 	smb2_create_ctx_elem_t *cce;
104 	smb2_create_ctx_t cctx;
105 	smb_arg_open_t *op = &sr->arg.open;
106 	smb_ofile_t *of = NULL;
107 	uint16_t StructSize;
108 	uint8_t SecurityFlags;
109 	uint32_t ImpersonationLevel;
110 	uint64_t SmbCreateFlags;
111 	uint64_t Reserved4;
112 	uint16_t NameOffset;
113 	uint16_t NameLength;
114 	uint32_t CreateCtxOffset;
115 	uint32_t CreateCtxLength;
116 	smb2fid_t smb2fid = { 0, 0 };
117 	uint32_t status;
118 	int dh_flags;
119 	int skip;
120 	int rc = 0;
121 
122 	bzero(&cctx, sizeof (cctx));
123 	op->create_ctx = &cctx;	/* for debugging */
124 
125 	/*
126 	 * Paranoia.  This will set sr->fid_ofile, so
127 	 * if we already have one, release it now.
128 	 */
129 	if (sr->fid_ofile != NULL) {
130 		smb_ofile_release(sr->fid_ofile);
131 		sr->fid_ofile = NULL;
132 	}
133 
134 	/*
135 	 * Decode the SMB2 Create request
136 	 *
137 	 * Most decode errors return SDRC_ERROR, but
138 	 * for some we give a more specific error.
139 	 *
140 	 * In the "decode section" (starts here) any
141 	 * errors should either return SDRC_ERROR, or
142 	 * if any cleanup is needed, goto errout.
143 	 */
144 	rc = smb_mbc_decodef(
145 	    &sr->smb_data, "wbblqqlllllwwll",
146 	    &StructSize,		/* w */
147 	    &SecurityFlags,		/* b */
148 	    &op->op_oplock_level,	/* b */
149 	    &ImpersonationLevel,	/* l */
150 	    &SmbCreateFlags,		/* q */
151 	    &Reserved4,			/* q */
152 	    &op->desired_access,	/* l */
153 	    &op->dattr,			/* l */
154 	    &op->share_access,		/* l */
155 	    &op->create_disposition,	/* l */
156 	    &op->create_options,	/* l */
157 	    &NameOffset,		/* w */
158 	    &NameLength,		/* w */
159 	    &CreateCtxOffset,		/* l */
160 	    &CreateCtxLength);		/* l */
161 	if (rc != 0 || StructSize != 57)
162 		return (SDRC_ERROR);
163 
164 	/*
165 	 * We're normally positioned at the path name now,
166 	 * but there could be some padding before it.
167 	 */
168 	skip = (NameOffset + sr->smb2_cmd_hdr) -
169 	    sr->smb_data.chain_offset;
170 	if (skip < 0)
171 		return (SDRC_ERROR);
172 	if (skip > 0)
173 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
174 
175 	/*
176 	 * Get the path name
177 	 *
178 	 * Name too long is not technically a decode error,
179 	 * but it's very rare, so we'll just skip the
180 	 * dtrace probes for this error case.
181 	 */
182 	if (NameLength >= SMB_MAXPATHLEN) {
183 		status = NT_STATUS_OBJECT_PATH_INVALID;
184 		goto errout;
185 	}
186 	if (NameLength == 0) {
187 		op->fqi.fq_path.pn_path = "\\";
188 	} else {
189 		rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
190 		    NameLength, &op->fqi.fq_path.pn_path);
191 		if (rc) {
192 			status = NT_STATUS_OBJECT_PATH_INVALID;
193 			goto errout;
194 		}
195 	}
196 	op->fqi.fq_dnode = sr->tid_tree->t_snode;
197 
198 	/*
199 	 * If there is a "Create Context" payload, decode it.
200 	 * This may carry things like a security descriptor,
201 	 * extended attributes, etc. to be used in create.
202 	 *
203 	 * The create ctx buffer must start after the headers
204 	 * and file name, and must be 8-byte aligned.
205 	 */
206 	if (CreateCtxLength != 0) {
207 		if ((CreateCtxOffset & 7) != 0 ||
208 		    (CreateCtxOffset + sr->smb2_cmd_hdr) <
209 		    sr->smb_data.chain_offset) {
210 			status = NT_STATUS_INVALID_PARAMETER;
211 			goto errout;
212 		}
213 
214 		rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
215 		    sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
216 		if (rc) {
217 			status = NT_STATUS_INVALID_PARAMETER;
218 			goto errout;
219 		}
220 		status = smb2_decode_create_ctx(sr, &cctx);
221 		if (status)
222 			goto errout;
223 	}
224 
225 	/*
226 	 * Everything is decoded into some internal form, so
227 	 * in this probe one can look at sr->arg.open etc.
228 	 *
229 	 * This marks the end of the "decode" section and the
230 	 * beginning of the "body" section.  Any errors in
231 	 * this section should use: goto cmd_done (which is
232 	 * just before the dtrace "done" probe).
233 	 */
234 	DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */
235 
236 	/*
237 	 * Process the incoming create contexts (already decoded),
238 	 * that need action before the open, starting with the
239 	 * Durable Handle ones, which may override others.
240 	 */
241 
242 	/*
243 	 * Only disk trees get durable handles.
244 	 */
245 	if (smb2_enable_dh == 0 ||
246 	    (sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
247 		cctx.cc_in_flags &=
248 		    ~(CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
249 		    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
250 	}
251 
252 	/*
253 	 * DH v2 is only valid in SMB3.0 and later.
254 	 * If seen in earlier dialects, ignore.
255 	 */
256 	if (sr->session->dialect < SMB_VERS_3_0) {
257 		cctx.cc_in_flags &=
258 		    ~(CCTX_DH_REQUEST_V2|CCTX_DH_RECONNECT_V2);
259 	}
260 
261 	/*
262 	 * It is an error to specify more than one Durable Handle
263 	 * operation in a single create, except when only the v1
264 	 * REQUEST and RECONNECT operations are specified. In that
265 	 * case, the v1 REQUEST is ignored.
266 	 */
267 	dh_flags = cctx.cc_in_flags &
268 	    (CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
269 	    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
270 	if ((dh_flags & (dh_flags - 1)) != 0 &&
271 	    dh_flags != (CCTX_DH_REQUEST|CCTX_DH_RECONNECT)) {
272 		status = NT_STATUS_INVALID_PARAMETER;
273 		goto cmd_done;
274 	}
275 
276 	/*
277 	 * Reconnect is special in MANY ways, including the
278 	 * somewhat surprising (specified) behavior that
279 	 * most other creat parameters are ignored, and
280 	 * many create context types are ignored too.
281 	 */
282 	op->dh_vers = SMB2_NOT_DURABLE;
283 	op->dh_v2_flags = 0;
284 	if ((cctx.cc_in_flags &
285 	    (CCTX_DH_RECONNECT|CCTX_DH_RECONNECT_V2)) != 0) {
286 
287 		if ((cctx.cc_in_flags & CCTX_DH_RECONNECT_V2) != 0)
288 			op->dh_vers = SMB2_DURABLE_V2;
289 		else
290 			op->dh_vers = SMB2_DURABLE_V1;
291 
292 		/* Ignore these create contexts. */
293 		cctx.cc_in_flags &=
294 		    ~(CCTX_DH_REQUEST |
295 		    CCTX_DH_REQUEST_V2 |
296 		    CCTX_EA_BUFFER |
297 		    CCTX_SD_BUFFER |
298 		    CCTX_ALLOCATION_SIZE |
299 		    CCTX_TIMEWARP_TOKEN |
300 		    CCTX_QUERY_ON_DISK_ID);
301 
302 		/*
303 		 * Reconnect check needs to know if a lease was requested.
304 		 * The requested oplock level is ignored in reconnect, so
305 		 * using op_oplock_level to convey this info.
306 		 */
307 		if (cctx.cc_in_flags & CCTX_REQUEST_LEASE)
308 			op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
309 		else
310 			op->op_oplock_level = 0;
311 
312 		status = smb2_dh_reconnect(sr);
313 		if (status != NT_STATUS_SUCCESS)
314 			goto cmd_done;
315 
316 		/*
317 		 * Skip most open execution during reconnect,
318 		 * but need (reclaimed) oplock state in *op.
319 		 */
320 		of = sr->fid_ofile;
321 		smb2_oplock_reconnect(sr);
322 		goto reconnect_done;
323 	}
324 
325 	/*
326 	 * Real create (of a new handle, not reconnect)
327 	 */
328 
329 	/*
330 	 * Validate the requested oplock level.
331 	 * Conversion to internal form is in smb2_oplock_acquire()
332 	 */
333 	switch (op->op_oplock_level) {
334 	case SMB2_OPLOCK_LEVEL_NONE:		/* OPLOCK_LEVEL_NONE */
335 	case SMB2_OPLOCK_LEVEL_II:		/* OPLOCK_LEVEL_TWO */
336 	case SMB2_OPLOCK_LEVEL_EXCLUSIVE:	/* OPLOCK_LEVEL_ONE */
337 	case SMB2_OPLOCK_LEVEL_BATCH:		/* OPLOCK_LEVEL_BATCH */
338 		/*
339 		 * Ignore lease create context (if any)
340 		 */
341 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
342 		break;
343 
344 	case SMB2_OPLOCK_LEVEL_LEASE:		/* OPLOCK_LEVEL_GRANULAR */
345 		/*
346 		 * Require a lease create context.
347 		 */
348 		if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) == 0) {
349 			cmn_err(CE_NOTE, "smb2:create, oplock=ff and no lease");
350 			status = NT_STATUS_INVALID_PARAMETER;
351 			goto cmd_done;
352 		}
353 
354 		/*
355 		 * Validate lease request state
356 		 * Only a few valid combinations.
357 		 */
358 		switch (op->lease_state) {
359 		case SMB2_LEASE_NONE:
360 		case SMB2_LEASE_READ_CACHING:
361 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_HANDLE_CACHING:
362 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING:
363 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING |
364 		    SMB2_LEASE_HANDLE_CACHING:
365 			break;
366 
367 		default:
368 			/*
369 			 * Invalid lease state flags
370 			 * Just force to "none".
371 			 */
372 			op->lease_state = SMB2_LEASE_NONE;
373 			break;
374 		}
375 		break;
376 
377 	default:
378 		/* Unknown SMB2 oplock level. */
379 		status = NT_STATUS_INVALID_PARAMETER;
380 		goto cmd_done;
381 	}
382 
383 	/*
384 	 * Only disk trees get oplocks or leases.
385 	 */
386 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
387 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
388 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
389 	}
390 
391 	if ((cctx.cc_in_flags &
392 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0) {
393 		if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0)
394 			op->dh_vers = SMB2_DURABLE_V2;
395 		else
396 			op->dh_vers = SMB2_DURABLE_V1;
397 	}
398 
399 	if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
400 		status = NT_STATUS_EAS_NOT_SUPPORTED;
401 		goto cmd_done;
402 	}
403 
404 	/*
405 	 * ImpersonationLevel (spec. says validate + ignore)
406 	 * SmbCreateFlags (spec. says ignore)
407 	 */
408 
409 	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
410 	    !(op->desired_access & DELETE)) {
411 		status = NT_STATUS_INVALID_PARAMETER;
412 		goto cmd_done;
413 	}
414 
415 	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
416 		op->create_options |= FILE_WRITE_THROUGH;
417 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
418 		op->create_options |= FILE_DELETE_ON_CLOSE;
419 	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
420 		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
421 	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
422 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
423 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
424 		status = NT_STATUS_INVALID_PARAMETER;
425 		goto cmd_done;
426 	}
427 
428 	/*
429 	 * The real open call.   Note: this gets attributes into
430 	 * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
431 	 * When of != NULL, goto errout closes it.
432 	 */
433 	status = smb_common_open(sr);
434 	if (status != NT_STATUS_SUCCESS)
435 		goto cmd_done;
436 	of = sr->fid_ofile;
437 
438 	/*
439 	 * Set the "persistent" part of the file ID
440 	 * (only for DISK shares).  Need this even for
441 	 * non-durable handles in case we get the ioctl
442 	 * to set "resiliency" on this handle.
443 	 */
444 	if (of->f_ftype == SMB_FTYPE_DISK)
445 		smb_ofile_set_persistid(of);
446 
447 	/*
448 	 * [MS-SMB2] 3.3.5.9.8
449 	 * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
450 	 */
451 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) {
452 		status = smb2_lease_create(sr);
453 		if (status != NT_STATUS_SUCCESS) {
454 			if (op->action_taken == SMB_OACT_CREATED) {
455 				smb_ofile_set_delete_on_close(sr, of);
456 			}
457 			goto cmd_done;
458 		}
459 	}
460 	if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
461 		smb2_lease_acquire(sr);
462 	} else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
463 		smb2_oplock_acquire(sr);
464 	}
465 
466 	/*
467 	 * Make this a durable open, but only if:
468 	 * (durable handle requested and...)
469 	 *
470 	 * 1. op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH
471 	 * 2. A lease is requested with handle caching
472 	 *    - for v1, the lease must not be on a directory
473 	 * 3. For v2, flags has "persistent" (tree is CA)
474 	 *    (when tree not CA, turned off persist above)
475 	 *
476 	 * Otherwise, DH requests are ignored, so we set
477 	 * dh_vers = not durable
478 	 */
479 	if ((cctx.cc_in_flags &
480 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 &&
481 	    smb_node_is_file(of->f_node) &&
482 	    ((op->op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH) ||
483 	    (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE &&
484 	    (op->lease_state & OPLOCK_LEVEL_CACHE_HANDLE) != 0))) {
485 		/*
486 		 * OK, make this handle "durable"
487 		 */
488 		if (op->dh_vers == SMB2_DURABLE_V2) {
489 			(void) memcpy(of->dh_create_guid,
490 			    op->create_guid, UUID_LEN);
491 
492 			/* no persistent handles yet */
493 			of->dh_persist = B_FALSE;
494 		}
495 		if (op->dh_vers != SMB2_NOT_DURABLE) {
496 			uint32_t msto;
497 
498 			of->dh_vers = op->dh_vers;
499 			of->dh_expire_time = 0;
500 
501 			/*
502 			 * Client may provide timeout=0 to request
503 			 * the default timeout (in mSec.)
504 			 */
505 			msto = op->dh_timeout;
506 			if (msto == 0)
507 				msto = smb2_dh_def_timeout;
508 			if (msto > smb2_dh_max_timeout)
509 				msto = smb2_dh_max_timeout;
510 			op->dh_timeout = msto;
511 			of->dh_timeout_offset = MSEC2NSEC(msto);
512 		}
513 	} else {
514 		op->dh_vers = SMB2_NOT_DURABLE;
515 	}
516 
517 	/*
518 	 * NB: after the above smb_common_open() success,
519 	 * we have a handle allocated (sr->fid_ofile).
520 	 * If we don't return success, we must close it.
521 	 *
522 	 * Using sr->smb_fid as the file handle for now,
523 	 * though it could later be something larger,
524 	 * (16 bytes) similar to an NFSv4 open handle.
525 	 */
526 reconnect_done:
527 	smb2fid.persistent = of->f_persistid;
528 	smb2fid.temporal = sr->smb_fid;
529 
530 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
531 	case STYPE_DISKTREE:
532 	case STYPE_PRINTQ:
533 		if (op->create_options & FILE_DELETE_ON_CLOSE)
534 			smb_ofile_set_delete_on_close(sr, of);
535 		break;
536 	}
537 
538 	/*
539 	 * Process any outgoing create contexts that need work
540 	 * after the open succeeds.  Encode happens later.
541 	 */
542 	if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
543 		op->maximum_access = 0;
544 		if (of->f_node != NULL) {
545 			smb_fsop_eaccess(sr, of->f_cr, of->f_node,
546 			    &op->maximum_access);
547 		}
548 		op->maximum_access |= of->f_granted_access;
549 		cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
550 	}
551 
552 	if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
553 	    of->f_node != NULL) {
554 		op->op_fsid = SMB_NODE_FSID(of->f_node);
555 		cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
556 	}
557 
558 	if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
559 		cce = &cctx.cc_out_aapl;
560 		/*
561 		 * smb2_aapl_crctx has a variable response depending on
562 		 * what the incoming context looks like, so it does all
563 		 * the work of building cc_out_aapl, including setting
564 		 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
565 		 * If we see errors getting this, simply omit it from
566 		 * the collection of returned create contexts.
567 		 */
568 		status = smb2_aapl_crctx(sr,
569 		    &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
570 		if (status == 0) {
571 			cce->cce_len = cce->cce_mbc.chain_offset;
572 			cctx.cc_out_flags |= CCTX_AAPL_EXT;
573 		}
574 		status = 0;
575 	}
576 
577 	/*
578 	 * If a lease was requested, and we got one...
579 	 */
580 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 &&
581 	    op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)
582 		cctx.cc_out_flags |= CCTX_REQUEST_LEASE;
583 
584 	/*
585 	 * If a durable handle was requested and we got one...
586 	 */
587 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 &&
588 	    of->dh_vers == SMB2_DURABLE_V1) {
589 		cctx.cc_out_flags |= CCTX_DH_REQUEST;
590 	}
591 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 &&
592 	    of->dh_vers == SMB2_DURABLE_V2) {
593 		cctx.cc_out_flags |= CCTX_DH_REQUEST_V2;
594 	}
595 
596 	/*
597 	 * This marks the end of the "body" section and the
598 	 * beginning of the "encode" section.  Any errors
599 	 * encoding the response should use: goto errout
600 	 */
601 cmd_done:
602 	/* Want status visible in the done probe. */
603 	sr->smb2_status = status;
604 	DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
605 	if (status != NT_STATUS_SUCCESS)
606 		goto errout;
607 
608 	/*
609 	 * Encode all the create contexts to return.
610 	 */
611 	if (cctx.cc_out_flags) {
612 		sr->raw_data.max_bytes = smb2_max_trans;
613 		status = smb2_encode_create_ctx(sr, &cctx);
614 		if (status)
615 			goto errout;
616 	}
617 
618 	/*
619 	 * Encode the SMB2 Create reply
620 	 */
621 	attr = &op->fqi.fq_fattr;
622 	rc = smb_mbc_encodef(
623 	    &sr->reply,
624 	    "wb.lTTTTqqllqqll",
625 	    89,	/* StructSize */	/* w */
626 	    op->op_oplock_level,	/* b */
627 	    op->action_taken,		/* l */
628 	    &attr->sa_crtime,		/* T */
629 	    &attr->sa_vattr.va_atime,	/* T */
630 	    &attr->sa_vattr.va_mtime,	/* T */
631 	    &attr->sa_vattr.va_ctime,	/* T */
632 	    attr->sa_allocsz,		/* q */
633 	    attr->sa_vattr.va_size,	/* q */
634 	    attr->sa_dosattr,		/* l */
635 	    0, /* reserved2 */		/* l */
636 	    smb2fid.persistent,		/* q */
637 	    smb2fid.temporal,		/* q */
638 	    0,  /* CreateCtxOffset	   l */
639 	    0); /* CreateCtxLength	   l */
640 	if (rc != 0) {
641 		status = NT_STATUS_UNSUCCESSFUL;
642 		goto errout;
643 	}
644 
645 	CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
646 	CreateCtxLength = MBC_LENGTH(&sr->raw_data);
647 	if (CreateCtxLength != 0) {
648 		/*
649 		 * Overwrite CreateCtxOffset, CreateCtxLength, pad
650 		 */
651 		sr->reply.chain_offset -= 8;
652 		rc = smb_mbc_encodef(
653 		    &sr->reply,
654 		    "ll#C",
655 		    CreateCtxOffset,	/* l */
656 		    CreateCtxLength,	/* l */
657 		    CreateCtxLength,	/* # */
658 		    &sr->raw_data);	/* C */
659 		if (rc != 0) {
660 			status = NT_STATUS_UNSUCCESSFUL;
661 			goto errout;
662 		}
663 	} else {
664 		(void) smb_mbc_encodef(&sr->reply, ".");
665 	}
666 
667 	if (status != 0) {
668 	errout:
669 		if (of != NULL)
670 			smb_ofile_close(of, 0);
671 		smb2sr_put_error(sr, status);
672 	}
673 	if (op->sd != NULL) {
674 		smb_sd_term(op->sd);
675 		kmem_free(op->sd, sizeof (*op->sd));
676 	}
677 	if (cctx.cc_out_flags)
678 		smb2_free_create_ctx(&cctx);
679 
680 	return (SDRC_SUCCESS);
681 }
682 
683 /*
684  * Decode an SMB2 Create Context buffer into our internal form.
685  * Avoid policy decisions about what's supported here, just decode.
686  */
687 static uint32_t
688 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
689 {
690 	smb_arg_open_t *op = &sr->arg.open;
691 	smb2_create_ctx_elem_t *cce;
692 	mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
693 	mbuf_chain_t name_mbc;
694 	union {
695 		uint32_t i;
696 		char ch[4];
697 	} cc_name;
698 	uint32_t status;
699 	int32_t next_off;
700 	uint32_t data_len;
701 	uint16_t data_off;
702 	uint16_t name_off;
703 	uint16_t name_len;
704 	int top_offset;
705 	int rc;
706 
707 	/*
708 	 * Any break from the loop below before we've decoded
709 	 * the entire create context means it was malformatted,
710 	 * so we should return INVALID_PARAMETER.
711 	 */
712 	status = NT_STATUS_INVALID_PARAMETER;
713 	for (;;) {
714 		cce = NULL;
715 		top_offset = in_mbc->chain_offset;
716 		rc = smb_mbc_decodef(
717 		    in_mbc,
718 		    "lww..wl",
719 		    &next_off,	/* l */
720 		    &name_off,	/* w */
721 		    &name_len,	/* w */
722 		    /* reserved	  .. */
723 		    &data_off,	/* w */
724 		    &data_len); /* l */
725 		if (rc)
726 			break;
727 
728 		/*
729 		 * The Create Context "name", per [MS-SMB] 2.2.13.2
730 		 * They're defined as network-order integers for our
731 		 * switch below.  We don't have routines to decode
732 		 * native order, so read as char[4] then ntohl.
733 		 * NB: in SMB3, some of these are 8 bytes.
734 		 */
735 		if ((top_offset + name_off) < in_mbc->chain_offset)
736 			break;
737 		rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
738 		    top_offset + name_off, name_len);
739 		if (rc)
740 			break;
741 		rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
742 		if (rc)
743 			break;
744 		cc_name.i = ntohl(cc_name.i);
745 
746 		switch (cc_name.i) {
747 		case SMB2_CREATE_EA_BUFFER:		/* ("ExtA") */
748 			cc->cc_in_flags |= CCTX_EA_BUFFER;
749 			cce = &cc->cc_in_ext_attr;
750 			break;
751 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
752 			cc->cc_in_flags |= CCTX_SD_BUFFER;
753 			cce = &cc->cc_in_sec_desc;
754 			break;
755 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
756 			cc->cc_in_flags |= CCTX_DH_REQUEST;
757 			cce = &cc->cc_in_dh_request;
758 			break;
759 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
760 			cc->cc_in_flags |= CCTX_DH_RECONNECT;
761 			cce = &cc->cc_in_dh_reconnect;
762 			break;
763 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
764 			cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
765 			cce = &cc->cc_in_alloc_size;
766 			break;
767 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
768 			cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
769 			/* no input data for this */
770 			break;
771 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
772 			cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
773 			cce = &cc->cc_in_time_warp;
774 			break;
775 		case SMB2_CREATE_QUERY_ON_DISK_ID:	/* ("QFid") */
776 			cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
777 			/* no input data for this */
778 			break;
779 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
780 			cc->cc_in_flags |= CCTX_REQUEST_LEASE;
781 			cce = &cc->cc_in_req_lease;
782 			break;
783 		case SMB2_CREATE_CTX_AAPL:		/* ("AAPL") */
784 			cc->cc_in_flags |= CCTX_AAPL_EXT;
785 			cce = &cc->cc_in_aapl;
786 			break;
787 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
788 			cc->cc_in_flags |= CCTX_DH_REQUEST_V2;
789 			cce = &cc->cc_in_dh_request_v2;
790 			break;
791 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
792 			cc->cc_in_flags |= CCTX_DH_RECONNECT_V2;
793 			cce = &cc->cc_in_dh_reconnect_v2;
794 			break;
795 		case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */
796 			/* 9ccbcf9e 04c1e643 980e158d a1f6ec83 */
797 			/* silently ignore */
798 			break;
799 		default:
800 			/*
801 			 * Unknown create context values are normal, and
802 			 * should be ignored.  However, in debug mode,
803 			 * let's log them so we know which ones we're
804 			 * not handling (and may want to add).
805 			 */
806 #ifdef	DEBUG
807 			cmn_err(CE_NOTE, "unknown create context ID 0x%x",
808 			    cc_name.i);
809 #endif
810 			cce = NULL;
811 			break;
812 		}
813 
814 		if (cce == NULL || data_len == 0)
815 			goto next_cc;
816 
817 		if ((data_off & 7) != 0)
818 			break;
819 		if ((top_offset + data_off) < in_mbc->chain_offset)
820 			break;
821 		rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
822 		    top_offset + data_off, data_len);
823 		if (rc)
824 			break;
825 		cce->cce_len = data_len;
826 
827 		/*
828 		 * Additonal decoding for some create contexts.
829 		 */
830 		switch (cc_name.i) {
831 			uint64_t nttime;
832 
833 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
834 			op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
835 			if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
836 				goto errout;
837 			break;
838 
839 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
840 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
841 			if (rc != 0)
842 				goto errout;
843 			break;
844 
845 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
846 			/*
847 			 * Support for opening "Previous Versions".
848 			 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
849 			 */
850 			rc = smb_mbc_decodef(&cce->cce_mbc,
851 			    "q", &nttime);
852 			if (rc != 0)
853 				goto errout;
854 			smb_time_nt_to_unix(nttime, &op->timewarp);
855 			op->create_timewarp = B_TRUE;
856 			break;
857 
858 		/*
859 		 * Note: This handles both V1 and V2 leases,
860 		 * which differ only by their length.
861 		 */
862 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
863 			if (data_len == 52) {
864 				op->lease_version = 2;
865 			} else if (data_len == 32) {
866 				op->lease_version = 1;
867 			} else {
868 				cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x",
869 				    data_len);
870 			}
871 			rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq",
872 			    UUID_LEN,			/* # */
873 			    op->lease_key,		/* c */
874 			    &op->lease_state,		/* l */
875 			    &op->lease_flags,		/* l */
876 			    &nttime);	/* (ignored)	   q */
877 			if (rc != 0)
878 				goto errout;
879 			if (op->lease_version == 2) {
880 				rc = smb_mbc_decodef(&cce->cce_mbc,
881 				    "#cw..",
882 				    UUID_LEN,
883 				    op->parent_lease_key,
884 				    &op->lease_epoch);
885 				if (rc != 0)
886 					goto errout;
887 			} else {
888 				bzero(op->parent_lease_key, UUID_LEN);
889 			}
890 			break;
891 
892 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
893 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl",
894 			    &op->dh_fileid.persistent,	/* q */
895 			    &op->dh_fileid.temporal,	/* q */
896 			    UUID_LEN,			/* # */
897 			    op->create_guid,		/* c */
898 			    &op->dh_v2_flags);		/* l */
899 			if (rc != 0)
900 				goto errout;
901 			break;
902 
903 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
904 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq",
905 			    &op->dh_fileid.persistent, /* q */
906 			    &op->dh_fileid.temporal); /* q */
907 			if (rc != 0)
908 				goto errout;
909 			bzero(op->create_guid, UUID_LEN);
910 			op->dh_v2_flags = 0;
911 			break;
912 
913 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
914 			rc = smb_mbc_decodef(&cce->cce_mbc,
915 			    "ll8.#c",
916 			    &op->dh_timeout,	/* l */
917 			    &op->dh_v2_flags,	/* l */
918 			    /* reserved */	/* 8. */
919 			    UUID_LEN, /* # */
920 			    op->create_guid); /* c */
921 			if (rc != 0)
922 				goto errout;
923 			break;
924 
925 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
926 			rc = smb_mbc_decodef(&cce->cce_mbc,
927 			    "16."); /* reserved */
928 			if (rc != 0)
929 				goto errout;
930 			op->dh_timeout = 0;	/* default */
931 			op->dh_v2_flags = 0;
932 			break;
933 		}
934 
935 	next_cc:
936 		if (next_off == 0) {
937 			/* Normal loop termination */
938 			status = 0;
939 			break;
940 		}
941 
942 		if ((next_off & 7) != 0)
943 			break;
944 		if ((top_offset + next_off) < in_mbc->chain_offset)
945 			break;
946 		if ((top_offset + next_off) > in_mbc->max_bytes)
947 			break;
948 		in_mbc->chain_offset = top_offset + next_off;
949 	}
950 
951 errout:
952 	return (status);
953 }
954 
955 /*
956  * Encode an SMB2 Create Context buffer from our internal form.
957  *
958  * Build the Create Context to return; first the
959  * per-element parts, then the aggregated buffer.
960  *
961  * No response for these:
962  *	CCTX_EA_BUFFER
963  *	CCTX_SD_BUFFER
964  *	CCTX_ALLOCATION_SIZE
965  *	CCTX_TIMEWARP_TOKEN
966  *
967  * Remember to add code sections to smb2_free_create_ctx()
968  * for each section here that encodes a context element.
969  */
970 static uint32_t
971 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
972 {
973 	smb_arg_open_t *op = &sr->arg.open;
974 	smb2_create_ctx_elem_t *cce;
975 	mbuf_chain_t *mbc = &sr->raw_data;
976 	int last_top = -1;
977 	int rc;
978 
979 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
980 		cce = &cc->cc_out_max_access;
981 
982 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
983 		(void) smb_mbc_encodef(&cce->cce_mbc,
984 		    "ll", 0, op->maximum_access);
985 
986 		last_top = mbc->chain_offset;
987 		rc = smb2_encode_create_ctx_elem(mbc, cce,
988 		    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
989 		if (rc)
990 			return (NT_STATUS_INTERNAL_ERROR);
991 		(void) smb_mbc_poke(mbc, last_top, "l",
992 		    mbc->chain_offset - last_top);
993 	}
994 
995 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
996 		cce = &cc->cc_out_file_id;
997 
998 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
999 		(void) smb_mbc_encodef(
1000 		    &cce->cce_mbc, "qll.15.",
1001 		    op->fileid,			/* q */
1002 		    op->op_fsid.val[0],		/* l */
1003 		    op->op_fsid.val[1]);	/* l */
1004 		    /* reserved (16 bytes)	.15. */
1005 
1006 		last_top = mbc->chain_offset;
1007 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1008 		    SMB2_CREATE_QUERY_ON_DISK_ID);
1009 		if (rc)
1010 			return (NT_STATUS_INTERNAL_ERROR);
1011 		(void) smb_mbc_poke(mbc, last_top, "l",
1012 		    mbc->chain_offset - last_top);
1013 	}
1014 
1015 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1016 		cce = &cc->cc_out_aapl;
1017 		/* cc_out_aapl already encoded */
1018 
1019 		last_top = mbc->chain_offset;
1020 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1021 		    SMB2_CREATE_CTX_AAPL);
1022 		if (rc)
1023 			return (NT_STATUS_INTERNAL_ERROR);
1024 		(void) smb_mbc_poke(mbc, last_top, "l",
1025 		    mbc->chain_offset - last_top);
1026 	}
1027 
1028 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1029 		cce = &cc->cc_out_req_lease;
1030 
1031 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
1032 		(void) smb_mbc_encodef(&cce->cce_mbc, "#cllq",
1033 		    UUID_LEN,			/* # */
1034 		    op->lease_key,		/* c */
1035 		    op->lease_state,		/* l */
1036 		    op->lease_flags,		/* l */
1037 		    0LL);			/* q */
1038 		if (op->lease_version == 2) {
1039 			cce->cce_mbc.max_bytes = cce->cce_len = 52;
1040 			(void) smb_mbc_encodef(&cce->cce_mbc,
1041 			    "#cw..",
1042 			    UUID_LEN,
1043 			    op->parent_lease_key,
1044 			    op->lease_epoch);
1045 		}
1046 
1047 		last_top = mbc->chain_offset;
1048 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1049 		    SMB2_CREATE_REQUEST_LEASE);
1050 		if (rc)
1051 			return (NT_STATUS_INTERNAL_ERROR);
1052 		(void) smb_mbc_poke(mbc, last_top, "l",
1053 		    mbc->chain_offset - last_top);
1054 	}
1055 
1056 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1057 		cce = &cc->cc_out_dh_request;
1058 
1059 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1060 		(void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL);
1061 
1062 		last_top = mbc->chain_offset;
1063 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1064 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST);
1065 		if (rc)
1066 			return (NT_STATUS_INTERNAL_ERROR);
1067 		(void) smb_mbc_poke(mbc, last_top, "l",
1068 		    mbc->chain_offset - last_top);
1069 	}
1070 
1071 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1072 		cce = &cc->cc_out_dh_request_v2;
1073 
1074 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1075 		(void) smb_mbc_encodef(&cce->cce_mbc, "ll",
1076 		    op->dh_timeout, op->dh_v2_flags);
1077 
1078 		last_top = mbc->chain_offset;
1079 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1080 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);
1081 		if (rc)
1082 			return (NT_STATUS_INTERNAL_ERROR);
1083 		(void) smb_mbc_poke(mbc, last_top, "l",
1084 		    mbc->chain_offset - last_top);
1085 	}
1086 
1087 	if (last_top >= 0)
1088 		(void) smb_mbc_poke(mbc, last_top, "l", 0);
1089 
1090 	return (0);
1091 }
1092 
1093 static int
1094 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
1095     smb2_create_ctx_elem_t *cce, uint32_t id)
1096 {
1097 	union {
1098 		uint32_t i;
1099 		char ch[4];
1100 	} cc_name;
1101 	int rc;
1102 
1103 	/* as above */
1104 	cc_name.i = htonl(id);
1105 
1106 	/*
1107 	 * This is the header, per [MS-SMB2] 2.2.13.2
1108 	 * Sorry about the fixed offsets.  We know we'll
1109 	 * layout the data part as [name, payload] and
1110 	 * name is a fixed length, so this easy.
1111 	 * The final layout looks like this:
1112 	 *	a: this header (16 bytes)
1113 	 *	b: the name (4 bytes, 4 pad)
1114 	 *	c: the payload (variable)
1115 	 *	d: padding (to align 8)
1116 	 *
1117 	 * Note that "Next elem." is filled in later.
1118 	 */
1119 	rc = smb_mbc_encodef(
1120 	    out_mbc, "lwwwwl",
1121 	    0,		/* Next offset	l */
1122 	    16,		/* NameOffset	w */
1123 	    4,		/* NameLength	w */
1124 	    0,		/* Reserved	w */
1125 	    24,		/* DataOffset	w */
1126 	    cce->cce_len); /* DataLen	l */
1127 	if (rc)
1128 		return (rc);
1129 
1130 	/*
1131 	 * Now the "name" and payload.
1132 	 */
1133 	rc = smb_mbc_encodef(
1134 	    out_mbc, "4c4.#C",
1135 	    cc_name.ch,		/* 4c4. */
1136 	    cce->cce_len,	/* # */
1137 	    &cce->cce_mbc);	/* C */
1138 
1139 	(void) smb_mbc_put_align(out_mbc, 8);
1140 
1141 	return (rc);
1142 }
1143 
1144 static void
1145 smb2_free_create_ctx(smb2_create_ctx_t *cc)
1146 {
1147 	smb2_create_ctx_elem_t *cce;
1148 
1149 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1150 		cce = &cc->cc_out_max_access;
1151 		MBC_FLUSH(&cce->cce_mbc);
1152 	}
1153 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1154 		cce = &cc->cc_out_file_id;
1155 		MBC_FLUSH(&cce->cce_mbc);
1156 	}
1157 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1158 		cce = &cc->cc_out_aapl;
1159 		MBC_FLUSH(&cce->cce_mbc);
1160 	}
1161 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1162 		cce = &cc->cc_out_req_lease;
1163 		MBC_FLUSH(&cce->cce_mbc);
1164 	}
1165 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1166 		cce = &cc->cc_out_dh_request;
1167 		MBC_FLUSH(&cce->cce_mbc);
1168 	}
1169 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1170 		cce = &cc->cc_out_dh_request_v2;
1171 		MBC_FLUSH(&cce->cce_mbc);
1172 	}
1173 }
1174