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*7619SJose.Borrego@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 /* 275772Sas200622 * MLRPC heap management. The heap is used for temporary storage by 285772Sas200622 * both the client and server side library routines. In order to 295772Sas200622 * support the different requirements of the various RPCs, the heap 305772Sas200622 * can grow dynamically if required. We start with a single block 315772Sas200622 * and perform sub-allocations from it. If an RPC requires more space 325772Sas200622 * we will continue to add it a block at a time. This means that we 335772Sas200622 * don't hog lots of memory on every call to support the few times 345772Sas200622 * that we actually need a lot heap space. 355772Sas200622 * 365772Sas200622 * Note that there is no individual free function. Once space has been 375772Sas200622 * allocated, it remains allocated until the heap is destroyed. This 385772Sas200622 * shouldn't be an issue because the heap is being filled with data to 395772Sas200622 * be marshalled or unmarshalled and we need it all to be there until 405772Sas200622 * the point that the entire heap is no longer required. 415772Sas200622 */ 425772Sas200622 435772Sas200622 #include <sys/errno.h> 445772Sas200622 #include <stdlib.h> 455772Sas200622 #include <string.h> 465772Sas200622 #include <strings.h> 475772Sas200622 #include <sys/uio.h> 485772Sas200622 495772Sas200622 #include <smbsrv/libsmb.h> 505772Sas200622 #include <smbsrv/mlrpc.h> 515772Sas200622 525772Sas200622 /* 535772Sas200622 * Allocate a heap structure and the first heap block. For many RPC 545772Sas200622 * operations this will be the only time we need to malloc memory 555772Sas200622 * in this instance of the heap. The only point of note here is that 565772Sas200622 * we put the heap management data in the first block to avoid a 575772Sas200622 * second malloc. Make sure that sizeof(mlrpc_heap_t) is smaller 585772Sas200622 * than MLRPC_HEAP_BLKSZ. 595772Sas200622 * 605772Sas200622 * Note that the heap management data is at the start of the first block. 615772Sas200622 * 625772Sas200622 * Returns a pointer to the newly created heap, which is used like an 635772Sas200622 * opaque handle with the rest of the heap management interface.. 645772Sas200622 */ 655772Sas200622 mlrpc_heap_t * 665772Sas200622 mlrpc_heap_create(void) 675772Sas200622 { 685772Sas200622 mlrpc_heap_t *heap; 695772Sas200622 char *base; 705772Sas200622 715772Sas200622 if ((base = (char *)malloc(MLRPC_HEAP_BLKSZ)) == NULL) 725772Sas200622 return (NULL); 735772Sas200622 745772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 755772Sas200622 heap = (mlrpc_heap_t *)base; 765772Sas200622 bzero(heap, sizeof (mlrpc_heap_t)); 775772Sas200622 785772Sas200622 heap->iovcnt = MLRPC_HEAP_MAXIOV; 795772Sas200622 heap->iov = heap->iovec; 805772Sas200622 heap->iov->iov_base = base; 815772Sas200622 heap->iov->iov_len = sizeof (mlrpc_heap_t); 825772Sas200622 heap->top = base + MLRPC_HEAP_BLKSZ; 835772Sas200622 heap->next = base + sizeof (mlrpc_heap_t); 845772Sas200622 855772Sas200622 return (heap); 865772Sas200622 } 875772Sas200622 885772Sas200622 /* 895772Sas200622 * Deallocate all of the memory associated with a heap. This is the 905772Sas200622 * only way to deallocate heap memory, it isn't possible to free the 915772Sas200622 * space obtained by individual malloc calls. 925772Sas200622 * 935772Sas200622 * Note that the first block contains the heap management data, which 945772Sas200622 * is deleted last. 955772Sas200622 */ 965772Sas200622 void 975772Sas200622 mlrpc_heap_destroy(mlrpc_heap_t *heap) 985772Sas200622 { 995772Sas200622 int i; 1005772Sas200622 char *p; 1015772Sas200622 1025772Sas200622 if (heap) { 1035772Sas200622 for (i = 1; i < MLRPC_HEAP_MAXIOV; ++i) { 1045772Sas200622 if ((p = heap->iovec[i].iov_base) != NULL) 1055772Sas200622 free(p); 1065772Sas200622 } 1075772Sas200622 1085772Sas200622 free(heap); 1095772Sas200622 } 1105772Sas200622 } 1115772Sas200622 1125772Sas200622 /* 1135772Sas200622 * Allocate space in the specified heap. All requests are padded, if 1145772Sas200622 * required, to ensure dword alignment. If the current iov will be 1155772Sas200622 * exceeded, we allocate a new block and setup the next iov. Otherwise 1165772Sas200622 * all we have to do is move the next pointer and update the current 1175772Sas200622 * iov length. 1185772Sas200622 * 1195772Sas200622 * On success, a pointer to the allocated (dword aligned) area is 1205772Sas200622 * returned. Otherwise a null pointer is returned. 1215772Sas200622 */ 1225772Sas200622 void * 1235772Sas200622 mlrpc_heap_malloc(mlrpc_heap_t *heap, unsigned size) 1245772Sas200622 { 1255772Sas200622 char *p; 1265772Sas200622 int align; 1275772Sas200622 int incr_size; 1285772Sas200622 1295772Sas200622 align = (4 - size) & 3; 1305772Sas200622 size += align; 1315772Sas200622 1325772Sas200622 if (heap == NULL || size == 0) 1335772Sas200622 return (NULL); 1345772Sas200622 1355772Sas200622 p = heap->next; 1365772Sas200622 1375772Sas200622 if (p + size > heap->top) { 1385772Sas200622 if ((heap->iovcnt == 0) || ((--heap->iovcnt) == 0)) 1395772Sas200622 return (NULL); 1405772Sas200622 1415772Sas200622 incr_size = (size < MLRPC_HEAP_BLKSZ) ? MLRPC_HEAP_BLKSZ : size; 1425772Sas200622 1435772Sas200622 if ((p = (char *)malloc(incr_size)) == NULL) 1445772Sas200622 return (NULL); 1455772Sas200622 1465772Sas200622 ++heap->iov; 1475772Sas200622 heap->iov->iov_base = p; 1485772Sas200622 heap->iov->iov_len = 0; 1495772Sas200622 heap->top = p + incr_size; 1505772Sas200622 } 1515772Sas200622 1525772Sas200622 heap->next = p + size; 1535772Sas200622 heap->iov->iov_len += size; 1545772Sas200622 return ((void *)p); 1555772Sas200622 } 1565772Sas200622 1575772Sas200622 /* 1585772Sas200622 * Convenience function to do heap strdup. 1595772Sas200622 */ 1605772Sas200622 void * 1615772Sas200622 mlrpc_heap_strsave(mlrpc_heap_t *heap, char *s) 1625772Sas200622 { 1635772Sas200622 int len; 1645772Sas200622 void *p; 1655772Sas200622 1665772Sas200622 if (s == NULL) 1675772Sas200622 return (NULL); 1685772Sas200622 1695772Sas200622 /* 1705772Sas200622 * We don't need to clutter the heap with empty strings. 1715772Sas200622 */ 1725772Sas200622 if ((len = strlen(s)) == 0) 1735772Sas200622 return (""); 1745772Sas200622 1755772Sas200622 if ((p = mlrpc_heap_malloc(heap, len+1)) != NULL) 1765772Sas200622 (void) strcpy((char *)p, s); 1775772Sas200622 1785772Sas200622 return (p); 1795772Sas200622 } 1805772Sas200622 1815772Sas200622 /* 1825772Sas200622 * Our regular string marshalling always creates null terminated strings 1835772Sas200622 * but some Windows clients and servers are pedantic about the string 1845772Sas200622 * formats they will accept and require non-null terminated strings. 1855772Sas200622 * This function can be used to build a wide-char, non-null terminated 1865772Sas200622 * string in the heap as a varying/conformant array. We need to do the 1875772Sas200622 * wide-char conversion here because the marshalling code won't be 1885772Sas200622 * aware that this is really a string. 1895772Sas200622 */ 1905772Sas200622 void 191*7619SJose.Borrego@Sun.COM mlrpc_heap_mkvcs(mlrpc_heap_t *heap, char *s, mlrpc_vcstr_t *vc) 1925772Sas200622 { 1935772Sas200622 int mlen; 1945772Sas200622 195*7619SJose.Borrego@Sun.COM vc->wclen = mts_wcequiv_strlen(s); 196*7619SJose.Borrego@Sun.COM vc->wcsize = vc->wclen; 197*7619SJose.Borrego@Sun.COM 198*7619SJose.Borrego@Sun.COM mlen = sizeof (struct mlrpc_vcs) + vc->wcsize + sizeof (mts_wchar_t); 199*7619SJose.Borrego@Sun.COM 200*7619SJose.Borrego@Sun.COM vc->vcs = mlrpc_heap_malloc(heap, mlen); 2015772Sas200622 202*7619SJose.Borrego@Sun.COM if (vc->vcs) { 203*7619SJose.Borrego@Sun.COM vc->vcs->vc_first_is = 0; 204*7619SJose.Borrego@Sun.COM vc->vcs->vc_length_is = vc->wclen / sizeof (mts_wchar_t); 205*7619SJose.Borrego@Sun.COM (void) mts_mbstowcs((mts_wchar_t *)vc->vcs->buffer, s, 206*7619SJose.Borrego@Sun.COM vc->vcs->vc_length_is); 207*7619SJose.Borrego@Sun.COM } 208*7619SJose.Borrego@Sun.COM } 2095772Sas200622 210*7619SJose.Borrego@Sun.COM void 211*7619SJose.Borrego@Sun.COM mlrpc_heap_mkvcb(mlrpc_heap_t *heap, uint8_t *data, uint32_t datalen, 212*7619SJose.Borrego@Sun.COM mlrpc_vcbuf_t *vcbuf) 213*7619SJose.Borrego@Sun.COM { 214*7619SJose.Borrego@Sun.COM int mlen; 215*7619SJose.Borrego@Sun.COM 216*7619SJose.Borrego@Sun.COM if (data == NULL || datalen == 0) { 217*7619SJose.Borrego@Sun.COM bzero(vcbuf, sizeof (mlrpc_vcbuf_t)); 218*7619SJose.Borrego@Sun.COM return; 219*7619SJose.Borrego@Sun.COM } 2205772Sas200622 221*7619SJose.Borrego@Sun.COM vcbuf->len = datalen; 222*7619SJose.Borrego@Sun.COM vcbuf->size = datalen; 223*7619SJose.Borrego@Sun.COM 224*7619SJose.Borrego@Sun.COM mlen = sizeof (mlrpc_vcbuf_t) + datalen; 225*7619SJose.Borrego@Sun.COM 226*7619SJose.Borrego@Sun.COM vcbuf->vcb = mlrpc_heap_malloc(heap, mlen); 227*7619SJose.Borrego@Sun.COM 228*7619SJose.Borrego@Sun.COM if (vcbuf->vcb) { 229*7619SJose.Borrego@Sun.COM vcbuf->vcb->vc_first_is = 0; 230*7619SJose.Borrego@Sun.COM vcbuf->vcb->vc_length_is = datalen; 231*7619SJose.Borrego@Sun.COM bcopy(data, vcbuf->vcb->buffer, datalen); 2325772Sas200622 } 2335772Sas200622 } 2345772Sas200622 2355772Sas200622 int 2365772Sas200622 mlrpc_heap_used(mlrpc_heap_t *heap) 2375772Sas200622 { 2385772Sas200622 int used = 0; 2395772Sas200622 int i; 2405772Sas200622 2415772Sas200622 for (i = 0; i < MLRPC_HEAP_MAXIOV; ++i) 2425772Sas200622 used += heap->iovec[i].iov_len; 2435772Sas200622 2445772Sas200622 return (used); 2455772Sas200622 } 2465772Sas200622 2475772Sas200622 int 2485772Sas200622 mlrpc_heap_avail(mlrpc_heap_t *heap) 2495772Sas200622 { 2505772Sas200622 int avail; 2515772Sas200622 int count; 2525772Sas200622 2535772Sas200622 count = (heap->iovcnt == 0) ? 0 : (heap->iovcnt - 1); 2545772Sas200622 2555772Sas200622 avail = count * MLRPC_HEAP_BLKSZ; 2565772Sas200622 avail += (heap->top - heap->next); 2575772Sas200622 2585772Sas200622 return (avail); 2595772Sas200622 } 260