From 05c7e304271bcf88901da3782fcd3f28a0c7c9cf Mon Sep 17 00:00:00 2001 From: laforge Date: Tue, 8 Nov 2005 08:34:15 +0000 Subject: use autoconf/automake git-svn-id: https://svn.gnumonks.org/trunk/librfid@1658 e0336214-984f-0b4b-a45f-81c69e1f0ede --- src/Makefile.am | 13 + src/rc632.h | 214 ++++++ src/rfid.c | 56 ++ src/rfid_asic_rc632.c | 1295 ++++++++++++++++++++++++++++++++++ src/rfid_asic_rc632_14443a.c | 394 +++++++++++ src/rfid_asic_rc632_14443b.c | 69 ++ src/rfid_asic_rc632_mifare.c | 25 + src/rfid_iso14443_common.c | 58 ++ src/rfid_iso14443_common.h | 11 + src/rfid_layer2.c | 76 ++ src/rfid_layer2_iso14443a.c | 294 ++++++++ src/rfid_layer2_iso14443b.c | 344 +++++++++ src/rfid_layer2_iso15693.c | 302 ++++++++ src/rfid_proto_mifare_classic.c | 148 ++++ src/rfid_proto_mifare_ul.c | 162 +++++ src/rfid_proto_tcl.c | 694 ++++++++++++++++++ src/rfid_protocol.c | 113 +++ src/rfid_reader.c | 65 ++ src/rfid_reader_cm5121.c | 337 +++++++++ src/rfid_reader_cm5121_ccid_direct.c | 36 + src/rfid_reader_cm5121_openct.c | 59 ++ 21 files changed, 4765 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/rc632.h create mode 100644 src/rfid.c create mode 100644 src/rfid_asic_rc632.c create mode 100644 src/rfid_asic_rc632_14443a.c create mode 100644 src/rfid_asic_rc632_14443b.c create mode 100644 src/rfid_asic_rc632_mifare.c create mode 100644 src/rfid_iso14443_common.c create mode 100644 src/rfid_iso14443_common.h create mode 100644 src/rfid_layer2.c create mode 100644 src/rfid_layer2_iso14443a.c create mode 100644 src/rfid_layer2_iso14443b.c create mode 100644 src/rfid_layer2_iso15693.c create mode 100644 src/rfid_proto_mifare_classic.c create mode 100644 src/rfid_proto_mifare_ul.c create mode 100644 src/rfid_proto_tcl.c create mode 100644 src/rfid_protocol.c create mode 100644 src/rfid_reader.c create mode 100644 src/rfid_reader_cm5121.c create mode 100644 src/rfid_reader_cm5121_ccid_direct.c create mode 100644 src/rfid_reader_cm5121_openct.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..2f35d9b --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,13 @@ +LIBVERSION= 0:0:0 +INCLUDES = $(all_includes) -I$(top_srcdir)/include + +lib_LTLIBRARIES = librfid.la + +CORE=rfid.c rfid_layer2.c rfid_protocol.c rfid_reader.c +L2=rfid_layer2_iso14443a.c rfid_layer2_14443b.c rfid_layer2_iso15693.c rfid_iso14443_common.o +PROTO=rfid_proto_tcl.c rfid_proto_mifare_ul.c rfid_proto_mifare_classic.c +READER=rfid_reader_cm5121.c rfid_asic_rc632.c + +librfid_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION) +librfid_la_SOURCES = $(CORE) $(L2) $(PROTO) $(READER) + diff --git a/src/rc632.h b/src/rc632.h new file mode 100644 index 0000000..4ad0e99 --- /dev/null +++ b/src/rc632.h @@ -0,0 +1,214 @@ +/* Register definitions for Philips CL RC632 RFID Reader IC + * + * (C) 2005 Harald Welte + * + * Licensed under GNU General Public License, Version 2 + */ + +enum rc632_registers { + RC632_REG_PAGE0 = 0x00, + RC632_REG_COMMAND = 0x01, + RC632_REG_FIFO_DATA = 0x02, + RC632_REG_PRIMARY_STATUS = 0x03, + RC632_REG_FIFO_LENGTH = 0x04, + RC632_REG_SECONDARY_STATUS = 0x05, + RC632_REG_INTERRUPT_EN = 0x06, + RC632_REG_INTERRUPT_RQ = 0x07, + + RC632_REG_PAGE1 = 0x08, + RC632_REG_CONTROL = 0x09, + RC632_REG_ERROR_FLAG = 0x0a, + RC632_REG_COLL_POS = 0x0b, + RC632_REG_TIMER_VALUE = 0x0c, + RC632_REG_CRC_RESULT_LSB = 0x0d, + RC632_REG_CRC_RESULT_MSB = 0x0e, + RC632_REG_BIT_FRAMING = 0x0f, + + RC632_REG_PAGE2 = 0x10, + RC632_REG_TX_CONTROL = 0x11, + RC632_REG_CW_CONDUCTANCE = 0x12, + RC632_REG_MOD_CONDUCTANCE = 0x13, + RC632_REG_CODER_CONTROL = 0x14, + RC632_REG_MOD_WIDTH = 0x15, + RC632_REG_MOD_WIDTH_SOF = 0x16, + RC632_REG_TYPE_B_FRAMING = 0x17, + + RC632_REG_PAGE3 = 0x18, + RC632_REG_RX_CONTROL1 = 0x19, + RC632_REG_DECODER_CONTROL = 0x1a, + RC632_REG_BIT_PHASE = 0x1b, + RC632_REG_RX_THRESHOLD = 0x1c, + RC632_REG_BPSK_DEM_CONTROL = 0x1d, + RC632_REG_RX_CONTROL2 = 0x1e, + RC632_REG_CLOCK_Q_CONTROL = 0x1f, + + RC632_REG_PAGE4 = 0x20, + RC632_REG_RX_WAIT = 0x21, + RC632_REG_CHANNEL_REDUNDANCY = 0x22, + RC632_REG_CRC_PRESET_LSB = 0x23, + RC632_REG_CRC_PRESET_MSB = 0x24, + RC632_REG_TIME_SLOT_PERIOD = 0x25, + RC632_REG_MFOUT_SELECT = 0x26, + RC632_REG_PRESET_27 = 0x27, + + RC632_REG_PAGE5 = 0x28, + RC632_REG_FIFO_LEVEL = 0x29, + RC632_REG_TIMER_CLOCK = 0x2a, + RC632_REG_TIMER_CONTROL = 0x2b, + RC632_REG_TIMER_RELOAD = 0x2c, + RC632_REG_IRQ_PIN_CONFIG = 0x2d, + RC632_REG_PRESET_2E = 0x2e, + RC632_REG_PRESET_2F = 0x2f, + + RC632_REG_PAGE6 = 0x30, + + RC632_REG_PAGE7 = 0x38, + RC632_REG_TEST_ANA_SELECT = 0x3a, + RC632_REG_TEST_DIGI_SELECT = 0x3d, +}; + +enum rc632_reg_command { + RC632_CMD_IDLE = 0x00, + RC632_CMD_WRITE_E2 = 0x01, + RC632_CMD_READ_E2 = 0x03, + RC632_CMD_LOAD_CONFIG = 0x07, + RC632_CMD_LOAD_KEY_E2 = 0x0b, + RC632_CMD_AUTHENT1 = 0x0c, + RC632_CMD_CALC_CRC = 0x12, + RC632_CMD_AUTHENT2 = 0x14, + RC632_CMD_RECEIVE = 0x16, + RC632_CMD_LOAD_KEY = 0x19, + RC632_CMD_TRANSMIT = 0x1a, + RC632_CMD_TRANSCIEVE = 0x1e, + RC632_CMD_STARTUP = 0x3f, +}; + +enum rc632_reg_control { + RC632_CONTROL_CRYPTO1_ON = 0x08, + RC632_CONTROL_POWERDOWN = 0x10, +}; + +enum rc632_reg_error_flag { + RC632_ERR_FLAG_COL_ERR = 0x01, + RC632_ERR_FLAG_PARITY_ERR = 0x02, + RC632_ERR_FLAG_FRAMING_ERR = 0x04, + RC632_ERR_FLAG_CRC_ERR = 0x08, + RC632_ERR_FLAG_FIFO_OVERFLOW = 0x10, + RC632_ERR_FLAG_ACCESS_ERR = 0x20, + RC632_ERR_FLAG_KEY_ERR = 0x40, +}; + +enum rc632_reg_tx_control { + RC632_TXCTRL_TX1_RF_EN = 0x01, + RC632_TXCTRL_TX2_RF_EN = 0x02, + RC632_TXCTRL_TX2_CW = 0x04, + RC632_TXCTRL_TX2_INV = 0x08, + RC632_TXCTRL_FORCE_100_ASK = 0x10, + + RC632_TXCTRL_MOD_SRC_LOW = 0x00, + RC632_TXCTRL_MOD_SRC_HIGH = 0x20, + RC632_TXCTRL_MOD_SRC_INT = 0x40, + RC632_TXCTRL_MOD_SRC_MFIN = 0x60, +}; + +enum rc632_reg_coder_control { + RC632_CDRCTRL_TXCD_NRZ = 0x00, + RC632_CDRCTRL_TXCD_14443A = 0x01, + RC632_CDRCTRL_TXCD_ICODE_STD = 0x04, + + RC632_CDRCTRL_RATE_848K = 0x00, +#if 0 + /* See mc073930.pdf, page 41 */ + RC632_CDRCTRL_RATE_424K = 0x80, +#else + RC632_CDRCTRL_RATE_424K = 0x08, +#endif + RC632_CDRCTRL_RATE_212K = 0x10, + RC632_CDRCTRL_RATE_106K = 0x18, + RC632_CDRCTRL_RATE_14443B = 0x20, + RC632_CDRCTRL_RATE_15693 = 0x28, + RC632_CDRCTRL_RATE_ICODE_FAST = 0x30, +}; + +enum rc632_erg_type_b_framing { + RC632_TBFRAMING_SOF_10L_2H = 0x00, + RC632_TBFRAMING_SOF_10L_3H = 0x01, + RC632_TBFRAMING_SOF_11L_2H = 0x02, + RC632_TBFRAMING_SOF_11L_3H = 0x03, + + RC632_TBFRAMING_EOF_10 = 0x00, + RC632_TBFRAMING_EOF_11 = 0x20, + + RC632_TBFRAMING_NO_TX_SOF = 0x80, + RC632_TBFRAMING_NO_TX_EOF = 0x40, +}; +#define RC632_TBFRAMING_SPACE_SHIFT 2 +#define RC632_TBFRAMING_SPACE_MASK 7 + +enum rc632_reg_rx_control1 { + RC632_RXCTRL1_GAIN_20DB = 0x00, + RC632_RXCTRL1_GAIN_24DB = 0x01, + RC632_RXCTRL1_GAIN_31DB = 0x02, + RC632_RXCTRL1_GAIN_35DB = 0x03, + + RC632_RXCTRL1_LP_OFF = 0x04, + RC632_RXCTRL1_ISO15693 = 0x08, + RC632_RXCTRL1_ISO14443 = 0x10, + + RC632_RXCTRL1_SUBCP_1 = 0x00, + RC632_RXCTRL1_SUBCP_2 = 0x20, + RC632_RXCTRL1_SUBCP_4 = 0x40, + RC632_RXCTRL1_SUBCP_8 = 0x60, + RC632_RXCTRL1_SUBCP_16 = 0x80, +}; + +enum rc632_reg_decoder_control { + RC632_DECCTRL_MANCHESTER = 0x00, + RC632_DECCTRL_BPSK = 0x01, + + RC632_DECCTRL_RX_INVERT = 0x04, + + RC632_DECCTRL_RXFR_ICODE = 0x00, + RC632_DECCTRL_RXFR_14443A = 0x08, + RC632_DECCTRL_RXFR_15693 = 0x10, + RC632_DECCTRL_RXFR_14443B = 0x18, + + RC632_DECCTRL_ZEROAFTERCOL = 0x20, + + RC632_DECCTRL_RX_MULTIPLE = 0x40, +}; + +enum rc632_reg_bpsk_dem_control { + RC632_BPSKD_TAUB_SHIFT = 0x00, + RC632_BPSKD_TAUB_MASK = 0x03, + + RC632_BPSKD_TAUD_SHIFT = 0x02, + RC632_BPSKD_TAUD_MASK = 0x03, + + RC632_BPSKD_FILTER_AMP_DETECT = 0x10, + RC632_BPSKD_NO_RX_EOF = 0x20, + RC632_BPSKD_NO_RX_EGT = 0x40, + RC632_BPSKD_NO_RX_SOF = 0x80, +}; + +enum rc632_reg_rx_control2 { + RC632_RXCTRL2_DECSRC_LOW = 0x00, + RC632_RXCTRL2_DECSRC_INT = 0x01, + RC632_RXCTRL2_DECSRC_SUBC_MFIN = 0x10, + RC632_RXCTRL2_DECSRC_BASE_MFIN = 0x11, + + RC632_RXCTRL2_AUTO_PD = 0x40, + RC632_RXCTRL2_CLK_I = 0x80, + RC632_RXCTRL2_CLK_Q = 0x00, +}; + +enum rc632_reg_channel_redundancy { + RC632_CR_PARITY_ENABLE = 0x01, + RC632_CR_PARITY_ODD = 0x02, + RC632_CR_TX_CRC_ENABLE = 0x04, + RC632_CR_RX_CRC_ENABLE = 0x08, + RC632_CR_CRC8 = 0x10, + RC632_CR_CRC3309 = 0x20, +}; + + diff --git a/src/rfid.c b/src/rfid.c new file mode 100644 index 0000000..be72f12 --- /dev/null +++ b/src/rfid.c @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ +#include +#include + +#include +#include +#include +#include +#include + +const char * +rfid_hexdump(const void *data, unsigned int len) +{ + static char string[1024]; + unsigned char *d = (unsigned char *) data; + unsigned int i, left; + + string[0] = '\0'; + left = sizeof(string); + for (i = 0; len--; i += 3) { + if (i >= sizeof(string) -4) + break; + snprintf(string+i, 4, " %02x", *d++); + } + return string; +} + +int rfid_init() +{ + rfid_reader_register(&rfid_reader_cm5121); + rfid_layer2_register(&rfid_layer2_iso14443a); + rfid_layer2_register(&rfid_layer2_iso14443b); + rfid_protocol_register(&rfid_protocol_tcl); + rfid_protocol_register(&rfid_protocol_mful); + rfid_protocol_register(&rfid_protocol_mfcl); + + return 0; +} + +void rfid_fini() +{ + /* FIXME: implementation */ +} diff --git a/src/rfid_asic_rc632.c b/src/rfid_asic_rc632.c new file mode 100644 index 0000000..4377d73 --- /dev/null +++ b/src/rfid_asic_rc632.c @@ -0,0 +1,1295 @@ +/* Generic Philips CL RC632 Routines + * + * (C) Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "rfid_iso14443_common.h" +#include "rc632.h" +//#include "rc632_14443a.h" + + +#define RC632_TMO_AUTH1 14000 + +#define ENTER() DEBUGP("entering\n") +struct rfid_asic rc632; + +/* Register and FIFO Access functions */ +static int +rc632_reg_write(struct rfid_asic_handle *handle, + u_int8_t reg, + u_int8_t val) +{ + return handle->rath->rat->priv.rc632.fn.reg_write(handle->rath, reg, val); +} + +static int +rc632_reg_read(struct rfid_asic_handle *handle, + u_int8_t reg, + u_int8_t *val) +{ + return handle->rath->rat->priv.rc632.fn.reg_read(handle->rath, reg, val); +} + +static int +rc632_fifo_write(struct rfid_asic_handle *handle, + u_int8_t len, + const u_int8_t *buf, + u_int8_t flags) +{ + return handle->rath->rat->priv.rc632.fn.fifo_write(handle->rath, + len, buf, flags); +} + +static int +rc632_fifo_read(struct rfid_asic_handle *handle, + u_int8_t len, + u_int8_t *buf) +{ + return handle->rath->rat->priv.rc632.fn.fifo_read(handle->rath, len, buf); +} + + +static int +rc632_set_bits(struct rfid_asic_handle *handle, + u_int8_t reg, + u_int8_t val) +{ + int ret; + u_int8_t tmp; + + ret = rc632_reg_read(handle, reg, &tmp); + if (ret < 0) + return -1; + + /* if bits are already set, no need to set them again */ + if ((tmp & val) == val) + return 0; + + return rc632_reg_write(handle, reg, (tmp|val)&0xff); +} + +static int +rc632_clear_bits(struct rfid_asic_handle *handle, + u_int8_t reg, + u_int8_t val) +{ + int ret; + u_int8_t tmp; + + ret = rc632_reg_read(handle, reg, &tmp); + if (ret < 0) { + DEBUGP("error during reg_read(%p, %d):%d\n", + handle, reg, ret); + return -1; + } + /* if bits are already cleared, no need to clear them again */ + if ((tmp & val) == 0) + return 0; + + return rc632_reg_write(handle, reg, (tmp & ~val)&0xff); +} + +static int +rc632_turn_on_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +static int +rc632_turn_off_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +static int +rc632_power_up(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +static int +rc632_power_down(struct rfid_asic_handle *handle) +{ + return rc632_set_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +/* Stupid RC623 implementations don't evaluate interrupts but poll the + * command register for "status idle" */ +static int +rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout) +{ + u_int8_t cmd = 0xff; + int ret; + + while (cmd != 0) { + ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd); + if (ret < 0) + return ret; + + if (cmd == 0) { + /* FIXME: read second time ?? */ + return 0; + } + + { + u_int8_t foo; + rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo); + if (foo & 0x04) + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo); + } + + usleep(100); + + /* Fixme: Abort after some timeout */ + } + + return 0; +} + +static int +rc632_transmit(struct rfid_asic_handle *handle, + const u_int8_t *buf, + u_int8_t len, + u_int64_t timeout) +{ + int ret; + + ret = rc632_fifo_write(handle, len, buf, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSMIT); + if (ret < 0) + return ret; + + return rc632_wait_idle(handle, timeout); +} + +static int +tcl_toggle_pcb(struct rfid_asic_handle *handle) +{ + // FIXME: toggle something between 0x0a and 0x0b + return 0; +} + +static int +rc632_transcieve(struct rfid_asic_handle *handle, + const u_int8_t *tx_buf, + u_int8_t tx_len, + u_int8_t *rx_buf, + u_int8_t *rx_len, + unsigned int timer, + unsigned int toggle) +{ + int ret; + + ret = rc632_fifo_write(handle, tx_len, tx_buf, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSCIEVE); + if (ret < 0) + return ret; + + if (toggle == 1) + tcl_toggle_pcb(handle); + + ret = rc632_wait_idle(handle, timer); + if (ret < 0) + return ret; + + ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len); + if (ret < 0) + return ret; + + if (*rx_len == 0) { + u_int8_t tmp; + + DEBUGP("rx_len == 0\n"); + + rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp); + rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp); + + return -1; + } + + return rc632_fifo_read(handle, *rx_len, rx_buf); +} + +static int +rc632_read_eeprom(struct rfid_asic_handle *handle) +{ + u_int8_t recvbuf[60]; + u_int8_t sndbuf[3]; + int ret; + + sndbuf[0] = 0x00; + sndbuf[1] = 0x00; + sndbuf[2] = 0x3c; + + ret = rc632_fifo_write(handle, 3, sndbuf, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_READ_E2); + if (ret < 0) + return ret; + + usleep(20000); + + ret = rc632_fifo_read(handle, sizeof(recvbuf), recvbuf); + if (ret < 0) + return ret; + + // FIXME: do something with eeprom contents + return ret; +} + +static int +rc632_calc_crc16_from(struct rfid_asic_handle *handle) +{ + u_int8_t sndbuf[2] = { 0x01, 0x02 }; + u_int8_t crc_lsb = 0x00 , crc_msb = 0x00; + int ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x12); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xe0); + if (ret < 0) + return ret; + + ret = rc632_fifo_write(handle, sizeof(sndbuf), sndbuf, 3); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_CALC_CRC); + if (ret < 0) + return ret; + + usleep(10000); // FIXME: no checking for cmd completion? + + ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_LSB, &crc_lsb); + if (ret < 0) + return ret; + + ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_MSB, &crc_msb); + if (ret < 0) + return ret; + + // FIXME: what to do with crc result? + return ret; +} + + +int +rc632_register_dump(struct rfid_asic_handle *handle, u_int8_t *buf) +{ + int ret; + u_int8_t i; + + for (i = 0; i <= 0x3f; i++) { + ret = rc632_reg_read(handle, i, &buf[i]); + // do we want error checks? + } + return 0; +} + + + +/* generic FIFO access functions (if no more efficient ones provided by + * transport driver) */ + +static int +generic_fifo_write() +{ + // FIXME: implementation (not needed for CM 5121) + return -1; +} + +static int +generic_fifo_read() +{ + // FIXME: implementation (not neded for CM 5121) + return -1; +} + +static int +rc632_init(struct rfid_asic_handle *ah) +{ + int ret; + + /* switch off rf (make sure PICCs are reset at init time) */ + ret = rc632_power_down(ah); + if (ret < 0) + return ret; + + usleep(10000); + + /* switch on rf */ + ret = rc632_power_up(ah); + if (ret < 0) + return ret; + + /* disable register paging */ + ret = rc632_reg_write(ah, 0x00, 0x00); + if (ret < 0) + return ret; + + /* set some sane default values */ + ret = rc632_reg_write(ah, 0x11, 0x5b); + if (ret < 0) + return ret; + + /* switch on rf */ + ret = rc632_turn_on_rf(ah); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_fini(struct rfid_asic_handle *ah) +{ + int ret; + + /* switch off rf */ + ret = rc632_turn_off_rf(ah); + if (ret < 0) + return ret; + + ret = rc632_power_down(ah); + if (ret < 0) + return ret; + + return 0; +} + +struct rfid_asic_handle * +rc632_open(struct rfid_asic_transport_handle *th) +{ + struct rfid_asic_handle *h; + + h = malloc(sizeof(*h)); + if (!h) + return NULL; + memset(h, 0, sizeof(*h)); + + h->asic = &rc632; + h->rath = th; + h->fc = h->asic->fc; + h->mtu = h->mru = 40; /* FIXME */ + + if (rc632_init(h) < 0) { + free(h); + return NULL; + } + + return h; +} + +void +rc632_close(struct rfid_asic_handle *h) +{ + rc632_fini(h); + free(h); +} + + +/* + * Philips CL RC632 primitives for ISO 14443-A compliant PICC's + * + * (C) 2005 by Harald Welte + * + */ + +static int +rc632_iso14443a_init(struct rfid_asic_handle *handle) +{ + int ret; + + // FIXME: some fifo work (drain fifo?) + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_FORCE_100_ASK | + RC632_TXCTRL_MOD_SRC_INT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, + CM5121_CW_CONDUCTANCE); + if (ret < 0) + return ret; + + /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */ + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, + CM5121_MOD_CONDUCTANCE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_14443A | + RC632_CDRCTRL_RATE_106K)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_MANCHESTER | + RC632_DECCTRL_RXFR_14443A)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + CM5121_14443A_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + CM5121_14443A_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_DECSRC_INT | + RC632_RXCTRL2_CLK_Q)); + if (ret < 0) + return ret; + + /* Omnikey proprietary driver has 0x03, but 0x06 is the default reset value ?!? */ + ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x06); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_iso14443a_fini(struct iso14443a_handle *handle_14443) +{ + +#if 0 + ret = rc632_turn_off_rf(handle); + if (ret < 0) + return ret; +#endif + + + return 0; +} + + +/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */ +static int +rc632_iso14443a_transcieve_sf(struct rfid_asic_handle *handle, + u_int8_t cmd, + struct iso14443a_atqa *atqa) +{ + int ret; + u_int8_t tx_buf[1]; + u_int8_t rx_len = 2; + + memset(atqa, 0, sizeof(atqa)); + + tx_buf[0] = cmd; + + /* transfer only 7 bits of last byte in frame */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07); + if (ret < 0) + return ret; + + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + +#if 0 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); + +#endif + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf), + (u_int8_t *)atqa, &rx_len, 0x32, 0); + if (ret < 0) { + DEBUGP("error during rc632_transcieve()\n"); + return ret; + } + + /* switch back to normal 8bit last byte */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00); + if (ret < 0) + return ret; + + if (rx_len != 2) { + DEBUGP("rx_len(%d) != 2\n", rx_len); + return -1; + } + + return 0; +} + +/* transcieve regular frame */ +static int +rc632_iso14443ab_transcieve(struct rfid_asic_handle *handle, + unsigned int frametype, + const u_int8_t *tx_buf, unsigned int tx_len, + u_int8_t *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + int ret; + u_int8_t rxl = *rx_len & 0xff; + u_int8_t channel_red; + + memset(rx_buf, 0, *rx_len); + + switch (frametype) { + case RFID_14443A_FRAME_REGULAR: + case RFID_MIFARE_FRAME: + channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE + |RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; + break; + case RFID_14443B_FRAME_REGULAR: + channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE + |RC632_CR_CRC3309; + break; +#if 0 + case RFID_MIFARE_FRAME: + channel_red = RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD; + break; +#endif + default: + return -EINVAL; + break; + } + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + channel_red); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + +/* transcieve anti collission bitframe */ +static int +rc632_iso14443a_transcieve_acf(struct rfid_asic_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + int ret; + u_int8_t rx_buf[64]; + u_int8_t rx_len = sizeof(rx_buf); + u_int8_t rx_align = 0, tx_last_bits, tx_bytes; + u_int8_t boc; + u_int8_t error_flag; + *bit_of_col = ISO14443A_BITOFCOL_NONE; + memset(rx_buf, 0, sizeof(rx_buf)); + + /* disable mifare cryto */ + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + /* disable CRC summing */ +#if 0 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); +#endif + if (ret < 0) + return ret; + + tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */ + tx_bytes = acf->nvb >> 4; + if (tx_last_bits) { + tx_bytes++; + rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */ + } + + //rx_align = 8 - tx_last_bits;/* rx frame complements tx */ + + /* set RxAlign and TxLastBits*/ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, + (rx_align << 4) | (tx_last_bits)); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, (u_int8_t *)acf, tx_bytes, + rx_buf, &rx_len, 0x32, 0); + if (ret < 0) + return ret; + + /* bitwise-OR the two halves of the split byte */ + acf->uid_bits[tx_bytes-2] = ( + (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits))) + | rx_buf[0]); + /* copy the rest */ + memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1); + + /* determine whether there was a collission */ + ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag); + if (ret < 0) + return ret; + + if (error_flag & RC632_ERR_FLAG_COL_ERR) { + /* retrieve bit of collission */ + ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc); + if (ret < 0) + return ret; + + /* bit of collission relative to start of part 1 of + * anticollision frame (!) */ + *bit_of_col = 2*8 + boc; + } + + return 0; +} + +static int rc632_iso14443b_init(struct rfid_asic_handle *handle) +{ + int ret; + + // FIXME: some FIFO work + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_MOD_SRC_INT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, 0x04); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_NRZ | + RC632_CDRCTRL_RATE_14443B)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, + (RC632_TBFRAMING_SOF_11L_3H | + (6 << RC632_TBFRAMING_SPACE_SHIFT) | + RC632_TBFRAMING_EOF_11)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_BPSK | + RC632_DECCTRL_RXFR_14443B)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + CM5121_14443B_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + CM5121_14443B_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, + ((0x2 & RC632_BPSKD_TAUB_MASK)<> 4; + key12[i * 2 + 1] = (~ln << 4) | ln; + key12[i * 2] = (~hn << 4) | hn; + } + return 0; +} + +static int +rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key) +{ + u_int8_t coded_key[RFID_MIFARE_KEY_CODED_LEN]; + u_int8_t reg; + int ret; + + ret = rc632_mifare_transform_key(key, coded_key); + if (ret < 0) + return ret; + + ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY); + if (ret < 0) + return ret; + + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + ret = rc632_reg_read(h, RC632_REG_ERROR_FLAG, ®); + if (ret < 0) + return ret; + + if (reg & RC632_ERR_FLAG_KEY_ERR) + return -EINVAL; + + return 0; +} + +static int +rc632_mifare_auth(struct rfid_asic_handle *h, u_int8_t cmd, u_int32_t serno, + u_int8_t block) +{ + int ret; + struct mifare_authcmd acmd; + u_int8_t reg; + + if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B) + return -EINVAL; + + /* Initialize acmd */ + acmd.block_address = block & 0xff; + acmd.auth_cmd = cmd; + //acmd.serno = htonl(serno); + acmd.serno = serno; + + ret = rc632_clear_bits(h, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + + /* Clear Rx CRC */ + ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE); + if (ret < 0) + return ret; + + /* Send Authent1 Command */ + ret = rc632_fifo_write(h, sizeof(acmd), (unsigned char *)&acmd, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1); + if (ret < 0) + return ret; + + /* Wait until transmitter is idle */ + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, ®); + if (ret < 0) + return ret; + if (reg & 0x07) + return -EIO; + + /* Clear Tx CRC */ + ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE); + if (ret < 0) + return ret; + + /* Send Authent2 Command */ + ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT2); + if (ret < 0) + return ret; + + /* Wait until transmitter is idle */ + ret = rc632_wait_idle(h, RC632_TMO_AUTH1); + if (ret < 0) + return ret; + + /* Check whether authentication was successful */ + ret = rc632_reg_read(h, RC632_REG_CONTROL, ®); + if (ret < 0) + return ret; + + if (!(reg & RC632_CONTROL_CRYPTO1_ON)) + return -EACCES; + + return 0; + +} + +/* transcieve regular frame */ +static int +rc632_mifare_transcieve(struct rfid_asic_handle *handle, + const u_int8_t *tx_buf, unsigned int tx_len, + u_int8_t *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + int ret; + u_int8_t rxl = *rx_len & 0xff; + + DEBUGP("entered\n"); + memset(rx_buf, 0, *rx_len); + +#if 1 + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD | + RC632_CR_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE)); +#else + ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE); +#endif + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + +struct rfid_asic rc632 = { + .name = "Philips CL RC632", + .fc = ISO14443_FREQ_CARRIER, + .priv.rc632 = { + .fn = { + .power_up = &rc632_power_up, + .power_down = &rc632_power_down, + .turn_on_rf = &rc632_turn_on_rf, + .turn_off_rf = &rc632_turn_off_rf, + .transcieve = &rc632_iso14443ab_transcieve, + .iso14443a = { + .init = &rc632_iso14443a_init, + .transcieve_sf = &rc632_iso14443a_transcieve_sf, + .transcieve_acf = &rc632_iso14443a_transcieve_acf, + }, + .iso14443b = { + .init = &rc632_iso14443b_init, + }, + .iso15693 = { + .init = &rc632_iso15693_init, + }, + .mifare_classic = { + .setkey = &rc632_mifare_set_key, + .auth = &rc632_mifare_auth, + }, + }, + }, +}; diff --git a/src/rfid_asic_rc632_14443a.c b/src/rfid_asic_rc632_14443a.c new file mode 100644 index 0000000..4c8a37b --- /dev/null +++ b/src/rfid_asic_rc632_14443a.c @@ -0,0 +1,394 @@ +/* + * Philips CL RC632 primitives for ISO 14443-A compliant PICC's + * + * (C) 2005 by Harald Welte + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "rc632.h" + +#include "cm5121_rfid.h" /* FIXME: this needs to be modular */ + +static int +rc632_iso14443a_init(struct rfid_asic_handle *handle) +{ + int ret; + +#if 0 + ret = rc632_power_up(handle); + if (ret < 0) + return ret; + + ret = rc632_turn_on_rf(handle); + if (ret < 0) + return ret; +#endif + + // FIXME: some fifo work (drain fifo?) + + /* flush fifo (our way) */ + ret = rc632_reg_write(handle, RC632_REG_CONTROL, 0x01); + + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_FORCE_100_ASK | + RC632_TXCTRL_MOD_SRC_INT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, + CM5121_CW_CONDUCTANCE); + if (ret < 0) + return ret; + + /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */ + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, + CM5121_MOD_CONDUCTANCE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL, + (RC632_CDRCTRL_TXCD_14443A | + RC632_CDRCTRL_RATE_106K)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL, + (RC632_DECCTRL_MANCHESTER | + RC632_DECCTRL_RXFR_14443A)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + CM5121_14443A_BITPHASE); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + CM5121_14443A_THRESHOLD); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_DECSRC_INT | + RC632_RXCTRL2_CLK_Q)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x03); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63); + if (ret < 0) + return ret; + + return 0; +} + +static int +rc632_iso14443a_fini(struct iso14443a_handle *handle_14443) +{ + +#if 0 + ret = rc632_turn_off_rf(handle); + if (ret < 0) + return ret; +#endif + + + return 0; +} + +#if 0 +int +rc632_iso14443a_select(struct rc632_handle *handle, + unsigned char *retptr, + ) +{ + int ret; + unsigned char tx_buf[7]; + unsigned char rx_buf[64]; + unsigned char rx_len = 1; + + memset(rx_buf, 0, sizeof(rx_buf)); + + tx_buf[0] = arg_8; + tx_buf[1] = 0x70; + (u_int32_t *)tx_buf[2] = arg_4; + tx_buf[6] = arg4+4; + + /* disable mifare cryto */ + ret = rc632_clear_bit(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD | + RC632_CR_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE)); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf), + rx_buf, &rx_len, 0x32, 0); + + if (ret < 0 || rx_len != 1) + return ret; + + *retptr = rx_buf[0]; + + return 0; +} + +/* issue a 14443-3 A PCD -> PICC command, such as REQA, WUPA */ +int +rc632_iso14443a_req(sutruct rc632_handle *handle, unsigned char req, + unsigned char *resp) +{ + int ret; + unsigned char tx_buf[1]; + unsigned char rx_buf[0x40]; + unsigned char rx_len = 2; + + memset(rx_buf, 0, sizeof(rx_buf)); + + tx_buf[0] = req; + + /* transfer only 7 bits of last byte in frame */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07); + if (ret < 0) + return ret; + + + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf), rx_buf, + &rx_len, 0x32, 0); + if (ret < 0) + return ret; + + /* switch back to normal 8bit last byte */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00); + if (ret < 0) + return ret; + + if ((rx_len != 2) || (rx_buf[1] != 0xf0)) + return -1; + + resp[0] = rx_buf[0]; + resp[1] = rx_buf[1]; + + return 0; +} +#endif + +/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */ +static int +rc632_iso14443a_transcieve_sf(struct rfid_asic_handle *handle, + unsigned char cmd, + struct iso14443a_atqa *atqa) +{ + int ret; + unsigned char tx_buf[1]; + unsigned char rx_len = 2; + + memset(atqa, 0, sizeof(atqa)); + + tx_buf[0] = cmd; + + /* transfer only 7 bits of last byte in frame */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07); + if (ret < 0) + return ret; + + + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf), + (unsigned char *)atqa, &rx_len, 0x32, 0); + if (ret < 0) { + DEBUGP("error during rc632_transcieve()\n"); + return ret; + } + + /* switch back to normal 8bit last byte */ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00); + if (ret < 0) + return ret; + + if (rx_len != 2) { + DEBUGP("rx_len(%d) != 2\n", rx_len); + return -1; + } + + return 0; +} + +/* transcieve regular frame */ +static int +rc632_iso14443a_transcieve(struct rfid_asic_handle *handle, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + int ret; + unsigned char rxl = *rx_len & 0xff; + + memset(rx_buf, 0, *rx_len); + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD | + RC632_CR_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE)); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0); + *rx_len = rxl; + if (ret < 0) + return ret; + + + return 0; +} + +/* transcieve anti collission bitframe */ +static int +rc632_iso14443a_transcieve_acf(struct rfid_asic_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + int ret; + unsigned char rx_buf[64]; + unsigned char rx_len = sizeof(rx_buf); + unsigned char rx_align = 0, tx_last_bits, tx_bytes; + unsigned char boc; + unsigned char error_flag; + *bit_of_col = ISO14443A_BITOFCOL_NONE; + memset(rx_buf, 0, sizeof(rx_buf)); + + /* disable mifare cryto */ + ret = rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_CRYPTO1_ON); + if (ret < 0) + return ret; + + /* disalbe CRC summing */ + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY, + (RC632_CR_PARITY_ENABLE | + RC632_CR_PARITY_ODD)); + if (ret < 0) + return ret; + + tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */ + tx_bytes = acf->nvb >> 4; + if (tx_last_bits) { + tx_bytes++; + rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */ + } + + //rx_align = 8 - tx_last_bits;/* rx frame complements tx */ + + /* set RxAlign and TxLastBits*/ + ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, + (rx_align << 4) | (tx_last_bits)); + if (ret < 0) + return ret; + + ret = rc632_transcieve(handle, (unsigned char *)acf, tx_bytes, + rx_buf, &rx_len, 0x32, 0); + if (ret < 0) + return ret; + + /* bitwise-OR the two halves of the split byte */ + acf->uid_bits[tx_bytes-2] = ( + (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits))) + | rx_buf[0]); + /* copy the rest */ + memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1); + + /* determine whether there was a collission */ + ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag); + if (ret < 0) + return ret; + + if (error_flag & RC632_ERR_FLAG_COL_ERR) { + /* retrieve bit of collission */ + ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc); + if (ret < 0) + return ret; + + /* bit of collission relative to start of part 1 of + * anticollision frame (!) */ + *bit_of_col = 2*8 + boc; + } + + return 0; +} + + diff --git a/src/rfid_asic_rc632_14443b.c b/src/rfid_asic_rc632_14443b.c new file mode 100644 index 0000000..62aa224 --- /dev/null +++ b/src/rfid_asic_rc632_14443b.c @@ -0,0 +1,69 @@ + +#include "rc632.h" + +int rc632_iso14443b_init(struct rc632_handle *handle) +{ + // FIXME: some FIFO work + // + ret = rc632_reg_write(handle, RC632_REG_TX_CONTROL, + (RC632_TXCTRL_TX1_RF_EN | + RC632_TXCTRL_TX2_RF_EN | + RC632_TXCTRL_TX2_INV | + RC632_TXCTRL_MOD_SRC_INT)); + + ret = rc632_reg_write(handle, RC632_REG_CW_CONDUCTANCE, 0x3f); + + ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE, 0x04); + + ret = rc632_reg_write(handle, RC632_REG_CODE_CONTROL, + (RC632_CDRCTRL_TXCD_NRZ | + RC632_CDRCTRL_RATE_14443B)); + + ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13); + + ret = rc632_reg_write(handle, RC632_REG_SOF_WIDTH, 0x3f); + + ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, + (RC632_TBFRAMING_SOF_11L_3H | + (6 << RC632_TBFRAMING_SPACE_SHIFT) | + RC632_TBFRAMING_EOF_11)); + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1, + (RC632_RXCTRL1_GAIN_35DB | + RC632_RXCTRL1_ISO14443 | + RC632_RXCTRL1_SUBCP_8)); + + ret = rc632_reg_write(handle, RC632_REG_DECODE_CONTROL, + (RC632_DECCTRL_BPSK | + RC632_DECCTRL_RXFR_14443B)); + + ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE, + CM5121_14443B_BITPHASE); + + ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD, + CM5121_14443B_THRESHOLD); + + ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, + ((0x10 & RC632_BPSKD_TAUB_MASK)< sizeof(fsdi_table)/sizeof(unsigned int)) + return -1; + + *fsd = fsdi_table[fsdi]; + return 0; +} + +int iso14443_fsd_to_fsdi(unsigned char *fsdi, unsigned int fsd) +{ + int i; + + for (i = 0; i < sizeof(fsdi_table)/sizeof(unsigned int); i++) { + if (fsdi_table[i] == fsd) { + *fsdi = i; + return 0; + } + } + + return -1; +} + +/* calculate the fsd that is equal or the closest smaller value + * that can be coded as fsd */ +unsigned int iso14443_fsd_approx(unsigned int fsd) +{ + unsigned int tbl_size = sizeof(fsdi_table)/sizeof(unsigned int); + int i; + + for (i = tbl_size-1; i >= 0; i--) { + if (fsdi_table[i] <= fsd) + return fsdi_table[i]; + } + /* not reached: return smallest possible FSD */ + return fsdi_table[0]; +} + diff --git a/src/rfid_iso14443_common.h b/src/rfid_iso14443_common.h new file mode 100644 index 0000000..848d983 --- /dev/null +++ b/src/rfid_iso14443_common.h @@ -0,0 +1,11 @@ +#ifndef __RFID_ISO14443_COMMON_H +#define __RFID_ISO14443_COMMON_H + +int iso14443_fsdi_to_fsd(unsigned int *fsd, unsigned char fsdi); +int iso14443_fsd_to_fsdi(unsigned char *fsdi, unsigned int fsd); +unsigned int iso14443_fsd_approx(unsigned int fsd); + +#define ISO14443_FREQ_CARRIER 13560000 +#define ISO14443_FREQ_SUBCARRIER (ISO14443_FREQ_CARRIER/16) + +#endif diff --git a/src/rfid_layer2.c b/src/rfid_layer2.c new file mode 100644 index 0000000..c1ab6a6 --- /dev/null +++ b/src/rfid_layer2.c @@ -0,0 +1,76 @@ +/* librfid - layer 2 protocol handler + * (C) 2005 by Harald Welte + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include + +#include +#include + +static struct rfid_layer2 *rfid_layer2_list; + +struct rfid_layer2_handle * +rfid_layer2_init(struct rfid_reader_handle *rh, unsigned int id) +{ + struct rfid_layer2 *p; + + for (p = rfid_layer2_list; p; p = p->next) + if (p->id == id) + return p->fn.init(rh); + + DEBUGP("unable to find matching layer2 protocol\n"); + return NULL; +} + +int +rfid_layer2_open(struct rfid_layer2_handle *ph) +{ + return ph->l2->fn.open(ph); +} + +int +rfid_layer2_transcieve(struct rfid_layer2_handle *ph, + enum rfid_frametype frametype, + const unsigned char *tx_buf, unsigned int len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + return ph->l2->fn.transcieve(ph, frametype, tx_buf, len, rx_buf, + rx_len, timeout, flags); +} + +int rfid_layer2_fini(struct rfid_layer2_handle *ph) +{ + return ph->l2->fn.fini(ph); +} + +int +rfid_layer2_close(struct rfid_layer2_handle *ph) +{ + return ph->l2->fn.close(ph); +} + +int +rfid_layer2_register(struct rfid_layer2 *p) +{ + p->next = rfid_layer2_list; + rfid_layer2_list = p; + + return 0; +} diff --git a/src/rfid_layer2_iso14443a.c b/src/rfid_layer2_iso14443a.c new file mode 100644 index 0000000..d93f917 --- /dev/null +++ b/src/rfid_layer2_iso14443a.c @@ -0,0 +1,294 @@ +/* ISO 14443-3 A anticollision implementation + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define TIMEOUT 1236 + +/* Transcieve a 7-bit short frame */ +static int +iso14443a_transcieve_sf(struct rfid_layer2_handle *handle, + unsigned char cmd, + struct iso14443a_atqa *atqa) +{ + struct rfid_reader *rdr = handle->rh->reader; + + return rdr->iso14443a.transcieve_sf(handle->rh, cmd, atqa); +} + +/* Transmit an anticollission bit frame */ +static int +iso14443a_transcieve_acf(struct rfid_layer2_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + struct rfid_reader *rdr = handle->rh->reader; + + return rdr->iso14443a.transcieve_acf(handle->rh, acf, bit_of_col); +} + +/* Transmit a regular frame */ +static int +iso14443a_transcieve(struct rfid_layer2_handle *handle, + enum rfid_frametype frametype, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + return handle->rh->reader->transcieve(handle->rh, frametype, tx_buf, + tx_len, rx_buf, rx_len, timeout, flags); +} + +static int +iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits) +{ + unsigned int byte_count = bits / 8; + unsigned int bit_count = bits % 8; + + if (byte_count < 2 || byte_count > 7) + return -1; + + *nvb = ((byte_count & 0xf) << 4) | bit_count; + + return 0; +} + +/* first bit is '1', second bit '2' */ +static void +set_bit_in_field(unsigned char *bitfield, unsigned int bit) +{ + unsigned int byte_count = bit / 8; + unsigned int bit_count = bit % 8; + + DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n", + bitfield, byte_count, bit_count); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); + *(bitfield+byte_count) |= 1 << (bit_count-1); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); +} + +static int +iso14443a_anticol(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned int uid_size; + struct iso14443a_handle *h = &handle->priv.iso14443a; + struct iso14443a_atqa atqa; + struct iso14443a_anticol_cmd acf; + unsigned int bit_of_col; + unsigned char sak[3]; + unsigned int rx_len = sizeof(sak); + char *aqptr = (char *) &atqa; + + memset(handle->uid, 0, sizeof(handle->uid)); + memset(sak, 0, sizeof(sak)); + memset(&atqa, 0, sizeof(atqa)); + memset(&acf, 0, sizeof(acf)); + + ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa); + if (ret < 0) { + h->state = ISO14443A_STATE_REQA_SENT; + DEBUGP("error during transcieve_sf: %d\n", ret); + return ret; + } + h->state = ISO14443A_STATE_ATQA_RCVD; + + DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1)); + + if (!atqa.bf_anticol) { + h->state = ISO14443A_STATE_NO_BITFRAME_ANTICOL; + DEBUGP("no bitframe anticollission bits set, aborting\n"); + return -1; + } + + if (atqa.uid_size == 2 || atqa.uid_size == 3) + uid_size = 3; + else if (atqa.uid_size == 1) + uid_size = 2; + else + uid_size = 1; + + acf.sel_code = ISO14443A_AC_SEL_CODE_CL1; + + h->state = ISO14443A_STATE_ANTICOL_RUNNING; + h->level = ISO14443A_LEVEL_CL1; + +cascade: + iso14443a_code_nvb_bits(&acf.nvb, 16); + + ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col); + if (ret < 0) + return ret; + DEBUGP("bit_of_col = %u\n", bit_of_col); + + while (bit_of_col != ISO14443A_BITOFCOL_NONE) { + set_bit_in_field(&acf.uid_bits[0], bit_of_col-16); + iso14443a_code_nvb_bits(&acf.nvb, bit_of_col); + ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col); + DEBUGP("bit_of_col = %u\n", bit_of_col); + if (ret < 0) + return ret; + } + + iso14443a_code_nvb_bits(&acf.nvb, 7*8); + ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR, + (unsigned char *)&acf, 7, + (unsigned char *) &sak, &rx_len, + TIMEOUT, 0); + if (ret < 0) + return ret; + + if (sak[0] & 0x04) { + /* Cascade bit set, UID not complete */ + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* cascading from CL1 to CL2 */ + if (acf.uid_bits[0] != 0x88) { + DEBUGP("Cascade bit set, but UID0 != 0x88\n"); + return -1; + } + memcpy(&handle->uid[0], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL2; + h->level = ISO14443A_LEVEL_CL2; + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* cascading from CL2 to CL3 */ + memcpy(&handle->uid[3], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL3; + h->level = ISO14443A_LEVEL_CL3; + break; + default: + DEBUGP("cannot cascade any further than CL3\n"); + h->state = ISO14443A_STATE_ERROR; + return -1; + break; + } + goto cascade; + + } else { + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* single size UID (4 bytes) */ + memcpy(&handle->uid[0], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* double size UID (7 bytes) */ + memcpy(&handle->uid[3], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL3: + /* triple size UID (10 bytes) */ + memcpy(&handle->uid[6], &acf.uid_bits[0], 4); + break; + } + } + + h->level = ISO14443A_LEVEL_NONE; + h->state = ISO14443A_STATE_SELECTED; + + { + if (uid_size == 1) + handle->uid_len = 4; + else if (uid_size == 2) + handle->uid_len = 7; + else + handle->uid_len = 10; + + DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len)); + } + + if (sak[0] & 0x20) { + DEBUGP("we have a T=CL compliant PICC\n"); + h->tcl_capable = 1; + } else { + DEBUGP("we have a T!=CL PICC\n"); + h->tcl_capable = 0; + } + + return 0; +} + +static int +iso14443a_hlta(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned char tx_buf[2] = { 0x50, 0x00 }; + unsigned char rx_buf[10]; + unsigned int rx_len = sizeof(rx_buf); + + ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR, + tx_buf, sizeof(tx_buf), + rx_buf, &rx_len, 1000 /* 1ms */, 0); + if (ret < 0) { + /* "error" case: we don't get somethng back from the card */ + return 0; + } + return -1; +} + +static struct rfid_layer2_handle * +iso14443a_init(struct rfid_reader_handle *rh) +{ + int ret; + struct rfid_layer2_handle *h = malloc(sizeof(*h)); + if (!h) + return NULL; + + h->l2 = &rfid_layer2_iso14443a; + h->rh = rh; + h->priv.iso14443a.state = ISO14443A_STATE_NONE; + h->priv.iso14443a.level = ISO14443A_LEVEL_NONE; + + ret = h->rh->reader->iso14443a.init(h->rh); + if (ret < 0) { + free(h); + return NULL; + } + + return h; +} + +static int +iso14443a_fini(struct rfid_layer2_handle *handle) +{ + free(handle); + return 0; +} + + +struct rfid_layer2 rfid_layer2_iso14443a = { + .id = RFID_LAYER2_ISO14443A, + .name = "ISO 14443-3 A", + .fn = { + .init = &iso14443a_init, + .open = &iso14443a_anticol, + .transcieve = &iso14443a_transcieve, + .close = &iso14443a_hlta, + .fini = &iso14443a_fini, + }, +}; + diff --git a/src/rfid_layer2_iso14443b.c b/src/rfid_layer2_iso14443b.c new file mode 100644 index 0000000..f874071 --- /dev/null +++ b/src/rfid_layer2_iso14443b.c @@ -0,0 +1,344 @@ +/* ISO 14443-3 B anticollision implementation + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "rfid_iso14443_common.h" + +#define ATQB_TIMEOUT ((256*10e6/ISO14443_FREQ_SUBCARRIER) \ + +(200*10e6/ISO14443_FREQ_SUBCARRIER)) + +static inline int +fwi_to_fwt(struct rfid_layer2_handle *h, unsigned int *fwt, unsigned int fwi) +{ + unsigned int multiplier, tmp; + + /* 15 is RFU */ + if (fwi > 14) + return -1; + + /* According to ISO 14443-3:200(E), Chapter 7.9.4.3, the forumala is + * (256 * 16 / fC) * 2^fwi We avoid floating point computations by + * shifting everything into the microsecond range. In integer + * calculations 1000000*256*16/13560000 evaluates to 302 (instead of + * 302.064897), which provides sufficient precision, IMHO. The max + * result is 302 * 16384 (4947968), which fits well within the 31/32 + * bit range of an integer */ + + multiplier = 1 << fwi; /* 2 to the power of fwi */ + + tmp = (unsigned int) 1000000 * 256 * 16; + + return (tmp / h->rh->ah->asic->fc) * multiplier; +} + +static int +parse_atqb(struct rfid_layer2_handle *h, struct iso14443b_atqb *atqb) +{ + int ret; + + if (atqb->fifty != 0x50) + return -1; + + if (atqb->protocol_info.fo & 0x01) + h->priv.iso14443b.flags |= ISO14443B_CID_SUPPORTED; + if (atqb->protocol_info.fo & 0x02) + h->priv.iso14443b.flags |= ISO14443B_NAD_SUPPORTED; + + ret = fwi_to_fwt(h, &h->priv.iso14443b.fwt, atqb->protocol_info.fwi); + if (ret < 0) { + DEBUGP("invalid fwi %u\n", atqb->protocol_info.fwi); + return ret; + } + + if (atqb->protocol_info.protocol_type == 0x1) { + DEBUGP("we have a T=CL compliant PICC\n"); + h->priv.iso14443b.tcl_capable = 1; + } else { + DEBUGP("we have a T!=CL PICC\n"); + h->priv.iso14443b.tcl_capable = 0; + } + + iso14443_fsdi_to_fsd(&h->priv.iso14443b.fsc, + atqb->protocol_info.max_frame_size); + + /* FIXME: speed capability */ + + memcpy(h->uid, atqb->pupi, sizeof(atqb->pupi)); + h->uid_len = sizeof(atqb->pupi); + + return 0; +} + +static int +send_reqb(struct rfid_layer2_handle *h, unsigned char afi, + unsigned int is_wup, unsigned int num_initial_slots) +{ + int ret; + unsigned char reqb[3]; + struct iso14443b_atqb atqb; + unsigned int atqb_len = sizeof(atqb); + unsigned int num_slot_idx = num_initial_slots; + + reqb[0] = 0x05; + reqb[1] = afi; + + for (num_slot_idx = num_initial_slots; num_slot_idx <= 4; + num_slot_idx++) { + reqb[2] = num_slot_idx & 0x07; + if (is_wup) + reqb[2] |= 0x08; + + ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR, + reqb, sizeof(reqb), + (unsigned char *)&atqb, + &atqb_len, ATQB_TIMEOUT, 0); + h->priv.iso14443b.state = ISO14443B_STATE_REQB_SENT; + if (ret < 0) { + DEBUGP("error during transcieve of REQB/WUBP\n"); + continue; + } + + /* FIXME: send N-1 slot marker frames */ + + if (atqb_len != sizeof(atqb)) { + DEBUGP("error: atqb_len = %u instead of %Zu\n", + atqb_len, sizeof(atqb)); + continue; + } + + /* FIXME: how to detect a collission at 14443B ? I guess we + * can only rely on the CRC checking (CRCErr in ErrorFlag + * register?) */ + + if (parse_atqb(h, &atqb) >= 0) { + h->priv.iso14443b.state = ISO14443B_STATE_ATQB_RCVD; + return 0; + } + } + + return -1; +} + +static inline unsigned int mbli_to_mbl(struct rfid_layer2_handle *h, + unsigned int mbli) +{ + return (h->priv.iso14443b.fsc * 2 ^ (mbli-1)); +} + +static int +transcieve_attrib(struct rfid_layer2_handle *h, const unsigned char *inf, + unsigned int inf_len, unsigned char *rx_data, unsigned int *rx_len) +{ + struct iso14443b_attrib_hdr *attrib; + unsigned int attrib_size = sizeof(*attrib) + inf_len; + unsigned char *rx_buf; + unsigned char fsdi; + int ret = 0; + + DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd); + attrib = malloc(attrib_size); + if (!attrib) { + perror("attrib_alloc"); + return -1; + } + + DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd); + rx_buf = malloc(*rx_len+1); + if (!rx_buf) { + perror("rx_buf malloc"); + ret = -1; + goto out_attrib; + } + + /* initialize attrib frame */ + memset(attrib, 0, attrib_size); + if (inf_len) + memcpy((unsigned char *)attrib+sizeof(*attrib), inf, inf_len); + + attrib->one_d = 0x1d; + memcpy(attrib->identifier, h->uid, 4); + + /* FIXME: do we want to change TR0/TR1 from its default ? */ + /* FIXME: do we want to change SOF/EOF from its default ? */ + + ret = iso14443_fsd_to_fsdi(&fsdi, h->priv.iso14443b.fsd); + if (ret < 0) { + DEBUGP("unable to map FSD(%u) to FSDI\n", + h->priv.iso14443b.fsd); + goto out_rx; + } + attrib->param2.fsdi = fsdi; + + /* FIXME: spd_in / spd_out */ + if (h->priv.iso14443b.tcl_capable == 1) + attrib->param3.protocol_type = 0x1; + + *rx_len = *rx_len + 1; + ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR, + (unsigned char *) attrib, + sizeof(*attrib)+inf_len, + rx_buf, rx_len, h->priv.iso14443b.fwt, + 0); + h->priv.iso14443b.state = ISO14443B_STATE_ATTRIB_SENT; + if (ret < 0) { + DEBUGP("transcieve problem\n"); + goto out_rx; + } + + if ((rx_buf[0] & 0x0f) != h->priv.iso14443b.cid) { + DEBUGP("ATTRIB response with invalid CID %u\n", + rx_buf[0] & 0x0f); + ret = -1; + goto out_rx; + } + + h->priv.iso14443b.state = ISO14443B_STATE_SELECTED; + + h->priv.iso14443b.mbl = mbli_to_mbl(h, (rx_data[0] & 0xf0) >> 4); + + *rx_len = *rx_len - 1; + memcpy(rx_data, rx_buf+1, *rx_len); + +out_rx: + free(rx_buf); +out_attrib: + free(attrib); + + return ret; +} + +static int +iso14443b_hltb(struct rfid_layer2_handle *h) +{ + int ret; + unsigned char hltb[5]; + unsigned char hltb_resp[1]; + unsigned int hltb_len = 1; + + hltb[0] = 0x50; + memcpy(hltb+1, h->uid, 4); + + ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR, + hltb, 5, + hltb_resp, &hltb_len, + h->priv.iso14443b.fwt, 0); + h->priv.iso14443b.state = ISO14443B_STATE_HLTB_SENT; + if (ret < 0) { + DEBUGP("transcieve problem\n"); + return ret; + } + + if (hltb_len != 1 || hltb_resp[0] != 0x00) { + DEBUGP("bad HLTB response\n"); + return -1; + } + h->priv.iso14443b.state = ISO14443B_STATE_HALTED; + + return 0; +} + +static int +iso14443b_anticol(struct rfid_layer2_handle *handle) +{ + unsigned char afi = 0; /* FIXME */ + int ret; + unsigned char buf[255]; + unsigned int buf_len = sizeof(buf); + + ret = send_reqb(handle, afi, 0, 0); + if (ret < 0) + return ret; + + ret = transcieve_attrib(handle, NULL, 0, buf, &buf_len); + if (ret < 0) + return ret; + + return 0; +} + +static struct rfid_layer2_handle * +iso14443b_init(struct rfid_reader_handle *rh) +{ + int ret; + struct rfid_layer2_handle *h = malloc(sizeof(*h)); + if (!h) + return NULL; + + h->l2 = &rfid_layer2_iso14443b; + h->rh = rh; + h->priv.iso14443b.state = ISO14443B_STATE_NONE; + + h->priv.iso14443b.fsd = iso14443_fsd_approx(rh->ah->mru); + DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd); + + /* 14443-3 Section 7.1.6 */ + h->priv.iso14443b.tr0 = (256/ISO14443_FREQ_SUBCARRIER)*10e6; + h->priv.iso14443b.tr1 = (200/ISO14443_FREQ_SUBCARRIER)*10e6; + + ret = h->rh->reader->iso14443b.init(h->rh); + if (ret < 0) { + DEBUGP("error during reader 14443b init\n"); + free(h); + return NULL; + } + + return h; +} + +static int +iso14443b_fini(struct rfid_layer2_handle *handle) +{ + free(handle); + return 0; +} + +static int +iso14443b_transcieve(struct rfid_layer2_handle *handle, + enum rfid_frametype frametype, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + DEBUGP("transcieving %u bytes, expecting max %u\n", tx_len, *rx_len); + return handle->rh->reader->transcieve(handle->rh, frametype, + tx_buf, tx_len, + rx_buf, rx_len, timeout, flags); +} + +struct rfid_layer2 rfid_layer2_iso14443b = { + .id = RFID_LAYER2_ISO14443B, + .name = "ISO 14443-3 B", + .fn = { + .init = &iso14443b_init, + .open = &iso14443b_anticol, + .transcieve = &iso14443b_transcieve, + .close = &iso14443b_hltb, + .fini = &iso14443b_fini, + }, +}; diff --git a/src/rfid_layer2_iso15693.c b/src/rfid_layer2_iso15693.c new file mode 100644 index 0000000..15ff18a --- /dev/null +++ b/src/rfid_layer2_iso15693.c @@ -0,0 +1,302 @@ +/* ISO 15693 anticollision implementation + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include + +#include +#include +#include +#include + +#if 0 +/* Transcieve a 7-bit short frame */ +static int +iso14443a_transcieve_sf(struct rfid_layer2_handle *handle, + unsigned char cmd, + struct iso14443a_atqa *atqa) +{ + struct rfid_reader *rdr = handle->rh->reader; + + return rdr->iso14443a.transcieve_sf(handle->rh, cmd, atqa); +} + +/* Transmit an anticollission bit frame */ +static int +iso14443a_transcieve_acf(struct rfid_layer2_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col) +{ + struct rfid_reader *rdr = handle->rh->reader; + + return rdr->iso14443a.transcieve_acf(handle->rh, acf, bit_of_col); +} + +/* Transmit a regular frame */ +static int +iso14443a_transcieve(struct rfid_layer2_handle *handle, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t, unsigned int flags) +{ + return handle->rh->reader->transcieve(handle->rh, tx_buf, tx_len, + rx_buf, rx_len, timeout, flags); +} + +static int +iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits) +{ + unsigned int byte_count = bits / 8; + unsigned int bit_count = bits % 8; + + if (byte_count < 2 || byte_count > 7) + return -1; + + *nvb = ((byte_count & 0xf) << 4) | bit_count; + + return 0; +} + +/* first bit is '1', second bit '2' */ +static void +set_bit_in_field(unsigned char *bitfield, unsigned int bit) +{ + unsigned int byte_count = bit / 8; + unsigned int bit_count = bit % 8; + + DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n", + bitfield, byte_count, bit_count); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); + *(bitfield+byte_count) |= 1 << (bit_count-1); + DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count)); +} + +static int +iso14443a_anticol(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned int uid_size; + struct iso14443a_atqa atqa; + struct iso14443a_anticol_cmd acf; + unsigned int bit_of_col; + unsigned char sak[3]; + unsigned char uid[10]; // triple size equals 10 bytes; + unsigned int rx_len = sizeof(sak); + char *aqptr = (char *) &atqa; + static int first = 0; + + memset(uid, 0, sizeof(uid)); + memset(sak, 0, sizeof(sak)); + memset(&atqa, 0, sizeof(atqa)); + memset(&acf, 0, sizeof(acf)); + + if (first == 0) { + DEBUGP("Sending REQA\n"); + ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa); + first = 1; + } else { + DEBUGP("Sending WUPA\n"); + ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_WUPA, &atqa); + } + + if (ret < 0) { + handle->priv.iso14443a.state = ISO14443A_STATE_REQA_SENT; + DEBUGP("error during transcieve_sf: %d\n", ret); + return ret; + } + handle->priv.iso14443a.state = ISO14443A_STATE_ATQA_RCVD; + + DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1)); + + if (!atqa.bf_anticol) { + handle->priv.iso14443a.state =ISO14443A_STATE_NO_BITFRAME_ANTICOL; + DEBUGP("no bitframe anticollission bits set, aborting\n"); + return -1; + } + + if (atqa.uid_size == 2 || atqa.uid_size == 3) + uid_size = 3; + else if (atqa.uid_size == 1) + uid_size = 2; + else + uid_size = 1; + + acf.sel_code = ISO14443A_AC_SEL_CODE_CL1; + + handle->priv.iso14443a.state = ISO14443A_STATE_ANTICOL_RUNNING; + handle->priv.iso14443a.level = ISO14443A_LEVEL_CL1; + +cascade: + iso14443a_code_nvb_bits(&acf.nvb, 16); + + ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col); + if (ret < 0) + return ret; + DEBUGP("bit_of_col = %u\n", bit_of_col); + + while (bit_of_col != ISO14443A_BITOFCOL_NONE) { + set_bit_in_field(&acf.uid_bits[0], bit_of_col-16); + iso14443a_code_nvb_bits(&acf.nvb, bit_of_col); + ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col); + DEBUGP("bit_of_col = %u\n", bit_of_col); + if (ret < 0) + return ret; + } + + iso14443a_code_nvb_bits(&acf.nvb, 7*8); + ret = iso14443a_transcieve(handle, (unsigned char *)&acf, 7, + (unsigned char *) &sak, &rx_len, + TIMEOUT, 0); + if (ret < 0) + return ret; + + if (sak[0] & 0x04) { + /* Cascade bit set, UID not complete */ + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* cascading from CL1 to CL2 */ + if (acf.uid_bits[0] != 0x88) { + DEBUGP("Cascade bit set, but UID0 != 0x88\n"); + return -1; + } + memcpy(&uid[0], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL2; + handle->priv.iso14443a.level = ISO14443A_LEVEL_CL2; + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* cascading from CL2 to CL3 */ + memcpy(&uid[3], &acf.uid_bits[1], 3); + acf.sel_code = ISO14443A_AC_SEL_CODE_CL3; + handle->priv.iso14443a.level = ISO14443A_LEVEL_CL3; + break; + default: + DEBUGP("cannot cascade any further than CL3\n"); + handle->priv.iso14443a.state = ISO14443A_STATE_ERROR; + return -1; + break; + } + goto cascade; + + } else { + switch (acf.sel_code) { + case ISO14443A_AC_SEL_CODE_CL1: + /* single size UID (4 bytes) */ + memcpy(&uid[0], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL2: + /* double size UID (7 bytes) */ + memcpy(&uid[3], &acf.uid_bits[0], 4); + break; + case ISO14443A_AC_SEL_CODE_CL3: + /* triple size UID (10 bytes) */ + memcpy(&uid[6], &acf.uid_bits[0], 4); + break; + } + } + + handle->priv.iso14443a.level = ISO14443A_LEVEL_NONE; + handle->priv.iso14443a.state = ISO14443A_STATE_SELECTED; + + { + int uid_len; + if (uid_size == 1) + uid_len = 4; + else if (uid_size == 2) + uid_len = 7; + else + uid_len = 10; + + DEBUGP("UID %s\n", rfid_hexdump(uid, uid_len)); + } + + if (sak[0] & 0x20) { + DEBUGP("we have a T=CL compliant PICC\n"); + handle->priv.iso14443a.tcl_capable = 1; + } else { + DEBUGP("we have a T!=CL PICC\n"); + handle->priv.iso14443a.tcl_capable = 0; + } + + return 0; +} + +static int +iso14443a_hlta(struct rfid_layer2_handle *handle) +{ + int ret; + unsigned char tx_buf[2] = { 0x50, 0x00 }; + unsigned char rx_buf[10]; + unsigned int rx_len = sizeof(rx_buf); + + return 0; + + ret = iso14443a_transcieve(handle, tx_buf, sizeof(tx_buf), + rx_buf, &rx_len, 1000 /* 1ms */, 0); + if (ret < 0) { + /* "error" case: we don't get somethng back from the card */ + return 0; + } + return -1; +} +#endif + +static struct rfid_layer2_handle * +iso15693_init(struct rfid_reader_handle *rh) +{ + int ret; + struct rfid_layer2_handle *h = malloc(sizeof(*h)); + if (!h) + return NULL; + + h->l2 = &rfid_layer2_iso15693; + h->rh = rh; + h->priv.iso15693.state = ISO15693_STATE_NONE; + + ret = h->rh->reader->iso15693.init(h->rh); + if (ret < 0) { + free(h); + return NULL; + } + + return h; +} + +static int +iso15693_fini(struct rfid_layer2_handle *handle) +{ + free(handle); + return 0; +} + + +struct rfid_layer2 rfid_layer2_iso15693 = { + .id = RFID_LAYER2_ISO15693, + .name = "ISO 15693", + .fn = { + .init = &iso15693_init, + //.open = &iso15693_anticol, + //.transcieve = &iso15693_transcieve, + //.close = &iso14443a_hlta, + .fini = &iso15693_fini, + }, +}; + diff --git a/src/rfid_proto_mifare_classic.c b/src/rfid_proto_mifare_classic.c new file mode 100644 index 0000000..10de288 --- /dev/null +++ b/src/rfid_proto_mifare_classic.c @@ -0,0 +1,148 @@ + +/* Mifare Classic implementation, PCD side. + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "rfid_iso14443_common.h" + + +#define MIFARE_UL_CMD_WRITE 0xA2 +#define MIFARE_UL_CMD_READ 0x30 + +/* FIXME */ +#define MIFARE_CL_READ_FWT 100 +#define MIFARE_CL_WRITE_FWT 100 + +static int +mfcl_read(struct rfid_protocol_handle *ph, unsigned int page, + unsigned char *rx_data, unsigned int *rx_len) +{ + unsigned char rx_buf[16]; + unsigned int real_rx_len = sizeof(rx_buf); + unsigned char tx[2]; + int ret; + + if (page > MIFARE_CL_PAGE_MAX) + return -EINVAL; + + tx[0] = MIFARE_CL_CMD_READ; + tx[1] = page & 0xff; + + ret = ph->l2h->l2->fn.transcieve(ph->l2h, RFID_MIFARE_FRAME, tx, + sizeof(tx), rx_buf, &real_rx_len, + MIFARE_CL_READ_FWT, 0); + + if (ret < 0) + return ret; + + if (real_rx_len < *rx_len) + *rx_len = real_rx_len; + + memcpy(rx_data, rx_buf, *rx_len); + + return ret; +} + +static int +mfcl_write(struct rfid_protocol_handle *ph, unsigned int page, + unsigned char *tx_data, unsigned int tx_len) +{ + unsigned int i; + unsigned char tx[18]; + unsigned char rx[1]; + unsigned int rx_len; + int ret; + + if (tx_len != 16 || page > MIFARE_CL_PAGE_MAX) + return -EINVAL; + + tx[0] = MIFARE_CL_CMD_WRITE16; + tx[1] = page & 0xff; + + memcpy(tx+2, tx_data, 16); + + ret = ph->l2h->l2->fn.transcieve(ph->l2h, RFID_MIFARE_FRAME, tx, + sizeof(tx), rx, &rx_len, + MIFARE_CL_WRITE_FWT, 0); + + if (ret < 0) + return ret; + + if (rx[0] != MIFARE_UL_RESP_ACK) + return -EIO; + + return ret; +} + +static struct rfid_protocol_handle * +mfcl_init(struct rfid_layer2_handle *l2h) +{ + struct rfid_protocol_handle *ph; + ph = malloc(sizeof(struct rfid_protocol_handle)); + return ph; +} + +static int mfcl_fini(struct rfid_protocol_handle *ph) +{ + free(ph); + return 0; +} + +struct rfid_protocol rfid_protocol_mfcl = { + .id = RFID_PROTOCOL_MIFARE_CLASSIC, + .name = "Mifare Classic", + .fn = { + .init = &mfcl_init, + .read = &mfcl_read, + .write = &mfcl_write, + .fini = &mfcl_fini, + }, +}; + +int mfcl_set_key(struct rfid_protocol_handle *ph, unsigned char *key) +{ + if (!ph->l2h->rh->reader->mifare_classic.setkey) + return -ENODEV; + + return ph->l2h->rh->reader->mifare_classic.setkey(ph->l2h->rh, key); +} + +int mfcl_auth(struct rfid_protocol_handle *ph, u_int8_t cmd, u_int8_t block) +{ + u_int32_t serno = *((u_int32_t *)ph->l2h->uid); + + if (!ph->l2h->rh->reader->mifare_classic.auth) + return -ENODEV; + + return ph->l2h->rh->reader->mifare_classic.auth(ph->l2h->rh, cmd, + serno, block); +} diff --git a/src/rfid_proto_mifare_ul.c b/src/rfid_proto_mifare_ul.c new file mode 100644 index 0000000..9e5363f --- /dev/null +++ b/src/rfid_proto_mifare_ul.c @@ -0,0 +1,162 @@ + +/* Mifare Ultralight implementation, PCD side. + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "rfid_iso14443_common.h" + + +/* FIXME */ +#define MIFARE_UL_READ_FWT 100 +#define MIFARE_UL_WRITE_FWT 100 + +static int +mful_read(struct rfid_protocol_handle *ph, unsigned int page, + unsigned char *rx_data, unsigned int *rx_len) +{ + unsigned char rx_buf[16]; + unsigned int real_rx_len = sizeof(rx_buf); + unsigned char tx[2]; + int ret; + + if (page > MIFARE_UL_PAGE_MAX) + return -EINVAL; + + tx[0] = MIFARE_UL_CMD_READ; + tx[1] = page & 0xff; + + ret = ph->l2h->l2->fn.transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR, + tx, sizeof(tx), rx_buf, + &real_rx_len, MIFARE_UL_READ_FWT, 0); + + if (ret < 0) + return ret; + + if (real_rx_len < *rx_len) + *rx_len = real_rx_len; + + memcpy(rx_data, rx_buf, *rx_len); + + return ret; +} + +static int +mful_write(struct rfid_protocol_handle *ph, unsigned int page, + unsigned char *tx_data, unsigned int tx_len) +{ + unsigned int i; + unsigned char tx[6]; + unsigned char rx[10]; + unsigned int rx_len = sizeof(rx); + int ret; + + if (tx_len != 4 || page > MIFARE_UL_PAGE_MAX) + return -EINVAL; + + tx[0] = MIFARE_UL_CMD_WRITE; + tx[1] = page & 0xff; + + for (i = 0; i < 4; i++) + tx[2+i] = tx_data[i]; + + ret = ph->l2h->l2->fn.transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR, + tx, sizeof(tx), rx, &rx_len, + MIFARE_UL_WRITE_FWT, 0); + + if (ret < 0) + return ret; + + if (rx[0] != MIFARE_UL_RESP_ACK) + return -EIO; + + return ret; +} + +static int +mful_transcieve(struct rfid_protocol_handle *ph, + const unsigned char *tx_data, unsigned int tx_len, + unsigned char *rx_data, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + return -EINVAL; +} + +static struct rfid_protocol_handle * +mful_init(struct rfid_layer2_handle *l2h) +{ + struct rfid_protocol_handle *ph; + ph = malloc(sizeof(struct rfid_protocol_handle)); + return ph; +} + +static int mful_fini(struct rfid_protocol_handle *ph) +{ + free(ph); + return 0; +} + +struct rfid_protocol rfid_protocol_mful = { + .id = RFID_PROTOCOL_MIFARE_UL, + .name = "Mifare Ultralight", + .fn = { + .init = &mful_init, + .read = &mful_read, + .write = &mful_write, + .fini = &mful_fini, + }, +}; + +/* Functions below are not (yet? covered in the generic librfid api */ + + +/* lock a certain page */ +int rfid_mful_lock_page(struct rfid_protocol_handle *ph, unsigned int page) +{ + unsigned char buf[4] = { 0x00, 0x00, 0x00, 0x00 }; + + if (ph->proto != &rfid_protocol_mful) + return -EINVAL; + + if (page < 3 || page > 15) + return -EINVAL; + + if (page > 8) + buf[2] = (1 << page); + else + buf[3] = (1 << (page - 8)); + + return mful_write(ph, MIFARE_UL_PAGE_LOCK, buf, sizeof(buf)); +} + +/* convenience wrapper to lock the otp page */ +int rfid_mful_lock_otp(struct rfid_protocol_handle *ph) +{ + return rfid_mful_lock_page(ph, MIFARE_UL_PAGE_OTP); +} diff --git a/src/rfid_proto_tcl.c b/src/rfid_proto_tcl.c new file mode 100644 index 0000000..f070614 --- /dev/null +++ b/src/rfid_proto_tcl.c @@ -0,0 +1,694 @@ +/* ISO 14443-4 (T=CL) implementation, PCD side. + * + * (C) 2005 by Harald Welte + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "rfid_iso14443_common.h" + +#if 1 +#ifdef DEBUGP +#undef DEBUGP +#define DEBUGP(x, ...) +#define DEBUGPC(x, ...) +#endif +#endif + +static enum rfid_frametype l2_to_frame(unsigned int layer2) +{ + switch (layer2) { + case RFID_LAYER2_ISO14443A: + return RFID_14443A_FRAME_REGULAR; + break; + case RFID_LAYER2_ISO14443B: + return RFID_14443B_FRAME_REGULAR; + break; + } + return 0; +} + +static unsigned int sfgi_to_sfgt(struct rfid_protocol_handle *h, + unsigned char sfgi) +{ + unsigned int multiplier; + unsigned int tmp; + + if (sfgi > 14) + sfgi = 14; + + multiplier = 1 << sfgi; /* 2 to the power of sfgi */ + + /* ISO 14443-4:2000(E) Section 5.2.5: + * (256 * 16 / h->l2h->rh->ah->fc) * (2 ^ sfgi) */ + tmp = (unsigned int) 1000000 * 256 * 16; + + return (tmp / h->l2h->rh->ah->fc) * multiplier; +} + +static unsigned int fwi_to_fwt(struct rfid_protocol_handle *h, + unsigned char fwi) +{ + unsigned int multiplier, tmp; + + if (fwi > 14) + fwi = 14; + + multiplier = 1 << fwi; /* 2 to the power of fwi */ + + /* ISO 14443-4:2000(E) Section 7.2.: + * (256*16 / h->l2h->rh->ah->fc) * (2 ^ fwi) */ + + tmp = (unsigned int) 1000000 * 256 * 16; + + return (tmp / h->l2h->rh->ah->fc) * multiplier; +} + +/* 4.9seconds as microseconds (4.9 billion seconds) exceeds 2^32 */ +#define activation_fwt(x) (((u_int64_t)1000000 * 65536 / x->l2h->rh->ah->fc)) +#define deactivation_fwt(x) activation_fwt(x) + +static int +tcl_parse_ats(struct rfid_protocol_handle *h, + unsigned char *ats, unsigned int size) +{ + unsigned char len = ats[0]; + unsigned char t0; + unsigned char *cur; + + if (len == 0 || size == 0) + return -1; + + if (size < len) + len = size; + + h->priv.tcl.ta = 0; + + if (len == 1) { + /* FIXME: assume some default values */ + h->priv.tcl.fsc = 32; + h->priv.tcl.ta = 0x80; /* 0x80 (same d for both dirs) */ + h->priv.tcl.sfgt = sfgi_to_sfgt(h, 0); + if (h->l2h->l2->id == RFID_LAYER2_ISO14443A) { + /* Section 7.2: fwi default for type A is 4 */ + h->priv.tcl.fwt = fwi_to_fwt(h, 4); + } else { + /* Section 7.2: fwi for type B is always in ATQB */ + /* Value is assigned in tcl_connect() */ + /* This function is never called for Type B, since it has no (R)ATS */ + } + return 0; + } + + /* guarateed to be at least 2 bytes in size */ + + t0 = ats[1]; + cur = &ats[2]; + + iso14443_fsdi_to_fsd(&h->priv.tcl.fsc, t0 & 0x0f); + + if (t0 & (1 << 4)) { + /* TA is transmitted */ + h->priv.tcl.ta = *cur++; + } + + if (t0 & (1 << 5)) { + /* TB is transmitted */ + h->priv.tcl.sfgt = sfgi_to_sfgt(h, *cur & 0x0f); + h->priv.tcl.fwt = fwi_to_fwt(h, (*cur & 0xf0) >> 4); + cur++; + } + + if (t0 & (1 << 6)) { + /* TC is transmitted */ + if (*cur & 0x01) + h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED; + if (*cur & 0x02) + h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED; + cur++; + } + + h->priv.tcl.historical_len = (ats+len) - cur; + h->priv.tcl.historical_bytes = cur; + + return 0; +} + + +/* request an ATS from the PICC */ +static int +tcl_request_ats(struct rfid_protocol_handle *h) +{ + int ret; + unsigned char rats[2]; + unsigned char fsdi; + + if (h->priv.tcl.state != TCL_STATE_INITIAL) + return -1; + + ret = iso14443_fsd_to_fsdi(&fsdi, h->priv.tcl.fsd); + if (ret < 0) { + DEBUGP("unable to encode FSD of %u as FSDI\n", h->priv.tcl.fsd); + return ret; + } + + rats[0] = 0xe0; + rats[1] = (h->priv.tcl.cid & 0x0f) | ((fsdi << 4) & 0xf0); + + /* transcieve (with CRC) */ + ret = h->l2h->l2->fn.transcieve(h->l2h, RFID_14443A_FRAME_REGULAR, + rats, 2, h->priv.tcl.ats, + &h->priv.tcl.ats_len, activation_fwt(h), + TCL_TRANSP_F_TX_CRC); + if (ret < 0) { + DEBUGP("transcieve of rats failed\n"); + h->priv.tcl.state = TCL_STATE_RATS_SENT; + /* FIXME: retransmit */ + return ret; + } + h->priv.tcl.state = TCL_STATE_ATS_RCVD; + + ret = tcl_parse_ats(h, h->priv.tcl.ats, h->priv.tcl.ats_len); + if (ret < 0) { + DEBUGP("parsing of ats failed\n"); + return ret; + } + + return 0; +} + +#define ATS_TA_DIV_2 1 +#define ATS_TA_DIV_4 2 +#define ATS_TA_DIV_8 4 + +#define PPS_DIV_8 3 +#define PPS_DIV_4 2 +#define PPS_DIV_2 1 +#define PPS_DIV_1 0 +static unsigned char d_to_di(struct rfid_protocol_handle *h, unsigned char D) +{ + static char DI; + unsigned int speed = h->l2h->rh->reader->iso14443a.speed; + + if ((D & ATS_TA_DIV_8) && (speed & RFID_READER_SPEED_848K)) + DI = PPS_DIV_8; + else if ((D & ATS_TA_DIV_4) && (speed & RFID_READER_SPEED_424K)) + DI = PPS_DIV_4; + else if ((D & ATS_TA_DIV_2) && (speed & RFID_READER_SPEED_212K)) + DI = PPS_DIV_2; + else + DI = PPS_DIV_1; + + return DI; +} + + +/* start a PSS run (autimatically configure highest possible speed */ +static int +tcl_do_pps(struct rfid_protocol_handle *h) +{ +#if 0 + int ret; + unsigned char ppss[3]; + unsigned char pps_response[1]; + unsigned int rx_len = 1; + unsigned char Dr, Ds, DrI, DsI; + + if (h->priv.tcl.state != TCL_STATE_ATS_RCVD) + return -1; + + Dr = h->priv.tcl.ta & 0x07; + Ds = h->priv.tcl.ta & 0x70 >> 4; + + if (Dr != Ds && !(h->priv.tcl.ta & 0x80)) { + /* device supports different divisors for rx and tx, but not ?!? */ + DEBUGP("PICC has contradictory TA, aborting PPS\n"); + return -1; + }; + + /* ISO 14443-4:2000(E) Section 5.3. */ + + ppss[0] = 0xd0 & (h->priv.tcl.cid & 0x0f); + ppss[1] = 0x11; + + /* FIXME: deal with different speed for each direction */ + DrI = d_to_di(h, Dr); + DsI = d_to_di(h, Ds); + + ppss[2] = (ppss[2] & 0xf0) | (DrI | DsI << 2); + + ret = h->l2h->l2->fn.transcieve(h->l2h, ppss, 3, pps_response, + &rx_len, h->priv.tcl.fwt, + TCL_TRANSP_F_TX_CRC); + if (ret < 0) + return ret; + + if (pps_response[0] != ppss[0]) { + DEBUGP("PPS Response != PPSS\n"); + return -1; + } + + h->priv.tcl.state = TCL_STATE_ESTABLISHED; +#endif + return 0; +} + + +static int +tcl_build_prologue2(struct tcl_handle *th, + unsigned char *prlg, unsigned int *prlg_len, + unsigned char pcb) +{ + *prlg_len = 1; + + *prlg = pcb; + + if (th->toggle) { + /* we've sent a toggle bit last time */ + th->toggle = 0; + } else { + /* we've not sent a toggle last time: send one */ + th->toggle = 1; + *prlg |= 0x01; + } + + if (th->flags & TCL_HANDLE_F_CID_USED) { + /* ISO 14443-4:2000(E) Section 7.1.1.2 */ + *prlg |= TCL_PCB_CID_FOLLOWING; + (*prlg_len)++; + prlg[*prlg_len] = th->cid & 0x0f; + } + + /* nad only for I-block (0xc0 == 00) */ + if ((th->flags & TCL_HANDLE_F_NAD_USED) && + ((pcb & 0xc0) == 0x00)) { + /* ISO 14443-4:2000(E) Section 7.1.1.3 */ + /* FIXME: in case of chaining only for first frame */ + *prlg |= TCL_PCB_NAD_FOLLOWING; + prlg[*prlg_len] = th->nad; + (*prlg_len)++; + } + + return 0; +} + +static int +tcl_build_prologue_i(struct tcl_handle *th, + unsigned char *prlg, unsigned int *prlg_len) +{ + /* ISO 14443-4:2000(E) Section 7.1.1.1 */ + return tcl_build_prologue2(th, prlg, prlg_len, 0x02); +} + +static int +tcl_build_prologue_r(struct tcl_handle *th, + unsigned char *prlg, unsigned int *prlg_len, + unsigned int nak) +{ + unsigned char pcb = 0xa2; + /* ISO 14443-4:2000(E) Section 7.1.1.1 */ + + if (nak) + pcb |= 0x10; + + return tcl_build_prologue2(th, prlg, prlg_len, pcb); +} + +static int +tcl_build_prologue_s(struct tcl_handle *th, + unsigned char *prlg, unsigned int *prlg_len) +{ + /* ISO 14443-4:2000(E) Section 7.1.1.1 */ + + /* the only S-block from PCD->PICC is DESELECT, + * well, actually there is the S(WTX) response. */ + return tcl_build_prologue2(th, prlg, prlg_len, 0xc2); +} + +/* FIXME: WTXM implementation */ + +static int tcl_prlg_len(struct tcl_handle *th) +{ + int prlg_len = 1; + + if (th->flags & TCL_HANDLE_F_CID_USED) + prlg_len++; + + if (th->flags & TCL_HANDLE_F_NAD_USED) + prlg_len++; + + return prlg_len; +} + +#define max_net_tx_framesize(x) (x->fsc - tcl_prlg_len(x)) + +static int +tcl_connect(struct rfid_protocol_handle *h) +{ + int ret; + + if (h->priv.tcl.state != TCL_STATE_DESELECTED && + h->priv.tcl.state != TCL_STATE_INITIAL) + return -1; + + switch (h->l2h->l2->id) { + case RFID_LAYER2_ISO14443A: + /* Start Type A T=CL Activation Sequence */ + ret = tcl_request_ats(h); + if (ret < 0) + return ret; + + /* Only do PPS if any non-default divisors supported */ + if (h->priv.tcl.ta & 0x77) { + ret = tcl_do_pps(h); + if (ret < 0) + return ret; + } + break; + case RFID_LAYER2_ISO14443B: + /* initialized T=CL state from Type B Activation Data */ + h->priv.tcl.cid = h->l2h->priv.iso14443b.cid; + h->priv.tcl.fsc = h->l2h->priv.iso14443b.fsc; + h->priv.tcl.fsd = h->l2h->priv.iso14443b.fsd; + h->priv.tcl.fwt = h->l2h->priv.iso14443b.fwt; + + /* what about ta? sfgt? */ + + if (h->l2h->priv.iso14443b.flags & ISO14443B_CID_SUPPORTED) + h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED; + if (h->l2h->priv.iso14443b.flags & ISO14443B_NAD_SUPPORTED) + h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED; + + switch (h->l2h->priv.iso14443b.state) { + case ISO14443B_STATE_SELECTED: + h->priv.tcl.state = TCL_STATE_ATS_RCVD; + break; + case ISO14443B_STATE_ATTRIB_SENT: + h->priv.tcl.state = TCL_STATE_RATS_SENT; + break; + } + + /* PUPI will be presented as ATS/historical bytes */ + memcpy(h->priv.tcl.ats, h->l2h->uid, 4); + h->priv.tcl.ats_len = 4; + h->priv.tcl.historical_bytes = h->priv.tcl.ats; + + break; + default: + DEBUGP("unsupported l2: %u\n", h->l2h->l2->id); + return -1; + break; + } + + return 0; +} + +static int +tcl_deselect(struct rfid_protocol_handle *h) +{ + /* ISO 14443-4:2000(E) Section 8 */ + int ret; + unsigned char frame[3]; /* 3 bytes prologue, no information */ + unsigned char rx[3]; + unsigned int rx_len = sizeof(rx); + unsigned int prlg_len; + struct tcl_handle *th = &h->priv.tcl; + + if (th->state != TCL_STATE_ESTABLISHED) { + /* FIXME: not sure whether deselect is possible here, + * probably better send a HLTA? */ + } + + /* build DESELECT S-block */ + ret = tcl_build_prologue_s(th, frame, &prlg_len); + if (ret < 0) + return ret; + + ret = h->l2h->l2->fn.transcieve(h->l2h, RFID_14443A_FRAME_REGULAR, + frame, prlg_len, rx, + &rx_len, deactivation_fwt(h), + TCL_TRANSP_F_TX_CRC); + if (ret < 0) { + /* FIXME: retransmit, HLT(A|B) */ + return ret; + } + + th->state = TCL_STATE_DESELECTED; + + return 0; +} + +#define is_s_block(x) ((x & 0xc0) == 0xc0) +#define is_r_block(x) ((x & 0xc0) == 0x80) +#define is_i_block(x) ((x & 0xc0) == 0x00) + +static int +tcl_transcieve(struct rfid_protocol_handle *h, + const unsigned char *tx_data, unsigned int tx_len, + unsigned char *rx_data, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + int ret; + unsigned char *tx_buf, *rx_buf; + unsigned char *_rx_data = rx_data; + unsigned int _rx_len; + unsigned int max_rx_len = *rx_len; /* maximum number of payoload that + caller has requested */ + unsigned int prlg_len; + struct tcl_handle *th = &h->priv.tcl; + + unsigned char *_tx; + unsigned int _tx_len, _timeout; + unsigned char wtx_resp[3]; + unsigned char ack[10]; + unsigned int ack_len; + + if (tx_len > max_net_tx_framesize(th)) { + /* slow path: we need to use chaining */ + return -1; + } + + tx_buf = malloc(tcl_prlg_len(th) + tx_len); + if (!tx_buf) { + ret = -ENOMEM; + goto out; + } + rx_buf = malloc(tcl_prlg_len(th) + *rx_len); + if (!rx_buf) { + ret = -ENOMEM; + goto out_txb; + } + + if (tcl_build_prologue_i(th, tx_buf, &prlg_len) < 0) { + ret = -1; + goto out_rxb; + } + memcpy(tx_buf + prlg_len, tx_data, tx_len); + + /* intialize to data-to-be-transferred */ + _tx = tx_buf; + _tx_len = tx_len+prlg_len; + _timeout = th->fwt; + _rx_len = *rx_len; + *rx_len = 0; + +do_tx: + ret = h->l2h->l2->fn.transcieve(h->l2h, l2_to_frame(h->l2h->l2->id), + _tx, _tx_len, + rx_buf, &_rx_len, _timeout, 0); + DEBUGP("l2 transcieve finished\n"); + if (ret < 0) + goto out_rxb; + + if ((*rx_buf & 0x01) != h->priv.tcl.toggle) { + DEBUGP("response with wrong toggle bit\n"); + goto out_rxb; + } + + if (is_r_block(*rx_buf)) { + unsigned int txed = _tx - tx_buf; + DEBUGP("R-Block\n"); + /* Handle ACK frame in case of chaining */ + if (*rx_buf & TCL_PCB_CID_FOLLOWING) { + if (*(rx_buf+1) != h->priv.tcl.cid) { + DEBUGP("CID %u is not valid\n", *(rx_buf)+1); + goto out_rxb; + } + } + /* set up parameters for next frame in chain */ + if (txed < tx_len) { + /* move tx pointer by the amount of bytes transferred + * in last frame */ + _tx += _tx_len; + _tx_len = (tx_len - txed); + if (_tx_len > max_net_tx_framesize(th)) { + /* not last frame in chain */ + _tx_len = max_net_tx_framesize(th); + } else { + /* last frame in chain */ + } + goto do_tx; + } else { + DEBUGP("Received ACK in response to last frame in " + "chain?!? Expected I-frame.\n"); + ret = -1; + goto out_rxb; + } + } else if (is_s_block(*rx_buf)) { + unsigned char inf; + unsigned int prlg_len; + + DEBUGP("S-Block\n"); + /* Handle Wait Time Extension */ + if (*rx_buf & TCL_PCB_CID_FOLLOWING) { + if (_rx_len < 3) { + DEBUGP("S-Block with CID but short len\n"); + ret = -1; + goto out_rxb; + } + if (*(rx_buf+1) != h->priv.tcl.cid) { + DEBUGP("CID %u is not valid\n", *(rx_buf)+1); + goto out_rxb; + } + inf = *(rx_buf+2); + } else + inf = *(rx_buf+1); + + if ((*rx_buf & 0x30) != 0x30) { + DEBUGP("S-Block but not WTX?\n"); + ret = -1; + goto out_rxb; + } + inf &= 0x3f; /* only lower 6 bits code WTXM */ + if (inf == 0 || (inf >= 60 && inf <= 63)) { + DEBUGP("WTXM %u is RFU!\n", inf); + ret = -1; + goto out_rxb; + } + + /* Acknowledge WTXM */ + tcl_build_prologue_s(&h->priv.tcl, wtx_resp, &prlg_len); + /* set two bits that make this block a wtx */ + wtx_resp[0] |= 0x30; + wtx_resp[prlg_len] = inf; + _tx = wtx_resp; + _tx_len = prlg_len+1; + _timeout = th->fwt * inf; + + /* start over with next transcieve */ + goto do_tx; /* FIXME: do transcieve locally since we use + totally different buffer */ + + } else if (is_i_block(*rx_buf)) { + unsigned char *inf = rx_buf+1; + unsigned int net_payload_len; + /* we're actually receiving payload data */ + + DEBUGP("I-Block: "); + if (*rx_buf & TCL_PCB_CID_FOLLOWING) { + if (*(rx_buf+1) != h->priv.tcl.cid) { + DEBUGPC("CID %u is not valid\n", *(rx_buf)+1); + goto out_rxb; + } + inf++; + } + if (*rx_buf & TCL_PCB_NAD_FOLLOWING) { + inf++; + } + net_payload_len = _rx_len - (inf - rx_buf); + DEBUGPC("%u bytes\n", net_payload_len); + memcpy(_rx_data, inf, net_payload_len); + /* increment the number of payload bytes that we actually received */ + *rx_len += net_payload_len; + _rx_data += net_payload_len; + + if (*rx_buf & 0x10) { + /* we're not the last frame in the chain, continue rx */ + DEBUGP("we're not the last frame in the chain, continue\n"); + ack_len = sizeof(ack); + tcl_build_prologue_r(&h->priv.tcl, ack, &ack_len, 0); + _tx = ack; + _tx_len = ack_len; + goto do_tx; + } + } + +out_rxb: + free(rx_buf); +out_txb: + free(tx_buf); +out: + return ret; +} + +static struct rfid_protocol_handle * +tcl_init(struct rfid_layer2_handle *l2h) +{ + struct rfid_protocol_handle *th; + unsigned int mru = l2h->rh->ah->mru; + + th = malloc(sizeof(struct rfid_protocol_handle) + mru); + if (!th) + return NULL; + + /* FIXME: mru should be attribute of layer2 (in case it adds/removes + * some overhead */ + memset(th, 0, sizeof(struct rfid_protocol_handle) + mru); + + /* maximum received ats length equals mru of asic/reader */ + th->priv.tcl.state = TCL_STATE_INITIAL; + th->priv.tcl.ats_len = mru; + th->priv.tcl.toggle = 1; + + th->priv.tcl.fsd = iso14443_fsd_approx(mru); + + return th; +} + +static int +tcl_fini(struct rfid_protocol_handle *ph) +{ + free(ph); + return 0; +} + +struct rfid_protocol rfid_protocol_tcl = { + .id = RFID_PROTOCOL_TCL, + .name = "ISO 14443-4 / T=CL", + .fn = { + .init = &tcl_init, + .open = &tcl_connect, + .transcieve = &tcl_transcieve, + .close = &tcl_deselect, + .fini = &tcl_fini, + }, +}; diff --git a/src/rfid_protocol.c b/src/rfid_protocol.c new file mode 100644 index 0000000..abbd04d --- /dev/null +++ b/src/rfid_protocol.c @@ -0,0 +1,113 @@ +/* librfid - layer 3 protocol handler + * (C) 2005 by Harald Welte + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include + +#include +#include + +static struct rfid_protocol *rfid_protocol_list; + +struct rfid_protocol_handle * +rfid_protocol_init(struct rfid_layer2_handle *l2h, unsigned int id) +{ + struct rfid_protocol *p; + struct rfid_protocol_handle *ph = NULL; + + for (p = rfid_protocol_list; p; p = p->next) { + if (p->id == id) { + ph = p->fn.init(l2h); + break; + } + } + + if (!ph) + return NULL; + + ph->proto = p; + ph->l2h = l2h; + + return ph; +} + +int +rfid_protocol_open(struct rfid_protocol_handle *ph) +{ + if (ph->proto->fn.open) + return ph->proto->fn.open(ph); + return 0; +} + +int +rfid_protocol_transcieve(struct rfid_protocol_handle *ph, + const unsigned char *tx_buf, unsigned int len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + return ph->proto->fn.transcieve(ph, tx_buf, len, rx_buf, rx_len, + timeout, flags); +} + +int +rfid_protocol_read(struct rfid_protocol_handle *ph, + unsigned int page, + unsigned char *rx_data, + unsigned int *rx_len) +{ + if (ph->proto->fn.read) + return ph->proto->fn.read(ph, page, rx_data, rx_len); + else + return -EINVAL; +} + +int +rfid_protocol_write(struct rfid_protocol_handle *ph, + unsigned int page, + unsigned char *tx_data, + unsigned int tx_len) +{ + if (ph->proto->fn.write) + return ph->proto->fn.write(ph, page, tx_data, tx_len); + else + return -EINVAL; +} + +int rfid_protocol_fini(struct rfid_protocol_handle *ph) +{ + return ph->proto->fn.fini(ph); +} + +int +rfid_protocol_close(struct rfid_protocol_handle *ph) +{ + if (ph->proto->fn.close) + return ph->proto->fn.close(ph); + return 0; +} + +int +rfid_protocol_register(struct rfid_protocol *p) +{ + p->next = rfid_protocol_list; + rfid_protocol_list = p; + + return 0; +} diff --git a/src/rfid_reader.c b/src/rfid_reader.c new file mode 100644 index 0000000..9e46a29 --- /dev/null +++ b/src/rfid_reader.c @@ -0,0 +1,65 @@ +/* librfid - core reader handling + * (C) 2005 by Harald Welte + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include + +#include +#include + +static struct rfid_reader *rfid_reader_list; + +struct rfid_reader_handle * +rfid_reader_open(void *data, unsigned int id) +{ + struct rfid_reader *p; + + for (p = rfid_reader_list; p; p = p->next) + if (p->id == id) + return p->open(data); + + DEBUGP("unable to find matching reader\n"); + return NULL; +} + +int +rfid_reader_transcieve(struct rfid_reader_handle *rh, + enum rfid_frametype frametype, + const unsigned char *tx_buf, unsigned int len, + unsigned char *rx_buf, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + return rh->reader->transcieve(rh, frametype, tx_buf, len, rx_buf, + rx_len, timeout, flags); +} + +void +rfid_reader_close(struct rfid_reader_handle *rh) +{ + rh->reader->close(rh); +} + +int +rfid_reader_register(struct rfid_reader *r) +{ + r->next = rfid_reader_list; + rfid_reader_list = r; + + return 0; +} diff --git a/src/rfid_reader_cm5121.c b/src/rfid_reader_cm5121.c new file mode 100644 index 0000000..978e18f --- /dev/null +++ b/src/rfid_reader_cm5121.c @@ -0,0 +1,337 @@ +/* Omnikey CardMan 5121 specific RC632 transport layer + * + * (C) 2005 by Harald Welte + * + * The 5121 is an Atmel AT98C5122 based USB CCID reader (probably the same + * design like the 3121). It's CL RC632 is connected via address/data bus, + * not via SPI. + * + * The vendor-supplied reader firmware provides some undocumented extensions + * to CCID (via PC_to_RDR_Escape) that allow access to registers and FIFO of + * the RC632. + * + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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 + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +//#define SENDBUF_LEN 40 +#define SENDBUF_LEN 100 +#define RECVBUF_LEN 40 + +#if 1 +#ifdef DEBUGP +#undef DEBUGP +#define DEBUGP(x, ...) +#define DEBUGPC(x, ...) +#endif +#endif + +static +int Write1ByteToReg(struct rfid_asic_transport_handle *rath, + unsigned char reg, unsigned char value) +{ + unsigned char sndbuf[SENDBUF_LEN]; + unsigned char rcvbuf[RECVBUF_LEN]; + unsigned int retlen = RECVBUF_LEN; + + sndbuf[0] = 0x20; + sndbuf[1] = 0x00; + sndbuf[2] = 0x01; + sndbuf[3] = 0x00; + sndbuf[4] = 0x00; + sndbuf[5] = 0x00; + sndbuf[6] = reg; + sndbuf[7] = value; + + DEBUGP("reg=0x%02x, val=%02x: ", reg, value); + + if (PC_to_RDR_Escape(rath->data, sndbuf, 8, rcvbuf, + &retlen) == 0) { + DEBUGPC("OK\n"); + return 0; + } + + DEBUGPC("ERROR\n"); + return -1; +} + +static int Read1ByteFromReg(struct rfid_asic_transport_handle *rath, + unsigned char reg, + unsigned char *value) +{ + unsigned char sndbuf[SENDBUF_LEN]; + unsigned char recvbuf[RECVBUF_LEN]; + unsigned int retlen = sizeof(recvbuf); + + sndbuf[0] = 0x20; + sndbuf[1] = 0x00; + sndbuf[2] = 0x00; + sndbuf[3] = 0x00; + sndbuf[4] = 0x01; + sndbuf[5] = 0x00; + sndbuf[6] = reg; + + if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf, + &retlen) == 0) { + *value = recvbuf[1]; + DEBUGP("reg=0x%02x, val=%02x: ", reg, *value); + DEBUGPC("OK\n"); + return 0; + } + + DEBUGPC("ERROR\n"); + return -1; +} + +static int ReadNBytesFromFIFO(struct rfid_asic_transport_handle *rath, + unsigned char num_bytes, + unsigned char *buf) +{ + unsigned char sndbuf[SENDBUF_LEN]; + unsigned char recvbuf[0x7f]; + unsigned int retlen = sizeof(recvbuf); + + sndbuf[0] = 0x20; + sndbuf[1] = 0x00; + sndbuf[2] = 0x00; + sndbuf[3] = 0x00; + sndbuf[4] = num_bytes; + sndbuf[5] = 0x00; + sndbuf[6] = 0x02; + + DEBUGP("num_bytes=%u: ", num_bytes); + if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf, &retlen) == 0) { + DEBUGPC("%u [%s]\n", retlen, + rfid_hexdump(recvbuf+1, num_bytes)); + memcpy(buf, recvbuf+1, num_bytes); // len == 0x7f + return 0; + } + + DEBUGPC("ERROR\n"); + return -1; +} + +static int WriteNBytesToFIFO(struct rfid_asic_transport_handle *rath, + unsigned char len, + const unsigned char *bytes, + unsigned char flags) +{ + unsigned char sndbuf[SENDBUF_LEN]; + unsigned char recvbuf[0x7f]; + unsigned int retlen = sizeof(recvbuf); + + sndbuf[0] = 0x20; + sndbuf[1] = 0x00; + sndbuf[2] = len; + sndbuf[3] = 0x00; + sndbuf[4] = 0x00; + sndbuf[5] = flags; + sndbuf[6] = 0x02; + + DEBUGP("%u [%s]: ", len, rfid_hexdump(bytes, len)); + + memcpy(sndbuf+7, bytes, len); + + if (PC_to_RDR_Escape(rath->data, sndbuf, len+7, recvbuf, &retlen) == 0) { + DEBUGPC("OK (%u [%s])\n", retlen, rfid_hexdump(recvbuf, retlen)); + return 0; + } + + DEBUGPC("ERROR\n"); + return -1; +} + +#if 0 +static int TestFIFO(struct rc632_handle *handle) +{ + unsigned char sndbuf[60]; // 0x3c + + // FIXME: repne stosd, call + + memset(sndbuf, 0, sizeof(sndbuf)); + + if (WriteNBytesToFIFO(handle, sizeof(sndbuf), sndbuf, 0) < 0) + return -1; + + return ReadNBytesFromFIFO(handle, sizeof(sndbuf), sndbuf); +} +#endif + +static int cm5121_transcieve(struct rfid_reader_handle *rh, + enum rfid_frametype frametype, + const unsigned char *tx_data, unsigned int tx_len, + unsigned char *rx_data, unsigned int *rx_len, + u_int64_t timeout, unsigned int flags) +{ + return rh->ah->asic->priv.rc632.fn.transcieve(rh->ah, frametype, + tx_data, tx_len, rx_data, + rx_len, timeout, flags); +} + +static int cm5121_transcieve_sf(struct rfid_reader_handle *rh, + unsigned char cmd, struct iso14443a_atqa *atqa) +{ + return rh->ah->asic->priv.rc632.fn.iso14443a.transcieve_sf(rh->ah, + cmd, + atqa); +} + +static int +cm5121_transcieve_acf(struct rfid_reader_handle *rh, + struct iso14443a_anticol_cmd *cmd, + unsigned int *bit_of_col) +{ + return rh->ah->asic->priv.rc632.fn.iso14443a.transcieve_acf(rh->ah, + cmd, bit_of_col); +} + +static int +cm5121_14443a_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso14443a.init(rh->ah); +} + +static int +cm5121_14443b_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso14443b.init(rh->ah); +} + +static int +cm5121_15693_init(struct rfid_reader_handle *rh) +{ + return rh->ah->asic->priv.rc632.fn.iso15693.init(rh->ah); +} + +static int +cm5121_mifare_setkey(struct rfid_reader_handle *rh, const u_int8_t *key) +{ + return rh->ah->asic->priv.rc632.fn.mifare_classic.setkey(rh->ah, key); +} + +static int +cm5121_mifare_auth(struct rfid_reader_handle *rh, u_int8_t cmd, + u_int32_t serno, u_int8_t block) +{ + return rh->ah->asic->priv.rc632.fn.mifare_classic.auth(rh->ah, + cmd, serno, block); +} + +struct rfid_asic_transport cm5121_ccid = { + .name = "CM5121 OpenCT", + .priv.rc632 = { + .fn = { + .reg_write = &Write1ByteToReg, + .reg_read = &Read1ByteFromReg, + .fifo_write = &WriteNBytesToFIFO, + .fifo_read = &ReadNBytesFromFIFO, + }, + }, +}; + +static int cm5121_enable_rc632(struct rfid_asic_transport_handle *rath) +{ + unsigned char tx_buf[1] = { 0x01 }; + unsigned char rx_buf[64]; + unsigned int rx_len = sizeof(rx_buf); + + PC_to_RDR_Escape(rath->data, tx_buf, 1, rx_buf, &rx_len); + printf("received %u bytes from 01 command\n", rx_len); + + return 0; +} + +static struct rfid_reader_handle * +cm5121_open(void *data) +{ + struct rfid_reader_handle *rh; + struct rfid_asic_transport_handle *rath; + + rh = malloc(sizeof(*rh)); + if (!rh) + return NULL; + memset(rh, 0, sizeof(*rh)); + + rath = malloc(sizeof(*rath)); + if (!rath) + goto out_rh; + memset(rath, 0, sizeof(*rath)); + + rath->rat = &cm5121_ccid; + rh->reader = &rfid_reader_cm5121; + + if (cm5121_source_init(rath) < 0) + goto out_rath; + + if (cm5121_enable_rc632(rath) < 0) + goto out_rath; + + rh->ah = rc632_open(rath); + if (!rh->ah) + goto out_rath; + + DEBUGP("returning %p\n", rh); + return rh; + +out_rath: + free(rath); +out_rh: + free(rh); + + return NULL; +} + +static void +cm5121_close(struct rfid_reader_handle *rh) +{ + struct rfid_asic_transport_handle *rath = rh->ah->rath; + rc632_close(rh->ah); + free(rath); + free(rh); +} + +struct rfid_reader rfid_reader_cm5121 = { + .name = "Omnikey CardMan 5121 RFID", + .open = &cm5121_open, + .close = &cm5121_close, + .transcieve = &cm5121_transcieve, + .iso14443a = { + .init = &cm5121_14443a_init, + .transcieve_sf = &cm5121_transcieve_sf, + .transcieve_acf = &cm5121_transcieve_acf, + .speed = RFID_READER_SPEED_106K | RFID_READER_SPEED_212K | + RFID_READER_SPEED_424K | RFID_READER_SPEED_848K, + }, + .iso14443b = { + .init = &cm5121_14443b_init, + }, + .mifare_classic = { + .setkey = &cm5121_mifare_setkey, + .auth = &cm5121_mifare_auth, + }, +}; + + diff --git a/src/rfid_reader_cm5121_ccid_direct.c b/src/rfid_reader_cm5121_ccid_direct.c new file mode 100644 index 0000000..7f53bb7 --- /dev/null +++ b/src/rfid_reader_cm5121_ccid_direct.c @@ -0,0 +1,36 @@ +/* CM5121 backend for 'internal' CCID driver */ +#include +#include +#include + +#include + +#include "ccid/ccid-driver.h" + +/* this is the sole function required by rfid_reader_cm5121.c */ +int +PC_to_RDR_Escape(void *handle, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len) +{ + int rc; + ccid_driver_t ch = handle; + size_t maxrxlen = *rx_len; + + rc = ccid_transceive_escape (ch, tx_buf, tx_len, + rx_buf, maxrxlen, rx_len); + + return rc; +} + +int cm5121_source_init(struct rfid_asic_transport_handle *rath) +{ + int rc; + + rc = ccid_open_reader(&rath->data, NULL); + if (rc) { + fprintf (stderr, "failed to open CCID reader: %#x\n", rc); + return -1; + } + return 0; +} diff --git a/src/rfid_reader_cm5121_openct.c b/src/rfid_reader_cm5121_openct.c new file mode 100644 index 0000000..9d96638 --- /dev/null +++ b/src/rfid_reader_cm5121_openct.c @@ -0,0 +1,59 @@ +/* CM5121 backend for OpenCT virtual slot */ + +#include + +#include +#include + +/* FIXME: get rid of this global crap. In fact this needs to become part of + * struct rfid_reader_handle */ +static ct_lock_handle lock; +static int slot = 1; + +/* this is the sole function required by rfid_reader_cm5121.c */ +int +PC_to_RDR_Escape(void *handle, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len) +{ + int rc; + ct_handle *h = (ct_handle *) handle; + + rc = ct_card_transact(h, 1, tx_buf, tx_len, rx_buf, *rx_len); + if (rc >= 0) { + *rx_len = rc; + return 0; + } + + return rc; +} + + +int cm5121_source_init(struct rfid_asic_transport_handle *rath) +{ + struct ct_handle *h; + int rc; + unsigned char atr[64]; + + h = ct_reader_connect(0); + if (!h) + return -1; + + printf("acquiring card lock\n"); + rc = ct_card_lock(h, slot, IFD_LOCK_EXCLUSIVE, &lock); + if (rc < 0) { + fprintf(stderr, "error, no card lock\n"); + return -1; + } + + rc = ct_card_reset(h, slot, atr, sizeof(atr)); + if (rc < 0) { + fprintf(stderr, "error, can't reset virtual card\n"); + return -1; + } + + rath->data = h; + + return 0; +} + -- cgit v1.2.3