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.
656 lines
16 KiB
656 lines
16 KiB
4 years ago
|
/*
|
||
|
* $Id: cmp.c,v 1.41 2006/11/07 21:13:24 adridg Exp $
|
||
|
*
|
||
|
* cmp.c: Pilot Connection Management Protocol
|
||
|
*
|
||
|
* Copyright (c) 1996, Kenneth Albanowski.
|
||
|
* Copyright (c) 1999, Tilo Christ
|
||
|
*
|
||
|
* 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 "pi-debug.h"
|
||
|
#include "pi-source.h"
|
||
|
#include "pi-socket.h"
|
||
|
#include "pi-padp.h"
|
||
|
#include "pi-cmp.h"
|
||
|
#include "pi-error.h"
|
||
|
|
||
|
/* Declare prototypes */
|
||
|
static int cmp_flush(pi_socket_t *ps, int flags);
|
||
|
static int cmp_getsockopt(pi_socket_t *ps, int level, int option_name,
|
||
|
void *option_value, size_t *option_len);
|
||
|
static int cmp_setsockopt(pi_socket_t *ps, int level, int option_name,
|
||
|
const void *option_value, size_t *option_len);
|
||
|
|
||
|
static pi_protocol_t *cmp_protocol_dup (pi_protocol_t *prot);
|
||
|
static void cmp_protocol_free (pi_protocol_t *prot);
|
||
|
|
||
|
/* Protocol Functions */
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_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*
|
||
|
cmp_protocol_dup (pi_protocol_t *prot)
|
||
|
{
|
||
|
pi_protocol_t *new_prot;
|
||
|
|
||
|
struct pi_cmp_data *data,
|
||
|
*new_data;
|
||
|
|
||
|
new_prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t));
|
||
|
new_data = (struct pi_cmp_data *)malloc (sizeof (struct pi_cmp_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_cmp_data *)prot->data;
|
||
|
new_data->type = data->type;
|
||
|
new_data->flags = data->flags;
|
||
|
new_data->version = data->version;
|
||
|
new_data->baudrate = data->baudrate;
|
||
|
|
||
|
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: cmp_protocol_free
|
||
|
*
|
||
|
* Summary: frees an existing pi_protocol struct
|
||
|
*
|
||
|
* Parameters: pi_protocol_t*
|
||
|
*
|
||
|
* Returns: void
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static void
|
||
|
cmp_protocol_free (pi_protocol_t *prot)
|
||
|
{
|
||
|
if (prot != NULL) {
|
||
|
if (prot->data != NULL)
|
||
|
free(prot->data);
|
||
|
free(prot);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_protocol
|
||
|
*
|
||
|
* Summary: creates and inits pi_protocol struct instance
|
||
|
*
|
||
|
* Parameters: void
|
||
|
*
|
||
|
* Returns: pi_protocol_t* or NULL if operation failed
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
pi_protocol_t*
|
||
|
cmp_protocol (void)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
|
||
|
prot = (pi_protocol_t *)malloc (sizeof (pi_protocol_t));
|
||
|
data = (struct pi_cmp_data *)malloc (sizeof (struct pi_cmp_data));
|
||
|
|
||
|
if (prot != NULL && data != NULL) {
|
||
|
prot->level = PI_LEVEL_CMP;
|
||
|
prot->dup = cmp_protocol_dup;
|
||
|
prot->free = cmp_protocol_free;
|
||
|
prot->read = cmp_rx;
|
||
|
prot->write = cmp_tx;
|
||
|
prot->flush = cmp_flush;
|
||
|
prot->getsockopt = cmp_getsockopt;
|
||
|
prot->setsockopt = cmp_setsockopt;
|
||
|
|
||
|
data->type = 0;
|
||
|
data->flags = 0;
|
||
|
data->version = 0;
|
||
|
data->baudrate = 0;
|
||
|
|
||
|
prot->data = data;
|
||
|
|
||
|
} else if (prot != NULL) {
|
||
|
free(prot);
|
||
|
prot = NULL;
|
||
|
} else if (data != NULL) {
|
||
|
free(data);
|
||
|
data = NULL;
|
||
|
}
|
||
|
|
||
|
return prot;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_rx_handshake
|
||
|
*
|
||
|
* Summary: establishes RX handshake
|
||
|
*
|
||
|
* Parameters: pi_socket_t*, baudrate, hirate enable
|
||
|
*
|
||
|
* Returns: 0 for success, negative otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int
|
||
|
cmp_rx_handshake(pi_socket_t *ps, int establishrate,
|
||
|
int establishhighrate)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
pi_buffer_t *buf;
|
||
|
int bytes;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
|
||
|
/* Read the cmp packet */
|
||
|
buf = pi_buffer_new (PI_CMP_HEADER_LEN);
|
||
|
if (buf == NULL) {
|
||
|
errno = ENOMEM;
|
||
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY);
|
||
|
}
|
||
|
|
||
|
bytes = cmp_rx(ps, buf, PI_CMP_HEADER_LEN, 0);
|
||
|
|
||
|
pi_buffer_free (buf);
|
||
|
if (bytes < 0)
|
||
|
return bytes;
|
||
|
|
||
|
if ((data->version & 0xFF00) == 0x0100) {
|
||
|
if (establishrate != -1) {
|
||
|
if (establishrate > data->baudrate) {
|
||
|
if (establishhighrate) {
|
||
|
LOG((PI_DBG_CMP, PI_DBG_LVL_INFO,
|
||
|
"CMP Establishing higher rate %ul (%ul)\n",
|
||
|
establishrate, data->baudrate));
|
||
|
data->baudrate = establishrate;
|
||
|
}
|
||
|
} else {
|
||
|
data->baudrate = establishrate;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((bytes = cmp_init(ps, data->baudrate)) < 0)
|
||
|
return bytes;
|
||
|
} else {
|
||
|
/* 0x80 means the comm version wasn't compatible */
|
||
|
LOG((PI_DBG_CMP, PI_DBG_LVL_ERR, "CMP Incompatible Version\n"));
|
||
|
cmp_abort(ps, 0x80);
|
||
|
errno = ECONNREFUSED;
|
||
|
return pi_set_error(ps->sd, PI_ERR_PROT_INCOMPATIBLE);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_tx_handshake
|
||
|
*
|
||
|
* Summary: establishes TX handshake
|
||
|
*
|
||
|
* Parameters: pi_socket_t*
|
||
|
*
|
||
|
* Returns: >= 0 for success, negative otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int
|
||
|
cmp_tx_handshake(pi_socket_t *ps)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
int result;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
|
||
|
if ((result = cmp_wakeup(ps, 38400)) < 0) /* Assume box can't go over 38400 */
|
||
|
return result;
|
||
|
|
||
|
if ((result = cmp_rx(ps, NULL, 0, 0)) < 0)
|
||
|
return result; /* failed to read, errno already set */
|
||
|
|
||
|
switch (data->type) {
|
||
|
case PI_CMP_TYPE_INIT:
|
||
|
return 0;
|
||
|
case PI_CMP_TYPE_ABRT:
|
||
|
LOG((PI_DBG_CMP, PI_DBG_LVL_NONE,
|
||
|
"CMP Aborted by other end\n"));
|
||
|
errno = -EIO;
|
||
|
return pi_set_error(ps->sd, PI_ERR_PROT_ABORTED);
|
||
|
}
|
||
|
|
||
|
return PI_ERR_PROT_INCOMPATIBLE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_tx
|
||
|
*
|
||
|
* Summary: Transmit CMP Packets
|
||
|
*
|
||
|
* Parameters: pi_socket_t*, char* to buf, buf length, flags
|
||
|
*
|
||
|
* Returns: A negative number on error, 0 otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
ssize_t
|
||
|
cmp_tx(pi_socket_t *ps, const unsigned char *buf, size_t len, int flags)
|
||
|
{
|
||
|
int bytes,
|
||
|
type;
|
||
|
size_t size;
|
||
|
pi_protocol_t *prot,
|
||
|
*next;
|
||
|
struct pi_cmp_data *data;
|
||
|
unsigned char cmp_buf[PI_CMP_HEADER_LEN];
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
next = pi_protocol_next(ps->sd, PI_LEVEL_CMP);
|
||
|
if (next == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
type = padData;
|
||
|
size = sizeof(type);
|
||
|
pi_setsockopt(ps->sd, PI_LEVEL_PADP, PI_PADP_TYPE, &type, &size);
|
||
|
|
||
|
set_byte(&cmp_buf[PI_CMP_OFFSET_TYPE], data->type);
|
||
|
set_byte(&cmp_buf[PI_CMP_OFFSET_FLGS], data->flags);
|
||
|
set_short(&cmp_buf[PI_CMP_OFFSET_VERS], data->version > PI_CMP_VERSION ? PI_CMP_VERSION : data->version);
|
||
|
set_short(&cmp_buf[PI_CMP_OFFSET_RESV], 0);
|
||
|
set_long(&cmp_buf[PI_CMP_OFFSET_BAUD], data->baudrate);
|
||
|
|
||
|
CHECK(PI_DBG_CMP, PI_DBG_LVL_INFO, cmp_dump(cmp_buf, 1));
|
||
|
|
||
|
bytes = next->write(ps, cmp_buf, PI_CMP_HEADER_LEN, flags);
|
||
|
if (bytes < 10)
|
||
|
return (bytes < 0) ? bytes : pi_set_error(ps->sd, PI_ERR_PROT_ABORTED);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_rx
|
||
|
*
|
||
|
* Summary: Receive CMP packets
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: A negative number on error, 0 otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
ssize_t
|
||
|
cmp_rx(pi_socket_t *ps, pi_buffer_t *msg, size_t len, int flags)
|
||
|
{
|
||
|
int bytes;
|
||
|
pi_protocol_t *prot,
|
||
|
*next;
|
||
|
struct pi_cmp_data *data;
|
||
|
|
||
|
LOG((PI_DBG_CMP, PI_DBG_LVL_DEBUG, "CMP RX len=%d flags=0x%02x\n",
|
||
|
len, flags));
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
next = pi_protocol_next(ps->sd, PI_LEVEL_CMP);
|
||
|
if (next == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
bytes = next->read(ps, msg, len, flags);
|
||
|
if (bytes < 10)
|
||
|
return pi_set_error(ps->sd, (bytes < 0) ? bytes : PI_ERR_PROT_ABORTED);
|
||
|
|
||
|
CHECK(PI_DBG_CMP, PI_DBG_LVL_INFO, cmp_dump(msg->data, 0));
|
||
|
|
||
|
data->type = get_byte(&msg->data[PI_CMP_OFFSET_TYPE]);
|
||
|
data->flags = get_byte(&msg->data[PI_CMP_OFFSET_FLGS]);
|
||
|
data->version = get_short(&msg->data[PI_CMP_OFFSET_VERS]);
|
||
|
data->baudrate = get_long(&msg->data[PI_CMP_OFFSET_BAUD]);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_flush
|
||
|
*
|
||
|
* Summary: Flush input and output buffers
|
||
|
*
|
||
|
* Parameters: pi_socket_t*, flags
|
||
|
*
|
||
|
* Returns: A negative number on error, 0 otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
cmp_flush(pi_socket_t *ps, int flags)
|
||
|
{
|
||
|
pi_protocol_t *prot,
|
||
|
*next;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
next = pi_protocol_next(ps->sd, PI_LEVEL_CMP);
|
||
|
if (next == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
return next->flush(ps, flags);
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_init
|
||
|
*
|
||
|
* Summary: Initialize the socket for CMP transmission
|
||
|
*
|
||
|
* Parameters: pi_socket_t*, baudrate
|
||
|
*
|
||
|
* Returns: Number of packets transmitted
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int
|
||
|
cmp_init(pi_socket_t *ps, int baudrate)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
|
||
|
data->type = PI_CMP_TYPE_INIT;
|
||
|
data->flags = CMP_FL_LONG_PACKET_SUPPORT;
|
||
|
if (baudrate != 9600)
|
||
|
data->flags = CMP_FL_CHANGE_BAUD_RATE;
|
||
|
data->baudrate = baudrate;
|
||
|
|
||
|
return cmp_tx(ps, NULL, 0, 0);
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_abort
|
||
|
*
|
||
|
* Summary: Abort a CMP session in progress
|
||
|
*
|
||
|
* Parameters: pi_socket_t*
|
||
|
*
|
||
|
* Returns: Number of PADP packets transmitted or negative on error
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int
|
||
|
cmp_abort(pi_socket_t *ps, int reason)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
data->type = PI_CMP_TYPE_ABRT;
|
||
|
data->flags = reason;
|
||
|
|
||
|
LOG((PI_DBG_CMP, PI_DBG_LVL_NONE, "CMP ABORT\n"));
|
||
|
|
||
|
return cmp_tx (ps, NULL, 0, 0);
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_wakeup
|
||
|
*
|
||
|
* Summary: Wakeup the CMP listener process
|
||
|
*
|
||
|
* Parameters: pi_socket_t*
|
||
|
*
|
||
|
* Returns: Number of PADP packets transmitted or negative on error
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int
|
||
|
cmp_wakeup(pi_socket_t *ps, int maxbaud)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
data->type = PI_CMP_TYPE_WAKE;
|
||
|
data->flags = 0;
|
||
|
data->version = PI_CMP_VERSION;
|
||
|
data->baudrate = maxbaud;
|
||
|
|
||
|
return cmp_tx(ps, NULL, 0, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_getsockopt
|
||
|
*
|
||
|
* Summary: get options on socket
|
||
|
*
|
||
|
* Parameters: pi_socket*, level, option name, option value, option length
|
||
|
*
|
||
|
* Returns: 0 for success, negative otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
cmp_getsockopt(pi_socket_t *ps, int level, int option_name,
|
||
|
void *option_value, size_t *option_len)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_cmp_data *data;
|
||
|
|
||
|
(void) level;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_CMP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
data = (struct pi_cmp_data *)prot->data;
|
||
|
|
||
|
switch (option_name) {
|
||
|
case PI_CMP_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_CMP_FLAGS:
|
||
|
if (*option_len != sizeof (data->flags))
|
||
|
goto error;
|
||
|
memcpy (option_value, &data->flags,
|
||
|
sizeof (data->flags));
|
||
|
*option_len = sizeof (data->flags);
|
||
|
break;
|
||
|
|
||
|
case PI_CMP_VERS:
|
||
|
if (*option_len != sizeof (data->version))
|
||
|
goto error;
|
||
|
memcpy (option_value, &data->version,
|
||
|
sizeof (data->version));
|
||
|
*option_len = sizeof (data->version);
|
||
|
break;
|
||
|
|
||
|
case PI_CMP_BAUD:
|
||
|
if (*option_len != sizeof (data->baudrate))
|
||
|
goto error;
|
||
|
memcpy (option_value, &data->baudrate,
|
||
|
sizeof (data->baudrate));
|
||
|
*option_len = sizeof (data->baudrate);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
error:
|
||
|
errno = EINVAL;
|
||
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_setsockopt
|
||
|
*
|
||
|
* Summary: set options on socket
|
||
|
*
|
||
|
* Parameters: pi_socket*, level, option name, option value, option length
|
||
|
*
|
||
|
* Returns: 0 for success, negative otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
cmp_setsockopt(pi_socket_t *ps, int level, int option_name,
|
||
|
const void *option_value, size_t *option_len)
|
||
|
{
|
||
|
pi_protocol_t *prot;
|
||
|
struct pi_padp_data *data;
|
||
|
|
||
|
(void) level;
|
||
|
|
||
|
prot = pi_protocol(ps->sd, PI_LEVEL_PADP);
|
||
|
if (prot == NULL)
|
||
|
return pi_set_error(ps->sd, PI_ERR_SOCK_INVALID);
|
||
|
data = (struct pi_padp_data *)prot->data;
|
||
|
|
||
|
if (option_name == PI_PADP_TYPE) {
|
||
|
if (*option_len != sizeof (data->type))
|
||
|
goto error;
|
||
|
memcpy (&data->type, option_value,
|
||
|
sizeof (data->type));
|
||
|
*option_len = sizeof (data->type);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
error:
|
||
|
errno = EINVAL;
|
||
|
return pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: cmp_dump
|
||
|
*
|
||
|
* Summary: Dump the CMP packet frames
|
||
|
*
|
||
|
* Parameters: char* to cmp packet, TX boolean
|
||
|
*
|
||
|
* Returns: void
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
void
|
||
|
cmp_dump(const unsigned char *cmp, int rxtx)
|
||
|
{
|
||
|
char *type;
|
||
|
|
||
|
(void) rxtx;
|
||
|
|
||
|
switch (get_byte(&cmp[PI_CMP_OFFSET_TYPE])) {
|
||
|
case PI_CMP_TYPE_WAKE:
|
||
|
type = "WAKE";
|
||
|
break;
|
||
|
case PI_CMP_TYPE_INIT:
|
||
|
type = "INIT";
|
||
|
break;
|
||
|
case PI_CMP_TYPE_ABRT:
|
||
|
type = "ABRT";
|
||
|
break;
|
||
|
default:
|
||
|
type = "UNK";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
LOG((PI_DBG_CMP, PI_DBG_LVL_NONE,
|
||
|
"CMP %s %s Type: 0x%02x Flags: 0x%02x Version: 0x%04x Baud: %d\n",
|
||
|
rxtx ? "TX" : "RX", type,
|
||
|
get_byte(&cmp[PI_CMP_OFFSET_TYPE]),
|
||
|
get_byte(&cmp[PI_CMP_OFFSET_FLGS]),
|
||
|
get_long(&cmp[PI_CMP_OFFSET_VERS]),
|
||
|
get_long(&cmp[PI_CMP_OFFSET_BAUD])));
|
||
|
}
|
||
|
|
||
|
/* 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: */
|