wireshark/epan/sigcomp-udvm.c
Peter Wu 4e82d2e34f sigcomp: Add buffer check to STATE-ACCESS
Two conditions were not checked, state_length == 0 && state_begin != 0
and the boundaries of the state buffer. The former is not a big deal,
but the second issue causes a buffer overrun (detected by ASAN).

The buffer size is supposed to be stored in the state buffer, that was
not the case for the initial two SIP SDP and Presence state buffers.
Fix a typo for presence_buf zero-ing while at it.

Bug: 9601
Change-Id: I41dde83185da60b670cca010ecc7b2a2aaaedeb9
Reviewed-on: https://code.wireshark.org/review/1529
Reviewed-by: Anders Broman <a.broman58@gmail.com>
2014-05-06 14:03:12 +00:00

3213 lines
109 KiB
C

/* sigcomp-udvm.c
* Routines making up the Universal Decompressor Virtual Machine (UDVM) used for
* Signaling Compression (SigComp) dissection.
* Copyright 2004, Anders Broman <anders.broman@ericsson.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* References:
* http://www.ietf.org/rfc/rfc3320.txt?number=3320
* http://www.ietf.org/rfc/rfc3321.txt?number=3321
* Useful links :
* http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-impl-guide-05.txt
* http://www.ietf.org/internet-drafts/draft-ietf-rohc-sigcomp-sip-01.txt
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <epan/emem.h>
#include <wsutil/sha1.h>
#include <wsutil/crc16.h>
#include "packet.h"
#include "exceptions.h"
#include "strutil.h"
#include "to_str.h"
#include "sigcomp-udvm.h"
#include "sigcomp_state_hdlr.h"
#include "except.h"
#define SIGCOMP_INSTR_DECOMPRESSION_FAILURE 0
#define SIGCOMP_INSTR_AND 1
#define SIGCOMP_INSTR_OR 2
#define SIGCOMP_INSTR_NOT 3
#define SIGCOMP_INSTR_LSHIFT 4
#define SIGCOMP_INSTR_RSHIFT 5
#define SIGCOMP_INSTR_ADD 6
#define SIGCOMP_INSTR_SUBTRACT 7
#define SIGCOMP_INSTR_MULTIPLY 8
#define SIGCOMP_INSTR_DIVIDE 9
#define SIGCOMP_INSTR_REMAINDER 10
#define SIGCOMP_INSTR_SORT_ASCENDING 11
#define SIGCOMP_INSTR_SORT_DESCENDING 12
#define SIGCOMP_INSTR_SHA_1 13
#define SIGCOMP_INSTR_LOAD 14
#define SIGCOMP_INSTR_MULTILOAD 15
#define SIGCOMP_INSTR_PUSH 16
#define SIGCOMP_INSTR_POP 17
#define SIGCOMP_INSTR_COPY 18
#define SIGCOMP_INSTR_COPY_LITERAL 19
#define SIGCOMP_INSTR_COPY_OFFSET 20
#define SIGCOMP_INSTR_MEMSET 21
#define SIGCOMP_INSTR_JUMP 22
#define SIGCOMP_INSTR_COMPARE 23
#define SIGCOMP_INSTR_CALL 24
#define SIGCOMP_INSTR_RETURN 25
#define SIGCOMP_INSTR_SWITCH 26
#define SIGCOMP_INSTR_CRC 27
#define SIGCOMP_INSTR_INPUT_BYTES 28
#define SIGCOMP_INSTR_INPUT_BITS 29
#define SIGCOMP_INSTR_INPUT_HUFFMAN 30
#define SIGCOMP_INSTR_STATE_ACCESS 31
#define SIGCOMP_INSTR_STATE_CREATE 32
#define SIGCOMP_INSTR_STATE_FREE 33
#define SIGCOMP_INSTR_OUTPUT 34
#define SIGCOMP_INSTR_END_MESSAGE 35
static gboolean print_level_1;
static gboolean print_level_2;
static gboolean print_level_3;
static gint show_instr_detail_level;
/* Internal result code values of decompression failures */
const value_string result_code_vals[] = {
{ 0, "No decompression failure" },
{ 1, "Partial state length less than 6 or greater than 20 bytes long" },
{ 2, "No state match" },
{ 3, "state_begin + state_length > size of state" },
{ 4, "Operand_2 is Zero" },
{ 5, "Switch statement failed j >= n" },
{ 6, "Attempt to jump outside of UDVM memory" },
{ 7, "L in input-bits > 16" },
{ 8, "input_bit_order > 7" },
{ 9, "Instruction Decompression failure encountered" },
{10, "Input huffman failed j > n" },
{11, "Input bits requested beyond end of message" },
{12, "more than four state creation requests are made before the END-MESSAGE instruction" },
{13, "state_retention_priority is 65535" },
{14, "Input bytes requested beyond end of message" },
{15, "Maximum number of UDVM cycles reached" },
{16, "UDVM stack underflow" },
{17, "state_length is 0, but state_begin is non-zero" },
{ 255, "This branch isn't coded yet" },
{ 0, NULL }
};
static int decode_udvm_literal_operand(guint8 *buff,guint operand_address, guint16 *value);
static int dissect_udvm_reference_operand(guint8 *buff,guint operand_address, guint16 *value, guint *result_dest);
static int decode_udvm_multitype_operand(guint8 *buff,guint operand_address,guint16 *value);
static int decode_udvm_address_operand(guint8 *buff,guint operand_address, guint16 *value,guint current_address);
static int decomp_dispatch_get_bits(tvbuff_t *message_tvb,proto_tree *udvm_tree,guint8 bit_order,
guint8 *buff,guint16 *old_input_bit_order, guint16 *remaining_bits,
guint16 *input_bits, guint *input_address, guint16 length, guint16 *result_code,guint msg_end);
tvbuff_t*
decompress_sigcomp_message(tvbuff_t *bytecode_tvb, tvbuff_t *message_tvb, packet_info *pinfo,
proto_tree *udvm_tree, gint udvm_mem_dest,
gint print_flags, gint hf_id,
gint header_len,
gint byte_code_state_len, gint byte_code_id_len,
gint udvm_start_ip)
{
tvbuff_t *decomp_tvb;
/* UDVM memory must be initialised to zero */
guint8 *buff = (guint8 *)ep_alloc0(UDVM_MEMORY_SIZE);
char string[2];
guint8 *out_buff; /* Largest allowed size for a message is UDVM_MEMORY_SIZE = 65536 */
guint32 i = 0;
guint16 n = 0;
guint16 m = 0;
guint16 x;
guint k = 0;
guint16 H;
guint16 oldH;
guint offset = 0;
guint result_dest;
guint code_length =0;
guint8 current_instruction;
guint current_address;
guint operand_address;
guint input_address;
guint16 output_address = 0;
guint next_operand_address;
guint8 octet;
guint8 msb;
guint8 lsb;
guint16 byte_copy_right;
guint16 byte_copy_left;
guint16 input_bit_order;
guint16 stack_location;
guint16 stack_fill;
guint16 result;
guint msg_end = tvb_reported_length_remaining(message_tvb, 0);
guint16 result_code = 0;
guint16 old_input_bit_order = 0;
guint16 remaining_bits = 0;
guint16 input_bits = 0;
guint8 bit_order = 0;
gboolean outside_huffman_boundaries = TRUE;
gboolean print_in_loop = FALSE;
guint16 instruction_address;
guint8 no_of_state_create = 0;
guint16 state_length_buff[5];
guint16 state_address_buff[5];
guint16 state_instruction_buff[5];
guint16 state_minimum_access_length_buff[5];
/* guint16 state_state_retention_priority_buff[5]; */
guint32 used_udvm_cycles = 0;
guint cycles_per_bit;
guint maximum_UDVM_cycles;
guint8 *sha1buff;
unsigned char sha1_digest_buf[STATE_BUFFER_SIZE];
sha1_context ctx;
/* UDVM operand variables */
guint16 length;
guint16 at_address;
guint16 destination;
guint16 addr;
guint16 value;
guint16 p_id_start;
guint16 p_id_length;
guint16 state_begin;
guint16 state_length;
guint16 state_address;
guint16 state_instruction;
guint16 operand_1;
guint16 operand_2;
guint16 value_1;
guint16 value_2;
guint16 at_address_1;
guint16 at_address_2;
guint16 at_address_3;
guint16 j;
guint16 bits_n;
guint16 lower_bound_n;
guint16 upper_bound_n;
guint16 uncompressed_n;
guint16 position;
guint16 ref_destination; /* could I have used $destination ? */
guint16 multy_offset;
guint16 output_start;
guint16 output_length;
guint16 minimum_access_length;
guint16 state_retention_priority;
guint16 requested_feedback_location;
guint16 returned_parameters_location;
guint16 start_value;
/* Set print parameters */
print_level_1 = FALSE;
print_level_2 = FALSE;
print_level_3 = FALSE;
show_instr_detail_level = 0;
switch( print_flags ) {
case 0:
break;
case 1:
print_level_1 = TRUE;
show_instr_detail_level = 1;
break;
case 2:
print_level_1 = TRUE;
print_level_2 = TRUE;
show_instr_detail_level = 1;
break;
case 3:
print_level_1 = TRUE;
print_level_2 = TRUE;
print_level_3 = TRUE;
show_instr_detail_level = 2;
break;
default:
print_level_1 = TRUE;
show_instr_detail_level = 1;
break;
}
/* Set initial UDVM data
* The first 32 bytes of UDVM memory are then initialized to special
* values as illustrated in Figure 5.
*
* 0 7 8 15
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | UDVM_memory_size | 0 - 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | cycles_per_bit | 2 - 3
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | SigComp_version | 4 - 5
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | partial_state_ID_length | 6 - 7
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | state_length | 8 - 9
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |
* : reserved : 10 - 31
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Figure 5: Initializing Useful Values in UDVM memory
*/
/* UDVM_memory_size */
buff[0] = (UDVM_MEMORY_SIZE >> 8) & 0x00FF;
buff[1] = UDVM_MEMORY_SIZE & 0x00FF;
/* cycles_per_bit */
buff[2] = 0;
buff[3] = 16;
/* SigComp_version */
buff[4] = 0;
buff[5] = 1;
/* partial_state_ID_length */
buff[6] = (byte_code_id_len >> 8) & 0x00FF;
buff[7] = byte_code_id_len & 0x00FF;
/* state_length */
buff[8] = (byte_code_state_len >> 8) & 0x00FF;
buff[9] = byte_code_state_len & 0x00FF;
code_length = tvb_reported_length_remaining(bytecode_tvb, 0);
cycles_per_bit = buff[2] << 8;
cycles_per_bit = cycles_per_bit | buff[3];
/*
* maximum_UDVM_cycles = (8 * n + 1000) * cycles_per_bit
*/
maximum_UDVM_cycles = (( 8 * (header_len + msg_end) ) + 1000) * cycles_per_bit;
proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"maximum_UDVM_cycles(%u) = (( 8 * msg_end(%u) ) + 1000) * cycles_per_bit(%u)",maximum_UDVM_cycles,msg_end,cycles_per_bit);
proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"Message Length: %u,Byte code length: %u, Maximum UDVM cycles: %u",msg_end,code_length,maximum_UDVM_cycles);
/* Load bytecode into UDVM starting at "udvm_mem_dest" */
i = udvm_mem_dest;
if ( print_level_3 )
proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"Load bytecode into UDVM starting at %u",i);
while ( code_length > offset && i < UDVM_MEMORY_SIZE ) {
buff[i] = tvb_get_guint8(bytecode_tvb, offset);
if ( print_level_3 )
proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,
" Addr: %u Instruction code(0x%0x) ", i, buff[i]);
i++;
offset++;
}
/* Largest allowed size for a message is UDVM_MEMORY_SIZE = 65536 */
out_buff = (guint8 *)g_malloc(UDVM_MEMORY_SIZE);
/* Start executing code */
current_address = udvm_start_ip;
input_address = 0;
proto_tree_add_text(udvm_tree, bytecode_tvb, offset, 1,"UDVM EXECUTION STARTED at Address: %u Message size %u",
current_address, msg_end);
execute_next_instruction:
if ( used_udvm_cycles > maximum_UDVM_cycles ){
result_code = 15;
goto decompression_failure;
}
used_udvm_cycles++;
current_instruction = buff[current_address & 0xffff];
switch ( current_instruction ) {
case SIGCOMP_INSTR_DECOMPRESSION_FAILURE:
if ( result_code == 0 )
result_code = 9;
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## DECOMPRESSION-FAILURE(0)",
current_address);
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Wireshark UDVM diagnostic: %s.",
val_to_str(result_code, result_code_vals,"Unknown (%u)"));
if ( output_address > 0 ){
/* At least something got decompressed, show it */
decomp_tvb = tvb_new_child_real_data(message_tvb, out_buff,output_address,output_address);
/* Arrange that the allocated packet data copy be freed when the
* tvbuff is freed.
*/
tvb_set_free_cb( decomp_tvb, g_free );
/* Add the tvbuff to the list of tvbuffs to which the tvbuff we
* were handed refers, so it'll get cleaned up when that tvbuff
* is cleaned up.
*/
add_new_data_source(pinfo, decomp_tvb, "Decompressed SigComp message(Incomplete)");
proto_tree_add_text(udvm_tree, decomp_tvb, 0, -1,"SigComp message Decompression failure");
return decomp_tvb;
}
g_free(out_buff);
return NULL;
break;
case SIGCOMP_INSTR_AND: /* 1 AND ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## AND(1) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## AND (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/* execute the instruction */
result = operand_1 & operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_OR: /* 2 OR ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## OR(2) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## OR (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/* execute the instruction */
result = operand_1 | operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_NOT: /* 3 NOT ($operand_1) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## NOT(3) ($operand_1)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## NOT (operand_1=%u)",
current_address, operand_1);
}
/* execute the instruction */
result = operand_1 ^ 0xffff;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_LSHIFT: /* 4 LSHIFT ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## LSHIFT(4) ($operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## LSHIFT (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/* execute the instruction */
result = operand_1 << operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_RSHIFT: /* 5 RSHIFT ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## RSHIFT(5) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## RSHIFT (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/* execute the instruction */
result = operand_1 >> operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_ADD: /* 6 ADD ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## ADD(6) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## ADD (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/* execute the instruction */
result = operand_1 + operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
case SIGCOMP_INSTR_SUBTRACT: /* 7 SUBTRACT ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## SUBTRACT(7) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## SUBTRACT (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/* execute the instruction */
result = operand_1 - operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_MULTIPLY: /* 8 MULTIPLY ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ##MULTIPLY(8) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## MULTIPLY (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/*
* execute the instruction
* MULTIPLY (m, n) := m * n (modulo 2^16)
*/
if ( operand_2 == 0){
result_code = 4;
goto decompression_failure;
}
result = operand_1 * operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_DIVIDE: /* 9 DIVIDE ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## DIVIDE(9) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## DIVIDE (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/*
* execute the instruction
* DIVIDE (m, n) := floor(m / n)
* Decompression failure occurs if a DIVIDE or REMAINDER instruction
* encounters an operand_2 that is zero.
*/
if ( operand_2 == 0){
result_code = 4;
goto decompression_failure;
}
result = operand_1 / operand_2;
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_REMAINDER: /* 10 REMAINDER ($operand_1, %operand_2) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## REMAINDER(10) (operand_1, operand_2)",
current_address);
}
/* $operand_1*/
operand_address = current_address + 1;
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &operand_1, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_1 %u",
operand_address, operand_1);
}
operand_address = next_operand_address;
/* %operand_2*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &operand_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u operand_2 %u",
operand_address, operand_2);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## REMAINDER (operand_1=%u, operand_2=%u)",
current_address, operand_1, operand_2);
}
/*
* execute the instruction
* REMAINDER (m, n) := m - n * floor(m / n)
* Decompression failure occurs if a DIVIDE or REMAINDER instruction
* encounters an operand_2 that is zero.
*/
if ( operand_2 == 0){
result_code = 4;
goto decompression_failure;
}
result = operand_1 - operand_2 * (operand_1 / operand_2);
lsb = result & 0xff;
msb = result >> 8;
buff[result_dest] = msb;
buff[(result_dest+1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading result %u at %u",
result, result_dest);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_SORT_ASCENDING: /* 11 SORT-ASCENDING (%start, %n, %k) */
/*
* used_udvm_cycles = 1 + k * (ceiling(log2(k)) + n)
*/
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## SORT-ASCENDING(11) (start, n, k))",
current_address);
}
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
/*
* used_udvm_cycles = 1 + k * (ceiling(log2(k)) + n)
*/
break;
case SIGCOMP_INSTR_SORT_DESCENDING: /* 12 SORT-DESCENDING (%start, %n, %k) */
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## SORT-DESCENDING(12) (start, n, k))",
current_address);
}
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Execution of this instruction is NOT implemented");
/*
* used_udvm_cycles = 1 + k * (ceiling(log2(k)) + n)
*/
break;
case SIGCOMP_INSTR_SHA_1: /* 13 SHA-1 (%position, %length, %destination) */
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## SHA-1(13) (position, length, destination)",
current_address);
}
operand_address = current_address + 1;
/* %position */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u position %u",
operand_address, position);
}
operand_address = next_operand_address;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* $destination */
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u $destination %u",
operand_address, ref_destination);
}
used_udvm_cycles = used_udvm_cycles + length;
n = 0;
k = position;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, 0, -1,
"byte_copy_right = %u", byte_copy_right);
}
sha1_starts( &ctx );
while (n<length) {
guint16 handle_now = length;
if ( k < byte_copy_right && byte_copy_right <= k + (length-n) ){
handle_now = byte_copy_right - position;
}
if (k + handle_now >= UDVM_MEMORY_SIZE)
goto decompression_failure;
sha1_update( &ctx, &buff[k], handle_now );
k = ( k + handle_now ) & 0xffff;
n = ( n + handle_now ) & 0xffff;
if ( k >= byte_copy_right ) {
k = byte_copy_left;
}
}
sha1_finish( &ctx, sha1_digest_buf );
k = ref_destination;
for ( n=0; n< STATE_BUFFER_SIZE; n++ ) {
buff[k] = sha1_digest_buf[n];
k = ( k + 1 ) & 0xffff;
n++;
if ( k == byte_copy_right ){
k = byte_copy_left;
}
}
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, 0, -1,
"Calculated SHA-1: %s",
bytes_to_ep_str(sha1_digest_buf, STATE_BUFFER_SIZE));
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_LOAD: /* 14 LOAD (%address, %value) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## LOAD(14) (%%address, %%value)",
current_address);
}
operand_address = current_address + 1;
/* %address */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &addr);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Address %u",
operand_address, addr);
}
operand_address = next_operand_address;
/* %value */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## LOAD (%%address=%u, %%value=%u)",
current_address, addr, value);
}
lsb = value & 0xff;
msb = value >> 8;
buff[addr] = msb;
buff[(addr + 1) & 0xffff] = lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Value %u",
operand_address, value);
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Loading bytes at %u Value %u 0x%x",
addr, value, value);
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_MULTILOAD: /* 15 MULTILOAD (%address, #n, %value_0, ..., %value_n-1) */
/* RFC 3320:
* The MULTILOAD instruction sets a contiguous block of 2-byte words in
* the UDVM memory to specified values.
* Hmm what if the value to load only takes one byte ? Chose to always load two bytes.
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## MULTILOAD(15) (%%address, #n, value_0, ..., value_n-1)",
current_address);
}
operand_address = current_address + 1;
/* %address */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &addr);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Address %u",
operand_address, addr);
}
operand_address = next_operand_address;
/* #n */
next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u n %u",
operand_address, n);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## MULTILOAD (%%address=%u, #n=%u, value_0, ..., value_%d)",
current_address, addr, n, n-1);
}
operand_address = next_operand_address;
used_udvm_cycles = used_udvm_cycles + n;
while ( n > 0) {
n = n - 1;
/* %value */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
lsb = value & 0xff;
msb = value >> 8;
if (addr >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[addr] = msb;
buff[(addr + 1) & 0xffff] = lsb;
/* debug
*/
length = next_operand_address - operand_address;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1, "Addr: %u Value %5u - Loading bytes at %5u Value %5u 0x%x",
operand_address, value, addr, value, value);
}
addr = addr + 2;
operand_address = next_operand_address;
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_PUSH: /* 16 PUSH (%value) */
if (show_instr_detail_level == 2){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## PUSH(16) (value)",
current_address);
}
operand_address = current_address + 1;
/* %value */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
if (show_instr_detail_level == 2){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Value %u",
operand_address, value);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## PUSH (value=%u)",
current_address, value);
}
current_address = next_operand_address;
/* Push the value address onto the stack */
stack_location = (buff[70] << 8) | buff[71];
stack_fill = (buff[stack_location] << 8)
| buff[(stack_location+1) & 0xFFFF];
addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
if (addr >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[addr] = (value >> 8) & 0x00FF;
buff[(addr+1) & 0xFFFF] = value & 0x00FF;
if (stack_location >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
stack_fill = (stack_fill + 1) & 0xFFFF;
buff[stack_location] = (stack_fill >> 8) & 0x00FF;
buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_POP: /* 17 POP (%address) */
if (show_instr_detail_level == 2){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## POP(16) (value)",
current_address);
}
operand_address = current_address + 1;
/* %value */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
if (show_instr_detail_level == 2){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Value %u",
operand_address, destination);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## POP (address=%u)",
current_address, destination);
}
current_address = next_operand_address;
/* Pop value from the top of the stack */
stack_location = (buff[70] << 8) | buff[71];
stack_fill = (buff[stack_location] << 8)
| buff[(stack_location+1) & 0xFFFF];
if (stack_fill == 0)
{
result_code = 16;
goto decompression_failure;
}
if (stack_location >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
stack_fill = (stack_fill - 1) & 0xFFFF;
buff[stack_location] = (stack_fill >> 8) & 0x00FF;
buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;
addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
if (addr >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
value = (buff[addr] << 8)
| buff[(addr+1) & 0xFFFF];
/* ... and store the popped value. */
if (destination >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[destination] = (value >> 8) & 0x00FF;
buff[(destination+1) & 0xFFFF] = value & 0x00FF;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_COPY: /* 18 COPY (%position, %length, %destination) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COPY(18) (position, length, destination)",
current_address);
}
operand_address = current_address + 1;
/* %position */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u position %u",
operand_address, position);
}
operand_address = next_operand_address;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* %destination */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Destination %u",
operand_address, destination);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COPY (position=%u, length=%u, destination=%u)",
current_address, position, length, destination);
}
current_address = next_operand_address;
/*
* 8.4. Byte copying
* :
* The string of bytes is copied in ascending order of memory address,
* respecting the bounds set by byte_copy_left and byte_copy_right.
* More precisely, if a byte is copied from/to Address m then the next
* byte is copied from/to Address n where n is calculated as follows:
*
* Set k := m + 1 (modulo 2^16)
* If k = byte_copy_right then set n := byte_copy_left, else set n := k
*
*/
n = 0;
k = destination;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_right = %u", byte_copy_right);
}
while ( n < length ){
buff[k] = buff[position];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Copying value: %u (0x%x) to Addr: %u",
buff[position], buff[position], k);
}
position = ( position + 1 ) & 0xffff;
k = ( k + 1 ) & 0xffff;
n++;
/*
* Check for circular buffer wrapping after the positions are
* incremented. If either started at BCR then they should continue
* to increment beyond BCR.
*/
if ( k == byte_copy_right ){
k = byte_copy_left;
}
if ( position == byte_copy_right ){
position = byte_copy_left;
}
}
used_udvm_cycles = used_udvm_cycles + length;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_COPY_LITERAL: /* 19 COPY-LITERAL (%position, %length, $destination) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COPY-LITERAL(19) (position, length, $destination)",
current_address);
}
operand_address = current_address + 1;
/* %position */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u position %u",
operand_address, position);
}
operand_address = next_operand_address;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* $destination */
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u destination %u",
operand_address, ref_destination);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COPY-LITERAL (position=%u, length=%u, $destination=%u)",
current_address, position, length, ref_destination);
}
current_address = next_operand_address;
/*
* 8.4. Byte copying
* :
* The string of bytes is copied in ascending order of memory address,
* respecting the bounds set by byte_copy_left and byte_copy_right.
* More precisely, if a byte is copied from/to Address m then the next
* byte is copied from/to Address n where n is calculated as follows:
*
* Set k := m + 1 (modulo 2^16)
* If k = byte_copy_right then set n := byte_copy_left, else set n := k
*
*/
n = 0;
k = ref_destination;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_right = %u", byte_copy_right);
}
while ( n < length ){
buff[k] = buff[position];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Copying value: %u (0x%x) to Addr: %u",
buff[position], buff[position], k);
}
position = ( position + 1 ) & 0xffff;
k = ( k + 1 ) & 0xffff;
n++;
/*
* Check for circular buffer wrapping after the positions are
* incremented. It is important that k cannot be left set
* to BCR. Also, if either started at BCR then they should continue
* to increment beyond BCR.
*/
if ( k == byte_copy_right ){
k = byte_copy_left;
}
if ( position == byte_copy_right ){
position = byte_copy_left;
}
}
buff[result_dest] = k >> 8;
buff[(result_dest + 1) & 0xffff] = k & 0x00ff;
used_udvm_cycles = used_udvm_cycles + length;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_COPY_OFFSET: /* 20 COPY-OFFSET (%offset, %length, $destination) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COPY-OFFSET(20) (offset, length, $destination)",
current_address);
}
operand_address = current_address + 1;
/* %offset */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &multy_offset);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u offset %u",
operand_address, multy_offset);
}
operand_address = next_operand_address;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* $destination */
next_operand_address = dissect_udvm_reference_operand(buff, operand_address, &ref_destination, &result_dest);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u $destination %u",
operand_address, ref_destination);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COPY-OFFSET (offset=%u, length=%u, $destination=%u)",
current_address, multy_offset, length, result_dest);
}
current_address = next_operand_address;
/* Execute the instruction:
* To derive the value of the position operand, starting at the memory
* address specified by destination, the UDVM counts backwards a total
* of offset memory addresses.
*
* If the memory address specified in byte_copy_left is reached, the
* next memory address is taken to be (byte_copy_right - 1) modulo 2^16.
*/
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
/*
* In order to work out the position, simple arithmetic is tricky
* to apply because there some nasty corner cases. A simple loop
* is inefficient but the logic is simple.
*
* FUTURE: This could be optimised.
*/
for (position = ref_destination, i = 0; i < multy_offset; i++)
{
if ( position == byte_copy_left )
{
position = (byte_copy_right - 1) & 0xffff;
}
else
{
position = (position - 1) & 0xffff;
}
}
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_left = %u byte_copy_right = %u position= %u",
byte_copy_left, byte_copy_right, position);
}
/* The COPY-OFFSET instruction then behaves as a COPY-LITERAL
* instruction, taking the value of the position operand to be the last
* memory address reached in the above step.
*/
/*
* 8.4. Byte copying
* :
* The string of bytes is copied in ascending order of memory address,
* respecting the bounds set by byte_copy_left and byte_copy_right.
* More precisely, if a byte is copied from/to Address m then the next
* byte is copied from/to Address n where n is calculated as follows:
*
* Set k := m + 1 (modulo 2^16)
* If k = byte_copy_right then set n := byte_copy_left, else set n := k
*
*/
n = 0;
k = ref_destination;
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_left = %u byte_copy_right = %u", byte_copy_left, byte_copy_right);
}
while ( n < length ){
buff[k] = buff[position];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Copying value: %5u (0x%x) from Addr: %u to Addr: %u",
buff[position], buff[position],(position), k);
}
n++;
k = ( k + 1 ) & 0xffff;
position = ( position + 1 ) & 0xffff;
/*
* Check for circular buffer wrapping after the positions are
* incremented. It is important that k cannot be left set
* to BCR. Also, if either started at BCR then they should continue
* to increment beyond BCR.
*/
if ( k == byte_copy_right ){
k = byte_copy_left;
}
if ( position == byte_copy_right ){
position = byte_copy_left;
}
}
buff[result_dest] = k >> 8;
buff[result_dest + 1] = k & 0x00ff;
used_udvm_cycles = used_udvm_cycles + length;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_MEMSET: /* 21 MEMSET (%address, %length, %start_value, %offset) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## MEMSET(21) (address, length, start_value, offset)",
current_address);
}
operand_address = current_address + 1;
/* %address */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &addr);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Address %u",
operand_address, addr);
}
operand_address = next_operand_address;
/* %length, */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* %start_value */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &start_value);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u start_value %u",
operand_address, start_value);
}
operand_address = next_operand_address;
/* %offset */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &multy_offset);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u offset %u",
operand_address, multy_offset);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## MEMSET (address=%u, length=%u, start_value=%u, offset=%u)",
current_address, addr, length, start_value, multy_offset);
}
current_address = next_operand_address;
/* exetute the instruction
* The sequence of values used by the MEMSET instruction is specified by
* the following formula:
*
* Seq[n] := (start_value + n * offset) modulo 256
*/
n = 0;
k = addr;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_left = %u byte_copy_right = %u", byte_copy_left, byte_copy_right);
}
while ( n < length ){
if ( k == byte_copy_right ){
k = byte_copy_left;
}
buff[k] = (start_value + ( n * multy_offset)) & 0xff;
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Storing value: %u (0x%x) at Addr: %u",
buff[k], buff[k], k);
}
k = ( k + 1 ) & 0xffff;
n++;
}/* end while */
used_udvm_cycles = used_udvm_cycles + length;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_JUMP: /* 22 JUMP (@address) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## JUMP(22) (@address)",
current_address);
}
operand_address = current_address + 1;
/* @address */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
/*next_operand_address = */decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## JUMP (@address=%u)",
current_address, at_address);
}
current_address = at_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_COMPARE: /* 23 */
/* COMPARE (%value_1, %value_2, @address_1, @address_2, @address_3)
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COMPARE(23) (value_1, value_2, @address_1, @address_2, @address_3)",
current_address);
}
operand_address = current_address + 1;
/* %value_1 */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value_1);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Value %u",
operand_address, value_1);
}
operand_address = next_operand_address;
/* %value_2 */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value_2);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Value %u",
operand_address, value_2);
}
operand_address = next_operand_address;
/* @address_1 */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_1);
at_address_1 = ( current_address + at_address_1) & 0xffff;
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address_1);
}
operand_address = next_operand_address;
/* @address_2 */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_2);
at_address_2 = ( current_address + at_address_2) & 0xffff;
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address_2);
}
operand_address = next_operand_address;
/* @address_3 */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
/*next_operand_address = */decode_udvm_multitype_operand(buff, operand_address, &at_address_3);
at_address_3 = ( current_address + at_address_3) & 0xffff;
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address_3);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## COMPARE (value_1=%u, value_2=%u, @address_1=%u, @address_2=%u, @address_3=%u)",
current_address, value_1, value_2, at_address_1, at_address_2, at_address_3);
}
/* execute the instruction
* If value_1 < value_2 then the UDVM continues instruction execution at
* the memory address specified by address 1. If value_1 = value_2 then
* it jumps to the address specified by address_2. If value_1 > value_2
* then it jumps to the address specified by address_3.
*/
if ( value_1 < value_2 )
current_address = at_address_1;
if ( value_1 == value_2 )
current_address = at_address_2;
if ( value_1 > value_2 )
current_address = at_address_3;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_CALL: /* 24 CALL (@address) (PUSH addr )*/
if (show_instr_detail_level == 2){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## CALL(24) (@address) (PUSH addr )",
current_address);
}
operand_address = current_address + 1;
/* @address */
next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## CALL (@address=%u)",
current_address, at_address);
}
current_address = next_operand_address;
/* Push the current address onto the stack */
stack_location = (buff[70] << 8) | buff[71];
stack_fill = (buff[stack_location] << 8)
| buff[(stack_location+1) & 0xFFFF];
addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
if (addr >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[addr] = (current_address >> 8) & 0x00FF;
buff[(addr+1) & 0xFFFF] = current_address & 0x00FF;
stack_fill = (stack_fill + 1) & 0xFFFF;
if (stack_location >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[stack_location] = (stack_fill >> 8) & 0x00FF;
buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;
/* ... and jump to the destination address */
current_address = at_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_RETURN: /* 25 POP and return */
if (print_level_1 || show_instr_detail_level == 1){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## POP(25) and return",
current_address);
}
/* Pop value from the top of the stack */
stack_location = (buff[70] << 8) | buff[71];
stack_fill = (buff[stack_location] << 8)
| buff[(stack_location+1) & 0xFFFF];
if (stack_fill == 0)
{
result_code = 16;
goto decompression_failure;
}
stack_fill = (stack_fill - 1) & 0xFFFF;
if (stack_location >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[stack_location] = (stack_fill >> 8) & 0x00FF;
buff[(stack_location+1) & 0xFFFF] = stack_fill & 0x00FF;
addr = (stack_location + stack_fill * 2 + 2) & 0xFFFF;
at_address = (buff[addr] << 8)
| buff[(addr+1) & 0xFFFF];
/* ... and set the PC to the popped value */
current_address = at_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_SWITCH: /* 26 SWITCH (#n, %j, @address_0, @address_1, ... , @address_n-1) */
/*
* When a SWITCH instruction is encountered the UDVM reads the value of
* j. It then continues instruction execution at the address specified
* by address j.
*
* Decompression failure occurs if j specifies a value of n or more, or
* if the address lies beyond the overall UDVM memory size.
*/
instruction_address = current_address;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## SWITCH (#n, j, @address_0, @address_1, ... , @address_n-1))",
current_address);
}
operand_address = current_address + 1;
/* #n
* Number of addresses in the instruction
*/
next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u n %u",
operand_address, n);
}
operand_address = next_operand_address;
/* %j */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &j);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u j %u",
operand_address, j);
}
operand_address = next_operand_address;
m = 0;
while ( m < n ){
/* @address_n-1 */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address_1);
at_address_1 = ( instruction_address + at_address_1) & 0xffff;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address_1);
}
if ( j == m ){
current_address = at_address_1;
}
operand_address = next_operand_address;
m++;
}
/* Check decompression failure */
if ( ( j == n ) || ( j > n )){
result_code = 5;
goto decompression_failure;
}
if ( current_address > UDVM_MEMORY_SIZE ){
result_code = 6;
goto decompression_failure;
}
used_udvm_cycles = used_udvm_cycles + n;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_CRC: /* 27 CRC (%value, %position, %length, @address) */
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## CRC (value, position, length, @address)",
current_address);
}
operand_address = current_address + 1;
/* %value */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &value);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Value %u",
operand_address, value);
}
operand_address = next_operand_address;
/* %position */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &position);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u position %u",
operand_address, position);
}
operand_address = next_operand_address;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* @address */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address);
at_address = ( current_address + at_address) & 0xffff;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address);
}
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
used_udvm_cycles = used_udvm_cycles + length;
n = 0;
k = position;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
result = 0;
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, 0, -1,
"byte_copy_right = %u", byte_copy_right);
}
while (n<length) {
guint16 handle_now = length - n;
if ( k < byte_copy_right && byte_copy_right <= k + (length-n) ){
handle_now = byte_copy_right - k;
}
if (k + handle_now >= UDVM_MEMORY_SIZE)
goto decompression_failure;
result = crc16_ccitt_seed(&buff[k], handle_now, (guint16) (result ^ 0xffff));
k = ( k + handle_now ) & 0xffff;
n = ( n + handle_now ) & 0xffff;
if ( k >= byte_copy_right ) {
k = byte_copy_left;
}
}
result = result ^ 0xffff;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1, "Calculated CRC %u", result);
}
if (result != value){
current_address = at_address;
}
else {
current_address = next_operand_address;
}
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_INPUT_BYTES: /* 28 INPUT-BYTES (%length, %destination, @address) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## INPUT-BYTES(28) length, destination, @address)",
current_address);
}
operand_address = current_address + 1;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* %destination */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Destination %u",
operand_address, destination);
}
operand_address = next_operand_address;
/* @address */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &at_address);
at_address = ( current_address + at_address) & 0xffff;
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## INPUT-BYTES length=%u, destination=%u, @address=%u)",
current_address, length, destination, at_address);
}
/* execute the instruction TODO insert checks
* RFC 3320 :
*
* 0 7 8 15
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | byte_copy_left | 64 - 65
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | byte_copy_right | 66 - 67
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | input_bit_order | 68 - 69
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | stack_location | 70 - 71
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Figure 7: Memory addresses of the UDVM registers
* :
* 8.4. Byte copying
* :
* The string of bytes is copied in ascending order of memory address,
* respecting the bounds set by byte_copy_left and byte_copy_right.
* More precisely, if a byte is copied from/to Address m then the next
* byte is copied from/to Address n where n is calculated as follows:
*
* Set k := m + 1 (modulo 2^16)
* If k = byte_copy_right then set n := byte_copy_left, else set n := k
*
*/
n = 0;
k = destination;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_1 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_right = %u", byte_copy_right);
}
/* clear out remaining bits if any */
remaining_bits = 0;
input_bits=0;
/* operand_address used as dummy */
while ( n < length ){
if (input_address > ( msg_end - 1)){
current_address = at_address;
result_code = 14;
goto execute_next_instruction;
}
if ( k == byte_copy_right ){
k = byte_copy_left;
}
octet = tvb_get_guint8(message_tvb, input_address);
buff[k] = octet;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Loading value: %u (0x%x) at Addr: %u", octet, octet, k);
}
input_address++;
/*
* If the instruction requests data that lies beyond the end of the
* SigComp message, no data is returned. Instead the UDVM moves program
* execution to the address specified by the address operand.
*/
k = ( k + 1 ) & 0xffff;
n++;
}
used_udvm_cycles = used_udvm_cycles + length;
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_INPUT_BITS:/* 29 INPUT-BITS (%length, %destination, @address) */
/*
* The length operand indicates the requested number of bits.
* Decompression failure occurs if this operand does not lie between 0
* and 16 inclusive.
*
* The destination operand specifies the memory address to which the
* compressed data should be copied. Note that the requested bits are
* interpreted as a 2-byte integer ranging from 0 to 2^length - 1, as
* explained in Section 8.2.
*
* If the instruction requests data that lies beyond the end of the
* SigComp message, no data is returned. Instead the UDVM moves program
* execution to the address specified by the address operand.
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## INPUT-BITS(29) (length, destination, @address)",
current_address);
}
operand_address = current_address + 1;
/* %length */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u length %u",
operand_address, length);
}
operand_address = next_operand_address;
/* %destination */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Destination %u",
operand_address, destination);
}
operand_address = next_operand_address;
/* @address */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## INPUT-BITS length=%u, destination=%u, @address=%u)",
current_address, length, destination, at_address);
}
current_address = next_operand_address;
/*
* Execute actual instr.
* The input_bit_order register contains the following three flags:
*
* 0 7 8 15
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | reserved |F|H|P| 68 - 69
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
input_bit_order = buff[68] << 8;
input_bit_order = input_bit_order | buff[69];
/*
* If the instruction requests data that lies beyond the end of the
* SigComp message, no data is returned. Instead the UDVM moves program
* execution to the address specified by the address operand.
*/
if ( length > 16 ){
result_code = 7;
goto decompression_failure;
}
if ( input_bit_order > 7 ){
result_code = 8;
goto decompression_failure;
}
/*
* Transfer F bit to bit_order to tell decomp dispatcher which bit order to use
*/
bit_order = ( input_bit_order & 0x0004 ) >> 2;
value = decomp_dispatch_get_bits( message_tvb, udvm_tree, bit_order,
buff, &old_input_bit_order, &remaining_bits,
&input_bits, &input_address, length, &result_code, msg_end);
if ( result_code == 11 ){
current_address = at_address;
goto execute_next_instruction;
}
msb = value >> 8;
lsb = value & 0x00ff;
if (destination >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[destination] = msb;
buff[(destination + 1) & 0xffff]=lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Loading value: %u (0x%x) at Addr: %u, remaining_bits: %u", value, value, destination, remaining_bits);
}
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_INPUT_HUFFMAN: /* 30 */
/*
* INPUT-HUFFMAN (%destination, @address, #n, %bits_1, %lower_bound_1,
* %upper_bound_1, %uncompressed_1, ... , %bits_n, %lower_bound_n,
* %upper_bound_n, %uncompressed_n)
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## INPUT-HUFFMAN (destination, @address, #n, bits_1, lower_bound_1,upper_bound_1, uncompressed_1, ... , bits_n, lower_bound_n,upper_bound_n, uncompressed_n)",
current_address);
}
operand_address = current_address + 1;
/* %destination */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &destination);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u Destination %u",
operand_address, destination);
}
operand_address = next_operand_address;
/* @address */
/* operand_value = (memory_address_of_instruction + D) modulo 2^16 */
next_operand_address = decode_udvm_address_operand(buff,operand_address, &at_address, current_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u @Address %u",
operand_address, at_address);
}
operand_address = next_operand_address;
/* #n */
next_operand_address = decode_udvm_literal_operand(buff,operand_address, &n);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u n %u",
operand_address, n);
}
operand_address = next_operand_address;
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## INPUT-HUFFMAN (destination=%u, @address=%u, #n=%u, bits_1, lower_1,upper_1, unc_1, ... , bits_%d, lower_%d,upper_%d, unc_%d)",
current_address, destination, at_address, n, n, n, n, n);
}
used_udvm_cycles = used_udvm_cycles + n;
/*
* Note that if n = 0 then the INPUT-HUFFMAN instruction is ignored and
* program execution resumes at the following instruction.
* Decompression failure occurs if (bits_1 + ... + bits_n) > 16.
*
* In all other cases, the behavior of the INPUT-HUFFMAN instruction is
* defined below:
*
* 1. Set j := 1 and set H := 0.
*
* 2. Request bits_j compressed bits. Interpret the returned bits as an
* integer k from 0 to 2^bits_j - 1, as explained in Section 8.2.
*
* 3. Set H := H * 2^bits_j + k.
*
* 4. If data is requested that lies beyond the end of the SigComp
* message, terminate the INPUT-HUFFMAN instruction and move program
* execution to the memory address specified by the address operand.
*
* 5. If (H < lower_bound_j) or (H > upper_bound_j) then set j := j + 1.
* Then go back to Step 2, unless j > n in which case decompression
* failure occurs.
*
* 6. Copy (H + uncompressed_j - lower_bound_j) modulo 2^16 to the
* memory address specified by the destination operand.
*
*/
/*
* The input_bit_order register contains the following three flags:
*
* 0 7 8 15
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | reserved |F|H|P| 68 - 69
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Transfer H bit to bit_order to tell decomp dispatcher which bit order to use
*/
input_bit_order = buff[68] << 8;
input_bit_order = input_bit_order | buff[69];
bit_order = ( input_bit_order & 0x0002 ) >> 1;
j = 1;
H = 0;
m = n;
outside_huffman_boundaries = TRUE;
print_in_loop = print_level_3;
while ( m > 0 ){
/* %bits_n */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &bits_n);
if (print_in_loop ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u bits_n %u",
operand_address, bits_n);
}
operand_address = next_operand_address;
/* %lower_bound_n */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &lower_bound_n);
if (print_in_loop ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u lower_bound_n %u",
operand_address, lower_bound_n);
}
operand_address = next_operand_address;
/* %upper_bound_n */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &upper_bound_n);
if (print_in_loop ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u upper_bound_n %u",
operand_address, upper_bound_n);
}
operand_address = next_operand_address;
/* %uncompressed_n */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &uncompressed_n);
if (print_in_loop ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u uncompressed_n %u",
operand_address, uncompressed_n);
}
operand_address = next_operand_address;
/* execute instruction */
if ( outside_huffman_boundaries ) {
/*
* 2. Request bits_j compressed bits. Interpret the returned bits as an
* integer k from 0 to 2^bits_j - 1, as explained in Section 8.2.
*/
k = decomp_dispatch_get_bits( message_tvb, udvm_tree, bit_order,
buff, &old_input_bit_order, &remaining_bits,
&input_bits, &input_address, bits_n, &result_code, msg_end);
if ( result_code == 11 ){
/*
* 4. If data is requested that lies beyond the end of the SigComp
* message, terminate the INPUT-HUFFMAN instruction and move program
* execution to the memory address specified by the address operand.
*/
current_address = at_address;
goto execute_next_instruction;
}
/*
* 3. Set H := H * 2^bits_j + k.
* [In practice is a shift+OR operation.]
*/
oldH = H;
H = (H << bits_n) | k;
if (print_level_3 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," Set H(%u) := H(%u) * 2^bits_j(%u) + k(%u)",
H ,oldH, 1<<bits_n,k);
}
/*
* 5. If (H < lower_bound_j) or (H > upper_bound_j) then set j := j + 1.
* Then go back to Step 2, unless j > n in which case decompression
* failure occurs.
*/
if ((H < lower_bound_n) || (H > upper_bound_n)){
outside_huffman_boundaries = TRUE;
}else{
outside_huffman_boundaries = FALSE;
print_in_loop = FALSE;
/*
* 6. Copy (H + uncompressed_j - lower_bound_j) modulo 2^16 to the
* memory address specified by the destination operand.
*/
if (print_level_2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
" H(%u) = H(%u) + uncompressed_n(%u) - lower_bound_n(%u)",
(H + uncompressed_n - lower_bound_n ),H, uncompressed_n, lower_bound_n);
}
H = H + uncompressed_n - lower_bound_n;
msb = H >> 8;
lsb = H & 0x00ff;
if (destination >= UDVM_MEMORY_SIZE - 1)
goto decompression_failure;
buff[destination] = msb;
buff[(destination + 1) & 0xffff]=lsb;
if (print_level_1 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" Loading H: %u (0x%x) at Addr: %u,j = %u remaining_bits: %u",
H, H, destination,( n - m + 1 ), remaining_bits);
}
}
}
m = m - 1;
}
if ( outside_huffman_boundaries ) {
result_code = 10;
goto decompression_failure;
}
current_address = next_operand_address;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_STATE_ACCESS: /* 31 */
/* STATE-ACCESS (%partial_identifier_start, %partial_identifier_length,
* %state_begin, %state_length, %state_address, %state_instruction)
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## STATE-ACCESS(31) (partial_identifier_start, partial_identifier_length,state_begin, state_length, state_address, state_instruction)",
current_address);
}
operand_address = current_address + 1;
/*
* %partial_identifier_start
*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_start);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u partial_identifier_start %u",
operand_address, p_id_start);
}
/*
* %partial_identifier_length
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u partial_identifier_length %u",
operand_address, p_id_length);
}
/*
* %state_begin
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_begin);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_begin %u",
operand_address, state_begin);
}
/*
* %state_length
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_length %u",
operand_address, state_length);
}
/*
* %state_address
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_address %u",
operand_address, state_address);
}
/*
* %state_instruction
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_instruction %u",
operand_address, state_instruction);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## STATE-ACCESS(31) (partial_identifier_start=%u, partial_identifier_length=%u,state_begin=%u, state_length=%u, state_address=%u, state_instruction=%u)",
current_address, p_id_start, p_id_length, state_begin, state_length, state_address, state_instruction);
}
current_address = next_operand_address;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_2 ){
proto_tree_add_text(udvm_tree, message_tvb, input_address, 1,
" byte_copy_right = %u, byte_copy_left = %u", byte_copy_right,byte_copy_left);
}
result_code = udvm_state_access(message_tvb, udvm_tree, buff, p_id_start, p_id_length, state_begin, &state_length,
&state_address, &state_instruction, hf_id);
if ( result_code != 0 ){
goto decompression_failure;
}
used_udvm_cycles = used_udvm_cycles + state_length;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_STATE_CREATE: /* 32 */
/*
* STATE-CREATE (%state_length, %state_address, %state_instruction,
* %minimum_access_length, %state_retention_priority)
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## STATE-CREATE(32) (state_length, state_address, state_instruction,minimum_access_length, state_retention_priority)",
current_address);
}
operand_address = current_address + 1;
/*
* %state_length
*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_length %u",
operand_address, state_length);
}
/*
* %state_address
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_address %u",
operand_address, state_address);
}
/*
* %state_instruction
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_instruction %u",
operand_address, state_instruction);
}
/*
* %minimum_access_length
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &minimum_access_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u minimum_access_length %u",
operand_address, minimum_access_length);
}
/*
* %state_retention_priority
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_retention_priority);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_retention_priority %u",
operand_address, state_retention_priority);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## STATE-CREATE(32) (state_length=%u, state_address=%u, state_instruction=%u,minimum_access_length=%u, state_retention_priority=%u)",
current_address, state_length, state_address, state_instruction,minimum_access_length, state_retention_priority);
}
current_address = next_operand_address;
/* Execute the instruction
* TODO Implement the instruction
* RFC3320:
* Note that the new state item cannot be created until a valid
* compartment identifier has been returned by the application.
* Consequently, when a STATE-CREATE instruction is encountered the UDVM
* simply buffers the five supplied operands until the END-MESSAGE
* instruction is reached. The steps taken at this point are described
* in Section 9.4.9.
*
* Decompression failure MUST occur if more than four state creation
* requests are made before the END-MESSAGE instruction is encountered.
* Decompression failure also occurs if the minimum_access_length does
* not lie between 6 and 20 inclusive, or if the
* state_retention_priority is 65535.
*/
no_of_state_create++;
if ( no_of_state_create > 4 ){
result_code = 12;
goto decompression_failure;
}
if (( minimum_access_length < 6 ) || ( minimum_access_length > STATE_BUFFER_SIZE )){
result_code = 1;
goto decompression_failure;
}
if ( state_retention_priority == 65535 ){
result_code = 13;
goto decompression_failure;
}
state_length_buff[no_of_state_create] = state_length;
state_address_buff[no_of_state_create] = state_address;
state_instruction_buff[no_of_state_create] = state_instruction;
state_minimum_access_length_buff[no_of_state_create] = minimum_access_length;
/* state_state_retention_priority_buff[no_of_state_create] = state_retention_priority; */
used_udvm_cycles = used_udvm_cycles + state_length;
/* Debug */
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
n = 0;
k = state_address;
while ( n < state_length ){
if ( k == byte_copy_right ){
k = byte_copy_left;
}
string[0]= buff[k];
string[1]= '\0';
if (print_level_3 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
" Addr: %5u State value: %u (0x%x) ASCII(%s)",
k,buff[k],buff[k],format_text(string, 1));
}
k = ( k + 1 ) & 0xffff;
n++;
}
/* End debug */
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_STATE_FREE: /* 33 */
/*
* STATE-FREE (%partial_identifier_start, %partial_identifier_length)
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## STATE-FREE (partial_identifier_start, partial_identifier_length)",
current_address);
}
operand_address = current_address + 1;
/*
* %partial_identifier_start
*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_start);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u partial_identifier_start %u",
operand_address, p_id_start);
}
operand_address = next_operand_address;
/*
* %partial_identifier_length
*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &p_id_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u partial_identifier_length %u",
operand_address, p_id_length);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## STATE-FREE (partial_identifier_start=%u, partial_identifier_length=%u)",
current_address, p_id_start, p_id_length);
}
current_address = next_operand_address;
/* Execute the instruction:
* TODO implement it
*/
udvm_state_free(buff,p_id_start,p_id_length);
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_OUTPUT: /* 34 OUTPUT (%output_start, %output_length) */
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## OUTPUT(34) (output_start, output_length)",
current_address);
}
operand_address = current_address + 1;
/*
* %output_start
*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &output_start);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u output_start %u",
operand_address, output_start);
}
operand_address = next_operand_address;
/*
* %output_length
*/
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &output_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u output_length %u",
operand_address, output_length);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## OUTPUT (output_start=%u, output_length=%u)",
current_address, output_start, output_length);
}
current_address = next_operand_address;
/*
* Execute instruction
* 8.4. Byte copying
* :
* The string of bytes is copied in ascending order of memory address,
* respecting the bounds set by byte_copy_left and byte_copy_right.
* More precisely, if a byte is copied from/to Address m then the next
* byte is copied from/to Address n where n is calculated as follows:
*
* Set k := m + 1 (modulo 2^16)
* If k = byte_copy_right then set n := byte_copy_left, else set n := k
*
*/
n = 0;
k = output_start;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
if (print_level_3 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
" byte_copy_right = %u", byte_copy_right);
}
while ( n < output_length ){
if ( k == byte_copy_right ){
k = byte_copy_left;
}
out_buff[output_address] = buff[k];
string[0]= buff[k];
string[1]= '\0';
if (print_level_3 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
" Output value: %u (0x%x) ASCII(%s) from Addr: %u ,output to dispatcher position %u",
buff[k],buff[k],format_text(string,1), k,output_address);
}
k = ( k + 1 ) & 0xffff;
output_address ++;
n++;
}
used_udvm_cycles = used_udvm_cycles + output_length;
goto execute_next_instruction;
break;
case SIGCOMP_INSTR_END_MESSAGE: /* 35 */
/*
* END-MESSAGE (%requested_feedback_location,
* %returned_parameters_location, %state_length, %state_address,
* %state_instruction, %minimum_access_length,
* %state_retention_priority)
*/
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## END-MESSAGE (requested_feedback_location,state_instruction, minimum_access_length,state_retention_priority)",
current_address);
}
operand_address = current_address + 1;
/* %requested_feedback_location */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &requested_feedback_location);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u requested_feedback_location %u",
operand_address, requested_feedback_location);
}
operand_address = next_operand_address;
/* returned_parameters_location */
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &returned_parameters_location);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u returned_parameters_location %u",
operand_address, returned_parameters_location);
}
/*
* %state_length
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_length %u",
operand_address, state_length);
}
/*
* %state_address
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_address);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_address %u",
operand_address, state_address);
}
/*
* %state_instruction
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &state_instruction);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_instruction %u",
operand_address, state_instruction);
}
/*
* %minimum_access_length
*/
operand_address = next_operand_address;
next_operand_address = decode_udvm_multitype_operand(buff, operand_address, &minimum_access_length);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u minimum_access_length %u",
operand_address, minimum_access_length);
}
/*
* %state_retention_priority
*/
operand_address = next_operand_address;
/*next_operand_address =*/ decode_udvm_multitype_operand(buff, operand_address, &state_retention_priority);
if (show_instr_detail_level == 2 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"Addr: %u state_retention_priority %u",
operand_address, state_retention_priority);
}
if (show_instr_detail_level == 1)
{
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,
"Addr: %u ## END-MESSAGE (requested_feedback_location=%u, returned_parameters_location=%u, state_length=%u, state_address=%u, state_instruction=%u, minimum_access_length=%u, state_retention_priority=%u)",
current_address, requested_feedback_location, returned_parameters_location, state_length, state_address, state_instruction, minimum_access_length,state_retention_priority);
}
/* TODO: This isn't currently totaly correct as END_INSTRUCTION might not create state */
no_of_state_create++;
if ( no_of_state_create > 4 ){
result_code = 12;
goto decompression_failure;
}
state_length_buff[no_of_state_create] = state_length;
state_address_buff[no_of_state_create] = state_address;
state_instruction_buff[no_of_state_create] = state_instruction;
/* Not used ? */
state_minimum_access_length_buff[no_of_state_create] = minimum_access_length;
/* state_state_retention_priority_buff[no_of_state_create] = state_retention_priority; */
/* Execute the instruction
*/
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"no_of_state_create %u",no_of_state_create);
if ( no_of_state_create != 0 ){
memset(sha1_digest_buf, 0, STATE_BUFFER_SIZE);
n = 1;
byte_copy_right = buff[66] << 8;
byte_copy_right = byte_copy_right | buff[67];
byte_copy_left = buff[64] << 8;
byte_copy_left = byte_copy_left | buff[65];
while ( n < no_of_state_create + 1 ){
sha1buff = (guint8 *)g_malloc(state_length_buff[n]+8);
sha1buff[0] = state_length_buff[n] >> 8;
sha1buff[1] = state_length_buff[n] & 0xff;
sha1buff[2] = state_address_buff[n] >> 8;
sha1buff[3] = state_address_buff[n] & 0xff;
sha1buff[4] = state_instruction_buff[n] >> 8;
sha1buff[5] = state_instruction_buff[n] & 0xff;
sha1buff[6] = state_minimum_access_length_buff[n] >> 8;
sha1buff[7] = state_minimum_access_length_buff[n] & 0xff;
if (print_level_3 ){
for( x=0; x < 8; x++){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"sha1buff %u 0x%x",
x,sha1buff[x]);
}
}
k = state_address_buff[n];
for( x=0; x < state_length_buff[n]; x++)
{
if ( k == byte_copy_right ){
k = byte_copy_left;
}
sha1buff[8+x] = buff[k];
k = ( k + 1 ) & 0xffff;
}
sha1_starts( &ctx );
sha1_update( &ctx, (guint8 *) sha1buff, state_length_buff[n] + 8);
sha1_finish( &ctx, sha1_digest_buf );
if (print_level_3 ){
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"SHA1 digest %s",bytes_to_ep_str(sha1_digest_buf, STATE_BUFFER_SIZE));
}
/* begin partial state-id change cco@iptel.org */
#if 0
udvm_state_create(sha1buff, sha1_digest_buf, state_minimum_access_length_buff[n]);
#endif
udvm_state_create(sha1buff, sha1_digest_buf, STATE_MIN_ACCESS_LEN);
/* end partial state-id change cco@iptel.org */
proto_tree_add_text(udvm_tree,bytecode_tvb, 0, -1,"### Creating state ###");
proto_tree_add_string(udvm_tree,hf_id, bytecode_tvb, 0, 0, bytes_to_ep_str(sha1_digest_buf, state_minimum_access_length_buff[n]));
n++;
}
}
/* At least something got decompressed, show it */
decomp_tvb = tvb_new_child_real_data(message_tvb, out_buff,output_address,output_address);
/* Arrange that the allocated packet data copy be freed when the
* tvbuff is freed.
*/
tvb_set_free_cb( decomp_tvb, g_free );
add_new_data_source(pinfo, decomp_tvb, "Decompressed SigComp message");
/*
proto_tree_add_text(udvm_tree, decomp_tvb, 0, -1,"SigComp message Decompressed");
*/
used_udvm_cycles = used_udvm_cycles + state_length;
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"maximum_UDVM_cycles %u used_udvm_cycles %u",
maximum_UDVM_cycles, used_udvm_cycles);
return decomp_tvb;
break;
default:
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1," ### Addr %u Invalid instruction: %u (0x%x)",
current_address,current_instruction,current_instruction);
break;
}
g_free(out_buff);
return NULL;
decompression_failure:
proto_tree_add_text(udvm_tree, bytecode_tvb, 0, -1,"DECOMPRESSION FAILURE: %s",
val_to_str(result_code, result_code_vals,"Unknown (%u)"));
THROW(ReportedBoundsError);
g_free(out_buff);
return NULL;
}
/* The simplest operand type is the literal (#), which encodes a
* constant integer from 0 to 65535 inclusive. A literal operand may
* require between 1 and 3 bytes depending on its value.
* Bytecode: Operand value: Range:
* 0nnnnnnn N 0 - 127
* 10nnnnnn nnnnnnnn N 0 - 16383
* 11000000 nnnnnnnn nnnnnnnn N 0 - 65535
*
* Figure 8: Bytecode for a literal (#) operand
*
*/
static int
decode_udvm_literal_operand(guint8 *buff,guint operand_address, guint16 *value)
{
guint bytecode;
guint16 operand;
guint test_bits;
guint offset = operand_address;
guint8 temp_data;
bytecode = buff[operand_address];
test_bits = bytecode >> 7;
if (test_bits == 1){
test_bits = bytecode >> 6;
if (test_bits == 2){
/*
* 10nnnnnn nnnnnnnn N 0 - 16383
*/
temp_data = buff[operand_address] & 0x1f;
operand = temp_data << 8;
temp_data = buff[(operand_address + 1) & 0xffff];
operand = operand | temp_data;
*value = operand;
offset = offset + 2;
}else{
/*
* 111000000 nnnnnnnn nnnnnnnn N 0 - 65535
*/
offset ++;
temp_data = buff[operand_address] & 0x1f;
operand = temp_data << 8;
temp_data = buff[(operand_address + 1) & 0xffff];
operand = operand | temp_data;
*value = operand;
offset = offset + 2;
}
}else{
/*
* 0nnnnnnn N 0 - 127
*/
operand = ( bytecode & 0x7f);
*value = operand;
offset ++;
}
return offset;
}
/*
* The second operand type is the reference ($), which is always used to
* access a 2-byte value located elsewhere in the UDVM memory. The
* bytecode for a reference operand is decoded to be a constant integer
* from 0 to 65535 inclusive, which is interpreted as the memory address
* containing the actual value of the operand.
* Bytecode: Operand value: Range:
*
* 0nnnnnnn memory[2 * N] 0 - 65535
* 10nnnnnn nnnnnnnn memory[2 * N] 0 - 65535
* 11000000 nnnnnnnn nnnnnnnn memory[N] 0 - 65535
*
* Figure 9: Bytecode for a reference ($) operand
*/
static int
dissect_udvm_reference_operand(guint8 *buff,guint operand_address, guint16 *value,guint *result_dest)
{
guint bytecode;
guint16 operand;
guint offset = operand_address;
guint test_bits;
guint8 temp_data;
guint16 temp_data16;
bytecode = buff[operand_address];
test_bits = bytecode >> 7;
if (test_bits == 1){
test_bits = bytecode >> 6;
if (test_bits == 2){
/*
* 10nnnnnn nnnnnnnn memory[2 * N] 0 - 65535
*/
temp_data = buff[operand_address] & 0x3f;
operand = temp_data << 8;
temp_data = buff[(operand_address + 1) & 0xffff];
operand = operand | temp_data;
operand = (operand * 2);
*result_dest = operand;
temp_data16 = buff[operand] << 8;
temp_data16 = temp_data16 | buff[(operand+1) & 0xffff];
*value = temp_data16;
offset = offset + 2;
}else{
/*
* 11000000 nnnnnnnn nnnnnnnn memory[N] 0 - 65535
*/
operand_address++;
operand = buff[operand_address] << 8;
operand = operand | buff[(operand_address + 1) & 0xffff];
*result_dest = operand;
temp_data16 = buff[operand] << 8;
temp_data16 = temp_data16 | buff[(operand+1) & 0xffff];
*value = temp_data16;
offset = offset + 3;
}
}else{
/*
* 0nnnnnnn memory[2 * N] 0 - 65535
*/
operand = ( bytecode & 0x7f);
operand = (operand * 2);
*result_dest = operand;
temp_data16 = buff[operand] << 8;
temp_data16 = temp_data16 | buff[(operand+1) & 0xffff];
*value = temp_data16;
offset ++;
}
if (offset >= UDVM_MEMORY_SIZE || *result_dest >= UDVM_MEMORY_SIZE - 1 )
THROW(ReportedBoundsError);
return offset;
}
/* RFC3320
* Figure 10: Bytecode for a multitype (%) operand
* Bytecode: Operand value: Range: HEX val
* 00nnnnnn N 0 - 63 0x00
* 01nnnnnn memory[2 * N] 0 - 65535 0x40
* 1000011n 2 ^ (N + 6) 64 , 128 0x86
* 10001nnn 2 ^ (N + 8) 256 , ... , 32768 0x88
* 111nnnnn N + 65504 65504 - 65535 0xe0
* 1001nnnn nnnnnnnn N + 61440 61440 - 65535 0x90
* 101nnnnn nnnnnnnn N 0 - 8191 0xa0
* 110nnnnn nnnnnnnn memory[N] 0 - 65535 0xc0
* 10000000 nnnnnnnn nnnnnnnn N 0 - 65535 0x80
* 10000001 nnnnnnnn nnnnnnnn memory[N] 0 - 65535 0x81
*/
static int
decode_udvm_multitype_operand(guint8 *buff,guint operand_address, guint16 *value)
{
guint test_bits;
guint bytecode;
guint offset = operand_address;
guint16 operand;
guint32 result;
guint8 temp_data;
guint16 temp_data16;
guint16 memmory_addr = 0;
*value = 0;
bytecode = buff[operand_address];
test_bits = ( bytecode & 0xc0 ) >> 6;
switch (test_bits ){
case 0:
/*
* 00nnnnnn N 0 - 63
*/
operand = buff[operand_address];
/* debug
*g_warning("Reading 0x%x From address %u",operand,offset);
*/
*value = operand;
offset ++;
break;
case 1:
/*
* 01nnnnnn memory[2 * N] 0 - 65535
*/
memmory_addr = ( bytecode & 0x3f) * 2;
temp_data16 = buff[memmory_addr] << 8;
temp_data16 = temp_data16 | buff[(memmory_addr+1) & 0xffff];
*value = temp_data16;
offset ++;
break;
case 2:
/* Check tree most significant bits */
test_bits = ( bytecode & 0xe0 ) >> 5;
if ( test_bits == 5 ){
/*
* 101nnnnn nnnnnnnn N 0 - 8191
*/
temp_data = buff[operand_address] & 0x1f;
operand = temp_data << 8;
temp_data = buff[(operand_address + 1) & 0xffff];
operand = operand | temp_data;
*value = operand;
offset = offset + 2;
}else{
test_bits = ( bytecode & 0xf0 ) >> 4;
if ( test_bits == 9 ){
/*
* 1001nnnn nnnnnnnn N + 61440 61440 - 65535
*/
temp_data = buff[operand_address] & 0x0f;
operand = temp_data << 8;
temp_data = buff[(operand_address + 1) & 0xffff];
operand = operand | temp_data;
operand = operand + 61440;
*value = operand;
offset = offset + 2;
}else{
test_bits = ( bytecode & 0x08 ) >> 3;
if ( test_bits == 1){
/*
* 10001nnn 2 ^ (N + 8) 256 , ... , 32768
*/
result = 1 << ((buff[operand_address] & 0x07) + 8);
operand = result & 0xffff;
*value = operand;
offset ++;
}else{
test_bits = ( bytecode & 0x0e ) >> 1;
if ( test_bits == 3 ){
/*
* 1000 011n 2 ^ (N + 6) 64 , 128
*/
result = 1 << ((buff[operand_address] & 0x01) + 6);
operand = result & 0xffff;
*value = operand;
offset ++;
}else{
/*
* 1000 0000 nnnnnnnn nnnnnnnn N 0 - 65535
* 1000 0001 nnnnnnnn nnnnnnnn memory[N] 0 - 65535
*/
offset ++;
temp_data16 = buff[(operand_address + 1) & 0xffff] << 8;
temp_data16 = temp_data16 | buff[(operand_address + 2) & 0xffff];
/* debug
* g_warning("Reading 0x%x From address %u",temp_data16,operand_address);
*/
if ( (bytecode & 0x01) == 1 ){
memmory_addr = temp_data16;
temp_data16 = buff[memmory_addr] << 8;
temp_data16 = temp_data16 | buff[(memmory_addr+1) & 0xffff];
}
*value = temp_data16;
offset = offset +2;
}
}
}
}
break;
case 3:
test_bits = ( bytecode & 0x20 ) >> 5;
if ( test_bits == 1 ){
/*
* 111nnnnn N + 65504 65504 - 65535
*/
operand = ( buff[operand_address] & 0x1f) + 65504;
*value = operand;
offset ++;
}else{
/*
* 110nnnnn nnnnnnnn memory[N] 0 - 65535
*/
memmory_addr = buff[operand_address] & 0x1f;
memmory_addr = memmory_addr << 8;
memmory_addr = memmory_addr | buff[(operand_address + 1) & 0xffff];
temp_data16 = buff[memmory_addr] << 8;
temp_data16 = temp_data16 | buff[(memmory_addr+1) & 0xffff];
*value = temp_data16;
/* debug
* g_warning("Reading 0x%x From address %u",temp_data16,memmory_addr);
*/
offset = offset +2;
}
default :
break;
}
return offset;
}
/*
*
* The fourth operand type is the address (@). This operand is decoded
* as a multitype operand followed by a further step: the memory address
* of the UDVM instruction containing the address operand is added to
* obtain the correct operand value. So if the operand value from
* Figure 10 is D then the actual operand value of an address is
* calculated as follows:
*
* operand_value = (memory_address_of_instruction + D) modulo 2^16
*
* Address operands are always used in instructions that control program
* flow, because they ensure that the UDVM bytecode is position-
* independent code (i.e., it will run independently of where it is
* placed in the UDVM memory).
*/
static int
decode_udvm_address_operand(guint8 *buff,guint operand_address, guint16 *value,guint current_address)
{
guint32 result;
guint16 value1;
guint next_opreand_address;
next_opreand_address = decode_udvm_multitype_operand(buff, operand_address, &value1);
result = value1 & 0xffff;
result = result + current_address;
*value = result & 0xffff;
return next_opreand_address;
}
/*
* This is a lookup table used to reverse the bits in a byte.
*/
static guint8 reverse [] = {
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
static int
decomp_dispatch_get_bits(
tvbuff_t *message_tvb,
proto_tree *udvm_tree,
guint8 bit_order,
guint8 *buff,
guint16 *old_input_bit_order,
guint16 *remaining_bits,
guint16 *input_bits,
guint *input_address,
guint16 length,
guint16 *result_code,
guint msg_end)
{
guint16 input_bit_order;
guint16 bits_still_required = length;
guint16 value = 0;
guint8 octet;
gint extra_bytes_available = msg_end - *input_address;
gint p_bit;
gint prev_p_bit = *old_input_bit_order & 0x0001;
gint bits_to_use = 0;
input_bit_order = buff[68] << 8;
input_bit_order = input_bit_order | buff[69];
*result_code = 0;
p_bit = (input_bit_order & 0x0001) != 0;
/*
* Discard any spare bits.
* Note: We take care to avoid remaining_bits having the value of 8.
*/
if (prev_p_bit != p_bit)
{
*remaining_bits = 0;
*old_input_bit_order = input_bit_order;
}
/*
* Check we can suppy the required number of bits now, before we alter
* the input buffer's state.
*/
if (*remaining_bits + extra_bytes_available * 8 < length)
{
*result_code = 11;
return 0xfbad;
}
/* Note: This is never called with length > 16, so the following loop
* never loops more than three time. */
while (bits_still_required > 0)
{
/*
* We only put anything into input_bits if we know we will remove
* at least one bit. That ensures we can simply discard the spare
* bits if the P-bit changes.
*/
if (*remaining_bits == 0)
{
octet = tvb_get_guint8(message_tvb, *input_address);
if (print_level_1 ){
proto_tree_add_text(udvm_tree, message_tvb, *input_address , 1,
" Getting value: %u (0x%x) From Addr: %u", octet, octet, *input_address);
}
*input_address = *input_address + 1;
if (p_bit != 0)
{
octet = reverse[octet];
}
*input_bits = octet;
*remaining_bits = 8;
}
/* Add some more bits to the accumulated value. */
bits_to_use = bits_still_required < *remaining_bits ? bits_still_required : *remaining_bits;
bits_still_required -= bits_to_use;
*input_bits <<= bits_to_use; /* Shift bits into MSByte */
value = (value << bits_to_use) /* Then add to the accumulated value */
| ((*input_bits >> 8) & 0xFF);
*remaining_bits -= bits_to_use;
*input_bits &= 0x00FF; /* Leave just the remaining bits */
}
if (bit_order != 0)
{
/* Bit reverse the entire word. */
guint16 lsb = reverse[(value >> 8) & 0xFF];
guint16 msb = reverse[value & 0xFF];
value = ((msb << 8) | lsb) >> (16 - length);
}
return value;
}
/* end udvm */