/** *ZigBee Device Profile dissector for the unbind request. * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_unbind(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 version) { proto_item *ti; guint sizeof_cluster = (version >= ZBEE_VERSION_2007)?(int)sizeof(guint16):(int)sizeof(guint8); guint offset = 0; guint64 src64; /*guint8 src_ep;*/ guint32 cluster, dst_mode, dst = 0; guint64 dst64 = 0; /*guint8 dst_ep;*/ src64 = zbee_parse_eui64(tree, hf_zbee_zdp_bind_src64, tvb, &offset, (int)sizeof(guint64), NULL); proto_tree_add_item(tree, hf_zbee_zdp_bind_src_ep, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; ti = proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_cluster, tvb, offset, sizeof_cluster, ENC_LITTLE_ENDIAN, &cluster); offset += sizeof_cluster; proto_item_append_text(ti, " (%s)", rval_to_str(cluster, zbee_aps_cid_names, "Unknown Cluster")); if (version >= ZBEE_VERSION_2007) { proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_addr_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN, &dst_mode); offset += 1; } else { /* ZigBee 2003 & earlier does not have a address mode, and is unicast only. */ dst_mode = ZBEE_ZDP_ADDR_MODE_UNICAST; } if (dst_mode == ZBEE_ZDP_ADDR_MODE_GROUP) { proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_bind_dst, tvb, offset, 2, ENC_LITTLE_ENDIAN, &dst); offset += 2; } else if (dst_mode == ZBEE_ZDP_ADDR_MODE_UNICAST) { dst64 = zbee_parse_eui64(tree, hf_zbee_zdp_bind_dst64, tvb, &offset, (int)sizeof(guint64), NULL); proto_tree_add_item(tree, hf_zbee_zdp_bind_dst_ep, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; } zbee_append_info(tree, pinfo, ", %s (Cluster ID: 0x%04x)", rval_to_str(cluster, zbee_aps_cid_names, "Unknown Cluster"), cluster); if (version >= ZBEE_VERSION_2007) { zbee_append_info(tree, pinfo, " Src: %s", eui64_to_display(wmem_packet_scope(), src64)); } if (dst_mode == ZBEE_ZDP_ADDR_MODE_GROUP) { zbee_append_info(tree, pinfo, ", Dst: 0x%04x", dst); } else { zbee_append_info(tree, pinfo, ", Dst: %s", eui64_to_display(wmem_packet_scope(), dst64)); } /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_unbind */
/** *ZigBee Device Profile dissector for the store backup binding * *@param tvb pointer to buffer containing raw packet. *@param pinfo pointer to packet information fields *@param tree pointer to data tree Wireshark uses to display packet. */ void dissect_zbee_zdp_req_store_bak_bind_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint8 version) { proto_item *ti; guint sizeof_cluster = (version >= ZBEE_VERSION_2007)?(int)sizeof(guint16):(int)sizeof(guint8); guint offset = 0; guint64 src64; guint32 src_ep, cluster, dst_mode; src64 = zbee_parse_eui64(tree, hf_zbee_zdp_bind_src64, tvb, &offset, (int)sizeof(guint64), NULL); proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_bind_src_ep, tvb, offset, 1, ENC_LITTLE_ENDIAN, &src_ep); offset += 1; ti = proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_cluster, tvb, offset, sizeof_cluster, ENC_LITTLE_ENDIAN, &cluster); offset += sizeof_cluster; proto_item_append_text(ti, " (%s)", rval_to_str(cluster, zbee_aps_cid_names, "Unknown Cluster")); proto_tree_add_item_ret_uint(tree, hf_zbee_zdp_addr_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN, &dst_mode); offset += 1; if (dst_mode == ZBEE_ZDP_ADDR_MODE_GROUP) { proto_tree_add_item(tree, hf_zbee_zdp_bind_dst, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; } else if (dst_mode == ZBEE_ZDP_ADDR_MODE_UNICAST) { /*guint64 dst64;*/ /*guint8 dst_ep;*/ /*dst64 =*/ zbee_parse_eui64(tree, hf_zbee_zdp_bind_dst64, tvb, &offset, (int)sizeof(guint64), NULL); proto_tree_add_item(tree, hf_zbee_zdp_bind_dst_ep, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; } zbee_append_info(tree, pinfo, ", %s (Cluster ID: 0x%04x)", rval_to_str(cluster, zbee_aps_cid_names, "Unknown Cluster"), cluster); zbee_append_info(tree, pinfo, ", Src: %s", eui64_to_display(wmem_packet_scope(), src64)); zbee_append_info(tree, pinfo, ", Src Endpoint: %d", src_ep); /* Dump any leftover bytes. */ zdp_dump_excess(tvb, offset, pinfo, tree); } /* dissect_zbee_zdp_req_store_bak_bind_entry */
static gboolean print_field_value(field_info *finfo, int cmd_line_index) { header_field_info *hfinfo; static char *fs_buf = NULL; char *fs_ptr = fs_buf; static GString *label_s = NULL; int fs_buf_len = FIELD_STR_INIT_LEN, fs_len; guint i; string_fmt_t *sf; guint32 uvalue; gint32 svalue; const true_false_string *tfstring = &tfs_true_false; hfinfo = finfo->hfinfo; if (!fs_buf) { fs_buf = g_malloc(fs_buf_len + 1); fs_ptr = fs_buf; } if (!label_s) { label_s = g_string_new(""); } if(finfo->value.ftype->val_to_string_repr) { /* * this field has an associated value, * e.g: ip.hdr_len */ fs_len = fvalue_string_repr_len(&finfo->value, FTREPR_DFILTER); while (fs_buf_len < fs_len) { fs_buf_len *= 2; fs_buf = g_realloc(fs_buf, fs_buf_len + 1); fs_ptr = fs_buf; } fvalue_to_string_repr(&finfo->value, FTREPR_DFILTER, fs_buf); /* String types are quoted. Remove them. */ if ((finfo->value.ftype->ftype == FT_STRING || finfo->value.ftype->ftype == FT_STRINGZ) && fs_len > 2) { fs_buf[fs_len - 1] = '\0'; fs_ptr++; } } if (string_fmts->len > 0 && finfo->hfinfo->strings) { g_string_truncate(label_s, 0); for (i = 0; i < string_fmts->len; i++) { sf = g_ptr_array_index(string_fmts, i); if (sf->plain) { g_string_append(label_s, sf->plain); } else { switch (sf->format) { case SF_NAME: g_string_append(label_s, hfinfo->name); break; case SF_NUMVAL: g_string_append(label_s, fs_ptr); break; case SF_STRVAL: switch(hfinfo->type) { case FT_BOOLEAN: uvalue = fvalue_get_uinteger(&finfo->value); tfstring = (const struct true_false_string*) hfinfo->strings; g_string_append(label_s, uvalue ? tfstring->true_string : tfstring->false_string); break; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: DISSECTOR_ASSERT(!hfinfo->bitmask); svalue = fvalue_get_sinteger(&finfo->value); if (hfinfo->display & BASE_RANGE_STRING) { g_string_append(label_s, rval_to_str(svalue, hfinfo->strings, "Unknown")); } else { g_string_append(label_s, val_to_str(svalue, cVALS(hfinfo->strings), "Unknown")); } case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: uvalue = fvalue_get_uinteger(&finfo->value); if (!hfinfo->bitmask && hfinfo->display & BASE_RANGE_STRING) { g_string_append(label_s, rval_to_str(uvalue, hfinfo->strings, "Unknown")); } else { g_string_append(label_s, val_to_str(uvalue, cVALS(hfinfo->strings), "Unknown")); } break; default: break; } break; default: break; } } } printf(" %u=\"%s\"", cmd_line_index, label_s->str); return TRUE; } if(finfo->value.ftype->val_to_string_repr) { printf(" %u=\"%s\"", cmd_line_index, fs_ptr); return TRUE; } /* * This field doesn't have an associated value, * e.g. http * We return n.a. */ printf(" %u=\"n.a.\"", cmd_line_index); return TRUE; }
static gint dissect_acr122(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { proto_item *main_item; proto_tree *main_tree; proto_item *p1_item; proto_tree *p1_tree; proto_item *p2_item; proto_tree *p2_tree; proto_item *sub_item; proto_item *sub_tree; proto_item *sw2_item; proto_item *sw2_tree; gint offset = 0; guint32 value; tvbuff_t *next_tvb; guint8 acr_class; guint8 ins; guint8 p1; guint8 p2; guint8 length; guint8 command = CMD_UNKNOWN; command_data_t *command_data; usb_conv_info_t *usb_conv_info; wmem_tree_key_t key[5]; guint32 bus_id; guint32 device_address; guint32 endpoint; guint32 k_bus_id; guint32 k_device_address; guint32 k_endpoint; guint32 k_frame_number; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACR 122"); col_clear(pinfo->cinfo, COL_INFO); main_item = proto_tree_add_item(tree, proto_acr122, tvb, offset, -1, ENC_NA); main_tree = proto_item_add_subtree(main_item, ett_acr122); if (!data) return offset; usb_conv_info = (usb_conv_info_t *) data; bus_id = usb_conv_info->bus_id; device_address = usb_conv_info->device_address; endpoint = usb_conv_info->endpoint; k_bus_id = bus_id; k_device_address = device_address; k_endpoint = endpoint; k_frame_number = pinfo->fd->num; key[0].length = 1; key[0].key = &k_bus_id; key[1].length = 1; key[1].key = &k_device_address; key[2].length = 1; key[2].key = &k_endpoint; key[3].length = 1; key[3].key = &k_frame_number; key[4].length = 0; key[4].key = NULL; if (pinfo->p2p_dir == P2P_DIR_SENT) { /* Request */ acr_class = tvb_get_guint8(tvb, offset); ins = tvb_get_guint8(tvb, offset + 1); p1 = tvb_get_guint8(tvb, offset + 2); p2 = tvb_get_guint8(tvb, offset + 3); length = tvb_get_guint8(tvb, offset + 4); /* Recognize command by simple heuristic */ if (acr_class == 0xFF) { if (ins == 0xCA && p1 == 0x00 && p2 == 0x00 && length == 0) command = CMD_GET_DATA_UID; if (ins == 0xCA && p1 == 0x01 && p2 == 0x00 && length == 0) command = CMD_GET_DATA_ATS; else if (ins == 0x82 && length == 6) command = CMD_LOAD_AUTHENTICATION_KEYS; else if (ins == 0x88 && p1 == 0x00) command = CMD_AUTHENTICATION_OBSOLETE; else if (ins == 0x86 && p1 == 0x00 && p2 == 0x00 && length == 5) command = CMD_AUTHENTICATION; else if (ins == 0xB0 && p1 == 0x00) command = CMD_READ_BINARY_BLOCKS; else if (ins == 0xD6 && p1 == 0x00) command = CMD_UPDATE_BINARY_BLOCKS; else if (ins == 0xD7 && p1 == 0x00 && length == 5) command = CMD_VALUE_BLOCK_OPERATION; else if (ins == 0xB1 && p1 == 0x00 && length == 4) command = CMD_READ_VALUE_BLOCK; else if (ins == 0xD7 && p1 == 0x00 && length == 2) command = CMD_RESTORE_VALUE_BLOCK; else if (ins == 0x00 && p1 == 0x00 && p2 == 0x00) command = CMD_DIRECT_TRANSMIT; else if (ins == 0x00 && p1 == 0x40 && length == 4) command = CMD_BI_COLOR_AND_BUZZER_LED_CONTROL; else if (ins == 0x00 && p1 == 0x48 && p2 == 0x00) command = CMD_GET_FIRMWARE_VERSION; else if (ins == 0x00 && p1 == 0x50 && p2 == 0x00) command = CMD_GET_PICC_OPERATING_PARAMETER; else if (ins == 0x00 && p1 == 0x51 && length == 0) command = CMD_SET_PICC_OPERATING_PARAMETER; else if (ins == 0x00 && p1 == 0x41 && length == 0) command = CMD_SET_TIMEOUT_PARAMETER; else if (ins == 0x00 && p1 == 0x52 && length == 0) command = CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION; } sub_item = proto_tree_add_uint(main_tree, hf_command, tvb, offset, 4 + length, command); PROTO_ITEM_SET_GENERATED(sub_item); if (command == CMD_UNKNOWN) proto_tree_add_expert(sub_item, pinfo, &ei_unknown_command_or_invalid_parameters, tvb, offset, 4 + length); col_add_fstr(pinfo->cinfo, COL_INFO, "Command: %s", val_to_str_const(command, command_vals, "Unknown")); proto_tree_add_item(main_tree, hf_class, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(main_tree, hf_ins, tvb, offset, 1, ENC_NA); offset += 1; p1_item = proto_tree_add_item(main_tree, hf_p1, tvb, offset, 1, ENC_NA); offset += 1; p2_item = proto_tree_add_item(main_tree, hf_p2, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(main_tree, hf_length, tvb, offset, 1, ENC_NA); offset += 1; switch (command) { case CMD_DIRECT_TRANSMIT: if (length > 0) { next_tvb = tvb_new_subset(tvb, offset, length, length); call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info); offset += length; } break; case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_led_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_green_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_red_mask, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_initial_green_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_initial_red_blinking_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_final_green_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_led_final_red_state, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_led_t1_duration, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_led_t2_duration, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_led_number_of_repetition, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_led_link_to_buzzer, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_GET_DATA_UID: case CMD_GET_DATA_ATS: /* Nothing to decode */ break; case CMD_LOAD_AUTHENTICATION_KEYS: p1_tree = proto_item_add_subtree(p1_item, ett_p1_item); proto_tree_add_item(p1_tree, hf_key_structure, tvb, offset - 3, 1, ENC_BIG_ENDIAN); p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_key_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_key, tvb, offset, 6, ENC_NA); offset += 6; break; case CMD_AUTHENTICATION_OBSOLETE: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_AUTHENTICATION: proto_tree_add_item(main_tree, hf_version, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; proto_tree_add_item(main_tree, hf_block_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_key_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_key_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_READ_BINARY_BLOCKS: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_UPDATE_BINARY_BLOCKS: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); offset += length; break; case CMD_VALUE_BLOCK_OPERATION: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_vb_op, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; break; case CMD_READ_VALUE_BLOCK: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_RESTORE_VALUE_BLOCK: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_source_block_number, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(main_tree, hf_static_byte, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; proto_tree_add_item(main_tree, hf_target_block_number, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; break; case CMD_SET_PICC_OPERATING_PARAMETER: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_picc_operating_auto_picc_polling, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_auto_ats_generation, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_polling_interval, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_felica_424k, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_felica_212k, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_topaz, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(p2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_SET_TIMEOUT_PARAMETER: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_timeout, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION: p2_tree = proto_item_add_subtree(p2_item, ett_p2_item); proto_tree_add_item(p2_tree, hf_poll_buzzer_status, tvb, offset - 2, 1, ENC_BIG_ENDIAN); break; case CMD_GET_PICC_OPERATING_PARAMETER: /* No parameters */ break; } if (!pinfo->fd->flags.visited) { command_data = wmem_new(wmem_file_scope(), command_data_t); command_data->bus_id = bus_id; command_data->device_address = device_address; command_data->endpoint = endpoint; command_data->command = command; command_data->command_frame_number = pinfo->fd->num; command_data->response_frame_number = 0; wmem_tree_insert32_array(command_info, key, command_data); } } else { /* Response */ guint32 command_frame_number = 0; gboolean use_status_word = FALSE; wmem_tree_t *wmem_tree; 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, pinfo->fd->num); if (command_data && (command_data->response_frame_number == 0 || command_data->response_frame_number == pinfo->fd->num)) { command = command_data->command; command_frame_number = command_data->command_frame_number; if (!pinfo->fd->flags.visited && command_data->response_frame_number == 0) { command_data->response_frame_number = pinfo->fd->num; } } } sub_item = proto_tree_add_uint(main_tree, hf_response, tvb, offset, tvb_length_remaining(tvb, offset), command); PROTO_ITEM_SET_GENERATED(sub_item); col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s", val_to_str_const(command, command_vals, "Unknown")); if (command != CMD_UNKNOWN) { sub_item = proto_tree_add_uint(main_tree, hf_response_for, tvb, offset, tvb_length_remaining(tvb, offset), command_frame_number); PROTO_ITEM_SET_GENERATED(sub_item); } switch (command) { case CMD_GET_FIRMWARE_VERSION: proto_tree_add_item(main_tree, hf_firmware_version, tvb, offset, -1, ENC_NA | ENC_ASCII); offset += tvb_length_remaining(tvb, offset); break; case CMD_DIRECT_TRANSMIT: use_status_word = TRUE; if (tvb_length_remaining(tvb, offset) > 2) { next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset) - 2, tvb_length_remaining(tvb, offset) - 2); call_dissector_with_data(pn532_handle, next_tvb, pinfo, tree, usb_conv_info); offset += tvb_length_remaining(tvb, offset) - 2; } break; case CMD_READ_BINARY_BLOCKS: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_data, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA); offset += tvb_length_remaining(tvb, offset) - 2; break; case CMD_READ_VALUE_BLOCK: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_value, tvb, offset, 4, ENC_BIG_ENDIAN); break; case CMD_GET_DATA_UID: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_uid, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA); offset += tvb_length_remaining(tvb, offset) - 2; break; case CMD_GET_DATA_ATS: use_status_word = TRUE; proto_tree_add_item(main_tree, hf_ats, tvb, offset, tvb_length_remaining(tvb, offset) - 2, ENC_NA); offset += tvb_length_remaining(tvb, offset) - 2; break; case CMD_BI_COLOR_AND_BUZZER_LED_CONTROL: case CMD_LOAD_AUTHENTICATION_KEYS: case CMD_AUTHENTICATION: case CMD_AUTHENTICATION_OBSOLETE: case CMD_UPDATE_BINARY_BLOCKS: case CMD_VALUE_BLOCK_OPERATION: case CMD_RESTORE_VALUE_BLOCK: case CMD_SET_TIMEOUT_PARAMETER: case CMD_SET_BUZZER_OUTPUT_FOR_CARD_DETECTION: case CMD_SET_PICC_OPERATING_PARAMETER: case CMD_GET_PICC_OPERATING_PARAMETER: default: use_status_word = TRUE; break; } if (use_status_word) { value = tvb_get_ntohs(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " - %s%s", (((value & 0xFF00) != 0x9000) && (value & 0xFF00) != 0x6100) ? "Error: " : "", rval_to_str(value, status_word_rvals, "Unknown error")); if ((value & 0xFF00) == 0x6100) col_append_fstr(pinfo->cinfo, COL_INFO, " - Length %u", value & 0x00FF); sub_item = proto_tree_add_item(main_tree, hf_status_word, tvb, offset, 2, ENC_BIG_ENDIAN); sub_tree = proto_item_add_subtree(sub_item, ett_status_word); proto_tree_add_item(sub_tree, hf_status_word_sw1, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; sw2_item = proto_tree_add_item(sub_tree, hf_status_word_sw2, tvb, offset, 1, ENC_BIG_ENDIAN); if (command == CMD_BI_COLOR_AND_BUZZER_LED_CONTROL) { sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2); col_append_fstr(pinfo->cinfo, COL_INFO, " - Red LED: %s, Green LED: %s", (value & 0x02) ? "On" : "Off", (value & 0x01) ? "On" : "Off"); proto_tree_add_item(sw2_tree, hf_status_word_led_reserved, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_status_word_led_green, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_status_word_led_red, tvb, offset, 1, ENC_BIG_ENDIAN); } else if (command == CMD_SET_PICC_OPERATING_PARAMETER || command == CMD_GET_PICC_OPERATING_PARAMETER) { sw2_tree = proto_item_add_subtree(sw2_item, ett_status_word_sw2); proto_tree_add_item(sw2_tree, hf_picc_operating_auto_picc_polling, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_auto_ats_generation, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_polling_interval, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_felica_424k, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_felica_212k, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_topaz, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_b, tvb, offset - 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(sw2_tree, hf_picc_operating_iso_14443_type_a, tvb, offset - 2, 1, ENC_BIG_ENDIAN); } offset += 1; } } return offset; }
/* G.7041 6.1.2 GFP payload area */ static void dissect_gfp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *gfp_tree, guint *offset, guint payload_len) { tvbuff_t *payload_tvb; proto_item *type_ti = NULL; proto_item *fcs_ti; proto_tree *fcs_tree = NULL; guint pti, pfi, exi, upi; guint fcs, fcs_calc; guint fcs_len = 0; /* G.7041 6.1.2.3 Payload area scrambling * Note that payload when sent on the wire is scrambled as per ATM * with a 1 + x^43 multiplicative scrambler. Likely already removed by * the time we get a capture file (as with ATM). Could have a pref, * but if it's present we have to save state over subsequent frames, * always would fail to decode the first 43 payload bytes of a capture. */ /* G.7041 6.1.2.1 Payload Header - at least 4 bytes */ tvb_ensure_bytes_exist(tvb, *offset, 4); payload_len -= 4; /* G.7041 6.1.2.1.1 GFP type field - mandatory 2 bytes */ pti = tvb_get_bits8(tvb, 8*(*offset), 3); pfi = tvb_get_bits8(tvb, 8*(*offset)+3, 1); exi = tvb_get_bits8(tvb, 8*(*offset)+4, 4); upi = tvb_get_guint8(tvb, *offset+1); p_add_proto_data(pinfo->pool, pinfo, proto_gfp, 0, GUINT_TO_POINTER(upi)); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pti, gfp_pti_vals, "Reserved PTI (%d)")); if (pti == GFP_USER_DATA || pti == GFP_MANAGEMENT_COMMUNICATIONS) { /* G.7041 Table 6-3 - GFP_MANAGEMENT_COMMUNICATIONS * uses the same UPI table as USER_DATA, though * "not all of these UPI types are applicable" in that case. */ type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, ett_gfp_type, gfp_type_data_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str(upi, gfp_upi_data_rvals, "Unknown 0x%02x")); } else if (pti == GFP_CLIENT_MANAGEMENT) { /* G.7041 Table 6-4 */ type_ti = proto_tree_add_bitmask_with_flags(gfp_tree, tvb, *offset, hf_gfp_type, ett_gfp_type, gfp_type_management_fields, ENC_BIG_ENDIAN, BMT_NO_FLAGS); col_append_sep_str(pinfo->cinfo, COL_INFO, ": ", rval_to_str(upi, gfp_upi_management_rvals, "Unknown 0x%02x")); } /* G.7041 6.1.2.1.2 Type HEC (tHEC) - mandatory 2 bytes */ gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_thec, hf_gfp_thec_status, &ei_gfp_thec_bad); switch (exi) { case GFP_EXT_NULL: /* G.7041 6.1.2.1.3.1 Null extension header */ break; case GFP_EXT_LINEAR: /* G.7041 6.1.2.1.3.2 Extension header for a linear frame */ if (payload_len < 4) { expert_add_info(pinfo, type_ti, &ei_gfp_exi_short); payload_len = 0; } else { payload_len -= 4; } proto_tree_add_item(gfp_tree, hf_gfp_cid, tvb, *offset, 1, ENC_BIG_ENDIAN); /* Next byte spare field, reserved */ /* 6.1.2.1.4 Extension HEC field */ gfp_add_hec_tree(tvb, pinfo, gfp_tree, offset, 2, hf_gfp_ehec, hf_gfp_ehec_status, &ei_gfp_ehec_bad); break; case GFP_EXT_RING: /* 6.1.2.1.3.3 Extension header for a ring frame */ /* "For further study." Undefined so fall through */ default: /* Reserved */ /* TODO: Mark as error / unhandled? */ break; } proto_item_set_end(gfp_tree, tvb, *offset); if (pfi == 1) { /* 6.1.2.2.1 Payload FCS field present */ if (payload_len < 4) { expert_add_info(pinfo, type_ti, &ei_gfp_pfi_short); fcs_len = payload_len; payload_len = 0; } else { fcs_len = 4; payload_len -= 4; } proto_tree_set_appendix(gfp_tree, tvb, *offset + payload_len, fcs_len); fcs = tvb_get_ntohl(tvb, *offset + payload_len); /* Same CRC32 as ATM */ /* As with ATM, we can either compute the CRC as it would be * calculated and compare (last step involves taking the complement), * or we can include the passed CRC in the input and check to see * if the remainder is a known value. I like the first method * only because it lets us display what we should have received. */ /* Method 1: */ fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len); if (fcs == ~fcs_calc) { fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [correct]", fcs); fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, TRUE); PROTO_ITEM_SET_GENERATED(fcs_ti); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, FALSE); PROTO_ITEM_SET_GENERATED(fcs_ti); } else { fcs_ti = proto_tree_add_uint_format_value(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs, "0x%08x [incorrect, should be 0x%08x]", fcs, fcs_calc); fcs_tree = proto_item_add_subtree(fcs_ti, ett_gfp_fcs); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_good, tvb, *offset+payload_len, 4, FALSE); PROTO_ITEM_SET_GENERATED(fcs_ti); fcs_ti = proto_tree_add_boolean(fcs_tree, hf_gfp_fcs_bad, tvb, *offset+payload_len, 4, TRUE); PROTO_ITEM_SET_GENERATED(fcs_ti); expert_add_info(pinfo, fcs_ti, &ei_gfp_fcs_bad); } /* Method 2: */ /* fcs_calc = crc32_mpeg2_tvb_offset(tvb, *offset, payload_len+4); fcs_ti = proto_tree_add_uint(gfp_tree, hf_gfp_fcs, tvb, *offset+payload_len, 4, fcs); proto_item_append_text(fcs_ti, (fcs_calc == 0xC704DD7B) ? " [correct]" : " [incorrect]"); */ } /* Some client frames we can do. Others are not implemented yet. * Transparent mode types are much trickier than frame-mapped, * since they requires reassembling streams across multiple GFP packets. */ payload_tvb = tvb_new_subset_length(tvb, *offset, payload_len); switch (pti) { case GFP_USER_DATA: case GFP_MANAGEMENT_COMMUNICATIONS: if (!dissector_try_uint(gfp_dissector_table, upi, payload_tvb, pinfo, tree)) { expert_add_info_format(pinfo, type_ti, &ei_gfp_payload_undecoded, "Payload type 0x%02x (%s) unsupported", upi, rval_to_str_const(upi, gfp_upi_data_rvals, "UNKNOWN")); call_data_dissector(payload_tvb, pinfo, tree); } break; case GFP_CLIENT_MANAGEMENT: call_data_dissector(payload_tvb, pinfo, tree); break; default: break; } *offset += payload_len; *offset += fcs_len; }