1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
2289dc44ceSjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
2468b2bbf2SGordon Ross  *
2568b2bbf2SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
288d7e4166Sjose borrego #include <uuid/uuid.h>
298d7e4166Sjose borrego #include <ctype.h>
30dc20a302Sas #include <synch.h>
31da6c28aaSamw #include <stdio.h>
32dc20a302Sas #include <unistd.h>
33da6c28aaSamw #include <string.h>
34da6c28aaSamw #include <strings.h>
35dc20a302Sas #include <assert.h>
36da6c28aaSamw 
37*3299f39fSGordon Ross #include <libmlrpc.h>
38da6c28aaSamw 
39dc20a302Sas 
40dc20a302Sas /*
41dc20a302Sas  * Global list of allocated handles.  Handles are used in various
42dc20a302Sas  * server-side RPC functions: typically, issued when a service is
43dc20a302Sas  * opened and obsoleted when it is closed.  Clients should treat
44dc20a302Sas  * handles as opaque data.
45dc20a302Sas  */
46dc20a302Sas static ndr_handle_t *ndr_handle_list;
47dc20a302Sas static mutex_t ndr_handle_lock;
48dc20a302Sas 
49dc20a302Sas /*
50dc20a302Sas  * Table of registered services.
51dc20a302Sas  */
528d7e4166Sjose borrego #define	NDR_MAX_SERVICES	32
538d7e4166Sjose borrego static ndr_service_t *ndr_services[NDR_MAX_SERVICES];
548d7e4166Sjose borrego 
558d7e4166Sjose borrego /*
568d7e4166Sjose borrego  * Register a service.
578d7e4166Sjose borrego  *
588d7e4166Sjose borrego  * Returns:
598d7e4166Sjose borrego  *	0	Success
608d7e4166Sjose borrego  *	-1	Duplicate service
618d7e4166Sjose borrego  *	-2	Duplicate name
628d7e4166Sjose borrego  *	-3	Table overflow
638d7e4166Sjose borrego  */
648d7e4166Sjose borrego int
ndr_svc_register(ndr_service_t * svc)658d7e4166Sjose borrego ndr_svc_register(ndr_service_t *svc)
668d7e4166Sjose borrego {
678d7e4166Sjose borrego 	ndr_service_t 	*p;
688d7e4166Sjose borrego 	int		free_slot = -1;
698d7e4166Sjose borrego 	int		i;
708d7e4166Sjose borrego 
718d7e4166Sjose borrego 	for (i = 0; i < NDR_MAX_SERVICES; i++) {
728d7e4166Sjose borrego 		if ((p = ndr_services[i]) == NULL) {
738d7e4166Sjose borrego 			if (free_slot < 0)
748d7e4166Sjose borrego 				free_slot = i;
758d7e4166Sjose borrego 			continue;
768d7e4166Sjose borrego 		}
778d7e4166Sjose borrego 
788d7e4166Sjose borrego 		if (p == svc)
798d7e4166Sjose borrego 			return (-1);
808d7e4166Sjose borrego 
818d7e4166Sjose borrego 		if (strcasecmp(p->name, svc->name) == 0)
828d7e4166Sjose borrego 			return (-2);
838d7e4166Sjose borrego 	}
848d7e4166Sjose borrego 
858d7e4166Sjose borrego 	if (free_slot < 0)
868d7e4166Sjose borrego 		return (-3);
87dc20a302Sas 
888d7e4166Sjose borrego 	ndr_services[free_slot] = svc;
898d7e4166Sjose borrego 	return (0);
908d7e4166Sjose borrego }
918d7e4166Sjose borrego 
928d7e4166Sjose borrego void
ndr_svc_unregister(ndr_service_t * svc)938d7e4166Sjose borrego ndr_svc_unregister(ndr_service_t *svc)
948d7e4166Sjose borrego {
958d7e4166Sjose borrego 	int i;
968d7e4166Sjose borrego 
978d7e4166Sjose borrego 	for (i = 0; i < NDR_MAX_SERVICES; i++) {
988d7e4166Sjose borrego 		if (ndr_services[i] == svc)
998d7e4166Sjose borrego 			ndr_services[i] = NULL;
1008d7e4166Sjose borrego 	}
1018d7e4166Sjose borrego }
1028d7e4166Sjose borrego 
1038d7e4166Sjose borrego ndr_stub_table_t *
ndr_svc_find_stub(ndr_service_t * svc,int opnum)1048d7e4166Sjose borrego ndr_svc_find_stub(ndr_service_t *svc, int opnum)
105da6c28aaSamw {
1068d7e4166Sjose borrego 	ndr_stub_table_t *ste;
107da6c28aaSamw 
1088d7e4166Sjose borrego 	for (ste = svc->stub_table; ste->func; ste++) {
109da6c28aaSamw 		if (ste->opnum == opnum)
110da6c28aaSamw 			return (ste);
111da6c28aaSamw 	}
112da6c28aaSamw 
113da6c28aaSamw 	return (NULL);
114da6c28aaSamw }
115da6c28aaSamw 
1168d7e4166Sjose borrego ndr_service_t *
ndr_svc_lookup_name(const char * name)1178d7e4166Sjose borrego ndr_svc_lookup_name(const char *name)
118da6c28aaSamw {
1198d7e4166Sjose borrego 	ndr_service_t 	*svc;
120da6c28aaSamw 	int			i;
121da6c28aaSamw 
1228d7e4166Sjose borrego 	for (i = 0; i < NDR_MAX_SERVICES; i++) {
1238d7e4166Sjose borrego 		if ((svc = ndr_services[i]) == NULL)
124da6c28aaSamw 			continue;
125da6c28aaSamw 
1268d7e4166Sjose borrego 		if (strcasecmp(name, svc->name) != 0)
127da6c28aaSamw 			continue;
128da6c28aaSamw 
1298d7e4166Sjose borrego 		ndo_printf(0, 0, "%s %s", svc->name, svc->desc);
1308d7e4166Sjose borrego 		return (svc);
131da6c28aaSamw 	}
132da6c28aaSamw 
133da6c28aaSamw 	return (NULL);
134da6c28aaSamw }
135da6c28aaSamw 
1368d7e4166Sjose borrego ndr_service_t *
ndr_svc_lookup_uuid(ndr_uuid_t * as_uuid,int as_vers,ndr_uuid_t * ts_uuid,int ts_vers)1378d7e4166Sjose borrego ndr_svc_lookup_uuid(ndr_uuid_t *as_uuid, int as_vers,
138dc20a302Sas     ndr_uuid_t *ts_uuid, int ts_vers)
139da6c28aaSamw {
1408d7e4166Sjose borrego 	ndr_service_t *svc;
1418d7e4166Sjose borrego 	char abstract_syntax[UUID_PRINTABLE_STRING_LENGTH];
1428d7e4166Sjose borrego 	char transfer_syntax[UUID_PRINTABLE_STRING_LENGTH];
143da6c28aaSamw 	int i;
144da6c28aaSamw 
145da6c28aaSamw 	if (as_uuid)
1468d7e4166Sjose borrego 		ndr_uuid_unparse(as_uuid, abstract_syntax);
147da6c28aaSamw 
148da6c28aaSamw 	if (ts_uuid)
1498d7e4166Sjose borrego 		ndr_uuid_unparse(ts_uuid, transfer_syntax);
150da6c28aaSamw 
1518d7e4166Sjose borrego 	for (i = 0; i < NDR_MAX_SERVICES; i++) {
1528d7e4166Sjose borrego 		if ((svc = ndr_services[i]) == NULL)
153da6c28aaSamw 			continue;
154da6c28aaSamw 
155da6c28aaSamw 		if (as_uuid) {
1568d7e4166Sjose borrego 			if (svc->abstract_syntax_uuid == 0)
157da6c28aaSamw 				continue;
158da6c28aaSamw 
1598d7e4166Sjose borrego 			if (svc->abstract_syntax_version != as_vers)
160da6c28aaSamw 				continue;
161da6c28aaSamw 
162da6c28aaSamw 			if (strcasecmp(abstract_syntax,
1638d7e4166Sjose borrego 			    svc->abstract_syntax_uuid))
164da6c28aaSamw 				continue;
165da6c28aaSamw 		}
166da6c28aaSamw 
167da6c28aaSamw 		if (ts_uuid) {
1688d7e4166Sjose borrego 			if (svc->transfer_syntax_uuid == 0)
169da6c28aaSamw 				continue;
170da6c28aaSamw 
1718d7e4166Sjose borrego 			if (svc->transfer_syntax_version != ts_vers)
172da6c28aaSamw 				continue;
173da6c28aaSamw 
174da6c28aaSamw 			if (strcasecmp(transfer_syntax,
1758d7e4166Sjose borrego 			    svc->transfer_syntax_uuid))
176da6c28aaSamw 				continue;
177da6c28aaSamw 		}
178da6c28aaSamw 
1798d7e4166Sjose borrego 		ndo_printf(0, 0, "%s %s", svc->name, svc->desc);
1808d7e4166Sjose borrego 		return (svc);
181da6c28aaSamw 	}
182da6c28aaSamw 
1838d7e4166Sjose borrego 	ndo_printf(0, 0, "ndr_svc_lookup_uuid: unknown service");
1848d7e4166Sjose borrego 	ndo_printf(0, 0, "abstract=%s v%d, transfer=%s v%d",
1858d7e4166Sjose borrego 	    abstract_syntax, as_vers, transfer_syntax, ts_vers);
186da6c28aaSamw 	return (NULL);
187da6c28aaSamw }
188da6c28aaSamw 
189dc20a302Sas /*
190dc20a302Sas  * Allocate a handle for use with the server-side RPC functions.
191dc20a302Sas  *
192dc20a302Sas  * An arbitrary caller context can be associated with the handle
193dc20a302Sas  * via data; it will not be dereferenced by the handle API.
194dc20a302Sas  */
195dc20a302Sas ndr_hdid_t *
ndr_hdalloc(const ndr_xa_t * xa,const void * data)196dc20a302Sas ndr_hdalloc(const ndr_xa_t *xa, const void *data)
197dc20a302Sas {
1988d7e4166Sjose borrego 	static ndr_hdid_t id;
199dc20a302Sas 	ndr_handle_t *hd;
2008d7e4166Sjose borrego 	uuid_t uu;
201dc20a302Sas 
202dc20a302Sas 	if ((hd = malloc(sizeof (ndr_handle_t))) == NULL)
203dc20a302Sas 		return (NULL);
204dc20a302Sas 
2058d7e4166Sjose borrego 	if (id.data2 == 0) {
2068d7e4166Sjose borrego 		uuid_generate_random(uu);
2078d7e4166Sjose borrego 		bcopy(uu, &id.data2, sizeof (uuid_t));
2088d7e4166Sjose borrego 		id.data1 = 0;
2098d7e4166Sjose borrego 		id.data2 = 0;
210dc20a302Sas 	}
211dc20a302Sas 
2128d7e4166Sjose borrego 	++id.data2;
213dc20a302Sas 
2148d7e4166Sjose borrego 	bcopy(&id, &hd->nh_id, sizeof (ndr_hdid_t));
21568b2bbf2SGordon Ross 	hd->nh_pipe = xa->pipe;
216dc20a302Sas 	hd->nh_svc = xa->binding->service;
217dc20a302Sas 	hd->nh_data = (void *)data;
21889dc44ceSjose borrego 	hd->nh_data_free = NULL;
219dc20a302Sas 
220dc20a302Sas 	(void) mutex_lock(&ndr_handle_lock);
221dc20a302Sas 	hd->nh_next = ndr_handle_list;
222dc20a302Sas 	ndr_handle_list = hd;
223dc20a302Sas 	(void) mutex_unlock(&ndr_handle_lock);
224dc20a302Sas 
225dc20a302Sas 	return (&hd->nh_id);
226dc20a302Sas }
227dc20a302Sas 
228dc20a302Sas /*
229dc20a302Sas  * Remove a handle from the global list and free it.
230dc20a302Sas  */
231dc20a302Sas void
ndr_hdfree(const ndr_xa_t * xa,const ndr_hdid_t * id)232dc20a302Sas ndr_hdfree(const ndr_xa_t *xa, const ndr_hdid_t *id)
233dc20a302Sas {
2348d7e4166Sjose borrego 	ndr_service_t *svc = xa->binding->service;
235dc20a302Sas 	ndr_handle_t *hd;
236dc20a302Sas 	ndr_handle_t **pphd;
237dc20a302Sas 
238dc20a302Sas 	assert(id);
239dc20a302Sas 
240dc20a302Sas 	(void) mutex_lock(&ndr_handle_lock);
241dc20a302Sas 	pphd = &ndr_handle_list;
242dc20a302Sas 
243dc20a302Sas 	while (*pphd) {
244dc20a302Sas 		hd = *pphd;
245dc20a302Sas 
246dc20a302Sas 		if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) {
247dc20a302Sas 			if (hd->nh_svc == svc) {
248dc20a302Sas 				*pphd = hd->nh_next;
249dc20a302Sas 				free(hd);
250dc20a302Sas 			}
251dc20a302Sas 			break;
252dc20a302Sas 		}
253dc20a302Sas 
254dc20a302Sas 		pphd = &(*pphd)->nh_next;
255dc20a302Sas 	}
256dc20a302Sas 
257dc20a302Sas 	(void) mutex_unlock(&ndr_handle_lock);
258dc20a302Sas }
259dc20a302Sas 
260dc20a302Sas /*
261dc20a302Sas  * Lookup a handle by id.  If the handle is in the list and it matches
262dc20a302Sas  * the specified service, a pointer to it is returned.  Otherwise a null
263dc20a302Sas  * pointer is returned.
264dc20a302Sas  */
265dc20a302Sas ndr_handle_t *
ndr_hdlookup(const ndr_xa_t * xa,const ndr_hdid_t * id)266dc20a302Sas ndr_hdlookup(const ndr_xa_t *xa, const ndr_hdid_t *id)
267dc20a302Sas {
2688d7e4166Sjose borrego 	ndr_service_t *svc = xa->binding->service;
269dc20a302Sas 	ndr_handle_t *hd;
270dc20a302Sas 
271dc20a302Sas 	assert(id);
272dc20a302Sas 	(void) mutex_lock(&ndr_handle_lock);
273dc20a302Sas 	hd = ndr_handle_list;
274dc20a302Sas 
275dc20a302Sas 	while (hd) {
276dc20a302Sas 		if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) {
277dc20a302Sas 			if (hd->nh_svc != svc)
278dc20a302Sas 				break;
279dc20a302Sas 			(void) mutex_unlock(&ndr_handle_lock);
280dc20a302Sas 			return (hd);
281dc20a302Sas 		}
282dc20a302Sas 
283dc20a302Sas 		hd = hd->nh_next;
284dc20a302Sas 	}
285dc20a302Sas 
286dc20a302Sas 	(void) mutex_unlock(&ndr_handle_lock);
287dc20a302Sas 	return (NULL);
288dc20a302Sas }
289dc20a302Sas 
290dc20a302Sas /*
291dc20a302Sas  * Called when a pipe is closed to release any associated handles.
292dc20a302Sas  */
293dc20a302Sas void
ndr_hdclose(ndr_pipe_t * pipe)29468b2bbf2SGordon Ross ndr_hdclose(ndr_pipe_t *pipe)
295dc20a302Sas {
296dc20a302Sas 	ndr_handle_t *hd;
297dc20a302Sas 	ndr_handle_t **pphd;
298dc20a302Sas 
299dc20a302Sas 	(void) mutex_lock(&ndr_handle_lock);
300dc20a302Sas 	pphd = &ndr_handle_list;
301dc20a302Sas 
302dc20a302Sas 	while (*pphd) {
303dc20a302Sas 		hd = *pphd;
304dc20a302Sas 
30568b2bbf2SGordon Ross 		if (hd->nh_pipe == pipe) {
306dc20a302Sas 			*pphd = hd->nh_next;
30789dc44ceSjose borrego 
30889dc44ceSjose borrego 			if (hd->nh_data_free)
30989dc44ceSjose borrego 				(*hd->nh_data_free)(hd->nh_data);
31089dc44ceSjose borrego 
311dc20a302Sas 			free(hd);
312dc20a302Sas 			continue;
313dc20a302Sas 		}
314dc20a302Sas 
315dc20a302Sas 		pphd = &(*pphd)->nh_next;
316dc20a302Sas 	}
317dc20a302Sas 
318dc20a302Sas 	(void) mutex_unlock(&ndr_handle_lock);
319dc20a302Sas }
320dc20a302Sas 
3218d7e4166Sjose borrego /*
3228d7e4166Sjose borrego  * Convert a UUID to a string.
3238d7e4166Sjose borrego  */
324da6c28aaSamw void
ndr_uuid_unparse(ndr_uuid_t * uuid,char * out)3258d7e4166Sjose borrego ndr_uuid_unparse(ndr_uuid_t *uuid, char *out)
326da6c28aaSamw {
3278d7e4166Sjose borrego 	(void) sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
328da6c28aaSamw 	    uuid->data1, uuid->data2, uuid->data3,
329da6c28aaSamw 	    uuid->data4[0], uuid->data4[1],
330da6c28aaSamw 	    uuid->data4[2], uuid->data4[3],
331da6c28aaSamw 	    uuid->data4[4], uuid->data4[5],
332da6c28aaSamw 	    uuid->data4[6], uuid->data4[7]);
333da6c28aaSamw }
334da6c28aaSamw 
3358d7e4166Sjose borrego /*
3368d7e4166Sjose borrego  * Convert a string to a UUID.
3378d7e4166Sjose borrego  */
338da6c28aaSamw int
ndr_uuid_parse(char * in,ndr_uuid_t * uuid)3398d7e4166Sjose borrego ndr_uuid_parse(char *in, ndr_uuid_t *uuid)
340da6c28aaSamw {
3418d7e4166Sjose borrego 	char 		*p = in;
342da6c28aaSamw 	char 		*q;
343da6c28aaSamw 	char		buf[4];
344da6c28aaSamw 	int		i;
345da6c28aaSamw 
3468d7e4166Sjose borrego 	if (strlen(in) != UUID_PRINTABLE_STRING_LENGTH - 1)
3478d7e4166Sjose borrego 		return (-1);
3488d7e4166Sjose borrego 
349da6c28aaSamw 	uuid->data1 = strtoul(p, &p, 16);
350da6c28aaSamw 	if (*p != '-')
3518d7e4166Sjose borrego 		return (-1);
352da6c28aaSamw 	p++;
353da6c28aaSamw 
354da6c28aaSamw 	uuid->data2 = strtol(p, &p, 16);
355da6c28aaSamw 	if (*p != '-')
3568d7e4166Sjose borrego 		return (-1);
357da6c28aaSamw 	p++;
358da6c28aaSamw 
359da6c28aaSamw 	uuid->data3 = strtol(p, &p, 16);
360da6c28aaSamw 	if (*p != '-')
3618d7e4166Sjose borrego 		return (-1);
362da6c28aaSamw 	p++;
363da6c28aaSamw 
364da6c28aaSamw 	for (i = 0; i < 8; i++) {
3658d7e4166Sjose borrego 		if (*p ==  '-')
3668d7e4166Sjose borrego 			p++;
3678d7e4166Sjose borrego 
368da6c28aaSamw 		if (p[0] == 0 || p[1] == 0)
3698d7e4166Sjose borrego 			return (-1);
370da6c28aaSamw 
371da6c28aaSamw 		buf[0] = *p++;
372da6c28aaSamw 		buf[1] = *p++;
373da6c28aaSamw 		buf[2] = 0;
374da6c28aaSamw 		uuid->data4[i] = strtol(buf, &q, 16);
375da6c28aaSamw 		if (*q != 0)
3768d7e4166Sjose borrego 			return (-1);
377da6c28aaSamw 	}
378da6c28aaSamw 
379da6c28aaSamw 	if (*p != 0)
3808d7e4166Sjose borrego 		return (-1);
381da6c28aaSamw 
3828d7e4166Sjose borrego 	return (0);
383da6c28aaSamw }
384da6c28aaSamw 
385da6c28aaSamw void
ndr_svc_binding_pool_init(ndr_binding_t ** headpp,ndr_binding_t pool[],int n_pool)3868d7e4166Sjose borrego ndr_svc_binding_pool_init(ndr_binding_t **headpp, ndr_binding_t pool[],
3878d7e4166Sjose borrego     int n_pool)
388da6c28aaSamw {
3898d7e4166Sjose borrego 	ndr_binding_t	*head = NULL;
3908d7e4166Sjose borrego 	int		ix;
391da6c28aaSamw 
392da6c28aaSamw 	for (ix = n_pool - 1; ix >= 0; ix--) {
393da6c28aaSamw 		pool[ix].next = head;
394da6c28aaSamw 		pool[ix].service = NULL;
395da6c28aaSamw 		pool[ix].p_cont_id = 0xffff;
396da6c28aaSamw 		pool[ix].instance_specific = 0;
397da6c28aaSamw 		head = &pool[ix];
398da6c28aaSamw 	}
399da6c28aaSamw 
400da6c28aaSamw 	*headpp = head;
401da6c28aaSamw }
402da6c28aaSamw 
4038d7e4166Sjose borrego ndr_binding_t *
ndr_svc_find_binding(ndr_xa_t * mxa,ndr_p_context_id_t p_cont_id)4048d7e4166Sjose borrego ndr_svc_find_binding(ndr_xa_t *mxa, ndr_p_context_id_t p_cont_id)
405da6c28aaSamw {
4068d7e4166Sjose borrego 	ndr_binding_t *mbind;
407da6c28aaSamw 
408da6c28aaSamw 	for (mbind = mxa->binding_list; mbind; mbind = mbind->next) {
409da6c28aaSamw 		if (mbind->service != NULL &&
4108d7e4166Sjose borrego 		    mbind->which_side == NDR_BIND_SIDE_SERVER &&
411da6c28aaSamw 		    mbind->p_cont_id == p_cont_id)
412da6c28aaSamw 			break;
413da6c28aaSamw 	}
414da6c28aaSamw 
415da6c28aaSamw 	return (mbind);
416da6c28aaSamw }
417da6c28aaSamw 
4188d7e4166Sjose borrego ndr_binding_t *
ndr_svc_new_binding(ndr_xa_t * mxa)4198d7e4166Sjose borrego ndr_svc_new_binding(ndr_xa_t *mxa)
420da6c28aaSamw {
4218d7e4166Sjose borrego 	ndr_binding_t *mbind;
422da6c28aaSamw 
423da6c28aaSamw 	for (mbind = mxa->binding_list; mbind; mbind = mbind->next) {
424da6c28aaSamw 		if (mbind->service == NULL)
425da6c28aaSamw 			break;
426da6c28aaSamw 	}
427da6c28aaSamw 
428da6c28aaSamw 	return (mbind);
429da6c28aaSamw }
4303db3f65cSamw 
4313db3f65cSamw /*
4323db3f65cSamw  * Move bytes between a buffer and a uio structure.
4333db3f65cSamw  * The transfer direction is controlled by rw:
4343db3f65cSamw  *	UIO_READ:  transfer from buf to uio
4353db3f65cSamw  *	UIO_WRITE: transfer from uio to buf
4363db3f65cSamw  *
4373db3f65cSamw  * Returns the number of bytes moved.
4383db3f65cSamw  */
4393db3f65cSamw ssize_t
ndr_uiomove(caddr_t buf,size_t buflen,enum uio_rw rw,struct uio * uio)4403db3f65cSamw ndr_uiomove(caddr_t buf, size_t buflen, enum uio_rw rw, struct uio *uio)
4413db3f65cSamw {
4423db3f65cSamw 	struct iovec *iov;
4433db3f65cSamw 	int reading = (rw == UIO_READ);
4443db3f65cSamw 	size_t nbytes;
4453db3f65cSamw 	size_t nxfer = 0;
4463db3f65cSamw 
4473db3f65cSamw 	assert(rw == UIO_READ || rw == UIO_WRITE);
4483db3f65cSamw 
4493db3f65cSamw 	while (buflen && uio->uio_resid && uio->uio_iovcnt) {
4503db3f65cSamw 		iov = uio->uio_iov;
4513db3f65cSamw 		if ((nbytes = iov->iov_len) == 0) {
4523db3f65cSamw 			uio->uio_iov++;
4533db3f65cSamw 			uio->uio_iovcnt--;
4543db3f65cSamw 			continue;
4553db3f65cSamw 		}
4563db3f65cSamw 
4573db3f65cSamw 		if (nbytes > buflen)
4583db3f65cSamw 			nbytes = buflen;
4593db3f65cSamw 
4603db3f65cSamw 		if (reading)
4613db3f65cSamw 			bcopy(buf, iov->iov_base, nbytes);
4623db3f65cSamw 		else
4633db3f65cSamw 			bcopy(iov->iov_base, buf, nbytes);
4643db3f65cSamw 
4653db3f65cSamw 		iov->iov_base += nbytes;
4663db3f65cSamw 		iov->iov_len -= nbytes;
4673db3f65cSamw 		uio->uio_resid -= nbytes;
4683db3f65cSamw 		uio->uio_offset += nbytes;
4693db3f65cSamw 		buf += nbytes;
4703db3f65cSamw 		buflen -= nbytes;
4713db3f65cSamw 		nxfer += nbytes;
4723db3f65cSamw 	}
4733db3f65cSamw 
4743db3f65cSamw 	return (nxfer);
4753db3f65cSamw }
476