X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=rfid_proto_tcl.c;h=248eea5724272d1b873743102657c76aac68ea9d;hb=99030a0cac259d059926f68970e6562c2cfe4c1e;hp=299360e67bc84285d1dae68f9095f46394ab01fc;hpb=8bcc201799604278c4224d719eb49c97fd488252;p=librfid diff --git a/rfid_proto_tcl.c b/rfid_proto_tcl.c index 299360e..248eea5 100644 --- a/rfid_proto_tcl.c +++ b/rfid_proto_tcl.c @@ -4,6 +4,21 @@ * */ +/* + * 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 @@ -25,18 +40,41 @@ static unsigned int sfgi_to_sfgt(struct rfid_protocol_handle *h, unsigned char sfgi) { - /* ISO 14443-4:2000(E) Section 5.2.5. */ - return (256 * 16 / h->l2h->rh->ah->fc) * (2 ^ 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) { - /* ISO 14443-4:2000(E) Section 7.2. */ - return (256*16 / h->l2h->rh->ah->fc) * (2 ^ 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; } -#define activation_fwt(x) (65536 / x->l2h->rh->ah->fc) +/* 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 @@ -53,17 +91,20 @@ tcl_parse_ats(struct rfid_protocol_handle *h, 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 = 0; + h->priv.tcl.ta = 0x80; /* 0x80 (same d for both dirs) */ h->priv.tcl.sfgt = sfgi_to_sfgt(h, 0); - if (1 /* FIXME: is_iso14443a */) { + 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 */ - /* FIXME */ + /* Value is assigned in tcl_connect() */ + /* This function is never called for Type B, since it has no (R)ATS */ } return 0; } @@ -143,28 +184,81 @@ tcl_request_ats(struct rfid_protocol_handle *h) 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_pss(struct rfid_protocol_handle *h) +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; - //ppss[2] = 0x00 & foo; + /* FIXME: deal with different speed for each direction */ + DrI = d_to_di(h, Dr); + DsI = d_to_di(h, Ds); - // FIXME: finish - - return -1; + 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; } @@ -177,6 +271,15 @@ tcl_build_prologue2(struct tcl_handle *th, *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; @@ -225,7 +328,8 @@ tcl_build_prologue_s(struct tcl_handle *th, { /* ISO 14443-4:2000(E) Section 7.1.1.1 */ - /* the only S-block from PCD->PICC is DESELECT: */ + /* 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); } @@ -262,10 +366,11 @@ tcl_connect(struct rfid_protocol_handle *h) if (ret < 0) return ret; - if (0 /* FIXME */) { - ret = tcl_do_pss(h); + /* Only do PPS if any non-default divisors supported */ + if (h->priv.tcl.ta & 0x77) { + ret = tcl_do_pps(h); if (ret < 0) - return -1; + return ret; } break; case RFID_LAYER2_ISO14443B: @@ -292,7 +397,7 @@ tcl_connect(struct rfid_protocol_handle *h) } /* PUPI will be presented as ATS/historical bytes */ - memcpy(h->priv.tcl.ats, h->l2h->priv.iso14443b.pupi, 4); + memcpy(h->priv.tcl.ats, h->l2h->uid, 4); h->priv.tcl.ats_len = 4; h->priv.tcl.historical_bytes = h->priv.tcl.ats; @@ -340,6 +445,10 @@ tcl_deselect(struct rfid_protocol_handle *h) 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, @@ -351,6 +460,12 @@ tcl_transcieve(struct rfid_protocol_handle *h, 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; @@ -373,13 +488,124 @@ tcl_transcieve(struct rfid_protocol_handle *h, } memcpy(tx_buf + prlg_len, tx_data, tx_len); - ret = h->l2h->l2->fn.transcieve(h->l2h, tx_buf, tx_len+prlg_len, - rx_buf, rx_len, th->fwt, 0); + /* intialize to data-to-be-transferred */ + _tx = tx_buf; + _tx_len = tx_len+prlg_len; + _timeout = th->fwt; + +do_tx: + ret = h->l2h->l2->fn.transcieve(h->l2h, _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; + } - memcpy(rx_data, rx_buf, *rx_len); + 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; + /* we're actually receiving payload data */ + + DEBUGP("I-Block\n"); + 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; + } + inf++; + } + if (*rx_buf & TCL_PCB_NAD_FOLLOWING) { + inf++; + } + memcpy(rx_data, inf, *rx_len - (inf - rx_buf)); + + 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); @@ -420,8 +646,7 @@ tcl_init(struct rfid_layer2_handle *l2h) /* maximum received ats length equals mru of asic/reader */ th->priv.tcl.state = TCL_STATE_INITIAL; th->priv.tcl.ats_len = mru; - th->l2h = l2h; - th->proto = &rfid_protocol_tcl; + th->priv.tcl.toggle = 1; th->priv.tcl.fsd = iso14443_fsd_approx(mru);