cake
/
libp7
Archived
1
0
Fork 1
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libp7/src/protocol/seven/command.c

267 lines
8.2 KiB
C

/* *****************************************************************************
* protocol/seven/command.c -- the command utilities.
* Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
*
* This file is part of libp7.
* libp7 is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3.0 of the License,
* or (at your option) any later version.
*
* libp7 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libp7; if not, see <http://www.gnu.org/licenses/>.
*
* Actually, most of the commands have the same format, so most are inline
* functions defined in `libp7/packetio.h`. These are the functions for the
* general format, and the commands with custom formats.
* ************************************************************************** */
#include <libp7/internals.h>
#include <stdlib.h>
#include <string.h>
/* ************************************************************************** */
/* Macros */
/* ************************************************************************** */
/* if command is not supported, return */
#define CHECK_IF_COMMAND_IS_SUPPORTED(N) \
if (!command_is_supported(N)) \
return (p7_error_unsupported);
/**
* p7_send_cmd:
* Send command packet without data field.
*
* Used to perform or request actions. The subtype selects the action.
*
* @arg handle the libp7 handle
* @arg subtype the subcommand
* @return if it worked
*/
int p7_send_cmd(p7_handle_t *handle, p7ushort_t subtype)
{
CHECK_IF_COMMAND_IS_SUPPORTED(subtype)
/* save last sent command */
handle->_last_sent_command = subtype;
/* send */
return (p7_send_basic(handle, p7_pt_cmd, subtype, 1));
}
/**
* p7_send_cmd_data:
* Send command packet with data field.
*
* Used to perform or request actions. The subtype selects the action.
*
* @arg handle the libp7 handle
* @arg subtype The subcommand
* @arg overwrite Mode of operation if a file exists
* @arg datatype MCS data type
* @arg filesize the filesize
* @arg arg1 first command argument
* @arg arg2 second command argument
* @arg arg3 third command argument
* @arg arg4 fourth command argument
* @arg arg5 fifth command argument
* @arg arg6 sixth command argument
* @return if it worked
*/
int p7_send_cmd_data(p7_handle_t *handle, p7ushort_t subtype,
int overwrite, p7ushort_t datatype, p7uint_t filesize,
const char *arg1, const char *arg2, const char *arg3,
const char *arg4, const char *arg5, const char *arg6)
{
CHECK_IF_COMMAND_IS_SUPPORTED(subtype)
/* save last sent command */
handle->_last_sent_command = subtype;
/* get args length */
size_t l1 = arg1 ? strlen(arg1) : 0;
size_t l2 = arg2 ? strlen(arg2) : 0;
size_t l3 = arg3 ? strlen(arg3) : 0;
size_t l4 = arg4 ? strlen(arg4) : 0;
size_t l5 = arg5 ? strlen(arg5) : 0;
size_t l6 = arg6 ? strlen(arg6) : 0;
/* prepare data buffer */
unsigned int buflen = (unsigned int)(24 + l1 + l2 + l3 + l4 + l5 + l6);
unsigned char buf[buflen];
/* put info */
p7_putascii(buf, overwrite, 2);
p7_putascii(&buf[2], datatype, 2);
p7_putascii(&buf[4], filesize, 8);
p7_putascii(&buf[12], l1, 2);
p7_putascii(&buf[14], l2, 2);
p7_putascii(&buf[16], l3, 2);
p7_putascii(&buf[18], l4, 2);
p7_putascii(&buf[20], l5, 2);
p7_putascii(&buf[22], l6, 2);
/* put strings */
unsigned char *b = &buf[24];
memcpy(b, arg1, l1); b += l1;
memcpy(b, arg2, l2); b += l2;
memcpy(b, arg3, l3); b += l3;
memcpy(b, arg4, l4); b += l4;
memcpy(b, arg5, l5); b += l5;
memcpy(b, arg6, l6);
/* send */
return (p7_send_ext(handle, p7_pt_cmd, subtype, buf, buflen, 1));
}
/* ************************************************************************** */
/* Special commands */
/* ************************************************************************** */
/**
* p7_send_cmdsys_setlink:
* Set link settings.
*
* No input validation: we're trusting the user here.
*
* @arg handle the libp7 handle.
* @arg baudrate the baud rate.
* @arg parity the parity (0 for none, 1 for odd, 2 for even).
* @arg stopbits the number of stop bits (1 or 2).
* @return if it worked.
*/
int p7_send_cmdsys_setlink(p7_handle_t *handle,
int baudrate, int parity, int stopbits)
{
/* check if is a serial connexion */
if (~handle->_flags & p7_intflag_serial) return (p7_error_unsupported);
/* make arguments */
char sbaud[10], sparity[10], sstopbits[2];
sprintf(sbaud, "%d", baudrate >= 0 && baudrate < 1000000 ? baudrate : 9600);
sprintf(sstopbits, "%d", (stopbits >= 2) + 1);
if (!parity) strcpy(sparity, "NONE");
else if (parity % 2) strcpy(sparity, "ODD");
else strcpy(sparity, "EVEN");
/* send the command and receive answer */
return (p7_send_cmd_data(handle, 0x02, 0, 0, 0,
sbaud, sparity, sstopbits, NULL, NULL, NULL));
}
/**
* p7_send_cmdosu_upandrun:
* Upload and run a binary.
*
* Risky and can only be interpreted by bootcode (OS Update mode).
*
* @arg handle the libp7 handle
* @arg upsize the uploaded file size
* @arg loadaddr the load address (usually 0x88030000)
* @arg straddr the start adress (usually 0x88030000)
* @return if it worked
*/
int p7_send_cmdosu_upandrun(p7_handle_t *handle,
p7uint_t upsize, p7uint_t loadaddr, p7uint_t straddr)
{
CHECK_IF_COMMAND_IS_SUPPORTED(0x56)
/* save last sent command */
handle->_last_sent_command = 0x56;
/* prepare data buffer */
unsigned int buflen = 8 + 8 + 8;
unsigned char buf[buflen];
/* put info */
p7_putascii(buf, upsize, 8);
p7_putascii(&buf[8], loadaddr, 8);
p7_putascii(&buf[16], straddr, 8);
/* send packet */
return (p7_send_ext(handle, p7_pt_cmd, 0x56, buf, buflen, 1));
}
/* ************************************************************************** */
/* Decode incoming packet */
/* ************************************************************************** */
/* macro to copy an argument into the packet */
#define cpy_arg(I) { \
size_t ALEN = arglengths[I]; \
memcpy(packet->_argsdata[I], p, ALEN); \
packet->_argsdata[I][ALEN] = 0; \
packet->args[I] = ALEN ? packet->_argsdata[I] : NULL; \
p += ALEN; \
\
log_info("D%d is '%s'", I, packet->args[I]); }
/**
* p7_decode_command:
* Get data from command data field.
*
* Layout is described in the fxReverse projet documentation.
*
* @arg handle the handle
* @arg raw the raw data
* @arg raw_size the raw data size
* @return if there was an error
*/
int p7_decode_command(p7_handle_t *handle,
const unsigned char *raw, size_t raw_size)
{
p7_packet_t *packet = &handle->_response;
/* check up_and_run command */
if (packet->code == 0x56) {
if (raw_size != 12) return (1);
packet->uploadsize = p7_getascii(raw, 4);
packet->loadaddr = p7_getascii(&raw[4], 4);
packet->straddr = p7_getascii(&raw[8], 4);
return (0);
}
/* check minimum size */
if (raw_size < 24) return (1);
/* get overwrite */
packet->ow = p7_getascii(raw, 2);
log_info("overwrite mode is '%s' (0x%02x)",
p7_getowstring(packet->ow), packet->ow);
/* get data type (?) */
packet->mcstype = p7_getascii(&raw[2], 2);
log_info("datatype is *todo: put MCS datatypes* (0x%02x)", packet->mcstype);
/* filesize */
packet->filesize = p7_getascii(&raw[4], 8);
log_info("filesize is %" PRIuP7INT "o", packet->filesize);
/* args length */
size_t arglengths[6] = {
p7_getascii(&raw[12], 2), p7_getascii(&raw[14], 2),
p7_getascii(&raw[16], 2), p7_getascii(&raw[18], 2),
p7_getascii(&raw[20], 2), p7_getascii(&raw[22], 2)
};
size_t total_args = arglengths[0] + arglengths[1]
+ arglengths[2] + arglengths[3] + arglengths[4]
+ arglengths[5];
/* re-check size */
if (raw_size != 24 + total_args) return (1);
/* copy the arguments */
const unsigned char *p = &raw[24];
cpy_arg(0) cpy_arg(1) cpy_arg(2)
cpy_arg(3) cpy_arg(4) cpy_arg(5)
/* it worked */
return (0);
}