Skip to content

Instantly share code, notes, and snippets.

@vmlemon
Created March 2, 2012 17:02
Show Gist options
  • Save vmlemon/1959674 to your computer and use it in GitHub Desktop.
Save vmlemon/1959674 to your computer and use it in GitHub Desktop.
Partial PN532 dissector
/* 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