X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=src%2Frfid_layer2_iso14443a.c;h=528c5fb8d426278fb5f618d1f7f7982d9b0017d7;hb=248a277403de24869114e75330fa3317199bf7e8;hp=d93f91770f0c606646e1c792be662a2c5f562a05;hpb=05c7e304271bcf88901da3782fcd3f28a0c7c9cf;p=librfid diff --git a/src/rfid_layer2_iso14443a.c b/src/rfid_layer2_iso14443a.c index d93f917..528c5fb 100644 --- a/src/rfid_layer2_iso14443a.c +++ b/src/rfid_layer2_iso14443a.c @@ -1,6 +1,6 @@ /* ISO 14443-3 A anticollision implementation * - * (C) 2005 by Harald Welte + * (C) 2005-2006 by Harald Welte * */ @@ -16,51 +16,58 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include +#include +#ifdef __MINGW32__ +#include +#endif/*__MINGW32__*/ -#include -#include -#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 long randctx[4]={0x22d4a017,0x773a1f44,0xc39e1460,0x9cde8801}; + +/* Transceive a 7-bit short frame */ +int +iso14443a_transceive_sf(struct rfid_layer2_handle *handle, unsigned char cmd, struct iso14443a_atqa *atqa) { - struct rfid_reader *rdr = handle->rh->reader; + const struct rfid_reader *rdr = handle->rh->reader; - return rdr->iso14443a.transcieve_sf(handle->rh, cmd, atqa); + return rdr->iso14443a.transceive_sf(handle->rh, cmd, atqa); } /* Transmit an anticollission bit frame */ static int -iso14443a_transcieve_acf(struct rfid_layer2_handle *handle, +iso14443a_transceive_acf(struct rfid_layer2_handle *handle, struct iso14443a_anticol_cmd *acf, unsigned int *bit_of_col) { - struct rfid_reader *rdr = handle->rh->reader; + const struct rfid_reader *rdr = handle->rh->reader; - return rdr->iso14443a.transcieve_acf(handle->rh, acf, bit_of_col); + return rdr->iso14443a.transceive_acf(handle->rh, acf, bit_of_col); } /* Transmit a regular frame */ static int -iso14443a_transcieve(struct rfid_layer2_handle *handle, +iso14443a_transceive(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, + return handle->rh->reader->transceive(handle->rh, frametype, tx_buf, tx_len, rx_buf, rx_len, timeout, flags); } @@ -78,57 +85,77 @@ iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits) return 0; } +static int random_bit(void) +{ + unsigned long e; + + e = randctx[0]; + randctx[0] = randctx[1]; + randctx[1] = (randctx[2]<<19) + (randctx[2]>>13) + randctx[3]; + randctx[2] = randctx[3] ^ randctx[0]; + randctx[3] = e+randctx[1]; + + return randctx[1]&1; +} + /* first bit is '1', second bit '2' */ static void -set_bit_in_field(unsigned char *bitfield, unsigned int bit) +rnd_toggle_bit_in_field(unsigned char *bitfield, unsigned int size, 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)); + unsigned int byte,rnd; + + if (bit && (bit <= (size*8))) { + rnd = random_bit(); + + DEBUGP("xor'ing bit %u with %u\n",bit,rnd); + bit--; + byte = bit/8; + bit = rnd << (bit % 8); + bitfield[byte] ^= bit; + } } + 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_atqa *atqa = &h->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; + char *aqptr = (char *) atqa; memset(handle->uid, 0, sizeof(handle->uid)); memset(sak, 0, sizeof(sak)); - memset(&atqa, 0, sizeof(atqa)); + memset(atqa, 0, sizeof(&atqa)); memset(&acf, 0, sizeof(acf)); - ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa); + if (handle->flags & RFID_OPT_LAYER2_WUP) + ret = iso14443a_transceive_sf(handle, ISO14443A_SF_CMD_WUPA, atqa); + else + ret = iso14443a_transceive_sf(handle, ISO14443A_SF_CMD_REQA, atqa); if (ret < 0) { h->state = ISO14443A_STATE_REQA_SENT; - DEBUGP("error during transcieve_sf: %d\n", ret); + DEBUGP("error during transceive_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) { + 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) + if (atqa->uid_size == 2 || atqa->uid_size == 3) uid_size = 3; - else if (atqa.uid_size == 1) + else if (atqa->uid_size == 1) uid_size = 2; else uid_size = 1; @@ -139,24 +166,27 @@ iso14443a_anticol(struct rfid_layer2_handle *handle) h->level = ISO14443A_LEVEL_CL1; cascade: + rx_len = sizeof(sak); iso14443a_code_nvb_bits(&acf.nvb, 16); - ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col); + ret = iso14443a_transceive_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); + DEBUGP("collision at pos %u\n", bit_of_col); + 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); + rnd_toggle_bit_in_field(acf.uid_bits, sizeof(acf.uid_bits), bit_of_col); + DEBUGP("acf: nvb=0x%02X uid_bits=%s\n",acf.nvb,rfid_hexdump(acf.uid_bits,sizeof(acf.uid_bits))); + ret = iso14443a_transceive_acf(handle, &acf, &bit_of_col); if (ret < 0) return ret; } iso14443a_code_nvb_bits(&acf.nvb, 7*8); - ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR, + + ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, (unsigned char *)&acf, 7, (unsigned char *) &sak, &rx_len, TIMEOUT, 0); @@ -207,13 +237,10 @@ cascade: } } - h->level = ISO14443A_LEVEL_NONE; - h->state = ISO14443A_STATE_SELECTED; - { - if (uid_size == 1) + if (h->level == ISO14443A_LEVEL_CL1) handle->uid_len = 4; - else if (uid_size == 2) + else if (h->level == ISO14443A_LEVEL_CL2) handle->uid_len = 7; else handle->uid_len = 10; @@ -221,11 +248,18 @@ cascade: DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len)); } + h->level = ISO14443A_LEVEL_NONE; + h->state = ISO14443A_STATE_SELECTED; + h->sak = sak[0]; + if (sak[0] & 0x20) { DEBUGP("we have a T=CL compliant PICC\n"); + handle->proto_supported = 1 << RFID_PROTOCOL_TCL; h->tcl_capable = 1; } else { DEBUGP("we have a T!=CL PICC\n"); + handle->proto_supported = (1 << RFID_PROTOCOL_MIFARE_UL)| + (1 << RFID_PROTOCOL_MIFARE_CLASSIC); h->tcl_capable = 0; } @@ -240,7 +274,7 @@ iso14443a_hlta(struct rfid_layer2_handle *handle) unsigned char rx_buf[10]; unsigned int rx_len = sizeof(rx_buf); - ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR, + ret = iso14443a_transceive(handle, RFID_14443A_FRAME_REGULAR, tx_buf, sizeof(tx_buf), rx_buf, &rx_len, 1000 /* 1ms */, 0); if (ret < 0) { @@ -250,22 +284,94 @@ iso14443a_hlta(struct rfid_layer2_handle *handle) return -1; } +static int +iso14443a_setopt(struct rfid_layer2_handle *handle, int optname, + const void *optval, unsigned int optlen) +{ + int ret = -EINVAL; + const struct rfid_reader *rdr = handle->rh->reader; + unsigned int speed; + + switch (optname) { + case RFID_OPT_14443A_SPEED_RX: + if (!rdr->iso14443a.set_speed) + return -ENOTSUP; + speed = *(unsigned int *)optval; + ret = rdr->iso14443a.set_speed(handle->rh, 0, speed); + break; + case RFID_OPT_14443A_SPEED_TX: + if (!rdr->iso14443a.set_speed) + return -ENOTSUP; + speed = *(unsigned int *)optval; + ret = rdr->iso14443a.set_speed(handle->rh, 1, speed); + break; + case RFID_OPT_14443A_WUPA: + if((unsigned int*)optval) + handle->flags |= RFID_OPT_LAYER2_WUP; + else + handle->flags &= ~RFID_OPT_LAYER2_WUP; + ret = 0; + break; + }; + + return ret; +} + +static int +iso14443a_getopt(struct rfid_layer2_handle *handle, int optname, + void *optval, unsigned int *optlen) +{ + int ret = -EINVAL; + struct iso14443a_handle *h = &handle->priv.iso14443a; + struct iso14443a_atqa *atqa = optval; + u_int8_t *opt_u8 = optval; + int *wupa = optval; + + switch (optname) { + case RFID_OPT_14443A_SAK: + *opt_u8 = h->sak; + *optlen = sizeof(*opt_u8); + break; + case RFID_OPT_14443A_ATQA: + *atqa = h->atqa; + *optlen = sizeof(*atqa) + ret = 0; + break; + case RFID_OPT_14443A_WUPA: + *wupa = ((handle->flags & RFID_OPT_LAYER2_WUP) != 0); + *optlen = sizeof(*wupa); + ret = 0; + break; + }; + + return ret; +} + + static struct rfid_layer2_handle * iso14443a_init(struct rfid_reader_handle *rh) { int ret; - struct rfid_layer2_handle *h = malloc(sizeof(*h)); + struct rfid_layer2_handle *h = malloc_layer2_handle(sizeof(*h)); if (!h) return NULL; + memset(h, 0, sizeof(*h)); + +#ifdef __MINGW32__ + randctx[0] ^= GetTickCount(); +#endif/*__MINGW32__*/ + for(ret=0;ret<23;ret++) + random_bit(); + 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); + ret = h->rh->reader->init(h->rh, RFID_LAYER2_ISO14443A); if (ret < 0) { - free(h); + free_layer2_handle(h); return NULL; } @@ -275,20 +381,22 @@ iso14443a_init(struct rfid_reader_handle *rh) static int iso14443a_fini(struct rfid_layer2_handle *handle) { - free(handle); + free_layer2_handle(handle); return 0; } -struct rfid_layer2 rfid_layer2_iso14443a = { +const 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, + .transceive = &iso14443a_transceive, .close = &iso14443a_hlta, .fini = &iso14443a_fini, + .setopt = &iso14443a_setopt, + .getopt = &iso14443a_getopt, }, };