xref: /onnv-gate/usr/src/lib/smbsrv/libmlrpc/common/ndr_client.c (revision 10475:1f599611bc1f)
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 /*
229914Samw@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235772Sas200622  * Use is subject to license terms.
245772Sas200622  */
255772Sas200622 
265772Sas200622 #include <sys/errno.h>
275772Sas200622 #include <string.h>
285772Sas200622 #include <strings.h>
295772Sas200622 
305772Sas200622 #include <smbsrv/libsmb.h>
318334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h>
325772Sas200622 
338334SJose.Borrego@Sun.COM #define	NDR_DEFAULT_FRAGSZ	8192
34*10475Samw@Sun.COM #define	NDR_MULTI_FRAGSZ	(60 * 1024)
355772Sas200622 
368334SJose.Borrego@Sun.COM static void ndr_clnt_init_hdr(ndr_client_t *, ndr_xa_t *);
37*10475Samw@Sun.COM static void ndr_clnt_remove_hdr(ndr_stream_t *);
388334SJose.Borrego@Sun.COM static int ndr_clnt_get_frags(ndr_client_t *, ndr_xa_t *);
39*10475Samw@Sun.COM static int ndr_clnt_get_frag(ndr_client_t *, ndr_xa_t *, ndr_common_header_t *);
405772Sas200622 
415772Sas200622 int
428334SJose.Borrego@Sun.COM ndr_clnt_bind(ndr_client_t *clnt, const char *service_name,
438334SJose.Borrego@Sun.COM     ndr_binding_t **ret_binding_p)
445772Sas200622 {
458334SJose.Borrego@Sun.COM 	ndr_service_t		*msvc;
468334SJose.Borrego@Sun.COM 	ndr_binding_t		*mbind;
478334SJose.Borrego@Sun.COM 	ndr_xa_t		mxa;
487619SJose.Borrego@Sun.COM 	ndr_bind_hdr_t		*bhdr;
498334SJose.Borrego@Sun.COM 	ndr_p_cont_elem_t 	*pce;
507619SJose.Borrego@Sun.COM 	ndr_bind_ack_hdr_t	*bahdr;
518334SJose.Borrego@Sun.COM 	ndr_p_result_t		*pre;
525772Sas200622 	int			rc;
535772Sas200622 
545772Sas200622 	bzero(&mxa, sizeof (mxa));
555772Sas200622 
568334SJose.Borrego@Sun.COM 	msvc = ndr_svc_lookup_name(service_name);
575772Sas200622 	if (msvc == NULL)
588334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_API_SERVICE_INVALID);
595772Sas200622 
608334SJose.Borrego@Sun.COM 	mxa.binding_list = clnt->binding_list;
618334SJose.Borrego@Sun.COM 	if ((mbind = ndr_svc_new_binding(&mxa)) == NULL)
628334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_API_BIND_NO_SLOTS);
635772Sas200622 
648334SJose.Borrego@Sun.COM 	ndr_clnt_init_hdr(clnt, &mxa);
655772Sas200622 
665772Sas200622 	bhdr = &mxa.send_hdr.bind_hdr;
678334SJose.Borrego@Sun.COM 	bhdr->common_hdr.ptype = NDR_PTYPE_BIND;
685772Sas200622 	bhdr->common_hdr.frag_length = sizeof (*bhdr);
698334SJose.Borrego@Sun.COM 	bhdr->max_xmit_frag = NDR_DEFAULT_FRAGSZ;
708334SJose.Borrego@Sun.COM 	bhdr->max_recv_frag = NDR_DEFAULT_FRAGSZ;
715772Sas200622 	bhdr->assoc_group_id = 0;
725772Sas200622 	bhdr->p_context_elem.n_context_elem = 1;
735772Sas200622 
745772Sas200622 	/* Assign presentation context id */
755772Sas200622 	pce = &bhdr->p_context_elem.p_cont_elem[0];
768334SJose.Borrego@Sun.COM 	pce->p_cont_id = clnt->next_p_cont_id++;
775772Sas200622 	pce->n_transfer_syn = 1;
785772Sas200622 
795772Sas200622 	/* Set up UUIDs and versions from the service */
805772Sas200622 	pce->abstract_syntax.if_version = msvc->abstract_syntax_version;
818334SJose.Borrego@Sun.COM 	rc = ndr_uuid_parse(msvc->abstract_syntax_uuid,
825772Sas200622 	    &pce->abstract_syntax.if_uuid);
838334SJose.Borrego@Sun.COM 	if (rc != 0)
848334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_API_SERVICE_INVALID);
855772Sas200622 
865772Sas200622 	pce->transfer_syntaxes[0].if_version = msvc->transfer_syntax_version;
878334SJose.Borrego@Sun.COM 	rc = ndr_uuid_parse(msvc->transfer_syntax_uuid,
885772Sas200622 	    &pce->transfer_syntaxes[0].if_uuid);
898334SJose.Borrego@Sun.COM 	if (rc != 0)
908334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_API_SERVICE_INVALID);
915772Sas200622 
925772Sas200622 	/* Format and exchange the PDU */
935772Sas200622 
948334SJose.Borrego@Sun.COM 	if ((*clnt->xa_init)(clnt, &mxa) < 0)
958334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_OUT_OF_MEMORY);
965772Sas200622 
978334SJose.Borrego@Sun.COM 	rc = ndr_encode_pdu_hdr(&mxa);
988334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
995772Sas200622 		goto fault_exit;
1005772Sas200622 
1018334SJose.Borrego@Sun.COM 	if ((*clnt->xa_exchange)(clnt, &mxa) < 0) {
1028334SJose.Borrego@Sun.COM 		rc = NDR_DRC_FAULT_SEND_FAILED;
1035772Sas200622 		goto fault_exit;
1048334SJose.Borrego@Sun.COM 	}
1055772Sas200622 
1068334SJose.Borrego@Sun.COM 	rc = ndr_decode_pdu_hdr(&mxa);
1078334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
1085772Sas200622 		goto fault_exit;
1095772Sas200622 
1105772Sas200622 	/* done with buffers */
1118334SJose.Borrego@Sun.COM 	(*clnt->xa_destruct)(clnt, &mxa);
1125772Sas200622 
1135772Sas200622 	bahdr = &mxa.recv_hdr.bind_ack_hdr;
1145772Sas200622 
1158334SJose.Borrego@Sun.COM 	if (mxa.ptype != NDR_PTYPE_BIND_ACK)
1168334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
1175772Sas200622 
1185772Sas200622 	if (bahdr->p_result_list.n_results != 1)
1198334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
1205772Sas200622 
1215772Sas200622 	pre = &bahdr->p_result_list.p_results[0];
1225772Sas200622 
1238334SJose.Borrego@Sun.COM 	if (pre->result != NDR_PCDR_ACCEPTANCE)
1248334SJose.Borrego@Sun.COM 		return (NDR_DRC_FAULT_RECEIVED_MALFORMED);
1255772Sas200622 
1265772Sas200622 	mbind->p_cont_id = pce->p_cont_id;
1278334SJose.Borrego@Sun.COM 	mbind->which_side = NDR_BIND_SIDE_CLIENT;
1288334SJose.Borrego@Sun.COM 	mbind->clnt = clnt;
1295772Sas200622 	mbind->service = msvc;
1305772Sas200622 	mbind->instance_specific = 0;
1315772Sas200622 
1325772Sas200622 	*ret_binding_p = mbind;
1338334SJose.Borrego@Sun.COM 	return (NDR_DRC_OK);
1345772Sas200622 
1355772Sas200622 fault_exit:
1368334SJose.Borrego@Sun.COM 	(*clnt->xa_destruct)(clnt, &mxa);
1375772Sas200622 	return (rc);
1385772Sas200622 }
1395772Sas200622 
1405772Sas200622 int
1418334SJose.Borrego@Sun.COM ndr_clnt_call(ndr_binding_t *mbind, int opnum, void *params)
1425772Sas200622 {
1438334SJose.Borrego@Sun.COM 	ndr_client_t		*clnt = mbind->clnt;
1448334SJose.Borrego@Sun.COM 	ndr_service_t		*msvc = mbind->service;
1458334SJose.Borrego@Sun.COM 	ndr_xa_t		mxa;
1467619SJose.Borrego@Sun.COM 	ndr_request_hdr_t	*reqhdr;
1477619SJose.Borrego@Sun.COM 	ndr_common_header_t	*rsphdr;
1488334SJose.Borrego@Sun.COM 	unsigned long		recv_pdu_scan_offset;
1495772Sas200622 	int			rc;
1505772Sas200622 
1519914Samw@Sun.COM 	if (ndr_svc_lookup_name(msvc->name) == NULL)
1529914Samw@Sun.COM 		return (NDR_DRC_FAULT_API_SERVICE_INVALID);
1535772Sas200622 
1545772Sas200622 	bzero(&mxa, sizeof (mxa));
1558334SJose.Borrego@Sun.COM 	mxa.ptype = NDR_PTYPE_REQUEST;
1565772Sas200622 	mxa.opnum = opnum;
1575772Sas200622 	mxa.binding = mbind;
1585772Sas200622 
1598334SJose.Borrego@Sun.COM 	ndr_clnt_init_hdr(clnt, &mxa);
1605772Sas200622 
1615772Sas200622 	reqhdr = &mxa.send_hdr.request_hdr;
1628334SJose.Borrego@Sun.COM 	reqhdr->common_hdr.ptype = NDR_PTYPE_REQUEST;
1635772Sas200622 	reqhdr->p_cont_id = mbind->p_cont_id;
1645772Sas200622 	reqhdr->opnum = opnum;
1655772Sas200622 
1668334SJose.Borrego@Sun.COM 	rc = (*clnt->xa_init)(clnt, &mxa);
1678334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
1685772Sas200622 		return (rc);
1695772Sas200622 
1705772Sas200622 	/* Reserve room for hdr */
1718334SJose.Borrego@Sun.COM 	mxa.send_nds.pdu_scan_offset = sizeof (*reqhdr);
1725772Sas200622 
1738334SJose.Borrego@Sun.COM 	rc = ndr_encode_call(&mxa, params);
1748334SJose.Borrego@Sun.COM 	if (!NDR_DRC_IS_OK(rc))
1755772Sas200622 		goto fault_exit;
1765772Sas200622 
1778334SJose.Borrego@Sun.COM 	mxa.send_nds.pdu_scan_offset = 0;
1785772Sas200622 
1795772Sas200622 	/*
1805772Sas200622 	 * Now we have the PDU size, we need to set up the
1815772Sas200622 	 * frag_length and calculate the alloc_hint.
1825772Sas200622 	 */
1838334SJose.Borrego@Sun.COM 	mxa.send_hdr.common_hdr.frag_length = mxa.send_nds.pdu_size;
1848334SJose.Borrego@Sun.COM 	reqhdr->alloc_hint = mxa.send_nds.pdu_size -
1857619SJose.Borrego@Sun.COM 	    sizeof (ndr_request_hdr_t);
1865772Sas200622 
1878334SJose.Borrego@Sun.COM 	rc = ndr_encode_pdu_hdr(&mxa);
1888334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
1895772Sas200622 		goto fault_exit;
1905772Sas200622 
1918334SJose.Borrego@Sun.COM 	rc = (*clnt->xa_exchange)(clnt, &mxa);
1928334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
1935772Sas200622 		goto fault_exit;
1945772Sas200622 
1958334SJose.Borrego@Sun.COM 	rc = ndr_decode_pdu_hdr(&mxa);
1968334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
1975772Sas200622 		goto fault_exit;
1985772Sas200622 
1998334SJose.Borrego@Sun.COM 	if (mxa.ptype != NDR_PTYPE_RESPONSE) {
2008334SJose.Borrego@Sun.COM 		rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
2015772Sas200622 		goto fault_exit;
2025772Sas200622 	}
2035772Sas200622 
2045772Sas200622 	rsphdr = &mxa.recv_hdr.common_hdr;
2055772Sas200622 
2068334SJose.Borrego@Sun.COM 	if (!NDR_IS_LAST_FRAG(rsphdr->pfc_flags)) {
2075772Sas200622 		/*
2085772Sas200622 		 * This is a multi-fragment response.
2095772Sas200622 		 * Preserve the current scan offset while getting
2105772Sas200622 		 * fragments so that we can continue afterward
2115772Sas200622 		 * as if we had received the entire response as
2125772Sas200622 		 * a single PDU.
2135772Sas200622 		 */
214*10475Samw@Sun.COM 		(void) NDS_GROW_PDU(&mxa.recv_nds, NDR_MULTI_FRAGSZ, NULL);
215*10475Samw@Sun.COM 
2168334SJose.Borrego@Sun.COM 		recv_pdu_scan_offset = mxa.recv_nds.pdu_scan_offset;
217*10475Samw@Sun.COM 		mxa.recv_nds.pdu_scan_offset = rsphdr->frag_length;
218*10475Samw@Sun.COM 		mxa.recv_nds.pdu_size = rsphdr->frag_length;
2195772Sas200622 
2208334SJose.Borrego@Sun.COM 		if (ndr_clnt_get_frags(clnt, &mxa) < 0) {
2218334SJose.Borrego@Sun.COM 			rc = NDR_DRC_FAULT_RECEIVED_MALFORMED;
2225772Sas200622 			goto fault_exit;
2235772Sas200622 		}
2245772Sas200622 
2258334SJose.Borrego@Sun.COM 		mxa.recv_nds.pdu_scan_offset = recv_pdu_scan_offset;
2265772Sas200622 	}
2275772Sas200622 
2288334SJose.Borrego@Sun.COM 	rc = ndr_decode_return(&mxa, params);
2298334SJose.Borrego@Sun.COM 	if (NDR_DRC_IS_FAULT(rc))
2305772Sas200622 		goto fault_exit;
2315772Sas200622 
2328334SJose.Borrego@Sun.COM 	(*clnt->xa_preserve)(clnt, &mxa);
2338334SJose.Borrego@Sun.COM 	(*clnt->xa_destruct)(clnt, &mxa);
2348334SJose.Borrego@Sun.COM 	return (NDR_DRC_OK);
2355772Sas200622 
2365772Sas200622 fault_exit:
2378334SJose.Borrego@Sun.COM 	(*clnt->xa_destruct)(clnt, &mxa);
2385772Sas200622 	return (rc);
2395772Sas200622 }
2405772Sas200622 
2415772Sas200622 void
2428334SJose.Borrego@Sun.COM ndr_clnt_free_heap(ndr_client_t *clnt)
2435772Sas200622 {
2448334SJose.Borrego@Sun.COM 	(*clnt->xa_release)(clnt);
2455772Sas200622 }
2465772Sas200622 
2475772Sas200622 static void
2488334SJose.Borrego@Sun.COM ndr_clnt_init_hdr(ndr_client_t *clnt, ndr_xa_t *mxa)
2495772Sas200622 {
2507619SJose.Borrego@Sun.COM 	ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
2515772Sas200622 
2525772Sas200622 	hdr->rpc_vers = 5;
2535772Sas200622 	hdr->rpc_vers_minor = 0;
2548334SJose.Borrego@Sun.COM 	hdr->pfc_flags = NDR_PFC_FIRST_FRAG + NDR_PFC_LAST_FRAG;
2558334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep = NDR_REPLAB_CHAR_ASCII;
2565772Sas200622 #ifndef _BIG_ENDIAN
2578334SJose.Borrego@Sun.COM 	hdr->packed_drep.intg_char_rep |= NDR_REPLAB_INTG_LITTLE_ENDIAN;
2585772Sas200622 #endif
2595772Sas200622 	/* hdr->frag_length */
2605772Sas200622 	hdr->auth_length = 0;
2618334SJose.Borrego@Sun.COM 	hdr->call_id = clnt->next_call_id++;
2625772Sas200622 }
2635772Sas200622 
2645772Sas200622 /*
2658334SJose.Borrego@Sun.COM  * ndr_clnt_remove_hdr
2665772Sas200622  *
2675772Sas200622  * Remove an RPC fragment header from the received data stream.
2685772Sas200622  *
2695772Sas200622  * Original RPC receive buffer:
2705772Sas200622  * |-      frag1                   -|    |-frag M(partial)-|
2715772Sas200622  * +==================+=============+----+=================+
2725772Sas200622  * | SmbTransact Rsp1 | SmbTransact |    | SmbReadX RspN   |
2735772Sas200622  * | (with RPC hdr)   | Rsp2        | .. | (with RPC hdr)  |
2745772Sas200622  * +-----+------------+-------------+    +-----+-----------+
2755772Sas200622  * | hdr | data       | data        | .. | hdr | data      |
2765772Sas200622  * +=====+============+=============+----+=====+===========+
2775772Sas200622  *                                       <------
2785772Sas200622  * ^                                     ^     ^
2795772Sas200622  * |                                     |     |
2805772Sas200622  * base_offset                          hdr   data
2815772Sas200622  *
2825772Sas200622  * |-------------------------------------|-----------------|
283*10475Samw@Sun.COM  *            scan_offset                         len
2845772Sas200622  *
2855772Sas200622  * RPC receive buffer (after this call):
2865772Sas200622  * +==================+=============+----+===========+
2875772Sas200622  * | SmbTransact Rsp1 | SmbTransact |    | SmbReadX  |
2885772Sas200622  * | (with RPC hdr)   | Rsp2        | .. | RspN      |
2895772Sas200622  * +-----+------------+-------------+    +-----------+
2905772Sas200622  * | hdr | data       | data        | .. | data      |
2915772Sas200622  * +=====+============+=============+----+===========+
2925772Sas200622  */
2935772Sas200622 static void
294*10475Samw@Sun.COM ndr_clnt_remove_hdr(ndr_stream_t *nds)
2955772Sas200622 {
2965772Sas200622 	char *hdr;
2975772Sas200622 	char *data;
298*10475Samw@Sun.COM 	int nbytes;
2995772Sas200622 
3008334SJose.Borrego@Sun.COM 	hdr = (char *)nds->pdu_base_offset + nds->pdu_scan_offset;
3018334SJose.Borrego@Sun.COM 	data = hdr + NDR_RSP_HDR_SIZE;
302*10475Samw@Sun.COM 	nbytes = nds->pdu_size - nds->pdu_scan_offset - NDR_RSP_HDR_SIZE;
3035772Sas200622 
304*10475Samw@Sun.COM 	bcopy(data, hdr, nbytes);
3058334SJose.Borrego@Sun.COM 	nds->pdu_size -= NDR_RSP_HDR_SIZE;
3065772Sas200622 }
3075772Sas200622 
3085772Sas200622 /*
3098334SJose.Borrego@Sun.COM  * ndr_clnt_get_frags
3105772Sas200622  *
3115772Sas200622  * A DCE RPC message that is larger than a single fragment is transmitted
3125772Sas200622  * as a series of fragments: 5280 bytes for Windows NT and 4280 bytes for
3135772Sas200622  * both Windows 2000 and 2003.
3145772Sas200622  *
3155772Sas200622  * Collect RPC fragments and append them to the receive stream buffer.
3165772Sas200622  * Each received fragment has a header, which we need to remove as we
317*10475Samw@Sun.COM  * build the full RPC PDU.  The scan offset is used to track frag headers.
3185772Sas200622  */
3195772Sas200622 static int
3208334SJose.Borrego@Sun.COM ndr_clnt_get_frags(ndr_client_t *clnt, ndr_xa_t *mxa)
3215772Sas200622 {
3228334SJose.Borrego@Sun.COM 	ndr_stream_t *nds = &mxa->recv_nds;
3237619SJose.Borrego@Sun.COM 	ndr_common_header_t hdr;
3245772Sas200622 	int frag_size;
3255772Sas200622 	int last_frag;
3265772Sas200622 
3275772Sas200622 	do {
328*10475Samw@Sun.COM 		if (ndr_clnt_get_frag(clnt, mxa, &hdr) < 0) {
329*10475Samw@Sun.COM 			nds_show_state(nds);
330*10475Samw@Sun.COM 			return (-1);
331*10475Samw@Sun.COM 		}
3325772Sas200622 
333*10475Samw@Sun.COM 		last_frag = NDR_IS_LAST_FRAG(hdr.pfc_flags);
334*10475Samw@Sun.COM 		frag_size = hdr.frag_length;
3355772Sas200622 
336*10475Samw@Sun.COM 		if (frag_size > (nds->pdu_size - nds->pdu_scan_offset)) {
337*10475Samw@Sun.COM 			nds_show_state(nds);
338*10475Samw@Sun.COM 			return (-1);
339*10475Samw@Sun.COM 		}
3405772Sas200622 
341*10475Samw@Sun.COM 		ndr_clnt_remove_hdr(nds);
342*10475Samw@Sun.COM 		nds->pdu_scan_offset += frag_size - NDR_RSP_HDR_SIZE;
3435772Sas200622 	} while (!last_frag);
3445772Sas200622 
3455772Sas200622 	return (0);
3465772Sas200622 }
347*10475Samw@Sun.COM 
348*10475Samw@Sun.COM /*
349*10475Samw@Sun.COM  * Read the next RPC fragment.  The xa_read() calls correspond to SmbReadX
350*10475Samw@Sun.COM  * requests.  Note that there is no correspondence between SmbReadX buffering
351*10475Samw@Sun.COM  * and DCE RPC fragment alignment.
352*10475Samw@Sun.COM  */
353*10475Samw@Sun.COM static int
354*10475Samw@Sun.COM ndr_clnt_get_frag(ndr_client_t *clnt, ndr_xa_t *mxa, ndr_common_header_t *hdr)
355*10475Samw@Sun.COM {
356*10475Samw@Sun.COM 	ndr_stream_t		*nds = &mxa->recv_nds;
357*10475Samw@Sun.COM 	unsigned long		available;
358*10475Samw@Sun.COM 	int			nbytes = 0;
359*10475Samw@Sun.COM 
360*10475Samw@Sun.COM 	available = nds->pdu_size - nds->pdu_scan_offset;
361*10475Samw@Sun.COM 
362*10475Samw@Sun.COM 	while (available < NDR_RSP_HDR_SIZE) {
363*10475Samw@Sun.COM 		if ((nbytes += (*clnt->xa_read)(clnt, mxa)) <= 0)
364*10475Samw@Sun.COM 			return (-1);
365*10475Samw@Sun.COM 		available += nbytes;
366*10475Samw@Sun.COM 	}
367*10475Samw@Sun.COM 
368*10475Samw@Sun.COM 	ndr_decode_frag_hdr(nds, hdr);
369*10475Samw@Sun.COM 	ndr_show_hdr(hdr);
370*10475Samw@Sun.COM 
371*10475Samw@Sun.COM 	while (available < hdr->frag_length) {
372*10475Samw@Sun.COM 		if ((nbytes = (*clnt->xa_read)(clnt, mxa)) <= 0)
373*10475Samw@Sun.COM 			return (-1);
374*10475Samw@Sun.COM 		available += nbytes;
375*10475Samw@Sun.COM 	}
376*10475Samw@Sun.COM 
377*10475Samw@Sun.COM 	return (nbytes);
378*10475Samw@Sun.COM }
379