libp7/src/packet/ack.c

302 lines
9.7 KiB
C

/* ************************************************************************** */
/* _____ _ */
/* packet/ack.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: libp7 | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2017/01/04 15:01:48 |___/ */
/* */
/* ************************************************************************** */
#include <libp7/internals.h>
#include <string.h>
/* ************************************************************************** */
/* Raw layout of an extended ack data */
/* ************************************************************************** */
typedef struct {
/* hardware identifier - ASCII */
unsigned char hwid[8];
/* processor identifier - ASCII */
unsigned char cpuid[16];
/* preprogrammed ROM capacity - ASCII-hex (Ko) */
unsigned char preprog_rom_capacity[8];
/* flash ROM capacity - ASCII-hex (Ko) */
unsigned char flash_rom_capacity[8];
/* RAM capacity - ASCII-hex (Ko) */
unsigned char ram_capacity[8];
/* preprogrammed ROM version - "xx.xx.xxxx" + 0xff bytes */
unsigned char preprog_rom_version[16];
/* bootcode version - "xx.xx.xxxx" + 0xff bytes */
unsigned char bootcode_version[16];
/* bootcode offset - ASCII-hex */
unsigned char bootcode_offset[8];
/* bootcode size - ASCII-hex (Ko) */
unsigned char bootcode_size[8];
/* OS version - "xx.xx.xxxx" + 0xff bytes */
unsigned char os_version[16];
/* OS offset - ASCII-hex */
unsigned char os_offset[8];
/* OS size - ASCII-hex (Ko) */
unsigned char os_size[8];
/* protocol version - "x.xx" */
unsigned char protocol_version[4];
/* product ID */
unsigned char product_id[16];
/* name set by user in SYSTEM */
unsigned char username[16];
} packetdata_ackext_t;
/* ************************************************************************** */
/* Utilities */
/* ************************************************************************** */
/**
* version_of_string:
* Get version from 16-bytes char buffer.
*
* data is not a string as it doesn't finish with an '\0'.
*
* @arg ver the version destination
* @arg data the raw version data ("xx.xx.xx" + type)
*/
static void version_of_string(p7_version_t *ver, const unsigned char *data)
{
ver->major = p7_getdec(p7_getascii(data, 2));
ver->minor = p7_getdec(p7_getascii(&data[3], 2));
ver->rev = p7_getdec(p7_getascii(&data[6], 4));
}
/**
* string_of_version:
* Put version in 16-bytes char buffer.
*
* @arg ver the version source.
* @arg data the raw version data destination ("xx.xx.xx" + type).
*/
static void string_of_version(unsigned char *data, const p7_version_t *ver)
{
/* put data */
memcpy(data, "xx.xx.xxxx\xFF\xFF\xFF\xFF\xFF\xFF", 16);
p7_putascii(data, p7_gethex(ver->major), 2);
p7_putascii(&data[3], p7_gethex(ver->minor), 2);
p7_putascii(&data[6], p7_gethex(ver->rev), 4);
}
/* ************************************************************************** */
/* Send ACK packets */
/* ************************************************************************** */
/**
* p7_send_ack:
* Send basic command acknowledge.
*
* Default response at successful packet reception.
*
* @arg handle the libp7 handle
* @arg resp get response or not
* @return the error code (0 if ok).
*/
int p7_send_ack(p7_handle_t *handle, int resp)
{
return (p7_send_basic(handle, p7_pt_ack, 0x00, resp));
}
/**
* p7_confirm_ow:
* Sends overwrite confirmation.
*
* @arg handle the libp7 handle
* @return the error code (0 if ok)
*/
int p7_confirm_ow(p7_handle_t *handle)
{
return (p7_send_basic(handle, p7_pt_ack, 0x01, 1));
}
/**
* p7_send_eack:
* Sends an extended ack.
*
* @arg handle the libp7 handle
* @arg info the libp7 server info to return.
* @return the error code (0 if ok)
*/
int p7_send_eack(p7_handle_t *handle, p7_server_t *info)
{
packetdata_ackext_t raw;
/* initialize the structure with 0xFFs */
memset(&raw, 0xFF, sizeof(packetdata_ackext_t));
/* put in the structure */
memcpy(raw.hwid, info->hwid, strnlen(info->hwid, 8));
memcpy(raw.cpuid, info->cpuid, strnlen(info->cpuid, 16));
if (!info->preprog_rom_wiped) {
p7_putascii(raw.preprog_rom_capacity, info->preprog_rom_capacity, 8);
string_of_version(raw.preprog_rom_version, &info->preprog_rom_version);
}
p7_putascii(raw.flash_rom_capacity,
p7_gethex(info->flash_rom_capacity / 1024), 8);
p7_putascii(raw.ram_capacity,
p7_gethex(info->ram_capacity / 1024), 8);
if (!info->bootcode_wiped) {
string_of_version(raw.bootcode_version, &info->bootcode_version);
p7_putascii(raw.bootcode_offset, info->bootcode_offset, 8);
p7_putascii(raw.bootcode_size,
p7_gethex(info->bootcode_size / 1024), 8);
}
if (!info->os_wiped) {
string_of_version(raw.os_version, &info->os_version);
p7_putascii(raw.os_offset, info->os_offset, 8);
p7_putascii(raw.os_size,
p7_gethex(info->os_size / 1024), 8);
}
memcpy(raw.protocol_version, "7.00", 4);
memcpy(raw.product_id, info->product_id, strnlen(info->product_id, 16));
memcpy(raw.username, info->username, strnlen(info->username, 16));
/* send the packet */
return (p7_send_ext(handle, p7_pt_ack, 0x02, &raw,
sizeof(packetdata_ackext_t), 1));
}
/* ************************************************************************** */
/* Decode an ACK packet */
/* ************************************************************************** */
/**
* cpy_string:
* Copy a string terminated with 0xFFs, with a maximum size.
*
* @arg dest the destination string.
* @arg src the source string.
* @arg n the maximum size of the string.
*/
static inline void cpy_string(char *dest, const char *src, size_t n)
{
const char *l = memchr(src, 0xFF, n);
memset(dest, 0, n + 1);
memcpy(dest, src, l ? (size_t)(l - src) : n);
}
/**
* p7_decode_ack:
* Get data from ack data field.
*
* Layout is described in the fxReverse projet documentation.
*
* @arg handle the handle
* @arg data the raw data
* @arg data_size the raw data size
* @return if there was an error
*/
int p7_decode_ack(p7_handle_t *handle,
const unsigned char *data, size_t data_size)
{
p7_packet_t *packet = handle->_response;
/* check the data size */
if (data_size != sizeof(packetdata_ackext_t)) return (1);
const packetdata_ackext_t *d = (const packetdata_ackext_t*)data;
p7_server_t *info = &packet->info;
/* log */
log_info("ack packet is extended");
/* hardware identifier */
cpy_string(info->hwid, (const char*)d->hwid, 8);
log_info("hardware identifier is '%s'", info->hwid);
/* processor identifier */
cpy_string(info->cpuid, (const char*)d->cpuid, 16);
log_info("cpu identifier is '%s'", info->cpuid);
/* preprogrammed ROM information is wiped */
info->preprog_rom_wiped = (d->preprog_rom_version[2] == 0xFF);
#if LOGLEVEL <= ll_info
if (info->preprog_rom_wiped)
log_info("Preprogrammed ROM information looks wiped out!");
#endif
/* preprogrammed ROM capacity */
info->preprog_rom_capacity =
p7_getascii(d->preprog_rom_capacity, 8) * 1000;
log_info("preprogrammed ROM capacity is %" PRIuP7INT "o",
info->preprog_rom_capacity);
/* preprogrammed ROM version */
version_of_string(&info->preprog_rom_version, d->preprog_rom_version);
log_info("preprogrammed ROM version is %02u.%02u.%04u",
info->preprog_rom_version.major, info->preprog_rom_version.minor,
info->preprog_rom_version.rev);
/* flash ROM capacity */
info->flash_rom_capacity =
p7_getdec(p7_getascii(d->flash_rom_capacity, 8)) * 1024;
log_info("flash ROM capacity is %" PRIuP7INT "KiB",
info->flash_rom_capacity / 1024);
/* RAM capacity */
info->ram_capacity =
p7_getdec(p7_getascii(d->ram_capacity, 8)) * 1024;
log_info("RAM capacity is %" PRIuP7INT "KiB",
info->ram_capacity / 1024);
/* bootcode information is wiped */
info->bootcode_wiped = (d->bootcode_version[2] == 0xFF);
#if LOGLEVEL <= ll_info
if (info->bootcode_wiped)
log_info("Bootcode information looks wiped out!");
#endif
/* bootcode version */
version_of_string(&info->bootcode_version, d->bootcode_version);
log_info("bootcode version is %02u.%02u.%04u",
info->bootcode_version.major, info->bootcode_version.minor,
info->bootcode_version.rev);
/* bootcode offset */
info->bootcode_offset = p7_getascii(d->bootcode_offset, 8);
log_info("bootcode offset is 0x%08" PRIxP7INT, info->bootcode_offset);
/* bootcode size */
info->bootcode_size = p7_getdec(p7_getascii(d->bootcode_size, 8)) * 1024;
log_info("bootcode size is %" PRIuP7INT "KiB", info->bootcode_size / 1024);
/* OS information is wiped */
info->os_wiped = (d->os_version[2] == 0xFF);
#if LOGLEVEL <= ll_info
if (info->os_wiped)
log_info("OS information looks wiped out!");
#endif
/* OS version */
version_of_string(&info->os_version, d->os_version);
log_info("OS version is %02u.%02u.%04u",
info->os_version.major, info->os_version.minor,
info->os_version.rev);
/* OS offset */
info->os_offset = p7_getascii(d->os_offset, 8);
log_info("OS offset is 0x%08" PRIxP7INT , info->os_offset);
/* OS size */
info->os_size = p7_getdec(p7_getascii(d->os_size, 8)) * 1024;
log_info("OS size is %" PRIuP7INT "KiB", info->os_size / 1024);
/* product ID */
cpy_string(info->product_id, (const char*)d->product_id, 16);
log_info("product ID is %s", info->product_id);
/* username */
cpy_string(info->username, (const char*)d->username, 16);
log_info("username is %s", info->username);
/* no error */
return (0);
}