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 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 26*8334SJose.Borrego@Sun.COM #include <uuid/uuid.h> 27*8334SJose.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> 36*8334SJose.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 */ 51*8334SJose.Borrego@Sun.COM #define NDR_MAX_SERVICES 32 52*8334SJose.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 64*8334SJose.Borrego@Sun.COM ndr_svc_register(ndr_service_t *svc) 655772Sas200622 { 66*8334SJose.Borrego@Sun.COM ndr_service_t *p; 67*8334SJose.Borrego@Sun.COM int free_slot = -1; 68*8334SJose.Borrego@Sun.COM int i; 695772Sas200622 70*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 71*8334SJose.Borrego@Sun.COM if ((p = ndr_services[i]) == NULL) { 725772Sas200622 if (free_slot < 0) 735772Sas200622 free_slot = i; 745772Sas200622 continue; 755772Sas200622 } 765772Sas200622 77*8334SJose.Borrego@Sun.COM if (p == svc) 785772Sas200622 return (-1); 795772Sas200622 80*8334SJose.Borrego@Sun.COM if (strcasecmp(p->name, svc->name) == 0) 815772Sas200622 return (-2); 825772Sas200622 } 835772Sas200622 845772Sas200622 if (free_slot < 0) 855772Sas200622 return (-3); 865772Sas200622 87*8334SJose.Borrego@Sun.COM ndr_services[free_slot] = svc; 885772Sas200622 return (0); 895772Sas200622 } 905772Sas200622 915772Sas200622 void 92*8334SJose.Borrego@Sun.COM ndr_svc_unregister(ndr_service_t *svc) 935772Sas200622 { 945772Sas200622 int i; 955772Sas200622 96*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 97*8334SJose.Borrego@Sun.COM if (ndr_services[i] == svc) 98*8334SJose.Borrego@Sun.COM ndr_services[i] = NULL; 995772Sas200622 } 1005772Sas200622 } 1015772Sas200622 1025772Sas200622 int 103*8334SJose.Borrego@Sun.COM ndr_svc_list(char *buffer, int bufsize) 1045772Sas200622 { 105*8334SJose.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 111*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 112*8334SJose.Borrego@Sun.COM if ((svc = ndr_services[i]) != 0) { 1135772Sas200622 (void) smb_ctxbuf_printf(&ctx, "%-16s %s\n", 114*8334SJose.Borrego@Sun.COM svc->name, svc->desc); 1155772Sas200622 } 1165772Sas200622 } 1175772Sas200622 1185772Sas200622 return (smb_ctxbuf_len(&ctx)); 1195772Sas200622 } 1205772Sas200622 121*8334SJose.Borrego@Sun.COM ndr_stub_table_t * 122*8334SJose.Borrego@Sun.COM ndr_svc_find_stub(ndr_service_t *svc, int opnum) 123*8334SJose.Borrego@Sun.COM { 124*8334SJose.Borrego@Sun.COM ndr_stub_table_t *ste; 125*8334SJose.Borrego@Sun.COM 126*8334SJose.Borrego@Sun.COM for (ste = svc->stub_table; ste->func; ste++) { 127*8334SJose.Borrego@Sun.COM if (ste->opnum == opnum) 128*8334SJose.Borrego@Sun.COM return (ste); 129*8334SJose.Borrego@Sun.COM } 130*8334SJose.Borrego@Sun.COM 131*8334SJose.Borrego@Sun.COM return (NULL); 132*8334SJose.Borrego@Sun.COM } 133*8334SJose.Borrego@Sun.COM 134*8334SJose.Borrego@Sun.COM ndr_service_t * 135*8334SJose.Borrego@Sun.COM ndr_svc_lookup_name(const char *name) 136*8334SJose.Borrego@Sun.COM { 137*8334SJose.Borrego@Sun.COM ndr_service_t *svc; 138*8334SJose.Borrego@Sun.COM int i; 139*8334SJose.Borrego@Sun.COM 140*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 141*8334SJose.Borrego@Sun.COM if ((svc = ndr_services[i]) == NULL) 142*8334SJose.Borrego@Sun.COM continue; 143*8334SJose.Borrego@Sun.COM 144*8334SJose.Borrego@Sun.COM if (strcasecmp(name, svc->name) != 0) 145*8334SJose.Borrego@Sun.COM continue; 146*8334SJose.Borrego@Sun.COM 147*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 148*8334SJose.Borrego@Sun.COM return (svc); 149*8334SJose.Borrego@Sun.COM } 150*8334SJose.Borrego@Sun.COM 151*8334SJose.Borrego@Sun.COM return (NULL); 152*8334SJose.Borrego@Sun.COM } 153*8334SJose.Borrego@Sun.COM 154*8334SJose.Borrego@Sun.COM ndr_service_t * 155*8334SJose.Borrego@Sun.COM ndr_svc_lookup_uuid(ndr_uuid_t *as_uuid, int as_vers, 156*8334SJose.Borrego@Sun.COM ndr_uuid_t *ts_uuid, int ts_vers) 157*8334SJose.Borrego@Sun.COM { 158*8334SJose.Borrego@Sun.COM ndr_service_t *svc; 159*8334SJose.Borrego@Sun.COM char abstract_syntax[UUID_PRINTABLE_STRING_LENGTH]; 160*8334SJose.Borrego@Sun.COM char transfer_syntax[UUID_PRINTABLE_STRING_LENGTH]; 161*8334SJose.Borrego@Sun.COM int i; 162*8334SJose.Borrego@Sun.COM 163*8334SJose.Borrego@Sun.COM if (as_uuid) 164*8334SJose.Borrego@Sun.COM ndr_uuid_unparse(as_uuid, abstract_syntax); 165*8334SJose.Borrego@Sun.COM 166*8334SJose.Borrego@Sun.COM if (ts_uuid) 167*8334SJose.Borrego@Sun.COM ndr_uuid_unparse(ts_uuid, transfer_syntax); 168*8334SJose.Borrego@Sun.COM 169*8334SJose.Borrego@Sun.COM for (i = 0; i < NDR_MAX_SERVICES; i++) { 170*8334SJose.Borrego@Sun.COM if ((svc = ndr_services[i]) == NULL) 171*8334SJose.Borrego@Sun.COM continue; 172*8334SJose.Borrego@Sun.COM 173*8334SJose.Borrego@Sun.COM if (as_uuid) { 174*8334SJose.Borrego@Sun.COM if (svc->abstract_syntax_uuid == 0) 175*8334SJose.Borrego@Sun.COM continue; 176*8334SJose.Borrego@Sun.COM 177*8334SJose.Borrego@Sun.COM if (svc->abstract_syntax_version != as_vers) 178*8334SJose.Borrego@Sun.COM continue; 179*8334SJose.Borrego@Sun.COM 180*8334SJose.Borrego@Sun.COM if (strcasecmp(abstract_syntax, 181*8334SJose.Borrego@Sun.COM svc->abstract_syntax_uuid)) 182*8334SJose.Borrego@Sun.COM continue; 183*8334SJose.Borrego@Sun.COM } 184*8334SJose.Borrego@Sun.COM 185*8334SJose.Borrego@Sun.COM if (ts_uuid) { 186*8334SJose.Borrego@Sun.COM if (svc->transfer_syntax_uuid == 0) 187*8334SJose.Borrego@Sun.COM continue; 188*8334SJose.Borrego@Sun.COM 189*8334SJose.Borrego@Sun.COM if (svc->transfer_syntax_version != ts_vers) 190*8334SJose.Borrego@Sun.COM continue; 191*8334SJose.Borrego@Sun.COM 192*8334SJose.Borrego@Sun.COM if (strcasecmp(transfer_syntax, 193*8334SJose.Borrego@Sun.COM svc->transfer_syntax_uuid)) 194*8334SJose.Borrego@Sun.COM continue; 195*8334SJose.Borrego@Sun.COM } 196*8334SJose.Borrego@Sun.COM 197*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "%s %s", svc->name, svc->desc); 198*8334SJose.Borrego@Sun.COM return (svc); 199*8334SJose.Borrego@Sun.COM } 200*8334SJose.Borrego@Sun.COM 201*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "ndr_svc_lookup_uuid: unknown service"); 202*8334SJose.Borrego@Sun.COM ndo_printf(0, 0, "abstract=%s v%d, transfer=%s v%d", 203*8334SJose.Borrego@Sun.COM abstract_syntax, as_vers, transfer_syntax, ts_vers); 204*8334SJose.Borrego@Sun.COM return (NULL); 205*8334SJose.Borrego@Sun.COM } 206*8334SJose.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 { 216*8334SJose.Borrego@Sun.COM static ndr_hdid_t id; 2175772Sas200622 ndr_handle_t *hd; 218*8334SJose.Borrego@Sun.COM uuid_t uu; 2195772Sas200622 2205772Sas200622 if ((hd = malloc(sizeof (ndr_handle_t))) == NULL) 2215772Sas200622 return (NULL); 2225772Sas200622 223*8334SJose.Borrego@Sun.COM if (id.data2 == 0) { 224*8334SJose.Borrego@Sun.COM uuid_generate_random(uu); 225*8334SJose.Borrego@Sun.COM bcopy(uu, &id.data2, sizeof (uuid_t)); 226*8334SJose.Borrego@Sun.COM id.data1 = 0; 227*8334SJose.Borrego@Sun.COM id.data2 = 0; 2285772Sas200622 } 2295772Sas200622 230*8334SJose.Borrego@Sun.COM ++id.data2; 2315772Sas200622 232*8334SJose.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; 2365772Sas200622 2375772Sas200622 (void) mutex_lock(&ndr_handle_lock); 2385772Sas200622 hd->nh_next = ndr_handle_list; 2395772Sas200622 ndr_handle_list = hd; 2405772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 2415772Sas200622 2425772Sas200622 return (&hd->nh_id); 2435772Sas200622 } 2445772Sas200622 2455772Sas200622 /* 2465772Sas200622 * Remove a handle from the global list and free it. 2475772Sas200622 */ 2485772Sas200622 void 2495772Sas200622 ndr_hdfree(const ndr_xa_t *xa, const ndr_hdid_t *id) 2505772Sas200622 { 251*8334SJose.Borrego@Sun.COM ndr_service_t *svc = xa->binding->service; 2525772Sas200622 ndr_handle_t *hd; 2535772Sas200622 ndr_handle_t **pphd; 2545772Sas200622 2555772Sas200622 assert(id); 2565772Sas200622 2575772Sas200622 (void) mutex_lock(&ndr_handle_lock); 2585772Sas200622 pphd = &ndr_handle_list; 2595772Sas200622 2605772Sas200622 while (*pphd) { 2615772Sas200622 hd = *pphd; 2625772Sas200622 2635772Sas200622 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 2645772Sas200622 if (hd->nh_svc == svc) { 2655772Sas200622 *pphd = hd->nh_next; 2665772Sas200622 free(hd); 2675772Sas200622 } 2685772Sas200622 break; 2695772Sas200622 } 2705772Sas200622 2715772Sas200622 pphd = &(*pphd)->nh_next; 2725772Sas200622 } 2735772Sas200622 2745772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 2755772Sas200622 } 2765772Sas200622 2775772Sas200622 /* 2785772Sas200622 * Lookup a handle by id. If the handle is in the list and it matches 2795772Sas200622 * the specified service, a pointer to it is returned. Otherwise a null 2805772Sas200622 * pointer is returned. 2815772Sas200622 */ 2825772Sas200622 ndr_handle_t * 2835772Sas200622 ndr_hdlookup(const ndr_xa_t *xa, const ndr_hdid_t *id) 2845772Sas200622 { 285*8334SJose.Borrego@Sun.COM ndr_service_t *svc = xa->binding->service; 2865772Sas200622 ndr_handle_t *hd; 2875772Sas200622 2885772Sas200622 assert(id); 2895772Sas200622 (void) mutex_lock(&ndr_handle_lock); 2905772Sas200622 hd = ndr_handle_list; 2915772Sas200622 2925772Sas200622 while (hd) { 2935772Sas200622 if (bcmp(&hd->nh_id, id, sizeof (ndr_hdid_t)) == 0) { 2945772Sas200622 if (hd->nh_svc != svc) 2955772Sas200622 break; 2965772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 2975772Sas200622 return (hd); 2985772Sas200622 } 2995772Sas200622 3005772Sas200622 hd = hd->nh_next; 3015772Sas200622 } 3025772Sas200622 3035772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 3045772Sas200622 return (NULL); 3055772Sas200622 } 3065772Sas200622 3075772Sas200622 /* 3085772Sas200622 * Called when a pipe is closed to release any associated handles. 3095772Sas200622 */ 3105772Sas200622 void 3115772Sas200622 ndr_hdclose(int fid) 3125772Sas200622 { 3135772Sas200622 ndr_handle_t *hd; 3145772Sas200622 ndr_handle_t **pphd; 3155772Sas200622 3165772Sas200622 (void) mutex_lock(&ndr_handle_lock); 3175772Sas200622 pphd = &ndr_handle_list; 3185772Sas200622 3195772Sas200622 while (*pphd) { 3205772Sas200622 hd = *pphd; 3215772Sas200622 3225772Sas200622 if (hd->nh_fid == fid) { 3235772Sas200622 *pphd = hd->nh_next; 3245772Sas200622 free(hd); 3255772Sas200622 continue; 3265772Sas200622 } 3275772Sas200622 3285772Sas200622 pphd = &(*pphd)->nh_next; 3295772Sas200622 } 3305772Sas200622 3315772Sas200622 (void) mutex_unlock(&ndr_handle_lock); 3325772Sas200622 } 3335772Sas200622 334*8334SJose.Borrego@Sun.COM /* 335*8334SJose.Borrego@Sun.COM * Convert a UUID to a string. 336*8334SJose.Borrego@Sun.COM */ 3375772Sas200622 void 338*8334SJose.Borrego@Sun.COM ndr_uuid_unparse(ndr_uuid_t *uuid, char *out) 3395772Sas200622 { 340*8334SJose.Borrego@Sun.COM (void) sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 3415772Sas200622 uuid->data1, uuid->data2, uuid->data3, 3425772Sas200622 uuid->data4[0], uuid->data4[1], 3435772Sas200622 uuid->data4[2], uuid->data4[3], 3445772Sas200622 uuid->data4[4], uuid->data4[5], 3455772Sas200622 uuid->data4[6], uuid->data4[7]); 3465772Sas200622 } 3475772Sas200622 348*8334SJose.Borrego@Sun.COM /* 349*8334SJose.Borrego@Sun.COM * Convert a string to a UUID. 350*8334SJose.Borrego@Sun.COM */ 3515772Sas200622 int 352*8334SJose.Borrego@Sun.COM ndr_uuid_parse(char *in, ndr_uuid_t *uuid) 3535772Sas200622 { 354*8334SJose.Borrego@Sun.COM char *p = in; 3555772Sas200622 char *q; 3565772Sas200622 char buf[4]; 3575772Sas200622 int i; 3585772Sas200622 359*8334SJose.Borrego@Sun.COM if (strlen(in) != UUID_PRINTABLE_STRING_LENGTH - 1) 360*8334SJose.Borrego@Sun.COM return (-1); 361*8334SJose.Borrego@Sun.COM 3625772Sas200622 uuid->data1 = strtoul(p, &p, 16); 3635772Sas200622 if (*p != '-') 364*8334SJose.Borrego@Sun.COM return (-1); 3655772Sas200622 p++; 3665772Sas200622 3675772Sas200622 uuid->data2 = strtol(p, &p, 16); 3685772Sas200622 if (*p != '-') 369*8334SJose.Borrego@Sun.COM return (-1); 3705772Sas200622 p++; 3715772Sas200622 3725772Sas200622 uuid->data3 = strtol(p, &p, 16); 3735772Sas200622 if (*p != '-') 374*8334SJose.Borrego@Sun.COM return (-1); 3755772Sas200622 p++; 3765772Sas200622 3775772Sas200622 for (i = 0; i < 8; i++) { 378*8334SJose.Borrego@Sun.COM if (*p == '-') 379*8334SJose.Borrego@Sun.COM p++; 380*8334SJose.Borrego@Sun.COM 3815772Sas200622 if (p[0] == 0 || p[1] == 0) 382*8334SJose.Borrego@Sun.COM return (-1); 3835772Sas200622 3845772Sas200622 buf[0] = *p++; 3855772Sas200622 buf[1] = *p++; 3865772Sas200622 buf[2] = 0; 3875772Sas200622 uuid->data4[i] = strtol(buf, &q, 16); 3885772Sas200622 if (*q != 0) 389*8334SJose.Borrego@Sun.COM return (-1); 3905772Sas200622 } 3915772Sas200622 3925772Sas200622 if (*p != 0) 393*8334SJose.Borrego@Sun.COM return (-1); 3945772Sas200622 395*8334SJose.Borrego@Sun.COM return (0); 3965772Sas200622 } 3975772Sas200622 3985772Sas200622 void 399*8334SJose.Borrego@Sun.COM ndr_svc_binding_pool_init(ndr_binding_t **headpp, ndr_binding_t pool[], 400*8334SJose.Borrego@Sun.COM int n_pool) 4015772Sas200622 { 402*8334SJose.Borrego@Sun.COM ndr_binding_t *head = NULL; 403*8334SJose.Borrego@Sun.COM int ix; 4045772Sas200622 4055772Sas200622 for (ix = n_pool - 1; ix >= 0; ix--) { 4065772Sas200622 pool[ix].next = head; 4075772Sas200622 pool[ix].service = NULL; 4085772Sas200622 pool[ix].p_cont_id = 0xffff; 4095772Sas200622 pool[ix].instance_specific = 0; 4105772Sas200622 head = &pool[ix]; 4115772Sas200622 } 4125772Sas200622 4135772Sas200622 *headpp = head; 4145772Sas200622 } 4155772Sas200622 416*8334SJose.Borrego@Sun.COM ndr_binding_t * 417*8334SJose.Borrego@Sun.COM ndr_svc_find_binding(ndr_xa_t *mxa, ndr_p_context_id_t p_cont_id) 4185772Sas200622 { 419*8334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 4205772Sas200622 4215772Sas200622 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 4225772Sas200622 if (mbind->service != NULL && 423*8334SJose.Borrego@Sun.COM mbind->which_side == NDR_BIND_SIDE_SERVER && 4245772Sas200622 mbind->p_cont_id == p_cont_id) 4255772Sas200622 break; 4265772Sas200622 } 4275772Sas200622 4285772Sas200622 return (mbind); 4295772Sas200622 } 4305772Sas200622 431*8334SJose.Borrego@Sun.COM ndr_binding_t * 432*8334SJose.Borrego@Sun.COM ndr_svc_new_binding(ndr_xa_t *mxa) 4335772Sas200622 { 434*8334SJose.Borrego@Sun.COM ndr_binding_t *mbind; 4355772Sas200622 4365772Sas200622 for (mbind = mxa->binding_list; mbind; mbind = mbind->next) { 4375772Sas200622 if (mbind->service == NULL) 4385772Sas200622 break; 4395772Sas200622 } 4405772Sas200622 4415772Sas200622 return (mbind); 4425772Sas200622 } 4437052Samw 4447052Samw /* 4457052Samw * Move bytes between a buffer and a uio structure. 4467052Samw * The transfer direction is controlled by rw: 4477052Samw * UIO_READ: transfer from buf to uio 4487052Samw * UIO_WRITE: transfer from uio to buf 4497052Samw * 4507052Samw * Returns the number of bytes moved. 4517052Samw */ 4527052Samw ssize_t 4537052Samw ndr_uiomove(caddr_t buf, size_t buflen, enum uio_rw rw, struct uio *uio) 4547052Samw { 4557052Samw struct iovec *iov; 4567052Samw int reading = (rw == UIO_READ); 4577052Samw size_t nbytes; 4587052Samw size_t nxfer = 0; 4597052Samw 4607052Samw assert(rw == UIO_READ || rw == UIO_WRITE); 4617052Samw 4627052Samw while (buflen && uio->uio_resid && uio->uio_iovcnt) { 4637052Samw iov = uio->uio_iov; 4647052Samw if ((nbytes = iov->iov_len) == 0) { 4657052Samw uio->uio_iov++; 4667052Samw uio->uio_iovcnt--; 4677052Samw continue; 4687052Samw } 4697052Samw 4707052Samw if (nbytes > buflen) 4717052Samw nbytes = buflen; 4727052Samw 4737052Samw if (reading) 4747052Samw bcopy(buf, iov->iov_base, nbytes); 4757052Samw else 4767052Samw bcopy(iov->iov_base, buf, nbytes); 4777052Samw 4787052Samw iov->iov_base += nbytes; 4797052Samw iov->iov_len -= nbytes; 4807052Samw uio->uio_resid -= nbytes; 4817052Samw uio->uio_offset += nbytes; 4827052Samw buf += nbytes; 4837052Samw buflen -= nbytes; 4847052Samw nxfer += nbytes; 4857052Samw } 4867052Samw 4877052Samw return (nxfer); 4887052Samw } 489