xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c (revision 6030:6bebab7d43d5)
15772Sas200622 /*
25772Sas200622  * CDDL HEADER START
35772Sas200622  *
45772Sas200622  * The contents of this file are subject to the terms of the
55772Sas200622  * Common Development and Distribution License (the "License").
65772Sas200622  * You may not use this file except in compliance with the License.
75772Sas200622  *
85772Sas200622  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95772Sas200622  * or http://www.opensolaris.org/os/licensing.
105772Sas200622  * See the License for the specific language governing permissions
115772Sas200622  * and limitations under the License.
125772Sas200622  *
135772Sas200622  * When distributing Covered Code, include this CDDL HEADER in each
145772Sas200622  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155772Sas200622  * If applicable, add the following below this CDDL HEADER, with the
165772Sas200622  * fields enclosed by brackets "[]" replaced with your own identifying
175772Sas200622  * information: Portions Copyright [yyyy] [name of copyright owner]
185772Sas200622  *
195772Sas200622  * CDDL HEADER END
205772Sas200622  */
215772Sas200622 /*
225772Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235772Sas200622  * Use is subject to license terms.
245772Sas200622  */
255772Sas200622 
265772Sas200622 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275772Sas200622 
285772Sas200622 /*
295772Sas200622  * Server side RPC handler.
305772Sas200622  */
315772Sas200622 
325772Sas200622 #include <sys/byteorder.h>
335772Sas200622 #include <thread.h>
345772Sas200622 #include <synch.h>
355772Sas200622 #include <stdlib.h>
365772Sas200622 #include <strings.h>
375772Sas200622 #include <string.h>
385772Sas200622 #include <time.h>
395772Sas200622 
405772Sas200622 #include <smbsrv/libsmb.h>
415772Sas200622 #include <smbsrv/libmlrpc.h>
425772Sas200622 #include <smbsrv/mlsvc.h>
435772Sas200622 #include <smbsrv/ndr.h>
445772Sas200622 #include <smbsrv/mlrpc.h>
455772Sas200622 #include <smbsrv/mlsvc_util.h>
465772Sas200622 #include <smbsrv/ntsid.h>
475772Sas200622 #include <smbsrv/smb_winpipe.h>
485772Sas200622 
495772Sas200622 /*
505772Sas200622  * Fragment size (5680: NT style).
515772Sas200622  */
525772Sas200622 #define	MLRPC_FRAG_SZ		5680
535772Sas200622 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ;
545772Sas200622 
555772Sas200622 /*
565772Sas200622  * Context table.
575772Sas200622  */
585772Sas200622 #define	CTXT_TABLE_ENTRIES	128
595772Sas200622 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES];
605772Sas200622 static mutex_t mlrpc_context_lock;
615772Sas200622 
625772Sas200622 static int mlrpc_s_process(struct mlrpc_xaction *);
635772Sas200622 static int mlrpc_s_bind(struct mlrpc_xaction *);
645772Sas200622 static int mlrpc_s_request(struct mlrpc_xaction *);
655772Sas200622 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *);
665772Sas200622 static int mlrpc_s_alter_context(struct mlrpc_xaction *);
675772Sas200622 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *);
685772Sas200622 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long);
695772Sas200622 static int mlrpc_build_reply(struct mlrpc_xaction *);
705772Sas200622 
715772Sas200622 /*
725772Sas200622  * This is the RPC service server-side entry point.  All MSRPC encoded
735772Sas200622  * messages should be passed through here.  We use the same context
745772Sas200622  * structure as the client side but we don't need to set up the client
755772Sas200622  * side info.
765772Sas200622  */
775772Sas200622 struct mlsvc_rpc_context *
785772Sas200622 mlrpc_process(int fid, smb_dr_user_ctx_t *user_ctx)
795772Sas200622 {
805772Sas200622 	struct mlsvc_rpc_context	*context;
815772Sas200622 	struct mlrpc_xaction		*mxa;
825772Sas200622 	struct mlndr_stream		*recv_mlnds;
835772Sas200622 	struct mlndr_stream		*send_mlnds;
845772Sas200622 	unsigned char			*pdu_base_addr;
855772Sas200622 	char				*data;
865772Sas200622 	int				datalen;
875772Sas200622 
885772Sas200622 	if ((context = mlrpc_lookup(fid)) == NULL)
895772Sas200622 		return (NULL);
905772Sas200622 
915772Sas200622 	context->user_ctx = user_ctx;
925772Sas200622 	data = context->inpipe->sp_data;
935772Sas200622 	datalen = context->inpipe->sp_datalen;
945772Sas200622 
955772Sas200622 	mxa = (struct mlrpc_xaction *)malloc(sizeof (struct mlrpc_xaction));
965772Sas200622 	if (mxa == NULL)
975772Sas200622 		return (NULL);
985772Sas200622 
995772Sas200622 	bzero(mxa, sizeof (struct mlrpc_xaction));
1005772Sas200622 	mxa->fid = fid;
1015772Sas200622 	mxa->context = context;
1025772Sas200622 	mxa->binding_list = context->binding;
1035772Sas200622 
1045772Sas200622 	if ((mxa->heap = mlrpc_heap_create()) == NULL) {
1055772Sas200622 		free(mxa);
1065772Sas200622 		return (NULL);
1075772Sas200622 	}
1085772Sas200622 
1095772Sas200622 	recv_mlnds = &mxa->recv_mlnds;
1105772Sas200622 	(void) mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV,
1115772Sas200622 	    mxa->heap);
1125772Sas200622 
1135772Sas200622 	bcopy(data, recv_mlnds->pdu_base_addr, datalen);
1145772Sas200622 
1155772Sas200622 	send_mlnds = &mxa->send_mlnds;
1165772Sas200622 	(void) mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap);
1175772Sas200622 
1185772Sas200622 	(void) mlrpc_s_process(mxa);
1195772Sas200622 
1205772Sas200622 	/*
1215772Sas200622 	 * Different pointers for single frag vs multi frag responses.
1225772Sas200622 	 */
1235772Sas200622 	if (send_mlnds->pdu_base_addr_with_rpc_hdrs)
1245772Sas200622 		pdu_base_addr = send_mlnds->pdu_base_addr_with_rpc_hdrs;
1255772Sas200622 	else
1265772Sas200622 		pdu_base_addr = send_mlnds->pdu_base_addr;
1275772Sas200622 
1285772Sas200622 	datalen = send_mlnds->pdu_size_with_rpc_hdrs;
1295772Sas200622 	context->outpipe->sp_datalen = datalen;
1305772Sas200622 	bcopy(pdu_base_addr, context->outpipe->sp_data, datalen);
1315772Sas200622 
1325772Sas200622 	mlnds_destruct(&mxa->recv_mlnds);
1335772Sas200622 	mlnds_destruct(&mxa->send_mlnds);
1345772Sas200622 	mlrpc_heap_destroy(mxa->heap);
1355772Sas200622 	free(mxa);
1365772Sas200622 	return (context);
1375772Sas200622 }
1385772Sas200622 
1395772Sas200622 /*
1405772Sas200622  * Lookup the context for pipeid. If one exists, return a pointer to it.
1415772Sas200622  * Otherwise attempt to allocate a new context and return it. If the
1425772Sas200622  * context table is full, return a null pointer.
1435772Sas200622  */
1445772Sas200622 struct mlsvc_rpc_context *
1455772Sas200622 mlrpc_lookup(int fid)
1465772Sas200622 {
1475772Sas200622 	struct mlsvc_rpc_context *context;
1485772Sas200622 	struct mlsvc_rpc_context *available = NULL;
1495772Sas200622 	int i;
1505772Sas200622 
1515772Sas200622 	(void) mutex_lock(&mlrpc_context_lock);
1525772Sas200622 
1535772Sas200622 	for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
1545772Sas200622 		context = &context_table[i];
1555772Sas200622 
1565772Sas200622 		if (available == NULL && context->fid == 0) {
1575772Sas200622 			available = context;
1585772Sas200622 			continue;
1595772Sas200622 		}
1605772Sas200622 
1615772Sas200622 		if (context->fid == fid) {
1625772Sas200622 			(void) mutex_unlock(&mlrpc_context_lock);
1635772Sas200622 			return (context);
1645772Sas200622 		}
1655772Sas200622 	}
1665772Sas200622 
1675772Sas200622 	if (available) {
1685772Sas200622 		bzero(available, sizeof (struct mlsvc_rpc_context));
169*6030Sjb150015 		available->inpipe = malloc(SMB_CTXT_PIPE_SZ);
170*6030Sjb150015 		available->outpipe = malloc(SMB_CTXT_PIPE_SZ);
1715772Sas200622 
1725772Sas200622 		if (available->inpipe == NULL || available->outpipe == NULL) {
1735772Sas200622 			free(available->inpipe);
1745772Sas200622 			free(available->outpipe);
1755772Sas200622 			bzero(available, sizeof (struct mlsvc_rpc_context));
1765772Sas200622 			(void) mutex_unlock(&mlrpc_context_lock);
1775772Sas200622 			return (NULL);
1785772Sas200622 		}
1795772Sas200622 
1805772Sas200622 		bzero(available->inpipe, sizeof (smb_pipe_t));
1815772Sas200622 		bzero(available->outpipe, sizeof (smb_pipe_t));
1825772Sas200622 		available->fid = fid;
1835772Sas200622 		available->inpipe->sp_pipeid = fid;
1845772Sas200622 		available->outpipe->sp_pipeid = fid;
1855772Sas200622 
1865772Sas200622 		mlrpc_binding_pool_initialize(&available->binding,
1875772Sas200622 		    available->binding_pool, CTXT_N_BINDING_POOL);
1885772Sas200622 	}
1895772Sas200622 
1905772Sas200622 	(void) mutex_unlock(&mlrpc_context_lock);
1915772Sas200622 	return (available);
1925772Sas200622 }
1935772Sas200622 
1945772Sas200622 /*
1955772Sas200622  * This function should be called to release the context associated
1965772Sas200622  * with a fid when the client performs a close file.
1975772Sas200622  */
1985772Sas200622 void
1995772Sas200622 mlrpc_release(int fid)
2005772Sas200622 {
2015772Sas200622 	struct mlsvc_rpc_context *context;
2025772Sas200622 	int i;
2035772Sas200622 
2045772Sas200622 	(void) mutex_lock(&mlrpc_context_lock);
2055772Sas200622 
2065772Sas200622 	for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) {
2075772Sas200622 		context = &context_table[i];
2085772Sas200622 
2095772Sas200622 		if (context->fid == fid) {
2105772Sas200622 			ndr_hdclose(fid);
2115772Sas200622 			free(context->inpipe);
2125772Sas200622 			free(context->outpipe);
2135772Sas200622 			bzero(context, sizeof (struct mlsvc_rpc_context));
2145772Sas200622 			break;
2155772Sas200622 		}
2165772Sas200622 	}
2175772Sas200622 
2185772Sas200622 	(void) mutex_unlock(&mlrpc_context_lock);
2195772Sas200622 }
2205772Sas200622 
2215772Sas200622 /*
2225772Sas200622  * This is the entry point for all server-side RPC processing.
2235772Sas200622  * It is assumed that the PDU has already been received.
2245772Sas200622  */
2255772Sas200622 static int
2265772Sas200622 mlrpc_s_process(struct mlrpc_xaction *mxa)
2275772Sas200622 {
2285772Sas200622 	int rc;
2295772Sas200622 
2305772Sas200622 	rc = mlrpc_decode_pdu_hdr(mxa);
2315772Sas200622 	if (!MLRPC_DRC_IS_OK(rc))
2325772Sas200622 		return (-1);
2335772Sas200622 
2345772Sas200622 	(void) mlrpc_reply_prepare_hdr(mxa);
2355772Sas200622 
2365772Sas200622 	switch (mxa->ptype) {
2375772Sas200622 	case MLRPC_PTYPE_BIND:
2385772Sas200622 		rc = mlrpc_s_bind(mxa);
2395772Sas200622 		break;
2405772Sas200622 
2415772Sas200622 	case MLRPC_PTYPE_REQUEST:
2425772Sas200622 		rc = mlrpc_s_request(mxa);
2435772Sas200622 		break;
2445772Sas200622 
2455772Sas200622 	case MLRPC_PTYPE_ALTER_CONTEXT:
2465772Sas200622 		rc = mlrpc_s_alter_context(mxa);
2475772Sas200622 		break;
2485772Sas200622 
2495772Sas200622 	default:
2505772Sas200622 		rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID;
2515772Sas200622 		break;
2525772Sas200622 	}
2535772Sas200622 
2545772Sas200622 	if (MLRPC_DRC_IS_FAULT(rc))
2555772Sas200622 		mlrpc_reply_fault(mxa, rc);
2565772Sas200622 
2575772Sas200622 	(void) mlrpc_build_reply(mxa);
2585772Sas200622 	return (rc);
2595772Sas200622 }
2605772Sas200622 
2615772Sas200622 /*
2625772Sas200622  * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple
2635772Sas200622  * p_results[] not supported.
2645772Sas200622  */
2655772Sas200622 static int
2665772Sas200622 mlrpc_s_bind(struct mlrpc_xaction *mxa)
2675772Sas200622 {
2685772Sas200622 	mlrpc_p_cont_list_t	*cont_list;
2695772Sas200622 	mlrpc_p_result_list_t	*result_list;
2705772Sas200622 	mlrpc_p_result_t	*result;
2715772Sas200622 	unsigned		p_cont_id;
2725772Sas200622 	struct mlrpc_binding	*mbind;
2735772Sas200622 	ndr_uuid_t		*as_uuid;
2745772Sas200622 	ndr_uuid_t		*ts_uuid;
2755772Sas200622 	char			as_buf[64];
2765772Sas200622 	char			ts_buf[64];
2775772Sas200622 	int			as_vers;
2785772Sas200622 	int			ts_vers;
2795772Sas200622 	struct mlndr_stream	*send_mlnds;
2805772Sas200622 	struct mlrpc_service	*msvc;
2815772Sas200622 	int			rc;
2825772Sas200622 	mlrpc_port_any_t	*sec_addr;
2835772Sas200622 
2845772Sas200622 	/* acquire targets */
2855772Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
2865772Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
2875772Sas200622 	result = &result_list->p_results[0];
2885772Sas200622 
2895772Sas200622 	/*
2905772Sas200622 	 * Set up temporary secondary address port.
2915772Sas200622 	 * We will correct this later (below).
2925772Sas200622 	 */
2935772Sas200622 	send_mlnds = &mxa->send_mlnds;
2945772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
2955772Sas200622 	sec_addr->length = 13;
2965772Sas200622 	(void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs");
2975772Sas200622 
2985772Sas200622 	result_list->n_results = 1;
2995772Sas200622 	result_list->reserved = 0;
3005772Sas200622 	result_list->reserved2 = 0;
3015772Sas200622 	result->result = MLRPC_PCDR_ACCEPTANCE;
3025772Sas200622 	result->reason = 0;
3035772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
3045772Sas200622 
3055772Sas200622 	/* sanity check */
3065772Sas200622 	if (cont_list->n_context_elem != 1 ||
3075772Sas200622 	    cont_list->p_cont_elem[0].n_transfer_syn != 1) {
3085772Sas200622 		mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem");
3095772Sas200622 	}
3105772Sas200622 
3115772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
3125772Sas200622 
3135772Sas200622 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) {
3145772Sas200622 		/*
3155772Sas200622 		 * Duplicate p_cont_id.
3165772Sas200622 		 * Send a bind_ack with a better error.
3175772Sas200622 		 */
3185772Sas200622 		mlndo_trace("mlrpc_s_bind: duplicate binding");
3195772Sas200622 		return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
3205772Sas200622 	}
3215772Sas200622 
3225772Sas200622 	if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
3235772Sas200622 		/*
3245772Sas200622 		 * No free binding slot
3255772Sas200622 		 */
3265772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
3275772Sas200622 		result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
3285772Sas200622 		mlndo_trace("mlrpc_s_bind: no resources");
3295772Sas200622 		return (MLRPC_DRC_OK);
3305772Sas200622 	}
3315772Sas200622 
3325772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
3335772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
3345772Sas200622 
3355772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
3365772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
3375772Sas200622 
3385772Sas200622 	msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
3395772Sas200622 	if (!msvc) {
3405772Sas200622 		mlrpc_uuid_to_str(as_uuid, as_buf);
3415772Sas200622 		mlrpc_uuid_to_str(ts_uuid, ts_buf);
3425772Sas200622 
3435772Sas200622 		mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service");
3445772Sas200622 		mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d",
3455772Sas200622 		    as_buf, as_vers, ts_buf, ts_vers);
3465772Sas200622 
3475772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
3485772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
3495772Sas200622 		return (MLRPC_DRC_OK);
3505772Sas200622 	}
3515772Sas200622 
3525772Sas200622 	/*
3535772Sas200622 	 * We can now use the correct secondary address port.
3545772Sas200622 	 */
3555772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
3565772Sas200622 	sec_addr->length = strlen(msvc->sec_addr_port) + 1;
3575772Sas200622 	(void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port,
3585772Sas200622 	    MLRPC_PORT_ANY_MAX_PORT_SPEC);
3595772Sas200622 
3605772Sas200622 	mbind->p_cont_id = p_cont_id;
3615772Sas200622 	mbind->which_side = MLRPC_BIND_SIDE_SERVER;
3625772Sas200622 	/* mbind->context set by app */
3635772Sas200622 	mbind->service = msvc;
3645772Sas200622 	mbind->instance_specific = 0;
3655772Sas200622 
3665772Sas200622 	mxa->binding = mbind;
3675772Sas200622 
3685772Sas200622 	if (msvc->bind_req) {
3695772Sas200622 		/*
3705772Sas200622 		 * Call the service-specific bind() handler.  If
3715772Sas200622 		 * this fails, we shouild send a specific error
3725772Sas200622 		 * on the bind ack.
3735772Sas200622 		 */
3745772Sas200622 		rc = (msvc->bind_req)(mxa);
3755772Sas200622 		if (MLRPC_DRC_IS_FAULT(rc)) {
3765772Sas200622 			mbind->service = 0;	/* free binding slot */
3775772Sas200622 			mbind->which_side = 0;
3785772Sas200622 			mbind->p_cont_id = 0;
3795772Sas200622 			mbind->instance_specific = 0;
3805772Sas200622 			return (rc);
3815772Sas200622 		}
3825772Sas200622 	}
3835772Sas200622 
3845772Sas200622 	result->transfer_syntax =
3855772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
3865772Sas200622 
3875772Sas200622 	/*
3885772Sas200622 	 * Special rejection of Windows 2000 DSSETUP interface.
3895772Sas200622 	 * This interface was introduced in Windows 2000 but has
3905772Sas200622 	 * been subsequently deprecated due to problems.
3915772Sas200622 	 */
3925772Sas200622 	if (strcmp(msvc->name, "DSSETUP") == 0) {
3935772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
3945772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
3955772Sas200622 	}
3965772Sas200622 
3975772Sas200622 	return (MLRPC_DRC_BINDING_MADE);
3985772Sas200622 }
3995772Sas200622 
4005772Sas200622 /*
4015772Sas200622  * mlrpc_s_alter_context
4025772Sas200622  *
4035772Sas200622  * The alter context request is used to request additional presentation
4045772Sas200622  * context for another interface and/or version. It's very similar to a
4055772Sas200622  * bind request.
4065772Sas200622  *
4075772Sas200622  * We don't fully support multiple contexts so, for now, we reject this
4085772Sas200622  * request.  Windows 2000 clients attempt to use an alternate LSA context
4095772Sas200622  * when ACLs are modified.
4105772Sas200622  */
4115772Sas200622 static int
4125772Sas200622 mlrpc_s_alter_context(struct mlrpc_xaction *mxa)
4135772Sas200622 {
4145772Sas200622 	mlrpc_p_result_list_t *result_list;
4155772Sas200622 	mlrpc_p_result_t *result;
4165772Sas200622 	mlrpc_p_cont_list_t *cont_list;
4175772Sas200622 	struct mlrpc_binding *mbind;
4185772Sas200622 	struct mlrpc_service *msvc;
4195772Sas200622 	unsigned p_cont_id;
4205772Sas200622 	ndr_uuid_t *as_uuid;
4215772Sas200622 	ndr_uuid_t *ts_uuid;
4225772Sas200622 	int as_vers;
4235772Sas200622 	int ts_vers;
4245772Sas200622 	mlrpc_port_any_t *sec_addr;
4255772Sas200622 
4265772Sas200622 	result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list;
4275772Sas200622 	result_list->n_results = 1;
4285772Sas200622 	result_list->reserved = 0;
4295772Sas200622 	result_list->reserved2 = 0;
4305772Sas200622 
4315772Sas200622 	result = &result_list->p_results[0];
4325772Sas200622 	result->result = MLRPC_PCDR_ACCEPTANCE;
4335772Sas200622 	result->reason = 0;
4345772Sas200622 	bzero(&result->transfer_syntax, sizeof (result->transfer_syntax));
4355772Sas200622 
4365772Sas200622 	if (mxa != NULL) {
4375772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
4385772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
4395772Sas200622 		return (MLRPC_DRC_OK);
4405772Sas200622 	}
4415772Sas200622 
4425772Sas200622 	cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem;
4435772Sas200622 	p_cont_id = cont_list->p_cont_elem[0].p_cont_id;
4445772Sas200622 
4455772Sas200622 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL)
4465772Sas200622 		return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY);
4475772Sas200622 
4485772Sas200622 	if ((mbind = mlrpc_new_binding(mxa)) == NULL) {
4495772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
4505772Sas200622 		result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED;
4515772Sas200622 		return (MLRPC_DRC_OK);
4525772Sas200622 	}
4535772Sas200622 
4545772Sas200622 	as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid;
4555772Sas200622 	as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version;
4565772Sas200622 
4575772Sas200622 	ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid;
4585772Sas200622 	ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version;
4595772Sas200622 
4605772Sas200622 	msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers);
4615772Sas200622 	if (msvc == 0) {
4625772Sas200622 		result->result = MLRPC_PCDR_PROVIDER_REJECTION;
4635772Sas200622 		result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED;
4645772Sas200622 		return (MLRPC_DRC_OK);
4655772Sas200622 	}
4665772Sas200622 
4675772Sas200622 	mbind->p_cont_id = p_cont_id;
4685772Sas200622 	mbind->which_side = MLRPC_BIND_SIDE_SERVER;
4695772Sas200622 	/* mbind->context set by app */
4705772Sas200622 	mbind->service = msvc;
4715772Sas200622 	mbind->instance_specific = 0;
4725772Sas200622 	mxa->binding = mbind;
4735772Sas200622 
4745772Sas200622 	sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr;
4755772Sas200622 	sec_addr->length = 0;
4765772Sas200622 	bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC);
4775772Sas200622 
4785772Sas200622 	result->transfer_syntax =
4795772Sas200622 	    cont_list->p_cont_elem[0].transfer_syntaxes[0];
4805772Sas200622 
4815772Sas200622 	return (MLRPC_DRC_BINDING_MADE);
4825772Sas200622 }
4835772Sas200622 
4845772Sas200622 static int
4855772Sas200622 mlrpc_s_request(struct mlrpc_xaction *mxa)
4865772Sas200622 {
4875772Sas200622 	struct mlrpc_binding	*mbind;
4885772Sas200622 	struct mlrpc_service	*msvc;
4895772Sas200622 	unsigned		p_cont_id;
4905772Sas200622 	int			rc;
4915772Sas200622 
4925772Sas200622 	mxa->opnum = mxa->recv_hdr.request_hdr.opnum;
4935772Sas200622 	p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id;
4945772Sas200622 
4955772Sas200622 	if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL)
4965772Sas200622 		return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID);
4975772Sas200622 
4985772Sas200622 	mxa->binding = mbind;
4995772Sas200622 	msvc = mbind->service;
5005772Sas200622 
5015772Sas200622 	/*
5025772Sas200622 	 * Make room for the response hdr.
5035772Sas200622 	 */
5045772Sas200622 	mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE;
5055772Sas200622 
5065772Sas200622 	if (msvc->call_stub)
5075772Sas200622 		rc = (*msvc->call_stub)(mxa);
5085772Sas200622 	else
5095772Sas200622 		rc = mlrpc_generic_call_stub(mxa);
5105772Sas200622 
5115772Sas200622 	if (MLRPC_DRC_IS_FAULT(rc)) {
5125772Sas200622 		mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x",
5135772Sas200622 		    msvc->name, mxa->opnum, rc);
5145772Sas200622 	}
5155772Sas200622 
5165772Sas200622 	return (rc);
5175772Sas200622 }
5185772Sas200622 
5195772Sas200622 /*
5205772Sas200622  * The transaction and the two mlnds streams use the same heap, which
5215772Sas200622  * should already exist at this point.  The heap will also be available
5225772Sas200622  * to the stub.
5235772Sas200622  */
5245772Sas200622 int
5255772Sas200622 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa)
5265772Sas200622 {
5275772Sas200622 	struct mlrpc_binding 	*mbind = mxa->binding;
5285772Sas200622 	struct mlrpc_service 	*msvc = mbind->service;
5295772Sas200622 	struct ndr_typeinfo 	*intf_ti = msvc->interface_ti;
5305772Sas200622 	struct mlrpc_stub_table *ste;
5315772Sas200622 	int			opnum = mxa->opnum;
5325772Sas200622 	unsigned		p_len = intf_ti->c_size_fixed_part;
5335772Sas200622 	char 			*param;
5345772Sas200622 	int			rc;
5355772Sas200622 
5365772Sas200622 	if (mxa->heap == NULL) {
5375772Sas200622 		mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum);
5385772Sas200622 		return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
5395772Sas200622 	}
5405772Sas200622 
5415772Sas200622 	if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) {
5425772Sas200622 		mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum",
5435772Sas200622 		    msvc->name, opnum);
5445772Sas200622 		return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID);
5455772Sas200622 	}
5465772Sas200622 
5475772Sas200622 	if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL)
5485772Sas200622 		return (MLRPC_DRC_FAULT_OUT_OF_MEMORY);
5495772Sas200622 
5505772Sas200622 	bzero(param, p_len);
5515772Sas200622 
5525772Sas200622 	rc = mlrpc_decode_call(mxa, param);
5535772Sas200622 	if (!MLRPC_DRC_IS_OK(rc))
5545772Sas200622 		return (rc);
5555772Sas200622 
5565772Sas200622 	rc = (*ste->func)(param, mxa);
5575772Sas200622 	if (rc == MLRPC_DRC_OK)
5585772Sas200622 		rc = mlrpc_encode_return(mxa, param);
5595772Sas200622 
5605772Sas200622 	return (rc);
5615772Sas200622 }
5625772Sas200622 
5635772Sas200622 /*
5645772Sas200622  * We can perform some initial setup of the response header here.
5655772Sas200622  * We also need to cache some of the information from the bind
5665772Sas200622  * negotiation for use during subsequent RPC calls.
5675772Sas200622  */
5685772Sas200622 static void
5695772Sas200622 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa)
5705772Sas200622 {
5715772Sas200622 	mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
5725772Sas200622 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
5735772Sas200622 
5745772Sas200622 	hdr->rpc_vers = 5;
5755772Sas200622 	hdr->rpc_vers_minor = 0;
5765772Sas200622 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
5775772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
5785772Sas200622 	hdr->frag_length = 0;
5795772Sas200622 	hdr->auth_length = 0;
5805772Sas200622 	hdr->call_id = rhdr->call_id;
5815772Sas200622 #ifdef _BIG_ENDIAN
5825772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
5835772Sas200622 	    | MLRPC_REPLAB_INTG_BIG_ENDIAN;
5845772Sas200622 #else
5855772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
5865772Sas200622 	    | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
5875772Sas200622 #endif
5885772Sas200622 
5895772Sas200622 	switch (mxa->ptype) {
5905772Sas200622 	case MLRPC_PTYPE_BIND:
5915772Sas200622 		hdr->ptype = MLRPC_PTYPE_BIND_ACK;
5925772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_xmit_frag =
5935772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
5945772Sas200622 		mxa->send_hdr.bind_ack_hdr.max_recv_frag =
5955772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
5965772Sas200622 		mxa->send_hdr.bind_ack_hdr.assoc_group_id =
5975772Sas200622 		    mxa->recv_hdr.bind_hdr.assoc_group_id;
5985772Sas200622 
5995772Sas200622 		if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0)
6005772Sas200622 			mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0);
6015772Sas200622 
6025772Sas200622 		/*
6035772Sas200622 		 * Save the maximum fragment sizes
6045772Sas200622 		 * for use with subsequent requests.
6055772Sas200622 		 */
6065772Sas200622 		mxa->context->max_xmit_frag =
6075772Sas200622 		    mxa->recv_hdr.bind_hdr.max_xmit_frag;
6085772Sas200622 
6095772Sas200622 		mxa->context->max_recv_frag =
6105772Sas200622 		    mxa->recv_hdr.bind_hdr.max_recv_frag;
6115772Sas200622 
6125772Sas200622 		break;
6135772Sas200622 
6145772Sas200622 	case MLRPC_PTYPE_REQUEST:
6155772Sas200622 		hdr->ptype = MLRPC_PTYPE_RESPONSE;
6165772Sas200622 		/* mxa->send_hdr.response_hdr.alloc_hint */
6175772Sas200622 		mxa->send_hdr.response_hdr.p_cont_id =
6185772Sas200622 		    mxa->recv_hdr.request_hdr.p_cont_id;
6195772Sas200622 		mxa->send_hdr.response_hdr.cancel_count = 0;
6205772Sas200622 		mxa->send_hdr.response_hdr.reserved = 0;
6215772Sas200622 		break;
6225772Sas200622 
6235772Sas200622 	case MLRPC_PTYPE_ALTER_CONTEXT:
6245772Sas200622 		hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP;
6255772Sas200622 		/*
6265772Sas200622 		 * The max_xmit_frag, max_recv_frag
6275772Sas200622 		 * and assoc_group_id are ignored.
6285772Sas200622 		 */
6295772Sas200622 		break;
6305772Sas200622 
6315772Sas200622 	default:
6325772Sas200622 		hdr->ptype = 0xFF;
6335772Sas200622 	}
6345772Sas200622 }
6355772Sas200622 
6365772Sas200622 /*
6375772Sas200622  * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header.
6385772Sas200622  * The frag_length is different from a regular RPC response.
6395772Sas200622  */
6405772Sas200622 static void
6415772Sas200622 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa)
6425772Sas200622 {
6435772Sas200622 	mlrpcconn_common_header_t	*hdr;
6445772Sas200622 	mlrpcconn_bind_ack_hdr_t	*bahdr;
6455772Sas200622 
6465772Sas200622 	hdr = &mxa->send_hdr.common_hdr;
6475772Sas200622 	bahdr = &mxa->send_hdr.bind_ack_hdr;
6485772Sas200622 	hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr);
6495772Sas200622 }
6505772Sas200622 
6515772Sas200622 /*
6525772Sas200622  * Signal an RPC fault. The stream is reset and we overwrite whatever
6535772Sas200622  * was in the response header with the fault information.
6545772Sas200622  */
6555772Sas200622 static void
6565772Sas200622 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc)
6575772Sas200622 {
6585772Sas200622 	mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr;
6595772Sas200622 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
6605772Sas200622 	struct mlndr_stream *mlnds = &mxa->send_mlnds;
6615772Sas200622 	unsigned long fault_status;
6625772Sas200622 
6635772Sas200622 	MLNDS_RESET(mlnds);
6645772Sas200622 
6655772Sas200622 	hdr->rpc_vers = 5;
6665772Sas200622 	hdr->rpc_vers_minor = 0;
6675772Sas200622 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG;
6685772Sas200622 	hdr->packed_drep = rhdr->packed_drep;
6695772Sas200622 	hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr);
6705772Sas200622 	hdr->auth_length = 0;
6715772Sas200622 	hdr->call_id = rhdr->call_id;
6725772Sas200622 #ifdef _BIG_ENDIAN
6735772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
6745772Sas200622 	    | MLRPC_REPLAB_INTG_BIG_ENDIAN;
6755772Sas200622 #else
6765772Sas200622 	hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII
6775772Sas200622 	    | MLRPC_REPLAB_INTG_LITTLE_ENDIAN;
6785772Sas200622 #endif
6795772Sas200622 
6805772Sas200622 	switch (drc & MLRPC_DRC_MASK_SPECIFIER) {
6815772Sas200622 	case MLRPC_DRC_FAULT_OUT_OF_MEMORY:
6825772Sas200622 	case MLRPC_DRC_FAULT_ENCODE_TOO_BIG:
6835772Sas200622 		fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG;
6845772Sas200622 		break;
6855772Sas200622 
6865772Sas200622 	case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID:
6875772Sas200622 		fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID;
6885772Sas200622 		break;
6895772Sas200622 
6905772Sas200622 	case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID:
6915772Sas200622 		fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR;
6925772Sas200622 		break;
6935772Sas200622 
6945772Sas200622 	case MLRPC_DRC_FAULT_DECODE_FAILED:
6955772Sas200622 	case MLRPC_DRC_FAULT_ENCODE_FAILED:
6965772Sas200622 		fault_status = MLRPC_FAULT_NCA_PROTO_ERROR;
6975772Sas200622 		break;
6985772Sas200622 
6995772Sas200622 	default:
7005772Sas200622 		fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT;
7015772Sas200622 		break;
7025772Sas200622 	}
7035772Sas200622 
7045772Sas200622 	mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT;
7055772Sas200622 	mxa->send_hdr.fault_hdr.status = fault_status;
7065772Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length;
7075772Sas200622 }
7085772Sas200622 
7095772Sas200622 static int
7105772Sas200622 mlrpc_build_reply(struct mlrpc_xaction *mxa)
7115772Sas200622 {
7125772Sas200622 	mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr;
7135772Sas200622 	struct mlndr_stream *mlnds = &mxa->send_mlnds;
7145772Sas200622 	unsigned long pdu_size;
7155772Sas200622 	unsigned long frag_size;
7165772Sas200622 	unsigned long pdu_data_size;
7175772Sas200622 	unsigned long frag_data_size;
7185772Sas200622 	uint32_t rem_dlen;
7195772Sas200622 	uint32_t save_rem_dlen;
7205772Sas200622 	uint32_t bytesoff;
7215772Sas200622 	uint32_t cnt;
7225772Sas200622 	uint32_t obytes;
7235772Sas200622 	uint32_t num_ext_frags;
7245772Sas200622 	uint16_t last_frag = 0;
7255772Sas200622 	uchar_t  *frag_startp;
7265772Sas200622 	mlrpcconn_common_header_t *rpc_hdr;
7275772Sas200622 
7285772Sas200622 	hdr = &mxa->send_hdr.common_hdr;
7295772Sas200622 
7305772Sas200622 	frag_size = mlrpc_frag_size;
7315772Sas200622 	pdu_size = mlnds->pdu_size;
7325772Sas200622 
7335772Sas200622 	if (pdu_size <= frag_size) {
7345772Sas200622 		/*
7355772Sas200622 		 * Single fragment response. The PDU size may be zero
7365772Sas200622 		 * here (i.e. bind or fault response). So don't make
7375772Sas200622 		 * any assumptions about it until after the header is
7385772Sas200622 		 * encoded.
7395772Sas200622 		 */
7405772Sas200622 		switch (hdr->ptype) {
7415772Sas200622 		case MLRPC_PTYPE_BIND_ACK:
7425772Sas200622 			mlrpc_reply_bind_ack(mxa);
7435772Sas200622 			break;
7445772Sas200622 
7455772Sas200622 		case MLRPC_PTYPE_FAULT:
7465772Sas200622 			/* already setup */
7475772Sas200622 			break;
7485772Sas200622 
7495772Sas200622 		case MLRPC_PTYPE_RESPONSE:
7505772Sas200622 			hdr->frag_length = pdu_size;
7515772Sas200622 			mxa->send_hdr.response_hdr.alloc_hint =
7525772Sas200622 			    hdr->frag_length;
7535772Sas200622 			break;
7545772Sas200622 
7555772Sas200622 		default:
7565772Sas200622 			hdr->frag_length = pdu_size;
7575772Sas200622 			break;
7585772Sas200622 		}
7595772Sas200622 
7605772Sas200622 		mlnds->pdu_scan_offset = 0;
7615772Sas200622 		(void) mlrpc_encode_pdu_hdr(mxa);
7625772Sas200622 
7635772Sas200622 		mlnds->pdu_size_with_rpc_hdrs = mlnds->pdu_size;
7645772Sas200622 		mlnds->pdu_base_addr_with_rpc_hdrs = 0;
7655772Sas200622 		return (0);
7665772Sas200622 	}
7675772Sas200622 
7685772Sas200622 	/*
7695772Sas200622 	 * Multiple fragment response.
7705772Sas200622 	 */
7715772Sas200622 	hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG;
7725772Sas200622 	hdr->frag_length = frag_size;
7735772Sas200622 	mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE;
7745772Sas200622 	mlnds->pdu_scan_offset = 0;
7755772Sas200622 
7765772Sas200622 	(void) mlrpc_encode_pdu_hdr(mxa);
7775772Sas200622 
7785772Sas200622 	/*
7795772Sas200622 	 * We need to update the 24-byte header in subsequent fragments.
7805772Sas200622 	 *
7815772Sas200622 	 *	pdu_data_size:	total data remaining to be handled
7825772Sas200622 	 *	frag_size:		total fragment size including header
7835772Sas200622 	 *	frag_data_size: data in fragment
7845772Sas200622 	 *			(i.e. frag_size - MLRPC_RSP_HDR_SIZE)
7855772Sas200622 	 */
7865772Sas200622 	pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE;
7875772Sas200622 	frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE;
7885772Sas200622 
7895772Sas200622 	num_ext_frags = pdu_data_size / frag_data_size;
7905772Sas200622 
7915772Sas200622 	/*
7925772Sas200622 	 * We may need to stretch the pipe and insert an RPC header
7935772Sas200622 	 * at each frag boundary.  The response will get chunked into
7945772Sas200622 	 * xdrlen sizes for each trans request.
7955772Sas200622 	 */
7965772Sas200622 	mlnds->pdu_base_addr_with_rpc_hdrs
7975772Sas200622 	    = malloc(pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE));
7985772Sas200622 	mlnds->pdu_size_with_rpc_hdrs =
7995772Sas200622 	    mlnds->pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE);
8005772Sas200622 
8015772Sas200622 	/*
8025772Sas200622 	 * Start stretching loop.
8035772Sas200622 	 */
8045772Sas200622 	bcopy(mlnds->pdu_base_addr,
8055772Sas200622 	    mlnds->pdu_base_addr_with_rpc_hdrs, frag_size);
8065772Sas200622 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
8075772Sas200622 	rpc_hdr = (mlrpcconn_common_header_t *)
8085772Sas200622 	    mlnds->pdu_base_addr_with_rpc_hdrs;
8095772Sas200622 	rpc_hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG;
8105772Sas200622 	rem_dlen = pdu_data_size - frag_size;
8115772Sas200622 	bytesoff = frag_size;
8125772Sas200622 	cnt = 1;
8135772Sas200622 	while (num_ext_frags--) {
8145772Sas200622 		/* first copy the RPC header to the front of the frag */
8155772Sas200622 		bcopy(mlnds->pdu_base_addr, mlnds->pdu_base_addr_with_rpc_hdrs +
8165772Sas200622 		    (cnt * frag_size), MLRPC_RSP_HDR_SIZE);
8175772Sas200622 
8185772Sas200622 		/* then copy the data portion of the frag */
8195772Sas200622 		save_rem_dlen = rem_dlen;
8205772Sas200622 		if (rem_dlen >= (frag_size - MLRPC_RSP_HDR_SIZE)) {
8215772Sas200622 			rem_dlen = rem_dlen - frag_size + MLRPC_RSP_HDR_SIZE;
8225772Sas200622 			obytes = frag_size - MLRPC_RSP_HDR_SIZE;
8235772Sas200622 		} else {
8245772Sas200622 			last_frag = 1;   /* this is the last one */
8255772Sas200622 			obytes = rem_dlen;
8265772Sas200622 		}
8275772Sas200622 
8285772Sas200622 		frag_startp = mlnds->pdu_base_addr_with_rpc_hdrs +
8295772Sas200622 		    (cnt * frag_size);
8305772Sas200622 		bcopy(mlnds->pdu_base_addr + bytesoff,
8315772Sas200622 		    frag_startp + MLRPC_RSP_HDR_SIZE, obytes);
8325772Sas200622 
8335772Sas200622 		/* set the FRAG FLAGS in the frag header spot */
8345772Sas200622 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
8355772Sas200622 		rpc_hdr = (mlrpcconn_common_header_t *)frag_startp;
8365772Sas200622 		if (last_frag) {
8375772Sas200622 			rpc_hdr->frag_length = save_rem_dlen;
8385772Sas200622 			rpc_hdr->pfc_flags = MLRPC_PFC_LAST_FRAG;
8395772Sas200622 		} else {
8405772Sas200622 			rpc_hdr->pfc_flags = 0;
8415772Sas200622 		}
8425772Sas200622 
8435772Sas200622 		bytesoff += (frag_size - MLRPC_RSP_HDR_SIZE);
8445772Sas200622 		cnt++;
8455772Sas200622 	}
8465772Sas200622 
8475772Sas200622 	return (0);
8485772Sas200622 }
849