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 /* 22*8474SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 268334SJose.Borrego@Sun.COM #include <uuid/uuid.h> 278334SJose.Borrego@Sun.COM #include <ctype.h> 285772Sas200622 #include <synch.h> 295772Sas200622 #include <stdio.h> 305772Sas200622 #include <unistd.h> 315772Sas200622 #include <string.h> 325772Sas200622 #include <strings.h> 335772Sas200622 #include <assert.h> 345772Sas200622 355772Sas200622 #include <smbsrv/libsmb.h> 368334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h> 375772Sas200622 385772Sas200622 395772Sas200622 /* 405772Sas200622 * Global list of allocated handles. Handles are used in various 415772Sas200622 * server-side RPC functions: typically, issued when a service is 425772Sas200622 * opened and obsoleted when it is closed. Clients should treat 435772Sas200622 * handles as opaque data. 445772Sas200622 */ 455772Sas200622 static ndr_handle_t *ndr_handle_list; 465772Sas200622 static mutex_t ndr_handle_lock; 475772Sas200622 485772Sas200622 /* 495772Sas200622 * Table of registered services. 505772Sas200622 */ 518334SJose.Borrego@Sun.COM #define NDR_MAX_SERVICES 32 528334SJose.Borrego@Sun.COM static ndr_service_t *ndr_services[NDR_MAX_SERVICES]; 535772Sas200622 545772Sas200622 /* 555772Sas200622 * Register a service. 565772Sas200622 * 575772Sas200622 * Returns: 585772Sas200622 * 0 Success 595772Sas200622 * -1 Duplicate service 605772Sas200622 * -2 Duplicate name 615772Sas200622 * -3 Table overflow 625772Sas200622 */ 635772Sas200622 int 648334SJose.Borrego@Sun.COM ndr_svc_register(ndr_service_t *svc) 655772Sas200622 { 668334SJose.Borrego@Sun.COM ndr_service_t *p; 678334SJose.Borrego@Sun.COM int free_slot = -1; 688334SJose.Borrego@Sun.COM int i; 695772Sas200622 708334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 718334SJose.Borrego@Sun.COM if ((p = ndr_services[i]) == NULL) { 725772Sas200622 if (free_slot < 0) 735772Sas200622 free_slot = i; 745772Sas200622 continue; 755772Sas200622 } 765772Sas200622 778334SJose.Borrego@Sun.COM if (p == svc) 785772Sas200622 return (-1); 795772Sas200622 808334SJose.Borrego@Sun.COM if (strcasecmp(p->name, svc->name) == 0) 815772Sas200622 return (-2); 825772Sas200622 } 835772Sas200622 845772Sas200622 if (free_slot < 0) 855772Sas200622 return (-3); 865772Sas200622 878334SJose.Borrego@Sun.COM ndr_services[free_slot] = svc; 885772Sas200622 return (0); 895772Sas200622 } 905772Sas200622 915772Sas200622 void 928334SJose.Borrego@Sun.COM ndr_svc_unregister(ndr_service_t *svc) 935772Sas200622 { 945772Sas200622 int i; 955772Sas200622 968334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 978334SJose.Borrego@Sun.COM if (ndr_services[i] == svc) 988334SJose.Borrego@Sun.COM ndr_services[i] = NULL; 995772Sas200622 } 1005772Sas200622 } 1015772Sas200622 1025772Sas200622 int 1038334SJose.Borrego@Sun.COM ndr_svc_list(char *buffer, int bufsize) 1045772Sas200622 { 1058334SJose.Borrego@Sun.COM ndr_service_t *svc; 1065772Sas200622 smb_ctxbuf_t ctx; 1075772Sas200622 int i; 1085772Sas200622 1095772Sas200622 (void) smb_ctxbuf_init(&ctx, (uint8_t *)buffer, bufsize); 1105772Sas200622 1118334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 1128334SJose.Borrego@Sun.COM if ((svc = ndr_services[i]) != 0) { 1135772Sas200622 (void) smb_ctxbuf_printf(&ctx, "%-16s %s\n", 1148334SJose.Borrego@Sun.COM svc->name, svc->desc); 1155772Sas200622 } 1165772Sas200622 } 1175772Sas200622 1185772Sas200622 return (smb_ctxbuf_len(&ctx)); 1195772Sas200622 } 1205772Sas200622 1218334SJose.Borrego@Sun.COM ndr_stub_table_t * 1228334SJose.Borrego@Sun.COM ndr_svc_find_stub(ndr_service_t *svc, int opnum) 1238334SJose.Borrego@Sun.COM { 1248334SJose.Borrego@Sun.COM ndr_stub_table_t *ste; 1258334SJose.Borrego@Sun.COM 1268334SJose.Borrego@Sun.COM for (ste = svc->stub_table; ste->func; ste++) { 1278334SJose.Borrego@Sun.COM if (ste->opnum == opnum) 1288334SJose.Borrego@Sun.COM return (ste); 1298334SJose.Borrego@Sun.COM } 1308334SJose.Borrego@Sun.COM 1318334SJose.Borrego@Sun.COM return (NULL); 1328334SJose.Borrego@Sun.COM } 1338334SJose.Borrego@Sun.COM 1348334SJose.Borrego@Sun.COM ndr_service_t * 1358334SJose.Borrego@Sun.COM ndr_svc_lookup_name(const char *name) 1368334SJose.Borrego@Sun.COM { 1378334SJose.Borrego@Sun.COM ndr_service_t *svc; 1388334SJose.Borrego@Sun.COM int i; 1398334SJose.Borrego@Sun.COM 1408334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 1418334SJose.Borrego@Sun.COM if ((svc = ndr_services[i]) == NULL) 1428334SJose.Borrego@Sun.COM continue; 1438334SJose.Borrego@Sun.COM 1448334SJose.Borrego@Sun.COM if (strcasecmp(name, svc->name) != 0) 1458334SJose.Borrego@Sun.COM continue; 1468334SJose.Borrego@Sun.COM 1478334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 1488334SJose.Borrego@Sun.COM return (svc); 1498334SJose.Borrego@Sun.COM } 1508334SJose.Borrego@Sun.COM 1518334SJose.Borrego@Sun.COM return (NULL); 1528334SJose.Borrego@Sun.COM } 1538334SJose.Borrego@Sun.COM 1548334SJose.Borrego@Sun.COM ndr_service_t * 1558334SJose.Borrego@Sun.COM ndr_svc_lookup_uuid(ndr_uuid_t *as_uuid, int as_vers, 1568334SJose.Borrego@Sun.COM ndr_uuid_t *ts_uuid, int ts_vers) 1578334SJose.Borrego@Sun.COM { 1588334SJose.Borrego@Sun.COM ndr_service_t *svc; 1598334SJose.Borrego@Sun.COM char abstract_syntax[UUID_PRINTABLE_STRING_LENGTH]; 1608334SJose.Borrego@Sun.COM char transfer_syntax[UUID_PRINTABLE_STRING_LENGTH]; 1618334SJose.Borrego@Sun.COM int i; 1628334SJose.Borrego@Sun.COM 1638334SJose.Borrego@Sun.COM if (as_uuid) 1648334SJose.Borrego@Sun.COM ndr_uuid_unparse(as_uuid, abstract_syntax); 1658334SJose.Borrego@Sun.COM 1668334SJose.Borrego@Sun.COM if (ts_uuid) 1678334SJose.Borrego@Sun.COM ndr_uuid_unparse(ts_uuid, transfer_syntax); 1688334SJose.Borrego@Sun.COM 1698334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 1708334SJose.Borrego@Sun.COM if ((svc = ndr_services[i]) == NULL) 1718334SJose.Borrego@Sun.COM continue; 1728334SJose.Borrego@Sun.COM 1738334SJose.Borrego@Sun.COM if (as_uuid) { 1748334SJose.Borrego@Sun.COM if (svc->abstract_syntax_uuid == 0) 1758334SJose.Borrego@Sun.COM continue; 1768334SJose.Borrego@Sun.COM 1778334SJose.Borrego@Sun.COM if (svc->abstract_syntax_version != as_vers) 1788334SJose.Borrego@Sun.COM continue; 1798334SJose.Borrego@Sun.COM 1808334SJose.Borrego@Sun.COM if (strcasecmp(abstract_syntax, 1818334SJose.Borrego@Sun.COM svc->abstract_syntax_uuid)) 1828334SJose.Borrego@Sun.COM continue; 1838334SJose.Borrego@Sun.COM } 1848334SJose.Borrego@Sun.COM 1858334SJose.Borrego@Sun.COM if (ts_uuid) { 1868334SJose.Borrego@Sun.COM if (svc->transfer_syntax_uuid == 0) 1878334SJose.Borrego@Sun.COM continue; 1888334SJose.Borrego@Sun.COM 1898334SJose.Borrego@Sun.COM if (svc->transfer_syntax_version != ts_vers) 1908334SJose.Borrego@Sun.COM continue; 1918334SJose.Borrego@Sun.COM 1928334SJose.Borrego@Sun.COM if (strcasecmp(transfer_syntax, 1938334SJose.Borrego@Sun.COM svc->transfer_syntax_uuid)) 1948334SJose.Borrego@Sun.COM continue; 1958334SJose.Borrego@Sun.COM } 1968334SJose.Borrego@Sun.COM 1978334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 1988334SJose.Borrego@Sun.COM return (svc); 1998334SJose.Borrego@Sun.COM } 2008334SJose.Borrego@Sun.COM 2018334SJose.Borrego@Sun.COM ndo_printf(0, 0, "ndr_svc_lookup_uuid: unknown service"); 2028334SJose.Borrego@Sun.COM ndo_printf(0, 0, "abstract=%s v%d, transfer=%s v%d", 2038334SJose.Borrego@Sun.COM abstract_syntax, as_vers, transfer_syntax, ts_vers); 2048334SJose.Borrego@Sun.COM return (NULL); 2058334SJose.Borrego@Sun.COM } 2068334SJose.Borrego@Sun.COM 2075772Sas200622 /* 2085772Sas200622 * Allocate a handle for use with the server-side RPC functions. 2095772Sas200622 * 2105772Sas200622 * An arbitrary caller context can be associated with the handle 2115772Sas200622 * via data; it will not be dereferenced by the handle API. 2125772Sas200622 */ 2135772Sas200622 ndr_hdid_t * 2145772Sas200622 ndr_hdalloc(const ndr_xa_t *xa, const void *data) 2155772Sas200622 { 2168334SJose.Borrego@Sun.COM static ndr_hdid_t id; 2175772Sas200622 ndr_handle_t *hd; 2188334SJose.Borrego@Sun.COM uuid_t uu; 2195772Sas200622 2205772Sas200622 if ((hd = malloc(sizeof (ndr_handle_t))) == NULL) 2215772Sas200622 return (NULL); 2225772Sas200622 2238334SJose.Borrego@Sun.COM if (id.data2 == 0) { 2248334SJose.Borrego@Sun.COM uuid_generate_random(uu); 2258334SJose.Borrego@Sun.COM bcopy(uu, &id.data2, sizeof (uuid_t)); 2268334SJose.Borrego@Sun.COM id.data1 = 0; 2278334SJose.Borrego@Sun.COM id.data2 = 0; 2285772Sas200622 } 2295772Sas200622 2308334SJose.Borrego@Sun.COM ++id.data2; 2315772Sas200622 2328334SJose.Borrego@Sun.COM bcopy(&id, &hd->nh_id, sizeof (ndr_hdid_t)); 2335772Sas200622 hd->nh_fid = xa->fid; 2345772Sas200622 hd->nh_svc = xa->binding->service; 2355772Sas200622 hd->nh_data = (void *)data; 236*8474SJose.Borrego@Sun.COM hd->nh_data_free = NULL; 2375772Sas200622 2385772Sas200622 (void) mutex_lock(&ndr_handle_lock); 2395772Sas200622 hd->nh_next = ndr_handle_list; 2405772Sas200622 ndr_handle_list = hd; 2415772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 2425772Sas200622 2435772Sas200622 return (&hd->nh_id); 2445772Sas200622 } 2455772Sas200622 2465772Sas200622 /* 2475772Sas200622 * Remove a handle from the global list and free it. 2485772Sas200622 */ 2495772Sas200622 void 2505772Sas200622 ndr_hdfree(const ndr_xa_t *xa, const ndr_hdid_t *id) 2515772Sas200622 { 2528334SJose.Borrego@Sun.COM ndr_service_t *svc = xa->binding->service; 2535772Sas200622 ndr_handle_t *hd; 2545772Sas200622 ndr_handle_t **pphd; 2555772Sas200622 2565772Sas200622 assert(id); 2575772Sas200622 2585772Sas200622 (void) mutex_lock(&ndr_handle_lock); 2595772Sas200622 pphd = &ndr_handle_list; 2605772Sas200622 2615772Sas200622 while (*pphd) { 2625772Sas200622 hd = *pphd; 2635772Sas200622 2645772Sas200622 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 2655772Sas200622 if (hd->nh_svc == svc) { 2665772Sas200622 *pphd = hd->nh_next; 2675772Sas200622 free(hd); 2685772Sas200622 } 2695772Sas200622 break; 2705772Sas200622 } 2715772Sas200622 2725772Sas200622 pphd = &(*pphd)->nh_next; 2735772Sas200622 } 2745772Sas200622 2755772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 2765772Sas200622 } 2775772Sas200622 2785772Sas200622 /* 2795772Sas200622 * Lookup a handle by id. If the handle is in the list and it matches 2805772Sas200622 * the specified service, a pointer to it is returned. Otherwise a null 2815772Sas200622 * pointer is returned. 2825772Sas200622 */ 2835772Sas200622 ndr_handle_t * 2845772Sas200622 ndr_hdlookup(const ndr_xa_t *xa, const ndr_hdid_t *id) 2855772Sas200622 { 2868334SJose.Borrego@Sun.COM ndr_service_t *svc = xa->binding->service; 2875772Sas200622 ndr_handle_t *hd; 2885772Sas200622 2895772Sas200622 assert(id); 2905772Sas200622 (void) mutex_lock(&ndr_handle_lock); 2915772Sas200622 hd = ndr_handle_list; 2925772Sas200622 2935772Sas200622 while (hd) { 2945772Sas200622 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 2955772Sas200622 if (hd->nh_svc != svc) 2965772Sas200622 break; 2975772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 2985772Sas200622 return (hd); 2995772Sas200622 } 3005772Sas200622 3015772Sas200622 hd = hd->nh_next; 3025772Sas200622 } 3035772Sas200622 3045772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 3055772Sas200622 return (NULL); 3065772Sas200622 } 3075772Sas200622 3085772Sas200622 /* 3095772Sas200622 * Called when a pipe is closed to release any associated handles. 3105772Sas200622 */ 3115772Sas200622 void 3125772Sas200622 ndr_hdclose(int fid) 3135772Sas200622 { 3145772Sas200622 ndr_handle_t *hd; 3155772Sas200622 ndr_handle_t **pphd; 3165772Sas200622 3175772Sas200622 (void) mutex_lock(&ndr_handle_lock); 3185772Sas200622 pphd = &ndr_handle_list; 3195772Sas200622 3205772Sas200622 while (*pphd) { 3215772Sas200622 hd = *pphd; 3225772Sas200622 3235772Sas200622 if (hd->nh_fid == fid) { 3245772Sas200622 *pphd = hd->nh_next; 325*8474SJose.Borrego@Sun.COM 326*8474SJose.Borrego@Sun.COM if (hd->nh_data_free) 327*8474SJose.Borrego@Sun.COM (*hd->nh_data_free)(hd->nh_data); 328*8474SJose.Borrego@Sun.COM 3295772Sas200622 free(hd); 3305772Sas200622 continue; 3315772Sas200622 } 3325772Sas200622 3335772Sas200622 pphd = &(*pphd)->nh_next; 3345772Sas200622 } 3355772Sas200622 3365772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 3375772Sas200622 } 3385772Sas200622 3398334SJose.Borrego@Sun.COM /* 3408334SJose.Borrego@Sun.COM * Convert a UUID to a string. 3418334SJose.Borrego@Sun.COM */ 3425772Sas200622 void 3438334SJose.Borrego@Sun.COM ndr_uuid_unparse(ndr_uuid_t *uuid, char *out) 3445772Sas200622 { 3458334SJose.Borrego@Sun.COM (void) sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 3465772Sas200622 uuid->data1, uuid->data2, uuid->data3, 3475772Sas200622 uuid->data4[0], uuid->data4[1], 3485772Sas200622 uuid->data4[2], uuid->data4[3], 3495772Sas200622 uuid->data4[4], uuid->data4[5], 3505772Sas200622 uuid->data4[6], uuid->data4[7]); 3515772Sas200622 } 3525772Sas200622 3538334SJose.Borrego@Sun.COM /* 3548334SJose.Borrego@Sun.COM * Convert a string to a UUID. 3558334SJose.Borrego@Sun.COM */ 3565772Sas200622 int 3578334SJose.Borrego@Sun.COM ndr_uuid_parse(char *in, ndr_uuid_t *uuid) 3585772Sas200622 { 3598334SJose.Borrego@Sun.COM char *p = in; 3605772Sas200622 char *q; 3615772Sas200622 char buf[4]; 3625772Sas200622 int i; 3635772Sas200622 3648334SJose.Borrego@Sun.COM if (strlen(in) != UUID_PRINTABLE_STRING_LENGTH - 1) 3658334SJose.Borrego@Sun.COM return (-1); 3668334SJose.Borrego@Sun.COM 3675772Sas200622 uuid->data1 = strtoul(p, &p, 16); 3685772Sas200622 if (*p != '-') 3698334SJose.Borrego@Sun.COM return (-1); 3705772Sas200622 p++; 3715772Sas200622 3725772Sas200622 uuid->data2 = strtol(p, &p, 16); 3735772Sas200622 if (*p != '-') 3748334SJose.Borrego@Sun.COM return (-1); 3755772Sas200622 p++; 3765772Sas200622 3775772Sas200622 uuid->data3 = strtol(p, &p, 16); 3785772Sas200622 if (*p != '-') 3798334SJose.Borrego@Sun.COM return (-1); 3805772Sas200622 p++; 3815772Sas200622 3825772Sas200622 for (i = 0; i < 8; i++) { 3838334SJose.Borrego@Sun.COM if (*p == '-') 3848334SJose.Borrego@Sun.COM p++; 3858334SJose.Borrego@Sun.COM 3865772Sas200622 if (p[0] == 0 || p[1] == 0) 3878334SJose.Borrego@Sun.COM return (-1); 3885772Sas200622 3895772Sas200622 buf[0] = *p++; 3905772Sas200622 buf[1] = *p++; 3915772Sas200622 buf[2] = 0; 3925772Sas200622 uuid->data4[i] = strtol(buf, &q, 16); 3935772Sas200622 if (*q != 0) 3948334SJose.Borrego@Sun.COM return (-1); 3955772Sas200622 } 3965772Sas200622 3975772Sas200622 if (*p != 0) 3988334SJose.Borrego@Sun.COM return (-1); 3995772Sas200622 4008334SJose.Borrego@Sun.COM return (0); 4015772Sas200622 } 4025772Sas200622 4035772Sas200622 void 4048334SJose.Borrego@Sun.COM ndr_svc_binding_pool_init(ndr_binding_t **headpp, ndr_binding_t pool[], 4058334SJose.Borrego@Sun.COM int n_pool) 4065772Sas200622 { 4078334SJose.Borrego@Sun.COM ndr_binding_t *head = NULL; 4088334SJose.Borrego@Sun.COM int ix; 4095772Sas200622 4105772Sas200622 for (ix = n_pool - 1; ix >= 0; ix--) { 4115772Sas200622 pool[ix].next = head; 4125772Sas200622 pool[ix].service = NULL; 4135772Sas200622 pool[ix].p_cont_id = 0xffff; 4145772Sas200622 pool[ix].instance_specific = 0; 4155772Sas200622 head = &pool[ix]; 4165772Sas200622 } 4175772Sas200622 4185772Sas200622 *headpp = head; 4195772Sas200622 } 4205772Sas200622 4218334SJose.Borrego@Sun.COM ndr_binding_t * 4228334SJose.Borrego@Sun.COM ndr_svc_find_binding(ndr_xa_t *mxa, ndr_p_context_id_t p_cont_id) 4235772Sas200622 { 4248334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 4255772Sas200622 4265772Sas200622 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 4275772Sas200622 if (mbind->service != NULL && 4288334SJose.Borrego@Sun.COM mbind->which_side == NDR_BIND_SIDE_SERVER && 4295772Sas200622 mbind->p_cont_id == p_cont_id) 4305772Sas200622 break; 4315772Sas200622 } 4325772Sas200622 4335772Sas200622 return (mbind); 4345772Sas200622 } 4355772Sas200622 4368334SJose.Borrego@Sun.COM ndr_binding_t * 4378334SJose.Borrego@Sun.COM ndr_svc_new_binding(ndr_xa_t *mxa) 4385772Sas200622 { 4398334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 4405772Sas200622 4415772Sas200622 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 4425772Sas200622 if (mbind->service == NULL) 4435772Sas200622 break; 4445772Sas200622 } 4455772Sas200622 4465772Sas200622 return (mbind); 4475772Sas200622 } 4487052Samw 4497052Samw /* 4507052Samw * Move bytes between a buffer and a uio structure. 4517052Samw * The transfer direction is controlled by rw: 4527052Samw * UIO_READ: transfer from buf to uio 4537052Samw * UIO_WRITE: transfer from uio to buf 4547052Samw * 4557052Samw * Returns the number of bytes moved. 4567052Samw */ 4577052Samw ssize_t 4587052Samw ndr_uiomove(caddr_t buf, size_t buflen, enum uio_rw rw, struct uio *uio) 4597052Samw { 4607052Samw struct iovec *iov; 4617052Samw int reading = (rw == UIO_READ); 4627052Samw size_t nbytes; 4637052Samw size_t nxfer = 0; 4647052Samw 4657052Samw assert(rw == UIO_READ || rw == UIO_WRITE); 4667052Samw 4677052Samw while (buflen && uio->uio_resid && uio->uio_iovcnt) { 4687052Samw iov = uio->uio_iov; 4697052Samw if ((nbytes = iov->iov_len) == 0) { 4707052Samw uio->uio_iov++; 4717052Samw uio->uio_iovcnt--; 4727052Samw continue; 4737052Samw } 4747052Samw 4757052Samw if (nbytes > buflen) 4767052Samw nbytes = buflen; 4777052Samw 4787052Samw if (reading) 4797052Samw bcopy(buf, iov->iov_base, nbytes); 4807052Samw else 4817052Samw bcopy(iov->iov_base, buf, nbytes); 4827052Samw 4837052Samw iov->iov_base += nbytes; 4847052Samw iov->iov_len -= nbytes; 4857052Samw uio->uio_resid -= nbytes; 4867052Samw uio->uio_offset += nbytes; 4877052Samw buf += nbytes; 4887052Samw buflen -= nbytes; 4897052Samw nxfer += nbytes; 4907052Samw } 4917052Samw 4927052Samw return (nxfer); 4937052Samw } 494