proto_item *ti; proto_tree *ax25_tree; int offset; int via_index; char *info_buffer; /* char v2cmdresp; */ const char *ax25_version; int is_response; guint8 control; guint8 pid = AX25_P_NO_L3; guint8 src_ssid; guint8 dst_ssid; tvbuff_t *next_tvb = NULL; info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN ); info_buffer[0] = '\0'; col_set_str( pinfo->cinfo, COL_PROTOCOL, "AX.25" ); col_clear( pinfo->cinfo, COL_INFO ); /* start at the dst addr */ offset = 0; /* create display subtree for the protocol */ ti = proto_tree_add_protocol_format( parent_tree, proto_ax25, tvb, offset, -1, "AX.25"); ax25_tree = proto_item_add_subtree( ti, ett_ax25 ); proto_tree_add_item( ax25_tree, hf_ax25_dst, tvb, offset, AX25_ADDR_LEN, ENC_NA); set_address_tvb(&pinfo->dl_dst, AT_AX25, AX25_ADDR_LEN, tvb, offset); copy_address_shallow(&pinfo->dst, &pinfo->dl_dst); dst_ssid = tvb_get_guint8(tvb, offset+6);
static void dissect_cimd_ud(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset) { /* Set up structures needed to add the param subtree and manage it */ proto_tree *param_tree; gchar *payloadText, *tmpBuffer, *tmpBuffer1; int loop,i,poz, bufPoz = 0, bufPoz1 = 0, size, size1, resch; gint g_offset, g_size; gchar token[4]; gchar ch; static const char* mapping[128] = { "_Oa" , "_L-", "" , "_Y-", "_e`", "_e'", "_u`", "_i`", "_o`", "_C,", /*10*/ "" , "_O/", "_o/" , "" , "_A*", "_a*", "_gd", "_--", "_gf", "_gg", "_gl", /*21*/ "_go" , "_gp", "_gi" , "_gs", "_gt", "_gx", "_XX", "_AE", "_ae", "_ss", "_E'", /*32*/ "" , "" , "_qq" , "" , "_ox", "" , "" , "" , "" , "" , "" , "" , "" , "" , "", "", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "", "", "_!!" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "", "", "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "_A\"", "_O\"", "_N~", "_U\"", "_so", "_??" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "" , "", "_a\"", "_o\"", "_n~", "_n\"","_a`" }; param_tree = proto_tree_add_subtree(tree, tvb, startOffset + 1, endOffset - (startOffset + 1), (*vals_hdr_PC[pindex].ett_p), NULL, cimd_vals_PC[pindex].strptr ); proto_tree_add_item(param_tree, hf_cimd_pcode_indicator, tvb, startOffset + 1, CIMD_PC_LENGTH, ENC_ASCII|ENC_NA); g_offset = startOffset + 1 + CIMD_PC_LENGTH + 1; g_size = endOffset - g_offset; payloadText = tvb_format_text(tvb, g_offset, g_size); size = (int)strlen(payloadText); tmpBuffer = (gchar*)wmem_alloc(wmem_packet_scope(), size+1); for (loop = 0; loop < size; loop++) { if (payloadText[loop] == '_') { if (loop < size - 2) { token[0] = payloadText[loop++]; token[1] = payloadText[loop++]; token[2] = payloadText[loop]; token[3] = '\0'; poz = -1; for (i = 0; i < 128; i++) { if (strcmp(token, mapping[i]) == 0) { poz = i; break; } } if (poz > 0) { tmpBuffer[bufPoz++] = poz; } else { tmpBuffer[bufPoz++] = payloadText[loop-2]; tmpBuffer[bufPoz++] = payloadText[loop-1]; tmpBuffer[bufPoz++] = payloadText[loop]; } } else { if (loop < size) tmpBuffer[bufPoz++] = payloadText[loop++]; if (loop < size) tmpBuffer[bufPoz++] = payloadText[loop++]; if (loop < size) tmpBuffer[bufPoz++] = payloadText[loop++]; } } else { tmpBuffer[bufPoz++] = payloadText[loop]; } } tmpBuffer[bufPoz] = '\0'; size1 = (int)strlen(tmpBuffer); tmpBuffer1 = (gchar*)wmem_alloc(wmem_packet_scope(), size1+1); for (loop=0; loop<size1; loop++) { ch = tmpBuffer[loop]; switch ((gint)ch) { case 0x40: resch = 0x0040; break; case 0x01: resch = 0x00A3; break; case 0x02: resch = 0x0024; break; case 0x03: resch = 0x00A5; break; case 0x04: resch = 0x00E8; break; case 0x05: resch = 0x00E9; break; case 0x06: resch = 0x00F9; break; case 0x07: resch = 0x00EC; break; case 0x08: resch = 0x00F2; break; case 0x09: resch = 0x00E7; break; case 0x0B: resch = 0x00D8; break; case 0x0C: resch = 0x00F8; break; case 0x0E: resch = 0x00C5; break; case 0x0F: resch = 0x00E5; break; case 0x11: resch = 0x005F; break; /* case 0x1B14: resch = 0x005E; break; */ /* case 0x1B28: resch = 0x007B; break; */ /* case 0x1B29: resch = 0x007D; break; */ /* case 0x1B2F: resch = 0x005C; break; */ /* case 0x1B3C: resch = 0x005B; break; */ /* case 0x1B3D: resch = 0x007E; break; */ /* case 0x1B3E: resch = 0x005D; break; */ /* case 0x1B40: resch = 0x007C; break; */ case 0x1C: resch = 0x00C6; break; case 0x1D: resch = 0x00E6; break; case 0x1E: resch = 0x00DF; break; case 0x1F: resch = 0x00C9; break; case 0x20: resch = 0x0020; break; case 0x21: resch = 0x0021; break; case 0x22: resch = 0x0022; break; case 0x23: resch = 0x0023; break; case 0xA4: resch = 0x00A4; break; case 0x25: resch = 0x0025; break; case 0x26: resch = 0x0026; break; case 0x27: resch = 0x0027; break; case 0x28: resch = 0x0028; break; case 0x29: resch = 0x0029; break; case 0x2A: resch = 0x002A; break; case 0x2B: resch = 0x002B; break; case 0x2C: resch = 0x002C; break; case 0x2D: resch = 0x002D; break; case 0x2E: resch = 0x002E; break; case 0x2F: resch = 0x002F; break; case 0x30: resch = 0x0030; break; case 0x31: resch = 0x0031; break; case 0x32: resch = 0x0032; break; case 0x33: resch = 0x0033; break; case 0x34: resch = 0x0034; break; case 0x35: resch = 0x0035; break; case 0x36: resch = 0x0036; break; case 0x37: resch = 0x0037; break; case 0x38: resch = 0x0038; break; case 0x39: resch = 0x0039; break; case 0x3A: resch = 0x003A; break; case 0x3B: resch = 0x003B; break; case 0x3C: resch = 0x003C; break; case 0x3D: resch = 0x003D; break; case 0x3E: resch = 0x003E; break; case 0x3F: resch = 0x003F; break; /* case 0x40: resch = 0x00A1; break; */ case 0x41: resch = 0x0041; break; case 0x42: resch = 0x0042; break; /* case 0x42: resch = 0x0392; break; */ case 0x43: resch = 0x0043; break; case 0x44: resch = 0x0044; break; case 0x45: resch = 0x0045; break; case 0x46: resch = 0x0046; break; case 0x47: resch = 0x0047; break; case 0x48: resch = 0x0048; break; case 0x49: resch = 0x0049; break; case 0x4A: resch = 0x004A; break; case 0x4B: resch = 0x004B; break; case 0x4C: resch = 0x004C; break; case 0x4D: resch = 0x004D; break; case 0x4E: resch = 0x004E; break; case 0x4F: resch = 0x004F; break; case 0x50: resch = 0x0050; break; case 0x51: resch = 0x0051; break; case 0x52: resch = 0x0052; break; case 0x53: resch = 0x0053; break; case 0x54: resch = 0x0054; break; case 0x55: resch = 0x0055; break; case 0x56: resch = 0x0056; break; case 0x57: resch = 0x0057; break; case 0x58: resch = 0x0058; break; case 0x59: resch = 0x0059; break; case 0x5A: resch = 0x005A; break; case 0x5B: resch = 0x00C4; break; case 0x5C: resch = 0x00D6; break; case 0x5D: resch = 0x00D1; break; case 0x5E: resch = 0x00DC; break; case 0x5F: resch = 0x00A7; break; case 0x60: resch = 0x00BF; break; case 0x61: resch = 0x0061; break; case 0x62: resch = 0x0062; break; case 0x63: resch = 0x0063; break; case 0x64: resch = 0x0064; break; case 0x65: resch = 0x0065; break; case 0x66: resch = 0x0066; break; case 0x67: resch = 0x0067; break; case 0x68: resch = 0x0068; break; case 0x69: resch = 0x0069; break; case 0x6A: resch = 0x006A; break; case 0x6B: resch = 0x006B; break; case 0x6C: resch = 0x006C; break; case 0x6D: resch = 0x006D; break; case 0x6E: resch = 0x006E; break; case 0x6F: resch = 0x006F; break; case 0x70: resch = 0x0070; break; case 0x71: resch = 0x0071; break; case 0x72: resch = 0x0072; break; case 0x73: resch = 0x0073; break; case 0x74: resch = 0x0074; break; case 0x75: resch = 0x0075; break; case 0x76: resch = 0x0076; break; case 0x77: resch = 0x0077; break; case 0x78: resch = 0x0078; break; case 0x79: resch = 0x0079; break; case 0x7A: resch = 0x007A; break; case 0x7B: resch = 0x00E4; break; case 0x7C: resch = 0x00F6; break; case 0x7D: resch = 0x00F1; break; case 0x7F: resch = 0x00E0; break; default:resch = ch; break; } tmpBuffer1[bufPoz1++] = (gchar)resch; } tmpBuffer1[bufPoz1] = '\0'; proto_tree_add_string(param_tree, (*vals_hdr_PC[pindex].hf_p), tvb, g_offset, g_size, tmpBuffer1); }
static gint dissect_adb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *arg0_item; proto_tree *arg0_tree; proto_item *arg1_item; proto_tree *arg1_tree; proto_item *magic_item; proto_item *crc_item; proto_tree *crc_tree = NULL; proto_item *sub_item; gint offset = 0; guint32 command; guint32 arg0; guint32 arg1; guint32 data_length = 0; guint32 crc32 = 0; usb_conv_info_t *usb_conv_info = NULL; wmem_tree_key_t key[5]; guint32 interface_id; guint32 bus_id; guint32 device_address; guint32 side_id; guint32 frame_number; gboolean is_command = TRUE; gboolean is_next_fragment = FALSE; gboolean is_service = FALSE; gint proto; gint direction = P2P_DIR_UNKNOWN; wmem_tree_t *wmem_tree; command_data_t *command_data = NULL; service_data_t *service_data = NULL; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ADB"); col_clear(pinfo->cinfo, COL_INFO); main_item = proto_tree_add_item(tree, proto_adb, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_adb); frame_number = pinfo->fd->num; /* XXX: Why? If interface is USB only first try is correct * (and seems strange...), in other cases standard check for * previous protocol is correct */ proto = (gint) GPOINTER_TO_INT(wmem_list_frame_data(/*wmem_list_frame_prev*/(wmem_list_tail(pinfo->layers)))); if (proto != proto_usb) { proto = (gint) GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers)))); } if (proto == proto_usb) { usb_conv_info = (usb_conv_info_t *) data; DISSECTOR_ASSERT(usb_conv_info); direction = usb_conv_info->direction; } else if (proto == proto_tcp) { if (pinfo->destport == ADB_TCP_PORT) direction = P2P_DIR_SENT; else direction = P2P_DIR_RECV; } else { return offset; } if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID) interface_id = pinfo->phdr->interface_id; else interface_id = 0; if (proto == proto_usb) { bus_id = usb_conv_info->bus_id; device_address = usb_conv_info->device_address; key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; key[1].key = &bus_id; key[2].length = 1; key[2].key = &device_address; key[3].length = 0; key[3].key = NULL; } else { /* tcp */ key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; key[2].length = 1; if (direction == P2P_DIR_SENT) { key[1].key = &pinfo->srcport; key[2].key = &pinfo->destport; } else { key[1].key = &pinfo->destport; key[2].key = &pinfo->srcport; } key[3].length = 0; key[3].key = NULL; } wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(command_info, key); if (wmem_tree) { command_data = (command_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number); if (command_data && command_data->completed_in_frame >= frame_number && command_data->command_in_frame <= frame_number) { if (command_data->command_in_frame != frame_number) { is_command = FALSE; is_next_fragment = TRUE; } data_length = command_data->data_length; crc32 = command_data->crc32; if (direction == P2P_DIR_SENT) if (command_data->command == A_CLSE) side_id = command_data->arg1; /* OUT: local id */ else side_id = command_data->arg0; /* OUT: local id */ else if (command_data->command == A_OKAY) { side_id = command_data->arg1; /* IN: remote id */ } else side_id = command_data->arg1; /* IN: remote id */ key[3].length = 1; key[3].key = &side_id; key[4].length = 0; key[4].key = NULL; wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(service_info, key); if (wmem_tree) { service_data = (service_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number); if (service_data && command_data->command == A_OPEN) { is_service = TRUE; } } } } /* Simple heuristics to check if packet is command or data */ if ((command_data && command_data->completed_in_frame <= frame_number) || !command_data) { if (tvb_reported_length(tvb) < 24) { is_command = FALSE; } else if (tvb_reported_length(tvb) >= 24) { command = tvb_get_letohl(tvb, offset); if (command != A_SYNC && command != A_CLSE && command != A_WRTE && command != A_AUTH && command != A_CNXN && command != A_OPEN && command != A_OKAY) is_command = FALSE; else if (command != (0xFFFFFFFF ^ tvb_get_letohl(tvb, offset + 20))) is_command = FALSE; if (is_command) { data_length = tvb_get_letohl(tvb, offset + 12); crc32 = tvb_get_letohl(tvb, offset + 16); } if (command == A_OPEN) is_service = TRUE; } } if (service_data && !(command_data->command == A_OPEN && is_next_fragment)) { sub_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service_data->service); PROTO_ITEM_SET_GENERATED(sub_item); } if (service_data) { sub_item = proto_tree_add_uint(main_tree, hf_service_start_in_frame, tvb, offset, 0, service_data->start_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); if (service_data->close_local_in_frame < max_in_frame) { sub_item = proto_tree_add_uint(main_tree, hf_close_local_in_frame, tvb, offset, 0, service_data->close_local_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } if (service_data->close_remote_in_frame < max_in_frame) { sub_item = proto_tree_add_uint(main_tree, hf_close_remote_in_frame, tvb, offset, 0, service_data->close_remote_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } } if (is_command) { proto_tree_add_item(main_tree, hf_command, tvb, offset, 4, ENC_LITTLE_ENDIAN); command = tvb_get_letohl(tvb, offset); offset += 4; col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(command, command_vals, "Unknown command")); arg0_item = proto_tree_add_item(main_tree, hf_argument_0, tvb, offset, 4, ENC_LITTLE_ENDIAN); arg0_tree = proto_item_add_subtree(arg0_item, ett_adb_arg0); arg0 = tvb_get_letohl(tvb, offset); offset += 4; arg1_item = proto_tree_add_item(main_tree, hf_argument_1, tvb, offset, 4, ENC_LITTLE_ENDIAN); arg1_tree = proto_item_add_subtree(arg1_item, ett_adb_arg1); arg1 = tvb_get_letohl(tvb, offset); offset += 4; switch (command) { case A_CNXN: proto_tree_add_item(arg0_tree, hf_version, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_max_data, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(version=%u.%u.%u, max_data=%u)", tvb_get_guint8(tvb, offset - 5), tvb_get_guint8(tvb, offset - 6), tvb_get_letohs(tvb, offset - 7), tvb_get_letohl(tvb, offset - 4)); break; case A_AUTH: proto_tree_add_item(arg0_tree, hf_auth_type, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_zero, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(type=%s, 0)", val_to_str_const(tvb_get_letohl(tvb, offset - 8), auth_type_vals, "Unknown")); break; case A_OPEN: proto_tree_add_item(arg0_tree, hf_local_id, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_zero, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(local=%u, 0)", tvb_get_letohl(tvb, offset - 8)); break; case A_WRTE: proto_tree_add_item(arg0_tree, hf_zero, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_remote_id, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(0, remote=%u)", tvb_get_letohl(tvb, offset - 4)); break; case A_CLSE: case A_OKAY: proto_tree_add_item(arg0_tree, hf_local_id, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_remote_id, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(local=%u, remote=%u)", tvb_get_letohl(tvb, offset - 8), tvb_get_letohl(tvb, offset - 4)); break; case A_SYNC: proto_tree_add_item(arg0_tree, hf_online, tvb, offset - 8, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(arg1_tree, hf_sequence, tvb, offset - 4, 4, ENC_LITTLE_ENDIAN); col_append_fstr(pinfo->cinfo, COL_INFO, "(online=%s, sequence=%u)", tvb_get_letohl(tvb, offset - 8) ? "Yes": "No", tvb_get_letohl(tvb, offset - 4)); break; } proto_tree_add_item(main_tree, hf_data_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; if (data_length > 0) col_append_fstr(pinfo->cinfo, COL_INFO, " length=%u ", data_length); crc_item = proto_tree_add_item(main_tree, hf_data_crc32, tvb, offset, 4, ENC_LITTLE_ENDIAN); crc_tree = proto_item_add_subtree(crc_item, ett_adb_crc); crc32 = tvb_get_letohl(tvb, offset); offset += 4; magic_item = proto_tree_add_item(main_tree, hf_magic, tvb, offset, 4, ENC_LITTLE_ENDIAN); if ((tvb_get_letohl(tvb, offset) ^ 0xFFFFFFFF) != command) { proto_tree *expert_tree; expert_tree = proto_item_add_subtree(magic_item, ett_adb_magic); proto_tree_add_expert(expert_tree, pinfo, &ei_invalid_magic, tvb, offset, 4); } if (!pinfo->fd->flags.visited) save_command(command, arg0, arg1, data_length, crc32, service_data, proto, data, pinfo, &service_data, &command_data); offset += 4; } if (!pinfo->fd->flags.visited && command_data) { if (command_data->command_in_frame != frame_number) { is_command = FALSE; is_next_fragment = TRUE; } data_length = command_data->data_length; crc32 = command_data->crc32; if ((command_data->command_in_frame != frame_number && tvb_captured_length(tvb) == data_length) || (command_data->command_in_frame == frame_number && tvb_captured_length(tvb) == data_length + 24) ) { command_data->reassemble_data_length = command_data->data_length; command_data->completed_in_frame = frame_number; } } if (is_next_fragment && command_data) { sub_item = proto_tree_add_uint(main_tree, hf_command_in_frame, tvb, offset, 0, command_data->command_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 0, command_data->command); PROTO_ITEM_SET_GENERATED(sub_item); sub_item = proto_tree_add_uint(main_tree, hf_data_length, tvb, offset, 0, command_data->data_length); PROTO_ITEM_SET_GENERATED(sub_item); crc_item = proto_tree_add_uint(main_tree, hf_data_crc32, tvb, offset, 0, command_data->crc32); crc_tree = proto_item_add_subtree(crc_item, ett_adb_crc); PROTO_ITEM_SET_GENERATED(crc_item); } if (command_data && command_data->completed_in_frame != frame_number) { sub_item = proto_tree_add_uint(main_tree, hf_completed_in_frame, tvb, offset, 0, command_data->completed_in_frame); PROTO_ITEM_SET_GENERATED(sub_item); } if (tvb_captured_length_remaining(tvb, offset) > 0 && (!is_command || data_length > 0)) { guint32 crc = 0; guint32 i_offset; if ((!pinfo->fd->flags.visited && command_data && command_data->reassemble_data_length < command_data->data_length) || data_length > (guint32) tvb_captured_length_remaining(tvb, offset)) { /* need reassemble */ if (!pinfo->fd->flags.visited && command_data && command_data->reassemble_data_length < command_data->data_length) { tvb_memcpy(tvb, command_data->reassemble_data + command_data->reassemble_data_length, offset, tvb_captured_length_remaining(tvb, offset)); command_data->reassemble_data_length += tvb_captured_length_remaining(tvb, offset); if (command_data->reassemble_data_length >= command_data->data_length) command_data->completed_in_frame = frame_number; } proto_tree_add_item(main_tree, hf_data_fragment, tvb, offset, -1, ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Data Fragment"); offset = tvb_captured_length(tvb); if (service_data && command_data && command_data->reassemble_data_length >= command_data->data_length && frame_number == command_data->completed_in_frame) { tvbuff_t *next_tvb; adb_service_data_t adb_service_data; next_tvb = tvb_new_child_real_data(tvb, command_data->reassemble_data, command_data->reassemble_data_length, command_data->reassemble_data_length); add_new_data_source(pinfo, next_tvb, "ADB Reassembled Data"); adb_service_data.service = service_data->service; adb_service_data.direction = direction; adb_service_data.session_key_length = 3; adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32)); adb_service_data.session_key[0] = interface_id; if (proto == proto_usb) { adb_service_data.session_key[1] = usb_conv_info->bus_id; adb_service_data.session_key[2] = usb_conv_info->device_address; } else { /* tcp */ if (direction == P2P_DIR_SENT) { adb_service_data.session_key[1] = pinfo->srcport; adb_service_data.session_key[2] = pinfo->destport; } else { adb_service_data.session_key[1] = pinfo->destport; adb_service_data.session_key[2] = pinfo->srcport; } } call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data); } } else { /* full message */ for (i_offset = 0; i_offset < data_length; ++i_offset) crc += tvb_get_guint8(tvb, offset + i_offset); if (crc32 > 0 && crc32 != crc) proto_tree_add_expert(crc_tree, pinfo, &ei_invalid_crc, tvb, offset, -1); if (is_service) { proto_tree_add_item(main_tree, hf_service, tvb, offset, -1, ENC_ASCII | ENC_NA); if (!pinfo->fd->flags.visited && service_data) { service_data->service = tvb_get_stringz_enc(wmem_file_scope(), tvb, offset, NULL, ENC_ASCII); } col_append_fstr(pinfo->cinfo, COL_INFO, "Service: %s", tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, NULL, ENC_ASCII)); offset = tvb_captured_length(tvb); } else if (command_data && command_data->command == A_CNXN) { gchar *info; gint len; info = tvb_get_stringz_enc(wmem_packet_scope(), tvb, offset, &len, ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, "Connection Info: %s", info); proto_tree_add_item(main_tree, hf_connection_info, tvb, offset, len, ENC_ASCII | ENC_NA); offset += len; } else { col_append_str(pinfo->cinfo, COL_INFO, "Data"); /* Decode service payload */ if (service_data) { tvbuff_t *next_tvb; adb_service_data_t adb_service_data; adb_service_data.service = service_data->service; adb_service_data.direction = direction; adb_service_data.session_key_length = 3; adb_service_data.session_key = (guint32 *) wmem_alloc(wmem_packet_scope(), adb_service_data.session_key_length * sizeof(guint32)); adb_service_data.session_key[0] = interface_id; if (proto == proto_usb) { adb_service_data.session_key[1] = usb_conv_info->bus_id; adb_service_data.session_key[2] = usb_conv_info->device_address; } else { /* tcp */ if (direction == P2P_DIR_SENT) { adb_service_data.session_key[1] = pinfo->srcport; adb_service_data.session_key[2] = pinfo->destport; } else { adb_service_data.session_key[1] = pinfo->destport; adb_service_data.session_key[2] = pinfo->srcport; } } next_tvb = tvb_new_subset(tvb, offset, tvb_captured_length_remaining(tvb, offset), tvb_captured_length_remaining(tvb, offset)); call_dissector_with_data(adb_service_handle, next_tvb, pinfo, tree, &adb_service_data); } else { proto_item *data_item; gchar *data_str; data_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, data_length, ENC_NA); data_str = tvb_format_text(tvb, offset, data_length); proto_item_append_text(data_item, ": %s", data_str); col_append_fstr(pinfo->cinfo, COL_INFO, " Raw: %s", data_str); } offset = tvb_captured_length(tvb); } } } return offset; }
/* * Unfold and clean up a MIME-like header, and process LWS as follows: * o Preserves LWS in quoted text * o Remove LWS before and after a separator * o Remove trailing LWS * o Replace other LWS with a single space * Set value to the start of the value * Return the cleaned-up RFC2822 header (buffer must be freed). */ static char * unfold_and_compact_mime_header(const char *lines, gint *first_colon_offset) { const char *p = lines; char c; char *ret, *q; char sep_seen = 0; /* Did we see a separator ":;," */ char lws = FALSE; /* Did we see LWS (incl. folding) */ gint colon = -1; if (! lines) return NULL; c = *p; ret = (char *)wmem_alloc(wmem_packet_scope(), strlen(lines) + 1); q = ret; while (c) { if (c == ':') { lws = FALSE; /* Prevent leading LWS from showing up */ if (colon == -1) {/* First colon */ colon = (gint) (q - ret); } *(q++) = sep_seen = c; p++; } else if (c == ';' || c == ',' || c == '=') { lws = FALSE; /* Prevent leading LWS from showing up */ *(q++) = sep_seen = c; p++; } else if (c == ' ' || c == '\t') { lws = TRUE; p++; } else if (c == '\n') { lws = FALSE; /* Skip trailing LWS */ if ((c = *(p+1))) { if (c == ' ' || c == '\t') { /* Header unfolding */ lws = TRUE; p += 2; } else { *q = c = 0; /* Stop */ } } } else if (c == '\r') { lws = FALSE; if ((c = *(p+1))) { if (c == '\n') { if ((c = *(p+2))) { if (c == ' ' || c == '\t') { /* Header unfolding */ lws = TRUE; p += 3; } else { *q = c = 0; /* Stop */ } } } else if (c == ' ' || c == '\t') { /* Header unfolding */ lws = TRUE; p += 2; } else { *q = c = 0; /* Stop */ } } } else if (c == '"') { /* Start of quoted-string */ lws = FALSE; *(q++) = c; while (c) { c = *(q++) = *(++p); if (c == '"') { p++; /* Skip closing quote */ break; } } /* if already zero terminated now, rewind one char to avoid an "off by one" */ if(c == 0) { q--; } } else { /* Regular character */ if (sep_seen) { sep_seen = 0; } else { if (lws) { *(q++) = ' '; } } lws = FALSE; *(q++) = c; p++; /* OK */ } if (c) { c = *p; } } *q = 0; *first_colon_offset = colon; return (ret); }
static void dissect_fw1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *volatile fh_tree = NULL; char direction; char chain; char *interface_name; guint32 iface_len = 10; wmem_strbuf_t *header; int i; gboolean found; static const char fw1_header[] = "FW1 Monitor"; ethertype_data_t ethertype_data; header = wmem_strbuf_new_label(wmem_epan_scope()); wmem_strbuf_append(header, fw1_header); /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FW1"); col_clear(pinfo->cinfo, COL_INFO); /* g_snprintf(header, sizeof(header), fw1_header); */ /* fetch info to local variable */ direction = tvb_get_guint8(tvb, 0); if (!fw1_iflist_with_chain) chain = ' '; else chain = tvb_get_guint8(tvb, 1); if (fw1_with_uuid) iface_len = 6; interface_name=(char *)wmem_alloc(wmem_packet_scope(), iface_len+1); tvb_get_nstringz0(tvb, 2, iface_len+1, interface_name); /* Known interface name - if not, remember it */ found=FALSE; for (i=0; i<interface_anzahl; i++) { if ( strcmp(p_interfaces[i], interface_name) == 0 ) { found=TRUE; break; } } if (!found && interface_anzahl < MAX_INTERFACES) { p_interfaces[interface_anzahl] = wmem_strdup(wmem_file_scope(), interface_name); interface_anzahl++; } /* display all interfaces always in the same order */ for (i=0; i<interface_anzahl; i++) { if ( strcmp(p_interfaces[i], interface_name) == 0 ) { wmem_strbuf_append_printf(header, " %c%c %s %c%c", direction == 'i' ? 'i' : (direction == 'O' ? 'O' : ' '), (direction == 'i' || direction == 'O') ? chain : ' ', p_interfaces[i], direction == 'I' ? 'I' : (direction == 'o' ? 'o' : ' '), (direction == 'I' || direction == 'o') ? chain : ' ' ); } else { wmem_strbuf_append_printf(header, " %s ", p_interfaces[i]); } } col_add_str(pinfo->cinfo, COL_IF_DIR, wmem_strbuf_get_str(header) + sizeof(fw1_header) + 1); if (tree) { if (!fw1_summary_in_tree) /* Do not show the summary in Protocol Tree */ ti = proto_tree_add_protocol_format(tree, proto_fw1, tvb, 0, ETH_HEADER_SIZE, "%s", fw1_header); else ti = proto_tree_add_protocol_format(tree, proto_fw1, tvb, 0, ETH_HEADER_SIZE, "%s", wmem_strbuf_get_str(header)); /* create display subtree for the protocol */ fh_tree = proto_item_add_subtree(ti, ett_fw1); proto_tree_add_item(fh_tree, hf_fw1_direction, tvb, 0, 1, ENC_ASCII|ENC_NA); if (fw1_iflist_with_chain) proto_tree_add_item(fh_tree, hf_fw1_chain, tvb, 1, 1, ENC_ASCII|ENC_NA); proto_tree_add_item(fh_tree, hf_fw1_interface, tvb, 2, iface_len, ENC_ASCII|ENC_NA); if (fw1_with_uuid) proto_tree_add_item(fh_tree, hf_fw1_uuid, tvb, 8, 4, ENC_BIG_ENDIAN); } ethertype_data.etype = tvb_get_ntohs(tvb, 12); ethertype_data.offset_after_ethertype = ETH_HEADER_SIZE; ethertype_data.fh_tree = fh_tree; ethertype_data.etype_id = hf_fw1_type; ethertype_data.trailer_id = hf_fw1_trailer; ethertype_data.fcs_len = 0; call_dissector_with_data(ethertype_handle, tvb, pinfo, tree, ðertype_data); }
/* Code to actually dissect the packets */ static void dissect_wtp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { char *szInfo; int offCur = 0; /* current offset from start of WTP data */ gint returned_length, str_index = 0; unsigned char b0; /* continuation flag */ unsigned char fCon; /* Continue flag */ unsigned char fRID; /* Re-transmission indicator*/ unsigned char fTTR = '\0'; /* Transmission trailer */ guint cbHeader = 0; /* Fixed header length */ guint vHeader = 0; /* Variable header length*/ int abortType = 0; /* Set up structures we'll need to add the protocol subtree and manage it */ proto_item *ti = NULL; proto_tree *wtp_tree = NULL; char pdut; char clsTransaction = 3; int numMissing = 0; /* Number of missing packets in a negative ack */ int i; tvbuff_t *wsp_tvb = NULL; guint8 psn = 0; /* Packet sequence number*/ guint16 TID = 0; /* Transaction-Id */ int dataOffset; gint dataLen; #define SZINFO_SIZE 256 szInfo=(char *)wmem_alloc(wmem_packet_scope(), SZINFO_SIZE); b0 = tvb_get_guint8 (tvb, offCur + 0); /* Discover Concatenated PDUs */ if (b0 == 0) { guint c_fieldlen = 0; /* Length of length-field */ guint c_pdulen = 0; /* Length of conc. PDU */ if (tree) { ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 1, ENC_NA); wtp_tree = proto_item_add_subtree(ti, ett_wtp_sub_pdu_tree); proto_item_append_text(ti, ", PDU concatenation"); } offCur = 1; i = 1; while (offCur < (int) tvb_reported_length(tvb)) { tvbuff_t *wtp_tvb; /* The length of an embedded WTP PDU is coded as either: * - a 7-bit value contained in one octet with highest bit == 0. * - a 15-bit value contained in two octets (little endian) * if the 1st octet has its highest bit == 1. * This means that this is NOT encoded as an uintvar-integer!!! */ b0 = tvb_get_guint8(tvb, offCur + 0); if (b0 & 0x80) { c_fieldlen = 2; c_pdulen = ((b0 & 0x7f) << 8) | tvb_get_guint8(tvb, offCur + 1); } else { c_fieldlen = 1; c_pdulen = b0; } if (tree) { proto_tree_add_uint(wtp_tree, hf_wtp_header_sub_pdu_size, tvb, offCur, c_fieldlen, c_pdulen); } if (i > 1) { col_append_str(pinfo->cinfo, COL_INFO, ", "); } /* Skip the length field for the WTP sub-tvb */ wtp_tvb = tvb_new_subset_length(tvb, offCur + c_fieldlen, c_pdulen); dissect_wtp_common(wtp_tvb, pinfo, wtp_tree); offCur += c_fieldlen + c_pdulen; i++; } if (tree) { proto_item_append_text(ti, ", PDU count: %u", i); } return; } /* No concatenation */ fCon = b0 & 0x80; fRID = retransmission_indicator(b0); pdut = pdu_type(b0); #ifdef DEBUG printf("WTP packet %u: tree = %p, pdu = %s (%u) length: %u\n", pinfo->fd->num, tree, val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x"), pdut, tvb_captured_length(tvb)); #endif /* Develop the string to put in the Info column */ returned_length = g_snprintf(szInfo, SZINFO_SIZE, "WTP %s", val_to_str(pdut, vals_wtp_pdu_type, "Unknown PDU type 0x%x")); str_index += MIN(returned_length, SZINFO_SIZE-str_index); switch (pdut) { case INVOKE: fTTR = transmission_trailer(b0); TID = tvb_get_ntohs(tvb, offCur + 1); psn = 0; clsTransaction = transaction_class(tvb_get_guint8(tvb, offCur + 3)); returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " Class %d", clsTransaction); str_index += MIN(returned_length, SZINFO_SIZE-str_index); cbHeader = 4; break; case SEGMENTED_INVOKE: case SEGMENTED_RESULT: fTTR = transmission_trailer(b0); TID = tvb_get_ntohs(tvb, offCur + 1); psn = tvb_get_guint8(tvb, offCur + 3); if (psn != 0) { returned_length = g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " (%u)", psn); str_index += MIN(returned_length, SZINFO_SIZE-str_index); } cbHeader = 4; break; case ABORT: cbHeader = 4; break; case RESULT: fTTR = transmission_trailer(b0); TID = tvb_get_ntohs(tvb, offCur + 1); psn = 0; cbHeader = 3; break; case ACK: cbHeader = 3; break; case NEGATIVE_ACK: /* Variable number of missing packets */ numMissing = tvb_get_guint8(tvb, offCur + 3); cbHeader = numMissing + 4; break; default: break; }; if (fRID) { /*returned_length =*/ g_snprintf(&szInfo[str_index], SZINFO_SIZE-str_index, " R" ); /*str_index += MIN(returned_length, SZINFO_SIZE-str_index);*/ }; /* In the interest of speed, if "tree" is NULL, don't do any work not necessary to generate protocol tree items. */ if (tree) { #ifdef DEBUG fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader); #endif /* NOTE - Length will be set when we process the TPI */ ti = proto_tree_add_item(tree, proto_wtp, tvb, offCur, 0, ENC_NA); #ifdef DEBUG fprintf(stderr, "dissect_wtp: (7) Returned from proto_tree_add_item\n"); #endif wtp_tree = proto_item_add_subtree(ti, ett_wtp); /* Code to process the packet goes here */ #ifdef DEBUG fprintf(stderr, "dissect_wtp: cbHeader = %d\n", cbHeader); fprintf(stderr, "dissect_wtp: offCur = %d\n", offCur); #endif /* Add common items: only CON and PDU Type */ proto_tree_add_item( wtp_tree, /* tree */ hf_wtp_header_flag_continue, /* id */ tvb, offCur, /* start of highlight */ 1, /* length of highlight*/ b0 /* value */ ); proto_tree_add_item(wtp_tree, hf_wtp_header_pdu_type, tvb, offCur, 1, ENC_LITTLE_ENDIAN); switch(pdut) { case INVOKE: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_version , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_TIDNew, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_flag_UP, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_Reserved, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_Inv_TransactionClass, tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Invoke (%u)" ", Transaction Class: %s (%u)", INVOKE, val_to_str_const(clsTransaction, vals_transaction_classes, "Undefined"), clsTransaction); break; case RESULT: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", PDU: Result (%u)", RESULT); break; case ACK: proto_tree_add_item(wtp_tree, hf_wtp_header_Ack_flag_TVETOK, tvb, offCur, 1, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_item_append_text(ti, ", PDU: ACK (%u)", ACK); break; case ABORT: abortType = tvb_get_guint8 (tvb, offCur) & 0x07; proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_type , tvb, offCur , 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); if (abortType == PROVIDER) { guint8 reason = tvb_get_guint8(tvb, offCur + 3); proto_tree_add_item( wtp_tree, hf_wtp_header_Abort_reason_provider , tvb, offCur + 3 , 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Abort (%u)" ", Type: Provider (%u)" ", Reason: %s (%u)", ABORT, PROVIDER, val_to_str_const(reason, vals_abort_reason_provider, "Undefined"), reason); } else if (abortType == USER) { guint8 reason = tvb_get_guint8(tvb, offCur + 3); proto_tree_add_item(wtp_tree, hf_wtp_header_Abort_reason_user , tvb, offCur + 3 , 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Abort (%u)" ", Type: User (%u)" ", Reason: %s (%u)", ABORT, PROVIDER, val_to_str_ext_const(reason, &vals_wsp_reason_codes_ext, "Undefined"), reason); } break; case SEGMENTED_INVOKE: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Segmented Invoke (%u)" ", Packet Sequence Number: %u", SEGMENTED_INVOKE, psn); break; case SEGMENTED_RESULT: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_Trailer, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); proto_item_append_text(ti, ", PDU: Segmented Result (%u)" ", Packet Sequence Number: %u", SEGMENTED_RESULT, psn); break; case NEGATIVE_ACK: proto_tree_add_item(wtp_tree, hf_wtp_header_flag_RID, tvb, offCur, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID_response, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_flag_TID, tvb, offCur + 1, 2, ENC_BIG_ENDIAN); proto_tree_add_item(wtp_tree, hf_wtp_header_missing_packets , tvb, offCur + 3, 1, ENC_LITTLE_ENDIAN); /* Iterate through missing packets */ for (i = 0; i < numMissing; i++) { proto_tree_add_item(wtp_tree, hf_wtp_header_sequence_number, tvb, offCur + 4 + i, 1, ENC_LITTLE_ENDIAN); } proto_item_append_text(ti, ", PDU: Negative Ack (%u)" ", Missing Packets: %u", NEGATIVE_ACK, numMissing); break; default: break; }; if (fRID) { proto_item_append_text(ti, ", Retransmission"); } } else { /* tree is NULL */ #ifdef DEBUG fprintf(stderr, "dissect_wtp: (4) tree was %p\n", tree); #endif } /* Process the variable part */ if (fCon) { /* Now, analyze variable part */ guint8 tCon; guint8 tByte; guint tpiLen; tvbuff_t *tmp_tvb; vHeader = 0; /* Start scan all over */ do { tByte = tvb_get_guint8(tvb, offCur + cbHeader + vHeader); tCon = tByte & 0x80; if (tByte & 0x04) /* Long TPI */ tpiLen = 2 + tvb_get_guint8(tvb, offCur + cbHeader + vHeader + 1); else tpiLen = 1 + (tByte & 0x03); if (tree) { tmp_tvb = tvb_new_subset_length(tvb, offCur + cbHeader + vHeader, tpiLen); wtp_handle_tpi(wtp_tree, tmp_tvb); } vHeader += tpiLen; } while (tCon); } else { /* There is no variable part */ } /* End of variable part of header */ /* Set the length of the WTP protocol part now we know the length of the * fixed and variable WTP headers */ if (tree) proto_item_set_len(ti, cbHeader + vHeader); #ifdef DEBUG fprintf( stderr, "dissect_wtp: cbHeader = %d\n", cbHeader ); #endif /* * Any remaining data ought to be WSP data (if not WTP ACK, NACK * or ABORT pdu), so, if we have any remaining data, and it's * not an ACK, NACK, or ABORT PDU, hand it off (defragmented) to the * WSP dissector. * Note that the last packet of a fragmented WTP message needn't * contain any data, so we allow payloadless packets to be * reassembled. (XXX - does the reassembly code handle this * for packets other than the last packet?) * * Try calling a subdissector only if: * - The WTP payload is ressembled in this very packet, * - The WTP payload is not fragmented across packets. */ dataOffset = offCur + cbHeader + vHeader; dataLen = tvb_reported_length_remaining(tvb, dataOffset); if ((dataLen >= 0) && ! ((pdut==ACK) || (pdut==NEGATIVE_ACK) || (pdut==ABORT))) { /* Try to reassemble if needed, and hand over to WSP * A fragmented WTP packet is either: * - An INVOKE with fTTR (transmission trailer) not set, * - a SEGMENTED_INVOKE, * - A RESULT with fTTR (transmission trailer) not set, * - a SEGMENTED_RESULT. */ if ( ( (pdut == SEGMENTED_INVOKE) || (pdut == SEGMENTED_RESULT) || ( ((pdut == INVOKE) || (pdut == RESULT)) && (!fTTR) ) ) && tvb_bytes_exist(tvb, dataOffset, dataLen) ) { /* Try reassembling fragments */ fragment_head *fd_wtp = NULL; guint32 reassembled_in = 0; gboolean save_fragmented = pinfo->fragmented; pinfo->fragmented = TRUE; fd_wtp = fragment_add_seq(&wtp_reassembly_table, tvb, dataOffset, pinfo, TID, NULL, psn, dataLen, !fTTR, 0); /* XXX - fragment_add_seq() yields NULL unless Wireshark knows * that the packet is part of a reassembled whole. This means * that fd_wtp will be NULL as long as Wireshark did not encounter * (and process) the packet containing the last fragment. * This implies that Wireshark needs two passes over the data for * correct reassembly. At the first pass, a capture containing * three fragments plus a retransmssion of the last fragment * will progressively show: * * Packet 1: (Unreassembled fragment 1) * Packet 2: (Unreassembled fragment 2) * Packet 3: (Reassembled WTP) * Packet 4: (WTP payload reassembled in packet 3) * * However at subsequent evaluation (e.g., by applying a display * filter) the packet summary will show: * * Packet 1: (WTP payload reassembled in packet 3) * Packet 2: (WTP payload reassembled in packet 3) * Packet 3: (Reassembled WTP) * Packet 4: (WTP payload reassembled in packet 3) * * This is important to know, and also affects read filters! */ wsp_tvb = process_reassembled_data(tvb, dataOffset, pinfo, "Reassembled WTP", fd_wtp, &wtp_frag_items, NULL, wtp_tree); #ifdef DEBUG printf("WTP: Packet %u %s -> %d: wsp_tvb = %p, fd_wtp = %p, frame = %u\n", pinfo->fd->num, fd_wtp ? "Reassembled" : "Not reassembled", fd_wtp ? fd_wtp->reassembled_in : -1, wsp_tvb, fd_wtp ); #endif if (fd_wtp) { /* Reassembled */ reassembled_in = fd_wtp->reassembled_in; if (pinfo->fd->num == reassembled_in) { /* Reassembled in this very packet: * We can safely hand the tvb to the WSP dissector */ call_dissector(wsp_handle, wsp_tvb, pinfo, tree); } else { /* Not reassembled in this packet */ col_append_fstr(pinfo->cinfo, COL_INFO, "%s (WTP payload reassembled in packet %u)", szInfo, fd_wtp->reassembled_in); proto_tree_add_item(wtp_tree, hf_wtp_payload, tvb, dataOffset, -1, ENC_NA); } } else { /* Not reassembled yet, or not reassembled at all */ col_append_fstr(pinfo->cinfo, COL_INFO, "%s (Unreassembled fragment %u)", szInfo, psn); proto_tree_add_item(wtp_tree, hf_wtp_payload, tvb, dataOffset, -1, ENC_NA); } /* Now reset fragmentation information in pinfo */ pinfo->fragmented = save_fragmented; } else if ( ((pdut == INVOKE) || (pdut == RESULT)) && (fTTR) ) { /* Non-fragmented payload */ wsp_tvb = tvb_new_subset_remaining(tvb, dataOffset); /* We can safely hand the tvb to the WSP dissector */ call_dissector(wsp_handle, wsp_tvb, pinfo, tree); } else { /* Nothing to hand to subdissector */ col_append_str(pinfo->cinfo, COL_INFO, szInfo); } } else { /* Nothing to hand to subdissector */ col_append_str(pinfo->cinfo, COL_INFO, szInfo); } }
static void dissect_cimd_dcs(tvbuff_t *tvb, proto_tree *tree, gint pindex, gint startOffset, gint endOffset) { /* Set up structures needed to add the param subtree and manage it */ proto_item *param_item; proto_tree *param_tree; gint offset; guint dcs; guint dcs_cg; /* coding group */ guint dcs_cf; /* compressed flag */ guint dcs_mcm; /* message class meaning flag */ guint dcs_chs; /* character set */ guint dcs_mc; /* message class */ guint dcs_is; /* indication sense */ guint dcs_it; /* indication type */ gchar* bigbuf = (gchar*)wmem_alloc(wmem_packet_scope(), 1024); param_item = proto_tree_add_text(tree, tvb, startOffset + 1, endOffset - (startOffset + 1), "%s", cimd_vals_PC[pindex].strptr ); param_tree = proto_item_add_subtree(param_item, (*vals_hdr_PC[pindex].ett_p)); proto_tree_add_string(param_tree, hf_cimd_pcode_indicator, tvb, startOffset + 1, CIMD_PC_LENGTH, tvb_format_text(tvb, startOffset + 1, CIMD_PC_LENGTH) ); offset = startOffset + 1 + CIMD_PC_LENGTH + 1; dcs = decimal_int_value(tvb, offset, endOffset - offset); proto_tree_add_uint(param_tree, (*vals_hdr_PC[pindex].hf_p), tvb, offset, endOffset - offset, dcs); dcs_cg = (dcs & 0xF0) >> 4; other_decode_bitfield_value(bigbuf, dcs, (dcs_cg <= 0x07 ? 0xC0 : 0xF0), 8); proto_tree_add_uint_format(param_tree, hf_cimd_dcs_coding_group_indicator, tvb, offset, 1, dcs_cg, "%s = %s: %s (%d)", bigbuf, proto_registrar_get_nth(hf_cimd_dcs_coding_group_indicator)->name, val_to_str(dcs_cg, cimd_dcs_coding_groups, "Unknown (%d)"), dcs_cg ); if (dcs_cg <= 0x07) { dcs_cf = (dcs & 0x20) >> 5; other_decode_bitfield_value(bigbuf, dcs, 0x20, 8); proto_tree_add_uint_format(param_tree, hf_cimd_dcs_compressed_indicator, tvb, offset, 1, dcs_cf, "%s = %s: %s (%d)", bigbuf, proto_registrar_get_nth(hf_cimd_dcs_compressed_indicator)->name, val_to_str(dcs_cf, cimd_dcs_compressed, "Unknown (%d)"), dcs_cf ); dcs_mcm = (dcs & 0x10) >> 4; other_decode_bitfield_value(bigbuf, dcs, 0x10, 8); proto_tree_add_uint_format(param_tree, hf_cimd_dcs_message_class_meaning_indicator, tvb, offset, 1, dcs_mcm, "%s = %s: %s (%d)", bigbuf, proto_registrar_get_nth(hf_cimd_dcs_message_class_meaning_indicator)->name, val_to_str(dcs_mcm, cimd_dcs_message_class_meaning, "Unknown (%d)"), dcs_mcm ); dcs_chs = (dcs & 0x0C) >> 2; other_decode_bitfield_value(bigbuf, dcs, 0x0C, 8); proto_tree_add_uint_format(param_tree, hf_cimd_dcs_character_set_indicator, tvb, offset, 1, dcs_chs, "%s = %s: %s (%d)", bigbuf, proto_registrar_get_nth(hf_cimd_dcs_character_set_indicator)->name, val_to_str(dcs_chs, cimd_dcs_character_set, "Unknown (%d)"), dcs_chs ); if (dcs_mcm) { dcs_mc = (dcs & 0x03); other_decode_bitfield_value(bigbuf, dcs, 0x03, 8); proto_tree_add_uint_format(param_tree, hf_cimd_dcs_message_class_indicator, tvb, offset, 1, dcs_mc, "%s = %s: %s (%d)", bigbuf, proto_registrar_get_nth(hf_cimd_dcs_message_class_indicator)->name, val_to_str(dcs_mc, cimd_dcs_message_class, "Unknown (%d)"), dcs_mc ); } }
/** Dissector for SoupBinTCP messages */ static void dissect_soupbintcp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { struct conv_data *conv_data; struct pdu_data *pdu_data; const char *pkt_name; const char *tmp_buf; proto_item *ti; proto_tree *soupbintcp_tree = NULL; conversation_t *conv = NULL; guint16 expected_len; guint8 pkt_type; gint offset = 0; guint this_seq = 0, next_seq; heur_dtbl_entry_t *hdtbl_entry; /* Get the 16-bit big-endian SOUP packet length */ expected_len = tvb_get_ntohs(tvb, 0); /* Get the 1-byte SOUP message type */ pkt_type = tvb_get_guint8(tvb, 2); /* Since we use the packet name a few times, get and save that value */ pkt_name = val_to_str(pkt_type, pkt_type_val, "Unknown (%u)"); /* Set the protocol name in the summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SoupBinTCP"); /* Set the packet name in the info column */ col_add_str(pinfo->cinfo, COL_INFO, pkt_name); /* Sequence number tracking * * SOUP does not number packets from client to server (the server * acknowledges all important messages, so the client should use * the acks to figure out if the server received the message, and * otherwise resend it). * * Packets from server to client are numbered, but it's implicit. * The Login Accept packet contains the next sequence number that * the server will send, and the client needs to count the * Sequenced Data packets that it receives to know what their * sequence numbers are. * * So, we grab the next sequence number from the Login Acceptance * packet, and save it in a conversation_t we associate with the * TCP session. Then, for each Sequenced Data packet we receive, * the first time it's processed (when PINFO_FD_VISITED() is * false), we write it into the PDU's frame's private data pointer * and increment the saved sequence number (in the conversation_t). * * If the visited flag is true, then we've dissected this packet * already, and so we can fetch the sequence number from the * frame's private data area. * * In either case, if there's any problem, we report zero as the * sequence number, and try to continue dissecting. */ /* If first dissection of Login Accept, save sequence number */ if (pkt_type == 'A' && !PINFO_FD_VISITED(pinfo)) { tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, 13, 20, ENC_ASCII); next_seq = atoi(tmp_buf); /* Create new conversation for this session */ conv = conversation_new(PINFO_FD_NUM(pinfo), &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); /* Store starting sequence number for session's packets */ conv_data = (struct conv_data *)wmem_alloc(wmem_file_scope(), sizeof(struct conv_data)); conv_data->next_seq = next_seq; conversation_add_proto_data(conv, proto_soupbintcp, conv_data); } /* Handle sequence numbering for a Sequenced Data packet */ if (pkt_type == 'S') { if (!PINFO_FD_VISITED(pinfo)) { /* Get next expected sequence number from conversation */ conv = find_conversation(PINFO_FD_NUM(pinfo), &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conv) { this_seq = 0; } else { conv_data = (struct conv_data *)conversation_get_proto_data(conv, proto_soupbintcp); if (conv_data) { this_seq = conv_data->next_seq++; } else { this_seq = 0; } pdu_data = (struct pdu_data *)wmem_alloc( wmem_file_scope(), sizeof(struct pdu_data)); pdu_data->seq_num = this_seq; p_add_proto_data(wmem_file_scope(), pinfo, proto_soupbintcp, 0, pdu_data); } } else { pdu_data = (struct pdu_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_soupbintcp, 0); if (pdu_data) { this_seq = pdu_data->seq_num; } else { this_seq = 0; } } col_append_fstr(pinfo->cinfo, COL_INFO, ", SeqNum = %u", this_seq); } if (tree) { /* Create sub-tree for SoupBinTCP details */ ti = proto_tree_add_item(tree, proto_soupbintcp, tvb, 0, -1, ENC_NA); soupbintcp_tree = proto_item_add_subtree(ti, ett_soupbintcp); /* Append the packet name to the sub-tree item */ proto_item_append_text(ti, ", %s", pkt_name); /* Length */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_packet_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Type */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; switch (pkt_type) { case '+': /* Debug Message */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_text, tvb, offset, expected_len - 1, ENC_ASCII|ENC_NA); break; case 'A': /* Login Accept */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_session, tvb, offset, 10, ENC_ASCII|ENC_NA); offset += 10; tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 20, ENC_ASCII); proto_tree_add_string_format_value(soupbintcp_tree, hf_soupbintcp_next_seq_num, tvb, offset, 20, "X", "%d", atoi(tmp_buf)); break; case 'J': /* Login Reject */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_reject_code, tvb, offset, 1, ENC_BIG_ENDIAN); break; case 'U': /* Unsequenced Data */ /* Display handled by sub-dissector */ break; case 'S': /* Sequenced Data */ proto_item_append_text(ti, ", SeqNum=%u", this_seq); proto_tree_add_string_format_value(soupbintcp_tree, hf_soupbintcp_seq_num, tvb, offset, 0, "X", "%u (Calculated)", this_seq); /* Display handled by sub-dissector */ break; case 'L': /* Login Request */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_username, tvb, offset, 6, ENC_ASCII|ENC_NA); offset += 6; proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_password, tvb, offset, 10, ENC_ASCII|ENC_NA); offset += 10; proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_session, tvb, offset, 10, ENC_ASCII|ENC_NA); offset += 10; tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 20, ENC_ASCII); proto_tree_add_string_format_value(soupbintcp_tree, hf_soupbintcp_req_seq_num, tvb, offset, 20, "X", "%d", atoi(tmp_buf)); break; case 'H': /* Server Heartbeat */ break; case 'O': /* Logout Request */ break; case 'R': /* Client Heartbeat */ break; case 'Z': /* End of Session */ break; default: /* Unknown */ proto_tree_add_item(tree, hf_soupbintcp_message, tvb, offset, -1, ENC_NA); break; } } /* Call sub-dissector for encapsulated data */ if (pkt_type == 'S' || pkt_type == 'U') { tvbuff_t *sub_tvb; /* Sub-dissector tvb starts at 3 (length (2) + pkt_type (1)) */ sub_tvb = tvb_new_subset_remaining(tvb, 3); #if 0 /* XXX: It's not valid for a soupbintcp subdissector to call */ /* conversation_set_dissector() since the conversation is really */ /* a TCP conversation. (A 'soupbintcp' port type would need to */ /* be defined to be able to use conversation_set_dissector()). */ /* In addition, no current soupbintcp subdissector calls */ /* conversation_set_dissector(). */ /* If this packet is part of a conversation, call dissector * for the conversation if available */ if (try_conversation_dissector(&pinfo->dst, &pinfo->src, pinfo->ptype, pinfo->srcport, pinfo->destport, sub_tvb, pinfo, tree, NULL)) { return; } #endif /* Otherwise, try heuristic dissectors */ if (dissector_try_heuristic(heur_subdissector_list, sub_tvb, pinfo, tree, &hdtbl_entry, NULL)) { return; } /* Otherwise, give up, and just print the bytes in hex */ if (tree) { proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_message, sub_tvb, 0, -1, ENC_NA); } } }
int PBE_decrypt_data(const char *object_identifier_id_param, tvbuff_t *encrypted_tvb, asn1_ctx_t *actx, proto_item *item) { #ifdef HAVE_LIBGCRYPT const char *encryption_algorithm; gcry_cipher_hd_t cipher; gcry_error_t err; int algo; int mode; int ivlen = 0; int keylen = 0; int datalen = 0; char *key = NULL; char *iv = NULL; char *clear_data = NULL; tvbuff_t *clear_tvb = NULL; const gchar *oidname; GString *name; proto_tree *tree; char byte; gboolean decrypt_ok = TRUE; if(((password == NULL) || (*password == '\0')) && (try_null_password == FALSE)) { /* we are not configured to decrypt */ return FALSE; } encryption_algorithm = x509af_get_last_algorithm_id(); /* these are the only encryption schemes we understand for now */ if(!strcmp(encryption_algorithm, PKCS12_PBE_3DES_SHA1_OID)) { ivlen = 8; keylen = 24; algo = GCRY_CIPHER_3DES; mode = GCRY_CIPHER_MODE_CBC; } else if(!strcmp(encryption_algorithm, PKCS12_PBE_ARCFOUR_SHA1_OID)) { ivlen = 0; keylen = 16; algo = GCRY_CIPHER_ARCFOUR; mode = GCRY_CIPHER_MODE_NONE; } else if(!strcmp(encryption_algorithm, PKCS12_PBE_RC2_40_SHA1_OID)) { ivlen = 8; keylen = 5; algo = GCRY_CIPHER_RFC2268_40; mode = GCRY_CIPHER_MODE_CBC; } else { /* we don't know how to decrypt this */ proto_item_append_text(item, " [Unsupported encryption algorithm]"); return FALSE; } if((iteration_count == 0) || (salt == NULL)) { proto_item_append_text(item, " [Insufficient parameters]"); return FALSE; } /* allocate buffers */ key = (char *)wmem_alloc(wmem_packet_scope(), keylen); if(!generate_key_or_iv(1 /*LEY */, salt, iteration_count, password, keylen, key)) return FALSE; if(ivlen) { iv = (char *)wmem_alloc(wmem_packet_scope(), ivlen); if(!generate_key_or_iv(2 /* IV */, salt, iteration_count, password, ivlen, iv)) return FALSE; } /* now try an internal function */ err = gcry_cipher_open(&cipher, algo, mode, 0); if (gcry_err_code (err)) return FALSE; err = gcry_cipher_setkey (cipher, key, keylen); if (gcry_err_code (err)) { gcry_cipher_close (cipher); return FALSE; } if(ivlen) { err = gcry_cipher_setiv (cipher, iv, ivlen); if (gcry_err_code (err)) { gcry_cipher_close (cipher); return FALSE; } } datalen = tvb_captured_length(encrypted_tvb); clear_data = (char *)g_malloc(datalen); err = gcry_cipher_decrypt (cipher, clear_data, datalen, (char *)tvb_memdup(wmem_packet_scope(), encrypted_tvb, 0, datalen), datalen); if (gcry_err_code (err)) { proto_item_append_text(item, " [Failed to decrypt with password preference]"); gcry_cipher_close (cipher); g_free(clear_data); return FALSE; } gcry_cipher_close (cipher); /* We don't know if we have successfully decrypted the data or not so we: a) check the trailing bytes b) see if we start with a sequence or a set (is this too constraining? */ /* first the trailing bytes */ byte = clear_data[datalen-1]; if(byte <= 0x08) { int i; for(i = (int)byte; i > 0 ; i--) { if(clear_data[datalen - i] != byte) { decrypt_ok = FALSE; break; } } } else { /* XXX: is this a failure? */ } /* we assume the result is ASN.1 - check it is a SET or SEQUENCE */ byte = clear_data[0]; if((byte != 0x30) && (byte != 0x31)) { /* do we need more here? OCTET STRING? */ decrypt_ok = FALSE; } if(!decrypt_ok) { g_free(clear_data); proto_item_append_text(item, " [Failed to decrypt with supplied password]"); return FALSE; } proto_item_append_text(item, " [Decrypted successfully]"); tree = proto_item_add_subtree(item, ett_decrypted_pbe); /* OK - so now clear_data contains the decrypted data */ clear_tvb = tvb_new_child_real_data(encrypted_tvb,(const guint8 *)clear_data, datalen, datalen); tvb_set_free_cb(clear_tvb, g_free); name = g_string_new(""); oidname = oid_resolved_from_string(object_identifier_id_param); g_string_printf(name, "Decrypted %s", oidname ? oidname : object_identifier_id_param); /* add it as a new source */ add_new_data_source(actx->pinfo, clear_tvb, name->str); g_string_free(name, TRUE); /* now try and decode it */ call_ber_oid_callback(object_identifier_id_param, clear_tvb, 0, actx->pinfo, tree, NULL); return TRUE; #else /* we cannot decrypt */ return FALSE; #endif }
static void dissect_ax25_nol3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree ) { proto_item *ti; proto_tree *ax25_nol3_tree; char *info_buffer; int offset; tvbuff_t *next_tvb = NULL; guint8 dti = 0; gboolean dissected; info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN ); info_buffer[0] = '\0'; col_set_str( pinfo->cinfo, COL_PROTOCOL, "AX.25-NoL3"); col_clear( pinfo->cinfo, COL_INFO); offset = 0; g_snprintf( info_buffer, STRLEN, "Text" ); if ( gPREF_APRS ) { dti = tvb_get_guint8( tvb, offset ); if ( isaprs( dti ) ) g_snprintf( info_buffer, STRLEN, "APRS" ); } if ( gPREF_DX ) { if ( tvb_get_guint8( tvb, offset ) == 'D' && tvb_get_guint8( tvb, offset + 1 ) == 'X' ) g_snprintf( info_buffer, STRLEN, "DX cluster" ); } col_add_str( pinfo->cinfo, COL_INFO, info_buffer ); /* Call sub-dissectors here */ if ( parent_tree ) { /* create display subtree for the protocol */ ti = proto_tree_add_protocol_format( parent_tree, proto_ax25_nol3, tvb, 0, -1, "AX.25 No Layer 3 - (%s)", info_buffer ); ax25_nol3_tree = proto_item_add_subtree( ti, ett_ax25_nol3 ); next_tvb = tvb_new_subset_remaining(tvb, offset); dissected = FALSE; if ( gPREF_APRS ) { if ( isaprs( dti ) ) { dissected = TRUE; call_dissector( aprs_handle , next_tvb, pinfo, ax25_nol3_tree ); } } if ( gPREF_DX ) { if ( tvb_get_guint8( tvb, offset ) == 'D' && tvb_get_guint8( tvb, offset + 1 ) == 'X' ) { dissected = TRUE; dissect_dx( next_tvb, pinfo, ax25_nol3_tree ); } } if ( ! dissected ) call_dissector( default_handle , next_tvb, pinfo, ax25_nol3_tree ); } }
static const char * COM_Parse (const char *data, int data_len, int* token_start, int* token_len) { int c; char* com_token = (char*)wmem_alloc(wmem_packet_scope(), data_len+1); com_token[0] = '\0'; *token_start = 0; *token_len = 0; if (data == NULL) return NULL; /* skip whitespace */ skipwhite: while (TRUE) { c = *data; if (c == '\0') return NULL; /* end of file; */ if ((c != ' ') && (!g_ascii_iscntrl(c))) break; data++; (*token_start)++; } /* skip // comments */ if ((c=='/') && (data[1]=='/')) { while (*data && *data != '\n'){ data++; (*token_start)++; } goto skipwhite; } /* handle quoted strings specially */ if (c == '\"') { data++; (*token_start)++; while (*token_len < data_len) { c = *data++; if ((c=='\"') || (c=='\0')) { com_token[*token_len] = '\0'; return data; } com_token[*token_len] = c; (*token_len)++; } } if (*token_len == data_len) { com_token[*token_len] = '\0'; return data; } /* parse a regular word */ do { com_token[*token_len] = c; data++; (*token_len)++; c = *data; } while (( c != ' ') && (!g_ascii_iscntrl(c)) && (*token_len < data_len)); com_token[*token_len] = '\0'; return data; }
static int dissect_aim_chat_userinfo_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *chat_tree) { int offset = 0; while(tvb_length_remaining(tvb, offset) > 0) { offset = dissect_aim_userinfo(tvb, pinfo, offset, chat_tree); } return offset; } static int dissect_aim_chat_outgoing_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *chat_tree _U_) { guchar *buddyname; guchar *msg; int buddyname_length; buddyname=(guchar *)wmem_alloc(wmem_packet_scope(), MAX_BUDDYNAME_LENGTH+1); msg=(guchar *)wmem_alloc(wmem_packet_scope(), 1000); buddyname_length = aim_get_buddyname( buddyname, tvb, 30, 31 ); /* channel message from client */ aim_get_message( msg, tvb, 40 + buddyname_length, tvb_length(tvb) - 40 - buddyname_length ); col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s", msg); return tvb_length(tvb); } static int dissect_aim_chat_incoming_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *chat_tree) {
static gint dissect_adb_service(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *sub_item; proto_tree *sub_tree; gint offset = 0; adb_service_data_t *adb_service_data = (adb_service_data_t *) data; const guint8 *service; wmem_tree_key_t key[5]; wmem_tree_t *subtree; guint32 i_key; main_item = proto_tree_add_item(tree, proto_adb_service, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_adb_service); DISSECTOR_ASSERT(adb_service_data); service = adb_service_data->service; sub_item = proto_tree_add_string(main_tree, hf_service, tvb, offset, 0, service); PROTO_ITEM_SET_GENERATED(sub_item); if (g_strcmp0(service, "host:version") == 0) { guint32 version; guint32 data_length; continuation_data_t *continuation_data; DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 0; key[i_key].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(continuation_infos, key); continuation_data = (subtree) ? (continuation_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL; if (continuation_data && continuation_data->completed_in_frame < pinfo->num) continuation_data = NULL; if (!continuation_data || (continuation_data && continuation_data->length_in_frame == pinfo->num)) offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); if (!pinfo->fd->flags.visited && !continuation_data && tvb_reported_length_remaining(tvb, offset) < 4) { key[i_key].length = 1; key[i_key++].key = &pinfo->num; key[i_key].length = 0; key[i_key].key = NULL; continuation_data = wmem_new(wmem_file_scope(), continuation_data_t); continuation_data->length_in_frame = pinfo->num; continuation_data->completed_in_frame = G_MAXUINT32; continuation_data->length = data_length; wmem_tree_insert32_array(continuation_infos, key, continuation_data); continuation_data = NULL; } if (tvb_reported_length_remaining(tvb, offset) >= 4 || (continuation_data && continuation_data->completed_in_frame == pinfo->num)) { if (!pinfo->fd->flags.visited && continuation_data) { continuation_data->completed_in_frame = pinfo->num; } offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_version, ett_version, hf_version, tvb, offset, &version); col_append_fstr(pinfo->cinfo, COL_INFO, " Version=%u", version); } } else if (g_strcmp0(service, "host:devices") == 0 || g_strcmp0(service, "host:devices-l") == 0 || g_strcmp0(service, "host:track-devices") == 0) { guint32 data_length; offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); sub_item = proto_tree_add_item(main_tree, hf_devices, tvb, offset, -1, ENC_NA | ENC_ASCII); if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) { expert_add_info(pinfo, sub_item, &ei_incomplete_message); } } else if (g_strcmp0(service, "host:get-state") == 0 || g_strcmp0(service, "host:get-serialno") == 0 || g_strcmp0(service, "host:get-devpath") == 0 || g_str_has_prefix(service, "connect:") || g_str_has_prefix(service, "disconnect:")) { guint32 data_length; offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); sub_item = proto_tree_add_item(main_tree, hf_result, tvb, offset, -1, ENC_NA | ENC_ASCII); if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) { expert_add_info(pinfo, sub_item, &ei_incomplete_message); } } else if (g_str_has_prefix(service, "framebuffer:")) { framebuffer_data_t *framebuffer_data = NULL; DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 0; key[i_key].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(framebuffer_infos, key); framebuffer_data = (subtree) ? (framebuffer_data_t *) wmem_tree_lookup32_le(subtree, pinfo->num) : NULL; if (framebuffer_data && framebuffer_data->completed_in_frame < pinfo->num) framebuffer_data = NULL; if (!pinfo->fd->flags.visited && !framebuffer_data) { key[i_key].length = 1; key[i_key++].key = &pinfo->num; key[i_key].length = 0; key[i_key].key = NULL; framebuffer_data = wmem_new(wmem_file_scope(), framebuffer_data_t); framebuffer_data->data_in = pinfo->num; framebuffer_data->current_size = 0; framebuffer_data->completed_in_frame = G_MAXUINT32; framebuffer_data->size = tvb_get_letohl(tvb, offset + 4 * 2); framebuffer_data->red_offset = tvb_get_letohl(tvb, offset + 4 * 5); framebuffer_data->red_length = tvb_get_letohl(tvb, offset + 4 * 6); framebuffer_data->green_offset = tvb_get_letohl(tvb, offset + 4 * 7); framebuffer_data->green_length = tvb_get_letohl(tvb, offset + 4 * 8); framebuffer_data->blue_offset = tvb_get_letohl(tvb, offset + 4 * 9); framebuffer_data->blue_length = tvb_get_letohl(tvb, offset + 4 * 10); framebuffer_data->alpha_offset = tvb_get_letohl(tvb, offset + 4 * 11); framebuffer_data->alpha_length = tvb_get_letohl(tvb, offset + 4 * 12); wmem_tree_insert32_array(framebuffer_infos, key, framebuffer_data); } if (framebuffer_data && framebuffer_data->data_in == pinfo->num) { proto_tree_add_item(main_tree, hf_framebuffer_version, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_depth, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_size, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_width, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_height, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_red_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_red_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_blue_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_blue_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_green_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_green_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_alpha_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; proto_tree_add_item(main_tree, hf_framebuffer_alpha_length, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; } if (tvb_reported_length_remaining(tvb, offset) > 0) { sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); sub_tree = proto_item_add_subtree(sub_item, ett_data); if (!pinfo->fd->flags.visited && framebuffer_data) { framebuffer_data->current_size += tvb_captured_length_remaining(tvb, offset); if (framebuffer_data->current_size >= framebuffer_data->size) framebuffer_data->completed_in_frame = pinfo->num; } if (pref_dissect_more_detail_framebuffer) { proto_item *pixel_item; proto_tree *pixel_tree; if (framebuffer_data && framebuffer_data->red_length == 5 && framebuffer_data->green_length == 6 && framebuffer_data->blue_length == 5 && framebuffer_data->red_offset == 11 && framebuffer_data->green_offset == 5 && framebuffer_data->blue_offset == 0) { while (tvb_reported_length_remaining(tvb, offset) > 0) { if (tvb_reported_length_remaining(tvb, offset) < 2) { proto_tree_add_item(main_tree, hf_fragment, tvb, offset, -1, ENC_NA); offset += 1; } pixel_item = proto_tree_add_item(sub_tree, hf_framebuffer_pixel, tvb, offset, 2, ENC_NA); pixel_tree = proto_item_add_subtree(pixel_item, ett_pixel); proto_tree_add_item(pixel_tree, hf_framebuffer_blue_5, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_green_6, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_red_5, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; } } else if (framebuffer_data && framebuffer_data->red_length == 8 && framebuffer_data->green_length == 8 && framebuffer_data->blue_length == 8 && (framebuffer_data->alpha_length == 0 || framebuffer_data->alpha_length == 8)) { while (tvb_reported_length_remaining(tvb, offset) > 0) { if (tvb_reported_length_remaining(tvb, offset) < 3 || (tvb_reported_length_remaining(tvb, offset) < 4 && framebuffer_data->alpha_offset > 0)) { proto_tree_add_item(main_tree, hf_fragment, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); break; } pixel_item = proto_tree_add_item(sub_tree, hf_framebuffer_pixel, tvb, offset, 3, ENC_NA); pixel_tree = proto_item_add_subtree(pixel_item, ett_pixel); proto_tree_add_item(pixel_tree, hf_framebuffer_red, tvb, offset + framebuffer_data->red_offset / 8, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_green, tvb, offset + framebuffer_data->green_offset / 8, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(pixel_tree, hf_framebuffer_blue, tvb, offset + framebuffer_data->blue_offset / 8, 1, ENC_LITTLE_ENDIAN); if (framebuffer_data->alpha_offset > 0) { if (framebuffer_data->alpha_length == 0) proto_tree_add_item(pixel_tree, hf_framebuffer_unused, tvb, offset + framebuffer_data->alpha_offset / 8, 1, ENC_LITTLE_ENDIAN); else proto_tree_add_item(pixel_tree, hf_framebuffer_alpha, tvb, offset + framebuffer_data->alpha_offset / 8, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_item_set_len(pixel_item, 4); } offset += 3; } } else { offset = tvb_captured_length(tvb); } } else { offset = tvb_captured_length(tvb); } } } else if (g_strcmp0(service, "track-jdwp") == 0) { guint32 data_length; offset = dissect_ascii_uint32(main_tree, hf_hex_ascii_length, ett_length, hf_length, tvb, offset, &data_length); if (tvb_reported_length_remaining(tvb, offset) > 0) { sub_item = proto_tree_add_item(main_tree, hf_pids, tvb, offset, -1, ENC_NA | ENC_ASCII); if ((gint64) data_length < tvb_reported_length_remaining(tvb, offset)) { expert_add_info(pinfo, sub_item, &ei_incomplete_message); } } offset = tvb_captured_length(tvb); } else if ((g_strcmp0(service, "shell:export ANDROID_LOG_TAGS=\"\" ; exec logcat -B") == 0) || (g_strcmp0(service, "shell:logcat -B") == 0)) { tvbuff_t *next_tvb; tvbuff_t *new_tvb; guint8 *buffer = NULL; gint size = 0; gint i_offset = offset; gint old_offset; gint i_char = 0; guint8 c1; guint8 c2 = '\0'; guint16 payload_length; guint16 try_header_size; gint logcat_length = 0; fragment_t *fragment; DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 1 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 0; key[i_key].key = NULL; subtree = (wmem_tree_t *) wmem_tree_lookup32_array(fragments, key); fragment = (subtree) ? (fragment_t *) wmem_tree_lookup32_le(subtree, pinfo->num - 1) : NULL; if (fragment) { if (!pinfo->fd->flags.visited && fragment->reassembled_in_frame == -1) fragment->reassembled_in_frame = pinfo->num; if (fragment->reassembled_in_frame == pinfo->num) { size += fragment->length; i_char += fragment->length; } } size += tvb_reported_length_remaining(tvb, i_offset); if (size > 0) { buffer = (guint8 *) wmem_alloc(pinfo->pool, size); if (fragment && i_char > 0) memcpy(buffer, fragment->data, i_char); if (i_char >= 1 && buffer[i_char - 1] == '\r' && tvb_get_guint8(tvb, i_offset) == '\n') { buffer[i_char - 1] = '\n'; i_offset += 1; } c1 = tvb_get_guint8(tvb, i_offset); i_offset += 1; old_offset = i_offset; while (tvb_reported_length_remaining(tvb, i_offset) > 0) { c2 = tvb_get_guint8(tvb, i_offset); if (c1 == '\r' && c2 == '\n') { buffer[i_char] = c2; if (tvb_reported_length_remaining(tvb, i_offset) > 1) { c1 = tvb_get_guint8(tvb, i_offset + 1); i_offset += 2; i_char += 1; } else { i_offset += 1; } continue; } buffer[i_char] = c1; c1 = c2; i_char += 1; i_offset += 1; } if (tvb_reported_length_remaining(tvb, old_offset) == 0) { buffer[i_char] = c1; i_char += 1; } else if (tvb_reported_length_remaining(tvb, old_offset) > 0) { buffer[i_char] = c2; i_char += 1; } next_tvb = tvb_new_child_real_data(tvb, buffer, i_char, i_char); add_new_data_source(pinfo, next_tvb, "Logcat"); i_offset = 0; while (tvb_reported_length_remaining(next_tvb, i_offset) > 0) { if (tvb_reported_length_remaining(next_tvb, i_offset) >= 4) { payload_length = tvb_get_letohs(next_tvb, i_offset); try_header_size = tvb_get_letohs(next_tvb, i_offset + 2); if (try_header_size != 24) logcat_length = payload_length + 20; else logcat_length = payload_length + 24; } if (tvb_reported_length_remaining(next_tvb, i_offset) >= 4 && tvb_reported_length_remaining(next_tvb, i_offset) >= logcat_length) { new_tvb = tvb_new_subset_length(next_tvb, i_offset, logcat_length); call_dissector(logcat_handle, new_tvb, pinfo, main_tree); i_offset += logcat_length; } else { if (!pinfo->fd->flags.visited) { DISSECTOR_ASSERT_HINT(adb_service_data->session_key_length + 2 <= sizeof(key) / sizeof(key[0]), "Tree session key is too small"); for (i_key = 0; i_key < adb_service_data->session_key_length; i_key += 1) { key[i_key].length = 1; key[i_key].key = &adb_service_data->session_key[i_key]; } key[i_key].length = 1; key[i_key++].key = &pinfo->num; key[i_key].length = 0; key[i_key].key = NULL; fragment = wmem_new(wmem_file_scope(), fragment_t); fragment->length = tvb_captured_length_remaining(next_tvb, i_offset); fragment->data = (guint8 *) wmem_alloc(wmem_file_scope(), fragment->length); tvb_memcpy(next_tvb, fragment->data, i_offset, fragment->length); fragment->reassembled_in_frame = -1; wmem_tree_insert32_array(fragments, key, fragment); } proto_tree_add_item(main_tree, hf_fragment, next_tvb, i_offset, -1, ENC_NA); i_offset = tvb_captured_length(next_tvb); } } } offset = tvb_captured_length(tvb); } else if (g_str_has_prefix(service, "shell:")) { if (adb_service_data->direction == P2P_DIR_SENT) { proto_tree_add_item(main_tree, hf_stdin, tvb, offset, -1, ENC_NA | ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " Stdin=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset))); } else { proto_tree_add_item(main_tree, hf_stdout, tvb, offset, -1, ENC_NA | ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " Stdout=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset))); } offset = tvb_captured_length(tvb); } else if (g_str_has_prefix(service, "jdwp:")) { /* TODO */ proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); } else if (g_str_has_prefix(service, "sync:")) { /* TODO */ proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); } else if (g_strcmp0(service, "host:list-forward") == 0 || g_str_has_prefix(service, "root:") || g_str_has_prefix(service, "remount:") || g_str_has_prefix(service, "tcpip:") || g_str_has_prefix(service, "usb:")) { if (tvb_reported_length_remaining(tvb, offset)) { proto_tree_add_item(main_tree, hf_result, tvb, offset, -1, ENC_NA | ENC_ASCII); col_append_fstr(pinfo->cinfo, COL_INFO, " Result=<%s>", tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset))); offset = tvb_captured_length(tvb); } } else { proto_tree_add_item(main_tree, hf_data, tvb, offset, -1, ENC_NA); offset = tvb_captured_length(tvb); } return offset; }
#define EOMc (0x11) #define EOMu (0x12) #define EOMi (0x13) #define MAX_EOM_MSG_SIZE (16) /* max size of an EOMx indicator string */ static void dissect_ipars(tvbuff_t *tvb, packet_info *pinfo _U_ , proto_tree *tree) { int bytes; guint8 ia = 0, ta = 0, cmd = 0, la = 0; tvbuff_t *next_tvb; int offset = 0; gchar *eom_msg; eom_msg = (gchar *)wmem_alloc(wmem_packet_scope(), MAX_EOM_MSG_SIZE); eom_msg[0] = 0; col_clear(pinfo->cinfo, COL_INFO); col_set_str(pinfo->cinfo, COL_PROTOCOL, "IPARS"); if (tvb_length_remaining(tvb, 0) >= 2 ) { ia = tvb_get_guint8(tvb, 0) & 0x3f; ta = tvb_get_guint8(tvb, 1) & 0x3f; if (ia == S1 && ta == S2) { /* if the first two bytes are S1/S2 skip over them */ offset = 2; } } if (tvb_length_remaining(tvb, offset) >= 1) ia = tvb_get_guint8(tvb, offset + 0); if (tvb_length_remaining(tvb, offset) >= 2) ta = tvb_get_guint8(tvb, offset + 1);
/* Code to actually dissect the packets */ static void dissect_manolito(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { unsigned int offset; /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *manolito_tree; const char* packet_type = 0; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MANOLITO"); ti = proto_tree_add_item(tree, proto_manolito, tvb, 0, -1, ENC_NA); manolito_tree = proto_item_add_subtree(ti, ett_manolito); /* MANOLITO packet header (network byte order) */ proto_tree_add_item(manolito_tree, hf_manolito_checksum, tvb, 0, 4, ENC_BIG_ENDIAN); proto_tree_add_item(manolito_tree, hf_manolito_seqno, tvb, 4, 4, ENC_BIG_ENDIAN); proto_tree_add_item(manolito_tree, hf_manolito_src, tvb, 8, 4, ENC_BIG_ENDIAN); proto_tree_add_item(manolito_tree, hf_manolito_dest, tvb, 12, 4, ENC_BIG_ENDIAN); if (tvb_reported_length(tvb) == 19) { packet_type = "Ping (truncated)"; proto_tree_add_item(manolito_tree, hf_manolito_options_short, tvb, 16, 3, ENC_BIG_ENDIAN); } else { proto_tree_add_item(manolito_tree, hf_manolito_options, tvb, 16, 4, ENC_BIG_ENDIAN); } if (tvb_reported_length(tvb) <= 20) /* no payload, just headers */ { col_set_str(pinfo->cinfo, COL_INFO, "Ping"); } else { offset = 20; /* fields start here */ /* fields format: 2-byte name, optional NULL, 1-byte lenlen, */ /* that many bytes(len or data), for NI,CN,VL is len, more */ /* (that many bytes) data follows; else is raw data. */ do { guint16 field_name; /* 16-bit field name */ guint8 dtype; /* data-type */ guint8 length; /* length */ guint8* data; /* payload */ int start; /* field starting location */ char field_name_str[3]; /* printable name */ const char* longname; /* human-friendly field name */ start = offset; /* 2-byte field name */ field_name = tvb_get_ntohs(tvb, offset); offset += 2; /* Identify the packet based on existing fields */ /* Maybe using the options fields is a better idea...*/ if (field_name == 0x434b) /* CK */ packet_type = "Search Hit"; if (field_name == 0x4e43) /* NC */ packet_type = "User Information"; if (field_name == 0x464e) /* FN - if only field */ packet_type = "Search Query"; if (field_name == 0x4944) /* ID ?? search by CK? */ packet_type = "Search Query (by hash)"; if (field_name == 0x5054) /* PT */ packet_type = "Download Request"; if (field_name == 0x4d45) /* ME */ packet_type = "Chat"; if (tvb_reported_length(tvb) == 20) /* no fields */ packet_type = "Ping"; /* Find the long name of the field */ switch(field_name) { case 0x5346: longname = "Shared Files"; break; /* SF */ case 0x534b: longname = "Shared Kilobytes";break; /* SK */ case 0x4e49: longname = "Network ID"; break; /* NI */ case 0x4e43: longname = "Num. Connections";break; /* NC */ case 0x4356: longname = "Client Version"; break; /* CV */ case 0x564c: longname = "Velocity"; break; /* VL */ case 0x464e: longname = "Filename"; break; /* FN */ case 0x464c: longname = "File Length"; break; /* FL */ case 0x4252: longname = "Bit Rate"; break; /* BR */ case 0x4643: longname = "Frequency"; break; /* FC */ case 0x5354: longname = "???"; break; /* ST */ case 0x534c: longname = "Song Length (s)"; break; /* SL */ case 0x434b: longname = "Checksum"; break; /* CK */ case 0x4e4e: longname = "Nickname"; break; /* NN */ case 0x434e: longname = "Client Name"; break; /* CN */ case 0x5054: longname = "Port"; break; /* PT */ case 0x484e: longname = "???"; break; /* HN */ case 0x4d45: longname = "Message"; break; /* ME */ case 0x4944: longname = "Identification"; break; /* ID */ case 0x4144: longname = "???"; break; /* AD */ default: longname = "unknown"; break; } /* 1-byte data type */ #define MANOLITO_STRING 1 #define MANOLITO_INTEGER 0 dtype = tvb_get_guint8(tvb, offset); length = tvb_get_guint8(tvb, ++offset); /* * Get the payload. * * XXX - is the cast necessary? I think the * "usual arithmetic conversions" should * widen it past 8 bits, so there shouldn't * be an overflow. */ data = (guint8 *)wmem_alloc(wmem_packet_scope(), (guint)length + 1); tvb_memcpy(tvb, data, ++offset, length); offset += length; /* convert the 16-bit integer field name to a string */ /* XXX: changed this to use g_htons */ field_name_str[0] = g_htons(field_name) & 0x00ff; field_name_str[1] = (g_htons(field_name) & 0xff00) >> 8; field_name_str[2] = 0; if (dtype == MANOLITO_STRING) { data[length] = 0; proto_tree_add_text(manolito_tree, tvb, start, offset - start, "%s (%s): %s", (char*)field_name_str, longname, data); } else if (dtype == MANOLITO_INTEGER) { int n = 0; /* integers can be up to 5 bytes */ switch(length) { case 5: n += data[4] << ((length - 5) * 8); case 4: n += data[3] << ((length - 4) * 8); case 3: n += data[2] << ((length - 3) * 8); case 2: n += data[1] << ((length - 2) * 8); case 1: n += data[0] << ((length - 1) * 8); } proto_tree_add_text(manolito_tree, tvb, start, offset - start, "%s (%s): %d", (char*)field_name_str, longname, n); } else { proto_tree_add_text(manolito_tree, tvb, start, offset - start, "unknown type %d", dtype); } } while(offset < tvb_reported_length(tvb)); } if (packet_type) { col_set_str(pinfo->cinfo, COL_INFO, packet_type); } }
static void dissect_imap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *imap_tree, *reqresp_tree; proto_item *ti, *hidden_item; gint offset = 0; gint uid_offset = 0; gint folder_offset = 0; const guchar *line; const guchar *uid_line; const guchar *folder_line; gint next_offset; int linelen; int tokenlen; int uid_tokenlen; int folder_tokenlen; const guchar *next_token; const guchar *uid_next_token; const guchar *folder_next_token; guchar *tokenbuf; guchar *command_token; int iter; int commandlen; tokenbuf = (guchar *)wmem_alloc(wmem_packet_scope(), MAX_BUFFER); command_token = (guchar *)wmem_alloc(wmem_packet_scope(), MAX_BUFFER); memset(tokenbuf, '\0', MAX_BUFFER); memset(command_token, '\0', MAX_BUFFER); commandlen = 0; folder_offset = 0; folder_tokenlen = 0; folder_line = NULL; col_set_str(pinfo->cinfo, COL_PROTOCOL, "IMAP"); if (pinfo->match_uint == pinfo->destport) is_request = TRUE; else is_request = FALSE; /* * Put the first line from the buffer into the summary * (but leave out the line terminator). */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "Request" : "Response", format_text(line, linelen)); if (tree) { ti = proto_tree_add_item(tree, proto_imap, tvb, offset, -1, ENC_NA); imap_tree = proto_item_add_subtree(ti, ett_imap); hidden_item = proto_tree_add_boolean(imap_tree, hf_imap_isrequest, tvb, 0, 0, is_request); PROTO_ITEM_SET_HIDDEN(hidden_item); while(tvb_length_remaining(tvb, offset) > 0) { /* * Find the end of each line * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); /* * Put the line into the protocol tree. */ ti = proto_tree_add_item(imap_tree, hf_imap_line, tvb, offset, next_offset - offset, ENC_ASCII|ENC_NA); reqresp_tree = proto_item_add_subtree(ti, ett_imap_reqresp); /* * Check that the line doesn't begin with '*', because that's a continuation line. * Otherwise if a tag is present then extract tokens. */ if ( (line) && ((line[0] != '*') || (TRUE == is_request)) ) { /* * Show each line as tags + requests or replies. */ /* * Extract the first token, and, if there is a first * token, add it as the request or reply tag. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_imap_request_tag : hf_imap_response_tag, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); offset += (gint) (next_token - line); linelen -= (int) (next_token - line); line = next_token; } /* * Extract second token, and, if there is a second * token, and it's not uid, add it as the request or reply command. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { for (iter = 0; iter < tokenlen && iter < MAX_BUFFER-1; iter++) { tokenbuf[iter] = g_ascii_tolower(line[iter]); } if ( TRUE == is_request && strncmp(tokenbuf,"uid",tokenlen) == 0) { proto_tree_add_item(reqresp_tree, hf_imap_request_uid, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); /* * UID is a precursor to a command, if following the tag, * so move to next token to grab the actual command. */ uid_offset = offset; uid_offset += (gint) (next_token - line); uid_line = next_token; uid_tokenlen = get_token_len(uid_line, uid_line + (linelen - tokenlen), &uid_next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, hf_imap_request_command, tvb, uid_offset, uid_tokenlen, ENC_ASCII|ENC_NA); /* * Save command string to do specialized processing. */ for (iter = 0; iter < uid_tokenlen && iter < MAX_BUFFER-1; iter++) { command_token[iter] = g_ascii_tolower(uid_line[iter]); } commandlen = uid_tokenlen; folder_offset = uid_offset; folder_offset += (gint) (uid_next_token - uid_line); folder_line = uid_next_token; folder_tokenlen = get_token_len(folder_line, folder_line + (linelen - tokenlen - uid_tokenlen), &folder_next_token); } } else { /* * Not a UID request so perform normal parsing. */ proto_tree_add_item(reqresp_tree, (is_request) ? hf_imap_request_command : hf_imap_response_status, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); if (is_request) { /* * Save command string to do specialized processing. */ for (iter = 0; iter < tokenlen && iter < 256; iter++) { command_token[iter] = g_ascii_tolower(line[iter]); } commandlen = tokenlen; folder_offset = offset; folder_offset += (gint) (next_token - line); folder_line = next_token; folder_tokenlen = get_token_len(folder_line, folder_line + (linelen - tokenlen - 1), &folder_next_token); } } if (commandlen > 0 && ( strncmp(command_token, "select", commandlen) == 0 || strncmp(command_token, "examine", commandlen) == 0 || strncmp(command_token, "create", commandlen) == 0 || strncmp(command_token, "delete", commandlen) == 0 || strncmp(command_token, "rename", commandlen) == 0 || strncmp(command_token, "subscribe", commandlen) == 0 || strncmp(command_token, "unsubscribe", commandlen) == 0 || strncmp(command_token, "status", commandlen) == 0 || strncmp(command_token, "append", commandlen) == 0 || strncmp(command_token, "search", commandlen) == 0)) { /* * These commands support folder as an argument, * so parse out the folder name. */ if (folder_tokenlen != 0) proto_tree_add_item(reqresp_tree, hf_imap_request_folder, tvb, folder_offset, folder_tokenlen, ENC_ASCII|ENC_NA); } if ( is_request && (NULL != folder_line) && strncmp(command_token, "copy", commandlen) == 0) { /* * Handle the copy command separately since folder * is the second argument for this command. */ folder_offset += (gint) (folder_next_token - folder_line); folder_line = folder_next_token; folder_tokenlen = get_token_len(folder_line, folder_line + (linelen - tokenlen), &folder_next_token); if (folder_tokenlen != 0) proto_tree_add_item(reqresp_tree, hf_imap_request_folder, tvb, folder_offset, folder_tokenlen, ENC_ASCII|ENC_NA); } } /* * Add the rest of the line as request or reply data. */ if (linelen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_imap_request : hf_imap_response, tvb, offset, linelen, ENC_ASCII|ENC_NA); } } offset = next_offset; /* Skip over last line and \r\n at the end of it */ } } }
// Allocate our records using wmem. static void *operator new(size_t size) { return wmem_alloc(wmem_file_scope(), size); }
static void dissect_pgmopts(ptvcursor_t* cursor, packet_info *pinfo, const char *pktname) { proto_item *tf, *ti, *ti_len; proto_tree *opts_tree = NULL; proto_tree *opt_tree = NULL; tvbuff_t *tvb = ptvcursor_tvbuff(cursor); gboolean theend = FALSE; guint16 opts_total_len; guint8 genopts_type; guint8 genopts_len; guint8 opts_type; opts_tree = proto_tree_add_subtree_format(ptvcursor_tree(cursor), tvb, ptvcursor_current_offset(cursor), -1, ett_pgm_opts, &tf, "%s Options", pktname); ptvcursor_set_tree(cursor, opts_tree); opts_type = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_opt_type, 1, ENC_BIG_ENDIAN); if (opts_type != PGM_OPT_LENGTH) { expert_add_info_format(pinfo, ti, &ei_pgm_opt_type, "%s Options - initial option is %s, should be %s", pktname, val_to_str(opts_type, opt_vals, "Unknown (0x%02x)"), val_to_str(PGM_OPT_LENGTH, opt_vals, "Unknown (0x%02x)")); return; } ptvcursor_add(cursor, hf_pgm_opt_len, 1, ENC_BIG_ENDIAN); opts_total_len = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); proto_item_append_text(tf, " (Total Length %d)", opts_total_len); proto_item_set_len(tf, opts_total_len); ti_len = ptvcursor_add(cursor, hf_pgm_opt_tlen, 2, ENC_BIG_ENDIAN); if (opts_total_len < 4) { expert_add_info_format(pinfo, ti_len, &ei_pgm_opt_tlen, "%s Options (Total Length %u - invalid, must be >= 4)", pktname, opts_total_len); return; } for (opts_total_len -= 4; !theend && opts_total_len != 0;){ if (opts_total_len < 4) { expert_add_info_format(pinfo, ti_len, &ei_pgm_opt_tlen, "Remaining total options length doesn't have enough for an options header"); break; } genopts_type = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor)); genopts_len = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor)+1); if (genopts_type & PGM_OPT_END) { genopts_type &= ~PGM_OPT_END; theend = TRUE; } switch(genopts_type) { case PGM_OPT_JOIN:{ TLV_CHECK(ett_pgm_opts_join); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_JOIN_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_JOIN_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_join_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_join_minjoin, 4, ENC_BIG_ENDIAN); break; } case PGM_OPT_PARITY_PRM:{ guint8 optdata_po; TLV_CHECK(ett_pgm_opts_parityprm); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_PARITY_PRM_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, ptvcursor_tvbuff(cursor), ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_PARITY_PRM_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); optdata_po = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor)); proto_tree_add_uint_format_value(opt_tree, hf_pgm_opt_parity_prm_po, tvb, ptvcursor_current_offset(cursor), 1, optdata_po, "%s (0x%x)", paritystr(optdata_po), optdata_po); ptvcursor_advance(cursor, 1); ptvcursor_add(cursor, hf_pgm_opt_parity_prm_prmtgsz, 4, ENC_BIG_ENDIAN); break; } case PGM_OPT_PARITY_GRP:{ TLV_CHECK(ett_pgm_opts_paritygrp); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_PARITY_GRP_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_PARITY_GRP_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_parity_grp_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_parity_grp_prmgrp, 4, ENC_BIG_ENDIAN); break; } case PGM_OPT_NAK_LIST:{ guint8 optdata_len; guint32 naklist[PGM_MAX_NAK_LIST_SZ+1]; unsigned char *nakbuf; gboolean firsttime; int i, j, naks, soffset; TLV_CHECK(ett_pgm_opts_naklist); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); optdata_len = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor)); ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_res, 1, ENC_BIG_ENDIAN); optdata_len -= PGM_OPT_NAK_LIST_SIZE; tvb_memcpy(tvb, (guint8 *)naklist, ptvcursor_current_offset(cursor), optdata_len); firsttime = TRUE; soffset = 0; naks = (int)(optdata_len/sizeof(guint32)); nakbuf = (unsigned char *)wmem_alloc(wmem_packet_scope(), 8192); j = 0; /* * Print out 8 per line */ for (i=0; i < naks; i++) { soffset += MIN(8192-soffset, g_snprintf(nakbuf+soffset, 8192-soffset, "0x%lx ", (unsigned long)g_ntohl(naklist[i]))); if ((++j % 8) == 0) { if (firsttime) { proto_tree_add_bytes_format(opt_tree, hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, nakbuf, "List(%d): %s", naks, nakbuf); soffset = 0; firsttime = FALSE; } else { proto_tree_add_bytes_format_value(opt_tree, hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, nakbuf, "%s", nakbuf); soffset = 0; } ptvcursor_advance(cursor, j*4); j = 0; } } if (j) { if (firsttime) { proto_tree_add_bytes_format(opt_tree, hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, nakbuf, "List(%d): %s", naks, nakbuf); } else { proto_tree_add_bytes_format_value(opt_tree, hf_pgm_opt_nak_list, tvb, ptvcursor_current_offset(cursor), j*4, nakbuf, "%s", nakbuf); } ptvcursor_advance(cursor, j*4); } break; } case PGM_OPT_PGMCC_DATA:{ guint16 optdata_afi; TLV_CHECK(ett_pgm_opts_ccdata); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_PGMCC_DATA_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_PGMCC_DATA_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_ccdata_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_ccdata_tsp, 4, ENC_BIG_ENDIAN); optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_opt_ccdata_afi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_ccdata_res2, 2, ENC_BIG_ENDIAN); switch (optdata_afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_opt_ccdata_acker6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); break; } break; } case PGM_OPT_PGMCC_FEEDBACK:{ guint16 optdata_afi; TLV_CHECK(ett_pgm_opts_ccdata); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_PGMCC_FEEDBACK_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_PGMCC_FEEDBACK_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_tsp, 4, ENC_BIG_ENDIAN); optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_afi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_lossrate, 2, ENC_BIG_ENDIAN); switch (optdata_afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_opt_ccfeedbk_acker6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); break; } break; } case PGM_OPT_NAK_BO_IVL:{ TLV_CHECK(ett_pgm_opts_nak_bo_ivl); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_NAK_BO_IVL_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_NAK_BO_IVL_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_bo_ivl, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_bo_ivl_bo_ivl_sqn, 4, ENC_BIG_ENDIAN); break; } case PGM_OPT_NAK_BO_RNG:{ TLV_CHECK(ett_pgm_opts_nak_bo_rng); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_NAK_BO_RNG_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_NAK_BO_RNG_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_min_bo_ivl, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_nak_bo_rng_max_bo_ivl, 4, ENC_BIG_ENDIAN); break; } case PGM_OPT_REDIRECT:{ guint16 optdata_afi; TLV_CHECK(ett_pgm_opts_redirect); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_REDIRECT_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_REDIRECT_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_redirect_res, 1, ENC_BIG_ENDIAN); optdata_afi = tvb_get_ntohs(tvb, ptvcursor_current_offset(cursor)); ti = ptvcursor_add(cursor, hf_pgm_opt_redirect_afi, 2, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_redirect_res2, 2, ENC_BIG_ENDIAN); switch (optdata_afi) { case AFNUM_INET: ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr, 4, ENC_BIG_ENDIAN); break; case AFNUM_INET6: ptvcursor_add(cursor, hf_pgm_opt_redirect_dlr6, 16, ENC_NA); break; default: expert_add_info(pinfo, ti, &ei_address_format_invalid); break; } break; } case PGM_OPT_FRAGMENT:{ TLV_CHECK(ett_pgm_opts_fragment); ptvcursor_set_tree(cursor, opt_tree); ptvcursor_add_no_advance(cursor, hf_pgm_genopt_end, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_type, 1, ENC_BIG_ENDIAN); if (genopts_len < PGM_OPT_FRAGMENT_SIZE) { proto_tree_add_uint_format_value(opt_tree, hf_pgm_genopt_len, tvb, ptvcursor_current_offset(cursor), 1, genopts_len, "%u (bogus, must be >= %u)", genopts_len, PGM_OPT_FRAGMENT_SIZE); break; } ptvcursor_add(cursor, hf_pgm_genopt_len, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_genopt_opx, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_fragment_res, 1, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_fragment_first_sqn, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_fragment_offset, 4, ENC_BIG_ENDIAN); ptvcursor_add(cursor, hf_pgm_opt_fragment_total_length, 4, ENC_BIG_ENDIAN); break; } default:{ TLV_CHECK(ett_pgm_opts); ptvcursor_advance(cursor, genopts_len); break; } } opts_total_len -= genopts_len; } return; }
void *PacketListRecord::operator new(size_t size) { return wmem_alloc(wmem_file_scope(), size); }
static int nmas_string(tvbuff_t* tvb, int hfinfo, proto_tree *nmas_tree, int offset, gboolean little) { int foffset = offset; guint32 str_length; char *buffer; guint32 i; guint16 c_char; guint32 length_remaining = 0; buffer = (char *)wmem_alloc(wmem_packet_scope(), ITEM_LABEL_LENGTH+1); if (little) { str_length = tvb_get_letohl(tvb, foffset); } else { str_length = tvb_get_ntohl(tvb, foffset); } foffset += 4; if (str_length >= ITEM_LABEL_LENGTH) { proto_tree_add_string(nmas_tree, hfinfo, tvb, foffset, length_remaining + 4, "<String too long to process>"); foffset += length_remaining; return foffset; } if (str_length == 0) { proto_tree_add_string(nmas_tree, hfinfo, tvb, offset, 4, "<Not Specified>"); return foffset; } /* * XXX - other than the special-casing of null bytes, * we could just use "proto_tree_add_item()", as for * FT_STRING, FT_STRINGZ, and FT_UINT_STRING fields, * the display representation of an item is generated * using "format_text()", so it handles non-printable * characters. */ for ( i = 0; i < str_length; i++ ) { c_char = tvb_get_guint8(tvb, foffset ); if (c_char<0x20 || c_char>0x7e) { if (c_char != 0x00) { c_char = 0x2e; buffer[i] = c_char & 0xff; } else { i--; str_length--; } } else { buffer[i] = c_char & 0xff; } foffset++; length_remaining--; if (length_remaining==1) { i++; break; } } buffer[i] = '\0'; if (little) { str_length = tvb_get_letohl(tvb, offset); } else { str_length = tvb_get_ntohl(tvb, offset); } proto_tree_add_string(nmas_tree, hfinfo, tvb, offset+4, str_length, buffer); return foffset; }
/* Code to actually dissect the packets */ static void dissect_ax25_kiss( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree ) { proto_item *ti; proto_tree *kiss_tree; int offset; int kiss_cmd; int kiss_type; int kiss_port; int kiss_param; int kiss_param_len; const char *frame_type_text; char *info_buffer; tvbuff_t *next_tvb = NULL; info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN ); info_buffer[0] = '\0'; col_set_str( pinfo->cinfo, COL_PROTOCOL, "AX.25 KISS" ); col_clear( pinfo->cinfo, COL_INFO ); /* protocol offset for the KISS header */ offset = 0; kiss_cmd = tvb_get_guint8( tvb, offset ) & 0xff; kiss_type = kiss_cmd & KISS_CMD_MASK; kiss_port = (kiss_cmd & KISS_PORT_MASK) >> 4; offset += KISS_HEADER_SIZE; kiss_param = 0; kiss_param_len = 0; switch ( kiss_type ) { case KISS_TXDELAY : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break; case KISS_PERSISTENCE : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break; case KISS_SLOT_TIME : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break; case KISS_TXTAIL : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break; case KISS_FULLDUPLEX : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break; case KISS_SETHARDWARE : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break; default : break; } frame_type_text = val_to_str(kiss_type, kiss_frame_types, "Unknown (%u)"); g_snprintf( info_buffer, STRLEN, "%s, Port %u", frame_type_text, kiss_port ); if ( kiss_param_len > 0 ) g_snprintf( info_buffer, STRLEN, "%s %u, Port %u", frame_type_text, kiss_param, kiss_port ); offset += kiss_param_len; col_add_str( pinfo->cinfo, COL_INFO, info_buffer ); if ( parent_tree ) { /* protocol offset for the KISS header */ offset = 0; /* create display subtree for the protocol */ ti = proto_tree_add_protocol_format( parent_tree, proto_ax25_kiss, tvb, offset, KISS_HEADER_SIZE + kiss_param_len, "KISS: %s", info_buffer ); kiss_tree = proto_item_add_subtree( ti, ett_ax25_kiss ); proto_tree_add_uint( kiss_tree, hf_ax25_kiss_cmd, tvb, offset, KISS_HEADER_SIZE, kiss_cmd ); proto_tree_add_uint( kiss_tree, hf_ax25_kiss_port, tvb, offset, KISS_HEADER_SIZE, kiss_port ); offset += KISS_HEADER_SIZE; switch ( kiss_type ) { case KISS_DATA_FRAME : break; case KISS_TXDELAY : proto_tree_add_uint( kiss_tree, hf_ax25_kiss_txdelay, tvb, offset, kiss_param_len, kiss_param ); offset += kiss_param_len; break; case KISS_PERSISTENCE : proto_tree_add_uint( kiss_tree, hf_ax25_kiss_persistence, tvb, offset, kiss_param_len, kiss_param ); offset += kiss_param_len; break; case KISS_SLOT_TIME : proto_tree_add_uint( kiss_tree, hf_ax25_kiss_slottime, tvb, offset, kiss_param_len, kiss_param ); offset += kiss_param_len; break; case KISS_TXTAIL : proto_tree_add_uint( kiss_tree, hf_ax25_kiss_txtail, tvb, offset, kiss_param_len, kiss_param ); offset += kiss_param_len; break; case KISS_FULLDUPLEX : proto_tree_add_uint( kiss_tree, hf_ax25_kiss_fullduplex, tvb, offset, kiss_param_len, kiss_param ); offset += kiss_param_len; break; case KISS_SETHARDWARE : proto_tree_add_uint( kiss_tree, hf_ax25_kiss_sethardware, tvb, offset, kiss_param_len, kiss_param ); offset += kiss_param_len; break; case KISS_RETURN : break; default : break; } } /* Call sub-dissectors here */ if ( kiss_type == KISS_DATA_FRAME ) { next_tvb = tvb_new_subset_remaining( tvb, offset ); call_dissector( ax25_handle, next_tvb, pinfo, parent_tree ); } }
static void save_command(guint32 cmd, guint32 arg0, guint32 arg1, guint32 data_length, guint32 crc32, service_data_t *service_data, gint proto, void *data, packet_info *pinfo, service_data_t **returned_service_data, command_data_t **returned_command_data) { wmem_tree_key_t key[6]; guint32 interface_id; guint32 bus_id; guint32 device_address; guint32 side_id; guint32 frame_number; command_data_t *command_data; wmem_tree_t *wmem_tree; gint direction = P2P_DIR_UNKNOWN; usb_conv_info_t *usb_conv_info = (usb_conv_info_t *) data; frame_number = pinfo->fd->num; if (pinfo->phdr->presence_flags & WTAP_HAS_INTERFACE_ID) interface_id = pinfo->phdr->interface_id; else interface_id = 0; if (proto == proto_usb) { usb_conv_info = (usb_conv_info_t *) data; DISSECTOR_ASSERT(usb_conv_info); direction = usb_conv_info->direction; bus_id = usb_conv_info->bus_id; device_address = usb_conv_info->device_address; key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; key[1].key = &bus_id; key[2].length = 1; key[2].key = &device_address; key[3].length = 1; key[3].key = &side_id; key[4].length = 1; key[4].key = &frame_number; key[5].length = 0; key[5].key = NULL; } else { /* tcp */ if (pinfo->destport == ADB_TCP_PORT) direction = P2P_DIR_SENT; else direction = P2P_DIR_RECV; key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; key[2].length = 1; if (direction == P2P_DIR_SENT) { key[1].key = &pinfo->srcport; key[2].key = &pinfo->destport; } else { key[1].key = &pinfo->destport; key[2].key = &pinfo->srcport; } key[3].length = 1; key[3].key = &side_id; key[4].length = 1; key[4].key = &frame_number; key[5].length = 0; key[5].key = NULL; } if (direction == P2P_DIR_SENT) if (cmd == A_CLSE) side_id = arg1; /* OUT: local id */ else side_id = arg0; /* OUT: local id */ else side_id = arg1; /* IN: remote id */ if (cmd == A_OPEN) { service_data = wmem_new(wmem_file_scope(), service_data_t); service_data->start_in_frame = pinfo->fd->num; service_data->close_local_in_frame = max_in_frame; service_data->close_remote_in_frame = max_in_frame; service_data->local_id = arg0; service_data->remote_id = arg1; service_data->service = "unknown"; wmem_tree_insert32_array(service_info, key, service_data); } command_data = wmem_new(wmem_file_scope(), command_data_t); command_data->command = cmd; command_data->arg0 = arg0; command_data->arg1 = arg1; command_data->command_in_frame = pinfo->fd->num; command_data->response_in_frame = max_in_frame; command_data->crc32 = crc32; command_data->data_length = data_length; if (data_length == 0) command_data->completed_in_frame = pinfo->fd->num; else command_data->completed_in_frame = max_in_frame; command_data->reassemble_data_length = 0; command_data->reassemble_data = (guint8 *) wmem_alloc(wmem_file_scope(), command_data->data_length); key[3].length = 1; key[3].key = &frame_number; key[4].length = 0; key[4].key = NULL; wmem_tree_insert32_array(command_info, key, command_data); if (direction == P2P_DIR_SENT) if (command_data->command == A_CLSE) side_id = command_data->arg1; /* OUT: local id */ else side_id = command_data->arg0; /* OUT: local id */ else side_id = command_data->arg1; /* IN: remote id */ key[3].length = 1; key[3].key = &side_id; key[4].length = 0; key[4].key = NULL; wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(service_info, key); if (wmem_tree) { service_data = (service_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number); } if (cmd == A_OKAY) { if (!service_data) { if (direction == P2P_DIR_SENT) side_id = command_data->arg0; /* OUT: local id */ else side_id = command_data->arg1; /* IN: remote id */ wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(service_info, key); if (wmem_tree) { service_data = (service_data_t *) wmem_tree_lookup32_le(wmem_tree, frame_number); } } if (service_data && service_data->remote_id == 0 && direction == P2P_DIR_RECV) { if (direction == P2P_DIR_SENT) { service_data->remote_id = arg1; } else { service_data->remote_id = arg0; } side_id = service_data->remote_id; key[4].length = 1; key[4].key = &frame_number; key[5].length = 0; key[5].key = NULL; wmem_tree_insert32_array(service_info, key, service_data); } } else if (cmd == A_CLSE) { if (service_data) { if (direction == P2P_DIR_RECV && service_data->local_id == arg1) service_data->close_local_in_frame = pinfo->fd->num; else if (direction == P2P_DIR_SENT && service_data->remote_id == arg1) service_data->close_remote_in_frame = pinfo->fd->num; } } DISSECTOR_ASSERT(returned_service_data && returned_command_data); *returned_service_data = service_data; *returned_command_data = command_data; }
/*FUNCTION:------------------------------------------------------ * NAME * dissect_zbee_secure * DESCRIPTION * Dissects and decrypts secured ZigBee frames. * * Will return a valid tvbuff only if security processing was * successful. If processing fails, then this function will * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxiliary security header. * guint64 src64 - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset) { proto_tree *sec_tree; zbee_security_packet packet; guint mic_len; gint payload_len; tvbuff_t *payload_tvb; #ifdef HAVE_LIBGCRYPT proto_item *ti; proto_item *key_item; guint8 *enc_buffer; guint8 *dec_buffer; gboolean decrypted; GSList **nwk_keyring; GSList *GSList_i; key_record_t *key_rec = NULL; #endif zbee_nwk_hints_t *nwk_hints; ieee802154_hints_t *ieee_hints; ieee802154_map_rec *map_rec = NULL; static const int * sec_flags[] = { &hf_zbee_sec_key_id, &hf_zbee_sec_nonce, NULL }; /* Init */ memset(&packet, 0, sizeof(zbee_security_packet)); /* Get pointers to any useful frame data from lower layers */ nwk_hints = (zbee_nwk_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK), 0); ieee_hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0); /* Create a subtree for the security information. */ sec_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_zbee_sec, NULL, "ZigBee Security Header"); /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just * so we can fix these 3 bits. Memory allocated by tvb_memdup(wmem_packet_scope(),...) * is automatically freed before the next packet is processed. */ #ifdef HAVE_LIBGCRYPT enc_buffer = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, tvb_captured_length(tvb)); /* * Override the const qualifiers and patch the security level field, we * know it is safe to overide the const qualifiers because we just * allocated this memory via tvb_memdup(wmem_packet_scope(),...). */ enc_buffer[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); packet.key_id = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); proto_tree_add_bitmask(sec_tree, tvb, offset, hf_zbee_sec_field, ett_zbee_sec_control, sec_flags, ENC_NA); offset += 1; /* Get and display the frame counter field. */ packet.counter = tvb_get_letohl(tvb, offset); proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, 4, packet.counter); offset += 4; if (packet.nonce) { /* Get and display the source address of the device that secured this payload. */ packet.src64 = tvb_get_letoh64(tvb, offset); proto_tree_add_item(sec_tree, hf_zbee_sec_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN); #if 1 if (!pinfo->fd->flags.visited) { switch ( packet.key_id ) { case ZBEE_SEC_KEY_LINK: if (nwk_hints && ieee_hints) { /* Map this long address with the nwk layer short address. */ nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, nwk_hints->src, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->num); } break; case ZBEE_SEC_KEY_NWK: if (ieee_hints) { /* Map this long address with the ieee short address. */ ieee_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, ieee_hints->src16, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->num); } break; /* We ignore the extended source addresses used to encrypt payloads with these * types of keys, because they can emerge from APS tunnels created by nodes whose * short address is not recorded in the packet. */ case ZBEE_SEC_KEY_TRANSPORT: case ZBEE_SEC_KEY_LOAD: break; } } #endif offset += 8; } else { /* Look for a source address in hints */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: /* use the ieee extended source address for NWK decryption */ if ( ieee_hints && (map_rec = ieee_hints->map_rec) ) packet.src64 = map_rec->addr64; else proto_tree_add_expert(sec_tree, pinfo, &ei_zbee_sec_extended_source_unknown, tvb, 0, 0); break; default: /* use the nwk extended source address for APS decryption */ if ( nwk_hints && (map_rec = nwk_hints->map_rec) ) packet.src64 = map_rec->addr64; else proto_tree_add_expert(sec_tree, pinfo, &ei_zbee_sec_extended_source_unknown, tvb, 0, 0); break; } } if (packet.key_id == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, 1, packet.key_seqno); offset += 1; } /* Determine the length of the MIC. */ switch (packet.level) { case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: mic_len=0; break; case ZBEE_SEC_ENC_MIC32: case ZBEE_SEC_MIC32: mic_len=4; break; case ZBEE_SEC_ENC_MIC64: case ZBEE_SEC_MIC64: mic_len=8; break; case ZBEE_SEC_ENC_MIC128: case ZBEE_SEC_MIC128: mic_len=16; break; } /* switch */ /* Get and display the MIC. */ if (mic_len) { /* Display the MIC. */ proto_tree_add_item(sec_tree, hf_zbee_sec_mic, tvb, (gint)(tvb_captured_length(tvb)-mic_len), mic_len, ENC_NA); } /* Check for null payload. */ payload_len = tvb_reported_length_remaining(tvb, offset+mic_len); if (payload_len == 0) return NULL; /********************************************** * Perform Security Operations on the Frame * ********************************************** */ if ((packet.level == ZBEE_SEC_NONE) || (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset_length(tvb, offset, payload_len); } #ifdef HAVE_LIBGCRYPT /* Have we captured all the payload? */ if (tvb_captured_length_remaining(tvb, offset+mic_len) < payload_len) { /* * No - don't try to decrypt it. * * XXX - it looks as if the decryption code is assuming we have the * MIC, which won't be the case if the packet was cut short. Is * that in fact that case, or can we still make this work with a * partially-captured packet? */ /* Add expert info. */ expert_add_info(pinfo, sec_tree, &ei_zbee_sec_encrypted_payload_sliced); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset_length(tvb, offset, payload_len); /* Dump the payload to the data dissector. */ call_data_dissector(payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* Allocate memory to decrypt the payload into. */ dec_buffer = (guint8 *)wmem_alloc(pinfo->pool, payload_len); decrypted = FALSE; if ( packet.src64 ) { if (pinfo->fd->flags.visited) { if ( nwk_hints ) { /* Use previously found key */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: if ( (key_rec = nwk_hints->nwk) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->nwk->key); } break; default: if ( (key_rec = nwk_hints->link) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->link->key); } break; } } } /* ( !pinfo->fd->flags.visited ) */ else { /* We only search for sniffed keys in the first pass, * to save time, and because decrypting with keys * transported in future packets is cheating */ /* Lookup NWK and link key in hash for this pan. */ /* This overkill approach is a placeholder for a hash that looks up * a key ring for a link key associated with a pair of devices. */ if ( nwk_hints ) { nwk_keyring = (GSList **)g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); if ( nwk_keyring ) { GSList_i = *nwk_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } /* Loop through user's password table for preconfigured keys, our last resort */ GSList_i = zbee_pc_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } } /* ( ! pinfo->fd->flags.visited ) */ } /* ( packet.src64 ) */ if ( decrypted ) { if ( tree && key_rec ) { key_item = proto_tree_add_bytes(sec_tree, hf_zbee_sec_key, tvb, 0, ZBEE_SEC_CONST_KEYSIZE, key_rec->key); PROTO_ITEM_SET_GENERATED(key_item); if ( key_rec->frame_num == ZBEE_SEC_PC_KEY ) { ti = proto_tree_add_string(sec_tree, hf_zbee_sec_decryption_key, tvb, 0, 0, key_rec->label); } else { ti = proto_tree_add_uint(sec_tree, hf_zbee_sec_key_origin, tvb, 0, 0, key_rec->frame_num); } PROTO_ITEM_SET_GENERATED(ti); } /* Found a key that worked, setup the new tvbuff_t and return */ payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); /* Done! */ return payload_tvb; } #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ expert_add_info(pinfo, sec_tree, &ei_zbee_sec_encrypted_payload); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset_length(tvb, offset, payload_len); /* Dump the payload to the data dissector. */ call_data_dissector(payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* dissect_zbee_secure */
/* * Main dissection functions */ static guint16 dissect_control(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int is_response) { proto_tree *ctl_tree; proto_item *ctl_ti; guint16 ctl, poll_final; const char *frame_type; char *info; info = (char *)wmem_alloc(wmem_packet_scope(), 80); /* Grab complete control field */ ctl = tvb_get_ntohs(tvb, 1) >> 4; poll_final = ctl & LAPSAT_CTL_P_F; /* Generate small 'descriptive' text */ switch (ctl & LAPSAT_CTL_TYPE_S_U_MSK) { case LAPSAT_CTL_TYPE_S: /* * Supervisory frame. */ switch (ctl & LAPSAT_CTL_S_FTYPE_MSK) { case LAPSAT_RR: frame_type = "RR";
/* dissect the "device" suboption */ static int dissect_PNDCP_Suboption_Device(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, proto_item *block_item, proto_item *dcp_item, guint8 service_id, gboolean is_response) { guint8 suboption; guint16 block_length; gchar *info_str; guint8 device_role; guint16 vendor_id; guint16 device_id; char *typeofstation; char *nameofstation; char *aliasname; guint16 block_info; guint16 block_qualifier; gboolean have_block_info = FALSE; gboolean have_block_qualifier = FALSE; guint8 device_instance_high; guint8 device_instance_low; /* SuboptionDevice... */ offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device, &suboption); /* DCPBlockLength */ offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_length, &block_length); /* BlockInfo? */ if ( ((service_id == PNDCP_SERVICE_ID_IDENTIFY) && is_response) || ((service_id == PNDCP_SERVICE_ID_HELLO) && !is_response) || ((service_id == PNDCP_SERVICE_ID_GET) && is_response)) { offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_info, &block_info); have_block_info = TRUE; block_length -= 2; } /* BlockQualifier? */ if ( (service_id == PNDCP_SERVICE_ID_SET) && !is_response) { offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_block_qualifier, &block_qualifier); have_block_qualifier = TRUE; block_length -= 2; } switch (suboption) { case PNDCP_SUBOPTION_DEVICE_MANUF: typeofstation = (char *)wmem_alloc(wmem_packet_scope(), block_length+1); tvb_memcpy(tvb, (guint8 *) typeofstation, offset, block_length); typeofstation[block_length] = '\0'; proto_tree_add_string (tree, hf_pn_dcp_suboption_device_typeofstation, tvb, offset, block_length, typeofstation); pn_append_info(pinfo, dcp_item, ", DeviceVendorValue"); proto_item_append_text(block_item, "Device/Manufacturer specific"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info){ proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); } proto_item_append_text(block_item, ", DeviceVendorValue: \"%s\"", typeofstation); offset += block_length; break; case PNDCP_SUBOPTION_DEVICE_NAMEOFSTATION: nameofstation = (char *)wmem_alloc(wmem_packet_scope(), block_length+1); tvb_memcpy(tvb, (guint8 *) nameofstation, offset, block_length); nameofstation[block_length] = '\0'; proto_tree_add_string (tree, hf_pn_dcp_suboption_device_nameofstation, tvb, offset, block_length, nameofstation); pn_append_info(pinfo, dcp_item, wmem_strdup_printf(wmem_packet_scope(), ", NameOfStation:\"%s\"", nameofstation)); proto_item_append_text(block_item, "Device/NameOfStation"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info) { proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); } proto_item_append_text(block_item, ", \"%s\"", nameofstation); offset += block_length; break; case PNDCP_SUBOPTION_DEVICE_DEV_ID: offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_vendor_id, &vendor_id); offset = dissect_pn_uint16(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_id, &device_id); pn_append_info(pinfo, dcp_item, ", Dev-ID"); proto_item_append_text(block_item, "Device/Device ID"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info) { proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); } proto_item_append_text(block_item, ", VendorID: 0x%04x / DeviceID: 0x%04x", vendor_id, device_id); break; case PNDCP_SUBOPTION_DEVICE_DEV_ROLE: offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_role, &device_role); offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_reserved8, NULL); pn_append_info(pinfo, dcp_item, ", Dev-Role"); proto_item_append_text(block_item, "Device/Device Role"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info) proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); if (device_role & 0x01) proto_item_append_text(block_item, ", IO-Device"); if (device_role & 0x02) proto_item_append_text(block_item, ", IO-Controller"); if (device_role & 0x04) proto_item_append_text(block_item, ", IO-Multidevice"); if (device_role & 0x08) proto_item_append_text(block_item, ", PN-Supervisor"); break; case PNDCP_SUBOPTION_DEVICE_DEV_OPTIONS: info_str = wmem_strdup_printf(wmem_packet_scope(), ", Dev-Options(%u)", block_length/2); pn_append_info(pinfo, dcp_item, info_str); proto_item_append_text(block_item, "Device/Device Options"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info) { proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); } proto_item_append_text(block_item, ", %u options", block_length/2); for( ; block_length != 0; block_length -= 2) { offset = dissect_PNDCP_Option(tvb, offset, pinfo, tree, NULL /*block_item*/, hf_pn_dcp_option, FALSE /* append_col */); } break; case PNDCP_SUBOPTION_DEVICE_ALIAS_NAME: aliasname = (char *)wmem_alloc(wmem_packet_scope(), block_length+1); tvb_memcpy(tvb, (guint8 *) aliasname, offset, block_length); aliasname[block_length] = '\0'; proto_tree_add_string (tree, hf_pn_dcp_suboption_device_aliasname, tvb, offset, block_length, aliasname); pn_append_info(pinfo, dcp_item, wmem_strdup_printf(wmem_packet_scope(), ", AliasName:\"%s\"", aliasname)); proto_item_append_text(block_item, "Device/AliasName"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info) { proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); } proto_item_append_text(block_item, ", \"%s\"", aliasname); offset += block_length; break; case PNDCP_SUBOPTION_DEVICE_DEV_INSTANCE: offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_instance_high, &device_instance_high); offset = dissect_pn_uint8(tvb, offset, pinfo, tree, hf_pn_dcp_suboption_device_instance_low, &device_instance_low); pn_append_info(pinfo, dcp_item, ", Dev-Instance"); proto_item_append_text(block_item, "Device/Device Instance"); if (have_block_qualifier) { proto_item_append_text(block_item, ", BlockQualifier: %s", val_to_str(block_qualifier, pn_dcp_block_qualifier, "Unknown")); } if (have_block_info) { proto_item_append_text(block_item, ", BlockInfo: %s", val_to_str(block_info, pn_dcp_block_info, "Unknown")); } proto_item_append_text(block_item, ", InstanceHigh: %d, Instance Low: %d", device_instance_high, device_instance_low); break; default: offset = dissect_pn_undecoded(tvb, offset, pinfo, tree, block_length); } return offset; }
static int get_form_key_value(tvbuff_t *tvb, char **ptr, int offset, char stop) { const int orig_offset = offset; char *tmp; int len; len = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { guint8 ch; ch = tvb_get_guint8(tvb, offset); if (!ch) return -1; if (ch == stop) break; if (ch == '%') { offset++; ch = tvb_get_guint8(tvb, offset); if (ws_xton(ch) == -1) return -1; offset++; ch = tvb_get_guint8(tvb, offset); if (ws_xton(ch) == -1) return -1; } len++; offset++; } *ptr = tmp = (char*)wmem_alloc(wmem_packet_scope(), len + 1); tmp[len] = '\0'; len = 0; offset = orig_offset; while (tvb_reported_length_remaining(tvb, offset) > 0) { guint8 ch; ch = tvb_get_guint8(tvb, offset); if (!ch) return -1; if (ch == stop) break; if (ch == '%') { guint8 ch1, ch2; offset++; ch1 = tvb_get_guint8(tvb, offset); offset++; ch2 = tvb_get_guint8(tvb, offset); tmp[len] = ws_xton(ch1) << 4 | ws_xton(ch2); } else if (ch == '+') tmp[len] = ' '; else tmp[len] = ch; len++; offset++; } return offset; }
static cattp_pck* parse_cattp_packet(tvbuff_t *tvb) { cattp_pck* ret; ret = wmem_alloc(wmem_packet_scope(),sizeof(cattp_pck)); /* Check if the standard header fits in. */ gulong len; len = tvb_captured_length(tvb); if (len < CATTP_HBLEN) { /* this is not a valid CATTP packet */ return NULL; } /* Parse the header. */ int offset; offset = 0; guint8 fb; fb = tvb_get_guint8(tvb,offset); offset++; ret->flags = fb & 0xFC; /* mask the flags only */ ret->syn = (fb & F_SYN) > 0; ret->ack = (fb & F_ACK) > 0; ret->eak = (fb & F_EAK) > 0; ret->rst = (fb & F_RST) > 0; ret->nul = (fb & F_NUL) > 0; ret->seg = (fb & F_SEG) > 0; ret->version = fb & M_VERSION; /* mask the version only */ ret->rfu = tvb_get_ntohs(tvb,offset); offset+=2; ret->hlen = tvb_get_guint8(tvb,offset); offset++; ret->srcport = tvb_get_ntohs(tvb,offset); offset+=2; ret->dstport = tvb_get_ntohs(tvb,offset); offset+=2; ret->dlen = tvb_get_ntohs(tvb,offset); offset+=2; ret->seqno = tvb_get_ntohs(tvb,offset); offset+=2; ret->ackno = tvb_get_ntohs(tvb,offset); offset+=2; ret->wsize = tvb_get_ntohs(tvb,offset); offset+=2; ret->chksum = tvb_get_ntohs(tvb,offset); offset+=2; /* Verify the header: */ if ((ret->hlen + ret->dlen) != len) { /* Invalid header/data len -> abort */ return NULL; } /* Parse SYN (only syn flag set) */ if ((ret->flags & M_PDU_SYN) == F_SYN) { ret->pdu.syn.maxpdu = tvb_get_ntohs(tvb,offset); offset+=2; ret->pdu.syn.maxsdu = tvb_get_ntohs(tvb,offset); offset+=2; int idlen; idlen = ret->pdu.syn.idlen = tvb_get_guint8(tvb,offset); offset++; if (idlen != ret->hlen - offset) { return NULL; } guint8* id; id = wmem_alloc(wmem_packet_scope(),sizeof(guint8) * idlen + 1); int i; for (i = 0; i <idlen; i++) { id[i] = tvb_get_guint8(tvb,offset); offset++; } id[idlen] = 0; ret->pdu.syn.id = id; return ret; } /* Parse ACK PDU */ if ((ret->flags & M_PDU_ACK) == F_ACK) { if (ret->flags & F_EAK) { int eak_len; eak_len = ret->pdu.ack.eak_len = (len-CATTP_HBLEN) >> 1; ret->pdu.ack.eaks = wmem_alloc(wmem_packet_scope(),sizeof(guint8) * eak_len +1); int i; for (i = 0; i < eak_len; i++) { ret->pdu.ack.eaks[i] = tvb_get_ntohs(tvb,offset); offset+=2; } ret->pdu.ack.eaks[eak_len] = 0; } else {