You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
658 lines
17 KiB
658 lines
17 KiB
/*
|
|
* $Id: slp.c,v 1.56 2006/10/13 09:52:13 fpillet Exp $
|
|
*
|
|
* slp.c: Pilot SLP protocol
|
|
*
|
|
* (c) 1996, D. Jeff Dionne.
|
|
* Much of this code adapted from Brian J. Swetland <swetland@uiuc.edu>
|
|
* Additional work Copyright (c) 2005, Florent Pillet
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Library General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include "pi-debug.h"
|
|
#include "pi-source.h"
|
|
#include "pi-serial.h"
|
|
#include "pi-slp.h"
|
|
#include "pi-error.h"
|
|
|
|
/* Declare function prototypes */
|
|
static int slp_flush(pi_socket_t *ps, int flags);
|
|
static int slp_getsockopt(pi_socket_t *ps, int level, int option_name,
|
|
void *option_value, size_t *option_len);
|
|
static int slp_setsockopt(pi_socket_t *ps, int level, int option_name,
|
|
const void *option_value, size_t *option_len);
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_protocol_dup
|
|
*
|
|
* Summary: clones an existing pi_protocol struct
|
|
*
|
|
* Parameters: pi_protocol_t*
|
|
*
|
|
* Returns: pi_protocol_t* or NULL if operation failed
|
|
*
|
|
***********************************************************************/
|
|
static pi_protocol_t*
|
|
slp_protocol_dup (pi_protocol_t *prot)
|
|
{
|
|
pi_protocol_t *new_prot;
|
|
|
|
struct pi_slp_data *data,
|
|
*new_data;
|
|
|
|
new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t));
|
|
new_data = (struct pi_slp_data *)malloc (sizeof (struct pi_slp_data));
|
|
|
|
if (new_prot != NULL && new_data != NULL) {
|
|
new_prot->level = prot->level;
|
|
new_prot->dup = prot->dup;
|
|
new_prot->free = prot->free;
|
|
new_prot->read = prot->read;
|
|
new_prot->write = prot->write;
|
|
new_prot->flush = prot->flush;
|
|
new_prot->getsockopt = prot->getsockopt;
|
|
new_prot->setsockopt = prot->setsockopt;
|
|
|
|
data = (struct pi_slp_data *)prot->data;
|
|
|
|
new_data->dest = data->dest;
|
|
new_data->last_dest = data->last_dest;
|
|
new_data->src = data->src;
|
|
new_data->last_src = data->last_src;
|
|
new_data->type = data->type;
|
|
new_data->last_type = data->last_type;
|
|
new_data->txid = data->txid;
|
|
new_data->last_txid = data->last_txid;
|
|
|
|
new_prot->data = new_data;
|
|
|
|
} else if (new_prot != NULL) {
|
|
free(new_prot);
|
|
new_prot = NULL;
|
|
} else if (new_data != NULL) {
|
|
free(new_data);
|
|
new_data = NULL;
|
|
}
|
|
|
|
return new_prot;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_protocol_free
|
|
*
|
|
* Summary: frees an existing pi_protocol struct
|
|
*
|
|
* Parameters: pi_protocol_t*
|
|
*
|
|
* Returns: void
|
|
*
|
|
***********************************************************************/
|
|
static void
|
|
slp_protocol_free (pi_protocol_t *prot)
|
|
{
|
|
if (prot != NULL) {
|
|
if (prot->data != NULL)
|
|
free(prot->data);
|
|
free(prot);
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_protocol
|
|
*
|
|
* Summary: creates a pi_protocol struct instance
|
|
*
|
|
* Parameters: pi_protocol_t*
|
|
*
|
|
* Returns: pi_protocol_t* or NULL if operation failed
|
|
*
|
|
***********************************************************************/
|
|
pi_protocol_t*
|
|
slp_protocol (void)
|
|
{
|
|
pi_protocol_t *prot;
|
|
struct pi_slp_data *data;
|
|
|
|
prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t));
|
|
data = (struct pi_slp_data *)malloc (sizeof (struct pi_slp_data));
|
|
|
|
if (prot != NULL && data != NULL) {
|
|
prot->level = PI_LEVEL_SLP;
|
|
prot->dup = slp_protocol_dup;
|
|
prot->free = slp_protocol_free;
|
|
prot->read = slp_rx;
|
|
prot->write = slp_tx;
|
|
prot->flush = slp_flush;
|
|
prot->getsockopt = slp_getsockopt;
|
|
prot->setsockopt = slp_setsockopt;
|
|
|
|
data->dest = PI_SLP_SOCK_DLP;
|
|
data->last_dest = -1;
|
|
data->src = PI_SLP_SOCK_DLP;
|
|
data->last_src = -1;
|
|
data->type = PI_SLP_TYPE_PADP;
|
|
data->last_type = -1;
|
|
data->txid = 0xfe;
|
|
data->last_txid = 0xff;
|
|
prot->data = data;
|
|
|
|
} else if (prot != NULL) {
|
|
free(prot);
|
|
prot = NULL;
|
|
} else if (data != NULL) {
|
|
free(data);
|
|
data = NULL;
|
|
}
|
|
|
|
return prot;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_tx
|
|
*
|
|
* Summary: Build and queue up an SLP packet to be transmitted
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: A negative number on error, 0 otherwise
|
|
*
|
|
***********************************************************************/
|
|
ssize_t
|
|
slp_tx(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags)
|
|
{
|
|
int bytes;
|
|
pi_protocol_t *prot,
|
|
*next;
|
|
struct pi_slp_data *data;
|
|
struct slp *slp;
|
|
unsigned char *slp_buf;
|
|
unsigned int i,
|
|
n;
|
|
|
|
prot = pi_protocol(ps->sd, PI_LEVEL_SLP);
|
|
if (prot == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
data = (struct pi_slp_data *)prot->data;
|
|
next = pi_protocol_next(ps->sd, PI_LEVEL_SLP);
|
|
if (next == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
slp_buf = (unsigned char *) malloc (PI_SLP_HEADER_LEN +
|
|
PI_SLP_MTU + PI_SLP_FOOTER_LEN);
|
|
if (slp_buf == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY);
|
|
|
|
slp = (struct slp *) slp_buf;
|
|
|
|
/* Header values */
|
|
slp->_be = 0xbe;
|
|
slp->_ef = 0xef;
|
|
slp->_ed = 0xed;
|
|
slp->dest = data->dest;
|
|
slp->src = data->src;
|
|
slp->type = data->type;
|
|
set_short(&slp->dlen, len);
|
|
slp->id_ = data->txid;
|
|
|
|
for (n = i = 0; i < 9; i++)
|
|
n += slp_buf[i];
|
|
slp->csum = 0xff & n;
|
|
|
|
/* Copy in the packet data */
|
|
memcpy (slp_buf + PI_SLP_HEADER_LEN, buf, len);
|
|
|
|
/* CRC value */
|
|
set_short(&slp_buf[PI_SLP_HEADER_LEN + len],
|
|
crc16(slp_buf, (int)(PI_SLP_HEADER_LEN + len)));
|
|
|
|
/* Write out the data */
|
|
bytes = next->write(ps, slp_buf,
|
|
PI_SLP_HEADER_LEN + len + PI_SLP_FOOTER_LEN, flags);
|
|
|
|
if (bytes >= 0) {
|
|
CHECK(PI_DBG_SLP, PI_DBG_LVL_INFO, slp_dump_header(slp_buf, 1));
|
|
CHECK(PI_DBG_SLP, PI_DBG_LVL_DEBUG, slp_dump(slp_buf));
|
|
}
|
|
|
|
free (slp_buf);
|
|
|
|
return bytes;
|
|
}
|
|
|
|
/* Sigh. SLP is a really broken protocol. It has no proper framing, so it
|
|
makes a proper "device driver" layer impossible. There ought to be a
|
|
layer below SLP that reads frames off the wire and passes them up.
|
|
Instead, all we can do is have the device driver give us bytes and SLP has
|
|
to keep a pile of status info while it builds frames for itself. So
|
|
here's the code that does that. */
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_rx
|
|
*
|
|
* Summary: Accept SLP packets on the wire
|
|
*
|
|
* Parameters: None
|
|
*
|
|
* Returns: packet length or negative on error
|
|
*
|
|
***********************************************************************/
|
|
ssize_t
|
|
slp_rx(pi_socket_t *ps, pi_buffer_t *buf, size_t len, int flags)
|
|
{
|
|
int i,
|
|
computed_crc,
|
|
received_crc,
|
|
b1,
|
|
b2,
|
|
b3,
|
|
state,
|
|
expect = 0,
|
|
packet_len,
|
|
bytes;
|
|
unsigned char
|
|
header_checksum;
|
|
pi_protocol_t *prot,
|
|
*next;
|
|
pi_buffer_t *slp_buf;
|
|
struct pi_slp_data *data;
|
|
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_DEBUG, "SLP RX len=%d flags=0x%04x\n",
|
|
len, flags));
|
|
|
|
prot = pi_protocol(ps->sd, PI_LEVEL_SLP);
|
|
if (prot == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
data = (struct pi_slp_data *)prot->data;
|
|
next = pi_protocol_next(ps->sd, PI_LEVEL_SLP);
|
|
if (next == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
slp_buf = pi_buffer_new (PI_SLP_HEADER_LEN + PI_SLP_MTU + PI_SLP_FOOTER_LEN);
|
|
if (slp_buf == NULL) {
|
|
errno = ENOMEM;
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY);
|
|
}
|
|
|
|
state = 0;
|
|
packet_len = 0;
|
|
|
|
for (;;) {
|
|
switch (state) {
|
|
case 0:
|
|
expect = 3;
|
|
state++;
|
|
break;
|
|
|
|
case 1:
|
|
b1 = slp_buf->data[PI_SLP_OFFSET_SIG1];
|
|
b2 = slp_buf->data[PI_SLP_OFFSET_SIG2];
|
|
b3 = slp_buf->data[PI_SLP_OFFSET_SIG3];
|
|
if (b1 == PI_SLP_SIG_BYTE1 &&
|
|
b2 == PI_SLP_SIG_BYTE2 &&
|
|
b3 == PI_SLP_SIG_BYTE3) {
|
|
state++;
|
|
expect = PI_SLP_HEADER_LEN - 3;
|
|
} else {
|
|
slp_buf->data[PI_SLP_OFFSET_SIG1] = slp_buf->data[PI_SLP_OFFSET_SIG2];
|
|
slp_buf->data[PI_SLP_OFFSET_SIG2] = slp_buf->data[PI_SLP_OFFSET_SIG3];
|
|
expect = 1;
|
|
slp_buf->used = 2;
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_WARN,
|
|
"SLP RX Unexpected signature"
|
|
" 0x%.2x 0x%.2x 0x%.2x\n",
|
|
b1, b2, b3));
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
/* Addition check sum for header */
|
|
for (header_checksum = i = 0; i < 9; i++)
|
|
header_checksum += slp_buf->data[i];
|
|
|
|
/* read in the whole SLP header. */
|
|
if (header_checksum == slp_buf->data[PI_SLP_OFFSET_SUM]) {
|
|
state++;
|
|
packet_len = get_short(&slp_buf->data[PI_SLP_OFFSET_SIZE]);
|
|
if (packet_len > (int)len) {
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_ERR,
|
|
"SLP RX Packet size exceed buffer\n"));
|
|
pi_buffer_free (slp_buf);
|
|
return pi_set_error(ps->sd, PI_ERR_PROT_BADPACKET);
|
|
}
|
|
expect = packet_len;
|
|
} else {
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_WARN,
|
|
"SLP RX Header checksum failed for header:\n"));
|
|
pi_dumpdata((const char *)slp_buf->data, PI_SLP_HEADER_LEN);
|
|
pi_buffer_free (slp_buf);
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
state++;
|
|
expect = PI_SLP_FOOTER_LEN;
|
|
break;
|
|
|
|
case 4:
|
|
/* that should be the whole packet. */
|
|
computed_crc = crc16(slp_buf->data, PI_SLP_HEADER_LEN + packet_len);
|
|
received_crc = get_short(&slp_buf->data[PI_SLP_HEADER_LEN + packet_len]);
|
|
if (get_byte(&slp_buf->data[PI_SLP_OFFSET_TYPE]) == PI_SLP_TYPE_LOOP) {
|
|
/* Adjust because every tenth loopback
|
|
* packet has a bogus check sum */
|
|
if (computed_crc != received_crc)
|
|
computed_crc |= 0x00e0;
|
|
}
|
|
if (computed_crc != received_crc) {
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_ERR,
|
|
"SLP RX packet crc failed: "
|
|
"computed=0x%.4x received=0x%.4x\n",
|
|
computed_crc, received_crc));
|
|
pi_buffer_free (slp_buf);
|
|
return 0;
|
|
}
|
|
|
|
/* Track the info so getsockopt will work */
|
|
data->last_dest = get_byte(&slp_buf->data[PI_SLP_OFFSET_DEST]);
|
|
data->last_src = get_byte(&slp_buf->data[PI_SLP_OFFSET_SRC]);
|
|
data->last_type = get_byte(&slp_buf->data[PI_SLP_OFFSET_TYPE]);
|
|
data->last_txid = get_byte(&slp_buf->data[PI_SLP_OFFSET_TXID]);
|
|
|
|
CHECK(PI_DBG_SLP, PI_DBG_LVL_INFO, slp_dump_header(slp_buf->data, 0));
|
|
CHECK(PI_DBG_SLP, PI_DBG_LVL_DEBUG, slp_dump(slp_buf->data));
|
|
|
|
if (pi_buffer_append (buf, &slp_buf->data[PI_SLP_HEADER_LEN], packet_len) == NULL) {
|
|
errno = ENOMEM;
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY);
|
|
}
|
|
pi_buffer_free (slp_buf);
|
|
return packet_len;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
do {
|
|
bytes = next->read(ps, slp_buf, (size_t)expect, flags);
|
|
if (bytes < 0) {
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_ERR,
|
|
"SLP RX Read Error %d\n",
|
|
bytes));
|
|
pi_buffer_free (slp_buf);
|
|
return bytes;
|
|
}
|
|
expect -= bytes;
|
|
} while (expect > 0);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_flush
|
|
*
|
|
* Summary: Flush input and output buffers
|
|
*
|
|
* Parameters: pi_socket_t*, flags
|
|
*
|
|
* Returns: A negative number on error, 0 otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
slp_flush(pi_socket_t *ps, int flags)
|
|
{
|
|
pi_protocol_t *prot,
|
|
*next;
|
|
|
|
prot = pi_protocol(ps->sd, PI_LEVEL_SLP);
|
|
if (prot == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
next = pi_protocol_next(ps->sd, PI_LEVEL_SLP);
|
|
if (next == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
return next->flush(ps, flags);
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_getsockopt
|
|
*
|
|
* Summary: get options on socket
|
|
*
|
|
* Parameters: pi_socket*, level, option name, option value, option length
|
|
*
|
|
* Returns: 0 for success, negative otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
slp_getsockopt(pi_socket_t *ps, int level, int option_name,
|
|
void *option_value, size_t *option_len)
|
|
{
|
|
pi_protocol_t *prot;
|
|
struct pi_slp_data *data;
|
|
|
|
prot = pi_protocol(ps->sd, PI_LEVEL_SLP);
|
|
if (prot == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
|
|
data = (struct pi_slp_data *)prot->data;
|
|
|
|
switch (option_name) {
|
|
case PI_SLP_DEST:
|
|
if (*option_len < sizeof (data->dest))
|
|
goto error;
|
|
memcpy (option_value, &data->dest, sizeof (data->dest));
|
|
*option_len = sizeof (data->dest);
|
|
break;
|
|
case PI_SLP_LASTDEST:
|
|
if (*option_len < sizeof (data->dest))
|
|
goto error;
|
|
memcpy (option_value, &data->last_dest,
|
|
sizeof (data->last_dest));
|
|
*option_len = sizeof (data->last_dest);
|
|
break;
|
|
case PI_SLP_SRC:
|
|
if (*option_len < sizeof (data->src))
|
|
goto error;
|
|
memcpy (option_value, &data->src,
|
|
sizeof (data->src));
|
|
*option_len = sizeof (data->src);
|
|
break;
|
|
case PI_SLP_LASTSRC:
|
|
if (*option_len < sizeof (data->last_src))
|
|
goto error;
|
|
memcpy (option_value, &data->last_src,
|
|
sizeof (data->last_src));
|
|
*option_len = sizeof (data->last_src);
|
|
break;
|
|
case PI_SLP_TYPE:
|
|
if (*option_len < sizeof (data->type))
|
|
goto error;
|
|
memcpy (option_value, &data->type,
|
|
sizeof (data->type));
|
|
*option_len = sizeof (data->type);
|
|
break;
|
|
case PI_SLP_LASTTYPE:
|
|
if (*option_len < sizeof (data->last_type))
|
|
goto error;
|
|
memcpy (option_value, &data->last_type,
|
|
sizeof (data->last_type));
|
|
*option_len = sizeof (data->last_type);
|
|
break;
|
|
case PI_SLP_TXID:
|
|
if (*option_len < sizeof (data->txid))
|
|
goto error;
|
|
memcpy (option_value, &data->txid,
|
|
sizeof (data->txid));
|
|
*option_len = sizeof (data->txid);
|
|
break;
|
|
case PI_SLP_LASTTXID:
|
|
if (*option_len < sizeof (data->last_txid))
|
|
goto error;
|
|
memcpy (option_value, &data->last_txid,
|
|
sizeof (data->last_txid));
|
|
*option_len = sizeof (data->last_txid);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
errno = EINVAL;
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_setsockopt
|
|
*
|
|
* Summary: set options on socket
|
|
*
|
|
* Parameters: pi_socket*, level, option name, option value, option length
|
|
*
|
|
* Returns: 0 for success, negative otherwise
|
|
*
|
|
***********************************************************************/
|
|
static int
|
|
slp_setsockopt(pi_socket_t *ps, int level, int option_name,
|
|
const void *option_value, size_t *option_len)
|
|
{
|
|
pi_protocol_t *prot;
|
|
struct pi_slp_data *data;
|
|
|
|
prot = pi_protocol(ps->sd, PI_LEVEL_SLP);
|
|
if (prot == NULL)
|
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
|
data = (struct pi_slp_data *)prot->data;
|
|
|
|
switch (option_name) {
|
|
case PI_SLP_DEST:
|
|
if (*option_len != sizeof (data->dest))
|
|
goto error;
|
|
memcpy (&data->dest, option_value,
|
|
sizeof (data->dest));
|
|
*option_len = sizeof (data->dest);
|
|
break;
|
|
case PI_SLP_SRC:
|
|
if (*option_len != sizeof (data->src))
|
|
goto error;
|
|
memcpy (&data->src, option_value,
|
|
sizeof (data->src));
|
|
*option_len = sizeof (data->src);
|
|
break;
|
|
case PI_SLP_TYPE:
|
|
if (*option_len != sizeof (data->type))
|
|
goto error;
|
|
memcpy (&data->type, option_value,
|
|
sizeof (data->type));
|
|
*option_len = sizeof (data->type);
|
|
break;
|
|
case PI_SLP_TXID:
|
|
if (*option_len != sizeof (data->txid))
|
|
goto error;
|
|
memcpy (&data->txid, option_value,
|
|
sizeof (data->txid));
|
|
*option_len = sizeof (data->txid);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
errno = EINVAL;
|
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_dump_header
|
|
*
|
|
* Summary: Dump the contents of the SPL frame header
|
|
*
|
|
* Parameters: char* to data buffer, RXTX flag
|
|
*
|
|
* Returns: void
|
|
*
|
|
***********************************************************************/
|
|
void
|
|
slp_dump_header(const unsigned char *data, int rxtx)
|
|
{
|
|
LOG((PI_DBG_SLP, PI_DBG_LVL_NONE,
|
|
"SLP %s %d->%d type=%d txid=0x%.2x len=0x%.4x checksum=0x%.2x\n",
|
|
rxtx ? "TX" : "RX",
|
|
get_byte(&data[PI_SLP_OFFSET_DEST]),
|
|
get_byte(&data[PI_SLP_OFFSET_SRC]),
|
|
get_byte(&data[PI_SLP_OFFSET_TYPE]),
|
|
get_byte(&data[PI_SLP_OFFSET_TXID]),
|
|
get_short(&data[PI_SLP_OFFSET_SIZE]),
|
|
get_byte(&data[PI_SLP_OFFSET_SUM])));
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Function: slp_dump
|
|
*
|
|
* Summary: Dump the contents of the SPL frame
|
|
*
|
|
* Parameters: char* to data buffer
|
|
*
|
|
* Returns: void
|
|
*
|
|
***********************************************************************/
|
|
void
|
|
slp_dump(const unsigned char *data)
|
|
{
|
|
pi_dumpdata((char *)&data[PI_SLP_HEADER_LEN], get_short(&data[PI_SLP_OFFSET_SIZE]));
|
|
}
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */
|
|
/* ex: set tabstop=4 expandtab: */
|
|
/* Local Variables: */
|
|
/* indent-tabs-mode: t */
|
|
/* c-basic-offset: 8 */
|
|
/* End: */
|