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