/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
* Msgbuf buffer management implementation. The smb_msgbuf interface is
* style operations. It contains special handling for the SMB header.
* It can also be used for general purpose encoding and decoding.
*/
#include <sys/byteorder.h>
#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <strings.h>
#else
#endif
/*
* Returns the offset or number of bytes used within the buffer.
*/
{
/*LINTED E_PTRDIFF_OVERFLOW*/
}
/*
* Returns the actual buffer size.
*/
{
}
uint8_t *
{
}
/*
* Ensure that the scan is aligned on a word (16-bit) boundary.
*/
void
{
}
/*
* Ensure that the scan is aligned on a dword (32-bit) boundary.
*/
void
{
}
/*
* Checks whether or not the buffer has space for the amount of data
* specified. Returns 1 if there is space, otherwise returns 0.
*/
int
{
return (0);
return (1);
}
/*
* Set flags the smb_msgbuf.
*/
void
{
}
/*
* Clear flags the smb_msgbuf.
*/
void
{
}
/*
* smb_msgbuf_init
*
* Initialize a smb_msgbuf_t structure based on the buffer and size
* specified. Both scan and base initially point to the beginning
* of the buffer and end points to the limit of the buffer. As
* data is added scan should be incremented to point to the next
* offset at which data will be written. Max and count are set
* to the actual buffer size.
*/
void
{
}
/*
* smb_msgbuf_term
*
* Destruct a smb_msgbuf_t. Free any memory hanging off the mlist.
*/
void
{
while (item) {
#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
#else
#endif
}
}
/*
* smb_msgbuf_decode
*
* Decode a smb_msgbuf buffer as indicated by the format string into
* the variable arg list. This is similar to a scanf operation.
*
* On success, returns the number of bytes encoded. Otherwise
* returns a -ve error code.
*/
int
{
int rc;
if (rc != SMB_MSGBUF_SUCCESS) {
return (rc);
}
/*LINTED E_PTRDIFF_OVERFLOW*/
}
/*
* buf_decode
*
* Private decode function, where the real work of decoding the smb_msgbuf
* is done. This function should only be called via smb_msgbuf_decode to
* ensure correct behaviour and error handling.
*/
static int
{
uint8_t c;
char *cvalp;
char **cvalpp;
int repc;
int rc;
while ((c = *fmt++) != 0) {
repc = 1;
if (c == ' ' || c == '\t')
continue;
if (c == '(') {
while (((c = *fmt++) != 0) && c != ')')
;
if (!c)
return (SMB_MSGBUF_SUCCESS);
continue;
}
if ('0' <= c && c <= '9') {
repc = 0;
do {
c = *fmt++;
} while ('0' <= c && c <= '9');
} else if (c == '#') {
c = *fmt++;
}
switch (c) {
case '.':
return (SMB_MSGBUF_UNDERFLOW);
break;
case 'c': /* get char */
return (SMB_MSGBUF_UNDERFLOW);
break;
case 'b': /* get byte */
return (SMB_MSGBUF_UNDERFLOW);
while (repc-- > 0) {
}
break;
case 'w': /* get word */
if (rc == 0)
return (SMB_MSGBUF_UNDERFLOW);
while (repc-- > 0) {
}
break;
case 'l': /* get long */
if (rc == 0)
return (SMB_MSGBUF_UNDERFLOW);
while (repc-- > 0) {
}
break;
case 'q': /* get quad */
if (rc == 0)
return (SMB_MSGBUF_UNDERFLOW);
while (repc-- > 0) {
}
break;
case 'u': /* Convert from unicode if flags are set */
goto unicode_translation;
/*FALLTHROUGH*/
case 's': /* get string */
if (!repc_specified)
return (SMB_MSGBUF_UNDERFLOW);
return (SMB_MSGBUF_UNDERFLOW);
/* Translate OEM to mbs */
while (repc > 0) {
repc--;
if (wchar == 0)
break;
}
*cvalp = '\0';
if (repc > 0)
break;
case 'U': /* get unicode string */
/*
* Unicode strings are always word aligned.
* The malloc'd area is larger than the
* original string because the UTF-8 chars
* may be longer than the wide-chars.
*/
if (!repc_specified) {
/*
* Count bytes, including the null.
*/
tmp_scan += 2;
repc += 2;
}
}
return (SMB_MSGBUF_UNDERFLOW);
/*
* Get space for translated string
* Allocates worst-case size.
*/
return (SMB_MSGBUF_UNDERFLOW);
/*
* Translate unicode to mbs, stopping after
* null or repc limit.
*/
while (repc >= 2) {
repc -= 2;
if (wchar == 0)
break;
}
*cvalp = '\0';
if (repc > 0)
break;
case 'M':
return (SMB_MSGBUF_UNDERFLOW);
return (SMB_MSGBUF_INVALID_HEADER);
}
break;
default:
return (SMB_MSGBUF_INVALID_FORMAT);
}
}
return (SMB_MSGBUF_SUCCESS);
}
/*
* smb_msgbuf_encode
*
* Encode a smb_msgbuf buffer as indicated by the format string using
* the variable arg list. This is similar to a sprintf operation.
*
* On success, returns the number of bytes encoded. Otherwise
* returns a -ve error code.
*/
int
{
int rc;
if (rc != SMB_MSGBUF_SUCCESS) {
return (rc);
}
/*LINTED E_PTRDIFF_OVERFLOW*/
}
/*
* buf_encode
*
* Private encode function, where the real work of encoding the smb_msgbuf
* is done. This function should only be called via smb_msgbuf_encode to
* ensure correct behaviour and error handling.
*/
static int
{
char *cvalp;
uint8_t c;
int count;
int repc;
int rc;
while ((c = *fmt++) != 0) {
repc = 1;
if (c == ' ' || c == '\t')
continue;
if (c == '(') {
while (((c = *fmt++) != 0) && c != ')')
;
if (!c)
return (SMB_MSGBUF_SUCCESS);
continue;
}
if ('0' <= c && c <= '9') {
repc = 0;
do {
c = *fmt++;
} while ('0' <= c && c <= '9');
} else if (c == '#') {
c = *fmt++;
}
switch (c) {
case '.':
return (SMB_MSGBUF_OVERFLOW);
while (repc-- > 0)
break;
case 'c': /* put char */
return (SMB_MSGBUF_OVERFLOW);
break;
case 'b': /* put byte */
return (SMB_MSGBUF_OVERFLOW);
while (repc-- > 0) {
}
break;
case 'w': /* put word */
if (rc == 0)
return (SMB_MSGBUF_OVERFLOW);
while (repc-- > 0) {
}
break;
case 'l': /* put long */
if (rc == 0)
return (SMB_MSGBUF_OVERFLOW);
while (repc-- > 0) {
}
break;
case 'q': /* put quad */
if (rc == 0)
return (SMB_MSGBUF_OVERFLOW);
while (repc-- > 0) {
}
break;
case 'u': /* conditional unicode */
goto unicode_translation;
/* FALLTHROUGH */
case 's': /* put string */
if (!repc_specified) {
if (repc == -1)
return (SMB_MSGBUF_OVERFLOW);
repc++;
}
return (SMB_MSGBUF_OVERFLOW);
while (repc > 0) {
if (count < 0)
return (SMB_MSGBUF_DATA_ERROR);
if (wchar == 0)
break;
repc--;
if (wchar & 0xff00) {
repc--;
}
}
repc--;
}
while (repc > 0) {
repc--;
}
break;
case 'U': /* put unicode string */
/*
* Unicode strings are always word aligned.
*/
if (!repc_specified) {
repc += 2;
}
return (SMB_MSGBUF_OVERFLOW);
while (repc >= 2) {
if (count < 0)
return (SMB_MSGBUF_DATA_ERROR);
if (wchar == 0)
break;
repc -= 2;
}
repc -= 2;
}
while (repc > 0) {
repc--;
}
break;
case 'M':
return (SMB_MSGBUF_OVERFLOW);
break;
default:
return (SMB_MSGBUF_INVALID_FORMAT);
}
}
return (SMB_MSGBUF_SUCCESS);
}
/*
* smb_msgbuf_malloc
*
* Allocate some memory for use with this smb_msgbuf. We increase the
* requested size to hold the list pointer and return a pointer
* to the area for use by the caller.
*/
static void *
{
size += sizeof (smb_msgbuf_mlist_t);
#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
return (NULL);
#else
#endif
/*
* The caller gets a pointer to the address
* immediately after the smb_msgbuf_mlist_t.
*/
return ((void *)(item + 1));
}
/*
* smb_msgbuf_chkerc
*
* Diagnostic function to write an appropriate message to the system log.
*/
static int
{
static struct {
int erc;
char *name;
} etable[] = {
{ SMB_MSGBUF_SUCCESS, "success" },
{ SMB_MSGBUF_UNDERFLOW, "overflow/underflow" },
{ SMB_MSGBUF_INVALID_FORMAT, "invalid format" },
{ SMB_MSGBUF_INVALID_HEADER, "invalid header" },
{ SMB_MSGBUF_DATA_ERROR, "data error" }
};
int i;
if (text == 0)
text = "smb_msgbuf_chkerc";
break;
}
}
return (erc);
}