diff options
author | Martin Kaiser <wireshark@kaiser.cx> | 2015-11-10 08:53:31 +0100 |
---|---|---|
committer | Martin Kaiser <wireshark@kaiser.cx> | 2015-11-17 17:19:13 +0000 |
commit | 019715674e42c5d967d1c20f60581cca9fbad187 (patch) | |
tree | 9a5d920cf7da9dad5d416e3cbc7b71c0c11a95a7 /epan | |
parent | 7da8b65568966b23dad729e0ea4cbfc1b2332bb2 (diff) |
update the ISO1443 dissector
handle the ..._CRC_DROPPED events
use pinfo->p2p_dir to store the direction
pass a boolean 'crc_dropped' to the sub-dissectors for message types
subtree for an ISO1443 message
dissect most components of most messages
Change-Id: I2570dd4d941e5db7fa541723b70ccad6ce70ab49
Reviewed-on: https://code.wireshark.org/review/11912
Reviewed-by: Martin Kaiser <wireshark@kaiser.cx>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/dissectors/packet-iso14443.c | 627 |
1 files changed, 556 insertions, 71 deletions
diff --git a/epan/dissectors/packet-iso14443.c b/epan/dissectors/packet-iso14443.c index 8ded21a8f7..14a18cd7ae 100644 --- a/epan/dissectors/packet-iso14443.c +++ b/epan/dissectors/packet-iso14443.c @@ -37,26 +37,40 @@ #include "config.h" - +#include <math.h> #include <epan/packet.h> #include <epan/expert.h> +/* Proximity Integrated Circuit Card, i.e. the smartcard */ +#define ADDR_PICC "PICC" +/* Proximity Coupling Device, i.e. the card reader */ +#define ADDR_PCD "PCD" + /* event byte in the PCAP ISO14443 pseudo-header */ -#define ISO14443_EVT_DATA_PICC_TO_PCD 0xFF -#define ISO14443_EVT_DATA_PCD_TO_PICC 0xFE -#define ISO14443_EVT_FIELD_OFF 0xFD -#define ISO14443_EVT_FIELD_ON 0xFC +#define ISO14443_EVT_DATA_PICC_TO_PCD 0xFF +#define ISO14443_EVT_DATA_PCD_TO_PICC 0xFE +#define ISO14443_EVT_FIELD_OFF 0xFD +#define ISO14443_EVT_FIELD_ON 0xFC +#define ISO14443_EVT_DATA_PICC_TO_PCD_CRC_DROPPED 0xFB +#define ISO14443_EVT_DATA_PCD_TO_PICC_CRC_DROPPED 0xFA static const value_string iso14443_event[] = { { ISO14443_EVT_DATA_PICC_TO_PCD, "Data transfer PICC -> PCD" }, { ISO14443_EVT_DATA_PCD_TO_PICC, "Data transfer PCD -> PICC" }, { ISO14443_EVT_FIELD_ON, "Field on" }, { ISO14443_EVT_FIELD_OFF, "Field off" }, + { ISO14443_EVT_DATA_PICC_TO_PCD_CRC_DROPPED, + "Data transfer PICC -> PCD (CRC bytes were dropped)" }, + { ISO14443_EVT_DATA_PCD_TO_PICC_CRC_DROPPED, + "Data transfer PCD -> PICC (CRC bytes were dropped)" }, { 0, NULL } }; #define IS_DATA_TRANSFER(e) \ - ((e)==ISO14443_EVT_DATA_PICC_TO_PCD || (e)==ISO14443_EVT_DATA_PCD_TO_PICC) + ((e)==ISO14443_EVT_DATA_PICC_TO_PCD || \ + (e)==ISO14443_EVT_DATA_PCD_TO_PICC || \ + (e)==ISO14443_EVT_DATA_PICC_TO_PCD_CRC_DROPPED || \ + (e)==ISO14443_EVT_DATA_PCD_TO_PICC_CRC_DROPPED) typedef enum _iso14443_cmd_t { CMD_TYPE_WUPA, /* REQA, WUPA or ATQA */ @@ -84,7 +98,20 @@ static const value_string iso14443_short_frame[] = { { 0, NULL } }; +static const value_string iso14443_block_type[] = { + { 0x00 , "I-block" }, + { 0x02 , "R-block" }, + { 0x03 , "S-block" }, + { 0, NULL } +}; + const true_false_string tfs_wupb_reqb = { "WUPB", "REQB" }; +const true_false_string tfs_compliant_not_compliant = { "Compliant", "Not compliant" }; +const true_false_string tfs_incomplete_complete = { "Incomplete", "Complete" }; + +#define CT_BYTE 0x88 + +#define CRC_LEN 2 void proto_register_iso14443(void); void proto_reg_handoff_iso14443(void); @@ -95,6 +122,8 @@ static dissector_table_t iso14443_cmd_type_table; static int ett_iso14443 = -1; static int ett_iso14443_hdr = -1; +static int ett_iso14443_msg = -1; +static int ett_iso14443_pcb = -1; static int hf_iso14443_hdr_ver = -1; static int hf_iso14443_event = -1; @@ -102,125 +131,395 @@ static int hf_iso14443_len_field = -1; static int hf_iso14443_resp_to = -1; static int hf_iso14443_resp_in = -1; static int hf_iso14443_short_frame = -1; +static int hf_iso14443_propr_coding = -1; +static int hf_iso14443_uid_size = -1; +static int hf_iso14443_bit_frame_anticoll = -1; static int hf_iso14443_apf = -1; static int hf_iso14443_afi = -1; static int hf_iso14443_ext_atqb = -1; /* if this is present but unset, we have a REQB */ static int hf_iso14443_wupb = -1; - +static int hf_iso14443_n = -1; +static int hf_iso14443_atqb_start = -1; +static int hf_iso14443_app_data = -1; +static int hf_iso14443_proto_info = -1; +static int hf_iso14443_hlta = -1; +static int hf_iso14443_sel = -1; +static int hf_iso14443_nvb = -1; +static int hf_iso14443_4_compliant = -1; +static int hf_iso14443_uid_complete = -1; +static int hf_iso14443_ct = -1; +static int hf_iso14443_uid_cln = -1; +static int hf_iso14443_bcc = -1; +static int hf_iso14443_rats_start = -1; +static int hf_iso14443_fsdi = -1; +static int hf_iso14443_cid = -1; +static int hf_iso14443_tl = -1; +static int hf_iso14443_attrib_start = -1; +static int hf_iso14443_pupi = -1; +static int hf_iso14443_param1 = -1; +static int hf_iso14443_param2 = -1; +static int hf_iso14443_param3 = -1; +static int hf_iso14443_param4 = -1; +static int hf_iso14443_mbli = -1; +static int hf_iso14443_pcb = -1; +static int hf_iso14443_block_type = -1; +static int hf_iso14443_inf = -1; +static int hf_iso14443_crc = -1; static expert_field ei_iso14443_unknown_cmd = EI_INIT; -/* Proximity Integrated Circuit Card, i.e. the smartcard */ -#define ADDR_PICC "PICC" -/* Proximity Coupling Device, i.e. the card reader */ -#define ADDR_PCD "PCD" - -static int dissect_iso14443_cmd_type_wupa( - tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - void *data) +static int +dissect_iso14443_cmd_type_wupa(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, void *data _U_) { - guint8 direction = GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); + gint offset = 0; + guint8 uid_bits, uid_size = 0; - if (direction == ISO14443_EVT_DATA_PCD_TO_PICC) { + if (pinfo->p2p_dir == P2P_DIR_SENT) { const gchar *sf_str; sf_str = try_val_to_str( tvb_get_guint8(tvb, 0), iso14443_short_frame); proto_tree_add_item(tree, hf_iso14443_short_frame, - tvb, 0, 1, ENC_BIG_ENDIAN); - if (sf_str) + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + if (sf_str) { + proto_item_append_text(ti, ": %s", sf_str); col_set_str(pinfo->cinfo, COL_INFO, sf_str); + } } - else if (direction == ISO14443_EVT_DATA_PICC_TO_PCD) { + else if (pinfo->p2p_dir == P2P_DIR_RECV) { col_set_str(pinfo->cinfo, COL_INFO, "ATQA"); + proto_item_append_text(ti, ": ATQA"); + + proto_tree_add_item(tree, hf_iso14443_propr_coding, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + + uid_bits = (tvb_get_guint8(tvb, offset) & 0xC0) >> 6; + if (uid_bits == 0x00) + uid_size = 4; + else if (uid_bits == 0x01) + uid_size = 7; + else if (uid_bits == 0x02) + uid_size = 10; + /* XXX- expert info for invalid uid size */ + proto_tree_add_uint_bits_format_value(tree, hf_iso14443_uid_size, + tvb, offset*8, 2, uid_size, "%d", uid_size); + proto_tree_add_item(tree, hf_iso14443_bit_frame_anticoll, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; } - return tvb_captured_length(tvb); + return offset; } -static int dissect_iso14443_cmd_type_wupb( - tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, - void *data) +static int +dissect_iso14443_cmd_type_wupb(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, void *data) { - guint8 direction = GPOINTER_TO_UINT(data); + gboolean crc_dropped = (gboolean)GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); gint offset = 0; + guint8 param; + const char *msg_type; + gint rem_len; + guint8 proto_info_len = 0; - if (direction == ISO14443_EVT_DATA_PCD_TO_PICC) { - guint8 param; - + if (pinfo->p2p_dir == P2P_DIR_SENT) { proto_tree_add_item(tree, hf_iso14443_apf, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; proto_tree_add_item(tree, hf_iso14443_afi, tvb, offset, 1, ENC_BIG_ENDIAN); offset++; + param = tvb_get_guint8(tvb, offset); proto_tree_add_item(tree, hf_iso14443_ext_atqb, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_iso14443_wupb, tvb, offset, 1, ENC_BIG_ENDIAN); - col_set_str(pinfo->cinfo, COL_INFO, - (param & 0x08) ? tfs_wupb_reqb.true_string : - tfs_wupb_reqb.false_string); + msg_type = (param & 0x08) ? + tfs_wupb_reqb.true_string : tfs_wupb_reqb.false_string; + col_set_str(pinfo->cinfo, COL_INFO, msg_type); + proto_item_append_text(ti, ": %s", msg_type); + proto_tree_add_uint_bits_format_value(tree, hf_iso14443_n, + tvb, offset*8+5, 3, (guint8)pow(2, param&0x07), + "%d", (guint8)pow(2, param&0x07)); + offset++; + + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } } - else if (direction == ISO14443_EVT_DATA_PICC_TO_PCD) { + else if (pinfo->p2p_dir == P2P_DIR_RECV) { col_set_str(pinfo->cinfo, COL_INFO, "ATQB"); + proto_item_append_text(ti, ": ATQB"); + proto_tree_add_item(tree, hf_iso14443_atqb_start, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + + proto_tree_add_item(tree, hf_iso14443_pupi, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* XXX - add a subtree and dissect the components */ + proto_tree_add_item(tree, hf_iso14443_app_data, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* we should not link the protocol info length to the "extended + ATQB supported" field in the WUPB - even if the PCD supports + extended ATQB, the PICC may still send a basic one */ + rem_len = tvb_reported_length_remaining(tvb, offset); + if (!crc_dropped) { + if (rem_len == 5 || rem_len == 6) + proto_info_len = rem_len - 2; + } + else if (rem_len == 3 || rem_len == 4) + proto_info_len = rem_len; + + /* XXX - exception if (proto_info_len==0) */ + /* XXX - add a subtree and dissect the components */ + proto_tree_add_item(tree, hf_iso14443_proto_info, + tvb, offset, proto_info_len, ENC_BIG_ENDIAN); + offset += proto_info_len; + + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } } - return tvb_captured_length(tvb); + return offset; } static int dissect_iso14443_cmd_type_hlta(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree _U_, void *data _U_) + proto_tree *tree, void *data) { + gboolean crc_dropped = (gboolean)GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); + gint offset = 0; + col_set_str(pinfo->cinfo, COL_INFO, "HLTA"); + proto_item_append_text(ti, ": HLTA"); + proto_tree_add_item(tree, hf_iso14443_hlta, + tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; - return tvb_captured_length(tvb); + /* XXX - is the CRC calculation different for type A and type B? */ + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } + + return offset; +} + + +static int dissect_iso14443_uid_part( + tvbuff_t *tvb, gint offset, packet_info *pinfo _U_, proto_tree *tree) +{ + guint8 uid_len = 4; + + if (tvb_get_guint8(tvb, offset) == CT_BYTE) { + proto_tree_add_item(tree, hf_iso14443_ct, tvb, offset, 1, ENC_NA); + offset++; + uid_len = 3; + } + + proto_tree_add_item(tree, hf_iso14443_uid_cln, tvb, offset, uid_len, ENC_NA); + offset += uid_len; + proto_tree_add_item(tree, hf_iso14443_bcc, tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + + return offset; } static int dissect_iso14443_cmd_type_uid(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree _U_, void *data _U_) + proto_tree *tree, void *data) { - col_set_str(pinfo->cinfo, COL_INFO, "UID"); + gboolean crc_dropped = (gboolean)GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); + gint offset = 0; - return tvb_captured_length(tvb); + if (pinfo->p2p_dir == P2P_DIR_SENT) { + proto_tree_add_item(tree, hf_iso14443_sel, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + proto_tree_add_item(tree, hf_iso14443_nvb, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + + if (tvb_reported_length_remaining(tvb, offset) == 0) { + col_set_str(pinfo->cinfo, COL_INFO, "Anticollision"); + proto_item_append_text(ti, ": Anticollision"); + } + else { + col_set_str(pinfo->cinfo, COL_INFO, "Select"); + proto_item_append_text(ti, ": Select"); + offset = dissect_iso14443_uid_part(tvb, offset, pinfo, tree); + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } + } + } + else if (pinfo->p2p_dir == P2P_DIR_RECV) { + if (tvb_reported_length_remaining(tvb, offset) <= 3) { + col_set_str(pinfo->cinfo, COL_INFO, "SAK"); + proto_item_append_text(ti, ": SAK"); + proto_tree_add_item(tree, hf_iso14443_4_compliant, + tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(tree, hf_iso14443_uid_complete, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } + } + else if (tvb_reported_length_remaining(tvb, offset) == 5) { + col_set_str(pinfo->cinfo, COL_INFO, "UID"); + offset = dissect_iso14443_uid_part(tvb, offset, pinfo, tree); + } + } + + return offset; } -static int dissect_iso14443_cmd_type_ats( - tvbuff_t *tvb _U_, packet_info *pinfo, proto_tree *tree _U_, - void *data) +static int +dissect_iso14443_cmd_type_ats(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, void *data) { - guint8 direction = GPOINTER_TO_UINT(data); + gboolean crc_dropped = (gboolean)GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); + gint offset = 0; + guint8 fsdi, cid; + guint8 tl; - if (direction == ISO14443_EVT_DATA_PCD_TO_PICC) { + if (pinfo->p2p_dir == P2P_DIR_SENT) { col_set_str(pinfo->cinfo, COL_INFO, "RATS"); + proto_item_append_text(ti, ": RATS"); + + proto_tree_add_item(tree, hf_iso14443_rats_start, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + fsdi = tvb_get_guint8(tvb, offset) >> 4; + proto_tree_add_uint_bits_format_value(tree, hf_iso14443_fsdi, + tvb, offset*8, 4, fsdi, "%d", fsdi); + cid = tvb_get_guint8(tvb, offset) & 0x0F; + proto_tree_add_uint_bits_format_value(tree, hf_iso14443_cid, + tvb, offset*8+4, 4, cid, "%d", cid); + offset++; + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } } - else if (direction == ISO14443_EVT_DATA_PICC_TO_PCD) { + else if (pinfo->p2p_dir == P2P_DIR_RECV) { col_set_str(pinfo->cinfo, COL_INFO, "ATS"); + proto_item_append_text(ti, ": ATS"); + tl = tvb_get_guint8(tvb, offset); + proto_tree_add_item(tree, hf_iso14443_tl, + tvb, offset, 1, ENC_BIG_ENDIAN); + /* TL includes itself */ + offset += tl; + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } } - return tvb_captured_length(tvb); + return offset; } -static int dissect_iso14443_cmd_type_attrib( - tvbuff_t *tvb _U_, packet_info *pinfo, proto_tree *tree _U_, - void *data) +static int +dissect_iso14443_cmd_type_attrib(tvbuff_t *tvb, packet_info *pinfo, + proto_tree *tree, void *data) { - guint8 direction = GPOINTER_TO_UINT(data); + gboolean crc_dropped = (gboolean)GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); + gint offset = 0; + gint hl_inf_len, hl_resp_len; + guint8 mbli, cid; - if (direction == ISO14443_EVT_DATA_PCD_TO_PICC) { + if (pinfo->p2p_dir == P2P_DIR_SENT) { col_set_str(pinfo->cinfo, COL_INFO, "Attrib"); + proto_item_append_text(ti, ": Attrib"); + + proto_tree_add_item(tree, hf_iso14443_attrib_start, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + proto_tree_add_item(tree, hf_iso14443_pupi, + tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + /* XXX - subtree, details for each parameter */ + proto_tree_add_item(tree, hf_iso14443_param1, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + proto_tree_add_item(tree, hf_iso14443_param2, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + proto_tree_add_item(tree, hf_iso14443_param3, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + proto_tree_add_item(tree, hf_iso14443_param4, + tvb, offset, 1, ENC_BIG_ENDIAN); + offset++; + hl_inf_len = crc_dropped ? + tvb_reported_length_remaining(tvb, offset) : + tvb_reported_length_remaining(tvb, offset) - CRC_LEN; + if (hl_inf_len > 0) { + offset += hl_inf_len; + } + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } } - else if (direction == ISO14443_EVT_DATA_PICC_TO_PCD) { + else if (pinfo->p2p_dir == P2P_DIR_RECV) { col_set_str(pinfo->cinfo, COL_INFO, "Response to Attrib"); + proto_item_append_text(ti, ": Response to Attrib"); + + mbli = tvb_get_guint8(tvb, offset) >> 4; + proto_tree_add_uint_bits_format_value(tree, hf_iso14443_mbli, + tvb, offset*8, 4, mbli, "%d", mbli); + cid = tvb_get_guint8(tvb, offset) & 0x0F; + proto_tree_add_uint_bits_format_value(tree, hf_iso14443_cid, + tvb, offset*8+4, 4, cid, "%d", cid); + offset++; + + hl_resp_len = crc_dropped ? + tvb_reported_length_remaining(tvb, offset) : + tvb_reported_length_remaining(tvb, offset) - CRC_LEN; + if (hl_resp_len > 0) { + offset += hl_resp_len; + } + + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } } return tvb_captured_length(tvb); @@ -229,11 +528,56 @@ static int dissect_iso14443_cmd_type_attrib( static int dissect_iso14443_cmd_type_block(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree _U_, void *data _U_) + proto_tree *tree, void *data) { - col_set_str(pinfo->cinfo, COL_INFO, "Block"); + gboolean crc_dropped = (gboolean)GPOINTER_TO_UINT(data); + proto_item *ti = proto_tree_get_parent(tree); + gint offset = 0; + guint8 pcb, block_type; + const gchar *bt_str; + proto_item *pcb_ti; + proto_tree *pcb_tree; + gboolean has_cid, has_nad = FALSE; + guint8 inf_len; + + pcb = tvb_get_guint8(tvb, offset); + block_type = (pcb & 0xC0) >> 6; + bt_str = try_val_to_str(block_type, iso14443_block_type); + has_cid = ((pcb & 0x08) != 0); + if (block_type == 0x00) + has_nad = ((pcb & 0x04) != 0); + + pcb_ti = proto_tree_add_item(tree, hf_iso14443_pcb, + tvb, offset, 1, ENC_BIG_ENDIAN); + pcb_tree = proto_item_add_subtree(pcb_ti, ett_iso14443_pcb); + proto_tree_add_item(pcb_tree, hf_iso14443_block_type, + tvb, offset, 1, ENC_BIG_ENDIAN); + if (bt_str) { + proto_item_append_text(ti, ": %s", bt_str); + col_set_str(pinfo->cinfo, COL_INFO, bt_str); + } + offset++; - return tvb_captured_length(tvb); + if (has_cid) + offset++; + if (has_nad) + offset++; + + inf_len = crc_dropped ? + tvb_reported_length_remaining(tvb, offset) : + tvb_reported_length_remaining(tvb, offset) - 2; + + proto_tree_add_item(tree, hf_iso14443_inf, + tvb, offset, inf_len, ENC_NA); + offset += inf_len; + + if (!crc_dropped) { + proto_tree_add_item(tree, hf_iso14443_crc, + tvb, offset, CRC_LEN, ENC_BIG_ENDIAN); + offset += CRC_LEN; + } + + return offset; } @@ -243,17 +587,26 @@ iso14443_set_addrs(guint8 event, packet_info *pinfo) if (!IS_DATA_TRANSFER(event)) return -1; - if (event == ISO14443_EVT_DATA_PICC_TO_PCD) { + /* pinfo->p2p_dir is from the perspective of the card reader, + like in iso7816 + i.e sent is from reader to card, received is from card to reader */ + if (event == ISO14443_EVT_DATA_PCD_TO_PICC || + event == ISO14443_EVT_DATA_PCD_TO_PICC_CRC_DROPPED) { + set_address(&pinfo->src, AT_STRINGZ, - (int)strlen(ADDR_PICC)+1 , ADDR_PICC); - set_address(&pinfo->dst, AT_STRINGZ, (int)strlen(ADDR_PCD)+1, ADDR_PCD); + set_address(&pinfo->dst, AT_STRINGZ, + (int)strlen(ADDR_PICC)+1 , ADDR_PICC); + + pinfo->p2p_dir = P2P_DIR_SENT; } else { set_address(&pinfo->src, AT_STRINGZ, - (int)strlen(ADDR_PCD)+1, ADDR_PCD); - set_address(&pinfo->dst, AT_STRINGZ, (int)strlen(ADDR_PICC)+1 , ADDR_PICC); + set_address(&pinfo->dst, AT_STRINGZ, + (int)strlen(ADDR_PCD)+1, ADDR_PCD); + + pinfo->p2p_dir = P2P_DIR_RECV; } return 1; @@ -280,13 +633,13 @@ iso14443_block_pcb(guint8 byte) } -static iso14443_transaction_t *iso14443_get_transaction( - packet_info *pinfo, proto_tree *tree, guint8 direction) +static iso14443_transaction_t * +iso14443_get_transaction(packet_info *pinfo, proto_tree *tree) { proto_item *it; iso14443_transaction_t *iso14443_trans = NULL; - if (direction == ISO14443_EVT_DATA_PCD_TO_PICC) { + if (pinfo->p2p_dir == P2P_DIR_SENT) { if (PINFO_FD_VISITED(pinfo)) { iso14443_trans = (iso14443_transaction_t *)wmem_tree_lookup32( transactions, PINFO_FD_NUM(pinfo)); @@ -306,7 +659,7 @@ static iso14443_transaction_t *iso14443_get_transaction( iso14443_trans->rqst_frame, (void *)iso14443_trans); } } - else if (direction == ISO14443_EVT_DATA_PICC_TO_PCD) { + else if (pinfo->p2p_dir == P2P_DIR_RECV) { iso14443_trans = (iso14443_transaction_t *)wmem_tree_lookup32_le( transactions, PINFO_FD_NUM(pinfo)); if (iso14443_trans && iso14443_trans->resp_frame==0) { @@ -326,13 +679,13 @@ static iso14443_transaction_t *iso14443_get_transaction( static iso14443_cmd_t iso14443_get_cmd_type( - tvbuff_t *tvb, guint8 direction, iso14443_transaction_t *trans) + tvbuff_t *tvb, packet_info *pinfo, iso14443_transaction_t *trans) { guint8 first_byte; first_byte = tvb_get_guint8(tvb, 0); - if (direction == ISO14443_EVT_DATA_PCD_TO_PICC) { + if (pinfo->p2p_dir == P2P_DIR_SENT) { if (tvb_reported_length(tvb) == 1) { return CMD_TYPE_WUPA; } @@ -355,7 +708,7 @@ static iso14443_cmd_t iso14443_get_cmd_type( return CMD_TYPE_BLOCK; } } - else if (direction == ISO14443_EVT_DATA_PICC_TO_PCD) { + else if (pinfo->p2p_dir == P2P_DIR_RECV) { if (trans->cmd != CMD_TYPE_UNKNOWN) { return trans->cmd; } @@ -374,22 +727,32 @@ static iso14443_cmd_t iso14443_get_cmd_type( static gint dissect_iso14443_msg(tvbuff_t *tvb, packet_info *pinfo, - proto_tree *tree, guint8 direction) + proto_tree *tree, guint8 event) { + gboolean crc_dropped = FALSE; iso14443_transaction_t *iso14443_trans; iso14443_cmd_t cmd; + proto_tree *msg_tree; gint ret; - iso14443_trans = iso14443_get_transaction(pinfo, tree, direction); + if (event == ISO14443_EVT_DATA_PCD_TO_PICC_CRC_DROPPED || + event == ISO14443_EVT_DATA_PCD_TO_PICC_CRC_DROPPED) { + crc_dropped = TRUE; + } + + iso14443_trans = iso14443_get_transaction(pinfo, tree); if (!iso14443_trans) return -1; - cmd = iso14443_get_cmd_type(tvb, direction, iso14443_trans); + cmd = iso14443_get_cmd_type(tvb, pinfo, iso14443_trans); if (cmd != CMD_TYPE_UNKNOWN) iso14443_trans->cmd = cmd; + msg_tree = proto_tree_add_subtree( + tree, tvb, 0, -1, ett_iso14443_msg, NULL, "Message"); + ret = dissector_try_uint_new(iso14443_cmd_type_table, cmd, - tvb, pinfo, tree, FALSE, GUINT_TO_POINTER((guint)direction)); + tvb, pinfo, msg_tree, FALSE, GUINT_TO_POINTER((guint)crc_dropped)); if (ret == 0) { proto_tree_add_expert(tree, pinfo, &ei_iso14443_unknown_cmd, tvb, 0, tvb_captured_length(tvb)); @@ -495,6 +858,18 @@ proto_register_iso14443(void) { "Short frame", "iso14443.short_frame", FT_UINT8, BASE_HEX, VALS(iso14443_short_frame), 0, NULL, HFILL } }, + { &hf_iso14443_propr_coding, + { "Proprietary coding", "iso14443.propr_coding", + FT_UINT8, BASE_HEX, NULL, 0x0F, NULL, HFILL } + }, + { &hf_iso14443_uid_size, + { "UID size", "iso14443.uid_size", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_bit_frame_anticoll, + { "Bit frame anicollision", "iso14443.bit_frame_anticoll", + FT_UINT8, BASE_HEX, NULL, 0x1F, NULL, HFILL } + }, { &hf_iso14443_apf, { "Anticollision prefix", "iso14443.apf", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } @@ -510,12 +885,122 @@ proto_register_iso14443(void) { &hf_iso14443_wupb, { "WUPB/REQB", "iso14443.wupb", FT_BOOLEAN, 8, TFS(&tfs_wupb_reqb), 0x08, NULL, HFILL } + }, + { &hf_iso14443_n, + { "N", "iso14443.n", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_atqb_start, + { "Start byte", "iso14443.atqb_start", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_app_data, + { "Application data", "iso14443.application_data", + FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_proto_info, + { "Protocol info", "iso14443.protocol_info", + FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_hlta, + { "HLTA", "iso14443.hlta", + FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_sel, + { "SEL", "iso14443.sel", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_nvb, + { "NVB", "iso14443.nvb", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_4_compliant, + { "Compliant with ISO 14443-4", "iso14443.4_compliant", FT_BOOLEAN, 8, + TFS(&tfs_compliant_not_compliant), 0x20, NULL, HFILL } + }, + { &hf_iso14443_uid_complete, + { "UID complete", "iso14443.uid_complete", FT_BOOLEAN, 8, + TFS(&tfs_incomplete_complete), 0x04, NULL, HFILL } + }, + { &hf_iso14443_ct, + { "CT", "iso14443.ct", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_uid_cln, + { "UID_CLn", "iso14443.uid_cln", + FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_bcc, + { "BCC", "iso14443.bcc", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_rats_start, + { "Start byte", "iso14443.rats_start", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_fsdi, + { "FSDI", "iso14443.fsdi", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_cid, + { "CID", "iso14443.cid", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_tl, + { "Length byte TL", "iso14443.tl", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_attrib_start, + { "Start byte", "iso14443.attrib_start", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_pupi, + { "PUPI", "iso14443.pupi", + FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_param1, + { "Param 1", "iso14443.param1", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_param2, + { "Param 2", "iso14443.param2", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_param3, + { "Param 3", "iso14443.param3", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_param4, + { "Param 4", "iso14443.param4", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_mbli, + { "MBLI", "iso14443.mbli", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_pcb, + { "PCB", "iso14443.pcb", + FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_block_type, + { "Block type", "iso14443.block_type", FT_UINT8, + BASE_HEX, VALS(iso14443_block_type), 0xC0, NULL, HFILL } + }, + { &hf_iso14443_inf, + { "INF", "iso14443.inf", + FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } + }, + { &hf_iso14443_crc, + { "CRC", "iso14443.crc", + FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } } }; static gint *ett[] = { &ett_iso14443, - &ett_iso14443_hdr + &ett_iso14443_hdr, + &ett_iso14443_msg, + &ett_iso14443_pcb }; static ei_register_info ei[] = { |