Created
March 2, 2012 17:02
-
-
Save vmlemon/1959674 to your computer and use it in GitHub Desktop.
Partial PN532 dissector
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* packet-rfid-pn532.c | |
* Dissector for the NXP PN532 Protocol | |
* | |
* References: | |
* http://www.nxp.com/documents/user_manual/141520.pdf | |
* | |
* Copyright 2012, Tyson Key <tyson.key@gmail.com> | |
* | |
* $Id$ | |
* | |
* Wireshark - Network traffic analyzer | |
* By Gerald Combs <gerald@wireshark.org> | |
* Copyright 1998 Gerald Combs | |
* | |
* This program is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU General Public License | |
* as published by the Free Software Foundation; either version 2 | |
* of the License, or (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with this program; if not, write to the Free Software | |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
* | |
*/ | |
#ifdef HAVE_CONFIG_H | |
#include "config.h" | |
#endif | |
#include <glib.h> | |
#include <epan/packet.h> | |
static int proto_pn532 = -1; | |
static int hf_pn532_command = -1; | |
static int hf_pn532_direction = -1; | |
static int hf_pn532_MaxTg = -1; | |
static int hf_pn532_BrTy = -1; | |
/* Command Set (Misc) */ | |
#define DIAGNOSE 0x00 | |
#define GET_FIRMWARE_VERSION 0x02 | |
#define GET_GENERAL_STATUS 0x04 | |
#define READ_REGISTER 0x06 | |
#define WRITE_REGISTER 0x08 | |
#define READ_GPIO 0x0C | |
#define WRITE_GPIO 0x0E | |
#define SET_SERIAL_BAUD_RATE 0x10 | |
#define SET_PARAMETERS 0x12 | |
#define SAM_CONFIGURATION 0x14 | |
#define POWER_DOWN 0x16 | |
/* RF Communication Commands */ | |
#define RF_CONFIGURATION 0x32 | |
#define RF_REGULATION_TEST 0x58 | |
/* - Initiator Commands - */ | |
#define IN_JUMP_FOR_DEP 0x56 | |
#define IN_JUMP_FOR_PSL 0x46 | |
/* List targets (tags) in the field */ | |
#define IN_LIST_PASSIVE_TARGET_REQ 0x4A | |
#define IN_LIST_PASSIVE_TARGET_RSP 0x4B | |
#define IN_ATR 0x50 | |
#define IN_PSL 0x4E | |
#define IN_DATA_EXCHANGE 0x40 | |
#define IN_COMMUNICATE_THRU 0x42 | |
#define IN_DESELECT 0x44 | |
#define IN_RELEASE 0x52 | |
#define IN_SELECT 0x54 | |
#define IN_AUTO_POLL 0x60 | |
/* Target Commands */ | |
#define TG_INIT_AS_TARGET 0x8C | |
#define TG_SET_GENERAL_BYTES 0x92 | |
#define TG_GET_DATA 0x86 | |
#define TG_SET_DATA 0x8E | |
#define TG_SET_METADATA 0x94 | |
#define TG_GET_INITIATOR_CMD 0x88 | |
#define TG_RESP_TO_INITIATOR 0x90 | |
#define TG_GET_TARGET_STATUS 0x8A | |
/* TFI (Frame Identifier) Directions */ | |
#define HOST_TO_PN532 0xD4 | |
#define PN532_TO_HOST 0xD5 | |
/* Baud rate and modulation types */ | |
#define ISO_IEC_14443A_106 0x00 | |
#define FELICA_212 0x01 | |
#define FELICA_424 0x02 | |
#define ISO_IEC_14443B_106 0x03 | |
#define JEWEL_14443A_106 0x04 | |
static const value_string hf_pn532_commands[] = { | |
{DIAGNOSE, "Diagnose"}, | |
{GET_FIRMWARE_VERSION, "GetFirmwareVersion"}, | |
{GET_GENERAL_STATUS, "GetGeneralStatus"}, | |
{READ_REGISTER, "ReadRegister"}, | |
{WRITE_REGISTER, "WriteRegister"}, | |
{READ_GPIO, "ReadGPIO"}, | |
{WRITE_GPIO, "WriteGPIO"}, | |
{SET_SERIAL_BAUD_RATE, "SetSerialBaudRate"}, | |
{SET_PARAMETERS, "SetParameters"}, | |
{SAM_CONFIGURATION, "SAMConfiguration"}, | |
{POWER_DOWN, "PowerDown"}, | |
{RF_CONFIGURATION, "RFConfiguration"}, | |
{RF_REGULATION_TEST, "RFRegulationTest"}, | |
{IN_JUMP_FOR_DEP, "InJumpForDEP"}, | |
{IN_JUMP_FOR_PSL, "InJumpForPSL"}, | |
/* List tags in the proximity of the reader's field */ | |
{IN_LIST_PASSIVE_TARGET_REQ, "InListPassiveTarget"}, | |
{IN_LIST_PASSIVE_TARGET_RSP, "InListPassiveTarget"}, | |
{IN_ATR, "InATR"}, | |
{IN_PSL, "InPSL"}, | |
{IN_DATA_EXCHANGE, "InDataExchange"}, | |
{IN_COMMUNICATE_THRU, "InCommunicateThru"}, | |
{IN_DESELECT, "InDeselect"}, | |
{IN_RELEASE, "InRelease"}, | |
{IN_SELECT, "InSelect"}, | |
{IN_AUTO_POLL, "InAutoPoll"}, | |
{TG_INIT_AS_TARGET, "TgInitAsTarget"}, | |
{TG_SET_GENERAL_BYTES, "TgSetGeneralBytes"}, | |
{TG_GET_DATA, "TgGetData"}, | |
{TG_SET_DATA, "TgSetData"}, | |
{TG_SET_METADATA, "TgSetMetaData"}, | |
{TG_GET_INITIATOR_CMD, "TgGetInitiatorCommand"}, | |
{TG_RESP_TO_INITIATOR, "TgResponseToInitiator"}, | |
{TG_GET_TARGET_STATUS, "TgGetTargetStatus"}, | |
/* End of commands */ | |
{0x00, NULL} | |
}; | |
/* TFI - 1 byte frame identifier; specifying direction of communication */ | |
static const value_string hf_pn532_directions[] = { | |
{HOST_TO_PN532, "Host to PN532"}, | |
{PN532_TO_HOST, "PN532 to Host"}, | |
/* End of directions */ | |
{0x00, NULL} | |
}; | |
/* Baud rates and modulation types */ | |
static const value_string hf_pn532_brtypes[] = { | |
{ISO_IEC_14443A_106, "ISO/IEC 14443-A at 106 kbps"}, | |
{FELICA_212, "FeliCa at 212 kbps"}, | |
{FELICA_424, "FeliCa at 424 kbps"}, | |
{ISO_IEC_14443B_106, "ISO/IEC 14443-B at 106 kbps"}, | |
{JEWEL_14443A_106, "InnoVision Jewel/Topaz at 106 kbps"}, | |
/* End of directions */ | |
{0x00, NULL} | |
}; | |
static dissector_handle_t data_handle; | |
static dissector_handle_t felica_handle; | |
static dissector_table_t pn532_dissector_table; | |
/* Subtree handles: set by register_subtree_array */ | |
static gint ett_pn532 = -1; | |
static void | |
dissect_pn532(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) | |
{ | |
proto_item *item; | |
proto_tree *pn532_tree; | |
guint8 cmd; | |
tvbuff_t *next_tvb = NULL; | |
col_set_str(pinfo->cinfo, COL_PROTOCOL, "PN532"); | |
col_set_str(pinfo->cinfo, COL_INFO, "PN532 Packet"); | |
if (tree) { | |
/* Start with a top-level item to add everything else to */ | |
item = proto_tree_add_item(tree, proto_pn532, tvb, 0, -1, ENC_NA); | |
pn532_tree = proto_item_add_subtree(item, ett_pn532); | |
proto_tree_add_item(pn532_tree, hf_pn532_direction, tvb, 0, 1, ENC_NA); | |
proto_tree_add_item(pn532_tree, hf_pn532_command, tvb, 1, 1, ENC_NA); | |
/* Direction byte */ | |
cmd = tvb_get_guint8(tvb, 1); /* Command byte starts here*/ | |
switch (cmd) { | |
case DIAGNOSE: | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_key_a, tvb, 2, 6, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_uid, tvb, 8, 4, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Diagnose"); | |
break; | |
case GET_FIRMWARE_VERSION: | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_key_b, tvb, 2, 6, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_uid, tvb, 8, 4, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Get Firmware Version"); | |
break; | |
case GET_GENERAL_STATUS: | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Get General Status"); | |
break; | |
case READ_REGISTER: | |
col_set_str(pinfo->cinfo, COL_INFO, "Read Register"); | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
break; | |
case WRITE_REGISTER: | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Write Register"); | |
break; | |
case READ_GPIO: | |
// proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_operand, tvb, 2, 4, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Read GPIO"); | |
break; | |
case WRITE_GPIO: | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_operand, tvb, 2, 4, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Write GPIO"); | |
break; | |
case SET_SERIAL_BAUD_RATE: | |
//proto_tree_add_item(pn532_tree, hf_pn532_block_address, tvb, 1, 1, ENC_BIG_ENDIAN); | |
//proto_tree_add_item(pn532_tree, hf_pn532_operand, tvb, 2, 4, ENC_BIG_ENDIAN); | |
col_set_str(pinfo->cinfo, COL_INFO, "Set Serial Baud Rate"); | |
break; | |
case SET_PARAMETERS: | |
col_set_str(pinfo->cinfo, COL_INFO, "Set Parameters"); | |
break; | |
case SAM_CONFIGURATION: | |
col_set_str(pinfo->cinfo, COL_INFO, "SAM Configuration"); | |
break; | |
case POWER_DOWN: | |
col_set_str(pinfo->cinfo, COL_INFO, "Power Down"); | |
break; | |
case RF_CONFIGURATION: | |
col_set_str(pinfo->cinfo, COL_INFO, "RF Configuration"); | |
break; | |
case RF_REGULATION_TEST: | |
col_set_str(pinfo->cinfo, COL_INFO, "RF Regulation Test"); | |
break; | |
case IN_JUMP_FOR_DEP: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Jump for DEP"); | |
break; | |
case IN_JUMP_FOR_PSL: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Jump for PSL"); | |
break; | |
/* List targets (tags) in the field */ | |
case IN_LIST_PASSIVE_TARGET_REQ: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: List Passive Targets"); | |
//0dir, 1cmd | |
/* Maximum number of supported tags */ | |
proto_tree_add_item(pn532_tree, hf_pn532_MaxTg, tvb, 2, 1, ENC_BIG_ENDIAN); | |
/* Modulation and Baud Rate Type */ | |
proto_tree_add_item(pn532_tree, hf_pn532_BrTy, tvb, 3, 1, ENC_BIG_ENDIAN); | |
/* Attempt to dissect FeliCa payloads */ | |
if (tvb_get_guint8(tvb, 3) == FELICA_212 || | |
tvb_get_guint8(tvb, 3) == FELICA_424) { | |
next_tvb = tvb_new_subset_remaining(tvb, 4); | |
call_dissector(felica_handle, next_tvb, pinfo, tree); | |
} | |
break; | |
case IN_LIST_PASSIVE_TARGET_RSP: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: List Passive Targets (Response)"); | |
break; | |
case IN_ATR: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: ATR"); | |
break; | |
case IN_PSL: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: PSL"); | |
break; | |
case IN_DATA_EXCHANGE: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Data Exchance"); | |
break; | |
case IN_COMMUNICATE_THRU: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Communicate Through"); | |
break; | |
case IN_DESELECT: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Deselect"); | |
break; | |
case IN_RELEASE: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Release"); | |
break; | |
case IN_SELECT: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Select"); | |
break; | |
case IN_AUTO_POLL: | |
col_set_str(pinfo->cinfo, COL_INFO, "Initiator: Auto Poll"); | |
break; | |
case TG_INIT_AS_TARGET: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Initialise as Target"); | |
break; | |
case TG_SET_GENERAL_BYTES: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Set General Bytes"); | |
break; | |
case TG_GET_DATA: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Get Data"); | |
break; | |
case TG_SET_DATA: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Set Data"); | |
break; | |
case TG_SET_METADATA: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Set Metadata"); | |
break; | |
case TG_GET_INITIATOR_CMD: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Get Initiator Command"); | |
break; | |
case TG_RESP_TO_INITIATOR: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Response to Initiator"); | |
break; | |
case TG_GET_TARGET_STATUS: | |
col_set_str(pinfo->cinfo, COL_INFO, "Target: Get Target Status"); | |
break; | |
default: | |
col_set_str(pinfo->cinfo, COL_INFO, "Unknown"); | |
break; | |
} | |
} | |
} | |
void | |
proto_register_pn532(void) | |
{ | |
static hf_register_info hf[] = { | |
{&hf_pn532_command, | |
{ "Command", "pn532.cmd", FT_UINT8, BASE_HEX, | |
VALS(hf_pn532_commands), 0x0, NULL, HFILL }}, | |
{&hf_pn532_direction, | |
{ "Direction", "pn532.tfi", FT_UINT8, BASE_HEX, | |
VALS(hf_pn532_directions), 0x0, NULL, HFILL }}, | |
{&hf_pn532_BrTy, | |
{ "Baud Rate and Modulation", "pn532.BrTy", FT_UINT8, BASE_HEX, | |
VALS(hf_pn532_brtypes), 0x0, NULL, HFILL }}, | |
/* {&hf_pn532_block_address, | |
{ "Block Address", "pn532.block.addr", FT_UINT8, BASE_DEC, | |
NULL, 0x0, NULL, HFILL }}, | |
{&hf_pn532_key_a, | |
{ "Key A", "pn532.key.a", FT_UINT64, BASE_HEX, | |
NULL, 0x0, NULL, HFILL }}, | |
{&hf_pn532_key_b, | |
{ "Key B", "pn532.key.b", FT_UINT64, BASE_HEX, | |
NULL, 0x0, NULL, HFILL }}, | |
{&hf_pn532_uid, | |
{ "UID", "pn532.uid", FT_UINT32, BASE_HEX, | |
NULL, 0x0, NULL, HFILL }},*/ | |
{&hf_pn532_MaxTg, | |
{ "Maximum Number of Targets", "pn532.MaxTg", FT_INT8, BASE_DEC, | |
NULL, 0x0, NULL, HFILL }} | |
}; | |
static gint *ett[] = { | |
&ett_pn532 | |
}; | |
proto_pn532 = proto_register_protocol("NXP PN532", "PN532", "pn532"); | |
proto_register_field_array(proto_pn532, hf, array_length(hf)); | |
proto_register_subtree_array(ett, array_length(ett)); | |
pn532_dissector_table = register_dissector_table("pn532.payload", | |
"PN532 Payload", FT_UINT8, BASE_DEC); | |
register_dissector("pn532", dissect_pn532, proto_pn532); | |
} | |
/* Handler registration */ | |
void | |
proto_reg_handoff_pn532(void) | |
{ | |
data_handle = find_dissector("data"); | |
felica_handle = find_dissector("felica"); | |
} | |
/* | |
* Editor modelines - http://www.wireshark.org/tools/modelines.html | |
* | |
* Local variables: | |
* c-basic-offset: 4 | |
* tab-width: 8 | |
* indent-tabs-mode: nil | |
* End: | |
* | |
* ex: set shiftwidth=4 tabstop=8 expandtab: | |
* :indentSize=4:tabSize=8:noTabs=true: | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment