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 /* 22*f96bd5c8SAlan Wright * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw /* 27da6c28aaSamw * SMB mbuf marshaling encode/decode. 28da6c28aaSamw */ 29da6c28aaSamw 30bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 31e3f2c991SKeyur Desai 32e3f2c991SKeyur Desai 33da6c28aaSamw #define MALLOC_QUANTUM 80 34da6c28aaSamw 35da6c28aaSamw #define DECODE_NO_ERROR 0 36da6c28aaSamw #define DECODE_NO_MORE_DATA 1 37da6c28aaSamw #define DECODE_ALLOCATION_ERROR 2 38da6c28aaSamw #define DECODE_CONVERSION_ERROR 3 39da6c28aaSamw 40e3f2c991SKeyur Desai static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t); 413db3f65cSamw static int mbc_marshal_make_room(mbuf_chain_t *, int32_t); 423db3f65cSamw static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t); 433db3f65cSamw static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t); 443db3f65cSamw static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t); 453db3f65cSamw static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t); 463db3f65cSamw static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t); 473db3f65cSamw static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int); 483db3f65cSamw static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int); 493db3f65cSamw static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *); 503db3f65cSamw static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m); 513db3f65cSamw static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc); 523db3f65cSamw static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc); 533db3f65cSamw static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data); 543db3f65cSamw static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data); 553db3f65cSamw static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data); 563db3f65cSamw static uint64_t qswap(uint64_t ll); 573db3f65cSamw static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data); 583db3f65cSamw static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data); 59bbf6f00cSJordan Brown static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *, 60bbf6f00cSJordan Brown uint8_t **ascii, int); 61bbf6f00cSJordan Brown static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *, 62bbf6f00cSJordan Brown uint8_t **, int); 633db3f65cSamw static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **); 643db3f65cSamw static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *); 653db3f65cSamw static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *); 663db3f65cSamw static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t); 67da6c28aaSamw 68da6c28aaSamw /* 693db3f65cSamw * smb_mbc_vdecodef 70da6c28aaSamw * 713db3f65cSamw * This function reads the contents of the mbc chain passed in under the list 723db3f65cSamw * of arguments passed in. 73da6c28aaSamw * 74da6c28aaSamw * The format string provides a description of the parameters passed in as well 753db3f65cSamw * as an action to be taken by smb_mbc_vdecodef(). 76da6c28aaSamw * 77da6c28aaSamw * % Pointer to an SMB request structure (smb_request_t *). There 78da6c28aaSamw * should be only one of these in the string. 79da6c28aaSamw * 80da6c28aaSamw * C Pointer to an mbuf chain. Copy to that mbuf chain the number of 81da6c28aaSamw * bytes specified (number preceding C). 82da6c28aaSamw * 83da6c28aaSamw * m Pointer to an mbuf. Copy to that mbuf the number of bytes 84da6c28aaSamw * specified (number preceding m). 85da6c28aaSamw * 86da6c28aaSamw * M Read the 32 bit value at the current location of the mbuf chain 87da6c28aaSamw * and check if it matches the signature of an SMB request (SMBX). 88da6c28aaSamw * 89da6c28aaSamw * b Pointer to a buffer. Copy to that buffer the number of bytes 90da6c28aaSamw * specified (number preceding b). 91da6c28aaSamw * 92da6c28aaSamw * c Same as 'b'. 93da6c28aaSamw * 94da6c28aaSamw * w Pointer to a word (16bit value). Copy the next 16bit value into 95da6c28aaSamw * that location. 96da6c28aaSamw * 97da6c28aaSamw * l Pointer to a long (32bit value). Copy the next 32bit value into 98da6c28aaSamw * that location. 99da6c28aaSamw * 100da6c28aaSamw * q Pointer to a quad (64bit value). Copy the next 64bit value into 101da6c28aaSamw * that location. 102da6c28aaSamw * 103da6c28aaSamw * Q Same as above with a call to qswap(). 104da6c28aaSamw * 105da6c28aaSamw * B Pointer to a vardata_block structure. That structure is used to 106da6c28aaSamw * retrieve data from the mbuf chain (an iovec type structure is 107da6c28aaSamw * embedded in a vardata_block). 108da6c28aaSamw * 109da6c28aaSamw * D Pointer to a vardata_block structure. That structure is used to 110da6c28aaSamw * retrieve data from the mbuf chain, however, two fields of the 111da6c28aaSamw * vardata_block structure (tag and len) are first initialized 112da6c28aaSamw * using the mbuf chain itself. 113da6c28aaSamw * 114da6c28aaSamw * V Same as 'D'. 115da6c28aaSamw * 116da6c28aaSamw * L 117da6c28aaSamw * 118da6c28aaSamw * A 119da6c28aaSamw * 120da6c28aaSamw * P Same as 'A' 121da6c28aaSamw * 122da6c28aaSamw * S Same as 'A' 123da6c28aaSamw * 124da6c28aaSamw * u Pointer to a string pointer. Allocate memory and retrieve the 125da6c28aaSamw * string at the current location in the mbuf chain. Store the 126da6c28aaSamw * address to the buffer allocated at the address specified by 127da6c28aaSamw * the pointer. In addition if an sr was passed and it indicates 128da6c28aaSamw * that the string is an unicode string, convert it. 129da6c28aaSamw * 130da6c28aaSamw * s Same as 'u' without convertion. 131da6c28aaSamw * 132da6c28aaSamw * U Same as 'u'. The string to retrieve is unicode. 133da6c28aaSamw * 134da6c28aaSamw * y Pointer to a 32bit value. Read the dos time at the current mbuf 135da6c28aaSamw * chain location, convert it to unix time and store it at the 136da6c28aaSamw * location indicated by the pointer. 137da6c28aaSamw * 138da6c28aaSamw * Y Same as 'y' bt the dos time coded in the mbuf chain is inverted. 139da6c28aaSamw * 140da6c28aaSamw * . Skip the number of bytes indicated by the number preceding '.'. 141da6c28aaSamw * 142da6c28aaSamw * , Same as '.' but take in account it is an unicode string. 143da6c28aaSamw */ 144da6c28aaSamw int 1453db3f65cSamw smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 146da6c28aaSamw { 1473db3f65cSamw uint8_t c; 1483db3f65cSamw uint8_t cval; 1493db3f65cSamw uint8_t *cvalp; 1503db3f65cSamw uint8_t **cvalpp; 1512c2961f8Sjose borrego uint16_t wval; 1523db3f65cSamw uint16_t *wvalp; 153da6c28aaSamw uint32_t *lvalp; 154da6c28aaSamw uint64_t *llvalp; 1553db3f65cSamw smb_vdb_t *vdp; 1563db3f65cSamw smb_request_t *sr = NULL; 157da6c28aaSamw uint32_t lval; 158da6c28aaSamw int unicode = 0; 159da6c28aaSamw int repc; 160da6c28aaSamw 161da6c28aaSamw while ((c = *fmt++) != 0) { 162da6c28aaSamw repc = 1; 163da6c28aaSamw 164da6c28aaSamw if ('0' <= c && c <= '9') { 165da6c28aaSamw repc = 0; 166da6c28aaSamw do { 167da6c28aaSamw repc = repc * 10 + c - '0'; 168da6c28aaSamw c = *fmt++; 169da6c28aaSamw } while ('0' <= c && c <= '9'); 170da6c28aaSamw } else if (c == '#') { 171da6c28aaSamw repc = va_arg(ap, int); 172da6c28aaSamw c = *fmt++; 173da6c28aaSamw } 174da6c28aaSamw 175da6c28aaSamw switch (c) { 176da6c28aaSamw case '%': 177da6c28aaSamw sr = va_arg(ap, struct smb_request *); 178da6c28aaSamw unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 179da6c28aaSamw break; 180da6c28aaSamw 181da6c28aaSamw case 'C': /* Mbuf_chain */ 182da6c28aaSamw if (mbc_marshal_get_mbuf_chain(mbc, repc, 1833db3f65cSamw va_arg(ap, mbuf_chain_t *)) != 0) 1843db3f65cSamw return (-1); 185da6c28aaSamw break; 186da6c28aaSamw 187da6c28aaSamw case 'm': /* struct_mbuf */ 188da6c28aaSamw if (mbc_marshal_get_mbufs(mbc, repc, 1893db3f65cSamw va_arg(ap, mbuf_t **)) != 0) 1903db3f65cSamw return (-1); 191da6c28aaSamw break; 192da6c28aaSamw 193da6c28aaSamw case 'M': 1943db3f65cSamw if (mbc_marshal_get_long(mbc, &lval) != 0) 195da6c28aaSamw /* Data will never be available */ 1963db3f65cSamw return (-1); 1973db3f65cSamw 198da6c28aaSamw if (lval != 0x424D53FF) /* 0xFF S M B */ 1993db3f65cSamw return (-1); 200da6c28aaSamw break; 201da6c28aaSamw 202da6c28aaSamw case 'b': 203da6c28aaSamw case 'c': 2043db3f65cSamw cvalp = va_arg(ap, uint8_t *); 2053db3f65cSamw if (MBC_ROOM_FOR(mbc, repc) == 0) 206da6c28aaSamw /* Data will never be available */ 2073db3f65cSamw return (-1); 2083db3f65cSamw 209da6c28aaSamw while (repc-- > 0) 210da6c28aaSamw *cvalp++ = mbc_marshal_fetch_byte(mbc); 211da6c28aaSamw break; 212da6c28aaSamw 213da6c28aaSamw case 'w': 2143db3f65cSamw wvalp = va_arg(ap, uint16_t *); 215da6c28aaSamw while (repc-- > 0) 216da6c28aaSamw if (mbc_marshal_get_short(mbc, wvalp++) != 0) 2173db3f65cSamw return (-1); 218da6c28aaSamw break; 219da6c28aaSamw 220da6c28aaSamw case 'l': 221da6c28aaSamw lvalp = va_arg(ap, uint32_t *); 222da6c28aaSamw while (repc-- > 0) 223da6c28aaSamw if (mbc_marshal_get_long(mbc, lvalp++) != 0) 2243db3f65cSamw return (-1); 225da6c28aaSamw break; 226da6c28aaSamw 227da6c28aaSamw case 'q': 228da6c28aaSamw llvalp = va_arg(ap, uint64_t *); 229da6c28aaSamw while (repc-- > 0) 230da6c28aaSamw if (mbc_marshal_get_long_long( 231da6c28aaSamw mbc, llvalp++) != 0) 2323db3f65cSamw return (-1); 233da6c28aaSamw break; 234da6c28aaSamw 235da6c28aaSamw case 'Q': 236da6c28aaSamw llvalp = va_arg(ap, uint64_t *); 237da6c28aaSamw while (repc-- > 0) 238da6c28aaSamw if (mbc_marshal_get_odd_long_long( 239da6c28aaSamw mbc, llvalp++) != 0) 2403db3f65cSamw return (-1); 241da6c28aaSamw break; 242da6c28aaSamw 243da6c28aaSamw case 'B': 244da6c28aaSamw vdp = va_arg(ap, struct vardata_block *); 2452c2961f8Sjose borrego vdp->vdb_tag = 0; 2462c2961f8Sjose borrego vdp->vdb_len = repc; 2472c2961f8Sjose borrego vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; 2482c2961f8Sjose borrego vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; 249*f96bd5c8SAlan Wright vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 2502c2961f8Sjose borrego vdp->vdb_uio.uio_resid = repc; 2512c2961f8Sjose borrego if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0) 2523db3f65cSamw return (-1); 253da6c28aaSamw break; 254da6c28aaSamw 2553db3f65cSamw case 'D': 2563db3f65cSamw case 'V': 257da6c28aaSamw vdp = va_arg(ap, struct vardata_block *); 2582c2961f8Sjose borrego if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0) 2593db3f65cSamw return (-1); 2602c2961f8Sjose borrego if (mbc_marshal_get_short(mbc, &wval) != 0) 2613db3f65cSamw return (-1); 2622c2961f8Sjose borrego vdp->vdb_len = (uint32_t)wval; 2632c2961f8Sjose borrego vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0]; 2642c2961f8Sjose borrego vdp->vdb_uio.uio_iovcnt = MAX_IOVEC; 265*f96bd5c8SAlan Wright vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 2662c2961f8Sjose borrego vdp->vdb_uio.uio_resid = vdp->vdb_len; 2672c2961f8Sjose borrego if (vdp->vdb_len != 0) { 2682c2961f8Sjose borrego if (mbc_marshal_get_uio(mbc, 2692c2961f8Sjose borrego &vdp->vdb_uio) != 0) 2703db3f65cSamw return (-1); 271da6c28aaSamw } 272da6c28aaSamw break; 273da6c28aaSamw 274da6c28aaSamw case 'L': 275da6c28aaSamw if (mbc_marshal_get_char(mbc, &cval) != 0) 2763db3f65cSamw return (-1); 277da6c28aaSamw if (cval != 2) 2783db3f65cSamw return (-1); 279da6c28aaSamw goto ascii_conversion; 280da6c28aaSamw 2813db3f65cSamw case 'A': 2823db3f65cSamw case 'S': 283da6c28aaSamw if (mbc_marshal_get_char(mbc, &cval) != 0) 2843db3f65cSamw return (-1); 285da6c28aaSamw if (((c == 'A' || c == 'S') && cval != 4) || 2863db3f65cSamw (c == 'L' && cval != 2)) 2873db3f65cSamw return (-1); 288da6c28aaSamw /* FALLTHROUGH */ 289da6c28aaSamw 290da6c28aaSamw case 'u': /* Convert from unicode if flags are set */ 291da6c28aaSamw if (unicode) 292da6c28aaSamw goto unicode_translation; 293da6c28aaSamw /* FALLTHROUGH */ 294da6c28aaSamw 295da6c28aaSamw case 's': 296da6c28aaSamw ascii_conversion: 297da6c28aaSamw ASSERT(sr != NULL); 2983db3f65cSamw cvalpp = va_arg(ap, uint8_t **); 299da6c28aaSamw if (repc <= 1) 300da6c28aaSamw repc = 0; 301bbf6f00cSJordan Brown if (mbc_marshal_get_ascii_string(sr, 302da6c28aaSamw mbc, cvalpp, repc) != 0) 3033db3f65cSamw return (-1); 304da6c28aaSamw break; 305da6c28aaSamw 306da6c28aaSamw case 'U': /* Convert from unicode */ 307da6c28aaSamw unicode_translation: 308da6c28aaSamw ASSERT(sr != 0); 3093db3f65cSamw cvalpp = va_arg(ap, uint8_t **); 310da6c28aaSamw if (repc <= 1) 311da6c28aaSamw repc = 0; 312da6c28aaSamw if (mbc->chain_offset & 1) 313da6c28aaSamw mbc->chain_offset++; 314bbf6f00cSJordan Brown if (mbc_marshal_get_unicode_string(sr, 315da6c28aaSamw mbc, cvalpp, repc) != 0) 3163db3f65cSamw return (-1); 317da6c28aaSamw break; 318da6c28aaSamw 319da6c28aaSamw case 'Y': /* dos time to unix time tt/dd */ 320da6c28aaSamw lvalp = va_arg(ap, uint32_t *); 321da6c28aaSamw while (repc-- > 0) { 322da6c28aaSamw short d, t; 323da6c28aaSamw 324da6c28aaSamw if (mbc_marshal_get_short(mbc, 3253db3f65cSamw (uint16_t *)&t) != 0) 3263db3f65cSamw return (-1); 327da6c28aaSamw if (mbc_marshal_get_short(mbc, 3283db3f65cSamw (uint16_t *)&d) != 0) 3293db3f65cSamw return (-1); 330e3f2c991SKeyur Desai *lvalp++ = smb_time_dos_to_unix(d, t); 331da6c28aaSamw } 332da6c28aaSamw break; 333da6c28aaSamw 334da6c28aaSamw case 'y': /* dos time to unix time dd/tt */ 335da6c28aaSamw lvalp = va_arg(ap, uint32_t *); 336da6c28aaSamw while (repc-- > 0) { 337da6c28aaSamw short d, t; 338da6c28aaSamw 339da6c28aaSamw if (mbc_marshal_get_short(mbc, 3403db3f65cSamw (uint16_t *)&d) != 0) 3413db3f65cSamw return (-1); 342da6c28aaSamw if (mbc_marshal_get_short(mbc, 3433db3f65cSamw (uint16_t *)&t) != 0) 3443db3f65cSamw return (-1); 345e3f2c991SKeyur Desai *lvalp++ = smb_time_dos_to_unix(d, t); 346da6c28aaSamw } 347da6c28aaSamw break; 348da6c28aaSamw 349da6c28aaSamw case ',': 350da6c28aaSamw if (unicode) 351da6c28aaSamw repc *= 2; 352da6c28aaSamw /* FALLTHROUGH */ 353da6c28aaSamw 354da6c28aaSamw case '.': 355da6c28aaSamw if (mbc_marshal_get_skip(mbc, repc) != 0) 3563db3f65cSamw return (-1); 357da6c28aaSamw break; 3583db3f65cSamw 3593db3f65cSamw default: 3603db3f65cSamw ASSERT(0); 3613db3f65cSamw return (-1); 362da6c28aaSamw } 363da6c28aaSamw } 364da6c28aaSamw return (0); 365da6c28aaSamw } 366da6c28aaSamw 3673db3f65cSamw /* 3683db3f65cSamw * smb_mbc_decodef 3693db3f65cSamw * 3703db3f65cSamw * This function reads the contents of the mbc chain passed in under the 3713db3f65cSamw * control of the format fmt. 3723db3f65cSamw * 3733db3f65cSamw * (for a description of the format string see smb_mbc_vencodef()). 3743db3f65cSamw */ 375da6c28aaSamw int 3763db3f65cSamw smb_mbc_decodef(mbuf_chain_t *mbc, char *fmt, ...) 377da6c28aaSamw { 378da6c28aaSamw int xx; 379da6c28aaSamw va_list ap; 380da6c28aaSamw 381da6c28aaSamw va_start(ap, fmt); 3823db3f65cSamw xx = smb_mbc_vdecodef(mbc, fmt, ap); 383da6c28aaSamw va_end(ap); 384da6c28aaSamw return (xx); 385da6c28aaSamw } 386da6c28aaSamw 3873db3f65cSamw /* 3883db3f65cSamw * smb_mbc_peek 3893db3f65cSamw * 3903db3f65cSamw * This function reads the contents of the mbc passed in at the specified offset 3913db3f65cSamw * under the control of the format fmt. The offset of the chain passed in is not 3923db3f65cSamw * modified. 3933db3f65cSamw * 3943db3f65cSamw * (for a description of the format string see smb_mbc_vdecodef()). 3953db3f65cSamw */ 396da6c28aaSamw int 3973db3f65cSamw smb_mbc_peek(mbuf_chain_t *mbc, int offset, char *fmt, ...) 398da6c28aaSamw { 3993db3f65cSamw mbuf_chain_t tmp; 400da6c28aaSamw va_list ap; 4013db3f65cSamw int xx; 402da6c28aaSamw 403da6c28aaSamw va_start(ap, fmt); 404da6c28aaSamw 4053db3f65cSamw (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 4063db3f65cSamw xx = smb_mbc_vdecodef(&tmp, fmt, ap); 407da6c28aaSamw va_end(ap); 4083db3f65cSamw return (xx); 409da6c28aaSamw } 410da6c28aaSamw 411da6c28aaSamw /* 4123db3f65cSamw * smb_mbc_vencodef 4133db3f65cSamw * 4143db3f65cSamw * This function builds a stream of bytes in the mbc chain passed in under the 4153db3f65cSamw * control of the list of arguments passed in. 416da6c28aaSamw * 417da6c28aaSamw * The format string provides a description of the parameters passed in as well 4183db3f65cSamw * as an action to be taken by smb_mbc_vencodef(). 419da6c28aaSamw * 420da6c28aaSamw * \b Restore the mbuf chain offset to its initial value. 421da6c28aaSamw * 422da6c28aaSamw * % Pointer to an SMB request structure (smb_request_t *). There 423da6c28aaSamw * should be only one of these in the string. If an sr in present 424da6c28aaSamw * it will be used to determine if unicode conversion should be 425da6c28aaSamw * applied to the strings. 426da6c28aaSamw * 427da6c28aaSamw * C Pointer to an mbuf chain. Copy that mbuf chain into the 428da6c28aaSamw * destination mbuf chain. 429da6c28aaSamw * 430da6c28aaSamw * D Pointer to a vardata_block structure. Copy the data described 431da6c28aaSamw * by that structure into the mbuf chain. The tag field is hard 432da6c28aaSamw * coded to '1'. 433da6c28aaSamw * 434da6c28aaSamw * M Write the SMB request signature ('SMBX') into the mbuf chain. 435da6c28aaSamw * 436da6c28aaSamw * T Pointer to a timestruc_t. Convert the content of the structure 437da6c28aaSamw * into NT time and store the result of the conversion in the 438da6c28aaSamw * mbuf chain. 439da6c28aaSamw * 440da6c28aaSamw * V Same as 'D' but the tag field is hard coded to '5'. 441da6c28aaSamw * 442da6c28aaSamw * b Byte. Store the byte or the nymber of bytes specified into the 443da6c28aaSamw * the mbuf chain. A format string like this "2b" would require 2 444da6c28aaSamw * bytes to be passed in. 445da6c28aaSamw * 446da6c28aaSamw * m Pointer to an mbuf. Copy the contents of the mbuf into the mbuf 447da6c28aaSamw * chain. 448da6c28aaSamw * 449da6c28aaSamw * c Pointer to a buffer. Copy the buffer into the mbuf chain. The 450da6c28aaSamw * size of the buffer is indicated by the number preceding 'c'. 451da6c28aaSamw * 452da6c28aaSamw * w Word (16bit value). Store the word or the number of words 453da6c28aaSamw * specified into the the mbuf chain. A format string like this 454da6c28aaSamw * "2w" would require 2 words to be passed in. 455da6c28aaSamw * 456da6c28aaSamw * l Long (32bit value). Store the long or the number of longs 457da6c28aaSamw * specified into the the mbuf chain. A format string like this 458da6c28aaSamw * "2l" would require 2 longs to be passed in. 459da6c28aaSamw * 460da6c28aaSamw * q Quad (64bit value). Store the quad or the number of quads 461da6c28aaSamw * specified into the the mbuf chain. A format string like this 462da6c28aaSamw * "2q" would require 2 quads to be passed in. 463da6c28aaSamw * 464da6c28aaSamw * L Pointer to a string. Store the string passed in into the mbuf 465da6c28aaSamw * chain preceded with a tag value of '2'. 466da6c28aaSamw * 467da6c28aaSamw * S Pointer to a string. Store the string passed in into the mbuf 468da6c28aaSamw * chain preceded with a tag value of '4'. Applied a unicode 469da6c28aaSamw * conversion is appropriate. 470da6c28aaSamw * 471da6c28aaSamw * A Same as 'S' 472da6c28aaSamw * 473da6c28aaSamw * P Pointer to a string. Store the string passed in into the mbuf 474da6c28aaSamw * chain preceded with a tag value of '5'. Applied a unicode 475da6c28aaSamw * conversion is appropriate. 476da6c28aaSamw * 477da6c28aaSamw * u Pointer to a string. Store the string passed in into the mbuf 478da6c28aaSamw * chain. Applied a unicode conversion is appropriate. 479da6c28aaSamw * 480da6c28aaSamw * s Pointer to a string. Store the string passed in into the mbuf 481da6c28aaSamw * chain. 482da6c28aaSamw * 483da6c28aaSamw * Y Date/Time. Store the Date/Time or the number of Date/Time(s) 484da6c28aaSamw * specified into the the mbuf chain. A format string like this 485da6c28aaSamw * "2Y" would require 2 Date/Time values. The Date/Time is 486da6c28aaSamw * converted to DOS before storing. 487da6c28aaSamw * 488da6c28aaSamw * y Same as 'Y'. The order of Date and Time is reversed. 489da6c28aaSamw * 490da6c28aaSamw * , Character. Store the character or number of character specified 491da6c28aaSamw * into the mbuf chain. A format string like this "2c" would 492da6c28aaSamw * require 2 characters to be passed in. A unicode conversion is 493da6c28aaSamw * applied if appropriate. 494da6c28aaSamw * 495da6c28aaSamw * . Same as '`' without unicode conversion. 496da6c28aaSamw * 497da6c28aaSamw * U Align the offset of the mbuf chain on a 16bit boundary. 498da6c28aaSamw */ 499da6c28aaSamw int 5003db3f65cSamw smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap) 501da6c28aaSamw { 5023db3f65cSamw uint8_t *cvalp; 503da6c28aaSamw timestruc_t *tvp; 5043db3f65cSamw smb_vdb_t *vdp; 5053db3f65cSamw smb_request_t *sr = NULL; 5063db3f65cSamw uint64_t llval; 507da6c28aaSamw int64_t nt_time; 5083db3f65cSamw uint32_t lval; 5093db3f65cSamw uint_t tag; 510da6c28aaSamw int unicode = 0; 511da6c28aaSamw int repc = 1; 5123db3f65cSamw uint16_t wval; 5133db3f65cSamw uint8_t cval; 5143db3f65cSamw uint8_t c; 515da6c28aaSamw 516da6c28aaSamw while ((c = *fmt++) != 0) { 517da6c28aaSamw repc = 1; 518da6c28aaSamw 519da6c28aaSamw if ('0' <= c && c <= '9') { 520da6c28aaSamw repc = 0; 521da6c28aaSamw do { 522da6c28aaSamw repc = repc * 10 + c - '0'; 523da6c28aaSamw c = *fmt++; 524da6c28aaSamw } while ('0' <= c && c <= '9'); 525da6c28aaSamw } else if (c == '#') { 526da6c28aaSamw repc = va_arg(ap, int); 527da6c28aaSamw c = *fmt++; 528da6c28aaSamw } 529da6c28aaSamw 530da6c28aaSamw switch (c) { 531da6c28aaSamw case '%': 532da6c28aaSamw sr = va_arg(ap, struct smb_request *); 533da6c28aaSamw unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE; 534da6c28aaSamw break; 535da6c28aaSamw 536da6c28aaSamw case 'C': /* Mbuf_chain */ 537da6c28aaSamw if (mbc_marshal_put_mbuf_chain(mbc, 5383db3f65cSamw va_arg(ap, mbuf_chain_t *)) != 0) 539da6c28aaSamw return (DECODE_NO_MORE_DATA); 540da6c28aaSamw break; 541da6c28aaSamw 542da6c28aaSamw case 'D': 543da6c28aaSamw vdp = va_arg(ap, struct vardata_block *); 544da6c28aaSamw 545da6c28aaSamw if (mbc_marshal_put_char(mbc, 1) != 0) 546da6c28aaSamw return (DECODE_NO_MORE_DATA); 5472c2961f8Sjose borrego if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) 548da6c28aaSamw return (DECODE_NO_MORE_DATA); 5492c2961f8Sjose borrego if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) 550da6c28aaSamw return (DECODE_NO_MORE_DATA); 551da6c28aaSamw break; 552da6c28aaSamw 553da6c28aaSamw case 'M': 554da6c28aaSamw /* 0xFF S M B */ 555da6c28aaSamw if (mbc_marshal_put_long(mbc, 0x424D53FF)) 556da6c28aaSamw return (DECODE_NO_MORE_DATA); 557da6c28aaSamw break; 558da6c28aaSamw 559da6c28aaSamw case 'T': 560da6c28aaSamw tvp = va_arg(ap, timestruc_t *); 561e3f2c991SKeyur Desai nt_time = smb_time_unix_to_nt(tvp); 562da6c28aaSamw if (mbc_marshal_put_long_long(mbc, nt_time) != 0) 563da6c28aaSamw return (DECODE_NO_MORE_DATA); 564da6c28aaSamw break; 565da6c28aaSamw 566da6c28aaSamw case 'V': 567da6c28aaSamw vdp = va_arg(ap, struct vardata_block *); 568da6c28aaSamw 569da6c28aaSamw if (mbc_marshal_put_char(mbc, 5) != 0) 570da6c28aaSamw return (DECODE_NO_MORE_DATA); 5712c2961f8Sjose borrego if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0) 572da6c28aaSamw return (DECODE_NO_MORE_DATA); 5732c2961f8Sjose borrego if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0) 574da6c28aaSamw return (DECODE_NO_MORE_DATA); 575da6c28aaSamw break; 576da6c28aaSamw 577da6c28aaSamw case 'b': 578da6c28aaSamw while (repc-- > 0) { 579da6c28aaSamw cval = va_arg(ap, int); 580da6c28aaSamw if (mbc_marshal_put_char(mbc, cval) != 0) 581da6c28aaSamw return (DECODE_NO_MORE_DATA); 582da6c28aaSamw } 583da6c28aaSamw break; 584da6c28aaSamw 585da6c28aaSamw case 'm': /* struct_mbuf */ 586da6c28aaSamw if (mbc_marshal_put_mbufs(mbc, 5873db3f65cSamw va_arg(ap, mbuf_t *)) != 0) 588da6c28aaSamw return (DECODE_NO_MORE_DATA); 589da6c28aaSamw break; 590da6c28aaSamw 591da6c28aaSamw case 'c': 5923db3f65cSamw cvalp = va_arg(ap, uint8_t *); 593da6c28aaSamw while (repc-- > 0) { 594da6c28aaSamw if (mbc_marshal_put_char(mbc, 595da6c28aaSamw *cvalp++) != 0) 596da6c28aaSamw return (DECODE_NO_MORE_DATA); 597da6c28aaSamw } 598da6c28aaSamw break; 599da6c28aaSamw 600da6c28aaSamw case 'w': 601da6c28aaSamw while (repc-- > 0) { 602da6c28aaSamw wval = va_arg(ap, int); 603da6c28aaSamw if (mbc_marshal_put_short(mbc, wval) != 0) 604da6c28aaSamw return (DECODE_NO_MORE_DATA); 605da6c28aaSamw } 606da6c28aaSamw break; 607da6c28aaSamw 608da6c28aaSamw case 'l': 609da6c28aaSamw while (repc-- > 0) { 610da6c28aaSamw lval = va_arg(ap, uint32_t); 611da6c28aaSamw if (mbc_marshal_put_long(mbc, lval) != 0) 612da6c28aaSamw return (DECODE_NO_MORE_DATA); 613da6c28aaSamw } 614da6c28aaSamw break; 615da6c28aaSamw 616da6c28aaSamw case 'q': 617da6c28aaSamw while (repc-- > 0) { 618da6c28aaSamw llval = va_arg(ap, uint64_t); 619da6c28aaSamw if (mbc_marshal_put_long_long(mbc, llval) != 0) 620da6c28aaSamw return (DECODE_NO_MORE_DATA); 621da6c28aaSamw } 622da6c28aaSamw break; 623da6c28aaSamw 624da6c28aaSamw 625da6c28aaSamw case 'L': 626da6c28aaSamw tag = 2; 627da6c28aaSamw goto ascii_conversion; 628da6c28aaSamw 629da6c28aaSamw case 'S': 6303db3f65cSamw case 'A': 6313db3f65cSamw tag = 4; 6323db3f65cSamw goto tagged_str; 6333db3f65cSamw 6343db3f65cSamw case 'P': 6353db3f65cSamw tag = 3; 6363db3f65cSamw goto tagged_str; 6373db3f65cSamw 638da6c28aaSamw tagged_str: 639da6c28aaSamw if (mbc_marshal_put_char(mbc, tag) != 0) 640da6c28aaSamw return (DECODE_NO_MORE_DATA); 641da6c28aaSamw /* FALLTHROUGH */ 642da6c28aaSamw 643da6c28aaSamw case 'u': /* Convert from unicode if flags are set */ 644da6c28aaSamw if (unicode) 645da6c28aaSamw goto unicode_translation; 646da6c28aaSamw /* FALLTHROUGH */ 647da6c28aaSamw 648da6c28aaSamw case 's': /* ASCII/multibyte string */ 6493db3f65cSamw ascii_conversion: cvalp = va_arg(ap, uint8_t *); 650da6c28aaSamw if (mbc_marshal_put_ascii_string(mbc, 651da6c28aaSamw (char *)cvalp, repc) != 0) 652da6c28aaSamw return (DECODE_NO_MORE_DATA); 653da6c28aaSamw break; 654da6c28aaSamw 655da6c28aaSamw case 'Y': /* int32_t, encode dos date/time */ 656da6c28aaSamw while (repc-- > 0) { 6573db3f65cSamw uint16_t d, t; 658da6c28aaSamw 659da6c28aaSamw lval = va_arg(ap, uint32_t); 660e3f2c991SKeyur Desai smb_time_unix_to_dos(lval, 661da6c28aaSamw (short *)&d, (short *)&t); 662da6c28aaSamw if (mbc_marshal_put_short(mbc, t) != 0) 663da6c28aaSamw return (DECODE_NO_MORE_DATA); 664da6c28aaSamw if (mbc_marshal_put_short(mbc, d) != 0) 665da6c28aaSamw return (DECODE_NO_MORE_DATA); 666da6c28aaSamw } 667da6c28aaSamw break; 668da6c28aaSamw 669da6c28aaSamw case 'y': /* int32_t, encode dos date/time */ 670da6c28aaSamw while (repc-- > 0) { 6713db3f65cSamw uint16_t d, t; 672da6c28aaSamw 673da6c28aaSamw lval = va_arg(ap, uint32_t); 674e3f2c991SKeyur Desai smb_time_unix_to_dos(lval, 675da6c28aaSamw (short *)&d, (short *)&t); 676da6c28aaSamw if (mbc_marshal_put_short(mbc, d) != 0) 677da6c28aaSamw return (DECODE_NO_MORE_DATA); 678da6c28aaSamw if (mbc_marshal_put_short(mbc, t) != 0) 679da6c28aaSamw return (DECODE_NO_MORE_DATA); 680da6c28aaSamw } 681da6c28aaSamw break; 682da6c28aaSamw 683da6c28aaSamw case ',': 684da6c28aaSamw if (unicode) 685da6c28aaSamw repc *= 2; 686da6c28aaSamw /* FALLTHROUGH */ 687da6c28aaSamw 688da6c28aaSamw case '.': 689da6c28aaSamw while (repc-- > 0) 690da6c28aaSamw if (mbc_marshal_put_char(mbc, 0) != 0) 691da6c28aaSamw return (DECODE_NO_MORE_DATA); 692da6c28aaSamw break; 693da6c28aaSamw 694da6c28aaSamw case 'U': /* Convert to unicode, align to word boundary */ 695da6c28aaSamw unicode_translation: 696da6c28aaSamw if (mbc->chain_offset & 1) 697da6c28aaSamw mbc->chain_offset++; 6983db3f65cSamw cvalp = va_arg(ap, uint8_t *); 699da6c28aaSamw if (mbc_marshal_put_unicode_string(mbc, 700da6c28aaSamw (char *)cvalp, repc) != 0) 701da6c28aaSamw return (DECODE_NO_MORE_DATA); 702da6c28aaSamw break; 7033db3f65cSamw 7043db3f65cSamw default: 7053db3f65cSamw ASSERT(0); 7063db3f65cSamw return (-1); 707da6c28aaSamw } 708da6c28aaSamw } 709da6c28aaSamw return (0); 710da6c28aaSamw } 711da6c28aaSamw 7123db3f65cSamw /* 7133db3f65cSamw * smb_mbc_encodef 7143db3f65cSamw * 7153db3f65cSamw * This function builds a stream of bytes in the mbc chain passed in under the 7163db3f65cSamw * control of the format fmt. 7173db3f65cSamw * 7183db3f65cSamw * (for a description of the format string see smb_mbc_vencodef()). 7193db3f65cSamw */ 720da6c28aaSamw int 7213db3f65cSamw smb_mbc_encodef(mbuf_chain_t *mbc, char *fmt, ...) 722da6c28aaSamw { 723da6c28aaSamw int rc; 724da6c28aaSamw va_list ap; 725da6c28aaSamw 726da6c28aaSamw va_start(ap, fmt); 7273db3f65cSamw rc = smb_mbc_vencodef(mbc, fmt, ap); 728da6c28aaSamw va_end(ap); 729da6c28aaSamw return (rc); 730da6c28aaSamw } 731da6c28aaSamw 7323db3f65cSamw /* 7333db3f65cSamw * smb_mbc_poke 7343db3f65cSamw * 7353db3f65cSamw * This function writes a stream of bytes in the mbc passed in at the specified 7363db3f65cSamw * offset under the control of the format fmt. The offset of the chain passed in 7373db3f65cSamw * is not modified. 7383db3f65cSamw * 7393db3f65cSamw * (for a description of the format string see smb_mbc_vencodef()). 7403db3f65cSamw */ 741da6c28aaSamw int 7423db3f65cSamw smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...) 743da6c28aaSamw { 744da6c28aaSamw int xx; 7453db3f65cSamw mbuf_chain_t tmp; 746da6c28aaSamw va_list ap; 747da6c28aaSamw 748da6c28aaSamw (void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset); 749da6c28aaSamw va_start(ap, fmt); 7503db3f65cSamw xx = smb_mbc_vencodef(&tmp, fmt, ap); 751da6c28aaSamw va_end(ap); 752da6c28aaSamw return (xx); 753da6c28aaSamw } 7543db3f65cSamw 7553db3f65cSamw /* 7563db3f65cSamw * Put data into mbuf chain allocating as needed. 7573db3f65cSamw * Adds room to end of mbuf chain if needed. 7583db3f65cSamw */ 7593db3f65cSamw static int 7603db3f65cSamw mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed) 7613db3f65cSamw { 7623db3f65cSamw mbuf_t *m; 7633db3f65cSamw mbuf_t *l; 7643db3f65cSamw int32_t bytes_available; 7653db3f65cSamw 7663db3f65cSamw bytes_needed += mbc->chain_offset; 7673db3f65cSamw if (bytes_needed > mbc->max_bytes) 7683db3f65cSamw return (EMSGSIZE); 7693db3f65cSamw 7703db3f65cSamw if ((m = mbc->chain) == 0) { 7713db3f65cSamw MGET(m, M_WAIT, MT_DATA); 7723db3f65cSamw m->m_len = 0; 7733db3f65cSamw if (mbc->max_bytes > MLEN) 7743db3f65cSamw MCLGET(m, M_WAIT); 7753db3f65cSamw mbc->chain = m; 7763db3f65cSamw /* xxxx */ 7773db3f65cSamw /* ^ */ 7783db3f65cSamw } 7793db3f65cSamw 7803db3f65cSamw /* ---- ----- --xx ---xxx */ 7813db3f65cSamw /* ^ */ 7823db3f65cSamw 7833db3f65cSamw l = 0; 7843db3f65cSamw while ((m != 0) && (bytes_needed >= m->m_len)) { 7853db3f65cSamw l = m; 7863db3f65cSamw bytes_needed -= m->m_len; 7873db3f65cSamw m = m->m_next; 7883db3f65cSamw } 7893db3f65cSamw 7903db3f65cSamw if ((bytes_needed == 0) || (m != 0)) { 7913db3f65cSamw /* We have enough room already */ 7923db3f65cSamw return (0); 7933db3f65cSamw } 7943db3f65cSamw 7953db3f65cSamw /* ---- ----- --xx ---xxx */ 7963db3f65cSamw /* ^ */ 7973db3f65cSamw /* Back up to start of last mbuf */ 7983db3f65cSamw m = l; 7993db3f65cSamw bytes_needed += m->m_len; 8003db3f65cSamw 8013db3f65cSamw /* ---- ----- --xx ---xxx */ 8023db3f65cSamw /* ^ */ 8033db3f65cSamw 8043db3f65cSamw bytes_available = (m->m_flags & M_EXT) ? 8053db3f65cSamw m->m_ext.ext_size : MLEN; 8063db3f65cSamw 8073db3f65cSamw /* ---- ----- --xx ---xxx */ 8083db3f65cSamw /* ^ */ 8093db3f65cSamw while ((bytes_needed != 0) && (bytes_needed > bytes_available)) { 8103db3f65cSamw m->m_len = bytes_available; 8113db3f65cSamw bytes_needed -= m->m_len; 8123db3f65cSamw /* ---- ----- --xx ------ */ 8133db3f65cSamw /* ^ */ 8143db3f65cSamw 8153db3f65cSamw MGET(m->m_next, M_WAIT, MT_DATA); 8163db3f65cSamw m = m->m_next; 8173db3f65cSamw m->m_len = 0; 8183db3f65cSamw if (bytes_needed > MLEN) 8193db3f65cSamw MCLGET(m, M_WAIT); 8203db3f65cSamw 8213db3f65cSamw bytes_available = (m->m_flags & M_EXT) ? 8223db3f65cSamw m->m_ext.ext_size : MLEN; 8233db3f65cSamw 8243db3f65cSamw /* ---- ----- --xx ------ xxxx */ 8253db3f65cSamw /* ^ */ 8263db3f65cSamw } 8273db3f65cSamw 8283db3f65cSamw /* ---- ----- --xx ------ xxxx */ 8293db3f65cSamw /* ^ */ 8303db3f65cSamw /* Expand last tail as needed */ 8313db3f65cSamw if (m->m_len <= bytes_needed) { 8323db3f65cSamw m->m_len = bytes_needed; 8333db3f65cSamw /* ---- ----- --xx ------ --xx */ 8343db3f65cSamw /* ^ */ 8353db3f65cSamw } 8363db3f65cSamw 8373db3f65cSamw return (0); 8383db3f65cSamw } 8393db3f65cSamw 8403db3f65cSamw static void 8413db3f65cSamw mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data) 8423db3f65cSamw { 8433db3f65cSamw mbuf_t *m = mbc->chain; 8443db3f65cSamw int32_t cur_offset = mbc->chain_offset; 8453db3f65cSamw 8463db3f65cSamw /* 8473db3f65cSamw * Scan forward looking for the last data currently in chain. 8483db3f65cSamw */ 8493db3f65cSamw while (cur_offset >= m->m_len) { 8503db3f65cSamw cur_offset -= m->m_len; 8513db3f65cSamw m = m->m_next; 8523db3f65cSamw } 8533db3f65cSamw ((char *)m->m_data)[cur_offset] = data; 8543db3f65cSamw mbc->chain_offset++; 8553db3f65cSamw } 8563db3f65cSamw 8573db3f65cSamw static int 8583db3f65cSamw mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data) 8593db3f65cSamw { 8603db3f65cSamw if (mbc_marshal_make_room(mbc, sizeof (char)) != 0) 8613db3f65cSamw return (DECODE_NO_MORE_DATA); 8623db3f65cSamw mbc_marshal_store_byte(mbc, data); 8633db3f65cSamw return (0); 8643db3f65cSamw } 8653db3f65cSamw 8663db3f65cSamw static int 8673db3f65cSamw mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data) 8683db3f65cSamw { 8693db3f65cSamw if (mbc_marshal_make_room(mbc, sizeof (short))) 8703db3f65cSamw return (DECODE_NO_MORE_DATA); 8713db3f65cSamw mbc_marshal_store_byte(mbc, data); 8723db3f65cSamw mbc_marshal_store_byte(mbc, data >> 8); 8733db3f65cSamw return (0); 8743db3f65cSamw } 8753db3f65cSamw 8763db3f65cSamw static int 8773db3f65cSamw mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data) 8783db3f65cSamw { 8793db3f65cSamw if (mbc_marshal_make_room(mbc, sizeof (int32_t))) 8803db3f65cSamw return (DECODE_NO_MORE_DATA); 8813db3f65cSamw mbc_marshal_store_byte(mbc, data); 8823db3f65cSamw mbc_marshal_store_byte(mbc, data >> 8); 8833db3f65cSamw mbc_marshal_store_byte(mbc, data >> 16); 8843db3f65cSamw mbc_marshal_store_byte(mbc, data >> 24); 8853db3f65cSamw return (0); 8863db3f65cSamw } 8873db3f65cSamw 8883db3f65cSamw static int 8893db3f65cSamw mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data) 8903db3f65cSamw { 8913db3f65cSamw if (mbc_marshal_make_room(mbc, sizeof (int64_t))) 8923db3f65cSamw return (DECODE_NO_MORE_DATA); 8933db3f65cSamw 8943db3f65cSamw mbc_marshal_store_byte(mbc, data); 8953db3f65cSamw mbc_marshal_store_byte(mbc, data >> 8); 8963db3f65cSamw mbc_marshal_store_byte(mbc, data >> 16); 8973db3f65cSamw mbc_marshal_store_byte(mbc, data >> 24); 8983db3f65cSamw mbc_marshal_store_byte(mbc, data >> 32); 8993db3f65cSamw mbc_marshal_store_byte(mbc, data >> 40); 9003db3f65cSamw mbc_marshal_store_byte(mbc, data >> 48); 9013db3f65cSamw mbc_marshal_store_byte(mbc, data >> 56); 9023db3f65cSamw return (0); 9033db3f65cSamw } 9043db3f65cSamw 9053db3f65cSamw /* 9063db3f65cSamw * When need to convert from UTF-8 (internal format) to a single 9073db3f65cSamw * byte string (external format ) when marshalling a string. 9083db3f65cSamw */ 9093db3f65cSamw static int 9103db3f65cSamw mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc) 9113db3f65cSamw { 912bbf6f00cSJordan Brown smb_wchar_t wide_char; 9133db3f65cSamw int nbytes; 9143db3f65cSamw int length; 9153db3f65cSamw 916bbf6f00cSJordan Brown if ((length = smb_sbequiv_strlen(mbs)) == -1) 9173db3f65cSamw return (DECODE_NO_MORE_DATA); 9183db3f65cSamw 9193db3f65cSamw length += sizeof (char); 9203db3f65cSamw 9213db3f65cSamw if ((repc > 1) && (repc < length)) 9223db3f65cSamw length = repc; 9233db3f65cSamw if (mbc_marshal_make_room(mbc, length)) 9243db3f65cSamw return (DECODE_NO_MORE_DATA); 9253db3f65cSamw 9263db3f65cSamw while (*mbs) { 9273db3f65cSamw /* 9283db3f65cSamw * We should restore oem chars here. 9293db3f65cSamw */ 930bbf6f00cSJordan Brown nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX); 9313db3f65cSamw if (nbytes == -1) 9323db3f65cSamw return (DECODE_NO_MORE_DATA); 9333db3f65cSamw 9343db3f65cSamw mbc_marshal_store_byte(mbc, (uint8_t)wide_char); 9353db3f65cSamw 9363db3f65cSamw if (wide_char & 0xFF00) 9373db3f65cSamw mbc_marshal_store_byte(mbc, wide_char >> 8); 9383db3f65cSamw 9393db3f65cSamw mbs += nbytes; 9403db3f65cSamw } 9413db3f65cSamw 9423db3f65cSamw mbc_marshal_store_byte(mbc, 0); 9433db3f65cSamw return (0); 9443db3f65cSamw } 9453db3f65cSamw 9463db3f65cSamw static int 9473db3f65cSamw mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc) 9483db3f65cSamw { 949bbf6f00cSJordan Brown smb_wchar_t wchar; 9503db3f65cSamw int consumed; 9513db3f65cSamw int length; 9523db3f65cSamw 953bbf6f00cSJordan Brown if ((length = smb_wcequiv_strlen(ascii)) == -1) 9543db3f65cSamw return (DECODE_NO_MORE_DATA); 9553db3f65cSamw 956bbf6f00cSJordan Brown length += sizeof (smb_wchar_t); 9573db3f65cSamw 9583db3f65cSamw if ((repc > 1) && (repc < length)) 9593db3f65cSamw length = repc; 9603db3f65cSamw 9613db3f65cSamw if (mbc_marshal_make_room(mbc, length)) 9623db3f65cSamw return (DECODE_NO_MORE_DATA); 9633db3f65cSamw while (length > 0) { 964bbf6f00cSJordan Brown consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX); 9653db3f65cSamw if (consumed == -1) 9663db3f65cSamw break; /* Invalid sequence */ 9673db3f65cSamw /* 9683db3f65cSamw * Note that consumed will be 0 when the null terminator 9693db3f65cSamw * is encountered and ascii will not be advanced beyond 9703db3f65cSamw * that point. Length will continue to be decremented so 9713db3f65cSamw * we won't get stuck here. 9723db3f65cSamw */ 9733db3f65cSamw ascii += consumed; 9743db3f65cSamw mbc_marshal_store_byte(mbc, wchar); 9753db3f65cSamw mbc_marshal_store_byte(mbc, wchar >> 8); 976bbf6f00cSJordan Brown length -= sizeof (smb_wchar_t); 9773db3f65cSamw } 9783db3f65cSamw return (0); 9793db3f65cSamw } 9803db3f65cSamw 9813db3f65cSamw static int 9823db3f65cSamw mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio) 9833db3f65cSamw { 9843db3f65cSamw mbuf_t **t; 9853db3f65cSamw mbuf_t *m = NULL; 9863db3f65cSamw struct iovec *iov = uio->uio_iov; 9873db3f65cSamw int32_t i, iov_cnt = uio->uio_iovcnt; 9883db3f65cSamw 9893db3f65cSamw iov = uio->uio_iov; 9903db3f65cSamw t = &mbc->chain; 9913db3f65cSamw for (i = 0; i < iov_cnt; i++) { 9923db3f65cSamw MGET(m, M_WAIT, MT_DATA); 9933db3f65cSamw m->m_ext.ext_buf = iov->iov_base; 9943db3f65cSamw m->m_ext.ext_ref = smb_noop; 9953db3f65cSamw m->m_data = m->m_ext.ext_buf; 9963db3f65cSamw m->m_flags |= M_EXT; 9973db3f65cSamw m->m_len = m->m_ext.ext_size = iov->iov_len; 9983db3f65cSamw mbc->max_bytes += m->m_len; 9993db3f65cSamw m->m_next = 0; 10003db3f65cSamw *t = m; 10013db3f65cSamw t = &m->m_next; 10023db3f65cSamw iov++; 10033db3f65cSamw } 10043db3f65cSamw return (0); 10053db3f65cSamw } 10063db3f65cSamw 10073db3f65cSamw static int 10083db3f65cSamw mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m) 10093db3f65cSamw { 10103db3f65cSamw mbuf_t *mt; 10113db3f65cSamw mbuf_t **t; 10123db3f65cSamw int bytes; 10133db3f65cSamw 10143db3f65cSamw if (m != NULL) { 10153db3f65cSamw mt = m; 10163db3f65cSamw bytes = mt->m_len; 10173db3f65cSamw while (mt->m_next != 0) { 10183db3f65cSamw mt = mt->m_next; 10193db3f65cSamw bytes += mt->m_len; 10203db3f65cSamw } 10213db3f65cSamw if (bytes != 0) { 10223db3f65cSamw t = &mbc->chain; 10233db3f65cSamw while (*t != 0) { 10243db3f65cSamw bytes += (*t)->m_len; 10253db3f65cSamw t = &(*t)->m_next; 10263db3f65cSamw } 10273db3f65cSamw *t = m; 10283db3f65cSamw mbc->chain_offset = bytes; 10293db3f65cSamw } else { 10303db3f65cSamw m_freem(m); 10313db3f65cSamw } 10323db3f65cSamw } 10333db3f65cSamw return (0); 10343db3f65cSamw } 10353db3f65cSamw 10363db3f65cSamw static int 10373db3f65cSamw mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc) 10383db3f65cSamw { 10393db3f65cSamw if (nmbc->chain != 0) { 10403db3f65cSamw if (mbc_marshal_put_mbufs(mbc, nmbc->chain)) 10413db3f65cSamw return (DECODE_NO_MORE_DATA); 10423db3f65cSamw MBC_SETUP(nmbc, nmbc->max_bytes); 10433db3f65cSamw } 10443db3f65cSamw return (0); 10453db3f65cSamw } 10463db3f65cSamw 10473db3f65cSamw static uint8_t 10483db3f65cSamw mbc_marshal_fetch_byte(mbuf_chain_t *mbc) 10493db3f65cSamw { 10503db3f65cSamw uint8_t data; 10513db3f65cSamw mbuf_t *m = mbc->chain; 10523db3f65cSamw int32_t offset = mbc->chain_offset; 10533db3f65cSamw 10543db3f65cSamw while (offset >= m->m_len) { 10553db3f65cSamw offset -= m->m_len; 10563db3f65cSamw m = m->m_next; 10573db3f65cSamw } 10583db3f65cSamw data = ((uint8_t *)m->m_data)[offset]; 10593db3f65cSamw mbc->chain_offset++; 10603db3f65cSamw return (data); 10613db3f65cSamw } 10623db3f65cSamw 10633db3f65cSamw static int 10643db3f65cSamw mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data) 10653db3f65cSamw { 10663db3f65cSamw if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 10673db3f65cSamw /* Data will never be available */ 10683db3f65cSamw return (DECODE_NO_MORE_DATA); 10693db3f65cSamw } 10703db3f65cSamw *data = mbc_marshal_fetch_byte(mbc); 10713db3f65cSamw return (0); 10723db3f65cSamw } 10733db3f65cSamw 10743db3f65cSamw static int 10753db3f65cSamw mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data) 10763db3f65cSamw { 10773db3f65cSamw uint16_t tmp; 10783db3f65cSamw mbuf_t *m = mbc->chain; 10793db3f65cSamw int32_t offset = mbc->chain_offset; 10803db3f65cSamw 10813db3f65cSamw if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) { 10823db3f65cSamw /* Data will never be available */ 10833db3f65cSamw return (DECODE_NO_MORE_DATA); 10843db3f65cSamw } 10853db3f65cSamw 10863db3f65cSamw while (offset >= m->m_len) { 10873db3f65cSamw offset -= m->m_len; 10883db3f65cSamw m = m->m_next; 10893db3f65cSamw } 10903db3f65cSamw if ((m->m_len - offset) >= sizeof (short)) { 10913db3f65cSamw *data = LE_IN16(m->m_data + offset); 10923db3f65cSamw mbc->chain_offset += sizeof (short); 10933db3f65cSamw } else { 10943db3f65cSamw tmp = (uint16_t)mbc_marshal_fetch_byte(mbc); 10953db3f65cSamw tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8; 10963db3f65cSamw *data = tmp; 10973db3f65cSamw } 10983db3f65cSamw return (0); 10993db3f65cSamw } 11003db3f65cSamw 11013db3f65cSamw static int 11023db3f65cSamw mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data) 11033db3f65cSamw { 11043db3f65cSamw uint32_t tmp; 11053db3f65cSamw mbuf_t *m = mbc->chain; 11063db3f65cSamw int32_t offset = mbc->chain_offset; 11073db3f65cSamw 11083db3f65cSamw if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) { 11093db3f65cSamw /* Data will never be available */ 11103db3f65cSamw return (DECODE_NO_MORE_DATA); 11113db3f65cSamw } 11123db3f65cSamw while (offset >= m->m_len) { 11133db3f65cSamw offset -= m->m_len; 11143db3f65cSamw m = m->m_next; 11153db3f65cSamw } 11163db3f65cSamw if ((m->m_len - offset) >= sizeof (int32_t)) { 11173db3f65cSamw *data = LE_IN32(m->m_data + offset); 11183db3f65cSamw mbc->chain_offset += sizeof (int32_t); 11193db3f65cSamw } else { 11203db3f65cSamw tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 11213db3f65cSamw tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8; 11223db3f65cSamw tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16; 11233db3f65cSamw tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24; 11243db3f65cSamw *data = tmp; 11253db3f65cSamw } 11263db3f65cSamw return (0); 11273db3f65cSamw } 11283db3f65cSamw 11293db3f65cSamw static uint64_t 11303db3f65cSamw qswap(uint64_t ll) 11313db3f65cSamw { 11323db3f65cSamw uint64_t v; 11333db3f65cSamw 11343db3f65cSamw v = ll >> 32; 11353db3f65cSamw v |= ll << 32; 11363db3f65cSamw 11373db3f65cSamw return (v); 11383db3f65cSamw } 11393db3f65cSamw 11403db3f65cSamw static int 11413db3f65cSamw mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data) 11423db3f65cSamw { 11433db3f65cSamw uint64_t tmp; 11443db3f65cSamw mbuf_t *m = mbc->chain; 11453db3f65cSamw int32_t offset = mbc->chain_offset; 11463db3f65cSamw 11473db3f65cSamw if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 11483db3f65cSamw /* Data will never be available */ 11493db3f65cSamw return (DECODE_NO_MORE_DATA); 11503db3f65cSamw } 11513db3f65cSamw while (offset >= m->m_len) { 11523db3f65cSamw offset -= m->m_len; 11533db3f65cSamw m = m->m_next; 11543db3f65cSamw } 11553db3f65cSamw 11563db3f65cSamw if ((m->m_len - offset) >= sizeof (int64_t)) { 11573db3f65cSamw *data = qswap(LE_IN64(m->m_data + offset)); 11583db3f65cSamw mbc->chain_offset += sizeof (int64_t); 11593db3f65cSamw } else { 11603db3f65cSamw tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32; 11613db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40; 11623db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48; 11633db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56; 11643db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc); 11653db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8; 11663db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16; 11673db3f65cSamw tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24; 11683db3f65cSamw 11693db3f65cSamw *(uint64_t *)data = tmp; 11703db3f65cSamw } 11713db3f65cSamw return (0); 11723db3f65cSamw } 11733db3f65cSamw 11743db3f65cSamw static int 11753db3f65cSamw mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data) 11763db3f65cSamw { 11773db3f65cSamw uint64_t tmp; 11783db3f65cSamw mbuf_t *m = mbc->chain; 11793db3f65cSamw int32_t offset = mbc->chain_offset; 11803db3f65cSamw 11813db3f65cSamw if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) { 11823db3f65cSamw /* Data will never be available */ 11833db3f65cSamw return (DECODE_NO_MORE_DATA); 11843db3f65cSamw } 11853db3f65cSamw while (offset >= m->m_len) { 11863db3f65cSamw offset -= m->m_len; 11873db3f65cSamw m = m->m_next; 11883db3f65cSamw } 11893db3f65cSamw if ((m->m_len - offset) >= sizeof (int64_t)) { 11903db3f65cSamw *data = LE_IN64(m->m_data + offset); 11913db3f65cSamw mbc->chain_offset += sizeof (int64_t); 11923db3f65cSamw } else { 11933db3f65cSamw tmp = (uint32_t)mbc_marshal_fetch_byte(mbc); 11943db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8; 11953db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16; 11963db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24; 11973db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32; 11983db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40; 11993db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48; 12003db3f65cSamw tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56; 12013db3f65cSamw *(uint64_t *)data = tmp; 12023db3f65cSamw } 12033db3f65cSamw return (0); 12043db3f65cSamw } 12053db3f65cSamw 12063db3f65cSamw /* 12073db3f65cSamw * mbc_marshal_get_ascii_string 12083db3f65cSamw * 12093db3f65cSamw * The ascii string in smb includes oem chars. Since the 12103db3f65cSamw * system needs utf8 encodes unicode char, conversion is 12113db3f65cSamw * required to convert the oem char to unicode and then 12123db3f65cSamw * to encode the converted wchars to utf8 format. 12133db3f65cSamw * Therefore, the **ascii returned will be in such format 12143db3f65cSamw * instead of the real ASCII format. 12153db3f65cSamw */ 12163db3f65cSamw static int 12173db3f65cSamw mbc_marshal_get_ascii_string( 1218bbf6f00cSJordan Brown smb_request_t *sr, 12193db3f65cSamw mbuf_chain_t *mbc, 12203db3f65cSamw uint8_t **ascii, 12213db3f65cSamw int max_ascii) 12223db3f65cSamw { 12233db3f65cSamw char *rcvbuf; 12243db3f65cSamw char *ch; 12253db3f65cSamw int max; 12263db3f65cSamw int length = 0; 12273db3f65cSamw 12283db3f65cSamw max = MALLOC_QUANTUM; 1229bbf6f00cSJordan Brown rcvbuf = smb_srm_alloc(sr, max); 12303db3f65cSamw 12313db3f65cSamw if (max_ascii == 0) 12323db3f65cSamw max_ascii = 0xffff; 12333db3f65cSamw 12343db3f65cSamw ch = rcvbuf; 12353db3f65cSamw for (;;) { 12363db3f65cSamw while (length < max) { 12373db3f65cSamw if (max_ascii-- <= 0) { 12383db3f65cSamw *ch++ = 0; 12393db3f65cSamw goto multibyte_encode; 12403db3f65cSamw } 12413db3f65cSamw if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) { 12423db3f65cSamw /* Data will never be available */ 12433db3f65cSamw return (DECODE_NO_MORE_DATA); 12443db3f65cSamw } 12453db3f65cSamw if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0) 12463db3f65cSamw goto multibyte_encode; 12473db3f65cSamw length++; 12483db3f65cSamw } 12493db3f65cSamw max += MALLOC_QUANTUM; 1250bbf6f00cSJordan Brown rcvbuf = smb_srm_realloc(sr, rcvbuf, max); 12513db3f65cSamw ch = rcvbuf + length; 12523db3f65cSamw } 12533db3f65cSamw 12543db3f65cSamw multibyte_encode: 12553db3f65cSamw /* 12563db3f65cSamw * UTF-8 encode the string for internal system use. 12573db3f65cSamw */ 12583db3f65cSamw length = strlen(rcvbuf) + 1; 1259bbf6f00cSJordan Brown *ascii = smb_srm_alloc(sr, length * MTS_MB_CHAR_MAX); 1260e3f2c991SKeyur Desai return (mbc_marshal_cstou8("CP850", (char *)*ascii, 1261e3f2c991SKeyur Desai (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length)); 12623db3f65cSamw } 12633db3f65cSamw 12643db3f65cSamw static int 1265bbf6f00cSJordan Brown mbc_marshal_get_unicode_string(smb_request_t *sr, 12663db3f65cSamw mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode) 12673db3f65cSamw { 12683db3f65cSamw int max; 12693db3f65cSamw uint16_t wchar; 12703db3f65cSamw char *ch; 12713db3f65cSamw int emitted; 12723db3f65cSamw int length = 0; 12733db3f65cSamw 12743db3f65cSamw if (max_unicode == 0) 12753db3f65cSamw max_unicode = 0xffff; 12763db3f65cSamw 12773db3f65cSamw max = MALLOC_QUANTUM; 1278bbf6f00cSJordan Brown *ascii = smb_srm_alloc(sr, max); 12793db3f65cSamw 12803db3f65cSamw ch = (char *)*ascii; 12813db3f65cSamw for (;;) { 12823db3f65cSamw while ((length + MTS_MB_CHAR_MAX) < max) { 12833db3f65cSamw if (max_unicode <= 0) 12843db3f65cSamw goto done; 12853db3f65cSamw max_unicode -= 2; 12863db3f65cSamw 12873db3f65cSamw if (mbc_marshal_get_short(mbc, &wchar) != 0) 12883db3f65cSamw return (DECODE_NO_MORE_DATA); 12893db3f65cSamw 12903db3f65cSamw if (wchar == 0) goto done; 12913db3f65cSamw 1292bbf6f00cSJordan Brown emitted = smb_wctomb(ch, wchar); 12933db3f65cSamw length += emitted; 12943db3f65cSamw ch += emitted; 12953db3f65cSamw } 12963db3f65cSamw max += MALLOC_QUANTUM; 1297bbf6f00cSJordan Brown *ascii = smb_srm_realloc(sr, *ascii, max); 12983db3f65cSamw ch = (char *)*ascii + length; 12993db3f65cSamw } 13003db3f65cSamw done: *ch = 0; 13013db3f65cSamw return (0); 13023db3f65cSamw } 13033db3f65cSamw 13043db3f65cSamw static int /*ARGSUSED*/ 13053db3f65cSamw mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m) 13063db3f65cSamw { 13073db3f65cSamw if (MBC_ROOM_FOR(mbc, bytes) == 0) { 13083db3f65cSamw /* Data will never be available */ 13093db3f65cSamw return (DECODE_NO_MORE_DATA); 13103db3f65cSamw } 13113db3f65cSamw return (0); 13123db3f65cSamw } 13133db3f65cSamw 13143db3f65cSamw static int 13153db3f65cSamw mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc) 13163db3f65cSamw { 13173db3f65cSamw int rc; 13183db3f65cSamw mbuf_t *m; 13193db3f65cSamw 13203db3f65cSamw if (bytes == 0) { 13213db3f65cSamw /* Get all the rest */ 13223db3f65cSamw bytes = mbc->max_bytes - mbc->chain_offset; 13233db3f65cSamw } 13243db3f65cSamw 13253db3f65cSamw MBC_SETUP(nmbc, mbc->max_bytes); 13263db3f65cSamw if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) { 13273db3f65cSamw if (m) 13283db3f65cSamw m_freem(m); 13293db3f65cSamw return (rc); 13303db3f65cSamw } 13313db3f65cSamw nmbc->chain = m; 13323db3f65cSamw while (m != 0) { 13333db3f65cSamw bytes += m->m_len; 13343db3f65cSamw m = m->m_next; 13353db3f65cSamw } 13363db3f65cSamw nmbc->max_bytes = bytes; 13373db3f65cSamw return (0); 13383db3f65cSamw } 13393db3f65cSamw 13403db3f65cSamw static int 13413db3f65cSamw mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio) 13423db3f65cSamw { 13433db3f65cSamw int i, offset; 13443db3f65cSamw int32_t bytes = uio->uio_resid; 13453db3f65cSamw int32_t remainder; 13463db3f65cSamw struct iovec *iov; 13473db3f65cSamw mbuf_t *m; 13483db3f65cSamw 13493db3f65cSamw /* 13503db3f65cSamw * The residual count is tested because in the case of write requests 13513db3f65cSamw * with no data (smbtorture RAW-WRITE test will generate that type of 13523db3f65cSamw * request) this function is called with a residual count of zero 13533db3f65cSamw * bytes. 13543db3f65cSamw */ 13557b6a044aSjose borrego if (bytes != 0) { 13563db3f65cSamw iov = uio->uio_iov; 13573db3f65cSamw uio->uio_segflg = UIO_SYSSPACE; 1358*f96bd5c8SAlan Wright uio->uio_extflg = UIO_COPY_DEFAULT; 13593db3f65cSamw 13603db3f65cSamw if (MBC_ROOM_FOR(mbc, bytes) == 0) { 13613db3f65cSamw /* Data will never be available */ 13623db3f65cSamw return (DECODE_NO_MORE_DATA); 13633db3f65cSamw } 13643db3f65cSamw 13653db3f65cSamw m = mbc->chain; 13663db3f65cSamw offset = mbc->chain_offset; 13673db3f65cSamw while (offset >= m->m_len) { 13683db3f65cSamw offset -= m->m_len; 13693db3f65cSamw m = m->m_next; 13703db3f65cSamw ASSERT((offset == 0) || (offset && m)); 13713db3f65cSamw } 13723db3f65cSamw 13733db3f65cSamw for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) { 13743db3f65cSamw iov[i].iov_base = &m->m_data[offset]; 13753db3f65cSamw remainder = m->m_len - offset; 13763db3f65cSamw if (remainder >= bytes) { 13773db3f65cSamw iov[i].iov_len = bytes; 13783db3f65cSamw mbc->chain_offset += bytes; 13797b6a044aSjose borrego uio->uio_iovcnt = i + 1; 13807b6a044aSjose borrego return (0); 13813db3f65cSamw } 13823db3f65cSamw iov[i].iov_len = remainder; 13833db3f65cSamw mbc->chain_offset += remainder; 13843db3f65cSamw bytes -= remainder; 13853db3f65cSamw m = m->m_next; 13863db3f65cSamw offset = 0; 13873db3f65cSamw } 13883db3f65cSamw return (DECODE_NO_MORE_DATA); 13893db3f65cSamw } 13903db3f65cSamw return (0); 13913db3f65cSamw } 13923db3f65cSamw 13933db3f65cSamw static int 13943db3f65cSamw mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip) 13953db3f65cSamw { 13963db3f65cSamw if (MBC_ROOM_FOR(mbc, skip) == 0) 13973db3f65cSamw return (DECODE_NO_MORE_DATA); 13983db3f65cSamw mbc->chain_offset += skip; 13993db3f65cSamw return (0); 14003db3f65cSamw } 1401e3f2c991SKeyur Desai 1402e3f2c991SKeyur Desai /* 1403e3f2c991SKeyur Desai * Converts oem string to UTF-8 string with an output string of max 1404e3f2c991SKeyur Desai * maxconv bytes. The string may be truncated or not null-terminated if 1405e3f2c991SKeyur Desai * there is not enough room. 1406e3f2c991SKeyur Desai * 1407e3f2c991SKeyur Desai * returns -1, cnt (partial conversion) or 0 (success) 1408e3f2c991SKeyur Desai */ 1409e3f2c991SKeyur Desai 1410e3f2c991SKeyur Desai static int 1411e3f2c991SKeyur Desai mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv, 1412e3f2c991SKeyur Desai char *inbuf, size_t srcbytes) 1413e3f2c991SKeyur Desai { 1414e3f2c991SKeyur Desai kiconv_t t2u; 1415e3f2c991SKeyur Desai size_t inlen = srcbytes; 1416e3f2c991SKeyur Desai size_t outlen = maxconv; 1417e3f2c991SKeyur Desai int err = 0; 1418e3f2c991SKeyur Desai size_t rc; 1419e3f2c991SKeyur Desai 1420e3f2c991SKeyur Desai if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1) 1421e3f2c991SKeyur Desai return (-1); 1422e3f2c991SKeyur Desai 1423e3f2c991SKeyur Desai rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err); 1424e3f2c991SKeyur Desai (void) kiconv_close(t2u); 1425e3f2c991SKeyur Desai return ((int)rc); 1426e3f2c991SKeyur Desai } 1427