diff options
Diffstat (limited to 'epan/sigcomp-udvm.c')
-rw-r--r-- | epan/sigcomp-udvm.c | 3223 |
1 files changed, 0 insertions, 3223 deletions
diff --git a/epan/sigcomp-udvm.c b/epan/sigcomp-udvm.c deleted file mode 100644 index ed172c3424..0000000000 --- a/epan/sigcomp-udvm.c +++ /dev/null @@ -1,3223 +0,0 @@ -/* 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 <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 *)wmem_alloc0(wmem_packet_scope(), 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++; - - } - /* 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); - - /* Largest allowed size for a message is UDVM_MEMORY_SIZE = 65536 */ - out_buff = (guint8 *)g_malloc(UDVM_MEMORY_SIZE); - -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, NULL, 0, 0, - "Addr: %u ## DECOMPRESSION-FAILURE(0)", - current_address); - proto_tree_add_text(udvm_tree, NULL, 0, 0,"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_str(wmem_packet_scope(), 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_str(wmem_packet_scope(), 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_str(wmem_packet_scope(), sha1_digest_buf, STATE_MIN_ACCESS_LEN)); - - 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)")); - g_free(out_buff); - THROW(ReportedBoundsError); - 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 */ - -/* - * Editor modelines - http://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 8 - * tab-width: 8 - * indent-tabs-mode: t - * End: - * - * vi: set shiftwidth=8 tabstop=8 noexpandtab: - * :indentSize=8:tabSize=8:noTabs=false: - */ |