1dc20a302Sas200622 /* 2dc20a302Sas200622 * CDDL HEADER START 3dc20a302Sas200622 * 4dc20a302Sas200622 * The contents of this file are subject to the terms of the 5dc20a302Sas200622 * Common Development and Distribution License (the "License"). 6dc20a302Sas200622 * You may not use this file except in compliance with the License. 7dc20a302Sas200622 * 8dc20a302Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9dc20a302Sas200622 * or http://www.opensolaris.org/os/licensing. 10dc20a302Sas200622 * See the License for the specific language governing permissions 11dc20a302Sas200622 * and limitations under the License. 12dc20a302Sas200622 * 13dc20a302Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 14dc20a302Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15dc20a302Sas200622 * If applicable, add the following below this CDDL HEADER, with the 16dc20a302Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 17dc20a302Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 18dc20a302Sas200622 * 19dc20a302Sas200622 * CDDL HEADER END 20dc20a302Sas200622 */ 21dc20a302Sas200622 /* 2289dc44ceSjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23dc20a302Sas200622 * Use is subject to license terms. 24*68b2bbf2SGordon Ross * 25*68b2bbf2SGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26dc20a302Sas200622 */ 27dc20a302Sas200622 288d7e4166Sjose borrego #include <uuid/uuid.h> 298d7e4166Sjose borrego #include <ctype.h> 30dc20a302Sas200622 #include <synch.h> 31dc20a302Sas200622 #include <stdio.h> 32dc20a302Sas200622 #include <unistd.h> 33dc20a302Sas200622 #include <string.h> 34dc20a302Sas200622 #include <strings.h> 35dc20a302Sas200622 #include <assert.h> 36dc20a302Sas200622 37dc20a302Sas200622 #include <smbsrv/libsmb.h> 388d7e4166Sjose borrego #include <smbsrv/libmlrpc.h> 39dc20a302Sas200622 40dc20a302Sas200622 41dc20a302Sas200622 /* 42dc20a302Sas200622 * Global list of allocated handles. Handles are used in various 43dc20a302Sas200622 * server-side RPC functions: typically, issued when a service is 44dc20a302Sas200622 * opened and obsoleted when it is closed. Clients should treat 45dc20a302Sas200622 * handles as opaque data. 46dc20a302Sas200622 */ 47dc20a302Sas200622 static ndr_handle_t *ndr_handle_list; 48dc20a302Sas200622 static mutex_t ndr_handle_lock; 49dc20a302Sas200622 50dc20a302Sas200622 /* 51dc20a302Sas200622 * Table of registered services. 52dc20a302Sas200622 */ 538d7e4166Sjose borrego #define NDR_MAX_SERVICES 32 548d7e4166Sjose borrego static ndr_service_t *ndr_services[NDR_MAX_SERVICES]; 55dc20a302Sas200622 56dc20a302Sas200622 /* 57dc20a302Sas200622 * Register a service. 58dc20a302Sas200622 * 59dc20a302Sas200622 * Returns: 60dc20a302Sas200622 * 0 Success 61dc20a302Sas200622 * -1 Duplicate service 62dc20a302Sas200622 * -2 Duplicate name 63dc20a302Sas200622 * -3 Table overflow 64dc20a302Sas200622 */ 65dc20a302Sas200622 int 668d7e4166Sjose borrego ndr_svc_register(ndr_service_t *svc) 67dc20a302Sas200622 { 688d7e4166Sjose borrego ndr_service_t *p; 69dc20a302Sas200622 int free_slot = -1; 70dc20a302Sas200622 int i; 71dc20a302Sas200622 728d7e4166Sjose borrego for (i = 0; i < NDR_MAX_SERVICES; i++) { 738d7e4166Sjose borrego if ((p = ndr_services[i]) == NULL) { 74dc20a302Sas200622 if (free_slot < 0) 75dc20a302Sas200622 free_slot = i; 76dc20a302Sas200622 continue; 77dc20a302Sas200622 } 78dc20a302Sas200622 798d7e4166Sjose borrego if (p == svc) 80dc20a302Sas200622 return (-1); 81dc20a302Sas200622 828d7e4166Sjose borrego if (strcasecmp(p->name, svc->name) == 0) 83dc20a302Sas200622 return (-2); 84dc20a302Sas200622 } 85dc20a302Sas200622 86dc20a302Sas200622 if (free_slot < 0) 87dc20a302Sas200622 return (-3); 88dc20a302Sas200622 898d7e4166Sjose borrego ndr_services[free_slot] = svc; 90dc20a302Sas200622 return (0); 91dc20a302Sas200622 } 92dc20a302Sas200622 93dc20a302Sas200622 void 948d7e4166Sjose borrego ndr_svc_unregister(ndr_service_t *svc) 95dc20a302Sas200622 { 96dc20a302Sas200622 int i; 97dc20a302Sas200622 988d7e4166Sjose borrego for (i = 0; i < NDR_MAX_SERVICES; i++) { 998d7e4166Sjose borrego if (ndr_services[i] == svc) 1008d7e4166Sjose borrego ndr_services[i] = NULL; 101dc20a302Sas200622 } 102dc20a302Sas200622 } 103dc20a302Sas200622 1048d7e4166Sjose borrego ndr_stub_table_t * 1058d7e4166Sjose borrego ndr_svc_find_stub(ndr_service_t *svc, int opnum) 1068d7e4166Sjose borrego { 1078d7e4166Sjose borrego ndr_stub_table_t *ste; 1088d7e4166Sjose borrego 1098d7e4166Sjose borrego for (ste = svc->stub_table; ste->func; ste++) { 1108d7e4166Sjose borrego if (ste->opnum == opnum) 1118d7e4166Sjose borrego return (ste); 1128d7e4166Sjose borrego } 1138d7e4166Sjose borrego 1148d7e4166Sjose borrego return (NULL); 1158d7e4166Sjose borrego } 1168d7e4166Sjose borrego 1178d7e4166Sjose borrego ndr_service_t * 1188d7e4166Sjose borrego ndr_svc_lookup_name(const char *name) 1198d7e4166Sjose borrego { 1208d7e4166Sjose borrego ndr_service_t *svc; 1218d7e4166Sjose borrego int i; 1228d7e4166Sjose borrego 1238d7e4166Sjose borrego for (i = 0; i < NDR_MAX_SERVICES; i++) { 1248d7e4166Sjose borrego if ((svc = ndr_services[i]) == NULL) 1258d7e4166Sjose borrego continue; 1268d7e4166Sjose borrego 1278d7e4166Sjose borrego if (strcasecmp(name, svc->name) != 0) 1288d7e4166Sjose borrego continue; 1298d7e4166Sjose borrego 1308d7e4166Sjose borrego ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 1318d7e4166Sjose borrego return (svc); 1328d7e4166Sjose borrego } 1338d7e4166Sjose borrego 1348d7e4166Sjose borrego return (NULL); 1358d7e4166Sjose borrego } 1368d7e4166Sjose borrego 1378d7e4166Sjose borrego ndr_service_t * 1388d7e4166Sjose borrego ndr_svc_lookup_uuid(ndr_uuid_t *as_uuid, int as_vers, 1398d7e4166Sjose borrego ndr_uuid_t *ts_uuid, int ts_vers) 1408d7e4166Sjose borrego { 1418d7e4166Sjose borrego ndr_service_t *svc; 1428d7e4166Sjose borrego char abstract_syntax[UUID_PRINTABLE_STRING_LENGTH]; 1438d7e4166Sjose borrego char transfer_syntax[UUID_PRINTABLE_STRING_LENGTH]; 1448d7e4166Sjose borrego int i; 1458d7e4166Sjose borrego 1468d7e4166Sjose borrego if (as_uuid) 1478d7e4166Sjose borrego ndr_uuid_unparse(as_uuid, abstract_syntax); 1488d7e4166Sjose borrego 1498d7e4166Sjose borrego if (ts_uuid) 1508d7e4166Sjose borrego ndr_uuid_unparse(ts_uuid, transfer_syntax); 1518d7e4166Sjose borrego 1528d7e4166Sjose borrego for (i = 0; i < NDR_MAX_SERVICES; i++) { 1538d7e4166Sjose borrego if ((svc = ndr_services[i]) == NULL) 1548d7e4166Sjose borrego continue; 1558d7e4166Sjose borrego 1568d7e4166Sjose borrego if (as_uuid) { 1578d7e4166Sjose borrego if (svc->abstract_syntax_uuid == 0) 1588d7e4166Sjose borrego continue; 1598d7e4166Sjose borrego 1608d7e4166Sjose borrego if (svc->abstract_syntax_version != as_vers) 1618d7e4166Sjose borrego continue; 1628d7e4166Sjose borrego 1638d7e4166Sjose borrego if (strcasecmp(abstract_syntax, 1648d7e4166Sjose borrego svc->abstract_syntax_uuid)) 1658d7e4166Sjose borrego continue; 1668d7e4166Sjose borrego } 1678d7e4166Sjose borrego 1688d7e4166Sjose borrego if (ts_uuid) { 1698d7e4166Sjose borrego if (svc->transfer_syntax_uuid == 0) 1708d7e4166Sjose borrego continue; 1718d7e4166Sjose borrego 1728d7e4166Sjose borrego if (svc->transfer_syntax_version != ts_vers) 1738d7e4166Sjose borrego continue; 1748d7e4166Sjose borrego 1758d7e4166Sjose borrego if (strcasecmp(transfer_syntax, 1768d7e4166Sjose borrego svc->transfer_syntax_uuid)) 1778d7e4166Sjose borrego continue; 1788d7e4166Sjose borrego } 1798d7e4166Sjose borrego 1808d7e4166Sjose borrego ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 1818d7e4166Sjose borrego return (svc); 1828d7e4166Sjose borrego } 1838d7e4166Sjose borrego 1848d7e4166Sjose borrego ndo_printf(0, 0, "ndr_svc_lookup_uuid: unknown service"); 1858d7e4166Sjose borrego ndo_printf(0, 0, "abstract=%s v%d, transfer=%s v%d", 1868d7e4166Sjose borrego abstract_syntax, as_vers, transfer_syntax, ts_vers); 1878d7e4166Sjose borrego return (NULL); 1888d7e4166Sjose borrego } 1898d7e4166Sjose borrego 190dc20a302Sas200622 /* 191dc20a302Sas200622 * Allocate a handle for use with the server-side RPC functions. 192dc20a302Sas200622 * 193dc20a302Sas200622 * An arbitrary caller context can be associated with the handle 194dc20a302Sas200622 * via data; it will not be dereferenced by the handle API. 195dc20a302Sas200622 */ 196dc20a302Sas200622 ndr_hdid_t * 197dc20a302Sas200622 ndr_hdalloc(const ndr_xa_t *xa, const void *data) 198dc20a302Sas200622 { 1998d7e4166Sjose borrego static ndr_hdid_t id; 200dc20a302Sas200622 ndr_handle_t *hd; 2018d7e4166Sjose borrego uuid_t uu; 202dc20a302Sas200622 203dc20a302Sas200622 if ((hd = malloc(sizeof (ndr_handle_t))) == NULL) 204dc20a302Sas200622 return (NULL); 205dc20a302Sas200622 2068d7e4166Sjose borrego if (id.data2 == 0) { 2078d7e4166Sjose borrego uuid_generate_random(uu); 2088d7e4166Sjose borrego bcopy(uu, &id.data2, sizeof (uuid_t)); 2098d7e4166Sjose borrego id.data1 = 0; 2108d7e4166Sjose borrego id.data2 = 0; 211dc20a302Sas200622 } 212dc20a302Sas200622 2138d7e4166Sjose borrego ++id.data2; 214dc20a302Sas200622 2158d7e4166Sjose borrego bcopy(&id, &hd->nh_id, sizeof (ndr_hdid_t)); 216*68b2bbf2SGordon Ross hd->nh_pipe = xa->pipe; 217dc20a302Sas200622 hd->nh_svc = xa->binding->service; 218dc20a302Sas200622 hd->nh_data = (void *)data; 21989dc44ceSjose borrego hd->nh_data_free = NULL; 220dc20a302Sas200622 221dc20a302Sas200622 (void) mutex_lock(&ndr_handle_lock); 222dc20a302Sas200622 hd->nh_next = ndr_handle_list; 223dc20a302Sas200622 ndr_handle_list = hd; 224dc20a302Sas200622 (void) mutex_unlock(&ndr_handle_lock); 225dc20a302Sas200622 226dc20a302Sas200622 return (&hd->nh_id); 227dc20a302Sas200622 } 228dc20a302Sas200622 229dc20a302Sas200622 /* 230dc20a302Sas200622 * Remove a handle from the global list and free it. 231dc20a302Sas200622 */ 232dc20a302Sas200622 void 233dc20a302Sas200622 ndr_hdfree(const ndr_xa_t *xa, const ndr_hdid_t *id) 234dc20a302Sas200622 { 2358d7e4166Sjose borrego ndr_service_t *svc = xa->binding->service; 236dc20a302Sas200622 ndr_handle_t *hd; 237dc20a302Sas200622 ndr_handle_t **pphd; 238dc20a302Sas200622 239dc20a302Sas200622 assert(id); 240dc20a302Sas200622 241dc20a302Sas200622 (void) mutex_lock(&ndr_handle_lock); 242dc20a302Sas200622 pphd = &ndr_handle_list; 243dc20a302Sas200622 244dc20a302Sas200622 while (*pphd) { 245dc20a302Sas200622 hd = *pphd; 246dc20a302Sas200622 247dc20a302Sas200622 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 248dc20a302Sas200622 if (hd->nh_svc == svc) { 249dc20a302Sas200622 *pphd = hd->nh_next; 250dc20a302Sas200622 free(hd); 251dc20a302Sas200622 } 252dc20a302Sas200622 break; 253dc20a302Sas200622 } 254dc20a302Sas200622 255dc20a302Sas200622 pphd = &(*pphd)->nh_next; 256dc20a302Sas200622 } 257dc20a302Sas200622 258dc20a302Sas200622 (void) mutex_unlock(&ndr_handle_lock); 259dc20a302Sas200622 } 260dc20a302Sas200622 261dc20a302Sas200622 /* 262dc20a302Sas200622 * Lookup a handle by id. If the handle is in the list and it matches 263dc20a302Sas200622 * the specified service, a pointer to it is returned. Otherwise a null 264dc20a302Sas200622 * pointer is returned. 265dc20a302Sas200622 */ 266dc20a302Sas200622 ndr_handle_t * 267dc20a302Sas200622 ndr_hdlookup(const ndr_xa_t *xa, const ndr_hdid_t *id) 268dc20a302Sas200622 { 2698d7e4166Sjose borrego ndr_service_t *svc = xa->binding->service; 270dc20a302Sas200622 ndr_handle_t *hd; 271dc20a302Sas200622 272dc20a302Sas200622 assert(id); 273dc20a302Sas200622 (void) mutex_lock(&ndr_handle_lock); 274dc20a302Sas200622 hd = ndr_handle_list; 275dc20a302Sas200622 276dc20a302Sas200622 while (hd) { 277dc20a302Sas200622 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 278dc20a302Sas200622 if (hd->nh_svc != svc) 279dc20a302Sas200622 break; 280dc20a302Sas200622 (void) mutex_unlock(&ndr_handle_lock); 281dc20a302Sas200622 return (hd); 282dc20a302Sas200622 } 283dc20a302Sas200622 284dc20a302Sas200622 hd = hd->nh_next; 285dc20a302Sas200622 } 286dc20a302Sas200622 287dc20a302Sas200622 (void) mutex_unlock(&ndr_handle_lock); 288dc20a302Sas200622 return (NULL); 289dc20a302Sas200622 } 290dc20a302Sas200622 291dc20a302Sas200622 /* 292dc20a302Sas200622 * Called when a pipe is closed to release any associated handles. 293dc20a302Sas200622 */ 294dc20a302Sas200622 void 295*68b2bbf2SGordon Ross ndr_hdclose(ndr_pipe_t *pipe) 296dc20a302Sas200622 { 297dc20a302Sas200622 ndr_handle_t *hd; 298dc20a302Sas200622 ndr_handle_t **pphd; 299dc20a302Sas200622 300dc20a302Sas200622 (void) mutex_lock(&ndr_handle_lock); 301dc20a302Sas200622 pphd = &ndr_handle_list; 302dc20a302Sas200622 303dc20a302Sas200622 while (*pphd) { 304dc20a302Sas200622 hd = *pphd; 305dc20a302Sas200622 306*68b2bbf2SGordon Ross if (hd->nh_pipe == pipe) { 307dc20a302Sas200622 *pphd = hd->nh_next; 30889dc44ceSjose borrego 30989dc44ceSjose borrego if (hd->nh_data_free) 31089dc44ceSjose borrego (*hd->nh_data_free)(hd->nh_data); 31189dc44ceSjose borrego 312dc20a302Sas200622 free(hd); 313dc20a302Sas200622 continue; 314dc20a302Sas200622 } 315dc20a302Sas200622 316dc20a302Sas200622 pphd = &(*pphd)->nh_next; 317dc20a302Sas200622 } 318dc20a302Sas200622 319dc20a302Sas200622 (void) mutex_unlock(&ndr_handle_lock); 320dc20a302Sas200622 } 321dc20a302Sas200622 3228d7e4166Sjose borrego /* 3238d7e4166Sjose borrego * Convert a UUID to a string. 3248d7e4166Sjose borrego */ 325dc20a302Sas200622 void 3268d7e4166Sjose borrego ndr_uuid_unparse(ndr_uuid_t *uuid, char *out) 327dc20a302Sas200622 { 3288d7e4166Sjose borrego (void) sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 329dc20a302Sas200622 uuid->data1, uuid->data2, uuid->data3, 330dc20a302Sas200622 uuid->data4[0], uuid->data4[1], 331dc20a302Sas200622 uuid->data4[2], uuid->data4[3], 332dc20a302Sas200622 uuid->data4[4], uuid->data4[5], 333dc20a302Sas200622 uuid->data4[6], uuid->data4[7]); 334dc20a302Sas200622 } 335dc20a302Sas200622 3368d7e4166Sjose borrego /* 3378d7e4166Sjose borrego * Convert a string to a UUID. 3388d7e4166Sjose borrego */ 339dc20a302Sas200622 int 3408d7e4166Sjose borrego ndr_uuid_parse(char *in, ndr_uuid_t *uuid) 341dc20a302Sas200622 { 3428d7e4166Sjose borrego char *p = in; 343dc20a302Sas200622 char *q; 344dc20a302Sas200622 char buf[4]; 345dc20a302Sas200622 int i; 346dc20a302Sas200622 3478d7e4166Sjose borrego if (strlen(in) != UUID_PRINTABLE_STRING_LENGTH - 1) 3488d7e4166Sjose borrego return (-1); 3498d7e4166Sjose borrego 350dc20a302Sas200622 uuid->data1 = strtoul(p, &p, 16); 351dc20a302Sas200622 if (*p != '-') 3528d7e4166Sjose borrego return (-1); 353dc20a302Sas200622 p++; 354dc20a302Sas200622 355dc20a302Sas200622 uuid->data2 = strtol(p, &p, 16); 356dc20a302Sas200622 if (*p != '-') 3578d7e4166Sjose borrego return (-1); 358dc20a302Sas200622 p++; 359dc20a302Sas200622 360dc20a302Sas200622 uuid->data3 = strtol(p, &p, 16); 361dc20a302Sas200622 if (*p != '-') 3628d7e4166Sjose borrego return (-1); 363dc20a302Sas200622 p++; 364dc20a302Sas200622 365dc20a302Sas200622 for (i = 0; i < 8; i++) { 3668d7e4166Sjose borrego if (*p == '-') 3678d7e4166Sjose borrego p++; 3688d7e4166Sjose borrego 369dc20a302Sas200622 if (p[0] == 0 || p[1] == 0) 3708d7e4166Sjose borrego return (-1); 371dc20a302Sas200622 372dc20a302Sas200622 buf[0] = *p++; 373dc20a302Sas200622 buf[1] = *p++; 374dc20a302Sas200622 buf[2] = 0; 375dc20a302Sas200622 uuid->data4[i] = strtol(buf, &q, 16); 376dc20a302Sas200622 if (*q != 0) 3778d7e4166Sjose borrego return (-1); 378dc20a302Sas200622 } 379dc20a302Sas200622 380dc20a302Sas200622 if (*p != 0) 3818d7e4166Sjose borrego return (-1); 382dc20a302Sas200622 3838d7e4166Sjose borrego return (0); 384dc20a302Sas200622 } 385dc20a302Sas200622 386dc20a302Sas200622 void 3878d7e4166Sjose borrego ndr_svc_binding_pool_init(ndr_binding_t **headpp, ndr_binding_t pool[], 3888d7e4166Sjose borrego int n_pool) 389dc20a302Sas200622 { 3908d7e4166Sjose borrego ndr_binding_t *head = NULL; 391dc20a302Sas200622 int ix; 392dc20a302Sas200622 393dc20a302Sas200622 for (ix = n_pool - 1; ix >= 0; ix--) { 394dc20a302Sas200622 pool[ix].next = head; 395dc20a302Sas200622 pool[ix].service = NULL; 396dc20a302Sas200622 pool[ix].p_cont_id = 0xffff; 397dc20a302Sas200622 pool[ix].instance_specific = 0; 398dc20a302Sas200622 head = &pool[ix]; 399dc20a302Sas200622 } 400dc20a302Sas200622 401dc20a302Sas200622 *headpp = head; 402dc20a302Sas200622 } 403dc20a302Sas200622 4048d7e4166Sjose borrego ndr_binding_t * 4058d7e4166Sjose borrego ndr_svc_find_binding(ndr_xa_t *mxa, ndr_p_context_id_t p_cont_id) 406dc20a302Sas200622 { 4078d7e4166Sjose borrego ndr_binding_t *mbind; 408dc20a302Sas200622 409dc20a302Sas200622 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 410dc20a302Sas200622 if (mbind->service != NULL && 4118d7e4166Sjose borrego mbind->which_side == NDR_BIND_SIDE_SERVER && 412dc20a302Sas200622 mbind->p_cont_id == p_cont_id) 413dc20a302Sas200622 break; 414dc20a302Sas200622 } 415dc20a302Sas200622 416dc20a302Sas200622 return (mbind); 417dc20a302Sas200622 } 418dc20a302Sas200622 4198d7e4166Sjose borrego ndr_binding_t * 4208d7e4166Sjose borrego ndr_svc_new_binding(ndr_xa_t *mxa) 421dc20a302Sas200622 { 4228d7e4166Sjose borrego ndr_binding_t *mbind; 423dc20a302Sas200622 424dc20a302Sas200622 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 425dc20a302Sas200622 if (mbind->service == NULL) 426dc20a302Sas200622 break; 427dc20a302Sas200622 } 428dc20a302Sas200622 429dc20a302Sas200622 return (mbind); 430dc20a302Sas200622 } 4313db3f65cSamw 4323db3f65cSamw /* 4333db3f65cSamw * Move bytes between a buffer and a uio structure. 4343db3f65cSamw * The transfer direction is controlled by rw: 4353db3f65cSamw * UIO_READ: transfer from buf to uio 4363db3f65cSamw * UIO_WRITE: transfer from uio to buf 4373db3f65cSamw * 4383db3f65cSamw * Returns the number of bytes moved. 4393db3f65cSamw */ 4403db3f65cSamw ssize_t 4413db3f65cSamw ndr_uiomove(caddr_t buf, size_t buflen, enum uio_rw rw, struct uio *uio) 4423db3f65cSamw { 4433db3f65cSamw struct iovec *iov; 4443db3f65cSamw int reading = (rw == UIO_READ); 4453db3f65cSamw size_t nbytes; 4463db3f65cSamw size_t nxfer = 0; 4473db3f65cSamw 4483db3f65cSamw assert(rw == UIO_READ || rw == UIO_WRITE); 4493db3f65cSamw 4503db3f65cSamw while (buflen && uio->uio_resid && uio->uio_iovcnt) { 4513db3f65cSamw iov = uio->uio_iov; 4523db3f65cSamw if ((nbytes = iov->iov_len) == 0) { 4533db3f65cSamw uio->uio_iov++; 4543db3f65cSamw uio->uio_iovcnt--; 4553db3f65cSamw continue; 4563db3f65cSamw } 4573db3f65cSamw 4583db3f65cSamw if (nbytes > buflen) 4593db3f65cSamw nbytes = buflen; 4603db3f65cSamw 4613db3f65cSamw if (reading) 4623db3f65cSamw bcopy(buf, iov->iov_base, nbytes); 4633db3f65cSamw else 4643db3f65cSamw bcopy(iov->iov_base, buf, nbytes); 4653db3f65cSamw 4663db3f65cSamw iov->iov_base += nbytes; 4673db3f65cSamw iov->iov_len -= nbytes; 4683db3f65cSamw uio->uio_resid -= nbytes; 4693db3f65cSamw uio->uio_offset += nbytes; 4703db3f65cSamw buf += nbytes; 4713db3f65cSamw buflen -= nbytes; 4723db3f65cSamw nxfer += nbytes; 4733db3f65cSamw } 4743db3f65cSamw 4753db3f65cSamw return (nxfer); 4763db3f65cSamw } 477