/* packet-aastra-aasp.c * Routines for AASP (Aastra Signalling Protocol) packet dissection. * Copyright 2011, Marek Tews * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ /* * AASP over SIP * Content-Type: message/x-aasp-signalling */ #include "config.h" #include /* commands id */ #define BEGIN_BLOCK_DATA 0x80 #define WINDOW 0x81 #define TITLE 0x83 #define ROW 0x84 #define MENU_ITEM 0x85 #define CONTEXT_INFO 0x86 #define BUTTON_PRESSED 0x87 #define COLUMN 0x88 #define SET_TEXT 0x89 #define DATE_TIME_INFO 0xA4 #define INCOMING_CALLER 0xA5 #define DO_COMMAND 0xA9 #define PUSH_BTN_C 0xC8 #define PUSH_BTN_TASK 0xC9 #define PUSH_BTN_PLUS 0xCA #define PUSH_BTN_MINUS 0xCB #define PUSH_BTN_MIC 0xCC #define PUSH_BTN_SPK 0xCD #define PUSH_BTN_TBOOK 0xCE #define PUSH_BTN_DBL_ARROW 0xCF #define PUSH_BTN_ON_HOOK 0xD0 #define PUSH_BTN_OFF_HOOK 0xD1 #define PUSH_BTN_UP 0xD2 #define PUSH_BTN_DOWN 0xD3 #define PUSH_BTN_LEFT 0xD4 #define PUSH_BTN_RIGHT 0xD5 #define END_BLOCK_DATA 0xFE /* Forward declarations */ void proto_register_aasp(void); void proto_reg_handoff_aasp(void); static dissector_handle_t aasp_handle; /* Initialize the protocol and registered fields */ static gint proto_aasp; static gint hf_a_data; static gint hf_a_cmd; static gint hf_a_id; static gint hf_a_length; static gint hf_a_text; static gint hf_a_line; static gint hf_a_cdpn; static gint hf_a_button_id; static gint hf_a_attr; static gint hf_a_item; static gint hf_a_hour; static gint hf_a_minute; static gint hf_a_day; static gint hf_a_month; static gint hf_a_weekofyear; static gint hf_a_weekday; static gint hf_a_month_name; static gint hf_a_weekofyear_prefix; /* Initialize the subtree pointers */ static gint ett_aasp; static gint ett_a_cmd; static gint ett_a_item; /* Preferences */ /** * Commands */ static const value_string szCmdID[] = { { BEGIN_BLOCK_DATA, "Begin Block Data" }, { WINDOW, "Window" }, { TITLE, "Title" }, { ROW, "Row" }, { MENU_ITEM, "Menu Item" }, { CONTEXT_INFO, "Context Info" }, { BUTTON_PRESSED, "Button Pressed" }, { COLUMN, "Column" }, { SET_TEXT, "Set Text" }, { DATE_TIME_INFO, "Date Time Info" }, { INCOMING_CALLER, "Incoming Caller" }, { DO_COMMAND, "Do Command" }, { PUSH_BTN_C, "Push Button 'C'" }, { PUSH_BTN_TASK, "Push Button 'Task'" }, { PUSH_BTN_PLUS, "Push Button '+'" }, { PUSH_BTN_MINUS, "Push Button '-'" }, { PUSH_BTN_MIC, "Push Button 'Microphone'" }, { PUSH_BTN_SPK, "Push Button 'Speaker'" }, { PUSH_BTN_TBOOK, "Push Button 'Telephone Book'" }, { PUSH_BTN_DBL_ARROW, "Push Button 'Double-Arrow'" }, { PUSH_BTN_ON_HOOK, "Red Button 'On Hook'" }, { PUSH_BTN_OFF_HOOK, "Green Button 'Off Hook'" }, { PUSH_BTN_UP, "Push Button 'Up'" }, { PUSH_BTN_DOWN, "Push Button 'Down'" }, { PUSH_BTN_LEFT, "Push Button 'Left'" }, { PUSH_BTN_RIGHT, "Push Button 'Right'" }, { END_BLOCK_DATA, "End Block Data" }, { 0, NULL } }; /** * Dissect single command */ static void dissect_a_binary_command(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree) { proto_item *ti; proto_tree *subtree; const guint8* pstr; guint i, len; /* create command subtree */ ti = proto_tree_add_item(tree, hf_a_cmd, tvb, 0, -1, ENC_NA); subtree = proto_item_add_subtree(ti, ett_a_cmd); proto_item_append_text(ti, ", %s", val_to_str(tvb_get_guint8(tvb, 0), szCmdID, "Unk %d")); /* command id */ proto_tree_add_item(subtree, hf_a_id, tvb, 0, 1, ENC_BIG_ENDIAN); /* attributes */ switch(tvb_get_guint8(tvb, 0)) { default: { if(tvb_reported_length(tvb) > 1) proto_tree_add_item(subtree, hf_a_data, tvb, 1, -1, ENC_NA); break; } case CONTEXT_INFO: { for(i = 1; i 3) { proto_tree_add_item(subtree, hf_a_data, tvb, 1, 3, ENC_NA); proto_tree_add_item(subtree, hf_a_length, tvb, 4, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_a_text, tvb, 5, -1, ENC_ASCII); pstr = tvb_get_string_enc(pinfo->pool, tvb, 5, tvb_get_guint8(tvb, 4), ENC_ASCII|ENC_NA); if(pstr) { proto_item_append_text(ti, ": '%s'", pstr); } } else { proto_tree_add_item(subtree, hf_a_data, tvb, 1, -1, ENC_NA); } break; } case DATE_TIME_INFO: { proto_tree *infotree; for(i=1; ipool, &pstr); if(pstr) proto_item_append_text(ti, ", Weekday: '%s'", pstr); i += len +2; break; } case 6: { len = tvb_get_guint8(tvb, i+1); ti = proto_tree_add_item(subtree, hf_a_item, tvb, i, len+2, ENC_NA); infotree = proto_item_add_subtree(ti, ett_a_item); proto_tree_add_item_ret_string(infotree, hf_a_month_name, tvb, i+2, len, ENC_ASCII|ENC_NA, pinfo->pool, &pstr); if(pstr) proto_item_append_text(ti, ", Month name: '%s'", pstr); i += len +2; break; } case 7: { len = tvb_get_guint8(tvb, i+1); ti = proto_tree_add_item(subtree, hf_a_item, tvb, i, len+2, ENC_NA); infotree = proto_item_add_subtree(ti, ett_a_item); proto_tree_add_item_ret_string(infotree, hf_a_weekofyear_prefix, tvb, i+2, len, ENC_ASCII|ENC_NA, pinfo->pool, &pstr); if(pstr) proto_item_append_text(ti, ", Week of the year prefix: '%s'", pstr); i += len +2; break; } case 8: { len = 2; ti = proto_tree_add_item(subtree, hf_a_item, tvb, i, len, ENC_NA); infotree = proto_item_add_subtree(ti, ett_a_item); proto_tree_add_item(infotree, hf_a_hour, tvb, i+1, 1, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", Hour: '%d'", tvb_get_guint8(tvb, i+1)); i += len; break; } case 9: { len = 2; ti = proto_tree_add_item(subtree, hf_a_item, tvb, i, len, ENC_NA); infotree = proto_item_add_subtree(ti, ett_a_item); proto_tree_add_item(infotree, hf_a_minute, tvb, i+1, 1, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", Minute: '%d'", tvb_get_guint8(tvb, i+1)); i += len; break; } case 10: { len = 2; ti = proto_tree_add_item(subtree, hf_a_item, tvb, i, len, ENC_NA); infotree = proto_item_add_subtree(ti, ett_a_item); proto_tree_add_item(infotree, hf_a_data, tvb, i+1, 1, ENC_NA); i += len; break; } } } break; } case DO_COMMAND: { if(tvb_reported_length(tvb) > 1) { proto_tree_add_item(subtree, hf_a_line, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_a_length, tvb, 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_a_cdpn, tvb, 3, -1, ENC_ASCII); pstr = tvb_get_string_enc(pinfo->pool, tvb, 3, tvb_get_guint8(tvb, 2), ENC_ASCII|ENC_NA); if(pstr) proto_item_append_text(ti, ": '%s'", pstr); } else proto_item_append_text(ti, ": ???"); break; } } } /** * Searching for the next command when the variable or unknown length. */ static guint searchNext(tvbuff_t *tvb, guint begin, guint end) { for(; begin < end; begin++) { if(tvb_get_guint8(tvb, begin) & 0x80) return begin; } return end; } /** * AASP-over-SIP */ static int dissect_aasp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *aasp_tree; guint n; /* Check that there's enough data */ n = tvb_reported_length(tvb); if(n < 3) return 0; col_clear(pinfo->cinfo, COL_INFO); col_append_str(pinfo->cinfo, COL_PROTOCOL, "/AASP"); if(tree) { guint i, prev; /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_aasp, tvb, 0, -1, ENC_NA); aasp_tree = proto_item_add_subtree(ti, ett_aasp); /* separation of command; jump "a=" */ if(tvb_memeql(tvb, 0, (const guint8*)"a=", 2) == 0) { prev = 2; for(i=2; i