X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=src%2Frfid_proto_tcl.c;h=cfde04b29f688c6b8a8ff42d2c961b7f7ec716f6;hb=refs%2Fheads%2Fsmartx;hp=0587611d0b71e1daccf52397ae10c45442b4fa10;hpb=a0123fec8d68b9986afac5d3078a38fdf57d8f40;p=librfid diff --git a/src/rfid_proto_tcl.c b/src/rfid_proto_tcl.c index 0587611..cfde04b 100644 --- a/src/rfid_proto_tcl.c +++ b/src/rfid_proto_tcl.c @@ -1,6 +1,6 @@ /* ISO 14443-4 (T=CL) implementation, PCD side. * - * (C) 2005 by Harald Welte + * (C) 2005-2006 by Harald Welte * */ @@ -16,7 +16,7 @@ * * 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 @@ -25,27 +25,22 @@ #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -#include -#include +#include +#include #include "rfid_iso14443_common.h" -#if 0 -#ifdef DEBUGP -#undef DEBUGP -#define DEBUGP(x, ...) -#endif -#ifdef DEBUGPC -#undef DEBUGPC -#define DEBUGPC(x, ...) -#endif -#endif +#define RFID_MAX_FRAMELEN 256 + +#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 enum rfid_frametype l2_to_frame(unsigned int layer2) { @@ -127,7 +122,8 @@ tcl_parse_ats(struct rfid_protocol_handle *h, } 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 */ + /* This function is never called for Type B, + * since Type B has no (R)ATS */ } return 0; } @@ -138,6 +134,8 @@ tcl_parse_ats(struct rfid_protocol_handle *h, cur = &ats[2]; iso14443_fsdi_to_fsd(&h->priv.tcl.fsc, t0 & 0x0f); + if (h->priv.tcl.fsc > h->l2h->rh->ah->mtu) + h->priv.tcl.fsc = h->l2h->rh->ah->mtu; if (t0 & (1 << 4)) { /* TA is transmitted */ @@ -153,15 +151,21 @@ tcl_parse_ats(struct rfid_protocol_handle *h, if (t0 & (1 << 6)) { /* TC is transmitted */ - if (*cur & 0x01) + if (*cur & 0x01) { h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED; - if (*cur & 0x02) + DEBUGP("This PICC supports NAD\n"); + } + if (*cur & 0x02) { h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED; + DEBUGP("This PICC supports CID\n"); + } cur++; } h->priv.tcl.historical_len = (ats+len) - cur; h->priv.tcl.historical_bytes = cur; + + DEBUGP("ATS parsed: %s\n", rfid_hexdump(ats, size)); return 0; } @@ -187,13 +191,13 @@ tcl_request_ats(struct rfid_protocol_handle *h) rats[0] = 0xe0; rats[1] = (h->priv.tcl.cid & 0x0f) | ((fsdi << 4) & 0xf0); - /* transcieve (with CRC) */ - ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR, + /* transceive (with CRC) */ + ret = rfid_layer2_transceive(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"); + DEBUGP("transceive of rats failed\n"); h->priv.tcl.state = TCL_STATE_RATS_SENT; /* FIXME: retransmit */ return ret; @@ -258,7 +262,9 @@ tcl_do_pps(struct rfid_protocol_handle *h) { int ret; unsigned char ppss[3]; - unsigned char pps_response[1]; + /* FIXME: this stinks like hell. IF we reduce pps_response size to one, + we'll get stack corruption! */ + unsigned char pps_response[10]; unsigned int rx_len = 1; unsigned char Dr, Ds, DrI, DsI; unsigned int speed; @@ -281,6 +287,7 @@ tcl_do_pps(struct rfid_protocol_handle *h) ppss[0] = 0xd0 | (h->priv.tcl.cid & 0x0f); ppss[1] = 0x11; + ppss[2] = 0x00; /* FIXME: deal with different speed for each direction */ DrI = d_to_di(h, Dr); @@ -289,7 +296,7 @@ tcl_do_pps(struct rfid_protocol_handle *h) ppss[2] = (ppss[2] & 0xf0) | (DrI | DsI << 2); - ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR, + ret = rfid_layer2_transceive(h->l2h, RFID_14443A_FRAME_REGULAR, ppss, 3, pps_response, &rx_len, h->priv.tcl.fwt, TCL_TRANSP_F_TX_CRC); if (ret < 0) @@ -325,13 +332,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 (!is_s_block(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) { @@ -341,9 +350,8 @@ tcl_build_prologue2(struct tcl_handle *th, prlg[*prlg_len] = th->cid & 0x0f; } - /* nad only for I-block (0xc0 == 00) */ - if ((th->flags & TCL_HANDLE_F_NAD_USED) && - ((pcb & 0xc0) == 0x00)) { + /* nad only for I-block */ + if ((th->flags & TCL_HANDLE_F_NAD_USED) && is_i_block(pcb)) { /* ISO 14443-4:2000(E) Section 7.1.1.3 */ /* FIXME: in case of chaining only for first frame */ *prlg |= TCL_PCB_NAD_FOLLOWING; @@ -488,7 +496,7 @@ tcl_deselect(struct rfid_protocol_handle *h) if (ret < 0) return ret; - ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR, + ret = rfid_layer2_transceive(h->l2h, RFID_14443A_FRAME_REGULAR, frame, prlg_len, rx, &rx_len, deactivation_fwt(h), TCL_TRANSP_F_TX_CRC); @@ -502,186 +510,227 @@ 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) +struct fr_buff { + unsigned int frame_len; /* length of frame */ + unsigned int hdr_len; /* length of header within frame */ + unsigned char data[RFID_MAX_FRAMELEN]; +}; + +#define frb_payload(x) (x.data + x.hdr_len) + + +/* RFID transceive buffer. */ +struct rfid_xcvb { + struct rfix_xcvb *next; /* next in queue of buffers */ + + u_int64_t timeout; /* timeout to wait for reply */ + struct fr_buff tx; + struct fr_buff rx; + + //struct rfid_protocol_handle *h; /* connection to which we belong */ +}; + +struct tcl_tx_context { + const unsigned char *tx; + unsigned char *rx; + const unsigned char *next_tx_byte; + unsigned char *next_rx_byte; + unsigned int rx_len; + unsigned int tx_len; + struct rfid_protocol_handle *h; +}; + +#define tcl_ctx_todo(ctx) (ctx->tx_len - (ctx->next_tx_byte - ctx->tx)) + +static int +tcl_refill_xcvb(struct rfid_xcvb *xcvb, struct tcl_tx_context *ctx) +{ + struct tcl_handle *th = &ctx->h->priv.tcl; + + if (ctx->next_tx_byte >= ctx->tx + ctx->tx_len) { + DEBUGP("tyring to refill tx xcvb but no data left!\n"); + return -1; + } + + if (tcl_build_prologue_i(th, xcvb->tx.data, + &xcvb->tx.hdr_len) < 0) + return -1; + + if (tcl_ctx_todo(ctx) > th->fsc - xcvb->tx.hdr_len) + xcvb->tx.frame_len = max_net_tx_framesize(th); + else + xcvb->tx.frame_len = tcl_ctx_todo(ctx); + + memcpy(frb_payload(xcvb->tx), ctx->next_tx_byte, + xcvb->tx.frame_len); + + ctx->next_tx_byte += xcvb->tx.frame_len; + + /* check whether we need to set the chaining bit */ + if (ctx->next_tx_byte < ctx->tx + ctx->tx_len) + xcvb->tx.data[0] |= 0x10; + + /* add hdr_len after copying the net payload */ + xcvb->tx.frame_len += xcvb->tx.hdr_len; + + xcvb->timeout = th->fwt; + + return 0; +} + +static void fill_xcvb_wtxm(struct tcl_handle *th, struct rfid_xcvb *xcvb, + unsigned char inf) +{ + /* Acknowledge WTXM */ + tcl_build_prologue_s(th, xcvb->tx.data, &xcvb->tx.hdr_len); + /* set two bits that make this block a wtx */ + xcvb->tx.data[0] |= 0x30; + xcvb->tx.data[xcvb->tx.hdr_len] = inf; + xcvb->tx.frame_len = xcvb->tx.hdr_len+1; + xcvb->timeout = th->fwt * inf; +} + +static int check_cid(struct tcl_handle *th, struct rfid_xcvb *xcvb) +{ + if (xcvb->rx.data[0] & TCL_PCB_CID_FOLLOWING) { + if (xcvb->rx.data[1] != th->cid) { + DEBUGP("CID %u is not valid, we expected %u\n", + xcvb->rx.data[1], th->cid); + return 0; + } + } + return 1; +} static int -tcl_transcieve(struct rfid_protocol_handle *h, +tcl_transceive(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 rfid_xcvb xcvb; + struct tcl_tx_context tcl_ctx; 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; - } + /* initialize context */ + tcl_ctx.next_tx_byte = tcl_ctx.tx = tx_data; + tcl_ctx.next_rx_byte = tcl_ctx.rx = rx_data; + tcl_ctx.rx_len = *rx_len; + tcl_ctx.tx_len = tx_len; + tcl_ctx.h = h; - 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; - } + /* initialize xcvb */ + xcvb.timeout = th->fwt; - if (tcl_build_prologue_i(th, tx_buf, &prlg_len) < 0) { +tx_refill: + if (tcl_refill_xcvb(&xcvb, &tcl_ctx) < 0) { ret = -1; - goto out_rxb; + goto out; } - 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 = rfid_layer2_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; + xcvb.rx.frame_len = sizeof(xcvb.rx.data); + ret = rfid_layer2_transceive(h->l2h, l2_to_frame(h->l2h->l2->id), + xcvb.tx.data, xcvb.tx.frame_len, + xcvb.rx.data, &xcvb.rx.frame_len, + xcvb.timeout, 0); - if ((*rx_buf & 0x01) != h->priv.tcl.toggle) { - DEBUGP("response with wrong toggle bit\n"); - goto out_rxb; - } + DEBUGP("l2 transceive finished\n"); + if (ret < 0) + goto out; - if (is_r_block(*rx_buf)) { - unsigned int txed = _tx - tx_buf; + if (is_r_block(xcvb.rx.data[0])) { 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; + + if ((xcvb.rx.data[0] & 0x01) != h->priv.tcl.toggle) { + DEBUGP("response with wrong toggle bit\n"); + goto out; } - } else if (is_s_block(*rx_buf)) { + + /* Handle ACK frame in case of chaining */ + if (!check_cid(th, &xcvb)) + goto out; + + goto tx_refill; + } else if (is_s_block(xcvb.rx.data[0])) { 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) { + + if (!check_cid(th, &xcvb)) + goto out; + + if (xcvb.rx.data[0] & TCL_PCB_CID_FOLLOWING) { + if (xcvb.rx.frame_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; + goto out; } - inf = *(rx_buf+2); + inf = xcvb.rx.data[2]; } else - inf = *(rx_buf+1); + inf = xcvb.rx.data[1]; - if ((*rx_buf & 0x30) != 0x30) { + if ((xcvb.rx.data[0] & 0x30) != 0x30) { DEBUGP("S-Block but not WTX?\n"); ret = -1; - goto out_rxb; + goto out; } 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; + goto out; } - /* 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; + fill_xcvb_wtxm(th, &xcvb, inf); + /* start over with next transceive */ + goto do_tx; + } else if (is_i_block(xcvb.rx.data[0])) { 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++; + + if ((xcvb.rx.data[0] & 0x01) != h->priv.tcl.toggle) { + DEBUGP("response with wrong toggle bit\n"); + goto out; } - net_payload_len = _rx_len - (inf - rx_buf); + + xcvb.rx.hdr_len = 1; + + if (!check_cid(th, &xcvb)) + goto out; + + if (xcvb.rx.data[0] & TCL_PCB_CID_FOLLOWING) + xcvb.rx.hdr_len++; + if (xcvb.rx.data[0] & TCL_PCB_NAD_FOLLOWING) + xcvb.rx.hdr_len++; + + net_payload_len = xcvb.rx.frame_len - xcvb.rx.hdr_len; 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; + memcpy(tcl_ctx.next_rx_byte, &xcvb.rx.data[xcvb.rx.hdr_len], + net_payload_len); + tcl_ctx.next_rx_byte += net_payload_len; - if (*rx_buf & 0x10) { + if (xcvb.rx.data[0] & 0x10) { /* we're not the last frame in the chain, continue rx */ - DEBUGP("we're not the last frame in the chain, continue\n"); + DEBUGP("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; + tcl_build_prologue_r(th, xcvb.tx.data, &xcvb.tx.frame_len, 0); + xcvb.timeout = th->fwt; goto do_tx; } } -out_rxb: - free(rx_buf); -out_txb: - free(tx_buf); out: + *rx_len = tcl_ctx.next_rx_byte - tcl_ctx.rx; return ret; } @@ -691,13 +740,13 @@ 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); + th = malloc_protocol_handle(sizeof(struct rfid_protocol_handle)); 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); + memset(th, 0, sizeof(struct rfid_protocol_handle)); /* maximum received ats length equals mru of asic/reader */ th->priv.tcl.state = TCL_STATE_INITIAL; @@ -712,18 +761,59 @@ tcl_init(struct rfid_layer2_handle *l2h) static int tcl_fini(struct rfid_protocol_handle *ph) { - free(ph); + free_protocol_handle(ph); return 0; } -struct rfid_protocol rfid_protocol_tcl = { +int +tcl_getopt(struct rfid_protocol_handle *h, int optname, void *optval, + unsigned int *optlen) +{ + u_int8_t *opt_str = optval; + + switch (optname) { + case RFID_OPT_P_TCL_ATS: + if (h->priv.tcl.ats_len < *optlen) + *optlen = h->priv.tcl.ats_len; + memcpy(opt_str, h->priv.tcl.ats, *optlen); + break; + case RFID_OPT_P_TCL_ATS_LEN: + if (*optlen < sizeof(u_int8_t)) + return -E2BIG; + *optlen = sizeof(u_int8_t); + *opt_str = h->priv.tcl.ats_len & 0xff; + break; + default: + return -EINVAL; + } + + return 0; +} + +int +tcl_setopt(struct rfid_protocol_handle *h, int optname, const void *optval, + unsigned int optlen) +{ + int ret = -EINVAL; + + switch (optname) { + default: + break; + } + + return ret; +} + +const 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, + .transceive = &tcl_transceive, .close = &tcl_deselect, .fini = &tcl_fini, + .getopt = &tcl_getopt, + .setopt = &tcl_setopt, }, };